📄 ljit_x86.dasc
字号:
| mov L->top, TOP } /* Otherwise keep TOP for next instruction. */}static void jit_op_tailcall(jit_State *J, int func, int nargs){ int cltype; if (!fhint_isset(J, NOCLOSE)) { /* May need to close open upvalues. */ | call &luaF_close, L, BASE } cltype = jit_inline_call(J, func, nargs, -2); if (cltype < 0) goto finish; /* Inlined? */ if (cltype == LUA_TFUNCTION) { jit_deopt_target(J, nargs); | isfunction func | jne L_DEOPTIMIZE // TYPE hint was wrong? } else { | isfunction func; jne >5 // Handle generic callables first. |.tail |5: // Fallback for generic callables. | addidx BASE, func if (nargs >= 0) { | lea TOP, BASE[1+nargs] } | mov edx, &J->nextins | jmp ->METATAILCALL |.code |.jsub METATAILCALL // TAILCALL to __call metamethod. | mov L->savedpc, edx | mov L->top, TOP | call &luaD_tryfuncTM, L, BASE // Resolve __call metamethod. | |// Relocate [eax, L->top) -> [L->ci->func, *). | mov CI, L->ci | mov edx, L->top | mov TOP, CI->func |1: | mov BASE, [eax] | add eax, aword*1 | mov [TOP], BASE | add TOP, aword*1 | cmp eax, edx | jb <1 | | mov BASE, CI->func | mov LCL, BASE->value | sub CI, #CI | add esp, FRAME_OFFSET | jmp aword LCL->jit_gate // Chain to callgate. |.endjsub } if (nargs >= 0) { /* Previous op was not open and did not set TOP. */ int i; /* Relocate [BASE+func, BASE+func+nargs] -> [ci->func, ci->func+nargs]. */ /* TODO: loop for large nargs? */ if (!J->pt->is_vararg) { /* Fixarg function. */ | mov LCL, BASE[func].value for (i = 0; i < nargs; i++) { | copyslot BASE[i], BASE[func+1+i], ecx, edx } | lea TOP, BASE[nargs] | sub BASE, #BASE | mov CI, L->ci | mov BASE->value, LCL // Sufficient to copy func->value. } else { /* Vararg function. */ | mov CI, L->ci | lea TOP, BASE[func] | mov BASE, CI->func | mov LCL, TOP->value | mov BASE->value, LCL // Sufficient to copy func->value. for (i = 0; i < nargs; i++) { | copyslot BASE[i+1], TOP[i+1], eax, edx } | lea TOP, BASE[1+nargs] | mov LCL, BASE->value // Need to reload LCL = eax. } } else { /* Previous op was open and set TOP. */ |// Relocate [BASE+func, TOP) -> [ci->func, *). | mov CI, L->ci | addidx BASE, func | mov edx, CI->func |1: | mov eax, [BASE] | add BASE, aword*1 | mov [edx], eax | add edx, aword*1 | cmp BASE, TOP | jb <1 | mov BASE, CI->func | mov TOP, edx // Relocated TOP. | mov LCL, BASE->value } | sub CI, #CI | add esp, FRAME_OFFSET | jmp aword LCL->jit_gate // Chain to JIT function.finish: J->combine++; /* Combine with following return instruction. */}/* ------------------------------------------------------------------------ */static void jit_op_move(jit_State *J, int dest, int src){ | copyslot BASE[dest], BASE[src]}static void jit_op_loadk(jit_State *J, int dest, int kidx){ const TValue *kk = &J->pt->k[kidx]; int rk = jit_return_k(J); if (rk) dest = 0; | copyconst BASE[dest], kk if (rk) { | ret }}static void jit_op_loadnil(jit_State *J, int first, int last){ int idx, num = last - first + 1; int rk = jit_return_k(J); | xor eax, eax // Assumes: LUA_TNIL == 0 if (rk) { | settt BASE[0], eax | ret } else if (num <= 8) { for (idx = first; idx <= last; idx++) { | settt BASE[idx], eax // 3/6 bytes } } else { | lea ecx, BASE[first].tt // 15-21 bytes | lea edx, BASE[last].tt |1: | mov [ecx], eax | cmp ecx, edx | lea ecx, [ecx+#BASE] // Preserves CC. | jbe <1 }}static void jit_op_loadbool(jit_State *J, int dest, int b, int dojump){ int rk = jit_return_k(J); if (rk) dest = 0; | setbvalue BASE[dest], b if (rk) { | ret } else if (dojump) { const TValue *h = hint_getpc(J, COMBINE, J->nextpc); if (!(ttisboolean(h) && bvalue(h) == 0)) { /* Avoid jmp around dead ins. */ | jmp =>J->nextpc+1 } }}/* ------------------------------------------------------------------------ */static void jit_op_getupval(jit_State *J, int dest, int uvidx){ | getLCL | mov UPVAL:ecx, LCL->upvals[uvidx] | mov TOP, UPVAL:ecx->v | copyslot BASE[dest], TOP[0]}static void jit_op_setupval(jit_State *J, int src, int uvidx){ | getLCL | mov UPVAL:ecx, LCL->upvals[uvidx] | mov TOP, UPVAL:ecx->v | // This is really copyslot TOP[0], BASE[src] with compare mixed in. | mov eax, BASE[src].tt | mov GCOBJECT:edx, BASE[src].value | mov TOP->tt, eax | cmp eax, LUA_TSTRING // iscollectable(val)? | mov eax, BASE[src].value.na[1] | mov TOP->value, GCOBJECT:edx | mov TOP->value.na[1], eax | jae >5 |4: |.tail |5: | test byte GCOBJECT:edx->gch.marked, WHITEBITS // && iswhite(val) | jz <4 | test byte UPVAL:ecx->marked, bitmask(BLACKBIT) // && isblack(uv) | jz <4 | call ->BARRIERF // Yes, need barrier. | jmp <4 |.code |.jsub BARRIERF // luaC_barrierf() with regparms. | mov ARG4, GCOBJECT:edx | mov ARG3, UPVAL:ecx | mov ARG2, L | jmp &luaC_barrierf // Chain to C code. |.endjsub}/* ------------------------------------------------------------------------ *//* Optimized table lookup routines. Enter via jsub, fallback to C. *//* Fallback for GETTABLE_*. Temporary key is in L->env. */static void jit_gettable_fb(lua_State *L, Table *t, StkId dest){ Table *mt = t->metatable; const TValue *tm = luaH_getstr(mt, G(L)->tmname[TM_INDEX]); if (ttisnil(tm)) { /* No __index method? */ mt->flags |= 1<<TM_INDEX; /* Cache this fact. */ setnilvalue(dest); } else if (ttisfunction(tm)) { /* __index function? */ ptrdiff_t destr = savestack(L, dest); setobj2s(L, L->top, tm); sethvalue(L, L->top+1, t); setobj2s(L, L->top+2, &L->env); luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1); dest = restorestack(L, destr); L->top--; setobjs2s(L, dest, L->top); } else { /* Let luaV_gettable() continue with the __index object. */ luaV_gettable(L, tm, &L->env, dest); } |//----------------------------------------------------------------------- |.jsub GETGLOBAL // Lookup global variable. |// Call with: TSTRING:edx (key), BASE (dest) | mov CI, L->ci | mov TOP, CI->func | mov LCL, TOP->value | mov TABLE:edi, LCL->env | jmp >9 |.endjsub | |//----------------------------------------------------------------------- |.jsub GETTABLE_KSTR // Lookup constant string in table. |// Call with: TOP (tab), TSTRING:edx (key), BASE (dest) | cmp dword TOP->tt, LUA_TTABLE | mov TABLE:edi, TOP->value | jne ->DEOPTIMIZE_CALLER // Not a table? Deoptimize. | |// Common entry: TABLE:edi (tab), TSTRING:edx (key), BASE (dest) |// Restores BASE, destroys eax, ecx, edx, edi (TOP). |9: | movzx ecx, byte TABLE:edi->lsizenode // hashstr(t, key). | mov eax, 1 | shl eax, cl | dec eax | and eax, TSTRING:edx->tsv.hash | Nodemul NODE:eax | add NODE:eax, TABLE:edi->node | |1: // Start of inner loop. Check node key. | cmp dword NODE:eax->i_key.nk.tt, LUA_TSTRING | jne >2 | cmp aword NODE:eax->i_key.nk.value, TSTRING:edx | jne >2 | // Note: swapping the two checks is faster, but valgrind complains. |// Assumes: (int)&(((Node *)0)->i_val) == (int)&(((StkId)0)->value) | |// Ok, key found. Copy node value to destination (stack) slot. | mov ecx, NODE:eax->i_val.tt | test ecx, ecx; je >3 // Node has nil value? ||if (J->flags & JIT_F_CPU_SSE2) { | movq xmm0, qword NODE:eax->i_val.value | movq qword BASE->value, xmm0 ||} else { | mov edx, NODE:eax->i_val.value | mov edi, NODE:eax->i_val.value.na[1] | mov BASE->value, edx | mov BASE->value.na[1], edi ||} | mov BASE->tt, ecx | mov BASE, L->base | ret |2: | mov NODE:eax, NODE:eax->i_key.nk.next // Get next key in chain. | test NODE:eax, NODE:eax | jnz <1 // Loop if non-NULL. | | xor ecx, ecx |3: | mov TABLE:eax, TABLE:edi->metatable | test TABLE:eax, TABLE:eax | jz >4 // No metatable? | test byte TABLE:eax->flags, 1<<TM_INDEX | jz >5 // Or 'no __index' flag set? |4: | settt BASE[0], ecx // Yes, set to nil. | mov BASE, L->base | ret | |5: // Otherwise chain to C code which eventually calls luaV_gettable. | setsvalue L->env, TSTRING:edx // Use L->env as temp key. | mov ecx, [esp] | sub esp, FRAME_OFFSET | mov L->savedpc, ecx | call &jit_gettable_fb, L, TABLE:edi, BASE | add esp, FRAME_OFFSET | mov BASE, L->base | ret |.endjsub | |//----------------------------------------------------------------------- |.jsub GETTABLE_STR // Lookup string in table. |// Call with: TOP (tab), TVALUE:ecx (key), BASE (dest) | mov eax, TOP->tt; shl eax, 4; or eax, TVALUE:ecx->tt | cmp eax, LUA_TTABLE_STR | mov TABLE:edi, TOP->value | mov TSTRING:edx, TVALUE:ecx->value | je <9 // Types ok? Continue above. | jmp ->DEOPTIMIZE_CALLER // Otherwise deoptimize. |.endjsub}/* Fallback for SETTABLE_*STR. Temporary (string) key is in L->env. */static void jit_settable_fb(lua_State *L, Table *t, StkId val){ Table *mt = t->metatable; const TValue *tm = luaH_getstr(mt, G(L)->tmname[TM_NEWINDEX]); if (ttisnil(tm)) { /* No __newindex method? */ mt->flags |= 1<<TM_NEWINDEX; /* Cache this fact. */ t->flags = 0; /* But need to clear the cache for the table itself. */ setobj2t(L, luaH_setstr(L, t, rawtsvalue(&L->env)), val); luaC_barriert(L, t, val); } else if (ttisfunction(tm)) { /* __newindex function? */ setobj2s(L, L->top, tm); sethvalue(L, L->top+1, t); setobj2s(L, L->top+2, &L->env); setobj2s(L, L->top+3, val); luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0); } else { /* Let luaV_settable() continue with the __newindex object. */ luaV_settable(L, tm, &L->env, val); } |//----------------------------------------------------------------------- |.jsub BARRIERBACK // luaC_barrierback() with regparms. |// Call with: TABLE:edi (table). Destroys ecx, edx. | mov GL:ecx, L->l_G | and byte TABLE:edi->marked, (~bitmask(BLACKBIT))&0xff | mov edx, GL:ecx->grayagain | mov GL:ecx->grayagain, TABLE:edi | mov TABLE:edi->gclist, edx | ret |.endjsub | |//----------------------------------------------------------------------- |.jsub SETGLOBAL // Set global variable. |// Call with: TSTRING:edx (key), BASE (val) | mov CI, L->ci | mov TOP, CI->func | mov LCL, TOP->value | mov TABLE:edi, LCL->env | jmp >9 |.endjsub | |//----------------------------------------------------------------------- |.jsub SETTABLE_KSTR // Set constant string entry in table. |// Call with: TOP (tab), TSTRING:edx (key), BASE (val) | cmp dword TOP->tt, LUA_TTABLE | mov TABLE:edi, TOP->value | jne ->DEOPTIMIZE_CALLER // Not a table? Deoptimize. | |// Common entry: TABLE:edi (tab), TSTRING:edx (key), BASE (val) |// Restores BASE, destroys eax, ecx, edx, edi (TOP). |9: | movzx ecx, byte TABLE:edi->lsizenode // hashstr(t, key). | mov eax, 1 | shl eax, cl | dec eax | and eax, TSTRING:edx->tsv.hash | Nodemul NODE:eax | add NODE:eax, TABLE:edi->node | |1: // Start of inner loop. Check node key. | cmp dword NODE:eax->i_key.nk.tt, LUA_TSTRING | jne >4 | cmp aword NODE:eax->i_key.nk.value, TSTRING:edx | jne >4 | // Note: swapping the two checks is faster, but valgrind complains. | |// Ok, key found. Copy new value to node value. | cmp dword NODE:eax->i_val.tt, LUA_TNIL // Previous value is nil? | je >6 | // Assumes: (int)&(((Node *)0)->i_val) == (int)&(((StkId)0)->value) |2: | mov byte TABLE:edi->flags, 0 // Clear metamethod cache. |3: // Target for SETTABLE_NUM below. | test byte TABLE:edi->marked, bitmask(BLACKBIT) // isblack(table) | jnz >8 // Unlikely, but set barrier back. |7: // Caveat: recycled label. | copyslot TVALUE:eax[0], BASE[0], ecx, edx, TOP | mov BASE, L->base | ret | |8: // Avoid valiswhite() check -- black2gray(table) is ok. | call ->BARRIERBACK | jmp <7 | |4: | mov NODE:eax, NODE:eax->i_key.nk.next // Get next key in chain. | test NODE:eax, NODE:eax | jnz <1 // Loop if non-NULL. | |// Key not found. Add a new one, but check metatable first. | mov TABLE:ecx, TABLE:edi->metatable | test TABLE:ecx, TABLE:ecx | jz >5 // No metatable? | test byte TABLE:ecx->flags, 1<<TM_NEWINDEX | jz >7 // Or 'no __newindex' flag set? | |5: // Add new key. | // No need for setting L->savedpc since only LUA_ERRMEM may be thrown. | lea TVALUE:eax, L->env | setsvalue TVALUE:eax[0], TSTRING:edx | sub esp, FRAME_OFFSET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -