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

tarantool / luajit / 9593251616

20 Jun 2024 07:14AM UTC coverage: 92.646% (+0.02%) from 92.624%
9593251616

push

github

Buristan
cmake: fix warning about minimum required version

Since CMake 3.27 compatibility with versions of CMake older than
3.5 is deprecated [1]. CMake produces an annoying warning on the
configuration stage:

| CMake Deprecation Warning at src/CMakeLists.txt:7 (cmake_minimum_required):
|  Compatibility with CMake < 3.5 will be removed from a future version of
|  CMake.

We cannot bump a minimum required CMake version without bumping it in
the Tarantool build system. However, we can set a <policy_max>
(introduced in CMake 3.12, see [1]) and suppress a warning. <policy_max>
means that this CMake version is known to work properly and will not
result in any build errors right away for higher versions.

Note that the current CMake minimum required version in Tarantool is
equal to 2.8, but <policy_max> is introduced in CMake 3.12 [1].
However, according to [1] it is not a problem because if CMake is "older
than 3.12, the extra ... dots will be seen as version component
separators, resulting in the ...<max> part being ignored and preserving
the pre-3.12 behavior of basing policies on <min>".

<policy_max> is set to 3.18 because compatibility with versions of CMake
older than 2.8.12 is deprecated. Calls to
cmake_minimum_required(VERSION) that do not specify at least 2.8.12 as
their policy version (optionally via ...<max>) will produce a
deprecation warning in CMake 3.19 and above [2]. Compatibility with
2.8.12 is needed for CMP0002 [3], see commit 049e296ee114 ("test: run
LuaJIT tests via CMake").

1. https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html
2. https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html#policy-settings
3. https://cmake.org/cmake/help/latest/policy/CMP0002.html

5665 of 6021 branches covered (94.09%)

Branch coverage included in aggregate %.

21621 of 23431 relevant lines covered (92.28%)

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

47
/* Grow snapshot map buffer. */
48
void lj_snap_grow_map_(jit_State *J, MSize need)
223✔
49
{
50
  if (need < 2*J->sizesnapmap)
223✔
51
    need = 2*J->sizesnapmap;
52
  else if (need < 64)
128✔
53
    need = 64;
54
  J->snapmapbuf = (SnapEntry *)lj_mem_realloc(J->L, J->snapmapbuf,
446✔
55
                    J->sizesnapmap*sizeof(SnapEntry), need*sizeof(SnapEntry));
223✔
56
  J->cur.snapmap = J->snapmapbuf;
223✔
57
  J->sizesnapmap = need;
223✔
58
}
223✔
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)
1,906,750✔
64
{
65
  IRRef retf = J->chain[IR_RETF];  /* Limits SLOAD restore elimination. */
1,906,750✔
66
  BCReg s;
1,906,750✔
67
  MSize n = 0;
1,906,750✔
68
  for (s = 0; s < nslots; s++) {
19,992,909✔
69
    TRef tr = J->slot[s];
18,086,159✔
70
    IRRef ref = tref_ref(tr);
18,086,159✔
71
#if LJ_FR2
72
    if (s == 1) {  /* Ignore slot 1 in LJ_FR2 mode, except if tailcalled. */
18,086,159✔
73
      if ((tr & TREF_FRAME))
1,906,750✔
74
        map[n++] = SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL);
998,621✔
75
      continue;
1,906,750✔
76
    }
77
    if ((tr & (TREF_FRAME | TREF_CONT)) && !ref) {
16,179,409✔
78
      cTValue *base = J->L->base - J->baseslot;
603,649✔
79
      tr = J->slot[s] = (tr & 0xff0000) | lj_ir_k64(J, IR_KNUM, base[s].u64);
603,649✔
80
      ref = tref_ref(tr);
603,649✔
81
    }
82
#endif
83
    if (ref) {
16,179,409✔
84
      SnapEntry sn = SNAP_TR(s, tr);
12,202,199✔
85
      IRIns *ir = &J->cur.ir[ref];
12,202,199✔
86
      if ((LJ_FR2 || !(sn & (SNAP_CONT|SNAP_FRAME))) &&
12,202,199✔
87
          ir->o == IR_SLOAD && ir->op1 == s && ref > retf) {
12,202,199✔
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) &&
2,790,467✔
93
            (!LJ_FR2 || s == 0 || s+1 == nslots ||
2,702,648✔
94
             !(J->slot[s+1] & (TREF_CONT|TREF_FRAME))))
2,699,088✔
95
          continue;
2,710,821✔
96
        /* No need to restore readonly slots and unmodified non-parent slots. */
97
        if (!(LJ_DUALNUM && (ir->op2 & IRSLOAD_CONVERT)) &&
79,646✔
98
            (ir->op2 & (IRSLOAD_READONLY|IRSLOAD_PARENT)) != IRSLOAD_PARENT)
99
          sn |= SNAP_NORESTORE;
41,437✔
100
      }
101
      if (LJ_SOFTFP32 && irt_isnum(ir->t))
9,491,378✔
102
        sn |= SNAP_SOFTFPNUM;
103
      map[n++] = sn;
9,491,378✔
104
    }
105
  }
106
  return n;
1,906,750✔
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)
1,906,750✔
111
{
112
  cTValue *frame = J->L->base - 1;
1,906,750✔
113
  cTValue *lim = J->L->base - J->baseslot + LJ_FR2;
1,906,750✔
114
  GCfunc *fn = frame_func(frame);
1,906,750✔
115
  cTValue *ftop = isluafunc(fn) ? (frame+funcproto(fn)->framesize) : J->L->top;
1,906,750✔
116
#if LJ_FR2
117
  uint64_t pcbase = (u64ptr(J->pc) << 8) | (J->baseslot - 2);
1,906,750✔
118
  lj_assertJ(2 <= J->baseslot && J->baseslot <= 257, "bad baseslot");
1,906,750✔
119
  memcpy(map, &pcbase, sizeof(uint64_t));
1,906,750✔
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. */
3,895,563✔
128
    if (frame_islua(frame)) {
1,988,813✔
129
#if !LJ_FR2
130
      map[f++] = SNAP_MKPC(frame_pc(frame));
131
#endif
132
      frame = frame_prevl(frame);
1,988,195✔
133
    } else if (frame_iscont(frame)) {
618✔
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);
294✔
139
    } else {
140
      lj_assertJ(!frame_isc(frame), "broken frame chain");
324✔
141
#if !LJ_FR2
142
      map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
143
#endif
144
      frame = frame_prevd(frame);
324✔
145
      continue;
324✔
146
    }
147
    if (frame + funcproto(frame_func(frame))->framesize > ftop)
1,988,489✔
148
      ftop = frame + funcproto(frame_func(frame))->framesize;
149
  }
150
  *topslot = (uint8_t)(ftop - lim);
1,906,750✔
151
#if LJ_FR2
152
  lj_assertJ(sizeof(SnapEntry) * 2 == sizeof(uint64_t), "bad SnapEntry def");
1,906,750✔
153
  return 2;
1,906,750✔
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)
1,906,750✔
162
{
163
  BCReg nslots = J->baseslot + J->maxslot;
1,906,750✔
164
  MSize nent;
1,906,750✔
165
  SnapEntry *p;
1,906,750✔
166
  /* Conservative estimate. */
167
  lj_snap_grow_map(J, nsnapmap + nslots + (MSize)(LJ_FR2?2:J->framedepth+1));
1,906,750✔
168
  p = &J->cur.snapmap[nsnapmap];
1,906,750✔
169
  nent = snapshot_slots(J, p, nslots);
1,906,750✔
170
  snap->nent = (uint8_t)nent;
1,906,750✔
171
  nent += snapshot_framelinks(J, p + nent, &snap->topslot);
1,906,750✔
172
  snap->mapofs = (uint32_t)nsnapmap;
1,906,750✔
173
  snap->ref = (IRRef1)J->cur.nins;
1,906,750✔
174
  snap->mcofs = 0;
1,906,750✔
175
  snap->nslots = (uint8_t)nslots;
1,906,750✔
176
  snap->count = 0;
1,906,750✔
177
  J->cur.nsnapmap = (uint32_t)(nsnapmap + nent);
1,906,750✔
178
}
1,906,750✔
179

180
/* Add or merge a snapshot. */
181
void lj_snap_add(jit_State *J)
1,906,752✔
182
{
183
  MSize nsnap = J->cur.nsnap;
1,906,752✔
184
  MSize nsnapmap = J->cur.nsnapmap;
1,906,752✔
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) ||
1,906,752✔
187
      (J->mergesnap && !irt_isguard(J->guardemit))) {
1,154,903✔
188
    if (nsnap == 1) {  /* But preserve snap #0 PC. */
770,925✔
189
      emitir_raw(IRT(IR_NOP, IRT_NIL), 0, 0);
1,149✔
190
      goto nomerge;
1,149✔
191
    }
192
    nsnapmap = J->cur.snap[--nsnap].mapofs;
769,776✔
193
  } else {
194
  nomerge:
1,135,827✔
195
    lj_snap_grow_buf(J, nsnap+1);
1,136,976✔
196
    J->cur.nsnap = (uint16_t)(nsnap+1);
1,136,974✔
197
  }
198
  J->mergesnap = 0;
1,906,750✔
199
  J->guardemit.irt = 0;
1,906,750✔
200
  snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap);
1,906,750✔
201
}
1,906,750✔
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) { pc += bc_j(ins); break; }
256
      for (s = minslot; s < maxslot; s++) DEF_SLOT(s);
257
      return minslot < maxslot ? minslot : maxslot;
258
      }
259
    case BCMlit:
260
      if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
261
        goto handle_jump;
262
      } else if (bc_isret(op)) {
263
        BCReg top = op == BC_RETM ? maxslot : (bc_a(ins) + bc_d(ins)-1);
264
        for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s);
265
        for (; s < top; s++) USE_SLOT(s);
266
        for (; s < maxslot; s++) DEF_SLOT(s);
267
        return 0;
268
      }
269
      break;
270
    case BCMfunc: return maxslot;  /* NYI: will abort, anyway. */
271
    default: break;
272
    }
273
    switch (bcmode_a(op)) {
274
    case BCMvar: USE_SLOT(bc_a(ins)); break;
275
    case BCMdst:
276
       if (!(op == BC_ISTC || op == BC_ISFC)) DEF_SLOT(bc_a(ins));
277
       break;
278
    case BCMbase:
279
      if (op >= BC_CALLM && op <= BC_ITERN) {
280
        BCReg top = (op == BC_CALLM || op == BC_CALLMT || bc_c(ins) == 0) ?
281
                    maxslot : (bc_a(ins) + bc_c(ins)+LJ_FR2);
282
        if (LJ_FR2) DEF_SLOT(bc_a(ins)+1);
283
        s = bc_a(ins) - ((op == BC_ITERC || op == BC_ITERN) ? 3 : 0);
284
        for (; s < top; s++) USE_SLOT(s);
285
        for (; s < maxslot; s++) DEF_SLOT(s);
286
        if (op == BC_CALLT || op == BC_CALLMT) {
287
          for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s);
288
          return 0;
289
        }
290
      } else if (op == BC_VARG) {
291
        return maxslot;  /* NYI: punt. */
292
      } else if (op == BC_KNIL) {
293
        for (s = bc_a(ins); s <= bc_d(ins); s++) DEF_SLOT(s);
294
      } else if (op == BC_TSETM) {
295
        for (s = bc_a(ins)-1; s < maxslot; s++) USE_SLOT(s);
296
      }
297
      break;
298
    default: break;
299
    }
300
    lj_assertJ(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc,
301
               "use/def analysis PC out of range");
302
  }
303

304
#undef USE_SLOT
305
#undef DEF_SLOT
306

307
  return 0;  /* unreachable */
308
}
309

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

335
/* Purge dead slots before the next snapshot. */
336
void lj_snap_purge(jit_State *J)
1,068,165✔
337
{
338
  uint8_t udf[SNAP_USEDEF_SLOTS];
1,068,165✔
339
  BCReg s, maxslot = J->maxslot;
1,068,165✔
340
  if (bc_op(*J->pc) == BC_FUNCV && maxslot > J->pt->numparams)
1,068,165✔
341
    maxslot = J->pt->numparams;
342
  s = snap_usedef(J, udf, J->pc, maxslot);
1,068,165✔
343
  if (s < maxslot) {
1,068,165✔
344
    snap_useuv(J->pt, udf);
927,371✔
345
    for (; s < maxslot; s++)
3,373,172✔
346
      if (udf[s] != 0)
1,518,430✔
347
        J->base[s] = 0;  /* Purge dead slots. */
830,570✔
348
  }
349
}
1,068,165✔
350

351
/* Shrink last snapshot. */
352
void lj_snap_shrink(jit_State *J)
683,307✔
353
{
354
  SnapShot *snap = &J->cur.snap[J->cur.nsnap-1];
683,307✔
355
  SnapEntry *map = &J->cur.snapmap[snap->mapofs];
683,307✔
356
  MSize n, m, nlim, nent = snap->nent;
683,307✔
357
  uint8_t udf[SNAP_USEDEF_SLOTS];
683,307✔
358
  BCReg maxslot = J->maxslot;
683,307✔
359
  BCReg baseslot = J->baseslot;
683,307✔
360
  BCReg minslot = snap_usedef(J, udf, snap_pc(&map[nent]), maxslot);
683,307✔
361
  if (minslot < maxslot) snap_useuv(J->pt, udf);
683,307✔
362
  maxslot += baseslot;
683,307✔
363
  minslot += baseslot;
683,307✔
364
  snap->nslots = (uint8_t)maxslot;
683,307✔
365
  for (n = m = 0; n < nent; n++) {  /* Remove unused slots from snapshot. */
5,517,597✔
366
    BCReg s = snap_slot(map[n]);
4,834,290✔
367
    if (s < minslot || (s < maxslot && udf[s-baseslot] == 0))
4,834,290✔
368
      map[m++] = map[n];  /* Only copy used slots. */
4,132,493✔
369
  }
370
  snap->nent = (uint8_t)m;
683,307✔
371
  nlim = J->cur.nsnapmap - snap->mapofs - 1;
683,307✔
372
  while (n <= nlim) map[m++] = map[n++];  /* Move PC + frame links down. */
2,049,921✔
373
  J->cur.nsnapmap = (uint32_t)(snap->mapofs + m);  /* Free up space in map. */
683,307✔
374
}
683,307✔
375

376
/* -- Snapshot access ----------------------------------------------------- */
377

378
/* Initialize a Bloom Filter with all renamed refs.
379
** There are very few renames (often none), so the filter has
380
** very few bits set. This makes it suitable for negative filtering.
381
*/
382
static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim)
204,068✔
383
{
384
  BloomFilter rfilt = 0;
204,068✔
385
  IRIns *ir;
204,068✔
386
  for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
210,850✔
387
    if (ir->op2 <= lim)
6,782✔
388
      bloomset(rfilt, ir->op1);
3,670✔
389
  return rfilt;
190,872✔
390
}
391

392
/* Process matching renames to find the original RegSP. */
393
static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs)
2,219✔
394
{
395
  IRIns *ir;
2,219✔
396
  for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
7,845✔
397
    if (ir->op1 == ref && ir->op2 <= lim)
5,626✔
398
      rs = ir->prev;
2,286✔
399
  return rs;
400
}
401

402
/* Copy RegSP from parent snapshot to the parent links of the IR. */
403
IRIns *lj_snap_regspmap(jit_State *J, GCtrace *T, SnapNo snapno, IRIns *ir)
13,196✔
404
{
405
  SnapShot *snap = &T->snap[snapno];
13,196✔
406
  SnapEntry *map = &T->snapmap[snap->mapofs];
13,196✔
407
  BloomFilter rfilt = snap_renamefilter(T, snapno);
13,196✔
408
  MSize n = 0;
409
  IRRef ref = 0;
30,380✔
410
  UNUSED(J);
30,380✔
411
  for ( ; ; ir++) {
47,564✔
412
    uint32_t rs;
30,380✔
413
    if (ir->o == IR_SLOAD) {
30,380✔
414
      if (!(ir->op2 & IRSLOAD_PARENT)) break;
21,626✔
415
      for ( ; ; n++) {
66,921✔
416
        lj_assertJ(n < snap->nent, "slot %d not found in snapshot", ir->op1);
25,730✔
417
        if (snap_slot(map[n]) == ir->op1) {
41,191✔
418
          ref = snap_ref(map[n++]);
15,461✔
419
          break;
15,461✔
420
        }
421
      }
422
    } else if (LJ_SOFTFP32 && ir->o == IR_HIOP) {
8,754✔
423
      ref++;
424
    } else if (ir->o == IR_PVAL) {
8,754✔
425
      ref = ir->op1 + REF_BIAS;
1,723✔
426
    } else {
427
      break;
428
    }
429
    rs = T->ir[ref].prev;
17,184✔
430
    if (bloomtest(rfilt, ref))
17,184✔
431
      rs = snap_renameref(T, snapno, ref, rs);
163✔
432
    ir->prev = (uint16_t)rs;
17,184✔
433
    lj_assertJ(regsp_used(rs), "unused IR %04d in snapshot", ref - REF_BIAS);
17,184✔
434
  }
435
  return ir;
13,196✔
436
}
437

438
/* -- Snapshot replay ----------------------------------------------------- */
439

440
/* Replay constant from parent trace. */
441
static TRef snap_replay_const(jit_State *J, IRIns *ir)
30,858✔
442
{
443
  /* Only have to deal with constants that can occur in stack slots. */
444
  switch ((IROp)ir->o) {
30,858✔
445
  case IR_KPRI: return TREF_PRI(irt_type(ir->t));
172✔
446
  case IR_KINT: return lj_ir_kint(J, ir->i);
4,106✔
447
  case IR_KGC: return lj_ir_kgc(J, ir_kgc(ir), irt_t(ir->t));
18,266✔
448
  case IR_KNUM: case IR_KINT64:
8,314✔
449
    return lj_ir_k64(J, (IROp)ir->o, ir_k64(ir)->u64);
8,314✔
450
  case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir));  /* Continuation. */
×
451
  case IR_KNULL: return lj_ir_knull(J, irt_type(ir->t));
×
452
  default: lj_assertJ(0, "bad IR constant op %d", ir->o); return TREF_NIL;
453
  }
454
}
455

456
/* De-duplicate parent reference. */
457
static TRef snap_dedup(jit_State *J, SnapEntry *map, MSize nmax, IRRef ref)
458
{
459
  MSize j;
460
  for (j = 0; j < nmax; j++)
14,174✔
461
    if (snap_ref(map[j]) == ref)
13,651✔
462
      return J->slot[snap_slot(map[j])] & ~(SNAP_CONT|SNAP_FRAME);
1,821✔
463
  return 0;
464
}
465

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

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

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

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

684
/* -- Snapshot restore ---------------------------------------------------- */
685

686
static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
687
                        SnapNo snapno, BloomFilter rfilt,
688
                        IRIns *ir, TValue *o);
689

690
/* Restore a value from the trace exit state. */
691
static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex,
699,341✔
692
                            SnapNo snapno, BloomFilter rfilt,
693
                            IRRef ref, TValue *o)
694
{
695
  IRIns *ir = &T->ir[ref];
699,410✔
696
  IRType1 t = ir->t;
699,410✔
697
  RegSP rs = ir->prev;
699,410✔
698
  if (irref_isk(ref)) {  /* Restore constant slot. */
699,410✔
699
    if (ir->o == IR_KPTR) {
455,722✔
700
      o->u64 = (uint64_t)(uintptr_t)ir_kptr(ir);
×
701
    } else {
702
      lj_assertJ(!(ir->o == IR_KKPTR || ir->o == IR_KNULL),
455,722✔
703
                 "restore of const from IR %04d with bad op %d",
704
                 ref - REF_BIAS, ir->o);
705
      lj_ir_kvalue(J->L, o, ir);
455,722✔
706
    }
707
    return;
455,722✔
708
  }
709
  if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
243,688✔
710
    rs = snap_renameref(T, snapno, ref, rs);
2,056✔
711
  if (ra_hasspill(regsp_spill(rs))) {  /* Restore from spill slot. */
243,688✔
712
    int32_t *sps = &ex->spill[regsp_spill(rs)];
36,345✔
713
    if (irt_isinteger(t)) {
36,345✔
714
      setintV(o, *sps);
365✔
715
#if !LJ_SOFTFP32
716
    } else if (irt_isnum(t)) {
35,980✔
717
      o->u64 = *(uint64_t *)sps;
15,597✔
718
#endif
719
#if LJ_64 && !LJ_GC64
720
    } else if (irt_islightud(t)) {
721
      /* 64 bit lightuserdata which may escape already has the tag bits. */
722
      o->u64 = *(uint64_t *)sps;
723
#endif
724
    } else {
725
      lj_assertJ(!irt_ispri(t), "PRI ref with spill slot");
20,383✔
726
      setgcV(J->L, o, (GCobj *)(uintptr_t)*(GCSize *)sps, irt_toitype(t));
20,383✔
727
    }
728
  } else {  /* Restore from register. */
729
    Reg r = regsp_reg(rs);
207,343✔
730
    if (ra_noreg(r)) {
207,343✔
731
      lj_assertJ(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT,
69✔
732
                 "restore from IR %04d has no reg", ref - REF_BIAS);
733
      snap_restoreval(J, T, ex, snapno, rfilt, ir->op1, o);
69✔
734
      if (LJ_DUALNUM) setnumV(o, (lua_Number)intV(o));
735
      return;
69✔
736
    } else if (irt_isinteger(t)) {
207,274✔
737
      setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]);
5,175✔
738
#if !LJ_SOFTFP
739
    } else if (irt_isnum(t)) {
202,099✔
740
      setnumV(o, ex->fpr[r-RID_MIN_FPR]);
53,127✔
741
#elif LJ_64  /* && LJ_SOFTFP */
742
    } else if (irt_isnum(t)) {
743
      o->u64 = ex->gpr[r-RID_MIN_GPR];
744
#endif
745
#if LJ_64 && !LJ_GC64
746
    } else if (irt_is64(t)) {
747
      /* 64 bit values that already have the tag bits. */
748
      o->u64 = ex->gpr[r-RID_MIN_GPR];
749
#endif
750
    } else if (irt_ispri(t)) {
148,972✔
751
      setpriV(o, irt_toitype(t));
×
752
    } else {
753
      setgcV(J->L, o, (GCobj *)ex->gpr[r-RID_MIN_GPR], irt_toitype(t));
148,972✔
754
    }
755
  }
756
}
757

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

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

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

950
  /* Set interpreter PC to the next PC to get correct error messages. */
951
  setcframe_pc(cframe_raw(L->cframe), pc+1);
190,872✔
952

953
  /* Make sure the stack is big enough for the slots from the snapshot. */
954
  if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) {
190,872✔
955
    L->top = curr_topL(L);
42✔
956
    lj_state_growstack(L, snap->topslot - curr_proto(L)->framesize);
42✔
957
  }
958

959
  /* Fill stack slots with data from the registers and spill slots. */
960
  frame = L->base-1-LJ_FR2;
190,868✔
961
#if !LJ_FR2
962
  ftsz0 = frame_ftsz(frame);  /* Preserve link to previous frame in slot #0. */
963
#endif
964
  for (n = 0; n < nent; n++) {
939,746✔
965
    SnapEntry sn = map[n];
748,878✔
966
    if (!(sn & SNAP_NORESTORE)) {
748,878✔
967
      TValue *o = &frame[snap_slot(sn)];
703,379✔
968
      IRRef ref = snap_ref(sn);
703,379✔
969
      IRIns *ir = &T->ir[ref];
703,379✔
970
      if (ir->r == RID_SUNK) {
703,379✔
971
        MSize j;
972
        for (j = 0; j < n; j++)
35,288✔
973
          if (snap_ref(map[j]) == ref) {  /* De-duplicate sunk allocations. */
31,036✔
974
            copyTV(L, o, &frame[snap_slot(map[j])]);
10✔
975
            goto dupslot;
10✔
976
          }
977
        snap_unsink(J, T, ex, snapno, rfilt, ir, o);
4,252✔
978
      dupslot:
4,262✔
979
        continue;
4,262✔
980
      }
981
      snap_restoreval(J, T, ex, snapno, rfilt, ref, o);
699,117✔
982
      if (LJ_SOFTFP32 && (sn & SNAP_SOFTFPNUM) && tvisint(o)) {
699,117✔
983
        TValue tmp;
984
        snap_restoreval(J, T, ex, snapno, rfilt, ref+1, &tmp);
985
        o->u32.hi = tmp.u32.lo;
986
#if !LJ_FR2
987
      } else if ((sn & (SNAP_CONT|SNAP_FRAME))) {
988
        /* Overwrite tag with frame link. */
989
        setframe_ftsz(o, snap_slot(sn) != 0 ? (int32_t)*flinks-- : ftsz0);
990
        L->base = o+1;
991
#endif
992
      }
993
    }
994
  }
995
#if LJ_FR2
996
  L->base += (map[nent+LJ_BE] & 0xff);
190,868✔
997
#endif
998
  lj_assertJ(map + nent == flinks, "inconsistent frames in snapshot");
190,868✔
999

1000
  /* Compute current stack top. */
1001
  switch (bc_op(*pc)) {
190,868✔
1002
  default:
189,898✔
1003
    if (bc_op(*pc) < BC_FUNCF) {
189,898✔
1004
      L->top = curr_topL(L);
189,879✔
1005
      break;
189,879✔
1006
    }
1007
    /* fallthrough */
1008
  case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM:
1009
    L->top = frame + snap->nslots;
989✔
1010
    break;
989✔
1011
  }
1012
  J->nsnaprestore++;
190,868✔
1013
  return pc;
190,868✔
1014
}
1015

1016
#undef emitir_raw
1017
#undef emitir
1018

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