diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash b/libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash new file mode 100644 index 0000000..203642f --- /dev/null +++ b/libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash | |||
@@ -0,0 +1,625 @@ | |||
1 | /* | ||
2 | ** Function inlining support for x86 CPUs. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | /* ------------------------------------------------------------------------ */ | ||
7 | |||
8 | /* Private structure holding function inlining info. */ | ||
9 | typedef struct jit_InlineInfo { | ||
10 | int func; /* Function slot. 1st arg slot = func+1. */ | ||
11 | int res; /* 1st result slot. Overlaps func/ci->func. */ | ||
12 | int nargs; /* Number of args. */ | ||
13 | int nresults; /* Number of results. */ | ||
14 | int xnargs; /* Expected number of args. */ | ||
15 | int xnresults; /* Returned number of results. */ | ||
16 | int hidx; /* Library/function index numbers. */ | ||
17 | } jit_InlineInfo; | ||
18 | |||
19 | /* ------------------------------------------------------------------------ */ | ||
20 | |||
21 | enum { TFOR_FUNC, TFOR_TAB, TFOR_CTL, TFOR_KEY, TFOR_VAL }; | ||
22 | |||
23 | static void jit_inline_base(jit_State *J, jit_InlineInfo *ii) | ||
24 | { | ||
25 | int func = ii->func; | ||
26 | switch (JIT_IH_IDX(ii->hidx)) { | ||
27 | case JIT_IH_BASE_PAIRS: | ||
28 | case JIT_IH_BASE_IPAIRS: | ||
29 | |// Easy for regular calls: res == func. Not inlined for tailcalls. | ||
30 | |// Guaranteed to be inlined only if used in conjunction with TFORLOOP. | ||
31 | |// So we omit setting the iterator function and fake the control var. | ||
32 | | istable func+TFOR_TAB; jne L_DEOPTIMIZE // Caveat: deopt TFORLOOP, too! | ||
33 | | xor eax, eax // Assumes: LUA_TNIL == 0. | ||
34 | | mov BASE[func+TFOR_CTL].tt, eax // Fake nil type. | ||
35 | | mov BASE[func+TFOR_CTL].value, eax // Hidden control var = 0. | ||
36 | |// mov BASE[func+TFOR_FUNC].tt, eax // Kill function (not needed). | ||
37 | |.mfmap | ||
38 | | .word JIT_MFM_DEOPT_PAIRS, J->nextpc-1 // Deoptimize TFORLOOP, too. | ||
39 | |.code | ||
40 | break; | ||
41 | default: | ||
42 | jit_assert(0); | ||
43 | break; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /* ------------------------------------------------------------------------ */ | ||
48 | |||
49 | #ifndef COCO_DISABLE | ||
50 | |||
51 | /* Helper function for inlined coroutine.resume(). */ | ||
52 | static StkId jit_coroutine_resume(lua_State *L, StkId base, int nresults) | ||
53 | { | ||
54 | lua_State *co = thvalue(base-1); | ||
55 | /* Check for proper usage. Merge of lua_resume() and auxresume() checks. */ | ||
56 | if (co->status != LUA_YIELD) { | ||
57 | if (co->status > LUA_YIELD) { | ||
58 | errdead: | ||
59 | setsvalue(L, base-1, luaS_newliteral(L, "cannot resume dead coroutine")); | ||
60 | goto err; | ||
61 | } else if (co->ci != co->base_ci) { | ||
62 | setsvalue(L, base-1, | ||
63 | luaS_newliteral(L, "cannot resume non-suspended coroutine")); | ||
64 | goto err; | ||
65 | } else if (co->base == co->top) { | ||
66 | goto errdead; | ||
67 | } | ||
68 | } | ||
69 | { | ||
70 | ptrdiff_t ndelta = (char *)L->top - (char *)base; | ||
71 | int nargs = ndelta/sizeof(TValue); /* Compute nargs. */ | ||
72 | int status; | ||
73 | if ((char *)co->stack_last-(char *)co->top <= ndelta) { | ||
74 | co->ci->top = (StkId)(((char *)co->top) + ndelta); /* Ok before grow. */ | ||
75 | luaD_growstack(co, nargs); /* Grow thread stack. */ | ||
76 | } | ||
77 | /* Copy args. */ | ||
78 | co->top = (StkId)(((char *)co->top) + ndelta); | ||
79 | { StkId t = co->top, f = L->top; while (f > base) setobj2s(co, --t, --f); } | ||
80 | L->top = base; | ||
81 | status = luaCOCO_resume(co, nargs); /* Resume Coco thread. */ | ||
82 | if (status == 0 || status == LUA_YIELD) { /* Ok. */ | ||
83 | StkId f; | ||
84 | if (nresults == 0) return NULL; | ||
85 | if (nresults == -1) { | ||
86 | luaD_checkstack(L, co->top - co->base); /* Grow own stack. */ | ||
87 | } | ||
88 | base = L->top - 2; | ||
89 | setbvalue(base++, 1); /* true */ | ||
90 | /* Copy results. Fill unused result slots with nil. */ | ||
91 | f = co->base; | ||
92 | while (--nresults != 0 && f < co->top) setobj2s(L, base++, f++); | ||
93 | while (nresults-- > 0) setnilvalue(base++); | ||
94 | co->top = co->base; | ||
95 | return base; | ||
96 | } else { /* Error. */ | ||
97 | base = L->top; | ||
98 | setobj2s(L, base-1, co->top-1); /* Copy error object. */ | ||
99 | err: | ||
100 | setbvalue(base-2, 0); /* false */ | ||
101 | nresults -= 2; | ||
102 | while (--nresults >= 0) setnilvalue(base+nresults); /* Fill results. */ | ||
103 | return base; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static void jit_inline_coroutine(jit_State *J, jit_InlineInfo *ii) | ||
109 | { | ||
110 | int arg = ii->func+1; | ||
111 | int res = ii->res; | ||
112 | int i; | ||
113 | switch (JIT_IH_IDX(ii->hidx)) { | ||
114 | case JIT_IH_COROUTINE_YIELD: | ||
115 | | cmp aword [L+((int)&LHASCOCO((lua_State *)0))], 0 // Got a C stack? | ||
116 | | je L_DEOPTIMIZE | ||
117 | | mov L->savedpc, &J->nextins // Debugger-friendly. | ||
118 | | add BASE, arg*#TVALUE | ||
119 | if (ii->nargs >= 0) { /* Previous op was not open and did not set TOP. */ | ||
120 | | lea TOP, BASE[ii->nargs] | ||
121 | } | ||
122 | | mov L->base, BASE | ||
123 | | mov L->top, TOP | ||
124 | | call &luaCOCO_yield, L | ||
125 | | mov BASE, L->base | ||
126 | | mov TOP, L->top | ||
127 | jit_assert(ii->nresults >= 0 && ii->nresults <= EXTRA_STACK); | ||
128 | for (i = 0; i < ii->nresults; i++) { | ||
129 | | setnilvalue TOP[i] // Clear undefined result. | ||
130 | | copyslot BASE[res+i], BASE[arg+i] // Move result down. | ||
131 | } | ||
132 | ii->nargs = -1; /* Force restore of L->top. */ | ||
133 | break; | ||
134 | case JIT_IH_COROUTINE_RESUME: | ||
135 | jit_assert(ii->nargs != 0 && ii->res == ii->func); | ||
136 | | add BASE, (arg+1)*#TVALUE | ||
137 | if (ii->nargs >= 0) { /* Previous op was not open and did not set TOP. */ | ||
138 | | lea TOP, BASE[ii->nargs-1] | ||
139 | } else { | ||
140 | | cmp TOP, BASE; jb L_DEOPTIMIZE // No thread arg? Deoptimize. | ||
141 | } | ||
142 | | istt -1, LUA_TTHREAD; jne L_DEOPTIMIZE // Wrong type? Deoptimize. | ||
143 | | mov L:eax, BASE[-1].value | ||
144 | | cmp aword [L:eax+((int)&LHASCOCO((lua_State *)0))], 0 | ||
145 | | je L_DEOPTIMIZE // No C stack? Deoptimize. | ||
146 | | mov L->savedpc, &J->nextins // Debugger-friendly. | ||
147 | | mov L->top, TOP | ||
148 | | call &jit_coroutine_resume, L, BASE, ii->nresults | ||
149 | | mov BASE, L->base | ||
150 | if (ii->nresults == -1) { | ||
151 | | mov TOP, eax | ||
152 | } | ||
153 | ii->nargs = -1; /* Force restore of L->top. */ | ||
154 | break; | ||
155 | default: | ||
156 | jit_assert(0); | ||
157 | break; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | #endif /* COCO_DISABLE */ | ||
162 | |||
163 | /* ------------------------------------------------------------------------ */ | ||
164 | |||
165 | static void jit_inline_string(jit_State *J, jit_InlineInfo *ii) | ||
166 | { | ||
167 | int arg = ii->func+1; | ||
168 | int res = ii->res; | ||
169 | switch (JIT_IH_IDX(ii->hidx)) { | ||
170 | case JIT_IH_STRING_LEN: | ||
171 | | isstring arg; jne L_DEOPTIMIZE | ||
172 | | mov TSTRING:ecx, BASE[arg].value | ||
173 | | fild aword TSTRING:ecx->tsv.len // size_t | ||
174 | | settt BASE[res], LUA_TNUMBER | ||
175 | | fstp qword BASE[res].value | ||
176 | break; | ||
177 | case JIT_IH_STRING_SUB: | ||
178 | /* TODO: inline numeric constants with help from the optimizer. */ | ||
179 | /* But this would save only another 15-20% in a trivial loop. */ | ||
180 | jit_assert(ii->nargs >= 2); /* Open op caveat is ok, too. */ | ||
181 | if (ii->nargs > 2) { | ||
182 | | lea TOP, BASE[arg] | ||
183 | | call ->STRING_SUB3 | ||
184 | | setsvalue BASE[res], eax | ||
185 | } else { | ||
186 | | lea TOP, BASE[arg] | ||
187 | | call ->STRING_SUB2 | ||
188 | | setsvalue BASE[res], eax | ||
189 | } | ||
190 | break; | ||
191 | case JIT_IH_STRING_CHAR: | ||
192 | | isnumber arg; jne L_DEOPTIMIZE | ||
193 | | lea eax, L->env // Abuse L->env to hold temp string. | ||
194 | | fld qword BASE[arg].value | ||
195 | | fistp dword [eax] // LSB is at start (little-endian). | ||
196 | | cmp dword [eax], 255; ja L_DEOPTIMIZE | ||
197 | | call &luaS_newlstr, L, eax, 1 | ||
198 | | setsvalue BASE[res], eax | ||
199 | break; | ||
200 | default: | ||
201 | jit_assert(0); | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | |//----------------------------------------------------------------------- | ||
206 | |.jsub STRING_SUB3 // string.sub(str, start, end) | ||
207 | | mov eax, TOP[0].tt; shl eax, 4; or eax, TOP[1].tt; shl eax, 4 | ||
208 | | or eax, TOP[2].tt; sub eax, LUA_TSTR_NUM_NUM | ||
209 | | jne ->DEOPTIMIZE_CALLER // Wrong types? Deoptimize. | ||
210 | | // eax must be zero here! | ||
211 | | fld qword TOP[1].value | ||
212 | | fld qword TOP[2].value | ||
213 | | fistp aword TMP3 // size_t | ||
214 | | fistp aword TMP2 // size_t | ||
215 | | mov TSTRING:ecx, TOP[0].value | ||
216 | | mov TOP, aword TSTRING:ecx->tsv.len // size_t | ||
217 | | mov edx, TMP3 | ||
218 | | cmp TOP, edx | ||
219 | | jb >4 | ||
220 | |1: | ||
221 | | or eax, TMP2 // eax is known to be zero. | ||
222 | | jle >6 // start <= 0? | ||
223 | |2: | ||
224 | | sub edx, eax // newlen = end-start | ||
225 | | jl >7 // start > end? | ||
226 | | lea ecx, [TSTRING:ecx+eax+#TSTRING-1] // svalue()-1+start | ||
227 | | inc edx | ||
228 | |3: | ||
229 | | mov ARG2, L // First arg for tailcall is ARG2. | ||
230 | | mov ARG3, ecx // Pointer to start. | ||
231 | | mov ARG4, edx // Length. | ||
232 | | mov GL:edi, L->l_G | ||
233 | | mov eax, GL:edi->totalbytes // size_t | ||
234 | | cmp eax, GL:edi->GCthreshold // size_t | ||
235 | | jae >8 // G->totalbytes >= G->GCthreshold? | ||
236 | | jmp &luaS_newlstr // Tailcall to C function. | ||
237 | | | ||
238 | |4: // Negative end or overflow. | ||
239 | | jl >5 | ||
240 | | lea edx, [edx+TOP+1] // end = end+(len+1) | ||
241 | | jmp <1 | ||
242 | |5: // Overflow | ||
243 | | mov edx, TOP // end = len | ||
244 | | jmp <1 | ||
245 | | | ||
246 | |6: // Negative start or underflow. | ||
247 | | je >5 | ||
248 | | add eax, TOP // start = start+(len+1) | ||
249 | | inc eax | ||
250 | | jg <2 // start > 0? | ||
251 | |5: // Underflow. | ||
252 | | mov eax, 1 // start = 1 | ||
253 | | jmp <2 | ||
254 | | | ||
255 | |7: // Range underflow. | ||
256 | | xor edx, edx // Zero length. | ||
257 | | jmp <3 // Any pointer in ecx is ok. | ||
258 | |.endjsub | ||
259 | | | ||
260 | |//----------------------------------------------------------------------- | ||
261 | |.jsub STRING_SUB2 // string.sub(str, start) | ||
262 | | mov eax, TOP[0].tt; shl eax, 4; or eax, TOP[1].tt; sub eax, LUA_TSTR_NUM | ||
263 | | jne ->DEOPTIMIZE_CALLER // Wrong types? Deoptimize. | ||
264 | | // eax must be zero here! | ||
265 | | fld qword TOP[1].value | ||
266 | | fistp aword TMP2 // size_t | ||
267 | | mov TSTRING:ecx, TOP[0].value | ||
268 | | mov TOP, aword TSTRING:ecx->tsv.len // size_t | ||
269 | | mov edx, TOP | ||
270 | | jmp <1 // See STRING_SUB3. | ||
271 | | | ||
272 | |8: // GC threshold reached. | ||
273 | | sub esp, FRAME_OFFSET | ||
274 | | call &luaC_step, L | ||
275 | | add esp, FRAME_OFFSET | ||
276 | | mov BASE, L->base | ||
277 | | jmp &luaS_newlstr // Tailcall to C function. | ||
278 | |.endjsub | ||
279 | } | ||
280 | |||
281 | /* ------------------------------------------------------------------------ */ | ||
282 | |||
283 | /* Helper functions for inlined calls to table.*. */ | ||
284 | static void jit_table_insert(lua_State *L, TValue *arg) | ||
285 | { | ||
286 | setobj2t(L, luaH_setnum(L, hvalue(arg), luaH_getn(hvalue(arg))+1), arg+1); | ||
287 | luaC_barriert(L, hvalue(arg), arg+1); | ||
288 | } | ||
289 | |||
290 | static TValue *jit_table_remove(lua_State *L, TValue *arg, TValue *res) | ||
291 | { | ||
292 | int n = luaH_getn(hvalue(arg)); | ||
293 | if (n == 0) { | ||
294 | setnilvalue(res); /* For the nresults == 1 case. Harmless otherwise. */ | ||
295 | return res; /* For the nresults == -1 case. */ | ||
296 | } else { | ||
297 | TValue *val = luaH_setnum(L, hvalue(arg), n); | ||
298 | setobj2s(L, res, val); | ||
299 | setnilvalue(val); | ||
300 | return res+1; /* For the nresults == -1 case. */ | ||
301 | } | ||
302 | } | ||
303 | |||
304 | static void jit_inline_table(jit_State *J, jit_InlineInfo *ii) | ||
305 | { | ||
306 | int arg = ii->func+1; | ||
307 | int res = ii->res; | ||
308 | | istable arg; jne L_DEOPTIMIZE | ||
309 | switch (JIT_IH_IDX(ii->hidx)) { | ||
310 | case JIT_IH_TABLE_INSERT: | ||
311 | | lea TVALUE:eax, BASE[arg] | ||
312 | | call &jit_table_insert, L, TVALUE:eax | ||
313 | break; | ||
314 | case JIT_IH_TABLE_REMOVE: | ||
315 | | lea TVALUE:eax, BASE[arg] | ||
316 | | lea TVALUE:ecx, BASE[res] | ||
317 | | call &jit_table_remove, L, TVALUE:eax, TVALUE:ecx | ||
318 | if (ii->nresults == -1) { | ||
319 | ii->xnresults = -1; | ||
320 | | mov TOP, TVALUE:eax | ||
321 | } | ||
322 | break; | ||
323 | case JIT_IH_TABLE_GETN: | ||
324 | | mov TABLE:eax, BASE[arg].value | ||
325 | | call &luaH_getn, TABLE:eax | ||
326 | | mov TMP1, eax | ||
327 | | fild dword TMP1 | ||
328 | | fstp qword BASE[res].value | ||
329 | | settt BASE[res], LUA_TNUMBER | ||
330 | break; | ||
331 | default: | ||
332 | jit_assert(0); | ||
333 | break; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /* ------------------------------------------------------------------------ */ | ||
338 | |||
339 | /* This typedef must match the libm function signature. */ | ||
340 | /* Serves as a check against wrong lua_Number or wrong calling conventions. */ | ||
341 | typedef lua_Number (*mathfunc_11)(lua_Number); | ||
342 | |||
343 | /* Partially inlined math functions. */ | ||
344 | /* CHECK: must match with jit_hints.h and jit.opt_lib. */ | ||
345 | static const mathfunc_11 jit_mathfuncs_11[JIT_IH_MATH_SIN] = { | ||
346 | log, log10, exp, sinh, cosh, tanh, asin, acos, atan | ||
347 | }; | ||
348 | |||
349 | /* FPU control words for ceil and floor (exceptions masked, full precision). */ | ||
350 | static const unsigned short jit_fpucw[2] = { 0x0b7f, 0x077f }; | ||
351 | |||
352 | static void jit_inline_math(jit_State *J, jit_InlineInfo *ii) | ||
353 | { | ||
354 | int arg = ii->func+1; | ||
355 | int res = ii->res; | ||
356 | int idx = JIT_IH_IDX(ii->hidx); | ||
357 | |||
358 | if (idx < JIT_IH_MATH__21) { | ||
359 | | isnumber arg; jne L_DEOPTIMIZE | ||
360 | | fld qword BASE[arg].value | ||
361 | } else { | ||
362 | jit_assert(idx < JIT_IH_MATH__LAST); | ||
363 | | isnumber2 arg, arg+1; jne L_DEOPTIMIZE | ||
364 | } | ||
365 | switch (idx) { | ||
366 | /* We ignore sin/cos/tan range overflows (2^63 rad) just like -ffast-math. */ | ||
367 | case JIT_IH_MATH_SIN: | ||
368 | | fsin | ||
369 | break; | ||
370 | case JIT_IH_MATH_COS: | ||
371 | | fcos | ||
372 | break; | ||
373 | case JIT_IH_MATH_TAN: | ||
374 | | fptan; fpop | ||
375 | break; | ||
376 | case JIT_IH_MATH_CEIL: | ||
377 | case JIT_IH_MATH_FLOOR: | ||
378 | | fnstcw word TMP1 | ||
379 | | fldcw word [(ptrdiff_t)&jit_fpucw[idx-JIT_IH_MATH_CEIL]] | ||
380 | | frndint | ||
381 | | fldcw word TMP1 | ||
382 | break; | ||
383 | case JIT_IH_MATH_ABS: | ||
384 | | fabs | ||
385 | break; | ||
386 | case JIT_IH_MATH_SQRT: | ||
387 | | fsqrt | ||
388 | break; | ||
389 | case JIT_IH_MATH_FMOD: | ||
390 | | fld qword BASE[arg+1].value | ||
391 | | fld qword BASE[arg].value | ||
392 | |1: ; fprem; fnstsw ax; sahf; jp <1 | ||
393 | | fstp st1 | ||
394 | break; | ||
395 | case JIT_IH_MATH_ATAN2: | ||
396 | |// Inlining is easier than calling atan2(). | ||
397 | | fld qword BASE[arg].value | ||
398 | | fld qword BASE[arg+1].value | ||
399 | | fpatan | ||
400 | break; | ||
401 | default: | ||
402 | |// Partially inlined. Just call the libm function (__cdecl!). | ||
403 | | fstp FPARG1 | ||
404 | | call &jit_mathfuncs_11[idx] | ||
405 | break; | ||
406 | } | ||
407 | | settt BASE[res], LUA_TNUMBER | ||
408 | | fstp qword BASE[res].value | ||
409 | } | ||
410 | |||
411 | /* ------------------------------------------------------------------------ */ | ||
412 | |||
413 | /* Try to inline a CALL or TAILCALL instruction. */ | ||
414 | static int jit_inline_call(jit_State *J, int func, int nargs, int nresults) | ||
415 | { | ||
416 | const TValue *callable = hint_get(J, TYPE); /* TYPE hint = callable. */ | ||
417 | int cltype = ttype(callable); | ||
418 | const TValue *oidx; | ||
419 | jit_InlineInfo ii; | ||
420 | int idx; | ||
421 | |||
422 | if (cltype != LUA_TFUNCTION) goto fail; | ||
423 | if (J->flags & JIT_F_DEBUG) goto fail; /* DWIM. */ | ||
424 | |||
425 | oidx = hint_get(J, INLINE); /* INLINE hint = library/function index. */ | ||
426 | if (!ttisnumber(oidx)) goto fail; | ||
427 | |||
428 | ii.hidx = (int)nvalue(oidx); | ||
429 | idx = JIT_IH_IDX(ii.hidx); | ||
430 | |||
431 | if (nresults == -2) { /* Tailcall. */ | ||
432 | /* Tailcalls from vararg functions don't work with BASE[-1]. */ | ||
433 | if (J->pt->is_vararg) goto fail; /* So forget about this rare case. */ | ||
434 | ii.res = -1; /* Careful: 2nd result overlaps 1st stack slot. */ | ||
435 | ii.nresults = -1; | ||
436 | } else { | ||
437 | ii.res = func; | ||
438 | ii.nresults = nresults; | ||
439 | } | ||
440 | ii.func = func; | ||
441 | ii.nargs = nargs; | ||
442 | ii.xnargs = ii.xnresults = 1; /* Default: 1 arg, 1 result. */ | ||
443 | |||
444 | /* Check for the currently supported cases. */ | ||
445 | switch (JIT_IH_LIB(ii.hidx)) { | ||
446 | case JIT_IHLIB_BASE: | ||
447 | switch (idx) { | ||
448 | case JIT_IH_BASE_PAIRS: | ||
449 | case JIT_IH_BASE_IPAIRS: | ||
450 | if (nresults == -2) goto fail; /* Not useful for tailcalls. */ | ||
451 | ii.xnresults = 3; | ||
452 | goto check; | ||
453 | } | ||
454 | break; | ||
455 | #ifndef COCO_DISABLE | ||
456 | case JIT_IHLIB_COROUTINE: | ||
457 | switch (idx) { | ||
458 | case JIT_IH_COROUTINE_YIELD: | ||
459 | /* Only support common cases: no tailcalls, low number of results. */ | ||
460 | if (nresults < 0 || nresults > EXTRA_STACK) goto fail; | ||
461 | ii.xnargs = ii.xnresults = -1; | ||
462 | goto ok; /* Anything else is ok. */ | ||
463 | case JIT_IH_COROUTINE_RESUME: | ||
464 | /* Only support common cases: no tailcalls, not with 0 args (error). */ | ||
465 | if (nresults == -2 || nargs == 0) goto fail; | ||
466 | ii.xnargs = ii.xnresults = -1; | ||
467 | goto ok; /* Anything else is ok. */ | ||
468 | } | ||
469 | break; | ||
470 | #endif | ||
471 | case JIT_IHLIB_STRING: | ||
472 | switch (idx) { | ||
473 | case JIT_IH_STRING_LEN: | ||
474 | goto check; | ||
475 | case JIT_IH_STRING_SUB: | ||
476 | if (nargs < 2) goto fail; /* No support for open calls, too. */ | ||
477 | goto ok; /* 2 or more args are ok. */ | ||
478 | case JIT_IH_STRING_CHAR: | ||
479 | goto check; /* Only single arg supported. */ | ||
480 | } | ||
481 | break; | ||
482 | case JIT_IHLIB_TABLE: | ||
483 | switch (idx) { | ||
484 | case JIT_IH_TABLE_INSERT: | ||
485 | ii.xnargs = 2; | ||
486 | goto check; /* Only push (append) supported. */ | ||
487 | case JIT_IH_TABLE_REMOVE: | ||
488 | goto check; /* Only pop supported. */ | ||
489 | case JIT_IH_TABLE_GETN: | ||
490 | goto check; | ||
491 | } | ||
492 | break; | ||
493 | case JIT_IHLIB_MATH: | ||
494 | if (idx >= JIT_IH_MATH__LAST) goto fail; | ||
495 | if (idx >= JIT_IH_MATH__21) ii.xnargs = 2; | ||
496 | goto check; | ||
497 | } | ||
498 | fail: | ||
499 | return cltype; /* Call could not be inlined. Return type of callable. */ | ||
500 | |||
501 | check: | ||
502 | if (nargs != ii.xnargs && nargs != -1) goto fail; | ||
503 | /* The optimizer already checks the number of results (avoid setnil). */ | ||
504 | |||
505 | ok: /* Whew, all checks done. Go for it! */ | ||
506 | |||
507 | /* Start with the common leadin for inlined calls. */ | ||
508 | jit_deopt_target(J, nargs); | ||
509 | |// Caveat: Must save TOP for open ops if jsub uses DEOPTIMIZE_CALLER. | ||
510 | | isfunction func | ||
511 | | jne L_DEOPTIMIZE // Not a function? Deoptimize. | ||
512 | | cmp aword BASE[func].value, &clvalue(callable) | ||
513 | | jne L_DEOPTIMIZE // Wrong closure? Deoptimize. | ||
514 | if (nargs == -1 && ii.xnargs >= 0) { | ||
515 | | lea eax, BASE[func+1+ii.xnargs] | ||
516 | | cmp TOP, eax | ||
517 | | jne L_DEOPTIMIZE // Wrong #args? Deoptimize. | ||
518 | } | ||
519 | |||
520 | /* Now inline the function itself. */ | ||
521 | switch (JIT_IH_LIB(ii.hidx)) { | ||
522 | case JIT_IHLIB_BASE: jit_inline_base(J, &ii); break; | ||
523 | #ifndef COCO_DISABLE | ||
524 | case JIT_IHLIB_COROUTINE: jit_inline_coroutine(J, &ii); break; | ||
525 | #endif | ||
526 | case JIT_IHLIB_STRING: jit_inline_string(J, &ii); break; | ||
527 | case JIT_IHLIB_TABLE: jit_inline_table(J, &ii); break; | ||
528 | case JIT_IHLIB_MATH: jit_inline_math(J, &ii); break; | ||
529 | default: jit_assert(0); break; | ||
530 | } | ||
531 | |||
532 | /* And add the common leadout for inlined calls. */ | ||
533 | if (ii.nresults == -1) { | ||
534 | if (ii.xnresults >= 0) { | ||
535 | | lea TOP, BASE[ii.res+ii.xnresults] | ||
536 | } | ||
537 | } else if (ii.nargs == -1) { /* Restore L->top only if needed. */ | ||
538 | | lea TOP, BASE[J->pt->maxstacksize] | ||
539 | | mov L->top, TOP | ||
540 | } | ||
541 | |||
542 | if (nresults == -2) { /* Results are in place. Add return for tailcalls. */ | ||
543 | | add esp, FRAME_OFFSET | ||
544 | | sub BASE, #BASE | ||
545 | | sub aword L->ci, #CI | ||
546 | | ret | ||
547 | } | ||
548 | |||
549 | return -1; /* Success, call has been inlined. */ | ||
550 | } | ||
551 | |||
552 | /* ------------------------------------------------------------------------ */ | ||
553 | |||
554 | /* Helper function for inlined iterator code. Paraphrased from luaH_next. */ | ||
555 | /* TODO: GCC has trouble optimizing this. */ | ||
556 | static int jit_table_next(lua_State *L, TValue *ra) | ||
557 | { | ||
558 | Table *t = hvalue(&ra[TFOR_TAB]); | ||
559 | int i = ra[TFOR_CTL].value.b; /* Hidden control variable. */ | ||
560 | for (; i < t->sizearray; i++) { /* First the array part. */ | ||
561 | if (!ttisnil(&t->array[i])) { | ||
562 | setnvalue(&ra[TFOR_KEY], cast_num(i+1)); | ||
563 | setobj2s(L, &ra[TFOR_VAL], &t->array[i]); | ||
564 | ra[TFOR_CTL].value.b = i+1; | ||
565 | return 1; | ||
566 | } | ||
567 | } | ||
568 | for (i -= t->sizearray; i < sizenode(t); i++) { /* Then the hash part. */ | ||
569 | if (!ttisnil(gval(gnode(t, i)))) { | ||
570 | setobj2s(L, &ra[TFOR_KEY], key2tval(gnode(t, i))); | ||
571 | setobj2s(L, &ra[TFOR_VAL], gval(gnode(t, i))); | ||
572 | ra[TFOR_CTL].value.b = i+1+t->sizearray; | ||
573 | return 1; | ||
574 | } | ||
575 | } | ||
576 | return 0; /* End of iteration. */ | ||
577 | } | ||
578 | |||
579 | /* Try to inline a TFORLOOP instruction. */ | ||
580 | static int jit_inline_tforloop(jit_State *J, int ra, int nresults, int target) | ||
581 | { | ||
582 | const TValue *oidx = hint_get(J, INLINE); /* INLINE hint = lib/func idx. */ | ||
583 | int idx; | ||
584 | |||
585 | if (!ttisnumber(oidx)) return 0; /* No hint: don't inline anything. */ | ||
586 | idx = (int)nvalue(oidx); | ||
587 | if (J->flags & JIT_F_DEBUG) return 0; /* DWIM. */ | ||
588 | |||
589 | switch (idx) { | ||
590 | case JIT_IH_MKIDX(JIT_IHLIB_BASE, JIT_IH_BASE_PAIRS): | ||
591 | |// The type checks can be omitted -- see the iterator constructor. | ||
592 | | lea TOP, BASE[ra] | ||
593 | | call &jit_table_next, L, TOP | ||
594 | | test eax, eax | ||
595 | | jnz =>target | ||
596 | return 1; /* Success, iterator has been inlined. */ | ||
597 | case JIT_IH_MKIDX(JIT_IHLIB_BASE, JIT_IH_BASE_IPAIRS): | ||
598 | |// The type checks can be omitted -- see the iterator constructor. | ||
599 | | mov eax, BASE[ra+TFOR_CTL].value // Hidden control variable. | ||
600 | | inc eax | ||
601 | | mov TABLE:edx, BASE[ra+TFOR_TAB].value // Table object. | ||
602 | | mov BASE[ra+TFOR_CTL].value, eax | ||
603 | | call &luaH_getnum, TABLE:edx, eax | ||
604 | | // This is really copyslot BASE[ra+TFOR_VAL], TVALUE:eax[0] plus compare. | ||
605 | | mov ecx, TVALUE:eax->tt | ||
606 | | test ecx, ecx // Assumes: LUA_TNIL == 0. | ||
607 | | jz >9 // nil value stops iteration. | ||
608 | | fild dword BASE[ra+TFOR_CTL].value // Set numeric key. | ||
609 | | settt BASE[ra+TFOR_KEY], LUA_TNUMBER | ||
610 | | fstp qword BASE[ra+TFOR_KEY].value | ||
611 | | mov edx, TVALUE:eax->value | ||
612 | | mov eax, TVALUE:eax->value.na[1] // Overwrites eax. | ||
613 | | mov BASE[ra+TFOR_VAL].tt, ecx // Copy value from table slot. | ||
614 | | mov BASE[ra+TFOR_VAL].value, edx | ||
615 | | mov BASE[ra+TFOR_VAL].value.na[1], eax | ||
616 | | jmp =>target | ||
617 | |9: | ||
618 | return 1; /* Success, iterator has been inlined. */ | ||
619 | } | ||
620 | |||
621 | return 0; /* No support for inlining any other iterators. */ | ||
622 | } | ||
623 | |||
624 | /* ------------------------------------------------------------------------ */ | ||
625 | |||