2 ** Fast function call recorder.
3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
21 #include "lj_ircall.h"
24 #include "lj_record.h"
25 #include "lj_ffrecord.h"
26 #include "lj_crecord.h"
27 #include "lj_dispatch.h"
29 #include "lj_strscan.h"
31 /* Some local macros to save typing. Undef'd at the end. */
32 #define IR(ref) (&J->cur.ir[(ref)])
34 /* Pass IR on to next optimization in chain (FOLD). */
35 #define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
37 /* -- Fast function recording handlers ------------------------------------ */
39 /* Conventions for fast function call handlers:
41 ** The argument slots start at J->base[0]. All of them are guaranteed to be
42 ** valid and type-specialized references. J->base[J->maxslot] is set to 0
43 ** as a sentinel. The runtime argument values start at rd->argv[0].
45 ** In general fast functions should check for presence of all of their
46 ** arguments and for the correct argument types. Some simplifications
47 ** are allowed if the interpreter throws instead. But even if recording
48 ** is aborted, the generated IR must be consistent (no zero-refs).
50 ** The number of results in rd->nres is set to 1. Handlers that return
51 ** a different number of results need to override it. A negative value
52 ** prevents return processing (e.g. for pending calls).
54 ** Results need to be stored starting at J->base[0]. Return processing
55 ** moves them to the right slots later.
57 ** The per-ffid auxiliary data is the value of the 2nd part of the
58 ** LJLIB_REC() annotation. This allows handling similar functionality
59 ** in a common handler.
62 /* Type of handler to record a fast function. */
63 typedef void (LJ_FASTCALL
*RecordFunc
)(jit_State
*J
, RecordFFData
*rd
);
65 /* Get runtime value of int argument. */
66 static int32_t argv2int(jit_State
*J
, TValue
*o
)
68 if (!lj_strscan_numberobj(o
))
69 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
70 return tvisint(o
) ? intV(o
) : lj_num2int(numV(o
));
73 /* Get runtime value of string argument. */
74 static GCstr
*argv2str(jit_State
*J
, TValue
*o
)
76 if (LJ_LIKELY(tvisstr(o
))) {
81 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
83 s
= lj_str_fromint(J
->L
, intV(o
));
85 s
= lj_str_fromnum(J
->L
, &o
->n
);
91 /* Return number of results wanted by caller. */
92 static ptrdiff_t results_wanted(jit_State
*J
)
94 TValue
*frame
= J
->L
->base
-1;
95 if (frame_islua(frame
))
96 return (ptrdiff_t)bc_b(frame_pc(frame
)[-1]) - 1;
101 /* Throw error for unsupported variant of fast function. */
102 LJ_NORET
static void recff_nyiu(jit_State
*J
)
104 setfuncV(J
->L
, &J
->errinfo
, J
->fn
);
105 lj_trace_err_info(J
, LJ_TRERR_NYIFFU
);
108 /* Fallback handler for all fast functions that are not recorded (yet). */
109 static void LJ_FASTCALL
recff_nyi(jit_State
*J
, RecordFFData
*rd
)
111 setfuncV(J
->L
, &J
->errinfo
, J
->fn
);
112 lj_trace_err_info(J
, LJ_TRERR_NYIFF
);
116 /* C functions can have arbitrary side-effects and are not recorded (yet). */
117 static void LJ_FASTCALL
recff_c(jit_State
*J
, RecordFFData
*rd
)
119 setfuncV(J
->L
, &J
->errinfo
, J
->fn
);
120 lj_trace_err_info(J
, LJ_TRERR_NYICF
);
124 /* -- Base library fast functions ----------------------------------------- */
126 static void LJ_FASTCALL
recff_assert(jit_State
*J
, RecordFFData
*rd
)
128 /* Arguments already specialized. The interpreter throws for nil/false. */
129 rd
->nres
= J
->maxslot
; /* Pass through all arguments. */
132 static void LJ_FASTCALL
recff_type(jit_State
*J
, RecordFFData
*rd
)
134 /* Arguments already specialized. Result is a constant string. Neat, huh? */
136 if (tvisnumber(&rd
->argv
[0]))
138 else if (LJ_64
&& tvislightud(&rd
->argv
[0]))
141 t
= ~itype(&rd
->argv
[0]);
142 J
->base
[0] = lj_ir_kstr(J
, strV(&J
->fn
->c
.upvalue
[t
]));
146 static void LJ_FASTCALL
recff_getmetatable(jit_State
*J
, RecordFFData
*rd
)
148 TRef tr
= J
->base
[0];
152 copyTV(J
->L
, &ix
.tabv
, &rd
->argv
[0]);
153 if (lj_record_mm_lookup(J
, &ix
, MM_metatable
))
154 J
->base
[0] = ix
.mobj
;
157 } /* else: Interpreter will throw. */
160 static void LJ_FASTCALL
recff_setmetatable(jit_State
*J
, RecordFFData
*rd
)
162 TRef tr
= J
->base
[0];
163 TRef mt
= J
->base
[1];
164 if (tref_istab(tr
) && (tref_istab(mt
) || (mt
&& tref_isnil(mt
)))) {
168 copyTV(J
->L
, &ix
.tabv
, &rd
->argv
[0]);
169 lj_record_mm_lookup(J
, &ix
, MM_metatable
); /* Guard for no __metatable. */
170 fref
= emitir(IRT(IR_FREF
, IRT_P32
), tr
, IRFL_TAB_META
);
171 mtref
= tref_isnil(mt
) ? lj_ir_knull(J
, IRT_TAB
) : mt
;
172 emitir(IRT(IR_FSTORE
, IRT_TAB
), fref
, mtref
);
174 emitir(IRT(IR_TBAR
, IRT_TAB
), tr
, 0);
177 } /* else: Interpreter will throw. */
180 static void LJ_FASTCALL
recff_rawget(jit_State
*J
, RecordFFData
*rd
)
183 ix
.tab
= J
->base
[0]; ix
.key
= J
->base
[1];
184 if (tref_istab(ix
.tab
) && ix
.key
) {
185 ix
.val
= 0; ix
.idxchain
= 0;
186 settabV(J
->L
, &ix
.tabv
, tabV(&rd
->argv
[0]));
187 copyTV(J
->L
, &ix
.keyv
, &rd
->argv
[1]);
188 J
->base
[0] = lj_record_idx(J
, &ix
);
189 } /* else: Interpreter will throw. */
192 static void LJ_FASTCALL
recff_rawset(jit_State
*J
, RecordFFData
*rd
)
195 ix
.tab
= J
->base
[0]; ix
.key
= J
->base
[1]; ix
.val
= J
->base
[2];
196 if (tref_istab(ix
.tab
) && ix
.key
&& ix
.val
) {
198 settabV(J
->L
, &ix
.tabv
, tabV(&rd
->argv
[0]));
199 copyTV(J
->L
, &ix
.keyv
, &rd
->argv
[1]);
200 copyTV(J
->L
, &ix
.valv
, &rd
->argv
[2]);
201 lj_record_idx(J
, &ix
);
202 /* Pass through table at J->base[0] as result. */
203 } /* else: Interpreter will throw. */
206 static void LJ_FASTCALL
recff_rawequal(jit_State
*J
, RecordFFData
*rd
)
208 TRef tra
= J
->base
[0];
209 TRef trb
= J
->base
[1];
211 int diff
= lj_record_objcmp(J
, tra
, trb
, &rd
->argv
[0], &rd
->argv
[1]);
212 J
->base
[0] = diff
? TREF_FALSE
: TREF_TRUE
;
213 } /* else: Interpreter will throw. */
217 static void LJ_FASTCALL
recff_rawlen(jit_State
*J
, RecordFFData
*rd
)
219 TRef tr
= J
->base
[0];
221 J
->base
[0] = emitir(IRTI(IR_FLOAD
), tr
, IRFL_STR_LEN
);
222 else if (tref_istab(tr
))
223 J
->base
[0] = lj_ir_call(J
, IRCALL_lj_tab_len
, tr
);
224 /* else: Interpreter will throw. */
229 /* Determine mode of select() call. */
230 int32_t lj_ffrecord_select_mode(jit_State
*J
, TRef tr
, TValue
*tv
)
232 if (tref_isstr(tr
) && *strVdata(tv
) == '#') { /* select('#', ...) */
233 if (strV(tv
)->len
== 1) {
234 emitir(IRTG(IR_EQ
, IRT_STR
), tr
, lj_ir_kstr(J
, strV(tv
)));
236 TRef trptr
= emitir(IRT(IR_STRREF
, IRT_P32
), tr
, lj_ir_kint(J
, 0));
237 TRef trchar
= emitir(IRT(IR_XLOAD
, IRT_U8
), trptr
, IRXLOAD_READONLY
);
238 emitir(IRTG(IR_EQ
, IRT_INT
), trchar
, lj_ir_kint(J
, '#'));
241 } else { /* select(n, ...) */
242 int32_t start
= argv2int(J
, tv
);
243 if (start
== 0) lj_trace_err(J
, LJ_TRERR_BADTYPE
); /* A bit misleading. */
248 static void LJ_FASTCALL
recff_select(jit_State
*J
, RecordFFData
*rd
)
250 TRef tr
= J
->base
[0];
252 ptrdiff_t start
= lj_ffrecord_select_mode(J
, tr
, &rd
->argv
[0]);
253 if (start
== 0) { /* select('#', ...) */
254 J
->base
[0] = lj_ir_kint(J
, J
->maxslot
- 1);
255 } else if (tref_isk(tr
)) { /* select(k, ...) */
256 ptrdiff_t n
= (ptrdiff_t)J
->maxslot
;
257 if (start
< 0) start
+= n
;
258 else if (start
> n
) start
= n
;
261 rd
->nres
= n
- start
;
262 for (i
= 0; i
< n
- start
; i
++)
263 J
->base
[i
] = J
->base
[start
+i
];
264 } /* else: Interpreter will throw. */
268 } /* else: Interpreter will throw. */
271 static void LJ_FASTCALL
recff_tonumber(jit_State
*J
, RecordFFData
*rd
)
273 TRef tr
= J
->base
[0];
274 TRef base
= J
->base
[1];
275 if (tr
&& !tref_isnil(base
)) {
276 base
= lj_opt_narrow_toint(J
, base
);
277 if (!tref_isk(base
) || IR(tref_ref(base
))->i
!= 10)
280 if (tref_isnumber_str(tr
)) {
281 if (tref_isstr(tr
)) {
283 if (!lj_strscan_num(strV(&rd
->argv
[0]), &tmp
))
284 recff_nyiu(J
); /* Would need an inverted STRTO for this case. */
285 tr
= emitir(IRTG(IR_STRTO
, IRT_NUM
), tr
, 0);
288 } else if (tref_iscdata(tr
)) {
289 lj_crecord_tonumber(J
, rd
);
299 static TValue
*recff_metacall_cp(lua_State
*L
, lua_CFunction dummy
, void *ud
)
301 jit_State
*J
= (jit_State
*)ud
;
302 lj_record_tailcall(J
, 0, 1);
303 UNUSED(L
); UNUSED(dummy
);
307 static int recff_metacall(jit_State
*J
, RecordFFData
*rd
, MMS mm
)
311 copyTV(J
->L
, &ix
.tabv
, &rd
->argv
[0]);
312 if (lj_record_mm_lookup(J
, &ix
, mm
)) { /* Has metamethod? */
315 /* Temporarily insert metamethod below object. */
316 J
->base
[1] = J
->base
[0];
317 J
->base
[0] = ix
.mobj
;
318 copyTV(J
->L
, &argv0
, &rd
->argv
[0]);
319 copyTV(J
->L
, &rd
->argv
[1], &rd
->argv
[0]);
320 copyTV(J
->L
, &rd
->argv
[0], &ix
.mobjv
);
321 /* Need to protect lj_record_tailcall because it may throw. */
322 errcode
= lj_vm_cpcall(J
->L
, NULL
, J
, recff_metacall_cp
);
323 /* Always undo Lua stack changes to avoid confusing the interpreter. */
324 copyTV(J
->L
, &rd
->argv
[0], &argv0
);
326 lj_err_throw(J
->L
, errcode
); /* Propagate errors. */
327 rd
->nres
= -1; /* Pending call. */
328 return 1; /* Tailcalled to metamethod. */
333 static void LJ_FASTCALL
recff_tostring(jit_State
*J
, RecordFFData
*rd
)
335 TRef tr
= J
->base
[0];
336 if (tref_isstr(tr
)) {
337 /* Ignore __tostring in the string base metatable. */
338 /* Pass on result in J->base[0]. */
339 } else if (!recff_metacall(J
, rd
, MM_tostring
)) {
340 if (tref_isnumber(tr
)) {
341 J
->base
[0] = emitir(IRT(IR_TOSTR
, IRT_STR
), tr
, 0);
342 } else if (tref_ispri(tr
)) {
343 J
->base
[0] = lj_ir_kstr(J
, strV(&J
->fn
->c
.upvalue
[tref_type(tr
)]));
350 static void LJ_FASTCALL
recff_ipairs_aux(jit_State
*J
, RecordFFData
*rd
)
354 if (tref_istab(ix
.tab
)) {
355 if (!tvisnumber(&rd
->argv
[1])) /* No support for string coercion. */
356 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
357 setintV(&ix
.keyv
, numberVint(&rd
->argv
[1])+1);
358 settabV(J
->L
, &ix
.tabv
, tabV(&rd
->argv
[0]));
359 ix
.val
= 0; ix
.idxchain
= 0;
360 ix
.key
= lj_opt_narrow_toint(J
, J
->base
[1]);
361 J
->base
[0] = ix
.key
= emitir(IRTI(IR_ADD
), ix
.key
, lj_ir_kint(J
, 1));
362 J
->base
[1] = lj_record_idx(J
, &ix
);
363 rd
->nres
= tref_isnil(J
->base
[1]) ? 0 : 2;
364 } /* else: Interpreter will throw. */
367 static void LJ_FASTCALL
recff_ipairs(jit_State
*J
, RecordFFData
*rd
)
369 TRef tr
= J
->base
[0];
370 if (!((LJ_52
|| (LJ_HASFFI
&& tref_iscdata(tr
))) &&
371 recff_metacall(J
, rd
, MM_ipairs
))) {
372 if (tref_istab(tr
)) {
373 J
->base
[0] = lj_ir_kfunc(J
, funcV(&J
->fn
->c
.upvalue
[0]));
375 J
->base
[2] = lj_ir_kint(J
, 0);
377 } /* else: Interpreter will throw. */
381 static void LJ_FASTCALL
recff_pcall(jit_State
*J
, RecordFFData
*rd
)
383 if (J
->maxslot
>= 1) {
384 lj_record_call(J
, 0, J
->maxslot
- 1);
385 rd
->nres
= -1; /* Pending call. */
386 } /* else: Interpreter will throw. */
389 static TValue
*recff_xpcall_cp(lua_State
*L
, lua_CFunction dummy
, void *ud
)
391 jit_State
*J
= (jit_State
*)ud
;
392 lj_record_call(J
, 1, J
->maxslot
- 2);
393 UNUSED(L
); UNUSED(dummy
);
397 static void LJ_FASTCALL
recff_xpcall(jit_State
*J
, RecordFFData
*rd
)
399 if (J
->maxslot
>= 2) {
403 /* Swap function and traceback. */
404 tmp
= J
->base
[0]; J
->base
[0] = J
->base
[1]; J
->base
[1] = tmp
;
405 copyTV(J
->L
, &argv0
, &rd
->argv
[0]);
406 copyTV(J
->L
, &argv1
, &rd
->argv
[1]);
407 copyTV(J
->L
, &rd
->argv
[0], &argv1
);
408 copyTV(J
->L
, &rd
->argv
[1], &argv0
);
409 /* Need to protect lj_record_call because it may throw. */
410 errcode
= lj_vm_cpcall(J
->L
, NULL
, J
, recff_xpcall_cp
);
411 /* Always undo Lua stack swap to avoid confusing the interpreter. */
412 copyTV(J
->L
, &rd
->argv
[0], &argv0
);
413 copyTV(J
->L
, &rd
->argv
[1], &argv1
);
415 lj_err_throw(J
->L
, errcode
); /* Propagate errors. */
416 rd
->nres
= -1; /* Pending call. */
417 } /* else: Interpreter will throw. */
420 /* -- Math library fast functions ----------------------------------------- */
422 static void LJ_FASTCALL
recff_math_abs(jit_State
*J
, RecordFFData
*rd
)
424 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
425 J
->base
[0] = emitir(IRTN(IR_ABS
), tr
, lj_ir_knum_abs(J
));
429 /* Record rounding functions math.floor and math.ceil. */
430 static void LJ_FASTCALL
recff_math_round(jit_State
*J
, RecordFFData
*rd
)
432 TRef tr
= J
->base
[0];
433 if (!tref_isinteger(tr
)) { /* Pass through integers unmodified. */
434 tr
= emitir(IRTN(IR_FPMATH
), lj_ir_tonum(J
, tr
), rd
->data
);
435 /* Result is integral (or NaN/Inf), but may not fit an int32_t. */
436 if (LJ_DUALNUM
) { /* Try to narrow using a guarded conversion to int. */
437 lua_Number n
= lj_vm_foldfpm(numberVnum(&rd
->argv
[0]), rd
->data
);
438 if (n
== (lua_Number
)lj_num2int(n
))
439 tr
= emitir(IRTGI(IR_CONV
), tr
, IRCONV_INT_NUM
|IRCONV_CHECK
);
445 /* Record unary math.* functions, mapped to IR_FPMATH opcode. */
446 static void LJ_FASTCALL
recff_math_unary(jit_State
*J
, RecordFFData
*rd
)
448 J
->base
[0] = emitir(IRTN(IR_FPMATH
), lj_ir_tonum(J
, J
->base
[0]), rd
->data
);
451 /* Record math.log. */
452 static void LJ_FASTCALL
recff_math_log(jit_State
*J
, RecordFFData
*rd
)
454 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
456 #ifdef LUAJIT_NO_LOG2
457 uint32_t fpm
= IRFPM_LOG
;
459 uint32_t fpm
= IRFPM_LOG2
;
461 TRef trb
= lj_ir_tonum(J
, J
->base
[1]);
462 tr
= emitir(IRTN(IR_FPMATH
), tr
, fpm
);
463 trb
= emitir(IRTN(IR_FPMATH
), trb
, fpm
);
464 trb
= emitir(IRTN(IR_DIV
), lj_ir_knum_one(J
), trb
);
465 tr
= emitir(IRTN(IR_MUL
), tr
, trb
);
467 tr
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_LOG
);
473 /* Record math.atan2. */
474 static void LJ_FASTCALL
recff_math_atan2(jit_State
*J
, RecordFFData
*rd
)
476 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
477 TRef tr2
= lj_ir_tonum(J
, J
->base
[1]);
478 J
->base
[0] = emitir(IRTN(IR_ATAN2
), tr
, tr2
);
482 /* Record math.ldexp. */
483 static void LJ_FASTCALL
recff_math_ldexp(jit_State
*J
, RecordFFData
*rd
)
485 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
486 #if LJ_TARGET_X86ORX64
487 TRef tr2
= lj_ir_tonum(J
, J
->base
[1]);
489 TRef tr2
= lj_opt_narrow_toint(J
, J
->base
[1]);
491 J
->base
[0] = emitir(IRTN(IR_LDEXP
), tr
, tr2
);
495 /* Record math.asin, math.acos, math.atan. */
496 static void LJ_FASTCALL
recff_math_atrig(jit_State
*J
, RecordFFData
*rd
)
498 TRef y
= lj_ir_tonum(J
, J
->base
[0]);
499 TRef x
= lj_ir_knum_one(J
);
500 uint32_t ffid
= rd
->data
;
501 if (ffid
!= FF_math_atan
) {
502 TRef tmp
= emitir(IRTN(IR_MUL
), y
, y
);
503 tmp
= emitir(IRTN(IR_SUB
), x
, tmp
);
504 tmp
= emitir(IRTN(IR_FPMATH
), tmp
, IRFPM_SQRT
);
505 if (ffid
== FF_math_asin
) { x
= tmp
; } else { x
= y
; y
= tmp
; }
507 J
->base
[0] = emitir(IRTN(IR_ATAN2
), y
, x
);
510 static void LJ_FASTCALL
recff_math_htrig(jit_State
*J
, RecordFFData
*rd
)
512 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
513 J
->base
[0] = emitir(IRTN(IR_CALLN
), tr
, rd
->data
);
516 static void LJ_FASTCALL
recff_math_modf(jit_State
*J
, RecordFFData
*rd
)
518 TRef tr
= J
->base
[0];
519 if (tref_isinteger(tr
)) {
521 J
->base
[1] = lj_ir_kint(J
, 0);
524 tr
= lj_ir_tonum(J
, tr
);
525 trt
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_TRUNC
);
527 J
->base
[1] = emitir(IRTN(IR_SUB
), tr
, trt
);
532 static void LJ_FASTCALL
recff_math_degrad(jit_State
*J
, RecordFFData
*rd
)
534 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
535 TRef trm
= lj_ir_knum(J
, numV(&J
->fn
->c
.upvalue
[0]));
536 J
->base
[0] = emitir(IRTN(IR_MUL
), tr
, trm
);
540 static void LJ_FASTCALL
recff_math_pow(jit_State
*J
, RecordFFData
*rd
)
542 J
->base
[0] = lj_opt_narrow_pow(J
, J
->base
[0], J
->base
[1],
543 &rd
->argv
[0], &rd
->argv
[1]);
547 static void LJ_FASTCALL
recff_math_minmax(jit_State
*J
, RecordFFData
*rd
)
549 TRef tr
= lj_ir_tonumber(J
, J
->base
[0]);
550 uint32_t op
= rd
->data
;
552 for (i
= 1; J
->base
[i
] != 0; i
++) {
553 TRef tr2
= lj_ir_tonumber(J
, J
->base
[i
]);
555 if (!(tref_isinteger(tr
) && tref_isinteger(tr2
))) {
556 if (tref_isinteger(tr
)) tr
= emitir(IRTN(IR_CONV
), tr
, IRCONV_NUM_INT
);
557 if (tref_isinteger(tr2
)) tr2
= emitir(IRTN(IR_CONV
), tr2
, IRCONV_NUM_INT
);
560 tr
= emitir(IRT(op
, t
), tr
, tr2
);
565 static void LJ_FASTCALL
recff_math_random(jit_State
*J
, RecordFFData
*rd
)
567 GCudata
*ud
= udataV(&J
->fn
->c
.upvalue
[0]);
569 lj_ir_kgc(J
, obj2gco(ud
), IRT_UDATA
); /* Prevent collection. */
570 tr
= lj_ir_call(J
, IRCALL_lj_math_random_step
, lj_ir_kptr(J
, uddata(ud
)));
571 one
= lj_ir_knum_one(J
);
572 tr
= emitir(IRTN(IR_SUB
), tr
, one
);
574 TRef tr1
= lj_ir_tonum(J
, J
->base
[0]);
575 if (J
->base
[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */
576 TRef tr2
= lj_ir_tonum(J
, J
->base
[1]);
577 tr2
= emitir(IRTN(IR_SUB
), tr2
, tr1
);
578 tr2
= emitir(IRTN(IR_ADD
), tr2
, one
);
579 tr
= emitir(IRTN(IR_MUL
), tr
, tr2
);
580 tr
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_FLOOR
);
581 tr
= emitir(IRTN(IR_ADD
), tr
, tr1
);
582 } else { /* d = floor(d*r1) + 1.0 */
583 tr
= emitir(IRTN(IR_MUL
), tr
, tr1
);
584 tr
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_FLOOR
);
585 tr
= emitir(IRTN(IR_ADD
), tr
, one
);
592 /* -- Bit library fast functions ------------------------------------------ */
594 /* Record unary bit.tobit, bit.bnot, bit.bswap. */
595 static void LJ_FASTCALL
recff_bit_unary(jit_State
*J
, RecordFFData
*rd
)
597 TRef tr
= lj_opt_narrow_tobit(J
, J
->base
[0]);
598 J
->base
[0] = (rd
->data
== IR_TOBIT
) ? tr
: emitir(IRTI(rd
->data
), tr
, 0);
601 /* Record N-ary bit.band, bit.bor, bit.bxor. */
602 static void LJ_FASTCALL
recff_bit_nary(jit_State
*J
, RecordFFData
*rd
)
604 TRef tr
= lj_opt_narrow_tobit(J
, J
->base
[0]);
605 uint32_t op
= rd
->data
;
607 for (i
= 1; J
->base
[i
] != 0; i
++)
608 tr
= emitir(IRTI(op
), tr
, lj_opt_narrow_tobit(J
, J
->base
[i
]));
612 /* Record bit shifts. */
613 static void LJ_FASTCALL
recff_bit_shift(jit_State
*J
, RecordFFData
*rd
)
615 TRef tr
= lj_opt_narrow_tobit(J
, J
->base
[0]);
616 TRef tsh
= lj_opt_narrow_tobit(J
, J
->base
[1]);
617 IROp op
= (IROp
)rd
->data
;
618 if (!(op
< IR_BROL
? LJ_TARGET_MASKSHIFT
: LJ_TARGET_MASKROT
) &&
620 tsh
= emitir(IRTI(IR_BAND
), tsh
, lj_ir_kint(J
, 31));
621 #ifdef LJ_TARGET_UNIFYROT
622 if (op
== (LJ_TARGET_UNIFYROT
== 1 ? IR_BROR
: IR_BROL
)) {
623 op
= LJ_TARGET_UNIFYROT
== 1 ? IR_BROL
: IR_BROR
;
624 tsh
= emitir(IRTI(IR_NEG
), tsh
, tsh
);
627 J
->base
[0] = emitir(IRTI(op
), tr
, tsh
);
630 /* -- String library fast functions --------------------------------------- */
632 static void LJ_FASTCALL
recff_string_len(jit_State
*J
, RecordFFData
*rd
)
634 J
->base
[0] = emitir(IRTI(IR_FLOAD
), lj_ir_tostr(J
, J
->base
[0]), IRFL_STR_LEN
);
638 /* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
639 static void LJ_FASTCALL
recff_string_range(jit_State
*J
, RecordFFData
*rd
)
641 TRef trstr
= lj_ir_tostr(J
, J
->base
[0]);
642 TRef trlen
= emitir(IRTI(IR_FLOAD
), trstr
, IRFL_STR_LEN
);
643 TRef tr0
= lj_ir_kint(J
, 0);
645 GCstr
*str
= argv2str(J
, &rd
->argv
[0]);
647 if (rd
->data
) { /* string.sub(str, start [,end]) */
648 start
= argv2int(J
, &rd
->argv
[1]);
649 trstart
= lj_opt_narrow_toint(J
, J
->base
[1]);
651 if (tref_isnil(trend
)) {
652 trend
= lj_ir_kint(J
, -1);
655 trend
= lj_opt_narrow_toint(J
, trend
);
656 end
= argv2int(J
, &rd
->argv
[2]);
658 } else { /* string.byte(str, [,start [,end]]) */
659 if (tref_isnil(J
->base
[1])) {
661 trstart
= lj_ir_kint(J
, 1);
663 start
= argv2int(J
, &rd
->argv
[1]);
664 trstart
= lj_opt_narrow_toint(J
, J
->base
[1]);
666 if (J
->base
[1] && !tref_isnil(J
->base
[2])) {
667 trend
= lj_opt_narrow_toint(J
, J
->base
[2]);
668 end
= argv2int(J
, &rd
->argv
[2]);
675 emitir(IRTGI(IR_LT
), trend
, tr0
);
676 trend
= emitir(IRTI(IR_ADD
), emitir(IRTI(IR_ADD
), trlen
, trend
),
678 end
= end
+(int32_t)str
->len
+1;
679 } else if ((MSize
)end
<= str
->len
) {
680 emitir(IRTGI(IR_ULE
), trend
, trlen
);
682 emitir(IRTGI(IR_GT
), trend
, trlen
);
683 end
= (int32_t)str
->len
;
687 emitir(IRTGI(IR_LT
), trstart
, tr0
);
688 trstart
= emitir(IRTI(IR_ADD
), trlen
, trstart
);
689 start
= start
+(int32_t)str
->len
;
690 emitir(start
< 0 ? IRTGI(IR_LT
) : IRTGI(IR_GE
), trstart
, tr0
);
697 emitir(IRTGI(IR_EQ
), trstart
, tr0
);
700 trstart
= emitir(IRTI(IR_ADD
), trstart
, lj_ir_kint(J
, -1));
701 emitir(IRTGI(IR_GE
), trstart
, tr0
);
705 if (rd
->data
) { /* Return string.sub result. */
706 if (end
- start
>= 0) {
707 /* Also handle empty range here, to avoid extra traces. */
708 TRef trptr
, trslen
= emitir(IRTI(IR_SUB
), trend
, trstart
);
709 emitir(IRTGI(IR_GE
), trslen
, tr0
);
710 trptr
= emitir(IRT(IR_STRREF
, IRT_P32
), trstr
, trstart
);
711 J
->base
[0] = emitir(IRT(IR_SNEW
, IRT_STR
), trptr
, trslen
);
712 } else { /* Range underflow: return empty string. */
713 emitir(IRTGI(IR_LT
), trend
, trstart
);
714 J
->base
[0] = lj_ir_kstr(J
, lj_str_new(J
->L
, strdata(str
), 0));
716 } else { /* Return string.byte result(s). */
717 ptrdiff_t i
, len
= end
- start
;
719 TRef trslen
= emitir(IRTI(IR_SUB
), trend
, trstart
);
720 emitir(IRTGI(IR_EQ
), trslen
, lj_ir_kint(J
, (int32_t)len
));
721 if (J
->baseslot
+ len
> LJ_MAX_JSLOTS
)
722 lj_trace_err_info(J
, LJ_TRERR_STACKOV
);
724 for (i
= 0; i
< len
; i
++) {
725 TRef tmp
= emitir(IRTI(IR_ADD
), trstart
, lj_ir_kint(J
, (int32_t)i
));
726 tmp
= emitir(IRT(IR_STRREF
, IRT_P32
), trstr
, tmp
);
727 J
->base
[i
] = emitir(IRT(IR_XLOAD
, IRT_U8
), tmp
, IRXLOAD_READONLY
);
729 } else { /* Empty range or range underflow: return no results. */
730 emitir(IRTGI(IR_LE
), trend
, trstart
);
736 /* -- Table library fast functions ---------------------------------------- */
738 static void LJ_FASTCALL
recff_table_getn(jit_State
*J
, RecordFFData
*rd
)
740 if (tref_istab(J
->base
[0]))
741 J
->base
[0] = lj_ir_call(J
, IRCALL_lj_tab_len
, J
->base
[0]);
742 /* else: Interpreter will throw. */
746 static void LJ_FASTCALL
recff_table_remove(jit_State
*J
, RecordFFData
*rd
)
748 TRef tab
= J
->base
[0];
750 if (tref_istab(tab
)) {
751 if (tref_isnil(J
->base
[1])) { /* Simple pop: t[#t] = nil */
752 TRef trlen
= lj_ir_call(J
, IRCALL_lj_tab_len
, tab
);
753 GCtab
*t
= tabV(&rd
->argv
[0]);
754 MSize len
= lj_tab_len(t
);
755 emitir(IRTGI(len
? IR_NE
: IR_EQ
), trlen
, lj_ir_kint(J
, 0));
760 settabV(J
->L
, &ix
.tabv
, t
);
761 setintV(&ix
.keyv
, len
);
763 if (results_wanted(J
) != 0) { /* Specialize load only if needed. */
765 J
->base
[0] = lj_record_idx(J
, &ix
); /* Load previous value. */
767 /* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */
770 lj_record_idx(J
, &ix
); /* Remove value. */
772 } else { /* Complex case: remove in the middle. */
775 } /* else: Interpreter will throw. */
778 static void LJ_FASTCALL
recff_table_insert(jit_State
*J
, RecordFFData
*rd
)
784 if (tref_istab(ix
.tab
) && ix
.val
) {
785 if (!J
->base
[2]) { /* Simple push: t[#t+1] = v */
786 TRef trlen
= lj_ir_call(J
, IRCALL_lj_tab_len
, ix
.tab
);
787 GCtab
*t
= tabV(&rd
->argv
[0]);
788 ix
.key
= emitir(IRTI(IR_ADD
), trlen
, lj_ir_kint(J
, 1));
789 settabV(J
->L
, &ix
.tabv
, t
);
790 setintV(&ix
.keyv
, lj_tab_len(t
) + 1);
792 lj_record_idx(J
, &ix
); /* Set new value. */
793 } else { /* Complex case: insert in the middle. */
796 } /* else: Interpreter will throw. */
799 /* -- I/O library fast functions ------------------------------------------ */
801 /* Get FILE* for I/O function. Any I/O error aborts recording, so there's
802 ** no need to encode the alternate cases for any of the guards.
804 static TRef
recff_io_fp(jit_State
*J
, TRef
*udp
, int32_t id
)
807 if (id
) { /* io.func() */
808 tr
= lj_ir_kptr(J
, &J2G(J
)->gcroot
[id
]);
809 ud
= emitir(IRT(IR_XLOAD
, IRT_UDATA
), tr
, 0);
810 } else { /* fp:method() */
812 if (!tref_isudata(ud
))
813 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
814 tr
= emitir(IRT(IR_FLOAD
, IRT_U8
), ud
, IRFL_UDATA_UDTYPE
);
815 emitir(IRTGI(IR_EQ
), tr
, lj_ir_kint(J
, UDTYPE_IO_FILE
));
818 fp
= emitir(IRT(IR_FLOAD
, IRT_PTR
), ud
, IRFL_UDATA_FILE
);
819 emitir(IRTG(IR_NE
, IRT_PTR
), fp
, lj_ir_knull(J
, IRT_PTR
));
823 static void LJ_FASTCALL
recff_io_write(jit_State
*J
, RecordFFData
*rd
)
825 TRef ud
, fp
= recff_io_fp(J
, &ud
, rd
->data
);
826 TRef zero
= lj_ir_kint(J
, 0);
827 TRef one
= lj_ir_kint(J
, 1);
828 ptrdiff_t i
= rd
->data
== 0 ? 1 : 0;
829 for (; J
->base
[i
]; i
++) {
830 TRef str
= lj_ir_tostr(J
, J
->base
[i
]);
831 TRef buf
= emitir(IRT(IR_STRREF
, IRT_P32
), str
, zero
);
832 TRef len
= emitir(IRTI(IR_FLOAD
), str
, IRFL_STR_LEN
);
833 if (tref_isk(len
) && IR(tref_ref(len
))->i
== 1) {
834 TRef tr
= emitir(IRT(IR_XLOAD
, IRT_U8
), buf
, IRXLOAD_READONLY
);
835 tr
= lj_ir_call(J
, IRCALL_fputc
, tr
, fp
);
836 if (results_wanted(J
) != 0) /* Check result only if not ignored. */
837 emitir(IRTGI(IR_NE
), tr
, lj_ir_kint(J
, -1));
839 TRef tr
= lj_ir_call(J
, IRCALL_fwrite
, buf
, one
, len
, fp
);
840 if (results_wanted(J
) != 0) /* Check result only if not ignored. */
841 emitir(IRTGI(IR_EQ
), tr
, len
);
844 J
->base
[0] = LJ_52
? ud
: TREF_TRUE
;
847 static void LJ_FASTCALL
recff_io_flush(jit_State
*J
, RecordFFData
*rd
)
849 TRef ud
, fp
= recff_io_fp(J
, &ud
, rd
->data
);
850 TRef tr
= lj_ir_call(J
, IRCALL_fflush
, fp
);
851 if (results_wanted(J
) != 0) /* Check result only if not ignored. */
852 emitir(IRTGI(IR_EQ
), tr
, lj_ir_kint(J
, 0));
853 J
->base
[0] = TREF_TRUE
;
856 /* -- Record calls to fast functions -------------------------------------- */
858 #include "lj_recdef.h"
860 static uint32_t recdef_lookup(GCfunc
*fn
)
862 if (fn
->c
.ffid
< sizeof(recff_idmap
)/sizeof(recff_idmap
[0]))
863 return recff_idmap
[fn
->c
.ffid
];
868 /* Record entry to a fast function or C function. */
869 void lj_ffrecord_func(jit_State
*J
)
872 uint32_t m
= recdef_lookup(J
->fn
);
874 rd
.nres
= 1; /* Default is one result. */
875 rd
.argv
= J
->L
->base
;
876 J
->base
[J
->maxslot
] = 0; /* Mark end of arguments. */
877 (recff_func
[m
>> 8])(J
, &rd
); /* Call recff_* handler. */
879 if (J
->postproc
== LJ_POST_NONE
) J
->postproc
= LJ_POST_FFRETRY
;
880 lj_record_ret(J
, 0, rd
.nres
);