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