• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 6340880138

28 Sep 2023 03:15PM UTC coverage: 88.298% (+0.06%) from 88.241%
6340880138

push

github

fckxorg
Restore cur_L for specific Lua/C API use case.

Thanks to Peter Cawley.

(cherry-picked from commit e86990f7f)

Consider the following Lua C API function:

```
static int error_after_coroutine_return(lua_State *L)
{
	lua_State *innerL = lua_newthread(L);
	luaL_loadstring(innerL, "print('inner coro')");
	lua_pcall(innerL, 0, 0, 0);
	luaL_error(L, "my fancy error");
	return 0;
}
```

And the following Lua script:
```
local libcur_L = require('libcur_L')

local function onesnap_f(var)
  if var then
    return 1
  else
    return 0
  end
end

-- Compile function to trace with snapshot.
if jit then jit.opt.start('hotloop=1') end
onesnap_f(true)
onesnap_f(true)

local r, s = pcall(libcur_L.error_after_coroutine_return)
onesnap_f(false)
```

This is the only case when `cur_L` is not restored, according to
the analysis done in https://github.com/LuaJIT/LuaJIT/issues/1066.

This patch changes the error-catching routine, so now the patch
sets the actual cur_L there.
Now it is possible to throw errors on non-executing coroutines,
which is a violation of the Lua C API. So, even though it is now
possible, that behavior should be avoided anyway.

Maxim Kokryashkin:
* added the description for the problem

Resolves tarantool/tarantool#6323

5344 of 5972 branches covered (0.0%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 1 file covered. (100.0%)

20499 of 23296 relevant lines covered (87.99%)

2744986.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.4
/src/lib_base.c
1
/*
2
** Base and coroutine library.
3
** Copyright (C) 2005-2017 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

43
LJLIB_ASM(assert)                LJLIB_REC(.)
16✔
44
{
45
  lj_lib_checkany(L, 1);
16✔
46
  if (L->top == L->base+1)
14✔
47
    lj_err_caller(L, LJ_ERR_ASSERT);
4✔
48
  else if (tvisstr(L->base+1) || tvisnumber(L->base+1))
10✔
49
    lj_err_callermsg(L, strdata(lj_lib_checkstr(L, 2)));
8✔
50
  else
51
    lj_err_run(L);
2✔
52
  return FFH_UNREACHABLE;
53
}
54

55
/* ORDER LJ_T */
56
LJLIB_PUSH("nil")
57
LJLIB_PUSH("boolean")
58
LJLIB_PUSH(top-1)  /* boolean */
59
LJLIB_PUSH("userdata")
60
LJLIB_PUSH("string")
61
LJLIB_PUSH("upval")
62
LJLIB_PUSH("thread")
63
LJLIB_PUSH("proto")
64
LJLIB_PUSH("function")
65
LJLIB_PUSH("trace")
66
LJLIB_PUSH("cdata")
67
LJLIB_PUSH("table")
68
LJLIB_PUSH(top-9)  /* userdata */
69
LJLIB_PUSH("number")
70
LJLIB_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. */
76
LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
77

78
LJLIB_ASM(next)
1✔
79
{
80
  lj_lib_checktab(L, 1);
1✔
81
  return FFH_UNREACHABLE;
×
82
}
83

84
#if LJ_52 || LJ_HASFFI
85
static 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

105
LJLIB_PUSH(lastcl)
106
LJLIB_ASM(pairs)                LJLIB_REC(xpairs 0)
×
107
{
108
  return ffh_pairs(L, MM_pairs);
×
109
}
110

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

118
LJLIB_PUSH(lastcl)
119
LJLIB_ASM(ipairs)                LJLIB_REC(xpairs 1)
×
120
{
121
  return ffh_pairs(L, MM_ipairs);
×
122
}
123

124
/* -- Base library: getters and setters ----------------------------------- */
125

126
LJLIB_ASM_(getmetatable)        LJLIB_REC(.)
127
/* Recycle the lj_lib_checkany(L, 1) from assert. */
128

129
LJLIB_ASM(setmetatable)                LJLIB_REC(.)
813✔
130
{
131
  GCtab *t = lj_lib_checktab(L, 1);
813✔
132
  GCtab *mt = lj_lib_checktabornil(L, 2);
812✔
133
  if (!tvisnil(lj_meta_lookup(L, L->base, MM_metatable)))
810✔
134
    lj_err_caller(L, LJ_ERR_PROTMT);
4✔
135
  setgcref(t->metatable, obj2gco(mt));
806✔
136
  if (mt) { lj_gc_objbarriert(L, t, mt); }
806✔
137
  settabV(L, L->base-1-LJ_FR2, t);
806✔
138
  return FFH_RES(1);
806✔
139
}
140

141
LJLIB_CF(getfenv)                LJLIB_REC(.)
110✔
142
{
143
  GCfunc *fn;
110✔
144
  cTValue *o = L->base;
110✔
145
  if (!(o < L->top && tvisfunc(o))) {
110✔
146
    int level = lj_lib_optint(L, 1, 1);
97✔
147
    o = lj_debug_frame(L, level, &level);
97✔
148
    if (o == NULL)
97✔
149
      lj_err_arg(L, 1, LJ_ERR_INVLVL);
2✔
150
    if (LJ_FR2) o--;
95✔
151
  }
152
  fn = &gcval(o)->fn;
108✔
153
  settabV(L, L->top++, isluafunc(fn) ? tabref(fn->l.env) : tabref(L->env));
108✔
154
  return 1;
108✔
155
}
156

157
LJLIB_CF(setfenv)
43✔
158
{
159
  GCfunc *fn;
43✔
160
  GCtab *t = lj_lib_checktab(L, 2);
43✔
161
  cTValue *o = L->base;
43✔
162
  if (!(o < L->top && tvisfunc(o))) {
43✔
163
    int level = lj_lib_checkint(L, 1);
17✔
164
    if (level == 0) {
16✔
165
      /* NOBARRIER: A thread (i.e. L) is never black. */
166
      setgcref(L->env, obj2gco(t));
4✔
167
      return 0;
4✔
168
    }
169
    o = lj_debug_frame(L, level, &level);
12✔
170
    if (o == NULL)
12✔
171
      lj_err_arg(L, 1, LJ_ERR_INVLVL);
2✔
172
    if (LJ_FR2) o--;
10✔
173
  }
174
  fn = &gcval(o)->fn;
36✔
175
  if (!isluafunc(fn))
36✔
176
    lj_err_caller(L, LJ_ERR_SETFENV);
1✔
177
  setgcref(fn->l.env, obj2gco(t));
35✔
178
  lj_gc_objbarrier(L, obj2gco(fn), t);
35✔
179
  setfuncV(L, L->top++, fn);
35✔
180
  return 1;
35✔
181
}
182

183
LJLIB_ASM(rawget)                LJLIB_REC(.)
1✔
184
{
185
  lj_lib_checktab(L, 1);
1✔
186
  lj_lib_checkany(L, 2);
×
187
  return FFH_UNREACHABLE;
×
188
}
189

190
LJLIB_CF(rawset)                LJLIB_REC(.)
300✔
191
{
192
  lj_lib_checktab(L, 1);
300✔
193
  lj_lib_checkany(L, 2);
300✔
194
  L->top = 1+lj_lib_checkany(L, 3);
300✔
195
  lua_rawset(L, 1);
300✔
196
  return 1;
299✔
197
}
198

199
LJLIB_CF(rawequal)                LJLIB_REC(.)
20✔
200
{
201
  cTValue *o1 = lj_lib_checkany(L, 1);
20✔
202
  cTValue *o2 = lj_lib_checkany(L, 2);
20✔
203
  setboolV(L->top-1, lj_obj_equal(o1, o2));
20✔
204
  return 1;
20✔
205
}
206

207
#if LJ_52
208
LJLIB_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

221
LJLIB_CF(unpack)
62✔
222
{
223
  GCtab *t = lj_lib_checktab(L, 1);
62✔
224
  int32_t n, i = lj_lib_optint(L, 2, 1);
62✔
225
  int32_t e = (L->base+3-1 < L->top && !tvisnil(L->base+3-1)) ?
18✔
226
              lj_lib_checkint(L, 3) : (int32_t)lj_tab_len(t);
80✔
227
  uint32_t nu;
62✔
228
  if (i > e) return 0;
62✔
229
  nu = (uint32_t)e - (uint32_t)i;
57✔
230
  n = (int32_t)(nu+1);
57✔
231
  if (nu >= LUAI_MAXCSTACK || !lua_checkstack(L, n))
57✔
232
    lj_err_caller(L, LJ_ERR_UNPACK);
1✔
233
  do {
8,187✔
234
    cTValue *tv = lj_tab_getint(t, i);
8,187✔
235
    if (tv) {
8,187✔
236
      copyTV(L, L->top++, tv);
8,186✔
237
    } else {
238
      setnilV(L->top++);
1✔
239
    }
240
  } while (i++ < e);
8,187✔
241
  return n;
242
}
243

244
LJLIB_CF(select)                LJLIB_REC(.)
1,015✔
245
{
246
  int32_t n = (int32_t)(L->top - L->base);
1,015✔
247
  if (n >= 1 && tvisstr(L->base) && *strVdata(L->base) == '#') {
1,015✔
248
    setintV(L->top-1, n-1);
653✔
249
    return 1;
653✔
250
  } else {
251
    int32_t i = lj_lib_checkint(L, 1);
362✔
252
    if (i < 0) i = n + i; else if (i > n) i = n;
362✔
253
    if (i < 1)
362✔
254
      lj_err_arg(L, 1, LJ_ERR_IDXRNG);
3✔
255
    return n - i;
359✔
256
  }
257
}
258

259
/* -- Base library: conversions ------------------------------------------- */
260

261
LJLIB_ASM(tonumber)                LJLIB_REC(.)
101,179✔
262
{
263
  int32_t base = lj_lib_optint(L, 2, 10);
101,179✔
264
  if (base == 10) {
101,179✔
265
    TValue *o = lj_lib_checkany(L, 1);
100,848✔
266
    if (lj_strscan_numberobj(o)) {
100,846✔
267
      copyTV(L, L->base-1-LJ_FR2, o);
1,240✔
268
      return FFH_RES(1);
1,240✔
269
    }
270
#if LJ_HASFFI
271
    if (tviscdata(o)) {
99,606✔
272
      CTState *cts = ctype_cts(L);
98,852✔
273
      CType *ct = lj_ctype_rawref(cts, cdataV(o)->ctypeid);
98,852✔
274
      if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
98,852✔
275
      if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
98,852✔
276
        if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) &&
98,849✔
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),
98,849✔
284
                       (uint8_t *)&(L->base-1-LJ_FR2)->n, o, 0);
98,849✔
285
        return FFH_RES(1);
98,849✔
286
      }
287
    }
288
#endif
289
  } else {
290
    const char *p = strdata(lj_lib_checkstr(L, 1));
331✔
291
    char *ep;
331✔
292
    unsigned int neg = 0;
331✔
293
    unsigned long ul;
331✔
294
    if (base < 2 || base > 36)
331✔
295
      lj_err_arg(L, 2, LJ_ERR_BASERNG);
1✔
296
    while (lj_char_isspace((unsigned char)(*p))) p++;
352✔
297
    if (*p == '-') { p++; neg = 1; } else if (*p == '+') { p++; }
330✔
298
    if (lj_char_isalnum((unsigned char)(*p))) {
330✔
299
      ul = strtoul(p, &ep, base);
324✔
300
      if (p != ep) {
324✔
301
        while (lj_char_isspace((unsigned char)(*ep))) ep++;
341✔
302
        if (*ep == '\0') {
321✔
303
          if (LJ_DUALNUM && LJ_LIKELY(ul < 0x80000000u+neg)) {
321✔
304
            if (neg) ul = -ul;
305
            setintV(L->base-1-LJ_FR2, (int32_t)ul);
306
          } else {
307
            lua_Number n = (lua_Number)ul;
321✔
308
            if (neg) n = -n;
321✔
309
            setnumV(L->base-1-LJ_FR2, n);
321✔
310
          }
311
          return FFH_RES(1);
321✔
312
        }
313
      }
314
    }
315
  }
316
  setnilV(L->base-1-LJ_FR2);
766✔
317
  return FFH_RES(1);
766✔
318
}
319

320
LJLIB_ASM(tostring)                LJLIB_REC(.)
576✔
321
{
322
  TValue *o = lj_lib_checkany(L, 1);
576✔
323
  cTValue *mo;
574✔
324
  L->top = o+1;  /* Only keep one argument. */
574✔
325
  if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
574✔
326
    copyTV(L, L->base-1-LJ_FR2, mo);  /* Replace callable. */
190✔
327
    return FFH_TAILCALL;
190✔
328
  }
329
  lj_gc_check(L);
384✔
330
  setstrV(L, L->base-1-LJ_FR2, lj_strfmt_obj(L, L->base));
384✔
331
  return FFH_RES(1);
384✔
332
}
333

334
/* -- Base library: throw and catch errors -------------------------------- */
335

336
LJLIB_CF(error)
75✔
337
{
338
  int32_t level = lj_lib_optint(L, 2, 1);
75✔
339
  lua_settop(L, 1);
75✔
340
  if (lua_isstring(L, 1) && level > 0) {
75✔
341
    luaL_where(L, level);
22✔
342
    lua_pushvalue(L, 1);
22✔
343
    lua_concat(L, 2);
22✔
344
  }
345
  return lua_error(L);
75✔
346
}
347

348
LJLIB_ASM(pcall)                LJLIB_REC(.)
3✔
349
{
350
  lj_lib_checkany(L, 1);
3✔
351
  lj_lib_checkfunc(L, 2);  /* For xpcall only. */
2✔
352
  return FFH_UNREACHABLE;
×
353
}
354
LJLIB_ASM_(xpcall)                LJLIB_REC(.)
355

356
/* -- Base library: load Lua code ----------------------------------------- */
357

358
static int load_aux(lua_State *L, int status, int envarg)
51,494✔
359
{
360
  if (status == LUA_OK) {
51,494✔
361
    if (tvistab(L->base+envarg-1)) {
38,901✔
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;
38,901✔
368
  } else {
369
    setnilV(L->top-2);
12,593✔
370
    return 2;
12,593✔
371
  }
372
}
373

374
LJLIB_CF(loadfile)
36✔
375
{
376
  GCstr *fname = lj_lib_optstr(L, 1);
36✔
377
  GCstr *mode = lj_lib_optstr(L, 2);
36✔
378
  int status;
36✔
379
  lua_settop(L, 3);  /* Ensure env arg exists. */
36✔
380
  status = luaL_loadfilex(L, fname ? strdata(fname) : NULL,
36✔
381
                          mode ? strdata(mode) : NULL);
382
  return load_aux(L, status, 3);
36✔
383
}
384

385
static const char *reader_func(lua_State *L, void *ud, size_t *size)
566✔
386
{
387
  UNUSED(ud);
566✔
388
  luaL_checkstack(L, 2, "too many nested functions");
566✔
389
  copyTV(L, L->top++, L->base);
566✔
390
  lua_call(L, 0, 1);  /* Call user-supplied function. */
566✔
391
  L->top--;
565✔
392
  if (tvisnil(L->top)) {
565✔
393
    *size = 0;
102✔
394
    return NULL;
102✔
395
  } else if (tvisstr(L->top) || tvisnumber(L->top)) {
463✔
396
    copyTV(L, L->base+4, L->top);  /* Anchor string in reserved stack slot. */
462✔
397
    return lua_tolstring(L, 5, size);
462✔
398
  } else {
399
    lj_err_caller(L, LJ_ERR_RDRSTR);
1✔
400
    return NULL;
401
  }
402
}
403

404
LJLIB_CF(load)
51,458✔
405
{
406
  GCstr *name = lj_lib_optstr(L, 2);
51,458✔
407
  GCstr *mode = lj_lib_optstr(L, 3);
51,458✔
408
  int status;
51,458✔
409
  if (L->base < L->top && (tvisstr(L->base) || tvisnumber(L->base))) {
102,807✔
410
    GCstr *s = lj_lib_checkstr(L, 1);
51,349✔
411
    lua_settop(L, 4);  /* Ensure env arg exists. */
51,349✔
412
    status = luaL_loadbufferx(L, strdata(s), s->len, strdata(name ? name : s),
51,349✔
413
                              mode ? strdata(mode) : NULL);
414
  } else {
415
    lj_lib_checkfunc(L, 1);
109✔
416
    lua_settop(L, 5);  /* Reserve a slot for the string from the reader. */
109✔
417
    status = lua_loadx(L, reader_func, NULL, name ? strdata(name) : "=(load)",
109✔
418
                       mode ? strdata(mode) : NULL);
419
  }
420
  return load_aux(L, status, 4);
51,458✔
421
}
422

423
LJLIB_CF(loadstring)
51,111✔
424
{
425
  return lj_cf_load(L);
51,111✔
426
}
427

428
LJLIB_CF(dofile)
172✔
429
{
430
  GCstr *fname = lj_lib_optstr(L, 1);
172✔
431
  setnilV(L->top);
172✔
432
  L->top = L->base+1;
172✔
433
  if (luaL_loadfile(L, fname ? strdata(fname) : NULL) != LUA_OK)
172✔
434
    lua_error(L);
2✔
435
  lua_call(L, 0, LUA_MULTRET);
170✔
436
  return (int)(L->top - L->base) - 1;
170✔
437
}
438

439
/* -- Base library: GC control -------------------------------------------- */
440

441
LJLIB_CF(gcinfo)
15,200✔
442
{
443
  setintV(L->top++, (int32_t)(G(L)->gc.total >> 10));
15,200✔
444
  return 1;
15,200✔
445
}
446

447
LJLIB_CF(collectgarbage)
1,332✔
448
{
449
  int opt = lj_lib_checkopt(L, 1, LUA_GCCOLLECT,  /* ORDER LUA_GC* */
1,332✔
450
    "\4stop\7restart\7collect\5count\1\377\4step\10setpause\12setstepmul\1\377\11isrunning");
451
  int32_t data = lj_lib_optint(L, 2, 0);
1,330✔
452
  if (opt == LUA_GCCOUNT) {
1,330✔
453
    setnumV(L->top, (lua_Number)G(L)->gc.total/1024.0);
5✔
454
  } else {
455
    int res = lua_gc(L, opt, data);
1,325✔
456
    if (opt == LUA_GCSTEP || opt == LUA_GCISRUNNING)
1,324✔
457
      setboolV(L->top, res);
430✔
458
    else
459
      setintV(L->top, res);
894✔
460
  }
461
  L->top++;
1,329✔
462
  return 1;
1,329✔
463
}
464

465
/* -- Base library: miscellaneous functions ------------------------------- */
466

467
LJLIB_PUSH(top-2)  /* Upvalue holds weak table. */
468
LJLIB_CF(newproxy)
1,002,986✔
469
{
470
  lua_settop(L, 1);
1,002,986✔
471
  lua_newuserdata(L, 0);
1,002,986✔
472
  if (lua_toboolean(L, 1) == 0) {  /* newproxy(): without metatable. */
1,002,986✔
473
    return 1;
474
  } else if (lua_isboolean(L, 1)) {  /* newproxy(true): with metatable. */
1,000,980✔
475
    lua_newtable(L);
1,000,014✔
476
    lua_pushvalue(L, -1);
1,000,014✔
477
    lua_pushboolean(L, 1);
1,000,014✔
478
    lua_rawset(L, lua_upvalueindex(1));  /* Remember mt in weak table. */
1,000,014✔
479
  } else {  /* newproxy(proxy): inherit metatable. */
480
    int validproxy = 0;
966✔
481
    if (lua_getmetatable(L, 1)) {
966✔
482
      lua_rawget(L, lua_upvalueindex(1));
965✔
483
      validproxy = lua_toboolean(L, -1);
965✔
484
      lua_pop(L, 1);
965✔
485
    }
486
    if (!validproxy)
965✔
487
      lj_err_arg(L, 1, LJ_ERR_NOPROXY);
1✔
488
    lua_getmetatable(L, 1);
965✔
489
  }
490
  lua_setmetatable(L, 2);
1,000,979✔
491
  return 1;
1,000,979✔
492
}
493

494
LJLIB_PUSH("tostring")
495
LJLIB_CF(print)
2,248✔
496
{
497
  ptrdiff_t i, nargs = L->top - L->base;
2,248✔
498
  cTValue *tv = lj_tab_getstr(tabref(L->env), strV(lj_lib_upvalue(L, 1)));
2,248✔
499
  int shortcut;
2,248✔
500
  if (tv && !tvisnil(tv)) {
2,248✔
501
    copyTV(L, L->top++, tv);
2,247✔
502
  } else {
503
    setstrV(L, L->top++, strV(lj_lib_upvalue(L, 1)));
1✔
504
    lua_gettable(L, LUA_GLOBALSINDEX);
1✔
505
    tv = L->top-1;
1✔
506
  }
507
  shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring)
2,248✔
508
              && !gcrefu(basemt_it(G(L), LJ_TNUMX));
4,495✔
509
  for (i = 0; i < nargs; i++) {
4,498✔
510
    cTValue *o = &L->base[i];
2,252✔
511
    const char *str;
2,252✔
512
    size_t size;
2,252✔
513
    MSize len;
2,252✔
514
    if (shortcut && (str = lj_strfmt_wstrnum(L, o, &len)) != NULL) {
2,252✔
515
      size = len;
2,201✔
516
    } else {
517
      copyTV(L, L->top+1, o);
51✔
518
      copyTV(L, L->top, L->top-1);
51✔
519
      L->top += 2;
51✔
520
      lua_call(L, 1, 1);
51✔
521
      str = lua_tolstring(L, -1, &size);
51✔
522
      if (!str)
51✔
523
        lj_err_caller(L, LJ_ERR_PRTOSTR);
2✔
524
      L->top--;
49✔
525
    }
526
    if (i)
2,250✔
527
      putchar('\t');
5✔
528
    fwrite(str, 1, size, stdout);
2,250✔
529
  }
530
  putchar('\n');
2,246✔
531
  return 0;
2,246✔
532
}
533

534
LJLIB_PUSH(top-3)
535
LJLIB_SET(_VERSION)
536

537
#include "lj_libdef.h"
538

539
/* -- Coroutine library --------------------------------------------------- */
540

541
#define LJLIB_MODULE_coroutine
542

543
LJLIB_CF(coroutine_status)
15✔
544
{
545
  const char *s;
15✔
546
  lua_State *co;
15✔
547
  if (!(L->top > L->base && tvisthread(L->base)))
15✔
548
    lj_err_arg(L, 1, LJ_ERR_NOCORO);
1✔
549
  co = threadV(L->base);
14✔
550
  if (co == L) s = "running";
14✔
551
  else if (co->status == LUA_YIELD) s = "suspended";
13✔
552
  else if (co->status != LUA_OK) s = "dead";
8✔
553
  else if (co->base > tvref(co->stack)+1+LJ_FR2) s = "normal";
5✔
554
  else if (co->top == co->base) s = "dead";
5✔
555
  else s = "suspended";
2✔
556
  lua_pushstring(L, s);
14✔
557
  return 1;
14✔
558
}
559

560
LJLIB_CF(coroutine_running)
4✔
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))
4✔
568
    setnilV(L->top++);
2✔
569
  return 1;
4✔
570
#endif
571
}
572

573
LJLIB_CF(coroutine_isyieldable)
1✔
574
{
575
  setboolV(L->top++, cframe_canyield(L->cframe));
1✔
576
  return 1;
1✔
577
}
578

579
LJLIB_CF(coroutine_create)
1,095✔
580
{
581
  lua_State *L1;
1,095✔
582
  if (!(L->base < L->top && tvisfunc(L->base)))
1,095✔
583
    lj_err_argt(L, 1, LUA_TFUNCTION);
2✔
584
  L1 = lua_newthread(L);
1,093✔
585
  setfuncV(L, L1->top++, funcV(L->base));
1,093✔
586
  return 1;
1,093✔
587
}
588

589
LJLIB_ASM(coroutine_yield)
1✔
590
{
591
  lj_err_caller(L, LJ_ERR_CYIELD);
1✔
592
  return FFH_UNREACHABLE;
593
}
594

595
static int ffh_resume(lua_State *L, lua_State *co, int wrap)
14✔
596
{
597
  if (co->cframe != NULL || co->status > LUA_YIELD ||
14✔
598
      (co->status == LUA_OK && co->top == co->base)) {
10✔
599
    ErrMsg em = co->cframe ? LJ_ERR_CORUN : LJ_ERR_CODEAD;
14✔
600
    if (wrap) lj_err_caller(L, em);
14✔
601
    setboolV(L->base-1-LJ_FR2, 0);
14✔
602
    setstrV(L, L->base-LJ_FR2, lj_err_str(L, em));
14✔
603
    return FFH_RES(2);
14✔
604
  }
605
  lj_state_growstack(co, (MSize)(L->top - L->base));
×
606
  return FFH_RETRY;
×
607
}
608

609
LJLIB_ASM(coroutine_resume)
15✔
610
{
611
  if (!(L->top > L->base && tvisthread(L->base)))
15✔
612
    lj_err_arg(L, 1, LJ_ERR_NOCORO);
1✔
613
  return ffh_resume(L, threadV(L->base), 0);
14✔
614
}
615

616
LJLIB_NOREG LJLIB_ASM(coroutine_wrap_aux)
×
617
{
618
  return ffh_resume(L, threadV(lj_lib_upvalue(L, 1)), 1);
×
619
}
620

621
/* Inline declarations. */
622
LJ_ASMF void lj_ff_coroutine_wrap_aux(void);
623
#if !(LJ_TARGET_MIPS && defined(ljamalg_c))
624
LJ_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. */
629
void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, lua_State *co)
2✔
630
{
631
  co->top--; copyTV(L, L->top, co->top); L->top++;
2✔
632
  if (tvisstr(L->top-1))
2✔
633
    lj_err_callermsg(L, strVdata(L->top-1));
1✔
634
  else
635
    lj_err_run(L);
1✔
636
}
637

638
/* Forward declaration. */
639
static void setpc_wrap_aux(lua_State *L, GCfunc *fn);
640

641
LJLIB_CF(coroutine_wrap)
52✔
642
{
643
  GCfunc *fn;
52✔
644
  lj_cf_coroutine_create(L);
52✔
645
  fn = lj_lib_pushcc(L, lj_ffh_coroutine_wrap_aux, FF_coroutine_wrap_aux, 1);
51✔
646
  setpc_wrap_aux(L, fn);
51✔
647
  return 1;
51✔
648
}
649

650
#include "lj_libdef.h"
651

652
/* Fix the PC of wrap_aux. Really ugly workaround. */
653
static void setpc_wrap_aux(lua_State *L, GCfunc *fn)
51✔
654
{
655
  setmref(fn->c.pc, &L2GG(L)->bcff[lj_lib_init_coroutine[1]+2]);
51✔
656
}
657

658
/* ------------------------------------------------------------------------ */
659

660
static void newproxy_weaktable(lua_State *L)
236✔
661
{
662
  /* NOBARRIER: The table is new (marked white). */
663
  GCtab *t = lj_tab_new(L, 0, 1);
236✔
664
  settabV(L, L->top++, t);
236✔
665
  setgcref(t->metatable, obj2gco(t));
236✔
666
  setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
236✔
667
            lj_str_newlit(L, "kv"));
668
  t->nomm = (uint8_t)(~(1u<<MM_mode));
236✔
669
}
236✔
670

671
LUALIB_API int luaopen_base(lua_State *L)
236✔
672
{
673
  /* NOBARRIER: Table and value are the same. */
674
  GCtab *env = tabref(L->env);
236✔
675
  settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env);
236✔
676
  lua_pushliteral(L, LUA_VERSION);  /* top-3. */
236✔
677
  newproxy_weaktable(L);  /* top-2. */
236✔
678
  LJ_LIB_REG(L, "_G", base);
236✔
679
  LJ_LIB_REG(L, LUA_COLIBNAME, coroutine);
236✔
680
  return 2;
236✔
681
}
682

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc