1 |// Low-level VM code for ARM64 CPUs.
2 |// Bytecode interpreter, fast functions and helper functions.
3 |// Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
6 |.section code_op, code_sub
8 |.actionlist build_actionlist
10 |.globalnames globnames
11 |.externnames extnames
13 |// Note: The ragged indentation of the instructions is intentional.
14 |// The starting columns indicate data dependencies.
16 |//-----------------------------------------------------------------------
18 |// ARM64 registers and the AAPCS64 ABI 1.0 at a glance:
20 |// x0-x17 temp, x19-x28 callee-saved, x29 fp, x30 lr
21 |// x18 is reserved on most platforms. Don't use it, save it or restore it.
22 |// x31 doesn't exist. Register number 31 either means xzr/wzr (zero) or sp,
23 |// depending on the instruction.
24 |// v0-v7 temp, v8-v15 callee-saved (only d8-d15 preserved), v16-v31 temp
26 |// x0-x7/v0-v7 hold parameters and results.
28 |// Fixed register assignments for the interpreter.
30 |// The following must be C callee-save.
31 |.define BASE, x19 // Base of current Lua stack frame.
32 |.define KBASE, x20 // Constants of current Lua function.
33 |.define PC, x21 // Next PC.
34 |.define GLREG, x22 // Global state.
35 |.define LREG, x23 // Register holding lua_State (also in SAVE_L).
36 |.define TISNUM, x24 // Constant LJ_TISNUM << 47.
37 |.define TISNUMhi, x25 // Constant LJ_TISNUM << 15.
38 |.define TISNIL, x26 // Constant -1LL.
39 |.define fp, x29 // Yes, we have to maintain a frame pointer.
41 |.define ST_INTERP, w26 // Constant -1.
43 |// The following temporaries are not saved across C calls, except for RA/RC.
62 |// Calling conventions. Also used as temporaries.
80 |// Stack layout while in interpreter. Must match with lj_frame.h.
82 |.define CFRAME_SPACE, 208
83 |//----- 16 byte aligned, <-- sp entering interpreter
84 |// Unused [sp, #204] // 32 bit values
85 |.define SAVE_NRES, [sp, #200]
86 |.define SAVE_ERRF, [sp, #196]
87 |.define SAVE_MULTRES, [sp, #192]
88 |.define TMPD, [sp, #184] // 64 bit values
89 |.define SAVE_L, [sp, #176]
90 |.define SAVE_PC, [sp, #168]
91 |.define SAVE_CFRAME, [sp, #160]
92 |.define SAVE_FPR_, 96 // 96+8*8: 64 bit FPR saves
93 |.define SAVE_GPR_, 16 // 16+10*8: 64 bit GPR saves
94 |.define SAVE_LR, [sp, #8]
95 |.define SAVE_FP, [sp]
96 |//----- 16 byte aligned, <-- sp while in interpreter.
98 |.define TMPDofs, #184
100 |.macro save_, gpr1, gpr2, fpr1, fpr2
101 | stp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8]
102 | stp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8]
104 |.macro rest_, gpr1, gpr2, fpr1, fpr2
105 | ldp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8]
106 | ldp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8]
110 | stp fp, lr, [sp, #-CFRAME_SPACE]!
112 | stp x19, x20, [sp, # SAVE_GPR_]
114 | save_ 23, 24, 10, 11
115 | save_ 25, 26, 12, 13
116 | save_ 27, 28, 14, 15
119 | ldp x19, x20, [sp, # SAVE_GPR_]
121 | rest_ 23, 24, 10, 11
122 | rest_ 25, 26, 12, 13
123 | rest_ 27, 28, 14, 15
124 | ldp fp, lr, [sp], # CFRAME_SPACE
127 |// Type definitions. Some of these are only used for documentation.
128 |.type L, lua_State, LREG
129 |.type GL, global_State, GLREG
130 |.type TVALUE, TValue
134 |.type LFUNC, GCfuncL
135 |.type CFUNC, GCfuncC
136 |.type PROTO, GCproto
137 |.type UPVAL, GCupval
140 |.type TRACE, GCtrace
143 |//-----------------------------------------------------------------------
145 |// Trap for not-yet-implemented parts.
146 |.macro NYI; brk; .endmacro
148 |//-----------------------------------------------------------------------
150 |// Access to frame relative to BASE.
151 |.define FRAME_FUNC, #-16
152 |.define FRAME_PC, #-8
154 |.macro decode_RA, dst, ins; ubfx dst, ins, #8, #8; .endmacro
155 |.macro decode_RB, dst, ins; ubfx dst, ins, #24, #8; .endmacro
156 |.macro decode_RC, dst, ins; ubfx dst, ins, #16, #8; .endmacro
157 |.macro decode_RD, dst, ins; ubfx dst, ins, #16, #16; .endmacro
158 |.macro decode_RC8RD, dst, src; ubfiz dst, src, #3, #8; .endmacro
160 |// Instruction decode+dispatch.
163 | add TMP1, GL, INS, uxtb #3
165 | ldr TMP0, [TMP1, #GG_G2DISP]
170 |// Instruction footer.
172 | // Replicated dispatch. Less unpredictable branches, but higher I-Cache use.
173 | .define ins_next, ins_NEXT
174 | .define ins_next_, ins_NEXT
176 | // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch.
177 | // Affects only certain kinds of benchmarks (and only with -j off).
187 |// Call decode and dispatch.
189 | // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
190 | ldr PC, LFUNC:CARG3->pc
192 | add TMP1, GL, INS, uxtb #3
194 | ldr TMP0, [TMP1, #GG_G2DISP]
195 | add RA, BASE, RA, lsl #3
200 | // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, PC = caller PC
201 | str PC, [BASE, FRAME_PC]
205 |//-----------------------------------------------------------------------
207 |// Macros to check the TValue type and extract the GCobj. Branch on failure.
208 |.macro checktp, reg, tp, target
209 | asr ITYPE, reg, #47
211 | and reg, reg, #LJ_GCVMASK
214 |.macro checktp, dst, reg, tp, target
215 | asr ITYPE, reg, #47
217 | and dst, reg, #LJ_GCVMASK
220 |.macro checkstr, reg, target; checktp reg, LJ_TSTR, target; .endmacro
221 |.macro checktab, reg, target; checktp reg, LJ_TTAB, target; .endmacro
222 |.macro checkfunc, reg, target; checktp reg, LJ_TFUNC, target; .endmacro
223 |.macro checkint, reg, target
224 | cmp TISNUMhi, reg, lsr #32
227 |.macro checknum, reg, target
228 | cmp TISNUMhi, reg, lsr #32
231 |.macro checknumber, reg, target
232 | cmp TISNUMhi, reg, lsr #32
236 |.macro mov_false, reg; movn reg, #0x8000, lsl #32; .endmacro
237 |.macro mov_true, reg; movn reg, #0x0001, lsl #48; .endmacro
239 #define GL_J(field) (GG_OFS(J) + (int)offsetof(jit_State, field))
241 #define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto))
243 |.macro hotcheck, delta
248 | hotcheck HOTCOUNT_LOOP
253 | hotcheck HOTCOUNT_CALL
257 |// Set current VM state.
258 |.macro mv_vmstate, reg, st; movn reg, #LJ_VMST_..st; .endmacro
259 |.macro st_vmstate, reg; str reg, GL->vmstate; .endmacro
261 |// Move table write barrier back. Overwrites mark and tmp.
262 |.macro barrierback, tab, mark, tmp
263 | ldr tmp, GL->gc.grayagain
264 | and mark, mark, #~LJ_GC_BLACK // black2gray(tab)
265 | str tab, GL->gc.grayagain
266 | strb mark, tab->marked
267 | str tmp, tab->gclist
270 |//-----------------------------------------------------------------------
273 #error "Only dual-number mode supported for ARM64 target"
276 /* Generate subroutines used by opcodes and other parts of the VM. */
277 /* The .code_sub section should be last to help static branch prediction. */
278 static void build_subroutines(BuildCtx *ctx)
282 |//-----------------------------------------------------------------------
283 |//-- Return handling ----------------------------------------------------
284 |//-----------------------------------------------------------------------
287 | // See vm_return. Also: RB = previous base.
288 | tbz PC, #2, ->cont_dispatch // (PC & FRAME_P) == 0?
290 | // Return from pcall or xpcall fast func.
291 | ldr PC, [RB, FRAME_PC] // Fetch PC of previous frame.
294 | // Prepending may overwrite the pcall frame, so do it at the end.
295 | str TMP0, [RA, #-8]! // Prepend true to results.
298 | adds RC, RC, #8 // RC = (nresults+1)*8.
299 | mov CRET1, #LUA_YIELD
300 | beq ->vm_unwind_c_eh
301 | str RCw, SAVE_MULTRES
302 | ands CARG1, PC, #FRAME_TYPE
303 | beq ->BC_RET_Z // Handle regular return to Lua.
306 | // BASE = base, RA = resultptr, RC/MULTRES = (nresults+1)*8, PC = return
307 | // CARG1 = PC & FRAME_TYPE
308 | and RB, PC, #~FRAME_TYPEP
309 | cmp CARG1, #FRAME_C
310 | sub RB, BASE, RB // RB = previous base.
314 | ldrsw CARG2, SAVE_NRES // CARG2 = nresults+1.
315 | mv_vmstate TMP0w, C
316 | sub BASE, BASE, #16
321 | subs TMP2, TMP2, #8
323 | str TMP0, [BASE], #8
326 | cmp RC, CARG2, lsl #3 // More/less results wanted?
329 | str BASE, L->top // Store new top.
332 | ldr RC, SAVE_CFRAME // Restore previous C frame.
333 | mov CRET1, #0 // Ok return status for vm_pcall.
341 | bgt >7 // Less results wanted?
342 | // More results wanted. Check stack size and fill up results with nil.
343 | ldr CARG3, L->maxstack
346 | str TISNIL, [BASE], #8
350 |7: // Less results wanted.
351 | cbz CARG2, <3 // LUA_MULTRET+1 case?
352 | sub CARG1, RC, CARG2, lsl #3
353 | sub BASE, BASE, CARG1 // Shrink top.
356 |8: // Corner case: need to grow stack for filling up results.
357 | // This can happen if:
358 | // - A C function grows the stack (a lot).
359 | // - The GC shrinks the stack in between.
360 | // - A return back from a lua_call() with (high) nresults adjustment.
361 | str BASE, L->top // Save current top held in BASE (yes).
363 | bl extern lj_state_growstack // (lua_State *L, int n)
364 | ldr BASE, L->top // Need the (realloced) L->top in BASE.
365 | ldrsw CARG2, SAVE_NRES
368 |->vm_unwind_c: // Unwind C stack, return from vm_pcall.
369 | // (void *cframe, int errcode)
372 |->vm_unwind_c_eh: // Landing pad for external unwinder.
374 | mv_vmstate TMP0w, C
379 |->vm_unwind_ff: // Unwind C stack, return from ff pcall.
381 | and sp, CARG1, #CFRAME_RAWMASK
382 |->vm_unwind_ff_eh: // Landing pad for external unwinder.
384 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
385 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
387 | mov RC, #16 // 2 results: false + error message.
389 | ldr GL, L->glref // Setup pointer to global state.
391 | sub RA, BASE, #8 // Results start at BASE-8.
392 | ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame.
393 | str TMP0, [BASE, #-8] // Prepend false to error message.
394 | st_vmstate ST_INTERP
397 |//-----------------------------------------------------------------------
398 |//-- Grow stack for calls -----------------------------------------------
399 |//-----------------------------------------------------------------------
401 |->vm_growstack_c: // Grow stack for C function.
403 | mov CARG2, #LUA_MINSTACK
406 |->vm_growstack_l: // Grow stack for Lua function.
407 | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC
411 | stp BASE, RC, L->base
412 | add PC, PC, #4 // Must point after first instruction.
415 | // L->base = new base, L->top = top
417 | bl extern lj_state_growstack // (lua_State *L, int n)
418 | ldp BASE, RC, L->base
419 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
420 | sub NARGS8:RC, RC, BASE
421 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
422 | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
423 | ins_callt // Just retry the call.
425 |//-----------------------------------------------------------------------
426 |//-- Entry points into the assembler VM ---------------------------------
427 |//-----------------------------------------------------------------------
429 |->vm_resume: // Setup C frame and resume thread.
430 | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0)
433 | ldr GL, L->glref // Setup pointer to global state.
438 | add TMP0, sp, #CFRAME_RESUME
439 | ldrb TMP1w, L->status
441 | str L, SAVE_PC // Any value outside of bytecode is ok.
442 | str xzr, SAVE_CFRAME
443 | str TMP0, L->cframe
446 | // Resume after yield (like a return).
449 | ldp BASE, CARG1, L->base
450 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
451 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
452 | ldr PC, [BASE, FRAME_PC]
453 | strb wzr, L->status
455 | sub RC, CARG1, BASE
456 | ands CARG1, PC, #FRAME_TYPE
458 | st_vmstate ST_INTERP
459 | str RCw, SAVE_MULTRES
463 |->vm_pcall: // Setup protected C frame and enter VM.
464 | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef)
467 | str CARG4w, SAVE_ERRF
470 |->vm_call: // Setup C frame and enter VM.
471 | // (lua_State *L, TValue *base, int nres1)
475 |1: // Entry point for vm_pcall above (PC = ftype).
476 | ldr RC, L:CARG1->cframe
477 | str CARG3w, SAVE_NRES
480 | ldr GL, L->glref // Setup pointer to global state.
482 | str CARG1, SAVE_PC // Any value outside of bytecode is ok.
483 | str RC, SAVE_CFRAME
484 | str fp, L->cframe // Add our C frame to cframe chain.
486 |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype).
488 | ldp RB, CARG1, L->base // RB = old base (for vmeta_call).
489 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
490 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
493 | sub PC, PC, RB // PC = frame delta + frame type
494 | sub NARGS8:RC, CARG1, BASE
495 | st_vmstate ST_INTERP
498 | // RB = old base, BASE = new base, RC = nargs*8, PC = caller PC
499 | ldr CARG3, [BASE, FRAME_FUNC]
500 | checkfunc CARG3, ->vmeta_call
502 |->vm_call_dispatch_f:
504 | // BASE = new base, CARG3 = func, RC = nargs*8, PC = caller PC
506 |->vm_cpcall: // Setup protected C frame, call C.
507 | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
510 | ldr RA, L:CARG1->stack
512 | ldr GL, L->glref // Setup pointer to global state.
514 | str CARG1, SAVE_PC // Any value outside of bytecode is ok.
516 | sub RA, RA, RB // Compute -savestack(L, L->top).
517 | str RAw, SAVE_NRES // Neg. delta means cframe w/o frame.
518 | str wzr, SAVE_ERRF // No error function.
519 | str RC, SAVE_CFRAME
520 | str fp, L->cframe // Add our C frame to cframe chain.
522 | blr CARG4 // (lua_State *L, lua_CFunction func, void *ud)
525 | cbnz BASE, <3 // Else continue with the call.
526 | b ->vm_leave_cp // No base? Just remove C frame.
528 |//-----------------------------------------------------------------------
529 |//-- Metamethod handling ------------------------------------------------
530 |//-----------------------------------------------------------------------
532 |//-- Continuation dispatch ----------------------------------------------
535 | // BASE = meta base, RA = resultptr, RC = (nresults+1)*8
536 | ldr LFUNC:CARG3, [RB, FRAME_FUNC]
537 | ldr CARG1, [BASE, #-32] // Get continuation.
539 | mov BASE, RB // Restore caller BASE.
540 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
544 | ldr PC, [CARG4, #-24] // Restore PC from [cont|PC].
545 | ldr CARG3, LFUNC:CARG3->pc
547 | str TISNIL, [TMP0, #-8] // Ensure one valid arg.
551 | ldr KBASE, [CARG3, #PC2PROTO(k)]
552 | // BASE = base, RA = resultptr, CARG4 = meta base
557 | beq ->cont_ffi_callback // cont = 1: return from FFI callback.
558 | // cont = 0: tailcall from C function.
559 | sub CARG4, CARG4, #32
560 | sub RC, CARG4, BASE
564 |->cont_cat: // RA = resultptr, CARG4 = meta base
565 | ldr INSw, [PC, #-4]
566 | sub CARG2, CARG4, #32
571 | add TMP1, BASE, RB, lsl #3
572 | subs TMP1, CARG2, TMP1
575 | lsr CARG3, TMP1, #3
579 | str TMP0, [BASE, RA, lsl #3]
582 |//-- Table indexing metamethods -----------------------------------------
585 | movn CARG4, #~LJ_TSTR
586 | add CARG2, BASE, RB, lsl #3
587 | add CARG4, STR:RC, CARG4, lsl #47
591 | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48
592 | str CARG2, GL->tmptv
593 | add CARG2, GL, #offsetof(global_State, tmptv)
595 | add CARG3, sp, TMPDofs
599 |->vmeta_tgetb: // RB = table, RC = index
601 | add CARG2, BASE, RB, lsl #3
602 | add CARG3, sp, TMPDofs
606 |->vmeta_tgetv: // RB = table, RC = key
607 | add CARG2, BASE, RB, lsl #3
608 | add CARG3, BASE, RC, lsl #3
613 | bl extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k)
614 | // Returns TValue * (finished) or NULL (metamethod).
617 | str TMP0, [BASE, RA, lsl #3]
620 |3: // Call __index metamethod.
621 | // BASE = base, L->top = new base, stack = cont/func/t/k
622 | sub TMP1, BASE, #FRAME_CONT
624 | mov NARGS8:RC, #16 // 2 args for func(t, k).
625 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
626 | str PC, [BASE, #-24] // [cont|PC]
628 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
629 | b ->vm_call_dispatch_f
633 | bl extern lj_tab_getinth // (GCtab *t, int32_t key)
634 | // Returns cTValue * or NULL.
636 | cbz CRET1, ->BC_TGETR_Z
640 |//-----------------------------------------------------------------------
643 | movn CARG4, #~LJ_TSTR
644 | add CARG2, BASE, RB, lsl #3
645 | add CARG4, STR:RC, CARG4, lsl #47
649 | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48
650 | str CARG2, GL->tmptv
651 | add CARG2, GL, #offsetof(global_State, tmptv)
653 | add CARG3, sp, TMPDofs
657 |->vmeta_tsetb: // RB = table, RC = index
659 | add CARG2, BASE, RB, lsl #3
660 | add CARG3, sp, TMPDofs
665 | add CARG2, BASE, RB, lsl #3
666 | add CARG3, BASE, RC, lsl #3
671 | bl extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k)
672 | // Returns TValue * (finished) or NULL (metamethod).
673 | ldr TMP0, [BASE, RA, lsl #3]
675 | // NOBARRIER: lj_meta_tset ensures the table is not black.
679 |3: // Call __newindex metamethod.
680 | // BASE = base, L->top = new base, stack = cont/func/t/k/(v)
681 | sub TMP1, BASE, #FRAME_CONT
683 | mov NARGS8:RC, #24 // 3 args for func(t, k, v).
684 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
685 | str TMP0, [BASE, #16] // Copy value to third argument.
686 | str PC, [BASE, #-24] // [cont|PC]
688 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
689 | b ->vm_call_dispatch_f
695 | bl extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key)
696 | // Returns TValue *.
699 |//-- Comparison metamethods ---------------------------------------------
702 | add CARG2, BASE, RA, lsl #3
704 | add CARG3, BASE, RC, lsl #3
709 | bl extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op)
710 | // Returns 0/1 or TValue * (metamethod).
717 | add RB, PC, RB, lsl #2
718 | sub RB, RB, #0x20000
719 | csel PC, PC, RB, lo
723 |->cont_ra: // RA = resultptr
724 | ldr INSw, [PC, #-4]
726 | decode_RA TMP1, INS
727 | str TMP0, [BASE, TMP1, lsl #3]
730 |->cont_condt: // RA = resultptr
733 | cmp TMP1, TMP0 // Branch if result is true.
736 |->cont_condf: // RA = resultptr
739 | cmp TMP0, TMP1 // Branch if result is false.
743 | // CARG2, CARG3, CARG4 are already set by BC_ISEQV/BC_ISNEV.
744 | and TAB:CARG3, CARG3, #LJ_GCVMASK
749 | bl extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne)
750 | // Returns 0/1 or TValue * (metamethod).
760 | bl extern lj_meta_equal_cd // (lua_State *L, BCIns op)
761 | // Returns 0/1 or TValue * (metamethod).
772 | bl extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp)
775 |//-- Arithmetic metamethods ---------------------------------------------
778 | add CARG3, BASE, RB, lsl #3
779 | add CARG4, KBASE, RC, lsl #3
783 | add CARG4, BASE, RB, lsl #3
784 | add CARG3, KBASE, RC, lsl #3
788 | add CARG3, BASE, RC, lsl #3
793 | add CARG3, BASE, RB, lsl #3
794 | add CARG4, BASE, RC, lsl #3
797 | add CARG2, BASE, RA, lsl #3
801 | bl extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op)
802 | // Returns NULL (finished) or TValue * (metamethod).
803 | cbz CRET1, ->cont_nop
805 | // Call metamethod for binary op.
807 | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2
808 | sub TMP1, CRET1, BASE
809 | str PC, [CRET1, #-24] // [cont|PC]
810 | add PC, TMP1, #FRAME_CONT
812 | mov NARGS8:RC, #16 // 2 args for func(o1, o2).
813 | b ->vm_call_dispatch
816 | add CARG2, BASE, RC, lsl #3
818 | mov TAB:RC, TAB:CARG1 // Save table (ignored for other types).
823 | bl extern lj_meta_len // (lua_State *L, TValue *o)
824 | // Returns NULL (retry) or TValue * (metamethod base).
826 | cbnz CRET1, ->vmeta_binop // Binop call for compatibility.
827 | mov TAB:CARG1, TAB:RC
830 | b ->vmeta_binop // Binop call for compatibility.
833 |//-- Call metamethod ----------------------------------------------------
835 |->vmeta_call: // Resolve and call __call metamethod.
836 | // RB = old base, BASE = new base, RC = nargs*8
838 | str RB, L->base // This is the callers base!
839 | sub CARG2, BASE, #16
841 | add CARG3, BASE, NARGS8:RC
842 | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
843 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
844 | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
845 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
848 |->vmeta_callt: // Resolve __call for BC_CALLT.
849 | // BASE = old base, RA = new base, RC = nargs*8
854 | add CARG3, RA, NARGS8:RC
855 | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
856 | ldr TMP1, [RA, FRAME_FUNC] // Guaranteed to be a function here.
857 | ldr PC, [BASE, FRAME_PC]
858 | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
859 | and LFUNC:CARG3, TMP1, #LJ_GCVMASK
862 |//-- Argument coercion for 'for' statement ------------------------------
869 | bl extern lj_meta_for // (lua_State *L, TValue *base)
870 | ldr INSw, [PC, #-4]
877 | cmp TMP0, #BC_JFORI
882 |//-----------------------------------------------------------------------
883 |//-- Fast functions -----------------------------------------------------
884 |//-----------------------------------------------------------------------
890 |.macro .ffunc_1, name
897 |.macro .ffunc_2, name
899 | ldp CARG1, CARG2, [BASE]
904 |.macro .ffunc_n, name
910 | checknum CARG1, ->fff_fallback
913 |.macro .ffunc_nn, name
915 | ldp CARG1, CARG2, [BASE]
917 | ldp FARG1, FARG2, [BASE]
919 | checknum CARG1, ->fff_fallback
920 | checknum CARG2, ->fff_fallback
923 |// Inlined GC threshold check. Caveat: uses CARG1 and CARG2.
925 | ldp CARG1, CARG2, GL->gc.total // Assumes threshold follows total.
932 |//-- Base library: checks -----------------------------------------------
935 | ldr PC, [BASE, FRAME_PC]
939 | str CARG1, [BASE, #-16]
941 | subs RA, NARGS8:RC, #8
942 | add RC, NARGS8:RC, #8 // Compute (nresults+1)*8.
943 | cbz RA, ->fff_res // Done if exactly 1 argument.
945 | ldr CARG1, [RB, #16]
947 | str CARG1, [RB], #8
952 | mov TMP0, #~LJ_TISNUM
953 | asr ITYPE, CARG1, #47
954 | cmn ITYPE, #~LJ_TISNUM
955 | csinv TMP1, TMP0, ITYPE, lo
956 | add TMP1, TMP1, #offsetof(GCfuncC, upvalue)/8
957 | ldr CARG1, [CFUNC:CARG3, TMP1, lsl #3]
960 |//-- Base library: getters and setters ---------------------------------
962 |.ffunc_1 getmetatable
963 | asr ITYPE, CARG1, #47
964 | cmn ITYPE, #-LJ_TTAB
965 | ccmn ITYPE, #-LJ_TUDATA, #4, ne
966 | and TAB:CARG1, CARG1, #LJ_GCVMASK
968 |1: // Field metatable must be at same offset for GCtab and GCudata!
969 | ldr TAB:RB, TAB:CARG1->metatable
972 | ldr STR:RC, GL->gcroot[GCROOT_MMNAME+MM_metatable]
973 | cbz TAB:RB, ->fff_restv
974 | ldr TMP1w, TAB:RB->hmask
975 | ldr TMP2w, STR:RC->hash
976 | ldr NODE:CARG3, TAB:RB->node
977 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask
978 | add TMP1, TMP1, TMP1, lsl #1
979 | movn CARG4, #~LJ_TSTR
980 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8
981 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for.
982 |3: // Rearranged logic, because we expect _not_ to find the key.
983 | ldp CARG1, TMP0, NODE:CARG3->val
984 | ldr NODE:CARG3, NODE:CARG3->next
987 | cbnz NODE:CARG3, <3
989 | mov CARG1, RB // Use metatable as default result.
990 | movk CARG1, #(LJ_TTAB>>1)&0xffff, lsl #48
998 | movn TMP0, #~LJ_TISNUM
1000 | csel ITYPE, ITYPE, TMP0, hs
1001 | sub TMP1, GL, ITYPE, lsl #3
1002 | ldr TAB:RB, [TMP1, #offsetof(global_State, gcroot[GCROOT_BASEMT])-8]
1005 |.ffunc_2 setmetatable
1006 | // Fast path: no mt for table yet and not clearing the mt.
1007 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
1008 | ldr TAB:TMP0, TAB:TMP1->metatable
1009 | asr ITYPE, CARG2, #47
1010 | ldrb TMP2w, TAB:TMP1->marked
1011 | cmn ITYPE, #-LJ_TTAB
1012 | and TAB:CARG2, CARG2, #LJ_GCVMASK
1013 | ccmp TAB:TMP0, #0, #0, eq
1014 | bne ->fff_fallback
1015 | str TAB:CARG2, TAB:TMP1->metatable
1016 | tbz TMP2w, #2, ->fff_restv // isblack(table)
1017 | barrierback TAB:TMP1, TMP2w, TMP0
1022 | cmp NARGS8:RC, #16
1023 | blo ->fff_fallback
1024 | checktab CARG2, ->fff_fallback
1026 | add CARG3, BASE, #8
1027 | bl extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key)
1028 | // Returns cTValue *.
1029 | ldr CARG1, [CRET1]
1032 |//-- Base library: conversions ------------------------------------------
1035 | // Only handles the number case inline (without a base argument).
1038 | bne ->fff_fallback
1039 | checknumber CARG1, ->fff_fallback
1043 | // Only handles the string or number case inline.
1044 | asr ITYPE, CARG1, #47
1045 | cmn ITYPE, #-LJ_TSTR
1046 | // A __tostring method in the string base metatable is ignored.
1048 | // Handle numbers inline, unless a number base metatable is present.
1049 | ldr TMP1, GL->gcroot[GCROOT_BASEMT_NUM]
1051 | cmn ITYPE, #-LJ_TISNUM
1052 | ccmp TMP1, #0, #0, ls
1053 | str PC, SAVE_PC // Redundant (but a defined value).
1054 | bne ->fff_fallback
1058 | bl extern lj_strfmt_number // (lua_State *L, cTValue *o)
1059 | // Returns GCstr *.
1060 | movn TMP1, #~LJ_TSTR
1062 | add CARG1, CARG1, TMP1, lsl #47
1065 |//-- Base library: iterators -------------------------------------------
1068 | checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback
1069 | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
1070 | ldr PC, [BASE, FRAME_PC]
1071 | stp BASE, BASE, L->base // Add frame since C call can throw.
1073 | add CARG3, BASE, #8
1075 | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1076 | // Returns 0 at end of traversal.
1077 | str TISNIL, [BASE, #-16]
1078 | cbz CRET1, ->fff_res1 // End of traversal: return nil.
1079 | ldp CARG1, CARG2, [BASE, #8] // Copy key and value to results.
1081 | stp CARG1, CARG2, [BASE, #-16]
1085 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
1087 | ldr TAB:CARG2, TAB:TMP1->metatable
1089 | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0]
1090 | ldr PC, [BASE, FRAME_PC]
1092 | cbnz TAB:CARG2, ->fff_fallback
1095 | stp CARG1, TISNIL, [BASE, #-8]
1096 | str CFUNC:CARG4, [BASE, #-16]
1099 |.ffunc_2 ipairs_aux
1100 | checktab CARG1, ->fff_fallback
1101 | checkint CARG2, ->fff_fallback
1102 | ldr TMP1w, TAB:CARG1->asize
1103 | ldr CARG3, TAB:CARG1->array
1104 | ldr TMP0w, TAB:CARG1->hmask
1105 | add CARG2w, CARG2w, #1
1107 | ldr PC, [BASE, FRAME_PC]
1108 | add TMP2, CARG2, TISNUM
1110 | str TMP2, [BASE, #-16]
1111 | bhs >2 // Not in array part?
1112 | ldr TMP0, [CARG3, CARG2, lsl #3]
1114 | mov TMP1, #(2+1)*8
1116 | str TMP0, [BASE, #-8]
1117 | csel RC, RC, TMP1, eq
1119 |2: // Check for empty hash part first. Otherwise call C function.
1120 | cbz TMP0w, ->fff_res
1121 | bl extern lj_tab_getinth // (GCtab *t, int32_t key)
1122 | // Returns cTValue * or NULL.
1123 | cbz CRET1, ->fff_res
1128 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
1130 | ldr TAB:CARG2, TAB:TMP1->metatable
1132 | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0]
1133 | ldr PC, [BASE, FRAME_PC]
1135 | cbnz TAB:CARG2, ->fff_fallback
1138 | stp CARG1, TISNUM, [BASE, #-8]
1139 | str CFUNC:CARG4, [BASE, #-16]
1142 |//-- Base library: catch errors ----------------------------------------
1145 | ldrb TMP0w, GL->hookmask
1146 | subs NARGS8:RC, NARGS8:RC, #8
1147 | blo ->fff_fallback
1149 | add BASE, BASE, #16
1150 | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1
1151 | add PC, TMP0, #16+FRAME_PCALL
1152 | beq ->vm_call_dispatch
1154 | add TMP2, BASE, NARGS8:RC
1156 | ldr TMP0, [TMP2, #-16]
1157 | str TMP0, [TMP2, #-8]!
1160 | b ->vm_call_dispatch
1163 | ldp CARG1, CARG2, [BASE]
1164 | ldrb TMP0w, GL->hookmask
1165 | subs NARGS8:RC, NARGS8:RC, #16
1166 | blo ->fff_fallback
1168 | add BASE, BASE, #24
1169 | asr ITYPE, CARG2, #47
1170 | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1
1171 | cmn ITYPE, #-LJ_TFUNC
1172 | add PC, TMP0, #24+FRAME_PCALL
1173 | bne ->fff_fallback // Traceback must be a function.
1174 | stp CARG2, CARG1, [RB] // Swap function and traceback.
1175 | cbz NARGS8:RC, ->vm_call_dispatch
1178 |//-- Coroutine library --------------------------------------------------
1180 |.macro coroutine_resume_wrap, resume
1182 |.ffunc_1 coroutine_resume
1183 | checktp CARG1, LJ_TTHREAD, ->fff_fallback
1185 |.ffunc coroutine_wrap_aux
1186 | ldr L:CARG1, CFUNC:CARG3->upvalue[0].gcr
1187 | and L:CARG1, CARG1, #LJ_GCVMASK
1189 | ldr PC, [BASE, FRAME_PC]
1191 | ldp RB, CARG2, L:CARG1->base
1192 | ldrb TMP1w, L:CARG1->status
1193 | add TMP0, CARG2, TMP1
1196 | beq ->fff_fallback
1197 | cmp TMP1, #LUA_YIELD
1198 | add TMP0, CARG2, #8
1199 | csel CARG2, CARG2, TMP0, hs
1200 | ldr CARG4, L:CARG1->maxstack
1201 | add CARG3, CARG2, NARGS8:RC
1202 | ldr RB, L:CARG1->cframe
1203 | ccmp CARG3, CARG4, #2, ls
1204 | ccmp RB, #0, #2, ls
1205 | bhi ->fff_fallback
1207 | sub CARG3, CARG3, #8 // Keep resumed thread in stack for GC.
1208 | add BASE, BASE, #8
1209 | sub NARGS8:RC, NARGS8:RC, #8
1211 | str CARG3, L:CARG1->top
1214 |2: // Move args to coroutine.
1215 | ldr TMP0, [BASE, RB]
1217 | str TMP0, [CARG2, RB]
1224 | bl ->vm_resume // (lua_State *L, TValue *base, 0, 0)
1225 | // Returns thread status.
1227 | ldp CARG3, CARG4, L:RA->base
1228 | cmp CRET1, #LUA_YIELD
1231 | st_vmstate ST_INTERP
1233 | sub RC, CARG4, CARG3
1234 | ldr CARG1, L->maxstack
1235 | add CARG2, BASE, RC
1236 | cbz RC, >6 // No results?
1239 | bhi >9 // Need to grow stack?
1242 | str CARG3, L:RA->top // Clear coroutine stack.
1243 |5: // Move results from coroutine.
1244 | ldr TMP0, [CARG3, RB]
1246 | str TMP0, [BASE, RB]
1254 | str TMP1, [BASE, #-8] // Prepend true/false to results.
1260 | ands CARG1, PC, #FRAME_TYPE
1262 | str RCw, SAVE_MULTRES
1266 |8: // Coroutine returned with error (at co->top-1).
1268 | ldr TMP0, [CARG4, #-8]!
1271 | str CARG4, L:RA->top // Remove error from coroutine stack.
1272 | str TMP0, [BASE] // Copy error message.
1277 | bl extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co)
1281 |9: // Handle stack expansion on return from yield.
1284 | bl extern lj_state_growstack // (lua_State *L, int n)
1289 | coroutine_resume_wrap 1 // coroutine.resume
1290 | coroutine_resume_wrap 0 // coroutine.wrap
1292 |.ffunc coroutine_yield
1293 | ldr TMP0, L->cframe
1294 | add TMP1, BASE, NARGS8:RC
1295 | mov CRET1, #LUA_YIELD
1296 | stp BASE, TMP1, L->base
1297 | tbz TMP0, #0, ->fff_fallback
1298 | str xzr, L->cframe
1299 | strb CRET1w, L->status
1302 |//-- Math library -------------------------------------------------------
1304 |.macro math_round, func, round
1305 | .ffunc math_ .. func
1309 | blo ->fff_fallback
1310 | cmp TISNUMhi, CARG1, lsr #32
1312 | blo ->fff_fallback
1317 | math_round floor, frintm
1318 | math_round ceil, frintp
1321 | checknumber CARG1, ->fff_fallback
1322 | and CARG1, CARG1, #U64x(7fffffff,ffffffff)
1324 | eor CARG2w, CARG1w, CARG1w, asr #31
1325 | movz CARG3, #0x41e0, lsl #48 // 2^31.
1326 | subs CARG1w, CARG2w, CARG1w, asr #31
1327 | add CARG1, CARG1, TISNUM
1328 | csel CARG1, CARG1, CARG3, pl
1332 | // CARG1 = TValue result.
1333 | ldr PC, [BASE, FRAME_PC]
1334 | str CARG1, [BASE, #-16]
1339 | // RC = (nresults+1)*8, PC = return.
1340 | ands CARG1, PC, #FRAME_TYPE
1341 | str RCw, SAVE_MULTRES
1344 | ldr INSw, [PC, #-4]
1347 | cmp RC, RB, lsl #3 // More results expected?
1349 | decode_RA TMP1, INS
1350 | // Adjust BASE. KBASE is assumed to be set for the calling frame.
1351 | sub BASE, RA, TMP1, lsl #3
1354 |6: // Fill up results with nil.
1357 | str TISNIL, [TMP1, #-8]
1360 |.macro math_extern, func
1361 | .ffunc_n math_ .. func
1366 |.macro math_extern2, func
1367 | .ffunc_nn math_ .. func
1375 | ldr PC, [BASE, FRAME_PC]
1376 | str d0, [BASE, #-16]
1383 | bne ->fff_fallback // Need exactly 1 argument.
1384 | checknum CARG1, ->fff_fallback
1400 | math_extern2 atan2
1403 |.ffunc_2 math_ldexp
1405 | checknum CARG1, ->fff_fallback
1406 | checkint CARG2, ->fff_fallback
1407 | sxtw CARG1, CARG2w
1408 | bl extern ldexp // (double x, int exp)
1411 |.ffunc_n math_frexp
1412 | add CARG1, sp, TMPDofs
1415 | ldr PC, [BASE, FRAME_PC]
1416 | str d0, [BASE, #-16]
1418 | add CARG2, CARG2, TISNUM
1419 | str CARG2, [BASE, #-8]
1423 | sub CARG1, BASE, #16
1424 | ldr PC, [BASE, FRAME_PC]
1427 | str d0, [BASE, #-8]
1430 |.macro math_minmax, name, cond, fcond
1434 | checkint CARG1, >4
1435 |1: // Handle integers.
1439 | checkint CARG2, >3
1440 | cmp CARG1w, CARG2w
1442 | csel CARG1, CARG2, CARG1, cond
1444 |3: // Convert intermediate result to number and continue below.
1446 | blo ->fff_fallback
1452 | blo ->fff_fallback
1453 |5: // Handle numbers.
1458 | checknum CARG2, >7
1462 | fcsel d0, d1, d0, fcond
1464 |7: // Convert integer to number and continue above.
1466 | blo ->fff_fallback
1470 | math_minmax math_min, gt, hi
1471 | math_minmax math_max, lt, lo
1473 |//-- String library -----------------------------------------------------
1475 |.ffunc string_byte // Only handle the 1-arg case here.
1476 | ldp PC, CARG1, [BASE, FRAME_PC]
1478 | asr ITYPE, CARG1, #47
1479 | ccmn ITYPE, #-LJ_TSTR, #0, eq
1480 | and STR:CARG1, CARG1, #LJ_GCVMASK
1481 | bne ->fff_fallback
1482 | ldrb TMP0w, STR:CARG1[1] // Access is always ok (NUL at end).
1483 | ldr CARG3w, STR:CARG1->len
1484 | add TMP0, TMP0, TISNUM
1485 | str TMP0, [BASE, #-16]
1487 | cbz CARG3, ->fff_res
1490 |.ffunc string_char // Only handle the 1-arg case here.
1492 | ldp PC, CARG1, [BASE, FRAME_PC]
1494 | ccmp NARGS8:RC, #8, #0, ls // Need exactly 1 argument.
1495 | bne ->fff_fallback
1496 | checkint CARG1, ->fff_fallback
1498 | mov CARG2, BASE // Points to stack. Little-endian.
1500 | // CARG2 = str, CARG3 = len.
1504 | bl extern lj_str_new // (lua_State *L, char *str, size_t l)
1506 | // Returns GCstr *.
1508 | movn TMP1, #~LJ_TSTR
1509 | add CARG1, CARG1, TMP1, lsl #47
1515 | ldr CARG3, [BASE, #16]
1516 | cmp NARGS8:RC, #16
1519 | blo ->fff_fallback
1520 | checkint CARG3, ->fff_fallback
1523 | ldr CARG2, [BASE, #8]
1524 | checkstr CARG1, ->fff_fallback
1525 | ldr TMP1w, STR:CARG1->len
1526 | checkint CARG2, ->fff_fallback
1527 | sxtw CARG2, CARG2w
1528 | // CARG1 = str, TMP1 = str->len, CARG2 = start, RB = end
1529 | add TMP2, RB, TMP1
1531 | add TMP0, CARG2, TMP1
1532 | csinc RB, RB, TMP2, ge // if (end < 0) end += len+1
1534 | csinc CARG2, CARG2, TMP0, ge // if (start < 0) start += len+1
1536 | csel RB, RB, xzr, ge // if (end < 0) end = 0
1538 | csinc CARG2, CARG2, xzr, ge // if (start < 1) start = 1
1540 | csel RB, RB, TMP1, le // if (end > len) end = len
1541 | add CARG1, STR:CARG1, #sizeof(GCstr)-1
1542 | subs CARG3, RB, CARG2 // len = end - start
1543 | add CARG2, CARG1, CARG2
1544 | add CARG3, CARG3, #1 // len += 1
1546 | add STR:CARG1, GL, #offsetof(global_State, strempty)
1547 | movn TMP1, #~LJ_TSTR
1548 | add CARG1, CARG1, TMP1, lsl #47
1551 |.macro ffstring_op, name
1552 | .ffunc string_ .. name
1556 | asr ITYPE, CARG2, #47
1557 | ccmn ITYPE, #-LJ_TSTR, #0, hs
1558 | and STR:CARG2, CARG2, #LJ_GCVMASK
1559 | bne ->fff_fallback
1560 | ldr TMP0, GL->tmpbuf.b
1561 | add SBUF:CARG1, GL, #offsetof(global_State, tmpbuf)
1564 | str L, GL->tmpbuf.L
1565 | str TMP0, GL->tmpbuf.p
1566 | bl extern lj_buf_putstr_ .. name
1567 | bl extern lj_buf_tostr
1571 |ffstring_op reverse
1575 |//-- Bit library --------------------------------------------------------
1577 |// FP number to bit conversion for soft-float. Clobbers CARG1-CARG3
1579 | bls ->fff_fallback
1580 | add CARG2, CARG1, CARG1
1582 | sub CARG3, CARG3, CARG2, lsr #53
1585 | and CARG2, CARG2, #U64x(001fffff,ffffffff)
1586 | orr CARG2, CARG2, #U64x(00200000,00000000)
1588 | lsr CARG2, CARG2, CARG3
1589 | cneg CARG1w, CARG2w, mi
1595 |.macro .ffunc_bit, name
1596 | .ffunc_1 bit_..name
1598 | checkint CARG1, ->vm_tobit_fb
1602 |.macro .ffunc_bit_op, name, ins
1608 | ldr CARG1, [BASE, RA]
1612 | checkint CARG1, ->vm_tobit_fb
1614 | ins TMP0w, TMP0w, CARG1w
1618 |.ffunc_bit_op band, and
1619 |.ffunc_bit_op bor, orr
1620 |.ffunc_bit_op bxor, eor
1624 |9: // Label reused by .ffunc_bit_op users.
1625 | add CARG1, TMP0, TISNUM
1630 | add CARG1, TMP0, TISNUM
1635 | add CARG1, TMP0, TISNUM
1638 |.macro .ffunc_bit_sh, name, ins, shmod
1640 | ldp TMP0, CARG1, [BASE]
1641 | cmp NARGS8:RC, #16
1642 | blo ->fff_fallback
1644 | checkint CARG1, ->vm_tobit_fb
1653 | checkint CARG1, ->vm_tobit_fb
1655 | ins TMP0w, CARG1w, TMP1w
1656 | add CARG1, TMP0, TISNUM
1660 |.ffunc_bit_sh lshift, lsl, 0
1661 |.ffunc_bit_sh rshift, lsr, 0
1662 |.ffunc_bit_sh arshift, asr, 0
1663 |.ffunc_bit_sh rol, ror, 1
1664 |.ffunc_bit_sh ror, ror, 0
1666 |//-----------------------------------------------------------------------
1668 |->fff_fallback: // Call fast function fallback handler.
1669 | // BASE = new base, RC = nargs*8
1670 | ldp CFUNC:CARG3, PC, [BASE, FRAME_FUNC] // Fallback may overwrite PC.
1671 | ldr TMP2, L->maxstack
1672 | add TMP1, BASE, NARGS8:RC
1673 | stp BASE, TMP1, L->base
1674 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK
1675 | add TMP1, TMP1, #8*LUA_MINSTACK
1676 | ldr CARG3, CFUNC:CARG3->f
1677 | str PC, SAVE_PC // Redundant (but a defined value).
1680 | bhi >5 // Need to grow stack.
1681 | blr CARG3 // (lua_State *L)
1682 | // Either throws an error, or recovers and returns -1, 0 or nresults+1.
1687 | bgt ->fff_res // Returned nresults+1?
1688 |1: // Returned 0 or -1: retry fast path.
1690 | ldr CFUNC:CARG3, [BASE, FRAME_FUNC]
1691 | sub NARGS8:RC, CARG1, BASE
1692 | bne ->vm_call_tail // Returned -1?
1693 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK
1694 | ins_callt // Returned 0: retry fast path.
1696 |// Reconstruct previous base for vmeta_call during tailcall.
1698 | ands TMP0, PC, #FRAME_TYPE
1699 | and TMP1, PC, #~FRAME_TYPEP
1701 | ldrb RAw, [PC, #-3]
1705 | sub RB, BASE, TMP1
1706 | b ->vm_call_dispatch // Resolve again for tailcall.
1708 |5: // Grow stack for fallback handler.
1709 | mov CARG2, #LUA_MINSTACK
1710 | bl extern lj_state_growstack // (lua_State *L, int n)
1712 | cmp CARG1, CARG1 // Set zero-flag to force retry.
1715 |->fff_gcstep: // Call GC step function.
1716 | // BASE = new base, RC = nargs*8
1717 | add CARG2, BASE, NARGS8:RC // Calculate L->top.
1719 | stp BASE, CARG2, L->base
1720 | str PC, SAVE_PC // Redundant (but a defined value).
1722 | bl extern lj_gc_step // (lua_State *L)
1723 | ldp BASE, CARG2, L->base
1724 | ldr CFUNC:CARG3, [BASE, FRAME_FUNC]
1725 | mov lr, RA // Help return address predictor.
1726 | sub NARGS8:RC, CARG2, BASE // Calculate nargs*8.
1727 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK
1730 |//-----------------------------------------------------------------------
1731 |//-- Special dispatch targets -------------------------------------------
1732 |//-----------------------------------------------------------------------
1734 |->vm_record: // Dispatch target for recording phase.
1737 |->vm_rethook: // Dispatch target for return hooks.
1738 | ldrb TMP2w, GL->hookmask
1739 | tbz TMP2w, #HOOK_ACTIVE_SHIFT, >1 // Hook already active?
1740 |5: // Re-dispatch to static ins.
1741 | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC]
1744 |->vm_inshook: // Dispatch target for instr/line hooks.
1745 | ldrb TMP2w, GL->hookmask
1746 | ldr TMP3w, GL->hookcount
1747 | tbnz TMP2w, #HOOK_ACTIVE_SHIFT, <5 // Hook already active?
1748 | tst TMP2w, #LUA_MASKLINE|LUA_MASKCOUNT
1750 | sub TMP3w, TMP3w, #1
1751 | str TMP3w, GL->hookcount
1753 | tbz TMP2w, #LUA_HOOKLINE, <5
1758 | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
1759 | bl extern lj_dispatch_ins // (lua_State *L, const BCIns *pc)
1762 |4: // Re-dispatch to static ins.
1763 | ldr INSw, [PC, #-4]
1764 | add TMP1, GL, INS, uxtb #3
1766 | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC]
1770 |->cont_hook: // Continue from hook yield.
1771 | ldr CARG1, [CARG4, #-40]
1773 | str CARG1w, SAVE_MULTRES // Restore MULTRES for *M ins.
1776 |->vm_hotloop: // Hot loop counter underflow.
1779 |->vm_callhook: // Dispatch target for call hooks.
1785 |->vm_hotcall: // Hot call counter underflow.
1790 | add TMP1, BASE, NARGS8:RC
1794 | stp BASE, TMP1, L->base
1795 | bl extern lj_dispatch_call // (lua_State *L, const BCIns *pc)
1796 | // Returns ASMFunction.
1797 | ldp BASE, TMP1, L->base
1798 | str xzr, SAVE_PC // Invalidate for subsequent line hook.
1799 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
1801 | sub NARGS8:RC, TMP1, BASE
1802 | ldr INSw, [PC, #-4]
1803 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
1806 |->cont_stitch: // Trace stitching.
1809 |->vm_profhook: // Dispatch target for profiler hook.
1814 | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc)
1815 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
1821 |//-----------------------------------------------------------------------
1822 |//-- Trace exit handler -------------------------------------------------
1823 |//-----------------------------------------------------------------------
1830 |//-----------------------------------------------------------------------
1831 |//-- Math helper functions ----------------------------------------------
1832 |//-----------------------------------------------------------------------
1834 | // int lj_vm_modi(int dividend, int divisor);
1836 | eor CARG4w, CARG1w, CARG2w
1838 | eor CARG3w, CARG1w, CARG1w, asr #31
1839 | eor CARG4w, CARG2w, CARG2w, asr #31
1840 | sub CARG3w, CARG3w, CARG1w, asr #31
1841 | sub CARG4w, CARG4w, CARG2w, asr #31
1842 | udiv CARG1w, CARG3w, CARG4w
1843 | msub CARG1w, CARG1w, CARG4w, CARG3w
1844 | ccmp CARG1w, #0, #4, mi
1845 | sub CARG3w, CARG1w, CARG4w
1846 | csel CARG1w, CARG1w, CARG3w, eq
1847 | eor CARG3w, CARG1w, CARG2w
1849 | cneg CARG1w, CARG1w, mi
1852 |//-----------------------------------------------------------------------
1853 |//-- Miscellaneous functions --------------------------------------------
1854 |//-----------------------------------------------------------------------
1856 |//-----------------------------------------------------------------------
1857 |//-- FFI helper functions -----------------------------------------------
1858 |//-----------------------------------------------------------------------
1860 |// Handler for callback functions.
1861 |// Saveregs already performed. Callback slot number in [sp], g in r12.
1864 |.type CTSTATE, CTState, PC
1866 | ldr CTSTATE, GL:x10->ctype_state
1868 | add x10, sp, # CFRAME_SPACE
1869 | str w9, CTSTATE->cb.slot
1870 | stp x0, x1, CTSTATE->cb.gpr[0]
1871 | stp d0, d1, CTSTATE->cb.fpr[0]
1872 | stp x2, x3, CTSTATE->cb.gpr[2]
1873 | stp d2, d3, CTSTATE->cb.fpr[2]
1874 | stp x4, x5, CTSTATE->cb.gpr[4]
1875 | stp d4, d5, CTSTATE->cb.fpr[4]
1876 | stp x6, x7, CTSTATE->cb.gpr[6]
1877 | stp d6, d7, CTSTATE->cb.fpr[6]
1878 | str x10, CTSTATE->cb.stack
1879 | mov CARG1, CTSTATE
1880 | str CTSTATE, SAVE_PC // Any value outside of bytecode is ok.
1882 | bl extern lj_ccallback_enter // (CTState *cts, void *cf)
1883 | // Returns lua_State *.
1884 | ldp BASE, RC, L:CRET1->base
1885 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
1886 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
1889 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
1891 | st_vmstate ST_INTERP
1892 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
1896 |->cont_ffi_callback: // Return from FFI callback.
1898 | ldr CTSTATE, GL->ctype_state
1899 | stp BASE, CARG4, L->base
1901 | mov CARG1, CTSTATE
1903 | bl extern lj_ccallback_leave // (CTState *cts, TValue *o)
1904 | ldp x0, x1, CTSTATE->cb.gpr[0]
1905 | ldp d0, d1, CTSTATE->cb.fpr[0]
1909 |->vm_ffi_call: // Call C function via FFI.
1910 | // Caveat: needs special frame unwinding, see below.
1912 | .type CCSTATE, CCallState, x19
1913 | stp fp, lr, [sp, #-32]!
1915 | str CCSTATE, [sp, #16]
1917 | ldr TMP0w, CCSTATE:x0->spadj
1918 | ldrb TMP1w, CCSTATE->nsp
1919 | add TMP2, CCSTATE, #offsetof(CCallState, stack)
1920 | subs TMP1, TMP1, #1
1921 | ldr TMP3, CCSTATE->func
1924 |1: // Copy stack slots
1925 | ldr TMP0, [TMP2, TMP1, lsl #3]
1926 | str TMP0, [sp, TMP1, lsl #3]
1927 | subs TMP1, TMP1, #1
1930 | ldp x0, x1, CCSTATE->gpr[0]
1931 | ldp d0, d1, CCSTATE->fpr[0]
1932 | ldp x2, x3, CCSTATE->gpr[2]
1933 | ldp d2, d3, CCSTATE->fpr[2]
1934 | ldp x4, x5, CCSTATE->gpr[4]
1935 | ldp d4, d5, CCSTATE->fpr[4]
1936 | ldp x6, x7, CCSTATE->gpr[6]
1937 | ldp d6, d7, CCSTATE->fpr[6]
1938 | ldr x8, CCSTATE->retp
1941 | stp x0, x1, CCSTATE->gpr[0]
1942 | stp d0, d1, CCSTATE->fpr[0]
1943 | stp d2, d3, CCSTATE->fpr[2]
1944 | ldr CCSTATE, [sp, #16]
1945 | ldp fp, lr, [sp], #32
1948 |// Note: vm_ffi_call must be the last function in this object file!
1950 |//-----------------------------------------------------------------------
1953 /* Generate the code for a single instruction. */
1954 static void build_ins(BuildCtx *ctx, BCOp op, int defop)
1961 /* -- Comparison ops ---------------------------------------------------- */
1963 /* Remember: all ops branch for a true comparison, fall through otherwise. */
1965 case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
1966 | // RA = src1, RC = src2, JMP with RC = target
1967 | ldr CARG1, [BASE, RA, lsl #3]
1968 | ldrh RBw, [PC, #2]
1969 | ldr CARG2, [BASE, RC, lsl #3]
1971 | add RB, PC, RB, lsl #2
1972 | sub RB, RB, #0x20000
1973 | checkint CARG1, >3
1974 | checkint CARG2, >4
1975 | cmp CARG1w, CARG2w
1976 if (op == BC_ISLT) {
1977 | csel PC, RB, PC, lt
1978 } else if (op == BC_ISGE) {
1979 | csel PC, RB, PC, ge
1980 } else if (op == BC_ISLE) {
1981 | csel PC, RB, PC, le
1983 | csel PC, RB, PC, gt
1989 | ldr FARG1, [BASE, RA, lsl #3]
1991 | ldr FARG2, [BASE, RC, lsl #3]
1992 | cmp TISNUMhi, CARG2, lsr #32
1995 | // RA number, RC int.
1996 | scvtf FARG2, CARG2w
1999 |4: // RA int, RC not int
2000 | ldr FARG2, [BASE, RC, lsl #3]
2002 | // RA int, RC number.
2003 | scvtf FARG1, CARG1w
2005 |5: // RA number, RC number
2007 | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't.
2008 if (op == BC_ISLT) {
2009 | csel PC, RB, PC, lo
2010 } else if (op == BC_ISGE) {
2011 | csel PC, RB, PC, hs
2012 } else if (op == BC_ISLE) {
2013 | csel PC, RB, PC, ls
2015 | csel PC, RB, PC, hi
2020 case BC_ISEQV: case BC_ISNEV:
2021 vk = op == BC_ISEQV;
2022 | // RA = src1, RC = src2, JMP with RC = target
2023 | ldr CARG1, [BASE, RA, lsl #3]
2024 | add RC, BASE, RC, lsl #3
2025 | ldrh RBw, [PC, #2]
2028 | add RB, PC, RB, lsl #2
2029 | sub RB, RB, #0x20000
2030 | asr ITYPE, CARG3, #47
2031 | cmn ITYPE, #-LJ_TISNUM
2037 | // RC is not a number.
2038 | asr TMP0, CARG1, #47
2040 | // Check if RC or RA is a cdata.
2041 | cmn ITYPE, #-LJ_TCDATA
2042 | ccmn TMP0, #-LJ_TCDATA, #4, ne
2043 | beq ->vmeta_equal_cd
2047 | // Tag and value are equal.
2050 | mov PC, RB // Perform branch.
2055 |2: // Check if the tags are the same and it's a table or userdata.
2057 | ccmn ITYPE, #-LJ_TISTABUD, #2, eq
2061 | bhi ->BC_ISEQV_Z // Reuse code from opposite instruction.
2063 | // Different tables or userdatas. Need to check __eq metamethod.
2064 | // Field metatable must be at same offset for GCtab and GCudata!
2065 | and TAB:CARG2, CARG1, #LJ_GCVMASK
2066 | ldr TAB:TMP2, TAB:CARG2->metatable
2068 | cbz TAB:TMP2, <1 // No metatable?
2069 | ldrb TMP1w, TAB:TMP2->nomm
2070 | mov CARG4, #0 // ne = 0
2071 | tbnz TMP1w, #MM_eq, <1 // 'no __eq' flag set: done.
2073 | cbz TAB:TMP2, ->BC_ISEQV_Z // No metatable?
2074 | ldrb TMP1w, TAB:TMP2->nomm
2075 | mov CARG4, #1 // ne = 1.
2076 | tbnz TMP1w, #MM_eq, ->BC_ISEQV_Z // 'no __eq' flag set: done.
2081 case BC_ISEQS: case BC_ISNES:
2082 vk = op == BC_ISEQS;
2083 | // RA = src, RC = str_const (~), JMP with RC = target
2084 | ldr CARG1, [BASE, RA, lsl #3]
2086 | ldrh RBw, [PC, #2]
2087 | ldr CARG2, [KBASE, RC, lsl #3]
2089 | movn TMP0, #~LJ_TSTR
2091 | asr ITYPE, CARG1, #47
2093 | add RB, PC, RB, lsl #2
2094 | add CARG2, CARG2, TMP0, lsl #47
2095 | sub RB, RB, #0x20000
2097 | cmn ITYPE, #-LJ_TCDATA
2098 | beq ->vmeta_equal_cd
2102 | csel PC, RB, PC, eq
2104 | csel PC, RB, PC, ne
2109 case BC_ISEQN: case BC_ISNEN:
2110 vk = op == BC_ISEQN;
2111 | // RA = src, RC = num_const (~), JMP with RC = target
2112 | ldr CARG1, [BASE, RA, lsl #3]
2113 | add RC, KBASE, RC, lsl #3
2114 | ldrh RBw, [PC, #2]
2117 | add RB, PC, RB, lsl #2
2118 | sub RB, RB, #0x20000
2124 | checkint CARG1, >4
2125 | checkint CARG3, >6
2126 | cmp CARG1w, CARG3w
2129 | csel PC, RB, PC, eq
2133 | csel PC, RB, PC, ne
2144 | ldr FARG1, [BASE, RA, lsl #3]
2146 | cmp TISNUMhi, CARG3, lsr #32
2148 | // RA number, RC int.
2149 | scvtf FARG2, CARG3w
2151 | // RA number, RC number.
2155 |6: // RA int, RC number
2157 | scvtf FARG1, CARG1w
2163 | asr ITYPE, CARG1, #47
2164 | cmn ITYPE, #-LJ_TCDATA
2166 | b ->vmeta_equal_cd
2170 case BC_ISEQP: case BC_ISNEP:
2171 vk = op == BC_ISEQP;
2172 | // RA = src, RC = primitive_type (~), JMP with RC = target
2173 | ldr TMP0, [BASE, RA, lsl #3]
2174 | ldrh RBw, [PC, #2]
2177 | add RB, PC, RB, lsl #2
2179 | asr ITYPE, TMP0, #47
2180 | cmn ITYPE, #-LJ_TCDATA
2181 | beq ->vmeta_equal_cd
2184 | cmn RC, TMP0, asr #47
2186 | sub RB, RB, #0x20000
2188 | csel PC, RB, PC, eq
2190 | csel PC, RB, PC, ne
2195 /* -- Unary test and copy ops ------------------------------------------- */
2197 case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
2198 | // RA = dst or unused, RC = src, JMP with RC = target
2199 | ldrh RBw, [PC, #2]
2200 | ldr TMP0, [BASE, RC, lsl #3]
2203 | add RB, PC, RB, lsl #2
2205 | sub RB, RB, #0x20000
2206 if (op == BC_ISTC || op == BC_IST) {
2207 if (op == BC_ISTC) {
2208 | csel RA, RA, RC, lo
2210 | csel PC, RB, PC, lo
2212 if (op == BC_ISFC) {
2213 | csel RA, RA, RC, hs
2215 | csel PC, RB, PC, hs
2217 if (op == BC_ISTC || op == BC_ISFC) {
2218 | str TMP0, [BASE, RA, lsl #3]
2224 | // RA = src, RC = -type
2225 | ldr TMP0, [BASE, RA, lsl #3]
2226 | cmn RC, TMP0, asr #47
2227 | bne ->vmeta_istype
2231 | // RA = src, RC = -(TISNUM-1)
2232 | ldr TMP0, [BASE, RA]
2233 | checknum TMP0, ->vmeta_istype
2237 /* -- Unary ops --------------------------------------------------------- */
2240 | // RA = dst, RC = src
2241 | ldr TMP0, [BASE, RC, lsl #3]
2242 | str TMP0, [BASE, RA, lsl #3]
2246 | // RA = dst, RC = src
2247 | ldr TMP0, [BASE, RC, lsl #3]
2251 | csel TMP0, TMP1, TMP2, lo
2252 | str TMP0, [BASE, RA, lsl #3]
2256 | // RA = dst, RC = src
2257 | ldr TMP0, [BASE, RC, lsl #3]
2258 | asr ITYPE, TMP0, #47
2259 | cmn ITYPE, #-LJ_TISNUM
2261 | eor TMP0, TMP0, #U64x(80000000,00000000)
2264 | movz CARG3, #0x41e0, lsl #48 // 2^31.
2265 | add TMP0, TMP0, TISNUM
2266 | csel TMP0, TMP0, CARG3, vc
2268 | str TMP0, [BASE, RA, lsl #3]
2272 | // RA = dst, RC = src
2273 | ldr CARG1, [BASE, RC, lsl #3]
2274 | asr ITYPE, CARG1, #47
2275 | cmn ITYPE, #-LJ_TSTR
2276 | and CARG1, CARG1, #LJ_GCVMASK
2278 | ldr CARG1w, STR:CARG1->len
2280 | add CARG1, CARG1, TISNUM
2281 | str CARG1, [BASE, RA, lsl #3]
2285 | cmn ITYPE, #-LJ_TTAB
2288 | ldr TAB:CARG2, TAB:CARG1->metatable
2289 | cbnz TAB:CARG2, >9
2293 | bl extern lj_tab_len // (GCtab *t)
2294 | // Returns uint32_t (but less than 2^31).
2299 | ldrb TMP1w, TAB:CARG2->nomm
2300 | tbnz TMP1w, #MM_len, <3 // 'no __len' flag set: done.
2305 /* -- Binary ops -------------------------------------------------------- */
2307 |.macro ins_arithcheck_int, target
2308 | checkint CARG1, target
2309 | checkint CARG2, target
2312 |.macro ins_arithcheck_num, target
2313 | checknum CARG1, target
2314 | checknum CARG2, target
2317 |.macro ins_arithcheck_nzdiv, target
2318 | cbz CARG2w, target
2321 |.macro ins_arithhead
2322 ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
2332 |.macro ins_arithload, reg1, reg2
2333 | // RA = dst, RB = src1, RC = src2 | num_const
2336 | ldr reg1, [BASE, RB, lsl #3]
2337 | ldr reg2, [KBASE, RC, lsl #3]
2340 | ldr reg1, [KBASE, RC, lsl #3]
2341 | ldr reg2, [BASE, RB, lsl #3]
2344 | ldr reg1, [BASE, RB, lsl #3]
2345 | ldr reg2, [BASE, RC, lsl #3]
2350 |.macro ins_arithfallback, ins
2353 | ins ->vmeta_arith_vn
2356 | ins ->vmeta_arith_nv
2359 | ins ->vmeta_arith_vv
2364 |.macro ins_arithmod, res, reg1, reg2
2365 | fdiv d2, reg1, reg2
2367 | fmsub res, d2, reg2, reg1
2370 |.macro ins_arithdn, intins, fpins
2372 | ins_arithload CARG1, CARG2
2373 | ins_arithcheck_int >5
2374 |.if "intins" == "smull"
2375 | smull CARG1, CARG1w, CARG2w
2376 | cmp CARG1, CARG1, sxtw
2377 | mov CARG1w, CARG1w
2378 | ins_arithfallback bne
2379 |.elif "intins" == "ins_arithmodi"
2380 | ins_arithfallback ins_arithcheck_nzdiv
2383 | intins CARG1w, CARG1w, CARG2w
2384 | ins_arithfallback bvs
2386 | add CARG1, CARG1, TISNUM
2387 | str CARG1, [BASE, RA, lsl #3]
2392 | ins_arithload FARG1, FARG2
2393 | ins_arithfallback ins_arithcheck_num
2394 | fpins FARG1, FARG1, FARG2
2395 | str FARG1, [BASE, RA, lsl #3]
2399 |.macro ins_arithfp, fpins
2401 | ins_arithload CARG1, CARG2
2402 | ins_arithload FARG1, FARG2
2403 | ins_arithfallback ins_arithcheck_num
2404 |.if "fpins" == "fpow"
2407 | fpins FARG1, FARG1, FARG2
2409 | str FARG1, [BASE, RA, lsl #3]
2413 case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
2414 | ins_arithdn adds, fadd
2416 case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
2417 | ins_arithdn subs, fsub
2419 case BC_MULVN: case BC_MULNV: case BC_MULVV:
2420 | ins_arithdn smull, fmul
2422 case BC_DIVVN: case BC_DIVNV: case BC_DIVVV:
2425 case BC_MODVN: case BC_MODNV: case BC_MODVV:
2426 | ins_arithdn ins_arithmodi, ins_arithmod
2429 | // NYI: (partial) integer arithmetic.
2436 | // RA = dst, RB = src_start, RC = src_end
2439 | add CARG2, BASE, RC, lsl #3
2441 | // RA = dst, CARG2 = top-1, CARG3 = left
2444 | bl extern lj_meta_cat // (lua_State *L, TValue *top, int left)
2445 | // Returns NULL (finished) or TValue * (metamethod).
2446 | ldrb RBw, [PC, #-1]
2448 | cbnz CRET1, ->vmeta_binop
2449 | ldr TMP0, [BASE, RB, lsl #3]
2450 | str TMP0, [BASE, RA, lsl #3] // Copy result to RA.
2454 /* -- Constant ops ------------------------------------------------------ */
2457 | // RA = dst, RC = str_const (~)
2459 | ldr TMP0, [KBASE, RC, lsl #3]
2460 | movn TMP1, #~LJ_TSTR
2461 | add TMP0, TMP0, TMP1, lsl #47
2462 | str TMP0, [BASE, RA, lsl #3]
2467 | // RA = dst, RC = cdata_const (~)
2469 | ldr TMP0, [KBASE, RC, lsl #3]
2470 | movn TMP1, #~LJ_TCDATA
2471 | add TMP0, TMP0, TMP1, lsl #47
2472 | str TMP0, [BASE, RA, lsl #3]
2477 | // RA = dst, RC = int16_literal
2479 | add TMP0, RC, TISNUM
2480 | str TMP0, [BASE, RA, lsl #3]
2484 | // RA = dst, RC = num_const
2485 | ldr TMP0, [KBASE, RC, lsl #3]
2486 | str TMP0, [BASE, RA, lsl #3]
2490 | // RA = dst, RC = primitive_type (~)
2491 | mvn TMP0, RC, lsl #47
2492 | str TMP0, [BASE, RA, lsl #3]
2496 | // RA = base, RC = end
2497 | add RA, BASE, RA, lsl #3
2498 | add RC, BASE, RC, lsl #3
2499 | str TISNIL, [RA], #8
2502 | str TISNIL, [RA], #8
2507 /* -- Upvalue and function ops ------------------------------------------ */
2510 | // RA = dst, RC = uvnum
2511 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2512 | add RC, RC, #offsetof(GCfuncL, uvptr)/8
2513 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2514 | ldr UPVAL:CARG2, [LFUNC:CARG2, RC, lsl #3]
2515 | ldr CARG2, UPVAL:CARG2->v
2517 | str TMP0, [BASE, RA, lsl #3]
2521 | // RA = uvnum, RC = src
2522 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2523 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2524 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2525 | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3]
2526 | ldr CARG3, [BASE, RC, lsl #3]
2527 | ldr CARG2, UPVAL:CARG1->v
2528 | ldrb TMP2w, UPVAL:CARG1->marked
2529 | ldrb TMP0w, UPVAL:CARG1->closed
2530 | asr ITYPE, CARG3, #47
2531 | str CARG3, [CARG2]
2532 | add ITYPE, ITYPE, #-LJ_TISGCV
2533 | tst TMP2w, #LJ_GC_BLACK // isblack(uv)
2534 | ccmp TMP0w, #0, #4, ne // && uv->closed
2535 | ccmn ITYPE, #-(LJ_TNUMX - LJ_TISGCV), #0, ne // && tvisgcv(v)
2540 |2: // Check if new value is white.
2541 | and GCOBJ:CARG3, CARG3, #LJ_GCVMASK
2542 | ldrb TMP1w, GCOBJ:CARG3->gch.marked
2543 | tst TMP1w, #LJ_GC_WHITES // iswhite(str)
2545 | // Crossed a write barrier. Move the barrier forward.
2547 | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv)
2551 | // RA = uvnum, RC = str_const (~)
2552 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2553 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2555 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2556 | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3]
2557 | ldr STR:CARG3, [KBASE, RC, lsl #3]
2558 | movn TMP0, #~LJ_TSTR
2559 | ldr CARG2, UPVAL:CARG1->v
2560 | ldrb TMP2w, UPVAL:CARG1->marked
2561 | add TMP0, STR:CARG3, TMP0, lsl #47
2562 | ldrb TMP1w, STR:CARG3->marked
2564 | tbnz TMP2w, #2, >2 // isblack(uv)
2568 |2: // Check if string is white and ensure upvalue is closed.
2569 | ldrb TMP0w, UPVAL:CARG1->closed
2570 | tst TMP1w, #LJ_GC_WHITES // iswhite(str)
2571 | ccmp TMP0w, #0, #0, ne
2573 | // Crossed a write barrier. Move the barrier forward.
2575 | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv)
2579 | // RA = uvnum, RC = num_const
2580 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2581 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2582 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2583 | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3]
2584 | ldr TMP0, [KBASE, RC, lsl #3]
2585 | ldr CARG2, UPVAL:CARG2->v
2590 | // RA = uvnum, RC = primitive_type (~)
2591 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2592 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2593 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2594 | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3]
2595 | mvn TMP0, RC, lsl #47
2596 | ldr CARG2, UPVAL:CARG2->v
2602 | // RA = level, RC = target
2603 | ldr CARG3, L->openupval
2604 | add RC, PC, RC, lsl #2
2606 | sub PC, RC, #0x20000
2609 | add CARG2, BASE, RA, lsl #3
2610 | bl extern lj_func_closeuv // (lua_State *L, TValue *level)
2617 | // RA = dst, RC = proto_const (~) (holding function prototype)
2620 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
2622 | ldr CARG2, [KBASE, RC, lsl #3]
2624 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
2625 | // (lua_State *L, GCproto *pt, GCfuncL *parent)
2626 | bl extern lj_func_newL_gc
2627 | // Returns GCfuncL *.
2629 | movn TMP0, #~LJ_TFUNC
2630 | add CRET1, CRET1, TMP0, lsl #47
2631 | str CRET1, [BASE, RA, lsl #3]
2635 /* -- Table ops --------------------------------------------------------- */
2639 | // RA = dst, RC = (hbits|asize) | tab_const (~)
2640 | ldp CARG3, CARG4, GL->gc.total // Assumes threshold follows total.
2647 if (op == BC_TNEW) {
2648 | and CARG2, RC, #0x7ff
2649 | lsr CARG3, RC, #11
2652 | csel CARG2, CARG2, TMP0, ne
2653 | bl extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits)
2654 | // Returns GCtab *.
2657 | ldr CARG2, [KBASE, RC, lsl #3]
2658 | bl extern lj_tab_dup // (lua_State *L, Table *kt)
2659 | // Returns GCtab *.
2662 | movk CRET1, #(LJ_TTAB>>1)&0xffff, lsl #48
2663 | str CRET1, [BASE, RA, lsl #3]
2667 | bl extern lj_gc_step_fixtop // (lua_State *L)
2673 | // RA = dst, RC = str_const (~)
2675 | // RA = dst, RC = str_const (~)
2676 | ldr LFUNC:CARG1, [BASE, FRAME_FUNC]
2678 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
2679 | ldr TAB:CARG2, LFUNC:CARG1->env
2680 | ldr STR:RC, [KBASE, RC, lsl #3]
2681 if (op == BC_GGET) {
2691 | // RA = dst, RB = table, RC = key
2692 | ldr CARG2, [BASE, RB, lsl #3]
2693 | ldr TMP1, [BASE, RC, lsl #3]
2694 | checktab CARG2, ->vmeta_tgetv
2695 | checkint TMP1, >9 // Integer key?
2696 | ldr CARG3, TAB:CARG2->array
2697 | ldr CARG1w, TAB:CARG2->asize
2698 | add CARG3, CARG3, TMP1, uxtw #3
2699 | cmp TMP1w, CARG1w // In array part?
2705 | str TMP0, [BASE, RA, lsl #3]
2708 |5: // Check for __index if table value is nil.
2709 | ldr TAB:CARG1, TAB:CARG2->metatable
2710 | cbz TAB:CARG1, <1 // No metatable: done.
2711 | ldrb TMP1w, TAB:CARG1->nomm
2712 | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done.
2716 | asr ITYPE, TMP1, #47
2717 | cmn ITYPE, #-LJ_TSTR // String key?
2719 | and STR:RC, TMP1, #LJ_GCVMASK
2725 | // RA = dst, RB = table, RC = str_const (~)
2726 | ldr CARG2, [BASE, RB, lsl #3]
2728 | ldr STR:RC, [KBASE, RC, lsl #3]
2729 | checktab CARG2, ->vmeta_tgets1
2731 | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = dst
2732 | ldr TMP1w, TAB:CARG2->hmask
2733 | ldr TMP2w, STR:RC->hash
2734 | ldr NODE:CARG3, TAB:CARG2->node
2735 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask
2736 | add TMP1, TMP1, TMP1, lsl #1
2737 | movn CARG4, #~LJ_TSTR
2738 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8
2739 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for.
2741 | ldp TMP0, CARG1, NODE:CARG3->val
2742 | ldr NODE:CARG3, NODE:CARG3->next
2748 | str TMP0, [BASE, RA, lsl #3]
2751 |4: // Follow hash chain.
2752 | cbnz NODE:CARG3, <1
2753 | // End of hash chain: key not found, nil result.
2756 |5: // Check for __index if table value is nil.
2757 | ldr TAB:CARG1, TAB:CARG2->metatable
2758 | cbz TAB:CARG1, <3 // No metatable: done.
2759 | ldrb TMP1w, TAB:CARG1->nomm
2760 | tbnz TMP1w, #MM_index, <3 // 'no __index' flag set: done.
2766 | // RA = dst, RB = table, RC = index
2767 | ldr CARG2, [BASE, RB, lsl #3]
2768 | checktab CARG2, ->vmeta_tgetb
2769 | ldr CARG3, TAB:CARG2->array
2770 | ldr CARG1w, TAB:CARG2->asize
2771 | add CARG3, CARG3, RC, lsl #3
2772 | cmp RCw, CARG1w // In array part?
2778 | str TMP0, [BASE, RA, lsl #3]
2781 |5: // Check for __index if table value is nil.
2782 | ldr TAB:CARG1, TAB:CARG2->metatable
2783 | cbz TAB:CARG1, <1 // No metatable: done.
2784 | ldrb TMP1w, TAB:CARG1->nomm
2785 | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done.
2791 | // RA = dst, RB = table, RC = key
2792 | ldr CARG1, [BASE, RB, lsl #3]
2793 | ldr TMP1, [BASE, RC, lsl #3]
2794 | and TAB:CARG1, CARG1, #LJ_GCVMASK
2795 | ldr CARG3, TAB:CARG1->array
2796 | ldr TMP2w, TAB:CARG1->asize
2797 | add CARG3, CARG3, TMP1w, uxtw #3
2798 | cmp TMP1w, TMP2w // In array part?
2802 | str TMP0, [BASE, RA, lsl #3]
2809 | // RA = src, RB = table, RC = key
2810 | ldr CARG2, [BASE, RB, lsl #3]
2811 | ldr TMP1, [BASE, RC, lsl #3]
2812 | checktab CARG2, ->vmeta_tsetv
2813 | checkint TMP1, >9 // Integer key?
2814 | ldr CARG3, TAB:CARG2->array
2815 | ldr CARG1w, TAB:CARG2->asize
2816 | add CARG3, CARG3, TMP1, uxtw #3
2817 | cmp TMP1w, CARG1w // In array part?
2820 | ldr TMP0, [BASE, RA, lsl #3]
2821 | ldrb TMP2w, TAB:CARG2->marked
2822 | cmp TMP1, TISNIL // Previous value is nil?
2826 | tbnz TMP2w, #2, >7 // isblack(table)
2830 |5: // Check for __newindex if previous value is nil.
2831 | ldr TAB:CARG1, TAB:CARG2->metatable
2832 | cbz TAB:CARG1, <1 // No metatable: done.
2833 | ldrb TMP1w, TAB:CARG1->nomm
2834 | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done.
2837 |7: // Possible table write barrier for the value. Skip valiswhite check.
2838 | barrierback TAB:CARG2, TMP2w, TMP1
2842 | asr ITYPE, TMP1, #47
2843 | cmn ITYPE, #-LJ_TSTR // String key?
2845 | and STR:RC, TMP1, #LJ_GCVMASK
2851 | // RA = dst, RB = table, RC = str_const (~)
2852 | ldr CARG2, [BASE, RB, lsl #3]
2854 | ldr STR:RC, [KBASE, RC, lsl #3]
2855 | checktab CARG2, ->vmeta_tsets1
2857 | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = src
2858 | ldr TMP1w, TAB:CARG2->hmask
2859 | ldr TMP2w, STR:RC->hash
2860 | ldr NODE:CARG3, TAB:CARG2->node
2861 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask
2862 | add TMP1, TMP1, TMP1, lsl #1
2863 | movn CARG4, #~LJ_TSTR
2864 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8
2865 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for.
2866 | strb wzr, TAB:CARG2->nomm // Clear metamethod cache.
2868 | ldp TMP1, CARG1, NODE:CARG3->val
2869 | ldr NODE:TMP3, NODE:CARG3->next
2870 | ldrb TMP2w, TAB:CARG2->marked
2873 | ldr TMP0, [BASE, RA, lsl #3]
2874 | cmp TMP1, TISNIL // Previous value is nil?
2877 | str TMP0, NODE:CARG3->val
2878 | tbnz TMP2w, #2, >7 // isblack(table)
2882 |4: // Check for __newindex if previous value is nil.
2883 | ldr TAB:CARG1, TAB:CARG2->metatable
2884 | cbz TAB:CARG1, <2 // No metatable: done.
2885 | ldrb TMP1w, TAB:CARG1->nomm
2886 | tbnz TMP1w, #MM_newindex, <2 // 'no __newindex' flag set: done.
2889 |5: // Follow hash chain.
2890 | mov NODE:CARG3, NODE:TMP3
2891 | cbnz NODE:TMP3, <1
2892 | // End of hash chain: key not found, add a new one.
2894 | // But check for __newindex first.
2895 | ldr TAB:CARG1, TAB:CARG2->metatable
2896 | cbz TAB:CARG1, >6 // No metatable: continue.
2897 | ldrb TMP1w, TAB:CARG1->nomm
2898 | // 'no __newindex' flag NOT set: check.
2899 | tbz TMP1w, #MM_newindex, ->vmeta_tsets
2901 | movn TMP1, #~LJ_TSTR
2903 | add TMP0, STR:RC, TMP1, lsl #47
2907 | add CARG3, sp, TMPDofs
2908 | bl extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k)
2909 | // Returns TValue *.
2911 | ldr TMP0, [BASE, RA, lsl #3]
2913 | b <3 // No 2nd write barrier needed.
2915 |7: // Possible table write barrier for the value. Skip valiswhite check.
2916 | barrierback TAB:CARG2, TMP2w, TMP1
2922 | // RA = src, RB = table, RC = index
2923 | ldr CARG2, [BASE, RB, lsl #3]
2924 | checktab CARG2, ->vmeta_tsetb
2925 | ldr CARG3, TAB:CARG2->array
2926 | ldr CARG1w, TAB:CARG2->asize
2927 | add CARG3, CARG3, RC, lsl #3
2928 | cmp RCw, CARG1w // In array part?
2931 | ldr TMP0, [BASE, RA, lsl #3]
2932 | ldrb TMP2w, TAB:CARG2->marked
2933 | cmp TMP1, TISNIL // Previous value is nil?
2937 | tbnz TMP2w, #2, >7 // isblack(table)
2941 |5: // Check for __newindex if previous value is nil.
2942 | ldr TAB:CARG1, TAB:CARG2->metatable
2943 | cbz TAB:CARG1, <1 // No metatable: done.
2944 | ldrb TMP1w, TAB:CARG1->nomm
2945 | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done.
2948 |7: // Possible table write barrier for the value. Skip valiswhite check.
2949 | barrierback TAB:CARG2, TMP2w, TMP1
2955 | // RA = src, RB = table, RC = key
2956 | ldr CARG2, [BASE, RB, lsl #3]
2957 | ldr TMP1, [BASE, RC, lsl #3]
2958 | and TAB:CARG2, CARG2, #LJ_GCVMASK
2959 | ldr CARG1, TAB:CARG2->array
2960 | ldrb TMP2w, TAB:CARG2->marked
2961 | ldr CARG4w, TAB:CARG2->asize
2962 | add CARG1, CARG1, TMP1, uxtw #3
2963 | tbnz TMP2w, #2, >7 // isblack(table)
2965 | cmp TMP1w, CARG4w // In array part?
2968 | ldr TMP0, [BASE, RA, lsl #3]
2972 |7: // Possible table write barrier for the value. Skip valiswhite check.
2973 | barrierback TAB:CARG2, TMP2w, TMP0
2978 | // RA = base (table at base-1), RC = num_const (start index)
2979 | add RA, BASE, RA, lsl #3
2981 | ldr RBw, SAVE_MULTRES
2982 | ldr TAB:CARG2, [RA, #-8] // Guaranteed to be a table.
2983 | ldr TMP1, [KBASE, RC, lsl #3] // Integer constant is in lo-word.
2985 | cbz RB, >4 // Nothing to copy?
2986 | and TAB:CARG2, CARG2, #LJ_GCVMASK
2987 | ldr CARG1w, TAB:CARG2->asize
2988 | add CARG3w, TMP1w, RBw, lsr #3
2989 | ldr CARG4, TAB:CARG2->array
2993 | add TMP1, CARG4, TMP1w, uxtw #3
2994 | ldrb TMP2w, TAB:CARG2->marked
2995 |3: // Copy result slots to table.
2996 | ldr TMP0, [RA], #8
2997 | str TMP0, [TMP1], #8
3000 | tbnz TMP2w, #2, >7 // isblack(table)
3004 |5: // Need to resize array part.
3008 | bl extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize)
3009 | // Must not reallocate the stack.
3012 |7: // Possible table write barrier for any value. Skip valiswhite check.
3013 | barrierback TAB:CARG2, TMP2w, TMP1
3017 /* -- Calls and vararg handling ----------------------------------------- */
3020 | // RA = base, (RB = nresults+1,) RC = extra_nargs
3021 | ldr TMP0w, SAVE_MULTRES
3022 | decode_RC8RD NARGS8:RC, RC
3023 | add NARGS8:RC, NARGS8:RC, TMP0
3027 | decode_RC8RD NARGS8:RC, RC
3028 | // RA = base, (RB = nresults+1,) RC = (nargs+1)*8
3030 | mov RB, BASE // Save old BASE for vmeta_call.
3031 | add BASE, BASE, RA, lsl #3
3033 | sub NARGS8:RC, NARGS8:RC, #8
3034 | add BASE, BASE, #16
3035 | checkfunc CARG3, ->vmeta_call
3040 | // RA = base, (RB = 0,) RC = extra_nargs
3041 | ldr TMP0w, SAVE_MULTRES
3042 | add NARGS8:RC, TMP0, RC, lsl #3
3046 | lsl NARGS8:RC, RC, #3
3047 | // RA = base, (RB = 0,) RC = (nargs+1)*8
3049 | add RA, BASE, RA, lsl #3
3051 | sub NARGS8:RC, NARGS8:RC, #8
3053 | checktp CARG3, TMP1, LJ_TFUNC, ->vmeta_callt
3054 | ldr PC, [BASE, FRAME_PC]
3057 | ldrb TMP2w, LFUNC:CARG3->ffid
3058 | tst PC, #FRAME_TYPE
3061 | str TMP1, [BASE, FRAME_FUNC] // Copy function down, but keep PC.
3064 | ldr TMP0, [RA, RB]
3066 | cmp TMP1, NARGS8:RC
3067 | str TMP0, [BASE, RB]
3071 | cmp TMP2, #1 // (> FF_C) Calling a fast function?
3076 |5: // Tailcall to a fast function with a Lua frame below.
3077 | ldrb RAw, [PC, #-3]
3078 | sub CARG1, BASE, RA, lsl #3
3079 | ldr LFUNC:CARG1, [CARG1, #-32]
3080 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
3081 | ldr CARG1, LFUNC:CARG1->pc
3082 | ldr KBASE, [CARG1, #PC2PROTO(k)]
3085 |7: // Tailcall from a vararg function.
3086 | eor PC, PC, #FRAME_VARG
3087 | tst PC, #FRAME_TYPEP // Vararg frame below?
3088 | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below.
3090 | sub BASE, BASE, PC
3091 | ldr PC, [BASE, FRAME_PC]
3092 | tst PC, #FRAME_TYPE
3093 | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below.
3098 | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1))
3099 | add RA, BASE, RA, lsl #3
3100 | ldr CARG3, [RA, #-24]
3101 | mov RB, BASE // Save old BASE for vmeta_call.
3102 | ldp CARG1, CARG2, [RA, #-16]
3104 | mov NARGS8:RC, #16 // Iterators get 2 arguments.
3105 | str CARG3, [RA] // Copy callable.
3106 | stp CARG1, CARG2, [RA, #16] // Copy state and control var.
3107 | checkfunc CARG3, ->vmeta_call
3112 | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1))
3114 | // NYI: add hotloop, record BC_ITERN.
3116 | add RA, BASE, RA, lsl #3
3117 | ldr TAB:RB, [RA, #-16]
3118 | ldrh TMP3w, [PC, #2]
3119 | ldr CARG1w, [RA, #-8] // Get index from control var.
3121 | add TMP3, PC, TMP3, lsl #2
3122 | and TAB:RB, RB, #LJ_GCVMASK
3123 | sub TMP3, TMP3, #0x20000
3124 | ldr TMP1w, TAB:RB->asize
3125 | ldr CARG2, TAB:RB->array
3126 |1: // Traverse array part.
3127 | subs RC, CARG1, TMP1
3128 | add CARG3, CARG2, CARG1, lsl #3
3129 | bhs >5 // Index points after array part?
3132 | cinc CARG1, CARG1, eq // Skip holes in array part.
3134 | add CARG1, CARG1, TISNUM
3135 | stp CARG1, TMP0, [RA]
3136 | add CARG1, CARG1, #1
3138 | str CARG1w, [RA, #-8] // Update control var.
3143 |5: // Traverse hash part.
3144 | ldr TMP2w, TAB:RB->hmask
3145 | ldr NODE:RB, TAB:RB->node
3147 | add CARG1, RC, RC, lsl #1
3148 | cmp RC, TMP2 // End of iteration? Branch to ITERN+1.
3149 | add NODE:CARG3, NODE:RB, CARG1, lsl #3 // node = tab->node + idx*3*8
3151 | ldp TMP0, CARG1, NODE:CARG3->val
3154 | beq <6 // Skip holes in hash part.
3155 | stp CARG1, TMP0, [RA]
3156 | add CARG1, RC, TMP1
3161 | // RA = base, RC = target (points to ITERN)
3162 | add RA, BASE, RA, lsl #3
3163 | ldr CFUNC:CARG1, [RA, #-24]
3164 | add RC, PC, RC, lsl #2
3165 | ldp TAB:CARG3, CARG4, [RA, #-16]
3166 | sub RC, RC, #0x20000
3167 | checkfunc CFUNC:CARG1, >5
3168 | asr TMP0, TAB:CARG3, #47
3169 | ldrb TMP1w, CFUNC:CARG1->ffid
3170 | cmn TMP0, #-LJ_TTAB
3171 | ccmp CARG4, TISNIL, #0, eq
3172 | ccmp TMP1w, #FF_next_N, #0, eq
3174 | mov TMP0w, #0xfffe7fff
3175 | lsl TMP0, TMP0, #32
3176 | str TMP0, [RA, #-8] // Initialize control var.
3181 |5: // Despecialize bytecode if any of the checks fail.
3183 | mov TMP1, #BC_ITERC
3184 | strb TMP0w, [PC, #-4]
3192 | // RA = base, RB = (nresults+1), RC = numparams
3193 | ldr TMP1, [BASE, FRAME_PC]
3194 | add RC, BASE, RC, lsl #3
3195 | add RA, BASE, RA, lsl #3
3196 | add RC, RC, #FRAME_VARG
3197 | add TMP2, RA, RB, lsl #3
3198 | sub RC, RC, TMP1 // RC = vbase
3199 | // Note: RC may now be even _above_ BASE if nargs was < numparams.
3200 | sub TMP3, BASE, #16 // TMP3 = vtop
3202 | sub TMP2, TMP2, #16
3203 |1: // Copy vararg slots to destination slots.
3205 | ldr TMP0, [RC], #8
3206 | csel TMP0, TMP0, TISNIL, lo
3208 | str TMP0, [RA], #8
3213 |5: // Copy all varargs.
3214 | ldr TMP0, L->maxstack
3215 | subs TMP2, TMP3, RC
3216 | csel RB, xzr, TMP2, le // MULTRES = (max(vtop-vbase,0)+1)*8
3218 | add TMP1, RA, TMP2
3219 | str RBw, SAVE_MULTRES
3220 | ble <2 // Nothing to copy.
3224 | ldr TMP0, [RC], #8
3225 | str TMP0, [RA], #8
3230 |7: // Grow stack for varargs.
3231 | lsr CARG2, TMP2, #3
3232 | stp BASE, RA, L->base
3234 | sub RC, RC, BASE // Need delta, because BASE may change.
3236 | bl extern lj_state_growstack // (lua_State *L, int n)
3237 | ldp BASE, RA, L->base
3239 | sub TMP3, BASE, #16
3243 /* -- Returns ----------------------------------------------------------- */
3246 | // RA = results, RC = extra results
3247 | ldr TMP0w, SAVE_MULTRES
3248 | ldr PC, [BASE, FRAME_PC]
3249 | add RA, BASE, RA, lsl #3
3250 | add RC, TMP0, RC, lsl #3
3255 | // RA = results, RC = nresults+1
3256 | ldr PC, [BASE, FRAME_PC]
3258 | add RA, BASE, RA, lsl #3
3260 | str RCw, SAVE_MULTRES
3262 | ands CARG1, PC, #FRAME_TYPE
3263 | eor CARG2, PC, #FRAME_VARG
3267 | // BASE = base, RA = resultptr, RC = (nresults+1)*8, PC = return
3268 | ldr INSw, [PC, #-4]
3270 | sub CARG3, BASE, #16
3273 | ldr TMP0, [RA], #8
3274 | add BASE, BASE, #8
3275 | sub TMP1, TMP1, #8
3276 | str TMP0, [BASE, #-24]
3280 | sub CARG4, CARG3, RA, lsl #3
3282 | ldr LFUNC:CARG1, [CARG4, FRAME_FUNC]
3284 | cmp RC, RB, lsl #3 // More results expected?
3286 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
3288 | ldr CARG2, LFUNC:CARG1->pc
3289 | ldr KBASE, [CARG2, #PC2PROTO(k)]
3292 |6: // Fill up results with nil.
3293 | add BASE, BASE, #8
3295 | str TISNIL, [BASE, #-24]
3298 |->BC_RETV1_Z: // Non-standard return case.
3299 | add RA, BASE, RA, lsl #3
3301 | tst CARG2, #FRAME_TYPEP
3303 | // Return from vararg function: relocate BASE down.
3304 | sub BASE, BASE, CARG2
3305 | ldr PC, [BASE, FRAME_PC]
3309 case BC_RET0: case BC_RET1:
3310 | // RA = results, RC = nresults+1
3311 | ldr PC, [BASE, FRAME_PC]
3313 | str RCw, SAVE_MULTRES
3314 | ands CARG1, PC, #FRAME_TYPE
3315 | eor CARG2, PC, #FRAME_VARG
3317 | ldr INSw, [PC, #-4]
3318 if (op == BC_RET1) {
3319 | ldr TMP0, [BASE, RA, lsl #3]
3321 | sub CARG4, BASE, #16
3323 | sub BASE, CARG4, RA, lsl #3
3324 if (op == BC_RET1) {
3325 | str TMP0, [CARG4], #8
3328 | ldr LFUNC:CARG1, [BASE, FRAME_FUNC]
3330 | cmp RC, RB, lsl #3
3332 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
3333 | ldr CARG2, LFUNC:CARG1->pc
3334 | ldr KBASE, [CARG2, #PC2PROTO(k)]
3337 |6: // Fill up results with nil.
3339 | str TISNIL, [CARG4], #8
3343 /* -- Loops and branches ------------------------------------------------ */
3345 |.define FOR_IDX, [RA]; .define FOR_TIDX, [RA, #4]
3346 |.define FOR_STOP, [RA, #8]; .define FOR_TSTOP, [RA, #12]
3347 |.define FOR_STEP, [RA, #16]; .define FOR_TSTEP, [RA, #20]
3348 |.define FOR_EXT, [RA, #24]; .define FOR_TEXT, [RA, #28]
3354 | // Fall through. Assumes BC_IFORL follows.
3364 | // RA = base, RC = target (after end of loop or start of loop)
3365 vk = (op == BC_IFORL || op == BC_JFORL);
3366 | add RA, BASE, RA, lsl #3
3367 | ldp CARG1, CARG2, FOR_IDX // CARG1 = IDX, CARG2 = STOP
3368 | ldr CARG3, FOR_STEP // CARG3 = STEP
3369 if (op != BC_JFORL) {
3370 | add RC, PC, RC, lsl #2
3371 | sub RC, RC, #0x20000
3373 | checkint CARG1, >5
3375 | checkint CARG2, ->vmeta_for
3376 | checkint CARG3, ->vmeta_for
3377 | tbnz CARG3w, #31, >4
3378 | cmp CARG1w, CARG2w
3380 | adds CARG1w, CARG1w, CARG3w
3382 | add TMP0, CARG1, TISNUM
3383 | tbnz CARG3w, #31, >4
3384 | cmp CARG1w, CARG2w
3387 if (op == BC_FORI) {
3388 | csel PC, RC, PC, gt
3389 } else if (op == BC_JFORI) {
3390 | ldrh RCw, [RC, #-2]
3391 } else if (op == BC_IFORL) {
3392 | csel PC, RC, PC, le
3398 | str CARG1, FOR_EXT
3400 if (op == BC_JFORI || op == BC_JFORL) {
3406 |4: // Invert check for negative step.
3407 | cmp CARG2w, CARG1w
3411 | ldp d0, d1, FOR_IDX
3414 | checknum CARG2, ->vmeta_for
3415 | checknum CARG3, ->vmeta_for
3421 | tbnz CARG3, #63, >7
3428 if (op == BC_FORI) {
3429 | csel PC, RC, PC, hi
3430 } else if (op == BC_JFORI) {
3431 | ldrh RCw, [RC, #-2]
3433 } else if (op == BC_IFORL) {
3434 | csel PC, RC, PC, ls
3440 |7: // Invert check for negative step.
3449 | // Fall through. Assumes BC_IITERL follows.
3457 | // RA = base, RC = target
3458 | ldr CARG1, [BASE, RA, lsl #3]
3459 | add TMP1, BASE, RA, lsl #3
3461 | beq >1 // Stop if iterator returned nil.
3462 if (op == BC_JITERL) {
3463 | str CARG1, [TMP1, #-8]
3466 | add TMP0, PC, RC, lsl #2 // Otherwise save control var + branch.
3467 | sub PC, TMP0, #0x20000
3468 | str CARG1, [TMP1, #-8]
3475 | // RA = base, RC = target (loop extent)
3476 | // Note: RA/RC is only used by trace recorder to determine scope/extent
3477 | // This opcode does NOT jump, it's only purpose is to detect a hot loop.
3481 | // Fall through. Assumes BC_ILOOP follows.
3485 | // RA = base, RC = target (loop extent)
3496 | // RA = base (only used by trace recorder), RC = target
3497 | add RC, PC, RC, lsl #2
3498 | sub PC, RC, #0x20000
3502 /* -- Function headers -------------------------------------------------- */
3508 case BC_FUNCV: /* NYI: compiled vararg functions. */
3509 | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow.
3517 | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8
3518 | ldr CARG1, L->maxstack
3519 | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)]
3520 | ldr KBASE, [PC, #-4+PC2PROTO(k)]
3522 | bhi ->vm_growstack_l
3524 | cmp NARGS8:RC, TMP1, lsl #3 // Check for missing parameters.
3526 if (op == BC_JFUNCF) {
3533 |3: // Clear missing parameters.
3534 | str TISNIL, [BASE, NARGS8:RC]
3535 | add NARGS8:RC, NARGS8:RC, #8
3543 | NYI // NYI: compiled vararg functions
3544 break; /* NYI: compiled vararg functions. */
3547 | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8
3548 | ldr CARG1, L->maxstack
3549 | add TMP2, BASE, RC
3551 | add TMP0, RC, #16+FRAME_VARG
3552 | str LFUNC:CARG3, [TMP2], #8 // Store (untagged) copy of LFUNC.
3553 | ldr KBASE, [PC, #-4+PC2PROTO(k)]
3555 | str TMP0, [TMP2], #8 // Store delta + FRAME_VARG.
3556 | bhs ->vm_growstack_l
3558 | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)]
3563 | cmp RA, RC // Less args than parameters?
3566 | sub TMP1, TMP1, #1
3567 | str TISNIL, [RA], #8 // Clear old fixarg slot (help the GC).
3568 | str TMP0, [TMP2], #8
3574 | sub TMP1, TMP1, #1
3575 | str TISNIL, [TMP2], #8
3582 | // BASE = new base, RA = BASE+framesize*8, CARG3 = CFUNC, RC = nargs*8
3583 if (op == BC_FUNCC) {
3584 | ldr CARG4, CFUNC:CARG3->f
3586 | ldr CARG4, GL->wrapf
3588 | add CARG2, RA, NARGS8:RC
3589 | ldr CARG1, L->maxstack
3590 | add RC, BASE, NARGS8:RC
3592 | stp BASE, RC, L->base
3593 if (op == BC_FUNCCW) {
3594 | ldr CARG2, CFUNC:CARG3->f
3596 | mv_vmstate TMP0w, C
3598 | bhi ->vm_growstack_c // Need to grow stack.
3600 | blr CARG4 // (lua_State *L [, lua_CFunction f])
3601 | // Returns nresults.
3602 | ldp BASE, TMP1, L->base
3604 | sbfiz RC, CRET1, #3, #32
3605 | st_vmstate ST_INTERP
3606 | ldr PC, [BASE, FRAME_PC]
3607 | sub RA, TMP1, RC // RA = L->top - nresults*8
3611 /* ---------------------------------------------------------------------- */
3614 fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]);
3620 static int build_backend(BuildCtx *ctx)
3624 dasm_growpc(Dst, BC__MAX);
3626 build_subroutines(ctx);
3629 for (op = 0; op < BC__MAX; op++)
3630 build_ins(ctx, (BCOp)op, op);
3635 /* Emit pseudo frame-info for all assembler functions. */
3636 static void emit_asm_debug(BuildCtx *ctx)
3638 int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code);
3639 int i, cf = CFRAME_SIZE >> 3;
3640 switch (ctx->mode) {
3642 fprintf(ctx->fp, "\t.section .debug_frame,\"\",%%progbits\n");
3645 "\t.long .LECIE0-.LSCIE0\n"
3647 "\t.long 0xffffffff\n"
3652 "\t.byte 30\n" /* Return address is in lr. */
3653 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */
3658 "\t.long .LEFDE0-.LASFDE0\n"
3660 "\t.long .Lframe0\n"
3663 "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
3664 "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */
3665 "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */
3666 fcofs, CFRAME_SIZE, cf, cf-1);
3667 for (i = 19; i <= 28; i++) /* offset x19-x28 */
3668 fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17);
3669 for (i = 8; i <= 15; i++) /* offset d8-d15 */
3670 fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n",
3678 "\t.long .LEFDE1-.LASFDE1\n"
3680 "\t.long .Lframe0\n"
3681 "\t.quad lj_vm_ffi_call\n"
3683 "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */
3684 "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */
3685 "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */
3686 "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */
3688 ".LEFDE1:\n\n", (int)ctx->codesz - fcofs);
3690 fprintf(ctx->fp, "\t.section .eh_frame,\"a\",%%progbits\n");
3693 "\t.long .LECIE1-.LSCIE1\n"
3697 "\t.string \"zPR\"\n"
3700 "\t.byte 30\n" /* Return address is in lr. */
3701 "\t.uleb128 6\n" /* augmentation length */
3702 "\t.byte 0x1b\n" /* pcrel|sdata4 */
3703 "\t.long lj_err_unwind_dwarf-.\n"
3704 "\t.byte 0x1b\n" /* pcrel|sdata4 */
3705 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */
3710 "\t.long .LEFDE2-.LASFDE2\n"
3712 "\t.long .LASFDE2-.Lframe1\n"
3713 "\t.long .Lbegin-.\n"
3715 "\t.uleb128 0\n" /* augmentation length */
3716 "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
3717 "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */
3718 "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */
3719 fcofs, CFRAME_SIZE, cf, cf-1);
3720 for (i = 19; i <= 28; i++) /* offset x19-x28 */
3721 fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17);
3722 for (i = 8; i <= 15; i++) /* offset d8-d15 */
3723 fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n",
3731 "\t.long .LECIE2-.LSCIE2\n"
3735 "\t.string \"zR\"\n"
3738 "\t.byte 30\n" /* Return address is in lr. */
3739 "\t.uleb128 1\n" /* augmentation length */
3740 "\t.byte 0x1b\n" /* pcrel|sdata4 */
3741 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */
3746 "\t.long .LEFDE3-.LASFDE3\n"
3748 "\t.long .LASFDE3-.Lframe2\n"
3749 "\t.long lj_vm_ffi_call-.\n"
3751 "\t.uleb128 0\n" /* augmentation length */
3752 "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */
3753 "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */
3754 "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */
3755 "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */
3757 ".LEFDE3:\n\n", (int)ctx->codesz - fcofs);