1|// Low-level VM code for MIPS CPUs. 2|// Bytecode interpreter, fast functions and helper functions. 3|// Copyright (C) 2005-2021 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. */ 366static 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 | bltz CRET1, >9 // Check for error from exit. 2470 |. lw LFUNC:RB, FRAME_FUNC(BASE) 2471 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). 2472 | sll MULTRES, CRET1, 3 2473 | li TISNIL, LJ_TNIL 2474 | li TISNUM, LJ_TISNUM // Setup type comparison constants. 2475 | sw MULTRES, SAVE_MULTRES 2476 | .FPU mtc1 TMP3, TOBIT 2477 | lw TMP1, LFUNC:RB->pc 2478 | sw r0, DISPATCH_GL(jit_base)(DISPATCH) 2479 | lw KBASE, PC2PROTO(k)(TMP1) 2480 | .FPU cvt.d.s TOBIT, TOBIT 2481 | // Modified copy of ins_next which handles function header dispatch, too. 2482 | lw INS, 0(PC) 2483 | addiu PC, PC, 4 2484 | // Assumes TISNIL == ~LJ_VMST_INTERP == -1 2485 | sw TISNIL, DISPATCH_GL(vmstate)(DISPATCH) 2486 | decode_OP4a TMP1, INS 2487 | decode_OP4b TMP1 2488 | sltiu TMP2, TMP1, BC_FUNCF*4 2489 | addu TMP0, DISPATCH, TMP1 2490 | decode_RD8a RD, INS 2491 | lw AT, 0(TMP0) 2492 | decode_RA8a RA, INS 2493 | beqz TMP2, >2 2494 |. decode_RA8b RA 2495 | jr AT 2496 |. decode_RD8b RD 2497 |2: 2498 | sltiu TMP2, TMP1, (BC_FUNCC+2)*4 // Fast function? 2499 | bnez TMP2, >3 2500 |. lw TMP1, FRAME_PC(BASE) 2501 | // Check frame below fast function. 2502 | andi TMP0, TMP1, FRAME_TYPE 2503 | bnez TMP0, >3 // Trace stitching continuation? 2504 |. nop 2505 | // Otherwise set KBASE for Lua function below fast function. 2506 | lw TMP2, -4(TMP1) 2507 | decode_RA8a TMP0, TMP2 2508 | decode_RA8b TMP0 2509 | subu TMP1, BASE, TMP0 2510 | lw LFUNC:TMP2, -8+FRAME_FUNC(TMP1) 2511 | lw TMP1, LFUNC:TMP2->pc 2512 | lw KBASE, PC2PROTO(k)(TMP1) 2513 |3: 2514 | addiu RC, MULTRES, -8 2515 | jr AT 2516 |. addu RA, RA, BASE 2517 | 2518 |9: // Rethrow error from the right C frame. 2519 | load_got lj_err_trace 2520 | sub CARG2, r0, CRET1 2521 | call_intern lj_err_trace // (lua_State *L, int errcode) 2522 |. move CARG1, L 2523 |.endif 2524 | 2525 |//----------------------------------------------------------------------- 2526 |//-- Math helper functions ---------------------------------------------- 2527 |//----------------------------------------------------------------------- 2528 | 2529 |// Hard-float round to integer. 2530 |// Modifies AT, TMP0, FRET1, FRET2, f4. Keeps all others incl. FARG1. 2531 |.macro vm_round_hf, func 2532 | lui TMP0, 0x4330 // Hiword of 2^52 (double). 2533 | mtc1 r0, f4 2534 | mtc1 TMP0, f5 2535 | abs.d FRET2, FARG1 // |x| 2536 | mfc1 AT, f13 2537 | c.olt.d 0, FRET2, f4 2538 | add.d FRET1, FRET2, f4 // (|x| + 2^52) - 2^52 2539 | bc1f 0, >1 // Truncate only if |x| < 2^52. 2540 |. sub.d FRET1, FRET1, f4 2541 | slt AT, AT, r0 2542 |.if "func" == "ceil" 2543 | lui TMP0, 0xbff0 // Hiword of -1 (double). Preserves -0. 2544 |.else 2545 | lui TMP0, 0x3ff0 // Hiword of +1 (double). 2546 |.endif 2547 |.if "func" == "trunc" 2548 | mtc1 TMP0, f5 2549 | c.olt.d 0, FRET2, FRET1 // |x| < result? 2550 | sub.d FRET2, FRET1, f4 2551 | movt.d FRET1, FRET2, 0 // If yes, subtract +1. 2552 | neg.d FRET2, FRET1 2553 | jr ra 2554 |. movn.d FRET1, FRET2, AT // Merge sign bit back in. 2555 |.else 2556 | neg.d FRET2, FRET1 2557 | mtc1 TMP0, f5 2558 | movn.d FRET1, FRET2, AT // Merge sign bit back in. 2559 |.if "func" == "ceil" 2560 | c.olt.d 0, FRET1, FARG1 // x > result? 2561 |.else 2562 | c.olt.d 0, FARG1, FRET1 // x < result? 2563 |.endif 2564 | sub.d FRET2, FRET1, f4 // If yes, subtract +-1. 2565 | jr ra 2566 |. movt.d FRET1, FRET2, 0 2567 |.endif 2568 |1: 2569 | jr ra 2570 |. mov.d FRET1, FARG1 2571 |.endmacro 2572 | 2573 |.macro vm_round, func 2574 |.if FPU 2575 | vm_round_hf, func 2576 |.endif 2577 |.endmacro 2578 | 2579 |->vm_floor: 2580 | vm_round floor 2581 |->vm_ceil: 2582 | vm_round ceil 2583 |->vm_trunc: 2584 |.if JIT 2585 | vm_round trunc 2586 |.endif 2587 | 2588 |// Soft-float integer to number conversion. 2589 |.macro sfi2d, AHI, ALO 2590 |.if not FPU 2591 | beqz ALO, >9 // Handle zero first. 2592 |. sra TMP0, ALO, 31 2593 | xor TMP1, ALO, TMP0 2594 | subu TMP1, TMP1, TMP0 // Absolute value in TMP1. 2595 | clz AHI, TMP1 2596 | andi TMP0, TMP0, 0x800 // Mask sign bit. 2597 | li AT, 0x3ff+31-1 2598 | sllv TMP1, TMP1, AHI // Align mantissa left with leading 1. 2599 | subu AHI, AT, AHI // Exponent - 1 in AHI. 2600 | sll ALO, TMP1, 21 2601 | or AHI, AHI, TMP0 // Sign | Exponent. 2602 | srl TMP1, TMP1, 11 2603 | sll AHI, AHI, 20 // Align left. 2604 | jr ra 2605 |. addu AHI, AHI, TMP1 // Add mantissa, increment exponent. 2606 |9: 2607 | jr ra 2608 |. li AHI, 0 2609 |.endif 2610 |.endmacro 2611 | 2612 |// Input SFARG1LO. Output: SFARG1*. Temporaries: AT, TMP0, TMP1. 2613 |->vm_sfi2d_1: 2614 | sfi2d SFARG1HI, SFARG1LO 2615 | 2616 |// Input SFARG2LO. Output: SFARG2*. Temporaries: AT, TMP0, TMP1. 2617 |->vm_sfi2d_2: 2618 | sfi2d SFARG2HI, SFARG2LO 2619 | 2620 |// Soft-float comparison. Equivalent to c.eq.d. 2621 |// Input: SFARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1. 2622 |->vm_sfcmpeq: 2623 |.if not FPU 2624 | sll AT, SFARG1HI, 1 2625 | sll TMP0, SFARG2HI, 1 2626 | or CRET1, SFARG1LO, SFARG2LO 2627 | or TMP1, AT, TMP0 2628 | or TMP1, TMP1, CRET1 2629 | beqz TMP1, >8 // Both args +-0: return 1. 2630 |. sltu CRET1, r0, SFARG1LO 2631 | lui TMP1, 0xffe0 2632 | addu AT, AT, CRET1 2633 | sltu CRET1, r0, SFARG2LO 2634 | sltu AT, TMP1, AT 2635 | addu TMP0, TMP0, CRET1 2636 | sltu TMP0, TMP1, TMP0 2637 | or TMP1, AT, TMP0 2638 | bnez TMP1, >9 // Either arg is NaN: return 0; 2639 |. xor TMP0, SFARG1HI, SFARG2HI 2640 | xor TMP1, SFARG1LO, SFARG2LO 2641 | or AT, TMP0, TMP1 2642 | jr ra 2643 |. sltiu CRET1, AT, 1 // Same values: return 1. 2644 |8: 2645 | jr ra 2646 |. li CRET1, 1 2647 |9: 2648 | jr ra 2649 |. li CRET1, 0 2650 |.endif 2651 | 2652 |// Soft-float comparison. Equivalent to c.ult.d and c.olt.d. 2653 |// Input: SFARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1, CRET2. 2654 |->vm_sfcmpult: 2655 |.if not FPU 2656 | b >1 2657 |. li CRET2, 1 2658 |.endif 2659 | 2660 |->vm_sfcmpolt: 2661 |.if not FPU 2662 | li CRET2, 0 2663 |1: 2664 | sll AT, SFARG1HI, 1 2665 | sll TMP0, SFARG2HI, 1 2666 | or CRET1, SFARG1LO, SFARG2LO 2667 | or TMP1, AT, TMP0 2668 | or TMP1, TMP1, CRET1 2669 | beqz TMP1, >8 // Both args +-0: return 0. 2670 |. sltu CRET1, r0, SFARG1LO 2671 | lui TMP1, 0xffe0 2672 | addu AT, AT, CRET1 2673 | sltu CRET1, r0, SFARG2LO 2674 | sltu AT, TMP1, AT 2675 | addu TMP0, TMP0, CRET1 2676 | sltu TMP0, TMP1, TMP0 2677 | or TMP1, AT, TMP0 2678 | bnez TMP1, >9 // Either arg is NaN: return 0 or 1; 2679 |. and AT, SFARG1HI, SFARG2HI 2680 | bltz AT, >5 // Both args negative? 2681 |. nop 2682 | beq SFARG1HI, SFARG2HI, >8 2683 |. sltu CRET1, SFARG1LO, SFARG2LO 2684 | jr ra 2685 |. slt CRET1, SFARG1HI, SFARG2HI 2686 |5: // Swap conditions if both operands are negative. 2687 | beq SFARG1HI, SFARG2HI, >8 2688 |. sltu CRET1, SFARG2LO, SFARG1LO 2689 | jr ra 2690 |. slt CRET1, SFARG2HI, SFARG1HI 2691 |8: 2692 | jr ra 2693 |. nop 2694 |9: 2695 | jr ra 2696 |. move CRET1, CRET2 2697 |.endif 2698 | 2699 |->vm_sfcmpogt: 2700 |.if not FPU 2701 | sll AT, SFARG2HI, 1 2702 | sll TMP0, SFARG1HI, 1 2703 | or CRET1, SFARG2LO, SFARG1LO 2704 | or TMP1, AT, TMP0 2705 | or TMP1, TMP1, CRET1 2706 | beqz TMP1, >8 // Both args +-0: return 0. 2707 |. sltu CRET1, r0, SFARG2LO 2708 | lui TMP1, 0xffe0 2709 | addu AT, AT, CRET1 2710 | sltu CRET1, r0, SFARG1LO 2711 | sltu AT, TMP1, AT 2712 | addu TMP0, TMP0, CRET1 2713 | sltu TMP0, TMP1, TMP0 2714 | or TMP1, AT, TMP0 2715 | bnez TMP1, >9 // Either arg is NaN: return 0 or 1; 2716 |. and AT, SFARG2HI, SFARG1HI 2717 | bltz AT, >5 // Both args negative? 2718 |. nop 2719 | beq SFARG2HI, SFARG1HI, >8 2720 |. sltu CRET1, SFARG2LO, SFARG1LO 2721 | jr ra 2722 |. slt CRET1, SFARG2HI, SFARG1HI 2723 |5: // Swap conditions if both operands are negative. 2724 | beq SFARG2HI, SFARG1HI, >8 2725 |. sltu CRET1, SFARG1LO, SFARG2LO 2726 | jr ra 2727 |. slt CRET1, SFARG1HI, SFARG2HI 2728 |8: 2729 | jr ra 2730 |. nop 2731 |9: 2732 | jr ra 2733 |. li CRET1, 0 2734 |.endif 2735 | 2736 |// Soft-float comparison. Equivalent to c.ole.d a, b or c.ole.d b, a. 2737 |// Input: SFARG*, TMP3. Output: CRET1. Temporaries: AT, TMP0, TMP1. 2738 |->vm_sfcmpolex: 2739 |.if not FPU 2740 | sll AT, SFARG1HI, 1 2741 | sll TMP0, SFARG2HI, 1 2742 | or CRET1, SFARG1LO, SFARG2LO 2743 | or TMP1, AT, TMP0 2744 | or TMP1, TMP1, CRET1 2745 | beqz TMP1, >8 // Both args +-0: return 1. 2746 |. sltu CRET1, r0, SFARG1LO 2747 | lui TMP1, 0xffe0 2748 | addu AT, AT, CRET1 2749 | sltu CRET1, r0, SFARG2LO 2750 | sltu AT, TMP1, AT 2751 | addu TMP0, TMP0, CRET1 2752 | sltu TMP0, TMP1, TMP0 2753 | or TMP1, AT, TMP0 2754 | bnez TMP1, >9 // Either arg is NaN: return 0; 2755 |. and AT, SFARG1HI, SFARG2HI 2756 | xor AT, AT, TMP3 2757 | bltz AT, >5 // Both args negative? 2758 |. nop 2759 | beq SFARG1HI, SFARG2HI, >6 2760 |. sltu CRET1, SFARG2LO, SFARG1LO 2761 | jr ra 2762 |. slt CRET1, SFARG2HI, SFARG1HI 2763 |5: // Swap conditions if both operands are negative. 2764 | beq SFARG1HI, SFARG2HI, >6 2765 |. sltu CRET1, SFARG1LO, SFARG2LO 2766 | slt CRET1, SFARG1HI, SFARG2HI 2767 |6: 2768 | jr ra 2769 |. nop 2770 |8: 2771 | jr ra 2772 |. li CRET1, 1 2773 |9: 2774 | jr ra 2775 |. li CRET1, 0 2776 |.endif 2777 | 2778 |.macro sfmin_max, name, fpcall 2779 |->vm_sf .. name: 2780 |.if JIT and not FPU 2781 | move TMP2, ra 2782 | bal ->fpcall 2783 |. nop 2784 | move TMP0, CRET1 2785 | move SFRETHI, SFARG1HI 2786 | move SFRETLO, SFARG1LO 2787 | move ra, TMP2 2788 | movz SFRETHI, SFARG2HI, TMP0 2789 | jr ra 2790 |. movz SFRETLO, SFARG2LO, TMP0 2791 |.endif 2792 |.endmacro 2793 | 2794 | sfmin_max min, vm_sfcmpolt 2795 | sfmin_max max, vm_sfcmpogt 2796 | 2797 |//----------------------------------------------------------------------- 2798 |//-- Miscellaneous functions -------------------------------------------- 2799 |//----------------------------------------------------------------------- 2800 | 2801 |.define NEXT_TAB, TAB:CARG1 2802 |.define NEXT_IDX, CARG2 2803 |.define NEXT_ASIZE, CARG3 2804 |.define NEXT_NIL, CARG4 2805 |.define NEXT_TMP0, r12 2806 |.define NEXT_TMP1, r13 2807 |.define NEXT_TMP2, r14 2808 |.define NEXT_RES_VK, CRET1 2809 |.define NEXT_RES_IDX, CRET2 2810 |.define NEXT_RES_PTR, sp 2811 |.define NEXT_RES_VAL_I, 0(sp) 2812 |.define NEXT_RES_VAL_IT, 4(sp) 2813 |.define NEXT_RES_KEY_I, 8(sp) 2814 |.define NEXT_RES_KEY_IT, 12(sp) 2815 | 2816 |// TValue *lj_vm_next(GCtab *t, uint32_t idx) 2817 |// Next idx returned in CRET2. 2818 |->vm_next: 2819 |.if JIT and ENDIAN_LE 2820 | lw NEXT_ASIZE, NEXT_TAB->asize 2821 | lw NEXT_TMP0, NEXT_TAB->array 2822 | li NEXT_NIL, LJ_TNIL 2823 |1: // Traverse array part. 2824 | sltu AT, NEXT_IDX, NEXT_ASIZE 2825 | sll NEXT_TMP1, NEXT_IDX, 3 2826 | beqz AT, >5 2827 |. addu NEXT_TMP1, NEXT_TMP0, NEXT_TMP1 2828 | lw NEXT_TMP2, 4(NEXT_TMP1) 2829 | sw NEXT_IDX, NEXT_RES_KEY_I 2830 | beq NEXT_TMP2, NEXT_NIL, <1 2831 |. addiu NEXT_IDX, NEXT_IDX, 1 2832 | lw NEXT_TMP0, 0(NEXT_TMP1) 2833 | li AT, LJ_TISNUM 2834 | sw NEXT_TMP2, NEXT_RES_VAL_IT 2835 | sw AT, NEXT_RES_KEY_IT 2836 | sw NEXT_TMP0, NEXT_RES_VAL_I 2837 | move NEXT_RES_VK, NEXT_RES_PTR 2838 | jr ra 2839 |. move NEXT_RES_IDX, NEXT_IDX 2840 | 2841 |5: // Traverse hash part. 2842 | subu NEXT_RES_IDX, NEXT_IDX, NEXT_ASIZE 2843 | lw NODE:NEXT_RES_VK, NEXT_TAB->node 2844 | sll NEXT_TMP2, NEXT_RES_IDX, 5 2845 | lw NEXT_TMP0, NEXT_TAB->hmask 2846 | sll AT, NEXT_RES_IDX, 3 2847 | subu AT, NEXT_TMP2, AT 2848 | addu NODE:NEXT_RES_VK, NODE:NEXT_RES_VK, AT 2849 |6: 2850 | sltu AT, NEXT_TMP0, NEXT_RES_IDX 2851 | bnez AT, >8 2852 |. nop 2853 | lw NEXT_TMP2, NODE:NEXT_RES_VK->val.it 2854 | bne NEXT_TMP2, NEXT_NIL, >9 2855 |. addiu NEXT_RES_IDX, NEXT_RES_IDX, 1 2856 | // Skip holes in hash part. 2857 | b <6 2858 |. addiu NODE:NEXT_RES_VK, NODE:NEXT_RES_VK, sizeof(Node) 2859 | 2860 |8: // End of iteration. Set the key to nil (not the value). 2861 | sw NEXT_NIL, NEXT_RES_KEY_IT 2862 | move NEXT_RES_VK, NEXT_RES_PTR 2863 |9: 2864 | jr ra 2865 |. addu NEXT_RES_IDX, NEXT_RES_IDX, NEXT_ASIZE 2866 |.endif 2867 | 2868 |//----------------------------------------------------------------------- 2869 |//-- FFI helper functions ----------------------------------------------- 2870 |//----------------------------------------------------------------------- 2871 | 2872 |// Handler for callback functions. Callback slot number in r1, g in r2. 2873 |->vm_ffi_callback: 2874 |.if FFI 2875 |.type CTSTATE, CTState, PC 2876 | saveregs 2877 | lw CTSTATE, GL:r2->ctype_state 2878 | addiu DISPATCH, r2, GG_G2DISP 2879 | load_got lj_ccallback_enter 2880 | sw r1, CTSTATE->cb.slot 2881 | sw CARG1, CTSTATE->cb.gpr[0] 2882 | sw CARG2, CTSTATE->cb.gpr[1] 2883 | .FPU sdc1 FARG1, CTSTATE->cb.fpr[0] 2884 | sw CARG3, CTSTATE->cb.gpr[2] 2885 | sw CARG4, CTSTATE->cb.gpr[3] 2886 | .FPU sdc1 FARG2, CTSTATE->cb.fpr[1] 2887 | addiu TMP0, sp, CFRAME_SPACE+16 2888 | sw TMP0, CTSTATE->cb.stack 2889 | sw r0, SAVE_PC // Any value outside of bytecode is ok. 2890 | move CARG2, sp 2891 | call_intern lj_ccallback_enter // (CTState *cts, void *cf) 2892 |. move CARG1, CTSTATE 2893 | // Returns lua_State *. 2894 | lw BASE, L:CRET1->base 2895 | lw RC, L:CRET1->top 2896 | li TISNUM, LJ_TISNUM // Setup type comparison constants. 2897 | move L, CRET1 2898 | .FPU lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). 2899 | lw LFUNC:RB, FRAME_FUNC(BASE) 2900 | .FPU mtc1 TMP3, TOBIT 2901 | li_vmstate INTERP 2902 | li TISNIL, LJ_TNIL 2903 | subu RC, RC, BASE 2904 | st_vmstate 2905 | .FPU cvt.d.s TOBIT, TOBIT 2906 | ins_callt 2907 |.endif 2908 | 2909 |->cont_ffi_callback: // Return from FFI callback. 2910 |.if FFI 2911 | load_got lj_ccallback_leave 2912 | lw CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH) 2913 | sw BASE, L->base 2914 | sw RB, L->top 2915 | sw L, CTSTATE->L 2916 | move CARG2, RA 2917 | call_intern lj_ccallback_leave // (CTState *cts, TValue *o) 2918 |. move CARG1, CTSTATE 2919 | .FPU ldc1 FRET1, CTSTATE->cb.fpr[0] 2920 | lw CRET1, CTSTATE->cb.gpr[0] 2921 | .FPU ldc1 FRET2, CTSTATE->cb.fpr[1] 2922 | b ->vm_leave_unw 2923 |. lw CRET2, CTSTATE->cb.gpr[1] 2924 |.endif 2925 | 2926 |->vm_ffi_call: // Call C function via FFI. 2927 | // Caveat: needs special frame unwinding, see below. 2928 |.if FFI 2929 | .type CCSTATE, CCallState, CARG1 2930 | lw TMP1, CCSTATE->spadj 2931 | lbu CARG2, CCSTATE->nsp 2932 | move TMP2, sp 2933 | subu sp, sp, TMP1 2934 | sw ra, -4(TMP2) 2935 | sll CARG2, CARG2, 2 2936 | sw r16, -8(TMP2) 2937 | sw CCSTATE, -12(TMP2) 2938 | move r16, TMP2 2939 | addiu TMP1, CCSTATE, offsetof(CCallState, stack) 2940 | addiu TMP2, sp, 16 2941 | beqz CARG2, >2 2942 |. addu TMP3, TMP1, CARG2 2943 |1: 2944 | lw TMP0, 0(TMP1) 2945 | addiu TMP1, TMP1, 4 2946 | sltu AT, TMP1, TMP3 2947 | sw TMP0, 0(TMP2) 2948 | bnez AT, <1 2949 |. addiu TMP2, TMP2, 4 2950 |2: 2951 | lw CFUNCADDR, CCSTATE->func 2952 | lw CARG2, CCSTATE->gpr[1] 2953 | lw CARG3, CCSTATE->gpr[2] 2954 | lw CARG4, CCSTATE->gpr[3] 2955 | .FPU ldc1 FARG1, CCSTATE->fpr[0] 2956 | .FPU ldc1 FARG2, CCSTATE->fpr[1] 2957 | jalr CFUNCADDR 2958 |. lw CARG1, CCSTATE->gpr[0] // Do this last, since CCSTATE is CARG1. 2959 | lw CCSTATE:TMP1, -12(r16) 2960 | lw TMP2, -8(r16) 2961 | lw ra, -4(r16) 2962 | sw CRET1, CCSTATE:TMP1->gpr[0] 2963 | sw CRET2, CCSTATE:TMP1->gpr[1] 2964 |.if FPU 2965 | sdc1 FRET1, CCSTATE:TMP1->fpr[0] 2966 | sdc1 FRET2, CCSTATE:TMP1->fpr[1] 2967 |.else 2968 | sw CARG1, CCSTATE:TMP1->gpr[2] // Soft-float: complex double .im part. 2969 | sw CARG2, CCSTATE:TMP1->gpr[3] 2970 |.endif 2971 | move sp, r16 2972 | jr ra 2973 |. move r16, TMP2 2974 |.endif 2975 |// Note: vm_ffi_call must be the last function in this object file! 2976 | 2977 |//----------------------------------------------------------------------- 2978} 2979 2980/* Generate the code for a single instruction. */ 2981static void build_ins(BuildCtx *ctx, BCOp op, int defop) 2982{ 2983 int vk = 0; 2984 |=>defop: 2985 2986 switch (op) { 2987 2988 /* -- Comparison ops ---------------------------------------------------- */ 2989 2990 /* Remember: all ops branch for a true comparison, fall through otherwise. */ 2991 2992 case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: 2993 | // RA = src1*8, RD = src2*8, JMP with RD = target 2994 |.macro bc_comp, FRA, FRD, RAHI, RALO, RDHI, RDLO, movop, fmovop, fcomp, sfcomp 2995 | addu RA, BASE, RA 2996 | addu RD, BASE, RD 2997 | lw RAHI, HI(RA) 2998 | lw RDHI, HI(RD) 2999 | lhu TMP2, OFS_RD(PC) 3000 | addiu PC, PC, 4 3001 | bne RAHI, TISNUM, >2 3002 |. lw RALO, LO(RA) 3003 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3004 | lw RDLO, LO(RD) 3005 | bne RDHI, TISNUM, >5 3006 |. decode_RD4b TMP2 3007 | slt AT, SFARG1LO, SFARG2LO 3008 | addu TMP2, TMP2, TMP3 3009 | movop TMP2, r0, AT 3010 |1: 3011 | addu PC, PC, TMP2 3012 | ins_next 3013 | 3014 |2: // RA is not an integer. 3015 | sltiu AT, RAHI, LJ_TISNUM 3016 | beqz AT, ->vmeta_comp 3017 |. lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3018 | sltiu AT, RDHI, LJ_TISNUM 3019 |.if FPU 3020 | ldc1 FRA, 0(RA) 3021 | ldc1 FRD, 0(RD) 3022 |.else 3023 | lw RDLO, LO(RD) 3024 |.endif 3025 | beqz AT, >4 3026 |. decode_RD4b TMP2 3027 |3: // RA and RD are both numbers. 3028 |.if FPU 3029 | fcomp f20, f22 3030 | addu TMP2, TMP2, TMP3 3031 | b <1 3032 |. fmovop TMP2, r0 3033 |.else 3034 | bal sfcomp 3035 |. addu TMP2, TMP2, TMP3 3036 | b <1 3037 |. movop TMP2, r0, CRET1 3038 |.endif 3039 | 3040 |4: // RA is a number, RD is not a number. 3041 | bne RDHI, TISNUM, ->vmeta_comp 3042 | // RA is a number, RD is an integer. Convert RD to a number. 3043 |.if FPU 3044 |. lwc1 FRD, LO(RD) 3045 | b <3 3046 |. cvt.d.w FRD, FRD 3047 |.else 3048 |. nop 3049 |.if "RDHI" == "SFARG1HI" 3050 | bal ->vm_sfi2d_1 3051 |.else 3052 | bal ->vm_sfi2d_2 3053 |.endif 3054 |. nop 3055 | b <3 3056 |. nop 3057 |.endif 3058 | 3059 |5: // RA is an integer, RD is not an integer 3060 | sltiu AT, RDHI, LJ_TISNUM 3061 | beqz AT, ->vmeta_comp 3062 | // RA is an integer, RD is a number. Convert RA to a number. 3063 |.if FPU 3064 |. mtc1 RALO, FRA 3065 | ldc1 FRD, 0(RD) 3066 | b <3 3067 | cvt.d.w FRA, FRA 3068 |.else 3069 |. nop 3070 |.if "RAHI" == "SFARG1HI" 3071 | bal ->vm_sfi2d_1 3072 |.else 3073 | bal ->vm_sfi2d_2 3074 |.endif 3075 |. nop 3076 | b <3 3077 |. nop 3078 |.endif 3079 |.endmacro 3080 | 3081 if (op == BC_ISLT) { 3082 | bc_comp f20, f22, SFARG1HI, SFARG1LO, SFARG2HI, SFARG2LO, movz, movf, c.olt.d, ->vm_sfcmpolt 3083 } else if (op == BC_ISGE) { 3084 | bc_comp f20, f22, SFARG1HI, SFARG1LO, SFARG2HI, SFARG2LO, movn, movt, c.olt.d, ->vm_sfcmpolt 3085 } else if (op == BC_ISLE) { 3086 | bc_comp f22, f20, SFARG2HI, SFARG2LO, SFARG1HI, SFARG1LO, movn, movt, c.ult.d, ->vm_sfcmpult 3087 } else { 3088 | bc_comp f22, f20, SFARG2HI, SFARG2LO, SFARG1HI, SFARG1LO, movz, movf, c.ult.d, ->vm_sfcmpult 3089 } 3090 break; 3091 3092 case BC_ISEQV: case BC_ISNEV: 3093 vk = op == BC_ISEQV; 3094 | // RA = src1*8, RD = src2*8, JMP with RD = target 3095 | addu RA, BASE, RA 3096 | addiu PC, PC, 4 3097 | addu RD, BASE, RD 3098 | lw SFARG1HI, HI(RA) 3099 | lhu TMP2, -4+OFS_RD(PC) 3100 | lw SFARG2HI, HI(RD) 3101 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3102 | sltu AT, TISNUM, SFARG1HI 3103 | sltu TMP0, TISNUM, SFARG2HI 3104 | or AT, AT, TMP0 3105 if (vk) { 3106 | beqz AT, ->BC_ISEQN_Z 3107 } else { 3108 | beqz AT, ->BC_ISNEN_Z 3109 } 3110 |. decode_RD4b TMP2 3111 | // Either or both types are not numbers. 3112 | lw SFARG1LO, LO(RA) 3113 | lw SFARG2LO, LO(RD) 3114 | addu TMP2, TMP2, TMP3 3115 |.if FFI 3116 | li TMP3, LJ_TCDATA 3117 | beq SFARG1HI, TMP3, ->vmeta_equal_cd 3118 |.endif 3119 |. sltiu AT, SFARG1HI, LJ_TISPRI // Not a primitive? 3120 |.if FFI 3121 | beq SFARG2HI, TMP3, ->vmeta_equal_cd 3122 |.endif 3123 |. xor TMP3, SFARG1LO, SFARG2LO // Same tv? 3124 | xor SFARG2HI, SFARG2HI, SFARG1HI // Same type? 3125 | sltiu TMP0, SFARG1HI, LJ_TISTABUD+1 // Table or userdata? 3126 | movz TMP3, r0, AT // Ignore tv if primitive. 3127 | movn TMP0, r0, SFARG2HI // Tab/ud and same type? 3128 | or AT, SFARG2HI, TMP3 // Same type && (pri||same tv). 3129 | movz TMP0, r0, AT 3130 | beqz TMP0, >1 // Done if not tab/ud or not same type or same tv. 3131 if (vk) { 3132 |. movn TMP2, r0, AT 3133 } else { 3134 |. movz TMP2, r0, AT 3135 } 3136 | // Different tables or userdatas. Need to check __eq metamethod. 3137 | // Field metatable must be at same offset for GCtab and GCudata! 3138 | lw TAB:TMP1, TAB:SFARG1LO->metatable 3139 | beqz TAB:TMP1, >1 // No metatable? 3140 |. nop 3141 | lbu TMP1, TAB:TMP1->nomm 3142 | andi TMP1, TMP1, 1<<MM_eq 3143 | bnez TMP1, >1 // Or 'no __eq' flag set? 3144 |. nop 3145 | b ->vmeta_equal // Handle __eq metamethod. 3146 |. li TMP0, 1-vk // ne = 0 or 1. 3147 |1: 3148 | addu PC, PC, TMP2 3149 | ins_next 3150 break; 3151 3152 case BC_ISEQS: case BC_ISNES: 3153 vk = op == BC_ISEQS; 3154 | // RA = src*8, RD = str_const*8 (~), JMP with RD = target 3155 | addu RA, BASE, RA 3156 | addiu PC, PC, 4 3157 | lw TMP0, HI(RA) 3158 | srl RD, RD, 1 3159 | lw STR:TMP3, LO(RA) 3160 | subu RD, KBASE, RD 3161 | lhu TMP2, -4+OFS_RD(PC) 3162 |.if FFI 3163 | li AT, LJ_TCDATA 3164 | beq TMP0, AT, ->vmeta_equal_cd 3165 |.endif 3166 |. lw STR:TMP1, -4(RD) // KBASE-4-str_const*4 3167 | addiu TMP0, TMP0, -LJ_TSTR 3168 | decode_RD4b TMP2 3169 | xor TMP1, STR:TMP1, STR:TMP3 3170 | or TMP0, TMP0, TMP1 3171 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3172 | addu TMP2, TMP2, TMP3 3173 if (vk) { 3174 | movn TMP2, r0, TMP0 3175 } else { 3176 | movz TMP2, r0, TMP0 3177 } 3178 | addu PC, PC, TMP2 3179 | ins_next 3180 break; 3181 3182 case BC_ISEQN: case BC_ISNEN: 3183 vk = op == BC_ISEQN; 3184 | // RA = src*8, RD = num_const*8, JMP with RD = target 3185 | addu RA, BASE, RA 3186 | addu RD, KBASE, RD 3187 | lw SFARG1HI, HI(RA) 3188 | lw SFARG2HI, HI(RD) 3189 | lhu TMP2, OFS_RD(PC) 3190 | addiu PC, PC, 4 3191 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3192 | decode_RD4b TMP2 3193 if (vk) { 3194 |->BC_ISEQN_Z: 3195 } else { 3196 |->BC_ISNEN_Z: 3197 } 3198 | bne SFARG1HI, TISNUM, >3 3199 |. lw SFARG1LO, LO(RA) 3200 | lw SFARG2LO, LO(RD) 3201 | addu TMP2, TMP2, TMP3 3202 | bne SFARG2HI, TISNUM, >6 3203 |. xor AT, SFARG1LO, SFARG2LO 3204 if (vk) { 3205 | movn TMP2, r0, AT 3206 |1: 3207 | addu PC, PC, TMP2 3208 |2: 3209 } else { 3210 | movz TMP2, r0, AT 3211 |1: 3212 |2: 3213 | addu PC, PC, TMP2 3214 } 3215 | ins_next 3216 | 3217 |3: // RA is not an integer. 3218 | sltiu AT, SFARG1HI, LJ_TISNUM 3219 |.if FFI 3220 | beqz AT, >8 3221 |.else 3222 | beqz AT, <2 3223 |.endif 3224 |. addu TMP2, TMP2, TMP3 3225 | sltiu AT, SFARG2HI, LJ_TISNUM 3226 |.if FPU 3227 | ldc1 f20, 0(RA) 3228 | ldc1 f22, 0(RD) 3229 |.endif 3230 | beqz AT, >5 3231 |. lw SFARG2LO, LO(RD) 3232 |4: // RA and RD are both numbers. 3233 |.if FPU 3234 | c.eq.d f20, f22 3235 | b <1 3236 if (vk) { 3237 |. movf TMP2, r0 3238 } else { 3239 |. movt TMP2, r0 3240 } 3241 |.else 3242 | bal ->vm_sfcmpeq 3243 |. nop 3244 | b <1 3245 if (vk) { 3246 |. movz TMP2, r0, CRET1 3247 } else { 3248 |. movn TMP2, r0, CRET1 3249 } 3250 |.endif 3251 | 3252 |5: // RA is a number, RD is not a number. 3253 |.if FFI 3254 | bne SFARG2HI, TISNUM, >9 3255 |.else 3256 | bne SFARG2HI, TISNUM, <2 3257 |.endif 3258 | // RA is a number, RD is an integer. Convert RD to a number. 3259 |.if FPU 3260 |. lwc1 f22, LO(RD) 3261 | b <4 3262 |. cvt.d.w f22, f22 3263 |.else 3264 |. nop 3265 | bal ->vm_sfi2d_2 3266 |. nop 3267 | b <4 3268 |. nop 3269 |.endif 3270 | 3271 |6: // RA is an integer, RD is not an integer 3272 | sltiu AT, SFARG2HI, LJ_TISNUM 3273 |.if FFI 3274 | beqz AT, >9 3275 |.else 3276 | beqz AT, <2 3277 |.endif 3278 | // RA is an integer, RD is a number. Convert RA to a number. 3279 |.if FPU 3280 |. mtc1 SFARG1LO, f20 3281 | ldc1 f22, 0(RD) 3282 | b <4 3283 | cvt.d.w f20, f20 3284 |.else 3285 |. nop 3286 | bal ->vm_sfi2d_1 3287 |. nop 3288 | b <4 3289 |. nop 3290 |.endif 3291 | 3292 |.if FFI 3293 |8: 3294 | li AT, LJ_TCDATA 3295 | bne SFARG1HI, AT, <2 3296 |. nop 3297 | b ->vmeta_equal_cd 3298 |. nop 3299 |9: 3300 | li AT, LJ_TCDATA 3301 | bne SFARG2HI, AT, <2 3302 |. nop 3303 | b ->vmeta_equal_cd 3304 |. nop 3305 |.endif 3306 break; 3307 3308 case BC_ISEQP: case BC_ISNEP: 3309 vk = op == BC_ISEQP; 3310 | // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target 3311 | addu RA, BASE, RA 3312 | srl TMP1, RD, 3 3313 | lw TMP0, HI(RA) 3314 | lhu TMP2, OFS_RD(PC) 3315 | not TMP1, TMP1 3316 | addiu PC, PC, 4 3317 |.if FFI 3318 | li AT, LJ_TCDATA 3319 | beq TMP0, AT, ->vmeta_equal_cd 3320 |.endif 3321 |. xor TMP0, TMP0, TMP1 3322 | decode_RD4b TMP2 3323 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3324 | addu TMP2, TMP2, TMP3 3325 if (vk) { 3326 | movn TMP2, r0, TMP0 3327 } else { 3328 | movz TMP2, r0, TMP0 3329 } 3330 | addu PC, PC, TMP2 3331 | ins_next 3332 break; 3333 3334 /* -- Unary test and copy ops ------------------------------------------- */ 3335 3336 case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: 3337 | // RA = dst*8 or unused, RD = src*8, JMP with RD = target 3338 | addu RD, BASE, RD 3339 | lhu TMP2, OFS_RD(PC) 3340 | lw TMP0, HI(RD) 3341 | addiu PC, PC, 4 3342 if (op == BC_IST || op == BC_ISF) { 3343 | sltiu TMP0, TMP0, LJ_TISTRUECOND 3344 | decode_RD4b TMP2 3345 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3346 | addu TMP2, TMP2, TMP3 3347 if (op == BC_IST) { 3348 | movz TMP2, r0, TMP0 3349 } else { 3350 | movn TMP2, r0, TMP0 3351 } 3352 | addu PC, PC, TMP2 3353 } else { 3354 | sltiu TMP0, TMP0, LJ_TISTRUECOND 3355 | lw SFRETHI, HI(RD) 3356 | lw SFRETLO, LO(RD) 3357 if (op == BC_ISTC) { 3358 | beqz TMP0, >1 3359 } else { 3360 | bnez TMP0, >1 3361 } 3362 |. addu RA, BASE, RA 3363 | decode_RD4b TMP2 3364 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 3365 | addu TMP2, TMP2, TMP3 3366 | sw SFRETHI, HI(RA) 3367 | sw SFRETLO, LO(RA) 3368 | addu PC, PC, TMP2 3369 |1: 3370 } 3371 | ins_next 3372 break; 3373 3374 case BC_ISTYPE: 3375 | // RA = src*8, RD = -type*8 3376 | addu TMP2, BASE, RA 3377 | srl TMP1, RD, 3 3378 | lw TMP0, HI(TMP2) 3379 | ins_next1 3380 | addu AT, TMP0, TMP1 3381 | bnez AT, ->vmeta_istype 3382 |. ins_next2 3383 break; 3384 case BC_ISNUM: 3385 | // RA = src*8, RD = -(TISNUM-1)*8 3386 | addu TMP2, BASE, RA 3387 | lw TMP0, HI(TMP2) 3388 | ins_next1 3389 | sltiu AT, TMP0, LJ_TISNUM 3390 | beqz AT, ->vmeta_istype 3391 |. ins_next2 3392 break; 3393 3394 /* -- Unary ops --------------------------------------------------------- */ 3395 3396 case BC_MOV: 3397 | // RA = dst*8, RD = src*8 3398 | addu RD, BASE, RD 3399 | addu RA, BASE, RA 3400 | lw SFRETHI, HI(RD) 3401 | lw SFRETLO, LO(RD) 3402 | ins_next1 3403 | sw SFRETHI, HI(RA) 3404 | sw SFRETLO, LO(RA) 3405 | ins_next2 3406 break; 3407 case BC_NOT: 3408 | // RA = dst*8, RD = src*8 3409 | addu RD, BASE, RD 3410 | addu RA, BASE, RA 3411 | lw TMP0, HI(RD) 3412 | li TMP1, LJ_TFALSE 3413 | sltiu TMP0, TMP0, LJ_TISTRUECOND 3414 | addiu TMP1, TMP0, LJ_TTRUE 3415 | ins_next1 3416 | sw TMP1, HI(RA) 3417 | ins_next2 3418 break; 3419 case BC_UNM: 3420 | // RA = dst*8, RD = src*8 3421 | addu RB, BASE, RD 3422 | lw SFARG1HI, HI(RB) 3423 | addu RA, BASE, RA 3424 | bne SFARG1HI, TISNUM, >2 3425 |. lw SFARG1LO, LO(RB) 3426 | lui TMP1, 0x8000 3427 | beq SFARG1LO, TMP1, ->vmeta_unm // Meta handler deals with -2^31. 3428 |. negu SFARG1LO, SFARG1LO 3429 |1: 3430 | ins_next1 3431 | sw SFARG1HI, HI(RA) 3432 | sw SFARG1LO, LO(RA) 3433 | ins_next2 3434 |2: 3435 | sltiu AT, SFARG1HI, LJ_TISNUM 3436 | beqz AT, ->vmeta_unm 3437 |. lui TMP1, 0x8000 3438 | b <1 3439 |. xor SFARG1HI, SFARG1HI, TMP1 3440 break; 3441 case BC_LEN: 3442 | // RA = dst*8, RD = src*8 3443 | addu CARG2, BASE, RD 3444 | addu RA, BASE, RA 3445 | lw TMP0, HI(CARG2) 3446 | lw CARG1, LO(CARG2) 3447 | li AT, LJ_TSTR 3448 | bne TMP0, AT, >2 3449 |. li AT, LJ_TTAB 3450 | lw CRET1, STR:CARG1->len 3451 |1: 3452 | ins_next1 3453 | sw TISNUM, HI(RA) 3454 | sw CRET1, LO(RA) 3455 | ins_next2 3456 |2: 3457 | bne TMP0, AT, ->vmeta_len 3458 |. nop 3459#if LJ_52 3460 | lw TAB:TMP2, TAB:CARG1->metatable 3461 | bnez TAB:TMP2, >9 3462 |. nop 3463 |3: 3464#endif 3465 |->BC_LEN_Z: 3466 | load_got lj_tab_len 3467 | call_intern lj_tab_len // (GCtab *t) 3468 |. nop 3469 | // Returns uint32_t (but less than 2^31). 3470 | b <1 3471 |. nop 3472#if LJ_52 3473 |9: 3474 | lbu TMP0, TAB:TMP2->nomm 3475 | andi TMP0, TMP0, 1<<MM_len 3476 | bnez TMP0, <3 // 'no __len' flag set: done. 3477 |. nop 3478 | b ->vmeta_len 3479 |. nop 3480#endif 3481 break; 3482 3483 /* -- Binary ops -------------------------------------------------------- */ 3484 3485 |.macro fpmod, a, b, c 3486 | bal ->vm_floor // floor(b/c) 3487 |. div.d FARG1, b, c 3488 | mul.d a, FRET1, c 3489 | sub.d a, b, a // b - floor(b/c)*c 3490 |.endmacro 3491 3492 |.macro sfpmod 3493 | addiu sp, sp, -16 3494 | 3495 | load_got __divdf3 3496 | sw SFARG1HI, HI(sp) 3497 | sw SFARG1LO, LO(sp) 3498 | sw SFARG2HI, 8+HI(sp) 3499 | call_extern 3500 |. sw SFARG2LO, 8+LO(sp) 3501 | 3502 | load_got floor 3503 | move SFARG1HI, SFRETHI 3504 | call_extern 3505 |. move SFARG1LO, SFRETLO 3506 | 3507 | load_got __muldf3 3508 | move SFARG1HI, SFRETHI 3509 | move SFARG1LO, SFRETLO 3510 | lw SFARG2HI, 8+HI(sp) 3511 | call_extern 3512 |. lw SFARG2LO, 8+LO(sp) 3513 | 3514 | load_got __subdf3 3515 | lw SFARG1HI, HI(sp) 3516 | lw SFARG1LO, LO(sp) 3517 | move SFARG2HI, SFRETHI 3518 | call_extern 3519 |. move SFARG2LO, SFRETLO 3520 | 3521 | addiu sp, sp, 16 3522 |.endmacro 3523 3524 |.macro ins_arithpre, label 3525 ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); 3526 | // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8 3527 ||switch (vk) { 3528 ||case 0: 3529 | decode_RB8a RB, INS 3530 | decode_RB8b RB 3531 | decode_RDtoRC8 RC, RD 3532 | // RA = dst*8, RB = src1*8, RC = num_const*8 3533 | addu RB, BASE, RB 3534 |.if "label" ~= "none" 3535 | b label 3536 |.endif 3537 |. addu RC, KBASE, RC 3538 || break; 3539 ||case 1: 3540 | decode_RB8a RC, INS 3541 | decode_RB8b RC 3542 | decode_RDtoRC8 RB, RD 3543 | // RA = dst*8, RB = num_const*8, RC = src1*8 3544 | addu RC, BASE, RC 3545 |.if "label" ~= "none" 3546 | b label 3547 |.endif 3548 |. addu RB, KBASE, RB 3549 || break; 3550 ||default: 3551 | decode_RB8a RB, INS 3552 | decode_RB8b RB 3553 | decode_RDtoRC8 RC, RD 3554 | // RA = dst*8, RB = src1*8, RC = src2*8 3555 | addu RB, BASE, RB 3556 |.if "label" ~= "none" 3557 | b label 3558 |.endif 3559 |. addu RC, BASE, RC 3560 || break; 3561 ||} 3562 |.endmacro 3563 | 3564 |.macro ins_arith, intins, fpins, fpcall, label 3565 | ins_arithpre none 3566 | 3567 |.if "label" ~= "none" 3568 |label: 3569 |.endif 3570 | 3571 | lw SFARG1HI, HI(RB) 3572 | lw SFARG2HI, HI(RC) 3573 | 3574 |.if "intins" ~= "div" 3575 | 3576 | // Check for two integers. 3577 | lw SFARG1LO, LO(RB) 3578 | bne SFARG1HI, TISNUM, >5 3579 |. lw SFARG2LO, LO(RC) 3580 | bne SFARG2HI, TISNUM, >5 3581 | 3582 |.if "intins" == "addu" 3583 |. intins CRET1, SFARG1LO, SFARG2LO 3584 | xor TMP1, CRET1, SFARG1LO // ((y^a) & (y^b)) < 0: overflow. 3585 | xor TMP2, CRET1, SFARG2LO 3586 | and TMP1, TMP1, TMP2 3587 | bltz TMP1, ->vmeta_arith 3588 |. addu RA, BASE, RA 3589 |.elif "intins" == "subu" 3590 |. intins CRET1, SFARG1LO, SFARG2LO 3591 | xor TMP1, CRET1, SFARG1LO // ((y^a) & (a^b)) < 0: overflow. 3592 | xor TMP2, SFARG1LO, SFARG2LO 3593 | and TMP1, TMP1, TMP2 3594 | bltz TMP1, ->vmeta_arith 3595 |. addu RA, BASE, RA 3596 |.elif "intins" == "mult" 3597 |. intins SFARG1LO, SFARG2LO 3598 | mflo CRET1 3599 | mfhi TMP2 3600 | sra TMP1, CRET1, 31 3601 | bne TMP1, TMP2, ->vmeta_arith 3602 |. addu RA, BASE, RA 3603 |.else 3604 |. load_got lj_vm_modi 3605 | beqz SFARG2LO, ->vmeta_arith 3606 |. addu RA, BASE, RA 3607 |.if ENDIAN_BE 3608 | move CARG1, SFARG1LO 3609 |.endif 3610 | call_extern 3611 |. move CARG2, SFARG2LO 3612 |.endif 3613 | 3614 | ins_next1 3615 | sw TISNUM, HI(RA) 3616 | sw CRET1, LO(RA) 3617 |3: 3618 | ins_next2 3619 | 3620 |.elif not FPU 3621 | 3622 | lw SFARG1LO, LO(RB) 3623 | lw SFARG2LO, LO(RC) 3624 | 3625 |.endif 3626 | 3627 |5: // Check for two numbers. 3628 | .FPU ldc1 f20, 0(RB) 3629 | sltiu AT, SFARG1HI, LJ_TISNUM 3630 | sltiu TMP0, SFARG2HI, LJ_TISNUM 3631 | .FPU ldc1 f22, 0(RC) 3632 | and AT, AT, TMP0 3633 | beqz AT, ->vmeta_arith 3634 |. addu RA, BASE, RA 3635 | 3636 |.if FPU 3637 | fpins FRET1, f20, f22 3638 |.elif "fpcall" == "sfpmod" 3639 | sfpmod 3640 |.else 3641 | load_got fpcall 3642 | call_extern 3643 |. nop 3644 |.endif 3645 | 3646 | ins_next1 3647 |.if not FPU 3648 | sw SFRETHI, HI(RA) 3649 |.endif 3650 |.if "intins" ~= "div" 3651 | b <3 3652 |.endif 3653 |.if FPU 3654 |. sdc1 FRET1, 0(RA) 3655 |.else 3656 |. sw SFRETLO, LO(RA) 3657 |.endif 3658 |.if "intins" == "div" 3659 | ins_next2 3660 |.endif 3661 | 3662 |.endmacro 3663 3664 case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: 3665 | ins_arith addu, add.d, __adddf3, none 3666 break; 3667 case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: 3668 | ins_arith subu, sub.d, __subdf3, none 3669 break; 3670 case BC_MULVN: case BC_MULNV: case BC_MULVV: 3671 | ins_arith mult, mul.d, __muldf3, none 3672 break; 3673 case BC_DIVVN: 3674 | ins_arith div, div.d, __divdf3, ->BC_DIVVN_Z 3675 break; 3676 case BC_DIVNV: case BC_DIVVV: 3677 | ins_arithpre ->BC_DIVVN_Z 3678 break; 3679 case BC_MODVN: 3680 | ins_arith modi, fpmod, sfpmod, ->BC_MODVN_Z 3681 break; 3682 case BC_MODNV: case BC_MODVV: 3683 | ins_arithpre ->BC_MODVN_Z 3684 break; 3685 case BC_POW: 3686 | ins_arithpre none 3687 | lw SFARG1HI, HI(RB) 3688 | lw SFARG2HI, HI(RC) 3689 | sltiu AT, SFARG1HI, LJ_TISNUM 3690 | sltiu TMP0, SFARG2HI, LJ_TISNUM 3691 | and AT, AT, TMP0 3692 | load_got pow 3693 | beqz AT, ->vmeta_arith 3694 |. addu RA, BASE, RA 3695 |.if FPU 3696 | ldc1 FARG1, 0(RB) 3697 | ldc1 FARG2, 0(RC) 3698 |.else 3699 | lw SFARG1LO, LO(RB) 3700 | lw SFARG2LO, LO(RC) 3701 |.endif 3702 | call_extern 3703 |. nop 3704 | ins_next1 3705 |.if FPU 3706 | sdc1 FRET1, 0(RA) 3707 |.else 3708 | sw SFRETHI, HI(RA) 3709 | sw SFRETLO, LO(RA) 3710 |.endif 3711 | ins_next2 3712 break; 3713 3714 case BC_CAT: 3715 | // RA = dst*8, RB = src_start*8, RC = src_end*8 3716 | decode_RB8a RB, INS 3717 | decode_RB8b RB 3718 | decode_RDtoRC8 RC, RD 3719 | subu CARG3, RC, RB 3720 | sw BASE, L->base 3721 | addu CARG2, BASE, RC 3722 | move MULTRES, RB 3723 |->BC_CAT_Z: 3724 | load_got lj_meta_cat 3725 | srl CARG3, CARG3, 3 3726 | sw PC, SAVE_PC 3727 | call_intern lj_meta_cat // (lua_State *L, TValue *top, int left) 3728 |. move CARG1, L 3729 | // Returns NULL (finished) or TValue * (metamethod). 3730 | bnez CRET1, ->vmeta_binop 3731 |. lw BASE, L->base 3732 | addu RB, BASE, MULTRES 3733 | lw SFRETHI, HI(RB) 3734 | lw SFRETLO, LO(RB) 3735 | addu RA, BASE, RA 3736 | ins_next1 3737 | sw SFRETHI, HI(RA) 3738 | sw SFRETLO, LO(RA) 3739 | ins_next2 3740 break; 3741 3742 /* -- Constant ops ------------------------------------------------------ */ 3743 3744 case BC_KSTR: 3745 | // RA = dst*8, RD = str_const*8 (~) 3746 | srl TMP1, RD, 1 3747 | subu TMP1, KBASE, TMP1 3748 | ins_next1 3749 | lw TMP0, -4(TMP1) // KBASE-4-str_const*4 3750 | addu RA, BASE, RA 3751 | li TMP2, LJ_TSTR 3752 | sw TMP0, LO(RA) 3753 | sw TMP2, HI(RA) 3754 | ins_next2 3755 break; 3756 case BC_KCDATA: 3757 |.if FFI 3758 | // RA = dst*8, RD = cdata_const*8 (~) 3759 | srl TMP1, RD, 1 3760 | subu TMP1, KBASE, TMP1 3761 | ins_next1 3762 | lw TMP0, -4(TMP1) // KBASE-4-cdata_const*4 3763 | addu RA, BASE, RA 3764 | li TMP2, LJ_TCDATA 3765 | sw TMP0, LO(RA) 3766 | sw TMP2, HI(RA) 3767 | ins_next2 3768 |.endif 3769 break; 3770 case BC_KSHORT: 3771 | // RA = dst*8, RD = int16_literal*8 3772 | sra RD, INS, 16 3773 | addu RA, BASE, RA 3774 | ins_next1 3775 | sw TISNUM, HI(RA) 3776 | sw RD, LO(RA) 3777 | ins_next2 3778 break; 3779 case BC_KNUM: 3780 | // RA = dst*8, RD = num_const*8 3781 | addu RD, KBASE, RD 3782 | addu RA, BASE, RA 3783 | lw SFRETHI, HI(RD) 3784 | lw SFRETLO, LO(RD) 3785 | ins_next1 3786 | sw SFRETHI, HI(RA) 3787 | sw SFRETLO, LO(RA) 3788 | ins_next2 3789 break; 3790 case BC_KPRI: 3791 | // RA = dst*8, RD = primitive_type*8 (~) 3792 | srl TMP1, RD, 3 3793 | addu RA, BASE, RA 3794 | not TMP0, TMP1 3795 | ins_next1 3796 | sw TMP0, HI(RA) 3797 | ins_next2 3798 break; 3799 case BC_KNIL: 3800 | // RA = base*8, RD = end*8 3801 | addu RA, BASE, RA 3802 | sw TISNIL, HI(RA) 3803 | addiu RA, RA, 8 3804 | addu RD, BASE, RD 3805 |1: 3806 | sw TISNIL, HI(RA) 3807 | slt AT, RA, RD 3808 | bnez AT, <1 3809 |. addiu RA, RA, 8 3810 | ins_next_ 3811 break; 3812 3813 /* -- Upvalue and function ops ------------------------------------------ */ 3814 3815 case BC_UGET: 3816 | // RA = dst*8, RD = uvnum*8 3817 | lw LFUNC:RB, FRAME_FUNC(BASE) 3818 | srl RD, RD, 1 3819 | addu RD, RD, LFUNC:RB 3820 | lw UPVAL:RB, LFUNC:RD->uvptr 3821 | ins_next1 3822 | lw TMP1, UPVAL:RB->v 3823 | lw SFRETHI, HI(TMP1) 3824 | lw SFRETLO, LO(TMP1) 3825 | addu RA, BASE, RA 3826 | sw SFRETHI, HI(RA) 3827 | sw SFRETLO, LO(RA) 3828 | ins_next2 3829 break; 3830 case BC_USETV: 3831 | // RA = uvnum*8, RD = src*8 3832 | lw LFUNC:RB, FRAME_FUNC(BASE) 3833 | srl RA, RA, 1 3834 | addu RD, BASE, RD 3835 | addu RA, RA, LFUNC:RB 3836 | lw UPVAL:RB, LFUNC:RA->uvptr 3837 | lw SFRETHI, HI(RD) 3838 | lw SFRETLO, LO(RD) 3839 | lbu TMP3, UPVAL:RB->marked 3840 | lw CARG2, UPVAL:RB->v 3841 | andi TMP3, TMP3, LJ_GC_BLACK // isblack(uv) 3842 | lbu TMP0, UPVAL:RB->closed 3843 | sw SFRETHI, HI(CARG2) 3844 | sw SFRETLO, LO(CARG2) 3845 | li AT, LJ_GC_BLACK|1 3846 | or TMP3, TMP3, TMP0 3847 | beq TMP3, AT, >2 // Upvalue is closed and black? 3848 |. addiu TMP2, SFRETHI, -(LJ_TNUMX+1) 3849 |1: 3850 | ins_next 3851 | 3852 |2: // Check if new value is collectable. 3853 | sltiu AT, TMP2, LJ_TISGCV - (LJ_TNUMX+1) 3854 | beqz AT, <1 // tvisgcv(v) 3855 |. nop 3856 | lbu TMP3, GCOBJ:SFRETLO->gch.marked 3857 | andi TMP3, TMP3, LJ_GC_WHITES // iswhite(v) 3858 | beqz TMP3, <1 3859 |. load_got lj_gc_barrieruv 3860 | // Crossed a write barrier. Move the barrier forward. 3861 | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv) 3862 |. addiu CARG1, DISPATCH, GG_DISP2G 3863 | b <1 3864 |. nop 3865 break; 3866 case BC_USETS: 3867 | // RA = uvnum*8, RD = str_const*8 (~) 3868 | lw LFUNC:RB, FRAME_FUNC(BASE) 3869 | srl RA, RA, 1 3870 | srl TMP1, RD, 1 3871 | addu RA, RA, LFUNC:RB 3872 | subu TMP1, KBASE, TMP1 3873 | lw UPVAL:RB, LFUNC:RA->uvptr 3874 | lw STR:TMP1, -4(TMP1) // KBASE-4-str_const*4 3875 | lbu TMP2, UPVAL:RB->marked 3876 | lw CARG2, UPVAL:RB->v 3877 | lbu TMP3, STR:TMP1->marked 3878 | andi AT, TMP2, LJ_GC_BLACK // isblack(uv) 3879 | lbu TMP2, UPVAL:RB->closed 3880 | li TMP0, LJ_TSTR 3881 | sw STR:TMP1, LO(CARG2) 3882 | bnez AT, >2 3883 |. sw TMP0, HI(CARG2) 3884 |1: 3885 | ins_next 3886 | 3887 |2: // Check if string is white and ensure upvalue is closed. 3888 | beqz TMP2, <1 3889 |. andi AT, TMP3, LJ_GC_WHITES // iswhite(str) 3890 | beqz AT, <1 3891 |. load_got lj_gc_barrieruv 3892 | // Crossed a write barrier. Move the barrier forward. 3893 | call_intern lj_gc_barrieruv // (global_State *g, TValue *tv) 3894 |. addiu CARG1, DISPATCH, GG_DISP2G 3895 | b <1 3896 |. nop 3897 break; 3898 case BC_USETN: 3899 | // RA = uvnum*8, RD = num_const*8 3900 | lw LFUNC:RB, FRAME_FUNC(BASE) 3901 | srl RA, RA, 1 3902 | addu RD, KBASE, RD 3903 | addu RA, RA, LFUNC:RB 3904 | lw UPVAL:RB, LFUNC:RA->uvptr 3905 | lw SFRETHI, HI(RD) 3906 | lw SFRETLO, LO(RD) 3907 | lw TMP1, UPVAL:RB->v 3908 | ins_next1 3909 | sw SFRETHI, HI(TMP1) 3910 | sw SFRETLO, LO(TMP1) 3911 | ins_next2 3912 break; 3913 case BC_USETP: 3914 | // RA = uvnum*8, RD = primitive_type*8 (~) 3915 | lw LFUNC:RB, FRAME_FUNC(BASE) 3916 | srl RA, RA, 1 3917 | srl TMP0, RD, 3 3918 | addu RA, RA, LFUNC:RB 3919 | not TMP0, TMP0 3920 | lw UPVAL:RB, LFUNC:RA->uvptr 3921 | ins_next1 3922 | lw TMP1, UPVAL:RB->v 3923 | sw TMP0, HI(TMP1) 3924 | ins_next2 3925 break; 3926 3927 case BC_UCLO: 3928 | // RA = level*8, RD = target 3929 | lw TMP2, L->openupval 3930 | branch_RD // Do this first since RD is not saved. 3931 | load_got lj_func_closeuv 3932 | sw BASE, L->base 3933 | beqz TMP2, >1 3934 |. move CARG1, L 3935 | call_intern lj_func_closeuv // (lua_State *L, TValue *level) 3936 |. addu CARG2, BASE, RA 3937 | lw BASE, L->base 3938 |1: 3939 | ins_next 3940 break; 3941 3942 case BC_FNEW: 3943 | // RA = dst*8, RD = proto_const*8 (~) (holding function prototype) 3944 | srl TMP1, RD, 1 3945 | load_got lj_func_newL_gc 3946 | subu TMP1, KBASE, TMP1 3947 | lw CARG3, FRAME_FUNC(BASE) 3948 | lw CARG2, -4(TMP1) // KBASE-4-tab_const*4 3949 | sw BASE, L->base 3950 | sw PC, SAVE_PC 3951 | // (lua_State *L, GCproto *pt, GCfuncL *parent) 3952 | call_intern lj_func_newL_gc 3953 |. move CARG1, L 3954 | // Returns GCfuncL *. 3955 | lw BASE, L->base 3956 | li TMP0, LJ_TFUNC 3957 | ins_next1 3958 | addu RA, BASE, RA 3959 | sw LFUNC:CRET1, LO(RA) 3960 | sw TMP0, HI(RA) 3961 | ins_next2 3962 break; 3963 3964 /* -- Table ops --------------------------------------------------------- */ 3965 3966 case BC_TNEW: 3967 case BC_TDUP: 3968 | // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~) 3969 | lw TMP0, DISPATCH_GL(gc.total)(DISPATCH) 3970 | lw TMP1, DISPATCH_GL(gc.threshold)(DISPATCH) 3971 | sw BASE, L->base 3972 | sw PC, SAVE_PC 3973 | sltu AT, TMP0, TMP1 3974 | beqz AT, >5 3975 |1: 3976 if (op == BC_TNEW) { 3977 | load_got lj_tab_new 3978 | srl CARG2, RD, 3 3979 | andi CARG2, CARG2, 0x7ff 3980 | li TMP0, 0x801 3981 | addiu AT, CARG2, -0x7ff 3982 | srl CARG3, RD, 14 3983 | movz CARG2, TMP0, AT 3984 | // (lua_State *L, int32_t asize, uint32_t hbits) 3985 | call_intern lj_tab_new 3986 |. move CARG1, L 3987 | // Returns Table *. 3988 } else { 3989 | load_got lj_tab_dup 3990 | srl TMP1, RD, 1 3991 | subu TMP1, KBASE, TMP1 3992 | move CARG1, L 3993 | call_intern lj_tab_dup // (lua_State *L, Table *kt) 3994 |. lw CARG2, -4(TMP1) // KBASE-4-str_const*4 3995 | // Returns Table *. 3996 } 3997 | lw BASE, L->base 3998 | ins_next1 3999 | addu RA, BASE, RA 4000 | li TMP0, LJ_TTAB 4001 | sw TAB:CRET1, LO(RA) 4002 | sw TMP0, HI(RA) 4003 | ins_next2 4004 |5: 4005 | load_got lj_gc_step_fixtop 4006 | move MULTRES, RD 4007 | call_intern lj_gc_step_fixtop // (lua_State *L) 4008 |. move CARG1, L 4009 | b <1 4010 |. move RD, MULTRES 4011 break; 4012 4013 case BC_GGET: 4014 | // RA = dst*8, RD = str_const*8 (~) 4015 case BC_GSET: 4016 | // RA = src*8, RD = str_const*8 (~) 4017 | lw LFUNC:TMP2, FRAME_FUNC(BASE) 4018 | srl TMP1, RD, 1 4019 | subu TMP1, KBASE, TMP1 4020 | lw TAB:RB, LFUNC:TMP2->env 4021 | lw STR:RC, -4(TMP1) // KBASE-4-str_const*4 4022 if (op == BC_GGET) { 4023 | b ->BC_TGETS_Z 4024 } else { 4025 | b ->BC_TSETS_Z 4026 } 4027 |. addu RA, BASE, RA 4028 break; 4029 4030 case BC_TGETV: 4031 | // RA = dst*8, RB = table*8, RC = key*8 4032 | decode_RB8a RB, INS 4033 | decode_RB8b RB 4034 | decode_RDtoRC8 RC, RD 4035 | addu CARG2, BASE, RB 4036 | addu CARG3, BASE, RC 4037 | lw TMP1, HI(CARG2) 4038 | lw TMP2, HI(CARG3) 4039 | lw TAB:RB, LO(CARG2) 4040 | li AT, LJ_TTAB 4041 | bne TMP1, AT, ->vmeta_tgetv 4042 |. addu RA, BASE, RA 4043 | bne TMP2, TISNUM, >5 4044 |. lw RC, LO(CARG3) 4045 | lw TMP0, TAB:RB->asize 4046 | lw TMP1, TAB:RB->array 4047 | sltu AT, RC, TMP0 4048 | sll TMP2, RC, 3 4049 | beqz AT, ->vmeta_tgetv // Integer key and in array part? 4050 |. addu TMP2, TMP1, TMP2 4051 | lw SFRETHI, HI(TMP2) 4052 | beq SFRETHI, TISNIL, >2 4053 |. lw SFRETLO, LO(TMP2) 4054 |1: 4055 | ins_next1 4056 | sw SFRETHI, HI(RA) 4057 | sw SFRETLO, LO(RA) 4058 | ins_next2 4059 | 4060 |2: // Check for __index if table value is nil. 4061 | lw TAB:TMP2, TAB:RB->metatable 4062 | beqz TAB:TMP2, <1 // No metatable: done. 4063 |. nop 4064 | lbu TMP0, TAB:TMP2->nomm 4065 | andi TMP0, TMP0, 1<<MM_index 4066 | bnez TMP0, <1 // 'no __index' flag set: done. 4067 |. nop 4068 | b ->vmeta_tgetv 4069 |. nop 4070 | 4071 |5: 4072 | li AT, LJ_TSTR 4073 | bne TMP2, AT, ->vmeta_tgetv 4074 |. nop 4075 | b ->BC_TGETS_Z // String key? 4076 |. nop 4077 break; 4078 case BC_TGETS: 4079 | // RA = dst*8, RB = table*8, RC = str_const*4 (~) 4080 | decode_RB8a RB, INS 4081 | decode_RB8b RB 4082 | addu CARG2, BASE, RB 4083 | decode_RC4a RC, INS 4084 | lw TMP0, HI(CARG2) 4085 | decode_RC4b RC 4086 | li AT, LJ_TTAB 4087 | lw TAB:RB, LO(CARG2) 4088 | subu CARG3, KBASE, RC 4089 | lw STR:RC, -4(CARG3) // KBASE-4-str_const*4 4090 | bne TMP0, AT, ->vmeta_tgets1 4091 |. addu RA, BASE, RA 4092 |->BC_TGETS_Z: 4093 | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8 4094 | lw TMP0, TAB:RB->hmask 4095 | lw TMP1, STR:RC->sid 4096 | lw NODE:TMP2, TAB:RB->node 4097 | and TMP1, TMP1, TMP0 // idx = str->sid & tab->hmask 4098 | sll TMP0, TMP1, 5 4099 | sll TMP1, TMP1, 3 4100 | subu TMP1, TMP0, TMP1 4101 | addu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) 4102 |1: 4103 | lw CARG1, offsetof(Node, key)+HI(NODE:TMP2) 4104 | lw TMP0, offsetof(Node, key)+LO(NODE:TMP2) 4105 | lw NODE:TMP1, NODE:TMP2->next 4106 | lw SFRETHI, offsetof(Node, val)+HI(NODE:TMP2) 4107 | addiu CARG1, CARG1, -LJ_TSTR 4108 | xor TMP0, TMP0, STR:RC 4109 | or AT, CARG1, TMP0 4110 | bnez AT, >4 4111 |. lw TAB:TMP3, TAB:RB->metatable 4112 | beq SFRETHI, TISNIL, >5 // Key found, but nil value? 4113 |. lw SFRETLO, offsetof(Node, val)+LO(NODE:TMP2) 4114 |3: 4115 | ins_next1 4116 | sw SFRETHI, HI(RA) 4117 | sw SFRETLO, LO(RA) 4118 | ins_next2 4119 | 4120 |4: // Follow hash chain. 4121 | bnez NODE:TMP1, <1 4122 |. move NODE:TMP2, NODE:TMP1 4123 | // End of hash chain: key not found, nil result. 4124 | 4125 |5: // Check for __index if table value is nil. 4126 | beqz TAB:TMP3, <3 // No metatable: done. 4127 |. li SFRETHI, LJ_TNIL 4128 | lbu TMP0, TAB:TMP3->nomm 4129 | andi TMP0, TMP0, 1<<MM_index 4130 | bnez TMP0, <3 // 'no __index' flag set: done. 4131 |. nop 4132 | b ->vmeta_tgets 4133 |. nop 4134 break; 4135 case BC_TGETB: 4136 | // RA = dst*8, RB = table*8, RC = index*8 4137 | decode_RB8a RB, INS 4138 | decode_RB8b RB 4139 | addu CARG2, BASE, RB 4140 | decode_RDtoRC8 RC, RD 4141 | lw CARG1, HI(CARG2) 4142 | li AT, LJ_TTAB 4143 | lw TAB:RB, LO(CARG2) 4144 | addu RA, BASE, RA 4145 | bne CARG1, AT, ->vmeta_tgetb 4146 |. srl TMP0, RC, 3 4147 | lw TMP1, TAB:RB->asize 4148 | lw TMP2, TAB:RB->array 4149 | sltu AT, TMP0, TMP1 4150 | beqz AT, ->vmeta_tgetb 4151 |. addu RC, TMP2, RC 4152 | lw SFRETHI, HI(RC) 4153 | beq SFRETHI, TISNIL, >5 4154 |. lw SFRETLO, LO(RC) 4155 |1: 4156 | ins_next1 4157 | sw SFRETHI, HI(RA) 4158 | sw SFRETLO, LO(RA) 4159 | ins_next2 4160 | 4161 |5: // Check for __index if table value is nil. 4162 | lw TAB:TMP2, TAB:RB->metatable 4163 | beqz TAB:TMP2, <1 // No metatable: done. 4164 |. nop 4165 | lbu TMP1, TAB:TMP2->nomm 4166 | andi TMP1, TMP1, 1<<MM_index 4167 | bnez TMP1, <1 // 'no __index' flag set: done. 4168 |. nop 4169 | b ->vmeta_tgetb // Caveat: preserve TMP0 and CARG2! 4170 |. nop 4171 break; 4172 case BC_TGETR: 4173 | // RA = dst*8, RB = table*8, RC = key*8 4174 | decode_RB8a RB, INS 4175 | decode_RB8b RB 4176 | decode_RDtoRC8 RC, RD 4177 | addu RB, BASE, RB 4178 | addu RC, BASE, RC 4179 | lw TAB:CARG1, LO(RB) 4180 | lw CARG2, LO(RC) 4181 | addu RA, BASE, RA 4182 | lw TMP0, TAB:CARG1->asize 4183 | lw TMP1, TAB:CARG1->array 4184 | sltu AT, CARG2, TMP0 4185 | sll TMP2, CARG2, 3 4186 | beqz AT, ->vmeta_tgetr // In array part? 4187 |. addu CRET1, TMP1, TMP2 4188 | lw SFARG2HI, HI(CRET1) 4189 | lw SFARG2LO, LO(CRET1) 4190 |->BC_TGETR_Z: 4191 | ins_next1 4192 | sw SFARG2HI, HI(RA) 4193 | sw SFARG2LO, LO(RA) 4194 | ins_next2 4195 break; 4196 4197 case BC_TSETV: 4198 | // RA = src*8, RB = table*8, RC = key*8 4199 | decode_RB8a RB, INS 4200 | decode_RB8b RB 4201 | decode_RDtoRC8 RC, RD 4202 | addu CARG2, BASE, RB 4203 | addu CARG3, BASE, RC 4204 | lw TMP1, HI(CARG2) 4205 | lw TMP2, HI(CARG3) 4206 | lw TAB:RB, LO(CARG2) 4207 | li AT, LJ_TTAB 4208 | bne TMP1, AT, ->vmeta_tsetv 4209 |. addu RA, BASE, RA 4210 | bne TMP2, TISNUM, >5 4211 |. lw RC, LO(CARG3) 4212 | lw TMP0, TAB:RB->asize 4213 | lw TMP1, TAB:RB->array 4214 | sltu AT, RC, TMP0 4215 | sll TMP2, RC, 3 4216 | beqz AT, ->vmeta_tsetv // Integer key and in array part? 4217 |. addu TMP1, TMP1, TMP2 4218 | lw TMP0, HI(TMP1) 4219 | lbu TMP3, TAB:RB->marked 4220 | lw SFRETHI, HI(RA) 4221 | beq TMP0, TISNIL, >3 4222 |. lw SFRETLO, LO(RA) 4223 |1: 4224 | andi AT, TMP3, LJ_GC_BLACK // isblack(table) 4225 | sw SFRETHI, HI(TMP1) 4226 | bnez AT, >7 4227 |. sw SFRETLO, LO(TMP1) 4228 |2: 4229 | ins_next 4230 | 4231 |3: // Check for __newindex if previous value is nil. 4232 | lw TAB:TMP2, TAB:RB->metatable 4233 | beqz TAB:TMP2, <1 // No metatable: done. 4234 |. nop 4235 | lbu TMP2, TAB:TMP2->nomm 4236 | andi TMP2, TMP2, 1<<MM_newindex 4237 | bnez TMP2, <1 // 'no __newindex' flag set: done. 4238 |. nop 4239 | b ->vmeta_tsetv 4240 |. nop 4241 | 4242 |5: 4243 | li AT, LJ_TSTR 4244 | bne TMP2, AT, ->vmeta_tsetv 4245 |. nop 4246 | b ->BC_TSETS_Z // String key? 4247 |. nop 4248 | 4249 |7: // Possible table write barrier for the value. Skip valiswhite check. 4250 | barrierback TAB:RB, TMP3, TMP0, <2 4251 break; 4252 case BC_TSETS: 4253 | // RA = src*8, RB = table*8, RC = str_const*8 (~) 4254 | decode_RB8a RB, INS 4255 | decode_RB8b RB 4256 | addu CARG2, BASE, RB 4257 | decode_RC4a RC, INS 4258 | lw TMP0, HI(CARG2) 4259 | decode_RC4b RC 4260 | li AT, LJ_TTAB 4261 | subu CARG3, KBASE, RC 4262 | lw TAB:RB, LO(CARG2) 4263 | lw STR:RC, -4(CARG3) // KBASE-4-str_const*4 4264 | bne TMP0, AT, ->vmeta_tsets1 4265 |. addu RA, BASE, RA 4266 |->BC_TSETS_Z: 4267 | // TAB:RB = GCtab *, STR:RC = GCstr *, RA = BASE+src*8 4268 | lw TMP0, TAB:RB->hmask 4269 | lw TMP1, STR:RC->sid 4270 | lw NODE:TMP2, TAB:RB->node 4271 | sb r0, TAB:RB->nomm // Clear metamethod cache. 4272 | and TMP1, TMP1, TMP0 // idx = str->sid & tab->hmask 4273 | sll TMP0, TMP1, 5 4274 | sll TMP1, TMP1, 3 4275 | subu TMP1, TMP0, TMP1 4276 | addu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8) 4277 |.if FPU 4278 | ldc1 f20, 0(RA) 4279 |.else 4280 | lw SFRETHI, HI(RA) 4281 | lw SFRETLO, LO(RA) 4282 |.endif 4283 |1: 4284 | lw CARG1, offsetof(Node, key)+HI(NODE:TMP2) 4285 | lw TMP0, offsetof(Node, key)+LO(NODE:TMP2) 4286 | li AT, LJ_TSTR 4287 | lw NODE:TMP1, NODE:TMP2->next 4288 | bne CARG1, AT, >5 4289 |. lw CARG2, offsetof(Node, val)+HI(NODE:TMP2) 4290 | bne TMP0, STR:RC, >5 4291 |. lbu TMP3, TAB:RB->marked 4292 | beq CARG2, TISNIL, >4 // Key found, but nil value? 4293 |. lw TAB:TMP0, TAB:RB->metatable 4294 |2: 4295 | andi AT, TMP3, LJ_GC_BLACK // isblack(table) 4296 |.if FPU 4297 | bnez AT, >7 4298 |. sdc1 f20, NODE:TMP2->val 4299 |.else 4300 | sw SFRETHI, NODE:TMP2->val.u32.hi 4301 | bnez AT, >7 4302 |. sw SFRETLO, NODE:TMP2->val.u32.lo 4303 |.endif 4304 |3: 4305 | ins_next 4306 | 4307 |4: // Check for __newindex if previous value is nil. 4308 | beqz TAB:TMP0, <2 // No metatable: done. 4309 |. nop 4310 | lbu TMP0, TAB:TMP0->nomm 4311 | andi TMP0, TMP0, 1<<MM_newindex 4312 | bnez TMP0, <2 // 'no __newindex' flag set: done. 4313 |. nop 4314 | b ->vmeta_tsets 4315 |. nop 4316 | 4317 |5: // Follow hash chain. 4318 | bnez NODE:TMP1, <1 4319 |. move NODE:TMP2, NODE:TMP1 4320 | // End of hash chain: key not found, add a new one 4321 | 4322 | // But check for __newindex first. 4323 | lw TAB:TMP2, TAB:RB->metatable 4324 | beqz TAB:TMP2, >6 // No metatable: continue. 4325 |. addiu CARG3, DISPATCH, DISPATCH_GL(tmptv) 4326 | lbu TMP0, TAB:TMP2->nomm 4327 | andi TMP0, TMP0, 1<<MM_newindex 4328 | beqz TMP0, ->vmeta_tsets // 'no __newindex' flag NOT set: check. 4329 |. li AT, LJ_TSTR 4330 |6: 4331 | load_got lj_tab_newkey 4332 | sw STR:RC, LO(CARG3) 4333 | sw AT, HI(CARG3) 4334 | sw BASE, L->base 4335 | move CARG2, TAB:RB 4336 | sw PC, SAVE_PC 4337 | call_intern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k 4338 |. move CARG1, L 4339 | // Returns TValue *. 4340 | lw BASE, L->base 4341 |.if FPU 4342 | b <3 // No 2nd write barrier needed. 4343 |. sdc1 f20, 0(CRET1) 4344 |.else 4345 | lw SFARG1HI, HI(RA) 4346 | lw SFARG1LO, LO(RA) 4347 | sw SFARG1HI, HI(CRET1) 4348 | b <3 // No 2nd write barrier needed. 4349 |. sw SFARG1LO, LO(CRET1) 4350 |.endif 4351 | 4352 |7: // Possible table write barrier for the value. Skip valiswhite check. 4353 | barrierback TAB:RB, TMP3, TMP0, <3 4354 break; 4355 case BC_TSETB: 4356 | // RA = src*8, RB = table*8, RC = index*8 4357 | decode_RB8a RB, INS 4358 | decode_RB8b RB 4359 | addu CARG2, BASE, RB 4360 | decode_RDtoRC8 RC, RD 4361 | lw CARG1, HI(CARG2) 4362 | li AT, LJ_TTAB 4363 | lw TAB:RB, LO(CARG2) 4364 | addu RA, BASE, RA 4365 | bne CARG1, AT, ->vmeta_tsetb 4366 |. srl TMP0, RC, 3 4367 | lw TMP1, TAB:RB->asize 4368 | lw TMP2, TAB:RB->array 4369 | sltu AT, TMP0, TMP1 4370 | beqz AT, ->vmeta_tsetb 4371 |. addu RC, TMP2, RC 4372 | lw TMP1, HI(RC) 4373 | lbu TMP3, TAB:RB->marked 4374 | beq TMP1, TISNIL, >5 4375 |1: 4376 |. lw SFRETHI, HI(RA) 4377 | lw SFRETLO, LO(RA) 4378 | andi AT, TMP3, LJ_GC_BLACK // isblack(table) 4379 | sw SFRETHI, HI(RC) 4380 | bnez AT, >7 4381 |. sw SFRETLO, LO(RC) 4382 |2: 4383 | ins_next 4384 | 4385 |5: // Check for __newindex if previous value is nil. 4386 | lw TAB:TMP2, TAB:RB->metatable 4387 | beqz TAB:TMP2, <1 // No metatable: done. 4388 |. nop 4389 | lbu TMP1, TAB:TMP2->nomm 4390 | andi TMP1, TMP1, 1<<MM_newindex 4391 | bnez TMP1, <1 // 'no __newindex' flag set: done. 4392 |. nop 4393 | b ->vmeta_tsetb // Caveat: preserve TMP0 and CARG2! 4394 |. nop 4395 | 4396 |7: // Possible table write barrier for the value. Skip valiswhite check. 4397 | barrierback TAB:RB, TMP3, TMP0, <2 4398 break; 4399 case BC_TSETR: 4400 | // RA = dst*8, RB = table*8, RC = key*8 4401 | decode_RB8a RB, INS 4402 | decode_RB8b RB 4403 | decode_RDtoRC8 RC, RD 4404 | addu CARG1, BASE, RB 4405 | addu CARG3, BASE, RC 4406 | lw TAB:CARG2, LO(CARG1) 4407 | lw CARG3, LO(CARG3) 4408 | lbu TMP3, TAB:CARG2->marked 4409 | lw TMP0, TAB:CARG2->asize 4410 | lw TMP1, TAB:CARG2->array 4411 | andi AT, TMP3, LJ_GC_BLACK // isblack(table) 4412 | bnez AT, >7 4413 |. addu RA, BASE, RA 4414 |2: 4415 | sltu AT, CARG3, TMP0 4416 | sll TMP2, CARG3, 3 4417 | beqz AT, ->vmeta_tsetr // In array part? 4418 |. addu CRET1, TMP1, TMP2 4419 |->BC_TSETR_Z: 4420 | lw SFARG1HI, HI(RA) 4421 | lw SFARG1LO, LO(RA) 4422 | ins_next1 4423 | sw SFARG1HI, HI(CRET1) 4424 | sw SFARG1LO, LO(CRET1) 4425 | ins_next2 4426 | 4427 |7: // Possible table write barrier for the value. Skip valiswhite check. 4428 | barrierback TAB:CARG2, TMP3, CRET1, <2 4429 break; 4430 4431 case BC_TSETM: 4432 | // RA = base*8 (table at base-1), RD = num_const*8 (start index) 4433 | addu RA, BASE, RA 4434 |1: 4435 | addu TMP3, KBASE, RD 4436 | lw TAB:CARG2, -8+LO(RA) // Guaranteed to be a table. 4437 | addiu TMP0, MULTRES, -8 4438 | lw TMP3, LO(TMP3) // Integer constant is in lo-word. 4439 | beqz TMP0, >4 // Nothing to copy? 4440 |. srl CARG3, TMP0, 3 4441 | addu CARG3, CARG3, TMP3 4442 | lw TMP2, TAB:CARG2->asize 4443 | sll TMP1, TMP3, 3 4444 | lbu TMP3, TAB:CARG2->marked 4445 | lw CARG1, TAB:CARG2->array 4446 | sltu AT, TMP2, CARG3 4447 | bnez AT, >5 4448 |. addu TMP2, RA, TMP0 4449 | addu TMP1, TMP1, CARG1 4450 | andi TMP0, TMP3, LJ_GC_BLACK // isblack(table) 4451 |3: // Copy result slots to table. 4452 | lw SFRETHI, HI(RA) 4453 | lw SFRETLO, LO(RA) 4454 | addiu RA, RA, 8 4455 | sltu AT, RA, TMP2 4456 | sw SFRETHI, HI(TMP1) 4457 | sw SFRETLO, LO(TMP1) 4458 | bnez AT, <3 4459 |. addiu TMP1, TMP1, 8 4460 | bnez TMP0, >7 4461 |. nop 4462 |4: 4463 | ins_next 4464 | 4465 |5: // Need to resize array part. 4466 | load_got lj_tab_reasize 4467 | sw BASE, L->base 4468 | sw PC, SAVE_PC 4469 | move BASE, RD 4470 | call_intern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) 4471 |. move CARG1, L 4472 | // Must not reallocate the stack. 4473 | move RD, BASE 4474 | b <1 4475 |. lw BASE, L->base // Reload BASE for lack of a saved register. 4476 | 4477 |7: // Possible table write barrier for any value. Skip valiswhite check. 4478 | barrierback TAB:CARG2, TMP3, TMP0, <4 4479 break; 4480 4481 /* -- Calls and vararg handling ----------------------------------------- */ 4482 4483 case BC_CALLM: 4484 | // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8 4485 | decode_RDtoRC8 NARGS8:RC, RD 4486 | b ->BC_CALL_Z 4487 |. addu NARGS8:RC, NARGS8:RC, MULTRES 4488 break; 4489 case BC_CALL: 4490 | // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8 4491 | decode_RDtoRC8 NARGS8:RC, RD 4492 |->BC_CALL_Z: 4493 | move TMP2, BASE 4494 | addu BASE, BASE, RA 4495 | li AT, LJ_TFUNC 4496 | lw TMP0, HI(BASE) 4497 | lw LFUNC:RB, LO(BASE) 4498 | addiu BASE, BASE, 8 4499 | bne TMP0, AT, ->vmeta_call 4500 |. addiu NARGS8:RC, NARGS8:RC, -8 4501 | ins_call 4502 break; 4503 4504 case BC_CALLMT: 4505 | // RA = base*8, (RB = 0,) RC = extra_nargs*8 4506 | addu NARGS8:RD, NARGS8:RD, MULTRES // BC_CALLT gets RC from RD. 4507 | // Fall through. Assumes BC_CALLT follows. 4508 break; 4509 case BC_CALLT: 4510 | // RA = base*8, (RB = 0,) RC = (nargs+1)*8 4511 | addu RA, BASE, RA 4512 | li AT, LJ_TFUNC 4513 | lw TMP0, HI(RA) 4514 | lw LFUNC:RB, LO(RA) 4515 | move NARGS8:RC, RD 4516 | lw TMP1, FRAME_PC(BASE) 4517 | addiu RA, RA, 8 4518 | bne TMP0, AT, ->vmeta_callt 4519 |. addiu NARGS8:RC, NARGS8:RC, -8 4520 |->BC_CALLT_Z: 4521 | andi TMP0, TMP1, FRAME_TYPE // Caveat: preserve TMP0 until the 'or'. 4522 | lbu TMP3, LFUNC:RB->ffid 4523 | bnez TMP0, >7 4524 |. xori TMP2, TMP1, FRAME_VARG 4525 |1: 4526 | sw LFUNC:RB, FRAME_FUNC(BASE) // Copy function down, but keep PC. 4527 | sltiu AT, TMP3, 2 // (> FF_C) Calling a fast function? 4528 | move TMP2, BASE 4529 | beqz NARGS8:RC, >3 4530 |. move TMP3, NARGS8:RC 4531 |2: 4532 | lw SFRETHI, HI(RA) 4533 | lw SFRETLO, LO(RA) 4534 | addiu RA, RA, 8 4535 | addiu TMP3, TMP3, -8 4536 | sw SFRETHI, HI(TMP2) 4537 | sw SFRETLO, LO(TMP2) 4538 | bnez TMP3, <2 4539 |. addiu TMP2, TMP2, 8 4540 |3: 4541 | or TMP0, TMP0, AT 4542 | beqz TMP0, >5 4543 |. nop 4544 |4: 4545 | ins_callt 4546 | 4547 |5: // Tailcall to a fast function with a Lua frame below. 4548 | lw INS, -4(TMP1) 4549 | decode_RA8a RA, INS 4550 | decode_RA8b RA 4551 | subu TMP1, BASE, RA 4552 | lw LFUNC:TMP1, -8+FRAME_FUNC(TMP1) 4553 | lw TMP1, LFUNC:TMP1->pc 4554 | b <4 4555 |. lw KBASE, PC2PROTO(k)(TMP1) // Need to prepare KBASE. 4556 | 4557 |7: // Tailcall from a vararg function. 4558 | andi AT, TMP2, FRAME_TYPEP 4559 | bnez AT, <1 // Vararg frame below? 4560 |. subu TMP2, BASE, TMP2 // Relocate BASE down. 4561 | move BASE, TMP2 4562 | lw TMP1, FRAME_PC(TMP2) 4563 | b <1 4564 |. andi TMP0, TMP1, FRAME_TYPE 4565 break; 4566 4567 case BC_ITERC: 4568 | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8)) 4569 | move TMP2, BASE 4570 | addu BASE, BASE, RA 4571 | li AT, LJ_TFUNC 4572 | lw TMP1, -24+HI(BASE) 4573 | lw LFUNC:RB, -24+LO(BASE) 4574 | lw SFARG1HI, -16+HI(BASE) 4575 | lw SFARG1LO, -16+LO(BASE) 4576 | lw SFARG2HI, -8+HI(BASE) 4577 | lw SFARG2LO, -8+LO(BASE) 4578 | sw TMP1, HI(BASE) // Copy callable. 4579 | sw LFUNC:RB, LO(BASE) 4580 | sw SFARG1HI, 8+HI(BASE) // Copy state. 4581 | sw SFARG1LO, 8+LO(BASE) 4582 | sw SFARG2HI, 16+HI(BASE) // Copy control var. 4583 | sw SFARG2LO, 16+LO(BASE) 4584 | addiu BASE, BASE, 8 4585 | bne TMP1, AT, ->vmeta_call 4586 |. li NARGS8:RC, 16 // Iterators get 2 arguments. 4587 | ins_call 4588 break; 4589 4590 case BC_ITERN: 4591 |.if JIT and ENDIAN_LE 4592 | hotloop 4593 |.endif 4594 |->vm_IITERN: 4595 | // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8) 4596 | addu RA, BASE, RA 4597 | lw TAB:RB, -16+LO(RA) 4598 | lw RC, -8+LO(RA) // Get index from control var. 4599 | lw TMP0, TAB:RB->asize 4600 | lw TMP1, TAB:RB->array 4601 | addiu PC, PC, 4 4602 |1: // Traverse array part. 4603 | sltu AT, RC, TMP0 4604 | beqz AT, >5 // Index points after array part? 4605 |. sll TMP3, RC, 3 4606 | addu TMP3, TMP1, TMP3 4607 | lw SFARG1HI, HI(TMP3) 4608 | lw SFARG1LO, LO(TMP3) 4609 | lhu RD, -4+OFS_RD(PC) 4610 | sw TISNUM, HI(RA) 4611 | sw RC, LO(RA) 4612 | beq SFARG1HI, TISNIL, <1 // Skip holes in array part. 4613 |. addiu RC, RC, 1 4614 | sw SFARG1HI, 8+HI(RA) 4615 | sw SFARG1LO, 8+LO(RA) 4616 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 4617 | decode_RD4b RD 4618 | addu RD, RD, TMP3 4619 | sw RC, -8+LO(RA) // Update control var. 4620 | addu PC, PC, RD 4621 |3: 4622 | ins_next 4623 | 4624 |5: // Traverse hash part. 4625 | lw TMP1, TAB:RB->hmask 4626 | subu RC, RC, TMP0 4627 | lw TMP2, TAB:RB->node 4628 |6: 4629 | sltu AT, TMP1, RC // End of iteration? Branch to ITERL+1. 4630 | bnez AT, <3 4631 |. sll TMP3, RC, 5 4632 | sll RB, RC, 3 4633 | subu TMP3, TMP3, RB 4634 | addu NODE:TMP3, TMP3, TMP2 4635 | lw SFARG1HI, NODE:TMP3->val.u32.hi 4636 | lw SFARG1LO, NODE:TMP3->val.u32.lo 4637 | lhu RD, -4+OFS_RD(PC) 4638 | beq SFARG1HI, TISNIL, <6 // Skip holes in hash part. 4639 |. addiu RC, RC, 1 4640 | lw SFARG2HI, NODE:TMP3->key.u32.hi 4641 | lw SFARG2LO, NODE:TMP3->key.u32.lo 4642 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 4643 | sw SFARG1HI, 8+HI(RA) 4644 | sw SFARG1LO, 8+LO(RA) 4645 | addu RC, RC, TMP0 4646 | decode_RD4b RD 4647 | addu RD, RD, TMP3 4648 | sw SFARG2HI, HI(RA) 4649 | sw SFARG2LO, LO(RA) 4650 | addu PC, PC, RD 4651 | b <3 4652 |. sw RC, -8+LO(RA) // Update control var. 4653 break; 4654 4655 case BC_ISNEXT: 4656 | // RA = base*8, RD = target (points to ITERN) 4657 | addu RA, BASE, RA 4658 | srl TMP0, RD, 1 4659 | lw CARG1, -24+HI(RA) 4660 | lw CFUNC:CARG2, -24+LO(RA) 4661 | addu TMP0, PC, TMP0 4662 | lw CARG3, -16+HI(RA) 4663 | lw CARG4, -8+HI(RA) 4664 | li AT, LJ_TFUNC 4665 | bne CARG1, AT, >5 4666 |. lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535) 4667 | lbu CARG2, CFUNC:CARG2->ffid 4668 | addiu CARG3, CARG3, -LJ_TTAB 4669 | addiu CARG4, CARG4, -LJ_TNIL 4670 | or CARG3, CARG3, CARG4 4671 | addiu CARG2, CARG2, -FF_next_N 4672 | or CARG2, CARG2, CARG3 4673 | bnez CARG2, >5 4674 |. lui TMP1, (LJ_KEYINDEX >> 16) 4675 | addu PC, TMP0, TMP2 4676 | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff) 4677 | sw r0, -8+LO(RA) // Initialize control var. 4678 | sw TMP1, -8+HI(RA) 4679 |1: 4680 | ins_next 4681 |5: // Despecialize bytecode if any of the checks fail. 4682 | li TMP3, BC_JMP 4683 | li TMP1, BC_ITERC 4684 | sb TMP3, -4+OFS_OP(PC) 4685 | addu PC, TMP0, TMP2 4686 |.if JIT 4687 | lb TMP0, OFS_OP(PC) 4688 | li AT, BC_ITERN 4689 | bne TMP0, AT, >6 4690 |. lhu TMP2, OFS_RD(PC) 4691 |.endif 4692 | b <1 4693 |. sb TMP1, OFS_OP(PC) 4694 |.if JIT 4695 |6: // Unpatch JLOOP. 4696 | lw TMP0, DISPATCH_J(trace)(DISPATCH) 4697 | sll TMP2, TMP2, 2 4698 | addu TMP0, TMP0, TMP2 4699 | lw TRACE:TMP2, 0(TMP0) 4700 | lw TMP0, TRACE:TMP2->startins 4701 | li AT, -256 4702 | and TMP0, TMP0, AT 4703 | or TMP0, TMP0, TMP1 4704 | b <1 4705 |. sw TMP0, 0(PC) 4706 |.endif 4707 break; 4708 4709 case BC_VARG: 4710 | // RA = base*8, RB = (nresults+1)*8, RC = numparams*8 4711 | lw TMP0, FRAME_PC(BASE) 4712 | decode_RDtoRC8 RC, RD 4713 | decode_RB8a RB, INS 4714 | addu RC, BASE, RC 4715 | decode_RB8b RB 4716 | addu RA, BASE, RA 4717 | addiu RC, RC, FRAME_VARG 4718 | addu TMP2, RA, RB 4719 | addiu TMP3, BASE, -8 // TMP3 = vtop 4720 | subu RC, RC, TMP0 // RC = vbase 4721 | // Note: RC may now be even _above_ BASE if nargs was < numparams. 4722 | beqz RB, >5 // Copy all varargs? 4723 |. subu TMP1, TMP3, RC 4724 | addiu TMP2, TMP2, -16 4725 |1: // Copy vararg slots to destination slots. 4726 | lw CARG1, HI(RC) 4727 | sltu AT, RC, TMP3 4728 | lw CARG2, LO(RC) 4729 | addiu RC, RC, 8 4730 | movz CARG1, TISNIL, AT 4731 | sw CARG1, HI(RA) 4732 | sw CARG2, LO(RA) 4733 | sltu AT, RA, TMP2 4734 | bnez AT, <1 4735 |. addiu RA, RA, 8 4736 |3: 4737 | ins_next 4738 | 4739 |5: // Copy all varargs. 4740 | lw TMP0, L->maxstack 4741 | blez TMP1, <3 // No vararg slots? 4742 |. li MULTRES, 8 // MULTRES = (0+1)*8 4743 | addu TMP2, RA, TMP1 4744 | sltu AT, TMP0, TMP2 4745 | bnez AT, >7 4746 |. addiu MULTRES, TMP1, 8 4747 |6: 4748 | lw SFRETHI, HI(RC) 4749 | lw SFRETLO, LO(RC) 4750 | addiu RC, RC, 8 4751 | sw SFRETHI, HI(RA) 4752 | sw SFRETLO, LO(RA) 4753 | sltu AT, RC, TMP3 4754 | bnez AT, <6 // More vararg slots? 4755 |. addiu RA, RA, 8 4756 | b <3 4757 |. nop 4758 | 4759 |7: // Grow stack for varargs. 4760 | load_got lj_state_growstack 4761 | sw RA, L->top 4762 | subu RA, RA, BASE 4763 | sw BASE, L->base 4764 | subu BASE, RC, BASE // Need delta, because BASE may change. 4765 | sw PC, SAVE_PC 4766 | srl CARG2, TMP1, 3 4767 | call_intern lj_state_growstack // (lua_State *L, int n) 4768 |. move CARG1, L 4769 | move RC, BASE 4770 | lw BASE, L->base 4771 | addu RA, BASE, RA 4772 | addu RC, BASE, RC 4773 | b <6 4774 |. addiu TMP3, BASE, -8 4775 break; 4776 4777 /* -- Returns ----------------------------------------------------------- */ 4778 4779 case BC_RETM: 4780 | // RA = results*8, RD = extra_nresults*8 4781 | addu RD, RD, MULTRES // MULTRES >= 8, so RD >= 8. 4782 | // Fall through. Assumes BC_RET follows. 4783 break; 4784 4785 case BC_RET: 4786 | // RA = results*8, RD = (nresults+1)*8 4787 | lw PC, FRAME_PC(BASE) 4788 | addu RA, BASE, RA 4789 | move MULTRES, RD 4790 |1: 4791 | andi TMP0, PC, FRAME_TYPE 4792 | bnez TMP0, ->BC_RETV_Z 4793 |. xori TMP1, PC, FRAME_VARG 4794 | 4795 |->BC_RET_Z: 4796 | // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return 4797 | lw INS, -4(PC) 4798 | addiu TMP2, BASE, -8 4799 | addiu RC, RD, -8 4800 | decode_RA8a TMP0, INS 4801 | decode_RB8a RB, INS 4802 | decode_RA8b TMP0 4803 | decode_RB8b RB 4804 | addu TMP3, TMP2, RB 4805 | beqz RC, >3 4806 |. subu BASE, TMP2, TMP0 4807 |2: 4808 | lw SFRETHI, HI(RA) 4809 | lw SFRETLO, LO(RA) 4810 | addiu RA, RA, 8 4811 | addiu RC, RC, -8 4812 | sw SFRETHI, HI(TMP2) 4813 | sw SFRETLO, LO(TMP2) 4814 | bnez RC, <2 4815 |. addiu TMP2, TMP2, 8 4816 |3: 4817 | addiu TMP3, TMP3, -8 4818 |5: 4819 | sltu AT, TMP2, TMP3 4820 | bnez AT, >6 4821 |. lw LFUNC:TMP1, FRAME_FUNC(BASE) 4822 | ins_next1 4823 | lw TMP1, LFUNC:TMP1->pc 4824 | lw KBASE, PC2PROTO(k)(TMP1) 4825 | ins_next2 4826 | 4827 |6: // Fill up results with nil. 4828 | sw TISNIL, HI(TMP2) 4829 | b <5 4830 |. addiu TMP2, TMP2, 8 4831 | 4832 |->BC_RETV_Z: // Non-standard return case. 4833 | andi TMP2, TMP1, FRAME_TYPEP 4834 | bnez TMP2, ->vm_return 4835 |. nop 4836 | // Return from vararg function: relocate BASE down. 4837 | subu BASE, BASE, TMP1 4838 | b <1 4839 |. lw PC, FRAME_PC(BASE) 4840 break; 4841 4842 case BC_RET0: case BC_RET1: 4843 | // RA = results*8, RD = (nresults+1)*8 4844 | lw PC, FRAME_PC(BASE) 4845 | addu RA, BASE, RA 4846 | move MULTRES, RD 4847 | andi TMP0, PC, FRAME_TYPE 4848 | bnez TMP0, ->BC_RETV_Z 4849 |. xori TMP1, PC, FRAME_VARG 4850 | 4851 | lw INS, -4(PC) 4852 | addiu TMP2, BASE, -8 4853 if (op == BC_RET1) { 4854 | lw SFRETHI, HI(RA) 4855 | lw SFRETLO, LO(RA) 4856 } 4857 | decode_RB8a RB, INS 4858 | decode_RA8a RA, INS 4859 | decode_RB8b RB 4860 | decode_RA8b RA 4861 if (op == BC_RET1) { 4862 | sw SFRETHI, HI(TMP2) 4863 | sw SFRETLO, LO(TMP2) 4864 } 4865 | subu BASE, TMP2, RA 4866 |5: 4867 | sltu AT, RD, RB 4868 | bnez AT, >6 4869 |. lw LFUNC:TMP1, FRAME_FUNC(BASE) 4870 | ins_next1 4871 | lw TMP1, LFUNC:TMP1->pc 4872 | lw KBASE, PC2PROTO(k)(TMP1) 4873 | ins_next2 4874 | 4875 |6: // Fill up results with nil. 4876 | addiu TMP2, TMP2, 8 4877 | addiu RD, RD, 8 4878 | b <5 4879 if (op == BC_RET1) { 4880 |. sw TISNIL, HI(TMP2) 4881 } else { 4882 |. sw TISNIL, -8+HI(TMP2) 4883 } 4884 break; 4885 4886 /* -- Loops and branches ------------------------------------------------ */ 4887 4888 case BC_FORL: 4889 |.if JIT 4890 | hotloop 4891 |.endif 4892 | // Fall through. Assumes BC_IFORL follows. 4893 break; 4894 4895 case BC_JFORI: 4896 case BC_JFORL: 4897#if !LJ_HASJIT 4898 break; 4899#endif 4900 case BC_FORI: 4901 case BC_IFORL: 4902 | // RA = base*8, RD = target (after end of loop or start of loop) 4903 vk = (op == BC_IFORL || op == BC_JFORL); 4904 | addu RA, BASE, RA 4905 | lw SFARG1HI, FORL_IDX*8+HI(RA) 4906 | lw SFARG1LO, FORL_IDX*8+LO(RA) 4907 if (op != BC_JFORL) { 4908 | srl RD, RD, 1 4909 | lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535) 4910 | addu TMP2, RD, TMP2 4911 } 4912 if (!vk) { 4913 | lw SFARG2HI, FORL_STOP*8+HI(RA) 4914 | lw SFARG2LO, FORL_STOP*8+LO(RA) 4915 | bne SFARG1HI, TISNUM, >5 4916 |. lw SFRETHI, FORL_STEP*8+HI(RA) 4917 | xor AT, SFARG2HI, TISNUM 4918 | lw SFRETLO, FORL_STEP*8+LO(RA) 4919 | xor TMP0, SFRETHI, TISNUM 4920 | or AT, AT, TMP0 4921 | bnez AT, ->vmeta_for 4922 |. slt AT, SFRETLO, r0 4923 | slt CRET1, SFARG2LO, SFARG1LO 4924 | slt TMP1, SFARG1LO, SFARG2LO 4925 | movn CRET1, TMP1, AT 4926 } else { 4927 | bne SFARG1HI, TISNUM, >5 4928 |. lw SFARG2LO, FORL_STEP*8+LO(RA) 4929 | lw SFRETLO, FORL_STOP*8+LO(RA) 4930 | move TMP3, SFARG1LO 4931 | addu SFARG1LO, SFARG1LO, SFARG2LO 4932 | xor TMP0, SFARG1LO, TMP3 4933 | xor TMP1, SFARG1LO, SFARG2LO 4934 | and TMP0, TMP0, TMP1 4935 | slt TMP1, SFARG1LO, SFRETLO 4936 | slt CRET1, SFRETLO, SFARG1LO 4937 | slt AT, SFARG2LO, r0 4938 | slt TMP0, TMP0, r0 // ((y^a) & (y^b)) < 0: overflow. 4939 | movn CRET1, TMP1, AT 4940 | or CRET1, CRET1, TMP0 4941 } 4942 |1: 4943 if (op == BC_FORI) { 4944 | movz TMP2, r0, CRET1 4945 | addu PC, PC, TMP2 4946 } else if (op == BC_JFORI) { 4947 | addu PC, PC, TMP2 4948 | lhu RD, -4+OFS_RD(PC) 4949 } else if (op == BC_IFORL) { 4950 | movn TMP2, r0, CRET1 4951 | addu PC, PC, TMP2 4952 } 4953 if (vk) { 4954 | sw SFARG1HI, FORL_IDX*8+HI(RA) 4955 | sw SFARG1LO, FORL_IDX*8+LO(RA) 4956 } 4957 | ins_next1 4958 | sw SFARG1HI, FORL_EXT*8+HI(RA) 4959 | sw SFARG1LO, FORL_EXT*8+LO(RA) 4960 |2: 4961 if (op == BC_JFORI) { 4962 | beqz CRET1, =>BC_JLOOP 4963 |. decode_RD8b RD 4964 } else if (op == BC_JFORL) { 4965 | beqz CRET1, =>BC_JLOOP 4966 } 4967 | ins_next2 4968 | 4969 |5: // FP loop. 4970 |.if FPU 4971 if (!vk) { 4972 | ldc1 f0, FORL_IDX*8(RA) 4973 | ldc1 f2, FORL_STOP*8(RA) 4974 | sltiu TMP0, SFARG1HI, LJ_TISNUM 4975 | sltiu TMP1, SFARG2HI, LJ_TISNUM 4976 | sltiu AT, SFRETHI, LJ_TISNUM 4977 | and TMP0, TMP0, TMP1 4978 | and AT, AT, TMP0 4979 | beqz AT, ->vmeta_for 4980 |. slt TMP3, SFRETHI, r0 4981 | c.ole.d 0, f0, f2 4982 | c.ole.d 1, f2, f0 4983 | li CRET1, 1 4984 | movt CRET1, r0, 0 4985 | movt AT, r0, 1 4986 | b <1 4987 |. movn CRET1, AT, TMP3 4988 } else { 4989 | ldc1 f0, FORL_IDX*8(RA) 4990 | ldc1 f4, FORL_STEP*8(RA) 4991 | ldc1 f2, FORL_STOP*8(RA) 4992 | lw SFARG2HI, FORL_STEP*8+HI(RA) 4993 | add.d f0, f0, f4 4994 | c.ole.d 0, f0, f2 4995 | c.ole.d 1, f2, f0 4996 | slt TMP3, SFARG2HI, r0 4997 | li CRET1, 1 4998 | li AT, 1 4999 | movt CRET1, r0, 0 5000 | movt AT, r0, 1 5001 | movn CRET1, AT, TMP3 5002 if (op == BC_IFORL) { 5003 | movn TMP2, r0, CRET1 5004 | addu PC, PC, TMP2 5005 } 5006 | sdc1 f0, FORL_IDX*8(RA) 5007 | ins_next1 5008 | b <2 5009 |. sdc1 f0, FORL_EXT*8(RA) 5010 } 5011 |.else 5012 if (!vk) { 5013 | sltiu TMP0, SFARG1HI, LJ_TISNUM 5014 | sltiu TMP1, SFARG2HI, LJ_TISNUM 5015 | sltiu AT, SFRETHI, LJ_TISNUM 5016 | and TMP0, TMP0, TMP1 5017 | and AT, AT, TMP0 5018 | beqz AT, ->vmeta_for 5019 |. nop 5020 | bal ->vm_sfcmpolex 5021 |. move TMP3, SFRETHI 5022 | b <1 5023 |. nop 5024 } else { 5025 | lw SFARG2HI, FORL_STEP*8+HI(RA) 5026 | load_got __adddf3 5027 | call_extern 5028 |. sw TMP2, ARG5 5029 | lw SFARG2HI, FORL_STOP*8+HI(RA) 5030 | lw SFARG2LO, FORL_STOP*8+LO(RA) 5031 | move SFARG1HI, SFRETHI 5032 | move SFARG1LO, SFRETLO 5033 | bal ->vm_sfcmpolex 5034 |. lw TMP3, FORL_STEP*8+HI(RA) 5035 if ( op == BC_JFORL ) { 5036 | lhu RD, -4+OFS_RD(PC) 5037 | lw TMP2, ARG5 5038 | b <1 5039 |. decode_RD8b RD 5040 } else { 5041 | b <1 5042 |. lw TMP2, ARG5 5043 } 5044 } 5045 |.endif 5046 break; 5047 5048 case BC_ITERL: 5049 |.if JIT 5050 | hotloop 5051 |.endif 5052 | // Fall through. Assumes BC_IITERL follows. 5053 break; 5054 5055 case BC_JITERL: 5056#if !LJ_HASJIT 5057 break; 5058#endif 5059 case BC_IITERL: 5060 | // RA = base*8, RD = target 5061 | addu RA, BASE, RA 5062 | lw TMP1, HI(RA) 5063 | beq TMP1, TISNIL, >1 // Stop if iterator returned nil. 5064 |. lw TMP2, LO(RA) 5065 if (op == BC_JITERL) { 5066 | sw TMP1, -8+HI(RA) 5067 | b =>BC_JLOOP 5068 |. sw TMP2, -8+LO(RA) 5069 } else { 5070 | branch_RD // Otherwise save control var + branch. 5071 | sw TMP1, -8+HI(RA) 5072 | sw TMP2, -8+LO(RA) 5073 } 5074 |1: 5075 | ins_next 5076 break; 5077 5078 case BC_LOOP: 5079 | // RA = base*8, RD = target (loop extent) 5080 | // Note: RA/RD is only used by trace recorder to determine scope/extent 5081 | // This opcode does NOT jump, it's only purpose is to detect a hot loop. 5082 |.if JIT 5083 | hotloop 5084 |.endif 5085 | // Fall through. Assumes BC_ILOOP follows. 5086 break; 5087 5088 case BC_ILOOP: 5089 | // RA = base*8, RD = target (loop extent) 5090 | ins_next 5091 break; 5092 5093 case BC_JLOOP: 5094 |.if JIT 5095 | // RA = base*8 (ignored), RD = traceno*8 5096 | lw TMP1, DISPATCH_J(trace)(DISPATCH) 5097 | srl RD, RD, 1 5098 | li AT, 0 5099 | addu TMP1, TMP1, RD 5100 | // Traces on MIPS don't store the trace number, so use 0. 5101 | sw AT, DISPATCH_GL(vmstate)(DISPATCH) 5102 | lw TRACE:TMP2, 0(TMP1) 5103 | sw BASE, DISPATCH_GL(jit_base)(DISPATCH) 5104 | lw TMP2, TRACE:TMP2->mcode 5105 | sw L, DISPATCH_GL(tmpbuf.L)(DISPATCH) 5106 | jr TMP2 5107 |. addiu JGL, DISPATCH, GG_DISP2G+32768 5108 |.endif 5109 break; 5110 5111 case BC_JMP: 5112 | // RA = base*8 (only used by trace recorder), RD = target 5113 | branch_RD 5114 | ins_next 5115 break; 5116 5117 /* -- Function headers -------------------------------------------------- */ 5118 5119 case BC_FUNCF: 5120 |.if JIT 5121 | hotcall 5122 |.endif 5123 case BC_FUNCV: /* NYI: compiled vararg functions. */ 5124 | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. 5125 break; 5126 5127 case BC_JFUNCF: 5128#if !LJ_HASJIT 5129 break; 5130#endif 5131 case BC_IFUNCF: 5132 | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 5133 | lw TMP2, L->maxstack 5134 | lbu TMP1, -4+PC2PROTO(numparams)(PC) 5135 | lw KBASE, -4+PC2PROTO(k)(PC) 5136 | sltu AT, TMP2, RA 5137 | bnez AT, ->vm_growstack_l 5138 |. sll TMP1, TMP1, 3 5139 if (op != BC_JFUNCF) { 5140 | ins_next1 5141 } 5142 |2: 5143 | sltu AT, NARGS8:RC, TMP1 // Check for missing parameters. 5144 | bnez AT, >3 5145 |. addu AT, BASE, NARGS8:RC 5146 if (op == BC_JFUNCF) { 5147 | decode_RD8a RD, INS 5148 | b =>BC_JLOOP 5149 |. decode_RD8b RD 5150 } else { 5151 | ins_next2 5152 } 5153 | 5154 |3: // Clear missing parameters. 5155 | sw TISNIL, HI(AT) 5156 | b <2 5157 |. addiu NARGS8:RC, NARGS8:RC, 8 5158 break; 5159 5160 case BC_JFUNCV: 5161#if !LJ_HASJIT 5162 break; 5163#endif 5164 | NYI // NYI: compiled vararg functions 5165 break; /* NYI: compiled vararg functions. */ 5166 5167 case BC_IFUNCV: 5168 | // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8 5169 | addu TMP1, BASE, RC 5170 | lw TMP2, L->maxstack 5171 | addu TMP0, RA, RC 5172 | sw LFUNC:RB, LO(TMP1) // Store copy of LFUNC. 5173 | addiu TMP3, RC, 8+FRAME_VARG 5174 | sltu AT, TMP0, TMP2 5175 | lw KBASE, -4+PC2PROTO(k)(PC) 5176 | beqz AT, ->vm_growstack_l 5177 |. sw TMP3, HI(TMP1) // Store delta + FRAME_VARG. 5178 | lbu TMP2, -4+PC2PROTO(numparams)(PC) 5179 | move RA, BASE 5180 | move RC, TMP1 5181 | ins_next1 5182 | beqz TMP2, >3 5183 |. addiu BASE, TMP1, 8 5184 |1: 5185 | lw TMP0, HI(RA) 5186 | lw TMP3, LO(RA) 5187 | sltu AT, RA, RC // Less args than parameters? 5188 | move CARG1, TMP0 5189 | movz TMP0, TISNIL, AT // Clear missing parameters. 5190 | movn CARG1, TISNIL, AT // Clear old fixarg slot (help the GC). 5191 | sw TMP3, 8+LO(TMP1) 5192 | addiu TMP2, TMP2, -1 5193 | sw TMP0, 8+HI(TMP1) 5194 | addiu TMP1, TMP1, 8 5195 | sw CARG1, HI(RA) 5196 | bnez TMP2, <1 5197 |. addiu RA, RA, 8 5198 |3: 5199 | ins_next2 5200 break; 5201 5202 case BC_FUNCC: 5203 case BC_FUNCCW: 5204 | // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8 5205 if (op == BC_FUNCC) { 5206 | lw CFUNCADDR, CFUNC:RB->f 5207 } else { 5208 | lw CFUNCADDR, DISPATCH_GL(wrapf)(DISPATCH) 5209 } 5210 | addu TMP1, RA, NARGS8:RC 5211 | lw TMP2, L->maxstack 5212 | addu RC, BASE, NARGS8:RC 5213 | sw BASE, L->base 5214 | sltu AT, TMP2, TMP1 5215 | sw RC, L->top 5216 | li_vmstate C 5217 if (op == BC_FUNCCW) { 5218 | lw CARG2, CFUNC:RB->f 5219 } 5220 | bnez AT, ->vm_growstack_c // Need to grow stack. 5221 |. move CARG1, L 5222 | jalr CFUNCADDR // (lua_State *L [, lua_CFunction f]) 5223 |. st_vmstate 5224 | // Returns nresults. 5225 | lw BASE, L->base 5226 | sll RD, CRET1, 3 5227 | lw TMP1, L->top 5228 | li_vmstate INTERP 5229 | lw PC, FRAME_PC(BASE) // Fetch PC of caller. 5230 | subu RA, TMP1, RD // RA = L->top - nresults*8 5231 | sw L, DISPATCH_GL(cur_L)(DISPATCH) 5232 | b ->vm_returnc 5233 |. st_vmstate 5234 break; 5235 5236 /* ---------------------------------------------------------------------- */ 5237 5238 default: 5239 fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); 5240 exit(2); 5241 break; 5242 } 5243} 5244 5245static int build_backend(BuildCtx *ctx) 5246{ 5247 int op; 5248 5249 dasm_growpc(Dst, BC__MAX); 5250 5251 build_subroutines(ctx); 5252 5253 |.code_op 5254 for (op = 0; op < BC__MAX; op++) 5255 build_ins(ctx, (BCOp)op, op); 5256 5257 return BC__MAX; 5258} 5259 5260/* Emit pseudo frame-info for all assembler functions. */ 5261static void emit_asm_debug(BuildCtx *ctx) 5262{ 5263 int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); 5264 int i; 5265 switch (ctx->mode) { 5266 case BUILD_elfasm: 5267 fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n"); 5268 fprintf(ctx->fp, 5269 ".Lframe0:\n" 5270 "\t.4byte .LECIE0-.LSCIE0\n" 5271 ".LSCIE0:\n" 5272 "\t.4byte 0xffffffff\n" 5273 "\t.byte 0x1\n" 5274 "\t.string \"\"\n" 5275 "\t.uleb128 0x1\n" 5276 "\t.sleb128 -4\n" 5277 "\t.byte 31\n" 5278 "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" 5279 "\t.align 2\n" 5280 ".LECIE0:\n\n"); 5281 fprintf(ctx->fp, 5282 ".LSFDE0:\n" 5283 "\t.4byte .LEFDE0-.LASFDE0\n" 5284 ".LASFDE0:\n" 5285 "\t.4byte .Lframe0\n" 5286 "\t.4byte .Lbegin\n" 5287 "\t.4byte %d\n" 5288 "\t.byte 0xe\n\t.uleb128 %d\n" 5289 "\t.byte 0x9f\n\t.sleb128 1\n" 5290 "\t.byte 0x9e\n\t.sleb128 2\n", 5291 fcofs, CFRAME_SIZE); 5292 for (i = 23; i >= 16; i--) 5293 fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 26-i); 5294#if !LJ_SOFTFP 5295 for (i = 30; i >= 20; i -= 2) 5296 fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 42-i); 5297#endif 5298 fprintf(ctx->fp, 5299 "\t.align 2\n" 5300 ".LEFDE0:\n\n"); 5301#if LJ_HASFFI 5302 fprintf(ctx->fp, 5303 ".LSFDE1:\n" 5304 "\t.4byte .LEFDE1-.LASFDE1\n" 5305 ".LASFDE1:\n" 5306 "\t.4byte .Lframe0\n" 5307 "\t.4byte lj_vm_ffi_call\n" 5308 "\t.4byte %d\n" 5309 "\t.byte 0x9f\n\t.uleb128 1\n" 5310 "\t.byte 0x90\n\t.uleb128 2\n" 5311 "\t.byte 0xd\n\t.uleb128 0x10\n" 5312 "\t.align 2\n" 5313 ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); 5314#endif 5315#if !LJ_NO_UNWIND 5316 fprintf(ctx->fp, "\t.section .eh_frame,\"aw\",@progbits\n"); 5317 fprintf(ctx->fp, 5318 "\t.globl lj_err_unwind_dwarf\n" 5319 ".Lframe1:\n" 5320 "\t.4byte .LECIE1-.LSCIE1\n" 5321 ".LSCIE1:\n" 5322 "\t.4byte 0\n" 5323 "\t.byte 0x1\n" 5324 "\t.string \"zPR\"\n" 5325 "\t.uleb128 0x1\n" 5326 "\t.sleb128 -4\n" 5327 "\t.byte 31\n" 5328 "\t.uleb128 6\n" /* augmentation length */ 5329 "\t.byte 0\n" 5330 "\t.4byte lj_err_unwind_dwarf\n" 5331 "\t.byte 0\n" 5332 "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" 5333 "\t.align 2\n" 5334 ".LECIE1:\n\n"); 5335 fprintf(ctx->fp, 5336 ".LSFDE2:\n" 5337 "\t.4byte .LEFDE2-.LASFDE2\n" 5338 ".LASFDE2:\n" 5339 "\t.4byte .LASFDE2-.Lframe1\n" 5340 "\t.4byte .Lbegin\n" 5341 "\t.4byte %d\n" 5342 "\t.uleb128 0\n" /* augmentation length */ 5343 "\t.byte 0xe\n\t.uleb128 %d\n" 5344 "\t.byte 0x9f\n\t.sleb128 1\n" 5345 "\t.byte 0x9e\n\t.sleb128 2\n", 5346 fcofs, CFRAME_SIZE); 5347 for (i = 23; i >= 16; i--) 5348 fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 26-i); 5349#if !LJ_SOFTFP 5350 for (i = 30; i >= 20; i -= 2) 5351 fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 42-i); 5352#endif 5353 fprintf(ctx->fp, 5354 "\t.align 2\n" 5355 ".LEFDE2:\n\n"); 5356#if LJ_HASFFI 5357 fprintf(ctx->fp, 5358 ".Lframe2:\n" 5359 "\t.4byte .LECIE2-.LSCIE2\n" 5360 ".LSCIE2:\n" 5361 "\t.4byte 0\n" 5362 "\t.byte 0x1\n" 5363 "\t.string \"zR\"\n" 5364 "\t.uleb128 0x1\n" 5365 "\t.sleb128 -4\n" 5366 "\t.byte 31\n" 5367 "\t.uleb128 1\n" /* augmentation length */ 5368 "\t.byte 0\n" 5369 "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n" 5370 "\t.align 2\n" 5371 ".LECIE2:\n\n"); 5372 fprintf(ctx->fp, 5373 ".LSFDE3:\n" 5374 "\t.4byte .LEFDE3-.LASFDE3\n" 5375 ".LASFDE3:\n" 5376 "\t.4byte .LASFDE3-.Lframe2\n" 5377 "\t.4byte lj_vm_ffi_call\n" 5378 "\t.4byte %d\n" 5379 "\t.uleb128 0\n" /* augmentation length */ 5380 "\t.byte 0x9f\n\t.uleb128 1\n" 5381 "\t.byte 0x90\n\t.uleb128 2\n" 5382 "\t.byte 0xd\n\t.uleb128 0x10\n" 5383 "\t.align 2\n" 5384 ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); 5385#endif 5386#endif 5387 break; 5388 default: 5389 break; 5390 } 5391} 5392 5393