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

tarantool / luajit / 20506963995

25 Dec 2025 03:04PM UTC coverage: 93.051% (+0.004%) from 93.047%
20506963995

push

github

Buristan
ci: introduce the performance workflow

This patch adds the workflow to run benchmarks from various suites,
aggregate their results, and send statistics to the InfluxDB to be
processed later.

The workflow contains a matrix to measure GC64 and non-GC64 modes with
enabled/disabled JIT for x64 architecture.

5712 of 6046 branches covered (94.48%)

Branch coverage included in aggregate %.

21793 of 23513 relevant lines covered (92.68%)

3873160.74 hits per line

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

90.33
/src/lj_debug.c
1
/*
2
** Debugging and introspection.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
*/
5

6
#define lj_debug_c
7
#define LUA_CORE
8

9
#include "lj_obj.h"
10
#include "lj_err.h"
11
#include "lj_debug.h"
12
#include "lj_buf.h"
13
#include "lj_tab.h"
14
#include "lj_state.h"
15
#include "lj_frame.h"
16
#include "lj_bc.h"
17
#include "lj_strfmt.h"
18
#if LJ_HASJIT
19
#include "lj_jit.h"
20
#endif
21

22
/* -- Frames -------------------------------------------------------------- */
23

24
/* Get frame corresponding to a level. */
25
cTValue *lj_debug_frame(lua_State *L, int level, int *size)
71,696✔
26
{
27
  cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2;
71,696✔
28
  /* Traverse frames backwards. */
29
  for (nextframe = frame = L->base-1; frame > bot; ) {
1,601,682✔
30
    if (frame_gc(frame) == obj2gco(L))
1,601,637✔
31
      level++;  /* Skip dummy frames. See lj_err_optype_call(). */
25✔
32
    if (level-- == 0) {
1,601,637✔
33
      *size = (int)(nextframe - frame);
71,651✔
34
      return frame;  /* Level found. */
71,651✔
35
    }
36
    nextframe = frame;
1,529,986✔
37
    if (frame_islua(frame)) {
1,529,986✔
38
      frame = frame_prevl(frame);
1,520,680✔
39
    } else {
40
      if (frame_isvarg(frame))
9,306✔
41
        level++;  /* Skip vararg pseudo-frame. */
8,773✔
42
      frame = frame_prevd(frame);
9,306✔
43
    }
44
  }
45
  *size = level;
45✔
46
  return NULL;  /* Level not found. */
45✔
47
}
48

49
/* Invalid bytecode position. */
50
#define NO_BCPOS        (~(BCPos)0)
51

52
/* Return bytecode position for function/frame or NO_BCPOS. */
53
static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
54
{
55
  const BCIns *ins;
56
  GCproto *pt;
57
  BCPos pos;
58
  lj_assertL(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD,
59
             "function or frame expected");
60
  if (!isluafunc(fn)) {  /* Cannot derive a PC for non-Lua functions. */
61
    return NO_BCPOS;
62
  } else if (nextframe == NULL) {  /* Lua function on top. */
63
    void *cf = cframe_raw(L->cframe);
64
    if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
65
      return NO_BCPOS;
66
    ins = cframe_pc(cf);  /* Only happens during error/hook handling. */
67
    if (!ins) return NO_BCPOS;
68
  } else {
69
    if (frame_islua(nextframe)) {
70
      ins = frame_pc(nextframe);
71
    } else if (frame_iscont(nextframe)) {
72
      ins = frame_contpc(nextframe);
73
    } else {
74
      /* Lua function below errfunc/gc/hook: find cframe to get the PC. */
75
      void *cf = cframe_raw(L->cframe);
76
      TValue *f = L->base-1;
77
      for (;;) {
78
        if (cf == NULL)
79
          return NO_BCPOS;
80
        while (cframe_nres(cf) < 0) {
81
          if (f >= restorestack(L, -cframe_nres(cf)))
82
            break;
83
          cf = cframe_raw(cframe_prev(cf));
84
          if (cf == NULL)
85
            return NO_BCPOS;
86
        }
87
        if (f < nextframe)
88
          break;
89
        if (frame_islua(f)) {
90
          f = frame_prevl(f);
91
        } else {
92
          if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f)))
93
            cf = cframe_raw(cframe_prev(cf));
94
          f = frame_prevd(f);
95
        }
96
      }
97
      ins = cframe_pc(cf);
98
      if (!ins) return NO_BCPOS;
99
    }
100
  }
101
  pt = funcproto(fn);
102
  pos = proto_bcpos(pt, ins) - 1;
103
#if LJ_HASJIT
104
  if (pos == NO_BCPOS) return 1;  /* Pretend it's the first bytecode. */
105
  if (pos > pt->sizebc) {  /* Undo the effects of lj_trace_exit for JLOOP. */
106
    if (bc_isret(bc_op(ins[-1]))) {
107
      GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
108
      pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
109
    } else {
110
      pos = NO_BCPOS;  /* Punt in case of stack overflow for stitched trace. */
111
    }
112
  }
113
#endif
114
  return pos;
115
}
116

117
/* -- Line numbers -------------------------------------------------------- */
118

119
/* Get line number for a bytecode position. */
120
BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
32,322,253✔
121
{
122
  const void *lineinfo = proto_lineinfo(pt);
32,322,253✔
123
  if (pc <= pt->sizebc && lineinfo) {
32,322,253✔
124
    BCLine first = pt->firstline;
32,320,027✔
125
    if (pc == pt->sizebc) return first + pt->numline;
32,320,027✔
126
    if (pc-- == 0) return first;
32,320,025✔
127
    if (pt->numline < 256)
32,319,969✔
128
      return first + (BCLine)((const uint8_t *)lineinfo)[pc];
30,122,415✔
129
    else if (pt->numline < 65536)
2,197,554✔
130
      return first + (BCLine)((const uint16_t *)lineinfo)[pc];
1,287,343✔
131
    else
132
      return first + (BCLine)((const uint32_t *)lineinfo)[pc];
910,211✔
133
  }
134
  return 0;
135
}
136

137
/* Get line number for function/frame. */
138
BCLine lj_debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
2,438✔
139
{
140
  BCPos pc = debug_framepc(L, fn, nextframe);
2,438✔
141
  if (pc != NO_BCPOS) {
2,438✔
142
    GCproto *pt = funcproto(fn);
2,384✔
143
    lj_assertL(pc <= pt->sizebc, "PC out of range");
2,384✔
144
    return lj_debug_line(pt, pc);
2,384✔
145
  }
146
  return -1;
147
}
148

149
/* -- Variable names ------------------------------------------------------ */
150

151
/* Get name of a local variable from slot number and PC. */
152
static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
153
{
154
  const char *p = (const char *)proto_varinfo(pt);
155
  if (p) {
156
    BCPos lastpc = 0;
157
    for (;;) {
158
      const char *name = p;
159
      uint32_t vn = *(const uint8_t *)p;
160
      BCPos startpc, endpc;
161
      if (vn < VARNAME__MAX) {
162
        if (vn == VARNAME_END) break;  /* End of varinfo. */
163
      } else {
164
        do { p++; } while (*(const uint8_t *)p);  /* Skip over variable name. */
165
      }
166
      p++;
167
      lastpc = startpc = lastpc + lj_buf_ruleb128(&p);
168
      if (startpc > pc) break;
169
      endpc = startpc + lj_buf_ruleb128(&p);
170
      if (pc < endpc && slot-- == 0) {
171
        if (vn < VARNAME__MAX) {
172
#define VARNAMESTR(name, str)        str "\0"
173
          name = VARNAMEDEF(VARNAMESTR);
174
#undef VARNAMESTR
175
          if (--vn) while (*name++ || --vn) ;
176
        }
177
        return name;
178
      }
179
    }
180
  }
181
  return NULL;
182
}
183

184
/* Get name of local variable from 1-based slot number and function/frame. */
185
static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
186
                               const char **name, BCReg slot1)
187
{
188
  uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
189
  uint32_t size = (uint32_t)ar->i_ci >> 16;
190
  TValue *frame = tvref(L->stack) + offset;
191
  TValue *nextframe = size ? frame + size : NULL;
192
  GCfunc *fn = frame_func(frame);
193
  BCPos pc = debug_framepc(L, fn, nextframe);
194
  if (!nextframe) nextframe = L->top+LJ_FR2;
195
  if ((int)slot1 < 0) {  /* Negative slot number is for varargs. */
196
    if (pc != NO_BCPOS) {
197
      GCproto *pt = funcproto(fn);
198
      if ((pt->flags & PROTO_VARARG)) {
199
        slot1 = pt->numparams + (BCReg)(-(int)slot1);
200
        if (frame_isvarg(frame)) {  /* Vararg frame has been set up? (pc!=0) */
201
          nextframe = frame;
202
          frame = frame_prevd(frame);
203
        }
204
        if (frame + slot1+LJ_FR2 < nextframe) {
205
          *name = "(*vararg)";
206
          return frame+slot1;
207
        }
208
      }
209
    }
210
    return NULL;
211
  }
212
  if (pc != NO_BCPOS &&
213
      (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
214
    ;
215
  else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe)
216
    *name = "(*temporary)";
217
  return frame+slot1;
218
}
219

220
/* Get name of upvalue. */
221
const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
231✔
222
{
223
  const uint8_t *p = proto_uvinfo(pt);
231✔
224
  lj_assertX(idx < pt->sizeuv, "bad upvalue index");
231✔
225
  if (!p) return "";
78✔
226
  if (idx) while (*p++ || --idx) ;
946✔
227
  return (const char *)p;
228
}
229

230
/* Get name and value of upvalue. */
231
const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp, GCobj **op)
21✔
232
{
233
  if (tvisfunc(o)) {
21✔
234
    GCfunc *fn = funcV(o);
21✔
235
    if (isluafunc(fn)) {
21✔
236
      GCproto *pt = funcproto(fn);
19✔
237
      if (idx < pt->sizeuv) {
19✔
238
        GCobj *uvo = gcref(fn->l.uvptr[idx]);
12✔
239
        *tvp = uvval(&uvo->uv);
12✔
240
        *op = uvo;
12✔
241
        return lj_debug_uvname(pt, idx);
24✔
242
      }
243
    } else {
244
      if (idx < fn->c.nupvalues) {
2✔
245
        *tvp = &fn->c.upvalue[idx];
×
246
        *op = obj2gco(fn);
×
247
        return "";
×
248
      }
249
    }
250
  }
251
  return NULL;
252
}
253

254
/* Deduce name of an object from slot number and PC. */
255
const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
72,779✔
256
                              const char **name)
257
{
258
  const char *lname;
72,822✔
259
restart:
72,822✔
260
  lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
72,822✔
261
  if (lname != NULL) { *name = lname; return "local"; }
72,822✔
262
  while (--ip > proto_bc(pt)) {
73,382✔
263
    BCIns ins = *ip;
73,378✔
264
    BCOp op = bc_op(ins);
73,378✔
265
    BCReg ra = bc_a(ins);
73,378✔
266
    if (bcmode_a(op) == BCMbase) {
73,378✔
267
      if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
41✔
268
        return NULL;
269
    } else if (bcmode_a(op) == BCMdst && ra == slot) {
73,337✔
270
      switch (bc_op(ins)) {
72,750✔
271
      case BC_MOV:
272
        if (ra == slot) { slot = bc_d(ins); goto restart; }
43✔
273
        break;
274
      case BC_GGET:
71,465✔
275
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
71,465✔
276
        return "global";
71,465✔
277
      case BC_TGETS:
39✔
278
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
39✔
279
        if (ip > proto_bc(pt)) {
39✔
280
          BCIns insp = ip[-1];
39✔
281
          if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 &&
39✔
282
              bc_d(insp) == bc_b(ins))
5✔
283
            return "method";
284
        }
285
        return "field";
34✔
286
      case BC_UGET:
141✔
287
        *name = lj_debug_uvname(pt, bc_d(ins));
141✔
288
        return "upvalue";
141✔
289
      default:
290
        return NULL;
291
      }
292
    }
587✔
293
  }
294
  return NULL;
295
}
296

297
/* Deduce function name from caller of a frame. */
298
const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name)
71,465✔
299
{
300
  cTValue *pframe;
71,465✔
301
  GCfunc *fn;
71,465✔
302
  BCPos pc;
71,465✔
303
  if (frame <= tvref(L->stack)+LJ_FR2)
71,465✔
304
    return NULL;
305
  if (frame_isvarg(frame))
71,465✔
306
    frame = frame_prevd(frame);
65✔
307
  pframe = frame_prev(frame);
71,465✔
308
  fn = frame_func(pframe);
71,465✔
309
  pc = debug_framepc(L, fn, frame);
71,465✔
310
  if (pc != NO_BCPOS) {
71,465✔
311
    GCproto *pt = funcproto(fn);
71,328✔
312
    const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
71,328✔
313
    MMS mm = bcmode_mm(bc_op(*ip));
71,328✔
314
    if (mm == MM_call) {
71,328✔
315
      BCReg slot = bc_a(*ip);
71,287✔
316
      if (bc_op(*ip) == BC_ITERC) slot -= 3;
71,287✔
317
      return lj_debug_slotname(pt, ip, slot, name);
71,287✔
318
    } else if (mm != MM__MAX) {
41✔
319
      *name = strdata(mmname_str(G(L), mm));
40✔
320
      return "metamethod";
40✔
321
    }
322
  }
323
  return NULL;
324
}
325

326
/* -- Source code locations ----------------------------------------------- */
327

328
/* Generate shortened source name. */
329
void lj_debug_shortname(char *out, GCstr *str, BCLine line)
14,846✔
330
{
331
  const char *src = strdata(str);
14,846✔
332
  if (*src == '=') {
14,846✔
333
    strncpy(out, src+1, LUA_IDSIZE);  /* Remove first char. */
424✔
334
    out[LUA_IDSIZE-1] = '\0';  /* Ensures null termination. */
424✔
335
  } else if (*src == '@') {  /* Output "source", or "...source". */
14,422✔
336
    size_t len = str->len-1;
737✔
337
    src++;  /* Skip the `@' */
737✔
338
    if (len >= LUA_IDSIZE) {
737✔
339
      src += len-(LUA_IDSIZE-4);  /* Get last part of file name. */
733✔
340
      *out++ = '.'; *out++ = '.'; *out++ = '.';
733✔
341
    }
342
    strcpy(out, src);
737✔
343
  } else {  /* Output [string "string"] or [builtin:name]. */
344
    size_t len;  /* Length, up to first control char. */
345
    for (len = 0; len < LUA_IDSIZE-12; len++)
176,866✔
346
      if (((const unsigned char *)src)[len] < ' ') break;
176,848✔
347
    strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
13,685✔
348
    if (src[len] != '\0') {  /* Must truncate? */
13,685✔
349
      if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
9,485✔
350
      strncpy(out, src, len); out += len;
9,485✔
351
      strcpy(out, "..."); out += 3;
9,485✔
352
    } else {
353
      strcpy(out, src); out += len;
4,200✔
354
    }
355
    strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
27,370✔
356
  }
357
}
14,846✔
358

359
/* Add current location of a frame to error message. */
360
void lj_debug_addloc(lua_State *L, const char *msg,
33,601✔
361
                     cTValue *frame, cTValue *nextframe)
362
{
363
  if (frame) {
33,601✔
364
    GCfunc *fn = frame_func(frame);
33,374✔
365
    if (isluafunc(fn)) {
33,374✔
366
      BCLine line = lj_debug_frameline(L, fn, nextframe);
1,846✔
367
      if (line >= 0) {
1,846✔
368
        GCproto *pt = funcproto(fn);
1,843✔
369
        char buf[LUA_IDSIZE];
1,843✔
370
        lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
1,843✔
371
        lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg);
1,843✔
372
        return;
1,843✔
373
      }
374
    }
375
  }
376
  lj_strfmt_pushf(L, "%s", msg);
31,758✔
377
}
378

379
/* Push location string for a bytecode position to Lua stack. */
380
void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
49✔
381
{
382
  GCstr *name = proto_chunkname(pt);
49✔
383
  const char *s = strdata(name);
49✔
384
  MSize i, len = name->len;
49✔
385
  BCLine line = lj_debug_line(pt, pc);
49✔
386
  if (pt->firstline == ~(BCLine)0) {
49✔
387
    lj_strfmt_pushf(L, "builtin:%s", s);
1✔
388
  } else if (*s == '@') {
48✔
389
    s++; len--;
44✔
390
    for (i = len; i > 0; i--)
1,256✔
391
      if (s[i] == '/' || s[i] == '\\') {
1,254✔
392
        s += i+1;
42✔
393
        break;
42✔
394
      }
395
    lj_strfmt_pushf(L, "%s:%d", s, line);
44✔
396
  } else if (len > 40) {
4✔
397
    lj_strfmt_pushf(L, "%p:%d", pt, line);
4✔
398
  } else if (*s == '=') {
×
399
    lj_strfmt_pushf(L, "%s:%d", s+1, line);
×
400
  } else {
401
    lj_strfmt_pushf(L, "\"%s\":%d", s, line);
×
402
  }
403
}
49✔
404

405
/* -- Public debug API ---------------------------------------------------- */
406

407
/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
408

409
LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
20✔
410
{
411
  const char *name = NULL;
20✔
412
  if (ar) {
20✔
413
    TValue *o = debug_localname(L, ar, &name, (BCReg)n);
20✔
414
    if (name) {
20✔
415
      copyTV(L, L->top, o);
16✔
416
      incr_top(L);
16✔
417
    }
418
  } else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) {
×
419
    name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1);
×
420
  }
421
  return name;
20✔
422
}
423

424
LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
7✔
425
{
426
  const char *name = NULL;
7✔
427
  TValue *o = debug_localname(L, ar, &name, (BCReg)n);
7✔
428
  if (name)
7✔
429
    copyTV(L, o, L->top-1);
6✔
430
  L->top--;
7✔
431
  return name;
7✔
432
}
433

434
int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
71,449✔
435
{
436
  int opt_f = 0, opt_L = 0;
71,449✔
437
  TValue *frame = NULL;
71,449✔
438
  TValue *nextframe = NULL;
71,449✔
439
  GCfunc *fn;
71,449✔
440
  if (*what == '>') {
71,449✔
441
    TValue *func = L->top - 1;
25✔
442
    if (!tvisfunc(func)) return 0;
25✔
443
    fn = funcV(func);
24✔
444
    L->top--;
24✔
445
    what++;
24✔
446
  } else {
447
    uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
71,424✔
448
    uint32_t size = (uint32_t)ar->i_ci >> 16;
71,424✔
449
    lj_assertL(offset != 0, "bad frame offset");
71,424✔
450
    frame = tvref(L->stack) + offset;
71,424✔
451
    if (size) nextframe = frame + size;
71,424✔
452
    lj_assertL(frame <= tvref(L->maxstack) &&
71,424✔
453
               (!nextframe || nextframe <= tvref(L->maxstack)),
454
               "broken frame chain");
455
    fn = frame_func(frame);
71,424✔
456
    lj_assertL(fn->c.gct == ~LJ_TFUNC, "bad frame function");
457
  }
458
  for (; *what; what++) {
143,993✔
459
    if (*what == 'S') {
72,546✔
460
      if (isluafunc(fn)) {
336✔
461
        GCproto *pt = funcproto(fn);
289✔
462
        BCLine firstline = pt->firstline;
289✔
463
        GCstr *name = proto_chunkname(pt);
289✔
464
        ar->source = strdata(name);
289✔
465
        lj_debug_shortname(ar->short_src, name, pt->firstline);
289✔
466
        ar->linedefined = (int)firstline;
289✔
467
        ar->lastlinedefined = (int)(firstline + pt->numline);
289✔
468
        ar->what = (firstline || !pt->numline) ? "Lua" : "main";
322✔
469
      } else {
470
        ar->source = "=[C]";
47✔
471
        ar->short_src[0] = '[';
47✔
472
        ar->short_src[1] = 'C';
47✔
473
        ar->short_src[2] = ']';
47✔
474
        ar->short_src[3] = '\0';
47✔
475
        ar->linedefined = -1;
47✔
476
        ar->lastlinedefined = -1;
47✔
477
        ar->what = "C";
47✔
478
      }
479
    } else if (*what == 'l') {
72,210✔
480
      ar->currentline = frame ? lj_debug_frameline(L, fn, nextframe) : -1;
339✔
481
    } else if (*what == 'u') {
71,871✔
482
      ar->nups = fn->c.nupvalues;
112✔
483
      if (ext) {
112✔
484
        if (isluafunc(fn)) {
112✔
485
          GCproto *pt = funcproto(fn);
111✔
486
          ar->nparams = pt->numparams;
111✔
487
          ar->isvararg = !!(pt->flags & PROTO_VARARG);
111✔
488
        } else {
489
          ar->nparams = 0;
1✔
490
          ar->isvararg = 1;
1✔
491
        }
492
      }
493
    } else if (*what == 'n') {
71,759✔
494
      ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
71,369✔
495
      if (ar->namewhat == NULL) {
71,369✔
496
        ar->namewhat = "";
105✔
497
        ar->name = NULL;
105✔
498
      }
499
    } else if (*what == 'f') {
390✔
500
      opt_f = 1;
501
    } else if (*what == 'L') {
4✔
502
      opt_L = 1;
503
    } else {
504
      return 0;  /* Bad option. */
505
    }
506
  }
507
  if (opt_f) {
71,447✔
508
    setfuncV(L, L->top, fn);
386✔
509
    incr_top(L);
386✔
510
  }
511
  if (opt_L) {
71,447✔
512
    if (isluafunc(fn)) {
3✔
513
      GCtab *t = lj_tab_new(L, 0, 0);
3✔
514
      GCproto *pt = funcproto(fn);
3✔
515
      const void *lineinfo = proto_lineinfo(pt);
3✔
516
      if (lineinfo) {
3✔
517
        BCLine first = pt->firstline;
3✔
518
        int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
3✔
519
        MSize i, szl = pt->sizebc-1;
3✔
520
        for (i = 0; i < szl; i++) {
87✔
521
          BCLine line = first +
168✔
522
            (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
84✔
523
             sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
×
524
             (BCLine)((const uint32_t *)lineinfo)[i]);
×
525
          setboolV(lj_tab_setint(L, t, line), 1);
84✔
526
        }
527
      }
528
      settabV(L, L->top, t);
3✔
529
    } else {
530
      setnilV(L->top);
×
531
    }
532
    incr_top(L);
3✔
533
  }
534
  return 1;  /* Ok. */
535
}
536

537
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
227✔
538
{
539
  return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
12✔
540
}
541

542
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
71,507✔
543
{
544
  int size;
71,507✔
545
  cTValue *frame = lj_debug_frame(L, level, &size);
71,507✔
546
  if (frame) {
71,507✔
547
    ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
71,464✔
548
    return 1;
71,464✔
549
  } else {
550
    ar->i_ci = level - size;
43✔
551
    return 0;
43✔
552
  }
553
}
554

555
#if LJ_HASPROFILE
556
/* Put the chunkname into a buffer. */
557
static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip)
558
{
559
  GCstr *name = proto_chunkname(pt);
560
  const char *p = strdata(name);
561
  if (pt->firstline == ~(BCLine)0) {
562
    lj_buf_putmem(sb, "[builtin:", 9);
563
    lj_buf_putstr(sb, name);
564
    lj_buf_putb(sb, ']');
565
    return 0;
566
  }
567
  if (*p == '=' || *p == '@') {
568
    MSize len = name->len-1;
569
    p++;
570
    if (pathstrip) {
571
      int i;
572
      for (i = len-1; i >= 0; i--)
573
        if (p[i] == '/' || p[i] == '\\') {
574
          len -= i+1;
575
          p = p+i+1;
576
          break;
577
        }
578
    }
579
    lj_buf_putmem(sb, p, len);
580
  } else {
581
    lj_buf_putmem(sb, "[string]", 8);
582
  }
583
  return 1;
584
}
585

586
/* Put a compact stack dump into a buffer. */
587
void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth)
1✔
588
{
589
  int level = 0, dir = 1, pathstrip = 1;
1✔
590
  MSize lastlen = 0;
1✔
591
  if (depth < 0) { level = ~depth; depth = dir = -1; }  /* Reverse frames. */
1✔
592
  while (level != depth) {  /* Loop through all frame. */
2✔
593
    int size;
1✔
594
    cTValue *frame = lj_debug_frame(L, level, &size);
1✔
595
    if (frame) {
1✔
596
      cTValue *nextframe = size ? frame+size : NULL;
1✔
597
      GCfunc *fn = frame_func(frame);
1✔
598
      const uint8_t *p = (const uint8_t *)fmt;
1✔
599
      int c;
1✔
600
      while ((c = *p++)) {
1✔
601
        switch (c) {
5✔
602
        case 'p':  /* Preserve full path. */
603
          pathstrip = 0;
604
          break;
605
        case 'F': case 'f': {  /* Dump function name. */
1✔
606
          const char *name;
1✔
607
          const char *what = lj_debug_funcname(L, frame, &name);
1✔
608
          if (what) {
1✔
609
            if (c == 'F' && isluafunc(fn)) {  /* Dump module:name for 'F'. */
1✔
610
              GCproto *pt = funcproto(fn);
×
611
              if (pt->firstline != ~(BCLine)0) {  /* Not a bytecode builtin. */
×
612
                debug_putchunkname(sb, pt, pathstrip);
×
613
                lj_buf_putb(sb, ':');
×
614
              }
615
            }
616
            lj_buf_putmem(sb, name, (MSize)strlen(name));
1✔
617
            break;
1✔
618
          }  /* else: can't derive a name, dump module:line. */
619
          }
620
          /* fallthrough */
621
        case 'l':  /* Dump module:line. */
622
          if (isluafunc(fn)) {
×
623
            GCproto *pt = funcproto(fn);
×
624
            if (debug_putchunkname(sb, pt, pathstrip)) {
×
625
              /* Regular Lua function. */
626
              BCLine line = c == 'l' ? lj_debug_frameline(L, fn, nextframe) :
×
627
                                       pt->firstline;
628
              lj_buf_putb(sb, ':');
×
629
              lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline);
×
630
            }
631
          } else if (isffunc(fn)) {  /* Dump numbered builtins. */
×
632
            lj_buf_putmem(sb, "[builtin#", 9);
×
633
            lj_strfmt_putint(sb, fn->c.ffid);
×
634
            lj_buf_putb(sb, ']');
×
635
          } else {  /* Dump C function address. */
636
            lj_buf_putb(sb, '@');
×
637
            lj_strfmt_putptr(sb, fn->c.f);
×
638
          }
639
          break;
640
        case 'Z':  /* Zap trailing separator. */
1✔
641
          lastlen = sbuflen(sb);
1✔
642
          break;
1✔
643
        default:
644
          lj_buf_putb(sb, c);
9✔
645
          break;
646
        }
647
      }
648
    } else if (dir == 1) {
×
649
      break;
650
    } else {
651
      level -= size;  /* Reverse frame order: quickly skip missing level. */
×
652
    }
653
    level += dir;
1✔
654
  }
655
  if (lastlen)
1✔
656
    setsbufP(sb, sbufB(sb) + lastlen);  /* Zap trailing separator. */
1✔
657
}
1✔
658
#endif
659

660
/* Number of frames for the leading and trailing part of a traceback. */
661
#define TRACEBACK_LEVELS1        12
662
#define TRACEBACK_LEVELS2        10
663

664
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
29✔
665
                                int level)
666
{
667
  int top = (int)(L->top - L->base);
29✔
668
  int lim = TRACEBACK_LEVELS1;
29✔
669
  lua_Debug ar;
29✔
670
  if (msg) lua_pushfstring(L, "%s\n", msg);
29✔
671
  lua_pushliteral(L, "stack traceback:");
29✔
672
  while (lua_getstack(L1, level++, &ar)) {
250✔
673
    GCfunc *fn;
221✔
674
    if (level > lim) {
221✔
675
      if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
6✔
676
        level--;
677
      } else {
678
        lua_pushliteral(L, "\n\t...");
6✔
679
        lua_getstack(L1, -10, &ar);
6✔
680
        level = ar.i_ci - TRACEBACK_LEVELS2;
6✔
681
      }
682
      lim = 2147483647;
6✔
683
      continue;
6✔
684
    }
685
    lua_getinfo(L1, "Snlf", &ar);
215✔
686
    fn = funcV(L1->top-1); L1->top--;
215✔
687
    if (isffunc(fn) && !*ar.namewhat)
215✔
688
      lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
×
689
    else
690
      lua_pushfstring(L, "\n\t%s:", ar.short_src);
215✔
691
    if (ar.currentline > 0)
215✔
692
      lua_pushfstring(L, "%d:", ar.currentline);
168✔
693
    if (*ar.namewhat) {
215✔
694
      lua_pushfstring(L, " in function " LUA_QS, ar.name);
151✔
695
    } else {
696
      if (*ar.what == 'm') {
64✔
697
        lua_pushliteral(L, " in main chunk");
17✔
698
      } else if (*ar.what == 'C') {
47✔
699
        lua_pushfstring(L, " at %p", fn->c.f);
17✔
700
      } else {
701
        lua_pushfstring(L, " in function <%s:%d>",
30✔
702
                        ar.short_src, ar.linedefined);
703
      }
704
    }
705
    if ((int)(L->top - L->base) - top >= 15)
215✔
706
      lua_concat(L, (int)(L->top - L->base) - top);
32✔
707
  }
708
  lua_concat(L, (int)(L->top - L->base) - top);
29✔
709
}
29✔
710

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

© 2026 Coveralls, Inc