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

tarantool / luajit / 13951448164

19 Mar 2025 04:14PM UTC coverage: 92.997% (+0.04%) from 92.956%
13951448164

push

github

Buristan
Fix bit op coercion for shifts in DUALNUM builds.

Reported by Junlong Li.

(cherry picked from commit 69bbf3c1b)

This is a follow-up to the commit
8cd79d198 ("Fix bit op coercion in
DUALNUM builds."). After removing the coercion from
`lj_carith_check64()`, the bit shift operation may end in an infinite
loop in the case of infinite retrying to coerce the second operand from
number to integer TValue type.

This patch fixes that by unconditionally coercing the second argument in
the `LJLIB_ASM(bit_lshift)` fast function handler.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#11055

5702 of 6038 branches covered (94.44%)

Branch coverage included in aggregate %.

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

16 existing lines in 3 files now uncovered.

21732 of 23462 relevant lines covered (92.63%)

2960687.86 hits per line

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

85.71
/src/lj_sysprof.c
1
/*
2
** Implementation of sysprof - platform and Lua profiler.
3
*/
4

5
#define lj_sysprof_c
6
#define LUA_CORE
7

8
#include "lj_arch.h"
9
#include "lj_sysprof.h"
10

11
#if LJ_HASSYSPROF
12

13
#include "lj_obj.h"
14
#include "lj_debug.h"
15
#include "lj_dispatch.h"
16
#include "lj_frame.h"
17

18
#if LJ_HASJIT
19
#include "lj_jit.h"
20
#include "lj_trace.h"
21
#endif
22

23
#include "lj_wbuf.h"
24
#include "lj_profile_timer.h"
25
#include "lj_symtab.h"
26

27
#include <pthread.h>
28
#include <errno.h>
29
#include <execinfo.h>
30

31
/*
32
** Number of profiler frames we need to omit during stack
33
** unwinding.
34
**   +------------------------+
35
** 0 | default_backtrace_host |
36
**   +------------------------+
37
** 1 | stream_backtrace_host  |
38
**   +------------------------+
39
** 2 |  stream_{guest/host}   |
40
**   +------------------------+
41
** 3 |      stream_event      |
42
**   +------------------------+
43
** 4 | sysprof_record_sample  |
44
**   +------------------------+
45
** 5 | sysprof_signal_handler |
46
**   +------------------------+
47
*/
48
#define SYSPROF_HANDLER_STACK_DEPTH 6
49
#define SYSPROF_BACKTRACE_FRAME_MAX 512
50

51
/* Check that vmstate fits in 4 bits (see streaming format) */
52
#define vmstfit4(st) ((st & ~(uint32_t)((1 << 4) - 1)) == 0)
53

54
enum sysprof_state {
55
  /* Profiler is not running. */
56
  SPS_IDLE,
57
  /* Profiler is running. */
58
  SPS_PROFILE,
59
  /*
60
  ** Stopped in case of stopped or failed stream.
61
  ** Saved errno is set at luaM_sysprof_stop.
62
  */
63
  SPS_HALT
64
};
65

66
struct sysprof {
67
  global_State *g; /* Profiled VM. */
68
  pthread_t thread; /* Profiled thread. */
69
  volatile sig_atomic_t state; /* Internal state. */
70
  struct lj_wbuf out; /* Output accumulator. */
71
  struct luam_Sysprof_Counters counters; /* Profiling counters. */
72
  struct luam_Sysprof_Options opt; /* Profiling options. */
73
  luam_Sysprof_writer writer; /* Writer function for profile events. */
74
  luam_Sysprof_on_stop on_stop; /* Callback on profiling stopping. */
75
  luam_Sysprof_backtracer backtracer; /* Backtracing function for the host stack. */
76
  lj_profile_timer timer; /* Profiling timer. */
77
  int saved_errno; /* Saved errno when profiler failed. */
78
};
79
/*
80
** XXX: Only one VM can be profiled at a time.
81
*/
82

83
static struct sysprof sysprof = {0};
84

85
/* --- Stream ------------------------------------------------------------- */
86

87
static const uint8_t ljp_header[] = {'l', 'j', 'p', LJP_FORMAT_VERSION,
88
                                      0x0, 0x0, 0x0};
89

90
static int stream_is_needed(struct sysprof *sp)
24✔
91
{
92
  return sp->opt.mode != LUAM_SYSPROF_DEFAULT;
24✔
93
}
94

95
static int is_unconfigured(struct sysprof *sp)
1,129✔
96
{
97
  return sp->backtracer == NULL || sp->on_stop == NULL || sp->writer == NULL;
381✔
98
}
99

100
static void stream_prologue(struct sysprof *sp)
5✔
101
{
102
  /*
103
  ** XXX: Must be zero for the symtab module to dump all loaded libraries.
104
  */
105
  uint32_t unused_lib_adds = 0;
5✔
106
  lj_symtab_dump(&sp->out, sp->g, &unused_lib_adds);
5✔
107
  lj_wbuf_addn(&sp->out, ljp_header, sizeof(ljp_header));
5✔
108
}
5✔
109

110
static void stream_epilogue(struct sysprof *sp)
5✔
111
{
112
  lj_wbuf_addbyte(&sp->out, LJP_EPILOGUE_BYTE);
5✔
113
}
114

115
static void stream_ffunc_impl(struct lj_wbuf *buf, uint8_t ffid)
1✔
116
{
117
  lj_wbuf_addbyte(buf, LJP_FRAME_FFUNC);
1✔
118
  lj_wbuf_addu64(buf, ffid);
1✔
119
}
1✔
120

121
static void stream_lfunc(struct lj_wbuf *buf, const GCfunc *func)
122
{
123
  lj_assertX(isluafunc(func), "bad lua function in sysprof stream");
124
  const GCproto *pt = funcproto(func);
125
  lj_assertX(pt != NULL, "bad lua function prototype in sysprof stream");
126
  lj_wbuf_addbyte(buf, LJP_FRAME_LFUNC);
127
  lj_wbuf_addu64(buf, (uintptr_t)pt);
128
  lj_wbuf_addu64(buf, (uint64_t)pt->firstline);
129
}
130

131
static void stream_cfunc(struct lj_wbuf *buf, const GCfunc *func)
10✔
132
{
133
  lj_assertX(iscfunc(func), "bad C function in sysprof stream");
10✔
134
  lj_wbuf_addbyte(buf, LJP_FRAME_CFUNC);
10✔
135
  lj_wbuf_addu64(buf, (uintptr_t)func->c.f);
10✔
136
}
10✔
137

UNCOV
138
static void stream_ffunc(struct lj_wbuf *buf, const GCfunc *func)
×
139
{
UNCOV
140
  lj_assertX(isffunc(func), "bad fast function in sysprof stream");
×
UNCOV
141
  stream_ffunc_impl(buf, func->c.ffid);
×
UNCOV
142
}
×
143

144
static void stream_frame_lua(struct lj_wbuf *buf, const cTValue *frame)
248✔
145
{
146
  const GCfunc *func = frame_func(frame);
248✔
147
  lj_assertX(func != NULL, "bad function in sysprof stream");
248✔
148
  if (isluafunc(func))
248✔
149
    stream_lfunc(buf, func);
238✔
150
  else if (isffunc(func))
10✔
UNCOV
151
    stream_ffunc(buf, func);
×
152
  else if (iscfunc(func))
10✔
153
    stream_cfunc(buf, func);
10✔
154
  else
155
    /* Unreachable. */
156
    lj_assertX(0, "bad function type in sysprof stream");
248✔
157
}
248✔
158

159
static void stream_backtrace_lua(struct sysprof *sp, uint32_t vmstate)
11✔
160
{
161
  global_State *g = sp->g;
11✔
162
  struct lj_wbuf *buf = &sp->out;
11✔
163
  cTValue *top_frame = NULL, *frame = NULL, *bot = NULL;
11✔
164
  lua_State *L = NULL;
11✔
165

166
  lj_assertX(g != NULL, "uninitialized global state in sysprof state");
11✔
167
  L = gco2th(gcref(g->cur_L));
11✔
168
  lj_assertG(L != NULL, "uninitialized Lua state in sysprof state");
11✔
169
  /*
170
  ** Lua stack may be inconsistent during the execution of a
171
  ** fast-function, so instead of updating the `top_frame` for
172
  ** it, its `ffid` is set instead. The first frame on the
173
  ** result stack is streamed manually, and the rest of the
174
  ** stack is streamed based on the previous `top_frame` value.
175
  */
176
  if (vmstate == LJ_VMST_FFUNC) {
11✔
177
    uint8_t ffid = g->top_frame_info.ffid;
1✔
178
    stream_ffunc_impl(buf, ffid);
1✔
179
  }
180

181
  top_frame = g->top_frame_info.top_frame - 1;
11✔
182

183
  bot = tvref(L->stack) + LJ_FR2;
11✔
184
  /* Traverse frames backwards */
185
  for (frame = top_frame; frame > bot; frame = frame_prev(frame)) {
527✔
186
    if (frame_gc(frame) == obj2gco(L) || frame_isvarg(frame))
258✔
187
      continue;  /* Skip dummy frames. See lj_err_optype_call(). */
10✔
188
    stream_frame_lua(buf, frame);
248✔
189
  }
190

191
  lj_wbuf_addbyte(buf, LJP_FRAME_LUA_LAST);
11✔
192
}
11✔
193

194
static void *stream_frame_host(int frame_no, void *addr)
105✔
195
{
196
  struct sysprof *sp = &sysprof;
105✔
197
  /*
198
  ** We don't want the profiler stack to be streamed, as it will
199
  ** burden the profile with unnecessary information.
200
  */
201
  if (LJ_UNLIKELY(frame_no <= SYSPROF_HANDLER_STACK_DEPTH))
105✔
202
    return addr;
203
  else if (LJ_UNLIKELY(sp->opt.mode == LUAM_SYSPROF_LEAF &&
14✔
204
                         frame_no > SYSPROF_HANDLER_STACK_DEPTH))
205
    return NULL;
206

207
  lj_wbuf_addu64(&sp->out, (uintptr_t)addr);
14✔
208
  return addr;
14✔
209
}
210

211
static void default_backtrace_host(void *(writer)(int frame_no, void *addr))
16✔
212
{
213
  static void *backtrace_buf[SYSPROF_BACKTRACE_FRAME_MAX] = {};
16✔
214

215
  struct sysprof *sp = &sysprof;
16✔
216
  int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF
32✔
217
                  ? SYSPROF_HANDLER_STACK_DEPTH + 1
218
                  : SYSPROF_BACKTRACE_FRAME_MAX;
16✔
219
  const int depth = backtrace(backtrace_buf, max_depth);
16✔
220
  int level;
16✔
221

222
  lj_assertX(depth <= max_depth, "depth of C stack is too big");
16✔
223
  for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) {
137✔
224
    if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level]))
105✔
225
      return;
226
  }
227
}
228

229
static void stream_backtrace_host(struct sysprof *sp)
16✔
230
{
231
  lj_assertX(sp->backtracer != NULL, "uninitialized sysprof backtracer");
16✔
232
  sp->backtracer(stream_frame_host);
16✔
233
  lj_wbuf_addu64(&sp->out, (uintptr_t)LJP_FRAME_HOST_LAST);
16✔
234
}
235

236
#if LJ_HASJIT
237
static void stream_trace(struct sysprof *sp, uint32_t vmstate)
×
238
{
239
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
×
240
  struct lj_wbuf *out = &sp->out;
×
241
  uint32_t traceno = sp->g->vmstate;
×
242
  jit_State *J = G2J(sp->g);
×
243
  GCtrace *trace = traceref(J, traceno);
×
244

245
  GCproto *startpt = gco2pt(gcref(trace->startpt));
×
246

247
  lj_wbuf_addu64(out, traceno);
×
248
  lj_wbuf_addu64(out, (uintptr_t)startpt);
×
249
  lj_wbuf_addu64(out, startpt->firstline);
×
250
}
×
251
#endif
252

253
static void stream_guest(struct sysprof *sp, uint32_t vmstate)
11✔
254
{
255
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
11✔
256
  stream_backtrace_lua(sp, vmstate);
11✔
257
  stream_backtrace_host(sp);
11✔
258
}
11✔
259

260
static void stream_host(struct sysprof *sp, uint32_t vmstate)
5✔
261
{
262
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
5✔
263
  stream_backtrace_host(sp);
5✔
264
}
5✔
265

266
typedef void (*event_streamer)(struct sysprof *sp, uint32_t vmstate);
267

268
static event_streamer event_streamers[] = {
269
  /* XXX: order is important */
270
  stream_host,  /* LJ_VMST_INTERP */
271
  stream_guest, /* LJ_VMST_LFUNC */
272
  stream_guest, /* LJ_VMST_FFUNC */
273
  stream_guest, /* LJ_VMST_CFUNC */
274
  stream_host,  /* LJ_VMST_GC */
275
  stream_host,  /* LJ_VMST_EXIT */
276
  stream_host,  /* LJ_VMST_RECORD */
277
  stream_host,  /* LJ_VMST_OPT */
278
  stream_host,  /* LJ_VMST_ASM */
279
#if LJ_HASJIT
280
  stream_trace  /* LJ_VMST_TRACE */
281
#endif
282
};
283

284
static void stream_event(struct sysprof *sp, uint32_t vmstate)
285
{
286
  event_streamer stream = NULL;
287

288
  lj_assertX(vmstfit4(vmstate), "vmstate don't fit in 4 bits");
289
  stream = event_streamers[vmstate];
290
  lj_assertX(stream != NULL, "uninitialized sysprof stream");
291
  stream(sp, vmstate);
292
}
293

294
/* -- Signal handler ------------------------------------------------------ */
295

296
static void sysprof_record_sample(struct sysprof *sp, siginfo_t *info)
297
{
298
  global_State *g = sp->g;
299
  uint32_t _vmstate = ~(uint32_t)(g->vmstate);
300
  uint32_t vmstate = _vmstate < LJ_VMST_TRACE ? _vmstate : LJ_VMST_TRACE;
301

302
  lj_assertX(pthread_self() == sp->thread,
303
             "bad thread during sysprof record sample");
304

305
  /* Caveat: order of counters must match vmstate order in <lj_obj.h>. */
306
  ((uint64_t *)&sp->counters)[vmstate]++;
307

308
  sp->counters.samples++;
309

310
  if (!stream_is_needed(sp))
311
    return;
312

313
  stream_event(sp, vmstate);
314
  if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
315
    sp->saved_errno = lj_wbuf_errno(&sp->out);
316
    lj_wbuf_terminate(&sp->out);
317
    sp->state = SPS_HALT;
318
  }
319
}
320

321
static void sysprof_signal_handler(int sig, siginfo_t *info, void *ctx)
17✔
322
{
323
  struct sysprof *sp = &sysprof;
17✔
324
  UNUSED(sig);
17✔
325
  UNUSED(ctx);
17✔
326

327
  switch (sp->state) {
17✔
328
    case SPS_PROFILE:
17✔
329
      sysprof_record_sample(sp, info);
17✔
330
      break;
17✔
331

332
    case SPS_IDLE:
333
    case SPS_HALT:
334
      /* noop */
335
      break;
336

337
    default:
338
      lj_assertX(0, "bad sysprof profiler state");
339
      break;
340
  }
341
}
17✔
342

343
/* -- Internal ------------------------------------------------------------ */
344

345
static int sysprof_validate(struct sysprof *sp,
17✔
346
                            const struct luam_Sysprof_Options *opt)
347
{
348
  switch (sp->state) {
17✔
349
    case SPS_IDLE:
15✔
350
      if (opt->mode > LUAM_SYSPROF_CALLGRAPH) {
15✔
351
        return PROFILE_ERRUSE;
352
      } else if (opt->mode != LUAM_SYSPROF_DEFAULT &&
14✔
353
                 (opt->buf == NULL || opt->len == 0 || is_unconfigured(sp))) {
6✔
354
        return PROFILE_ERRUSE;
355
      } else if (opt->interval == 0) {
13✔
356
        return PROFILE_ERRUSE;
1✔
357
      }
358
      break;
359

360
    case SPS_PROFILE:
361
    case SPS_HALT:
362
      return PROFILE_ERRRUN;
363

364
    default:
365
      lj_assertX(0, "bad sysprof profiler state");
366
      break;
367
  }
368

369
  return PROFILE_SUCCESS;
370
}
371

372
static int sysprof_init(struct sysprof *sp, lua_State *L,
373
                        const struct luam_Sysprof_Options *opt)
374
{
375
  const int status = sysprof_validate(sp, opt);
376
  if (PROFILE_SUCCESS != status)
377
    return status;
378

379
  /* Copy validated options to sysprof state. */
380
  memcpy(&sp->opt, opt, sizeof(sp->opt));
381

382
  /* Init general fields. */
383
  sp->g = G(L);
384
  sp->thread = pthread_self();
385

386
  /* Reset counters. */
387
  memset(&sp->counters, 0, sizeof(sp->counters));
388

389
  /* Reset saved errno. */
390
  sp->saved_errno = 0;
391

392
  if (stream_is_needed(sp))
393
    lj_wbuf_init(&sp->out, sp->writer, opt->ctx, opt->buf, opt->len);
394

395
  return PROFILE_SUCCESS;
396
}
397

398
/* -- Public profiling API ------------------------------------------------ */
399

400
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
375✔
401
  struct sysprof *sp = &sysprof;
375✔
402

403
  if (sp->state != SPS_IDLE || writer == NULL)
375✔
404
    return PROFILE_ERRUSE;
405

406
  sp->writer = writer;
375✔
407
  if (!is_unconfigured(sp)) {
375✔
408
    sp->state = SPS_IDLE;
1✔
409
  }
410
  return PROFILE_SUCCESS;
411
}
412

413
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
375✔
414
  struct sysprof *sp = &sysprof;
375✔
415

416
  if (sp->state != SPS_IDLE || on_stop == NULL)
375✔
417
    return PROFILE_ERRUSE;
418

419
  sp->on_stop = on_stop;
375✔
420
  if (!is_unconfigured(sp)) {
375✔
421
    sp->state = SPS_IDLE;
1✔
422
  }
423
  return PROFILE_SUCCESS;
424
}
425

426
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
374✔
427
  struct sysprof *sp = &sysprof;
374✔
428

429
  if (sp->state != SPS_IDLE)
374✔
430
    return PROFILE_ERRUSE;
431
  if (backtracer == NULL) {
374✔
432
    sp->backtracer = default_backtrace_host;
374✔
433
    /*
434
    ** XXX: `backtrace` is not signal-safe, according to man,
435
    ** because it is lazy loaded on the first call, which triggers
436
    ** allocations. We need to call `backtrace` before starting profiling
437
    ** to avoid lazy loading.
438
    */
439
    void *dummy = NULL;
374✔
440
    backtrace(&dummy, 1);
374✔
441
  }
442
  else {
443
    sp->backtracer = backtracer;
×
444
  }
445
  if (!is_unconfigured(sp)) {
374✔
446
    sp->state = SPS_IDLE;
374✔
447
  }
448
  return PROFILE_SUCCESS;
449
}
450

451
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
17✔
452
{
453
  struct sysprof *sp = &sysprof;
17✔
454

455
  int status = sysprof_init(sp, L, opt);
17✔
456
  if (PROFILE_SUCCESS != status) {
17✔
457
    if (NULL != sp->on_stop) {
5✔
458
      /*
459
      ** Initialization may fail in case of unconfigured sysprof,
460
      ** so we cannot guarantee cleaning up resources in this case.
461
      */
462
      sp->on_stop(opt->ctx, opt->buf);
5✔
463
    }
464
    return status;
5✔
465
  }
466

467
  sp->state = SPS_PROFILE;
12✔
468

469
  if (stream_is_needed(sp)) {
12✔
470
    stream_prologue(sp);
5✔
471
    if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
5✔
472
      /* on_stop call may change errno value. */
473
      const int saved_errno = lj_wbuf_errno(&sp->out);
×
474
      /* Ignore possible errors. mp->out.buf may be NULL here. */
475
      sp->on_stop(opt->ctx, sp->out.buf);
×
476
      lj_wbuf_terminate(&sp->out);
×
477
      sp->state = SPS_IDLE;
×
478
      errno = saved_errno;
×
479
      return PROFILE_ERRIO;
×
480
    }
481
  }
482

483
  sp->timer.opt.interval_msec = opt->interval;
12✔
484
  sp->timer.opt.handler = sysprof_signal_handler;
12✔
485
  lj_profile_timer_start(&sp->timer);
12✔
486

487
  return PROFILE_SUCCESS;
12✔
488
}
489

490
int lj_sysprof_stop(lua_State *L)
385✔
491
{
492
  struct sysprof *sp = &sysprof;
385✔
493
  global_State *g = sp->g;
385✔
494
  struct lj_wbuf *out = &sp->out;
385✔
495

496
  if (SPS_IDLE == sp->state)
385✔
497
    return PROFILE_ERRRUN;
498
  else if (G(L) != g)
12✔
499
    return PROFILE_ERRUSE;
500

501
  lj_profile_timer_stop(&sp->timer);
12✔
502

503
  if (SPS_HALT == sp->state) {
12✔
504
    errno = sp->saved_errno;
×
505
    sp->state = SPS_IDLE;
×
506
    /* wbuf was terminated when error occurred. */
507
    return PROFILE_ERRIO;
×
508
  }
509

510
  sp->state = SPS_IDLE;
12✔
511

512
  if (stream_is_needed(sp)) {
12✔
513
    int cb_status = 0;
5✔
514

515
    stream_epilogue(sp);
5✔
516
    lj_wbuf_flush(out);
5✔
517

518
    cb_status = sp->on_stop(sp->opt.ctx, out->buf);
5✔
519
    if (LJ_UNLIKELY(lj_wbuf_test_flag(out, STREAM_ERRIO | STREAM_STOP)) ||
5✔
520
        cb_status != 0) {
521
      errno = lj_wbuf_errno(out);
×
522
      lj_wbuf_terminate(out);
×
523
      return PROFILE_ERRIO;
×
524
    }
525

526
    lj_wbuf_terminate(out);
5✔
527
  }
528

529
  return PROFILE_SUCCESS;
530
}
531

532
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
4✔
533
{
534
  const struct sysprof *sp = &sysprof;
4✔
535
  if (sp->state != SPS_IDLE)
4✔
536
    return PROFILE_ERRUSE;
537
  memcpy(counters, &sp->counters, sizeof(sp->counters));
4✔
538
  return PROFILE_SUCCESS;
4✔
539
}
540

541
void lj_sysprof_add_proto(const struct GCproto *pt)
63,486✔
542
{
543
  struct sysprof *sp = &sysprof;
63,486✔
544

545
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
63,486✔
546
    return;
547

548
  /*
549
  ** XXX: Avoid sampling during the symtab extension. That shouldn't have any
550
  ** significant effect on profile precision, but if it does, it's better to
551
  ** implement an async-safe queue for the symtab events.
552
  */
553
  sp->state = SPS_IDLE;
1✔
554
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_LFUNC_EVENT);
1✔
555
  lj_symtab_dump_proto(&sp->out, pt);
1✔
556
  sp->state = SPS_PROFILE;
1✔
557
}
558

559
#if LJ_HASJIT
560
void lj_sysprof_add_trace(const struct GCtrace *tr)
19,094✔
561
{
562
  struct sysprof *sp = &sysprof;
19,094✔
563

564
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
19,094✔
565
    return;
566

567
  /* See the comment about the sysprof state above. */
568
  sp->state = SPS_IDLE;
×
569
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_TRACE_EVENT);
×
570
  lj_symtab_dump_trace(&sp->out, tr);
×
571
  sp->state = SPS_PROFILE;
×
572
}
573
#endif /* LJ_HASJIT */
574

575
#else /* LJ_HASSYSPROF */
576

577
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
578
  UNUSED(writer);
579
  return PROFILE_ERRUSE;
580
}
581

582
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
583
  UNUSED(on_stop);
584
  return PROFILE_ERRUSE;
585
}
586

587
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
588
  UNUSED(backtracer);
589
  return PROFILE_ERRUSE;
590
}
591

592
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
593
{
594
  UNUSED(L);
595
  return PROFILE_ERRUSE;
596
}
597

598
int lj_sysprof_stop(lua_State *L)
599
{
600
  UNUSED(L);
601
  return PROFILE_ERRUSE;
602
}
603

604
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
605
{
606
  UNUSED(counters);
607
  return PROFILE_ERRUSE;
608
}
609

610
void lj_sysprof_add_proto(const struct GCproto *pt)
611
{
612
  UNUSED(pt);
613
}
614

615
#if LJ_HASJIT
616
void lj_sysprof_add_trace(const struct GCtrace *tr)
617
{
618
  UNUSED(tr);
619
}
620
#endif /* LJ_HASJIT */
621

622
#endif /* LJ_HASSYSPROF */
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