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