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