diff options
author | Mike Pall <mike> | 2010-02-16 04:04:16 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-02-16 04:04:16 +0100 |
commit | c225ee8db4300e1dbf13fcdfc15d8f44da175877 (patch) | |
tree | 529d92ad755f5753cc9c98ddb8d56ae9c3700e2c | |
parent | afa07e0c4645289c6c00541c653b190394b150a1 (diff) | |
download | luajit-c225ee8db4300e1dbf13fcdfc15d8f44da175877.tar.gz luajit-c225ee8db4300e1dbf13fcdfc15d8f44da175877.tar.bz2 luajit-c225ee8db4300e1dbf13fcdfc15d8f44da175877.zip |
Split CALL/FUNC recording.
Record __call resolving and specialization for CALL* bytecodes.
Record argument adjustment and fast functions for FUNC* bytecodes.
Avoids all pending/immediate decisions for chained fast functions.
Cleaner semantics for pcall(), xpcall() and __tostring metamethod.
Prerequisite to drop the shadow frame link stack again.
-rw-r--r-- | src/lj_dispatch.c | 11 | ||||
-rw-r--r-- | src/lj_record.c | 891 |
2 files changed, 455 insertions, 447 deletions
diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c index 29b06438..4629fb7e 100644 --- a/src/lj_dispatch.c +++ b/src/lj_dispatch.c | |||
@@ -71,7 +71,8 @@ void lj_dispatch_update(global_State *g) | |||
71 | uint8_t mode = 0; | 71 | uint8_t mode = 0; |
72 | #if LJ_HASJIT | 72 | #if LJ_HASJIT |
73 | mode |= (G2J(g)->flags & JIT_F_ON) ? DISPMODE_JIT : 0; | 73 | mode |= (G2J(g)->flags & JIT_F_ON) ? DISPMODE_JIT : 0; |
74 | mode |= G2J(g)->state != LJ_TRACE_IDLE ? (DISPMODE_REC|DISPMODE_INS) : 0; | 74 | mode |= G2J(g)->state != LJ_TRACE_IDLE ? |
75 | (DISPMODE_REC|DISPMODE_INS|DISPMODE_CALL) : 0; | ||
75 | #endif | 76 | #endif |
76 | mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0; | 77 | mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0; |
77 | mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0; | 78 | mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0; |
@@ -398,7 +399,7 @@ static void call_init(lua_State *L, GCfunc *fn) | |||
398 | } | 399 | } |
399 | } | 400 | } |
400 | 401 | ||
401 | /* Call dispatch. Used by call hooks and hot calls. */ | 402 | /* Call dispatch. Used by call hooks, hot calls or when recording. */ |
402 | ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc) | 403 | ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc) |
403 | { | 404 | { |
404 | GCfunc *fn = curr_func(L); | 405 | GCfunc *fn = curr_func(L); |
@@ -409,10 +410,14 @@ ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc) | |||
409 | #endif | 410 | #endif |
410 | call_init(L, fn); | 411 | call_init(L, fn); |
411 | #if LJ_HASJIT | 412 | #if LJ_HASJIT |
413 | J->L = L; | ||
412 | if ((uintptr_t)pc & 1) { /* Marker for hot call. */ | 414 | if ((uintptr_t)pc & 1) { /* Marker for hot call. */ |
413 | J->L = L; | ||
414 | lj_trace_hot(J, (const BCIns *)((uintptr_t)pc & ~(uintptr_t)1)); | 415 | lj_trace_hot(J, (const BCIns *)((uintptr_t)pc & ~(uintptr_t)1)); |
415 | goto out; | 416 | goto out; |
417 | } else if (J->state != LJ_TRACE_IDLE && | ||
418 | !(g->hookmask & (HOOK_GC|HOOK_VMEVENT))) { | ||
419 | /* Record the FUNC* bytecodes, too. */ | ||
420 | lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */ | ||
416 | } | 421 | } |
417 | #endif | 422 | #endif |
418 | if ((g->hookmask & LUA_MASKCALL)) | 423 | if ((g->hookmask & LUA_MASKCALL)) |
diff --git a/src/lj_record.c b/src/lj_record.c index ed882f1e..5d99f3a4 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -53,18 +53,9 @@ typedef struct RecordIndex { | |||
53 | int idxchain; /* Index indirections left or 0 for raw lookup. */ | 53 | int idxchain; /* Index indirections left or 0 for raw lookup. */ |
54 | } RecordIndex; | 54 | } RecordIndex; |
55 | 55 | ||
56 | /* Requested results from rec_call(). */ | ||
57 | enum { | ||
58 | /* Non-negative numbers are number of requested results. */ | ||
59 | CALLRES_MULTI = -1, /* Return multiple results. */ | ||
60 | CALLRES_TAILCALL = -2, /* Tail call. */ | ||
61 | CALLRES_PENDING = -3, /* Call is pending, no results yet. */ | ||
62 | CALLRES_CONT = -4 /* Continuation call. */ | ||
63 | }; | ||
64 | |||
65 | /* Forward declarations. */ | 56 | /* Forward declarations. */ |
57 | static int rec_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm); | ||
66 | static TRef rec_idx(jit_State *J, RecordIndex *ix); | 58 | static TRef rec_idx(jit_State *J, RecordIndex *ix); |
67 | static int rec_call(jit_State *J, BCReg func, ptrdiff_t cres, ptrdiff_t nargs); | ||
68 | 59 | ||
69 | /* -- Sanity checks ------------------------------------------------------- */ | 60 | /* -- Sanity checks ------------------------------------------------------- */ |
70 | 61 | ||
@@ -474,6 +465,126 @@ static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) | |||
474 | } /* Side trace continues across a loop that's left or not entered. */ | 465 | } /* Side trace continues across a loop that's left or not entered. */ |
475 | } | 466 | } |
476 | 467 | ||
468 | /* -- Record calls and returns -------------------------------------------- */ | ||
469 | |||
470 | /* Record call. */ | ||
471 | static void rec_call(jit_State *J, BCReg func, ptrdiff_t nargs) | ||
472 | { | ||
473 | RecordIndex ix; | ||
474 | TValue *functv = &J->L->base[func]; | ||
475 | TRef trfunc, *fbase = &J->base[func]; | ||
476 | |||
477 | if (!tref_isfunc(fbase[0])) { /* Resolve __call metamethod. */ | ||
478 | ptrdiff_t i; | ||
479 | ix.tab = fbase[0]; | ||
480 | copyTV(J->L, &ix.tabv, functv); | ||
481 | if (!rec_mm_lookup(J, &ix, MM_call) || !tref_isfunc(ix.mobj)) | ||
482 | lj_trace_err(J, LJ_TRERR_NOMM); | ||
483 | for (i = ++nargs; i > 0; i--) /* Shift arguments up. */ | ||
484 | fbase[i] = fbase[i-1]; | ||
485 | fbase[0] = ix.mobj; /* Replace function. */ | ||
486 | functv = &ix.mobjv; | ||
487 | } | ||
488 | |||
489 | /* Specialize to the runtime value of the called function. */ | ||
490 | trfunc = lj_ir_kfunc(J, funcV(functv)); | ||
491 | emitir(IRTG(IR_EQ, IRT_FUNC), fbase[0], trfunc); | ||
492 | fbase[0] = trfunc | TREF_FRAME; | ||
493 | |||
494 | /* Bump frame. */ | ||
495 | J->frame[J->framedepth++] = SNAP_MKPC(J->pc+1); | ||
496 | if (J->framedepth > LJ_MAX_JFRAME) | ||
497 | lj_trace_err(J, LJ_TRERR_STACKOV); | ||
498 | J->base += func+1; | ||
499 | J->baseslot += func+1; | ||
500 | J->maxslot = nargs; | ||
501 | } | ||
502 | |||
503 | /* Record tail call. */ | ||
504 | static void rec_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs) | ||
505 | { | ||
506 | rec_call(J, func, nargs); | ||
507 | /* Move func + args down. */ | ||
508 | J->framedepth--; | ||
509 | J->base -= func+1; | ||
510 | J->baseslot -= func+1; | ||
511 | memmove(&J->base[-1], &J->base[func], sizeof(TRef)*(J->maxslot+1)); | ||
512 | /* Note: the new TREF_FRAME is now at J->base[-1] (even for slot #0). */ | ||
513 | } | ||
514 | |||
515 | /* Record return. */ | ||
516 | static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | ||
517 | { | ||
518 | TValue *frame = J->L->base - 1; | ||
519 | ptrdiff_t i; | ||
520 | for (i = 0; i < gotresults; i++) | ||
521 | getslot(J, rbase+i); /* Ensure all results have a reference. */ | ||
522 | while (frame_ispcall(frame)) { /* Immediately resolve pcall() returns. */ | ||
523 | BCReg cbase = (BCReg)frame_delta(frame); | ||
524 | if (--J->framedepth < 0) | ||
525 | lj_trace_err(J, LJ_TRERR_NYIRETL); | ||
526 | lua_assert(J->baseslot > 1); | ||
527 | J->base[--rbase] = TREF_TRUE; /* Prepend true to results. */ | ||
528 | gotresults++; | ||
529 | rbase += cbase; | ||
530 | J->baseslot -= (BCReg)cbase; | ||
531 | J->base -= cbase; | ||
532 | frame = frame_prevd(frame); | ||
533 | } | ||
534 | if (frame_islua(frame)) { /* Return to Lua frame. */ | ||
535 | BCIns callins = *(frame_pc(frame)-1); | ||
536 | ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults; | ||
537 | BCReg cbase = bc_a(callins); | ||
538 | for (i = 0; i < nresults; i++) /* Adjust results. */ | ||
539 | J->base[i-1] = i < gotresults ? J->base[rbase+i] : TREF_NIL; | ||
540 | J->maxslot = cbase+(BCReg)nresults; | ||
541 | if (J->framedepth > 0) { /* Return to a frame that is part of the trace. */ | ||
542 | J->framedepth--; | ||
543 | lua_assert(J->baseslot > cbase+1); | ||
544 | J->baseslot -= cbase+1; | ||
545 | J->base -= cbase+1; | ||
546 | } else if (J->parent == 0) { | ||
547 | /* Return to lower frame would leave the loop in a root trace. */ | ||
548 | lj_trace_err(J, LJ_TRERR_LLEAVE); | ||
549 | } else { /* Return to lower frame. Guard for the target we return to. */ | ||
550 | GCproto *pt = funcproto(frame_func(frame - (cbase+1))); | ||
551 | TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); | ||
552 | TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame)); | ||
553 | emitir(IRTG(IR_RETF, IRT_PTR), trpt, trpc); | ||
554 | J->retdepth++; | ||
555 | J->needsnap = 1; | ||
556 | lua_assert(J->baseslot == 1); | ||
557 | /* Shift result slots up and clear the slots of the new frame below. */ | ||
558 | memmove(J->base + cbase, J->base-1, sizeof(TRef)*nresults); | ||
559 | memset(J->base-1, 0, sizeof(TRef)*(cbase+1)); | ||
560 | } | ||
561 | } else if (frame_iscont(frame)) { /* Return to continuation frame. */ | ||
562 | ASMFunction cont = frame_contf(frame); | ||
563 | BCReg cbase = (BCReg)frame_delta(frame); | ||
564 | if ((J->framedepth -= 2) < 0) | ||
565 | lj_trace_err(J, LJ_TRERR_NYIRETL); | ||
566 | J->baseslot -= (BCReg)cbase; | ||
567 | J->base -= cbase; | ||
568 | J->maxslot = cbase-2; | ||
569 | if (cont == lj_cont_ra) { | ||
570 | /* Copy result to destination slot. */ | ||
571 | BCReg dst = bc_a(*(frame_contpc(frame)-1)); | ||
572 | J->base[dst] = gotresults ? J->base[cbase+rbase] : TREF_NIL; | ||
573 | if (dst > J->maxslot) J->maxslot = dst+1; | ||
574 | } else if (cont == lj_cont_nop) { | ||
575 | /* Nothing to do here. */ | ||
576 | } else if (cont == lj_cont_cat) { | ||
577 | lua_assert(0); | ||
578 | } else { | ||
579 | /* Result type already specialized. */ | ||
580 | lua_assert(cont == lj_cont_condf || cont == lj_cont_condt); | ||
581 | } | ||
582 | } else { | ||
583 | lj_trace_err(J, LJ_TRERR_NYIRETL); /* NYI: handle return to C frame. */ | ||
584 | } | ||
585 | lua_assert(J->baseslot >= 1); | ||
586 | } | ||
587 | |||
477 | /* -- Metamethod handling ------------------------------------------------- */ | 588 | /* -- Metamethod handling ------------------------------------------------- */ |
478 | 589 | ||
479 | /* Prepare to record call to metamethod. */ | 590 | /* Prepare to record call to metamethod. */ |
@@ -556,7 +667,9 @@ static TRef rec_mm_arith(jit_State *J, RecordIndex *ix, MMS mm) | |||
556 | ok: | 667 | ok: |
557 | base[0] = ix->mobj; | 668 | base[0] = ix->mobj; |
558 | copyTV(J->L, basev+0, &ix->mobjv); | 669 | copyTV(J->L, basev+0, &ix->mobjv); |
559 | return rec_call(J, func, CALLRES_CONT, 2) ? J->base[func] : 0; | 670 | rec_call(J, func, 2); |
671 | J->frame[J->framedepth++] = SNAP_MKFTSZ((func+1)*sizeof(TValue)+FRAME_CONT); | ||
672 | return 0; /* No result yet. */ | ||
560 | } | 673 | } |
561 | 674 | ||
562 | /* Call a comparison metamethod. */ | 675 | /* Call a comparison metamethod. */ |
@@ -569,11 +682,8 @@ static void rec_mm_callcomp(jit_State *J, RecordIndex *ix, int op) | |||
569 | copyTV(J->L, tv+0, &ix->mobjv); | 682 | copyTV(J->L, tv+0, &ix->mobjv); |
570 | copyTV(J->L, tv+1, &ix->valv); | 683 | copyTV(J->L, tv+1, &ix->valv); |
571 | copyTV(J->L, tv+2, &ix->keyv); | 684 | copyTV(J->L, tv+2, &ix->keyv); |
572 | rec_call(J, func, CALLRES_CONT, 2); | 685 | rec_call(J, func, 2); |
573 | /* It doesn't matter whether this is immediately resolved or not. | 686 | J->frame[J->framedepth++] = SNAP_MKFTSZ((func+1)*sizeof(TValue)+FRAME_CONT); |
574 | ** Type specialization of the return type suffices to specialize | ||
575 | ** the control flow. | ||
576 | */ | ||
577 | } | 687 | } |
578 | 688 | ||
579 | /* Record call to equality comparison metamethod (for tab and udata only). */ | 689 | /* Record call to equality comparison metamethod (for tab and udata only). */ |
@@ -752,11 +862,13 @@ static TRef rec_idx(jit_State *J, RecordIndex *ix) | |||
752 | if (ix->val) { | 862 | if (ix->val) { |
753 | base[3] = ix->val; | 863 | base[3] = ix->val; |
754 | copyTV(J->L, tv+3, &ix->valv); | 864 | copyTV(J->L, tv+3, &ix->valv); |
755 | rec_call(J, func, CALLRES_CONT, 3); /* mobj(tab, key, val) */ | 865 | rec_call(J, func, 3); /* mobj(tab, key, val) */ |
866 | J->frame[J->framedepth++] = SNAP_MKFTSZ((func+1)*sizeof(TValue)+FRAME_CONT); | ||
756 | return 0; | 867 | return 0; |
757 | } else { | 868 | } else { |
758 | /* res = mobj(tab, key) */ | 869 | rec_call(J, func, 2); /* res = mobj(tab, key) */ |
759 | return rec_call(J, func, CALLRES_CONT, 2) ? J->base[func] : 0; | 870 | J->frame[J->framedepth++] = SNAP_MKFTSZ((func+1)*sizeof(TValue)+FRAME_CONT); |
871 | return 0; /* No result yet. */ | ||
760 | } | 872 | } |
761 | } | 873 | } |
762 | /* Otherwise retry lookup with metaobject. */ | 874 | /* Otherwise retry lookup with metaobject. */ |
@@ -915,19 +1027,12 @@ static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val) | |||
915 | /* Data used by handlers to record a fast function. */ | 1027 | /* Data used by handlers to record a fast function. */ |
916 | typedef struct RecordFFData { | 1028 | typedef struct RecordFFData { |
917 | TValue *argv; /* Runtime argument values. */ | 1029 | TValue *argv; /* Runtime argument values. */ |
918 | GCfunc *fn; /* The currently recorded function. */ | ||
919 | ptrdiff_t nargs; /* Number of passed arguments. */ | ||
920 | ptrdiff_t nres; /* Number of returned results (defaults to 1). */ | 1030 | ptrdiff_t nres; /* Number of returned results (defaults to 1). */ |
921 | ptrdiff_t cres; /* Wanted number of call results. */ | ||
922 | uint32_t data; /* Per-ffid auxiliary data (opcode, literal etc.). */ | 1031 | uint32_t data; /* Per-ffid auxiliary data (opcode, literal etc.). */ |
923 | int metacall; /* True if function was resolved via __call. */ | ||
924 | } RecordFFData; | 1032 | } RecordFFData; |
925 | 1033 | ||
926 | /* Type of handler to record a fast function. */ | 1034 | /* Type of handler to record a fast function. */ |
927 | typedef void (*RecordFunc)(jit_State *J, TRef *res, RecordFFData *rd); | 1035 | typedef void (LJ_FASTCALL *RecordFunc)(jit_State *J, RecordFFData *rd); |
928 | |||
929 | /* Avoid carrying two pointers around. */ | ||
930 | #define arg (res+1) | ||
931 | 1036 | ||
932 | /* Get runtime value of int argument. */ | 1037 | /* Get runtime value of int argument. */ |
933 | static int32_t argv2int(jit_State *J, TValue *o) | 1038 | static int32_t argv2int(jit_State *J, TValue *o) |
@@ -951,65 +1056,73 @@ static GCstr *argv2str(jit_State *J, TValue *o) | |||
951 | } | 1056 | } |
952 | } | 1057 | } |
953 | 1058 | ||
954 | /* Fallback handler for all fast functions that are not recorded (yet). */ | 1059 | /* Return number of results wanted by caller. */ |
955 | static void recff_nyi(jit_State *J, TRef *res, RecordFFData *rd) | 1060 | static ptrdiff_t results_wanted(jit_State *J) |
956 | { | 1061 | { |
957 | UNUSED(res); | 1062 | TValue *frame = J->L->base-1; |
958 | setfuncV(J->L, &J->errinfo, rd->fn); | 1063 | if (frame_islua(frame)) |
959 | lj_trace_err_info(J, LJ_TRERR_NYIFF); | 1064 | return (ptrdiff_t)bc_b(frame_pc(frame)[-1]) - 1; |
1065 | else | ||
1066 | return -1; | ||
960 | } | 1067 | } |
961 | 1068 | ||
962 | LJ_NORET static void recff_err_nyi(jit_State *J, RecordFFData *rd) | 1069 | /* Throw error for unsupported variant of fast function. */ |
1070 | LJ_NORET static void recff_nyiu(jit_State *J) | ||
963 | { | 1071 | { |
964 | setfuncV(J->L, &J->errinfo, rd->fn); | 1072 | setfuncV(J->L, &J->errinfo, J->fn); |
965 | lj_trace_err_info(J, LJ_TRERR_NYIFFU); | 1073 | lj_trace_err_info(J, LJ_TRERR_NYIFFU); |
966 | } | 1074 | } |
967 | 1075 | ||
1076 | /* Fallback handler for all fast functions that are not recorded (yet). */ | ||
1077 | static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) | ||
1078 | { | ||
1079 | setfuncV(J->L, &J->errinfo, J->fn); | ||
1080 | lj_trace_err_info(J, LJ_TRERR_NYIFF); | ||
1081 | UNUSED(rd); | ||
1082 | } | ||
1083 | |||
968 | /* C functions can have arbitrary side-effects and are not recorded (yet). */ | 1084 | /* C functions can have arbitrary side-effects and are not recorded (yet). */ |
969 | static void recff_c(jit_State *J, TRef *res, RecordFFData *rd) | 1085 | static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd) |
970 | { | 1086 | { |
971 | UNUSED(res); | 1087 | setfuncV(J->L, &J->errinfo, J->fn); |
972 | setlightudV(&J->errinfo, (void *)rd->fn->c.f); | ||
973 | lj_trace_err_info(J, LJ_TRERR_NYICF); | 1088 | lj_trace_err_info(J, LJ_TRERR_NYICF); |
1089 | UNUSED(rd); | ||
974 | } | 1090 | } |
975 | 1091 | ||
976 | /* -- Base library fast functions ----------------------------------------- */ | 1092 | /* -- Base library fast functions ----------------------------------------- */ |
977 | 1093 | ||
978 | static void recff_assert(jit_State *J, TRef *res, RecordFFData *rd) | 1094 | static void LJ_FASTCALL recff_assert(jit_State *J, RecordFFData *rd) |
979 | { | 1095 | { |
980 | /* Arguments already specialized. The interpreter throws for nil/false. */ | 1096 | /* Arguments already specialized. The interpreter throws for nil/false. */ |
981 | ptrdiff_t i; | 1097 | rd->nres = J->maxslot; /* Pass through all arguments. */ |
982 | for (i = 0; arg[i]; i++) /* Need to pass through all arguments. */ | ||
983 | res[i] = arg[i]; | ||
984 | rd->nres = i; | ||
985 | UNUSED(J); | ||
986 | } | 1098 | } |
987 | 1099 | ||
988 | static void recff_type(jit_State *J, TRef *res, RecordFFData *rd) | 1100 | static void LJ_FASTCALL recff_type(jit_State *J, RecordFFData *rd) |
989 | { | 1101 | { |
990 | /* Arguments already specialized. Result is a constant string. Neat, huh? */ | 1102 | /* Arguments already specialized. Result is a constant string. Neat, huh? */ |
991 | IRType t = tref_isinteger(arg[0]) ? IRT_NUM : tref_type(arg[0]); | 1103 | IRType t = tref_isinteger(J->base[0]) ? IRT_NUM : tref_type(J->base[0]); |
992 | res[0] = lj_ir_kstr(J, strV(&rd->fn->c.upvalue[t])); | 1104 | J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[t])); |
1105 | UNUSED(rd); | ||
993 | } | 1106 | } |
994 | 1107 | ||
995 | static void recff_getmetatable(jit_State *J, TRef *res, RecordFFData *rd) | 1108 | static void LJ_FASTCALL recff_getmetatable(jit_State *J, RecordFFData *rd) |
996 | { | 1109 | { |
997 | TRef tr = arg[0]; | 1110 | TRef tr = J->base[0]; |
998 | if (tref_istab(tr)) { | 1111 | if (tref_istab(tr)) { |
999 | RecordIndex ix; | 1112 | RecordIndex ix; |
1000 | ix.tab = tr; | 1113 | ix.tab = tr; |
1001 | copyTV(J->L, &ix.tabv, &rd->argv[0]); | 1114 | copyTV(J->L, &ix.tabv, &rd->argv[0]); |
1002 | if (rec_mm_lookup(J, &ix, MM_metatable)) | 1115 | if (rec_mm_lookup(J, &ix, MM_metatable)) |
1003 | res[0] = ix.mobj; | 1116 | J->base[0] = ix.mobj; |
1004 | else | 1117 | else |
1005 | res[0] = ix.mt; | 1118 | J->base[0] = ix.mt; |
1006 | } /* else: Interpreter will throw. */ | 1119 | } /* else: Interpreter will throw. */ |
1007 | } | 1120 | } |
1008 | 1121 | ||
1009 | static void recff_setmetatable(jit_State *J, TRef *res, RecordFFData *rd) | 1122 | static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd) |
1010 | { | 1123 | { |
1011 | TRef tr = arg[0]; | 1124 | TRef tr = J->base[0]; |
1012 | TRef mt = arg[1]; | 1125 | TRef mt = J->base[1]; |
1013 | if (tref_istab(tr) && (tref_istab(mt) || (mt && tref_isnil(mt)))) { | 1126 | if (tref_istab(tr) && (tref_istab(mt) || (mt && tref_isnil(mt)))) { |
1014 | TRef fref, mtref; | 1127 | TRef fref, mtref; |
1015 | RecordIndex ix; | 1128 | RecordIndex ix; |
@@ -1021,227 +1134,213 @@ static void recff_setmetatable(jit_State *J, TRef *res, RecordFFData *rd) | |||
1021 | emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref); | 1134 | emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref); |
1022 | if (!tref_isnil(mt)) | 1135 | if (!tref_isnil(mt)) |
1023 | emitir(IRT(IR_TBAR, IRT_TAB), tr, 0); | 1136 | emitir(IRT(IR_TBAR, IRT_TAB), tr, 0); |
1024 | res[0] = tr; | 1137 | J->base[0] = tr; |
1025 | J->needsnap = 1; | 1138 | J->needsnap = 1; |
1026 | } /* else: Interpreter will throw. */ | 1139 | } /* else: Interpreter will throw. */ |
1027 | } | 1140 | } |
1028 | 1141 | ||
1029 | static void recff_rawget(jit_State *J, TRef *res, RecordFFData *rd) | 1142 | static void LJ_FASTCALL recff_rawget(jit_State *J, RecordFFData *rd) |
1030 | { | 1143 | { |
1031 | if (tref_istab(arg[0]) && arg[1]) { | 1144 | RecordIndex ix; |
1032 | RecordIndex ix; | 1145 | ix.tab = J->base[0]; ix.key = J->base[1]; |
1033 | ix.tab = arg[0]; ix.key = arg[1]; ix.val = 0; ix.idxchain = 0; | 1146 | if (tref_istab(ix.tab) && ix.key) { |
1147 | ix.val = 0; ix.idxchain = 0; | ||
1034 | settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); | 1148 | settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); |
1035 | copyTV(J->L, &ix.keyv, &rd->argv[1]); | 1149 | copyTV(J->L, &ix.keyv, &rd->argv[1]); |
1036 | res[0] = rec_idx(J, &ix); | 1150 | J->base[0] = rec_idx(J, &ix); |
1037 | } /* else: Interpreter will throw. */ | 1151 | } /* else: Interpreter will throw. */ |
1038 | } | 1152 | } |
1039 | 1153 | ||
1040 | static void recff_rawset(jit_State *J, TRef *res, RecordFFData *rd) | 1154 | static void LJ_FASTCALL recff_rawset(jit_State *J, RecordFFData *rd) |
1041 | { | 1155 | { |
1042 | if (tref_istab(arg[0]) && arg[1] && arg[2]) { | 1156 | RecordIndex ix; |
1043 | RecordIndex ix; | 1157 | ix.tab = J->base[0]; ix.key = J->base[1]; ix.val = J->base[2]; |
1044 | ix.tab = arg[0]; ix.key = arg[1]; ix.val = arg[2]; ix.idxchain = 0; | 1158 | if (tref_istab(ix.tab) && ix.key && ix.val) { |
1159 | ix.idxchain = 0; | ||
1045 | settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); | 1160 | settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); |
1046 | copyTV(J->L, &ix.keyv, &rd->argv[1]); | 1161 | copyTV(J->L, &ix.keyv, &rd->argv[1]); |
1047 | copyTV(J->L, &ix.valv, &rd->argv[2]); | 1162 | copyTV(J->L, &ix.valv, &rd->argv[2]); |
1048 | rec_idx(J, &ix); | 1163 | rec_idx(J, &ix); |
1049 | res[0] = arg[0]; /* Returns table. */ | 1164 | /* Pass through table at J->base[0] as result. */ |
1050 | } /* else: Interpreter will throw. */ | 1165 | } /* else: Interpreter will throw. */ |
1051 | } | 1166 | } |
1052 | 1167 | ||
1053 | static void recff_rawequal(jit_State *J, TRef *res, RecordFFData *rd) | 1168 | static void LJ_FASTCALL recff_rawequal(jit_State *J, RecordFFData *rd) |
1054 | { | 1169 | { |
1055 | if (arg[0] && arg[1]) { | 1170 | TRef tra = J->base[0]; |
1056 | int diff = rec_objcmp(J, arg[0], arg[1], &rd->argv[0], &rd->argv[1]); | 1171 | TRef trb = J->base[1]; |
1057 | res[0] = diff ? TREF_FALSE : TREF_TRUE; | 1172 | if (tra && trb) { |
1173 | int diff = rec_objcmp(J, tra, trb, &rd->argv[0], &rd->argv[1]); | ||
1174 | J->base[0] = diff ? TREF_FALSE : TREF_TRUE; | ||
1058 | } /* else: Interpreter will throw. */ | 1175 | } /* else: Interpreter will throw. */ |
1059 | } | 1176 | } |
1060 | 1177 | ||
1061 | static void recff_tonumber(jit_State *J, TRef *res, RecordFFData *rd) | 1178 | static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd) |
1062 | { | 1179 | { |
1063 | TRef tr = arg[0]; | 1180 | TRef tr = J->base[0]; |
1064 | if (tref_isnumber_str(tr)) { | 1181 | if (tref_isnumber_str(tr)) { |
1065 | if (arg[1]) { | 1182 | TRef base = J->base[1]; |
1066 | TRef base = lj_ir_toint(J, arg[1]); | 1183 | if (base) { |
1184 | base = lj_ir_toint(J, base); | ||
1067 | if (!tref_isk(base) || IR(tref_ref(base))->i != 10) | 1185 | if (!tref_isk(base) || IR(tref_ref(base))->i != 10) |
1068 | recff_err_nyi(J, rd); | 1186 | recff_nyiu(J); |
1069 | } | 1187 | } |
1070 | if (tref_isstr(tr)) | 1188 | if (tref_isstr(tr)) |
1071 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); | 1189 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); |
1072 | } else { | 1190 | } else { |
1073 | tr = TREF_NIL; | 1191 | tr = TREF_NIL; |
1074 | } | 1192 | } |
1075 | res[0] = tr; | 1193 | J->base[0] = tr; |
1076 | UNUSED(rd); | 1194 | UNUSED(rd); |
1077 | } | 1195 | } |
1078 | 1196 | ||
1079 | static void recff_tostring(jit_State *J, TRef *res, RecordFFData *rd) | 1197 | static TValue *recff_tostring_cp(lua_State *L, lua_CFunction dummy, void *ud) |
1198 | { | ||
1199 | jit_State *J = (jit_State *)ud; | ||
1200 | rec_tailcall(J, 0, 1); | ||
1201 | UNUSED(L); UNUSED(dummy); | ||
1202 | return NULL; | ||
1203 | } | ||
1204 | |||
1205 | static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) | ||
1080 | { | 1206 | { |
1081 | TRef tr = arg[0]; | 1207 | TRef tr = J->base[0]; |
1082 | if (tref_isstr(tr)) { | 1208 | if (tref_isstr(tr)) { |
1083 | /* Ignore __tostring in the string base metatable. */ | 1209 | /* Ignore __tostring in the string base metatable. */ |
1084 | res[0] = tr; | 1210 | /* Pass on result in J->base[0]. */ |
1085 | } else { | 1211 | } else { |
1086 | RecordIndex ix; | 1212 | RecordIndex ix; |
1087 | ix.tab = tr; | 1213 | ix.tab = tr; |
1088 | copyTV(J->L, &ix.tabv, &rd->argv[0]); | 1214 | copyTV(J->L, &ix.tabv, &rd->argv[0]); |
1089 | if (rec_mm_lookup(J, &ix, MM_tostring)) { /* Has __tostring metamethod? */ | 1215 | if (rec_mm_lookup(J, &ix, MM_tostring)) { /* Has __tostring metamethod? */ |
1090 | if (rd->metacall) /* Must not use kludge. */ | 1216 | int errcode; |
1091 | recff_err_nyi(J, rd); | 1217 | /* Temporarily insert metamethod below object. */ |
1092 | res[0] = ix.mobj; | 1218 | J->base[1] = tr; |
1093 | copyTV(J->L, rd->argv - 1, &ix.mobjv); /* Kludge. */ | 1219 | J->base[0] = ix.mobj; |
1094 | J->framedepth--; | 1220 | copyTV(J->L, &rd->argv[1], &rd->argv[0]); |
1095 | if (rec_call(J, (BCReg)(res - J->base), 1, 1)) | 1221 | copyTV(J->L, &rd->argv[0], &ix.mobjv); |
1096 | J->framedepth++; | 1222 | /* Need to protect rec_tailcall because it may throw. */ |
1097 | else | 1223 | errcode = lj_vm_cpcall(J->L, NULL, J, recff_tostring_cp); |
1098 | rd->cres = CALLRES_PENDING; | 1224 | /* Always undo Lua stack changes to avoid confusing the interpreter. */ |
1099 | /* Otherwise res[0] already contains the result. */ | 1225 | copyTV(J->L, &rd->argv[0], &rd->argv[1]); |
1226 | if (errcode) | ||
1227 | lj_err_throw(J->L, errcode); /* Propagate errors. */ | ||
1228 | rd->nres = -1; /* Pending call. */ | ||
1100 | } else if (tref_isnumber(tr)) { | 1229 | } else if (tref_isnumber(tr)) { |
1101 | res[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); | 1230 | J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); |
1102 | } else if (tref_ispri(tr)) { | 1231 | } else if (tref_ispri(tr)) { |
1103 | res[0] = lj_ir_kstr(J, strV(&rd->fn->c.upvalue[tref_type(tr)])); | 1232 | J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); |
1104 | } else { | 1233 | } else { |
1105 | recff_err_nyi(J, rd); | 1234 | recff_nyiu(J); |
1106 | } | 1235 | } |
1107 | } | 1236 | } |
1108 | } | 1237 | } |
1109 | 1238 | ||
1110 | static void recff_ipairs_aux(jit_State *J, TRef *res, RecordFFData *rd) | 1239 | static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd) |
1111 | { | 1240 | { |
1112 | RecordIndex ix; | 1241 | RecordIndex ix; |
1113 | ix.tab = arg[0]; | 1242 | ix.tab = J->base[0]; |
1114 | if (tref_istab(ix.tab)) { | 1243 | if (tref_istab(ix.tab)) { |
1115 | if (!tvisnum(&rd->argv[1])) /* No support for string coercion. */ | 1244 | if (!tvisnum(&rd->argv[1])) /* No support for string coercion. */ |
1116 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 1245 | lj_trace_err(J, LJ_TRERR_BADTYPE); |
1117 | setnumV(&ix.keyv, numV(&rd->argv[1])+(lua_Number)1); | 1246 | setnumV(&ix.keyv, numV(&rd->argv[1])+(lua_Number)1); |
1118 | settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); | 1247 | settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); |
1119 | ix.val = 0; ix.idxchain = 0; | 1248 | ix.val = 0; ix.idxchain = 0; |
1120 | ix.key = lj_ir_toint(J, arg[1]); | 1249 | ix.key = lj_ir_toint(J, J->base[1]); |
1121 | res[0] = ix.key = emitir(IRTI(IR_ADD), ix.key, lj_ir_kint(J, 1)); | 1250 | J->base[0] = ix.key = emitir(IRTI(IR_ADD), ix.key, lj_ir_kint(J, 1)); |
1122 | res[1] = rec_idx(J, &ix); | 1251 | J->base[1] = rec_idx(J, &ix); |
1123 | rd->nres = tref_isnil(res[1]) ? 0 : 2; | 1252 | rd->nres = tref_isnil(J->base[1]) ? 0 : 2; |
1124 | } /* else: Interpreter will throw. */ | 1253 | } /* else: Interpreter will throw. */ |
1125 | } | 1254 | } |
1126 | 1255 | ||
1127 | static void recff_ipairs(jit_State *J, TRef *res, RecordFFData *rd) | 1256 | static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) |
1128 | { | 1257 | { |
1129 | TRef tab = arg[0]; | 1258 | TRef tab = J->base[0]; |
1130 | if (tref_istab(tab)) { | 1259 | if (tref_istab(tab)) { |
1131 | res[0] = lj_ir_kfunc(J, funcV(&rd->fn->c.upvalue[0])); | 1260 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); |
1132 | res[1] = tab; | 1261 | J->base[1] = tab; |
1133 | res[2] = lj_ir_kint(J, 0); | 1262 | J->base[2] = lj_ir_kint(J, 0); |
1134 | rd->nres = 3; | 1263 | rd->nres = 3; |
1135 | } /* else: Interpreter will throw. */ | 1264 | } /* else: Interpreter will throw. */ |
1136 | } | 1265 | } |
1137 | 1266 | ||
1138 | static void recff_pcall(jit_State *J, TRef *res, RecordFFData *rd) | 1267 | static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd) |
1139 | { | 1268 | { |
1140 | if (rd->nargs >= 1) { | 1269 | if (J->maxslot >= 1) { |
1141 | BCReg parg = (BCReg)(arg - J->base); | ||
1142 | J->pc = (const BCIns *)(sizeof(TValue) - 4 + | 1270 | J->pc = (const BCIns *)(sizeof(TValue) - 4 + |
1143 | (hook_active(J2G(J)) ? FRAME_PCALLH : FRAME_PCALL)); | 1271 | (hook_active(J2G(J)) ? FRAME_PCALLH : FRAME_PCALL)); |
1144 | if (rec_call(J, parg, CALLRES_MULTI, rd->nargs - 1)) { /* Resolved call. */ | 1272 | rec_call(J, 0, J->maxslot - 1); |
1145 | res[0] = TREF_TRUE; /* Prepend true result. No need to move results. */ | 1273 | rd->nres = -1; /* Pending call. */ |
1146 | rd->nres = (ptrdiff_t)J->maxslot - (ptrdiff_t)parg + 1; | ||
1147 | } else { /* Propagate pending call. */ | ||
1148 | rd->cres = CALLRES_PENDING; | ||
1149 | } | ||
1150 | } /* else: Interpreter will throw. */ | 1274 | } /* else: Interpreter will throw. */ |
1151 | } | 1275 | } |
1152 | 1276 | ||
1153 | /* Struct to pass context across lj_vm_cpcall. */ | ||
1154 | typedef struct RecordXpcall { | ||
1155 | ptrdiff_t nargs; | ||
1156 | BCReg parg; | ||
1157 | int resolved; | ||
1158 | } RecordXpcall; | ||
1159 | |||
1160 | static TValue *recff_xpcall_cp(lua_State *L, lua_CFunction dummy, void *ud) | 1277 | static TValue *recff_xpcall_cp(lua_State *L, lua_CFunction dummy, void *ud) |
1161 | { | 1278 | { |
1162 | jit_State *J = L2J(L); | 1279 | jit_State *J = (jit_State *)ud; |
1163 | RecordXpcall *rx = (RecordXpcall *)ud; | 1280 | rec_call(J, 1, J->maxslot - 2); |
1164 | UNUSED(dummy); | 1281 | UNUSED(L); UNUSED(dummy); |
1165 | rx->resolved = rec_call(J, rx->parg, CALLRES_MULTI, rx->nargs); | ||
1166 | return NULL; | 1282 | return NULL; |
1167 | } | 1283 | } |
1168 | 1284 | ||
1169 | static void recff_xpcall(jit_State *J, TRef *res, RecordFFData *rd) | 1285 | static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd) |
1170 | { | 1286 | { |
1171 | if (rd->nargs >= 2) { | 1287 | if (J->maxslot >= 2) { |
1172 | RecordXpcall rx; | ||
1173 | BCReg parg = (BCReg)(arg - J->base) + 1; | ||
1174 | TRef tmp; | ||
1175 | TValue argv0, argv1; | 1288 | TValue argv0, argv1; |
1176 | ptrdiff_t oargv; | 1289 | TRef tmp; |
1177 | int errcode; | 1290 | int errcode; |
1178 | /* Swap function and traceback. */ | 1291 | /* Swap function and traceback. */ |
1179 | tmp = arg[0]; arg[0] = arg[1]; arg[1] = tmp; | 1292 | tmp = J->base[0]; J->base[0] = J->base[1]; J->base[1] = tmp; |
1180 | copyTV(J->L, &argv0, &rd->argv[0]); | 1293 | copyTV(J->L, &argv0, &rd->argv[0]); |
1181 | copyTV(J->L, &argv1, &rd->argv[1]); | 1294 | copyTV(J->L, &argv1, &rd->argv[1]); |
1182 | copyTV(J->L, &rd->argv[0], &argv1); | 1295 | copyTV(J->L, &rd->argv[0], &argv1); |
1183 | copyTV(J->L, &rd->argv[1], &argv0); | 1296 | copyTV(J->L, &rd->argv[1], &argv0); |
1184 | oargv = savestack(J->L, rd->argv); | ||
1185 | J->pc = (const BCIns *)(2*sizeof(TValue) - 4 + | 1297 | J->pc = (const BCIns *)(2*sizeof(TValue) - 4 + |
1186 | (hook_active(J2G(J)) ? FRAME_PCALLH : FRAME_PCALL)); | 1298 | (hook_active(J2G(J)) ? FRAME_PCALLH : FRAME_PCALL)); |
1187 | /* Need to protect rec_call because the recorder may throw. */ | 1299 | /* Need to protect rec_call because it may throw. */ |
1188 | rx.parg = parg; | 1300 | errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp); |
1189 | rx.nargs = rd->nargs - 2; | ||
1190 | errcode = lj_vm_cpcall(J->L, NULL, &rx, recff_xpcall_cp); | ||
1191 | /* Always undo Lua stack swap to avoid confusing the interpreter. */ | 1301 | /* Always undo Lua stack swap to avoid confusing the interpreter. */ |
1192 | rd->argv = restorestack(J->L, oargv); /* Stack may have been resized. */ | ||
1193 | copyTV(J->L, &rd->argv[0], &argv0); | 1302 | copyTV(J->L, &rd->argv[0], &argv0); |
1194 | copyTV(J->L, &rd->argv[1], &argv1); | 1303 | copyTV(J->L, &rd->argv[1], &argv1); |
1195 | if (errcode) | 1304 | if (errcode) |
1196 | lj_err_throw(J->L, errcode); /* Propagate errors. */ | 1305 | lj_err_throw(J->L, errcode); /* Propagate errors. */ |
1197 | if (rx.resolved) { /* Resolved call. */ | 1306 | rd->nres = -1; /* Pending call. */ |
1198 | ptrdiff_t i, nres = (ptrdiff_t)J->maxslot - (ptrdiff_t)parg; | ||
1199 | rd->nres = nres + 1; | ||
1200 | res[0] = TREF_TRUE; /* Prepend true result. */ | ||
1201 | for (i = 1; i <= nres; i++) /* Move results down. */ | ||
1202 | res[i] = res[i+1]; | ||
1203 | } else { /* Propagate pending call. */ | ||
1204 | rd->cres = CALLRES_PENDING; | ||
1205 | } | ||
1206 | } /* else: Interpreter will throw. */ | 1307 | } /* else: Interpreter will throw. */ |
1207 | } | 1308 | } |
1208 | 1309 | ||
1209 | /* -- Math library fast functions ----------------------------------------- */ | 1310 | /* -- Math library fast functions ----------------------------------------- */ |
1210 | 1311 | ||
1211 | static void recff_math_abs(jit_State *J, TRef *res, RecordFFData *rd) | 1312 | static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd) |
1212 | { | 1313 | { |
1213 | TRef tr = lj_ir_tonum(J, arg[0]); | 1314 | TRef tr = lj_ir_tonum(J, J->base[0]); |
1214 | res[0] = emitir(IRTN(IR_ABS), tr, lj_ir_knum_abs(J)); | 1315 | J->base[0] = emitir(IRTN(IR_ABS), tr, lj_ir_knum_abs(J)); |
1215 | UNUSED(rd); | 1316 | UNUSED(rd); |
1216 | } | 1317 | } |
1217 | 1318 | ||
1218 | /* Record rounding functions math.floor and math.ceil. */ | 1319 | /* Record rounding functions math.floor and math.ceil. */ |
1219 | static void recff_math_round(jit_State *J, TRef *res, RecordFFData *rd) | 1320 | static void LJ_FASTCALL recff_math_round(jit_State *J, RecordFFData *rd) |
1220 | { | 1321 | { |
1221 | if (tref_isinteger(arg[0])) | 1322 | if (!tref_isinteger(J->base[0])) /* Pass through integers unmodified. */ |
1222 | res[0] = arg[0]; | 1323 | J->base[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, J->base[0]), rd->data); |
1223 | else | ||
1224 | res[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, arg[0]), rd->data); | ||
1225 | /* Note: result is integral (or NaN/Inf), but may not fit into an integer. */ | 1324 | /* Note: result is integral (or NaN/Inf), but may not fit into an integer. */ |
1226 | } | 1325 | } |
1227 | 1326 | ||
1228 | /* Record unary math.* functions, mapped to IR_FPMATH opcode. */ | 1327 | /* Record unary math.* functions, mapped to IR_FPMATH opcode. */ |
1229 | static void recff_math_unary(jit_State *J, TRef *res, RecordFFData *rd) | 1328 | static void LJ_FASTCALL recff_math_unary(jit_State *J, RecordFFData *rd) |
1230 | { | 1329 | { |
1231 | res[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, arg[0]), rd->data); | 1330 | J->base[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, J->base[0]), rd->data); |
1232 | } | 1331 | } |
1233 | 1332 | ||
1234 | /* Record binary math.* functions math.atan2 and math.ldexp. */ | 1333 | /* Record binary math.* functions math.atan2 and math.ldexp. */ |
1235 | static void recff_math_binary(jit_State *J, TRef *res, RecordFFData *rd) | 1334 | static void LJ_FASTCALL recff_math_binary(jit_State *J, RecordFFData *rd) |
1236 | { | 1335 | { |
1237 | TRef tr = lj_ir_tonum(J, arg[0]); | 1336 | TRef tr = lj_ir_tonum(J, J->base[0]); |
1238 | res[0] = emitir(IRTN(rd->data), tr, lj_ir_tonum(J, arg[1])); | 1337 | J->base[0] = emitir(IRTN(rd->data), tr, lj_ir_tonum(J, J->base[1])); |
1239 | } | 1338 | } |
1240 | 1339 | ||
1241 | /* Record math.asin, math.acos, math.atan. */ | 1340 | /* Record math.asin, math.acos, math.atan. */ |
1242 | static void recff_math_atrig(jit_State *J, TRef *res, RecordFFData *rd) | 1341 | static void LJ_FASTCALL recff_math_atrig(jit_State *J, RecordFFData *rd) |
1243 | { | 1342 | { |
1244 | TRef y = lj_ir_tonum(J, arg[0]); | 1343 | TRef y = lj_ir_tonum(J, J->base[0]); |
1245 | TRef x = lj_ir_knum_one(J); | 1344 | TRef x = lj_ir_knum_one(J); |
1246 | uint32_t ffid = rd->data; | 1345 | uint32_t ffid = rd->data; |
1247 | if (ffid != FF_math_atan) { | 1346 | if (ffid != FF_math_atan) { |
@@ -1250,66 +1349,70 @@ static void recff_math_atrig(jit_State *J, TRef *res, RecordFFData *rd) | |||
1250 | tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_SQRT); | 1349 | tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_SQRT); |
1251 | if (ffid == FF_math_asin) { x = tmp; } else { x = y; y = tmp; } | 1350 | if (ffid == FF_math_asin) { x = tmp; } else { x = y; y = tmp; } |
1252 | } | 1351 | } |
1253 | res[0] = emitir(IRTN(IR_ATAN2), y, x); | 1352 | J->base[0] = emitir(IRTN(IR_ATAN2), y, x); |
1254 | } | 1353 | } |
1255 | 1354 | ||
1256 | static void recff_math_htrig(jit_State *J, TRef *res, RecordFFData *rd) | 1355 | static void LJ_FASTCALL recff_math_htrig(jit_State *J, RecordFFData *rd) |
1257 | { | 1356 | { |
1258 | TRef tr = lj_ir_tonum(J, arg[0]); | 1357 | TRef tr = lj_ir_tonum(J, J->base[0]); |
1259 | res[0] = lj_ir_call(J, rd->data, tr); | 1358 | J->base[0] = lj_ir_call(J, rd->data, tr); |
1260 | } | 1359 | } |
1261 | 1360 | ||
1262 | static void recff_math_modf(jit_State *J, TRef *res, RecordFFData *rd) | 1361 | static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd) |
1263 | { | 1362 | { |
1264 | TRef tr = arg[0]; | 1363 | TRef tr = J->base[0]; |
1265 | if (tref_isinteger(tr)) { | 1364 | if (tref_isinteger(tr)) { |
1266 | res[0] = tr; | 1365 | J->base[0] = tr; |
1267 | res[1] = lj_ir_kint(J, 0); | 1366 | J->base[1] = lj_ir_kint(J, 0); |
1268 | } else { | 1367 | } else { |
1368 | TRef trt; | ||
1269 | tr = lj_ir_tonum(J, tr); | 1369 | tr = lj_ir_tonum(J, tr); |
1270 | res[0] = emitir(IRTN(IR_FPMATH), tr, IRFPM_TRUNC); | 1370 | trt = emitir(IRTN(IR_FPMATH), tr, IRFPM_TRUNC); |
1271 | res[1] = emitir(IRTN(IR_SUB), tr, res[0]); | 1371 | J->base[0] = trt; |
1372 | J->base[1] = emitir(IRTN(IR_SUB), tr, trt); | ||
1272 | } | 1373 | } |
1273 | rd->nres = 2; | 1374 | rd->nres = 2; |
1274 | } | 1375 | } |
1275 | 1376 | ||
1276 | static void recff_math_degrad(jit_State *J, TRef *res, RecordFFData *rd) | 1377 | static void LJ_FASTCALL recff_math_degrad(jit_State *J, RecordFFData *rd) |
1277 | { | 1378 | { |
1278 | TRef tr = lj_ir_tonum(J, arg[0]); | 1379 | TRef tr = lj_ir_tonum(J, J->base[0]); |
1279 | res[0] = emitir(IRTN(IR_MUL), tr, lj_ir_knum(J, numV(&rd->fn->c.upvalue[0]))); | 1380 | TRef trm = lj_ir_knum(J, numV(&J->fn->c.upvalue[0])); |
1381 | J->base[0] = emitir(IRTN(IR_MUL), tr, trm); | ||
1382 | UNUSED(rd); | ||
1280 | } | 1383 | } |
1281 | 1384 | ||
1282 | static void recff_math_pow(jit_State *J, TRef *res, RecordFFData *rd) | 1385 | static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) |
1283 | { | 1386 | { |
1284 | TRef tr = lj_ir_tonum(J, arg[0]); | 1387 | TRef tr = lj_ir_tonum(J, J->base[0]); |
1285 | if (!tref_isnumber_str(arg[1])) | 1388 | if (!tref_isnumber_str(J->base[1])) |
1286 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 1389 | lj_trace_err(J, LJ_TRERR_BADTYPE); |
1287 | res[0] = lj_opt_narrow_pow(J, tr, arg[1], &rd->argv[1]); | 1390 | J->base[0] = lj_opt_narrow_pow(J, tr, J->base[1], &rd->argv[1]); |
1288 | UNUSED(rd); | 1391 | UNUSED(rd); |
1289 | } | 1392 | } |
1290 | 1393 | ||
1291 | static void recff_math_minmax(jit_State *J, TRef *res, RecordFFData *rd) | 1394 | static void LJ_FASTCALL recff_math_minmax(jit_State *J, RecordFFData *rd) |
1292 | { | 1395 | { |
1293 | TRef tr = lj_ir_tonum(J, arg[0]); | 1396 | TRef tr = lj_ir_tonum(J, J->base[0]); |
1294 | uint32_t op = rd->data; | 1397 | uint32_t op = rd->data; |
1295 | BCReg i; | 1398 | BCReg i; |
1296 | for (i = 1; arg[i]; i++) | 1399 | for (i = 1; J->base[i] != 0; i++) |
1297 | tr = emitir(IRTN(op), tr, lj_ir_tonum(J, arg[i])); | 1400 | tr = emitir(IRTN(op), tr, lj_ir_tonum(J, J->base[i])); |
1298 | res[0] = tr; | 1401 | J->base[0] = tr; |
1299 | } | 1402 | } |
1300 | 1403 | ||
1301 | static void recff_math_random(jit_State *J, TRef *res, RecordFFData *rd) | 1404 | static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd) |
1302 | { | 1405 | { |
1303 | GCudata *ud = udataV(&rd->fn->c.upvalue[0]); | 1406 | GCudata *ud = udataV(&J->fn->c.upvalue[0]); |
1304 | TRef tr, one; | 1407 | TRef tr, one; |
1305 | lj_ir_kgc(J, obj2gco(ud), IRT_UDATA); /* Prevent collection. */ | 1408 | lj_ir_kgc(J, obj2gco(ud), IRT_UDATA); /* Prevent collection. */ |
1306 | tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud))); | 1409 | tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud))); |
1307 | one = lj_ir_knum_one(J); | 1410 | one = lj_ir_knum_one(J); |
1308 | tr = emitir(IRTN(IR_SUB), tr, one); | 1411 | tr = emitir(IRTN(IR_SUB), tr, one); |
1309 | if (arg[0]) { | 1412 | if (J->base[0]) { |
1310 | TRef tr1 = lj_ir_tonum(J, arg[0]); | 1413 | TRef tr1 = lj_ir_tonum(J, J->base[0]); |
1311 | if (arg[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */ | 1414 | if (J->base[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */ |
1312 | TRef tr2 = lj_ir_tonum(J, arg[1]); | 1415 | TRef tr2 = lj_ir_tonum(J, J->base[1]); |
1313 | tr2 = emitir(IRTN(IR_SUB), tr2, tr1); | 1416 | tr2 = emitir(IRTN(IR_SUB), tr2, tr1); |
1314 | tr2 = emitir(IRTN(IR_ADD), tr2, one); | 1417 | tr2 = emitir(IRTN(IR_ADD), tr2, one); |
1315 | tr = emitir(IRTN(IR_MUL), tr, tr2); | 1418 | tr = emitir(IRTN(IR_MUL), tr, tr2); |
@@ -1321,69 +1424,82 @@ static void recff_math_random(jit_State *J, TRef *res, RecordFFData *rd) | |||
1321 | tr = emitir(IRTN(IR_ADD), tr, one); | 1424 | tr = emitir(IRTN(IR_ADD), tr, one); |
1322 | } | 1425 | } |
1323 | } | 1426 | } |
1324 | res[0] = tr; | 1427 | J->base[0] = tr; |
1428 | UNUSED(rd); | ||
1325 | } | 1429 | } |
1326 | 1430 | ||
1327 | /* -- Bit library fast functions ------------------------------------------ */ | 1431 | /* -- Bit library fast functions ------------------------------------------ */ |
1328 | 1432 | ||
1329 | /* Record unary bit.tobit, bit.bnot, bit.bswap. */ | 1433 | /* Record unary bit.tobit, bit.bnot, bit.bswap. */ |
1330 | static void recff_bit_unary(jit_State *J, TRef *res, RecordFFData *rd) | 1434 | static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd) |
1331 | { | 1435 | { |
1332 | TRef tr = lj_ir_tobit(J, arg[0]); | 1436 | TRef tr = lj_ir_tobit(J, J->base[0]); |
1333 | res[0] = (rd->data == IR_TOBIT) ? tr : emitir(IRTI(rd->data), tr, 0); | 1437 | J->base[0] = (rd->data == IR_TOBIT) ? tr : emitir(IRTI(rd->data), tr, 0); |
1334 | } | 1438 | } |
1335 | 1439 | ||
1336 | /* Record N-ary bit.band, bit.bor, bit.bxor. */ | 1440 | /* Record N-ary bit.band, bit.bor, bit.bxor. */ |
1337 | static void recff_bit_nary(jit_State *J, TRef *res, RecordFFData *rd) | 1441 | static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) |
1338 | { | 1442 | { |
1339 | TRef tr = lj_ir_tobit(J, arg[0]); | 1443 | TRef tr = lj_ir_tobit(J, J->base[0]); |
1340 | uint32_t op = rd->data; | 1444 | uint32_t op = rd->data; |
1341 | BCReg i; | 1445 | BCReg i; |
1342 | for (i = 1; arg[i]; i++) | 1446 | for (i = 1; J->base[i] != 0; i++) |
1343 | tr = emitir(IRTI(op), tr, lj_ir_tobit(J, arg[i])); | 1447 | tr = emitir(IRTI(op), tr, lj_ir_tobit(J, J->base[i])); |
1344 | res[0] = tr; | 1448 | J->base[0] = tr; |
1345 | } | 1449 | } |
1346 | 1450 | ||
1347 | /* Record bit shifts. */ | 1451 | /* Record bit shifts. */ |
1348 | static void recff_bit_shift(jit_State *J, TRef *res, RecordFFData *rd) | 1452 | static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) |
1349 | { | 1453 | { |
1350 | TRef tr = lj_ir_tobit(J, arg[0]); | 1454 | TRef tr = lj_ir_tobit(J, J->base[0]); |
1351 | TRef tsh = lj_ir_tobit(J, arg[1]); | 1455 | TRef tsh = lj_ir_tobit(J, J->base[1]); |
1352 | #if !LJ_TARGET_MASKEDSHIFT | 1456 | #if !LJ_TARGET_MASKEDSHIFT |
1353 | if (!tref_isk(tsh)) | 1457 | if (!tref_isk(tsh)) |
1354 | tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); | 1458 | tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); |
1355 | #endif | 1459 | #endif |
1356 | res[0] = emitir(IRTI(rd->data), tr, tsh); | 1460 | J->base[0] = emitir(IRTI(rd->data), tr, tsh); |
1357 | } | 1461 | } |
1358 | 1462 | ||
1359 | /* -- String library fast functions --------------------------------------- */ | 1463 | /* -- String library fast functions --------------------------------------- */ |
1360 | 1464 | ||
1361 | static void recff_string_len(jit_State *J, TRef *res, RecordFFData *rd) | 1465 | static void LJ_FASTCALL recff_string_len(jit_State *J, RecordFFData *rd) |
1362 | { | 1466 | { |
1363 | res[0] = emitir(IRTI(IR_FLOAD), lj_ir_tostr(J, arg[0]), IRFL_STR_LEN); | 1467 | J->base[0] = emitir(IRTI(IR_FLOAD), lj_ir_tostr(J, J->base[0]), IRFL_STR_LEN); |
1364 | UNUSED(rd); | 1468 | UNUSED(rd); |
1365 | } | 1469 | } |
1366 | 1470 | ||
1367 | /* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ | 1471 | /* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ |
1368 | static void recff_string_range(jit_State *J, TRef *res, RecordFFData *rd) | 1472 | static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) |
1369 | { | 1473 | { |
1370 | TRef trstr = lj_ir_tostr(J, arg[0]); | 1474 | TRef trstr = lj_ir_tostr(J, J->base[0]); |
1371 | TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN); | 1475 | TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN); |
1372 | TRef tr0 = lj_ir_kint(J, 0); | 1476 | TRef tr0 = lj_ir_kint(J, 0); |
1373 | TRef trstart, trend; | 1477 | TRef trstart, trend; |
1374 | GCstr *str = argv2str(J, &rd->argv[0]); | 1478 | GCstr *str = argv2str(J, &rd->argv[0]); |
1375 | int32_t start, end; | 1479 | int32_t start, end; |
1376 | if (rd->data) { /* string.sub(str, start [,end]) */ | 1480 | if (rd->data) { /* string.sub(str, start [,end]) */ |
1377 | trstart = lj_ir_toint(J, arg[1]); | ||
1378 | trend = tref_isnil(arg[2]) ? lj_ir_kint(J, -1) : lj_ir_toint(J, arg[2]); | ||
1379 | start = argv2int(J, &rd->argv[1]); | 1481 | start = argv2int(J, &rd->argv[1]); |
1380 | end = tref_isnil(arg[2]) ? -1 : argv2int(J, &rd->argv[2]); | 1482 | trstart = lj_ir_toint(J, J->base[1]); |
1483 | trend = J->base[2]; | ||
1484 | if (tref_isnil(trend)) { | ||
1485 | trend = lj_ir_kint(J, -1); | ||
1486 | end = -1; | ||
1487 | } else { | ||
1488 | trend = lj_ir_toint(J, trend); | ||
1489 | end = argv2int(J, &rd->argv[2]); | ||
1490 | } | ||
1381 | } else { /* string.byte(str, [,start [,end]]) */ | 1491 | } else { /* string.byte(str, [,start [,end]]) */ |
1382 | if (arg[1]) { | 1492 | if (J->base[1]) { |
1383 | trstart = lj_ir_toint(J, arg[1]); | ||
1384 | trend = tref_isnil(arg[2]) ? trstart : lj_ir_toint(J, arg[2]); | ||
1385 | start = argv2int(J, &rd->argv[1]); | 1493 | start = argv2int(J, &rd->argv[1]); |
1386 | end = tref_isnil(arg[2]) ? start : argv2int(J, &rd->argv[2]); | 1494 | trstart = lj_ir_toint(J, J->base[1]); |
1495 | trend = J->base[2]; | ||
1496 | if (tref_isnil(trend)) { | ||
1497 | trend = trstart; | ||
1498 | end = start; | ||
1499 | } else { | ||
1500 | trend = lj_ir_toint(J, trend); | ||
1501 | end = argv2int(J, &rd->argv[2]); | ||
1502 | } | ||
1387 | } else { | 1503 | } else { |
1388 | trend = trstart = lj_ir_kint(J, 1); | 1504 | trend = trstart = lj_ir_kint(J, 1); |
1389 | end = start = 1; | 1505 | end = start = 1; |
@@ -1426,23 +1542,23 @@ static void recff_string_range(jit_State *J, TRef *res, RecordFFData *rd) | |||
1426 | TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart); | 1542 | TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart); |
1427 | emitir(IRTGI(IR_GE), trslen, tr0); | 1543 | emitir(IRTGI(IR_GE), trslen, tr0); |
1428 | trptr = emitir(IRT(IR_STRREF, IRT_PTR), trstr, trstart); | 1544 | trptr = emitir(IRT(IR_STRREF, IRT_PTR), trstr, trstart); |
1429 | res[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); | 1545 | J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); |
1430 | } else { /* Range underflow: return empty string. */ | 1546 | } else { /* Range underflow: return empty string. */ |
1431 | emitir(IRTGI(IR_LT), trend, trstart); | 1547 | emitir(IRTGI(IR_LT), trend, trstart); |
1432 | res[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0)); | 1548 | J->base[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0)); |
1433 | } | 1549 | } |
1434 | } else { /* Return string.byte result(s). */ | 1550 | } else { /* Return string.byte result(s). */ |
1435 | ptrdiff_t i, len = end - start; | 1551 | ptrdiff_t i, len = end - start; |
1436 | if (len > 0) { | 1552 | if (len > 0) { |
1437 | TRef trslen = emitir(IRTI(IR_SUB), trend, trstart); | 1553 | TRef trslen = emitir(IRTI(IR_SUB), trend, trstart); |
1438 | emitir(IRTGI(IR_EQ), trslen, lj_ir_kint(J, len)); | 1554 | emitir(IRTGI(IR_EQ), trslen, lj_ir_kint(J, len)); |
1439 | if (res + len > J->slot + LJ_MAX_JSLOTS) | 1555 | if (J->baseslot + len > LJ_MAX_JSLOTS) |
1440 | lj_trace_err(J, LJ_TRERR_STACKOV); | 1556 | lj_trace_err_info(J, LJ_TRERR_STACKOV); |
1441 | rd->nres = len; | 1557 | rd->nres = len; |
1442 | for (i = 0; i < len; i++) { | 1558 | for (i = 0; i < len; i++) { |
1443 | TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, i)); | 1559 | TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, i)); |
1444 | tmp = emitir(IRT(IR_STRREF, IRT_PTR), trstr, tmp); | 1560 | tmp = emitir(IRT(IR_STRREF, IRT_PTR), trstr, tmp); |
1445 | res[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY); | 1561 | J->base[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY); |
1446 | } | 1562 | } |
1447 | } else { /* Empty range or range underflow: return no results. */ | 1563 | } else { /* Empty range or range underflow: return no results. */ |
1448 | emitir(IRTGI(IR_LE), trend, trstart); | 1564 | emitir(IRTGI(IR_LE), trend, trstart); |
@@ -1453,62 +1569,63 @@ static void recff_string_range(jit_State *J, TRef *res, RecordFFData *rd) | |||
1453 | 1569 | ||
1454 | /* -- Table library fast functions ---------------------------------------- */ | 1570 | /* -- Table library fast functions ---------------------------------------- */ |
1455 | 1571 | ||
1456 | static void recff_table_getn(jit_State *J, TRef *res, RecordFFData *rd) | 1572 | static void LJ_FASTCALL recff_table_getn(jit_State *J, RecordFFData *rd) |
1457 | { | 1573 | { |
1458 | if (tref_istab(arg[0])) { | 1574 | if (tref_istab(J->base[0])) |
1459 | res[0] = lj_ir_call(J, IRCALL_lj_tab_len, arg[0]); | 1575 | J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, J->base[0]); |
1460 | } /* else: Interpreter will throw. */ | 1576 | /* else: Interpreter will throw. */ |
1461 | UNUSED(rd); | 1577 | UNUSED(rd); |
1462 | } | 1578 | } |
1463 | 1579 | ||
1464 | static void recff_table_remove(jit_State *J, TRef *res, RecordFFData *rd) | 1580 | static void LJ_FASTCALL recff_table_remove(jit_State *J, RecordFFData *rd) |
1465 | { | 1581 | { |
1466 | if (tref_istab(arg[0])) { | 1582 | TRef tab = J->base[0]; |
1467 | if (!arg[1] || tref_isnil(arg[1])) { /* Simple pop: t[#t] = nil */ | 1583 | rd->nres = 0; |
1468 | TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, arg[0]); | 1584 | if (tref_istab(tab)) { |
1585 | if (!J->base[1] || tref_isnil(J->base[1])) { /* Simple pop: t[#t] = nil */ | ||
1586 | TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, tab); | ||
1469 | GCtab *t = tabV(&rd->argv[0]); | 1587 | GCtab *t = tabV(&rd->argv[0]); |
1470 | MSize len = lj_tab_len(t); | 1588 | MSize len = lj_tab_len(t); |
1471 | emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0)); | 1589 | emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0)); |
1472 | if (len) { | 1590 | if (len) { |
1473 | RecordIndex ix; | 1591 | RecordIndex ix; |
1474 | ix.tab = arg[0]; | 1592 | ix.tab = tab; |
1475 | ix.key = trlen; | 1593 | ix.key = trlen; |
1476 | settabV(J->L, &ix.tabv, t); | 1594 | settabV(J->L, &ix.tabv, t); |
1477 | setintV(&ix.keyv, len); | 1595 | setintV(&ix.keyv, len); |
1478 | ix.idxchain = 0; | 1596 | ix.idxchain = 0; |
1479 | if (rd->cres != 0) { /* Specialize load only if result needed. */ | 1597 | if (results_wanted(J) != 0) { /* Specialize load only if needed. */ |
1480 | ix.val = 0; | 1598 | ix.val = 0; |
1481 | res[0] = rec_idx(J, &ix); /* Load previous value. */ | 1599 | J->base[0] = rec_idx(J, &ix); /* Load previous value. */ |
1600 | rd->nres = 1; | ||
1482 | /* Assumes ix.key/ix.tab is not modified for raw rec_idx(). */ | 1601 | /* Assumes ix.key/ix.tab is not modified for raw rec_idx(). */ |
1483 | } | 1602 | } |
1484 | ix.val = TREF_NIL; | 1603 | ix.val = TREF_NIL; |
1485 | rec_idx(J, &ix); /* Remove value. */ | 1604 | rec_idx(J, &ix); /* Remove value. */ |
1486 | } else { | ||
1487 | rd->nres = 0; | ||
1488 | } | 1605 | } |
1489 | } else { /* Complex case: remove in the middle. */ | 1606 | } else { /* Complex case: remove in the middle. */ |
1490 | recff_err_nyi(J, rd); | 1607 | recff_nyiu(J); |
1491 | } | 1608 | } |
1492 | } /* else: Interpreter will throw. */ | 1609 | } /* else: Interpreter will throw. */ |
1493 | } | 1610 | } |
1494 | 1611 | ||
1495 | static void recff_table_insert(jit_State *J, TRef *res, RecordFFData *rd) | 1612 | static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) |
1496 | { | 1613 | { |
1614 | RecordIndex ix; | ||
1615 | ix.tab = J->base[0]; | ||
1616 | ix.val = J->base[1]; | ||
1497 | rd->nres = 0; | 1617 | rd->nres = 0; |
1498 | if (tref_istab(arg[0]) && arg[1]) { | 1618 | if (tref_istab(ix.tab) && ix.val) { |
1499 | if (!arg[2]) { /* Simple push: t[#t+1] = v */ | 1619 | if (!J->base[2]) { /* Simple push: t[#t+1] = v */ |
1500 | TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, arg[0]); | 1620 | TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, ix.tab); |
1501 | GCtab *t = tabV(&rd->argv[0]); | 1621 | GCtab *t = tabV(&rd->argv[0]); |
1502 | RecordIndex ix; | ||
1503 | ix.tab = arg[0]; | ||
1504 | ix.val = arg[1]; | ||
1505 | ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1)); | 1622 | ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1)); |
1506 | settabV(J->L, &ix.tabv, t); | 1623 | settabV(J->L, &ix.tabv, t); |
1507 | setintV(&ix.keyv, lj_tab_len(t) + 1); | 1624 | setintV(&ix.keyv, lj_tab_len(t) + 1); |
1508 | ix.idxchain = 0; | 1625 | ix.idxchain = 0; |
1509 | rec_idx(J, &ix); /* Set new value. */ | 1626 | rec_idx(J, &ix); /* Set new value. */ |
1510 | } else { /* Complex case: insert in the middle. */ | 1627 | } else { /* Complex case: insert in the middle. */ |
1511 | recff_err_nyi(J, rd); | 1628 | recff_nyiu(J); |
1512 | } | 1629 | } |
1513 | } /* else: Interpreter will throw. */ | 1630 | } /* else: Interpreter will throw. */ |
1514 | } | 1631 | } |
@@ -1518,14 +1635,14 @@ static void recff_table_insert(jit_State *J, TRef *res, RecordFFData *rd) | |||
1518 | /* Get FILE* for I/O function. Any I/O error aborts recording, so there's | 1635 | /* Get FILE* for I/O function. Any I/O error aborts recording, so there's |
1519 | ** no need to encode the alternate cases for any of the guards. | 1636 | ** no need to encode the alternate cases for any of the guards. |
1520 | */ | 1637 | */ |
1521 | static TRef recff_io_fp(jit_State *J, TRef *res, uint32_t id) | 1638 | static TRef recff_io_fp(jit_State *J, uint32_t id) |
1522 | { | 1639 | { |
1523 | TRef tr, ud, fp; | 1640 | TRef tr, ud, fp; |
1524 | if (id) { /* io.func() */ | 1641 | if (id) { /* io.func() */ |
1525 | tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]); | 1642 | tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]); |
1526 | ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0); | 1643 | ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0); |
1527 | } else { /* fp:method() */ | 1644 | } else { /* fp:method() */ |
1528 | ud = arg[0]; | 1645 | ud = J->base[0]; |
1529 | if (!tref_isudata(ud)) | 1646 | if (!tref_isudata(ud)) |
1530 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 1647 | lj_trace_err(J, LJ_TRERR_BADTYPE); |
1531 | tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE); | 1648 | tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE); |
@@ -1536,130 +1653,75 @@ static TRef recff_io_fp(jit_State *J, TRef *res, uint32_t id) | |||
1536 | return fp; | 1653 | return fp; |
1537 | } | 1654 | } |
1538 | 1655 | ||
1539 | static void recff_io_write(jit_State *J, TRef *res, RecordFFData *rd) | 1656 | static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd) |
1540 | { | 1657 | { |
1541 | TRef fp = recff_io_fp(J, res, rd->data); | 1658 | TRef fp = recff_io_fp(J, rd->data); |
1542 | TRef zero = lj_ir_kint(J, 0); | 1659 | TRef zero = lj_ir_kint(J, 0); |
1543 | TRef one = lj_ir_kint(J, 1); | 1660 | TRef one = lj_ir_kint(J, 1); |
1544 | ptrdiff_t i = rd->data == 0 ? 1 : 0; | 1661 | ptrdiff_t i = rd->data == 0 ? 1 : 0; |
1545 | for (; arg[i]; i++) { | 1662 | for (; J->base[i]; i++) { |
1546 | TRef str = lj_ir_tostr(J, arg[i]); | 1663 | TRef str = lj_ir_tostr(J, J->base[i]); |
1547 | TRef buf = emitir(IRT(IR_STRREF, IRT_PTR), str, zero); | 1664 | TRef buf = emitir(IRT(IR_STRREF, IRT_PTR), str, zero); |
1548 | TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); | 1665 | TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); |
1549 | if (tref_isk(len) && IR(tref_ref(len))->i == 1) { | 1666 | if (tref_isk(len) && IR(tref_ref(len))->i == 1) { |
1550 | TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); | 1667 | TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); |
1551 | tr = lj_ir_call(J, IRCALL_fputc, tr, fp); | 1668 | tr = lj_ir_call(J, IRCALL_fputc, tr, fp); |
1552 | if (rd->cres != 0) /* Check result only if requested. */ | 1669 | if (results_wanted(J) != 0) /* Check result only if not ignored. */ |
1553 | emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); | 1670 | emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); |
1554 | } else { | 1671 | } else { |
1555 | TRef tr = lj_ir_call(J, IRCALL_fwrite, buf, one, len, fp); | 1672 | TRef tr = lj_ir_call(J, IRCALL_fwrite, buf, one, len, fp); |
1556 | if (rd->cres != 0) /* Check result only if requested. */ | 1673 | if (results_wanted(J) != 0) /* Check result only if not ignored. */ |
1557 | emitir(IRTGI(IR_EQ), tr, len); | 1674 | emitir(IRTGI(IR_EQ), tr, len); |
1558 | } | 1675 | } |
1559 | } | 1676 | } |
1560 | res[0] = TREF_TRUE; | 1677 | J->base[0] = TREF_TRUE; |
1561 | } | 1678 | } |
1562 | 1679 | ||
1563 | static void recff_io_flush(jit_State *J, TRef *res, RecordFFData *rd) | 1680 | static void LJ_FASTCALL recff_io_flush(jit_State *J, RecordFFData *rd) |
1564 | { | 1681 | { |
1565 | TRef fp = recff_io_fp(J, res, rd->data); | 1682 | TRef fp = recff_io_fp(J, rd->data); |
1566 | TRef tr = lj_ir_call(J, IRCALL_fflush, fp); | 1683 | TRef tr = lj_ir_call(J, IRCALL_fflush, fp); |
1567 | if (rd->cres != 0) /* Check result only if requested. */ | 1684 | if (results_wanted(J) != 0) /* Check result only if not ignored. */ |
1568 | emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0)); | 1685 | emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0)); |
1569 | res[0] = TREF_TRUE; | 1686 | J->base[0] = TREF_TRUE; |
1570 | } | 1687 | } |
1571 | 1688 | ||
1572 | /* -- Record calls and returns -------------------------------------------- */ | ||
1573 | |||
1574 | #undef arg | ||
1575 | |||
1576 | #include "lj_recdef.h" | 1689 | #include "lj_recdef.h" |
1577 | 1690 | ||
1578 | /* Record return. */ | 1691 | static uint32_t recdef_lookup(GCfunc *fn) |
1579 | static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | ||
1580 | { | 1692 | { |
1581 | TValue *frame = J->L->base - 1; | 1693 | if (fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0])) |
1582 | ptrdiff_t i; | 1694 | return recff_idmap[fn->c.ffid]; |
1583 | for (i = 0; i < gotresults; i++) | 1695 | else |
1584 | getslot(J, rbase+i); /* Ensure all results have a reference. */ | 1696 | return 0; |
1585 | J->tailcalled = 0; | 1697 | } |
1586 | while (frame_ispcall(frame)) { /* Immediately resolve pcall() returns. */ | 1698 | |
1587 | BCReg cbase = (BCReg)frame_delta(frame); | 1699 | /* Record call to fast function or C function. */ |
1588 | if (J->framedepth-- <= 0) | 1700 | static void rec_func_ff(jit_State *J) |
1589 | lj_trace_err(J, LJ_TRERR_NYIRETL); | 1701 | { |
1590 | lua_assert(J->baseslot > 1); | 1702 | RecordFFData rd; |
1591 | J->base[--rbase] = TREF_TRUE; /* Prepend true to results. */ | 1703 | uint32_t m = recdef_lookup(J->fn); |
1592 | gotresults++; | 1704 | rd.data = m & 0xff; |
1593 | rbase += cbase; | 1705 | rd.nres = 1; /* Default is one result. */ |
1594 | J->baseslot -= (BCReg)cbase; | 1706 | rd.argv = J->L->base; |
1595 | J->base -= cbase; | 1707 | J->base[J->maxslot] = 0; /* Mark end of arguments. */ |
1596 | frame = frame_prevd(frame); | 1708 | (recff_func[m >> 8])(J, &rd); /* Call recff_* handler. */ |
1597 | } | 1709 | if (rd.nres >= 0) |
1598 | if (frame_islua(frame)) { /* Return to Lua frame. */ | 1710 | rec_ret(J, 0, rd.nres); |
1599 | BCIns callins = *(frame_pc(frame)-1); | ||
1600 | ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults; | ||
1601 | BCReg cbase = bc_a(callins); | ||
1602 | for (i = 0; i < nresults; i++) /* Adjust results. */ | ||
1603 | J->base[i-1] = i < gotresults ? J->base[rbase+i] : TREF_NIL; | ||
1604 | J->maxslot = cbase+(BCReg)nresults; | ||
1605 | if (J->framedepth > 0) { /* Return to a frame that is part of the trace. */ | ||
1606 | J->framedepth--; | ||
1607 | lua_assert(J->baseslot > cbase+1); | ||
1608 | J->baseslot -= cbase+1; | ||
1609 | J->base -= cbase+1; | ||
1610 | } else if (J->parent == 0) { | ||
1611 | /* Return to lower frame would leave the loop in a root trace. */ | ||
1612 | lj_trace_err(J, LJ_TRERR_LLEAVE); | ||
1613 | } else { /* Return to lower frame. Guard for the target we return to. */ | ||
1614 | GCproto *pt = funcproto(frame_func(frame - (cbase+1))); | ||
1615 | TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); | ||
1616 | TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame)); | ||
1617 | emitir(IRTG(IR_RETF, IRT_PTR), trpt, trpc); | ||
1618 | J->retdepth++; | ||
1619 | J->needsnap = 1; | ||
1620 | lua_assert(J->baseslot == 1); | ||
1621 | /* Shift result slots up and clear the slots of the new frame below. */ | ||
1622 | memmove(J->base + cbase, J->base-1, sizeof(TRef)*nresults); | ||
1623 | memset(J->base-1, 0, sizeof(TRef)*(cbase+1)); | ||
1624 | } | ||
1625 | } else if (frame_iscont(frame)) { /* Return to continuation frame. */ | ||
1626 | ASMFunction cont = frame_contf(frame); | ||
1627 | BCReg cbase = (BCReg)frame_delta(frame); | ||
1628 | if ((J->framedepth -= 2) <= 0) | ||
1629 | lj_trace_err(J, LJ_TRERR_NYIRETL); | ||
1630 | J->baseslot -= (BCReg)cbase; | ||
1631 | J->base -= cbase; | ||
1632 | J->maxslot = cbase-2; | ||
1633 | if (cont == lj_cont_ra) { | ||
1634 | /* Copy result to destination slot. */ | ||
1635 | BCReg dst = bc_a(*(frame_contpc(frame)-1)); | ||
1636 | J->base[dst] = gotresults ? J->base[cbase+rbase] : TREF_NIL; | ||
1637 | if (dst > J->maxslot) J->maxslot = dst+1; | ||
1638 | } else if (cont == lj_cont_nop) { | ||
1639 | /* Nothing to do here. */ | ||
1640 | } else if (cont == lj_cont_cat) { | ||
1641 | lua_assert(0); | ||
1642 | } else { | ||
1643 | /* Result type already specialized. */ | ||
1644 | lua_assert(cont == lj_cont_condf || cont == lj_cont_condt); | ||
1645 | } | ||
1646 | } else { | ||
1647 | lj_trace_err(J, LJ_TRERR_NYIRETL); /* NYI: handle return to C frame. */ | ||
1648 | } | ||
1649 | lua_assert(J->baseslot >= 1); | ||
1650 | } | 1711 | } |
1651 | 1712 | ||
1713 | /* -- Record calls to Lua functions --------------------------------------- */ | ||
1714 | |||
1652 | /* Check unroll limits for calls. */ | 1715 | /* Check unroll limits for calls. */ |
1653 | static void check_call_unroll(jit_State *J, GCfunc *fn) | 1716 | static void check_call_unroll(jit_State *J) |
1654 | { | 1717 | { |
1655 | IRRef fref = tref_ref(J->base[-1]); | 1718 | IRRef fref = tref_ref(J->base[-1]); |
1656 | int32_t count = 0; | 1719 | int32_t count = 0; |
1657 | ptrdiff_t s; | 1720 | BCReg s; |
1658 | for (s = (ptrdiff_t)J->baseslot - 1; s > 0; s--) | 1721 | for (s = J->baseslot - 1; s > 0; s--) |
1659 | if ((J->slot[s] & TREF_FRAME) && tref_ref(J->slot[s]) == fref) | 1722 | if ((J->slot[s] & TREF_FRAME) && tref_ref(J->slot[s]) == fref) |
1660 | count++; | 1723 | count++; |
1661 | if (bc_op(J->cur.startins) == BC_CALL && | 1724 | if (J->pc == J->startpc) { |
1662 | funcproto(fn) == &gcref(J->cur.startpt)->pt) { | ||
1663 | if (count + J->tailcalled > J->param[JIT_P_recunroll]) | 1725 | if (count + J->tailcalled > J->param[JIT_P_recunroll]) |
1664 | lj_trace_err(J, LJ_TRERR_NYIRECU); | 1726 | lj_trace_err(J, LJ_TRERR_NYIRECU); |
1665 | } else { | 1727 | } else { |
@@ -1668,110 +1730,20 @@ static void check_call_unroll(jit_State *J, GCfunc *fn) | |||
1668 | } | 1730 | } |
1669 | } | 1731 | } |
1670 | 1732 | ||
1671 | /* Record call. Returns 0 for pending calls and 1 for resolved calls. */ | 1733 | static void rec_func_lua(jit_State *J) |
1672 | static int rec_call(jit_State *J, BCReg func, ptrdiff_t cres, ptrdiff_t nargs) | ||
1673 | { | 1734 | { |
1674 | RecordFFData rd; | 1735 | GCproto *pt = J->pt; |
1675 | TRef trfunc, *res = &J->base[func]; | 1736 | if ((pt->flags & PROTO_NO_JIT)) |
1676 | TValue *tv = &J->L->base[func]; | 1737 | lj_trace_err(J, LJ_TRERR_CJITOFF); |
1677 | 1738 | lua_assert(!(pt->flags & PROTO_IS_VARARG)); | |
1678 | if (tref_isfunc(res[0])) { /* Regular function call. */ | 1739 | if (J->baseslot + pt->framesize >= LJ_MAX_JSLOTS) |
1679 | rd.fn = funcV(tv); | ||
1680 | rd.argv = tv+1; | ||
1681 | rd.metacall = 0; | ||
1682 | } else { /* Otherwise resolve __call metamethod for called object. */ | ||
1683 | RecordIndex ix; | ||
1684 | ptrdiff_t i; | ||
1685 | ix.tab = res[0]; | ||
1686 | copyTV(J->L, &ix.tabv, tv); | ||
1687 | if (!rec_mm_lookup(J, &ix, MM_call) || !tref_isfunc(ix.mobj)) | ||
1688 | lj_trace_err(J, LJ_TRERR_NOMM); | ||
1689 | /* Update the recorder state, but not the Lua stack. */ | ||
1690 | for (i = ++nargs; i > 0; i--) | ||
1691 | res[i] = res[i-1]; | ||
1692 | res[0] = ix.mobj; | ||
1693 | rd.fn = funcV(&ix.mobjv); | ||
1694 | rd.argv = tv; /* The called object is the 1st arg. */ | ||
1695 | rd.metacall = 1; | ||
1696 | } | ||
1697 | |||
1698 | /* Specialize to the runtime value of the called function. */ | ||
1699 | trfunc = lj_ir_kfunc(J, rd.fn); | ||
1700 | emitir(IRTG(IR_EQ, IRT_FUNC), res[0], trfunc); | ||
1701 | res[0] = trfunc | TREF_FRAME; | ||
1702 | |||
1703 | /* Add frame links. */ | ||
1704 | J->frame[J->framedepth++] = SNAP_MKPC(J->pc+1); | ||
1705 | if (cres == CALLRES_CONT) /* Continuations need an extra frame stack slot. */ | ||
1706 | J->frame[J->framedepth++] = SNAP_MKFTSZ((func+1)*sizeof(TValue)+FRAME_CONT); | ||
1707 | /* NYI: func is wrong if any fast function ever sets up a continuation. */ | ||
1708 | if (J->framedepth > LJ_MAX_JFRAME) | ||
1709 | lj_trace_err(J, LJ_TRERR_STACKOV); | 1740 | lj_trace_err(J, LJ_TRERR_STACKOV); |
1710 | 1741 | /* Fill up missing args with nil. */ | |
1711 | if (isluafunc(rd.fn)) { /* Record call to Lua function. */ | 1742 | while (J->maxslot < pt->numparams) |
1712 | GCproto *pt = funcproto(rd.fn); | 1743 | J->base[J->maxslot++] = TREF_NIL; |
1713 | if ((pt->flags & PROTO_NO_JIT)) | 1744 | /* The remaining slots should never be read before they are written. */ |
1714 | lj_trace_err(J, LJ_TRERR_CJITOFF); | 1745 | J->maxslot = pt->numparams; |
1715 | if ((pt->flags & PROTO_IS_VARARG)) | 1746 | check_call_unroll(J); |
1716 | lj_trace_err(J, LJ_TRERR_NYIVF); | ||
1717 | if (cres == CALLRES_TAILCALL) { | ||
1718 | ptrdiff_t i; | ||
1719 | /* Tailcalls can form a loop, so count towards the loop unroll limit. */ | ||
1720 | if (++J->tailcalled > J->loopunroll) | ||
1721 | lj_trace_err(J, LJ_TRERR_LUNROLL); | ||
1722 | for (i = 0; i <= nargs; i++) /* Move func + args down. */ | ||
1723 | J->base[i-1] = res[i]; | ||
1724 | J->framedepth--; | ||
1725 | /* Note: the new FRAME is now at J->base[-1] (even for slot #0). */ | ||
1726 | } else { /* Regular call. */ | ||
1727 | J->base += func+1; | ||
1728 | J->baseslot += func+1; | ||
1729 | } | ||
1730 | if (J->baseslot + pt->framesize >= LJ_MAX_JSLOTS) | ||
1731 | lj_trace_err(J, LJ_TRERR_STACKOV); | ||
1732 | /* Fill up missing args with nil. */ | ||
1733 | while (nargs < pt->numparams) | ||
1734 | J->base[nargs++] = TREF_NIL; | ||
1735 | /* The remaining slots should never be read before they are written. */ | ||
1736 | J->maxslot = pt->numparams; | ||
1737 | check_call_unroll(J, rd.fn); | ||
1738 | return 0; /* No result yet. */ | ||
1739 | } else { /* Record call to C function or fast function. */ | ||
1740 | uint32_t m = 0; | ||
1741 | BCReg oldmaxslot = J->maxslot; | ||
1742 | res[1+nargs] = 0; | ||
1743 | rd.nargs = nargs; | ||
1744 | if (rd.fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0])) | ||
1745 | m = recff_idmap[rd.fn->c.ffid]; | ||
1746 | rd.data = m & 0xff; | ||
1747 | rd.cres = cres; | ||
1748 | rd.nres = 1; /* Default is one result. */ | ||
1749 | (recff_func[m >> 8])(J, res, &rd); /* Call recff_* handler. */ | ||
1750 | J->framedepth--; | ||
1751 | cres = rd.cres; | ||
1752 | if (cres >= 0) { | ||
1753 | /* Caller takes fixed number of results: local a,b = f() */ | ||
1754 | J->maxslot = func + (BCReg)cres; | ||
1755 | while (rd.nres < cres) /* Fill up missing results with nil. */ | ||
1756 | res[rd.nres++] = TREF_NIL; | ||
1757 | } else if (cres == CALLRES_MULTI) { | ||
1758 | /* Caller takes any number of results: return 1,f() */ | ||
1759 | J->maxslot = func + (BCReg)rd.nres; | ||
1760 | } else if (cres == CALLRES_TAILCALL) { | ||
1761 | /* Tail call: return f() */ | ||
1762 | rec_ret(J, func, rd.nres); | ||
1763 | } else if (cres == CALLRES_CONT) { | ||
1764 | /* Note: immediately resolved continuations must not change J->maxslot. */ | ||
1765 | J->maxslot = oldmaxslot; | ||
1766 | J->framedepth--; | ||
1767 | res[rd.nres] = TREF_NIL; /* Turn 0 results into nil result. */ | ||
1768 | } else { | ||
1769 | lua_assert(cres == CALLRES_PENDING); | ||
1770 | J->framedepth++; | ||
1771 | return 0; /* Pending call, no result yet. */ | ||
1772 | } | ||
1773 | return 1; /* Result resolved immediately. */ | ||
1774 | } | ||
1775 | } | 1747 | } |
1776 | 1748 | ||
1777 | /* -- Record allocations -------------------------------------------------- */ | 1749 | /* -- Record allocations -------------------------------------------------- */ |
@@ -2068,22 +2040,25 @@ void lj_record_ins(jit_State *J) | |||
2068 | copyTV(J->L, b+1, b-2); | 2040 | copyTV(J->L, b+1, b-2); |
2069 | copyTV(J->L, b+2, b-1); | 2041 | copyTV(J->L, b+2, b-1); |
2070 | } | 2042 | } |
2071 | goto callop; | 2043 | rec_call(J, ra, (ptrdiff_t)rc-1); |
2044 | break; | ||
2072 | 2045 | ||
2073 | case BC_CALLMT: | 2046 | /* L->top is set to L->base+ra+rc+NARGS-1+1. See lj_dispatch_ins(). */ |
2074 | rb = (TRef)(CALLRES_TAILCALL+1); | ||
2075 | /* fallthrough */ | ||
2076 | case BC_CALLM: | 2047 | case BC_CALLM: |
2077 | /* L->top is set to L->base+ra+rc+NRESULTS-1+1, see lj_dispatch_ins(). */ | ||
2078 | rc = (BCReg)(J->L->top - J->L->base) - ra; | 2048 | rc = (BCReg)(J->L->top - J->L->base) - ra; |
2079 | goto callop; | ||
2080 | |||
2081 | case BC_CALLT: | ||
2082 | rb = (TRef)(CALLRES_TAILCALL+1); | ||
2083 | /* fallthrough */ | 2049 | /* fallthrough */ |
2084 | case BC_CALL: | 2050 | case BC_CALL: |
2085 | callop: | 2051 | rec_call(J, ra, (ptrdiff_t)rc-1); |
2086 | rec_call(J, ra, (ptrdiff_t)rb-1, (ptrdiff_t)rc-1); | 2052 | break; |
2053 | |||
2054 | case BC_CALLMT: | ||
2055 | rc = (BCReg)(J->L->top - J->L->base) - ra; | ||
2056 | /* fallthrough */ | ||
2057 | case BC_CALLT: | ||
2058 | rec_tailcall(J, ra, (ptrdiff_t)rc-1); | ||
2059 | /* Tailcalls can form a loop, so count towards the loop unroll limit. */ | ||
2060 | if (++J->tailcalled > J->loopunroll) | ||
2061 | lj_trace_err(J, LJ_TRERR_LUNROLL); | ||
2087 | break; | 2062 | break; |
2088 | 2063 | ||
2089 | /* -- Returns ----------------------------------------------------------- */ | 2064 | /* -- Returns ----------------------------------------------------------- */ |
@@ -2094,6 +2069,7 @@ void lj_record_ins(jit_State *J) | |||
2094 | /* fallthrough */ | 2069 | /* fallthrough */ |
2095 | case BC_RET: case BC_RET0: case BC_RET1: | 2070 | case BC_RET: case BC_RET0: case BC_RET1: |
2096 | rec_ret(J, ra, (ptrdiff_t)rc-1); | 2071 | rec_ret(J, ra, (ptrdiff_t)rc-1); |
2072 | J->tailcalled = 0; /* NYI: logic is broken, need a better check. */ | ||
2097 | break; | 2073 | break; |
2098 | 2074 | ||
2099 | /* -- Loops and branches ------------------------------------------------ */ | 2075 | /* -- Loops and branches ------------------------------------------------ */ |
@@ -2132,6 +2108,8 @@ void lj_record_ins(jit_State *J) | |||
2132 | case BC_IFORL: | 2108 | case BC_IFORL: |
2133 | case BC_IITERL: | 2109 | case BC_IITERL: |
2134 | case BC_ILOOP: | 2110 | case BC_ILOOP: |
2111 | case BC_IFUNCF: | ||
2112 | case BC_IFUNCV: | ||
2135 | lj_trace_err(J, LJ_TRERR_LBLACKL); | 2113 | lj_trace_err(J, LJ_TRERR_LBLACKL); |
2136 | break; | 2114 | break; |
2137 | 2115 | ||
@@ -2140,12 +2118,37 @@ void lj_record_ins(jit_State *J) | |||
2140 | J->maxslot = ra; /* Shrink used slots. */ | 2118 | J->maxslot = ra; /* Shrink used slots. */ |
2141 | break; | 2119 | break; |
2142 | 2120 | ||
2121 | /* -- Function headers -------------------------------------------------- */ | ||
2122 | |||
2123 | case BC_FUNCF: | ||
2124 | rec_func_lua(J); | ||
2125 | break; | ||
2126 | |||
2127 | case BC_JFUNCF: | ||
2128 | lj_trace_err(J, LJ_TRERR_NYILNKF); | ||
2129 | break; | ||
2130 | |||
2131 | case BC_FUNCV: | ||
2132 | case BC_JFUNCV: | ||
2133 | lj_trace_err(J, LJ_TRERR_NYIVF); | ||
2134 | break; | ||
2135 | |||
2136 | case BC_FUNCC: | ||
2137 | case BC_FUNCCW: | ||
2138 | rec_func_ff(J); | ||
2139 | break; | ||
2140 | |||
2141 | default: | ||
2142 | if (op >= BC__MAX) { | ||
2143 | rec_func_ff(J); | ||
2144 | break; | ||
2145 | } | ||
2146 | /* fallthrough */ | ||
2143 | case BC_CAT: | 2147 | case BC_CAT: |
2144 | case BC_UCLO: | 2148 | case BC_UCLO: |
2145 | case BC_FNEW: | 2149 | case BC_FNEW: |
2146 | case BC_TSETM: | 2150 | case BC_TSETM: |
2147 | case BC_VARG: | 2151 | case BC_VARG: |
2148 | default: | ||
2149 | setintV(&J->errinfo, (int32_t)op); | 2152 | setintV(&J->errinfo, (int32_t)op); |
2150 | lj_trace_err_info(J, LJ_TRERR_NYIBC); | 2153 | lj_trace_err_info(J, LJ_TRERR_NYIBC); |
2151 | break; | 2154 | break; |