📄 ljit_x86.dasc
字号:
| fld qword BASE[rkc].value | fld qword [kval] } else { | fld qword [kval] | fld qword BASE[rkb].value } } else { | isnumber2 rkb, rkc | mov eax, BASE[rkb].value.na[1] | jne L_DEOPTIMIZEF | or eax, BASE[rkc].value.na[1]; js L_DEOPTIMIZEF | fld qword BASE[rkc].value | fld qword BASE[rkb].value } |1: ; fprem; fnstsw ax; sahf; jp <1 | fstp st1 goto fpstore; case TM_POW: if (hastail || !kval) break; /* Avoid this if not optimizing. */ if (rev) { /* x^k for k > 0, k integer. */ lua_Number n = kval->n; int k; lua_number2int(k, n); /* All positive integers would work. But need to limit code explosion. */ if (k > 0 && k <= 65536 && (lua_Number)k == n) { | isnumber idx; jne L_DEOPTIMIZEF | fld qword BASE[idx] for (; (k & 1) == 0; k >>= 1) { /* Handle leading zeroes (2^k). */ | fmul st0 } if ((k >>= 1) != 0) { /* Handle trailing bits. */ | fld st0 | fmul st0 for (; k != 1; k >>= 1) { if (k & 1) { | fmul st1, st0 } | fmul st0 } | fmulp st1 } goto fpstore; } } else if (kval->n > (lua_Number)0) { /* k^x for k > 0. */ int log2kval[3]; /* Enough storage for a tword (80 bits). */ log2kval[2] = 0; /* Avoid leaking garbage. */ /* Double precision log2(k) doesn't cut it (3^x != 3 for x = 1). */ ((void (*)(int *, double))J->jsub[JSUB_LOG2_TWORD])(log2kval, kval->n); | mov ARG1, log2kval[0] // Abuse stack for tword const. | mov ARG2, log2kval[1] | mov ARG3, log2kval[2] // TODO: store2load fwd stall. | isnumber idx; jne L_DEOPTIMIZEF | fld tword [esp] | fmul qword BASE[idx].value // log2(k)*x | fld st0; frndint; fsub st1, st0; fxch // Split into fract/int part. | f2xm1; fld1; faddp st1; fscale // (2^fract-1 +1) << int. | fstp st1 |.jsub LOG2_TWORD // Calculate log2(k) with max. precision. |// Called with (int *ptr, double k). | fld1; fld FPARG2 // Offset ok due to retaddr. | fyl2x | mov eax, ARG2 // Really ARG1. | fstp tword [eax] | ret |.endjsub goto fpstore; } break; } /* Check number type and load 1st operand. */ if (kval) { | isnumber idx; jne L_DEOPTIMIZEF | loadnvaluek kval } else { if (rkb == rkc) { | isnumber rkb } else { | isnumber2 rkb, rkc } | jne L_DEOPTIMIZEF | fld qword BASE[rkb].value } /* Encode arithmetic operation with 2nd operand. */ switch ((ev<<1)+rev) { case TM_ADD<<1: case (TM_ADD<<1)+1: if (rkb == rkc) { | fadd st0 } else { | fadd qword BASE[idx].value } break; case TM_SUB<<1: | fsub qword BASE[idx].value break; case (TM_SUB<<1)+1: | fsubr qword BASE[idx].value break; case TM_MUL<<1: case (TM_MUL<<1)+1: if (rkb == rkc) { | fmul st0 } else { | fmul qword BASE[idx].value } break; case TM_DIV<<1: | fdiv qword BASE[idx].value break; case (TM_DIV<<1)+1: | fdivr qword BASE[idx].value break; case TM_POW<<1: | sub esp, S2LFRAME_OFFSET | fstp FPARG1 | fld qword BASE[idx].value | fstp FPARG2 | call &pow | add esp, S2LFRAME_OFFSET break; case (TM_POW<<1)+1: | sub esp, S2LFRAME_OFFSET | fstp FPARG2 | fld qword BASE[idx].value | fstp FPARG1 | call &pow | add esp, S2LFRAME_OFFSET break; case TM_UNM<<1: case (TM_UNM<<1)+1: | fchs // No 2nd operand. break; default: /* TM_LT or TM_LE. */ | fld qword BASE[idx].value | fcomparepp | jp =>dest?(J->nextpc+1):target // Unordered means false. jit_assert(dest == 0 || dest == 1); /* Really cond. */ switch (((rev^dest)<<1)+(dest^(ev == TM_LT))) { case 0: | jb =>target break; case 1: | jbe =>target break; case 2: | ja =>target break; case 3: | jae =>target break; } goto skipstore; }fpstore: /* Store result and set result type (if necessary). */ | fstp qword BASE[dest].value if (dest != rkb && dest != rkc) { | settt BASE[dest], LUA_TNUMBER }skipstore: if (!hastail) { jit_deopt_target(J, 0); return; } |4: |.tail |L_DEOPTLABEL: // Recycle as fallback label.fallback: /* Generic fallback for arithmetic ops. */ if (kkb) { | mov ecx, &kkb } else { | lea ecx, BASE[rkb] } if (kkc) { | mov edx, &kkc } else { | lea edx, BASE[rkc] } if (target) { /* TM_LT or TM_LE. */ | mov L->savedpc, &(J->nextins+1) | call &ev==TM_LT?luaV_lessthan:luaV_lessequal, L, ecx, edx | test eax, eax | mov BASE, L->base if (dest) { /* cond */ | jnz =>target } else { | jz =>target } } else { | addidx BASE, dest | mov L->savedpc, &J->nextins | call &luaV_arith, L, BASE, ecx, edx, ev | mov BASE, L->base } if (hastail) { | jmp <4 |.code }}/* ------------------------------------------------------------------------ */static void jit_fallback_len(lua_State *L, StkId ra, const TValue *rb){ switch (ttype(rb)) { case LUA_TTABLE: setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; case LUA_TSTRING: setnvalue(ra, cast_num(tsvalue(rb)->len)); break; default: { const TValue *tm = luaT_gettmbyobj(L, rb, TM_LEN); if (ttisfunction(tm)) { ptrdiff_t rasave = savestack(L, ra); setobj2s(L, L->top, tm); setobj2s(L, L->top+1, rb); luaD_checkstack(L, 2); L->top += 2; luaD_call(L, L->top - 2, 1); ra = restorestack(L, rasave); L->top--; setobjs2s(L, ra, L->top); } else { luaG_typeerror(L, rb, "get length of"); } break; } }}static void jit_op_len(jit_State *J, int dest, int rb){ switch (ttype(hint_get(J, TYPE))) { case LUA_TTABLE: jit_deopt_target(J, 0); | istable rb | mov TABLE:ecx, BASE[rb].value | jne L_DEOPTIMIZE // TYPE hint was wrong? | call &luaH_getn, TABLE:ecx | mov TMP1, eax | fild dword TMP1 | fstp qword BASE[dest].value | settt BASE[dest], LUA_TNUMBER break; case LUA_TSTRING: jit_deopt_target(J, 0); | isstring rb | mov TSTRING:ecx, BASE[rb].value | jne L_DEOPTIMIZE // TYPE hint was wrong? | fild aword TSTRING:ecx->tsv.len // size_t | fstp qword BASE[dest].value | settt BASE[dest], LUA_TNUMBER break; default: | lea TVALUE:ecx, BASE[rb] | addidx BASE, dest | mov L->savedpc, &J->nextins | call &jit_fallback_len, L, BASE, TVALUE:ecx | mov BASE, L->base break; }}static void jit_op_not(jit_State *J, int dest, int rb){ /* l_isfalse() without a branch -- truly devious. */ /* ((value & tt) | (tt>>1)) is only zero for nil/false. */ /* Assumes: LUA_TNIL == 0, LUA_TBOOLEAN == 1, bvalue() == 0/1 */ | mov eax, BASE[rb].tt | mov ecx, BASE[rb].value | mov edx, 1 | and ecx, eax | shr eax, 1 | or ecx, eax | xor eax, eax | cmp ecx, edx | adc eax, eax | mov BASE[dest].tt, edx | mov BASE[dest].value, eax}/* ------------------------------------------------------------------------ */static void jit_op_concat(jit_State *J, int dest, int first, int last){ int num = last-first+1; if (num == 2 && ttisstring(hint_get(J, TYPE))) { /* Optimize common case. */ | addidx BASE, first | call ->CONCAT_STR2 | setsvalue BASE[dest], eax } else { /* Generic fallback. */ | mov L->savedpc, &J->nextins | call &luaV_concat, L, num, last | mov BASE, L->base if (dest != first) { | copyslot BASE[dest], BASE[first] } } jit_checkGC(J); /* Always do this, even for the optimized variant. */ |.jsub CONCAT_STR2 // Concatenate two strings. |// Call with: BASE (first). Destroys all regs. L and BASE restored. | mov ARG2, L // Save L (esi). | mov eax, BASE[0].tt; shl eax, 4; or eax, BASE[1].tt | sub eax, LUA_TSTR_STR // eax = 0 on success. | jne ->DEOPTIMIZE_CALLER // Wrong types? Deoptimize. | |1: | mov GL:edi, L->l_G | mov TSTRING:esi, BASE[0].value // Caveat: L (esi) is gone now! | mov TSTRING:edx, BASE[1].value | mov ecx, TSTRING:esi->tsv.len // size_t | test ecx, ecx | jz >2 // 1st string is empty? | or eax, TSTRING:edx->tsv.len // eax is known to be zero. | jz >4 // 2nd string is empty? | add eax, ecx | jc >9 // Length overflow? | cmp eax, GL:edi->buff.buffsize // size_t | ja >5 // Temp buffer overflow? | mov edi, GL:edi->buff.buffer | add esi, #TSTRING | rep; movsb // Copy first string. | mov ecx, TSTRING:edx->tsv.len | lea esi, TSTRING:edx[1] | rep; movsb // Copy second string. | | sub edi, eax // start = end - total. | mov L, ARG2 // Restore L (esi). Reuse as 1st arg. | mov ARG3, edi | mov ARG4, eax | mov BASE, L->base // Restore BASE. | jmp &luaS_newlstr | |2: // 1st string is empty. | mov eax, TSTRING:edx // Return 2nd string. |3: | mov L, ARG2 // Restore L (esi) and BASE. | mov BASE, L->base | ret | |4: // 2nd string is empty. | mov eax, TSTRING:esi // Return 1st string. | jmp <3 | |5: // Resize temp buffer. | // No need for setting L->savedpc since only LUA_ERRMEM may be thrown. | mov L, ARG2 // Restore L. | lea ecx, GL:edi->buff | sub esp, FRAME_OFFSET | call &luaZ_openspace, L, ecx, eax | add esp, FRAME_OFFSET | xor eax, eax // BASE (first) and L saved. eax = 0. | jmp <1 // Just restart. | |9: // Length overflow errors are rare (> 2 GB string required). | mov L, ARG2 // Need L for deoptimization. | jmp ->DEOPTIMIZE_CALLER |.endjsub}/* ------------------------------------------------------------------------ */static void jit_op_eq(jit_State *J, int cond, int rkb, int rkc){ int target = jit_jmp_target(J); int condtarget = cond ? (J->nextpc+1) : target; jit_assert(cond == 0 || cond == 1); /* Comparison of two constants. Evaluate at compile time. */ if (ISK(rkb&rkc)) { if ((rkb == rkc) == cond) { /* Constants are already unique. */ | jmp =>target } return; } if (ISK(rkb|rkc)) { /* Compare a variable and a constant. */ const TValue *kk; if (ISK(rkb)) { int t = rkc; rkc = rkb; rkb = t; } /* rkc holds const. */ kk = &J->pt->k[INDEXK(rkc)]; switch (ttype(kk)) { case LUA_TNIL: | isnil rkb break; case LUA_TBOOLEAN: if (bvalue(kk)) { | mov eax, BASE[rkb].tt | mov ecx, BASE[rkb].value | dec eax | dec ecx | or eax, ecx } else { | mov eax, BASE[rkb].tt | dec eax | or eax, BASE[rkb].value } break; case LUA_TNUMBER: |// Note: bitwise comparison is not faster (and needs to handle -0 == 0). | isnumber rkb | jne =>condtarget | fld qword BASE[rkb].value | fld qword [&kk->value] | fcomparepp | jp =>condtarget // Unordered means not equal. break; case LUA_TSTRING: | isstring rkb | jne =>condtarget | cmp aword BASE[rkb].value, &rawtsvalue(kk) break; default: jit_assert(0); break; } } else { /* Compare two variables. */ | mov eax, BASE[rkb].tt | cm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -