vm_arm64.dasc (106724B)
1 |// Low-level VM code for ARM64 CPUs. 2 |// Bytecode interpreter, fast functions and helper functions. 3 |// Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h 4 | 5 |.arch arm64 6 |.section code_op, code_sub 7 | 8 |.actionlist build_actionlist 9 |.globals GLOB_ 10 |.globalnames globnames 11 |.externnames extnames 12 | 13 |// Note: The ragged indentation of the instructions is intentional. 14 |// The starting columns indicate data dependencies. 15 | 16 |//----------------------------------------------------------------------- 17 | 18 |// ARM64 registers and the AAPCS64 ABI 1.0 at a glance: 19 |// 20 |// x0-x17 temp, x19-x28 callee-saved, x29 fp, x30 lr 21 |// x18 is reserved on most platforms. Don't use it, save it or restore it. 22 |// x31 doesn't exist. Register number 31 either means xzr/wzr (zero) or sp, 23 |// depending on the instruction. 24 |// v0-v7 temp, v8-v15 callee-saved (only d8-d15 preserved), v16-v31 temp 25 |// 26 |// x0-x7/v0-v7 hold parameters and results. 27 | 28 |// Fixed register assignments for the interpreter. 29 | 30 |// The following must be C callee-save. 31 |.define BASE, x19 // Base of current Lua stack frame. 32 |.define KBASE, x20 // Constants of current Lua function. 33 |.define PC, x21 // Next PC. 34 |.define GLREG, x22 // Global state. 35 |.define LREG, x23 // Register holding lua_State (also in SAVE_L). 36 |.define TISNUM, x24 // Constant LJ_TISNUM << 47. 37 |.define TISNUMhi, x25 // Constant LJ_TISNUM << 15. 38 |.define TISNIL, x26 // Constant -1LL. 39 |.define fp, x29 // Yes, we have to maintain a frame pointer. 40 | 41 |.define ST_INTERP, w26 // Constant -1. 42 | 43 |// The following temporaries are not saved across C calls, except for RA/RC. 44 |.define RA, x27 45 |.define RC, x28 46 |.define RB, x17 47 |.define RAw, w27 48 |.define RCw, w28 49 |.define RBw, w17 50 |.define INS, x16 51 |.define INSw, w16 52 |.define ITYPE, x15 53 |.define TMP0, x8 54 |.define TMP1, x9 55 |.define TMP2, x10 56 |.define TMP3, x11 57 |.define TMP0w, w8 58 |.define TMP1w, w9 59 |.define TMP2w, w10 60 |.define TMP3w, w11 61 | 62 |// Calling conventions. Also used as temporaries. 63 |.define CARG1, x0 64 |.define CARG2, x1 65 |.define CARG3, x2 66 |.define CARG4, x3 67 |.define CARG5, x4 68 |.define CARG1w, w0 69 |.define CARG2w, w1 70 |.define CARG3w, w2 71 |.define CARG4w, w3 72 |.define CARG5w, w4 73 | 74 |.define FARG1, d0 75 |.define FARG2, d1 76 | 77 |.define CRET1, x0 78 |.define CRET1w, w0 79 | 80 |// Stack layout while in interpreter. Must match with lj_frame.h. 81 | 82 |.define CFRAME_SPACE, 208 83 |//----- 16 byte aligned, <-- sp entering interpreter 84 |// Unused [sp, #204] // 32 bit values 85 |.define SAVE_NRES, [sp, #200] 86 |.define SAVE_ERRF, [sp, #196] 87 |.define SAVE_MULTRES, [sp, #192] 88 |.define TMPD, [sp, #184] // 64 bit values 89 |.define SAVE_L, [sp, #176] 90 |.define SAVE_PC, [sp, #168] 91 |.define SAVE_CFRAME, [sp, #160] 92 |.define SAVE_FPR_, 96 // 96+8*8: 64 bit FPR saves 93 |.define SAVE_GPR_, 16 // 16+10*8: 64 bit GPR saves 94 |.define SAVE_LR, [sp, #8] 95 |.define SAVE_FP, [sp] 96 |//----- 16 byte aligned, <-- sp while in interpreter. 97 | 98 |.define TMPDofs, #184 99 | 100 |.macro save_, gpr1, gpr2, fpr1, fpr2 101 | stp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8] 102 | stp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8] 103 |.endmacro 104 |.macro rest_, gpr1, gpr2, fpr1, fpr2 105 | ldp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8] 106 | ldp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8] 107 |.endmacro 108 | 109 |.macro saveregs 110 | stp fp, lr, [sp, #-CFRAME_SPACE]! 111 | add fp, sp, #0 112 | stp x19, x20, [sp, # SAVE_GPR_] 113 | save_ 21, 22, 8, 9 114 | save_ 23, 24, 10, 11 115 | save_ 25, 26, 12, 13 116 | save_ 27, 28, 14, 15 117 |.endmacro 118 |.macro restoreregs 119 | ldp x19, x20, [sp, # SAVE_GPR_] 120 | rest_ 21, 22, 8, 9 121 | rest_ 23, 24, 10, 11 122 | rest_ 25, 26, 12, 13 123 | rest_ 27, 28, 14, 15 124 | ldp fp, lr, [sp], # CFRAME_SPACE 125 |.endmacro 126 | 127 |// Type definitions. Some of these are only used for documentation. 128 |.type L, lua_State, LREG 129 |.type GL, global_State, GLREG 130 |.type TVALUE, TValue 131 |.type GCOBJ, GCobj 132 |.type STR, GCstr 133 |.type TAB, GCtab 134 |.type LFUNC, GCfuncL 135 |.type CFUNC, GCfuncC 136 |.type PROTO, GCproto 137 |.type UPVAL, GCupval 138 |.type NODE, Node 139 |.type NARGS8, int 140 |.type TRACE, GCtrace 141 |.type SBUF, SBuf 142 | 143 |//----------------------------------------------------------------------- 144 | 145 |// Trap for not-yet-implemented parts. 146 |.macro NYI; brk; .endmacro 147 | 148 |//----------------------------------------------------------------------- 149 | 150 |// Access to frame relative to BASE. 151 |.define FRAME_FUNC, #-16 152 |.define FRAME_PC, #-8 153 | 154 |.macro decode_RA, dst, ins; ubfx dst, ins, #8, #8; .endmacro 155 |.macro decode_RB, dst, ins; ubfx dst, ins, #24, #8; .endmacro 156 |.macro decode_RC, dst, ins; ubfx dst, ins, #16, #8; .endmacro 157 |.macro decode_RD, dst, ins; ubfx dst, ins, #16, #16; .endmacro 158 |.macro decode_RC8RD, dst, src; ubfiz dst, src, #3, #8; .endmacro 159 | 160 |// Instruction decode+dispatch. 161 |.macro ins_NEXT 162 | ldr INSw, [PC], #4 163 | add TMP1, GL, INS, uxtb #3 164 | decode_RA RA, INS 165 | ldr TMP0, [TMP1, #GG_G2DISP] 166 | decode_RD RC, INS 167 | br TMP0 168 |.endmacro 169 | 170 |// Instruction footer. 171 |.if 1 172 | // Replicated dispatch. Less unpredictable branches, but higher I-Cache use. 173 | .define ins_next, ins_NEXT 174 | .define ins_next_, ins_NEXT 175 |.else 176 | // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch. 177 | // Affects only certain kinds of benchmarks (and only with -j off). 178 | .macro ins_next 179 | b ->ins_next 180 | .endmacro 181 | .macro ins_next_ 182 | ->ins_next: 183 | ins_NEXT 184 | .endmacro 185 |.endif 186 | 187 |// Call decode and dispatch. 188 |.macro ins_callt 189 | // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC 190 | ldr PC, LFUNC:CARG3->pc 191 | ldr INSw, [PC], #4 192 | add TMP1, GL, INS, uxtb #3 193 | decode_RA RA, INS 194 | ldr TMP0, [TMP1, #GG_G2DISP] 195 | add RA, BASE, RA, lsl #3 196 | br TMP0 197 |.endmacro 198 | 199 |.macro ins_call 200 | // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, PC = caller PC 201 | str PC, [BASE, FRAME_PC] 202 | ins_callt 203 |.endmacro 204 | 205 |//----------------------------------------------------------------------- 206 | 207 |// Macros to check the TValue type and extract the GCobj. Branch on failure. 208 |.macro checktp, reg, tp, target 209 | asr ITYPE, reg, #47 210 | cmn ITYPE, #-tp 211 | and reg, reg, #LJ_GCVMASK 212 | bne target 213 |.endmacro 214 |.macro checktp, dst, reg, tp, target 215 | asr ITYPE, reg, #47 216 | cmn ITYPE, #-tp 217 | and dst, reg, #LJ_GCVMASK 218 | bne target 219 |.endmacro 220 |.macro checkstr, reg, target; checktp reg, LJ_TSTR, target; .endmacro 221 |.macro checktab, reg, target; checktp reg, LJ_TTAB, target; .endmacro 222 |.macro checkfunc, reg, target; checktp reg, LJ_TFUNC, target; .endmacro 223 |.macro checkint, reg, target 224 | cmp TISNUMhi, reg, lsr #32 225 | bne target 226 |.endmacro 227 |.macro checknum, reg, target 228 | cmp TISNUMhi, reg, lsr #32 229 | bls target 230 |.endmacro 231 |.macro checknumber, reg, target 232 | cmp TISNUMhi, reg, lsr #32 233 | blo target 234 |.endmacro 235 | 236 |.macro mov_false, reg; movn reg, #0x8000, lsl #32; .endmacro 237 |.macro mov_true, reg; movn reg, #0x0001, lsl #48; .endmacro 238 | 239 #define GL_J(field) (GG_OFS(J) + (int)offsetof(jit_State, field)) 240 | 241 #define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto)) 242 | 243 |.macro hotcheck, delta 244 | NYI 245 |.endmacro 246 | 247 |.macro hotloop 248 | hotcheck HOTCOUNT_LOOP 249 | blo ->vm_hotloop 250 |.endmacro 251 | 252 |.macro hotcall 253 | hotcheck HOTCOUNT_CALL 254 | blo ->vm_hotcall 255 |.endmacro 256 | 257 |// Set current VM state. 258 |.macro mv_vmstate, reg, st; movn reg, #LJ_VMST_..st; .endmacro 259 |.macro st_vmstate, reg; str reg, GL->vmstate; .endmacro 260 | 261 |// Move table write barrier back. Overwrites mark and tmp. 262 |.macro barrierback, tab, mark, tmp 263 | ldr tmp, GL->gc.grayagain 264 | and mark, mark, #~LJ_GC_BLACK // black2gray(tab) 265 | str tab, GL->gc.grayagain 266 | strb mark, tab->marked 267 | str tmp, tab->gclist 268 |.endmacro 269 | 270 |//----------------------------------------------------------------------- 271 272 #if !LJ_DUALNUM 273 #error "Only dual-number mode supported for ARM64 target" 274 #endif 275 276 /* Generate subroutines used by opcodes and other parts of the VM. */ 277 /* The .code_sub section should be last to help static branch prediction. */ 278 static void build_subroutines(BuildCtx *ctx) 279 { 280 |.code_sub 281 | 282 |//----------------------------------------------------------------------- 283 |//-- Return handling ---------------------------------------------------- 284 |//----------------------------------------------------------------------- 285 | 286 |->vm_returnp: 287 | // See vm_return. Also: RB = previous base. 288 | tbz PC, #2, ->cont_dispatch // (PC & FRAME_P) == 0? 289 | 290 | // Return from pcall or xpcall fast func. 291 | ldr PC, [RB, FRAME_PC] // Fetch PC of previous frame. 292 | mov_true TMP0 293 | mov BASE, RB 294 | // Prepending may overwrite the pcall frame, so do it at the end. 295 | str TMP0, [RA, #-8]! // Prepend true to results. 296 | 297 |->vm_returnc: 298 | adds RC, RC, #8 // RC = (nresults+1)*8. 299 | mov CRET1, #LUA_YIELD 300 | beq ->vm_unwind_c_eh 301 | str RCw, SAVE_MULTRES 302 | ands CARG1, PC, #FRAME_TYPE 303 | beq ->BC_RET_Z // Handle regular return to Lua. 304 | 305 |->vm_return: 306 | // BASE = base, RA = resultptr, RC/MULTRES = (nresults+1)*8, PC = return 307 | // CARG1 = PC & FRAME_TYPE 308 | and RB, PC, #~FRAME_TYPEP 309 | cmp CARG1, #FRAME_C 310 | sub RB, BASE, RB // RB = previous base. 311 | bne ->vm_returnp 312 | 313 | str RB, L->base 314 | ldrsw CARG2, SAVE_NRES // CARG2 = nresults+1. 315 | mv_vmstate TMP0w, C 316 | sub BASE, BASE, #16 317 | subs TMP2, RC, #8 318 | st_vmstate TMP0w 319 | beq >2 320 |1: 321 | subs TMP2, TMP2, #8 322 | ldr TMP0, [RA], #8 323 | str TMP0, [BASE], #8 324 | bne <1 325 |2: 326 | cmp RC, CARG2, lsl #3 // More/less results wanted? 327 | bne >6 328 |3: 329 | str BASE, L->top // Store new top. 330 | 331 |->vm_leave_cp: 332 | ldr RC, SAVE_CFRAME // Restore previous C frame. 333 | mov CRET1, #0 // Ok return status for vm_pcall. 334 | str RC, L->cframe 335 | 336 |->vm_leave_unw: 337 | restoreregs 338 | ret 339 | 340 |6: 341 | bgt >7 // Less results wanted? 342 | // More results wanted. Check stack size and fill up results with nil. 343 | ldr CARG3, L->maxstack 344 | cmp BASE, CARG3 345 | bhs >8 346 | str TISNIL, [BASE], #8 347 | add RC, RC, #8 348 | b <2 349 | 350 |7: // Less results wanted. 351 | cbz CARG2, <3 // LUA_MULTRET+1 case? 352 | sub CARG1, RC, CARG2, lsl #3 353 | sub BASE, BASE, CARG1 // Shrink top. 354 | b <3 355 | 356 |8: // Corner case: need to grow stack for filling up results. 357 | // This can happen if: 358 | // - A C function grows the stack (a lot). 359 | // - The GC shrinks the stack in between. 360 | // - A return back from a lua_call() with (high) nresults adjustment. 361 | str BASE, L->top // Save current top held in BASE (yes). 362 | mov CARG1, L 363 | bl extern lj_state_growstack // (lua_State *L, int n) 364 | ldr BASE, L->top // Need the (realloced) L->top in BASE. 365 | ldrsw CARG2, SAVE_NRES 366 | b <2 367 | 368 |->vm_unwind_c: // Unwind C stack, return from vm_pcall. 369 | // (void *cframe, int errcode) 370 | mov sp, CARG1 371 | mov CRET1, CARG2 372 |->vm_unwind_c_eh: // Landing pad for external unwinder. 373 | ldr L, SAVE_L 374 | mv_vmstate TMP0w, C 375 | ldr GL, L->glref 376 | st_vmstate TMP0w 377 | b ->vm_leave_unw 378 | 379 |->vm_unwind_ff: // Unwind C stack, return from ff pcall. 380 | // (void *cframe) 381 | and sp, CARG1, #CFRAME_RAWMASK 382 |->vm_unwind_ff_eh: // Landing pad for external unwinder. 383 | ldr L, SAVE_L 384 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 385 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 386 | movn TISNIL, #0 387 | mov RC, #16 // 2 results: false + error message. 388 | ldr BASE, L->base 389 | ldr GL, L->glref // Setup pointer to global state. 390 | mov_false TMP0 391 | sub RA, BASE, #8 // Results start at BASE-8. 392 | ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame. 393 | str TMP0, [BASE, #-8] // Prepend false to error message. 394 | st_vmstate ST_INTERP 395 | b ->vm_returnc 396 | 397 |//----------------------------------------------------------------------- 398 |//-- Grow stack for calls ----------------------------------------------- 399 |//----------------------------------------------------------------------- 400 | 401 |->vm_growstack_c: // Grow stack for C function. 402 | // CARG1 = L 403 | mov CARG2, #LUA_MINSTACK 404 | b >2 405 | 406 |->vm_growstack_l: // Grow stack for Lua function. 407 | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC 408 | add RC, BASE, RC 409 | sub RA, RA, BASE 410 | mov CARG1, L 411 | stp BASE, RC, L->base 412 | add PC, PC, #4 // Must point after first instruction. 413 | lsr CARG2, RA, #3 414 |2: 415 | // L->base = new base, L->top = top 416 | str PC, SAVE_PC 417 | bl extern lj_state_growstack // (lua_State *L, int n) 418 | ldp BASE, RC, L->base 419 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] 420 | sub NARGS8:RC, RC, BASE 421 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 422 | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC 423 | ins_callt // Just retry the call. 424 | 425 |//----------------------------------------------------------------------- 426 |//-- Entry points into the assembler VM --------------------------------- 427 |//----------------------------------------------------------------------- 428 | 429 |->vm_resume: // Setup C frame and resume thread. 430 | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0) 431 | saveregs 432 | mov L, CARG1 433 | ldr GL, L->glref // Setup pointer to global state. 434 | mov BASE, CARG2 435 | str L, SAVE_L 436 | mov PC, #FRAME_CP 437 | str wzr, SAVE_NRES 438 | add TMP0, sp, #CFRAME_RESUME 439 | ldrb TMP1w, L->status 440 | str wzr, SAVE_ERRF 441 | str L, SAVE_PC // Any value outside of bytecode is ok. 442 | str xzr, SAVE_CFRAME 443 | str TMP0, L->cframe 444 | cbz TMP1w, >3 445 | 446 | // Resume after yield (like a return). 447 | str L, GL->cur_L 448 | mov RA, BASE 449 | ldp BASE, CARG1, L->base 450 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 451 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 452 | ldr PC, [BASE, FRAME_PC] 453 | strb wzr, L->status 454 | movn TISNIL, #0 455 | sub RC, CARG1, BASE 456 | ands CARG1, PC, #FRAME_TYPE 457 | add RC, RC, #8 458 | st_vmstate ST_INTERP 459 | str RCw, SAVE_MULTRES 460 | beq ->BC_RET_Z 461 | b ->vm_return 462 | 463 |->vm_pcall: // Setup protected C frame and enter VM. 464 | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef) 465 | saveregs 466 | mov PC, #FRAME_CP 467 | str CARG4w, SAVE_ERRF 468 | b >1 469 | 470 |->vm_call: // Setup C frame and enter VM. 471 | // (lua_State *L, TValue *base, int nres1) 472 | saveregs 473 | mov PC, #FRAME_C 474 | 475 |1: // Entry point for vm_pcall above (PC = ftype). 476 | ldr RC, L:CARG1->cframe 477 | str CARG3w, SAVE_NRES 478 | mov L, CARG1 479 | str CARG1, SAVE_L 480 | ldr GL, L->glref // Setup pointer to global state. 481 | mov BASE, CARG2 482 | str CARG1, SAVE_PC // Any value outside of bytecode is ok. 483 | str RC, SAVE_CFRAME 484 | str fp, L->cframe // Add our C frame to cframe chain. 485 | 486 |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). 487 | str L, GL->cur_L 488 | ldp RB, CARG1, L->base // RB = old base (for vmeta_call). 489 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 490 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 491 | add PC, PC, BASE 492 | movn TISNIL, #0 493 | sub PC, PC, RB // PC = frame delta + frame type 494 | sub NARGS8:RC, CARG1, BASE 495 | st_vmstate ST_INTERP 496 | 497 |->vm_call_dispatch: 498 | // RB = old base, BASE = new base, RC = nargs*8, PC = caller PC 499 | ldr CARG3, [BASE, FRAME_FUNC] 500 | checkfunc CARG3, ->vmeta_call 501 | 502 |->vm_call_dispatch_f: 503 | ins_call 504 | // BASE = new base, CARG3 = func, RC = nargs*8, PC = caller PC 505 | 506 |->vm_cpcall: // Setup protected C frame, call C. 507 | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp) 508 | saveregs 509 | mov L, CARG1 510 | ldr RA, L:CARG1->stack 511 | str CARG1, SAVE_L 512 | ldr GL, L->glref // Setup pointer to global state. 513 | ldr RB, L->top 514 | str CARG1, SAVE_PC // Any value outside of bytecode is ok. 515 | ldr RC, L->cframe 516 | sub RA, RA, RB // Compute -savestack(L, L->top). 517 | str RAw, SAVE_NRES // Neg. delta means cframe w/o frame. 518 | str wzr, SAVE_ERRF // No error function. 519 | str RC, SAVE_CFRAME 520 | str fp, L->cframe // Add our C frame to cframe chain. 521 | str L, GL->cur_L 522 | blr CARG4 // (lua_State *L, lua_CFunction func, void *ud) 523 | mov BASE, CRET1 524 | mov PC, #FRAME_CP 525 | cbnz BASE, <3 // Else continue with the call. 526 | b ->vm_leave_cp // No base? Just remove C frame. 527 | 528 |//----------------------------------------------------------------------- 529 |//-- Metamethod handling ------------------------------------------------ 530 |//----------------------------------------------------------------------- 531 | 532 |//-- Continuation dispatch ---------------------------------------------- 533 | 534 |->cont_dispatch: 535 | // BASE = meta base, RA = resultptr, RC = (nresults+1)*8 536 | ldr LFUNC:CARG3, [RB, FRAME_FUNC] 537 | ldr CARG1, [BASE, #-32] // Get continuation. 538 | mov CARG4, BASE 539 | mov BASE, RB // Restore caller BASE. 540 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 541 |.if FFI 542 | cmp CARG1, #1 543 |.endif 544 | ldr PC, [CARG4, #-24] // Restore PC from [cont|PC]. 545 | ldr CARG3, LFUNC:CARG3->pc 546 | add TMP0, RA, RC 547 | str TISNIL, [TMP0, #-8] // Ensure one valid arg. 548 |.if FFI 549 | bls >1 550 |.endif 551 | ldr KBASE, [CARG3, #PC2PROTO(k)] 552 | // BASE = base, RA = resultptr, CARG4 = meta base 553 | br CARG1 554 | 555 |.if FFI 556 |1: 557 | beq ->cont_ffi_callback // cont = 1: return from FFI callback. 558 | // cont = 0: tailcall from C function. 559 | sub CARG4, CARG4, #32 560 | sub RC, CARG4, BASE 561 | b ->vm_call_tail 562 |.endif 563 | 564 |->cont_cat: // RA = resultptr, CARG4 = meta base 565 | ldr INSw, [PC, #-4] 566 | sub CARG2, CARG4, #32 567 | ldr TMP0, [RA] 568 | str BASE, L->base 569 | decode_RB RB, INS 570 | decode_RA RA, INS 571 | add TMP1, BASE, RB, lsl #3 572 | subs TMP1, CARG2, TMP1 573 | beq >1 574 | str TMP0, [CARG2] 575 | lsr CARG3, TMP1, #3 576 | b ->BC_CAT_Z 577 | 578 |1: 579 | str TMP0, [BASE, RA, lsl #3] 580 | b ->cont_nop 581 | 582 |//-- Table indexing metamethods ----------------------------------------- 583 | 584 |->vmeta_tgets1: 585 | movn CARG4, #~LJ_TSTR 586 | add CARG2, BASE, RB, lsl #3 587 | add CARG4, STR:RC, CARG4, lsl #47 588 | b >2 589 | 590 |->vmeta_tgets: 591 | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48 592 | str CARG2, GL->tmptv 593 | add CARG2, GL, #offsetof(global_State, tmptv) 594 |2: 595 | add CARG3, sp, TMPDofs 596 | str CARG4, TMPD 597 | b >1 598 | 599 |->vmeta_tgetb: // RB = table, RC = index 600 | add RC, RC, TISNUM 601 | add CARG2, BASE, RB, lsl #3 602 | add CARG3, sp, TMPDofs 603 | str RC, TMPD 604 | b >1 605 | 606 |->vmeta_tgetv: // RB = table, RC = key 607 | add CARG2, BASE, RB, lsl #3 608 | add CARG3, BASE, RC, lsl #3 609 |1: 610 | str BASE, L->base 611 | mov CARG1, L 612 | str PC, SAVE_PC 613 | bl extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k) 614 | // Returns TValue * (finished) or NULL (metamethod). 615 | cbz CRET1, >3 616 | ldr TMP0, [CRET1] 617 | str TMP0, [BASE, RA, lsl #3] 618 | ins_next 619 | 620 |3: // Call __index metamethod. 621 | // BASE = base, L->top = new base, stack = cont/func/t/k 622 | sub TMP1, BASE, #FRAME_CONT 623 | ldr BASE, L->top 624 | mov NARGS8:RC, #16 // 2 args for func(t, k). 625 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. 626 | str PC, [BASE, #-24] // [cont|PC] 627 | sub PC, BASE, TMP1 628 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 629 | b ->vm_call_dispatch_f 630 | 631 |->vmeta_tgetr: 632 | sxtw CARG2, TMP1w 633 | bl extern lj_tab_getinth // (GCtab *t, int32_t key) 634 | // Returns cTValue * or NULL. 635 | mov TMP0, TISNIL 636 | cbz CRET1, ->BC_TGETR_Z 637 | ldr TMP0, [CRET1] 638 | b ->BC_TGETR_Z 639 | 640 |//----------------------------------------------------------------------- 641 | 642 |->vmeta_tsets1: 643 | movn CARG4, #~LJ_TSTR 644 | add CARG2, BASE, RB, lsl #3 645 | add CARG4, STR:RC, CARG4, lsl #47 646 | b >2 647 | 648 |->vmeta_tsets: 649 | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48 650 | str CARG2, GL->tmptv 651 | add CARG2, GL, #offsetof(global_State, tmptv) 652 |2: 653 | add CARG3, sp, TMPDofs 654 | str CARG4, TMPD 655 | b >1 656 | 657 |->vmeta_tsetb: // RB = table, RC = index 658 | add RC, RC, TISNUM 659 | add CARG2, BASE, RB, lsl #3 660 | add CARG3, sp, TMPDofs 661 | str RC, TMPD 662 | b >1 663 | 664 |->vmeta_tsetv: 665 | add CARG2, BASE, RB, lsl #3 666 | add CARG3, BASE, RC, lsl #3 667 |1: 668 | str BASE, L->base 669 | mov CARG1, L 670 | str PC, SAVE_PC 671 | bl extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k) 672 | // Returns TValue * (finished) or NULL (metamethod). 673 | ldr TMP0, [BASE, RA, lsl #3] 674 | cbz CRET1, >3 675 | // NOBARRIER: lj_meta_tset ensures the table is not black. 676 | str TMP0, [CRET1] 677 | ins_next 678 | 679 |3: // Call __newindex metamethod. 680 | // BASE = base, L->top = new base, stack = cont/func/t/k/(v) 681 | sub TMP1, BASE, #FRAME_CONT 682 | ldr BASE, L->top 683 | mov NARGS8:RC, #24 // 3 args for func(t, k, v). 684 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. 685 | str TMP0, [BASE, #16] // Copy value to third argument. 686 | str PC, [BASE, #-24] // [cont|PC] 687 | sub PC, BASE, TMP1 688 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 689 | b ->vm_call_dispatch_f 690 | 691 |->vmeta_tsetr: 692 | sxtw CARG3, TMP1w 693 | str BASE, L->base 694 | str PC, SAVE_PC 695 | bl extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key) 696 | // Returns TValue *. 697 | b ->BC_TSETR_Z 698 | 699 |//-- Comparison metamethods --------------------------------------------- 700 | 701 |->vmeta_comp: 702 | add CARG2, BASE, RA, lsl #3 703 | sub PC, PC, #4 704 | add CARG3, BASE, RC, lsl #3 705 | str BASE, L->base 706 | mov CARG1, L 707 | str PC, SAVE_PC 708 | uxtb CARG4w, INSw 709 | bl extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op) 710 | // Returns 0/1 or TValue * (metamethod). 711 |3: 712 | cmp CRET1, #1 713 | bhi ->vmeta_binop 714 |4: 715 | ldrh RBw, [PC, #2] 716 | add PC, PC, #4 717 | add RB, PC, RB, lsl #2 718 | sub RB, RB, #0x20000 719 | csel PC, PC, RB, lo 720 |->cont_nop: 721 | ins_next 722 | 723 |->cont_ra: // RA = resultptr 724 | ldr INSw, [PC, #-4] 725 | ldr TMP0, [RA] 726 | decode_RA TMP1, INS 727 | str TMP0, [BASE, TMP1, lsl #3] 728 | b ->cont_nop 729 | 730 |->cont_condt: // RA = resultptr 731 | ldr TMP0, [RA] 732 | mov_true TMP1 733 | cmp TMP1, TMP0 // Branch if result is true. 734 | b <4 735 | 736 |->cont_condf: // RA = resultptr 737 | ldr TMP0, [RA] 738 | mov_false TMP1 739 | cmp TMP0, TMP1 // Branch if result is false. 740 | b <4 741 | 742 |->vmeta_equal: 743 | // CARG2, CARG3, CARG4 are already set by BC_ISEQV/BC_ISNEV. 744 | and TAB:CARG3, CARG3, #LJ_GCVMASK 745 | sub PC, PC, #4 746 | str BASE, L->base 747 | mov CARG1, L 748 | str PC, SAVE_PC 749 | bl extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne) 750 | // Returns 0/1 or TValue * (metamethod). 751 | b <3 752 | 753 |->vmeta_equal_cd: 754 |.if FFI 755 | sub PC, PC, #4 756 | str BASE, L->base 757 | mov CARG1, L 758 | mov CARG2, INS 759 | str PC, SAVE_PC 760 | bl extern lj_meta_equal_cd // (lua_State *L, BCIns op) 761 | // Returns 0/1 or TValue * (metamethod). 762 | b <3 763 |.endif 764 | 765 |->vmeta_istype: 766 | sub PC, PC, #4 767 | str BASE, L->base 768 | mov CARG1, L 769 | mov CARG2, RA 770 | mov CARG3, RC 771 | str PC, SAVE_PC 772 | bl extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp) 773 | b ->cont_nop 774 | 775 |//-- Arithmetic metamethods --------------------------------------------- 776 | 777 |->vmeta_arith_vn: 778 | add CARG3, BASE, RB, lsl #3 779 | add CARG4, KBASE, RC, lsl #3 780 | b >1 781 | 782 |->vmeta_arith_nv: 783 | add CARG4, BASE, RB, lsl #3 784 | add CARG3, KBASE, RC, lsl #3 785 | b >1 786 | 787 |->vmeta_unm: 788 | add CARG3, BASE, RC, lsl #3 789 | mov CARG4, CARG3 790 | b >1 791 | 792 |->vmeta_arith_vv: 793 | add CARG3, BASE, RB, lsl #3 794 | add CARG4, BASE, RC, lsl #3 795 |1: 796 | uxtb CARG5w, INSw 797 | add CARG2, BASE, RA, lsl #3 798 | str BASE, L->base 799 | mov CARG1, L 800 | str PC, SAVE_PC 801 | bl extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) 802 | // Returns NULL (finished) or TValue * (metamethod). 803 | cbz CRET1, ->cont_nop 804 | 805 | // Call metamethod for binary op. 806 |->vmeta_binop: 807 | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2 808 | sub TMP1, CRET1, BASE 809 | str PC, [CRET1, #-24] // [cont|PC] 810 | add PC, TMP1, #FRAME_CONT 811 | mov BASE, CRET1 812 | mov NARGS8:RC, #16 // 2 args for func(o1, o2). 813 | b ->vm_call_dispatch 814 | 815 |->vmeta_len: 816 | add CARG2, BASE, RC, lsl #3 817 #if LJ_52 818 | mov TAB:RC, TAB:CARG1 // Save table (ignored for other types). 819 #endif 820 | str BASE, L->base 821 | mov CARG1, L 822 | str PC, SAVE_PC 823 | bl extern lj_meta_len // (lua_State *L, TValue *o) 824 | // Returns NULL (retry) or TValue * (metamethod base). 825 #if LJ_52 826 | cbnz CRET1, ->vmeta_binop // Binop call for compatibility. 827 | mov TAB:CARG1, TAB:RC 828 | b ->BC_LEN_Z 829 #else 830 | b ->vmeta_binop // Binop call for compatibility. 831 #endif 832 | 833 |//-- Call metamethod ---------------------------------------------------- 834 | 835 |->vmeta_call: // Resolve and call __call metamethod. 836 | // RB = old base, BASE = new base, RC = nargs*8 837 | mov CARG1, L 838 | str RB, L->base // This is the callers base! 839 | sub CARG2, BASE, #16 840 | str PC, SAVE_PC 841 | add CARG3, BASE, NARGS8:RC 842 | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) 843 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here. 844 | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now. 845 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 846 | ins_call 847 | 848 |->vmeta_callt: // Resolve __call for BC_CALLT. 849 | // BASE = old base, RA = new base, RC = nargs*8 850 | mov CARG1, L 851 | str BASE, L->base 852 | sub CARG2, RA, #16 853 | str PC, SAVE_PC 854 | add CARG3, RA, NARGS8:RC 855 | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top) 856 | ldr TMP1, [RA, FRAME_FUNC] // Guaranteed to be a function here. 857 | ldr PC, [BASE, FRAME_PC] 858 | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now. 859 | and LFUNC:CARG3, TMP1, #LJ_GCVMASK 860 | b ->BC_CALLT2_Z 861 | 862 |//-- Argument coercion for 'for' statement ------------------------------ 863 | 864 |->vmeta_for: 865 | mov CARG1, L 866 | str BASE, L->base 867 | mov CARG2, RA 868 | str PC, SAVE_PC 869 | bl extern lj_meta_for // (lua_State *L, TValue *base) 870 | ldr INSw, [PC, #-4] 871 |.if JIT 872 | uxtb TMP0, INS 873 |.endif 874 | decode_RA RA, INS 875 | decode_RD RC, INS 876 |.if JIT 877 | cmp TMP0, #BC_JFORI 878 | beq =>BC_JFORI 879 |.endif 880 | b =>BC_FORI 881 | 882 |//----------------------------------------------------------------------- 883 |//-- Fast functions ----------------------------------------------------- 884 |//----------------------------------------------------------------------- 885 | 886 |.macro .ffunc, name 887 |->ff_ .. name: 888 |.endmacro 889 | 890 |.macro .ffunc_1, name 891 |->ff_ .. name: 892 | ldr CARG1, [BASE] 893 | cmp NARGS8:RC, #8 894 | blo ->fff_fallback 895 |.endmacro 896 | 897 |.macro .ffunc_2, name 898 |->ff_ .. name: 899 | ldp CARG1, CARG2, [BASE] 900 | cmp NARGS8:RC, #16 901 | blo ->fff_fallback 902 |.endmacro 903 | 904 |.macro .ffunc_n, name 905 | .ffunc name 906 | ldr CARG1, [BASE] 907 | cmp NARGS8:RC, #8 908 | ldr FARG1, [BASE] 909 | blo ->fff_fallback 910 | checknum CARG1, ->fff_fallback 911 |.endmacro 912 | 913 |.macro .ffunc_nn, name 914 | .ffunc name 915 | ldp CARG1, CARG2, [BASE] 916 | cmp NARGS8:RC, #16 917 | ldp FARG1, FARG2, [BASE] 918 | blo ->fff_fallback 919 | checknum CARG1, ->fff_fallback 920 | checknum CARG2, ->fff_fallback 921 |.endmacro 922 | 923 |// Inlined GC threshold check. Caveat: uses CARG1 and CARG2. 924 |.macro ffgccheck 925 | ldp CARG1, CARG2, GL->gc.total // Assumes threshold follows total. 926 | cmp CARG1, CARG2 927 | blt >1 928 | bl ->fff_gcstep 929 |1: 930 |.endmacro 931 | 932 |//-- Base library: checks ----------------------------------------------- 933 | 934 |.ffunc_1 assert 935 | ldr PC, [BASE, FRAME_PC] 936 | mov_false TMP1 937 | cmp CARG1, TMP1 938 | bhs ->fff_fallback 939 | str CARG1, [BASE, #-16] 940 | sub RB, BASE, #8 941 | subs RA, NARGS8:RC, #8 942 | add RC, NARGS8:RC, #8 // Compute (nresults+1)*8. 943 | cbz RA, ->fff_res // Done if exactly 1 argument. 944 |1: 945 | ldr CARG1, [RB, #16] 946 | sub RA, RA, #8 947 | str CARG1, [RB], #8 948 | cbnz RA, <1 949 | b ->fff_res 950 | 951 |.ffunc_1 type 952 | mov TMP0, #~LJ_TISNUM 953 | asr ITYPE, CARG1, #47 954 | cmn ITYPE, #~LJ_TISNUM 955 | csinv TMP1, TMP0, ITYPE, lo 956 | add TMP1, TMP1, #offsetof(GCfuncC, upvalue)/8 957 | ldr CARG1, [CFUNC:CARG3, TMP1, lsl #3] 958 | b ->fff_restv 959 | 960 |//-- Base library: getters and setters --------------------------------- 961 | 962 |.ffunc_1 getmetatable 963 | asr ITYPE, CARG1, #47 964 | cmn ITYPE, #-LJ_TTAB 965 | ccmn ITYPE, #-LJ_TUDATA, #4, ne 966 | and TAB:CARG1, CARG1, #LJ_GCVMASK 967 | bne >6 968 |1: // Field metatable must be at same offset for GCtab and GCudata! 969 | ldr TAB:RB, TAB:CARG1->metatable 970 |2: 971 | mov CARG1, TISNIL 972 | ldr STR:RC, GL->gcroot[GCROOT_MMNAME+MM_metatable] 973 | cbz TAB:RB, ->fff_restv 974 | ldr TMP1w, TAB:RB->hmask 975 | ldr TMP2w, STR:RC->hash 976 | ldr NODE:CARG3, TAB:RB->node 977 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask 978 | add TMP1, TMP1, TMP1, lsl #1 979 | movn CARG4, #~LJ_TSTR 980 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8 981 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for. 982 |3: // Rearranged logic, because we expect _not_ to find the key. 983 | ldp CARG1, TMP0, NODE:CARG3->val 984 | ldr NODE:CARG3, NODE:CARG3->next 985 | cmp TMP0, CARG4 986 | beq >5 987 | cbnz NODE:CARG3, <3 988 |4: 989 | mov CARG1, RB // Use metatable as default result. 990 | movk CARG1, #(LJ_TTAB>>1)&0xffff, lsl #48 991 | b ->fff_restv 992 |5: 993 | cmp TMP0, TISNIL 994 | bne ->fff_restv 995 | b <4 996 | 997 |6: 998 | movn TMP0, #~LJ_TISNUM 999 | cmp ITYPE, TMP0 1000 | csel ITYPE, ITYPE, TMP0, hs 1001 | sub TMP1, GL, ITYPE, lsl #3 1002 | ldr TAB:RB, [TMP1, #offsetof(global_State, gcroot[GCROOT_BASEMT])-8] 1003 | b <2 1004 | 1005 |.ffunc_2 setmetatable 1006 | // Fast path: no mt for table yet and not clearing the mt. 1007 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback 1008 | ldr TAB:TMP0, TAB:TMP1->metatable 1009 | asr ITYPE, CARG2, #47 1010 | ldrb TMP2w, TAB:TMP1->marked 1011 | cmn ITYPE, #-LJ_TTAB 1012 | and TAB:CARG2, CARG2, #LJ_GCVMASK 1013 | ccmp TAB:TMP0, #0, #0, eq 1014 | bne ->fff_fallback 1015 | str TAB:CARG2, TAB:TMP1->metatable 1016 | tbz TMP2w, #2, ->fff_restv // isblack(table) 1017 | barrierback TAB:TMP1, TMP2w, TMP0 1018 | b ->fff_restv 1019 | 1020 |.ffunc rawget 1021 | ldr CARG2, [BASE] 1022 | cmp NARGS8:RC, #16 1023 | blo ->fff_fallback 1024 | checktab CARG2, ->fff_fallback 1025 | mov CARG1, L 1026 | add CARG3, BASE, #8 1027 | bl extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key) 1028 | // Returns cTValue *. 1029 | ldr CARG1, [CRET1] 1030 | b ->fff_restv 1031 | 1032 |//-- Base library: conversions ------------------------------------------ 1033 | 1034 |.ffunc tonumber 1035 | // Only handles the number case inline (without a base argument). 1036 | ldr CARG1, [BASE] 1037 | cmp NARGS8:RC, #8 1038 | bne ->fff_fallback 1039 | checknumber CARG1, ->fff_fallback 1040 | b ->fff_restv 1041 | 1042 |.ffunc_1 tostring 1043 | // Only handles the string or number case inline. 1044 | asr ITYPE, CARG1, #47 1045 | cmn ITYPE, #-LJ_TSTR 1046 | // A __tostring method in the string base metatable is ignored. 1047 | beq ->fff_restv 1048 | // Handle numbers inline, unless a number base metatable is present. 1049 | ldr TMP1, GL->gcroot[GCROOT_BASEMT_NUM] 1050 | str BASE, L->base 1051 | cmn ITYPE, #-LJ_TISNUM 1052 | ccmp TMP1, #0, #0, ls 1053 | str PC, SAVE_PC // Redundant (but a defined value). 1054 | bne ->fff_fallback 1055 | ffgccheck 1056 | mov CARG1, L 1057 | mov CARG2, BASE 1058 | bl extern lj_strfmt_number // (lua_State *L, cTValue *o) 1059 | // Returns GCstr *. 1060 | movn TMP1, #~LJ_TSTR 1061 | ldr BASE, L->base 1062 | add CARG1, CARG1, TMP1, lsl #47 1063 | b ->fff_restv 1064 | 1065 |//-- Base library: iterators ------------------------------------------- 1066 | 1067 |.ffunc_1 next 1068 | checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback 1069 | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. 1070 | ldr PC, [BASE, FRAME_PC] 1071 | stp BASE, BASE, L->base // Add frame since C call can throw. 1072 | mov CARG1, L 1073 | add CARG3, BASE, #8 1074 | str PC, SAVE_PC 1075 | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) 1076 | // Returns 0 at end of traversal. 1077 | str TISNIL, [BASE, #-16] 1078 | cbz CRET1, ->fff_res1 // End of traversal: return nil. 1079 | ldp CARG1, CARG2, [BASE, #8] // Copy key and value to results. 1080 | mov RC, #(2+1)*8 1081 | stp CARG1, CARG2, [BASE, #-16] 1082 | b ->fff_res 1083 | 1084 |.ffunc_1 pairs 1085 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback 1086 #if LJ_52 1087 | ldr TAB:CARG2, TAB:TMP1->metatable 1088 #endif 1089 | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0] 1090 | ldr PC, [BASE, FRAME_PC] 1091 #if LJ_52 1092 | cbnz TAB:CARG2, ->fff_fallback 1093 #endif 1094 | mov RC, #(3+1)*8 1095 | stp CARG1, TISNIL, [BASE, #-8] 1096 | str CFUNC:CARG4, [BASE, #-16] 1097 | b ->fff_res 1098 | 1099 |.ffunc_2 ipairs_aux 1100 | checktab CARG1, ->fff_fallback 1101 | checkint CARG2, ->fff_fallback 1102 | ldr TMP1w, TAB:CARG1->asize 1103 | ldr CARG3, TAB:CARG1->array 1104 | ldr TMP0w, TAB:CARG1->hmask 1105 | add CARG2w, CARG2w, #1 1106 | cmp CARG2w, TMP1w 1107 | ldr PC, [BASE, FRAME_PC] 1108 | add TMP2, CARG2, TISNUM 1109 | mov RC, #(0+1)*8 1110 | str TMP2, [BASE, #-16] 1111 | bhs >2 // Not in array part? 1112 | ldr TMP0, [CARG3, CARG2, lsl #3] 1113 |1: 1114 | mov TMP1, #(2+1)*8 1115 | cmp TMP0, TISNIL 1116 | str TMP0, [BASE, #-8] 1117 | csel RC, RC, TMP1, eq 1118 | b ->fff_res 1119 |2: // Check for empty hash part first. Otherwise call C function. 1120 | cbz TMP0w, ->fff_res 1121 | bl extern lj_tab_getinth // (GCtab *t, int32_t key) 1122 | // Returns cTValue * or NULL. 1123 | cbz CRET1, ->fff_res 1124 | ldr TMP0, [CRET1] 1125 | b <1 1126 | 1127 |.ffunc_1 ipairs 1128 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback 1129 #if LJ_52 1130 | ldr TAB:CARG2, TAB:TMP1->metatable 1131 #endif 1132 | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0] 1133 | ldr PC, [BASE, FRAME_PC] 1134 #if LJ_52 1135 | cbnz TAB:CARG2, ->fff_fallback 1136 #endif 1137 | mov RC, #(3+1)*8 1138 | stp CARG1, TISNUM, [BASE, #-8] 1139 | str CFUNC:CARG4, [BASE, #-16] 1140 | b ->fff_res 1141 | 1142 |//-- Base library: catch errors ---------------------------------------- 1143 | 1144 |.ffunc pcall 1145 | ldrb TMP0w, GL->hookmask 1146 | subs NARGS8:RC, NARGS8:RC, #8 1147 | blo ->fff_fallback 1148 | mov RB, BASE 1149 | add BASE, BASE, #16 1150 | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1 1151 | add PC, TMP0, #16+FRAME_PCALL 1152 | beq ->vm_call_dispatch 1153 |1: 1154 | add TMP2, BASE, NARGS8:RC 1155 |2: 1156 | ldr TMP0, [TMP2, #-16] 1157 | str TMP0, [TMP2, #-8]! 1158 | cmp TMP2, BASE 1159 | bne <2 1160 | b ->vm_call_dispatch 1161 | 1162 |.ffunc xpcall 1163 | ldp CARG1, CARG2, [BASE] 1164 | ldrb TMP0w, GL->hookmask 1165 | subs NARGS8:RC, NARGS8:RC, #16 1166 | blo ->fff_fallback 1167 | mov RB, BASE 1168 | add BASE, BASE, #24 1169 | asr ITYPE, CARG2, #47 1170 | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1 1171 | cmn ITYPE, #-LJ_TFUNC 1172 | add PC, TMP0, #24+FRAME_PCALL 1173 | bne ->fff_fallback // Traceback must be a function. 1174 | stp CARG2, CARG1, [RB] // Swap function and traceback. 1175 | cbz NARGS8:RC, ->vm_call_dispatch 1176 | b <1 1177 | 1178 |//-- Coroutine library -------------------------------------------------- 1179 | 1180 |.macro coroutine_resume_wrap, resume 1181 |.if resume 1182 |.ffunc_1 coroutine_resume 1183 | checktp CARG1, LJ_TTHREAD, ->fff_fallback 1184 |.else 1185 |.ffunc coroutine_wrap_aux 1186 | ldr L:CARG1, CFUNC:CARG3->upvalue[0].gcr 1187 | and L:CARG1, CARG1, #LJ_GCVMASK 1188 |.endif 1189 | ldr PC, [BASE, FRAME_PC] 1190 | str BASE, L->base 1191 | ldp RB, CARG2, L:CARG1->base 1192 | ldrb TMP1w, L:CARG1->status 1193 | add TMP0, CARG2, TMP1 1194 | str PC, SAVE_PC 1195 | cmp TMP0, RB 1196 | beq ->fff_fallback 1197 | cmp TMP1, #LUA_YIELD 1198 | add TMP0, CARG2, #8 1199 | csel CARG2, CARG2, TMP0, hs 1200 | ldr CARG4, L:CARG1->maxstack 1201 | add CARG3, CARG2, NARGS8:RC 1202 | ldr RB, L:CARG1->cframe 1203 | ccmp CARG3, CARG4, #2, ls 1204 | ccmp RB, #0, #2, ls 1205 | bhi ->fff_fallback 1206 |.if resume 1207 | sub CARG3, CARG3, #8 // Keep resumed thread in stack for GC. 1208 | add BASE, BASE, #8 1209 | sub NARGS8:RC, NARGS8:RC, #8 1210 |.endif 1211 | str CARG3, L:CARG1->top 1212 | str BASE, L->top 1213 | cbz NARGS8:RC, >3 1214 |2: // Move args to coroutine. 1215 | ldr TMP0, [BASE, RB] 1216 | cmp RB, NARGS8:RC 1217 | str TMP0, [CARG2, RB] 1218 | add RB, RB, #8 1219 | bne <2 1220 |3: 1221 | mov CARG3, #0 1222 | mov L:RA, L:CARG1 1223 | mov CARG4, #0 1224 | bl ->vm_resume // (lua_State *L, TValue *base, 0, 0) 1225 | // Returns thread status. 1226 |4: 1227 | ldp CARG3, CARG4, L:RA->base 1228 | cmp CRET1, #LUA_YIELD 1229 | ldr BASE, L->base 1230 | str L, GL->cur_L 1231 | st_vmstate ST_INTERP 1232 | bhi >8 1233 | sub RC, CARG4, CARG3 1234 | ldr CARG1, L->maxstack 1235 | add CARG2, BASE, RC 1236 | cbz RC, >6 // No results? 1237 | cmp CARG2, CARG1 1238 | mov RB, #0 1239 | bhi >9 // Need to grow stack? 1240 | 1241 | sub CARG4, RC, #8 1242 | str CARG3, L:RA->top // Clear coroutine stack. 1243 |5: // Move results from coroutine. 1244 | ldr TMP0, [CARG3, RB] 1245 | cmp RB, CARG4 1246 | str TMP0, [BASE, RB] 1247 | add RB, RB, #8 1248 | bne <5 1249 |6: 1250 |.if resume 1251 | mov_true TMP1 1252 | add RC, RC, #16 1253 |7: 1254 | str TMP1, [BASE, #-8] // Prepend true/false to results. 1255 | sub RA, BASE, #8 1256 |.else 1257 | mov RA, BASE 1258 | add RC, RC, #8 1259 |.endif 1260 | ands CARG1, PC, #FRAME_TYPE 1261 | str PC, SAVE_PC 1262 | str RCw, SAVE_MULTRES 1263 | beq ->BC_RET_Z 1264 | b ->vm_return 1265 | 1266 |8: // Coroutine returned with error (at co->top-1). 1267 |.if resume 1268 | ldr TMP0, [CARG4, #-8]! 1269 | mov_false TMP1 1270 | mov RC, #(2+1)*8 1271 | str CARG4, L:RA->top // Remove error from coroutine stack. 1272 | str TMP0, [BASE] // Copy error message. 1273 | b <7 1274 |.else 1275 | mov CARG1, L 1276 | mov CARG2, L:RA 1277 | bl extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co) 1278 | // Never returns. 1279 |.endif 1280 | 1281 |9: // Handle stack expansion on return from yield. 1282 | mov CARG1, L 1283 | lsr CARG2, RC, #3 1284 | bl extern lj_state_growstack // (lua_State *L, int n) 1285 | mov CRET1, #0 1286 | b <4 1287 |.endmacro 1288 | 1289 | coroutine_resume_wrap 1 // coroutine.resume 1290 | coroutine_resume_wrap 0 // coroutine.wrap 1291 | 1292 |.ffunc coroutine_yield 1293 | ldr TMP0, L->cframe 1294 | add TMP1, BASE, NARGS8:RC 1295 | mov CRET1, #LUA_YIELD 1296 | stp BASE, TMP1, L->base 1297 | tbz TMP0, #0, ->fff_fallback 1298 | str xzr, L->cframe 1299 | strb CRET1w, L->status 1300 | b ->vm_leave_unw 1301 | 1302 |//-- Math library ------------------------------------------------------- 1303 | 1304 |.macro math_round, func, round 1305 | .ffunc math_ .. func 1306 | ldr CARG1, [BASE] 1307 | cmp NARGS8:RC, #8 1308 | ldr d0, [BASE] 1309 | blo ->fff_fallback 1310 | cmp TISNUMhi, CARG1, lsr #32 1311 | beq ->fff_restv 1312 | blo ->fff_fallback 1313 | round d0, d0 1314 | b ->fff_resn 1315 |.endmacro 1316 | 1317 | math_round floor, frintm 1318 | math_round ceil, frintp 1319 | 1320 |.ffunc_1 math_abs 1321 | checknumber CARG1, ->fff_fallback 1322 | and CARG1, CARG1, #U64x(7fffffff,ffffffff) 1323 | bne ->fff_restv 1324 | eor CARG2w, CARG1w, CARG1w, asr #31 1325 | movz CARG3, #0x41e0, lsl #48 // 2^31. 1326 | subs CARG1w, CARG2w, CARG1w, asr #31 1327 | add CARG1, CARG1, TISNUM 1328 | csel CARG1, CARG1, CARG3, pl 1329 | // Fallthrough. 1330 | 1331 |->fff_restv: 1332 | // CARG1 = TValue result. 1333 | ldr PC, [BASE, FRAME_PC] 1334 | str CARG1, [BASE, #-16] 1335 |->fff_res1: 1336 | // PC = return. 1337 | mov RC, #(1+1)*8 1338 |->fff_res: 1339 | // RC = (nresults+1)*8, PC = return. 1340 | ands CARG1, PC, #FRAME_TYPE 1341 | str RCw, SAVE_MULTRES 1342 | sub RA, BASE, #16 1343 | bne ->vm_return 1344 | ldr INSw, [PC, #-4] 1345 | decode_RB RB, INS 1346 |5: 1347 | cmp RC, RB, lsl #3 // More results expected? 1348 | blo >6 1349 | decode_RA TMP1, INS 1350 | // Adjust BASE. KBASE is assumed to be set for the calling frame. 1351 | sub BASE, RA, TMP1, lsl #3 1352 | ins_next 1353 | 1354 |6: // Fill up results with nil. 1355 | add TMP1, RA, RC 1356 | add RC, RC, #8 1357 | str TISNIL, [TMP1, #-8] 1358 | b <5 1359 | 1360 |.macro math_extern, func 1361 | .ffunc_n math_ .. func 1362 | bl extern func 1363 | b ->fff_resn 1364 |.endmacro 1365 | 1366 |.macro math_extern2, func 1367 | .ffunc_nn math_ .. func 1368 | bl extern func 1369 | b ->fff_resn 1370 |.endmacro 1371 | 1372 |.ffunc_n math_sqrt 1373 | fsqrt d0, d0 1374 |->fff_resn: 1375 | ldr PC, [BASE, FRAME_PC] 1376 | str d0, [BASE, #-16] 1377 | b ->fff_res1 1378 | 1379 |.ffunc math_log 1380 | ldr CARG1, [BASE] 1381 | cmp NARGS8:RC, #8 1382 | ldr FARG1, [BASE] 1383 | bne ->fff_fallback // Need exactly 1 argument. 1384 | checknum CARG1, ->fff_fallback 1385 | bl extern log 1386 | b ->fff_resn 1387 | 1388 | math_extern log10 1389 | math_extern exp 1390 | math_extern sin 1391 | math_extern cos 1392 | math_extern tan 1393 | math_extern asin 1394 | math_extern acos 1395 | math_extern atan 1396 | math_extern sinh 1397 | math_extern cosh 1398 | math_extern tanh 1399 | math_extern2 pow 1400 | math_extern2 atan2 1401 | math_extern2 fmod 1402 | 1403 |.ffunc_2 math_ldexp 1404 | ldr FARG1, [BASE] 1405 | checknum CARG1, ->fff_fallback 1406 | checkint CARG2, ->fff_fallback 1407 | sxtw CARG1, CARG2w 1408 | bl extern ldexp // (double x, int exp) 1409 | b ->fff_resn 1410 | 1411 |.ffunc_n math_frexp 1412 | add CARG1, sp, TMPDofs 1413 | bl extern frexp 1414 | ldr CARG2w, TMPD 1415 | ldr PC, [BASE, FRAME_PC] 1416 | str d0, [BASE, #-16] 1417 | mov RC, #(2+1)*8 1418 | add CARG2, CARG2, TISNUM 1419 | str CARG2, [BASE, #-8] 1420 | b ->fff_res 1421 | 1422 |.ffunc_n math_modf 1423 | sub CARG1, BASE, #16 1424 | ldr PC, [BASE, FRAME_PC] 1425 | bl extern modf 1426 | mov RC, #(2+1)*8 1427 | str d0, [BASE, #-8] 1428 | b ->fff_res 1429 | 1430 |.macro math_minmax, name, cond, fcond 1431 | .ffunc_1 name 1432 | add RB, BASE, RC 1433 | add RA, BASE, #8 1434 | checkint CARG1, >4 1435 |1: // Handle integers. 1436 | ldr CARG2, [RA] 1437 | cmp RA, RB 1438 | bhs ->fff_restv 1439 | checkint CARG2, >3 1440 | cmp CARG1w, CARG2w 1441 | add RA, RA, #8 1442 | csel CARG1, CARG2, CARG1, cond 1443 | b <1 1444 |3: // Convert intermediate result to number and continue below. 1445 | scvtf d0, CARG1w 1446 | blo ->fff_fallback 1447 | ldr d1, [RA] 1448 | b >6 1449 | 1450 |4: 1451 | ldr d0, [BASE] 1452 | blo ->fff_fallback 1453 |5: // Handle numbers. 1454 | ldr CARG2, [RA] 1455 | ldr d1, [RA] 1456 | cmp RA, RB 1457 | bhs ->fff_resn 1458 | checknum CARG2, >7 1459 |6: 1460 | fcmp d0, d1 1461 | add RA, RA, #8 1462 | fcsel d0, d1, d0, fcond 1463 | b <5 1464 |7: // Convert integer to number and continue above. 1465 | scvtf d1, CARG2w 1466 | blo ->fff_fallback 1467 | b <6 1468 |.endmacro 1469 | 1470 | math_minmax math_min, gt, hi 1471 | math_minmax math_max, lt, lo 1472 | 1473 |//-- String library ----------------------------------------------------- 1474 | 1475 |.ffunc string_byte // Only handle the 1-arg case here. 1476 | ldp PC, CARG1, [BASE, FRAME_PC] 1477 | cmp NARGS8:RC, #8 1478 | asr ITYPE, CARG1, #47 1479 | ccmn ITYPE, #-LJ_TSTR, #0, eq 1480 | and STR:CARG1, CARG1, #LJ_GCVMASK 1481 | bne ->fff_fallback 1482 | ldrb TMP0w, STR:CARG1[1] // Access is always ok (NUL at end). 1483 | ldr CARG3w, STR:CARG1->len 1484 | add TMP0, TMP0, TISNUM 1485 | str TMP0, [BASE, #-16] 1486 | mov RC, #(0+1)*8 1487 | cbz CARG3, ->fff_res 1488 | b ->fff_res1 1489 | 1490 |.ffunc string_char // Only handle the 1-arg case here. 1491 | ffgccheck 1492 | ldp PC, CARG1, [BASE, FRAME_PC] 1493 | cmp CARG1w, #255 1494 | ccmp NARGS8:RC, #8, #0, ls // Need exactly 1 argument. 1495 | bne ->fff_fallback 1496 | checkint CARG1, ->fff_fallback 1497 | mov CARG3, #1 1498 | mov CARG2, BASE // Points to stack. Little-endian. 1499 |->fff_newstr: 1500 | // CARG2 = str, CARG3 = len. 1501 | str BASE, L->base 1502 | mov CARG1, L 1503 | str PC, SAVE_PC 1504 | bl extern lj_str_new // (lua_State *L, char *str, size_t l) 1505 |->fff_resstr: 1506 | // Returns GCstr *. 1507 | ldr BASE, L->base 1508 | movn TMP1, #~LJ_TSTR 1509 | add CARG1, CARG1, TMP1, lsl #47 1510 | b ->fff_restv 1511 | 1512 |.ffunc string_sub 1513 | ffgccheck 1514 | ldr CARG1, [BASE] 1515 | ldr CARG3, [BASE, #16] 1516 | cmp NARGS8:RC, #16 1517 | movn RB, #0 1518 | beq >1 1519 | blo ->fff_fallback 1520 | checkint CARG3, ->fff_fallback 1521 | sxtw RB, CARG3w 1522 |1: 1523 | ldr CARG2, [BASE, #8] 1524 | checkstr CARG1, ->fff_fallback 1525 | ldr TMP1w, STR:CARG1->len 1526 | checkint CARG2, ->fff_fallback 1527 | sxtw CARG2, CARG2w 1528 | // CARG1 = str, TMP1 = str->len, CARG2 = start, RB = end 1529 | add TMP2, RB, TMP1 1530 | cmp RB, #0 1531 | add TMP0, CARG2, TMP1 1532 | csinc RB, RB, TMP2, ge // if (end < 0) end += len+1 1533 | cmp CARG2, #0 1534 | csinc CARG2, CARG2, TMP0, ge // if (start < 0) start += len+1 1535 | cmp RB, #0 1536 | csel RB, RB, xzr, ge // if (end < 0) end = 0 1537 | cmp CARG2, #1 1538 | csinc CARG2, CARG2, xzr, ge // if (start < 1) start = 1 1539 | cmp RB, TMP1 1540 | csel RB, RB, TMP1, le // if (end > len) end = len 1541 | add CARG1, STR:CARG1, #sizeof(GCstr)-1 1542 | subs CARG3, RB, CARG2 // len = end - start 1543 | add CARG2, CARG1, CARG2 1544 | add CARG3, CARG3, #1 // len += 1 1545 | bge ->fff_newstr 1546 | add STR:CARG1, GL, #offsetof(global_State, strempty) 1547 | movn TMP1, #~LJ_TSTR 1548 | add CARG1, CARG1, TMP1, lsl #47 1549 | b ->fff_restv 1550 | 1551 |.macro ffstring_op, name 1552 | .ffunc string_ .. name 1553 | ffgccheck 1554 | ldr CARG2, [BASE] 1555 | cmp NARGS8:RC, #8 1556 | asr ITYPE, CARG2, #47 1557 | ccmn ITYPE, #-LJ_TSTR, #0, hs 1558 | and STR:CARG2, CARG2, #LJ_GCVMASK 1559 | bne ->fff_fallback 1560 | ldr TMP0, GL->tmpbuf.b 1561 | add SBUF:CARG1, GL, #offsetof(global_State, tmpbuf) 1562 | str BASE, L->base 1563 | str PC, SAVE_PC 1564 | str L, GL->tmpbuf.L 1565 | str TMP0, GL->tmpbuf.p 1566 | bl extern lj_buf_putstr_ .. name 1567 | bl extern lj_buf_tostr 1568 | b ->fff_resstr 1569 |.endmacro 1570 | 1571 |ffstring_op reverse 1572 |ffstring_op lower 1573 |ffstring_op upper 1574 | 1575 |//-- Bit library -------------------------------------------------------- 1576 | 1577 |// FP number to bit conversion for soft-float. Clobbers CARG1-CARG3 1578 |->vm_tobit_fb: 1579 | bls ->fff_fallback 1580 | add CARG2, CARG1, CARG1 1581 | mov CARG3, #1076 1582 | sub CARG3, CARG3, CARG2, lsr #53 1583 | cmp CARG3, #53 1584 | bhi >1 1585 | and CARG2, CARG2, #U64x(001fffff,ffffffff) 1586 | orr CARG2, CARG2, #U64x(00200000,00000000) 1587 | cmp CARG1, #0 1588 | lsr CARG2, CARG2, CARG3 1589 | cneg CARG1w, CARG2w, mi 1590 | br lr 1591 |1: 1592 | mov CARG1w, #0 1593 | br lr 1594 | 1595 |.macro .ffunc_bit, name 1596 | .ffunc_1 bit_..name 1597 | adr lr, >1 1598 | checkint CARG1, ->vm_tobit_fb 1599 |1: 1600 |.endmacro 1601 | 1602 |.macro .ffunc_bit_op, name, ins 1603 | .ffunc_bit name 1604 | mov RA, #8 1605 | mov TMP0w, CARG1w 1606 | adr lr, >2 1607 |1: 1608 | ldr CARG1, [BASE, RA] 1609 | cmp RA, NARGS8:RC 1610 | add RA, RA, #8 1611 | bge >9 1612 | checkint CARG1, ->vm_tobit_fb 1613 |2: 1614 | ins TMP0w, TMP0w, CARG1w 1615 | b <1 1616 |.endmacro 1617 | 1618 |.ffunc_bit_op band, and 1619 |.ffunc_bit_op bor, orr 1620 |.ffunc_bit_op bxor, eor 1621 | 1622 |.ffunc_bit tobit 1623 | mov TMP0w, CARG1w 1624 |9: // Label reused by .ffunc_bit_op users. 1625 | add CARG1, TMP0, TISNUM 1626 | b ->fff_restv 1627 | 1628 |.ffunc_bit bswap 1629 | rev TMP0w, CARG1w 1630 | add CARG1, TMP0, TISNUM 1631 | b ->fff_restv 1632 | 1633 |.ffunc_bit bnot 1634 | mvn TMP0w, CARG1w 1635 | add CARG1, TMP0, TISNUM 1636 | b ->fff_restv 1637 | 1638 |.macro .ffunc_bit_sh, name, ins, shmod 1639 | .ffunc bit_..name 1640 | ldp TMP0, CARG1, [BASE] 1641 | cmp NARGS8:RC, #16 1642 | blo ->fff_fallback 1643 | adr lr, >1 1644 | checkint CARG1, ->vm_tobit_fb 1645 |1: 1646 |.if shmod == 0 1647 | mov TMP1, CARG1 1648 |.else 1649 | neg TMP1, CARG1 1650 |.endif 1651 | mov CARG1, TMP0 1652 | adr lr, >2 1653 | checkint CARG1, ->vm_tobit_fb 1654 |2: 1655 | ins TMP0w, CARG1w, TMP1w 1656 | add CARG1, TMP0, TISNUM 1657 | b ->fff_restv 1658 |.endmacro 1659 | 1660 |.ffunc_bit_sh lshift, lsl, 0 1661 |.ffunc_bit_sh rshift, lsr, 0 1662 |.ffunc_bit_sh arshift, asr, 0 1663 |.ffunc_bit_sh rol, ror, 1 1664 |.ffunc_bit_sh ror, ror, 0 1665 | 1666 |//----------------------------------------------------------------------- 1667 | 1668 |->fff_fallback: // Call fast function fallback handler. 1669 | // BASE = new base, RC = nargs*8 1670 | ldp CFUNC:CARG3, PC, [BASE, FRAME_FUNC] // Fallback may overwrite PC. 1671 | ldr TMP2, L->maxstack 1672 | add TMP1, BASE, NARGS8:RC 1673 | stp BASE, TMP1, L->base 1674 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK 1675 | add TMP1, TMP1, #8*LUA_MINSTACK 1676 | ldr CARG3, CFUNC:CARG3->f 1677 | str PC, SAVE_PC // Redundant (but a defined value). 1678 | cmp TMP1, TMP2 1679 | mov CARG1, L 1680 | bhi >5 // Need to grow stack. 1681 | blr CARG3 // (lua_State *L) 1682 | // Either throws an error, or recovers and returns -1, 0 or nresults+1. 1683 | ldr BASE, L->base 1684 | cmp CRET1w, #0 1685 | lsl RC, CRET1, #3 1686 | sub RA, BASE, #16 1687 | bgt ->fff_res // Returned nresults+1? 1688 |1: // Returned 0 or -1: retry fast path. 1689 | ldr CARG1, L->top 1690 | ldr CFUNC:CARG3, [BASE, FRAME_FUNC] 1691 | sub NARGS8:RC, CARG1, BASE 1692 | bne ->vm_call_tail // Returned -1? 1693 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK 1694 | ins_callt // Returned 0: retry fast path. 1695 | 1696 |// Reconstruct previous base for vmeta_call during tailcall. 1697 |->vm_call_tail: 1698 | ands TMP0, PC, #FRAME_TYPE 1699 | and TMP1, PC, #~FRAME_TYPEP 1700 | bne >3 1701 | ldrb RAw, [PC, #-3] 1702 | lsl RA, RA, #3 1703 | add TMP1, RA, #16 1704 |3: 1705 | sub RB, BASE, TMP1 1706 | b ->vm_call_dispatch // Resolve again for tailcall. 1707 | 1708 |5: // Grow stack for fallback handler. 1709 | mov CARG2, #LUA_MINSTACK 1710 | bl extern lj_state_growstack // (lua_State *L, int n) 1711 | ldr BASE, L->base 1712 | cmp CARG1, CARG1 // Set zero-flag to force retry. 1713 | b <1 1714 | 1715 |->fff_gcstep: // Call GC step function. 1716 | // BASE = new base, RC = nargs*8 1717 | add CARG2, BASE, NARGS8:RC // Calculate L->top. 1718 | mov RA, lr 1719 | stp BASE, CARG2, L->base 1720 | str PC, SAVE_PC // Redundant (but a defined value). 1721 | mov CARG1, L 1722 | bl extern lj_gc_step // (lua_State *L) 1723 | ldp BASE, CARG2, L->base 1724 | ldr CFUNC:CARG3, [BASE, FRAME_FUNC] 1725 | mov lr, RA // Help return address predictor. 1726 | sub NARGS8:RC, CARG2, BASE // Calculate nargs*8. 1727 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK 1728 | ret 1729 | 1730 |//----------------------------------------------------------------------- 1731 |//-- Special dispatch targets ------------------------------------------- 1732 |//----------------------------------------------------------------------- 1733 | 1734 |->vm_record: // Dispatch target for recording phase. 1735 | NYI 1736 | 1737 |->vm_rethook: // Dispatch target for return hooks. 1738 | ldrb TMP2w, GL->hookmask 1739 | tbz TMP2w, #HOOK_ACTIVE_SHIFT, >1 // Hook already active? 1740 |5: // Re-dispatch to static ins. 1741 | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC] 1742 | br TMP0 1743 | 1744 |->vm_inshook: // Dispatch target for instr/line hooks. 1745 | ldrb TMP2w, GL->hookmask 1746 | ldr TMP3w, GL->hookcount 1747 | tbnz TMP2w, #HOOK_ACTIVE_SHIFT, <5 // Hook already active? 1748 | tst TMP2w, #LUA_MASKLINE|LUA_MASKCOUNT 1749 | beq <5 1750 | sub TMP3w, TMP3w, #1 1751 | str TMP3w, GL->hookcount 1752 | cbz TMP3w, >1 1753 | tbz TMP2w, #LUA_HOOKLINE, <5 1754 |1: 1755 | mov CARG1, L 1756 | str BASE, L->base 1757 | mov CARG2, PC 1758 | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. 1759 | bl extern lj_dispatch_ins // (lua_State *L, const BCIns *pc) 1760 |3: 1761 | ldr BASE, L->base 1762 |4: // Re-dispatch to static ins. 1763 | ldr INSw, [PC, #-4] 1764 | add TMP1, GL, INS, uxtb #3 1765 | decode_RA RA, INS 1766 | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC] 1767 | decode_RD RC, INS 1768 | br TMP0 1769 | 1770 |->cont_hook: // Continue from hook yield. 1771 | ldr CARG1, [CARG4, #-40] 1772 | add PC, PC, #4 1773 | str CARG1w, SAVE_MULTRES // Restore MULTRES for *M ins. 1774 | b <4 1775 | 1776 |->vm_hotloop: // Hot loop counter underflow. 1777 | NYI 1778 | 1779 |->vm_callhook: // Dispatch target for call hooks. 1780 | mov CARG2, PC 1781 |.if JIT 1782 | b >1 1783 |.endif 1784 | 1785 |->vm_hotcall: // Hot call counter underflow. 1786 |.if JIT 1787 | orr CARG2, PC, #1 1788 |1: 1789 |.endif 1790 | add TMP1, BASE, NARGS8:RC 1791 | str PC, SAVE_PC 1792 | mov CARG1, L 1793 | sub RA, RA, BASE 1794 | stp BASE, TMP1, L->base 1795 | bl extern lj_dispatch_call // (lua_State *L, const BCIns *pc) 1796 | // Returns ASMFunction. 1797 | ldp BASE, TMP1, L->base 1798 | str xzr, SAVE_PC // Invalidate for subsequent line hook. 1799 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] 1800 | add RA, BASE, RA 1801 | sub NARGS8:RC, TMP1, BASE 1802 | ldr INSw, [PC, #-4] 1803 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 1804 | br CRET1 1805 | 1806 |->cont_stitch: // Trace stitching. 1807 | NYI 1808 | 1809 |->vm_profhook: // Dispatch target for profiler hook. 1810 #if LJ_HASPROFILE 1811 | mov CARG1, L 1812 | str BASE, L->base 1813 | mov CARG2, PC 1814 | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc) 1815 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction. 1816 | ldr BASE, L->base 1817 | sub PC, PC, #4 1818 | b ->cont_nop 1819 #endif 1820 | 1821 |//----------------------------------------------------------------------- 1822 |//-- Trace exit handler ------------------------------------------------- 1823 |//----------------------------------------------------------------------- 1824 | 1825 |->vm_exit_handler: 1826 | NYI 1827 |->vm_exit_interp: 1828 | NYI 1829 | 1830 |//----------------------------------------------------------------------- 1831 |//-- Math helper functions ---------------------------------------------- 1832 |//----------------------------------------------------------------------- 1833 | 1834 | // int lj_vm_modi(int dividend, int divisor); 1835 |->vm_modi: 1836 | eor CARG4w, CARG1w, CARG2w 1837 | cmp CARG4w, #0 1838 | eor CARG3w, CARG1w, CARG1w, asr #31 1839 | eor CARG4w, CARG2w, CARG2w, asr #31 1840 | sub CARG3w, CARG3w, CARG1w, asr #31 1841 | sub CARG4w, CARG4w, CARG2w, asr #31 1842 | udiv CARG1w, CARG3w, CARG4w 1843 | msub CARG1w, CARG1w, CARG4w, CARG3w 1844 | ccmp CARG1w, #0, #4, mi 1845 | sub CARG3w, CARG1w, CARG4w 1846 | csel CARG1w, CARG1w, CARG3w, eq 1847 | eor CARG3w, CARG1w, CARG2w 1848 | cmp CARG3w, #0 1849 | cneg CARG1w, CARG1w, mi 1850 | ret 1851 | 1852 |//----------------------------------------------------------------------- 1853 |//-- Miscellaneous functions -------------------------------------------- 1854 |//----------------------------------------------------------------------- 1855 | 1856 |//----------------------------------------------------------------------- 1857 |//-- FFI helper functions ----------------------------------------------- 1858 |//----------------------------------------------------------------------- 1859 | 1860 |// Handler for callback functions. 1861 |// Saveregs already performed. Callback slot number in [sp], g in r12. 1862 |->vm_ffi_callback: 1863 |.if FFI 1864 |.type CTSTATE, CTState, PC 1865 | saveregs 1866 | ldr CTSTATE, GL:x10->ctype_state 1867 | mov GL, x10 1868 | add x10, sp, # CFRAME_SPACE 1869 | str w9, CTSTATE->cb.slot 1870 | stp x0, x1, CTSTATE->cb.gpr[0] 1871 | stp d0, d1, CTSTATE->cb.fpr[0] 1872 | stp x2, x3, CTSTATE->cb.gpr[2] 1873 | stp d2, d3, CTSTATE->cb.fpr[2] 1874 | stp x4, x5, CTSTATE->cb.gpr[4] 1875 | stp d4, d5, CTSTATE->cb.fpr[4] 1876 | stp x6, x7, CTSTATE->cb.gpr[6] 1877 | stp d6, d7, CTSTATE->cb.fpr[6] 1878 | str x10, CTSTATE->cb.stack 1879 | mov CARG1, CTSTATE 1880 | str CTSTATE, SAVE_PC // Any value outside of bytecode is ok. 1881 | mov CARG2, sp 1882 | bl extern lj_ccallback_enter // (CTState *cts, void *cf) 1883 | // Returns lua_State *. 1884 | ldp BASE, RC, L:CRET1->base 1885 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 1886 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 1887 | movn TISNIL, #0 1888 | mov L, CRET1 1889 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] 1890 | sub RC, RC, BASE 1891 | st_vmstate ST_INTERP 1892 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 1893 | ins_callt 1894 |.endif 1895 | 1896 |->cont_ffi_callback: // Return from FFI callback. 1897 |.if FFI 1898 | ldr CTSTATE, GL->ctype_state 1899 | stp BASE, CARG4, L->base 1900 | str L, CTSTATE->L 1901 | mov CARG1, CTSTATE 1902 | mov CARG2, RA 1903 | bl extern lj_ccallback_leave // (CTState *cts, TValue *o) 1904 | ldp x0, x1, CTSTATE->cb.gpr[0] 1905 | ldp d0, d1, CTSTATE->cb.fpr[0] 1906 | b ->vm_leave_unw 1907 |.endif 1908 | 1909 |->vm_ffi_call: // Call C function via FFI. 1910 | // Caveat: needs special frame unwinding, see below. 1911 |.if FFI 1912 | .type CCSTATE, CCallState, x19 1913 | stp fp, lr, [sp, #-32]! 1914 | add fp, sp, #0 1915 | str CCSTATE, [sp, #16] 1916 | mov CCSTATE, x0 1917 | ldr TMP0w, CCSTATE:x0->spadj 1918 | ldrb TMP1w, CCSTATE->nsp 1919 | add TMP2, CCSTATE, #offsetof(CCallState, stack) 1920 | subs TMP1, TMP1, #1 1921 | ldr TMP3, CCSTATE->func 1922 | sub sp, fp, TMP0 1923 | bmi >2 1924 |1: // Copy stack slots 1925 | ldr TMP0, [TMP2, TMP1, lsl #3] 1926 | str TMP0, [sp, TMP1, lsl #3] 1927 | subs TMP1, TMP1, #1 1928 | bpl <1 1929 |2: 1930 | ldp x0, x1, CCSTATE->gpr[0] 1931 | ldp d0, d1, CCSTATE->fpr[0] 1932 | ldp x2, x3, CCSTATE->gpr[2] 1933 | ldp d2, d3, CCSTATE->fpr[2] 1934 | ldp x4, x5, CCSTATE->gpr[4] 1935 | ldp d4, d5, CCSTATE->fpr[4] 1936 | ldp x6, x7, CCSTATE->gpr[6] 1937 | ldp d6, d7, CCSTATE->fpr[6] 1938 | ldr x8, CCSTATE->retp 1939 | blr TMP3 1940 | mov sp, fp 1941 | stp x0, x1, CCSTATE->gpr[0] 1942 | stp d0, d1, CCSTATE->fpr[0] 1943 | stp d2, d3, CCSTATE->fpr[2] 1944 | ldr CCSTATE, [sp, #16] 1945 | ldp fp, lr, [sp], #32 1946 | ret 1947 |.endif 1948 |// Note: vm_ffi_call must be the last function in this object file! 1949 | 1950 |//----------------------------------------------------------------------- 1951 } 1952 1953 /* Generate the code for a single instruction. */ 1954 static void build_ins(BuildCtx *ctx, BCOp op, int defop) 1955 { 1956 int vk = 0; 1957 |=>defop: 1958 1959 switch (op) { 1960 1961 /* -- Comparison ops ---------------------------------------------------- */ 1962 1963 /* Remember: all ops branch for a true comparison, fall through otherwise. */ 1964 1965 case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT: 1966 | // RA = src1, RC = src2, JMP with RC = target 1967 | ldr CARG1, [BASE, RA, lsl #3] 1968 | ldrh RBw, [PC, #2] 1969 | ldr CARG2, [BASE, RC, lsl #3] 1970 | add PC, PC, #4 1971 | add RB, PC, RB, lsl #2 1972 | sub RB, RB, #0x20000 1973 | checkint CARG1, >3 1974 | checkint CARG2, >4 1975 | cmp CARG1w, CARG2w 1976 if (op == BC_ISLT) { 1977 | csel PC, RB, PC, lt 1978 } else if (op == BC_ISGE) { 1979 | csel PC, RB, PC, ge 1980 } else if (op == BC_ISLE) { 1981 | csel PC, RB, PC, le 1982 } else { 1983 | csel PC, RB, PC, gt 1984 } 1985 |1: 1986 | ins_next 1987 | 1988 |3: // RA not int. 1989 | ldr FARG1, [BASE, RA, lsl #3] 1990 | blo ->vmeta_comp 1991 | ldr FARG2, [BASE, RC, lsl #3] 1992 | cmp TISNUMhi, CARG2, lsr #32 1993 | bhi >5 1994 | bne ->vmeta_comp 1995 | // RA number, RC int. 1996 | scvtf FARG2, CARG2w 1997 | b >5 1998 | 1999 |4: // RA int, RC not int 2000 | ldr FARG2, [BASE, RC, lsl #3] 2001 | blo ->vmeta_comp 2002 | // RA int, RC number. 2003 | scvtf FARG1, CARG1w 2004 | 2005 |5: // RA number, RC number 2006 | fcmp FARG1, FARG2 2007 | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't. 2008 if (op == BC_ISLT) { 2009 | csel PC, RB, PC, lo 2010 } else if (op == BC_ISGE) { 2011 | csel PC, RB, PC, hs 2012 } else if (op == BC_ISLE) { 2013 | csel PC, RB, PC, ls 2014 } else { 2015 | csel PC, RB, PC, hi 2016 } 2017 | b <1 2018 break; 2019 2020 case BC_ISEQV: case BC_ISNEV: 2021 vk = op == BC_ISEQV; 2022 | // RA = src1, RC = src2, JMP with RC = target 2023 | ldr CARG1, [BASE, RA, lsl #3] 2024 | add RC, BASE, RC, lsl #3 2025 | ldrh RBw, [PC, #2] 2026 | ldr CARG3, [RC] 2027 | add PC, PC, #4 2028 | add RB, PC, RB, lsl #2 2029 | sub RB, RB, #0x20000 2030 | asr ITYPE, CARG3, #47 2031 | cmn ITYPE, #-LJ_TISNUM 2032 if (vk) { 2033 | bls ->BC_ISEQN_Z 2034 } else { 2035 | bls ->BC_ISNEN_Z 2036 } 2037 | // RC is not a number. 2038 | asr TMP0, CARG1, #47 2039 |.if FFI 2040 | // Check if RC or RA is a cdata. 2041 | cmn ITYPE, #-LJ_TCDATA 2042 | ccmn TMP0, #-LJ_TCDATA, #4, ne 2043 | beq ->vmeta_equal_cd 2044 |.endif 2045 | cmp CARG1, CARG3 2046 | bne >2 2047 | // Tag and value are equal. 2048 if (vk) { 2049 |->BC_ISEQV_Z: 2050 | mov PC, RB // Perform branch. 2051 } 2052 |1: 2053 | ins_next 2054 | 2055 |2: // Check if the tags are the same and it's a table or userdata. 2056 | cmp ITYPE, TMP0 2057 | ccmn ITYPE, #-LJ_TISTABUD, #2, eq 2058 if (vk) { 2059 | bhi <1 2060 } else { 2061 | bhi ->BC_ISEQV_Z // Reuse code from opposite instruction. 2062 } 2063 | // Different tables or userdatas. Need to check __eq metamethod. 2064 | // Field metatable must be at same offset for GCtab and GCudata! 2065 | and TAB:CARG2, CARG1, #LJ_GCVMASK 2066 | ldr TAB:TMP2, TAB:CARG2->metatable 2067 if (vk) { 2068 | cbz TAB:TMP2, <1 // No metatable? 2069 | ldrb TMP1w, TAB:TMP2->nomm 2070 | mov CARG4, #0 // ne = 0 2071 | tbnz TMP1w, #MM_eq, <1 // 'no __eq' flag set: done. 2072 } else { 2073 | cbz TAB:TMP2, ->BC_ISEQV_Z // No metatable? 2074 | ldrb TMP1w, TAB:TMP2->nomm 2075 | mov CARG4, #1 // ne = 1. 2076 | tbnz TMP1w, #MM_eq, ->BC_ISEQV_Z // 'no __eq' flag set: done. 2077 } 2078 | b ->vmeta_equal 2079 break; 2080 2081 case BC_ISEQS: case BC_ISNES: 2082 vk = op == BC_ISEQS; 2083 | // RA = src, RC = str_const (~), JMP with RC = target 2084 | ldr CARG1, [BASE, RA, lsl #3] 2085 | mvn RC, RC 2086 | ldrh RBw, [PC, #2] 2087 | ldr CARG2, [KBASE, RC, lsl #3] 2088 | add PC, PC, #4 2089 | movn TMP0, #~LJ_TSTR 2090 |.if FFI 2091 | asr ITYPE, CARG1, #47 2092 |.endif 2093 | add RB, PC, RB, lsl #2 2094 | add CARG2, CARG2, TMP0, lsl #47 2095 | sub RB, RB, #0x20000 2096 |.if FFI 2097 | cmn ITYPE, #-LJ_TCDATA 2098 | beq ->vmeta_equal_cd 2099 |.endif 2100 | cmp CARG1, CARG2 2101 if (vk) { 2102 | csel PC, RB, PC, eq 2103 } else { 2104 | csel PC, RB, PC, ne 2105 } 2106 | ins_next 2107 break; 2108 2109 case BC_ISEQN: case BC_ISNEN: 2110 vk = op == BC_ISEQN; 2111 | // RA = src, RC = num_const (~), JMP with RC = target 2112 | ldr CARG1, [BASE, RA, lsl #3] 2113 | add RC, KBASE, RC, lsl #3 2114 | ldrh RBw, [PC, #2] 2115 | ldr CARG3, [RC] 2116 | add PC, PC, #4 2117 | add RB, PC, RB, lsl #2 2118 | sub RB, RB, #0x20000 2119 if (vk) { 2120 |->BC_ISEQN_Z: 2121 } else { 2122 |->BC_ISNEN_Z: 2123 } 2124 | checkint CARG1, >4 2125 | checkint CARG3, >6 2126 | cmp CARG1w, CARG3w 2127 |1: 2128 if (vk) { 2129 | csel PC, RB, PC, eq 2130 |2: 2131 } else { 2132 |2: 2133 | csel PC, RB, PC, ne 2134 } 2135 |3: 2136 | ins_next 2137 | 2138 |4: // RA not int. 2139 |.if FFI 2140 | blo >7 2141 |.else 2142 | blo <2 2143 |.endif 2144 | ldr FARG1, [BASE, RA, lsl #3] 2145 | ldr FARG2, [RC] 2146 | cmp TISNUMhi, CARG3, lsr #32 2147 | bne >5 2148 | // RA number, RC int. 2149 | scvtf FARG2, CARG3w 2150 |5: 2151 | // RA number, RC number. 2152 | fcmp FARG1, FARG2 2153 | b <1 2154 | 2155 |6: // RA int, RC number 2156 | ldr FARG2, [RC] 2157 | scvtf FARG1, CARG1w 2158 | fcmp FARG1, FARG2 2159 | b <1 2160 | 2161 |.if FFI 2162 |7: 2163 | asr ITYPE, CARG1, #47 2164 | cmn ITYPE, #-LJ_TCDATA 2165 | bne <2 2166 | b ->vmeta_equal_cd 2167 |.endif 2168 break; 2169 2170 case BC_ISEQP: case BC_ISNEP: 2171 vk = op == BC_ISEQP; 2172 | // RA = src, RC = primitive_type (~), JMP with RC = target 2173 | ldr TMP0, [BASE, RA, lsl #3] 2174 | ldrh RBw, [PC, #2] 2175 | add PC, PC, #4 2176 | add RC, RC, #1 2177 | add RB, PC, RB, lsl #2 2178 |.if FFI 2179 | asr ITYPE, TMP0, #47 2180 | cmn ITYPE, #-LJ_TCDATA 2181 | beq ->vmeta_equal_cd 2182 | cmn RC, ITYPE 2183 |.else 2184 | cmn RC, TMP0, asr #47 2185 |.endif 2186 | sub RB, RB, #0x20000 2187 if (vk) { 2188 | csel PC, RB, PC, eq 2189 } else { 2190 | csel PC, RB, PC, ne 2191 } 2192 | ins_next 2193 break; 2194 2195 /* -- Unary test and copy ops ------------------------------------------- */ 2196 2197 case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF: 2198 | // RA = dst or unused, RC = src, JMP with RC = target 2199 | ldrh RBw, [PC, #2] 2200 | ldr TMP0, [BASE, RC, lsl #3] 2201 | add PC, PC, #4 2202 | mov_false TMP1 2203 | add RB, PC, RB, lsl #2 2204 | cmp TMP0, TMP1 2205 | sub RB, RB, #0x20000 2206 if (op == BC_ISTC || op == BC_IST) { 2207 if (op == BC_ISTC) { 2208 | csel RA, RA, RC, lo 2209 } 2210 | csel PC, RB, PC, lo 2211 } else { 2212 if (op == BC_ISFC) { 2213 | csel RA, RA, RC, hs 2214 } 2215 | csel PC, RB, PC, hs 2216 } 2217 if (op == BC_ISTC || op == BC_ISFC) { 2218 | str TMP0, [BASE, RA, lsl #3] 2219 } 2220 | ins_next 2221 break; 2222 2223 case BC_ISTYPE: 2224 | // RA = src, RC = -type 2225 | ldr TMP0, [BASE, RA, lsl #3] 2226 | cmn RC, TMP0, asr #47 2227 | bne ->vmeta_istype 2228 | ins_next 2229 break; 2230 case BC_ISNUM: 2231 | // RA = src, RC = -(TISNUM-1) 2232 | ldr TMP0, [BASE, RA] 2233 | checknum TMP0, ->vmeta_istype 2234 | ins_next 2235 break; 2236 2237 /* -- Unary ops --------------------------------------------------------- */ 2238 2239 case BC_MOV: 2240 | // RA = dst, RC = src 2241 | ldr TMP0, [BASE, RC, lsl #3] 2242 | str TMP0, [BASE, RA, lsl #3] 2243 | ins_next 2244 break; 2245 case BC_NOT: 2246 | // RA = dst, RC = src 2247 | ldr TMP0, [BASE, RC, lsl #3] 2248 | mov_false TMP1 2249 | mov_true TMP2 2250 | cmp TMP0, TMP1 2251 | csel TMP0, TMP1, TMP2, lo 2252 | str TMP0, [BASE, RA, lsl #3] 2253 | ins_next 2254 break; 2255 case BC_UNM: 2256 | // RA = dst, RC = src 2257 | ldr TMP0, [BASE, RC, lsl #3] 2258 | asr ITYPE, TMP0, #47 2259 | cmn ITYPE, #-LJ_TISNUM 2260 | bhi ->vmeta_unm 2261 | eor TMP0, TMP0, #U64x(80000000,00000000) 2262 | bne >5 2263 | negs TMP0w, TMP0w 2264 | movz CARG3, #0x41e0, lsl #48 // 2^31. 2265 | add TMP0, TMP0, TISNUM 2266 | csel TMP0, TMP0, CARG3, vc 2267 |5: 2268 | str TMP0, [BASE, RA, lsl #3] 2269 | ins_next 2270 break; 2271 case BC_LEN: 2272 | // RA = dst, RC = src 2273 | ldr CARG1, [BASE, RC, lsl #3] 2274 | asr ITYPE, CARG1, #47 2275 | cmn ITYPE, #-LJ_TSTR 2276 | and CARG1, CARG1, #LJ_GCVMASK 2277 | bne >2 2278 | ldr CARG1w, STR:CARG1->len 2279 |1: 2280 | add CARG1, CARG1, TISNUM 2281 | str CARG1, [BASE, RA, lsl #3] 2282 | ins_next 2283 | 2284 |2: 2285 | cmn ITYPE, #-LJ_TTAB 2286 | bne ->vmeta_len 2287 #if LJ_52 2288 | ldr TAB:CARG2, TAB:CARG1->metatable 2289 | cbnz TAB:CARG2, >9 2290 |3: 2291 #endif 2292 |->BC_LEN_Z: 2293 | bl extern lj_tab_len // (GCtab *t) 2294 | // Returns uint32_t (but less than 2^31). 2295 | b <1 2296 | 2297 #if LJ_52 2298 |9: 2299 | ldrb TMP1w, TAB:CARG2->nomm 2300 | tbnz TMP1w, #MM_len, <3 // 'no __len' flag set: done. 2301 | b ->vmeta_len 2302 #endif 2303 break; 2304 2305 /* -- Binary ops -------------------------------------------------------- */ 2306 2307 |.macro ins_arithcheck_int, target 2308 | checkint CARG1, target 2309 | checkint CARG2, target 2310 |.endmacro 2311 | 2312 |.macro ins_arithcheck_num, target 2313 | checknum CARG1, target 2314 | checknum CARG2, target 2315 |.endmacro 2316 | 2317 |.macro ins_arithcheck_nzdiv, target 2318 | cbz CARG2w, target 2319 |.endmacro 2320 | 2321 |.macro ins_arithhead 2322 ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN); 2323 ||if (vk == 1) { 2324 | and RC, RC, #255 2325 | decode_RB RB, INS 2326 ||} else { 2327 | decode_RB RB, INS 2328 | and RC, RC, #255 2329 ||} 2330 |.endmacro 2331 | 2332 |.macro ins_arithload, reg1, reg2 2333 | // RA = dst, RB = src1, RC = src2 | num_const 2334 ||switch (vk) { 2335 ||case 0: 2336 | ldr reg1, [BASE, RB, lsl #3] 2337 | ldr reg2, [KBASE, RC, lsl #3] 2338 || break; 2339 ||case 1: 2340 | ldr reg1, [KBASE, RC, lsl #3] 2341 | ldr reg2, [BASE, RB, lsl #3] 2342 || break; 2343 ||default: 2344 | ldr reg1, [BASE, RB, lsl #3] 2345 | ldr reg2, [BASE, RC, lsl #3] 2346 || break; 2347 ||} 2348 |.endmacro 2349 | 2350 |.macro ins_arithfallback, ins 2351 ||switch (vk) { 2352 ||case 0: 2353 | ins ->vmeta_arith_vn 2354 || break; 2355 ||case 1: 2356 | ins ->vmeta_arith_nv 2357 || break; 2358 ||default: 2359 | ins ->vmeta_arith_vv 2360 || break; 2361 ||} 2362 |.endmacro 2363 | 2364 |.macro ins_arithmod, res, reg1, reg2 2365 | fdiv d2, reg1, reg2 2366 | frintm d2, d2 2367 | fmsub res, d2, reg2, reg1 2368 |.endmacro 2369 | 2370 |.macro ins_arithdn, intins, fpins 2371 | ins_arithhead 2372 | ins_arithload CARG1, CARG2 2373 | ins_arithcheck_int >5 2374 |.if "intins" == "smull" 2375 | smull CARG1, CARG1w, CARG2w 2376 | cmp CARG1, CARG1, sxtw 2377 | mov CARG1w, CARG1w 2378 | ins_arithfallback bne 2379 |.elif "intins" == "ins_arithmodi" 2380 | ins_arithfallback ins_arithcheck_nzdiv 2381 | bl ->vm_modi 2382 |.else 2383 | intins CARG1w, CARG1w, CARG2w 2384 | ins_arithfallback bvs 2385 |.endif 2386 | add CARG1, CARG1, TISNUM 2387 | str CARG1, [BASE, RA, lsl #3] 2388 |4: 2389 | ins_next 2390 | 2391 |5: // FP variant. 2392 | ins_arithload FARG1, FARG2 2393 | ins_arithfallback ins_arithcheck_num 2394 | fpins FARG1, FARG1, FARG2 2395 | str FARG1, [BASE, RA, lsl #3] 2396 | b <4 2397 |.endmacro 2398 | 2399 |.macro ins_arithfp, fpins 2400 | ins_arithhead 2401 | ins_arithload CARG1, CARG2 2402 | ins_arithload FARG1, FARG2 2403 | ins_arithfallback ins_arithcheck_num 2404 |.if "fpins" == "fpow" 2405 | bl extern pow 2406 |.else 2407 | fpins FARG1, FARG1, FARG2 2408 |.endif 2409 | str FARG1, [BASE, RA, lsl #3] 2410 | ins_next 2411 |.endmacro 2412 2413 case BC_ADDVN: case BC_ADDNV: case BC_ADDVV: 2414 | ins_arithdn adds, fadd 2415 break; 2416 case BC_SUBVN: case BC_SUBNV: case BC_SUBVV: 2417 | ins_arithdn subs, fsub 2418 break; 2419 case BC_MULVN: case BC_MULNV: case BC_MULVV: 2420 | ins_arithdn smull, fmul 2421 break; 2422 case BC_DIVVN: case BC_DIVNV: case BC_DIVVV: 2423 | ins_arithfp fdiv 2424 break; 2425 case BC_MODVN: case BC_MODNV: case BC_MODVV: 2426 | ins_arithdn ins_arithmodi, ins_arithmod 2427 break; 2428 case BC_POW: 2429 | // NYI: (partial) integer arithmetic. 2430 | ins_arithfp fpow 2431 break; 2432 2433 case BC_CAT: 2434 | decode_RB RB, INS 2435 | and RC, RC, #255 2436 | // RA = dst, RB = src_start, RC = src_end 2437 | str BASE, L->base 2438 | sub CARG3, RC, RB 2439 | add CARG2, BASE, RC, lsl #3 2440 |->BC_CAT_Z: 2441 | // RA = dst, CARG2 = top-1, CARG3 = left 2442 | mov CARG1, L 2443 | str PC, SAVE_PC 2444 | bl extern lj_meta_cat // (lua_State *L, TValue *top, int left) 2445 | // Returns NULL (finished) or TValue * (metamethod). 2446 | ldrb RBw, [PC, #-1] 2447 | ldr BASE, L->base 2448 | cbnz CRET1, ->vmeta_binop 2449 | ldr TMP0, [BASE, RB, lsl #3] 2450 | str TMP0, [BASE, RA, lsl #3] // Copy result to RA. 2451 | ins_next 2452 break; 2453 2454 /* -- Constant ops ------------------------------------------------------ */ 2455 2456 case BC_KSTR: 2457 | // RA = dst, RC = str_const (~) 2458 | mvn RC, RC 2459 | ldr TMP0, [KBASE, RC, lsl #3] 2460 | movn TMP1, #~LJ_TSTR 2461 | add TMP0, TMP0, TMP1, lsl #47 2462 | str TMP0, [BASE, RA, lsl #3] 2463 | ins_next 2464 break; 2465 case BC_KCDATA: 2466 |.if FFI 2467 | // RA = dst, RC = cdata_const (~) 2468 | mvn RC, RC 2469 | ldr TMP0, [KBASE, RC, lsl #3] 2470 | movn TMP1, #~LJ_TCDATA 2471 | add TMP0, TMP0, TMP1, lsl #47 2472 | str TMP0, [BASE, RA, lsl #3] 2473 | ins_next 2474 |.endif 2475 break; 2476 case BC_KSHORT: 2477 | // RA = dst, RC = int16_literal 2478 | sxth RCw, RCw 2479 | add TMP0, RC, TISNUM 2480 | str TMP0, [BASE, RA, lsl #3] 2481 | ins_next 2482 break; 2483 case BC_KNUM: 2484 | // RA = dst, RC = num_const 2485 | ldr TMP0, [KBASE, RC, lsl #3] 2486 | str TMP0, [BASE, RA, lsl #3] 2487 | ins_next 2488 break; 2489 case BC_KPRI: 2490 | // RA = dst, RC = primitive_type (~) 2491 | mvn TMP0, RC, lsl #47 2492 | str TMP0, [BASE, RA, lsl #3] 2493 | ins_next 2494 break; 2495 case BC_KNIL: 2496 | // RA = base, RC = end 2497 | add RA, BASE, RA, lsl #3 2498 | add RC, BASE, RC, lsl #3 2499 | str TISNIL, [RA], #8 2500 |1: 2501 | cmp RA, RC 2502 | str TISNIL, [RA], #8 2503 | blt <1 2504 | ins_next_ 2505 break; 2506 2507 /* -- Upvalue and function ops ------------------------------------------ */ 2508 2509 case BC_UGET: 2510 | // RA = dst, RC = uvnum 2511 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] 2512 | add RC, RC, #offsetof(GCfuncL, uvptr)/8 2513 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK 2514 | ldr UPVAL:CARG2, [LFUNC:CARG2, RC, lsl #3] 2515 | ldr CARG2, UPVAL:CARG2->v 2516 | ldr TMP0, [CARG2] 2517 | str TMP0, [BASE, RA, lsl #3] 2518 | ins_next 2519 break; 2520 case BC_USETV: 2521 | // RA = uvnum, RC = src 2522 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] 2523 | add RA, RA, #offsetof(GCfuncL, uvptr)/8 2524 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK 2525 | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3] 2526 | ldr CARG3, [BASE, RC, lsl #3] 2527 | ldr CARG2, UPVAL:CARG1->v 2528 | ldrb TMP2w, UPVAL:CARG1->marked 2529 | ldrb TMP0w, UPVAL:CARG1->closed 2530 | asr ITYPE, CARG3, #47 2531 | str CARG3, [CARG2] 2532 | add ITYPE, ITYPE, #-LJ_TISGCV 2533 | tst TMP2w, #LJ_GC_BLACK // isblack(uv) 2534 | ccmp TMP0w, #0, #4, ne // && uv->closed 2535 | ccmn ITYPE, #-(LJ_TNUMX - LJ_TISGCV), #0, ne // && tvisgcv(v) 2536 | bhi >2 2537 |1: 2538 | ins_next 2539 | 2540 |2: // Check if new value is white. 2541 | and GCOBJ:CARG3, CARG3, #LJ_GCVMASK 2542 | ldrb TMP1w, GCOBJ:CARG3->gch.marked 2543 | tst TMP1w, #LJ_GC_WHITES // iswhite(str) 2544 | beq <1 2545 | // Crossed a write barrier. Move the barrier forward. 2546 | mov CARG1, GL 2547 | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) 2548 | b <1 2549 break; 2550 case BC_USETS: 2551 | // RA = uvnum, RC = str_const (~) 2552 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] 2553 | add RA, RA, #offsetof(GCfuncL, uvptr)/8 2554 | mvn RC, RC 2555 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK 2556 | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3] 2557 | ldr STR:CARG3, [KBASE, RC, lsl #3] 2558 | movn TMP0, #~LJ_TSTR 2559 | ldr CARG2, UPVAL:CARG1->v 2560 | ldrb TMP2w, UPVAL:CARG1->marked 2561 | add TMP0, STR:CARG3, TMP0, lsl #47 2562 | ldrb TMP1w, STR:CARG3->marked 2563 | str TMP0, [CARG2] 2564 | tbnz TMP2w, #2, >2 // isblack(uv) 2565 |1: 2566 | ins_next 2567 | 2568 |2: // Check if string is white and ensure upvalue is closed. 2569 | ldrb TMP0w, UPVAL:CARG1->closed 2570 | tst TMP1w, #LJ_GC_WHITES // iswhite(str) 2571 | ccmp TMP0w, #0, #0, ne 2572 | beq <1 2573 | // Crossed a write barrier. Move the barrier forward. 2574 | mov CARG1, GL 2575 | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv) 2576 | b <1 2577 break; 2578 case BC_USETN: 2579 | // RA = uvnum, RC = num_const 2580 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] 2581 | add RA, RA, #offsetof(GCfuncL, uvptr)/8 2582 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK 2583 | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3] 2584 | ldr TMP0, [KBASE, RC, lsl #3] 2585 | ldr CARG2, UPVAL:CARG2->v 2586 | str TMP0, [CARG2] 2587 | ins_next 2588 break; 2589 case BC_USETP: 2590 | // RA = uvnum, RC = primitive_type (~) 2591 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] 2592 | add RA, RA, #offsetof(GCfuncL, uvptr)/8 2593 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK 2594 | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3] 2595 | mvn TMP0, RC, lsl #47 2596 | ldr CARG2, UPVAL:CARG2->v 2597 | str TMP0, [CARG2] 2598 | ins_next 2599 break; 2600 2601 case BC_UCLO: 2602 | // RA = level, RC = target 2603 | ldr CARG3, L->openupval 2604 | add RC, PC, RC, lsl #2 2605 | str BASE, L->base 2606 | sub PC, RC, #0x20000 2607 | cbz CARG3, >1 2608 | mov CARG1, L 2609 | add CARG2, BASE, RA, lsl #3 2610 | bl extern lj_func_closeuv // (lua_State *L, TValue *level) 2611 | ldr BASE, L->base 2612 |1: 2613 | ins_next 2614 break; 2615 2616 case BC_FNEW: 2617 | // RA = dst, RC = proto_const (~) (holding function prototype) 2618 | mvn RC, RC 2619 | str BASE, L->base 2620 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] 2621 | str PC, SAVE_PC 2622 | ldr CARG2, [KBASE, RC, lsl #3] 2623 | mov CARG1, L 2624 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK 2625 | // (lua_State *L, GCproto *pt, GCfuncL *parent) 2626 | bl extern lj_func_newL_gc 2627 | // Returns GCfuncL *. 2628 | ldr BASE, L->base 2629 | movn TMP0, #~LJ_TFUNC 2630 | add CRET1, CRET1, TMP0, lsl #47 2631 | str CRET1, [BASE, RA, lsl #3] 2632 | ins_next 2633 break; 2634 2635 /* -- Table ops --------------------------------------------------------- */ 2636 2637 case BC_TNEW: 2638 case BC_TDUP: 2639 | // RA = dst, RC = (hbits|asize) | tab_const (~) 2640 | ldp CARG3, CARG4, GL->gc.total // Assumes threshold follows total. 2641 | str BASE, L->base 2642 | str PC, SAVE_PC 2643 | mov CARG1, L 2644 | cmp CARG3, CARG4 2645 | bhs >5 2646 |1: 2647 if (op == BC_TNEW) { 2648 | and CARG2, RC, #0x7ff 2649 | lsr CARG3, RC, #11 2650 | cmp CARG2, #0x7ff 2651 | mov TMP0, #0x801 2652 | csel CARG2, CARG2, TMP0, ne 2653 | bl extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits) 2654 | // Returns GCtab *. 2655 } else { 2656 | mvn RC, RC 2657 | ldr CARG2, [KBASE, RC, lsl #3] 2658 | bl extern lj_tab_dup // (lua_State *L, Table *kt) 2659 | // Returns GCtab *. 2660 } 2661 | ldr BASE, L->base 2662 | movk CRET1, #(LJ_TTAB>>1)&0xffff, lsl #48 2663 | str CRET1, [BASE, RA, lsl #3] 2664 | ins_next 2665 | 2666 |5: 2667 | bl extern lj_gc_step_fixtop // (lua_State *L) 2668 | mov CARG1, L 2669 | b <1 2670 break; 2671 2672 case BC_GGET: 2673 | // RA = dst, RC = str_const (~) 2674 case BC_GSET: 2675 | // RA = dst, RC = str_const (~) 2676 | ldr LFUNC:CARG1, [BASE, FRAME_FUNC] 2677 | mvn RC, RC 2678 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK 2679 | ldr TAB:CARG2, LFUNC:CARG1->env 2680 | ldr STR:RC, [KBASE, RC, lsl #3] 2681 if (op == BC_GGET) { 2682 | b ->BC_TGETS_Z 2683 } else { 2684 | b ->BC_TSETS_Z 2685 } 2686 break; 2687 2688 case BC_TGETV: 2689 | decode_RB RB, INS 2690 | and RC, RC, #255 2691 | // RA = dst, RB = table, RC = key 2692 | ldr CARG2, [BASE, RB, lsl #3] 2693 | ldr TMP1, [BASE, RC, lsl #3] 2694 | checktab CARG2, ->vmeta_tgetv 2695 | checkint TMP1, >9 // Integer key? 2696 | ldr CARG3, TAB:CARG2->array 2697 | ldr CARG1w, TAB:CARG2->asize 2698 | add CARG3, CARG3, TMP1, uxtw #3 2699 | cmp TMP1w, CARG1w // In array part? 2700 | bhs ->vmeta_tgetv 2701 | ldr TMP0, [CARG3] 2702 | cmp TMP0, TISNIL 2703 | beq >5 2704 |1: 2705 | str TMP0, [BASE, RA, lsl #3] 2706 | ins_next 2707 | 2708 |5: // Check for __index if table value is nil. 2709 | ldr TAB:CARG1, TAB:CARG2->metatable 2710 | cbz TAB:CARG1, <1 // No metatable: done. 2711 | ldrb TMP1w, TAB:CARG1->nomm 2712 | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done. 2713 | b ->vmeta_tgetv 2714 | 2715 |9: 2716 | asr ITYPE, TMP1, #47 2717 | cmn ITYPE, #-LJ_TSTR // String key? 2718 | bne ->vmeta_tgetv 2719 | and STR:RC, TMP1, #LJ_GCVMASK 2720 | b ->BC_TGETS_Z 2721 break; 2722 case BC_TGETS: 2723 | decode_RB RB, INS 2724 | and RC, RC, #255 2725 | // RA = dst, RB = table, RC = str_const (~) 2726 | ldr CARG2, [BASE, RB, lsl #3] 2727 | mvn RC, RC 2728 | ldr STR:RC, [KBASE, RC, lsl #3] 2729 | checktab CARG2, ->vmeta_tgets1 2730 |->BC_TGETS_Z: 2731 | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = dst 2732 | ldr TMP1w, TAB:CARG2->hmask 2733 | ldr TMP2w, STR:RC->hash 2734 | ldr NODE:CARG3, TAB:CARG2->node 2735 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask 2736 | add TMP1, TMP1, TMP1, lsl #1 2737 | movn CARG4, #~LJ_TSTR 2738 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8 2739 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for. 2740 |1: 2741 | ldp TMP0, CARG1, NODE:CARG3->val 2742 | ldr NODE:CARG3, NODE:CARG3->next 2743 | cmp CARG1, CARG4 2744 | bne >4 2745 | cmp TMP0, TISNIL 2746 | beq >5 2747 |3: 2748 | str TMP0, [BASE, RA, lsl #3] 2749 | ins_next 2750 | 2751 |4: // Follow hash chain. 2752 | cbnz NODE:CARG3, <1 2753 | // End of hash chain: key not found, nil result. 2754 | mov TMP0, TISNIL 2755 | 2756 |5: // Check for __index if table value is nil. 2757 | ldr TAB:CARG1, TAB:CARG2->metatable 2758 | cbz TAB:CARG1, <3 // No metatable: done. 2759 | ldrb TMP1w, TAB:CARG1->nomm 2760 | tbnz TMP1w, #MM_index, <3 // 'no __index' flag set: done. 2761 | b ->vmeta_tgets 2762 break; 2763 case BC_TGETB: 2764 | decode_RB RB, INS 2765 | and RC, RC, #255 2766 | // RA = dst, RB = table, RC = index 2767 | ldr CARG2, [BASE, RB, lsl #3] 2768 | checktab CARG2, ->vmeta_tgetb 2769 | ldr CARG3, TAB:CARG2->array 2770 | ldr CARG1w, TAB:CARG2->asize 2771 | add CARG3, CARG3, RC, lsl #3 2772 | cmp RCw, CARG1w // In array part? 2773 | bhs ->vmeta_tgetb 2774 | ldr TMP0, [CARG3] 2775 | cmp TMP0, TISNIL 2776 | beq >5 2777 |1: 2778 | str TMP0, [BASE, RA, lsl #3] 2779 | ins_next 2780 | 2781 |5: // Check for __index if table value is nil. 2782 | ldr TAB:CARG1, TAB:CARG2->metatable 2783 | cbz TAB:CARG1, <1 // No metatable: done. 2784 | ldrb TMP1w, TAB:CARG1->nomm 2785 | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done. 2786 | b ->vmeta_tgetb 2787 break; 2788 case BC_TGETR: 2789 | decode_RB RB, INS 2790 | and RC, RC, #255 2791 | // RA = dst, RB = table, RC = key 2792 | ldr CARG1, [BASE, RB, lsl #3] 2793 | ldr TMP1, [BASE, RC, lsl #3] 2794 | and TAB:CARG1, CARG1, #LJ_GCVMASK 2795 | ldr CARG3, TAB:CARG1->array 2796 | ldr TMP2w, TAB:CARG1->asize 2797 | add CARG3, CARG3, TMP1w, uxtw #3 2798 | cmp TMP1w, TMP2w // In array part? 2799 | bhs ->vmeta_tgetr 2800 | ldr TMP0, [CARG3] 2801 |->BC_TGETR_Z: 2802 | str TMP0, [BASE, RA, lsl #3] 2803 | ins_next 2804 break; 2805 2806 case BC_TSETV: 2807 | decode_RB RB, INS 2808 | and RC, RC, #255 2809 | // RA = src, RB = table, RC = key 2810 | ldr CARG2, [BASE, RB, lsl #3] 2811 | ldr TMP1, [BASE, RC, lsl #3] 2812 | checktab CARG2, ->vmeta_tsetv 2813 | checkint TMP1, >9 // Integer key? 2814 | ldr CARG3, TAB:CARG2->array 2815 | ldr CARG1w, TAB:CARG2->asize 2816 | add CARG3, CARG3, TMP1, uxtw #3 2817 | cmp TMP1w, CARG1w // In array part? 2818 | bhs ->vmeta_tsetv 2819 | ldr TMP1, [CARG3] 2820 | ldr TMP0, [BASE, RA, lsl #3] 2821 | ldrb TMP2w, TAB:CARG2->marked 2822 | cmp TMP1, TISNIL // Previous value is nil? 2823 | beq >5 2824 |1: 2825 | str TMP0, [CARG3] 2826 | tbnz TMP2w, #2, >7 // isblack(table) 2827 |2: 2828 | ins_next 2829 | 2830 |5: // Check for __newindex if previous value is nil. 2831 | ldr TAB:CARG1, TAB:CARG2->metatable 2832 | cbz TAB:CARG1, <1 // No metatable: done. 2833 | ldrb TMP1w, TAB:CARG1->nomm 2834 | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done. 2835 | b ->vmeta_tsetv 2836 | 2837 |7: // Possible table write barrier for the value. Skip valiswhite check. 2838 | barrierback TAB:CARG2, TMP2w, TMP1 2839 | b <2 2840 | 2841 |9: 2842 | asr ITYPE, TMP1, #47 2843 | cmn ITYPE, #-LJ_TSTR // String key? 2844 | bne ->vmeta_tsetv 2845 | and STR:RC, TMP1, #LJ_GCVMASK 2846 | b ->BC_TSETS_Z 2847 break; 2848 case BC_TSETS: 2849 | decode_RB RB, INS 2850 | and RC, RC, #255 2851 | // RA = dst, RB = table, RC = str_const (~) 2852 | ldr CARG2, [BASE, RB, lsl #3] 2853 | mvn RC, RC 2854 | ldr STR:RC, [KBASE, RC, lsl #3] 2855 | checktab CARG2, ->vmeta_tsets1 2856 |->BC_TSETS_Z: 2857 | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = src 2858 | ldr TMP1w, TAB:CARG2->hmask 2859 | ldr TMP2w, STR:RC->hash 2860 | ldr NODE:CARG3, TAB:CARG2->node 2861 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask 2862 | add TMP1, TMP1, TMP1, lsl #1 2863 | movn CARG4, #~LJ_TSTR 2864 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8 2865 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for. 2866 | strb wzr, TAB:CARG2->nomm // Clear metamethod cache. 2867 |1: 2868 | ldp TMP1, CARG1, NODE:CARG3->val 2869 | ldr NODE:TMP3, NODE:CARG3->next 2870 | ldrb TMP2w, TAB:CARG2->marked 2871 | cmp CARG1, CARG4 2872 | bne >5 2873 | ldr TMP0, [BASE, RA, lsl #3] 2874 | cmp TMP1, TISNIL // Previous value is nil? 2875 | beq >4 2876 |2: 2877 | str TMP0, NODE:CARG3->val 2878 | tbnz TMP2w, #2, >7 // isblack(table) 2879 |3: 2880 | ins_next 2881 | 2882 |4: // Check for __newindex if previous value is nil. 2883 | ldr TAB:CARG1, TAB:CARG2->metatable 2884 | cbz TAB:CARG1, <2 // No metatable: done. 2885 | ldrb TMP1w, TAB:CARG1->nomm 2886 | tbnz TMP1w, #MM_newindex, <2 // 'no __newindex' flag set: done. 2887 | b ->vmeta_tsets 2888 | 2889 |5: // Follow hash chain. 2890 | mov NODE:CARG3, NODE:TMP3 2891 | cbnz NODE:TMP3, <1 2892 | // End of hash chain: key not found, add a new one. 2893 | 2894 | // But check for __newindex first. 2895 | ldr TAB:CARG1, TAB:CARG2->metatable 2896 | cbz TAB:CARG1, >6 // No metatable: continue. 2897 | ldrb TMP1w, TAB:CARG1->nomm 2898 | // 'no __newindex' flag NOT set: check. 2899 | tbz TMP1w, #MM_newindex, ->vmeta_tsets 2900 |6: 2901 | movn TMP1, #~LJ_TSTR 2902 | str PC, SAVE_PC 2903 | add TMP0, STR:RC, TMP1, lsl #47 2904 | str BASE, L->base 2905 | mov CARG1, L 2906 | str TMP0, TMPD 2907 | add CARG3, sp, TMPDofs 2908 | bl extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k) 2909 | // Returns TValue *. 2910 | ldr BASE, L->base 2911 | ldr TMP0, [BASE, RA, lsl #3] 2912 | str TMP0, [CRET1] 2913 | b <3 // No 2nd write barrier needed. 2914 | 2915 |7: // Possible table write barrier for the value. Skip valiswhite check. 2916 | barrierback TAB:CARG2, TMP2w, TMP1 2917 | b <3 2918 break; 2919 case BC_TSETB: 2920 | decode_RB RB, INS 2921 | and RC, RC, #255 2922 | // RA = src, RB = table, RC = index 2923 | ldr CARG2, [BASE, RB, lsl #3] 2924 | checktab CARG2, ->vmeta_tsetb 2925 | ldr CARG3, TAB:CARG2->array 2926 | ldr CARG1w, TAB:CARG2->asize 2927 | add CARG3, CARG3, RC, lsl #3 2928 | cmp RCw, CARG1w // In array part? 2929 | bhs ->vmeta_tsetb 2930 | ldr TMP1, [CARG3] 2931 | ldr TMP0, [BASE, RA, lsl #3] 2932 | ldrb TMP2w, TAB:CARG2->marked 2933 | cmp TMP1, TISNIL // Previous value is nil? 2934 | beq >5 2935 |1: 2936 | str TMP0, [CARG3] 2937 | tbnz TMP2w, #2, >7 // isblack(table) 2938 |2: 2939 | ins_next 2940 | 2941 |5: // Check for __newindex if previous value is nil. 2942 | ldr TAB:CARG1, TAB:CARG2->metatable 2943 | cbz TAB:CARG1, <1 // No metatable: done. 2944 | ldrb TMP1w, TAB:CARG1->nomm 2945 | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done. 2946 | b ->vmeta_tsetb 2947 | 2948 |7: // Possible table write barrier for the value. Skip valiswhite check. 2949 | barrierback TAB:CARG2, TMP2w, TMP1 2950 | b <2 2951 break; 2952 case BC_TSETR: 2953 | decode_RB RB, INS 2954 | and RC, RC, #255 2955 | // RA = src, RB = table, RC = key 2956 | ldr CARG2, [BASE, RB, lsl #3] 2957 | ldr TMP1, [BASE, RC, lsl #3] 2958 | and TAB:CARG2, CARG2, #LJ_GCVMASK 2959 | ldr CARG1, TAB:CARG2->array 2960 | ldrb TMP2w, TAB:CARG2->marked 2961 | ldr CARG4w, TAB:CARG2->asize 2962 | add CARG1, CARG1, TMP1, uxtw #3 2963 | tbnz TMP2w, #2, >7 // isblack(table) 2964 |2: 2965 | cmp TMP1w, CARG4w // In array part? 2966 | bhs ->vmeta_tsetr 2967 |->BC_TSETR_Z: 2968 | ldr TMP0, [BASE, RA, lsl #3] 2969 | str TMP0, [CARG1] 2970 | ins_next 2971 | 2972 |7: // Possible table write barrier for the value. Skip valiswhite check. 2973 | barrierback TAB:CARG2, TMP2w, TMP0 2974 | b <2 2975 break; 2976 2977 case BC_TSETM: 2978 | // RA = base (table at base-1), RC = num_const (start index) 2979 | add RA, BASE, RA, lsl #3 2980 |1: 2981 | ldr RBw, SAVE_MULTRES 2982 | ldr TAB:CARG2, [RA, #-8] // Guaranteed to be a table. 2983 | ldr TMP1, [KBASE, RC, lsl #3] // Integer constant is in lo-word. 2984 | sub RB, RB, #8 2985 | cbz RB, >4 // Nothing to copy? 2986 | and TAB:CARG2, CARG2, #LJ_GCVMASK 2987 | ldr CARG1w, TAB:CARG2->asize 2988 | add CARG3w, TMP1w, RBw, lsr #3 2989 | ldr CARG4, TAB:CARG2->array 2990 | cmp CARG3, CARG1 2991 | add RB, RA, RB 2992 | bhi >5 2993 | add TMP1, CARG4, TMP1w, uxtw #3 2994 | ldrb TMP2w, TAB:CARG2->marked 2995 |3: // Copy result slots to table. 2996 | ldr TMP0, [RA], #8 2997 | str TMP0, [TMP1], #8 2998 | cmp RA, RB 2999 | blo <3 3000 | tbnz TMP2w, #2, >7 // isblack(table) 3001 |4: 3002 | ins_next 3003 | 3004 |5: // Need to resize array part. 3005 | str BASE, L->base 3006 | mov CARG1, L 3007 | str PC, SAVE_PC 3008 | bl extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize) 3009 | // Must not reallocate the stack. 3010 | b <1 3011 | 3012 |7: // Possible table write barrier for any value. Skip valiswhite check. 3013 | barrierback TAB:CARG2, TMP2w, TMP1 3014 | b <4 3015 break; 3016 3017 /* -- Calls and vararg handling ----------------------------------------- */ 3018 3019 case BC_CALLM: 3020 | // RA = base, (RB = nresults+1,) RC = extra_nargs 3021 | ldr TMP0w, SAVE_MULTRES 3022 | decode_RC8RD NARGS8:RC, RC 3023 | add NARGS8:RC, NARGS8:RC, TMP0 3024 | b ->BC_CALL_Z 3025 break; 3026 case BC_CALL: 3027 | decode_RC8RD NARGS8:RC, RC 3028 | // RA = base, (RB = nresults+1,) RC = (nargs+1)*8 3029 |->BC_CALL_Z: 3030 | mov RB, BASE // Save old BASE for vmeta_call. 3031 | add BASE, BASE, RA, lsl #3 3032 | ldr CARG3, [BASE] 3033 | sub NARGS8:RC, NARGS8:RC, #8 3034 | add BASE, BASE, #16 3035 | checkfunc CARG3, ->vmeta_call 3036 | ins_call 3037 break; 3038 3039 case BC_CALLMT: 3040 | // RA = base, (RB = 0,) RC = extra_nargs 3041 | ldr TMP0w, SAVE_MULTRES 3042 | add NARGS8:RC, TMP0, RC, lsl #3 3043 | b ->BC_CALLT1_Z 3044 break; 3045 case BC_CALLT: 3046 | lsl NARGS8:RC, RC, #3 3047 | // RA = base, (RB = 0,) RC = (nargs+1)*8 3048 |->BC_CALLT1_Z: 3049 | add RA, BASE, RA, lsl #3 3050 | ldr TMP1, [RA] 3051 | sub NARGS8:RC, NARGS8:RC, #8 3052 | add RA, RA, #16 3053 | checktp CARG3, TMP1, LJ_TFUNC, ->vmeta_callt 3054 | ldr PC, [BASE, FRAME_PC] 3055 |->BC_CALLT2_Z: 3056 | mov RB, #0 3057 | ldrb TMP2w, LFUNC:CARG3->ffid 3058 | tst PC, #FRAME_TYPE 3059 | bne >7 3060 |1: 3061 | str TMP1, [BASE, FRAME_FUNC] // Copy function down, but keep PC. 3062 | cbz NARGS8:RC, >3 3063 |2: 3064 | ldr TMP0, [RA, RB] 3065 | add TMP1, RB, #8 3066 | cmp TMP1, NARGS8:RC 3067 | str TMP0, [BASE, RB] 3068 | mov RB, TMP1 3069 | bne <2 3070 |3: 3071 | cmp TMP2, #1 // (> FF_C) Calling a fast function? 3072 | bhi >5 3073 |4: 3074 | ins_callt 3075 | 3076 |5: // Tailcall to a fast function with a Lua frame below. 3077 | ldrb RAw, [PC, #-3] 3078 | sub CARG1, BASE, RA, lsl #3 3079 | ldr LFUNC:CARG1, [CARG1, #-32] 3080 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK 3081 | ldr CARG1, LFUNC:CARG1->pc 3082 | ldr KBASE, [CARG1, #PC2PROTO(k)] 3083 | b <4 3084 | 3085 |7: // Tailcall from a vararg function. 3086 | eor PC, PC, #FRAME_VARG 3087 | tst PC, #FRAME_TYPEP // Vararg frame below? 3088 | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below. 3089 | bne <1 3090 | sub BASE, BASE, PC 3091 | ldr PC, [BASE, FRAME_PC] 3092 | tst PC, #FRAME_TYPE 3093 | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below. 3094 | b <1 3095 break; 3096 3097 case BC_ITERC: 3098 | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1)) 3099 | add RA, BASE, RA, lsl #3 3100 | ldr CARG3, [RA, #-24] 3101 | mov RB, BASE // Save old BASE for vmeta_call. 3102 | ldp CARG1, CARG2, [RA, #-16] 3103 | add BASE, RA, #16 3104 | mov NARGS8:RC, #16 // Iterators get 2 arguments. 3105 | str CARG3, [RA] // Copy callable. 3106 | stp CARG1, CARG2, [RA, #16] // Copy state and control var. 3107 | checkfunc CARG3, ->vmeta_call 3108 | ins_call 3109 break; 3110 3111 case BC_ITERN: 3112 | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1)) 3113 |.if JIT 3114 | // NYI: add hotloop, record BC_ITERN. 3115 |.endif 3116 | add RA, BASE, RA, lsl #3 3117 | ldr TAB:RB, [RA, #-16] 3118 | ldrh TMP3w, [PC, #2] 3119 | ldr CARG1w, [RA, #-8] // Get index from control var. 3120 | add PC, PC, #4 3121 | add TMP3, PC, TMP3, lsl #2 3122 | and TAB:RB, RB, #LJ_GCVMASK 3123 | sub TMP3, TMP3, #0x20000 3124 | ldr TMP1w, TAB:RB->asize 3125 | ldr CARG2, TAB:RB->array 3126 |1: // Traverse array part. 3127 | subs RC, CARG1, TMP1 3128 | add CARG3, CARG2, CARG1, lsl #3 3129 | bhs >5 // Index points after array part? 3130 | ldr TMP0, [CARG3] 3131 | cmp TMP0, TISNIL 3132 | cinc CARG1, CARG1, eq // Skip holes in array part. 3133 | beq <1 3134 | add CARG1, CARG1, TISNUM 3135 | stp CARG1, TMP0, [RA] 3136 | add CARG1, CARG1, #1 3137 |3: 3138 | str CARG1w, [RA, #-8] // Update control var. 3139 | mov PC, TMP3 3140 |4: 3141 | ins_next 3142 | 3143 |5: // Traverse hash part. 3144 | ldr TMP2w, TAB:RB->hmask 3145 | ldr NODE:RB, TAB:RB->node 3146 |6: 3147 | add CARG1, RC, RC, lsl #1 3148 | cmp RC, TMP2 // End of iteration? Branch to ITERN+1. 3149 | add NODE:CARG3, NODE:RB, CARG1, lsl #3 // node = tab->node + idx*3*8 3150 | bhi <4 3151 | ldp TMP0, CARG1, NODE:CARG3->val 3152 | cmp TMP0, TISNIL 3153 | add RC, RC, #1 3154 | beq <6 // Skip holes in hash part. 3155 | stp CARG1, TMP0, [RA] 3156 | add CARG1, RC, TMP1 3157 | b <3 3158 break; 3159 3160 case BC_ISNEXT: 3161 | // RA = base, RC = target (points to ITERN) 3162 | add RA, BASE, RA, lsl #3 3163 | ldr CFUNC:CARG1, [RA, #-24] 3164 | add RC, PC, RC, lsl #2 3165 | ldp TAB:CARG3, CARG4, [RA, #-16] 3166 | sub RC, RC, #0x20000 3167 | checkfunc CFUNC:CARG1, >5 3168 | asr TMP0, TAB:CARG3, #47 3169 | ldrb TMP1w, CFUNC:CARG1->ffid 3170 | cmn TMP0, #-LJ_TTAB 3171 | ccmp CARG4, TISNIL, #0, eq 3172 | ccmp TMP1w, #FF_next_N, #0, eq 3173 | bne >5 3174 | mov TMP0w, #0xfffe7fff 3175 | lsl TMP0, TMP0, #32 3176 | str TMP0, [RA, #-8] // Initialize control var. 3177 |1: 3178 | mov PC, RC 3179 | ins_next 3180 | 3181 |5: // Despecialize bytecode if any of the checks fail. 3182 | mov TMP0, #BC_JMP 3183 | mov TMP1, #BC_ITERC 3184 | strb TMP0w, [PC, #-4] 3185 | strb TMP1w, [RC] 3186 | b <1 3187 break; 3188 3189 case BC_VARG: 3190 | decode_RB RB, INS 3191 | and RC, RC, #255 3192 | // RA = base, RB = (nresults+1), RC = numparams 3193 | ldr TMP1, [BASE, FRAME_PC] 3194 | add RC, BASE, RC, lsl #3 3195 | add RA, BASE, RA, lsl #3 3196 | add RC, RC, #FRAME_VARG 3197 | add TMP2, RA, RB, lsl #3 3198 | sub RC, RC, TMP1 // RC = vbase 3199 | // Note: RC may now be even _above_ BASE if nargs was < numparams. 3200 | sub TMP3, BASE, #16 // TMP3 = vtop 3201 | cbz RB, >5 3202 | sub TMP2, TMP2, #16 3203 |1: // Copy vararg slots to destination slots. 3204 | cmp RC, TMP3 3205 | ldr TMP0, [RC], #8 3206 | csel TMP0, TMP0, TISNIL, lo 3207 | cmp RA, TMP2 3208 | str TMP0, [RA], #8 3209 | blo <1 3210 |2: 3211 | ins_next 3212 | 3213 |5: // Copy all varargs. 3214 | ldr TMP0, L->maxstack 3215 | subs TMP2, TMP3, RC 3216 | csel RB, xzr, TMP2, le // MULTRES = (max(vtop-vbase,0)+1)*8 3217 | add RB, RB, #8 3218 | add TMP1, RA, TMP2 3219 | str RBw, SAVE_MULTRES 3220 | ble <2 // Nothing to copy. 3221 | cmp TMP1, TMP0 3222 | bhi >7 3223 |6: 3224 | ldr TMP0, [RC], #8 3225 | str TMP0, [RA], #8 3226 | cmp RC, TMP3 3227 | blo <6 3228 | b <2 3229 | 3230 |7: // Grow stack for varargs. 3231 | lsr CARG2, TMP2, #3 3232 | stp BASE, RA, L->base 3233 | mov CARG1, L 3234 | sub RC, RC, BASE // Need delta, because BASE may change. 3235 | str PC, SAVE_PC 3236 | bl extern lj_state_growstack // (lua_State *L, int n) 3237 | ldp BASE, RA, L->base 3238 | add RC, BASE, RC 3239 | sub TMP3, BASE, #16 3240 | b <6 3241 break; 3242 3243 /* -- Returns ----------------------------------------------------------- */ 3244 3245 case BC_RETM: 3246 | // RA = results, RC = extra results 3247 | ldr TMP0w, SAVE_MULTRES 3248 | ldr PC, [BASE, FRAME_PC] 3249 | add RA, BASE, RA, lsl #3 3250 | add RC, TMP0, RC, lsl #3 3251 | b ->BC_RETM_Z 3252 break; 3253 3254 case BC_RET: 3255 | // RA = results, RC = nresults+1 3256 | ldr PC, [BASE, FRAME_PC] 3257 | lsl RC, RC, #3 3258 | add RA, BASE, RA, lsl #3 3259 |->BC_RETM_Z: 3260 | str RCw, SAVE_MULTRES 3261 |1: 3262 | ands CARG1, PC, #FRAME_TYPE 3263 | eor CARG2, PC, #FRAME_VARG 3264 | bne ->BC_RETV2_Z 3265 | 3266 |->BC_RET_Z: 3267 | // BASE = base, RA = resultptr, RC = (nresults+1)*8, PC = return 3268 | ldr INSw, [PC, #-4] 3269 | subs TMP1, RC, #8 3270 | sub CARG3, BASE, #16 3271 | beq >3 3272 |2: 3273 | ldr TMP0, [RA], #8 3274 | add BASE, BASE, #8 3275 | sub TMP1, TMP1, #8 3276 | str TMP0, [BASE, #-24] 3277 | cbnz TMP1, <2 3278 |3: 3279 | decode_RA RA, INS 3280 | sub CARG4, CARG3, RA, lsl #3 3281 | decode_RB RB, INS 3282 | ldr LFUNC:CARG1, [CARG4, FRAME_FUNC] 3283 |5: 3284 | cmp RC, RB, lsl #3 // More results expected? 3285 | blo >6 3286 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK 3287 | mov BASE, CARG4 3288 | ldr CARG2, LFUNC:CARG1->pc 3289 | ldr KBASE, [CARG2, #PC2PROTO(k)] 3290 | ins_next 3291 | 3292 |6: // Fill up results with nil. 3293 | add BASE, BASE, #8 3294 | add RC, RC, #8 3295 | str TISNIL, [BASE, #-24] 3296 | b <5 3297 | 3298 |->BC_RETV1_Z: // Non-standard return case. 3299 | add RA, BASE, RA, lsl #3 3300 |->BC_RETV2_Z: 3301 | tst CARG2, #FRAME_TYPEP 3302 | bne ->vm_return 3303 | // Return from vararg function: relocate BASE down. 3304 | sub BASE, BASE, CARG2 3305 | ldr PC, [BASE, FRAME_PC] 3306 | b <1 3307 break; 3308 3309 case BC_RET0: case BC_RET1: 3310 | // RA = results, RC = nresults+1 3311 | ldr PC, [BASE, FRAME_PC] 3312 | lsl RC, RC, #3 3313 | str RCw, SAVE_MULTRES 3314 | ands CARG1, PC, #FRAME_TYPE 3315 | eor CARG2, PC, #FRAME_VARG 3316 | bne ->BC_RETV1_Z 3317 | ldr INSw, [PC, #-4] 3318 if (op == BC_RET1) { 3319 | ldr TMP0, [BASE, RA, lsl #3] 3320 } 3321 | sub CARG4, BASE, #16 3322 | decode_RA RA, INS 3323 | sub BASE, CARG4, RA, lsl #3 3324 if (op == BC_RET1) { 3325 | str TMP0, [CARG4], #8 3326 } 3327 | decode_RB RB, INS 3328 | ldr LFUNC:CARG1, [BASE, FRAME_FUNC] 3329 |5: 3330 | cmp RC, RB, lsl #3 3331 | blo >6 3332 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK 3333 | ldr CARG2, LFUNC:CARG1->pc 3334 | ldr KBASE, [CARG2, #PC2PROTO(k)] 3335 | ins_next 3336 | 3337 |6: // Fill up results with nil. 3338 | add RC, RC, #8 3339 | str TISNIL, [CARG4], #8 3340 | b <5 3341 break; 3342 3343 /* -- Loops and branches ------------------------------------------------ */ 3344 3345 |.define FOR_IDX, [RA]; .define FOR_TIDX, [RA, #4] 3346 |.define FOR_STOP, [RA, #8]; .define FOR_TSTOP, [RA, #12] 3347 |.define FOR_STEP, [RA, #16]; .define FOR_TSTEP, [RA, #20] 3348 |.define FOR_EXT, [RA, #24]; .define FOR_TEXT, [RA, #28] 3349 3350 case BC_FORL: 3351 |.if JIT 3352 | hotloop 3353 |.endif 3354 | // Fall through. Assumes BC_IFORL follows. 3355 break; 3356 3357 case BC_JFORI: 3358 case BC_JFORL: 3359 #if !LJ_HASJIT 3360 break; 3361 #endif 3362 case BC_FORI: 3363 case BC_IFORL: 3364 | // RA = base, RC = target (after end of loop or start of loop) 3365 vk = (op == BC_IFORL || op == BC_JFORL); 3366 | add RA, BASE, RA, lsl #3 3367 | ldp CARG1, CARG2, FOR_IDX // CARG1 = IDX, CARG2 = STOP 3368 | ldr CARG3, FOR_STEP // CARG3 = STEP 3369 if (op != BC_JFORL) { 3370 | add RC, PC, RC, lsl #2 3371 | sub RC, RC, #0x20000 3372 } 3373 | checkint CARG1, >5 3374 if (!vk) { 3375 | checkint CARG2, ->vmeta_for 3376 | checkint CARG3, ->vmeta_for 3377 | tbnz CARG3w, #31, >4 3378 | cmp CARG1w, CARG2w 3379 } else { 3380 | adds CARG1w, CARG1w, CARG3w 3381 | bvs >2 3382 | add TMP0, CARG1, TISNUM 3383 | tbnz CARG3w, #31, >4 3384 | cmp CARG1w, CARG2w 3385 } 3386 |1: 3387 if (op == BC_FORI) { 3388 | csel PC, RC, PC, gt 3389 } else if (op == BC_JFORI) { 3390 | ldrh RCw, [RC, #-2] 3391 } else if (op == BC_IFORL) { 3392 | csel PC, RC, PC, le 3393 } 3394 if (vk) { 3395 | str TMP0, FOR_IDX 3396 | str TMP0, FOR_EXT 3397 } else { 3398 | str CARG1, FOR_EXT 3399 } 3400 if (op == BC_JFORI || op == BC_JFORL) { 3401 | ble =>BC_JLOOP 3402 } 3403 |2: 3404 | ins_next 3405 | 3406 |4: // Invert check for negative step. 3407 | cmp CARG2w, CARG1w 3408 | b <1 3409 | 3410 |5: // FP loop. 3411 | ldp d0, d1, FOR_IDX 3412 | blo ->vmeta_for 3413 if (!vk) { 3414 | checknum CARG2, ->vmeta_for 3415 | checknum CARG3, ->vmeta_for 3416 | str d0, FOR_EXT 3417 } else { 3418 | ldr d2, FOR_STEP 3419 | fadd d0, d0, d2 3420 } 3421 | tbnz CARG3, #63, >7 3422 | fcmp d0, d1 3423 |6: 3424 if (vk) { 3425 | str d0, FOR_IDX 3426 | str d0, FOR_EXT 3427 } 3428 if (op == BC_FORI) { 3429 | csel PC, RC, PC, hi 3430 } else if (op == BC_JFORI) { 3431 | ldrh RCw, [RC, #-2] 3432 | bls =>BC_JLOOP 3433 } else if (op == BC_IFORL) { 3434 | csel PC, RC, PC, ls 3435 } else { 3436 | bls =>BC_JLOOP 3437 } 3438 | b <2 3439 | 3440 |7: // Invert check for negative step. 3441 | fcmp d1, d0 3442 | b <6 3443 break; 3444 3445 case BC_ITERL: 3446 |.if JIT 3447 | hotloop 3448 |.endif 3449 | // Fall through. Assumes BC_IITERL follows. 3450 break; 3451 3452 case BC_JITERL: 3453 #if !LJ_HASJIT 3454 break; 3455 #endif 3456 case BC_IITERL: 3457 | // RA = base, RC = target 3458 | ldr CARG1, [BASE, RA, lsl #3] 3459 | add TMP1, BASE, RA, lsl #3 3460 | cmp CARG1, TISNIL 3461 | beq >1 // Stop if iterator returned nil. 3462 if (op == BC_JITERL) { 3463 | str CARG1, [TMP1, #-8] 3464 | b =>BC_JLOOP 3465 } else { 3466 | add TMP0, PC, RC, lsl #2 // Otherwise save control var + branch. 3467 | sub PC, TMP0, #0x20000 3468 | str CARG1, [TMP1, #-8] 3469 } 3470 |1: 3471 | ins_next 3472 break; 3473 3474 case BC_LOOP: 3475 | // RA = base, RC = target (loop extent) 3476 | // Note: RA/RC is only used by trace recorder to determine scope/extent 3477 | // This opcode does NOT jump, it's only purpose is to detect a hot loop. 3478 |.if JIT 3479 | hotloop 3480 |.endif 3481 | // Fall through. Assumes BC_ILOOP follows. 3482 break; 3483 3484 case BC_ILOOP: 3485 | // RA = base, RC = target (loop extent) 3486 | ins_next 3487 break; 3488 3489 case BC_JLOOP: 3490 |.if JIT 3491 | NYI 3492 |.endif 3493 break; 3494 3495 case BC_JMP: 3496 | // RA = base (only used by trace recorder), RC = target 3497 | add RC, PC, RC, lsl #2 3498 | sub PC, RC, #0x20000 3499 | ins_next 3500 break; 3501 3502 /* -- Function headers -------------------------------------------------- */ 3503 3504 case BC_FUNCF: 3505 |.if JIT 3506 | hotcall 3507 |.endif 3508 case BC_FUNCV: /* NYI: compiled vararg functions. */ 3509 | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow. 3510 break; 3511 3512 case BC_JFUNCF: 3513 #if !LJ_HASJIT 3514 break; 3515 #endif 3516 case BC_IFUNCF: 3517 | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8 3518 | ldr CARG1, L->maxstack 3519 | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)] 3520 | ldr KBASE, [PC, #-4+PC2PROTO(k)] 3521 | cmp RA, CARG1 3522 | bhi ->vm_growstack_l 3523 |2: 3524 | cmp NARGS8:RC, TMP1, lsl #3 // Check for missing parameters. 3525 | blo >3 3526 if (op == BC_JFUNCF) { 3527 | decode_RD RC, INS 3528 | b =>BC_JLOOP 3529 } else { 3530 | ins_next 3531 } 3532 | 3533 |3: // Clear missing parameters. 3534 | str TISNIL, [BASE, NARGS8:RC] 3535 | add NARGS8:RC, NARGS8:RC, #8 3536 | b <2 3537 break; 3538 3539 case BC_JFUNCV: 3540 #if !LJ_HASJIT 3541 break; 3542 #endif 3543 | NYI // NYI: compiled vararg functions 3544 break; /* NYI: compiled vararg functions. */ 3545 3546 case BC_IFUNCV: 3547 | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8 3548 | ldr CARG1, L->maxstack 3549 | add TMP2, BASE, RC 3550 | add RA, RA, RC 3551 | add TMP0, RC, #16+FRAME_VARG 3552 | str LFUNC:CARG3, [TMP2], #8 // Store (untagged) copy of LFUNC. 3553 | ldr KBASE, [PC, #-4+PC2PROTO(k)] 3554 | cmp RA, CARG1 3555 | str TMP0, [TMP2], #8 // Store delta + FRAME_VARG. 3556 | bhs ->vm_growstack_l 3557 | sub RC, TMP2, #16 3558 | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)] 3559 | mov RA, BASE 3560 | mov BASE, TMP2 3561 | cbz TMP1, >2 3562 |1: 3563 | cmp RA, RC // Less args than parameters? 3564 | bhs >3 3565 | ldr TMP0, [RA] 3566 | sub TMP1, TMP1, #1 3567 | str TISNIL, [RA], #8 // Clear old fixarg slot (help the GC). 3568 | str TMP0, [TMP2], #8 3569 | cbnz TMP1, <1 3570 |2: 3571 | ins_next 3572 | 3573 |3: 3574 | sub TMP1, TMP1, #1 3575 | str TISNIL, [TMP2], #8 3576 | cbz TMP1, <2 3577 | b <3 3578 break; 3579 3580 case BC_FUNCC: 3581 case BC_FUNCCW: 3582 | // BASE = new base, RA = BASE+framesize*8, CARG3 = CFUNC, RC = nargs*8 3583 if (op == BC_FUNCC) { 3584 | ldr CARG4, CFUNC:CARG3->f 3585 } else { 3586 | ldr CARG4, GL->wrapf 3587 } 3588 | add CARG2, RA, NARGS8:RC 3589 | ldr CARG1, L->maxstack 3590 | add RC, BASE, NARGS8:RC 3591 | cmp CARG2, CARG1 3592 | stp BASE, RC, L->base 3593 if (op == BC_FUNCCW) { 3594 | ldr CARG2, CFUNC:CARG3->f 3595 } 3596 | mv_vmstate TMP0w, C 3597 | mov CARG1, L 3598 | bhi ->vm_growstack_c // Need to grow stack. 3599 | st_vmstate TMP0w 3600 | blr CARG4 // (lua_State *L [, lua_CFunction f]) 3601 | // Returns nresults. 3602 | ldp BASE, TMP1, L->base 3603 | str L, GL->cur_L 3604 | sbfiz RC, CRET1, #3, #32 3605 | st_vmstate ST_INTERP 3606 | ldr PC, [BASE, FRAME_PC] 3607 | sub RA, TMP1, RC // RA = L->top - nresults*8 3608 | b ->vm_returnc 3609 break; 3610 3611 /* ---------------------------------------------------------------------- */ 3612 3613 default: 3614 fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]); 3615 exit(2); 3616 break; 3617 } 3618 } 3619 3620 static int build_backend(BuildCtx *ctx) 3621 { 3622 int op; 3623 3624 dasm_growpc(Dst, BC__MAX); 3625 3626 build_subroutines(ctx); 3627 3628 |.code_op 3629 for (op = 0; op < BC__MAX; op++) 3630 build_ins(ctx, (BCOp)op, op); 3631 3632 return BC__MAX; 3633 } 3634 3635 /* Emit pseudo frame-info for all assembler functions. */ 3636 static void emit_asm_debug(BuildCtx *ctx) 3637 { 3638 int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code); 3639 int i, cf = CFRAME_SIZE >> 3; 3640 switch (ctx->mode) { 3641 case BUILD_elfasm: 3642 fprintf(ctx->fp, "\t.section .debug_frame,\"\",%%progbits\n"); 3643 fprintf(ctx->fp, 3644 ".Lframe0:\n" 3645 "\t.long .LECIE0-.LSCIE0\n" 3646 ".LSCIE0:\n" 3647 "\t.long 0xffffffff\n" 3648 "\t.byte 0x1\n" 3649 "\t.string \"\"\n" 3650 "\t.uleb128 0x1\n" 3651 "\t.sleb128 -8\n" 3652 "\t.byte 30\n" /* Return address is in lr. */ 3653 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */ 3654 "\t.align 3\n" 3655 ".LECIE0:\n\n"); 3656 fprintf(ctx->fp, 3657 ".LSFDE0:\n" 3658 "\t.long .LEFDE0-.LASFDE0\n" 3659 ".LASFDE0:\n" 3660 "\t.long .Lframe0\n" 3661 "\t.quad .Lbegin\n" 3662 "\t.quad %d\n" 3663 "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ 3664 "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */ 3665 "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */ 3666 fcofs, CFRAME_SIZE, cf, cf-1); 3667 for (i = 19; i <= 28; i++) /* offset x19-x28 */ 3668 fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17); 3669 for (i = 8; i <= 15; i++) /* offset d8-d15 */ 3670 fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n", 3671 64+i, cf-i-4); 3672 fprintf(ctx->fp, 3673 "\t.align 3\n" 3674 ".LEFDE0:\n\n"); 3675 #if LJ_HASFFI 3676 fprintf(ctx->fp, 3677 ".LSFDE1:\n" 3678 "\t.long .LEFDE1-.LASFDE1\n" 3679 ".LASFDE1:\n" 3680 "\t.long .Lframe0\n" 3681 "\t.quad lj_vm_ffi_call\n" 3682 "\t.quad %d\n" 3683 "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */ 3684 "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */ 3685 "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */ 3686 "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */ 3687 "\t.align 3\n" 3688 ".LEFDE1:\n\n", (int)ctx->codesz - fcofs); 3689 #endif 3690 fprintf(ctx->fp, "\t.section .eh_frame,\"a\",%%progbits\n"); 3691 fprintf(ctx->fp, 3692 ".Lframe1:\n" 3693 "\t.long .LECIE1-.LSCIE1\n" 3694 ".LSCIE1:\n" 3695 "\t.long 0\n" 3696 "\t.byte 0x1\n" 3697 "\t.string \"zPR\"\n" 3698 "\t.uleb128 0x1\n" 3699 "\t.sleb128 -8\n" 3700 "\t.byte 30\n" /* Return address is in lr. */ 3701 "\t.uleb128 6\n" /* augmentation length */ 3702 "\t.byte 0x1b\n" /* pcrel|sdata4 */ 3703 "\t.long lj_err_unwind_dwarf-.\n" 3704 "\t.byte 0x1b\n" /* pcrel|sdata4 */ 3705 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */ 3706 "\t.align 3\n" 3707 ".LECIE1:\n\n"); 3708 fprintf(ctx->fp, 3709 ".LSFDE2:\n" 3710 "\t.long .LEFDE2-.LASFDE2\n" 3711 ".LASFDE2:\n" 3712 "\t.long .LASFDE2-.Lframe1\n" 3713 "\t.long .Lbegin-.\n" 3714 "\t.long %d\n" 3715 "\t.uleb128 0\n" /* augmentation length */ 3716 "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */ 3717 "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */ 3718 "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */ 3719 fcofs, CFRAME_SIZE, cf, cf-1); 3720 for (i = 19; i <= 28; i++) /* offset x19-x28 */ 3721 fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17); 3722 for (i = 8; i <= 15; i++) /* offset d8-d15 */ 3723 fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n", 3724 64+i, cf-i-4); 3725 fprintf(ctx->fp, 3726 "\t.align 3\n" 3727 ".LEFDE2:\n\n"); 3728 #if LJ_HASFFI 3729 fprintf(ctx->fp, 3730 ".Lframe2:\n" 3731 "\t.long .LECIE2-.LSCIE2\n" 3732 ".LSCIE2:\n" 3733 "\t.long 0\n" 3734 "\t.byte 0x1\n" 3735 "\t.string \"zR\"\n" 3736 "\t.uleb128 0x1\n" 3737 "\t.sleb128 -8\n" 3738 "\t.byte 30\n" /* Return address is in lr. */ 3739 "\t.uleb128 1\n" /* augmentation length */ 3740 "\t.byte 0x1b\n" /* pcrel|sdata4 */ 3741 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */ 3742 "\t.align 3\n" 3743 ".LECIE2:\n\n"); 3744 fprintf(ctx->fp, 3745 ".LSFDE3:\n" 3746 "\t.long .LEFDE3-.LASFDE3\n" 3747 ".LASFDE3:\n" 3748 "\t.long .LASFDE3-.Lframe2\n" 3749 "\t.long lj_vm_ffi_call-.\n" 3750 "\t.long %d\n" 3751 "\t.uleb128 0\n" /* augmentation length */ 3752 "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */ 3753 "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */ 3754 "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */ 3755 "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */ 3756 "\t.align 3\n" 3757 ".LEFDE3:\n\n", (int)ctx->codesz - fcofs); 3758 #endif 3759 break; 3760 default: 3761 break; 3762 } 3763 } 3764