📄 ljit_x86_inline.dash
字号:
/*** Function inlining support for x86 CPUs.** Copyright (C) 2005-2008 Mike Pall. See Copyright Notice in luajit.h*//* ------------------------------------------------------------------------ *//* Private structure holding function inlining info. */typedef struct jit_InlineInfo { int func; /* Function slot. 1st arg slot = func+1. */ int res; /* 1st result slot. Overlaps func/ci->func. */ int nargs; /* Number of args. */ int nresults; /* Number of results. */ int xnargs; /* Expected number of args. */ int xnresults; /* Returned number of results. */ int hidx; /* Library/function index numbers. */} jit_InlineInfo;/* ------------------------------------------------------------------------ */enum { TFOR_FUNC, TFOR_TAB, TFOR_CTL, TFOR_KEY, TFOR_VAL };static void jit_inline_base(jit_State *J, jit_InlineInfo *ii){ int func = ii->func; switch (JIT_IH_IDX(ii->hidx)) { case JIT_IH_BASE_PAIRS: case JIT_IH_BASE_IPAIRS: |// Easy for regular calls: res == func. Not inlined for tailcalls. |// Guaranteed to be inlined only if used in conjunction with TFORLOOP. |// So we omit setting the iterator function and fake the control var. | istable func+TFOR_TAB; jne L_DEOPTIMIZE // Caveat: deopt TFORLOOP, too! | xor eax, eax // Assumes: LUA_TNIL == 0. | mov BASE[func+TFOR_CTL].tt, eax // Fake nil type. | mov BASE[func+TFOR_CTL].value, eax // Hidden control var = 0. |// mov BASE[func+TFOR_FUNC].tt, eax // Kill function (not needed). |.mfmap | .word JIT_MFM_DEOPT_PAIRS, J->nextpc-1 // Deoptimize TFORLOOP, too. |.code break; default: jit_assert(0); break; }}/* ------------------------------------------------------------------------ */#ifndef COCO_DISABLE/* Helper function for inlined coroutine.resume(). */static StkId jit_coroutine_resume(lua_State *L, StkId base, int nresults){ lua_State *co = thvalue(base-1); /* Check for proper usage. Merge of lua_resume() and auxresume() checks. */ if (co->status != LUA_YIELD) { if (co->status > LUA_YIELD) {errdead: setsvalue(L, base-1, luaS_newliteral(L, "cannot resume dead coroutine")); goto err; } else if (co->ci != co->base_ci) { setsvalue(L, base-1, luaS_newliteral(L, "cannot resume non-suspended coroutine")); goto err; } else if (co->base == co->top) { goto errdead; } } { unsigned int ndelta = (char *)L->top - (char *)base; int nargs = ndelta/sizeof(TValue); /* Compute nargs. */ int status; if ((char *)co->stack_last-(char *)co->top <= ndelta) { co->ci->top = (StkId)(((char *)co->top) + ndelta); /* Ok before grow. */ luaD_growstack(co, nargs); /* Grow thread stack. */ } /* Copy args. */ co->top = (StkId)(((char *)co->top) + ndelta); { StkId t = co->top, f = L->top; while (f > base) setobj2s(co, --t, --f); } L->top = base; status = luaCOCO_resume(co, nargs); /* Resume Coco thread. */ if (status == 0 || status == LUA_YIELD) { /* Ok. */ StkId f; if (nresults == 0) return NULL; if (nresults == -1) { luaD_checkstack(L, co->top - co->base); /* Grow own stack. */ } base = L->top - 2; setbvalue(base++, 1); /* true */ /* Copy results. Fill unused result slots with nil. */ f = co->base; while (--nresults != 0 && f < co->top) setobj2s(L, base++, f++); while (nresults-- > 0) setnilvalue(base++); co->top = co->base; return base; } else { /* Error. */ base = L->top; setobj2s(L, base-1, co->top-1); /* Copy error object. */err: setbvalue(base-2, 0); /* false */ nresults -= 2; while (--nresults >= 0) setnilvalue(base+nresults); /* Fill results. */ return base; } }}static void jit_inline_coroutine(jit_State *J, jit_InlineInfo *ii){ int arg = ii->func+1; int res = ii->res; int i; switch (JIT_IH_IDX(ii->hidx)) { case JIT_IH_COROUTINE_YIELD: | cmp aword [L+((int)&LHASCOCO((lua_State *)0))], 0 // Got a C stack? | je L_DEOPTIMIZE | mov L->savedpc, &J->nextins // Debugger-friendly. | add BASE, arg*#TVALUE if (ii->nargs >= 0) { /* Previous op was not open and did not set TOP. */ | lea TOP, BASE[ii->nargs] } | mov L->base, BASE | mov L->top, TOP | call &luaCOCO_yield, L | mov BASE, L->base | mov TOP, L->top jit_assert(ii->nresults >= 0 && ii->nresults <= EXTRA_STACK); for (i = 0; i < ii->nresults; i++) { | setnilvalue TOP[i] // Clear undefined result. | copyslot BASE[res+i], BASE[arg+i] // Move result down. } ii->nargs = -1; /* Force restore of L->top. */ break; case JIT_IH_COROUTINE_RESUME: jit_assert(ii->nargs != 0 && ii->res == ii->func); | add BASE, (arg+1)*#TVALUE if (ii->nargs >= 0) { /* Previous op was not open and did not set TOP. */ | lea TOP, BASE[ii->nargs-1] } else { | cmp TOP, BASE; jb L_DEOPTIMIZE // No thread arg? Deoptimize. } | istt -1, LUA_TTHREAD; jne L_DEOPTIMIZE // Wrong type? Deoptimize. | mov L:eax, BASE[-1].value | cmp aword [L:eax+((int)&LHASCOCO((lua_State *)0))], 0 | je L_DEOPTIMIZE // No C stack? Deoptimize. | mov L->savedpc, &J->nextins // Debugger-friendly. | mov L->top, TOP | call &jit_coroutine_resume, L, BASE, ii->nresults | mov BASE, L->base if (ii->nresults == -1) { | mov TOP, eax } ii->nargs = -1; /* Force restore of L->top. */ break; default: jit_assert(0); break; }}#endif /* COCO_DISABLE *//* ------------------------------------------------------------------------ */static void jit_inline_string(jit_State *J, jit_InlineInfo *ii){ int arg = ii->func+1; int res = ii->res; switch (JIT_IH_IDX(ii->hidx)) { case JIT_IH_STRING_LEN: | isstring arg; jne L_DEOPTIMIZE | mov TSTRING:ecx, BASE[arg].value | fild aword TSTRING:ecx->tsv.len // size_t | settt BASE[res], LUA_TNUMBER | fstp qword BASE[res].value break; case JIT_IH_STRING_SUB: /* TODO: inline numeric constants with help from the optimizer. */ /* But this would save only another 15-20% in a trivial loop. */ jit_assert(ii->nargs >= 2); /* Open op caveat is ok, too. */ if (ii->nargs > 2) { | lea TOP, BASE[arg] | call ->STRING_SUB3 | setsvalue BASE[res], eax } else { | lea TOP, BASE[arg] | call ->STRING_SUB2 | setsvalue BASE[res], eax } break; case JIT_IH_STRING_CHAR: | isnumber arg; jne L_DEOPTIMIZE | lea eax, L->env // Abuse L->env to hold temp string. | fld qword BASE[arg].value | fistp dword [eax] // LSB is at start (little-endian). | cmp dword [eax], 255; ja L_DEOPTIMIZE | call &luaS_newlstr, L, eax, 1 | setsvalue BASE[res], eax break; default: jit_assert(0); break; } |//----------------------------------------------------------------------- |.jsub STRING_SUB3 // string.sub(str, start, end) | mov eax, TOP[0].tt; shl eax, 4; or eax, TOP[1].tt; shl eax, 4 | or eax, TOP[2].tt; sub eax, LUA_TSTR_NUM_NUM | jne ->DEOPTIMIZE_CALLER // Wrong types? Deoptimize. | // eax must be zero here! | fld qword TOP[1].value | fld qword TOP[2].value | fistp aword TMP3 // size_t | fistp aword TMP2 // size_t | mov TSTRING:ecx, TOP[0].value | mov TOP, aword TSTRING:ecx->tsv.len // size_t | mov edx, TMP3 | cmp TOP, edx | jb >4 |1: | or eax, TMP2 // eax is known to be zero. | jle >6 // start <= 0? |2: | sub edx, eax // newlen = end-start | jl >7 // start > end? | lea ecx, [TSTRING:ecx+eax+#TSTRING-1] // svalue()-1+start | inc edx |3: | mov ARG2, L // First arg for tailcall is ARG2. | mov ARG3, ecx // Pointer to start. | mov ARG4, edx // Length. | mov GL:edi, L->l_G | mov eax, GL:edi->totalbytes // size_t | cmp eax, GL:edi->GCthreshold // size_t | jae >8 // G->totalbytes >= G->GCthreshold? | jmp &luaS_newlstr // Tailcall to C function. | |4: // Negative end or overflow. | jl >5 | lea edx, [edx+TOP+1] // end = end+(len+1) | jmp <1 |5: // Overflow | mov edx, TOP // end = len | jmp <1 | |6: // Negative start or underflow. | je >5 | add eax, TOP // start = start+(len+1) | inc eax | jg <2 // start > 0? |5: // Underflow. | mov eax, 1 // start = 1 | jmp <2 | |7: // Range underflow. | xor edx, edx // Zero length. | jmp <3 // Any pointer in ecx is ok. |.endjsub | |//----------------------------------------------------------------------- |.jsub STRING_SUB2 // string.sub(str, start) | mov eax, TOP[0].tt; shl eax, 4; or eax, TOP[1].tt; sub eax, LUA_TSTR_NUM | jne ->DEOPTIMIZE_CALLER // Wrong types? Deoptimize. | // eax must be zero here! | fld qword TOP[1].value | fistp aword TMP2 // size_t | mov TSTRING:ecx, TOP[0].value | mov TOP, aword TSTRING:ecx->tsv.len // size_t | mov edx, TOP | jmp <1 // See STRING_SUB3. | |8: // GC threshold reached. | sub esp, FRAME_OFFSET | call &luaC_step, L | add esp, FRAME_OFFSET | mov BASE, L->base | jmp &luaS_newlstr // Tailcall to C function. |.endjsub}/* ------------------------------------------------------------------------ *//* Helper functions for inlined calls to table.*. */static void jit_table_insert(lua_State *L, TValue *arg){ setobj2t(L, luaH_setnum(L, hvalue(arg), luaH_getn(hvalue(arg))+1), arg+1); luaC_barriert(L, hvalue(arg), arg+1);}static TValue *jit_table_remove(lua_State *L, TValue *arg, TValue *res){ int n = luaH_getn(hvalue(arg)); if (n == 0) { setnilvalue(res); /* For the nresults == 1 case. Harmless otherwise. */ return res; /* For the nresults == -1 case. */ } else { TValue *val = luaH_setnum(L, hvalue(arg), n); setobj2s(L, res, val); setnilvalue(val); return res+1; /* For the nresults == -1 case. */ }}static void jit_inline_table(jit_State *J, jit_InlineInfo *ii){ int arg = ii->func+1; int res = ii->res; | istable arg; jne L_DEOPTIMIZE switch (JIT_IH_IDX(ii->hidx)) { case JIT_IH_TABLE_INSERT: jit_assert(ii->nargs == 2); | lea TVALUE:eax, BASE[arg] | call &jit_table_insert, L, TVALUE:eax break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -