1 | /* |
2 | ** Library function support. |
3 | ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h |
4 | */ |
5 | |
6 | #define lj_lib_c |
7 | #define LUA_CORE |
8 | |
9 | #include "lauxlib.h" |
10 | |
11 | #include "lj_obj.h" |
12 | #include "lj_gc.h" |
13 | #include "lj_err.h" |
14 | #include "lj_str.h" |
15 | #include "lj_tab.h" |
16 | #include "lj_func.h" |
17 | #include "lj_bc.h" |
18 | #include "lj_dispatch.h" |
19 | #include "lj_vm.h" |
20 | #include "lj_strscan.h" |
21 | #include "lj_strfmt.h" |
22 | #include "lj_lex.h" |
23 | #include "lj_bcdump.h" |
24 | #include "lj_lib.h" |
25 | |
26 | /* -- Library initialization ---------------------------------------------- */ |
27 | |
28 | static GCtab *lib_create_table(lua_State *L, const char *libname, int hsize) |
29 | { |
30 | if (libname) { |
31 | luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED" , 16); |
32 | lua_getfield(L, -1, libname); |
33 | if (!tvistab(L->top-1)) { |
34 | L->top--; |
35 | if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, hsize) != NULL) |
36 | lj_err_callerv(L, LJ_ERR_BADMODN, libname); |
37 | settabV(L, L->top, tabV(L->top-1)); |
38 | L->top++; |
39 | lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ |
40 | } |
41 | L->top--; |
42 | settabV(L, L->top-1, tabV(L->top)); |
43 | } else { |
44 | lua_createtable(L, 0, hsize); |
45 | } |
46 | return tabV(L->top-1); |
47 | } |
48 | |
49 | static const uint8_t *lib_read_lfunc(lua_State *L, const uint8_t *p, GCtab *tab) |
50 | { |
51 | int len = *p++; |
52 | GCstr *name = lj_str_new(L, (const char *)p, len); |
53 | LexState ls; |
54 | GCproto *pt; |
55 | GCfunc *fn; |
56 | memset(&ls, 0, sizeof(ls)); |
57 | ls.L = L; |
58 | ls.p = (const char *)(p+len); |
59 | ls.pe = (const char *)~(uintptr_t)0; |
60 | ls.c = -1; |
61 | ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE)); |
62 | ls.chunkname = name; |
63 | pt = lj_bcread_proto(&ls); |
64 | pt->firstline = ~(BCLine)0; |
65 | fn = lj_func_newL_empty(L, pt, tabref(L->env)); |
66 | /* NOBARRIER: See below for common barrier. */ |
67 | setfuncV(L, lj_tab_setstr(L, tab, name), fn); |
68 | return (const uint8_t *)ls.p; |
69 | } |
70 | |
71 | void lj_lib_register(lua_State *L, const char *libname, |
72 | const uint8_t *p, const lua_CFunction *cf) |
73 | { |
74 | GCtab *env = tabref(L->env); |
75 | GCfunc *ofn = NULL; |
76 | int ffid = *p++; |
77 | BCIns *bcff = &L2GG(L)->bcff[*p++]; |
78 | GCtab *tab = lib_create_table(L, libname, *p++); |
79 | ptrdiff_t tpos = L->top - L->base; |
80 | |
81 | /* Avoid barriers further down. */ |
82 | lj_gc_anybarriert(L, tab); |
83 | tab->nomm = 0; |
84 | |
85 | for (;;) { |
86 | uint32_t tag = *p++; |
87 | MSize len = tag & LIBINIT_LENMASK; |
88 | tag &= LIBINIT_TAGMASK; |
89 | if (tag != LIBINIT_STRING) { |
90 | const char *name; |
91 | MSize nuv = (MSize)(L->top - L->base - tpos); |
92 | GCfunc *fn = lj_func_newC(L, nuv, env); |
93 | if (nuv) { |
94 | L->top = L->base + tpos; |
95 | memcpy(fn->c.upvalue, L->top, sizeof(TValue)*nuv); |
96 | } |
97 | fn->c.ffid = (uint8_t)(ffid++); |
98 | name = (const char *)p; |
99 | p += len; |
100 | if (tag == LIBINIT_CF) |
101 | setmref(fn->c.pc, &G(L)->bc_cfunc_int); |
102 | else |
103 | setmref(fn->c.pc, bcff++); |
104 | if (tag == LIBINIT_ASM_) |
105 | fn->c.f = ofn->c.f; /* Copy handler from previous function. */ |
106 | else |
107 | fn->c.f = *cf++; /* Get cf or handler from C function table. */ |
108 | if (len) { |
109 | /* NOBARRIER: See above for common barrier. */ |
110 | setfuncV(L, lj_tab_setstr(L, tab, lj_str_new(L, name, len)), fn); |
111 | } |
112 | ofn = fn; |
113 | } else { |
114 | switch (tag | len) { |
115 | case LIBINIT_LUA: |
116 | p = lib_read_lfunc(L, p, tab); |
117 | break; |
118 | case LIBINIT_SET: |
119 | L->top -= 2; |
120 | if (tvisstr(L->top+1) && strV(L->top+1)->len == 0) |
121 | env = tabV(L->top); |
122 | else /* NOBARRIER: See above for common barrier. */ |
123 | copyTV(L, lj_tab_set(L, tab, L->top+1), L->top); |
124 | break; |
125 | case LIBINIT_NUMBER: |
126 | memcpy(&L->top->n, p, sizeof(double)); |
127 | L->top++; |
128 | p += sizeof(double); |
129 | break; |
130 | case LIBINIT_COPY: |
131 | copyTV(L, L->top, L->top - *p++); |
132 | L->top++; |
133 | break; |
134 | case LIBINIT_LASTCL: |
135 | setfuncV(L, L->top++, ofn); |
136 | break; |
137 | case LIBINIT_FFID: |
138 | ffid++; |
139 | break; |
140 | case LIBINIT_END: |
141 | return; |
142 | default: |
143 | setstrV(L, L->top++, lj_str_new(L, (const char *)p, len)); |
144 | p += len; |
145 | break; |
146 | } |
147 | } |
148 | } |
149 | } |
150 | |
151 | /* Push internal function on the stack. */ |
152 | GCfunc *lj_lib_pushcc(lua_State *L, lua_CFunction f, int id, int n) |
153 | { |
154 | GCfunc *fn; |
155 | lua_pushcclosure(L, f, n); |
156 | fn = funcV(L->top-1); |
157 | fn->c.ffid = (uint8_t)id; |
158 | setmref(fn->c.pc, &G(L)->bc_cfunc_int); |
159 | return fn; |
160 | } |
161 | |
162 | void lj_lib_prereg(lua_State *L, const char *name, lua_CFunction f, GCtab *env) |
163 | { |
164 | luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD" , 4); |
165 | lua_pushcfunction(L, f); |
166 | /* NOBARRIER: The function is new (marked white). */ |
167 | setgcref(funcV(L->top-1)->c.env, obj2gco(env)); |
168 | lua_setfield(L, -2, name); |
169 | L->top--; |
170 | } |
171 | |
172 | int lj_lib_postreg(lua_State *L, lua_CFunction cf, int id, const char *name) |
173 | { |
174 | GCfunc *fn = lj_lib_pushcf(L, cf, id); |
175 | GCtab *t = tabref(curr_func(L)->c.env); /* Reference to parent table. */ |
176 | setfuncV(L, lj_tab_setstr(L, t, lj_str_newz(L, name)), fn); |
177 | lj_gc_anybarriert(L, t); |
178 | setfuncV(L, L->top++, fn); |
179 | return 1; |
180 | } |
181 | |
182 | /* -- Type checks --------------------------------------------------------- */ |
183 | |
184 | TValue *lj_lib_checkany(lua_State *L, int narg) |
185 | { |
186 | TValue *o = L->base + narg-1; |
187 | if (o >= L->top) |
188 | lj_err_arg(L, narg, LJ_ERR_NOVAL); |
189 | return o; |
190 | } |
191 | |
192 | GCstr *lj_lib_checkstr(lua_State *L, int narg) |
193 | { |
194 | TValue *o = L->base + narg-1; |
195 | if (o < L->top) { |
196 | if (LJ_LIKELY(tvisstr(o))) { |
197 | return strV(o); |
198 | } else if (tvisnumber(o)) { |
199 | GCstr *s = lj_strfmt_number(L, o); |
200 | setstrV(L, o, s); |
201 | return s; |
202 | } |
203 | } |
204 | lj_err_argt(L, narg, LUA_TSTRING); |
205 | return NULL; /* unreachable */ |
206 | } |
207 | |
208 | GCstr *lj_lib_optstr(lua_State *L, int narg) |
209 | { |
210 | TValue *o = L->base + narg-1; |
211 | return (o < L->top && !tvisnil(o)) ? lj_lib_checkstr(L, narg) : NULL; |
212 | } |
213 | |
214 | #if LJ_DUALNUM |
215 | void lj_lib_checknumber(lua_State *L, int narg) |
216 | { |
217 | TValue *o = L->base + narg-1; |
218 | if (!(o < L->top && lj_strscan_numberobj(o))) |
219 | lj_err_argt(L, narg, LUA_TNUMBER); |
220 | } |
221 | #endif |
222 | |
223 | lua_Number lj_lib_checknum(lua_State *L, int narg) |
224 | { |
225 | TValue *o = L->base + narg-1; |
226 | if (!(o < L->top && |
227 | (tvisnumber(o) || (tvisstr(o) && lj_strscan_num(strV(o), o))))) |
228 | lj_err_argt(L, narg, LUA_TNUMBER); |
229 | if (LJ_UNLIKELY(tvisint(o))) { |
230 | lua_Number n = (lua_Number)intV(o); |
231 | setnumV(o, n); |
232 | return n; |
233 | } else { |
234 | return numV(o); |
235 | } |
236 | } |
237 | |
238 | int32_t lj_lib_checkint(lua_State *L, int narg) |
239 | { |
240 | TValue *o = L->base + narg-1; |
241 | if (!(o < L->top && lj_strscan_numberobj(o))) |
242 | lj_err_argt(L, narg, LUA_TNUMBER); |
243 | if (LJ_LIKELY(tvisint(o))) { |
244 | return intV(o); |
245 | } else { |
246 | int32_t i = lj_num2int(numV(o)); |
247 | if (LJ_DUALNUM) setintV(o, i); |
248 | return i; |
249 | } |
250 | } |
251 | |
252 | int32_t lj_lib_optint(lua_State *L, int narg, int32_t def) |
253 | { |
254 | TValue *o = L->base + narg-1; |
255 | return (o < L->top && !tvisnil(o)) ? lj_lib_checkint(L, narg) : def; |
256 | } |
257 | |
258 | GCfunc *lj_lib_checkfunc(lua_State *L, int narg) |
259 | { |
260 | TValue *o = L->base + narg-1; |
261 | if (!(o < L->top && tvisfunc(o))) |
262 | lj_err_argt(L, narg, LUA_TFUNCTION); |
263 | return funcV(o); |
264 | } |
265 | |
266 | GCtab *lj_lib_checktab(lua_State *L, int narg) |
267 | { |
268 | TValue *o = L->base + narg-1; |
269 | if (!(o < L->top && tvistab(o))) |
270 | lj_err_argt(L, narg, LUA_TTABLE); |
271 | return tabV(o); |
272 | } |
273 | |
274 | GCtab *lj_lib_checktabornil(lua_State *L, int narg) |
275 | { |
276 | TValue *o = L->base + narg-1; |
277 | if (o < L->top) { |
278 | if (tvistab(o)) |
279 | return tabV(o); |
280 | else if (tvisnil(o)) |
281 | return NULL; |
282 | } |
283 | lj_err_arg(L, narg, LJ_ERR_NOTABN); |
284 | return NULL; /* unreachable */ |
285 | } |
286 | |
287 | int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst) |
288 | { |
289 | GCstr *s = def >= 0 ? lj_lib_optstr(L, narg) : lj_lib_checkstr(L, narg); |
290 | if (s) { |
291 | const char *opt = strdata(s); |
292 | MSize len = s->len; |
293 | int i; |
294 | for (i = 0; *(const uint8_t *)lst; i++) { |
295 | if (*(const uint8_t *)lst == len && memcmp(opt, lst+1, len) == 0) |
296 | return i; |
297 | lst += 1+*(const uint8_t *)lst; |
298 | } |
299 | lj_err_argv(L, narg, LJ_ERR_INVOPTM, opt); |
300 | } |
301 | return def; |
302 | } |
303 | |
304 | |