aboutsummaryrefslogtreecommitdiff
path: root/src/vm_mips64.dasc
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm_mips64.dasc')
-rw-r--r--src/vm_mips64.dasc5112
1 files changed, 5112 insertions, 0 deletions
diff --git a/src/vm_mips64.dasc b/src/vm_mips64.dasc
new file mode 100644
index 00000000..1682c81e
--- /dev/null
+++ b/src/vm_mips64.dasc
@@ -0,0 +1,5112 @@
1|// Low-level VM code for MIPS64 CPUs.
2|// Bytecode interpreter, fast functions and helper functions.
3|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4|//
5|// Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
6|// Sponsored by Cisco Systems, Inc.
7|
8|.arch mips64
9|.section code_op, code_sub
10|
11|.actionlist build_actionlist
12|.globals GLOB_
13|.globalnames globnames
14|.externnames extnames
15|
16|// Note: The ragged indentation of the instructions is intentional.
17|// The starting columns indicate data dependencies.
18|
19|//-----------------------------------------------------------------------
20|
21|// Fixed register assignments for the interpreter.
22|// Don't use: r0 = 0, r26/r27 = reserved, r28 = gp, r29 = sp, r31 = ra
23|
24|.macro .FPU, a, b
25|.if FPU
26| a, b
27|.endif
28|.endmacro
29|
30|// The following must be C callee-save (but BASE is often refetched).
31|.define BASE, r16 // Base of current Lua stack frame.
32|.define KBASE, r17 // Constants of current Lua function.
33|.define PC, r18 // Next PC.
34|.define DISPATCH, r19 // Opcode dispatch table.
35|.define LREG, r20 // Register holding lua_State (also in SAVE_L).
36|.define MULTRES, r21 // Size of multi-result: (nresults+1)*8.
37|
38|.define JGL, r30 // On-trace: global_State + 32768.
39|
40|// Constants for type-comparisons, stores and conversions. C callee-save.
41|.define TISNIL, r30
42|.define TISNUM, r22
43|.if FPU
44|.define TOBIT, f30 // 2^52 + 2^51.
45|.endif
46|
47|// The following temporaries are not saved across C calls, except for RA.
48|.define RA, r23 // Callee-save.
49|.define RB, r8
50|.define RC, r9
51|.define RD, r10
52|.define INS, r11
53|
54|.define AT, r1 // Assembler temporary.
55|.define TMP0, r12
56|.define TMP1, r13
57|.define TMP2, r14
58|.define TMP3, r15
59|
60|// MIPS n64 calling convention.
61|.define CFUNCADDR, r25
62|.define CARG1, r4
63|.define CARG2, r5
64|.define CARG3, r6
65|.define CARG4, r7
66|.define CARG5, r8
67|.define CARG6, r9
68|.define CARG7, r10
69|.define CARG8, r11
70|
71|.define CRET1, r2
72|.define CRET2, r3
73|
74|.if FPU
75|.define FARG1, f12
76|.define FARG2, f13
77|.define FARG3, f14
78|.define FARG4, f15
79|.define FARG5, f16
80|.define FARG6, f17
81|.define FARG7, f18
82|.define FARG8, f19
83|
84|.define FRET1, f0
85|.define FRET2, f2
86|.endif
87|
88|// Stack layout while in interpreter. Must match with lj_frame.h.
89|.if FPU // MIPS64 hard-float.
90|
91|.define CFRAME_SPACE, 192 // Delta for sp.
92|
93|//----- 16 byte aligned, <-- sp entering interpreter
94|.define SAVE_ERRF, 188(sp) // 32 bit values.
95|.define SAVE_NRES, 184(sp)
96|.define SAVE_CFRAME, 176(sp) // 64 bit values.
97|.define SAVE_L, 168(sp)
98|.define SAVE_PC, 160(sp)
99|//----- 16 byte aligned
100|.define SAVE_GPR_, 80 // .. 80+10*8: 64 bit GPR saves.
101|.define SAVE_FPR_, 16 // .. 16+8*8: 64 bit FPR saves.
102|
103|.else // MIPS64 soft-float
104|
105|.define CFRAME_SPACE, 128 // Delta for sp.
106|
107|//----- 16 byte aligned, <-- sp entering interpreter
108|.define SAVE_ERRF, 124(sp) // 32 bit values.
109|.define SAVE_NRES, 120(sp)
110|.define SAVE_CFRAME, 112(sp) // 64 bit values.
111|.define SAVE_L, 104(sp)
112|.define SAVE_PC, 96(sp)
113|//----- 16 byte aligned
114|.define SAVE_GPR_, 16 // .. 16+10*8: 64 bit GPR saves.
115|
116|.endif
117|
118|.define TMPX, 8(sp) // Unused by interpreter, temp for JIT code.
119|.define TMPD, 0(sp)
120|//----- 16 byte aligned
121|
122|.define TMPD_OFS, 0
123|
124|.define SAVE_MULTRES, TMPD
125|
126|//-----------------------------------------------------------------------
127|
128|.macro saveregs
129| daddiu sp, sp, -CFRAME_SPACE
130| sd ra, SAVE_GPR_+9*8(sp)
131| sd r30, SAVE_GPR_+8*8(sp)
132| .FPU sdc1 f31, SAVE_FPR_+7*8(sp)
133| sd r23, SAVE_GPR_+7*8(sp)
134| .FPU sdc1 f30, SAVE_FPR_+6*8(sp)
135| sd r22, SAVE_GPR_+6*8(sp)
136| .FPU sdc1 f29, SAVE_FPR_+5*8(sp)
137| sd r21, SAVE_GPR_+5*8(sp)
138| .FPU sdc1 f28, SAVE_FPR_+4*8(sp)
139| sd r20, SAVE_GPR_+4*8(sp)
140| .FPU sdc1 f27, SAVE_FPR_+3*8(sp)
141| sd r19, SAVE_GPR_+3*8(sp)
142| .FPU sdc1 f26, SAVE_FPR_+2*8(sp)
143| sd r18, SAVE_GPR_+2*8(sp)
144| .FPU sdc1 f25, SAVE_FPR_+1*8(sp)
145| sd r17, SAVE_GPR_+1*8(sp)
146| .FPU sdc1 f24, SAVE_FPR_+0*8(sp)
147| sd r16, SAVE_GPR_+0*8(sp)
148|.endmacro
149|
150|.macro restoreregs_ret
151| ld ra, SAVE_GPR_+9*8(sp)
152| ld r30, SAVE_GPR_+8*8(sp)
153| ld r23, SAVE_GPR_+7*8(sp)
154| .FPU ldc1 f31, SAVE_FPR_+7*8(sp)
155| ld r22, SAVE_GPR_+6*8(sp)
156| .FPU ldc1 f30, SAVE_FPR_+6*8(sp)
157| ld r21, SAVE_GPR_+5*8(sp)
158| .FPU ldc1 f29, SAVE_FPR_+5*8(sp)
159| ld r20, SAVE_GPR_+4*8(sp)
160| .FPU ldc1 f28, SAVE_FPR_+4*8(sp)
161| ld r19, SAVE_GPR_+3*8(sp)
162| .FPU ldc1 f27, SAVE_FPR_+3*8(sp)
163| ld r18, SAVE_GPR_+2*8(sp)
164| .FPU ldc1 f26, SAVE_FPR_+2*8(sp)
165| ld r17, SAVE_GPR_+1*8(sp)
166| .FPU ldc1 f25, SAVE_FPR_+1*8(sp)
167| ld r16, SAVE_GPR_+0*8(sp)
168| .FPU ldc1 f24, SAVE_FPR_+0*8(sp)
169| jr ra
170| daddiu sp, sp, CFRAME_SPACE
171|.endmacro
172|
173|// Type definitions. Some of these are only used for documentation.
174|.type L, lua_State, LREG
175|.type GL, global_State
176|.type TVALUE, TValue
177|.type GCOBJ, GCobj
178|.type STR, GCstr
179|.type TAB, GCtab
180|.type LFUNC, GCfuncL
181|.type CFUNC, GCfuncC
182|.type PROTO, GCproto
183|.type UPVAL, GCupval
184|.type NODE, Node
185|.type NARGS8, int
186|.type TRACE, GCtrace
187|.type SBUF, SBuf
188|
189|//-----------------------------------------------------------------------
190|
191|// Trap for not-yet-implemented parts.
192|.macro NYI; .long 0xf0f0f0f0; .endmacro
193|
194|// Macros to mark delay slots.
195|.macro ., a; a; .endmacro
196|.macro ., a,b; a,b; .endmacro
197|.macro ., a,b,c; a,b,c; .endmacro
198|.macro ., a,b,c,d; a,b,c,d; .endmacro
199|
200|.define FRAME_PC, -8
201|.define FRAME_FUNC, -16
202|
203|//-----------------------------------------------------------------------
204|
205|// Endian-specific defines.
206|.if ENDIAN_LE
207|.define HI, 4
208|.define LO, 0
209|.define OFS_RD, 2
210|.define OFS_RA, 1
211|.define OFS_OP, 0
212|.else
213|.define HI, 0
214|.define LO, 4
215|.define OFS_RD, 0
216|.define OFS_RA, 2
217|.define OFS_OP, 3
218|.endif
219|
220|// Instruction decode.
221|.macro decode_OP1, dst, ins; andi dst, ins, 0xff; .endmacro
222|.macro decode_OP8a, dst, ins; andi dst, ins, 0xff; .endmacro
223|.macro decode_OP8b, dst; sll dst, dst, 3; .endmacro
224|.macro decode_RC8a, dst, ins; srl dst, ins, 13; .endmacro
225|.macro decode_RC8b, dst; andi dst, dst, 0x7f8; .endmacro
226|.macro decode_RD4b, dst; sll dst, dst, 2; .endmacro
227|.macro decode_RA8a, dst, ins; srl dst, ins, 5; .endmacro
228|.macro decode_RA8b, dst; andi dst, dst, 0x7f8; .endmacro
229|.macro decode_RB8a, dst, ins; srl dst, ins, 21; .endmacro
230|.macro decode_RB8b, dst; andi dst, dst, 0x7f8; .endmacro
231|.macro decode_RD8a, dst, ins; srl dst, ins, 16; .endmacro
232|.macro decode_RD8b, dst; sll dst, dst, 3; .endmacro
233|.macro decode_RDtoRC8, dst, src; andi dst, src, 0x7f8; .endmacro
234|
235|// Instruction fetch.
236|.macro ins_NEXT1
237| lw INS, 0(PC)
238| daddiu PC, PC, 4
239|.endmacro
240|// Instruction decode+dispatch.
241|.macro ins_NEXT2
242| decode_OP8a TMP1, INS
243| decode_OP8b TMP1
244| daddu TMP0, DISPATCH, TMP1
245| decode_RD8a RD, INS
246| ld AT, 0(TMP0)
247| decode_RA8a RA, INS
248| decode_RD8b RD
249| jr AT
250| decode_RA8b RA
251|.endmacro
252|.macro ins_NEXT
253| ins_NEXT1
254| ins_NEXT2
255|.endmacro
256|
257|// Instruction footer.
258|.if 1
259| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use.
260| .define ins_next, ins_NEXT
261| .define ins_next_, ins_NEXT
262| .define ins_next1, ins_NEXT1
263| .define ins_next2, ins_NEXT2
264|.else
265| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch.
266| // Affects only certain kinds of benchmarks (and only with -j off).
267| .macro ins_next
268| b ->ins_next
269| .endmacro
270| .macro ins_next1
271| .endmacro
272| .macro ins_next2
273| b ->ins_next
274| .endmacro
275| .macro ins_next_
276| ->ins_next:
277| ins_NEXT
278| .endmacro
279|.endif
280|
281|// Call decode and dispatch.
282|.macro ins_callt
283| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
284| ld PC, LFUNC:RB->pc
285| lw INS, 0(PC)
286| daddiu PC, PC, 4
287| decode_OP8a TMP1, INS
288| decode_RA8a RA, INS
289| decode_OP8b TMP1
290| decode_RA8b RA
291| daddu TMP0, DISPATCH, TMP1
292| ld TMP0, 0(TMP0)
293| jr TMP0
294| daddu RA, RA, BASE
295|.endmacro
296|
297|.macro ins_call
298| // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, PC = caller PC
299| sd PC, FRAME_PC(BASE)
300| ins_callt
301|.endmacro
302|
303|//-----------------------------------------------------------------------
304|
305|.macro branch_RD
306| srl TMP0, RD, 1
307| lui AT, (-(BCBIAS_J*4 >> 16) & 65535)
308| addu TMP0, TMP0, AT
309| daddu PC, PC, TMP0
310|.endmacro
311|
312|// Assumes DISPATCH is relative to GL.
313#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field))
314#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field))
315#define GG_DISP2GOT (GG_OFS(got) - GG_OFS(dispatch))
316#define DISPATCH_GOT(name) (GG_DISP2GOT + sizeof(void*)*LJ_GOT_##name)
317|
318#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto))
319|
320|.macro load_got, func
321| ld CFUNCADDR, DISPATCH_GOT(func)(DISPATCH)
322|.endmacro
323|// Much faster. Sadly, there's no easy way to force the required code layout.
324|// .macro call_intern, func; bal extern func; .endmacro
325|.macro call_intern, func; jalr CFUNCADDR; .endmacro
326|.macro call_extern; jalr CFUNCADDR; .endmacro
327|.macro jmp_extern; jr CFUNCADDR; .endmacro
328|
329|.macro hotcheck, delta, target
330| dsrl TMP1, PC, 1
331| andi TMP1, TMP1, 126
332| daddu TMP1, TMP1, DISPATCH
333| lhu TMP2, GG_DISP2HOT(TMP1)
334| addiu TMP2, TMP2, -delta
335| bltz TMP2, target
336|. sh TMP2, GG_DISP2HOT(TMP1)
337|.endmacro
338|
339|.macro hotloop
340| hotcheck HOTCOUNT_LOOP, ->vm_hotloop
341|.endmacro
342|
343|.macro hotcall
344| hotcheck HOTCOUNT_CALL, ->vm_hotcall
345|.endmacro
346|
347|// Set current VM state. Uses TMP0.
348|.macro li_vmstate, st; li TMP0, ~LJ_VMST_..st; .endmacro
349|.macro st_vmstate; sw TMP0, DISPATCH_GL(vmstate)(DISPATCH); .endmacro
350|
351|// Move table write barrier back. Overwrites mark and tmp.
352|.macro barrierback, tab, mark, tmp, target
353| ld tmp, DISPATCH_GL(gc.grayagain)(DISPATCH)
354| andi mark, mark, ~LJ_GC_BLACK & 255 // black2gray(tab)
355| sd tab, DISPATCH_GL(gc.grayagain)(DISPATCH)
356| sb mark, tab->marked
357| b target
358|. sd tmp, tab->gclist
359|.endmacro
360|
361|// Clear type tag. Isolate lowest 14+32+1=47 bits of reg.
362|.macro cleartp, reg; dextm reg, reg, 0, 14; .endmacro
363|.macro cleartp, dst, reg; dextm dst, reg, 0, 14; .endmacro
364|
365|// Set type tag: Merge 17 type bits into bits [15+32=47, 31+32+1=64) of dst.
366|.macro settp, dst, tp; dinsu dst, tp, 15, 31; .endmacro
367|
368|// Extract (negative) type tag.
369|.macro gettp, dst, src; dsra dst, src, 47; .endmacro
370|
371|// Macros to check the TValue type and extract the GCobj. Branch on failure.
372|.macro checktp, reg, tp, target
373| gettp AT, reg
374| daddiu AT, AT, tp
375| bnez AT, target
376|. cleartp reg
377|.endmacro
378|.macro checktp, dst, reg, tp, target
379| gettp AT, reg
380| daddiu AT, AT, tp
381| bnez AT, target
382|. cleartp dst, reg
383|.endmacro
384|.macro checkstr, reg, target; checktp reg, -LJ_TSTR, target; .endmacro
385|.macro checktab, reg, target; checktp reg, -LJ_TTAB, target; .endmacro
386|.macro checkfunc, reg, target; checktp reg, -LJ_TFUNC, target; .endmacro
387|.macro checkint, reg, target // Caveat: has delay slot!
388| gettp AT, reg
389| bne AT, TISNUM, target
390|.endmacro
391|.macro checknum, reg, target // Caveat: has delay slot!
392| gettp AT, reg
393| sltiu AT, AT, LJ_TISNUM
394| beqz AT, target
395|.endmacro
396|
397|.macro mov_false, reg
398| lu reg, 0x8000
399| dsll reg, reg, 32
400| not reg, reg
401|.endmacro
402|.macro mov_true, reg
403| li reg, 0x0001
404| dsll reg, reg, 48
405| not reg, reg
406|.endmacro
407|
408|//-----------------------------------------------------------------------
409
410/* Generate subroutines used by opcodes and other parts of the VM. */
411/* The .code_sub section should be last to help static branch prediction. */
412static void build_subroutines(BuildCtx *ctx)
413{
414 |.code_sub
415 |
416 |//-----------------------------------------------------------------------
417 |//-- Return handling ----------------------------------------------------
418 |//-----------------------------------------------------------------------
419 |
420 |->vm_returnp:
421 | // See vm_return. Also: TMP2 = previous base.
422 | andi AT, PC, FRAME_P
423 | beqz AT, ->cont_dispatch
424 |
425 | // Return from pcall or xpcall fast func.
426 |. mov_true TMP1
427 | ld PC, FRAME_PC(TMP2) // Fetch PC of previous frame.
428 | move BASE, TMP2 // Restore caller base.
429 | // Prepending may overwrite the pcall frame, so do it at the end.
430 | sd TMP1, -8(RA) // Prepend true to results.
431 | daddiu RA, RA, -8
432 |
433 |->vm_returnc:
434 | addiu RD, RD, 8 // RD = (nresults+1)*8.
435 | andi TMP0, PC, FRAME_TYPE
436 | beqz RD, ->vm_unwind_c_eh
437 |. li CRET1, LUA_YIELD
438 | beqz TMP0, ->BC_RET_Z // Handle regular return to Lua.
439 |. move MULTRES, RD
440 |
441 |->vm_return:
442 | // BASE = base, RA = resultptr, RD/MULTRES = (nresults+1)*8, PC = return
443 | // TMP0 = PC & FRAME_TYPE
444 | li TMP2, -8
445 | xori AT, TMP0, FRAME_C
446 | and TMP2, PC, TMP2
447 | bnez AT, ->vm_returnp
448 | dsubu TMP2, BASE, TMP2 // TMP2 = previous base.
449 |
450 | addiu TMP1, RD, -8
451 | sd TMP2, L->base
452 | li_vmstate C
453 | lw TMP2, SAVE_NRES
454 | daddiu BASE, BASE, -16
455 | st_vmstate
456 | beqz TMP1, >2
457 |. sll TMP2, TMP2, 3
458 |1:
459 | addiu TMP1, TMP1, -8
460 | ld CRET1, 0(RA)
461 | daddiu RA, RA, 8
462 | sd CRET1, 0(BASE)
463 | bnez TMP1, <1
464 |. daddiu BASE, BASE, 8
465 |
466 |2:
467 | bne TMP2, RD, >6
468 |3:
469 |. sd BASE, L->top // Store new top.
470 |
471 |->vm_leave_cp:
472 | ld TMP0, SAVE_CFRAME // Restore previous C frame.
473 | move CRET1, r0 // Ok return status for vm_pcall.
474 | sd TMP0, L->cframe
475 |
476 |->vm_leave_unw:
477 | restoreregs_ret
478 |
479 |6:
480 | ld TMP1, L->maxstack
481 | slt AT, TMP2, RD
482 | bnez AT, >7 // Less results wanted?
483 | // More results wanted. Check stack size and fill up results with nil.
484 |. slt AT, BASE, TMP1
485 | beqz AT, >8
486 |. nop
487 | sd TISNIL, 0(BASE)
488 | addiu RD, RD, 8
489 | b <2
490 |. daddiu BASE, BASE, 8
491 |
492 |7: // Less results wanted.
493 | subu TMP0, RD, TMP2
494 | dsubu TMP0, BASE, TMP0 // Either keep top or shrink it.
495 | b <3
496 |. movn BASE, TMP0, TMP2 // LUA_MULTRET+1 case?
497 |
498 |8: // Corner case: need to grow stack for filling up results.
499 | // This can happen if:
500 | // - A C function grows the stack (a lot).
501 | // - The GC shrinks the stack in between.
502 | // - A return back from a lua_call() with (high) nresults adjustment.
503 | load_got lj_state_growstack
504 | move MULTRES, RD
505 | srl CARG2, TMP2, 3
506 | call_intern lj_state_growstack // (lua_State *L, int n)
507 |. move CARG1, L
508 | lw TMP2, SAVE_NRES
509 | ld BASE, L->top // Need the (realloced) L->top in BASE.
510 | move RD, MULTRES
511 | b <2
512 |. sll TMP2, TMP2, 3
513 |
514 |->vm_unwind_c: // Unwind C stack, return from vm_pcall.
515 | // (void *cframe, int errcode)
516 | move sp, CARG1
517 | move CRET1, CARG2
518 |->vm_unwind_c_eh: // Landing pad for external unwinder.
519 | ld L, SAVE_L
520 | li TMP0, ~LJ_VMST_C
521 | ld GL:TMP1, L->glref
522 | b ->vm_leave_unw
523 |. sw TMP0, GL:TMP1->vmstate
524 |
525 |->vm_unwind_ff: // Unwind C stack, return from ff pcall.
526 | // (void *cframe)
527 | li AT, -4
528 | and sp, CARG1, AT
529 |->vm_unwind_ff_eh: // Landing pad for external unwinder.
530 | ld L, SAVE_L
531 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float).
532 | li TISNIL, LJ_TNIL
533 | li TISNUM, LJ_TISNUM
534 | ld BASE, L->base
535 | ld DISPATCH, L->glref // Setup pointer to dispatch table.
536 | .FPU mtc1 TMP3, TOBIT
537 | mov_false TMP1
538 | li_vmstate INTERP
539 | ld PC, FRAME_PC(BASE) // Fetch PC of previous frame.
540 | .FPU cvt.d.s TOBIT, TOBIT
541 | daddiu RA, BASE, -8 // Results start at BASE-8.
542 | daddiu DISPATCH, DISPATCH, GG_G2DISP
543 | sd TMP1, 0(RA) // Prepend false to error message.
544 | st_vmstate
545 | b ->vm_returnc
546 |. li RD, 16 // 2 results: false + error message.
547 |
548 |//-----------------------------------------------------------------------
549 |//-- Grow stack for calls -----------------------------------------------
550 |//-----------------------------------------------------------------------
551 |
552 |->vm_growstack_c: // Grow stack for C function.
553 | b >2
554 |. li CARG2, LUA_MINSTACK
555 |
556 |->vm_growstack_l: // Grow stack for Lua function.
557 | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC
558 | daddu RC, BASE, RC
559 | dsubu RA, RA, BASE
560 | sd BASE, L->base
561 | daddiu PC, PC, 4 // Must point after first instruction.
562 | sd RC, L->top
563 | srl CARG2, RA, 3
564 |2:
565 | // L->base = new base, L->top = top
566 | load_got lj_state_growstack
567 | sd PC, SAVE_PC
568 | call_intern lj_state_growstack // (lua_State *L, int n)
569 |. move CARG1, L
570 | ld BASE, L->base
571 | ld RC, L->top
572 | ld LFUNC:RB, FRAME_FUNC(BASE)
573 | dsubu RC, RC, BASE
574 | cleartp LFUNC:RB
575 | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
576 | ins_callt // Just retry the call.
577 |
578 |//-----------------------------------------------------------------------
579 |//-- Entry points into the assembler VM ---------------------------------
580 |//-----------------------------------------------------------------------
581 |
582 |->vm_resume: // Setup C frame and resume thread.
583 | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0)
584 | saveregs
585 | move L, CARG1
586 | ld DISPATCH, L->glref // Setup pointer to dispatch table.
587 | move BASE, CARG2
588 | lbu TMP1, L->status
589 | sd L, SAVE_L
590 | li PC, FRAME_CP
591 | daddiu TMP0, sp, CFRAME_RESUME
592 | daddiu DISPATCH, DISPATCH, GG_G2DISP
593 | sw r0, SAVE_NRES
594 | sw r0, SAVE_ERRF
595 | sd CARG1, SAVE_PC // Any value outside of bytecode is ok.
596 | sd r0, SAVE_CFRAME
597 | beqz TMP1, >3
598 |. sd TMP0, L->cframe
599 |
600 | // Resume after yield (like a return).
601 | sd L, DISPATCH_GL(cur_L)(DISPATCH)
602 | move RA, BASE
603 | ld BASE, L->base
604 | ld TMP1, L->top
605 | ld PC, FRAME_PC(BASE)
606 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float).
607 | dsubu RD, TMP1, BASE
608 | .FPU mtc1 TMP3, TOBIT
609 | sb r0, L->status
610 | .FPU cvt.d.s TOBIT, TOBIT
611 | li_vmstate INTERP
612 | daddiu RD, RD, 8
613 | st_vmstate
614 | move MULTRES, RD
615 | andi TMP0, PC, FRAME_TYPE
616 | li TISNIL, LJ_TNIL
617 | beqz TMP0, ->BC_RET_Z
618 |. li TISNUM, LJ_TISNUM
619 | b ->vm_return
620 |. nop
621 |
622 |->vm_pcall: // Setup protected C frame and enter VM.
623 | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef)
624 | saveregs
625 | sw CARG4, SAVE_ERRF
626 | b >1
627 |. li PC, FRAME_CP
628 |
629 |->vm_call: // Setup C frame and enter VM.
630 | // (lua_State *L, TValue *base, int nres1)
631 | saveregs
632 | li PC, FRAME_C
633 |
634 |1: // Entry point for vm_pcall above (PC = ftype).
635 | ld TMP1, L:CARG1->cframe
636 | move L, CARG1
637 | sw CARG3, SAVE_NRES
638 | ld DISPATCH, L->glref // Setup pointer to dispatch table.
639 | sd CARG1, SAVE_L
640 | move BASE, CARG2
641 | daddiu DISPATCH, DISPATCH, GG_G2DISP
642 | sd CARG1, SAVE_PC // Any value outside of bytecode is ok.
643 | sd TMP1, SAVE_CFRAME
644 | sd sp, L->cframe // Add our C frame to cframe chain.
645 |
646 |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype).
647 | sd L, DISPATCH_GL(cur_L)(DISPATCH)
648 | ld TMP2, L->base // TMP2 = old base (used in vmeta_call).
649 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float).
650 | ld TMP1, L->top
651 | .FPU mtc1 TMP3, TOBIT
652 | daddu PC, PC, BASE
653 | dsubu NARGS8:RC, TMP1, BASE
654 | li TISNUM, LJ_TISNUM
655 | dsubu PC, PC, TMP2 // PC = frame delta + frame type
656 | .FPU cvt.d.s TOBIT, TOBIT
657 | li_vmstate INTERP
658 | li TISNIL, LJ_TNIL
659 | st_vmstate
660 |
661 |->vm_call_dispatch:
662 | // TMP2 = old base, BASE = new base, RC = nargs*8, PC = caller PC
663 | ld LFUNC:RB, FRAME_FUNC(BASE)
664 | checkfunc LFUNC:RB, ->vmeta_call
665 |
666 |->vm_call_dispatch_f:
667 | ins_call
668 | // BASE = new base, RB = func, RC = nargs*8, PC = caller PC
669 |
670 |->vm_cpcall: // Setup protected C frame, call C.
671 | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
672 | saveregs
673 | move L, CARG1
674 | ld TMP0, L:CARG1->stack
675 | sd CARG1, SAVE_L
676 | ld TMP1, L->top
677 | ld DISPATCH, L->glref // Setup pointer to dispatch table.
678 | sd CARG1, SAVE_PC // Any value outside of bytecode is ok.
679 | dsubu TMP0, TMP0, TMP1 // Compute -savestack(L, L->top).
680 | ld TMP1, L->cframe
681 | daddiu DISPATCH, DISPATCH, GG_G2DISP
682 | sw TMP0, SAVE_NRES // Neg. delta means cframe w/o frame.
683 | sw r0, SAVE_ERRF // No error function.
684 | sd TMP1, SAVE_CFRAME
685 | sd sp, L->cframe // Add our C frame to cframe chain.
686 | sd L, DISPATCH_GL(cur_L)(DISPATCH)
687 | jalr CARG4 // (lua_State *L, lua_CFunction func, void *ud)
688 |. move CFUNCADDR, CARG4
689 | move BASE, CRET1
690 | bnez CRET1, <3 // Else continue with the call.
691 |. li PC, FRAME_CP
692 | b ->vm_leave_cp // No base? Just remove C frame.
693 |. nop
694 |
695 |//-----------------------------------------------------------------------
696 |//-- Metamethod handling ------------------------------------------------
697 |//-----------------------------------------------------------------------
698 |
699 |// The lj_meta_* functions (except for lj_meta_cat) don't reallocate the
700 |// stack, so BASE doesn't need to be reloaded across these calls.
701 |
702 |//-- Continuation dispatch ----------------------------------------------
703 |
704 |->cont_dispatch:
705 | // BASE = meta base, RA = resultptr, RD = (nresults+1)*8
706 | ld TMP0, -32(BASE) // Continuation.
707 | move RB, BASE
708 | move BASE, TMP2 // Restore caller BASE.
709 | ld LFUNC:TMP1, FRAME_FUNC(TMP2)
710 |.if FFI
711 | sltiu AT, TMP0, 2
712 |.endif
713 | ld PC, -24(RB) // Restore PC from [cont|PC].
714 | cleartp LFUNC:TMP1
715 | daddu TMP2, RA, RD
716 | ld TMP1, LFUNC:TMP1->pc
717 |.if FFI
718 | bnez AT, >1
719 |.endif
720 |. sd TISNIL, -8(TMP2) // Ensure one valid arg.
721 | // BASE = base, RA = resultptr, RB = meta base
722 | jr TMP0 // Jump to continuation.
723 |. ld KBASE, PC2PROTO(k)(TMP1)
724 |
725 |.if FFI
726 |1:
727 | bnez TMP0, ->cont_ffi_callback // cont = 1: return from FFI callback.
728 | // cont = 0: tailcall from C function.
729 |. daddiu TMP1, RB, -32
730 | b ->vm_call_tail
731 |. dsubu RC, TMP1, BASE
732 |.endif
733 |
734 |->cont_cat: // RA = resultptr, RB = meta base
735 | lw INS, -4(PC)
736 | daddiu CARG2, RB, -32
737 | ld CRET1, 0(RA)
738 | decode_RB8a MULTRES, INS
739 | decode_RA8a RA, INS
740 | decode_RB8b MULTRES
741 | decode_RA8b RA
742 | daddu TMP1, BASE, MULTRES
743 | sd BASE, L->base
744 | dsubu CARG3, CARG2, TMP1
745 | bne TMP1, CARG2, ->BC_CAT_Z
746 |. sd CRET1, 0(CARG2)
747 | daddu RA, BASE, RA
748 | b ->cont_nop
749 |. sd CRET1, 0(RA)
750 |
751 |//-- Table indexing metamethods -----------------------------------------
752 |
753 |->vmeta_tgets1:
754 | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
755 | li TMP0, LJ_TSTR
756 | settp STR:RC, TMP0
757 | b >1
758 |. sd STR:RC, 0(CARG3)
759 |
760 |->vmeta_tgets:
761 | daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
762 | li TMP0, LJ_TTAB
763 | li TMP1, LJ_TSTR
764 | settp TAB:RB, TMP0
765 | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv2)
766 | sd TAB:RB, 0(CARG2)
767 | settp STR:RC, TMP1
768 | b >1
769 |. sd STR:RC, 0(CARG3)
770 |
771 |->vmeta_tgetb: // TMP0 = index
772 | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
773 | settp TMP0, TISNUM
774 | sd TMP0, 0(CARG3)
775 |
776 |->vmeta_tgetv:
777 |1:
778 | load_got lj_meta_tget
779 | sd BASE, L->base
780 | sd PC, SAVE_PC
781 | call_intern lj_meta_tget // (lua_State *L, TValue *o, TValue *k)
782 |. move CARG1, L
783 | // Returns TValue * (finished) or NULL (metamethod).
784 | beqz CRET1, >3
785 |. daddiu TMP1, BASE, -FRAME_CONT
786 | ld CARG1, 0(CRET1)
787 | ins_next1
788 | sd CARG1, 0(RA)
789 | ins_next2
790 |
791 |3: // Call __index metamethod.
792 | // BASE = base, L->top = new base, stack = cont/func/t/k
793 | ld BASE, L->top
794 | sd PC, -24(BASE) // [cont|PC]
795 | dsubu PC, BASE, TMP1
796 | ld LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here.
797 | cleartp LFUNC:RB
798 | b ->vm_call_dispatch_f
799 |. li NARGS8:RC, 16 // 2 args for func(t, k).
800 |
801 |->vmeta_tgetr:
802 | load_got lj_tab_getinth
803 | call_intern lj_tab_getinth // (GCtab *t, int32_t key)
804 |. nop
805 | // Returns cTValue * or NULL.
806 | beqz CRET1, ->BC_TGETR_Z
807 |. move CARG2, TISNIL
808 | b ->BC_TGETR_Z
809 |. ld CARG2, 0(CRET1)
810 |
811 |//-----------------------------------------------------------------------
812 |
813 |->vmeta_tsets1:
814 | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
815 | li TMP0, LJ_TSTR
816 | settp STR:RC, TMP0
817 | b >1
818 |. sd STR:RC, 0(CARG3)
819 |
820 |->vmeta_tsets:
821 | daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
822 | li TMP0, LJ_TTAB
823 | li TMP1, LJ_TSTR
824 | settp TAB:RB, TMP0
825 | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv2)
826 | sd TAB:RB, 0(CARG2)
827 | settp STR:RC, TMP1
828 | b >1
829 |. sd STR:RC, 0(CARG3)
830 |
831 |->vmeta_tsetb: // TMP0 = index
832 | daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
833 | settp TMP0, TISNUM
834 | sd TMP0, 0(CARG3)
835 |
836 |->vmeta_tsetv:
837 |1:
838 | load_got lj_meta_tset
839 | sd BASE, L->base
840 | sd PC, SAVE_PC
841 | call_intern lj_meta_tset // (lua_State *L, TValue *o, TValue *k)
842 |. move CARG1, L
843 | // Returns TValue * (finished) or NULL (metamethod).
844 | beqz CRET1, >3
845 |. ld CARG1, 0(RA)
846 | // NOBARRIER: lj_meta_tset ensures the table is not black.
847 | ins_next1
848 | sd CARG1, 0(CRET1)
849 | ins_next2
850 |
851 |3: // Call __newindex metamethod.
852 | // BASE = base, L->top = new base, stack = cont/func/t/k/(v)
853 | daddiu TMP1, BASE, -FRAME_CONT
854 | ld BASE, L->top
855 | sd PC, -24(BASE) // [cont|PC]
856 | dsubu PC, BASE, TMP1
857 | ld LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here.
858 | cleartp LFUNC:RB
859 | sd CARG1, 16(BASE) // Copy value to third argument.
860 | b ->vm_call_dispatch_f
861 |. li NARGS8:RC, 24 // 3 args for func(t, k, v)
862 |
863 |->vmeta_tsetr:
864 | load_got lj_tab_setinth
865 | sd BASE, L->base
866 | sd PC, SAVE_PC
867 | call_intern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key)
868 |. move CARG1, L
869 | // Returns TValue *.
870 | b ->BC_TSETR_Z
871 |. nop
872 |
873 |//-- Comparison metamethods ---------------------------------------------
874 |
875 |->vmeta_comp:
876 | // RA/RD point to o1/o2.
877 | move CARG2, RA
878 | move CARG3, RD
879 | load_got lj_meta_comp
880 | daddiu PC, PC, -4
881 | sd BASE, L->base
882 | sd PC, SAVE_PC
883 | decode_OP1 CARG4, INS
884 | call_intern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op)
885 |. move CARG1, L
886 | // Returns 0/1 or TValue * (metamethod).
887 |3:
888 | sltiu AT, CRET1, 2
889 | beqz AT, ->vmeta_binop
890 | negu TMP2, CRET1
891 |4:
892 | lhu RD, OFS_RD(PC)
893 | daddiu PC, PC, 4
894 | lui TMP1, (-(BCBIAS_J*4 >> 16) & 65535)
895 | sll RD, RD, 2
896 | addu RD, RD, TMP1
897 | and RD, RD, TMP2
898 | daddu PC, PC, RD
899 |->cont_nop:
900 | ins_next
901 |
902 |->cont_ra: // RA = resultptr
903 | lbu TMP1, -4+OFS_RA(PC)
904 | ld CRET1, 0(RA)
905 | sll TMP1, TMP1, 3
906 | daddu TMP1, BASE, TMP1
907 | b ->cont_nop
908 |. sd CRET1, 0(TMP1)
909 |
910 |->cont_condt: // RA = resultptr
911 | ld TMP0, 0(RA)
912 | gettp TMP0, TMP0
913 | sltiu AT, TMP0, LJ_TISTRUECOND
914 | b <4
915 |. negu TMP2, AT // Branch if result is true.
916 |
917 |->cont_condf: // RA = resultptr
918 | ld TMP0, 0(RA)
919 | gettp TMP0, TMP0
920 | sltiu AT, TMP0, LJ_TISTRUECOND
921 | b <4
922 |. addiu TMP2, AT, -1 // Branch if result is false.
923 |
924 |->vmeta_equal:
925 | // CARG1/CARG2 point to o1/o2. TMP0 is set to 0/1.
926 | load_got lj_meta_equal
927 | cleartp LFUNC:CARG3, CARG2
928 | cleartp LFUNC:CARG2, CARG1
929 | move CARG4, TMP0
930 | daddiu PC, PC, -4
931 | sd BASE, L->base
932 | sd PC, SAVE_PC
933 | call_intern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne)
934 |. move CARG1, L
935 | // Returns 0/1 or TValue * (metamethod).
936 | b <3
937 |. nop
938 |
939 |->vmeta_equal_cd:
940 |.if FFI
941 | load_got lj_meta_equal_cd
942 | move CARG2, INS
943 | daddiu PC, PC, -4
944 | sd BASE, L->base
945 | sd PC, SAVE_PC
946 | call_intern lj_meta_equal_cd // (lua_State *L, BCIns op)
947 |. move CARG1, L
948 | // Returns 0/1 or TValue * (metamethod).
949 | b <3
950 |. nop
951 |.endif
952 |
953 |->vmeta_istype:
954 | load_got lj_meta_istype
955 | daddiu PC, PC, -4
956 | sd BASE, L->base
957 | srl CARG2, RA, 3
958 | srl CARG3, RD, 3
959 | sd PC, SAVE_PC
960 | call_intern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp)
961 |. move CARG1, L
962 | b ->cont_nop
963 |. nop
964 |
965 |//-- Arithmetic metamethods ---------------------------------------------
966 |
967 |->vmeta_unm:
968 | move RC, RB
969 |
970 |->vmeta_arith:
971 | load_got lj_meta_arith
972 | sd BASE, L->base
973 | move CARG2, RA
974 | sd PC, SAVE_PC
975 | move CARG3, RB
976 | move CARG4, RC
977 | decode_OP1 CARG5, INS // CARG5 == RB.
978 | call_intern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op)
979 |. move CARG1, L
980 | // Returns NULL (finished) or TValue * (metamethod).
981 | beqz CRET1, ->cont_nop
982 |. nop
983 |
984 | // Call metamethod for binary op.
985 |->vmeta_binop:
986 | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2
987 | dsubu TMP1, CRET1, BASE
988 | sd PC, -24(CRET1) // [cont|PC]
989 | move TMP2, BASE
990 | daddiu PC, TMP1, FRAME_CONT
991 | move BASE, CRET1
992 | b ->vm_call_dispatch
993 |. li NARGS8:RC, 16 // 2 args for func(o1, o2).
994 |
995 |->vmeta_len:
996 | // CARG2 already set by BC_LEN.
997#if LJ_52
998 | move MULTRES, CARG1
999#endif
1000 | load_got lj_meta_len
1001 | sd BASE, L->base
1002 | sd PC, SAVE_PC
1003 | call_intern lj_meta_len // (lua_State *L, TValue *o)
1004 |. move CARG1, L
1005 | // Returns NULL (retry) or TValue * (metamethod base).
1006#if LJ_52
1007 | bnez CRET1, ->vmeta_binop // Binop call for compatibility.
1008 |. nop
1009 | b ->BC_LEN_Z
1010 |. move CARG1, MULTRES
1011#else
1012 | b ->vmeta_binop // Binop call for compatibility.
1013 |. nop
1014#endif
1015 |
1016 |//-- Call metamethod ----------------------------------------------------
1017 |
1018 |->vmeta_call: // Resolve and call __call metamethod.
1019 | // TMP2 = old base, BASE = new base, RC = nargs*8
1020 | load_got lj_meta_call
1021 | sd TMP2, L->base // This is the callers base!
1022 | daddiu CARG2, BASE, -16
1023 | sd PC, SAVE_PC
1024 | daddu CARG3, BASE, RC
1025 | move MULTRES, NARGS8:RC
1026 | call_intern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
1027 |. move CARG1, L
1028 | ld LFUNC:RB, FRAME_FUNC(BASE) // Guaranteed to be a function here.
1029 | daddiu NARGS8:RC, MULTRES, 8 // Got one more argument now.
1030 | cleartp LFUNC:RB
1031 | ins_call
1032 |
1033 |->vmeta_callt: // Resolve __call for BC_CALLT.
1034 | // BASE = old base, RA = new base, RC = nargs*8
1035 | load_got lj_meta_call
1036 | sd BASE, L->base
1037 | daddiu CARG2, RA, -16
1038 | sd PC, SAVE_PC
1039 | daddu CARG3, RA, RC
1040 | move MULTRES, NARGS8:RC
1041 | call_intern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
1042 |. move CARG1, L
1043 | ld RB, FRAME_FUNC(RA) // Guaranteed to be a function here.
1044 | ld TMP1, FRAME_PC(BASE)
1045 | daddiu NARGS8:RC, MULTRES, 8 // Got one more argument now.
1046 | b ->BC_CALLT_Z
1047 |. cleartp LFUNC:CARG3, RB
1048 |
1049 |//-- Argument coercion for 'for' statement ------------------------------
1050 |
1051 |->vmeta_for:
1052 | load_got lj_meta_for
1053 | sd BASE, L->base
1054 | move CARG2, RA
1055 | sd PC, SAVE_PC
1056 | move MULTRES, INS
1057 | call_intern lj_meta_for // (lua_State *L, TValue *base)
1058 |. move CARG1, L
1059 |.if JIT
1060 | decode_OP1 TMP0, MULTRES
1061 | li AT, BC_JFORI
1062 |.endif
1063 | decode_RA8a RA, MULTRES
1064 | decode_RD8a RD, MULTRES
1065 | decode_RA8b RA
1066 |.if JIT
1067 | beq TMP0, AT, =>BC_JFORI
1068 |. decode_RD8b RD
1069 | b =>BC_FORI
1070 |. nop
1071 |.else
1072 | b =>BC_FORI
1073 |. decode_RD8b RD
1074 |.endif
1075 |
1076 |//-----------------------------------------------------------------------
1077 |//-- Fast functions -----------------------------------------------------
1078 |//-----------------------------------------------------------------------
1079 |
1080 |.macro .ffunc, name
1081 |->ff_ .. name:
1082 |.endmacro
1083 |
1084 |.macro .ffunc_1, name
1085 |->ff_ .. name:
1086 | beqz NARGS8:RC, ->fff_fallback
1087 |. ld CARG1, 0(BASE)
1088 |.endmacro
1089 |
1090 |.macro .ffunc_2, name
1091 |->ff_ .. name:
1092 | sltiu AT, NARGS8:RC, 16
1093 | ld CARG1, 0(BASE)
1094 | bnez AT, ->fff_fallback
1095 |. ld CARG2, 8(BASE)
1096 |.endmacro
1097 |
1098 |.macro .ffunc_n, name // Caveat: has delay slot!
1099 |->ff_ .. name:
1100 | ld CARG1, 0(BASE)
1101 | beqz NARGS8:RC, ->fff_fallback
1102 | // Either ldc1 or the 1st instruction of checknum is in the delay slot.
1103 | .FPU ldc1 FARG1, 0(BASE)
1104 | checknum CARG1, ->fff_fallback
1105 |.endmacro
1106 |
1107 |.macro .ffunc_nn, name // Caveat: has delay slot!
1108 |->ff_ .. name:
1109 | ld CARG1, 0(BASE)
1110 | sltiu AT, NARGS8:RC, 16
1111 | ld CARG2, 8(BASE)
1112 | bnez AT, ->fff_fallback
1113 |. gettp TMP0, CARG1
1114 | gettp TMP1, CARG2
1115 | sltiu TMP0, TMP0, LJ_TISNUM
1116 | sltiu TMP1, TMP1, LJ_TISNUM
1117 | .FPU ldc1 FARG1, 0(BASE)
1118 | and TMP0, TMP0, TMP1
1119 | .FPU ldc1 FARG2, 8(BASE)
1120 | beqz TMP0, ->fff_fallback
1121 |.endmacro
1122 |
1123 |// Inlined GC threshold check. Caveat: uses TMP0 and TMP1 and has delay slot!
1124 |.macro ffgccheck
1125 | ld TMP0, DISPATCH_GL(gc.total)(DISPATCH)
1126 | ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH)
1127 | dsubu AT, TMP0, TMP1
1128 | bgezal AT, ->fff_gcstep
1129 |.endmacro
1130 |
1131 |//-- Base library: checks -----------------------------------------------
1132 |.ffunc_1 assert
1133 | gettp AT, CARG1
1134 | sltiu AT, AT, LJ_TISTRUECOND
1135 | beqz AT, ->fff_fallback
1136 |. daddiu RA, BASE, -16
1137 | ld PC, FRAME_PC(BASE)
1138 | addiu RD, NARGS8:RC, 8 // Compute (nresults+1)*8.
1139 | daddu TMP2, RA, RD
1140 | daddiu TMP1, BASE, 8
1141 | beq BASE, TMP2, ->fff_res // Done if exactly 1 argument.
1142 |. sd CARG1, 0(RA)
1143 |1:
1144 | ld CRET1, 0(TMP1)
1145 | sd CRET1, -16(TMP1)
1146 | bne TMP1, TMP2, <1
1147 |. daddiu TMP1, TMP1, 8
1148 | b ->fff_res
1149 |. nop
1150 |
1151 |.ffunc_1 type
1152 | gettp TMP0, CARG1
1153 | sltu TMP1, TISNUM, TMP0
1154 | not TMP2, TMP0
1155 | li TMP3, ~LJ_TISNUM
1156 | movz TMP2, TMP3, TMP1
1157 | dsll TMP2, TMP2, 3
1158 | daddu TMP2, CFUNC:RB, TMP2
1159 | b ->fff_restv
1160 |. ld CARG1, CFUNC:TMP2->upvalue
1161 |
1162 |//-- Base library: getters and setters ---------------------------------
1163 |
1164 |.ffunc_1 getmetatable
1165 | gettp TMP2, CARG1
1166 | daddiu TMP0, TMP2, -LJ_TTAB
1167 | daddiu TMP1, TMP2, -LJ_TUDATA
1168 | movn TMP0, TMP1, TMP0
1169 | bnez TMP0, >6
1170 |. cleartp TAB:CARG1
1171 |1: // Field metatable must be at same offset for GCtab and GCudata!
1172 | ld TAB:RB, TAB:CARG1->metatable
1173 |2:
1174 | ld STR:RC, DISPATCH_GL(gcroot[GCROOT_MMNAME+MM_metatable])(DISPATCH)
1175 | beqz TAB:RB, ->fff_restv
1176 |. li CARG1, LJ_TNIL
1177 | lw TMP0, TAB:RB->hmask
1178 | lw TMP1, STR:RC->hash
1179 | ld NODE:TMP2, TAB:RB->node
1180 | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask
1181 | dsll TMP0, TMP1, 5
1182 | dsll TMP1, TMP1, 3
1183 | dsubu TMP1, TMP0, TMP1
1184 | daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
1185 | li CARG4, LJ_TSTR
1186 | settp STR:RC, CARG4 // Tagged key to look for.
1187 |3: // Rearranged logic, because we expect _not_ to find the key.
1188 | ld TMP0, NODE:TMP2->key
1189 | ld CARG1, NODE:TMP2->val
1190 | ld NODE:TMP2, NODE:TMP2->next
1191 | beq RC, TMP0, >5
1192 |. li AT, LJ_TTAB
1193 | bnez NODE:TMP2, <3
1194 |. nop
1195 |4:
1196 | move CARG1, RB
1197 | b ->fff_restv // Not found, keep default result.
1198 |. settp CARG1, AT
1199 |5:
1200 | bne CARG1, TISNIL, ->fff_restv
1201 |. nop
1202 | b <4 // Ditto for nil value.
1203 |. nop
1204 |
1205 |6:
1206 | sltiu AT, TMP2, LJ_TISNUM
1207 | movn TMP2, TISNUM, AT
1208 | dsll TMP2, TMP2, 3
1209 | dsubu TMP0, DISPATCH, TMP2
1210 | b <2
1211 |. ld TAB:RB, DISPATCH_GL(gcroot[GCROOT_BASEMT])-8(TMP0)
1212 |
1213 |.ffunc_2 setmetatable
1214 | // Fast path: no mt for table yet and not clearing the mt.
1215 | checktp TMP1, CARG1, -LJ_TTAB, ->fff_fallback
1216 | gettp TMP3, CARG2
1217 | ld TAB:TMP0, TAB:TMP1->metatable
1218 | lbu TMP2, TAB:TMP1->marked
1219 | daddiu AT, TMP3, -LJ_TTAB
1220 | cleartp TAB:CARG2
1221 | or AT, AT, TAB:TMP0
1222 | bnez AT, ->fff_fallback
1223 |. andi AT, TMP2, LJ_GC_BLACK // isblack(table)
1224 | beqz AT, ->fff_restv
1225 |. sd TAB:CARG2, TAB:TMP1->metatable
1226 | barrierback TAB:TMP1, TMP2, TMP0, ->fff_restv
1227 |
1228 |.ffunc rawget
1229 | ld CARG2, 0(BASE)
1230 | sltiu AT, NARGS8:RC, 16
1231 | load_got lj_tab_get
1232 | gettp TMP0, CARG2
1233 | cleartp CARG2
1234 | daddiu TMP0, TMP0, -LJ_TTAB
1235 | or AT, AT, TMP0
1236 | bnez AT, ->fff_fallback
1237 |. daddiu CARG3, BASE, 8
1238 | call_intern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key)
1239 |. move CARG1, L
1240 | b ->fff_restv
1241 |. ld CARG1, 0(CRET1)
1242 |
1243 |//-- Base library: conversions ------------------------------------------
1244 |
1245 |.ffunc tonumber
1246 | // Only handles the number case inline (without a base argument).
1247 | ld CARG1, 0(BASE)
1248 | xori AT, NARGS8:RC, 8 // Exactly one number argument.
1249 | gettp TMP1, CARG1
1250 | sltu TMP0, TISNUM, TMP1
1251 | or AT, AT, TMP0
1252 | bnez AT, ->fff_fallback
1253 |. nop
1254 | b ->fff_restv
1255 |. nop
1256 |
1257 |.ffunc_1 tostring
1258 | // Only handles the string or number case inline.
1259 | gettp TMP0, CARG1
1260 | daddiu AT, TMP0, -LJ_TSTR
1261 | // A __tostring method in the string base metatable is ignored.
1262 | beqz AT, ->fff_restv // String key?
1263 | // Handle numbers inline, unless a number base metatable is present.
1264 |. ld TMP1, DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])(DISPATCH)
1265 | sltu TMP0, TISNUM, TMP0
1266 | or TMP0, TMP0, TMP1
1267 | bnez TMP0, ->fff_fallback
1268 |. sd BASE, L->base // Add frame since C call can throw.
1269 | ffgccheck
1270 |. sd PC, SAVE_PC // Redundant (but a defined value).
1271 | load_got lj_strfmt_number
1272 | move CARG1, L
1273 | call_intern lj_strfmt_number // (lua_State *L, cTValue *o)
1274 |. move CARG2, BASE
1275 | // Returns GCstr *.
1276 | li AT, LJ_TSTR
1277 | settp CRET1, AT
1278 | b ->fff_restv
1279 |. move CARG1, CRET1
1280 |
1281 |//-- Base library: iterators -------------------------------------------
1282 |
1283 |.ffunc_1 next
1284 | checktp CARG2, CARG1, -LJ_TTAB, ->fff_fallback
1285 | daddu TMP2, BASE, NARGS8:RC
1286 | sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil.
1287 | ld PC, FRAME_PC(BASE)
1288 | load_got lj_tab_next
1289 | sd BASE, L->base // Add frame since C call can throw.
1290 | sd BASE, L->top // Dummy frame length is ok.
1291 | daddiu CARG3, BASE, 8
1292 | sd PC, SAVE_PC
1293 | call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1294 |. move CARG1, L
1295 | // Returns 0 at end of traversal.
1296 | beqz CRET1, ->fff_restv // End of traversal: return nil.
1297 |. move CARG1, TISNIL
1298 | ld TMP0, 8(BASE)
1299 | daddiu RA, BASE, -16
1300 | ld TMP2, 16(BASE)
1301 | sd TMP0, 0(RA)
1302 | sd TMP2, 8(RA)
1303 | b ->fff_res
1304 |. li RD, (2+1)*8
1305 |
1306 |.ffunc_1 pairs
1307 | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
1308 | ld PC, FRAME_PC(BASE)
1309#if LJ_52
1310 | ld TAB:TMP2, TAB:TMP1->metatable
1311 | ld TMP0, CFUNC:RB->upvalue[0]
1312 | bnez TAB:TMP2, ->fff_fallback
1313#else
1314 | ld TMP0, CFUNC:RB->upvalue[0]
1315#endif
1316 |. daddiu RA, BASE, -16
1317 | sd TISNIL, 0(BASE)
1318 | sd CARG1, -8(BASE)
1319 | sd TMP0, 0(RA)
1320 | b ->fff_res
1321 |. li RD, (3+1)*8
1322 |
1323 |.ffunc_2 ipairs_aux
1324 | checktab CARG1, ->fff_fallback
1325 | checkint CARG2, ->fff_fallback
1326 |. lw TMP0, TAB:CARG1->asize
1327 | ld TMP1, TAB:CARG1->array
1328 | ld PC, FRAME_PC(BASE)
1329 | sextw TMP2, CARG2
1330 | addiu TMP2, TMP2, 1
1331 | sltu AT, TMP2, TMP0
1332 | daddiu RA, BASE, -16
1333 | zextw TMP0, TMP2
1334 | settp TMP0, TISNUM
1335 | beqz AT, >2 // Not in array part?
1336 |. sd TMP0, 0(RA)
1337 | dsll TMP3, TMP2, 3
1338 | daddu TMP3, TMP1, TMP3
1339 | ld TMP1, 0(TMP3)
1340 |1:
1341 | beq TMP1, TISNIL, ->fff_res // End of iteration, return 0 results.
1342 |. li RD, (0+1)*8
1343 | sd TMP1, -8(BASE)
1344 | b ->fff_res
1345 |. li RD, (2+1)*8
1346 |2: // Check for empty hash part first. Otherwise call C function.
1347 | lw TMP0, TAB:CARG1->hmask
1348 | load_got lj_tab_getinth
1349 | beqz TMP0, ->fff_res
1350 |. li RD, (0+1)*8
1351 | call_intern lj_tab_getinth // (GCtab *t, int32_t key)
1352 |. move CARG2, TMP2
1353 | // Returns cTValue * or NULL.
1354 | beqz CRET1, ->fff_res
1355 |. li RD, (0+1)*8
1356 | b <1
1357 |. ld TMP1, 0(CRET1)
1358 |
1359 |.ffunc_1 ipairs
1360 | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
1361 | ld PC, FRAME_PC(BASE)
1362#if LJ_52
1363 | ld TAB:TMP2, TAB:TMP1->metatable
1364 | ld CFUNC:TMP0, CFUNC:RB->upvalue[0]
1365 | bnez TAB:TMP2, ->fff_fallback
1366#else
1367 | ld TMP0, CFUNC:RB->upvalue[0]
1368#endif
1369 | daddiu RA, BASE, -16
1370 | dsll AT, TISNUM, 47
1371 | sd CARG1, -8(BASE)
1372 | sd AT, 0(BASE)
1373 | sd CFUNC:TMP0, 0(RA)
1374 | b ->fff_res
1375 |. li RD, (3+1)*8
1376 |
1377 |//-- Base library: catch errors ----------------------------------------
1378 |
1379 |.ffunc pcall
1380 | daddiu NARGS8:RC, NARGS8:RC, -8
1381 | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
1382 | bltz NARGS8:RC, ->fff_fallback
1383 |. move TMP2, BASE
1384 | daddiu BASE, BASE, 16
1385 | // Remember active hook before pcall.
1386 | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
1387 | andi TMP3, TMP3, 1
1388 | daddiu PC, TMP3, 16+FRAME_PCALL
1389 | beqz NARGS8:RC, ->vm_call_dispatch
1390 |1:
1391 |. daddu TMP0, BASE, NARGS8:RC
1392 |2:
1393 | ld TMP1, -16(TMP0)
1394 | sd TMP1, -8(TMP0)
1395 | daddiu TMP0, TMP0, -8
1396 | bne TMP0, BASE, <2
1397 |. nop
1398 | b ->vm_call_dispatch
1399 |. nop
1400 |
1401 |.ffunc xpcall
1402 | daddiu NARGS8:TMP0, NARGS8:RC, -16
1403 | ld CARG1, 0(BASE)
1404 | ld CARG2, 8(BASE)
1405 | bltz NARGS8:TMP0, ->fff_fallback
1406 |. lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH)
1407 | gettp AT, CARG2
1408 | daddiu AT, AT, -LJ_TFUNC
1409 | bnez AT, ->fff_fallback // Traceback must be a function.
1410 |. move TMP2, BASE
1411 | move NARGS8:RC, NARGS8:TMP0
1412 | daddiu BASE, BASE, 24
1413 | // Remember active hook before pcall.
1414 | srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
1415 | sd CARG2, 0(TMP2) // Swap function and traceback.
1416 | andi TMP3, TMP3, 1
1417 | sd CARG1, 8(TMP2)
1418 | beqz NARGS8:RC, ->vm_call_dispatch
1419 |. daddiu PC, TMP3, 24+FRAME_PCALL
1420 | b <1
1421 |. nop
1422 |
1423 |//-- Coroutine library --------------------------------------------------
1424 |
1425 |.macro coroutine_resume_wrap, resume
1426 |.if resume
1427 |.ffunc_1 coroutine_resume
1428 | checktp CARG1, CARG1, -LJ_TTHREAD, ->fff_fallback
1429 |.else
1430 |.ffunc coroutine_wrap_aux
1431 | ld L:CARG1, CFUNC:RB->upvalue[0].gcr
1432 | cleartp L:CARG1
1433 |.endif
1434 | lbu TMP0, L:CARG1->status
1435 | ld TMP1, L:CARG1->cframe
1436 | ld CARG2, L:CARG1->top
1437 | ld TMP2, L:CARG1->base
1438 | addiu AT, TMP0, -LUA_YIELD
1439 | daddu CARG3, CARG2, TMP0
1440 | daddiu TMP3, CARG2, 8
1441 | bgtz AT, ->fff_fallback // st > LUA_YIELD?
1442 |. movn CARG2, TMP3, AT
1443 | xor TMP2, TMP2, CARG3
1444 | bnez TMP1, ->fff_fallback // cframe != 0?
1445 |. or AT, TMP2, TMP0
1446 | ld TMP0, L:CARG1->maxstack
1447 | beqz AT, ->fff_fallback // base == top && st == 0?
1448 |. ld PC, FRAME_PC(BASE)
1449 | daddu TMP2, CARG2, NARGS8:RC
1450 | sltu AT, TMP0, TMP2
1451 | bnez AT, ->fff_fallback // Stack overflow?
1452 |. sd PC, SAVE_PC
1453 | sd BASE, L->base
1454 |1:
1455 |.if resume
1456 | daddiu BASE, BASE, 8 // Keep resumed thread in stack for GC.
1457 | daddiu NARGS8:RC, NARGS8:RC, -8
1458 | daddiu TMP2, TMP2, -8
1459 |.endif
1460 | sd TMP2, L:CARG1->top
1461 | daddu TMP1, BASE, NARGS8:RC
1462 | move CARG3, CARG2
1463 | sd BASE, L->top
1464 |2: // Move args to coroutine.
1465 | ld CRET1, 0(BASE)
1466 | sltu AT, BASE, TMP1
1467 | beqz AT, >3
1468 |. daddiu BASE, BASE, 8
1469 | sd CRET1, 0(CARG3)
1470 | b <2
1471 |. daddiu CARG3, CARG3, 8
1472 |3:
1473 | bal ->vm_resume // (lua_State *L, TValue *base, 0, 0)
1474 |. move L:RA, L:CARG1
1475 | // Returns thread status.
1476 |4:
1477 | ld TMP2, L:RA->base
1478 | sltiu AT, CRET1, LUA_YIELD+1
1479 | ld TMP3, L:RA->top
1480 | li_vmstate INTERP
1481 | ld BASE, L->base
1482 | sd L, DISPATCH_GL(cur_L)(DISPATCH)
1483 | st_vmstate
1484 | beqz AT, >8
1485 |. dsubu RD, TMP3, TMP2
1486 | ld TMP0, L->maxstack
1487 | beqz RD, >6 // No results?
1488 |. daddu TMP1, BASE, RD
1489 | sltu AT, TMP0, TMP1
1490 | bnez AT, >9 // Need to grow stack?
1491 |. daddu TMP3, TMP2, RD
1492 | sd TMP2, L:RA->top // Clear coroutine stack.
1493 | move TMP1, BASE
1494 |5: // Move results from coroutine.
1495 | ld CRET1, 0(TMP2)
1496 | daddiu TMP2, TMP2, 8
1497 | sltu AT, TMP2, TMP3
1498 | sd CRET1, 0(TMP1)
1499 | bnez AT, <5
1500 |. daddiu TMP1, TMP1, 8
1501 |6:
1502 | andi TMP0, PC, FRAME_TYPE
1503 |.if resume
1504 | mov_true TMP1
1505 | daddiu RA, BASE, -8
1506 | sd TMP1, -8(BASE) // Prepend true to results.
1507 | daddiu RD, RD, 16
1508 |.else
1509 | move RA, BASE
1510 | daddiu RD, RD, 8
1511 |.endif
1512 |7:
1513 | sd PC, SAVE_PC
1514 | beqz TMP0, ->BC_RET_Z
1515 |. move MULTRES, RD
1516 | b ->vm_return
1517 |. nop
1518 |
1519 |8: // Coroutine returned with error (at co->top-1).
1520 |.if resume
1521 | daddiu TMP3, TMP3, -8
1522 | mov_false TMP1
1523 | ld CRET1, 0(TMP3)
1524 | sd TMP3, L:RA->top // Remove error from coroutine stack.
1525 | li RD, (2+1)*8
1526 | sd TMP1, -8(BASE) // Prepend false to results.
1527 | daddiu RA, BASE, -8
1528 | sd CRET1, 0(BASE) // Copy error message.
1529 | b <7
1530 |. andi TMP0, PC, FRAME_TYPE
1531 |.else
1532 | load_got lj_ffh_coroutine_wrap_err
1533 | move CARG2, L:RA
1534 | call_intern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co)
1535 |. move CARG1, L
1536 |.endif
1537 |
1538 |9: // Handle stack expansion on return from yield.
1539 | load_got lj_state_growstack
1540 | srl CARG2, RD, 3
1541 | call_intern lj_state_growstack // (lua_State *L, int n)
1542 |. move CARG1, L
1543 | b <4
1544 |. li CRET1, 0
1545 |.endmacro
1546 |
1547 | coroutine_resume_wrap 1 // coroutine.resume
1548 | coroutine_resume_wrap 0 // coroutine.wrap
1549 |
1550 |.ffunc coroutine_yield
1551 | ld TMP0, L->cframe
1552 | daddu TMP1, BASE, NARGS8:RC
1553 | sd BASE, L->base
1554 | andi TMP0, TMP0, CFRAME_RESUME
1555 | sd TMP1, L->top
1556 | beqz TMP0, ->fff_fallback
1557 |. li CRET1, LUA_YIELD
1558 | sd r0, L->cframe
1559 | b ->vm_leave_unw
1560 |. sb CRET1, L->status
1561 |
1562 |//-- Math library -------------------------------------------------------
1563 |
1564 |.ffunc_1 math_abs
1565 | gettp CARG2, CARG1
1566 | daddiu AT, CARG2, -LJ_TISNUM
1567 | bnez AT, >1
1568 |. sextw TMP1, CARG1
1569 | sra TMP0, TMP1, 31 // Extract sign.
1570 | xor TMP1, TMP1, TMP0
1571 | dsubu CARG1, TMP1, TMP0
1572 | dsll TMP3, CARG1, 32
1573 | bgez TMP3, ->fff_restv
1574 |. settp CARG1, TISNUM
1575 | li CARG1, 0x41e0 // 2^31 as a double.
1576 | b ->fff_restv
1577 |. dsll CARG1, CARG1, 48
1578 |1:
1579 | sltiu AT, CARG2, LJ_TISNUM
1580 | beqz AT, ->fff_fallback
1581 |. dextm CARG1, CARG1, 0, 30
1582 |// fallthrough
1583 |
1584 |->fff_restv:
1585 | // CARG1 = TValue result.
1586 | ld PC, FRAME_PC(BASE)
1587 | daddiu RA, BASE, -16
1588 | sd CARG1, -16(BASE)
1589 |->fff_res1:
1590 | // RA = results, PC = return.
1591 | li RD, (1+1)*8
1592 |->fff_res:
1593 | // RA = results, RD = (nresults+1)*8, PC = return.
1594 | andi TMP0, PC, FRAME_TYPE
1595 | bnez TMP0, ->vm_return
1596 |. move MULTRES, RD
1597 | lw INS, -4(PC)
1598 | decode_RB8a RB, INS
1599 | decode_RB8b RB
1600 |5:
1601 | sltu AT, RD, RB
1602 | bnez AT, >6 // More results expected?
1603 |. decode_RA8a TMP0, INS
1604 | decode_RA8b TMP0
1605 | ins_next1
1606 | // Adjust BASE. KBASE is assumed to be set for the calling frame.
1607 | dsubu BASE, RA, TMP0
1608 | ins_next2
1609 |
1610 |6: // Fill up results with nil.
1611 | daddu TMP1, RA, RD
1612 | daddiu RD, RD, 8
1613 | b <5
1614 |. sd TISNIL, -8(TMP1)
1615 |
1616 |.macro math_extern, func
1617 | .ffunc_n math_ .. func
1618 | load_got func
1619 | call_extern
1620 |. nop
1621 | b ->fff_resn
1622 |. nop
1623 |.endmacro
1624 |
1625 |.macro math_extern2, func
1626 | .ffunc_nn math_ .. func
1627 |. load_got func
1628 | call_extern
1629 |. nop
1630 | b ->fff_resn
1631 |. nop
1632 |.endmacro
1633 |
1634 |// TODO: Return integer type if result is integer (own sf implementation).
1635 |.macro math_round, func
1636 |->ff_math_ .. func:
1637 | ld CARG1, 0(BASE)
1638 | beqz NARGS8:RC, ->fff_fallback
1639 |. gettp TMP0, CARG1
1640 | beq TMP0, TISNUM, ->fff_restv
1641 |. sltu AT, TMP0, TISNUM
1642 | beqz AT, ->fff_fallback
1643 |.if FPU
1644 |. ldc1 FARG1, 0(BASE)
1645 | bal ->vm_ .. func
1646 |. nop
1647 |.else
1648 |. load_got func
1649 | call_extern
1650 |. nop
1651 |.endif
1652 | b ->fff_resn
1653 |. nop
1654 |.endmacro
1655 |
1656 | math_round floor
1657 | math_round ceil
1658 |
1659 |.ffunc math_log
1660 | li AT, 8
1661 | bne NARGS8:RC, AT, ->fff_fallback // Exactly 1 argument.
1662 |. ld CARG1, 0(BASE)
1663 | checknum CARG1, ->fff_fallback
1664 |. load_got log
1665 |.if FPU
1666 | call_extern
1667 |. ldc1 FARG1, 0(BASE)
1668 |.else
1669 | call_extern
1670 |. nop
1671 |.endif
1672 | b ->fff_resn
1673 |. nop
1674 |
1675 | math_extern log10
1676 | math_extern exp
1677 | math_extern sin
1678 | math_extern cos
1679 | math_extern tan
1680 | math_extern asin
1681 | math_extern acos
1682 | math_extern atan
1683 | math_extern sinh
1684 | math_extern cosh
1685 | math_extern tanh
1686 | math_extern2 pow
1687 | math_extern2 atan2
1688 | math_extern2 fmod
1689 |
1690 |.if FPU
1691 |.ffunc_n math_sqrt
1692 |. sqrt.d FRET1, FARG1
1693 |// fallthrough to ->fff_resn
1694 |.else
1695 | math_extern sqrt
1696 |.endif
1697 |
1698 |->fff_resn:
1699 | ld PC, FRAME_PC(BASE)
1700 | daddiu RA, BASE, -16
1701 | b ->fff_res1
1702 |.if FPU
1703 |. sdc1 FRET1, 0(RA)
1704 |.else
1705 |. sd CRET1, 0(RA)
1706 |.endif
1707 |
1708 |
1709 |.ffunc_2 math_ldexp
1710 | checknum CARG1, ->fff_fallback
1711 | checkint CARG2, ->fff_fallback
1712 |. load_got ldexp
1713 | .FPU ldc1 FARG1, 0(BASE)
1714 | call_extern
1715 |. lw CARG2, 8+LO(BASE)
1716 | b ->fff_resn
1717 |. nop
1718 |
1719 |.ffunc_n math_frexp
1720 | load_got frexp
1721 | ld PC, FRAME_PC(BASE)
1722 | call_extern
1723 |. daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
1724 | lw TMP1, DISPATCH_GL(tmptv)(DISPATCH)
1725 | daddiu RA, BASE, -16
1726 |.if FPU
1727 | mtc1 TMP1, FARG2
1728 | sdc1 FRET1, 0(RA)
1729 | cvt.d.w FARG2, FARG2
1730 | sdc1 FARG2, 8(RA)
1731 |.else
1732 | sd CRET1, 0(RA)
1733 | zextw TMP1, TMP1
1734 | settp TMP1, TISNUM
1735 | sd TMP1, 8(RA)
1736 |.endif
1737 | b ->fff_res
1738 |. li RD, (2+1)*8
1739 |
1740 |.ffunc_n math_modf
1741 | load_got modf
1742 | ld PC, FRAME_PC(BASE)
1743 | call_extern
1744 |. daddiu CARG2, BASE, -16
1745 | daddiu RA, BASE, -16
1746 |.if FPU
1747 | sdc1 FRET1, -8(BASE)
1748 |.else
1749 | sd CRET1, -8(BASE)
1750 |.endif
1751 | b ->fff_res
1752 |. li RD, (2+1)*8
1753 |
1754 |.macro math_minmax, name, intins, fpins
1755 | .ffunc_1 name
1756 | daddu TMP3, BASE, NARGS8:RC
1757 | checkint CARG1, >5
1758 |. daddiu TMP2, BASE, 8
1759 |1: // Handle integers.
1760 | beq TMP2, TMP3, ->fff_restv
1761 |. ld CARG2, 0(TMP2)
1762 | checkint CARG2, >3
1763 |. sextw CARG1, CARG1
1764 | lw CARG2, LO(TMP2)
1765 |. slt AT, CARG1, CARG2
1766 | intins CARG1, CARG2, AT
1767 | daddiu TMP2, TMP2, 8
1768 | zextw CARG1, CARG1
1769 | b <1
1770 |. settp CARG1, TISNUM
1771 |
1772 |3: // Convert intermediate result to number and continue with number loop.
1773 | checknum CARG2, ->fff_fallback
1774 |.if FPU
1775 |. mtc1 CARG1, FRET1
1776 | cvt.d.w FRET1, FRET1
1777 | b >7
1778 |. ldc1 FARG1, 0(TMP2)
1779 |.else
1780 |. nop
1781 | bal ->vm_sfi2d_1
1782 |. nop
1783 | b >7
1784 |. nop
1785 |.endif
1786 |
1787 |5:
1788 | .FPU ldc1 FRET1, 0(BASE)
1789 | checknum CARG1, ->fff_fallback
1790 |6: // Handle numbers.
1791 |. ld CARG2, 0(TMP2)
1792 | beq TMP2, TMP3, ->fff_resn
1793 |.if FPU
1794 | ldc1 FARG1, 0(TMP2)
1795 |.else
1796 | move CRET1, CARG1
1797 |.endif
1798 | checknum CARG2, >8
1799 |. nop
1800 |7:
1801 |.if FPU
1802 | c.olt.d FRET1, FARG1
1803 | fpins FRET1, FARG1
1804 |.else
1805 | bal ->vm_sfcmpolt
1806 |. nop
1807 | intins CARG1, CARG2, CRET1
1808 |.endif
1809 | b <6
1810 |. daddiu TMP2, TMP2, 8
1811 |
1812 |8: // Convert integer to number and continue with number loop.
1813 | checkint CARG2, ->fff_fallback
1814 |.if FPU
1815 |. lwc1 FARG1, LO(TMP2)
1816 | b <7
1817 |. cvt.d.w FARG1, FARG1
1818 |.else
1819 |. lw CARG2, LO(TMP2)
1820 | bal ->vm_sfi2d_2
1821 |. nop
1822 | b <7
1823 |. nop
1824 |.endif
1825 |
1826 |.endmacro
1827 |
1828 | math_minmax math_min, movz, movf.d
1829 | math_minmax math_max, movn, movt.d
1830 |
1831 |//-- String library -----------------------------------------------------
1832 |
1833 |.ffunc string_byte // Only handle the 1-arg case here.
1834 | ld CARG1, 0(BASE)
1835 | gettp TMP0, CARG1
1836 | xori AT, NARGS8:RC, 8
1837 | daddiu TMP0, TMP0, -LJ_TSTR
1838 | or AT, AT, TMP0
1839 | bnez AT, ->fff_fallback // Need exactly 1 string argument.
1840 |. cleartp STR:CARG1
1841 | lw TMP0, STR:CARG1->len
1842 | daddiu RA, BASE, -16
1843 | ld PC, FRAME_PC(BASE)
1844 | sltu RD, r0, TMP0
1845 | lbu TMP1, STR:CARG1[1] // Access is always ok (NUL at end).
1846 | addiu RD, RD, 1
1847 | sll RD, RD, 3 // RD = ((str->len != 0)+1)*8
1848 | settp TMP1, TISNUM
1849 | b ->fff_res
1850 |. sd TMP1, 0(RA)
1851 |
1852 |.ffunc string_char // Only handle the 1-arg case here.
1853 | ffgccheck
1854 |. nop
1855 | ld CARG1, 0(BASE)
1856 | gettp TMP0, CARG1
1857 | xori AT, NARGS8:RC, 8 // Exactly 1 argument.
1858 | daddiu TMP0, TMP0, -LJ_TISNUM // Integer.
1859 | li TMP1, 255
1860 | sextw CARG1, CARG1
1861 | or AT, AT, TMP0
1862 | sltu TMP1, TMP1, CARG1 // !(255 < n).
1863 | or AT, AT, TMP1
1864 | bnez AT, ->fff_fallback
1865 |. li CARG3, 1
1866 | daddiu CARG2, sp, TMPD_OFS
1867 | sb CARG1, TMPD
1868 |->fff_newstr:
1869 | load_got lj_str_new
1870 | sd BASE, L->base
1871 | sd PC, SAVE_PC
1872 | call_intern lj_str_new // (lua_State *L, char *str, size_t l)
1873 |. move CARG1, L
1874 | // Returns GCstr *.
1875 | ld BASE, L->base
1876 |->fff_resstr:
1877 | li AT, LJ_TSTR
1878 | settp CRET1, AT
1879 | b ->fff_restv
1880 |. move CARG1, CRET1
1881 |
1882 |.ffunc string_sub
1883 | ffgccheck
1884 |. nop
1885 | addiu AT, NARGS8:RC, -16
1886 | ld TMP0, 0(BASE)
1887 | bltz AT, ->fff_fallback
1888 |. gettp TMP3, TMP0
1889 | cleartp STR:CARG1, TMP0
1890 | ld CARG2, 8(BASE)
1891 | beqz AT, >1
1892 |. li CARG4, -1
1893 | ld CARG3, 16(BASE)
1894 | checkint CARG3, ->fff_fallback
1895 |. sextw CARG4, CARG3
1896 |1:
1897 | checkint CARG2, ->fff_fallback
1898 |. li AT, LJ_TSTR
1899 | bne TMP3, AT, ->fff_fallback
1900 |. sextw CARG3, CARG2
1901 | lw CARG2, STR:CARG1->len
1902 | // STR:CARG1 = str, CARG2 = str->len, CARG3 = start, CARG4 = end
1903 | slt AT, CARG4, r0
1904 | addiu TMP0, CARG2, 1
1905 | addu TMP1, CARG4, TMP0
1906 | slt TMP3, CARG3, r0
1907 | movn CARG4, TMP1, AT // if (end < 0) end += len+1
1908 | addu TMP1, CARG3, TMP0
1909 | movn CARG3, TMP1, TMP3 // if (start < 0) start += len+1
1910 | li TMP2, 1
1911 | slt AT, CARG4, r0
1912 | slt TMP3, r0, CARG3
1913 | movn CARG4, r0, AT // if (end < 0) end = 0
1914 | movz CARG3, TMP2, TMP3 // if (start < 1) start = 1
1915 | slt AT, CARG2, CARG4
1916 | movn CARG4, CARG2, AT // if (end > len) end = len
1917 | daddu CARG2, STR:CARG1, CARG3
1918 | subu CARG3, CARG4, CARG3 // len = end - start
1919 | daddiu CARG2, CARG2, sizeof(GCstr)-1
1920 | bgez CARG3, ->fff_newstr
1921 |. addiu CARG3, CARG3, 1 // len++
1922 |->fff_emptystr: // Return empty string.
1923 | li AT, LJ_TSTR
1924 | daddiu STR:CARG1, DISPATCH, DISPATCH_GL(strempty)
1925 | b ->fff_restv
1926 |. settp CARG1, AT
1927 |
1928 |.macro ffstring_op, name
1929 | .ffunc string_ .. name
1930 | ffgccheck
1931 |. nop
1932 | beqz NARGS8:RC, ->fff_fallback
1933 |. ld CARG2, 0(BASE)
1934 | checkstr STR:CARG2, ->fff_fallback
1935 | daddiu SBUF:CARG1, DISPATCH, DISPATCH_GL(tmpbuf)
1936 | load_got lj_buf_putstr_ .. name
1937 | ld TMP0, SBUF:CARG1->b
1938 | sd L, SBUF:CARG1->L
1939 | sd BASE, L->base
1940 | sd TMP0, SBUF:CARG1->p
1941 | call_intern extern lj_buf_putstr_ .. name
1942 |. sd PC, SAVE_PC
1943 | load_got lj_buf_tostr
1944 | call_intern lj_buf_tostr
1945 |. move SBUF:CARG1, SBUF:CRET1
1946 | b ->fff_resstr
1947 |. ld BASE, L->base
1948 |.endmacro
1949 |
1950 |ffstring_op reverse
1951 |ffstring_op lower
1952 |ffstring_op upper
1953 |
1954 |//-- Bit library --------------------------------------------------------
1955 |
1956 |->vm_tobit_fb:
1957 | beqz TMP1, ->fff_fallback
1958 |.if FPU
1959 |. ldc1 FARG1, 0(BASE)
1960 | add.d FARG1, FARG1, TOBIT
1961 | mfc1 CRET1, FARG1
1962 | jr ra
1963 |. zextw CRET1, CRET1
1964 |.else
1965 |// FP number to bit conversion for soft-float.
1966 |->vm_tobit:
1967 | dsll TMP0, CARG1, 1
1968 | li CARG3, 1076
1969 | dsrl AT, TMP0, 53
1970 | dsubu CARG3, CARG3, AT
1971 | sltiu AT, CARG3, 54
1972 | beqz AT, >1
1973 |. dextm TMP0, TMP0, 0, 20
1974 | dinsu TMP0, AT, 21, 21
1975 | slt AT, CARG1, r0
1976 | dsrlv CRET1, TMP0, CARG3
1977 | dsubu TMP0, r0, CRET1
1978 | movn CRET1, TMP0, AT
1979 | jr ra
1980 |. zextw CRET1, CRET1
1981 |1:
1982 | jr ra
1983 |. move CRET1, r0
1984 |
1985 |// FP number to int conversion with a check for soft-float.
1986 |// Modifies CARG1, CRET1, CRET2, TMP0, AT.
1987 |->vm_tointg:
1988 |.if JIT
1989 | dsll CRET2, CARG1, 1
1990 | beqz CRET2, >2
1991 |. li TMP0, 1076
1992 | dsrl AT, CRET2, 53
1993 | dsubu TMP0, TMP0, AT
1994 | sltiu AT, TMP0, 54
1995 | beqz AT, >1
1996 |. dextm CRET2, CRET2, 0, 20
1997 | dinsu CRET2, AT, 21, 21
1998 | slt AT, CARG1, r0
1999 | dsrlv CRET1, CRET2, TMP0
2000 | dsubu CARG1, r0, CRET1
2001 | movn CRET1, CARG1, AT
2002 | li CARG1, 64
2003 | subu TMP0, CARG1, TMP0
2004 | dsllv CRET2, CRET2, TMP0 // Integer check.
2005 | sextw AT, CRET1
2006 | xor AT, CRET1, AT // Range check.
2007 | jr ra
2008 |. movz CRET2, AT, CRET2
2009 |1:
2010 | jr ra
2011 |. li CRET2, 1
2012 |2:
2013 | jr ra
2014 |. move CRET1, r0
2015 |.endif
2016 |.endif
2017 |
2018 |.macro .ffunc_bit, name
2019 | .ffunc_1 bit_..name
2020 | gettp TMP0, CARG1
2021 | beq TMP0, TISNUM, >6
2022 |. zextw CRET1, CARG1
2023 | bal ->vm_tobit_fb
2024 |. sltiu TMP1, TMP0, LJ_TISNUM
2025 |6:
2026 |.endmacro
2027 |
2028 |.macro .ffunc_bit_op, name, bins
2029 | .ffunc_bit name
2030 | daddiu TMP2, BASE, 8
2031 | daddu TMP3, BASE, NARGS8:RC
2032 |1:
2033 | beq TMP2, TMP3, ->fff_resi
2034 |. ld CARG1, 0(TMP2)
2035 | gettp TMP0, CARG1
2036 |.if FPU
2037 | bne TMP0, TISNUM, >2
2038 |. daddiu TMP2, TMP2, 8
2039 | zextw CARG1, CARG1
2040 | b <1
2041 |. bins CRET1, CRET1, CARG1
2042 |2:
2043 | ldc1 FARG1, -8(TMP2)
2044 | sltiu AT, TMP0, LJ_TISNUM
2045 | beqz AT, ->fff_fallback
2046 |. add.d FARG1, FARG1, TOBIT
2047 | mfc1 CARG1, FARG1
2048 | zextw CARG1, CARG1
2049 | b <1
2050 |. bins CRET1, CRET1, CARG1
2051 |.else
2052 | beq TMP0, TISNUM, >2
2053 |. move CRET2, CRET1
2054 | bal ->vm_tobit_fb
2055 |. sltiu TMP1, TMP0, LJ_TISNUM
2056 | move CARG1, CRET2
2057 |2:
2058 | zextw CARG1, CARG1
2059 | bins CRET1, CRET1, CARG1
2060 | b <1
2061 |. daddiu TMP2, TMP2, 8
2062 |.endif
2063 |.endmacro
2064 |
2065 |.ffunc_bit_op band, and
2066 |.ffunc_bit_op bor, or
2067 |.ffunc_bit_op bxor, xor
2068 |
2069 |.ffunc_bit bswap
2070 | dsrl TMP0, CRET1, 8
2071 | dsrl TMP1, CRET1, 24
2072 | andi TMP2, TMP0, 0xff00
2073 | dins TMP1, CRET1, 24, 31
2074 | dins TMP2, TMP0, 16, 23
2075 | b ->fff_resi
2076 |. or CRET1, TMP1, TMP2
2077 |
2078 |.ffunc_bit bnot
2079 | not CRET1, CRET1
2080 | b ->fff_resi
2081 |. zextw CRET1, CRET1
2082 |
2083 |.macro .ffunc_bit_sh, name, shins, shmod
2084 | .ffunc_2 bit_..name
2085 | gettp TMP0, CARG1
2086 | beq TMP0, TISNUM, >1
2087 |. nop
2088 | bal ->vm_tobit_fb
2089 |. sltiu TMP1, TMP0, LJ_TISNUM
2090 | move CARG1, CRET1
2091 |1:
2092 | gettp TMP0, CARG2
2093 | bne TMP0, TISNUM, ->fff_fallback
2094 |. zextw CARG2, CARG2
2095 | sextw CARG1, CARG1
2096 |.if shmod == 1
2097 | negu CARG2, CARG2
2098 |.endif
2099 | shins CRET1, CARG1, CARG2
2100 | b ->fff_resi
2101 |. zextw CRET1, CRET1
2102 |.endmacro
2103 |
2104 |.ffunc_bit_sh lshift, sllv, 0
2105 |.ffunc_bit_sh rshift, srlv, 0
2106 |.ffunc_bit_sh arshift, srav, 0
2107 |.ffunc_bit_sh rol, rotrv, 1
2108 |.ffunc_bit_sh ror, rotrv, 0
2109 |
2110 |.ffunc_bit tobit
2111 |->fff_resi:
2112 | ld PC, FRAME_PC(BASE)
2113 | daddiu RA, BASE, -16
2114 | settp CRET1, TISNUM
2115 | b ->fff_res1
2116 |. sd CRET1, -16(BASE)
2117 |
2118 |//-----------------------------------------------------------------------
2119 |->fff_fallback: // Call fast function fallback handler.
2120 | // BASE = new base, RB = CFUNC, RC = nargs*8
2121 | ld TMP3, CFUNC:RB->f
2122 | daddu TMP1, BASE, NARGS8:RC
2123 | ld PC, FRAME_PC(BASE) // Fallback may overwrite PC.
2124 | daddiu TMP0, TMP1, 8*LUA_MINSTACK
2125 | ld TMP2, L->maxstack
2126 | sd PC, SAVE_PC // Redundant (but a defined value).
2127 | sltu AT, TMP2, TMP0
2128 | sd BASE, L->base
2129 | sd TMP1, L->top
2130 | bnez AT, >5 // Need to grow stack.
2131 |. move CFUNCADDR, TMP3
2132 | jalr TMP3 // (lua_State *L)
2133 |. move CARG1, L
2134 | // Either throws an error, or recovers and returns -1, 0 or nresults+1.
2135 | ld BASE, L->base
2136 | sll RD, CRET1, 3
2137 | bgtz CRET1, ->fff_res // Returned nresults+1?
2138 |. daddiu RA, BASE, -16
2139 |1: // Returned 0 or -1: retry fast path.
2140 | ld LFUNC:RB, FRAME_FUNC(BASE)
2141 | ld TMP0, L->top
2142 | cleartp LFUNC:RB
2143 | bnez CRET1, ->vm_call_tail // Returned -1?
2144 |. dsubu NARGS8:RC, TMP0, BASE
2145 | ins_callt // Returned 0: retry fast path.
2146 |
2147 |// Reconstruct previous base for vmeta_call during tailcall.
2148 |->vm_call_tail:
2149 | andi TMP0, PC, FRAME_TYPE
2150 | li AT, -4
2151 | bnez TMP0, >3
2152 |. and TMP1, PC, AT
2153 | lbu TMP1, OFS_RA(PC)
2154 | sll TMP1, TMP1, 3
2155 | addiu TMP1, TMP1, 16
2156 |3:
2157 | b ->vm_call_dispatch // Resolve again for tailcall.
2158 |. dsubu TMP2, BASE, TMP1
2159 |
2160 |5: // Grow stack for fallback handler.
2161 | load_got lj_state_growstack
2162 | li CARG2, LUA_MINSTACK
2163 | call_intern lj_state_growstack // (lua_State *L, int n)
2164 |. move CARG1, L
2165 | ld BASE, L->base
2166 | b <1
2167 |. li CRET1, 0 // Force retry.
2168 |
2169 |->fff_gcstep: // Call GC step function.
2170 | // BASE = new base, RC = nargs*8
2171 | move MULTRES, ra
2172 | load_got lj_gc_step
2173 | sd BASE, L->base
2174 | daddu TMP0, BASE, NARGS8:RC
2175 | sd PC, SAVE_PC // Redundant (but a defined value).
2176 | sd TMP0, L->top
2177 | call_intern lj_gc_step // (lua_State *L)
2178 |. move CARG1, L
2179 | ld BASE, L->base
2180 | move ra, MULTRES
2181 | ld TMP0, L->top
2182 | ld CFUNC:RB, FRAME_FUNC(BASE)
2183 | cleartp CFUNC:RB
2184 | jr ra
2185 |. dsubu NARGS8:RC, TMP0, BASE
2186 |
2187 |//-----------------------------------------------------------------------
2188 |//-- Special dispatch targets -------------------------------------------
2189 |//-----------------------------------------------------------------------
2190 |
2191 |->vm_record: // Dispatch target for recording phase.
2192 |.if JIT
2193 | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2194 | andi AT, TMP3, HOOK_VMEVENT // No recording while in vmevent.
2195 | bnez AT, >5
2196 | // Decrement the hookcount for consistency, but always do the call.
2197 |. lw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2198 | andi AT, TMP3, HOOK_ACTIVE
2199 | bnez AT, >1
2200 |. addiu TMP2, TMP2, -1
2201 | andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT
2202 | beqz AT, >1
2203 |. nop
2204 | b >1
2205 |. sw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2206 |.endif
2207 |
2208 |->vm_rethook: // Dispatch target for return hooks.
2209 | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2210 | andi AT, TMP3, HOOK_ACTIVE // Hook already active?
2211 | beqz AT, >1
2212 |5: // Re-dispatch to static ins.
2213 |. ld AT, GG_DISP2STATIC(TMP0) // Assumes TMP0 holds DISPATCH+OP*4.
2214 | jr AT
2215 |. nop
2216 |
2217 |->vm_inshook: // Dispatch target for instr/line hooks.
2218 | lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2219 | lw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2220 | andi AT, TMP3, HOOK_ACTIVE // Hook already active?
2221 | bnez AT, <5
2222 |. andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT
2223 | beqz AT, <5
2224 |. addiu TMP2, TMP2, -1
2225 | beqz TMP2, >1
2226 |. sw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2227 | andi AT, TMP3, LUA_MASKLINE
2228 | beqz AT, <5
2229 |1:
2230 |. load_got lj_dispatch_ins
2231 | sw MULTRES, SAVE_MULTRES
2232 | move CARG2, PC
2233 | sd BASE, L->base
2234 | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
2235 | call_intern lj_dispatch_ins // (lua_State *L, const BCIns *pc)
2236 |. move CARG1, L
2237 |3:
2238 | ld BASE, L->base
2239 |4: // Re-dispatch to static ins.
2240 | lw INS, -4(PC)
2241 | decode_OP8a TMP1, INS
2242 | decode_OP8b TMP1
2243 | daddu TMP0, DISPATCH, TMP1
2244 | decode_RD8a RD, INS
2245 | ld AT, GG_DISP2STATIC(TMP0)
2246 | decode_RA8a RA, INS
2247 | decode_RD8b RD
2248 | jr AT
2249 | decode_RA8b RA
2250 |
2251 |->cont_hook: // Continue from hook yield.
2252 | daddiu PC, PC, 4
2253 | b <4
2254 |. lw MULTRES, -24+LO(RB) // Restore MULTRES for *M ins.
2255 |
2256 |->vm_hotloop: // Hot loop counter underflow.
2257 |.if JIT
2258 | ld LFUNC:TMP1, FRAME_FUNC(BASE)
2259 | daddiu CARG1, DISPATCH, GG_DISP2J
2260 | cleartp LFUNC:TMP1
2261 | sd PC, SAVE_PC
2262 | ld TMP1, LFUNC:TMP1->pc
2263 | move CARG2, PC
2264 | sd L, DISPATCH_J(L)(DISPATCH)
2265 | lbu TMP1, PC2PROTO(framesize)(TMP1)
2266 | load_got lj_trace_hot
2267 | sd BASE, L->base
2268 | dsll TMP1, TMP1, 3
2269 | daddu TMP1, BASE, TMP1
2270 | call_intern lj_trace_hot // (jit_State *J, const BCIns *pc)
2271 |. sd TMP1, L->top
2272 | b <3
2273 |. nop
2274 |.endif
2275 |
2276 |
2277 |->vm_callhook: // Dispatch target for call hooks.
2278 |.if JIT
2279 | b >1
2280 |.endif
2281 |. move CARG2, PC
2282 |
2283 |->vm_hotcall: // Hot call counter underflow.
2284 |.if JIT
2285 | ori CARG2, PC, 1
2286 |1:
2287 |.endif
2288 | load_got lj_dispatch_call
2289 | daddu TMP0, BASE, RC
2290 | sd PC, SAVE_PC
2291 | sd BASE, L->base
2292 | dsubu RA, RA, BASE
2293 | sd TMP0, L->top
2294 | call_intern lj_dispatch_call // (lua_State *L, const BCIns *pc)
2295 |. move CARG1, L
2296 | // Returns ASMFunction.
2297 | ld BASE, L->base
2298 | ld TMP0, L->top
2299 | sd r0, SAVE_PC // Invalidate for subsequent line hook.
2300 | dsubu NARGS8:RC, TMP0, BASE
2301 | daddu RA, BASE, RA
2302 | ld LFUNC:RB, FRAME_FUNC(BASE)
2303 | cleartp LFUNC:RB
2304 | jr CRET1
2305 |. lw INS, -4(PC)
2306 |
2307 |->cont_stitch: // Trace stitching.
2308 |.if JIT
2309 | // RA = resultptr, RB = meta base
2310 | lw INS, -4(PC)
2311 | ld TRACE:TMP2, -40(RB) // Save previous trace.
2312 | decode_RA8a RC, INS
2313 | daddiu AT, MULTRES, -8
2314 | cleartp TRACE:TMP2
2315 | decode_RA8b RC
2316 | beqz AT, >2
2317 |. daddu RC, BASE, RC // Call base.
2318 |1: // Move results down.
2319 | ld CARG1, 0(RA)
2320 | daddiu AT, AT, -8
2321 | daddiu RA, RA, 8
2322 | sd CARG1, 0(RC)
2323 | bnez AT, <1
2324 |. daddiu RC, RC, 8
2325 |2:
2326 | decode_RA8a RA, INS
2327 | decode_RB8a RB, INS
2328 | decode_RA8b RA
2329 | decode_RB8b RB
2330 | daddu RA, RA, RB
2331 | daddu RA, BASE, RA
2332 |3:
2333 | sltu AT, RC, RA
2334 | bnez AT, >9 // More results wanted?
2335 |. nop
2336 |
2337 | lhu TMP3, TRACE:TMP2->traceno
2338 | lhu RD, TRACE:TMP2->link
2339 | beq RD, TMP3, ->cont_nop // Blacklisted.
2340 |. load_got lj_dispatch_stitch
2341 | bnez RD, =>BC_JLOOP // Jump to stitched trace.
2342 |. sll RD, RD, 3
2343 |
2344 | // Stitch a new trace to the previous trace.
2345 | sw TMP3, DISPATCH_J(exitno)(DISPATCH)
2346 | sd L, DISPATCH_J(L)(DISPATCH)
2347 | sd BASE, L->base
2348 | daddiu CARG1, DISPATCH, GG_DISP2J
2349 | call_intern lj_dispatch_stitch // (jit_State *J, const BCIns *pc)
2350 |. move CARG2, PC
2351 | b ->cont_nop
2352 |. ld BASE, L->base
2353 |
2354 |9:
2355 | sd TISNIL, 0(RC)
2356 | b <3
2357 |. daddiu RC, RC, 8
2358 |.endif
2359 |
2360 |->vm_profhook: // Dispatch target for profiler hook.
2361#if LJ_HASPROFILE
2362 | load_got lj_dispatch_profile
2363 | sw MULTRES, SAVE_MULTRES
2364 | move CARG2, PC
2365 | sd BASE, L->base
2366 | call_intern lj_dispatch_profile // (lua_State *L, const BCIns *pc)
2367 |. move CARG1, L
2368 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2369 | daddiu PC, PC, -4
2370 | b ->cont_nop
2371 |. ld BASE, L->base
2372#endif
2373 |
2374 |//-----------------------------------------------------------------------
2375 |//-- Trace exit handler -------------------------------------------------
2376 |//-----------------------------------------------------------------------
2377 |
2378 |.macro savex_, a, b
2379 |.if FPU
2380 | sdc1 f..a, a*8(sp)
2381 | sdc1 f..b, b*8(sp)
2382 | sd r..a, 32*8+a*8(sp)
2383 | sd r..b, 32*8+b*8(sp)
2384 |.else
2385 | sd r..a, a*8(sp)
2386 | sd r..b, b*8(sp)
2387 |.endif
2388 |.endmacro
2389 |
2390 |->vm_exit_handler:
2391 |.if JIT
2392 |.if FPU
2393 | daddiu sp, sp, -(32*8+32*8)
2394 |.else
2395 | daddiu sp, sp, -(32*8)
2396 |.endif
2397 | savex_ 0, 1
2398 | savex_ 2, 3
2399 | savex_ 4, 5
2400 | savex_ 6, 7
2401 | savex_ 8, 9
2402 | savex_ 10, 11
2403 | savex_ 12, 13
2404 | savex_ 14, 15
2405 | savex_ 16, 17
2406 | savex_ 18, 19
2407 | savex_ 20, 21
2408 | savex_ 22, 23
2409 | savex_ 24, 25
2410 | savex_ 26, 27
2411 | savex_ 28, 30
2412 |.if FPU
2413 | sdc1 f29, 29*8(sp)
2414 | sdc1 f31, 31*8(sp)
2415 | sd r0, 32*8+31*8(sp) // Clear RID_TMP.
2416 | daddiu TMP2, sp, 32*8+32*8 // Recompute original value of sp.
2417 | sd TMP2, 32*8+29*8(sp) // Store sp in RID_SP
2418 |.else
2419 | sd r0, 31*8(sp) // Clear RID_TMP.
2420 | daddiu TMP2, sp, 32*8 // Recompute original value of sp.
2421 | sd TMP2, 29*8(sp) // Store sp in RID_SP
2422 |.endif
2423 | li_vmstate EXIT
2424 | daddiu DISPATCH, JGL, -GG_DISP2G-32768
2425 | lw TMP1, 0(TMP2) // Load exit number.
2426 | st_vmstate
2427 | ld L, DISPATCH_GL(cur_L)(DISPATCH)
2428 | ld BASE, DISPATCH_GL(jit_base)(DISPATCH)
2429 | load_got lj_trace_exit
2430 | sd L, DISPATCH_J(L)(DISPATCH)
2431 | sw ra, DISPATCH_J(parent)(DISPATCH) // Store trace number.
2432 | sd BASE, L->base
2433 | sw TMP1, DISPATCH_J(exitno)(DISPATCH) // Store exit number.
2434 | daddiu CARG1, DISPATCH, GG_DISP2J
2435 | sd r0, DISPATCH_GL(jit_base)(DISPATCH)
2436 | call_intern lj_trace_exit // (jit_State *J, ExitState *ex)
2437 |. move CARG2, sp
2438 | // Returns MULTRES (unscaled) or negated error code.
2439 | ld TMP1, L->cframe
2440 | li AT, -4
2441 | ld BASE, L->base
2442 | and sp, TMP1, AT
2443 | ld PC, SAVE_PC // Get SAVE_PC.
2444 | b >1
2445 |. sd L, SAVE_L // Set SAVE_L (on-trace resume/yield).
2446 |.endif
2447 |->vm_exit_interp:
2448 |.if JIT
2449 | // CRET1 = MULTRES or negated error code, BASE, PC and JGL set.
2450 | ld L, SAVE_L
2451 | daddiu DISPATCH, JGL, -GG_DISP2G-32768
2452 | sd BASE, L->base
2453 |1:
2454 | bltz CRET1, >9 // Check for error from exit.
2455 |. ld LFUNC:RB, FRAME_FUNC(BASE)
2456 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float).
2457 | dsll MULTRES, CRET1, 3
2458 | cleartp LFUNC:RB
2459 | sw MULTRES, SAVE_MULTRES
2460 | li TISNIL, LJ_TNIL
2461 | li TISNUM, LJ_TISNUM // Setup type comparison constants.
2462 | .FPU mtc1 TMP3, TOBIT
2463 | ld TMP1, LFUNC:RB->pc
2464 | sd r0, DISPATCH_GL(jit_base)(DISPATCH)
2465 | ld KBASE, PC2PROTO(k)(TMP1)
2466 | .FPU cvt.d.s TOBIT, TOBIT
2467 | // Modified copy of ins_next which handles function header dispatch, too.
2468 | lw INS, 0(PC)
2469 | daddiu PC, PC, 4
2470 | // Assumes TISNIL == ~LJ_VMST_INTERP == -1
2471 | sw TISNIL, DISPATCH_GL(vmstate)(DISPATCH)
2472 | decode_OP8a TMP1, INS
2473 | decode_OP8b TMP1
2474 | sltiu TMP2, TMP1, BC_FUNCF*8
2475 | daddu TMP0, DISPATCH, TMP1
2476 | decode_RD8a RD, INS
2477 | ld AT, 0(TMP0)
2478 | decode_RA8a RA, INS
2479 | beqz TMP2, >2
2480 |. decode_RA8b RA
2481 | jr AT
2482 |. decode_RD8b RD
2483 |2:
2484 | sltiu TMP2, TMP1, (BC_FUNCC+2)*8 // Fast function?
2485 | bnez TMP2, >3
2486 |. ld TMP1, FRAME_PC(BASE)
2487 | // Check frame below fast function.
2488 | andi TMP0, TMP1, FRAME_TYPE
2489 | bnez TMP0, >3 // Trace stitching continuation?
2490 |. nop
2491 | // Otherwise set KBASE for Lua function below fast function.
2492 | lw TMP2, -4(TMP1)
2493 | decode_RA8a TMP0, TMP2
2494 | decode_RA8b TMP0
2495 | dsubu TMP1, BASE, TMP0
2496 | ld LFUNC:TMP2, -32(TMP1)
2497 | cleartp LFUNC:TMP2
2498 | ld TMP1, LFUNC:TMP2->pc
2499 | ld KBASE, PC2PROTO(k)(TMP1)
2500 |3:
2501 | daddiu RC, MULTRES, -8
2502 | jr AT
2503 |. daddu RA, RA, BASE
2504 |
2505 |9: // Rethrow error from the right C frame.
2506 | load_got lj_err_throw
2507 | negu CARG2, CRET1
2508 | call_intern lj_err_throw // (lua_State *L, int errcode)
2509 |. move CARG1, L
2510 |.endif
2511 |
2512 |//-----------------------------------------------------------------------
2513 |//-- Math helper functions ----------------------------------------------
2514 |//-----------------------------------------------------------------------
2515 |
2516 |// Hard-float round to integer.
2517 |// Modifies AT, TMP0, FRET1, FRET2, f4. Keeps all others incl. FARG1.
2518 |.macro vm_round_hf, func
2519 | lui TMP0, 0x4330 // Hiword of 2^52 (double).
2520 | dsll TMP0, TMP0, 32
2521 | dmtc1 TMP0, f4
2522 | abs.d FRET2, FARG1 // |x|
2523 | dmfc1 AT, FARG1
2524 | c.olt.d 0, FRET2, f4
2525 | add.d FRET1, FRET2, f4 // (|x| + 2^52) - 2^52
2526 | bc1f 0, >1 // Truncate only if |x| < 2^52.
2527 |. sub.d FRET1, FRET1, f4
2528 | slt AT, AT, r0
2529 |.if "func" == "ceil"
2530 | lui TMP0, 0xbff0 // Hiword of -1 (double). Preserves -0.
2531 |.else
2532 | lui TMP0, 0x3ff0 // Hiword of +1 (double).
2533 |.endif
2534 |.if "func" == "trunc"
2535 | dsll TMP0, TMP0, 32
2536 | dmtc1 TMP0, f4
2537 | c.olt.d 0, FRET2, FRET1 // |x| < result?
2538 | sub.d FRET2, FRET1, f4
2539 | movt.d FRET1, FRET2, 0 // If yes, subtract +1.
2540 | neg.d FRET2, FRET1
2541 | jr ra
2542 |. movn.d FRET1, FRET2, AT // Merge sign bit back in.
2543 |.else
2544 | neg.d FRET2, FRET1
2545 | dsll TMP0, TMP0, 32
2546 | dmtc1 TMP0, f4
2547 | movn.d FRET1, FRET2, AT // Merge sign bit back in.
2548 |.if "func" == "ceil"
2549 | c.olt.d 0, FRET1, FARG1 // x > result?
2550 |.else
2551 | c.olt.d 0, FARG1, FRET1 // x < result?
2552 |.endif
2553 | sub.d FRET2, FRET1, f4 // If yes, subtract +-1.
2554 | jr ra
2555 |. movt.d FRET1, FRET2, 0
2556 |.endif
2557 |1:
2558 | jr ra
2559 |. mov.d FRET1, FARG1
2560 |.endmacro
2561 |
2562 |.macro vm_round, func
2563 |.if FPU
2564 | vm_round_hf, func
2565 |.endif
2566 |.endmacro
2567 |
2568 |->vm_floor:
2569 | vm_round floor
2570 |->vm_ceil:
2571 | vm_round ceil
2572 |->vm_trunc:
2573 |.if JIT
2574 | vm_round trunc
2575 |.endif
2576 |
2577 |// Soft-float integer to number conversion.
2578 |.macro sfi2d, ARG
2579 |.if not FPU
2580 | beqz ARG, >9 // Handle zero first.
2581 |. sra TMP0, ARG, 31
2582 | xor TMP1, ARG, TMP0
2583 | dsubu TMP1, TMP1, TMP0 // Absolute value in TMP1.
2584 | dclz ARG, TMP1
2585 | addiu ARG, ARG, -11
2586 | li AT, 0x3ff+63-11-1
2587 | dsllv TMP1, TMP1, ARG // Align mantissa left with leading 1.
2588 | subu ARG, AT, ARG // Exponent - 1.
2589 | ins ARG, TMP0, 11, 11 // Sign | Exponent.
2590 | dsll ARG, ARG, 52 // Align left.
2591 | jr ra
2592 |. daddu ARG, ARG, TMP1 // Add mantissa, increment exponent.
2593 |9:
2594 | jr ra
2595 |. nop
2596 |.endif
2597 |.endmacro
2598 |
2599 |// Input CARG1. Output: CARG1. Temporaries: AT, TMP0, TMP1.
2600 |->vm_sfi2d_1:
2601 | sfi2d CARG1
2602 |
2603 |// Input CARG2. Output: CARG2. Temporaries: AT, TMP0, TMP1.
2604 |->vm_sfi2d_2:
2605 | sfi2d CARG2
2606 |
2607 |// Soft-float comparison. Equivalent to c.eq.d.
2608 |// Input: CARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1.
2609 |->vm_sfcmpeq:
2610 |.if not FPU
2611 | dsll AT, CARG1, 1
2612 | dsll TMP0, CARG2, 1
2613 | or TMP1, AT, TMP0
2614 | beqz TMP1, >8 // Both args +-0: return 1.
2615 |. lui TMP1, 0xffe0
2616 | dsll TMP1, TMP1, 32
2617 | sltu AT, TMP1, AT
2618 | sltu TMP0, TMP1, TMP0
2619 | or TMP1, AT, TMP0
2620 | bnez TMP1, >9 // Either arg is NaN: return 0;
2621 |. xor AT, CARG1, CARG2
2622 | jr ra
2623 |. sltiu CRET1, AT, 1 // Same values: return 1.
2624 |8:
2625 | jr ra
2626 |. li CRET1, 1
2627 |9:
2628 | jr ra
2629 |. li CRET1, 0
2630 |.endif
2631 |
2632 |// Soft-float comparison. Equivalent to c.ult.d and c.olt.d.
2633 |// Input: CARG1, CARG2. Output: CRET1. Temporaries: AT, TMP0, TMP1, CRET2.
2634 |->vm_sfcmpult:
2635 |.if not FPU
2636 | b >1
2637 |. li CRET2, 1
2638 |.endif
2639 |
2640 |->vm_sfcmpolt:
2641 |.if not FPU
2642 | li CRET2, 0
2643 |1:
2644 | dsll AT, CARG1, 1
2645 | dsll TMP0, CARG2, 1
2646 | or TMP1, AT, TMP0
2647 | beqz TMP1, >8 // Both args +-0: return 0.
2648 |. lui TMP1, 0xffe0
2649 | dsll TMP1, TMP1, 32
2650 | sltu AT, TMP1, AT
2651 | sltu TMP0, TMP1, TMP0
2652 | or TMP1, AT, TMP0
2653 | bnez TMP1, >9 // Either arg is NaN: return 0 or 1;
2654 |. and AT, CARG1, CARG2
2655 | bltz AT, >5 // Both args negative?
2656 |. nop
2657 | jr ra
2658 |. slt CRET1, CARG1, CARG2
2659 |5: // Swap conditions if both operands are negative.
2660 | jr ra
2661 |. slt CRET1, CARG2, CARG1
2662 |8:
2663 | jr ra
2664 |. li CRET1, 0
2665 |9:
2666 | jr ra
2667 |. move CRET1, CRET2
2668 |.endif
2669 |
2670 |// Soft-float comparison. Equivalent to c.ole.d a, b or c.ole.d b, a.
2671 |// Input: CARG1, CARG2, TMP3. Output: CRET1. Temporaries: AT, TMP0, TMP1.
2672 |->vm_sfcmpolex:
2673 |.if not FPU
2674 | dsll AT, CARG1, 1
2675 | dsll TMP0, CARG2, 1
2676 | or TMP1, AT, TMP0
2677 | beqz TMP1, >8 // Both args +-0: return 1.
2678 |. lui TMP1, 0xffe0
2679 | dsll TMP1, TMP1, 32
2680 | sltu AT, TMP1, AT
2681 | sltu TMP0, TMP1, TMP0
2682 | or TMP1, AT, TMP0
2683 | bnez TMP1, >9 // Either arg is NaN: return 0;
2684 |. and AT, CARG1, CARG2
2685 | xor AT, AT, TMP3
2686 | bltz AT, >5 // Both args negative?
2687 |. nop
2688 | jr ra
2689 |. slt CRET1, CARG2, CARG1
2690 |5: // Swap conditions if both operands are negative.
2691 | jr ra
2692 |. slt CRET1, CARG1, CARG2
2693 |8:
2694 | jr ra
2695 |. li CRET1, 1
2696 |9:
2697 | jr ra
2698 |. li CRET1, 0
2699 |.endif
2700 |
2701 |.macro sfmin_max, name, intins
2702 |->vm_sf .. name:
2703 |.if JIT and not FPU
2704 | move TMP2, ra
2705 | bal ->vm_sfcmpolt
2706 |. nop
2707 | move ra, TMP2
2708 | move TMP0, CRET1
2709 | move CRET1, CARG1
2710 | jr ra
2711 |. intins CRET1, CARG2, TMP0
2712 |.endif
2713 |.endmacro
2714 |
2715 | sfmin_max min, movz
2716 | sfmin_max max, movn
2717 |
2718 |//-----------------------------------------------------------------------
2719 |//-- Miscellaneous functions --------------------------------------------
2720 |//-----------------------------------------------------------------------
2721 |
2722 |//-----------------------------------------------------------------------
2723 |//-- FFI helper functions -----------------------------------------------
2724 |//-----------------------------------------------------------------------
2725 |
2726 |// Handler for callback functions. Callback slot number in r1, g in r2.
2727 |->vm_ffi_callback:
2728 |.if FFI
2729 |.type CTSTATE, CTState, PC
2730 | saveregs
2731 | ld CTSTATE, GL:r2->ctype_state
2732 | daddiu DISPATCH, r2, GG_G2DISP
2733 | load_got lj_ccallback_enter
2734 | sw r1, CTSTATE->cb.slot
2735 | sd CARG1, CTSTATE->cb.gpr[0]
2736 | .FPU sdc1 FARG1, CTSTATE->cb.fpr[0]
2737 | sd CARG2, CTSTATE->cb.gpr[1]
2738 | .FPU sdc1 FARG2, CTSTATE->cb.fpr[1]
2739 | sd CARG3, CTSTATE->cb.gpr[2]
2740 | .FPU sdc1 FARG3, CTSTATE->cb.fpr[2]
2741 | sd CARG4, CTSTATE->cb.gpr[3]
2742 | .FPU sdc1 FARG4, CTSTATE->cb.fpr[3]
2743 | sd CARG5, CTSTATE->cb.gpr[4]
2744 | .FPU sdc1 FARG5, CTSTATE->cb.fpr[4]
2745 | sd CARG6, CTSTATE->cb.gpr[5]
2746 | .FPU sdc1 FARG6, CTSTATE->cb.fpr[5]
2747 | sd CARG7, CTSTATE->cb.gpr[6]
2748 | .FPU sdc1 FARG7, CTSTATE->cb.fpr[6]
2749 | sd CARG8, CTSTATE->cb.gpr[7]
2750 | .FPU sdc1 FARG8, CTSTATE->cb.fpr[7]
2751 | daddiu TMP0, sp, CFRAME_SPACE
2752 | sd TMP0, CTSTATE->cb.stack
2753 | sd r0, SAVE_PC // Any value outside of bytecode is ok.
2754 | move CARG2, sp
2755 | call_intern lj_ccallback_enter // (CTState *cts, void *cf)
2756 |. move CARG1, CTSTATE
2757 | // Returns lua_State *.
2758 | ld BASE, L:CRET1->base
2759 | ld RC, L:CRET1->top
2760 | move L, CRET1
2761 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float).
2762 | ld LFUNC:RB, FRAME_FUNC(BASE)
2763 | .FPU mtc1 TMP3, TOBIT
2764 | li TISNIL, LJ_TNIL
2765 | li TISNUM, LJ_TISNUM
2766 | li_vmstate INTERP
2767 | subu RC, RC, BASE
2768 | cleartp LFUNC:RB
2769 | st_vmstate
2770 | .FPU cvt.d.s TOBIT, TOBIT
2771 | ins_callt
2772 |.endif
2773 |
2774 |->cont_ffi_callback: // Return from FFI callback.
2775 |.if FFI
2776 | load_got lj_ccallback_leave
2777 | ld CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH)
2778 | sd BASE, L->base
2779 | sd RB, L->top
2780 | sd L, CTSTATE->L
2781 | move CARG2, RA
2782 | call_intern lj_ccallback_leave // (CTState *cts, TValue *o)
2783 |. move CARG1, CTSTATE
2784 | .FPU ldc1 FRET1, CTSTATE->cb.fpr[0]
2785 | ld CRET1, CTSTATE->cb.gpr[0]
2786 | .FPU ldc1 FRET2, CTSTATE->cb.fpr[1]
2787 | b ->vm_leave_unw
2788 |. ld CRET2, CTSTATE->cb.gpr[1]
2789 |.endif
2790 |
2791 |->vm_ffi_call: // Call C function via FFI.
2792 | // Caveat: needs special frame unwinding, see below.
2793 |.if FFI
2794 | .type CCSTATE, CCallState, CARG1
2795 | lw TMP1, CCSTATE->spadj
2796 | lbu CARG2, CCSTATE->nsp
2797 | move TMP2, sp
2798 | dsubu sp, sp, TMP1
2799 | sd ra, -8(TMP2)
2800 | sll CARG2, CARG2, 3
2801 | sd r16, -16(TMP2)
2802 | sd CCSTATE, -24(TMP2)
2803 | move r16, TMP2
2804 | daddiu TMP1, CCSTATE, offsetof(CCallState, stack)
2805 | move TMP2, sp
2806 | beqz CARG2, >2
2807 |. daddu TMP3, TMP1, CARG2
2808 |1:
2809 | ld TMP0, 0(TMP1)
2810 | daddiu TMP1, TMP1, 8
2811 | sltu AT, TMP1, TMP3
2812 | sd TMP0, 0(TMP2)
2813 | bnez AT, <1
2814 |. daddiu TMP2, TMP2, 8
2815 |2:
2816 | ld CFUNCADDR, CCSTATE->func
2817 | .FPU ldc1 FARG1, CCSTATE->gpr[0]
2818 | ld CARG2, CCSTATE->gpr[1]
2819 | .FPU ldc1 FARG2, CCSTATE->gpr[1]
2820 | ld CARG3, CCSTATE->gpr[2]
2821 | .FPU ldc1 FARG3, CCSTATE->gpr[2]
2822 | ld CARG4, CCSTATE->gpr[3]
2823 | .FPU ldc1 FARG4, CCSTATE->gpr[3]
2824 | ld CARG5, CCSTATE->gpr[4]
2825 | .FPU ldc1 FARG5, CCSTATE->gpr[4]
2826 | ld CARG6, CCSTATE->gpr[5]
2827 | .FPU ldc1 FARG6, CCSTATE->gpr[5]
2828 | ld CARG7, CCSTATE->gpr[6]
2829 | .FPU ldc1 FARG7, CCSTATE->gpr[6]
2830 | ld CARG8, CCSTATE->gpr[7]
2831 | .FPU ldc1 FARG8, CCSTATE->gpr[7]
2832 | jalr CFUNCADDR
2833 |. ld CARG1, CCSTATE->gpr[0] // Do this last, since CCSTATE is CARG1.
2834 | ld CCSTATE:TMP1, -24(r16)
2835 | ld TMP2, -16(r16)
2836 | ld ra, -8(r16)
2837 | sd CRET1, CCSTATE:TMP1->gpr[0]
2838 | sd CRET2, CCSTATE:TMP1->gpr[1]
2839 |.if FPU
2840 | sdc1 FRET1, CCSTATE:TMP1->fpr[0]
2841 | sdc1 FRET2, CCSTATE:TMP1->fpr[1]
2842 |.else
2843 | sd CARG1, CCSTATE:TMP1->gpr[2] // 2nd FP struct field for soft-float.
2844 |.endif
2845 | move sp, r16
2846 | jr ra
2847 |. move r16, TMP2
2848 |.endif
2849 |// Note: vm_ffi_call must be the last function in this object file!
2850 |
2851 |//-----------------------------------------------------------------------
2852}
2853
2854/* Generate the code for a single instruction. */
2855static void build_ins(BuildCtx *ctx, BCOp op, int defop)
2856{
2857 int vk = 0;
2858 |=>defop:
2859
2860 switch (op) {
2861
2862 /* -- Comparison ops ---------------------------------------------------- */
2863
2864 /* Remember: all ops branch for a true comparison, fall through otherwise. */
2865
2866 case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
2867 | // RA = src1*8, RD = src2*8, JMP with RD = target
2868 |.macro bc_comp, FRA, FRD, ARGRA, ARGRD, movop, fmovop, fcomp, sfcomp
2869 | daddu RA, BASE, RA
2870 | daddu RD, BASE, RD
2871 | ld ARGRA, 0(RA)
2872 | ld ARGRD, 0(RD)
2873 | lhu TMP2, OFS_RD(PC)
2874 | gettp CARG3, ARGRA
2875 | gettp CARG4, ARGRD
2876 | bne CARG3, TISNUM, >2
2877 |. daddiu PC, PC, 4
2878 | bne CARG4, TISNUM, >5
2879 |. decode_RD4b TMP2
2880 | sextw ARGRA, ARGRA
2881 | sextw ARGRD, ARGRD
2882 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
2883 | slt AT, CARG1, CARG2
2884 | addu TMP2, TMP2, TMP3
2885 | movop TMP2, r0, AT
2886 |1:
2887 | daddu PC, PC, TMP2
2888 | ins_next
2889 |
2890 |2: // RA is not an integer.
2891 | sltiu AT, CARG3, LJ_TISNUM
2892 | beqz AT, ->vmeta_comp
2893 |. lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
2894 | sltiu AT, CARG4, LJ_TISNUM
2895 | beqz AT, >4
2896 |. decode_RD4b TMP2
2897 |.if FPU
2898 | ldc1 FRA, 0(RA)
2899 | ldc1 FRD, 0(RD)
2900 |.endif
2901 |3: // RA and RD are both numbers.
2902 |.if FPU
2903 | fcomp f20, f22
2904 | addu TMP2, TMP2, TMP3
2905 | b <1
2906 |. fmovop TMP2, r0
2907 |.else
2908 | bal sfcomp
2909 |. addu TMP2, TMP2, TMP3
2910 | b <1
2911 |. movop TMP2, r0, CRET1
2912 |.endif
2913 |
2914 |4: // RA is a number, RD is not a number.
2915 | bne CARG4, TISNUM, ->vmeta_comp
2916 | // RA is a number, RD is an integer. Convert RD to a number.
2917 |.if FPU
2918 |. lwc1 FRD, LO(RD)
2919 | ldc1 FRA, 0(RA)
2920 | b <3
2921 |. cvt.d.w FRD, FRD
2922 |.else
2923 |.if "ARGRD" == "CARG1"
2924 |. sextw CARG1, CARG1
2925 | bal ->vm_sfi2d_1
2926 |. nop
2927 |.else
2928 |. sextw CARG2, CARG2
2929 | bal ->vm_sfi2d_2
2930 |. nop
2931 |.endif
2932 | b <3
2933 |. nop
2934 |.endif
2935 |
2936 |5: // RA is an integer, RD is not an integer
2937 | sltiu AT, CARG4, LJ_TISNUM
2938 | beqz AT, ->vmeta_comp
2939 |. lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
2940 | // RA is an integer, RD is a number. Convert RA to a number.
2941 |.if FPU
2942 | lwc1 FRA, LO(RA)
2943 | ldc1 FRD, 0(RD)
2944 | b <3
2945 | cvt.d.w FRA, FRA
2946 |.else
2947 |.if "ARGRA" == "CARG1"
2948 | bal ->vm_sfi2d_1
2949 |. sextw CARG1, CARG1
2950 |.else
2951 | bal ->vm_sfi2d_2
2952 |. sextw CARG2, CARG2
2953 |.endif
2954 | b <3
2955 |. nop
2956 |.endif
2957 |.endmacro
2958 |
2959 if (op == BC_ISLT) {
2960 | bc_comp f20, f22, CARG1, CARG2, movz, movf, c.olt.d, ->vm_sfcmpolt
2961 } else if (op == BC_ISGE) {
2962 | bc_comp f20, f22, CARG1, CARG2, movn, movt, c.olt.d, ->vm_sfcmpolt
2963 } else if (op == BC_ISLE) {
2964 | bc_comp f22, f20, CARG2, CARG1, movn, movt, c.ult.d, ->vm_sfcmpult
2965 } else {
2966 | bc_comp f22, f20, CARG2, CARG1, movz, movf, c.ult.d, ->vm_sfcmpult
2967 }
2968 break;
2969
2970 case BC_ISEQV: case BC_ISNEV:
2971 vk = op == BC_ISEQV;
2972 | // RA = src1*8, RD = src2*8, JMP with RD = target
2973 | daddu RA, BASE, RA
2974 | daddiu PC, PC, 4
2975 | daddu RD, BASE, RD
2976 | ld CARG1, 0(RA)
2977 | lhu TMP2, -4+OFS_RD(PC)
2978 | ld CARG2, 0(RD)
2979 | gettp CARG3, CARG1
2980 | gettp CARG4, CARG2
2981 | sltu AT, TISNUM, CARG3
2982 | sltu TMP1, TISNUM, CARG4
2983 | or AT, AT, TMP1
2984 if (vk) {
2985 | beqz AT, ->BC_ISEQN_Z
2986 } else {
2987 | beqz AT, ->BC_ISNEN_Z
2988 }
2989 | // Either or both types are not numbers.
2990 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
2991 |.if FFI
2992 |. li AT, LJ_TCDATA
2993 | beq CARG3, AT, ->vmeta_equal_cd
2994 |.endif
2995 | decode_RD4b TMP2
2996 |.if FFI
2997 | beq CARG4, AT, ->vmeta_equal_cd
2998 |. nop
2999 |.endif
3000 | bne CARG1, CARG2, >2
3001 |. addu TMP2, TMP2, TMP3
3002 | // Tag and value are equal.
3003 if (vk) {
3004 |->BC_ISEQV_Z:
3005 | daddu PC, PC, TMP2
3006 }
3007 |1:
3008 | ins_next
3009 |
3010 |2: // Check if the tags are the same and it's a table or userdata.
3011 | xor AT, CARG3, CARG4 // Same type?
3012 | sltiu TMP0, CARG3, LJ_TISTABUD+1 // Table or userdata?
3013 | movn TMP0, r0, AT
3014 if (vk) {
3015 | beqz TMP0, <1
3016 } else {
3017 | beqz TMP0, ->BC_ISEQV_Z // Reuse code from opposite instruction.
3018 }
3019 | // Different tables or userdatas. Need to check __eq metamethod.
3020 | // Field metatable must be at same offset for GCtab and GCudata!
3021 |. cleartp TAB:TMP1, CARG1
3022 | ld TAB:TMP3, TAB:TMP1->metatable
3023 if (vk) {
3024 | beqz TAB:TMP3, <1 // No metatable?
3025 |. nop
3026 | lbu TMP3, TAB:TMP3->nomm
3027 | andi TMP3, TMP3, 1<<MM_eq
3028 | bnez TMP3, >1 // Or 'no __eq' flag set?
3029 } else {
3030 | beqz TAB:TMP3,->BC_ISEQV_Z // No metatable?
3031 |. nop
3032 | lbu TMP3, TAB:TMP3->nomm
3033 | andi TMP3, TMP3, 1<<MM_eq
3034 | bnez TMP3, ->BC_ISEQV_Z // Or 'no __eq' flag set?
3035 }
3036 |. nop
3037 | b ->vmeta_equal // Handle __eq metamethod.
3038 |. li TMP0, 1-vk // ne = 0 or 1.
3039 break;
3040
3041 case BC_ISEQS: case BC_ISNES:
3042 vk = op == BC_ISEQS;
3043 | // RA = src*8, RD = str_const*8 (~), JMP with RD = target
3044 | daddu RA, BASE, RA
3045 | daddiu PC, PC, 4
3046 | ld CARG1, 0(RA)
3047 | dsubu RD, KBASE, RD
3048 | lhu TMP2, -4+OFS_RD(PC)
3049 | ld CARG2, -8(RD) // KBASE-8-str_const*8
3050 |.if FFI
3051 | gettp TMP0, CARG1
3052 | li AT, LJ_TCDATA
3053 |.endif
3054 | li TMP1, LJ_TSTR
3055 | decode_RD4b TMP2
3056 |.if FFI
3057 | beq TMP0, AT, ->vmeta_equal_cd
3058 |.endif
3059 |. settp CARG2, TMP1
3060 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3061 | xor TMP1, CARG1, CARG2
3062 | addu TMP2, TMP2, TMP3
3063 if (vk) {
3064 | movn TMP2, r0, TMP1
3065 } else {
3066 | movz TMP2, r0, TMP1
3067 }
3068 | daddu PC, PC, TMP2
3069 | ins_next
3070 break;
3071
3072 case BC_ISEQN: case BC_ISNEN:
3073 vk = op == BC_ISEQN;
3074 | // RA = src*8, RD = num_const*8, JMP with RD = target
3075 | daddu RA, BASE, RA
3076 | daddu RD, KBASE, RD
3077 | ld CARG1, 0(RA)
3078 | ld CARG2, 0(RD)
3079 | lhu TMP2, OFS_RD(PC)
3080 | gettp CARG3, CARG1
3081 | gettp CARG4, CARG2
3082 | daddiu PC, PC, 4
3083 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3084 if (vk) {
3085 |->BC_ISEQN_Z:
3086 } else {
3087 |->BC_ISNEN_Z:
3088 }
3089 | bne CARG3, TISNUM, >3
3090 |. decode_RD4b TMP2
3091 | bne CARG4, TISNUM, >6
3092 |. addu TMP2, TMP2, TMP3
3093 | xor AT, CARG1, CARG2
3094 if (vk) {
3095 | movn TMP2, r0, AT
3096 |1:
3097 | daddu PC, PC, TMP2
3098 |2:
3099 } else {
3100 | movz TMP2, r0, AT
3101 |1:
3102 |2:
3103 | daddu PC, PC, TMP2
3104 }
3105 | ins_next
3106 |
3107 |3: // RA is not an integer.
3108 | sltu AT, CARG3, TISNUM
3109 |.if FFI
3110 | beqz AT, >8
3111 |.else
3112 | beqz AT, <2
3113 |.endif
3114 |. addu TMP2, TMP2, TMP3
3115 | sltu AT, CARG4, TISNUM
3116 |.if FPU
3117 | ldc1 f20, 0(RA)
3118 | ldc1 f22, 0(RD)
3119 |.endif
3120 | beqz AT, >5
3121 |. nop
3122 |4: // RA and RD are both numbers.
3123 |.if FPU
3124 | c.eq.d f20, f22
3125 | b <1
3126 if (vk) {
3127 |. movf TMP2, r0
3128 } else {
3129 |. movt TMP2, r0
3130 }
3131 |.else
3132 | bal ->vm_sfcmpeq
3133 |. nop
3134 | b <1
3135 if (vk) {
3136 |. movz TMP2, r0, CRET1
3137 } else {
3138 |. movn TMP2, r0, CRET1
3139 }
3140 |.endif
3141 |
3142 |5: // RA is a number, RD is not a number.
3143 |.if FFI
3144 | bne CARG4, TISNUM, >9
3145 |.else
3146 | bne CARG4, TISNUM, <2
3147 |.endif
3148 | // RA is a number, RD is an integer. Convert RD to a number.
3149 |.if FPU
3150 |. lwc1 f22, LO(RD)
3151 | b <4
3152 |. cvt.d.w f22, f22
3153 |.else
3154 |. sextw CARG2, CARG2
3155 | bal ->vm_sfi2d_2
3156 |. nop
3157 | b <4
3158 |. nop
3159 |.endif
3160 |
3161 |6: // RA is an integer, RD is not an integer
3162 | sltu AT, CARG4, TISNUM
3163 |.if FFI
3164 | beqz AT, >9
3165 |.else
3166 | beqz AT, <2
3167 |.endif
3168 | // RA is an integer, RD is a number. Convert RA to a number.
3169 |.if FPU
3170 |. lwc1 f20, LO(RA)
3171 | ldc1 f22, 0(RD)
3172 | b <4
3173 | cvt.d.w f20, f20
3174 |.else
3175 |. sextw CARG1, CARG1
3176 | bal ->vm_sfi2d_1
3177 |. nop
3178 | b <4
3179 |. nop
3180 |.endif
3181 |
3182 |.if FFI
3183 |8:
3184 | li AT, LJ_TCDATA
3185 | bne CARG3, AT, <2
3186 |. nop
3187 | b ->vmeta_equal_cd
3188 |. nop
3189 |9:
3190 | li AT, LJ_TCDATA
3191 | bne CARG4, AT, <2
3192 |. nop
3193 | b ->vmeta_equal_cd
3194 |. nop
3195 |.endif
3196 break;
3197
3198 case BC_ISEQP: case BC_ISNEP:
3199 vk = op == BC_ISEQP;
3200 | // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target
3201 | daddu RA, BASE, RA
3202 | srl TMP1, RD, 3
3203 | ld TMP0, 0(RA)
3204 | lhu TMP2, OFS_RD(PC)
3205 | not TMP1, TMP1
3206 | gettp TMP0, TMP0
3207 | daddiu PC, PC, 4
3208 |.if FFI
3209 | li AT, LJ_TCDATA
3210 | beq TMP0, AT, ->vmeta_equal_cd
3211 |.endif
3212 |. xor TMP0, TMP0, TMP1
3213 | decode_RD4b TMP2
3214 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3215 | addu TMP2, TMP2, TMP3
3216 if (vk) {
3217 | movn TMP2, r0, TMP0
3218 } else {
3219 | movz TMP2, r0, TMP0
3220 }
3221 | daddu PC, PC, TMP2
3222 | ins_next
3223 break;
3224
3225 /* -- Unary test and copy ops ------------------------------------------- */
3226
3227 case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
3228 | // RA = dst*8 or unused, RD = src*8, JMP with RD = target
3229 | daddu RD, BASE, RD
3230 | lhu TMP2, OFS_RD(PC)
3231 | ld TMP0, 0(RD)
3232 | daddiu PC, PC, 4
3233 | gettp TMP0, TMP0
3234 | sltiu TMP0, TMP0, LJ_TISTRUECOND
3235 if (op == BC_IST || op == BC_ISF) {
3236 | decode_RD4b TMP2
3237 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3238 | addu TMP2, TMP2, TMP3
3239 if (op == BC_IST) {
3240 | movz TMP2, r0, TMP0
3241 } else {
3242 | movn TMP2, r0, TMP0
3243 }
3244 | daddu PC, PC, TMP2
3245 } else {
3246 | ld CRET1, 0(RD)
3247 if (op == BC_ISTC) {
3248 | beqz TMP0, >1
3249 } else {
3250 | bnez TMP0, >1
3251 }
3252 |. daddu RA, BASE, RA
3253 | decode_RD4b TMP2
3254 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3255 | addu TMP2, TMP2, TMP3
3256 | sd CRET1, 0(RA)
3257 | daddu PC, PC, TMP2
3258 |1:
3259 }
3260 | ins_next
3261 break;
3262
3263 case BC_ISTYPE:
3264 | // RA = src*8, RD = -type*8
3265 | daddu TMP2, BASE, RA
3266 | srl TMP1, RD, 3
3267 | ld TMP0, 0(TMP2)
3268 | ins_next1
3269 | gettp TMP0, TMP0
3270 | daddu AT, TMP0, TMP1
3271 | bnez AT, ->vmeta_istype
3272 |. ins_next2
3273 break;
3274 case BC_ISNUM:
3275 | // RA = src*8, RD = -(TISNUM-1)*8
3276 | daddu TMP2, BASE, RA
3277 | ld TMP0, 0(TMP2)
3278 | ins_next1
3279 | checknum TMP0, ->vmeta_istype
3280 |. ins_next2
3281 break;
3282
3283 /* -- Unary ops --------------------------------------------------------- */
3284
3285 case BC_MOV:
3286 | // RA = dst*8, RD = src*8
3287 | daddu RD, BASE, RD
3288 | daddu RA, BASE, RA
3289 | ld CRET1, 0(RD)
3290 | ins_next1
3291 | sd CRET1, 0(RA)
3292 | ins_next2
3293 break;
3294 case BC_NOT:
3295 | // RA = dst*8, RD = src*8
3296 | daddu RD, BASE, RD
3297 | daddu RA, BASE, RA
3298 | ld TMP0, 0(RD)
3299 | li AT, LJ_TTRUE
3300 | gettp TMP0, TMP0
3301 | sltu TMP0, AT, TMP0
3302 | addiu TMP0, TMP0, 1
3303 | dsll TMP0, TMP0, 47
3304 | not TMP0, TMP0
3305 | ins_next1
3306 | sd TMP0, 0(RA)
3307 | ins_next2
3308 break;
3309 case BC_UNM:
3310 | // RA = dst*8, RD = src*8
3311 | daddu RB, BASE, RD
3312 | ld CARG1, 0(RB)
3313 | daddu RA, BASE, RA
3314 | gettp CARG3, CARG1
3315 | bne CARG3, TISNUM, >2
3316 |. lui TMP1, 0x8000
3317 | sextw CARG1, CARG1
3318 | beq CARG1, TMP1, ->vmeta_unm // Meta handler deals with -2^31.
3319 |. negu CARG1, CARG1
3320 | zextw CARG1, CARG1
3321 | settp CARG1, TISNUM
3322 |1:
3323 | ins_next1
3324 | sd CARG1, 0(RA)
3325 | ins_next2
3326 |2:
3327 | sltiu AT, CARG3, LJ_TISNUM
3328 | beqz AT, ->vmeta_unm
3329 |. dsll TMP1, TMP1, 32
3330 | b <1
3331 |. xor CARG1, CARG1, TMP1
3332 break;
3333 case BC_LEN:
3334 | // RA = dst*8, RD = src*8
3335 | daddu CARG2, BASE, RD
3336 | daddu RA, BASE, RA
3337 | ld TMP0, 0(CARG2)
3338 | gettp TMP1, TMP0
3339 | daddiu AT, TMP1, -LJ_TSTR
3340 | bnez AT, >2
3341 |. cleartp STR:CARG1, TMP0
3342 | lw CRET1, STR:CARG1->len
3343 |1:
3344 | settp CRET1, TISNUM
3345 | ins_next1
3346 | sd CRET1, 0(RA)
3347 | ins_next2
3348 |2:
3349 | daddiu AT, TMP1, -LJ_TTAB
3350 | bnez AT, ->vmeta_len
3351 |. nop
3352#if LJ_52
3353 | ld TAB:TMP2, TAB:CARG1->metatable
3354 | bnez TAB:TMP2, >9
3355 |. nop
3356 |3:
3357#endif
3358 |->BC_LEN_Z:
3359 | load_got lj_tab_len
3360 | call_intern lj_tab_len // (GCtab *t)
3361 |. nop
3362 | // Returns uint32_t (but less than 2^31).
3363 | b <1
3364 |. nop
3365#if LJ_52
3366 |9:
3367 | lbu TMP0, TAB:TMP2->nomm
3368 | andi TMP0, TMP0, 1<<MM_len
3369 | bnez TMP0, <3 // 'no __len' flag set: done.
3370 |. nop
3371 | b ->vmeta_len
3372 |. nop
3373#endif
3374 break;
3375
3376 /* -- Binary ops -------------------------------------------------------- */
3377
3378 |.macro fpmod, a, b, c
3379 | bal ->vm_floor // floor(b/c)
3380 |. div.d FARG1, b, c
3381 | mul.d a, FRET1, c
3382 | sub.d a, b, a // b - floor(b/c)*c
3383 |.endmacro
3384
3385 |.macro sfpmod
3386 | daddiu sp, sp, -16
3387 |
3388 | load_got __divdf3
3389 | sd CARG1, 0(sp)
3390 | call_extern
3391 |. sd CARG2, 8(sp)
3392 |
3393 | load_got floor
3394 | call_extern
3395 |. move CARG1, CRET1
3396 |
3397 | load_got __muldf3
3398 | move CARG1, CRET1
3399 | call_extern
3400 |. ld CARG2, 8(sp)
3401 |
3402 | load_got __subdf3
3403 | ld CARG1, 0(sp)
3404 | call_extern
3405 |. move CARG2, CRET1
3406 |
3407 | daddiu sp, sp, 16
3408 |.endmacro
3409
3410 |.macro ins_arithpre, label
3411 ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
3412 | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8
3413 ||switch (vk) {
3414 ||case 0:
3415 | decode_RB8a RB, INS
3416 | decode_RB8b RB
3417 | decode_RDtoRC8 RC, RD
3418 | // RA = dst*8, RB = src1*8, RC = num_const*8
3419 | daddu RB, BASE, RB
3420 |.if "label" ~= "none"
3421 | b label
3422 |.endif
3423 |. daddu RC, KBASE, RC
3424 || break;
3425 ||case 1:
3426 | decode_RB8a RC, INS
3427 | decode_RB8b RC
3428 | decode_RDtoRC8 RB, RD
3429 | // RA = dst*8, RB = num_const*8, RC = src1*8
3430 | daddu RC, BASE, RC
3431 |.if "label" ~= "none"
3432 | b label
3433 |.endif
3434 |. daddu RB, KBASE, RB
3435 || break;
3436 ||default:
3437 | decode_RB8a RB, INS
3438 | decode_RB8b RB
3439 | decode_RDtoRC8 RC, RD
3440 | // RA = dst*8, RB = src1*8, RC = src2*8
3441 | daddu RB, BASE, RB
3442 |.if "label" ~= "none"
3443 | b label
3444 |.endif
3445 |. daddu RC, BASE, RC
3446 || break;
3447 ||}
3448 |.endmacro
3449 |
3450 |.macro ins_arith, intins, fpins, fpcall, label
3451 | ins_arithpre none
3452 |
3453 |.if "label" ~= "none"
3454 |label:
3455 |.endif
3456 |
3457 |// Used in 5.
3458 | ld CARG1, 0(RB)
3459 | ld CARG2, 0(RC)
3460 | gettp TMP0, CARG1
3461 | gettp TMP1, CARG2
3462 |
3463 |.if "intins" ~= "div"
3464 |
3465 | // Check for two integers.
3466 | sextw CARG3, CARG1
3467 | bne TMP0, TISNUM, >5
3468 |. sextw CARG4, CARG2
3469 | bne TMP1, TISNUM, >5
3470 |
3471 |.if "intins" == "addu"
3472 |. intins CRET1, CARG3, CARG4
3473 | xor TMP1, CRET1, CARG3 // ((y^a) & (y^b)) < 0: overflow.
3474 | xor TMP2, CRET1, CARG4
3475 | and TMP1, TMP1, TMP2
3476 | bltz TMP1, ->vmeta_arith
3477 |. daddu RA, BASE, RA
3478 |.elif "intins" == "subu"
3479 |. intins CRET1, CARG3, CARG4
3480 | xor TMP1, CRET1, CARG3 // ((y^a) & (a^b)) < 0: overflow.
3481 | xor TMP2, CARG3, CARG4
3482 | and TMP1, TMP1, TMP2
3483 | bltz TMP1, ->vmeta_arith
3484 |. daddu RA, BASE, RA
3485 |.elif "intins" == "mult"
3486 |. intins CARG3, CARG4
3487 | mflo CRET1
3488 | mfhi TMP2
3489 | sra TMP1, CRET1, 31
3490 | bne TMP1, TMP2, ->vmeta_arith
3491 |. daddu RA, BASE, RA
3492 |.else
3493 |. load_got lj_vm_modi
3494 | beqz CARG4, ->vmeta_arith
3495 |. daddu RA, BASE, RA
3496 | move CARG1, CARG3
3497 | call_extern
3498 |. move CARG2, CARG4
3499 |.endif
3500 |
3501 | zextw CRET1, CRET1
3502 | settp CRET1, TISNUM
3503 | ins_next1
3504 | sd CRET1, 0(RA)
3505 |3:
3506 | ins_next2
3507 |
3508 |.endif
3509 |
3510 |5: // Check for two numbers.
3511 | .FPU ldc1 f20, 0(RB)
3512 | sltu AT, TMP0, TISNUM
3513 | sltu TMP0, TMP1, TISNUM
3514 | .FPU ldc1 f22, 0(RC)
3515 | and AT, AT, TMP0
3516 | beqz AT, ->vmeta_arith
3517 |. daddu RA, BASE, RA
3518 |
3519 |.if FPU
3520 | fpins FRET1, f20, f22
3521 |.elif "fpcall" == "sfpmod"
3522 | sfpmod
3523 |.else
3524 | load_got fpcall
3525 | call_extern
3526 |. nop
3527 |.endif
3528 |
3529 | ins_next1
3530 |.if "intins" ~= "div"
3531 | b <3
3532 |.endif
3533 |.if FPU
3534 |. sdc1 FRET1, 0(RA)
3535 |.else
3536 |. sd CRET1, 0(RA)
3537 |.endif
3538 |.if "intins" == "div"
3539 | ins_next2
3540 |.endif
3541 |
3542 |.endmacro
3543
3544 case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
3545 | ins_arith addu, add.d, __adddf3, none
3546 break;
3547 case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
3548 | ins_arith subu, sub.d, __subdf3, none
3549 break;
3550 case BC_MULVN: case BC_MULNV: case BC_MULVV:
3551 | ins_arith mult, mul.d, __muldf3, none
3552 break;
3553 case BC_DIVVN:
3554 | ins_arith div, div.d, __divdf3, ->BC_DIVVN_Z
3555 break;
3556 case BC_DIVNV: case BC_DIVVV:
3557 | ins_arithpre ->BC_DIVVN_Z
3558 break;
3559 case BC_MODVN:
3560 | ins_arith modi, fpmod, sfpmod, ->BC_MODVN_Z
3561 break;
3562 case BC_MODNV: case BC_MODVV:
3563 | ins_arithpre ->BC_MODVN_Z
3564 break;
3565 case BC_POW:
3566 | ins_arithpre none
3567 | ld CARG1, 0(RB)
3568 | ld CARG2, 0(RC)
3569 | gettp TMP0, CARG1
3570 | gettp TMP1, CARG2
3571 | sltiu TMP0, TMP0, LJ_TISNUM
3572 | sltiu TMP1, TMP1, LJ_TISNUM
3573 | and AT, TMP0, TMP1
3574 | load_got pow
3575 | beqz AT, ->vmeta_arith
3576 |. daddu RA, BASE, RA
3577 |.if FPU
3578 | ldc1 FARG1, 0(RB)
3579 | ldc1 FARG2, 0(RC)
3580 |.endif
3581 | call_extern
3582 |. nop
3583 | ins_next1
3584 |.if FPU
3585 | sdc1 FRET1, 0(RA)
3586 |.else
3587 | sd CRET1, 0(RA)
3588 |.endif
3589 | ins_next2
3590 break;
3591
3592 case BC_CAT:
3593 | // RA = dst*8, RB = src_start*8, RC = src_end*8
3594 | decode_RB8a RB, INS
3595 | decode_RB8b RB
3596 | decode_RDtoRC8 RC, RD
3597 | dsubu CARG3, RC, RB
3598 | sd BASE, L->base
3599 | daddu CARG2, BASE, RC
3600 | move MULTRES, RB
3601 |->BC_CAT_Z:
3602 | load_got lj_meta_cat
3603 | srl CARG3, CARG3, 3
3604 | sd PC, SAVE_PC
3605 | call_intern lj_meta_cat // (lua_State *L, TValue *top, int left)
3606 |. move CARG1, L
3607 | // Returns NULL (finished) or TValue * (metamethod).
3608 | bnez CRET1, ->vmeta_binop
3609 |. ld BASE, L->base
3610 | daddu RB, BASE, MULTRES
3611 | ld CRET1, 0(RB)
3612 | daddu RA, BASE, RA
3613 | ins_next1
3614 | sd CRET1, 0(RA)
3615 | ins_next2
3616 break;
3617
3618 /* -- Constant ops ------------------------------------------------------ */
3619
3620 case BC_KSTR:
3621 | // RA = dst*8, RD = str_const*8 (~)
3622 | dsubu TMP1, KBASE, RD
3623 | ins_next1
3624 | li TMP2, LJ_TSTR
3625 | ld TMP0, -8(TMP1) // KBASE-8-str_const*8
3626 | daddu RA, BASE, RA
3627 | settp TMP0, TMP2
3628 | sd TMP0, 0(RA)
3629 | ins_next2
3630 break;
3631 case BC_KCDATA:
3632 |.if FFI
3633 | // RA = dst*8, RD = cdata_const*8 (~)
3634 | dsubu TMP1, KBASE, RD
3635 | ins_next1
3636 | ld TMP0, -8(TMP1) // KBASE-8-cdata_const*8
3637 | li TMP2, LJ_TCDATA
3638 | daddu RA, BASE, RA
3639 | settp TMP0, TMP2
3640 | sd TMP0, 0(RA)
3641 | ins_next2
3642 |.endif
3643 break;
3644 case BC_KSHORT:
3645 | // RA = dst*8, RD = int16_literal*8
3646 | sra RD, INS, 16
3647 | daddu RA, BASE, RA
3648 | zextw RD, RD
3649 | ins_next1
3650 | settp RD, TISNUM
3651 | sd RD, 0(RA)
3652 | ins_next2
3653 break;
3654 case BC_KNUM:
3655 | // RA = dst*8, RD = num_const*8
3656 | daddu RD, KBASE, RD
3657 | daddu RA, BASE, RA
3658 | ld CRET1, 0(RD)
3659 | ins_next1
3660 | sd CRET1, 0(RA)
3661 | ins_next2
3662 break;
3663 case BC_KPRI:
3664 | // RA = dst*8, RD = primitive_type*8 (~)
3665 | daddu RA, BASE, RA
3666 | dsll TMP0, RD, 44
3667 | not TMP0, TMP0
3668 | ins_next1
3669 | sd TMP0, 0(RA)
3670 | ins_next2
3671 break;
3672 case BC_KNIL:
3673 | // RA = base*8, RD = end*8
3674 | daddu RA, BASE, RA
3675 | sd TISNIL, 0(RA)
3676 | daddiu RA, RA, 8
3677 | daddu RD, BASE, RD
3678 |1:
3679 | sd TISNIL, 0(RA)
3680 | slt AT, RA, RD
3681 | bnez AT, <1
3682 |. daddiu RA, RA, 8
3683 | ins_next_
3684 break;
3685
3686 /* -- Upvalue and function ops ------------------------------------------ */
3687
3688 case BC_UGET:
3689 | // RA = dst*8, RD = uvnum*8
3690 | ld LFUNC:RB, FRAME_FUNC(BASE)
3691 | daddu RA, BASE, RA
3692 | cleartp LFUNC:RB
3693 | daddu RD, RD, LFUNC:RB
3694 | ld UPVAL:RB, LFUNC:RD->uvptr
3695 | ins_next1
3696 | ld TMP1, UPVAL:RB->v
3697 | ld CRET1, 0(TMP1)
3698 | sd CRET1, 0(RA)
3699 | ins_next2
3700 break;
3701 case BC_USETV:
3702 | // RA = uvnum*8, RD = src*8
3703 | ld LFUNC:RB, FRAME_FUNC(BASE)
3704 | daddu RD, BASE, RD
3705 | cleartp LFUNC:RB
3706 | daddu RA, RA, LFUNC:RB
3707 | ld UPVAL:RB, LFUNC:RA->uvptr
3708 | ld CRET1, 0(RD)
3709 | lbu TMP3, UPVAL:RB->marked
3710 | ld CARG2, UPVAL:RB->v
3711 | andi TMP3, TMP3, LJ_GC_BLACK // isblack(uv)
3712 | lbu TMP0, UPVAL:RB->closed
3713 | gettp TMP2, CRET1
3714 | sd CRET1, 0(CARG2)
3715 | li AT, LJ_GC_BLACK|1
3716 | or TMP3, TMP3, TMP0
3717 | beq TMP3, AT, >2 // Upvalue is closed and black?
3718 |. daddiu TMP2, TMP2, -(LJ_TNUMX+1)
3719 |1:
3720 | ins_next
3721 |
3722 |2: // Check if new value is collectable.
3723 | sltiu AT, TMP2, LJ_TISGCV - (LJ_TNUMX+1)
3724 | beqz AT, <1 // tvisgcv(v)
3725 |. cleartp GCOBJ:CRET1, CRET1
3726 | lbu TMP3, GCOBJ:CRET1->gch.marked
3727 | andi TMP3, TMP3, LJ_GC_WHITES // iswhite(v)
3728 | beqz TMP3, <1
3729 |. load_got lj_gc_barrieruv
3730 | // Crossed a write barrier. Move the barrier forward.
3731 | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv)
3732 |. daddiu CARG1, DISPATCH, GG_DISP2G
3733 | b <1
3734 |. nop
3735 break;
3736 case BC_USETS:
3737 | // RA = uvnum*8, RD = str_const*8 (~)
3738 | ld LFUNC:RB, FRAME_FUNC(BASE)
3739 | dsubu TMP1, KBASE, RD
3740 | cleartp LFUNC:RB
3741 | daddu RA, RA, LFUNC:RB
3742 | ld UPVAL:RB, LFUNC:RA->uvptr
3743 | ld STR:TMP1, -8(TMP1) // KBASE-8-str_const*8
3744 | lbu TMP2, UPVAL:RB->marked
3745 | ld CARG2, UPVAL:RB->v
3746 | lbu TMP3, STR:TMP1->marked
3747 | andi AT, TMP2, LJ_GC_BLACK // isblack(uv)
3748 | lbu TMP2, UPVAL:RB->closed
3749 | li TMP0, LJ_TSTR
3750 | settp TMP1, TMP0
3751 | bnez AT, >2
3752 |. sd TMP1, 0(CARG2)
3753 |1:
3754 | ins_next
3755 |
3756 |2: // Check if string is white and ensure upvalue is closed.
3757 | beqz TMP2, <1
3758 |. andi AT, TMP3, LJ_GC_WHITES // iswhite(str)
3759 | beqz AT, <1
3760 |. load_got lj_gc_barrieruv
3761 | // Crossed a write barrier. Move the barrier forward.
3762 | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv)
3763 |. daddiu CARG1, DISPATCH, GG_DISP2G
3764 | b <1
3765 |. nop
3766 break;
3767 case BC_USETN:
3768 | // RA = uvnum*8, RD = num_const*8
3769 | ld LFUNC:RB, FRAME_FUNC(BASE)
3770 | daddu RD, KBASE, RD
3771 | cleartp LFUNC:RB
3772 | daddu RA, RA, LFUNC:RB
3773 | ld UPVAL:RB, LFUNC:RA->uvptr
3774 | ld CRET1, 0(RD)
3775 | ld TMP1, UPVAL:RB->v
3776 | ins_next1
3777 | sd CRET1, 0(TMP1)
3778 | ins_next2
3779 break;
3780 case BC_USETP:
3781 | // RA = uvnum*8, RD = primitive_type*8 (~)
3782 | ld LFUNC:RB, FRAME_FUNC(BASE)
3783 | dsll TMP0, RD, 44
3784 | cleartp LFUNC:RB
3785 | daddu RA, RA, LFUNC:RB
3786 | not TMP0, TMP0
3787 | ld UPVAL:RB, LFUNC:RA->uvptr
3788 | ins_next1
3789 | ld TMP1, UPVAL:RB->v
3790 | sd TMP0, 0(TMP1)
3791 | ins_next2
3792 break;
3793
3794 case BC_UCLO:
3795 | // RA = level*8, RD = target
3796 | ld TMP2, L->openupval
3797 | branch_RD // Do this first since RD is not saved.
3798 | load_got lj_func_closeuv
3799 | sd BASE, L->base
3800 | beqz TMP2, >1
3801 |. move CARG1, L
3802 | call_intern lj_func_closeuv // (lua_State *L, TValue *level)
3803 |. daddu CARG2, BASE, RA
3804 | ld BASE, L->base
3805 |1:
3806 | ins_next
3807 break;
3808
3809 case BC_FNEW:
3810 | // RA = dst*8, RD = proto_const*8 (~) (holding function prototype)
3811 | load_got lj_func_newL_gc
3812 | dsubu TMP1, KBASE, RD
3813 | ld CARG3, FRAME_FUNC(BASE)
3814 | ld CARG2, -8(TMP1) // KBASE-8-tab_const*8
3815 | sd BASE, L->base
3816 | sd PC, SAVE_PC
3817 | cleartp CARG3
3818 | // (lua_State *L, GCproto *pt, GCfuncL *parent)
3819 | call_intern lj_func_newL_gc
3820 |. move CARG1, L
3821 | // Returns GCfuncL *.
3822 | li TMP0, LJ_TFUNC
3823 | ld BASE, L->base
3824 | ins_next1
3825 | settp CRET1, TMP0
3826 | daddu RA, BASE, RA
3827 | sd CRET1, 0(RA)
3828 | ins_next2
3829 break;
3830
3831 /* -- Table ops --------------------------------------------------------- */
3832
3833 case BC_TNEW:
3834 case BC_TDUP:
3835 | // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~)
3836 | ld TMP0, DISPATCH_GL(gc.total)(DISPATCH)
3837 | ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH)
3838 | sd BASE, L->base
3839 | sd PC, SAVE_PC
3840 | sltu AT, TMP0, TMP1
3841 | beqz AT, >5
3842 |1:
3843 if (op == BC_TNEW) {
3844 | load_got lj_tab_new
3845 | srl CARG2, RD, 3
3846 | andi CARG2, CARG2, 0x7ff
3847 | li TMP0, 0x801
3848 | addiu AT, CARG2, -0x7ff
3849 | srl CARG3, RD, 14
3850 | movz CARG2, TMP0, AT
3851 | // (lua_State *L, int32_t asize, uint32_t hbits)
3852 | call_intern lj_tab_new
3853 |. move CARG1, L
3854 | // Returns Table *.
3855 } else {
3856 | load_got lj_tab_dup
3857 | dsubu TMP1, KBASE, RD
3858 | move CARG1, L
3859 | call_intern lj_tab_dup // (lua_State *L, Table *kt)
3860 |. ld CARG2, -8(TMP1) // KBASE-8-str_const*8
3861 | // Returns Table *.
3862 }
3863 | li TMP0, LJ_TTAB
3864 | ld BASE, L->base
3865 | ins_next1
3866 | daddu RA, BASE, RA
3867 | settp CRET1, TMP0
3868 | sd CRET1, 0(RA)
3869 | ins_next2
3870 |5:
3871 | load_got lj_gc_step_fixtop
3872 | move MULTRES, RD
3873 | call_intern lj_gc_step_fixtop // (lua_State *L)
3874 |. move CARG1, L
3875 | b <1
3876 |. move RD, MULTRES
3877 break;
3878
3879 case BC_GGET:
3880 | // RA = dst*8, RD = str_const*8 (~)
3881 case BC_GSET:
3882 | // RA = src*8, RD = str_const*8 (~)
3883 | ld LFUNC:TMP2, FRAME_FUNC(BASE)
3884 | dsubu TMP1, KBASE, RD
3885 | ld STR:RC, -8(TMP1) // KBASE-8-str_const*8
3886 | cleartp LFUNC:TMP2
3887 | ld TAB:RB, LFUNC:TMP2->env
3888 if (op == BC_GGET) {
3889 | b ->BC_TGETS_Z
3890 } else {
3891 | b ->BC_TSETS_Z
3892 }
3893 |. daddu RA, BASE, RA
3894 break;
3895
3896 case BC_TGETV:
3897 | // RA = dst*8, RB = table*8, RC = key*8
3898 | decode_RB8a RB, INS
3899 | decode_RB8b RB
3900 | decode_RDtoRC8 RC, RD
3901 | daddu CARG2, BASE, RB
3902 | daddu CARG3, BASE, RC
3903 | ld TAB:RB, 0(CARG2)
3904 | ld TMP2, 0(CARG3)
3905 | daddu RA, BASE, RA
3906 | checktab TAB:RB, ->vmeta_tgetv
3907 | gettp TMP3, TMP2
3908 | bne TMP3, TISNUM, >5 // Integer key?
3909 |. lw TMP0, TAB:RB->asize
3910 | sextw TMP2, TMP2
3911 | ld TMP1, TAB:RB->array
3912 | sltu AT, TMP2, TMP0
3913 | sll TMP2, TMP2, 3
3914 | beqz AT, ->vmeta_tgetv // Integer key and in array part?
3915 |. daddu TMP2, TMP1, TMP2
3916 | ld AT, 0(TMP2)
3917 | beq AT, TISNIL, >2
3918 |. ld CRET1, 0(TMP2)
3919 |1:
3920 | ins_next1
3921 | sd CRET1, 0(RA)
3922 | ins_next2
3923 |
3924 |2: // Check for __index if table value is nil.
3925 | ld TAB:TMP2, TAB:RB->metatable
3926 | beqz TAB:TMP2, <1 // No metatable: done.
3927 |. nop
3928 | lbu TMP0, TAB:TMP2->nomm
3929 | andi TMP0, TMP0, 1<<MM_index
3930 | bnez TMP0, <1 // 'no __index' flag set: done.
3931 |. nop
3932 | b ->vmeta_tgetv
3933 |. nop
3934 |
3935 |5:
3936 | li AT, LJ_TSTR
3937 | bne TMP3, AT, ->vmeta_tgetv
3938 |. cleartp RC, TMP2
3939 | b ->BC_TGETS_Z // String key?
3940 |. nop
3941 break;
3942 case BC_TGETS:
3943 | // RA = dst*8, RB = table*8, RC = str_const*8 (~)
3944 | decode_RB8a RB, INS
3945 | decode_RB8b RB
3946 | decode_RC8a RC, INS
3947 | daddu CARG2, BASE, RB
3948 | decode_RC8b RC
3949 | ld TAB:RB, 0(CARG2)
3950 | dsubu CARG3, KBASE, RC
3951 | daddu RA, BASE, RA
3952 | ld STR:RC, -8(CARG3) // KBASE-8-str_const*8
3953 | checktab TAB:RB, ->vmeta_tgets1
3954 |->BC_TGETS_Z:
3955 | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8
3956 | lw TMP0, TAB:RB->hmask
3957 | lw TMP1, STR:RC->hash
3958 | ld NODE:TMP2, TAB:RB->node
3959 | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask
3960 | sll TMP0, TMP1, 5
3961 | sll TMP1, TMP1, 3
3962 | subu TMP1, TMP0, TMP1
3963 | li TMP3, LJ_TSTR
3964 | daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
3965 | settp STR:RC, TMP3 // Tagged key to look for.
3966 |1:
3967 | ld CARG1, NODE:TMP2->key
3968 | ld CRET1, NODE:TMP2->val
3969 | ld NODE:TMP1, NODE:TMP2->next
3970 | bne CARG1, RC, >4
3971 |. ld TAB:TMP3, TAB:RB->metatable
3972 | beq CRET1, TISNIL, >5 // Key found, but nil value?
3973 |. nop
3974 |3:
3975 | ins_next1
3976 | sd CRET1, 0(RA)
3977 | ins_next2
3978 |
3979 |4: // Follow hash chain.
3980 | bnez NODE:TMP1, <1
3981 |. move NODE:TMP2, NODE:TMP1
3982 | // End of hash chain: key not found, nil result.
3983 |
3984 |5: // Check for __index if table value is nil.
3985 | beqz TAB:TMP3, <3 // No metatable: done.
3986 |. move CRET1, TISNIL
3987 | lbu TMP0, TAB:TMP3->nomm
3988 | andi TMP0, TMP0, 1<<MM_index
3989 | bnez TMP0, <3 // 'no __index' flag set: done.
3990 |. nop
3991 | b ->vmeta_tgets
3992 |. nop
3993 break;
3994 case BC_TGETB:
3995 | // RA = dst*8, RB = table*8, RC = index*8
3996 | decode_RB8a RB, INS
3997 | decode_RB8b RB
3998 | daddu CARG2, BASE, RB
3999 | decode_RDtoRC8 RC, RD
4000 | ld TAB:RB, 0(CARG2)
4001 | daddu RA, BASE, RA
4002 | srl TMP0, RC, 3
4003 | checktab TAB:RB, ->vmeta_tgetb
4004 | lw TMP1, TAB:RB->asize
4005 | ld TMP2, TAB:RB->array
4006 | sltu AT, TMP0, TMP1
4007 | beqz AT, ->vmeta_tgetb
4008 |. daddu RC, TMP2, RC
4009 | ld AT, 0(RC)
4010 | beq AT, TISNIL, >5
4011 |. ld CRET1, 0(RC)
4012 |1:
4013 | ins_next1
4014 | sd CRET1, 0(RA)
4015 | ins_next2
4016 |
4017 |5: // Check for __index if table value is nil.
4018 | ld TAB:TMP2, TAB:RB->metatable
4019 | beqz TAB:TMP2, <1 // No metatable: done.
4020 |. nop
4021 | lbu TMP1, TAB:TMP2->nomm
4022 | andi TMP1, TMP1, 1<<MM_index
4023 | bnez TMP1, <1 // 'no __index' flag set: done.
4024 |. nop
4025 | b ->vmeta_tgetb // Caveat: preserve TMP0 and CARG2!
4026 |. nop
4027 break;
4028 case BC_TGETR:
4029 | // RA = dst*8, RB = table*8, RC = key*8
4030 | decode_RB8a RB, INS
4031 | decode_RB8b RB
4032 | decode_RDtoRC8 RC, RD
4033 | daddu RB, BASE, RB
4034 | daddu RC, BASE, RC
4035 | ld TAB:CARG1, 0(RB)
4036 | lw CARG2, LO(RC)
4037 | daddu RA, BASE, RA
4038 | cleartp TAB:CARG1
4039 | lw TMP0, TAB:CARG1->asize
4040 | ld TMP1, TAB:CARG1->array
4041 | sltu AT, CARG2, TMP0
4042 | sll TMP2, CARG2, 3
4043 | beqz AT, ->vmeta_tgetr // In array part?
4044 |. daddu CRET1, TMP1, TMP2
4045 | ld CARG2, 0(CRET1)
4046 |->BC_TGETR_Z:
4047 | ins_next1
4048 | sd CARG2, 0(RA)
4049 | ins_next2
4050 break;
4051
4052 case BC_TSETV:
4053 | // RA = src*8, RB = table*8, RC = key*8
4054 | decode_RB8a RB, INS
4055 | decode_RB8b RB
4056 | decode_RDtoRC8 RC, RD
4057 | daddu CARG2, BASE, RB
4058 | daddu CARG3, BASE, RC
4059 | ld RB, 0(CARG2)
4060 | ld TMP2, 0(CARG3)
4061 | daddu RA, BASE, RA
4062 | checktab RB, ->vmeta_tsetv
4063 | checkint TMP2, >5
4064 |. sextw RC, TMP2
4065 | lw TMP0, TAB:RB->asize
4066 | ld TMP1, TAB:RB->array
4067 | sltu AT, RC, TMP0
4068 | sll TMP2, RC, 3
4069 | beqz AT, ->vmeta_tsetv // Integer key and in array part?
4070 |. daddu TMP1, TMP1, TMP2
4071 | ld TMP0, 0(TMP1)
4072 | lbu TMP3, TAB:RB->marked
4073 | beq TMP0, TISNIL, >3
4074 |. ld CRET1, 0(RA)
4075 |1:
4076 | andi AT, TMP3, LJ_GC_BLACK // isblack(table)
4077 | bnez AT, >7
4078 |. sd CRET1, 0(TMP1)
4079 |2:
4080 | ins_next
4081 |
4082 |3: // Check for __newindex if previous value is nil.
4083 | ld TAB:TMP2, TAB:RB->metatable
4084 | beqz TAB:TMP2, <1 // No metatable: done.
4085 |. nop
4086 | lbu TMP2, TAB:TMP2->nomm
4087 | andi TMP2, TMP2, 1<<MM_newindex
4088 | bnez TMP2, <1 // 'no __newindex' flag set: done.
4089 |. nop
4090 | b ->vmeta_tsetv
4091 |. nop
4092 |
4093 |5:
4094 | gettp AT, TMP2
4095 | daddiu AT, AT, -LJ_TSTR
4096 | bnez AT, ->vmeta_tsetv
4097 |. nop
4098 | b ->BC_TSETS_Z // String key?
4099 |. cleartp STR:RC, TMP2
4100 |
4101 |7: // Possible table write barrier for the value. Skip valiswhite check.
4102 | barrierback TAB:RB, TMP3, TMP0, <2
4103 break;
4104 case BC_TSETS:
4105 | // RA = src*8, RB = table*8, RC = str_const*8 (~)
4106 | decode_RB8a RB, INS
4107 | decode_RB8b RB
4108 | daddu CARG2, BASE, RB
4109 | decode_RC8a RC, INS
4110 | ld TAB:RB, 0(CARG2)
4111 | decode_RC8b RC
4112 | dsubu CARG3, KBASE, RC
4113 | ld RC, -8(CARG3) // KBASE-8-str_const*8
4114 | daddu RA, BASE, RA
4115 | cleartp STR:RC
4116 | checktab TAB:RB, ->vmeta_tsets1
4117 |->BC_TSETS_Z:
4118 | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = BASE+src*8
4119 | lw TMP0, TAB:RB->hmask
4120 | lw TMP1, STR:RC->hash
4121 | ld NODE:TMP2, TAB:RB->node
4122 | sb r0, TAB:RB->nomm // Clear metamethod cache.
4123 | and TMP1, TMP1, TMP0 // idx = str->hash & tab->hmask
4124 | sll TMP0, TMP1, 5
4125 | sll TMP1, TMP1, 3
4126 | subu TMP1, TMP0, TMP1
4127 | li TMP3, LJ_TSTR
4128 | daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
4129 | settp STR:RC, TMP3 // Tagged key to look for.
4130 |.if FPU
4131 | ldc1 f20, 0(RA)
4132 |.else
4133 | ld CRET1, 0(RA)
4134 |.endif
4135 |1:
4136 | ld TMP0, NODE:TMP2->key
4137 | ld CARG2, NODE:TMP2->val
4138 | ld NODE:TMP1, NODE:TMP2->next
4139 | bne TMP0, RC, >5
4140 |. lbu TMP3, TAB:RB->marked
4141 | beq CARG2, TISNIL, >4 // Key found, but nil value?
4142 |. ld TAB:TMP0, TAB:RB->metatable
4143 |2:
4144 | andi AT, TMP3, LJ_GC_BLACK // isblack(table)
4145 | bnez AT, >7
4146 |.if FPU
4147 |. sdc1 f20, NODE:TMP2->val
4148 |.else
4149 |. sd CRET1, NODE:TMP2->val
4150 |.endif
4151 |3:
4152 | ins_next
4153 |
4154 |4: // Check for __newindex if previous value is nil.
4155 | beqz TAB:TMP0, <2 // No metatable: done.
4156 |. nop
4157 | lbu TMP0, TAB:TMP0->nomm
4158 | andi TMP0, TMP0, 1<<MM_newindex
4159 | bnez TMP0, <2 // 'no __newindex' flag set: done.
4160 |. nop
4161 | b ->vmeta_tsets
4162 |. nop
4163 |
4164 |5: // Follow hash chain.
4165 | bnez NODE:TMP1, <1
4166 |. move NODE:TMP2, NODE:TMP1
4167 | // End of hash chain: key not found, add a new one
4168 |
4169 | // But check for __newindex first.
4170 | ld TAB:TMP2, TAB:RB->metatable
4171 | beqz TAB:TMP2, >6 // No metatable: continue.
4172 |. daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
4173 | lbu TMP0, TAB:TMP2->nomm
4174 | andi TMP0, TMP0, 1<<MM_newindex
4175 | beqz TMP0, ->vmeta_tsets // 'no __newindex' flag NOT set: check.
4176 |6:
4177 | load_got lj_tab_newkey
4178 | sd RC, 0(CARG3)
4179 | sd BASE, L->base
4180 | move CARG2, TAB:RB
4181 | sd PC, SAVE_PC
4182 | call_intern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k
4183 |. move CARG1, L
4184 | // Returns TValue *.
4185 | ld BASE, L->base
4186 |.if FPU
4187 | b <3 // No 2nd write barrier needed.
4188 |. sdc1 f20, 0(CRET1)
4189 |.else
4190 | ld CARG1, 0(RA)
4191 | b <3 // No 2nd write barrier needed.
4192 |. sd CARG1, 0(CRET1)
4193 |.endif
4194 |
4195 |7: // Possible table write barrier for the value. Skip valiswhite check.
4196 | barrierback TAB:RB, TMP3, TMP0, <3
4197 break;
4198 case BC_TSETB:
4199 | // RA = src*8, RB = table*8, RC = index*8
4200 | decode_RB8a RB, INS
4201 | decode_RB8b RB
4202 | daddu CARG2, BASE, RB
4203 | decode_RDtoRC8 RC, RD
4204 | ld TAB:RB, 0(CARG2)
4205 | daddu RA, BASE, RA
4206 | srl TMP0, RC, 3
4207 | checktab RB, ->vmeta_tsetb
4208 | lw TMP1, TAB:RB->asize
4209 | ld TMP2, TAB:RB->array
4210 | sltu AT, TMP0, TMP1
4211 | beqz AT, ->vmeta_tsetb
4212 |. daddu RC, TMP2, RC
4213 | ld TMP1, 0(RC)
4214 | lbu TMP3, TAB:RB->marked
4215 | beq TMP1, TISNIL, >5
4216 |1:
4217 |. ld CRET1, 0(RA)
4218 | andi AT, TMP3, LJ_GC_BLACK // isblack(table)
4219 | bnez AT, >7
4220 |. sd CRET1, 0(RC)
4221 |2:
4222 | ins_next
4223 |
4224 |5: // Check for __newindex if previous value is nil.
4225 | ld TAB:TMP2, TAB:RB->metatable
4226 | beqz TAB:TMP2, <1 // No metatable: done.
4227 |. nop
4228 | lbu TMP1, TAB:TMP2->nomm
4229 | andi TMP1, TMP1, 1<<MM_newindex
4230 | bnez TMP1, <1 // 'no __newindex' flag set: done.
4231 |. nop
4232 | b ->vmeta_tsetb // Caveat: preserve TMP0 and CARG2!
4233 |. nop
4234 |
4235 |7: // Possible table write barrier for the value. Skip valiswhite check.
4236 | barrierback TAB:RB, TMP3, TMP0, <2
4237 break;
4238 case BC_TSETR:
4239 | // RA = dst*8, RB = table*8, RC = key*8
4240 | decode_RB8a RB, INS
4241 | decode_RB8b RB
4242 | decode_RDtoRC8 RC, RD
4243 | daddu CARG1, BASE, RB
4244 | daddu CARG3, BASE, RC
4245 | ld TAB:CARG2, 0(CARG1)
4246 | lw CARG3, LO(CARG3)
4247 | cleartp TAB:CARG2
4248 | lbu TMP3, TAB:CARG2->marked
4249 | lw TMP0, TAB:CARG2->asize
4250 | ld TMP1, TAB:CARG2->array
4251 | andi AT, TMP3, LJ_GC_BLACK // isblack(table)
4252 | bnez AT, >7
4253 |. daddu RA, BASE, RA
4254 |2:
4255 | sltu AT, CARG3, TMP0
4256 | sll TMP2, CARG3, 3
4257 | beqz AT, ->vmeta_tsetr // In array part?
4258 |. daddu CRET1, TMP1, TMP2
4259 |->BC_TSETR_Z:
4260 | ld CARG1, 0(RA)
4261 | ins_next1
4262 | sd CARG1, 0(CRET1)
4263 | ins_next2
4264 |
4265 |7: // Possible table write barrier for the value. Skip valiswhite check.
4266 | barrierback TAB:CARG2, TMP3, CRET1, <2
4267 break;
4268
4269 case BC_TSETM:
4270 | // RA = base*8 (table at base-1), RD = num_const*8 (start index)
4271 | daddu RA, BASE, RA
4272 |1:
4273 | daddu TMP3, KBASE, RD
4274 | ld TAB:CARG2, -8(RA) // Guaranteed to be a table.
4275 | addiu TMP0, MULTRES, -8
4276 | lw TMP3, LO(TMP3) // Integer constant is in lo-word.
4277 | beqz TMP0, >4 // Nothing to copy?
4278 |. srl CARG3, TMP0, 3
4279 | cleartp CARG2
4280 | addu CARG3, CARG3, TMP3
4281 | lw TMP2, TAB:CARG2->asize
4282 | sll TMP1, TMP3, 3
4283 | lbu TMP3, TAB:CARG2->marked
4284 | ld CARG1, TAB:CARG2->array
4285 | sltu AT, TMP2, CARG3
4286 | bnez AT, >5
4287 |. daddu TMP2, RA, TMP0
4288 | daddu TMP1, TMP1, CARG1
4289 | andi TMP0, TMP3, LJ_GC_BLACK // isblack(table)
4290 |3: // Copy result slots to table.
4291 | ld CRET1, 0(RA)
4292 | daddiu RA, RA, 8
4293 | sltu AT, RA, TMP2
4294 | sd CRET1, 0(TMP1)
4295 | bnez AT, <3
4296 |. daddiu TMP1, TMP1, 8
4297 | bnez TMP0, >7
4298 |. nop
4299 |4:
4300 | ins_next
4301 |
4302 |5: // Need to resize array part.
4303 | load_got lj_tab_reasize
4304 | sd BASE, L->base
4305 | sd PC, SAVE_PC
4306 | move BASE, RD
4307 | call_intern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize)
4308 |. move CARG1, L
4309 | // Must not reallocate the stack.
4310 | move RD, BASE
4311 | b <1
4312 |. ld BASE, L->base // Reload BASE for lack of a saved register.
4313 |
4314 |7: // Possible table write barrier for any value. Skip valiswhite check.
4315 | barrierback TAB:CARG2, TMP3, TMP0, <4
4316 break;
4317
4318 /* -- Calls and vararg handling ----------------------------------------- */
4319
4320 case BC_CALLM:
4321 | // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8
4322 | decode_RDtoRC8 NARGS8:RC, RD
4323 | b ->BC_CALL_Z
4324 |. addu NARGS8:RC, NARGS8:RC, MULTRES
4325 break;
4326 case BC_CALL:
4327 | // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8
4328 | decode_RDtoRC8 NARGS8:RC, RD
4329 |->BC_CALL_Z:
4330 | move TMP2, BASE
4331 | daddu BASE, BASE, RA
4332 | ld LFUNC:RB, 0(BASE)
4333 | daddiu BASE, BASE, 16
4334 | addiu NARGS8:RC, NARGS8:RC, -8
4335 | checkfunc RB, ->vmeta_call
4336 | ins_call
4337 break;
4338
4339 case BC_CALLMT:
4340 | // RA = base*8, (RB = 0,) RC = extra_nargs*8
4341 | addu NARGS8:RD, NARGS8:RD, MULTRES // BC_CALLT gets RC from RD.
4342 | // Fall through. Assumes BC_CALLT follows.
4343 break;
4344 case BC_CALLT:
4345 | // RA = base*8, (RB = 0,) RC = (nargs+1)*8
4346 | daddu RA, BASE, RA
4347 | ld RB, 0(RA)
4348 | move NARGS8:RC, RD
4349 | ld TMP1, FRAME_PC(BASE)
4350 | daddiu RA, RA, 16
4351 | addiu NARGS8:RC, NARGS8:RC, -8
4352 | checktp CARG3, RB, -LJ_TFUNC, ->vmeta_callt
4353 |->BC_CALLT_Z:
4354 | andi TMP0, TMP1, FRAME_TYPE // Caveat: preserve TMP0 until the 'or'.
4355 | lbu TMP3, LFUNC:CARG3->ffid
4356 | bnez TMP0, >7
4357 |. xori TMP2, TMP1, FRAME_VARG
4358 |1:
4359 | sd RB, FRAME_FUNC(BASE) // Copy function down, but keep PC.
4360 | sltiu AT, TMP3, 2 // (> FF_C) Calling a fast function?
4361 | move TMP2, BASE
4362 | move RB, CARG3
4363 | beqz NARGS8:RC, >3
4364 |. move TMP3, NARGS8:RC
4365 |2:
4366 | ld CRET1, 0(RA)
4367 | daddiu RA, RA, 8
4368 | addiu TMP3, TMP3, -8
4369 | sd CRET1, 0(TMP2)
4370 | bnez TMP3, <2
4371 |. daddiu TMP2, TMP2, 8
4372 |3:
4373 | or TMP0, TMP0, AT
4374 | beqz TMP0, >5
4375 |. nop
4376 |4:
4377 | ins_callt
4378 |
4379 |5: // Tailcall to a fast function with a Lua frame below.
4380 | lw INS, -4(TMP1)
4381 | decode_RA8a RA, INS
4382 | decode_RA8b RA
4383 | dsubu TMP1, BASE, RA
4384 | ld TMP1, -32(TMP1)
4385 | cleartp LFUNC:TMP1
4386 | ld TMP1, LFUNC:TMP1->pc
4387 | b <4
4388 |. ld KBASE, PC2PROTO(k)(TMP1) // Need to prepare KBASE.
4389 |
4390 |7: // Tailcall from a vararg function.
4391 | andi AT, TMP2, FRAME_TYPEP
4392 | bnez AT, <1 // Vararg frame below?
4393 |. dsubu TMP2, BASE, TMP2 // Relocate BASE down.
4394 | move BASE, TMP2
4395 | ld TMP1, FRAME_PC(TMP2)
4396 | b <1
4397 |. andi TMP0, TMP1, FRAME_TYPE
4398 break;
4399
4400 case BC_ITERC:
4401 | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8))
4402 | move TMP2, BASE // Save old BASE fir vmeta_call.
4403 | daddu BASE, BASE, RA
4404 | ld RB, -24(BASE)
4405 | ld CARG1, -16(BASE)
4406 | ld CARG2, -8(BASE)
4407 | li NARGS8:RC, 16 // Iterators get 2 arguments.
4408 | sd RB, 0(BASE) // Copy callable.
4409 | sd CARG1, 16(BASE) // Copy state.
4410 | sd CARG2, 24(BASE) // Copy control var.
4411 | daddiu BASE, BASE, 16
4412 | checkfunc RB, ->vmeta_call
4413 | ins_call
4414 break;
4415
4416 case BC_ITERN:
4417 | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8)
4418 |.if JIT
4419 | // NYI: add hotloop, record BC_ITERN.
4420 |.endif
4421 | daddu RA, BASE, RA
4422 | ld TAB:RB, -16(RA)
4423 | lw RC, -8+LO(RA) // Get index from control var.
4424 | cleartp TAB:RB
4425 | daddiu PC, PC, 4
4426 | lw TMP0, TAB:RB->asize
4427 | ld TMP1, TAB:RB->array
4428 | dsll CARG3, TISNUM, 47
4429 |1: // Traverse array part.
4430 | sltu AT, RC, TMP0
4431 | beqz AT, >5 // Index points after array part?
4432 |. sll TMP3, RC, 3
4433 | daddu TMP3, TMP1, TMP3
4434 | ld CARG1, 0(TMP3)
4435 | lhu RD, -4+OFS_RD(PC)
4436 | or TMP2, RC, CARG3
4437 | beq CARG1, TISNIL, <1 // Skip holes in array part.
4438 |. addiu RC, RC, 1
4439 | sd TMP2, 0(RA)
4440 | sd CARG1, 8(RA)
4441 | or TMP0, RC, CARG3
4442 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4443 | decode_RD4b RD
4444 | daddu RD, RD, TMP3
4445 | sw TMP0, -8+LO(RA) // Update control var.
4446 | daddu PC, PC, RD
4447 |3:
4448 | ins_next
4449 |
4450 |5: // Traverse hash part.
4451 | lw TMP1, TAB:RB->hmask
4452 | subu RC, RC, TMP0
4453 | ld TMP2, TAB:RB->node
4454 |6:
4455 | sltu AT, TMP1, RC // End of iteration? Branch to ITERL+1.
4456 | bnez AT, <3
4457 |. sll TMP3, RC, 5
4458 | sll RB, RC, 3
4459 | subu TMP3, TMP3, RB
4460 | daddu NODE:TMP3, TMP3, TMP2
4461 | ld CARG1, 0(NODE:TMP3)
4462 | lhu RD, -4+OFS_RD(PC)
4463 | beq CARG1, TISNIL, <6 // Skip holes in hash part.
4464 |. addiu RC, RC, 1
4465 | ld CARG2, NODE:TMP3->key
4466 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4467 | sd CARG1, 8(RA)
4468 | addu RC, RC, TMP0
4469 | decode_RD4b RD
4470 | addu RD, RD, TMP3
4471 | sd CARG2, 0(RA)
4472 | daddu PC, PC, RD
4473 | b <3
4474 |. sw RC, -8+LO(RA) // Update control var.
4475 break;
4476
4477 case BC_ISNEXT:
4478 | // RA = base*8, RD = target (points to ITERN)
4479 | daddu RA, BASE, RA
4480 | srl TMP0, RD, 1
4481 | ld CFUNC:CARG1, -24(RA)
4482 | daddu TMP0, PC, TMP0
4483 | ld CARG2, -16(RA)
4484 | ld CARG3, -8(RA)
4485 | lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535)
4486 | checkfunc CFUNC:CARG1, >5
4487 | gettp CARG2, CARG2
4488 | daddiu CARG2, CARG2, -LJ_TTAB
4489 | lbu TMP1, CFUNC:CARG1->ffid
4490 | daddiu CARG3, CARG3, -LJ_TNIL
4491 | or AT, CARG2, CARG3
4492 | daddiu TMP1, TMP1, -FF_next_N
4493 | or AT, AT, TMP1
4494 | bnez AT, >5
4495 |. lui TMP1, 0xfffe
4496 | daddu PC, TMP0, TMP2
4497 | ori TMP1, TMP1, 0x7fff
4498 | dsll TMP1, TMP1, 32
4499 | sd TMP1, -8(RA)
4500 |1:
4501 | ins_next
4502 |5: // Despecialize bytecode if any of the checks fail.
4503 | li TMP3, BC_JMP
4504 | li TMP1, BC_ITERC
4505 | sb TMP3, -4+OFS_OP(PC)
4506 | daddu PC, TMP0, TMP2
4507 | b <1
4508 |. sb TMP1, OFS_OP(PC)
4509 break;
4510
4511 case BC_VARG:
4512 | // RA = base*8, RB = (nresults+1)*8, RC = numparams*8
4513 | ld TMP0, FRAME_PC(BASE)
4514 | decode_RDtoRC8 RC, RD
4515 | decode_RB8a RB, INS
4516 | daddu RC, BASE, RC
4517 | decode_RB8b RB
4518 | daddu RA, BASE, RA
4519 | daddiu RC, RC, FRAME_VARG
4520 | daddu TMP2, RA, RB
4521 | daddiu TMP3, BASE, -16 // TMP3 = vtop
4522 | dsubu RC, RC, TMP0 // RC = vbase
4523 | // Note: RC may now be even _above_ BASE if nargs was < numparams.
4524 | beqz RB, >5 // Copy all varargs?
4525 |. dsubu TMP1, TMP3, RC
4526 | daddiu TMP2, TMP2, -16
4527 |1: // Copy vararg slots to destination slots.
4528 | ld CARG1, 0(RC)
4529 | sltu AT, RC, TMP3
4530 | daddiu RC, RC, 8
4531 | movz CARG1, TISNIL, AT
4532 | sd CARG1, 0(RA)
4533 | sltu AT, RA, TMP2
4534 | bnez AT, <1
4535 |. daddiu RA, RA, 8
4536 |3:
4537 | ins_next
4538 |
4539 |5: // Copy all varargs.
4540 | ld TMP0, L->maxstack
4541 | blez TMP1, <3 // No vararg slots?
4542 |. li MULTRES, 8 // MULTRES = (0+1)*8
4543 | daddu TMP2, RA, TMP1
4544 | sltu AT, TMP0, TMP2
4545 | bnez AT, >7
4546 |. daddiu MULTRES, TMP1, 8
4547 |6:
4548 | ld CRET1, 0(RC)
4549 | daddiu RC, RC, 8
4550 | sd CRET1, 0(RA)
4551 | sltu AT, RC, TMP3
4552 | bnez AT, <6 // More vararg slots?
4553 |. daddiu RA, RA, 8
4554 | b <3
4555 |. nop
4556 |
4557 |7: // Grow stack for varargs.
4558 | load_got lj_state_growstack
4559 | sd RA, L->top
4560 | dsubu RA, RA, BASE
4561 | sd BASE, L->base
4562 | dsubu BASE, RC, BASE // Need delta, because BASE may change.
4563 | sd PC, SAVE_PC
4564 | srl CARG2, TMP1, 3
4565 | call_intern lj_state_growstack // (lua_State *L, int n)
4566 |. move CARG1, L
4567 | move RC, BASE
4568 | ld BASE, L->base
4569 | daddu RA, BASE, RA
4570 | daddu RC, BASE, RC
4571 | b <6
4572 |. daddiu TMP3, BASE, -16
4573 break;
4574
4575 /* -- Returns ----------------------------------------------------------- */
4576
4577 case BC_RETM:
4578 | // RA = results*8, RD = extra_nresults*8
4579 | addu RD, RD, MULTRES // MULTRES >= 8, so RD >= 8.
4580 | // Fall through. Assumes BC_RET follows.
4581 break;
4582
4583 case BC_RET:
4584 | // RA = results*8, RD = (nresults+1)*8
4585 | ld PC, FRAME_PC(BASE)
4586 | daddu RA, BASE, RA
4587 | move MULTRES, RD
4588 |1:
4589 | andi TMP0, PC, FRAME_TYPE
4590 | bnez TMP0, ->BC_RETV_Z
4591 |. xori TMP1, PC, FRAME_VARG
4592 |
4593 |->BC_RET_Z:
4594 | // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return
4595 | lw INS, -4(PC)
4596 | daddiu TMP2, BASE, -16
4597 | daddiu RC, RD, -8
4598 | decode_RA8a TMP0, INS
4599 | decode_RB8a RB, INS
4600 | decode_RA8b TMP0
4601 | decode_RB8b RB
4602 | daddu TMP3, TMP2, RB
4603 | beqz RC, >3
4604 |. dsubu BASE, TMP2, TMP0
4605 |2:
4606 | ld CRET1, 0(RA)
4607 | daddiu RA, RA, 8
4608 | daddiu RC, RC, -8
4609 | sd CRET1, 0(TMP2)
4610 | bnez RC, <2
4611 |. daddiu TMP2, TMP2, 8
4612 |3:
4613 | daddiu TMP3, TMP3, -8
4614 |5:
4615 | sltu AT, TMP2, TMP3
4616 | bnez AT, >6
4617 |. ld LFUNC:TMP1, FRAME_FUNC(BASE)
4618 | ins_next1
4619 | cleartp LFUNC:TMP1
4620 | ld TMP1, LFUNC:TMP1->pc
4621 | ld KBASE, PC2PROTO(k)(TMP1)
4622 | ins_next2
4623 |
4624 |6: // Fill up results with nil.
4625 | sd TISNIL, 0(TMP2)
4626 | b <5
4627 |. daddiu TMP2, TMP2, 8
4628 |
4629 |->BC_RETV_Z: // Non-standard return case.
4630 | andi TMP2, TMP1, FRAME_TYPEP
4631 | bnez TMP2, ->vm_return
4632 |. nop
4633 | // Return from vararg function: relocate BASE down.
4634 | dsubu BASE, BASE, TMP1
4635 | b <1
4636 |. ld PC, FRAME_PC(BASE)
4637 break;
4638
4639 case BC_RET0: case BC_RET1:
4640 | // RA = results*8, RD = (nresults+1)*8
4641 | ld PC, FRAME_PC(BASE)
4642 | daddu RA, BASE, RA
4643 | move MULTRES, RD
4644 | andi TMP0, PC, FRAME_TYPE
4645 | bnez TMP0, ->BC_RETV_Z
4646 |. xori TMP1, PC, FRAME_VARG
4647 | lw INS, -4(PC)
4648 | daddiu TMP2, BASE, -16
4649 if (op == BC_RET1) {
4650 | ld CRET1, 0(RA)
4651 }
4652 | decode_RB8a RB, INS
4653 | decode_RA8a RA, INS
4654 | decode_RB8b RB
4655 | decode_RA8b RA
4656 | dsubu BASE, TMP2, RA
4657 if (op == BC_RET1) {
4658 | sd CRET1, 0(TMP2)
4659 }
4660 |5:
4661 | sltu AT, RD, RB
4662 | bnez AT, >6
4663 |. ld TMP1, FRAME_FUNC(BASE)
4664 | ins_next1
4665 | cleartp LFUNC:TMP1
4666 | ld TMP1, LFUNC:TMP1->pc
4667 | ld KBASE, PC2PROTO(k)(TMP1)
4668 | ins_next2
4669 |
4670 |6: // Fill up results with nil.
4671 | daddiu TMP2, TMP2, 8
4672 | daddiu RD, RD, 8
4673 | b <5
4674 if (op == BC_RET1) {
4675 |. sd TISNIL, 0(TMP2)
4676 } else {
4677 |. sd TISNIL, -8(TMP2)
4678 }
4679 break;
4680
4681 /* -- Loops and branches ------------------------------------------------ */
4682
4683 case BC_FORL:
4684 |.if JIT
4685 | hotloop
4686 |.endif
4687 | // Fall through. Assumes BC_IFORL follows.
4688 break;
4689
4690 case BC_JFORI:
4691 case BC_JFORL:
4692#if !LJ_HASJIT
4693 break;
4694#endif
4695 case BC_FORI:
4696 case BC_IFORL:
4697 | // RA = base*8, RD = target (after end of loop or start of loop)
4698 vk = (op == BC_IFORL || op == BC_JFORL);
4699 | daddu RA, BASE, RA
4700 | ld CARG1, FORL_IDX*8(RA) // IDX CARG1 - CARG3 type
4701 | gettp CARG3, CARG1
4702 if (op != BC_JFORL) {
4703 | srl RD, RD, 1
4704 | lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535)
4705 | daddu TMP2, RD, TMP2
4706 }
4707 if (!vk) {
4708 | ld CARG2, FORL_STOP*8(RA) // STOP CARG2 - CARG4 type
4709 | ld CRET1, FORL_STEP*8(RA) // STEP CRET1 - CRET2 type
4710 | gettp CARG4, CARG2
4711 | bne CARG3, TISNUM, >5
4712 |. gettp CRET2, CRET1
4713 | bne CARG4, TISNUM, ->vmeta_for
4714 |. sextw CARG3, CARG1
4715 | bne CRET2, TISNUM, ->vmeta_for
4716 |. sextw CARG2, CARG2
4717 | dext AT, CRET1, 31, 0
4718 | slt CRET1, CARG2, CARG3
4719 | slt TMP1, CARG3, CARG2
4720 | movn CRET1, TMP1, AT
4721 } else {
4722 | bne CARG3, TISNUM, >5
4723 |. ld CARG2, FORL_STEP*8(RA) // STEP CARG2 - CARG4 type
4724 | ld CRET1, FORL_STOP*8(RA) // STOP CRET1 - CRET2 type
4725 | sextw TMP3, CARG1
4726 | sextw CARG2, CARG2
4727 | sextw CRET1, CRET1
4728 | addu CARG1, TMP3, CARG2
4729 | xor TMP0, CARG1, TMP3
4730 | xor TMP1, CARG1, CARG2
4731 | and TMP0, TMP0, TMP1
4732 | slt TMP1, CARG1, CRET1
4733 | slt CRET1, CRET1, CARG1
4734 | slt AT, CARG2, r0
4735 | slt TMP0, TMP0, r0 // ((y^a) & (y^b)) < 0: overflow.
4736 | movn CRET1, TMP1, AT
4737 | or CRET1, CRET1, TMP0
4738 | zextw CARG1, CARG1
4739 | settp CARG1, TISNUM
4740 }
4741 |1:
4742 if (op == BC_FORI) {
4743 | movz TMP2, r0, CRET1
4744 | daddu PC, PC, TMP2
4745 } else if (op == BC_JFORI) {
4746 | daddu PC, PC, TMP2
4747 | lhu RD, -4+OFS_RD(PC)
4748 } else if (op == BC_IFORL) {
4749 | movn TMP2, r0, CRET1
4750 | daddu PC, PC, TMP2
4751 }
4752 if (vk) {
4753 | sd CARG1, FORL_IDX*8(RA)
4754 }
4755 | ins_next1
4756 | sd CARG1, FORL_EXT*8(RA)
4757 |2:
4758 if (op == BC_JFORI) {
4759 | beqz CRET1, =>BC_JLOOP
4760 |. decode_RD8b RD
4761 } else if (op == BC_JFORL) {
4762 | beqz CRET1, =>BC_JLOOP
4763 }
4764 | ins_next2
4765 |
4766 |5: // FP loop.
4767 |.if FPU
4768 if (!vk) {
4769 | ldc1 f0, FORL_IDX*8(RA)
4770 | ldc1 f2, FORL_STOP*8(RA)
4771 | sltiu TMP0, CARG3, LJ_TISNUM
4772 | sltiu TMP1, CARG4, LJ_TISNUM
4773 | sltiu AT, CRET2, LJ_TISNUM
4774 | ld TMP3, FORL_STEP*8(RA)
4775 | and TMP0, TMP0, TMP1
4776 | and AT, AT, TMP0
4777 | beqz AT, ->vmeta_for
4778 |. slt TMP3, TMP3, r0
4779 | c.ole.d 0, f0, f2
4780 | c.ole.d 1, f2, f0
4781 | li CRET1, 1
4782 | movt CRET1, r0, 0
4783 | movt AT, r0, 1
4784 | b <1
4785 |. movn CRET1, AT, TMP3
4786 } else {
4787 | ldc1 f0, FORL_IDX*8(RA)
4788 | ldc1 f4, FORL_STEP*8(RA)
4789 | ldc1 f2, FORL_STOP*8(RA)
4790 | ld TMP3, FORL_STEP*8(RA)
4791 | add.d f0, f0, f4
4792 | c.ole.d 0, f0, f2
4793 | c.ole.d 1, f2, f0
4794 | slt TMP3, TMP3, r0
4795 | li CRET1, 1
4796 | li AT, 1
4797 | movt CRET1, r0, 0
4798 | movt AT, r0, 1
4799 | movn CRET1, AT, TMP3
4800 if (op == BC_IFORL) {
4801 | movn TMP2, r0, CRET1
4802 | daddu PC, PC, TMP2
4803 }
4804 | sdc1 f0, FORL_IDX*8(RA)
4805 | ins_next1
4806 | b <2
4807 |. sdc1 f0, FORL_EXT*8(RA)
4808 }
4809 |.else
4810 if (!vk) {
4811 | sltiu TMP0, CARG3, LJ_TISNUM
4812 | sltiu TMP1, CARG4, LJ_TISNUM
4813 | sltiu AT, CRET2, LJ_TISNUM
4814 | and TMP0, TMP0, TMP1
4815 | and AT, AT, TMP0
4816 | beqz AT, ->vmeta_for
4817 |. nop
4818 | bal ->vm_sfcmpolex
4819 |. lw TMP3, FORL_STEP*8+HI(RA)
4820 | b <1
4821 |. nop
4822 } else {
4823 | load_got __adddf3
4824 | call_extern
4825 |. sw TMP2, TMPD
4826 | ld CARG2, FORL_STOP*8(RA)
4827 | move CARG1, CRET1
4828 if ( op == BC_JFORL ) {
4829 | lhu RD, -4+OFS_RD(PC)
4830 | decode_RD8b RD
4831 }
4832 | bal ->vm_sfcmpolex
4833 |. lw TMP3, FORL_STEP*8+HI(RA)
4834 | b <1
4835 |. lw TMP2, TMPD
4836 }
4837 |.endif
4838 break;
4839
4840 case BC_ITERL:
4841 |.if JIT
4842 | hotloop
4843 |.endif
4844 | // Fall through. Assumes BC_IITERL follows.
4845 break;
4846
4847 case BC_JITERL:
4848#if !LJ_HASJIT
4849 break;
4850#endif
4851 case BC_IITERL:
4852 | // RA = base*8, RD = target
4853 | daddu RA, BASE, RA
4854 | ld TMP1, 0(RA)
4855 | beq TMP1, TISNIL, >1 // Stop if iterator returned nil.
4856 |. nop
4857 if (op == BC_JITERL) {
4858 | b =>BC_JLOOP
4859 |. sd TMP1, -8(RA)
4860 } else {
4861 | branch_RD // Otherwise save control var + branch.
4862 | sd TMP1, -8(RA)
4863 }
4864 |1:
4865 | ins_next
4866 break;
4867
4868 case BC_LOOP:
4869 | // RA = base*8, RD = target (loop extent)
4870 | // Note: RA/RD is only used by trace recorder to determine scope/extent
4871 | // This opcode does NOT jump, it's only purpose is to detect a hot loop.
4872 |.if JIT
4873 | hotloop
4874 |.endif
4875 | // Fall through. Assumes BC_ILOOP follows.
4876 break;
4877
4878 case BC_ILOOP:
4879 | // RA = base*8, RD = target (loop extent)
4880 | ins_next
4881 break;
4882
4883 case BC_JLOOP:
4884 |.if JIT
4885 | // RA = base*8 (ignored), RD = traceno*8
4886 | ld TMP1, DISPATCH_J(trace)(DISPATCH)
4887 | li AT, 0
4888 | daddu TMP1, TMP1, RD
4889 | // Traces on MIPS don't store the trace number, so use 0.
4890 | sd AT, DISPATCH_GL(vmstate)(DISPATCH)
4891 | ld TRACE:TMP2, 0(TMP1)
4892 | sd BASE, DISPATCH_GL(jit_base)(DISPATCH)
4893 | ld TMP2, TRACE:TMP2->mcode
4894 | sd L, DISPATCH_GL(tmpbuf.L)(DISPATCH)
4895 | jr TMP2
4896 |. daddiu JGL, DISPATCH, GG_DISP2G+32768
4897 |.endif
4898 break;
4899
4900 case BC_JMP:
4901 | // RA = base*8 (only used by trace recorder), RD = target
4902 | branch_RD
4903 | ins_next
4904 break;
4905
4906 /* -- Function headers -------------------------------------------------- */
4907
4908 case BC_FUNCF:
4909 |.if JIT
4910 | hotcall
4911 |.endif
4912 case BC_FUNCV: /* NYI: compiled vararg functions. */
4913 | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow.
4914 break;
4915
4916 case BC_JFUNCF:
4917#if !LJ_HASJIT
4918 break;
4919#endif
4920 case BC_IFUNCF:
4921 | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8
4922 | ld TMP2, L->maxstack
4923 | lbu TMP1, -4+PC2PROTO(numparams)(PC)
4924 | ld KBASE, -4+PC2PROTO(k)(PC)
4925 | sltu AT, TMP2, RA
4926 | bnez AT, ->vm_growstack_l
4927 |. sll TMP1, TMP1, 3
4928 if (op != BC_JFUNCF) {
4929 | ins_next1
4930 }
4931 |2:
4932 | sltu AT, NARGS8:RC, TMP1 // Check for missing parameters.
4933 | bnez AT, >3
4934 |. daddu AT, BASE, NARGS8:RC
4935 if (op == BC_JFUNCF) {
4936 | decode_RD8a RD, INS
4937 | b =>BC_JLOOP
4938 |. decode_RD8b RD
4939 } else {
4940 | ins_next2
4941 }
4942 |
4943 |3: // Clear missing parameters.
4944 | sd TISNIL, 0(AT)
4945 | b <2
4946 |. addiu NARGS8:RC, NARGS8:RC, 8
4947 break;
4948
4949 case BC_JFUNCV:
4950#if !LJ_HASJIT
4951 break;
4952#endif
4953 | NYI // NYI: compiled vararg functions
4954 break; /* NYI: compiled vararg functions. */
4955
4956 case BC_IFUNCV:
4957 | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8
4958 | li TMP0, LJ_TFUNC
4959 | daddu TMP1, BASE, RC
4960 | ld TMP2, L->maxstack
4961 | settp LFUNC:RB, TMP0
4962 | daddu TMP0, RA, RC
4963 | sd LFUNC:RB, 0(TMP1) // Store (tagged) copy of LFUNC.
4964 | daddiu TMP3, RC, 16+FRAME_VARG
4965 | sltu AT, TMP0, TMP2
4966 | ld KBASE, -4+PC2PROTO(k)(PC)
4967 | beqz AT, ->vm_growstack_l
4968 |. sd TMP3, 8(TMP1) // Store delta + FRAME_VARG.
4969 | lbu TMP2, -4+PC2PROTO(numparams)(PC)
4970 | move RA, BASE
4971 | move RC, TMP1
4972 | ins_next1
4973 | beqz TMP2, >3
4974 |. daddiu BASE, TMP1, 16
4975 |1:
4976 | ld TMP0, 0(RA)
4977 | sltu AT, RA, RC // Less args than parameters?
4978 | move CARG1, TMP0
4979 | movz TMP0, TISNIL, AT // Clear missing parameters.
4980 | movn CARG1, TISNIL, AT // Clear old fixarg slot (help the GC).
4981 | addiu TMP2, TMP2, -1
4982 | sd TMP0, 16(TMP1)
4983 | daddiu TMP1, TMP1, 8
4984 | sd CARG1, 0(RA)
4985 | bnez TMP2, <1
4986 |. daddiu RA, RA, 8
4987 |3:
4988 | ins_next2
4989 break;
4990
4991 case BC_FUNCC:
4992 case BC_FUNCCW:
4993 | // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8
4994 if (op == BC_FUNCC) {
4995 | ld CFUNCADDR, CFUNC:RB->f
4996 } else {
4997 | ld CFUNCADDR, DISPATCH_GL(wrapf)(DISPATCH)
4998 }
4999 | daddu TMP1, RA, NARGS8:RC
5000 | ld TMP2, L->maxstack
5001 | daddu RC, BASE, NARGS8:RC
5002 | sd BASE, L->base
5003 | sltu AT, TMP2, TMP1
5004 | sd RC, L->top
5005 | li_vmstate C
5006 if (op == BC_FUNCCW) {
5007 | ld CARG2, CFUNC:RB->f
5008 }
5009 | bnez AT, ->vm_growstack_c // Need to grow stack.
5010 |. move CARG1, L
5011 | jalr CFUNCADDR // (lua_State *L [, lua_CFunction f])
5012 |. st_vmstate
5013 | // Returns nresults.
5014 | ld BASE, L->base
5015 | sll RD, CRET1, 3
5016 | ld TMP1, L->top
5017 | li_vmstate INTERP
5018 | ld PC, FRAME_PC(BASE) // Fetch PC of caller.
5019 | dsubu RA, TMP1, RD // RA = L->top - nresults*8
5020 | sd L, DISPATCH_GL(cur_L)(DISPATCH)
5021 | b ->vm_returnc
5022 |. st_vmstate
5023 break;
5024
5025 /* ---------------------------------------------------------------------- */
5026
5027 default:
5028 fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]);
5029 exit(2);
5030 break;
5031 }
5032}
5033
5034static int build_backend(BuildCtx *ctx)
5035{
5036 int op;
5037
5038 dasm_growpc(Dst, BC__MAX);
5039
5040 build_subroutines(ctx);
5041
5042 |.code_op
5043 for (op = 0; op < BC__MAX; op++)
5044 build_ins(ctx, (BCOp)op, op);
5045
5046 return BC__MAX;
5047}
5048
5049/* Emit pseudo frame-info for all assembler functions. */
5050static void emit_asm_debug(BuildCtx *ctx)
5051{
5052 int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code);
5053 int i;
5054 switch (ctx->mode) {
5055 case BUILD_elfasm:
5056 fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n");
5057 fprintf(ctx->fp,
5058 ".Lframe0:\n"
5059 "\t.4byte .LECIE0-.LSCIE0\n"
5060 ".LSCIE0:\n"
5061 "\t.4byte 0xffffffff\n"
5062 "\t.byte 0x1\n"
5063 "\t.string \"\"\n"
5064 "\t.uleb128 0x1\n"
5065 "\t.sleb128 -4\n"
5066 "\t.byte 31\n"
5067 "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n"
5068 "\t.align 2\n"
5069 ".LECIE0:\n\n");
5070 fprintf(ctx->fp,
5071 ".LSFDE0:\n"
5072 "\t.4byte .LEFDE0-.LASFDE0\n"
5073 ".LASFDE0:\n"
5074 "\t.4byte .Lframe0\n"
5075 "\t.8byte .Lbegin\n"
5076 "\t.8byte %d\n"
5077 "\t.byte 0xe\n\t.uleb128 %d\n"
5078 "\t.byte 0x9f\n\t.sleb128 2*5\n"
5079 "\t.byte 0x9e\n\t.sleb128 2*6\n",
5080 fcofs, CFRAME_SIZE);
5081 for (i = 23; i >= 16; i--)
5082 fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 2*(30-i));
5083#if !LJ_SOFTFP
5084 for (i = 31; i >= 24; i--)
5085 fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 2*(46-i));
5086#endif
5087 fprintf(ctx->fp,
5088 "\t.align 2\n"
5089 ".LEFDE0:\n\n");
5090#if LJ_HASFFI
5091 fprintf(ctx->fp,
5092 ".LSFDE1:\n"
5093 "\t.4byte .LEFDE1-.LASFDE1\n"
5094 ".LASFDE1:\n"
5095 "\t.4byte .Lframe0\n"
5096 "\t.4byte lj_vm_ffi_call\n"
5097 "\t.4byte %d\n"
5098 "\t.byte 0x9f\n\t.uleb128 2*1\n"
5099 "\t.byte 0x90\n\t.uleb128 2*2\n"
5100 "\t.byte 0xd\n\t.uleb128 0x10\n"
5101 "\t.align 2\n"
5102 ".LEFDE1:\n\n", (int)ctx->codesz - fcofs);
5103#endif
5104#if !LJ_NO_UNWIND
5105 /* NYI */
5106#endif
5107 break;
5108 default:
5109 break;
5110 }
5111}
5112