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