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

tarantool / luajit / 7119513137

06 Dec 2023 07:37PM UTC coverage: 88.514% (+0.05%) from 88.469%
7119513137

push

github

igormunkin
Fix snapshot PC when linking to BC_JLOOP that was a BC_RET*.

Reported by Arseny Vakhrushev.
Fix contributed by Peter Cawley.

(cherry-picked from commit 5c46f4773)

As specified in the comment in `lj_record_stop`, all loops must
set `J->pc` to the next instruction. However, the chunk of logic
in `lj_trace_exit` expects it to be set to `BC_JLOOP` itself if
it used to be a `BC_RET`. This wrong pc results in the execution
of random data that goes after `BC_JLOOP` in the case of
restoration from the snapshot.

This patch fixes that behavior by adapting the loop recording
logic to this specific case.

NOTICE: This patch is only a part of the original commit,
and the other part is backported in the previous commit. The
patch was split into two, so the test case becomes easier to
implement since it can now depend on this assertion instead
of memory layout.

Maxim Kokryashkin:
* added the description and the test for the problem

Part of tarantool/tarantool#9145

Reviewed-by: Sergey Kaplun <skaplun@tarantool.org>
Reviewed-by: Sergey Bronnikov <sergeyb@tarantool.org>
Signed-off-by: Igor Munkin <imun@tarantool.org>
(cherry picked from commit 2ab0419fa)

5352 of 5969 branches covered (0.0%)

Branch coverage included in aggregate %.

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

26 existing lines in 5 files now uncovered.

20526 of 23267 relevant lines covered (88.22%)

694532.67 hits per line

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

97.11
/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)
135✔
39
{
40
  MSize maxsnap = (MSize)J->param[JIT_P_maxsnap];
135✔
41
  if (need > maxsnap)
135✔
42
    lj_trace_err(J, LJ_TRERR_SNAPOV);
×
43
  lj_mem_growvec(J->L, J->snapbuf, J->sizesnap, maxsnap, SnapShot);
135✔
44
  J->cur.snap = J->snapbuf;
135✔
45
}
135✔
46

47
/* Grow snapshot map buffer. */
48
void lj_snap_grow_map_(jit_State *J, MSize need)
138✔
49
{
50
  if (need < 2*J->sizesnapmap)
138✔
51
    need = 2*J->sizesnapmap;
52
  else if (need < 64)
90✔
53
    need = 64;
54
  J->snapmapbuf = (SnapEntry *)lj_mem_realloc(J->L, J->snapmapbuf,
276✔
55
                    J->sizesnapmap*sizeof(SnapEntry), need*sizeof(SnapEntry));
138✔
56
  J->cur.snapmap = J->snapmapbuf;
138✔
57
  J->sizesnapmap = need;
138✔
58
}
138✔
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)
93,287✔
64
{
65
  IRRef retf = J->chain[IR_RETF];  /* Limits SLOAD restore elimination. */
93,287✔
66
  BCReg s;
93,287✔
67
  MSize n = 0;
93,287✔
68
  for (s = 0; s < nslots; s++) {
1,021,822✔
69
    TRef tr = J->slot[s];
928,535✔
70
    IRRef ref = tref_ref(tr);
928,535✔
71
#if LJ_FR2
72
    if (s == 1) {  /* Ignore slot 1 in LJ_FR2 mode, except if tailcalled. */
928,535✔
73
      if ((tr & TREF_FRAME))
93,287✔
74
        map[n++] = SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL);
18,319✔
75
      continue;
93,287✔
76
    }
77
    if ((tr & (TREF_FRAME | TREF_CONT)) && !ref) {
835,248✔
78
      cTValue *base = J->L->base - J->baseslot;
10,586✔
79
      tr = J->slot[s] = (tr & 0xff0000) | lj_ir_k64(J, IR_KNUM, base[s].u64);
10,586✔
80
      ref = tref_ref(tr);
10,586✔
81
    }
82
#endif
83
    if (ref) {
835,248✔
84
      SnapEntry sn = SNAP_TR(s, tr);
468,423✔
85
      IRIns *ir = &J->cur.ir[ref];
468,423✔
86
      if ((LJ_FR2 || !(sn & (SNAP_CONT|SNAP_FRAME))) &&
468,423✔
87
          ir->o == IR_SLOAD && ir->op1 == s && ref > retf) {
468,423✔
88
        /* No need to snapshot unmodified non-inherited slots. */
89
        if (!(ir->op2 & IRSLOAD_INHERIT))
249,322✔
90
          continue;
196,866✔
91
        /* No need to restore readonly slots and unmodified non-parent slots. */
92
        if (!(LJ_DUALNUM && (ir->op2 & IRSLOAD_CONVERT)) &&
52,456✔
93
            (ir->op2 & (IRSLOAD_READONLY|IRSLOAD_PARENT)) != IRSLOAD_PARENT)
94
          sn |= SNAP_NORESTORE;
40,635✔
95
      }
96
      if (LJ_SOFTFP32 && irt_isnum(ir->t))
271,557✔
97
        sn |= SNAP_SOFTFPNUM;
98
      map[n++] = sn;
271,557✔
99
    }
100
  }
101
  return n;
93,287✔
102
}
103

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

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

174
/* Add or merge a snapshot. */
175
void lj_snap_add(jit_State *J)
93,287✔
176
{
177
  MSize nsnap = J->cur.nsnap;
93,287✔
178
  MSize nsnapmap = J->cur.nsnapmap;
93,287✔
179
  /* Merge if no ins. inbetween or if requested and no guard inbetween. */
180
  if ((nsnap > 0 && J->cur.snap[nsnap-1].ref == J->cur.nins) ||
93,287✔
181
      (J->mergesnap && !irt_isguard(J->guardemit))) {
79,236✔
182
    if (nsnap == 1) {  /* But preserve snap #0 PC. */
17,938✔
183
      emitir_raw(IRT(IR_NOP, IRT_NIL), 0, 0);
563✔
184
      goto nomerge;
563✔
185
    }
186
    nsnapmap = J->cur.snap[--nsnap].mapofs;
17,375✔
187
  } else {
188
  nomerge:
75,349✔
189
    lj_snap_grow_buf(J, nsnap+1);
75,912✔
190
    J->cur.nsnap = (uint16_t)(nsnap+1);
75,912✔
191
  }
192
  J->mergesnap = 0;
93,287✔
193
  J->guardemit.irt = 0;
93,287✔
194
  snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap);
93,287✔
195
}
93,287✔
196

197
/* -- Snapshot modification ----------------------------------------------- */
198

199
#define SNAP_USEDEF_SLOTS        (LJ_MAX_JSLOTS+LJ_STACK_EXTRA)
200

201
/* Find unused slots with reaching-definitions bytecode data-flow analysis. */
202
static BCReg snap_usedef(jit_State *J, uint8_t *udf,
203
                         const BCIns *pc, BCReg maxslot)
204
{
205
  BCReg s;
206
  GCobj *o;
207

208
  if (maxslot == 0) return 0;
209
#ifdef LUAJIT_USE_VALGRIND
210
  /* Avoid errors for harmless reads beyond maxslot. */
211
  memset(udf, 1, SNAP_USEDEF_SLOTS);
212
#else
213
  memset(udf, 1, maxslot);
214
#endif
215

216
  /* Treat open upvalues as used. */
217
  o = gcref(J->L->openupval);
218
  while (o) {
219
    if (uvval(gco2uv(o)) < J->L->base) break;
220
    udf[uvval(gco2uv(o)) - J->L->base] = 0;
221
    o = gcref(o->gch.nextgc);
222
  }
223

224
#define USE_SLOT(s)                udf[(s)] &= ~1
225
#define DEF_SLOT(s)                udf[(s)] *= 3
226

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

298
#undef USE_SLOT
299
#undef DEF_SLOT
300

301
  return 0;  /* unreachable */
302
}
303

304
/* Purge dead slots before the next snapshot. */
305
void lj_snap_purge(jit_State *J)
64,714✔
306
{
307
  uint8_t udf[SNAP_USEDEF_SLOTS];
64,714✔
308
  BCReg s, maxslot = J->maxslot;
64,714✔
309
  if (bc_op(*J->pc) == BC_FUNCV && maxslot > J->pt->numparams)
64,714✔
310
    maxslot = J->pt->numparams;
311
  s = snap_usedef(J, udf, J->pc, maxslot);
64,714✔
312
  for (; s < maxslot; s++)
245,950✔
313
    if (udf[s] != 0)
116,522✔
314
      J->base[s] = 0;  /* Purge dead slots. */
100,582✔
315
}
64,714✔
316

317
/* Shrink last snapshot. */
318
void lj_snap_shrink(jit_State *J)
11,435✔
319
{
320
  SnapShot *snap = &J->cur.snap[J->cur.nsnap-1];
11,435✔
321
  SnapEntry *map = &J->cur.snapmap[snap->mapofs];
11,435✔
322
  MSize n, m, nlim, nent = snap->nent;
11,435✔
323
  uint8_t udf[SNAP_USEDEF_SLOTS];
11,435✔
324
  BCReg maxslot = J->maxslot;
11,435✔
325
  BCReg baseslot = J->baseslot;
11,435✔
326
  BCReg minslot = snap_usedef(J, udf, snap_pc(&map[nent]), maxslot);
11,435✔
327
  maxslot += baseslot;
11,435✔
328
  minslot += baseslot;
11,435✔
329
  snap->nslots = (uint8_t)maxslot;
11,435✔
330
  for (n = m = 0; n < nent; n++) {  /* Remove unused slots from snapshot. */
89,746✔
331
    BCReg s = snap_slot(map[n]);
78,311✔
332
    if (s < minslot || (s < maxslot && udf[s-baseslot] == 0))
78,311✔
333
      map[m++] = map[n];  /* Only copy used slots. */
66,634✔
334
  }
335
  snap->nent = (uint8_t)m;
11,435✔
336
  nlim = J->cur.nsnapmap - snap->mapofs - 1;
11,435✔
337
  while (n <= nlim) map[m++] = map[n++];  /* Move PC + frame links down. */
34,305✔
338
  J->cur.nsnapmap = (uint32_t)(snap->mapofs + m);  /* Free up space in map. */
11,435✔
339
}
11,435✔
340

341
/* -- Snapshot access ----------------------------------------------------- */
342

343
/* Initialize a Bloom Filter with all renamed refs.
344
** There are very few renames (often none), so the filter has
345
** very few bits set. This makes it suitable for negative filtering.
346
*/
347
static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim)
33,566✔
348
{
349
  BloomFilter rfilt = 0;
33,566✔
350
  IRIns *ir;
33,566✔
351
  for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
35,575✔
352
    if (ir->op2 <= lim)
2,009✔
353
      bloomset(rfilt, ir->op1);
1,111✔
354
  return rfilt;
30,383✔
355
}
356

357
/* Process matching renames to find the original RegSP. */
358
static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs)
814✔
359
{
360
  IRIns *ir;
814✔
361
  for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
3,961✔
362
    if (ir->op1 == ref && ir->op2 <= lim)
3,147✔
363
      rs = ir->prev;
867✔
364
  return rs;
365
}
366

367
/* Copy RegSP from parent snapshot to the parent links of the IR. */
368
IRIns *lj_snap_regspmap(jit_State *J, GCtrace *T, SnapNo snapno, IRIns *ir)
3,183✔
369
{
370
  SnapShot *snap = &T->snap[snapno];
3,183✔
371
  SnapEntry *map = &T->snapmap[snap->mapofs];
3,183✔
372
  BloomFilter rfilt = snap_renamefilter(T, snapno);
3,183✔
373
  MSize n = 0;
374
  IRRef ref = 0;
9,208✔
375
  UNUSED(J);
9,208✔
376
  for ( ; ; ir++) {
15,233✔
377
    uint32_t rs;
9,208✔
378
    if (ir->o == IR_SLOAD) {
9,208✔
379
      if (!(ir->op2 & IRSLOAD_PARENT)) break;
6,038✔
380
      for ( ; ; n++) {
18,480✔
381
        lj_assertJ(n < snap->nent, "slot %d not found in snapshot", ir->op1);
6,987✔
382
        if (snap_slot(map[n]) == ir->op1) {
11,493✔
383
          ref = snap_ref(map[n++]);
4,506✔
384
          break;
4,506✔
385
        }
386
      }
387
    } else if (LJ_SOFTFP32 && ir->o == IR_HIOP) {
3,170✔
388
      ref++;
389
    } else if (ir->o == IR_PVAL) {
3,170✔
390
      ref = ir->op1 + REF_BIAS;
1,519✔
391
    } else {
392
      break;
393
    }
394
    rs = T->ir[ref].prev;
6,025✔
395
    if (bloomtest(rfilt, ref))
6,025✔
396
      rs = snap_renameref(T, snapno, ref, rs);
41✔
397
    ir->prev = (uint16_t)rs;
6,025✔
398
    lj_assertJ(regsp_used(rs), "unused IR %04d in snapshot", ref - REF_BIAS);
6,025✔
399
  }
400
  return ir;
3,183✔
401
}
402

403
/* -- Snapshot replay ----------------------------------------------------- */
404

405
/* Replay constant from parent trace. */
406
static TRef snap_replay_const(jit_State *J, IRIns *ir)
9,200✔
407
{
408
  /* Only have to deal with constants that can occur in stack slots. */
409
  switch ((IROp)ir->o) {
9,200✔
410
  case IR_KPRI: return TREF_PRI(irt_type(ir->t));
49✔
411
  case IR_KINT: return lj_ir_kint(J, ir->i);
3,211✔
412
  case IR_KGC: return lj_ir_kgc(J, ir_kgc(ir), irt_t(ir->t));
3,952✔
413
  case IR_KNUM: case IR_KINT64:
1,988✔
414
    return lj_ir_k64(J, (IROp)ir->o, ir_k64(ir)->u64);
1,988✔
UNCOV
415
  case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir));  /* Continuation. */
×
416
  default: lj_assertJ(0, "bad IR constant op %d", ir->o); return TREF_NIL;
417
  }
418
}
419

420
/* De-duplicate parent reference. */
421
static TRef snap_dedup(jit_State *J, SnapEntry *map, MSize nmax, IRRef ref)
422
{
423
  MSize j;
424
  for (j = 0; j < nmax; j++)
8,640✔
425
    if (snap_ref(map[j]) == ref)
8,383✔
426
      return J->slot[snap_slot(map[j])] & ~(SNAP_CONT|SNAP_FRAME);
637✔
427
  return 0;
428
}
429

430
/* Emit parent reference with de-duplication. */
431
static TRef snap_pref(jit_State *J, GCtrace *T, SnapEntry *map, MSize nmax,
432
                      BloomFilter seen, IRRef ref)
433
{
434
  IRIns *ir = &T->ir[ref];
435
  TRef tr;
436
  if (irref_isk(ref))
437
    tr = snap_replay_const(J, ir);
438
  else if (!regsp_used(ir->prev))
439
    tr = 0;
440
  else if (!bloomtest(seen, ref) || (tr = snap_dedup(J, map, nmax, ref)) == 0)
441
    tr = emitir(IRT(IR_PVAL, irt_type(ir->t)), ref - REF_BIAS, 0);
442
  return tr;
443
}
444

445
/* Check whether a sunk store corresponds to an allocation. Slow path. */
446
static int snap_sunk_store2(GCtrace *T, IRIns *ira, IRIns *irs)
447
{
448
  if (irs->o == IR_ASTORE || irs->o == IR_HSTORE ||
449
      irs->o == IR_FSTORE || irs->o == IR_XSTORE) {
450
    IRIns *irk = &T->ir[irs->op1];
451
    if (irk->o == IR_AREF || irk->o == IR_HREFK)
452
      irk = &T->ir[irk->op1];
453
    return (&T->ir[irk->op1] == ira);
454
  }
455
  return 0;
456
}
457

458
/* Check whether a sunk store corresponds to an allocation. Fast path. */
459
static LJ_AINLINE int snap_sunk_store(GCtrace *T, IRIns *ira, IRIns *irs)
54✔
460
{
461
  if (irs->s != 255)
54✔
462
    return (ira + irs->s == irs);  /* Fast check. */
54✔
UNCOV
463
  return snap_sunk_store2(T, ira, irs);
×
464
}
465

466
/* Replay snapshot state to setup side trace. */
467
void lj_snap_replay(jit_State *J, GCtrace *T)
3,007✔
468
{
469
  SnapShot *snap = &T->snap[J->exitno];
3,007✔
470
  SnapEntry *map = &T->snapmap[snap->mapofs];
3,007✔
471
  MSize n, nent = snap->nent;
3,007✔
472
  BloomFilter seen = 0;
3,007✔
473
  int pass23 = 0;
3,007✔
474
  J->framedepth = 0;
3,007✔
475
  /* Emit IR for slots inherited from parent snapshot. */
476
  for (n = 0; n < nent; n++) {
16,220✔
477
    SnapEntry sn = map[n];
13,213✔
478
    BCReg s = snap_slot(sn);
13,213✔
479
    IRRef ref = snap_ref(sn);
13,213✔
480
    IRIns *ir = &T->ir[ref];
13,213✔
481
    TRef tr;
13,213✔
482
    /* The bloom filter avoids O(nent^2) overhead for de-duping slots. */
483
    if (bloomtest(seen, ref) && (tr = snap_dedup(J, map, n, ref)) != 0)
14,107✔
484
      goto setslot;
637✔
485
    bloomset(seen, ref);
12,576✔
486
    if (irref_isk(ref)) {
12,576✔
487
      /* See special treatment of LJ_FR2 slot 1 in snapshot_slots() above. */
488
      if (LJ_FR2 && (sn == SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)))
6,452✔
489
        tr = 0;
490
      else
491
        tr = snap_replay_const(J, ir);
6,152✔
492
    } else if (!regsp_used(ir->prev)) {
6,124✔
493
      pass23 = 1;
494
      lj_assertJ(s != 0, "unused slot 0 in snapshot");
495
      tr = s;
496
    } else {
497
      IRType t = irt_type(ir->t);
4,605✔
498
      uint32_t mode = IRSLOAD_INHERIT|IRSLOAD_PARENT;
4,605✔
499
      if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM)) t = IRT_NUM;
4,605✔
500
      if (ir->o == IR_SLOAD) mode |= (ir->op2 & IRSLOAD_READONLY);
4,605✔
501
      tr = emitir_raw(IRT(IR_SLOAD, t), s, mode);
4,605✔
502
    }
503
  setslot:
13,213✔
504
    J->slot[s] = tr | (sn&(SNAP_CONT|SNAP_FRAME));  /* Same as TREF_* flags. */
13,213✔
505
    J->framedepth += ((sn & (SNAP_CONT|SNAP_FRAME)) && (s != LJ_FR2));
13,213✔
506
    if ((sn & SNAP_FRAME))
13,213✔
507
      J->baseslot = s+1;
2,311✔
508
  }
509
  if (pass23) {
3,007✔
510
    IRIns *irlast = &T->ir[snap->ref];
128✔
511
    pass23 = 0;
128✔
512
    /* Emit dependent PVALs. */
513
    for (n = 0; n < nent; n++) {
2,603✔
514
      SnapEntry sn = map[n];
2,475✔
515
      IRRef refp = snap_ref(sn);
2,475✔
516
      IRIns *ir = &T->ir[refp];
2,475✔
517
      if (regsp_reg(ir->r) == RID_SUNK) {
2,475✔
518
        if (J->slot[snap_slot(sn)] != snap_slot(sn)) continue;
1,518✔
519
        pass23 = 1;
1,517✔
520
        lj_assertJ(ir->o == IR_TNEW || ir->o == IR_TDUP ||
1,517✔
521
                   ir->o == IR_CNEW || ir->o == IR_CNEWI,
522
                   "sunk parent IR %04d has bad op %d", refp - REF_BIAS, ir->o);
523
        if (ir->op1 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op1);
1,517✔
524
        if (ir->op2 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op2);
1,517✔
525
        if (LJ_HASFFI && ir->o == IR_CNEWI) {
1,517✔
526
          if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP)
527
            snap_pref(J, T, map, nent, seen, (ir+1)->op2);
528
        } else {
529
          IRIns *irs;
11✔
530
          for (irs = ir+1; irs < irlast; irs++)
182✔
531
            if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
198✔
532
              if (snap_pref(J, T, map, nent, seen, irs->op2) == 0)
19✔
533
                snap_pref(J, T, map, nent, seen, T->ir[irs->op2].op1);
6✔
534
              else if ((LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) &&
535
                       irs+1 < irlast && (irs+1)->o == IR_HIOP)
536
                snap_pref(J, T, map, nent, seen, (irs+1)->op2);
537
            }
538
        }
539
      } else if (!irref_isk(refp) && !regsp_used(ir->prev)) {
957✔
540
        lj_assertJ(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
2✔
541
                   "sunk parent IR %04d has bad op %d", refp - REF_BIAS, ir->o);
542
        J->slot[snap_slot(sn)] = snap_pref(J, T, map, nent, seen, ir->op1);
2✔
543
      }
544
    }
545
    /* Replay sunk instructions. */
546
    for (n = 0; pass23 && n < nent; n++) {
2,600✔
547
      SnapEntry sn = map[n];
2,472✔
548
      IRRef refp = snap_ref(sn);
2,472✔
549
      IRIns *ir = &T->ir[refp];
2,472✔
550
      if (regsp_reg(ir->r) == RID_SUNK) {
2,472✔
551
        TRef op1, op2;
1,518✔
552
        if (J->slot[snap_slot(sn)] != snap_slot(sn)) {  /* De-dup allocs. */
1,518✔
553
          J->slot[snap_slot(sn)] = J->slot[J->slot[snap_slot(sn)]];
1✔
554
          continue;
1✔
555
        }
556
        op1 = ir->op1;
1,517✔
557
        if (op1 >= T->nk) op1 = snap_pref(J, T, map, nent, seen, op1);
1,517✔
558
        op2 = ir->op2;
1,517✔
559
        if (op2 >= T->nk) op2 = snap_pref(J, T, map, nent, seen, op2);
1,517✔
560
        if (LJ_HASFFI && ir->o == IR_CNEWI) {
1,517✔
561
          if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP) {
1,506✔
562
            lj_needsplit(J);  /* Emit joining HIOP. */
563
            op2 = emitir_raw(IRT(IR_HIOP, IRT_I64), op2,
564
                             snap_pref(J, T, map, nent, seen, (ir+1)->op2));
565
          }
566
          J->slot[snap_slot(sn)] = emitir(ir->ot & ~(IRT_MARK|IRT_ISPHI), op1, op2);
1,506✔
567
        } else {
568
          IRIns *irs;
11✔
569
          TRef tr = emitir(ir->ot, op1, op2);
11✔
570
          J->slot[snap_slot(sn)] = tr;
11✔
571
          for (irs = ir+1; irs < irlast; irs++)
182✔
572
            if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
217✔
573
              IRIns *irr = &T->ir[irs->op1];
19✔
574
              TRef val, key = irr->op2, tmp = tr;
19✔
575
              if (irr->o != IR_FREF) {
19✔
576
                IRIns *irk = &T->ir[key];
18✔
577
                if (irr->o == IR_HREFK)
18✔
578
                  key = lj_ir_kslot(J, snap_replay_const(J, &T->ir[irk->op1]),
2✔
579
                                    irk->op2);
2✔
580
                else
581
                  key = snap_replay_const(J, irk);
16✔
582
                if (irr->o == IR_HREFK || irr->o == IR_AREF) {
18✔
583
                  IRIns *irf = &T->ir[irr->op1];
10✔
584
                  tmp = emitir(irf->ot, tmp, irf->op2);
10✔
585
                }
586
              }
587
              tmp = emitir(irr->ot, tmp, key);
19✔
588
              val = snap_pref(J, T, map, nent, seen, irs->op2);
19✔
589
              if (val == 0) {
19✔
590
                IRIns *irc = &T->ir[irs->op2];
6✔
591
                lj_assertJ(irc->o == IR_CONV && irc->op2 == IRCONV_NUM_INT,
6✔
592
                           "sunk store for parent IR %04d with bad op %d",
593
                           refp - REF_BIAS, irc->o);
594
                val = snap_pref(J, T, map, nent, seen, irc->op1);
6✔
595
                val = emitir(IRTN(IR_CONV), val, IRCONV_NUM_INT);
6✔
596
              } else if ((LJ_SOFTFP32 || (LJ_32 && LJ_HASFFI)) &&
597
                         irs+1 < irlast && (irs+1)->o == IR_HIOP) {
598
                IRType t = IRT_I64;
599
                if (LJ_SOFTFP32 && irt_type((irs+1)->t) == IRT_SOFTFP)
600
                  t = IRT_NUM;
601
                lj_needsplit(J);
602
                if (irref_isk(irs->op2) && irref_isk((irs+1)->op2)) {
603
                  uint64_t k = (uint32_t)T->ir[irs->op2].i +
604
                               ((uint64_t)T->ir[(irs+1)->op2].i << 32);
605
                  val = lj_ir_k64(J, t == IRT_I64 ? IR_KINT64 : IR_KNUM, k);
606
                } else {
607
                  val = emitir_raw(IRT(IR_HIOP, t), val,
608
                          snap_pref(J, T, map, nent, seen, (irs+1)->op2));
609
                }
610
                tmp = emitir(IRT(irs->o, t), tmp, val);
611
                continue;
612
              }
613
              tmp = emitir(irs->ot, tmp, val);
19✔
614
            } else if (LJ_HASFFI && irs->o == IR_XBAR && ir->o == IR_CNEW) {
152✔
UNCOV
615
              emitir(IRT(IR_XBAR, IRT_NIL), 0, 0);
×
616
            }
617
        }
618
      }
619
    }
620
  }
621
  J->base = J->slot + J->baseslot;
3,007✔
622
  J->maxslot = snap->nslots - J->baseslot;
3,007✔
623
  lj_snap_add(J);
3,007✔
624
  if (pass23)  /* Need explicit GC step _after_ initial snapshot. */
3,007✔
625
    emitir_raw(IRTG(IR_GCSTEP, IRT_NIL), 0, 0);
127✔
626
}
3,007✔
627

628
/* -- Snapshot restore ---------------------------------------------------- */
629

630
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
631
                        SnapNo snapno, BloomFilter rfilt,
632
                        IRIns *ir, TValue *o);
633

634
/* Restore a value from the trace exit state. */
635
static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex,
129,829✔
636
                            SnapNo snapno, BloomFilter rfilt,
637
                            IRRef ref, TValue *o)
638
{
639
  IRIns *ir = &T->ir[ref];
129,909✔
640
  IRType1 t = ir->t;
129,909✔
641
  RegSP rs = ir->prev;
129,909✔
642
  if (irref_isk(ref)) {  /* Restore constant slot. */
129,909✔
643
    if (ir->o == IR_KPTR) {
78,366✔
UNCOV
644
      o->u64 = (uint64_t)(uintptr_t)ir_kptr(ir);
×
645
    } else {
646
      lj_assertJ(!(ir->o == IR_KKPTR || ir->o == IR_KNULL),
78,366✔
647
                 "restore of const from IR %04d with bad op %d",
648
                 ref - REF_BIAS, ir->o);
649
      lj_ir_kvalue(J->L, o, ir);
78,366✔
650
    }
651
    return;
78,366✔
652
  }
653
  if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
51,543✔
654
    rs = snap_renameref(T, snapno, ref, rs);
773✔
655
  if (ra_hasspill(regsp_spill(rs))) {  /* Restore from spill slot. */
51,543✔
656
    int32_t *sps = &ex->spill[regsp_spill(rs)];
2,503✔
657
    if (irt_isinteger(t)) {
2,503✔
658
      setintV(o, *sps);
377✔
659
#if !LJ_SOFTFP32
660
    } else if (irt_isnum(t)) {
2,126✔
661
      o->u64 = *(uint64_t *)sps;
1,208✔
662
#endif
663
#if LJ_64 && !LJ_GC64
664
    } else if (irt_islightud(t)) {
665
      /* 64 bit lightuserdata which may escape already has the tag bits. */
666
      o->u64 = *(uint64_t *)sps;
667
#endif
668
    } else {
669
      lj_assertJ(!irt_ispri(t), "PRI ref with spill slot");
918✔
670
      setgcV(J->L, o, (GCobj *)(uintptr_t)*(GCSize *)sps, irt_toitype(t));
918✔
671
    }
672
  } else {  /* Restore from register. */
673
    Reg r = regsp_reg(rs);
49,040✔
674
    if (ra_noreg(r)) {
49,040✔
675
      lj_assertJ(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
80✔
676
                 "restore from IR %04d has no reg", ref - REF_BIAS);
677
      snap_restoreval(J, T, ex, snapno, rfilt, ir->op1, o);
80✔
678
      if (LJ_DUALNUM) setnumV(o, (lua_Number)intV(o));
679
      return;
80✔
680
    } else if (irt_isinteger(t)) {
48,960✔
681
      setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]);
3,819✔
682
#if !LJ_SOFTFP
683
    } else if (irt_isnum(t)) {
45,141✔
684
      setnumV(o, ex->fpr[r-RID_MIN_FPR]);
13,494✔
685
#elif LJ_64  /* && LJ_SOFTFP */
686
    } else if (irt_isnum(t)) {
687
      o->u64 = ex->gpr[r-RID_MIN_GPR];
688
#endif
689
#if LJ_64 && !LJ_GC64
690
    } else if (irt_is64(t)) {
691
      /* 64 bit values that already have the tag bits. */
692
      o->u64 = ex->gpr[r-RID_MIN_GPR];
693
#endif
694
    } else if (irt_ispri(t)) {
31,647✔
UNCOV
695
      setpriV(o, irt_toitype(t));
×
696
    } else {
697
      setgcV(J->L, o, (GCobj *)ex->gpr[r-RID_MIN_GPR], irt_toitype(t));
31,647✔
698
    }
699
  }
700
}
701

702
#if LJ_HASFFI
703
/* Restore raw data from the trace exit state. */
704
static void snap_restoredata(jit_State *J, GCtrace *T, ExitState *ex,
2,116✔
705
                             SnapNo snapno, BloomFilter rfilt,
706
                             IRRef ref, void *dst, CTSize sz)
707
{
708
  IRIns *ir = &T->ir[ref];
2,116✔
709
  RegSP rs = ir->prev;
2,116✔
710
  int32_t *src;
2,116✔
711
  uint64_t tmp;
2,116✔
712
  UNUSED(J);
2,116✔
713
  if (irref_isk(ref)) {
2,116✔
714
    if (ir_isk64(ir)) {
3✔
715
      src = (int32_t *)&ir[1];
2✔
716
    } else if (sz == 8) {
1✔
UNCOV
717
      tmp = (uint64_t)(uint32_t)ir->i;
×
UNCOV
718
      src = (int32_t *)&tmp;
×
719
    } else {
720
      src = &ir->i;
1✔
721
    }
722
  } else {
723
    if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
2,113✔
UNCOV
724
      rs = snap_renameref(T, snapno, ref, rs);
×
725
    if (ra_hasspill(regsp_spill(rs))) {
2,113✔
726
      src = &ex->spill[regsp_spill(rs)];
818✔
727
      if (sz == 8 && !irt_is64(ir->t)) {
818✔
UNCOV
728
        tmp = (uint64_t)(uint32_t)*src;
×
UNCOV
729
        src = (int32_t *)&tmp;
×
730
      }
731
    } else {
732
      Reg r = regsp_reg(rs);
1,295✔
733
      if (ra_noreg(r)) {
1,295✔
734
        /* Note: this assumes CNEWI is never used for SOFTFP split numbers. */
735
        lj_assertJ(sz == 8 && ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
13✔
736
                   "restore from IR %04d has no reg", ref - REF_BIAS);
737
        snap_restoredata(J, T, ex, snapno, rfilt, ir->op1, dst, 4);
13✔
738
        *(lua_Number *)dst = (lua_Number)*(int32_t *)dst;
13✔
739
        return;
13✔
740
      }
741
      src = (int32_t *)&ex->gpr[r-RID_MIN_GPR];
1,282✔
742
#if !LJ_SOFTFP
743
      if (r >= RID_MAX_GPR) {
1,282✔
744
        src = (int32_t *)&ex->fpr[r-RID_MIN_FPR];
16✔
745
#if LJ_TARGET_PPC
746
        if (sz == 4) {  /* PPC FPRs are always doubles. */
747
          *(float *)dst = (float)*(double *)src;
748
          return;
749
        }
750
#else
751
        if (LJ_BE && sz == 4) src++;
16✔
752
#endif
753
      } else
754
#endif
755
      if (LJ_64 && LJ_BE && sz == 4) src++;
756
    }
757
  }
758
  lj_assertJ(sz == 1 || sz == 2 || sz == 4 || sz == 8,
2,103✔
759
             "restore from IR %04d with bad size %d", ref - REF_BIAS, sz);
760
  if (sz == 4) *(int32_t *)dst = *src;
2,103✔
761
  else if (sz == 8) *(int64_t *)dst = *(int64_t *)src;
2,053✔
UNCOV
762
  else if (sz == 1) *(int8_t *)dst = (int8_t)*src;
×
UNCOV
763
  else *(int16_t *)dst = (int16_t)*src;
×
764
}
765
#endif
766

767
/* Unsink allocation from the trace exit state. Unsink sunk stores. */
768
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
769
                        SnapNo snapno, BloomFilter rfilt,
770
                        IRIns *ir, TValue *o)
771
{
772
  lj_assertJ(ir->o == IR_TNEW || ir->o == IR_TDUP ||
773
             ir->o == IR_CNEW || ir->o == IR_CNEWI,
774
             "sunk allocation with bad op %d", ir->o);
775
#if LJ_HASFFI
776
  if (ir->o == IR_CNEW || ir->o == IR_CNEWI) {
777
    CTState *cts = ctype_cts(J->L);
778
    CTypeID id = (CTypeID)T->ir[ir->op1].i;
779
    CTSize sz;
780
    CTInfo info = lj_ctype_info(cts, id, &sz);
781
    GCcdata *cd = lj_cdata_newx(cts, id, sz, info);
782
    setcdataV(J->L, o, cd);
783
    if (ir->o == IR_CNEWI) {
784
      uint8_t *p = (uint8_t *)cdataptr(cd);
785
      lj_assertJ(sz == 4 || sz == 8, "sunk cdata with bad size %d", sz);
786
      if (LJ_32 && sz == 8 && ir+1 < T->ir + T->nins && (ir+1)->o == IR_HIOP) {
787
        snap_restoredata(J, T, ex, snapno, rfilt, (ir+1)->op2,
788
                         LJ_LE ? p+4 : p, 4);
789
        if (LJ_BE) p += 4;
790
        sz = 4;
791
      }
792
      snap_restoredata(J, T, ex, snapno, rfilt, ir->op2, p, sz);
793
    } else {
794
      IRIns *irs, *irlast = &T->ir[T->snap[snapno].ref];
795
      for (irs = ir+1; irs < irlast; irs++)
796
        if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
797
          IRIns *iro = &T->ir[T->ir[irs->op1].op2];
798
          uint8_t *p = (uint8_t *)cd;
799
          CTSize szs;
800
          lj_assertJ(irs->o == IR_XSTORE, "sunk store with bad op %d", irs->o);
801
          lj_assertJ(T->ir[irs->op1].o == IR_ADD,
802
                     "sunk store with bad add op %d", T->ir[irs->op1].o);
803
          lj_assertJ(iro->o == IR_KINT || iro->o == IR_KINT64,
804
                     "sunk store with bad const offset op %d", iro->o);
805
          if (irt_is64(irs->t)) szs = 8;
806
          else if (irt_isi8(irs->t) || irt_isu8(irs->t)) szs = 1;
807
          else if (irt_isi16(irs->t) || irt_isu16(irs->t)) szs = 2;
808
          else szs = 4;
809
          if (LJ_64 && iro->o == IR_KINT64)
810
            p += (int64_t)ir_k64(iro)->u64;
811
          else
812
            p += iro->i;
813
          lj_assertJ(p >= (uint8_t *)cdataptr(cd) &&
814
                     p + szs <= (uint8_t *)cdataptr(cd) + sz,
815
                     "sunk store with offset out of range");
816
          if (LJ_32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) {
817
            lj_assertJ(szs == 4, "sunk store with bad size %d", szs);
818
            snap_restoredata(J, T, ex, snapno, rfilt, (irs+1)->op2,
819
                             LJ_LE ? p+4 : p, 4);
820
            if (LJ_BE) p += 4;
821
          }
822
          snap_restoredata(J, T, ex, snapno, rfilt, irs->op2, p, szs);
823
        }
824
    }
825
  } else
826
#endif
827
  {
828
    IRIns *irs, *irlast;
829
    GCtab *t = ir->o == IR_TNEW ? lj_tab_new(J->L, ir->op1, ir->op2) :
830
                                  lj_tab_dup(J->L, ir_ktab(&T->ir[ir->op1]));
831
    settabV(J->L, o, t);
832
    irlast = &T->ir[T->snap[snapno].ref];
833
    for (irs = ir+1; irs < irlast; irs++)
834
      if (irs->r == RID_SINK && snap_sunk_store(T, ir, irs)) {
835
        IRIns *irk = &T->ir[irs->op1];
836
        TValue tmp, *val;
837
        lj_assertJ(irs->o == IR_ASTORE || irs->o == IR_HSTORE ||
838
                   irs->o == IR_FSTORE,
839
                   "sunk store with bad op %d", irs->o);
840
        if (irk->o == IR_FREF) {
841
          switch (irk->op2) {
842
          case IRFL_TAB_META:
843
            snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp);
844
            /* NOBARRIER: The table is new (marked white). */
845
            setgcref(t->metatable, obj2gco(tabV(&tmp)));
846
            break;
847
          case IRFL_TAB_NOMM:
848
            /* Negative metamethod cache invalidated by lj_tab_set() below. */
849
            break;
850
          default:
851
            lj_assertJ(0, "sunk store with bad field %d", irk->op2);
852
            break;
853
          }
854
        } else {
855
          irk = &T->ir[irk->op2];
856
          if (irk->o == IR_KSLOT) irk = &T->ir[irk->op1];
857
          lj_ir_kvalue(J->L, &tmp, irk);
858
          val = lj_tab_set(J->L, t, &tmp);
859
          /* NOBARRIER: The table is new (marked white). */
860
          snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, val);
861
          if (LJ_SOFTFP32 && irs+1 < T->ir + T->nins && (irs+1)->o == IR_HIOP) {
862
            snap_restoreval(J, T, ex, snapno, rfilt, (irs+1)->op2, &tmp);
863
            val->u32.hi = tmp.u32.lo;
864
          }
865
        }
866
      }
867
  }
868
}
869

870
/* Restore interpreter state from exit state with the help of a snapshot. */
871
const BCIns *lj_snap_restore(jit_State *J, void *exptr)
30,383✔
872
{
873
  ExitState *ex = (ExitState *)exptr;
30,383✔
874
  SnapNo snapno = J->exitno;  /* For now, snapno == exitno. */
30,383✔
875
  GCtrace *T = traceref(J, J->parent);
30,383✔
876
  SnapShot *snap = &T->snap[snapno];
30,383✔
877
  MSize n, nent = snap->nent;
30,383✔
878
  SnapEntry *map = &T->snapmap[snap->mapofs];
30,383✔
879
#if !LJ_FR2 || defined(LUA_USE_ASSERT)
880
  SnapEntry *flinks = &T->snapmap[snap_nextofs(T, snap)-1-LJ_FR2];
881
#endif
882
#if !LJ_FR2
883
  ptrdiff_t ftsz0;
884
#endif
885
  TValue *frame;
30,383✔
886
  BloomFilter rfilt = snap_renamefilter(T, snapno);
30,383✔
887
  const BCIns *pc = snap_pc(&map[nent]);
30,383✔
888
  lua_State *L = J->L;
30,383✔
889

890
  /* Set interpreter PC to the next PC to get correct error messages. */
891
  setcframe_pc(cframe_raw(L->cframe), pc+1);
30,383✔
892

893
  /* Make sure the stack is big enough for the slots from the snapshot. */
894
  if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) {
30,383✔
895
    L->top = curr_topL(L);
14✔
896
    lj_state_growstack(L, snap->topslot - curr_proto(L)->framesize);
14✔
897
  }
898

899
  /* Fill stack slots with data from the registers and spill slots. */
900
  frame = L->base-1-LJ_FR2;
30,382✔
901
#if !LJ_FR2
902
  ftsz0 = frame_ftsz(frame);  /* Preserve link to previous frame in slot #0. */
903
#endif
904
  for (n = 0; n < nent; n++) {
167,480✔
905
    SnapEntry sn = map[n];
137,098✔
906
    if (!(sn & SNAP_NORESTORE)) {
137,098✔
907
      TValue *o = &frame[snap_slot(sn)];
131,786✔
908
      IRRef ref = snap_ref(sn);
131,786✔
909
      IRIns *ir = &T->ir[ref];
131,786✔
910
      if (ir->r == RID_SUNK) {
131,786✔
911
        MSize j;
912
        for (j = 0; j < n; j++)
31,149✔
913
          if (snap_ref(map[j]) == ref) {  /* De-duplicate sunk allocations. */
28,989✔
914
            copyTV(L, o, &frame[snap_slot(map[j])]);
21✔
915
            goto dupslot;
21✔
916
          }
917
        snap_unsink(J, T, ex, snapno, rfilt, ir, o);
2,160✔
918
      dupslot:
2,181✔
919
        continue;
2,181✔
920
      }
921
      snap_restoreval(J, T, ex, snapno, rfilt, ref, o);
129,605✔
922
      if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM) && tvisint(o)) {
129,605✔
923
        TValue tmp;
924
        snap_restoreval(J, T, ex, snapno, rfilt, ref+1, &tmp);
925
        o->u32.hi = tmp.u32.lo;
926
#if !LJ_FR2
927
      } else if ((sn & (SNAP_CONT|SNAP_FRAME))) {
928
        /* Overwrite tag with frame link. */
929
        setframe_ftsz(o, snap_slot(sn) != 0 ? (int32_t)*flinks-- : ftsz0);
930
        L->base = o+1;
931
#endif
932
      }
933
    }
934
  }
935
#if LJ_FR2
936
  L->base += (map[nent+LJ_BE] & 0xff);
30,382✔
937
#endif
938
  lj_assertJ(map + nent == flinks, "inconsistent frames in snapshot");
30,382✔
939

940
  /* Compute current stack top. */
941
  switch (bc_op(*pc)) {
30,382✔
942
  default:
30,195✔
943
    if (bc_op(*pc) < BC_FUNCF) {
30,195✔
944
      L->top = curr_topL(L);
30,195✔
945
      break;
30,195✔
946
    }
947
    /* fallthrough */
948
  case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM:
949
    L->top = frame + snap->nslots;
187✔
950
    break;
187✔
951
  }
952
  J->nsnaprestore++;
30,382✔
953
  return pc;
30,382✔
954
}
955

956
#undef emitir_raw
957
#undef emitir
958

959
#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

© 2025 Coveralls, Inc