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

tarantool / luajit / 13195589116

07 Feb 2025 07:46AM UTC coverage: 92.995% (+0.06%) from 92.94%
13195589116

push

github

Buristan
Fix detection of inconsistent renames due to sunk values.

Thanks to Sergey Kaplun.

(cherry picked from commit 811e448da)

This commit is a follow-up to the commit
3a2e4847c ("Detect inconsistent renames
even in the presence of sunk values."). Due to the reversed assembling
order of a trace, all registers are allocated from the bottom of the
trace to the top. Furthermore, if the snapshot contains sunk values, IRs
for them will contain the `RID_SUNK` after the first processing. If
there is another snapshot (with a smaller number) containing this sunk
IR, this IR will not be processed during the bloom filter marking in the
allocation of the slot that escapes this snapshot (since it is already
sunk). Hence, such IRs still may lead to the rename invariant violation
like in the aforementioned commit.

This patch prevents scanning from stopping when already sunk IR is faced
during snapshot processing so bloom filters contain actual information.
The disadvantage of this approach is that it assumes that any sunk
table-typed IR can't refer to the same table inside it (so there should
not be any cycling references in the sunk table).

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

Resolves tarantool/tarantool#10746
Relates to tarantool/aeon#282
Part of tarantool/tarantool#11055

Reviewed-by: Sergey Bronnikov <sergeyb@tarantool.org>
Signed-off-by: Sergey Kaplun <skaplun@tarantool.org>

5699 of 6035 branches covered (94.43%)

Branch coverage included in aggregate %.

21713 of 23442 relevant lines covered (92.62%)

2963010.87 hits per line

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

96.98
/src/lj_snap.c
1
/*
2
** Snapshot handling.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
*/
5

6
#define lj_snap_c
7
#define LUA_CORE
8

9
#include "lj_obj.h"
10

11
#if LJ_HASJIT
12

13
#include "lj_gc.h"
14
#include "lj_tab.h"
15
#include "lj_state.h"
16
#include "lj_frame.h"
17
#include "lj_bc.h"
18
#include "lj_ir.h"
19
#include "lj_jit.h"
20
#include "lj_iropt.h"
21
#include "lj_trace.h"
22
#include "lj_snap.h"
23
#include "lj_target.h"
24
#if LJ_HASFFI
25
#include "lj_ctype.h"
26
#include "lj_cdata.h"
27
#endif
28

29
/* Pass IR on to next optimization in chain (FOLD). */
30
#define emitir(ot, a, b)        (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
31

32
/* Emit raw IR without passing through optimizations. */
33
#define emitir_raw(ot, a, b)        (lj_ir_set(J, (ot), (a), (b)), lj_ir_emit(J))
34

35
/* -- Snapshot buffer allocation ------------------------------------------ */
36

37
/* Grow snapshot buffer. */
38
void lj_snap_grow_buf_(jit_State *J, MSize need)
265✔
39
{
40
  MSize maxsnap = (MSize)J->param[JIT_P_maxsnap];
265✔
41
  if (need > maxsnap)
265✔
42
    lj_trace_err(J, LJ_TRERR_SNAPOV);
1✔
43
  lj_mem_growvec(J->L, J->snapbuf, J->sizesnap, maxsnap, SnapShot);
264✔
44
  J->cur.snap = J->snapbuf;
263✔
45
}
263✔
46

47
/* Grow snapshot map buffer. */
48
void lj_snap_grow_map_(jit_State *J, MSize need)
257✔
49
{
50
  if (need < 2*J->sizesnapmap)
257✔
51
    need = 2*J->sizesnapmap;
52
  else if (need < 64)
150✔
53
    need = 64;
54
  J->snapmapbuf = (SnapEntry *)lj_mem_realloc(J->L, J->snapmapbuf,
514✔
55
                    J->sizesnapmap*sizeof(SnapEntry), need*sizeof(SnapEntry));
257✔
56
  J->cur.snapmap = J->snapmapbuf;
257✔
57
  J->sizesnapmap = need;
257✔
58
}
257✔
59

60
/* -- Snapshot generation ------------------------------------------------- */
61

62
/* Add all modified slots to the snapshot. */
63
static MSize snapshot_slots(jit_State *J, SnapEntry *map, BCReg nslots)
2,386,698✔
64
{
65
  IRRef retf = J->chain[IR_RETF];  /* Limits SLOAD restore elimination. */
2,386,698✔
66
  BCReg s;
2,386,698✔
67
  MSize n = 0;
2,386,698✔
68
  for (s = 0; s < nslots; s++) {
24,633,287✔
69
    TRef tr = J->slot[s];
22,246,589✔
70
    IRRef ref = tref_ref(tr);
22,246,589✔
71
#if LJ_FR2
72
    if (s == 1) {  /* Ignore slot 1 in LJ_FR2 mode, except if tailcalled. */
22,246,589✔
73
      if ((tr & TREF_FRAME))
2,386,698✔
74
        map[n++] = SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL);
1,272,672✔
75
      continue;
2,386,698✔
76
    }
77
    if ((tr & (TREF_FRAME | TREF_CONT)) && !ref) {
19,859,891✔
78
      cTValue *base = J->L->base - J->baseslot;
760,105✔
79
      tr = J->slot[s] = (tr & 0xff0000) | lj_ir_k64(J, IR_KNUM, base[s].u64);
760,105✔
80
      ref = tref_ref(tr);
760,105✔
81
    }
82
#endif
83
    if (ref) {
19,859,891✔
84
      SnapEntry sn = SNAP_TR(s, tr);
14,999,173✔
85
      IRIns *ir = &J->cur.ir[ref];
14,999,173✔
86
      if ((LJ_FR2 || !(sn & (SNAP_CONT|SNAP_FRAME))) &&
14,999,173✔
87
          ir->o == IR_SLOAD && ir->op1 == s && ref > retf) {
14,999,173✔
88
        /*
89
        ** No need to snapshot unmodified non-inherited slots.
90
        ** But always snapshot the function below a frame in LJ_FR2 mode.
91
        */
92
        if (!(ir->op2 & IRSLOAD_INHERIT) &&
3,448,116✔
93
            (!LJ_FR2 || s == 0 || s+1 == nslots ||
3,353,548✔
94
             !(J->slot[s+1] & (TREF_CONT|TREF_FRAME))))
3,349,829✔
95
          continue;
3,362,933✔
96
        /* No need to restore readonly slots and unmodified non-parent slots. */
97
        if (!(LJ_DUALNUM && (ir->op2 & IRSLOAD_CONVERT)) &&
85,183✔
98
            (ir->op2 & (IRSLOAD_READONLY|IRSLOAD_PARENT)) != IRSLOAD_PARENT)
99
          sn |= SNAP_NORESTORE;
41,747✔
100
      }
101
      if (LJ_SOFTFP32 && irt_isnum(ir->t))
11,636,240✔
102
        sn |= SNAP_SOFTFPNUM;
103
      map[n++] = sn;
11,636,240✔
104
    }
105
  }
106
  return n;
2,386,698✔
107
}
108

109
/* Add frame links at the end of the snapshot. */
110
static MSize snapshot_framelinks(jit_State *J, SnapEntry *map, uint8_t *topslot)
2,386,698✔
111
{
112
  cTValue *frame = J->L->base - 1;
2,386,698✔
113
  cTValue *lim = J->L->base - J->baseslot + LJ_FR2;
2,386,698✔
114
  GCfunc *fn = frame_func(frame);
2,386,698✔
115
  cTValue *ftop = isluafunc(fn) ? (frame+funcproto(fn)->framesize) : J->L->top;
2,386,698✔
116
#if LJ_FR2
117
  uint64_t pcbase = (u64ptr(J->pc) << 8) | (J->baseslot - 2);
2,386,698✔
118
  lj_assertJ(2 <= J->baseslot && J->baseslot <= 257, "bad baseslot");
2,386,698✔
119
  memcpy(map, &pcbase, sizeof(uint64_t));
2,386,698✔
120
#else
121
  MSize f = 0;
122
  map[f++] = SNAP_MKPC(J->pc);  /* The current PC is always the first entry. */
123
  lj_assertJ(!J->pt ||
124
             (J->pc >= proto_bc(J->pt) &&
125
              J->pc < proto_bc(J->pt) + J->pt->sizebc), "bad snapshot PC");
126
#endif
127
  while (frame > lim) {  /* Backwards traversal of all frames above base. */
4,845,731✔
128
    if (frame_islua(frame)) {
2,459,033✔
129
#if !LJ_FR2
130
      map[f++] = SNAP_MKPC(frame_pc(frame));
131
#endif
132
      frame = frame_prevl(frame);
2,458,394✔
133
    } else if (frame_iscont(frame)) {
639✔
134
#if !LJ_FR2
135
      map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
136
      map[f++] = SNAP_MKPC(frame_contpc(frame));
137
#endif
138
      frame = frame_prevd(frame);
346✔
139
    } else {
140
      lj_assertJ(!frame_isc(frame), "broken frame chain");
293✔
141
#if !LJ_FR2
142
      map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
143
#endif
144
      frame = frame_prevd(frame);
293✔
145
      continue;
293✔
146
    }
147
    if (frame + funcproto(frame_func(frame))->framesize > ftop)
2,458,740✔
148
      ftop = frame + funcproto(frame_func(frame))->framesize;
149
  }
150
  *topslot = (uint8_t)(ftop - lim);
2,386,698✔
151
#if LJ_FR2
152
  lj_assertJ(sizeof(SnapEntry) * 2 == sizeof(uint64_t), "bad SnapEntry def");
2,386,698✔
153
  return 2;
2,386,698✔
154
#else
155
  lj_assertJ(f == (MSize)(1 + J->framedepth), "miscalculated snapshot size");
156
  return f;
157
#endif
158
}
159

160
/* Take a snapshot of the current stack. */
161
static void snapshot_stack(jit_State *J, SnapShot *snap, MSize nsnapmap)
2,386,698✔
162
{
163
  BCReg nslots = J->baseslot + J->maxslot;
2,386,698✔
164
  MSize nent;
2,386,698✔
165
  SnapEntry *p;
2,386,698✔
166
  /* Conservative estimate. */
167
  lj_snap_grow_map(J, nsnapmap + nslots + (MSize)(LJ_FR2?2:J->framedepth+1));
2,386,698✔
168
  p = &J->cur.snapmap[nsnapmap];
2,386,698✔
169
  nent = snapshot_slots(J, p, nslots);
2,386,698✔
170
  snap->nent = (uint8_t)nent;
2,386,698✔
171
  nent += snapshot_framelinks(J, p + nent, &snap->topslot);
2,386,698✔
172
  snap->mapofs = (uint32_t)nsnapmap;
2,386,698✔
173
  snap->ref = (IRRef1)J->cur.nins;
2,386,698✔
174
  snap->mcofs = 0;
2,386,698✔
175
  snap->nslots = (uint8_t)nslots;
2,386,698✔
176
  snap->count = 0;
2,386,698✔
177
  J->cur.nsnapmap = (uint32_t)(nsnapmap + nent);
2,386,698✔
178
}
2,386,698✔
179

180
/* Add or merge a snapshot. */
181
void lj_snap_add(jit_State *J)
2,386,700✔
182
{
183
  MSize nsnap = J->cur.nsnap;
2,386,700✔
184
  MSize nsnapmap = J->cur.nsnapmap;
2,386,700✔
185
  /* Merge if no ins. inbetween or if requested and no guard inbetween. */
186
  if ((nsnap > 0 && J->cur.snap[nsnap-1].ref == J->cur.nins) ||
2,386,700✔
187
      (J->mergesnap && !irt_isguard(J->guardemit))) {
1,436,978✔
188
    if (nsnap == 1) {  /* But preserve snap #0 PC. */
968,522✔
189
      emitir_raw(IRT(IR_NOP, IRT_NIL), 0, 0);
1,193✔
190
      goto nomerge;
1,193✔
191
    }
192
    nsnapmap = J->cur.snap[--nsnap].mapofs;
967,329✔
193
  } else {
194
  nomerge:
1,418,178✔
195
    lj_snap_grow_buf(J, nsnap+1);
1,419,371✔
196
    J->cur.nsnap = (uint16_t)(nsnap+1);
1,419,369✔
197
  }
198
  J->mergesnap = 0;
2,386,698✔
199
  J->guardemit.irt = 0;
2,386,698✔
200
  snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap);
2,386,698✔
201
}
2,386,698✔
202

203
/* -- Snapshot modification ----------------------------------------------- */
204

205
#define SNAP_USEDEF_SLOTS        (LJ_MAX_JSLOTS+LJ_STACK_EXTRA)
206

207
/* Find unused slots with reaching-definitions bytecode data-flow analysis. */
208
static BCReg snap_usedef(jit_State *J, uint8_t *udf,
209
                         const BCIns *pc, BCReg maxslot)
210
{
211
  BCReg s;
212
  GCobj *o;
213

214
  if (maxslot == 0) return 0;
215
#ifdef LUAJIT_USE_VALGRIND
216
  /* Avoid errors for harmless reads beyond maxslot. */
217
  memset(udf, 1, SNAP_USEDEF_SLOTS);
218
#else
219
  memset(udf, 1, maxslot);
220
#endif
221

222
  /* Treat open upvalues as used. */
223
  o = gcref(J->L->openupval);
224
  while (o) {
225
    if (uvval(gco2uv(o)) < J->L->base) break;
226
    udf[uvval(gco2uv(o)) - J->L->base] = 0;
227
    o = gcref(o->gch.nextgc);
228
  }
229

230
#define USE_SLOT(s)                udf[(s)] &= ~1
231
#define DEF_SLOT(s)                udf[(s)] *= 3
232

233
  /* Scan through following bytecode and check for uses/defs. */
234
  lj_assertJ(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc,
235
             "snapshot PC out of range");
236
  for (;;) {
237
    BCIns ins = *pc++;
238
    BCOp op = bc_op(ins);
239
    switch (bcmode_b(op)) {
240
    case BCMvar: USE_SLOT(bc_b(ins)); break;
241
    default: break;
242
    }
243
    switch (bcmode_c(op)) {
244
    case BCMvar: USE_SLOT(bc_c(ins)); break;
245
    case BCMrbase:
246
      lj_assertJ(op == BC_CAT, "unhandled op %d with RC rbase", op);
247
      for (s = bc_b(ins); s <= bc_c(ins); s++) USE_SLOT(s);
248
      for (; s < maxslot; s++) DEF_SLOT(s);
249
      break;
250
    case BCMjump:
251
    handle_jump: {
252
      BCReg minslot = bc_a(ins);
253
      if (op >= BC_FORI && op <= BC_JFORL) minslot += FORL_EXT;
254
      else if (op >= BC_ITERL && op <= BC_JITERL) minslot += bc_b(pc[-2])-1;
255
      else if (op == BC_UCLO) {
256
        ptrdiff_t delta = bc_j(ins);
257
        if (delta < 0) return maxslot;  /* Prevent loop. */
258
        pc += delta;
259
        break;
260
      }
261
      for (s = minslot; s < maxslot; s++) DEF_SLOT(s);
262
      return minslot < maxslot ? minslot : maxslot;
263
      }
264
    case BCMlit:
265
      if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
266
        goto handle_jump;
267
      } else if (bc_isret(op)) {
268
        BCReg top = op == BC_RETM ? maxslot : (bc_a(ins) + bc_d(ins)-1);
269
        for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s);
270
        for (; s < top; s++) USE_SLOT(s);
271
        for (; s < maxslot; s++) DEF_SLOT(s);
272
        return 0;
273
      }
274
      break;
275
    case BCMfunc: return maxslot;  /* NYI: will abort, anyway. */
276
    default: break;
277
    }
278
    switch (bcmode_a(op)) {
279
    case BCMvar: USE_SLOT(bc_a(ins)); break;
280
    case BCMdst:
281
       if (!(op == BC_ISTC || op == BC_ISFC)) DEF_SLOT(bc_a(ins));
282
       break;
283
    case BCMbase:
284
      if (op >= BC_CALLM && op <= BC_ITERN) {
285
        BCReg top = (op == BC_CALLM || op == BC_CALLMT || bc_c(ins) == 0) ?
286
                    maxslot : (bc_a(ins) + bc_c(ins)+LJ_FR2);
287
        if (LJ_FR2) DEF_SLOT(bc_a(ins)+1);
288
        s = bc_a(ins) - ((op == BC_ITERC || op == BC_ITERN) ? 3 : 0);
289
        for (; s < top; s++) USE_SLOT(s);
290
        for (; s < maxslot; s++) DEF_SLOT(s);
291
        if (op == BC_CALLT || op == BC_CALLMT) {
292
          for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s);
293
          return 0;
294
        }
295
      } else if (op == BC_VARG) {
296
        return maxslot;  /* NYI: punt. */
297
      } else if (op == BC_KNIL) {
298
        for (s = bc_a(ins); s <= bc_d(ins); s++) DEF_SLOT(s);
299
      } else if (op == BC_TSETM) {
300
        for (s = bc_a(ins)-1; s < maxslot; s++) USE_SLOT(s);
301
      }
302
      break;
303
    default: break;
304
    }
305
    lj_assertJ(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc,
306
               "use/def analysis PC out of range");
307
  }
308

309
#undef USE_SLOT
310
#undef DEF_SLOT
311

312
  return 0;  /* unreachable */
313
}
314

315
/* Mark slots used by upvalues of child prototypes as used. */
316
void snap_useuv(GCproto *pt, uint8_t *udf)
1,741,145✔
317
{
318
  /* This is a coarse check, because it's difficult to correlate the lifetime
319
  ** of slots and closures. But the number of false positives is quite low.
320
  ** A false positive may cause a slot not to be purged, which is just
321
  ** a missed optimization.
322
  */
323
  if ((pt->flags & PROTO_CHILD)) {
1,741,145✔
324
    ptrdiff_t i, j, n = pt->sizekgc;
236✔
325
    GCRef *kr = mref(pt->k, GCRef) - 1;
236✔
326
    for (i = 0; i < n; i++, kr--) {
7,127✔
327
      GCobj *o = gcref(*kr);
6,891✔
328
      if (o->gch.gct == ~LJ_TPROTO) {
6,891✔
329
        for (j = 0; j < gco2pt(o)->sizeuv; j++) {
1,259✔
330
          uint32_t v = proto_uv(gco2pt(o))[j];
532✔
331
          if ((v & PROTO_UV_LOCAL)) {
532✔
332
            udf[(v & 0xff)] = 0;
518✔
333
          }
334
        }
335
      }
336
    }
337
  }
338
}
1,741,145✔
339

340
/* Purge dead slots before the next snapshot. */
341
void lj_snap_purge(jit_State *J)
1,332,199✔
342
{
343
  uint8_t udf[SNAP_USEDEF_SLOTS];
1,332,199✔
344
  BCReg s, maxslot = J->maxslot;
1,332,199✔
345
  if (bc_op(*J->pc) == BC_FUNCV && maxslot > J->pt->numparams)
1,332,199✔
346
    maxslot = J->pt->numparams;
347
  s = snap_usedef(J, udf, J->pc, maxslot);
1,332,199✔
348
  if (s < maxslot) {
1,332,199✔
349
    snap_useuv(J->pt, udf);
1,157,659✔
350
    for (; s < maxslot; s++)
4,183,377✔
351
      if (udf[s] != 0)
1,868,059✔
352
        J->base[s] = 0;  /* Purge dead slots. */
998,952✔
353
  }
354
}
1,332,199✔
355

356
/* Shrink last snapshot. */
357
void lj_snap_shrink(jit_State *J)
859,141✔
358
{
359
  SnapShot *snap = &J->cur.snap[J->cur.nsnap-1];
859,141✔
360
  SnapEntry *map = &J->cur.snapmap[snap->mapofs];
859,141✔
361
  MSize n, m, nlim, nent = snap->nent;
859,141✔
362
  uint8_t udf[SNAP_USEDEF_SLOTS];
859,141✔
363
  BCReg maxslot = J->maxslot;
859,141✔
364
  BCReg baseslot = J->baseslot;
859,141✔
365
  BCReg minslot = snap_usedef(J, udf, snap_pc(&map[nent]), maxslot);
859,141✔
366
  if (minslot < maxslot) snap_useuv(J->pt, udf);
859,141✔
367
  maxslot += baseslot;
859,141✔
368
  minslot += baseslot;
859,141✔
369
  snap->nslots = (uint8_t)maxslot;
859,141✔
370
  for (n = m = 0; n < nent; n++) {  /* Remove unused slots from snapshot. */
6,822,747✔
371
    BCReg s = snap_slot(map[n]);
5,963,606✔
372
    if (s < minslot || (s < maxslot && udf[s-baseslot] == 0))
5,963,606✔
373
      map[m++] = map[n];  /* Only copy used slots. */
5,087,227✔
374
  }
375
  snap->nent = (uint8_t)m;
859,141✔
376
  nlim = J->cur.nsnapmap - snap->mapofs - 1;
859,141✔
377
  while (n <= nlim) map[m++] = map[n++];  /* Move PC + frame links down. */
2,577,423✔
378
  J->cur.nsnapmap = (uint32_t)(snap->mapofs + m);  /* Free up space in map. */
859,141✔
379
}
859,141✔
380

381
/* -- Snapshot access ----------------------------------------------------- */
382

383
/* Initialize a Bloom Filter with all renamed refs.
384
** There are very few renames (often none), so the filter has
385
** very few bits set. This makes it suitable for negative filtering.
386
*/
387
static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim)
261,998✔
388
{
389
  BloomFilter rfilt = 0;
261,998✔
390
  IRIns *ir;
261,998✔
391
  for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
270,267✔
392
    if (ir->op2 <= lim)
8,269✔
393
      bloomset(rfilt, ir->op1);
4,421✔
394
  return rfilt;
245,258✔
395
}
396

397
/* Process matching renames to find the original RegSP. */
398
static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs)
2,608✔
399
{
400
  IRIns *ir;
2,608✔
401
  for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
8,988✔
402
    if (ir->op1 == ref && ir->op2 <= lim)
6,380✔
403
      rs = ir->prev;
2,674✔
404
  return rs;
405
}
406

407
/* Copy RegSP from parent snapshot to the parent links of the IR. */
408
IRIns *lj_snap_regspmap(jit_State *J, GCtrace *T, SnapNo snapno, IRIns *ir)
16,740✔
409
{
410
  SnapShot *snap = &T->snap[snapno];
16,740✔
411
  SnapEntry *map = &T->snapmap[snap->mapofs];
16,740✔
412
  BloomFilter rfilt = snap_renamefilter(T, snapno);
16,740✔
413
  MSize n = 0;
414
  IRRef ref = 0;
38,104✔
415
  UNUSED(J);
38,104✔
416
  for ( ; ; ir++) {
59,468✔
417
    uint32_t rs;
38,104✔
418
    if (ir->o == IR_SLOAD) {
38,104✔
419
      if (!(ir->op2 & IRSLOAD_PARENT)) break;
27,314✔
420
      for ( ; ; n++) {
86,301✔
421
        lj_assertJ(n < snap->nent, "slot %d not found in snapshot", ir->op1);
33,363✔
422
        if (snap_slot(map[n]) == ir->op1) {
52,938✔
423
          ref = snap_ref(map[n++]);
19,575✔
424
          break;
19,575✔
425
        }
426
      }
427
    } else if (LJ_SOFTFP32 && ir->o == IR_HIOP) {
10,790✔
428
      ref++;
429
    } else if (ir->o == IR_PVAL) {
10,790✔
430
      ref = ir->op1 + REF_BIAS;
1,789✔
431
    } else {
432
      break;
433
    }
434
    rs = T->ir[ref].prev;
21,364✔
435
    if (bloomtest(rfilt, ref))
21,364✔
436
      rs = snap_renameref(T, snapno, ref, rs);
200✔
437
    ir->prev = (uint16_t)rs;
21,364✔
438
    lj_assertJ(regsp_used(rs), "unused IR %04d in snapshot", ref - REF_BIAS);
21,364✔
439
  }
440
  return ir;
16,740✔
441
}
442

443
/* -- Snapshot replay ----------------------------------------------------- */
444

445
/* Replay constant from parent trace. */
446
static TRef snap_replay_const(jit_State *J, IRIns *ir)
37,752✔
447
{
448
  /* Only have to deal with constants that can occur in stack slots. */
449
  switch ((IROp)ir->o) {
37,752✔
450
  case IR_KPRI: return TREF_PRI(irt_type(ir->t));
163✔
451
  case IR_KINT: return lj_ir_kint(J, ir->i);
4,357✔
452
  case IR_KGC: return lj_ir_kgc(J, ir_kgc(ir), irt_t(ir->t));
22,957✔
453
  case IR_KNUM: case IR_KINT64:
10,275✔
454
    return lj_ir_k64(J, (IROp)ir->o, ir_k64(ir)->u64);
10,275✔
455
  case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir));  /* Continuation. */
×
456
  case IR_KNULL: return lj_ir_knull(J, irt_type(ir->t));
×
457
  default: lj_assertJ(0, "bad IR constant op %d", ir->o); return TREF_NIL;
458
  }
459
}
460

461
/* De-duplicate parent reference. */
462
static TRef snap_dedup(jit_State *J, SnapEntry *map, MSize nmax, IRRef ref)
463
{
464
  MSize j;
465
  for (j = 0; j < nmax; j++)
15,592✔
466
    if (snap_ref(map[j]) == ref)
15,021✔
467
      return J->slot[snap_slot(map[j])] & ~(SNAP_CONT|SNAP_FRAME);
2,179✔
468
  return 0;
469
}
470

471
/* Emit parent reference with de-duplication. */
472
static TRef snap_pref(jit_State *J, GCtrace *T, SnapEntry *map, MSize nmax,
473
                      BloomFilter seen, IRRef ref)
474
{
475
  IRIns *ir = &T->ir[ref];
476
  TRef tr;
477
  if (irref_isk(ref))
478
    tr = snap_replay_const(J, ir);
479
  else if (!regsp_used(ir->prev))
480
    tr = 0;
481
  else if (!bloomtest(seen, ref) || (tr = snap_dedup(J, map, nmax, ref)) == 0)
482
    tr = emitir(IRT(IR_PVAL, irt_type(ir->t)), ref - REF_BIAS, 0);
483
  return tr;
484
}
485

486
/* Check whether a sunk store corresponds to an allocation. Slow path. */
487
static int snap_sunk_store2(GCtrace *T, IRIns *ira, IRIns *irs)
488
{
489
  if (irs->o == IR_ASTORE || irs->o == IR_HSTORE ||
490
      irs->o == IR_FSTORE || irs->o == IR_XSTORE) {
491
    IRIns *irk = &T->ir[irs->op1];
492
    if (irk->o == IR_AREF || irk->o == IR_HREFK)
493
      irk = &T->ir[irk->op1];
494
    return (&T->ir[irk->op1] == ira);
495
  }
496
  return 0;
497
}
498

499
/* Check whether a sunk store corresponds to an allocation. Fast path. */
500
static LJ_AINLINE int snap_sunk_store(GCtrace *T, IRIns *ira, IRIns *irs)
88✔
501
{
502
  if (irs->s != 255)
88✔
503
    return (ira + irs->s == irs);  /* Fast check. */
88✔
504
  return snap_sunk_store2(T, ira, irs);
×
505
}
506

507
/* Replay snapshot state to setup side trace. */
508
void lj_snap_replay(jit_State *J, GCtrace *T)
16,929✔
509
{
510
  SnapShot *snap = &T->snap[J->exitno];
16,929✔
511
  SnapEntry *map = &T->snapmap[snap->mapofs];
16,929✔
512
  MSize n, nent = snap->nent;
16,929✔
513
  BloomFilter seen = 0;
16,929✔
514
  int pass23 = 0;
16,929✔
515
  J->framedepth = 0;
16,929✔
516
  /* Emit IR for slots inherited from parent snapshot. */
517
  for (n = 0; n < nent; n++) {
76,882✔
518
    SnapEntry sn = map[n];
59,953✔
519
    BCReg s = snap_slot(sn);
59,953✔
520
    IRRef ref = snap_ref(sn);
59,953✔
521
    IRIns *ir = &T->ir[ref];
59,953✔
522
    TRef tr;
59,953✔
523
    /* The bloom filter avoids O(nent^2) overhead for de-duping slots. */
524
    if (bloomtest(seen, ref) && (tr = snap_dedup(J, map, n, ref)) != 0)
62,703✔
525
      goto setslot;
2,179✔
526
    bloomset(seen, ref);
57,774✔
527
    if (irref_isk(ref)) {
57,774✔
528
      /* See special treatment of LJ_FR2 slot 1 in snapshot_slots() above. */
529
      if (LJ_FR2 && (sn == SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)))
36,967✔
530
        tr = 0;
531
      else
532
        tr = snap_replay_const(J, ir);
34,111✔
533
    } else if (!regsp_used(ir->prev)) {
20,807✔
534
      pass23 = 1;
535
      lj_assertJ(s != 0, "unused slot 0 in snapshot");
536
      tr = s;
537
    } else {
538
      IRType t = irt_type(ir->t);
19,003✔
539
      uint32_t mode = IRSLOAD_INHERIT|IRSLOAD_PARENT;
19,003✔
540
      if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM)) t = IRT_NUM;
19,003✔
541
      if (ir->o == IR_SLOAD) mode |= (ir->op2 & IRSLOAD_READONLY);
19,003✔
542
      tr = emitir_raw(IRT(IR_SLOAD, t), s, mode);
19,003✔
543
    }
544
  setslot:
59,953✔
545
    J->slot[s] = tr | (sn&(SNAP_CONT|SNAP_FRAME));  /* Same as TREF_* flags. */
59,953✔
546
    J->framedepth += ((sn & (SNAP_CONT|SNAP_FRAME)) && (s != LJ_FR2));
59,953✔
547
    if ((sn & SNAP_FRAME))
59,953✔
548
      J->baseslot = s+1;
13,266✔
549
  }
550
  if (pass23) {
16,929✔
551
    IRIns *irlast = &T->ir[snap->ref];
413✔
552
    pass23 = 0;
413✔
553
    /* Emit dependent PVALs. */
554
    for (n = 0; n < nent; n++) {
3,594✔
555
      SnapEntry sn = map[n];
3,181✔
556
      IRRef refp = snap_ref(sn);
3,181✔
557
      IRIns *ir = &T->ir[refp];
3,181✔
558
      if (regsp_reg(ir->r) == RID_SUNK) {
3,181✔
559
        uint8_t m;
1,802✔
560
        if (J->slot[snap_slot(sn)] != snap_slot(sn)) continue;
1,802✔
561
        pass23 = 1;
1,802✔
562
        lj_assertJ(ir->o == IR_TNEW || ir->o == IR_TDUP ||
1,802✔
563
                   ir->o == IR_CNEW || ir->o == IR_CNEWI,
564
                   "sunk parent IR %04d has bad op %d", refp - REF_BIAS, ir->o);
565
        m = lj_ir_mode[ir->o];
1,802✔
566
        if (irm_op1(m) == IRMref) snap_pref(J, T, map, nent, seen, ir->op1);
1,802✔
567
        if (irm_op2(m) == IRMref) snap_pref(J, T, map, nent, seen, ir->op2);
1,802✔
568
        if (LJ_HASFFI && ir->o == IR_CNEWI) {
1,802✔
569
          if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP)
570
            snap_pref(J, T, map, nent, seen, (ir+1)->op2);
571
        } else {
572
          IRIns *irs;
15✔
573
          for (irs = ir+1; irs < irlast; irs++)
210✔
574
            if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
239✔
575
              if (snap_pref(J, T, map, nent, seen, irs->op2) == 0)
30✔
576
                snap_pref(J, T, map, nent, seen, T->ir[irs->op2].op1);
5✔
577
              else if ((LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) &&
578
                       irs+1 < irlast && (irs+1)->o == IR_HIOP)
579
                snap_pref(J, T, map, nent, seen, (irs+1)->op2);
580
            }
581
        }
582
      } else if (!irref_isk(refp) && !regsp_used(ir->prev)) {
1,379✔
583
        lj_assertJ(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
2✔
584
                   "sunk parent IR %04d has bad op %d", refp - REF_BIAS, ir->o);
585
        J->slot[snap_slot(sn)] = snap_pref(J, T, map, nent, seen, ir->op1);
2✔
586
      }
587
    }
588
    /* Replay sunk instructions. */
589
    for (n = 0; pass23 && n < nent; n++) {
3,591✔
590
      SnapEntry sn = map[n];
3,178✔
591
      IRRef refp = snap_ref(sn);
3,178✔
592
      IRIns *ir = &T->ir[refp];
3,178✔
593
      if (regsp_reg(ir->r) == RID_SUNK) {
3,178✔
594
        TRef op1, op2;
1,802✔
595
        uint8_t m;
1,802✔
596
        if (J->slot[snap_slot(sn)] != snap_slot(sn)) {  /* De-dup allocs. */
1,802✔
597
          J->slot[snap_slot(sn)] = J->slot[J->slot[snap_slot(sn)]];
×
598
          continue;
×
599
        }
600
        op1 = ir->op1;
1,802✔
601
        m = lj_ir_mode[ir->o];
1,802✔
602
        if (irm_op1(m) == IRMref) op1 = snap_pref(J, T, map, nent, seen, op1);
1,802✔
603
        op2 = ir->op2;
1,802✔
604
        if (irm_op2(m) == IRMref) op2 = snap_pref(J, T, map, nent, seen, op2);
1,802✔
605
        if (LJ_HASFFI && ir->o == IR_CNEWI) {
1,802✔
606
          if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP) {
1,787✔
607
            lj_needsplit(J);  /* Emit joining HIOP. */
608
            op2 = emitir_raw(IRT(IR_HIOP, IRT_I64), op2,
609
                             snap_pref(J, T, map, nent, seen, (ir+1)->op2));
610
          }
611
          J->slot[snap_slot(sn)] = emitir(ir->ot & ~(IRT_MARK|IRT_ISPHI), op1, op2);
1,787✔
612
        } else {
613
          IRIns *irs;
15✔
614
          TRef tr = emitir(ir->ot, op1, op2);
15✔
615
          J->slot[snap_slot(sn)] = tr;
15✔
616
          for (irs = ir+1; irs < irlast; irs++)
210✔
617
            if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
269✔
618
              IRIns *irr = &T->ir[irs->op1];
30✔
619
              TRef val, key = irr->op2, tmp = tr;
30✔
620
              if (irr->o != IR_FREF) {
30✔
621
                IRIns *irk = &T->ir[key];
29✔
622
                if (irr->o == IR_HREFK)
29✔
623
                  key = lj_ir_kslot(J, snap_replay_const(J, &T->ir[irk->op1]),
2✔
624
                                    irk->op2);
2✔
625
                else
626
                  key = snap_replay_const(J, irk);
27✔
627
                if (irr->o == IR_HREFK || irr->o == IR_AREF) {
29✔
628
                  IRIns *irf = &T->ir[irr->op1];
9✔
629
                  tmp = emitir(irf->ot, tmp, irf->op2);
9✔
630
                } else if (irr->o == IR_NEWREF) {
20✔
631
                  IRRef allocref = tref_ref(tr);
12✔
632
                  IRRef keyref = tref_ref(key);
12✔
633
                  IRRef newref_ref = J->chain[IR_NEWREF];
12✔
634
                  IRIns *newref = &J->cur.ir[newref_ref];
12✔
635
                  lj_assertJ(irref_isk(keyref),
12✔
636
                             "sunk store for parent IR %04d with bad key %04d",
637
                             refp - REF_BIAS, keyref - REF_BIAS);
638
                  if (newref_ref > allocref && newref->op2 == keyref) {
12✔
639
                    lj_assertJ(newref->op1 == allocref,
6✔
640
                               "sunk store for parent IR %04d with bad tab %04d",
641
                               refp - REF_BIAS, allocref - REF_BIAS);
642
                    tmp = newref_ref;
6✔
643
                    goto skip_newref;
6✔
644
                  }
645
                }
646
              }
647
              tmp = emitir(irr->ot, tmp, key);
24✔
648
            skip_newref:
30✔
649
              val = snap_pref(J, T, map, nent, seen, irs->op2);
30✔
650
              if (val == 0) {
30✔
651
                IRIns *irc = &T->ir[irs->op2];
5✔
652
                lj_assertJ(irc->o == IR_CONV && irc->op2 == IRCONV_NUM_INT,
5✔
653
                           "sunk store for parent IR %04d with bad op %d",
654
                           refp - REF_BIAS, irc->o);
655
                val = snap_pref(J, T, map, nent, seen, irc->op1);
5✔
656
                val = emitir(IRTN(IR_CONV), val, IRCONV_NUM_INT);
5✔
657
              } else if ((LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) &&
658
                         irs+1 < irlast && (irs+1)->o == IR_HIOP) {
659
                IRType t = IRT_I64;
660
                if (LJ_SOFTFP32 && irt_type((irs+1)->t) == IRT_SOFTFP)
661
                  t = IRT_NUM;
662
                lj_needsplit(J);
663
                if (irref_isk(irs->op2) && irref_isk((irs+1)->op2)) {
664
                  uint64_t k = (uint32_t)T->ir[irs->op2].i +
665
                               ((uint64_t)T->ir[(irs+1)->op2].i << 32);
666
                  val = lj_ir_k64(J, t == IRT_I64 ? IR_KINT64 : IR_KNUM, k);
667
                } else {
668
                  val = emitir_raw(IRT(IR_HIOP, t), val,
669
                          snap_pref(J, T, map, nent, seen, (irs+1)->op2));
670
                }
671
                tmp = emitir(IRT(irs->o, t), tmp, val);
672
                continue;
673
              }
674
              tmp = emitir(irs->ot, tmp, val);
30✔
675
            } else if (LJ_HASFFI && irs->o == IR_XBAR && ir->o == IR_CNEW) {
165✔
676
              emitir(IRT(IR_XBAR, IRT_NIL), 0, 0);
×
677
            }
678
        }
679
      }
680
    }
681
  }
682
  J->base = J->slot + J->baseslot;
16,929✔
683
  J->maxslot = snap->nslots - J->baseslot;
16,929✔
684
  lj_snap_add(J);
16,929✔
685
  if (pass23)  /* Need explicit GC step _after_ initial snapshot. */
16,929✔
686
    emitir_raw(IRTG(IR_GCSTEP, IRT_NIL), 0, 0);
412✔
687
}
16,929✔
688

689
/* -- Snapshot restore ---------------------------------------------------- */
690

691
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
692
                        SnapNo snapno, BloomFilter rfilt,
693
                        IRIns *ir, TValue *o);
694

695
/* Restore a value from the trace exit state. */
696
static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex,
894,472✔
697
                            SnapNo snapno, BloomFilter rfilt,
698
                            IRRef ref, TValue *o)
699
{
700
  IRIns *ir = &T->ir[ref];
894,542✔
701
  IRType1 t = ir->t;
894,542✔
702
  RegSP rs = ir->prev;
894,542✔
703
  if (irref_isk(ref)) {  /* Restore constant slot. */
894,542✔
704
    if (ir->o == IR_KPTR) {
586,477✔
705
      o->u64 = (uint64_t)(uintptr_t)ir_kptr(ir);
×
706
    } else {
707
      lj_assertJ(!(ir->o == IR_KKPTR || ir->o == IR_KNULL),
586,477✔
708
                 "restore of const from IR %04d with bad op %d",
709
                 ref - REF_BIAS, ir->o);
710
      lj_ir_kvalue(J->L, o, ir);
586,477✔
711
    }
712
    return;
586,477✔
713
  }
714
  if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
308,065✔
715
    rs = snap_renameref(T, snapno, ref, rs);
2,408✔
716
  if (ra_hasspill(regsp_spill(rs))) {  /* Restore from spill slot. */
308,065✔
717
    int32_t *sps = &ex->spill[regsp_spill(rs)];
47,692✔
718
    if (irt_isinteger(t)) {
47,692✔
719
      setintV(o, *sps);
397✔
720
#if !LJ_SOFTFP32
721
    } else if (irt_isnum(t)) {
47,295✔
722
      o->u64 = *(uint64_t *)sps;
20,730✔
723
#endif
724
#if LJ_64 && !LJ_GC64
725
    } else if (irt_islightud(t)) {
726
      /* 64 bit lightuserdata which may escape already has the tag bits. */
727
      o->u64 = *(uint64_t *)sps;
728
#endif
729
    } else {
730
      lj_assertJ(!irt_ispri(t), "PRI ref with spill slot");
26,565✔
731
      setgcV(J->L, o, (GCobj *)(uintptr_t)*(GCSize *)sps, irt_toitype(t));
26,565✔
732
    }
733
  } else {  /* Restore from register. */
734
    Reg r = regsp_reg(rs);
260,373✔
735
    if (ra_noreg(r)) {
260,373✔
736
      lj_assertJ(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
70✔
737
                 "restore from IR %04d has no reg", ref - REF_BIAS);
738
      snap_restoreval(J, T, ex, snapno, rfilt, ir->op1, o);
70✔
739
      if (LJ_DUALNUM) setnumV(o, (lua_Number)intV(o));
740
      return;
70✔
741
    } else if (irt_isinteger(t)) {
260,303✔
742
      setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]);
6,046✔
743
#if !LJ_SOFTFP
744
    } else if (irt_isnum(t)) {
254,257✔
745
      setnumV(o, ex->fpr[r-RID_MIN_FPR]);
66,795✔
746
#elif LJ_64  /* && LJ_SOFTFP */
747
    } else if (irt_isnum(t)) {
748
      o->u64 = ex->gpr[r-RID_MIN_GPR];
749
#endif
750
#if LJ_64 && !LJ_GC64
751
    } else if (irt_is64(t)) {
752
      /* 64 bit values that already have the tag bits. */
753
      o->u64 = ex->gpr[r-RID_MIN_GPR];
754
#endif
755
    } else if (irt_ispri(t)) {
187,462✔
756
      setpriV(o, irt_toitype(t));
×
757
    } else {
758
      setgcV(J->L, o, (GCobj *)ex->gpr[r-RID_MIN_GPR], irt_toitype(t));
187,462✔
759
    }
760
  }
761
}
762

763
#if LJ_HASFFI
764
/* Restore raw data from the trace exit state. */
765
static void snap_restoredata(jit_State *J, GCtrace *T, ExitState *ex,
4,888✔
766
                             SnapNo snapno, BloomFilter rfilt,
767
                             IRRef ref, void *dst, CTSize sz)
768
{
769
  IRIns *ir = &T->ir[ref];
4,888✔
770
  RegSP rs = ir->prev;
4,888✔
771
  int32_t *src;
4,888✔
772
  uint64_t tmp;
4,888✔
773
  UNUSED(J);
4,888✔
774
  if (irref_isk(ref)) {
4,888✔
775
    if (ir_isk64(ir)) {
8✔
776
      src = (int32_t *)&ir[1];
2✔
777
    } else if (sz == 8) {
6✔
778
      tmp = (uint64_t)(uint32_t)ir->i;
×
779
      src = (int32_t *)&tmp;
×
780
    } else {
781
      src = &ir->i;
6✔
782
    }
783
  } else {
784
    if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
4,880✔
785
      rs = snap_renameref(T, snapno, ref, rs);
×
786
    if (ra_hasspill(regsp_spill(rs))) {
4,880✔
787
      src = &ex->spill[regsp_spill(rs)];
818✔
788
      if (sz == 8 && !irt_is64(ir->t)) {
818✔
789
        tmp = (uint64_t)(uint32_t)*src;
×
790
        src = (int32_t *)&tmp;
×
791
      }
792
    } else {
793
      Reg r = regsp_reg(rs);
4,062✔
794
      if (ra_noreg(r)) {
4,062✔
795
        /* Note: this assumes CNEWI is never used for SOFTFP split numbers. */
796
        lj_assertJ(sz == 8 && ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
13✔
797
                   "restore from IR %04d has no reg", ref - REF_BIAS);
798
        snap_restoredata(J, T, ex, snapno, rfilt, ir->op1, dst, 4);
13✔
799
        *(lua_Number *)dst = (lua_Number)*(int32_t *)dst;
13✔
800
        return;
13✔
801
      }
802
#if !LJ_SOFTFP
803
      if (r >= RID_MAX_GPR) {
4,049✔
804
        src = (int32_t *)&ex->fpr[r-RID_MIN_FPR];
17✔
805
#if LJ_TARGET_PPC
806
        if (sz == 4) {  /* PPC FPRs are always doubles. */
807
          *(float *)dst = (float)*(double *)src;
808
          return;
809
        }
810
#else
811
        if (LJ_BE && sz == 4) src++;
17✔
812
#endif
813
      } else
814
#endif
815
      {
816
        src = (int32_t *)&ex->gpr[r-RID_MIN_GPR];
4,032✔
817
        if (LJ_64 && LJ_BE && sz == 4) src++;
4,032✔
818
      }
819
    }
820
  }
821
  lj_assertJ(sz == 1 || sz == 2 || sz == 4 || sz == 8,
4,875✔
822
             "restore from IR %04d with bad size %d", ref - REF_BIAS, sz);
823
  if (sz == 4) *(int32_t *)dst = *src;
4,875✔
824
  else if (sz == 8) *(int64_t *)dst = *(int64_t *)src;
4,816✔
825
  else if (sz == 1) *(int8_t *)dst = (int8_t)*src;
×
826
  else *(int16_t *)dst = (int16_t)*src;
×
827
}
828
#endif
829

830
/* Unsink allocation from the trace exit state. Unsink sunk stores. */
831
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
832
                        SnapNo snapno, BloomFilter rfilt,
833
                        IRIns *ir, TValue *o)
834
{
835
  lj_assertJ(ir->o == IR_TNEW || ir->o == IR_TDUP ||
836
             ir->o == IR_CNEW || ir->o == IR_CNEWI,
837
             "sunk allocation with bad op %d", ir->o);
838
#if LJ_HASFFI
839
  if (ir->o == IR_CNEW || ir->o == IR_CNEWI) {
840
    CTState *cts = ctype_cts(J->L);
841
    CTypeID id = (CTypeID)T->ir[ir->op1].i;
842
    CTSize sz;
843
    CTInfo info = lj_ctype_info(cts, id, &sz);
844
    GCcdata *cd = lj_cdata_newx(cts, id, sz, info);
845
    setcdataV(J->L, o, cd);
846
    if (ir->o == IR_CNEWI) {
847
      uint8_t *p = (uint8_t *)cdataptr(cd);
848
      lj_assertJ(sz == 4 || sz == 8, "sunk cdata with bad size %d", sz);
849
      if (LJ_32 && sz == 8 && ir+1 < T->ir + T->nins && (ir+1)->o == IR_HIOP) {
850
        snap_restoredata(J, T, ex, snapno, rfilt, (ir+1)->op2,
851
                         LJ_LE ? p+4 : p, 4);
852
        if (LJ_BE) p += 4;
853
        sz = 4;
854
      }
855
      snap_restoredata(J, T, ex, snapno, rfilt, ir->op2, p, sz);
856
    } else {
857
      IRIns *irs, *irlast = &T->ir[T->snap[snapno].ref];
858
      for (irs = ir+1; irs < irlast; irs++)
859
        if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
860
          IRIns *iro = &T->ir[T->ir[irs->op1].op2];
861
          uint8_t *p = (uint8_t *)cd;
862
          CTSize szs;
863
          lj_assertJ(irs->o == IR_XSTORE, "sunk store with bad op %d", irs->o);
864
          lj_assertJ(T->ir[irs->op1].o == IR_ADD,
865
                     "sunk store with bad add op %d", T->ir[irs->op1].o);
866
          lj_assertJ(iro->o == IR_KINT || iro->o == IR_KINT64,
867
                     "sunk store with bad const offset op %d", iro->o);
868
          if (irt_is64(irs->t)) szs = 8;
869
          else if (irt_isi8(irs->t) || irt_isu8(irs->t)) szs = 1;
870
          else if (irt_isi16(irs->t) || irt_isu16(irs->t)) szs = 2;
871
          else szs = 4;
872
          if (LJ_64 && iro->o == IR_KINT64)
873
            p += (int64_t)ir_k64(iro)->u64;
874
          else
875
            p += iro->i;
876
          lj_assertJ(p >= (uint8_t *)cdataptr(cd) &&
877
                     p + szs <= (uint8_t *)cdataptr(cd) + sz,
878
                     "sunk store with offset out of range");
879
          if (LJ_32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) {
880
            lj_assertJ(szs == 4, "sunk store with bad size %d", szs);
881
            snap_restoredata(J, T, ex, snapno, rfilt, (irs+1)->op2,
882
                             LJ_LE ? p+4 : p, 4);
883
            if (LJ_BE) p += 4;
884
          }
885
          snap_restoredata(J, T, ex, snapno, rfilt, irs->op2, p, szs);
886
        }
887
    }
888
  } else
889
#endif
890
  {
891
    IRIns *irs, *irlast;
892
    GCtab *t = ir->o == IR_TNEW ? lj_tab_new(J->L, ir->op1, ir->op2) :
893
                                  lj_tab_dup(J->L, ir_ktab(&T->ir[ir->op1]));
894
    settabV(J->L, o, t);
895
    irlast = &T->ir[T->snap[snapno].ref];
896
    for (irs = ir+1; irs < irlast; irs++)
897
      if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
898
        IRIns *irk = &T->ir[irs->op1];
899
        TValue tmp, *val;
900
        lj_assertJ(irs->o == IR_ASTORE || irs->o == IR_HSTORE ||
901
                   irs->o == IR_FSTORE,
902
                   "sunk store with bad op %d", irs->o);
903
        if (irk->o == IR_FREF) {
904
          switch (irk->op2) {
905
          case IRFL_TAB_META:
906
            if (T->ir[irs->op2].o == IR_KNULL) {
907
              setgcrefnull(t->metatable);
908
            } else {
909
              snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp);
910
              /* NOBARRIER: The table is new (marked white). */
911
              setgcref(t->metatable, obj2gco(tabV(&tmp)));
912
            }
913
            break;
914
          case IRFL_TAB_NOMM:
915
            /* Negative metamethod cache invalidated by lj_tab_set() below. */
916
            break;
917
          default:
918
            lj_assertJ(0, "sunk store with bad field %d", irk->op2);
919
            break;
920
          }
921
        } else {
922
          irk = &T->ir[irk->op2];
923
          if (irk->o == IR_KSLOT) irk = &T->ir[irk->op1];
924
          lj_ir_kvalue(J->L, &tmp, irk);
925
          val = lj_tab_set(J->L, t, &tmp);
926
          /* NOBARRIER: The table is new (marked white). */
927
          snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, val);
928
          if (LJ_SOFTFP32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) {
929
            snap_restoreval(J, T, ex, snapno, rfilt, (irs+1)->op2, &tmp);
930
            val->u32.hi = tmp.u32.lo;
931
          }
932
        }
933
      }
934
  }
935
}
936

937
/* Restore interpreter state from exit state with the help of a snapshot. */
938
const BCIns *lj_snap_restore(jit_State *J, void *exptr)
245,258✔
939
{
940
  ExitState *ex = (ExitState *)exptr;
245,258✔
941
  SnapNo snapno = J->exitno;  /* For now, snapno == exitno. */
245,258✔
942
  GCtrace *T = traceref(J, J->parent);
245,258✔
943
  SnapShot *snap = &T->snap[snapno];
245,258✔
944
  MSize n, nent = snap->nent;
245,258✔
945
  SnapEntry *map = &T->snapmap[snap->mapofs];
245,258✔
946
#if !LJ_FR2 || defined(LUA_USE_ASSERT)
947
  SnapEntry *flinks = &T->snapmap[snap_nextofs(T, snap)-1-LJ_FR2];
948
#endif
949
#if !LJ_FR2
950
  ptrdiff_t ftsz0;
951
#endif
952
  TValue *frame;
245,258✔
953
  BloomFilter rfilt = snap_renamefilter(T, snapno);
245,258✔
954
  const BCIns *pc = snap_pc(&map[nent]);
245,258✔
955
  lua_State *L = J->L;
245,258✔
956

957
  /* Set interpreter PC to the next PC to get correct error messages. */
958
  setcframe_pc(cframe_raw(L->cframe), pc+1);
245,258✔
959

960
  /* Make sure the stack is big enough for the slots from the snapshot. */
961
  if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) {
245,258✔
962
    L->top = curr_topL(L);
49✔
963
    lj_state_growstack(L, snap->topslot - curr_proto(L)->framesize);
49✔
964
  }
965

966
  /* Fill stack slots with data from the registers and spill slots. */
967
  frame = L->base-1-LJ_FR2;
245,253✔
968
#if !LJ_FR2
969
  ftsz0 = frame_ftsz(frame);  /* Preserve link to previous frame in slot #0. */
970
#endif
971
  for (n = 0; n < nent; n++) {
1,204,051✔
972
    SnapEntry sn = map[n];
958,798✔
973
    if (!(sn & SNAP_NORESTORE)) {
958,798✔
974
      TValue *o = &frame[snap_slot(sn)];
899,185✔
975
      IRRef ref = snap_ref(sn);
899,185✔
976
      IRIns *ir = &T->ir[ref];
899,185✔
977
      if (ir->r == RID_SUNK) {
899,185✔
978
        MSize j;
979
        for (j = 0; j < n; j++)
36,640✔
980
          if (snap_ref(map[j]) == ref) {  /* De-duplicate sunk allocations. */
31,708✔
981
            copyTV(L, o, &frame[snap_slot(map[j])]);
11✔
982
            goto dupslot;
11✔
983
          }
984
        snap_unsink(J, T, ex, snapno, rfilt, ir, o);
4,932✔
985
      dupslot:
4,943✔
986
        continue;
4,943✔
987
      }
988
      snap_restoreval(J, T, ex, snapno, rfilt, ref, o);
894,242✔
989
      if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM) && tvisint(o)) {
894,242✔
990
        TValue tmp;
991
        snap_restoreval(J, T, ex, snapno, rfilt, ref+1, &tmp);
992
        o->u32.hi = tmp.u32.lo;
993
#if !LJ_FR2
994
      } else if ((sn & (SNAP_CONT|SNAP_FRAME))) {
995
        /* Overwrite tag with frame link. */
996
        setframe_ftsz(o, snap_slot(sn) != 0 ? (int32_t)*flinks-- : ftsz0);
997
        L->base = o+1;
998
#endif
999
      }
1000
    }
1001
  }
1002
#if LJ_FR2
1003
  L->base += (map[nent+LJ_BE] & 0xff);
245,253✔
1004
#endif
1005
  lj_assertJ(map + nent == flinks, "inconsistent frames in snapshot");
245,253✔
1006

1007
  /* Compute current stack top. */
1008
  switch (bc_op(*pc)) {
245,253✔
1009
  default:
244,373✔
1010
    if (bc_op(*pc) < BC_FUNCF) {
244,373✔
1011
      L->top = curr_topL(L);
244,357✔
1012
      break;
244,357✔
1013
    }
1014
    /* fallthrough */
1015
  case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM:
1016
    L->top = frame + snap->nslots;
896✔
1017
    break;
896✔
1018
  }
1019
  J->nsnaprestore++;
245,253✔
1020
  return pc;
245,253✔
1021
}
1022

1023
#undef emitir_raw
1024
#undef emitir
1025

1026
#endif
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