2 ** Fast function call recorder.
3 ** Copyright (C) 2005-2012 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"
30 /* Some local macros to save typing. Undef'd at the end. */
31 #define IR(ref) (&J->cur.ir[(ref)])
33 /* Pass IR on to next optimization in chain (FOLD). */
34 #define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
36 /* -- Fast function recording handlers ------------------------------------ */
38 /* Conventions for fast function call handlers:
40 ** The argument slots start at J->base[0]. All of them are guaranteed to be
41 ** valid and type-specialized references. J->base[J->maxslot] is set to 0
42 ** as a sentinel. The runtime argument values start at rd->argv[0].
44 ** In general fast functions should check for presence of all of their
45 ** arguments and for the correct argument types. Some simplifications
46 ** are allowed if the interpreter throws instead. But even if recording
47 ** is aborted, the generated IR must be consistent (no zero-refs).
49 ** The number of results in rd->nres is set to 1. Handlers that return
50 ** a different number of results need to override it. A negative value
51 ** prevents return processing (e.g. for pending calls).
53 ** Results need to be stored starting at J->base[0]. Return processing
54 ** moves them to the right slots later.
56 ** The per-ffid auxiliary data is the value of the 2nd part of the
57 ** LJLIB_REC() annotation. This allows handling similar functionality
58 ** in a common handler.
61 /* Type of handler to record a fast function. */
62 typedef void (LJ_FASTCALL
*RecordFunc
)(jit_State
*J
, RecordFFData
*rd
);
64 /* Get runtime value of int argument. */
65 static int32_t argv2int(jit_State
*J
, TValue
*o
)
67 if (!tvisnumber(o
) && !(tvisstr(o
) && lj_str_tonumber(strV(o
), o
)))
68 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
69 return tvisint(o
) ? intV(o
) : lj_num2int(numV(o
));
72 /* Get runtime value of string argument. */
73 static GCstr
*argv2str(jit_State
*J
, TValue
*o
)
75 if (LJ_LIKELY(tvisstr(o
))) {
80 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
82 s
= lj_str_fromint(J
->L
, intV(o
));
84 s
= lj_str_fromnum(J
->L
, &o
->n
);
90 /* Return number of results wanted by caller. */
91 static ptrdiff_t results_wanted(jit_State
*J
)
93 TValue
*frame
= J
->L
->base
-1;
94 if (frame_islua(frame
))
95 return (ptrdiff_t)bc_b(frame_pc(frame
)[-1]) - 1;
100 /* Throw error for unsupported variant of fast function. */
101 LJ_NORET
static void recff_nyiu(jit_State
*J
)
103 setfuncV(J
->L
, &J
->errinfo
, J
->fn
);
104 lj_trace_err_info(J
, LJ_TRERR_NYIFFU
);
107 /* Fallback handler for all fast functions that are not recorded (yet). */
108 static void LJ_FASTCALL
recff_nyi(jit_State
*J
, RecordFFData
*rd
)
110 setfuncV(J
->L
, &J
->errinfo
, J
->fn
);
111 lj_trace_err_info(J
, LJ_TRERR_NYIFF
);
115 /* C functions can have arbitrary side-effects and are not recorded (yet). */
116 static void LJ_FASTCALL
recff_c(jit_State
*J
, RecordFFData
*rd
)
118 setfuncV(J
->L
, &J
->errinfo
, J
->fn
);
119 lj_trace_err_info(J
, LJ_TRERR_NYICF
);
123 /* -- Base library fast functions ----------------------------------------- */
125 static void LJ_FASTCALL
recff_assert(jit_State
*J
, RecordFFData
*rd
)
127 /* Arguments already specialized. The interpreter throws for nil/false. */
128 rd
->nres
= J
->maxslot
; /* Pass through all arguments. */
131 static void LJ_FASTCALL
recff_type(jit_State
*J
, RecordFFData
*rd
)
133 /* Arguments already specialized. Result is a constant string. Neat, huh? */
135 if (tvisnumber(&rd
->argv
[0]))
137 else if (LJ_64
&& tvislightud(&rd
->argv
[0]))
140 t
= ~itype(&rd
->argv
[0]);
141 J
->base
[0] = lj_ir_kstr(J
, strV(&J
->fn
->c
.upvalue
[t
]));
145 static void LJ_FASTCALL
recff_getmetatable(jit_State
*J
, RecordFFData
*rd
)
147 TRef tr
= J
->base
[0];
151 copyTV(J
->L
, &ix
.tabv
, &rd
->argv
[0]);
152 if (lj_record_mm_lookup(J
, &ix
, MM_metatable
))
153 J
->base
[0] = ix
.mobj
;
156 } /* else: Interpreter will throw. */
159 static void LJ_FASTCALL
recff_setmetatable(jit_State
*J
, RecordFFData
*rd
)
161 TRef tr
= J
->base
[0];
162 TRef mt
= J
->base
[1];
163 if (tref_istab(tr
) && (tref_istab(mt
) || (mt
&& tref_isnil(mt
)))) {
167 copyTV(J
->L
, &ix
.tabv
, &rd
->argv
[0]);
168 lj_record_mm_lookup(J
, &ix
, MM_metatable
); /* Guard for no __metatable. */
169 fref
= emitir(IRT(IR_FREF
, IRT_P32
), tr
, IRFL_TAB_META
);
170 mtref
= tref_isnil(mt
) ? lj_ir_knull(J
, IRT_TAB
) : mt
;
171 emitir(IRT(IR_FSTORE
, IRT_TAB
), fref
, mtref
);
173 emitir(IRT(IR_TBAR
, IRT_TAB
), tr
, 0);
176 } /* else: Interpreter will throw. */
179 static void LJ_FASTCALL
recff_rawget(jit_State
*J
, RecordFFData
*rd
)
182 ix
.tab
= J
->base
[0]; ix
.key
= J
->base
[1];
183 if (tref_istab(ix
.tab
) && ix
.key
) {
184 ix
.val
= 0; ix
.idxchain
= 0;
185 settabV(J
->L
, &ix
.tabv
, tabV(&rd
->argv
[0]));
186 copyTV(J
->L
, &ix
.keyv
, &rd
->argv
[1]);
187 J
->base
[0] = lj_record_idx(J
, &ix
);
188 } /* else: Interpreter will throw. */
191 static void LJ_FASTCALL
recff_rawset(jit_State
*J
, RecordFFData
*rd
)
194 ix
.tab
= J
->base
[0]; ix
.key
= J
->base
[1]; ix
.val
= J
->base
[2];
195 if (tref_istab(ix
.tab
) && ix
.key
&& ix
.val
) {
197 settabV(J
->L
, &ix
.tabv
, tabV(&rd
->argv
[0]));
198 copyTV(J
->L
, &ix
.keyv
, &rd
->argv
[1]);
199 copyTV(J
->L
, &ix
.valv
, &rd
->argv
[2]);
200 lj_record_idx(J
, &ix
);
201 /* Pass through table at J->base[0] as result. */
202 } /* else: Interpreter will throw. */
205 static void LJ_FASTCALL
recff_rawequal(jit_State
*J
, RecordFFData
*rd
)
207 TRef tra
= J
->base
[0];
208 TRef trb
= J
->base
[1];
210 int diff
= lj_record_objcmp(J
, tra
, trb
, &rd
->argv
[0], &rd
->argv
[1]);
211 J
->base
[0] = diff
? TREF_FALSE
: TREF_TRUE
;
212 } /* else: Interpreter will throw. */
215 /* Determine mode of select() call. */
216 int32_t lj_ffrecord_select_mode(jit_State
*J
, TRef tr
, TValue
*tv
)
218 if (tref_isstr(tr
) && *strVdata(tv
) == '#') { /* select('#', ...) */
219 if (strV(tv
)->len
== 1) {
220 emitir(IRTG(IR_EQ
, IRT_STR
), tr
, lj_ir_kstr(J
, strV(tv
)));
222 TRef trptr
= emitir(IRT(IR_STRREF
, IRT_P32
), tr
, lj_ir_kint(J
, 0));
223 TRef trchar
= emitir(IRT(IR_XLOAD
, IRT_U8
), trptr
, IRXLOAD_READONLY
);
224 emitir(IRTG(IR_EQ
, IRT_INT
), trchar
, lj_ir_kint(J
, '#'));
227 } else { /* select(n, ...) */
228 int32_t start
= argv2int(J
, tv
);
229 if (start
== 0) lj_trace_err(J
, LJ_TRERR_BADTYPE
); /* A bit misleading. */
234 static void LJ_FASTCALL
recff_select(jit_State
*J
, RecordFFData
*rd
)
236 TRef tr
= J
->base
[0];
238 ptrdiff_t start
= lj_ffrecord_select_mode(J
, tr
, &rd
->argv
[0]);
239 if (start
== 0) { /* select('#', ...) */
240 J
->base
[0] = lj_ir_kint(J
, J
->maxslot
- 1);
241 } else if (tref_isk(tr
)) { /* select(k, ...) */
242 ptrdiff_t n
= (ptrdiff_t)J
->maxslot
;
243 if (start
< 0) start
+= n
;
244 else if (start
> n
) start
= n
;
245 rd
->nres
= n
- start
;
248 for (i
= 0; i
< n
- start
; i
++)
249 J
->base
[i
] = J
->base
[start
+i
];
250 } /* else: Interpreter will throw. */
254 } /* else: Interpreter will throw. */
257 static void LJ_FASTCALL
recff_tonumber(jit_State
*J
, RecordFFData
*rd
)
259 TRef tr
= J
->base
[0];
260 TRef base
= J
->base
[1];
262 base
= lj_opt_narrow_toint(J
, base
);
263 if (!tref_isk(base
) || IR(tref_ref(base
))->i
!= 10)
266 if (tref_isnumber_str(tr
)) {
267 if (tref_isstr(tr
)) {
269 if (!lj_str_tonum(strV(&rd
->argv
[0]), &tmp
))
270 recff_nyiu(J
); /* Would need an inverted STRTO for this case. */
271 tr
= emitir(IRTG(IR_STRTO
, IRT_NUM
), tr
, 0);
274 } else if (tref_iscdata(tr
)) {
275 lj_crecord_tonumber(J
, rd
);
285 static TValue
*recff_metacall_cp(lua_State
*L
, lua_CFunction dummy
, void *ud
)
287 jit_State
*J
= (jit_State
*)ud
;
288 lj_record_tailcall(J
, 0, 1);
289 UNUSED(L
); UNUSED(dummy
);
293 static int recff_metacall(jit_State
*J
, RecordFFData
*rd
, MMS mm
)
297 copyTV(J
->L
, &ix
.tabv
, &rd
->argv
[0]);
298 if (lj_record_mm_lookup(J
, &ix
, mm
)) { /* Has metamethod? */
301 /* Temporarily insert metamethod below object. */
302 J
->base
[1] = J
->base
[0];
303 J
->base
[0] = ix
.mobj
;
304 copyTV(J
->L
, &argv0
, &rd
->argv
[0]);
305 copyTV(J
->L
, &rd
->argv
[1], &rd
->argv
[0]);
306 copyTV(J
->L
, &rd
->argv
[0], &ix
.mobjv
);
307 /* Need to protect lj_record_tailcall because it may throw. */
308 errcode
= lj_vm_cpcall(J
->L
, NULL
, J
, recff_metacall_cp
);
309 /* Always undo Lua stack changes to avoid confusing the interpreter. */
310 copyTV(J
->L
, &rd
->argv
[0], &argv0
);
312 lj_err_throw(J
->L
, errcode
); /* Propagate errors. */
313 rd
->nres
= -1; /* Pending call. */
314 return 1; /* Tailcalled to metamethod. */
319 static void LJ_FASTCALL
recff_tostring(jit_State
*J
, RecordFFData
*rd
)
321 TRef tr
= J
->base
[0];
322 if (tref_isstr(tr
)) {
323 /* Ignore __tostring in the string base metatable. */
324 /* Pass on result in J->base[0]. */
325 } else if (!recff_metacall(J
, rd
, MM_tostring
)) {
326 if (tref_isnumber(tr
)) {
327 J
->base
[0] = emitir(IRT(IR_TOSTR
, IRT_STR
), tr
, 0);
328 } else if (tref_ispri(tr
)) {
329 J
->base
[0] = lj_ir_kstr(J
, strV(&J
->fn
->c
.upvalue
[tref_type(tr
)]));
336 static void LJ_FASTCALL
recff_ipairs_aux(jit_State
*J
, RecordFFData
*rd
)
340 if (tref_istab(ix
.tab
)) {
341 if (!tvisnumber(&rd
->argv
[1])) /* No support for string coercion. */
342 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
343 setintV(&ix
.keyv
, numberVint(&rd
->argv
[1])+1);
344 settabV(J
->L
, &ix
.tabv
, tabV(&rd
->argv
[0]));
345 ix
.val
= 0; ix
.idxchain
= 0;
346 ix
.key
= lj_opt_narrow_toint(J
, J
->base
[1]);
347 J
->base
[0] = ix
.key
= emitir(IRTI(IR_ADD
), ix
.key
, lj_ir_kint(J
, 1));
348 J
->base
[1] = lj_record_idx(J
, &ix
);
349 rd
->nres
= tref_isnil(J
->base
[1]) ? 0 : 2;
350 } /* else: Interpreter will throw. */
353 static void LJ_FASTCALL
recff_ipairs(jit_State
*J
, RecordFFData
*rd
)
355 #ifdef LUAJIT_ENABLE_LUA52COMPAT
356 if (!recff_metacall(J
, rd
, MM_ipairs
))
359 TRef tab
= J
->base
[0];
360 if (tref_istab(tab
)) {
361 J
->base
[0] = lj_ir_kfunc(J
, funcV(&J
->fn
->c
.upvalue
[0]));
363 J
->base
[2] = lj_ir_kint(J
, 0);
365 } /* else: Interpreter will throw. */
369 static void LJ_FASTCALL
recff_pcall(jit_State
*J
, RecordFFData
*rd
)
371 if (J
->maxslot
>= 1) {
372 lj_record_call(J
, 0, J
->maxslot
- 1);
373 rd
->nres
= -1; /* Pending call. */
374 } /* else: Interpreter will throw. */
377 static TValue
*recff_xpcall_cp(lua_State
*L
, lua_CFunction dummy
, void *ud
)
379 jit_State
*J
= (jit_State
*)ud
;
380 lj_record_call(J
, 1, J
->maxslot
- 2);
381 UNUSED(L
); UNUSED(dummy
);
385 static void LJ_FASTCALL
recff_xpcall(jit_State
*J
, RecordFFData
*rd
)
387 if (J
->maxslot
>= 2) {
391 /* Swap function and traceback. */
392 tmp
= J
->base
[0]; J
->base
[0] = J
->base
[1]; J
->base
[1] = tmp
;
393 copyTV(J
->L
, &argv0
, &rd
->argv
[0]);
394 copyTV(J
->L
, &argv1
, &rd
->argv
[1]);
395 copyTV(J
->L
, &rd
->argv
[0], &argv1
);
396 copyTV(J
->L
, &rd
->argv
[1], &argv0
);
397 /* Need to protect lj_record_call because it may throw. */
398 errcode
= lj_vm_cpcall(J
->L
, NULL
, J
, recff_xpcall_cp
);
399 /* Always undo Lua stack swap to avoid confusing the interpreter. */
400 copyTV(J
->L
, &rd
->argv
[0], &argv0
);
401 copyTV(J
->L
, &rd
->argv
[1], &argv1
);
403 lj_err_throw(J
->L
, errcode
); /* Propagate errors. */
404 rd
->nres
= -1; /* Pending call. */
405 } /* else: Interpreter will throw. */
408 /* -- Math library fast functions ----------------------------------------- */
410 static void LJ_FASTCALL
recff_math_abs(jit_State
*J
, RecordFFData
*rd
)
412 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
413 J
->base
[0] = emitir(IRTN(IR_ABS
), tr
, lj_ir_knum_abs(J
));
417 /* Record rounding functions math.floor and math.ceil. */
418 static void LJ_FASTCALL
recff_math_round(jit_State
*J
, RecordFFData
*rd
)
420 TRef tr
= J
->base
[0];
421 if (!tref_isinteger(tr
)) { /* Pass through integers unmodified. */
422 tr
= emitir(IRTN(IR_FPMATH
), lj_ir_tonum(J
, tr
), rd
->data
);
423 /* Result is integral (or NaN/Inf), but may not fit an int32_t. */
424 if (LJ_DUALNUM
) { /* Try to narrow using a guarded conversion to int. */
425 lua_Number n
= lj_vm_foldfpm(numberVnum(&rd
->argv
[0]), rd
->data
);
426 if (n
== (lua_Number
)lj_num2int(n
))
427 tr
= emitir(IRTGI(IR_CONV
), tr
, IRCONV_INT_NUM
|IRCONV_CHECK
);
433 /* Record unary math.* functions, mapped to IR_FPMATH opcode. */
434 static void LJ_FASTCALL
recff_math_unary(jit_State
*J
, RecordFFData
*rd
)
436 J
->base
[0] = emitir(IRTN(IR_FPMATH
), lj_ir_tonum(J
, J
->base
[0]), rd
->data
);
439 /* Record math.atan2. */
440 static void LJ_FASTCALL
recff_math_atan2(jit_State
*J
, RecordFFData
*rd
)
442 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
443 TRef tr2
= lj_ir_tonum(J
, J
->base
[1]);
444 J
->base
[0] = emitir(IRTN(IR_ATAN2
), tr
, tr2
);
448 /* Record math.ldexp. */
449 static void LJ_FASTCALL
recff_math_ldexp(jit_State
*J
, RecordFFData
*rd
)
451 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
452 #if LJ_TARGET_X86ORX64
453 TRef tr2
= lj_ir_tonum(J
, J
->base
[1]);
455 TRef tr2
= lj_opt_narrow_toint(J
, J
->base
[1]);
457 J
->base
[0] = emitir(IRTN(IR_LDEXP
), tr
, tr2
);
461 /* Record math.asin, math.acos, math.atan. */
462 static void LJ_FASTCALL
recff_math_atrig(jit_State
*J
, RecordFFData
*rd
)
464 TRef y
= lj_ir_tonum(J
, J
->base
[0]);
465 TRef x
= lj_ir_knum_one(J
);
466 uint32_t ffid
= rd
->data
;
467 if (ffid
!= FF_math_atan
) {
468 TRef tmp
= emitir(IRTN(IR_MUL
), y
, y
);
469 tmp
= emitir(IRTN(IR_SUB
), x
, tmp
);
470 tmp
= emitir(IRTN(IR_FPMATH
), tmp
, IRFPM_SQRT
);
471 if (ffid
== FF_math_asin
) { x
= tmp
; } else { x
= y
; y
= tmp
; }
473 J
->base
[0] = emitir(IRTN(IR_ATAN2
), y
, x
);
476 static void LJ_FASTCALL
recff_math_htrig(jit_State
*J
, RecordFFData
*rd
)
478 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
479 J
->base
[0] = emitir(IRTN(IR_CALLN
), tr
, rd
->data
);
482 static void LJ_FASTCALL
recff_math_modf(jit_State
*J
, RecordFFData
*rd
)
484 TRef tr
= J
->base
[0];
485 if (tref_isinteger(tr
)) {
487 J
->base
[1] = lj_ir_kint(J
, 0);
490 tr
= lj_ir_tonum(J
, tr
);
491 trt
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_TRUNC
);
493 J
->base
[1] = emitir(IRTN(IR_SUB
), tr
, trt
);
498 static void LJ_FASTCALL
recff_math_degrad(jit_State
*J
, RecordFFData
*rd
)
500 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
501 TRef trm
= lj_ir_knum(J
, numV(&J
->fn
->c
.upvalue
[0]));
502 J
->base
[0] = emitir(IRTN(IR_MUL
), tr
, trm
);
506 static void LJ_FASTCALL
recff_math_pow(jit_State
*J
, RecordFFData
*rd
)
508 TRef tr
= lj_ir_tonum(J
, J
->base
[0]);
509 if (!tref_isnumber_str(J
->base
[1]))
510 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
511 J
->base
[0] = lj_opt_narrow_pow(J
, tr
, J
->base
[1], &rd
->argv
[1]);
515 static void LJ_FASTCALL
recff_math_minmax(jit_State
*J
, RecordFFData
*rd
)
517 TRef tr
= lj_ir_tonumber(J
, J
->base
[0]);
518 uint32_t op
= rd
->data
;
520 for (i
= 1; J
->base
[i
] != 0; i
++) {
521 TRef tr2
= lj_ir_tonumber(J
, J
->base
[i
]);
523 if (!(tref_isinteger(tr
) && tref_isinteger(tr2
))) {
524 if (tref_isinteger(tr
)) tr
= emitir(IRTN(IR_CONV
), tr
, IRCONV_NUM_INT
);
525 if (tref_isinteger(tr2
)) tr2
= emitir(IRTN(IR_CONV
), tr2
, IRCONV_NUM_INT
);
528 tr
= emitir(IRT(op
, t
), tr
, tr2
);
533 static void LJ_FASTCALL
recff_math_random(jit_State
*J
, RecordFFData
*rd
)
535 GCudata
*ud
= udataV(&J
->fn
->c
.upvalue
[0]);
537 lj_ir_kgc(J
, obj2gco(ud
), IRT_UDATA
); /* Prevent collection. */
538 tr
= lj_ir_call(J
, IRCALL_lj_math_random_step
, lj_ir_kptr(J
, uddata(ud
)));
539 one
= lj_ir_knum_one(J
);
540 tr
= emitir(IRTN(IR_SUB
), tr
, one
);
542 TRef tr1
= lj_ir_tonum(J
, J
->base
[0]);
543 if (J
->base
[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */
544 TRef tr2
= lj_ir_tonum(J
, J
->base
[1]);
545 tr2
= emitir(IRTN(IR_SUB
), tr2
, tr1
);
546 tr2
= emitir(IRTN(IR_ADD
), tr2
, one
);
547 tr
= emitir(IRTN(IR_MUL
), tr
, tr2
);
548 tr
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_FLOOR
);
549 tr
= emitir(IRTN(IR_ADD
), tr
, tr1
);
550 } else { /* d = floor(d*r1) + 1.0 */
551 tr
= emitir(IRTN(IR_MUL
), tr
, tr1
);
552 tr
= emitir(IRTN(IR_FPMATH
), tr
, IRFPM_FLOOR
);
553 tr
= emitir(IRTN(IR_ADD
), tr
, one
);
560 /* -- Bit library fast functions ------------------------------------------ */
562 /* Record unary bit.tobit, bit.bnot, bit.bswap. */
563 static void LJ_FASTCALL
recff_bit_unary(jit_State
*J
, RecordFFData
*rd
)
565 TRef tr
= lj_opt_narrow_tobit(J
, J
->base
[0]);
566 J
->base
[0] = (rd
->data
== IR_TOBIT
) ? tr
: emitir(IRTI(rd
->data
), tr
, 0);
569 /* Record N-ary bit.band, bit.bor, bit.bxor. */
570 static void LJ_FASTCALL
recff_bit_nary(jit_State
*J
, RecordFFData
*rd
)
572 TRef tr
= lj_opt_narrow_tobit(J
, J
->base
[0]);
573 uint32_t op
= rd
->data
;
575 for (i
= 1; J
->base
[i
] != 0; i
++)
576 tr
= emitir(IRTI(op
), tr
, lj_opt_narrow_tobit(J
, J
->base
[i
]));
580 /* Record bit shifts. */
581 static void LJ_FASTCALL
recff_bit_shift(jit_State
*J
, RecordFFData
*rd
)
583 TRef tr
= lj_opt_narrow_tobit(J
, J
->base
[0]);
584 TRef tsh
= lj_opt_narrow_tobit(J
, J
->base
[1]);
585 IROp op
= (IROp
)rd
->data
;
586 if (!(op
< IR_BROL
? LJ_TARGET_MASKSHIFT
: LJ_TARGET_MASKROT
) &&
588 tsh
= emitir(IRTI(IR_BAND
), tsh
, lj_ir_kint(J
, 31));
589 #ifdef LJ_TARGET_UNIFYROT
590 if (op
== (LJ_TARGET_UNIFYROT
== 1 ? IR_BROR
: IR_BROL
)) {
591 op
= LJ_TARGET_UNIFYROT
== 1 ? IR_BROL
: IR_BROR
;
592 tsh
= emitir(IRTI(IR_NEG
), tsh
, tsh
);
595 J
->base
[0] = emitir(IRTI(op
), tr
, tsh
);
598 /* -- String library fast functions --------------------------------------- */
600 static void LJ_FASTCALL
recff_string_len(jit_State
*J
, RecordFFData
*rd
)
602 J
->base
[0] = emitir(IRTI(IR_FLOAD
), lj_ir_tostr(J
, J
->base
[0]), IRFL_STR_LEN
);
606 /* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
607 static void LJ_FASTCALL
recff_string_range(jit_State
*J
, RecordFFData
*rd
)
609 TRef trstr
= lj_ir_tostr(J
, J
->base
[0]);
610 TRef trlen
= emitir(IRTI(IR_FLOAD
), trstr
, IRFL_STR_LEN
);
611 TRef tr0
= lj_ir_kint(J
, 0);
613 GCstr
*str
= argv2str(J
, &rd
->argv
[0]);
615 if (rd
->data
) { /* string.sub(str, start [,end]) */
616 start
= argv2int(J
, &rd
->argv
[1]);
617 trstart
= lj_opt_narrow_toint(J
, J
->base
[1]);
619 if (tref_isnil(trend
)) {
620 trend
= lj_ir_kint(J
, -1);
623 trend
= lj_opt_narrow_toint(J
, trend
);
624 end
= argv2int(J
, &rd
->argv
[2]);
626 } else { /* string.byte(str, [,start [,end]]) */
628 start
= argv2int(J
, &rd
->argv
[1]);
629 trstart
= lj_opt_narrow_toint(J
, J
->base
[1]);
631 if (tref_isnil(trend
)) {
635 trend
= lj_opt_narrow_toint(J
, trend
);
636 end
= argv2int(J
, &rd
->argv
[2]);
639 trend
= trstart
= lj_ir_kint(J
, 1);
644 emitir(IRTGI(IR_LT
), trend
, tr0
);
645 trend
= emitir(IRTI(IR_ADD
), emitir(IRTI(IR_ADD
), trlen
, trend
),
647 end
= end
+(int32_t)str
->len
+1;
648 } else if ((MSize
)end
<= str
->len
) {
649 emitir(IRTGI(IR_ULE
), trend
, trlen
);
651 emitir(IRTGI(IR_GT
), trend
, trlen
);
652 end
= (int32_t)str
->len
;
656 emitir(IRTGI(IR_LT
), trstart
, tr0
);
657 trstart
= emitir(IRTI(IR_ADD
), trlen
, trstart
);
658 start
= start
+(int32_t)str
->len
;
659 emitir(start
< 0 ? IRTGI(IR_LT
) : IRTGI(IR_GE
), trstart
, tr0
);
666 emitir(IRTGI(IR_EQ
), trstart
, tr0
);
669 trstart
= emitir(IRTI(IR_ADD
), trstart
, lj_ir_kint(J
, -1));
670 emitir(IRTGI(IR_GE
), trstart
, tr0
);
674 if (rd
->data
) { /* Return string.sub result. */
675 if (end
- start
>= 0) {
676 /* Also handle empty range here, to avoid extra traces. */
677 TRef trptr
, trslen
= emitir(IRTI(IR_SUB
), trend
, trstart
);
678 emitir(IRTGI(IR_GE
), trslen
, tr0
);
679 trptr
= emitir(IRT(IR_STRREF
, IRT_P32
), trstr
, trstart
);
680 J
->base
[0] = emitir(IRT(IR_SNEW
, IRT_STR
), trptr
, trslen
);
681 } else { /* Range underflow: return empty string. */
682 emitir(IRTGI(IR_LT
), trend
, trstart
);
683 J
->base
[0] = lj_ir_kstr(J
, lj_str_new(J
->L
, strdata(str
), 0));
685 } else { /* Return string.byte result(s). */
686 ptrdiff_t i
, len
= end
- start
;
688 TRef trslen
= emitir(IRTI(IR_SUB
), trend
, trstart
);
689 emitir(IRTGI(IR_EQ
), trslen
, lj_ir_kint(J
, (int32_t)len
));
690 if (J
->baseslot
+ len
> LJ_MAX_JSLOTS
)
691 lj_trace_err_info(J
, LJ_TRERR_STACKOV
);
693 for (i
= 0; i
< len
; i
++) {
694 TRef tmp
= emitir(IRTI(IR_ADD
), trstart
, lj_ir_kint(J
, (int32_t)i
));
695 tmp
= emitir(IRT(IR_STRREF
, IRT_P32
), trstr
, tmp
);
696 J
->base
[i
] = emitir(IRT(IR_XLOAD
, IRT_U8
), tmp
, IRXLOAD_READONLY
);
698 } else { /* Empty range or range underflow: return no results. */
699 emitir(IRTGI(IR_LE
), trend
, trstart
);
705 /* -- Table library fast functions ---------------------------------------- */
707 static void LJ_FASTCALL
recff_table_getn(jit_State
*J
, RecordFFData
*rd
)
709 if (tref_istab(J
->base
[0]))
710 J
->base
[0] = lj_ir_call(J
, IRCALL_lj_tab_len
, J
->base
[0]);
711 /* else: Interpreter will throw. */
715 static void LJ_FASTCALL
recff_table_remove(jit_State
*J
, RecordFFData
*rd
)
717 TRef tab
= J
->base
[0];
719 if (tref_istab(tab
)) {
720 if (!J
->base
[1] || tref_isnil(J
->base
[1])) { /* Simple pop: t[#t] = nil */
721 TRef trlen
= lj_ir_call(J
, IRCALL_lj_tab_len
, tab
);
722 GCtab
*t
= tabV(&rd
->argv
[0]);
723 MSize len
= lj_tab_len(t
);
724 emitir(IRTGI(len
? IR_NE
: IR_EQ
), trlen
, lj_ir_kint(J
, 0));
729 settabV(J
->L
, &ix
.tabv
, t
);
730 setintV(&ix
.keyv
, len
);
732 if (results_wanted(J
) != 0) { /* Specialize load only if needed. */
734 J
->base
[0] = lj_record_idx(J
, &ix
); /* Load previous value. */
736 /* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */
739 lj_record_idx(J
, &ix
); /* Remove value. */
741 } else { /* Complex case: remove in the middle. */
744 } /* else: Interpreter will throw. */
747 static void LJ_FASTCALL
recff_table_insert(jit_State
*J
, RecordFFData
*rd
)
753 if (tref_istab(ix
.tab
) && ix
.val
) {
754 if (!J
->base
[2]) { /* Simple push: t[#t+1] = v */
755 TRef trlen
= lj_ir_call(J
, IRCALL_lj_tab_len
, ix
.tab
);
756 GCtab
*t
= tabV(&rd
->argv
[0]);
757 ix
.key
= emitir(IRTI(IR_ADD
), trlen
, lj_ir_kint(J
, 1));
758 settabV(J
->L
, &ix
.tabv
, t
);
759 setintV(&ix
.keyv
, lj_tab_len(t
) + 1);
761 lj_record_idx(J
, &ix
); /* Set new value. */
762 } else { /* Complex case: insert in the middle. */
765 } /* else: Interpreter will throw. */
768 /* -- I/O library fast functions ------------------------------------------ */
770 /* Get FILE* for I/O function. Any I/O error aborts recording, so there's
771 ** no need to encode the alternate cases for any of the guards.
773 static TRef
recff_io_fp(jit_State
*J
, uint32_t id
)
776 if (id
) { /* io.func() */
777 tr
= lj_ir_kptr(J
, &J2G(J
)->gcroot
[id
]);
778 ud
= emitir(IRT(IR_XLOAD
, IRT_UDATA
), tr
, 0);
779 } else { /* fp:method() */
781 if (!tref_isudata(ud
))
782 lj_trace_err(J
, LJ_TRERR_BADTYPE
);
783 tr
= emitir(IRT(IR_FLOAD
, IRT_U8
), ud
, IRFL_UDATA_UDTYPE
);
784 emitir(IRTGI(IR_EQ
), tr
, lj_ir_kint(J
, UDTYPE_IO_FILE
));
786 fp
= emitir(IRT(IR_FLOAD
, IRT_PTR
), ud
, IRFL_UDATA_FILE
);
787 emitir(IRTG(IR_NE
, IRT_PTR
), fp
, lj_ir_knull(J
, IRT_PTR
));
791 static void LJ_FASTCALL
recff_io_write(jit_State
*J
, RecordFFData
*rd
)
793 TRef fp
= recff_io_fp(J
, rd
->data
);
794 TRef zero
= lj_ir_kint(J
, 0);
795 TRef one
= lj_ir_kint(J
, 1);
796 ptrdiff_t i
= rd
->data
== 0 ? 1 : 0;
797 for (; J
->base
[i
]; i
++) {
798 TRef str
= lj_ir_tostr(J
, J
->base
[i
]);
799 TRef buf
= emitir(IRT(IR_STRREF
, IRT_P32
), str
, zero
);
800 TRef len
= emitir(IRTI(IR_FLOAD
), str
, IRFL_STR_LEN
);
801 if (tref_isk(len
) && IR(tref_ref(len
))->i
== 1) {
802 TRef tr
= emitir(IRT(IR_XLOAD
, IRT_U8
), buf
, IRXLOAD_READONLY
);
803 tr
= lj_ir_call(J
, IRCALL_fputc
, tr
, fp
);
804 if (results_wanted(J
) != 0) /* Check result only if not ignored. */
805 emitir(IRTGI(IR_NE
), tr
, lj_ir_kint(J
, -1));
807 TRef tr
= lj_ir_call(J
, IRCALL_fwrite
, buf
, one
, len
, fp
);
808 if (results_wanted(J
) != 0) /* Check result only if not ignored. */
809 emitir(IRTGI(IR_EQ
), tr
, len
);
812 J
->base
[0] = TREF_TRUE
;
815 static void LJ_FASTCALL
recff_io_flush(jit_State
*J
, RecordFFData
*rd
)
817 TRef fp
= recff_io_fp(J
, rd
->data
);
818 TRef tr
= lj_ir_call(J
, IRCALL_fflush
, fp
);
819 if (results_wanted(J
) != 0) /* Check result only if not ignored. */
820 emitir(IRTGI(IR_EQ
), tr
, lj_ir_kint(J
, 0));
821 J
->base
[0] = TREF_TRUE
;
824 /* -- Record calls to fast functions -------------------------------------- */
826 #include "lj_recdef.h"
828 static uint32_t recdef_lookup(GCfunc
*fn
)
830 if (fn
->c
.ffid
< sizeof(recff_idmap
)/sizeof(recff_idmap
[0]))
831 return recff_idmap
[fn
->c
.ffid
];
836 /* Record entry to a fast function or C function. */
837 void lj_ffrecord_func(jit_State
*J
)
840 uint32_t m
= recdef_lookup(J
->fn
);
842 rd
.nres
= 1; /* Default is one result. */
843 rd
.argv
= J
->L
->base
;
844 J
->base
[J
->maxslot
] = 0; /* Mark end of arguments. */
845 (recff_func
[m
>> 8])(J
, &rd
); /* Call recff_* handler. */
847 if (J
->postproc
== LJ_POST_NONE
) J
->postproc
= LJ_POST_FFRETRY
;
848 lj_record_ret(J
, 0, rd
.nres
);