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