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