aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash')
-rw-r--r--libraries/LuaJIT-1.1.7/src/ljit_x86_inline.dash625
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. */
9typedef 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
21enum { TFOR_FUNC, TFOR_TAB, TFOR_CTL, TFOR_KEY, TFOR_VAL };
22
23static 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(). */
52static 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) {
58errdead:
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. */
99err:
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
108static 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
165static 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.*. */
284static 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
290static 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
304static 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. */
341typedef lua_Number (*mathfunc_11)(lua_Number);
342
343/* Partially inlined math functions. */
344/* CHECK: must match with jit_hints.h and jit.opt_lib. */
345static 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). */
350static const unsigned short jit_fpucw[2] = { 0x0b7f, 0x077f };
351
352static 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. */
414static 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 }
498fail:
499 return cltype; /* Call could not be inlined. Return type of callable. */
500
501check:
502 if (nargs != ii.xnargs && nargs != -1) goto fail;
503 /* The optimizer already checks the number of results (avoid setnil). */
504
505ok: /* 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. */
556static 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. */
580static 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