diff options
| -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; |
