1/*
2** Base and coroutine library.
3** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4**
5** Major portions taken verbatim or adapted from the Lua interpreter.
6** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7*/
8
9#include <stdio.h>
10
11#define lib_base_c
12#define LUA_LIB
13
14#include "lua.h"
15#include "lauxlib.h"
16#include "lualib.h"
17
18#include "lj_obj.h"
19#include "lj_gc.h"
20#include "lj_err.h"
21#include "lj_debug.h"
22#include "lj_str.h"
23#include "lj_tab.h"
24#include "lj_meta.h"
25#include "lj_state.h"
26#include "lj_frame.h"
27#if LJ_HASFFI
28#include "lj_ctype.h"
29#include "lj_cconv.h"
30#endif
31#include "lj_bc.h"
32#include "lj_ff.h"
33#include "lj_dispatch.h"
34#include "lj_char.h"
35#include "lj_strscan.h"
36#include "lj_strfmt.h"
37#include "lj_lib.h"
38
39/* -- Base library: checks ------------------------------------------------ */
40
41#define LJLIB_MODULE_base
42
43LJLIB_ASM(assert) LJLIB_REC(.)
44{
45 lj_lib_checkany(L, 1);
46 if (L->top == L->base+1)
47 lj_err_caller(L, LJ_ERR_ASSERT);
48 else if (tvisstr(L->base+1) || tvisnumber(L->base+1))
49 lj_err_callermsg(L, strdata(lj_lib_checkstr(L, 2)));
50 else
51 lj_err_run(L);
52 return FFH_UNREACHABLE;
53}
54
55/* ORDER LJ_T */
56LJLIB_PUSH("nil")
57LJLIB_PUSH("boolean")
58LJLIB_PUSH(top-1) /* boolean */
59LJLIB_PUSH("userdata")
60LJLIB_PUSH("string")
61LJLIB_PUSH("upval")
62LJLIB_PUSH("thread")
63LJLIB_PUSH("proto")
64LJLIB_PUSH("function")
65LJLIB_PUSH("trace")
66LJLIB_PUSH("cdata")
67LJLIB_PUSH("table")
68LJLIB_PUSH(top-9) /* userdata */
69LJLIB_PUSH("number")
70LJLIB_ASM_(type) LJLIB_REC(.)
71/* Recycle the lj_lib_checkany(L, 1) from assert. */
72
73/* -- Base library: iterators --------------------------------------------- */
74
75/* This solves a circular dependency problem -- change FF_next_N as needed. */
76LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
77
78LJLIB_ASM(next)
79{
80 lj_lib_checktab(L, 1);
81 return FFH_UNREACHABLE;
82}
83
84#if LJ_52 || LJ_HASFFI
85static int ffh_pairs(lua_State *L, MMS mm)
86{
87 TValue *o = lj_lib_checkany(L, 1);
88 cTValue *mo = lj_meta_lookup(L, o, mm);
89 if ((LJ_52 || tviscdata(o)) && !tvisnil(mo)) {
90 L->top = o+1; /* Only keep one argument. */
91 copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */
92 return FFH_TAILCALL;
93 } else {
94 if (!tvistab(o)) lj_err_argt(L, 1, LUA_TTABLE);
95 if (LJ_FR2) { copyTV(L, o-1, o); o--; }
96 setfuncV(L, o-1, funcV(lj_lib_upvalue(L, 1)));
97 if (mm == MM_pairs) setnilV(o+1); else setintV(o+1, 0);
98 return FFH_RES(3);
99 }
100}
101#else
102#define ffh_pairs(L, mm) (lj_lib_checktab(L, 1), FFH_UNREACHABLE)
103#endif
104
105LJLIB_PUSH(lastcl)
106LJLIB_ASM(pairs) LJLIB_REC(xpairs 0)
107{
108 return ffh_pairs(L, MM_pairs);
109}
110
111LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.)
112{
113 lj_lib_checktab(L, 1);
114 lj_lib_checkint(L, 2);
115 return FFH_UNREACHABLE;
116}
117
118LJLIB_PUSH(lastcl)
119LJLIB_ASM(ipairs) LJLIB_REC(xpairs 1)
120{
121 return ffh_pairs(L, MM_ipairs);
122}
123
124/* -- Base library: getters and setters ----------------------------------- */
125
126LJLIB_ASM_(getmetatable) LJLIB_REC(.)
127/* Recycle the lj_lib_checkany(L, 1) from assert. */
128
129LJLIB_ASM(setmetatable) LJLIB_REC(.)
130{
131 GCtab *t = lj_lib_checktab(L, 1);
132 GCtab *mt = lj_lib_checktabornil(L, 2);
133 if (!tvisnil(lj_meta_lookup(L, L->base, MM_metatable)))
134 lj_err_caller(L, LJ_ERR_PROTMT);
135 setgcref(t->metatable, obj2gco(mt));
136 if (mt) { lj_gc_objbarriert(L, t, mt); }
137 settabV(L, L->base-1-LJ_FR2, t);
138 return FFH_RES(1);
139}
140
141LJLIB_CF(getfenv) LJLIB_REC(.)
142{
143 GCfunc *fn;
144 cTValue *o = L->base;
145 if (!(o < L->top && tvisfunc(o))) {
146 int level = lj_lib_optint(L, 1, 1);
147 o = lj_debug_frame(L, level, &level);
148 if (o == NULL)
149 lj_err_arg(L, 1, LJ_ERR_INVLVL);
150 if (LJ_FR2) o--;
151 }
152 fn = &gcval(o)->fn;
153 settabV(L, L->top++, isluafunc(fn) ? tabref(fn->l.env) : tabref(L->env));
154 return 1;
155}
156
157LJLIB_CF(setfenv)
158{
159 GCfunc *fn;
160 GCtab *t = lj_lib_checktab(L, 2);
161 cTValue *o = L->base;
162 if (!(o < L->top && tvisfunc(o))) {
163 int level = lj_lib_checkint(L, 1);
164 if (level == 0) {
165 /* NOBARRIER: A thread (i.e. L) is never black. */
166 setgcref(L->env, obj2gco(t));
167 return 0;
168 }
169 o = lj_debug_frame(L, level, &level);
170 if (o == NULL)
171 lj_err_arg(L, 1, LJ_ERR_INVLVL);
172 if (LJ_FR2) o--;
173 }
174 fn = &gcval(o)->fn;
175 if (!isluafunc(fn))
176 lj_err_caller(L, LJ_ERR_SETFENV);
177 setgcref(fn->l.env, obj2gco(t));
178 lj_gc_objbarrier(L, obj2gco(fn), t);
179 setfuncV(L, L->top++, fn);
180 return 1;
181}
182
183LJLIB_ASM(rawget) LJLIB_REC(.)
184{
185 lj_lib_checktab(L, 1);
186 lj_lib_checkany(L, 2);
187 return FFH_UNREACHABLE;
188}
189
190LJLIB_CF(rawset) LJLIB_REC(.)
191{
192 lj_lib_checktab(L, 1);
193 lj_lib_checkany(L, 2);
194 L->top = 1+lj_lib_checkany(L, 3);
195 lua_rawset(L, 1);
196 return 1;
197}
198
199LJLIB_CF(rawequal) LJLIB_REC(.)
200{
201 cTValue *o1 = lj_lib_checkany(L, 1);
202 cTValue *o2 = lj_lib_checkany(L, 2);
203 setboolV(L->top-1, lj_obj_equal(o1, o2));
204 return 1;
205}
206
207#if LJ_52
208LJLIB_CF(rawlen) LJLIB_REC(.)
209{
210 cTValue *o = L->base;
211 int32_t len;
212 if (L->top > o && tvisstr(o))
213 len = (int32_t)strV(o)->len;
214 else
215 len = (int32_t)lj_tab_len(lj_lib_checktab(L, 1));
216 setintV(L->top-1, len);
217 return 1;
218}
219#endif
220
221LJLIB_CF(unpack)
222{
223 GCtab *t = lj_lib_checktab(L, 1);
224 int32_t n, i = lj_lib_optint(L, 2, 1);
225 int32_t e = (L->base+3-1 < L->top && !tvisnil(L->base+3-1)) ?
226 lj_lib_checkint(L, 3) : (int32_t)lj_tab_len(t);
227 uint32_t nu;
228 if (i > e) return 0;
229 nu = (uint32_t)e - (uint32_t)i;
230 n = (int32_t)(nu+1);
231 if (nu >= LUAI_MAXCSTACK || !lua_checkstack(L, n))
232 lj_err_caller(L, LJ_ERR_UNPACK);
233 do {
234 cTValue *tv = lj_tab_getint(t, i);
235 if (tv) {
236 copyTV(L, L->top++, tv);
237 } else {
238 setnilV(L->top++);
239 }
240 } while (i++ < e);
241 return n;
242}
243
244LJLIB_CF(select) LJLIB_REC(.)
245{
246 int32_t n = (int32_t)(L->top - L->base);
247 if (n >= 1 && tvisstr(L->base) && *strVdata(L->base) == '#') {
248 setintV(L->top-1, n-1);
249 return 1;
250 } else {
251 int32_t i = lj_lib_checkint(L, 1);
252 if (i < 0) i = n + i; else if (i > n) i = n;
253 if (i < 1)
254 lj_err_arg(L, 1, LJ_ERR_IDXRNG);
255 return n - i;
256 }
257}
258
259/* -- Base library: conversions ------------------------------------------- */
260
261LJLIB_ASM(tonumber) LJLIB_REC(.)
262{
263 int32_t base = lj_lib_optint(L, 2, 10);
264 if (base == 10) {
265 TValue *o = lj_lib_checkany(L, 1);
266 if (lj_strscan_numberobj(o)) {
267 copyTV(L, L->base-1-LJ_FR2, o);
268 return FFH_RES(1);
269 }
270#if LJ_HASFFI
271 if (tviscdata(o)) {
272 CTState *cts = ctype_cts(L);
273 CType *ct = lj_ctype_rawref(cts, cdataV(o)->ctypeid);
274 if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
275 if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
276 if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) &&
277 ct->size <= 4 && !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) {
278 int32_t i;
279 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, 0);
280 setintV(L->base-1-LJ_FR2, i);
281 return FFH_RES(1);
282 }
283 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE),
284 (uint8_t *)&(L->base-1-LJ_FR2)->n, o, 0);
285 return FFH_RES(1);
286 }
287 }
288#endif
289 } else {
290 const char *p = strdata(lj_lib_checkstr(L, 1));
291 char *ep;
292 unsigned int neg = 0;
293 unsigned long ul;
294 if (base < 2 || base > 36)
295 lj_err_arg(L, 2, LJ_ERR_BASERNG);
296 while (lj_char_isspace((unsigned char)(*p))) p++;
297 if (*p == '-') { p++; neg = 1; } else if (*p == '+') { p++; }
298 if (lj_char_isalnum((unsigned char)(*p))) {
299 ul = strtoul(p, &ep, base);
300 if (p != ep) {
301 while (lj_char_isspace((unsigned char)(*ep))) ep++;
302 if (*ep == '\0') {
303 if (LJ_DUALNUM && LJ_LIKELY(ul < 0x80000000u+neg)) {
304 if (neg) ul = (unsigned long)-(long)ul;
305 setintV(L->base-1-LJ_FR2, (int32_t)ul);
306 } else {
307 lua_Number n = (lua_Number)ul;
308 if (neg) n = -n;
309 setnumV(L->base-1-LJ_FR2, n);
310 }
311 return FFH_RES(1);
312 }
313 }
314 }
315 }
316 setnilV(L->base-1-LJ_FR2);
317 return FFH_RES(1);
318}
319
320LJLIB_ASM(tostring) LJLIB_REC(.)
321{
322 TValue *o = lj_lib_checkany(L, 1);
323 cTValue *mo;
324 L->top = o+1; /* Only keep one argument. */
325 if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
326 copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */
327 return FFH_TAILCALL;
328 }
329 lj_gc_check(L);
330 setstrV(L, L->base-1-LJ_FR2, lj_strfmt_obj(L, L->base));
331 return FFH_RES(1);
332}
333
334/* -- Base library: throw and catch errors -------------------------------- */
335
336LJLIB_CF(error)
337{
338 int32_t level = lj_lib_optint(L, 2, 1);
339 lua_settop(L, 1);
340 if (lua_isstring(L, 1) && level > 0) {
341 luaL_where(L, level);
342 lua_pushvalue(L, 1);
343 lua_concat(L, 2);
344 }
345 return lua_error(L);
346}
347
348LJLIB_ASM(pcall) LJLIB_REC(.)
349{
350 lj_lib_checkany(L, 1);
351 lj_lib_checkfunc(L, 2); /* For xpcall only. */
352 return FFH_UNREACHABLE;
353}
354LJLIB_ASM_(xpcall) LJLIB_REC(.)
355
356/* -- Base library: load Lua code ----------------------------------------- */
357
358static int load_aux(lua_State *L, int status, int envarg)
359{
360 if (status == LUA_OK) {
361 if (tvistab(L->base+envarg-1)) {
362 GCfunc *fn = funcV(L->top-1);
363 GCtab *t = tabV(L->base+envarg-1);
364 setgcref(fn->c.env, obj2gco(t));
365 lj_gc_objbarrier(L, fn, t);
366 }
367 return 1;
368 } else {
369 setnilV(L->top-2);
370 return 2;
371 }
372}
373
374LJLIB_CF(loadfile)
375{
376 GCstr *fname = lj_lib_optstr(L, 1);
377 GCstr *mode = lj_lib_optstr(L, 2);
378 int status;
379 lua_settop(L, 3); /* Ensure env arg exists. */
380 status = luaL_loadfilex(L, fname ? strdata(fname) : NULL,
381 mode ? strdata(mode) : NULL);
382 return load_aux(L, status, 3);
383}
384
385static const char *reader_func(lua_State *L, void *ud, size_t *size)
386{
387 UNUSED(ud);
388 luaL_checkstack(L, 2, "too many nested functions");
389 copyTV(L, L->top++, L->base);
390 lua_call(L, 0, 1); /* Call user-supplied function. */
391 L->top--;
392 if (tvisnil(L->top)) {
393 *size = 0;
394 return NULL;
395 } else if (tvisstr(L->top) || tvisnumber(L->top)) {
396 copyTV(L, L->base+4, L->top); /* Anchor string in reserved stack slot. */
397 return lua_tolstring(L, 5, size);
398 } else {
399 lj_err_caller(L, LJ_ERR_RDRSTR);
400 return NULL;
401 }
402}
403
404LJLIB_CF(load)
405{
406 GCstr *name = lj_lib_optstr(L, 2);
407 GCstr *mode = lj_lib_optstr(L, 3);
408 int status;
409 if (L->base < L->top && (tvisstr(L->base) || tvisnumber(L->base))) {
410 GCstr *s = lj_lib_checkstr(L, 1);
411 lua_settop(L, 4); /* Ensure env arg exists. */
412 status = luaL_loadbufferx(L, strdata(s), s->len, strdata(name ? name : s),
413 mode ? strdata(mode) : NULL);
414 } else {
415 lj_lib_checkfunc(L, 1);
416 lua_settop(L, 5); /* Reserve a slot for the string from the reader. */
417 status = lua_loadx(L, reader_func, NULL, name ? strdata(name) : "=(load)",
418 mode ? strdata(mode) : NULL);
419 }
420 return load_aux(L, status, 4);
421}
422
423LJLIB_CF(loadstring)
424{
425 return lj_cf_load(L);
426}
427
428LJLIB_CF(dofile)
429{
430 GCstr *fname = lj_lib_optstr(L, 1);
431 setnilV(L->top);
432 L->top = L->base+1;
433 if (luaL_loadfile(L, fname ? strdata(fname) : NULL) != LUA_OK)
434 lua_error(L);
435 lua_call(L, 0, LUA_MULTRET);
436 return (int)(L->top - L->base) - 1;
437}
438
439/* -- Base library: GC control -------------------------------------------- */
440
441LJLIB_CF(gcinfo)
442{
443 setintV(L->top++, (int32_t)(G(L)->gc.total >> 10));
444 return 1;
445}
446
447LJLIB_CF(collectgarbage)
448{
449 int opt = lj_lib_checkopt(L, 1, LUA_GCCOLLECT, /* ORDER LUA_GC* */
450 "\4stop\7restart\7collect\5count\1\377\4step\10setpause\12setstepmul\1\377\11isrunning");
451 int32_t data = lj_lib_optint(L, 2, 0);
452 if (opt == LUA_GCCOUNT) {
453 setnumV(L->top, (lua_Number)G(L)->gc.total/1024.0);
454 } else {
455 int res = lua_gc(L, opt, data);
456 if (opt == LUA_GCSTEP || opt == LUA_GCISRUNNING)
457 setboolV(L->top, res);
458 else
459 setintV(L->top, res);
460 }
461 L->top++;
462 return 1;
463}
464
465/* -- Base library: miscellaneous functions ------------------------------- */
466
467LJLIB_PUSH(top-2) /* Upvalue holds weak table. */
468LJLIB_CF(newproxy)
469{
470 lua_settop(L, 1);
471 lua_newuserdata(L, 0);
472 if (lua_toboolean(L, 1) == 0) { /* newproxy(): without metatable. */
473 return 1;
474 } else if (lua_isboolean(L, 1)) { /* newproxy(true): with metatable. */
475 lua_newtable(L);
476 lua_pushvalue(L, -1);
477 lua_pushboolean(L, 1);
478 lua_rawset(L, lua_upvalueindex(1)); /* Remember mt in weak table. */
479 } else { /* newproxy(proxy): inherit metatable. */
480 int validproxy = 0;
481 if (lua_getmetatable(L, 1)) {
482 lua_rawget(L, lua_upvalueindex(1));
483 validproxy = lua_toboolean(L, -1);
484 lua_pop(L, 1);
485 }
486 if (!validproxy)
487 lj_err_arg(L, 1, LJ_ERR_NOPROXY);
488 lua_getmetatable(L, 1);
489 }
490 lua_setmetatable(L, 2);
491 return 1;
492}
493
494LJLIB_PUSH("tostring")
495LJLIB_CF(print)
496{
497 ptrdiff_t i, nargs = L->top - L->base;
498 cTValue *tv = lj_tab_getstr(tabref(L->env), strV(lj_lib_upvalue(L, 1)));
499 int shortcut;
500 if (tv && !tvisnil(tv)) {
501 copyTV(L, L->top++, tv);
502 } else {
503 setstrV(L, L->top++, strV(lj_lib_upvalue(L, 1)));
504 lua_gettable(L, LUA_GLOBALSINDEX);
505 tv = L->top-1;
506 }
507 shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring) &&
508 !gcrefu(basemt_it(G(L), LJ_TNUMX));
509 for (i = 0; i < nargs; i++) {
510 cTValue *o = &L->base[i];
511 const char *str;
512 size_t size;
513 MSize len;
514 if (shortcut && (str = lj_strfmt_wstrnum(L, o, &len)) != NULL) {
515 size = len;
516 } else {
517 copyTV(L, L->top+1, o);
518 copyTV(L, L->top, L->top-1);
519 L->top += 2;
520 lua_call(L, 1, 1);
521 str = lua_tolstring(L, -1, &size);
522 if (!str)
523 lj_err_caller(L, LJ_ERR_PRTOSTR);
524 L->top--;
525 }
526 if (i)
527 putchar('\t');
528 fwrite(str, 1, size, stdout);
529 }
530 putchar('\n');
531 return 0;
532}
533
534LJLIB_PUSH(top-3)
535LJLIB_SET(_VERSION)
536
537#include "lj_libdef.h"
538
539/* -- Coroutine library --------------------------------------------------- */
540
541#define LJLIB_MODULE_coroutine
542
543LJLIB_CF(coroutine_status)
544{
545 const char *s;
546 lua_State *co;
547 if (!(L->top > L->base && tvisthread(L->base)))
548 lj_err_arg(L, 1, LJ_ERR_NOCORO);
549 co = threadV(L->base);
550 if (co == L) s = "running";
551 else if (co->status == LUA_YIELD) s = "suspended";
552 else if (co->status != LUA_OK) s = "dead";
553 else if (co->base > tvref(co->stack)+1+LJ_FR2) s = "normal";
554 else if (co->top == co->base) s = "dead";
555 else s = "suspended";
556 lua_pushstring(L, s);
557 return 1;
558}
559
560LJLIB_CF(coroutine_running)
561{
562#if LJ_52
563 int ismain = lua_pushthread(L);
564 setboolV(L->top++, ismain);
565 return 2;
566#else
567 if (lua_pushthread(L))
568 setnilV(L->top++);
569 return 1;
570#endif
571}
572
573LJLIB_CF(coroutine_isyieldable)
574{
575 setboolV(L->top++, cframe_canyield(L->cframe));
576 return 1;
577}
578
579LJLIB_CF(coroutine_create)
580{
581 lua_State *L1;
582 if (!(L->base < L->top && tvisfunc(L->base)))
583 lj_err_argt(L, 1, LUA_TFUNCTION);
584 L1 = lua_newthread(L);
585 setfuncV(L, L1->top++, funcV(L->base));
586 return 1;
587}
588
589LJLIB_ASM(coroutine_yield)
590{
591 lj_err_caller(L, LJ_ERR_CYIELD);
592 return FFH_UNREACHABLE;
593}
594
595static int ffh_resume(lua_State *L, lua_State *co, int wrap)
596{
597 if (co->cframe != NULL || co->status > LUA_YIELD ||
598 (co->status == LUA_OK && co->top == co->base)) {
599 ErrMsg em = co->cframe ? LJ_ERR_CORUN : LJ_ERR_CODEAD;
600 if (wrap) lj_err_caller(L, em);
601 setboolV(L->base-1-LJ_FR2, 0);
602 setstrV(L, L->base-LJ_FR2, lj_err_str(L, em));
603 return FFH_RES(2);
604 }
605 lj_state_growstack(co, (MSize)(L->top - L->base));
606 return FFH_RETRY;
607}
608
609LJLIB_ASM(coroutine_resume)
610{
611 if (!(L->top > L->base && tvisthread(L->base)))
612 lj_err_arg(L, 1, LJ_ERR_NOCORO);
613 return ffh_resume(L, threadV(L->base), 0);
614}
615
616LJLIB_NOREG LJLIB_ASM(coroutine_wrap_aux)
617{
618 return ffh_resume(L, threadV(lj_lib_upvalue(L, 1)), 1);
619}
620
621/* Inline declarations. */
622LJ_ASMF void lj_ff_coroutine_wrap_aux(void);
623#if !(LJ_TARGET_MIPS && defined(ljamalg_c))
624LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L,
625 lua_State *co);
626#endif
627
628/* Error handler, called from assembler VM. */
629void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, lua_State *co)
630{
631 co->top--; copyTV(L, L->top, co->top); L->top++;
632 if (tvisstr(L->top-1))
633 lj_err_callermsg(L, strVdata(L->top-1));
634 else
635 lj_err_run(L);
636}
637
638/* Forward declaration. */
639static void setpc_wrap_aux(lua_State *L, GCfunc *fn);
640
641LJLIB_CF(coroutine_wrap)
642{
643 GCfunc *fn;
644 lj_cf_coroutine_create(L);
645 fn = lj_lib_pushcc(L, lj_ffh_coroutine_wrap_aux, FF_coroutine_wrap_aux, 1);
646 setpc_wrap_aux(L, fn);
647 return 1;
648}
649
650#include "lj_libdef.h"
651
652/* Fix the PC of wrap_aux. Really ugly workaround. */
653static void setpc_wrap_aux(lua_State *L, GCfunc *fn)
654{
655 setmref(fn->c.pc, &L2GG(L)->bcff[lj_lib_init_coroutine[1]+2]);
656}
657
658/* ------------------------------------------------------------------------ */
659
660static void newproxy_weaktable(lua_State *L)
661{
662 /* NOBARRIER: The table is new (marked white). */
663 GCtab *t = lj_tab_new(L, 0, 1);
664 settabV(L, L->top++, t);
665 setgcref(t->metatable, obj2gco(t));
666 setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
667 lj_str_newlit(L, "kv"));
668 t->nomm = (uint8_t)(~(1u<<MM_mode));
669}
670
671LUALIB_API int luaopen_base(lua_State *L)
672{
673 /* NOBARRIER: Table and value are the same. */
674 GCtab *env = tabref(L->env);
675 settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env);
676 lua_pushliteral(L, LUA_VERSION); /* top-3. */
677 newproxy_weaktable(L); /* top-2. */
678 LJ_LIB_REG(L, "_G", base);
679 LJ_LIB_REG(L, LUA_COLIBNAME, coroutine);
680 return 2;
681}
682
683