diff options
Diffstat (limited to 'src/lj_ffrecord.c')
-rw-r--r-- | src/lj_ffrecord.c | 130 |
1 files changed, 96 insertions, 34 deletions
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 42aae8b5..6a156c7c 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c | |||
@@ -96,28 +96,81 @@ static ptrdiff_t results_wanted(jit_State *J) | |||
96 | return -1; | 96 | return -1; |
97 | } | 97 | } |
98 | 98 | ||
99 | /* Throw error for unsupported variant of fast function. */ | 99 | /* Trace stitching: add continuation below frame to start a new trace. */ |
100 | LJ_NORET static void recff_nyiu(jit_State *J) | 100 | static void recff_stitch(jit_State *J) |
101 | { | 101 | { |
102 | setfuncV(J->L, &J->errinfo, J->fn); | 102 | ASMFunction cont = lj_cont_stitch; |
103 | lj_trace_err_info(J, LJ_TRERR_NYIFFU); | 103 | TraceNo traceno = J->cur.traceno; |
104 | lua_State *L = J->L; | ||
105 | TValue *base = L->base; | ||
106 | const BCIns *pc = frame_pc(base-1); | ||
107 | TValue *pframe = frame_prevl(base-1); | ||
108 | TRef trcont; | ||
109 | |||
110 | /* Move func + args up in Lua stack and insert continuation. */ | ||
111 | memmove(&base[1], &base[-1], sizeof(TValue)*(J->maxslot+1)); | ||
112 | setframe_ftsz(base+1, (int)((char *)(base+1) - (char *)pframe) + FRAME_CONT); | ||
113 | setcont(base, cont); | ||
114 | setframe_pc(base, pc); | ||
115 | if (LJ_DUALNUM) setintV(base-1, traceno); else base[-1].u64 = traceno; | ||
116 | L->base += 2; | ||
117 | L->top += 2; | ||
118 | |||
119 | /* Ditto for the IR. */ | ||
120 | memmove(&J->base[1], &J->base[-1], sizeof(TRef)*(J->maxslot+1)); | ||
121 | #if LJ_64 | ||
122 | trcont = lj_ir_kptr(J, (void *)((int64_t)cont-(int64_t)lj_vm_asm_begin)); | ||
123 | #else | ||
124 | trcont = lj_ir_kptr(J, (void *)cont); | ||
125 | #endif | ||
126 | J->base[0] = trcont | TREF_CONT; | ||
127 | J->base[-1] = LJ_DUALNUM ? lj_ir_kint(J,traceno) : lj_ir_knum_u64(J,traceno); | ||
128 | J->maxslot += 2; | ||
129 | J->framedepth++; | ||
130 | |||
131 | lj_record_stop(J, LJ_TRLINK_STITCH, 0); | ||
132 | |||
133 | /* Undo Lua stack changes. */ | ||
134 | memmove(&base[-1], &base[1], sizeof(TValue)*(J->maxslot+1)); | ||
135 | setframe_pc(base-1, pc); | ||
136 | L->base -= 2; | ||
137 | L->top -= 2; | ||
104 | } | 138 | } |
105 | 139 | ||
106 | /* Fallback handler for all fast functions that are not recorded (yet). */ | 140 | /* Fallback handler for fast functions that are not recorded (yet). */ |
107 | static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) | 141 | static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) |
108 | { | 142 | { |
109 | setfuncV(J->L, &J->errinfo, J->fn); | 143 | if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) { |
110 | lj_trace_err_info(J, LJ_TRERR_NYIFF); | 144 | lj_trace_err_info(J, LJ_TRERR_TRACEUV); |
111 | UNUSED(rd); | 145 | } else { |
146 | /* Can only stitch from Lua call. */ | ||
147 | if (J->framedepth && frame_islua(J->L->base-1)) { | ||
148 | BCOp op = bc_op(*frame_pc(J->L->base-1)); | ||
149 | /* Stitched trace cannot start with *M op with variable # of args. */ | ||
150 | if (!(op == BC_CALLM || op == BC_RETM || op == BC_TSETM)) { | ||
151 | switch (J->fn->c.ffid) { | ||
152 | case FF_error: | ||
153 | case FF_debug_sethook: | ||
154 | case FF_jit_flush: | ||
155 | break; /* Don't stitch across special builtins. */ | ||
156 | default: | ||
157 | recff_stitch(J); /* Use trace stitching. */ | ||
158 | rd->nres = -1; | ||
159 | return; | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | /* Otherwise stop trace and return to interpreter. */ | ||
164 | lj_record_stop(J, LJ_TRLINK_RETURN, 0); | ||
165 | rd->nres = -1; | ||
166 | } | ||
112 | } | 167 | } |
113 | 168 | ||
114 | /* C functions can have arbitrary side-effects and are not recorded (yet). */ | 169 | /* Fallback handler for unsupported variants of fast functions. */ |
115 | static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd) | 170 | #define recff_nyiu recff_nyi |
116 | { | 171 | |
117 | setfuncV(J->L, &J->errinfo, J->fn); | 172 | /* Must stop the trace for classic C functions with arbitrary side-effects. */ |
118 | lj_trace_err_info(J, LJ_TRERR_NYICF); | 173 | #define recff_c recff_nyi |
119 | UNUSED(rd); | ||
120 | } | ||
121 | 174 | ||
122 | /* Emit BUFHDR for the global temporary buffer. */ | 175 | /* Emit BUFHDR for the global temporary buffer. */ |
123 | static TRef recff_bufhdr(jit_State *J) | 176 | static TRef recff_bufhdr(jit_State *J) |
@@ -268,7 +321,8 @@ static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd) | |||
268 | J->base[i] = J->base[start+i]; | 321 | J->base[i] = J->base[start+i]; |
269 | } /* else: Interpreter will throw. */ | 322 | } /* else: Interpreter will throw. */ |
270 | } else { | 323 | } else { |
271 | recff_nyiu(J); | 324 | recff_nyiu(J, rd); |
325 | return; | ||
272 | } | 326 | } |
273 | } /* else: Interpreter will throw. */ | 327 | } /* else: Interpreter will throw. */ |
274 | } | 328 | } |
@@ -279,14 +333,18 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd) | |||
279 | TRef base = J->base[1]; | 333 | TRef base = J->base[1]; |
280 | if (tr && !tref_isnil(base)) { | 334 | if (tr && !tref_isnil(base)) { |
281 | base = lj_opt_narrow_toint(J, base); | 335 | base = lj_opt_narrow_toint(J, base); |
282 | if (!tref_isk(base) || IR(tref_ref(base))->i != 10) | 336 | if (!tref_isk(base) || IR(tref_ref(base))->i != 10) { |
283 | recff_nyiu(J); | 337 | recff_nyiu(J, rd); |
338 | return; | ||
339 | } | ||
284 | } | 340 | } |
285 | if (tref_isnumber_str(tr)) { | 341 | if (tref_isnumber_str(tr)) { |
286 | if (tref_isstr(tr)) { | 342 | if (tref_isstr(tr)) { |
287 | TValue tmp; | 343 | TValue tmp; |
288 | if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) | 344 | if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) { |
289 | recff_nyiu(J); /* Would need an inverted STRTO for this case. */ | 345 | recff_nyiu(J, rd); /* Would need an inverted STRTO for this case. */ |
346 | return; | ||
347 | } | ||
290 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); | 348 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); |
291 | } | 349 | } |
292 | #if LJ_HASFFI | 350 | #if LJ_HASFFI |
@@ -348,7 +406,8 @@ static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) | |||
348 | } else if (tref_ispri(tr)) { | 406 | } else if (tref_ispri(tr)) { |
349 | J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0])); | 407 | J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0])); |
350 | } else { | 408 | } else { |
351 | recff_nyiu(J); | 409 | recff_nyiu(J, rd); |
410 | return; | ||
352 | } | 411 | } |
353 | } | 412 | } |
354 | } | 413 | } |
@@ -370,14 +429,14 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd) | |||
370 | } /* else: Interpreter will throw. */ | 429 | } /* else: Interpreter will throw. */ |
371 | } | 430 | } |
372 | 431 | ||
373 | static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) | 432 | static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd) |
374 | { | 433 | { |
375 | if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) { | 434 | if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) { |
376 | TRef tab = J->base[0]; | 435 | TRef tab = J->base[0]; |
377 | if (tref_istab(tab)) { | 436 | if (tref_istab(tab)) { |
378 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); | 437 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); |
379 | J->base[1] = tab; | 438 | J->base[1] = tab; |
380 | J->base[2] = lj_ir_kint(J, 0); | 439 | J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL; |
381 | rd->nres = 3; | 440 | rd->nres = 3; |
382 | } /* else: Interpreter will throw. */ | 441 | } /* else: Interpreter will throw. */ |
383 | } | 442 | } |
@@ -431,8 +490,7 @@ static void LJ_FASTCALL recff_getfenv(jit_State *J, RecordFFData *rd) | |||
431 | J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV); | 490 | J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV); |
432 | return; | 491 | return; |
433 | } | 492 | } |
434 | recff_nyiu(J); | 493 | recff_nyiu(J, rd); |
435 | UNUSED(rd); | ||
436 | } | 494 | } |
437 | 495 | ||
438 | /* -- Math library fast functions ----------------------------------------- */ | 496 | /* -- Math library fast functions ----------------------------------------- */ |
@@ -672,8 +730,7 @@ static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd) | |||
672 | TRef tr = recff_bit64_tohex(J, rd, hdr); | 730 | TRef tr = recff_bit64_tohex(J, rd, hdr); |
673 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); | 731 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); |
674 | #else | 732 | #else |
675 | UNUSED(rd); | 733 | recff_nyiu(J, rd); /* Don't bother working around this NYI. */ |
676 | recff_nyiu(J); /* Don't bother working around this NYI. */ | ||
677 | #endif | 734 | #endif |
678 | } | 735 | } |
679 | 736 | ||
@@ -891,7 +948,8 @@ static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd) | |||
891 | J->base[0] = TREF_NIL; | 948 | J->base[0] = TREF_NIL; |
892 | } | 949 | } |
893 | } else { /* Search for pattern. */ | 950 | } else { /* Search for pattern. */ |
894 | recff_nyiu(J); | 951 | recff_nyiu(J, rd); |
952 | return; | ||
895 | } | 953 | } |
896 | } | 954 | } |
897 | 955 | ||
@@ -931,7 +989,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | |||
931 | tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra); | 989 | tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra); |
932 | lj_needsplit(J); | 990 | lj_needsplit(J); |
933 | #else | 991 | #else |
934 | recff_nyiu(J); /* Don't bother working around this NYI. */ | 992 | recff_nyiu(J, rd); /* Don't bother working around this NYI. */ |
993 | return; | ||
935 | #endif | 994 | #endif |
936 | } | 995 | } |
937 | break; | 996 | break; |
@@ -946,8 +1005,10 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | |||
946 | if (LJ_SOFTFP) lj_needsplit(J); | 1005 | if (LJ_SOFTFP) lj_needsplit(J); |
947 | break; | 1006 | break; |
948 | case STRFMT_STR: | 1007 | case STRFMT_STR: |
949 | if (!tref_isstr(tra)) | 1008 | if (!tref_isstr(tra)) { |
950 | recff_nyiu(J); /* NYI: __tostring and non-string types for %s. */ | 1009 | recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */ |
1010 | return; | ||
1011 | } | ||
951 | if (sf == STRFMT_STR) /* Shortcut for plain %s. */ | 1012 | if (sf == STRFMT_STR) /* Shortcut for plain %s. */ |
952 | tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra); | 1013 | tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra); |
953 | else if ((sf & STRFMT_T_QUOTED)) | 1014 | else if ((sf & STRFMT_T_QUOTED)) |
@@ -966,8 +1027,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | |||
966 | case STRFMT_PTR: /* NYI */ | 1027 | case STRFMT_PTR: /* NYI */ |
967 | case STRFMT_ERR: | 1028 | case STRFMT_ERR: |
968 | default: | 1029 | default: |
969 | recff_nyiu(J); | 1030 | recff_nyiu(J, rd); |
970 | break; | 1031 | return; |
971 | } | 1032 | } |
972 | } | 1033 | } |
973 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); | 1034 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); |
@@ -991,7 +1052,8 @@ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) | |||
991 | ix.idxchain = 0; | 1052 | ix.idxchain = 0; |
992 | lj_record_idx(J, &ix); /* Set new value. */ | 1053 | lj_record_idx(J, &ix); /* Set new value. */ |
993 | } else { /* Complex case: insert in the middle. */ | 1054 | } else { /* Complex case: insert in the middle. */ |
994 | recff_nyiu(J); | 1055 | recff_nyiu(J, rd); |
1056 | return; | ||
995 | } | 1057 | } |
996 | } /* else: Interpreter will throw. */ | 1058 | } /* else: Interpreter will throw. */ |
997 | } | 1059 | } |