~ubuntu-branches/ubuntu/trusty/luajit/trusty

« back to all changes in this revision

Viewing changes to src/vm_mips.dasc

  • Committer: Package Import Robot
  • Author(s): Enrico Tassi
  • Date: 2012-11-03 14:07:56 UTC
  • mfrom: (1.2.1) (15.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20121103140756-z0zcnyrwqlvuc2m5
Tags: 2.0.0+dfsg-1
New upstream release

Show diffs side-by-side

added added

removed removed

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