| 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 | |