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