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