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