comparison third_party/luajit/src/vm_mips.dasc @ 178:94705b5986b3

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