1# Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. 2# 3# Redistribution and use in source and binary forms, with or without 4# modification, are permitted provided that the following conditions 5# are met: 6# 1. Redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer. 8# 2. Redistributions in binary form must reproduce the above copyright 9# notice, this list of conditions and the following disclaimer in the 10# documentation and/or other materials provided with the distribution. 11# 12# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 13# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 14# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 16# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 18# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 19# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 20# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 22# THE POSSIBILITY OF SUCH DAMAGE. 23 24 25# Crash course on the language that this is written in (which I just call 26# "assembly" even though it's more than that): 27# 28# - Mostly gas-style operand ordering. The last operand tends to be the 29# destination. So "a := b" is written as "mov b, a". But unlike gas, 30# comparisons are in-order, so "if (a < b)" is written as 31# "bilt a, b, ...". 32# 33# - "b" = byte, "h" = 16-bit word, "i" = 32-bit word, "p" = pointer. 34# Currently this is just 32-bit so "i" and "p" are interchangeable 35# except when an op supports one but not the other. 36# 37# - In general, valid operands for macro invocations and instructions are 38# registers (eg "t0"), addresses (eg "4[t0]"), base-index addresses 39# (eg "7[t0, t1, 2]"), absolute addresses (eg "0xa0000000[]"), or labels 40# (eg "_foo" or ".foo"). Macro invocations can also take anonymous 41# macros as operands. Instructions cannot take anonymous macros. 42# 43# - Labels must have names that begin with either "_" or ".". A "." label 44# is local and gets renamed before code gen to minimize namespace 45# pollution. A "_" label is an extern symbol (i.e. ".globl"). The "_" 46# may or may not be removed during code gen depending on whether the asm 47# conventions for C name mangling on the target platform mandate a "_" 48# prefix. 49# 50# - A "macro" is a lambda expression, which may be either anonymous or 51# named. But this has caveats. "macro" can take zero or more arguments, 52# which may be macros or any valid operands, but it can only return 53# code. But you can do Turing-complete things via continuation passing 54# style: "macro foo (a, b) b(a) end foo(foo, foo)". Actually, don't do 55# that, since you'll just crash the assembler. 56# 57# - An "if" is a conditional on settings. Any identifier supplied in the 58# predicate of an "if" is assumed to be a #define that is available 59# during code gen. So you can't use "if" for computation in a macro, but 60# you can use it to select different pieces of code for different 61# platforms. 62# 63# - Arguments to macros follow lexical scoping rather than dynamic scoping. 64# Const's also follow lexical scoping and may override (hide) arguments 65# or other consts. All variables (arguments and constants) can be bound 66# to operands. Additionally, arguments (but not constants) can be bound 67# to macros. 68 69 70# Below we have a bunch of constant declarations. Each constant must have 71# a corresponding ASSERT() in LLIntData.cpp. 72 73# Utilities 74macro dispatch(advance) 75 addp advance * 4, PC 76 jmp [PC] 77end 78 79macro dispatchBranchWithOffset(pcOffset) 80 lshifti 2, pcOffset 81 addp pcOffset, PC 82 jmp [PC] 83end 84 85macro dispatchBranch(pcOffset) 86 loadi pcOffset, t0 87 dispatchBranchWithOffset(t0) 88end 89 90macro dispatchAfterCall() 91 loadi ArgumentCount + TagOffset[cfr], PC 92 loadi 4[PC], t2 93 storei t1, TagOffset[cfr, t2, 8] 94 storei t0, PayloadOffset[cfr, t2, 8] 95 valueProfile(t1, t0, 4 * (CallOpCodeSize - 1), t3) 96 dispatch(CallOpCodeSize) 97end 98 99macro cCall2(function, arg1, arg2) 100 if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS 101 move arg1, a0 102 move arg2, a1 103 call function 104 elsif X86 or X86_WIN 105 subp 8, sp 106 push arg2 107 push arg1 108 call function 109 addp 16, sp 110 elsif SH4 111 setargs arg1, arg2 112 call function 113 elsif C_LOOP 114 cloopCallSlowPath function, arg1, arg2 115 else 116 error 117 end 118end 119 120macro cCall2Void(function, arg1, arg2) 121 if C_LOOP 122 cloopCallSlowPathVoid function, arg1, arg2 123 else 124 cCall2(function, arg1, arg2) 125 end 126end 127 128# This barely works. arg3 and arg4 should probably be immediates. 129macro cCall4(function, arg1, arg2, arg3, arg4) 130 if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS 131 move arg1, a0 132 move arg2, a1 133 move arg3, a2 134 move arg4, a3 135 call function 136 elsif X86 or X86_WIN 137 push arg4 138 push arg3 139 push arg2 140 push arg1 141 call function 142 addp 16, sp 143 elsif SH4 144 setargs arg1, arg2, arg3, arg4 145 call function 146 elsif C_LOOP 147 error 148 else 149 error 150 end 151end 152 153macro callSlowPath(slowPath) 154 cCall2(slowPath, cfr, PC) 155 move t0, PC 156end 157 158macro doCallToJavaScript(makeCall) 159 if X86 or X86_WIN 160 const entry = t4 161 const vm = t3 162 const protoCallFrame = t5 163 164 const previousCFR = t0 165 const previousPC = t1 166 const temp1 = t0 # Same as previousCFR 167 const temp2 = t1 # Same as previousPC 168 const temp3 = t2 169 const temp4 = t3 # same as vm 170 elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP 171 const entry = a0 172 const vm = a1 173 const protoCallFrame = a2 174 175 const previousCFR = t3 176 const previousPC = lr 177 const temp1 = t3 # Same as previousCFR 178 const temp2 = t4 179 const temp3 = t5 180 const temp4 = t4 # Same as temp2 181 elsif MIPS 182 const entry = a0 183 const vmTopCallFrame = a1 184 const protoCallFrame = a2 185 const topOfStack = a3 186 187 const previousCFR = t2 188 const previousPC = lr 189 const temp1 = t3 190 const temp2 = t5 191 const temp3 = t4 192 const temp4 = t6 193 elsif SH4 194 const entry = a0 195 const vm = a1 196 const protoCallFrame = a2 197 198 const previousCFR = t3 199 const previousPC = lr 200 const temp1 = t3 # Same as previousCFR 201 const temp2 = a3 202 const temp3 = t8 203 const temp4 = t9 204 end 205 206 callToJavaScriptPrologue() 207 208 if X86 209 loadp 36[sp], vm 210 loadp 32[sp], entry 211 elsif X86_WIN 212 loadp 40[sp, temp3], vm 213 loadp 36[sp, temp3], entry 214 else 215 move cfr, previousCFR 216 end 217 218 checkStackPointerAlignment(temp2, 0xbad0dc01) 219 220 # The stack reserved zone ensures that we have adequate space for the 221 # VMEntrySentinelFrame. Proceed with allocating and initializing the 222 # sentinel frame. 223 move sp, cfr 224 subp CallFrameHeaderSlots * 8, cfr 225 storep 0, ArgumentCount[cfr] 226 storep vm, Callee[cfr] 227 loadp VM::topCallFrame[vm], temp2 228 storep temp2, ScopeChain[cfr] 229 storep 1, CodeBlock[cfr] 230 if X86 231 loadp 28[sp], previousPC 232 loadp 24[sp], previousCFR 233 elsif X86_WIN 234 loadp 32[sp, temp3], previousPC 235 loadp 28[sp, temp3], previousCFR 236 end 237 storep previousPC, ReturnPC[cfr] 238 storep previousCFR, CallerFrame[cfr] 239 240 if X86 241 loadp 40[sp], protoCallFrame 242 elsif X86_WIN 243 loadp 44[sp, temp3], protoCallFrame 244 end 245 246 loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp2 247 addp CallFrameHeaderSlots, temp2, temp2 248 lshiftp 3, temp2 249 subp cfr, temp2, temp1 250 251 # Ensure that we have enough additional stack capacity for the incoming args, 252 # and the frame for the JS code we're executing. We need to do this check 253 # before we start copying the args from the protoCallFrame below. 254 bpaeq temp1, VM::m_jsStackLimit[vm], .stackHeightOK 255 256 if ARMv7 257 subp cfr, 8, temp2 258 move temp2, sp 259 else 260 subp cfr, 8, sp 261 end 262 263 if C_LOOP 264 move entry, temp2 265 move vm, temp3 266 cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, temp1 267 bpeq t0, 0, .stackCheckFailed 268 move temp2, entry 269 move temp3, vm 270 jmp .stackHeightOK 271 272.stackCheckFailed: 273 move temp2, entry 274 move temp3, vm 275 end 276 277 cCall2(_llint_throw_stack_overflow_error, vm, protoCallFrame) 278 callToJavaScriptEpilogue() 279 ret 280 281.stackHeightOK: 282 move temp1, sp 283 move 5, temp1 284 285.copyHeaderLoop: 286 subi 1, temp1 287 loadi TagOffset[protoCallFrame, temp1, 8], temp3 288 storei temp3, TagOffset + CodeBlock[sp, temp1, 8] 289 loadi PayloadOffset[protoCallFrame, temp1, 8], temp3 290 storei temp3, PayloadOffset + CodeBlock[sp, temp1, 8] 291 btinz temp1, .copyHeaderLoop 292 293 loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], temp2 294 subi 1, temp2 295 loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp3 296 subi 1, temp3 297 298 bieq temp2, temp3, .copyArgs 299.fillExtraArgsLoop: 300 subi 1, temp3 301 storei UndefinedTag, ThisArgumentOffset + 8 + TagOffset[sp, temp3, 8] 302 storei 0, ThisArgumentOffset + 8 + PayloadOffset[sp, temp3, 8] 303 bineq temp2, temp3, .fillExtraArgsLoop 304 305.copyArgs: 306 loadp ProtoCallFrame::args[protoCallFrame], temp1 307 308.copyArgsLoop: 309 btiz temp2, .copyArgsDone 310 subi 1, temp2 311 loadi TagOffset[temp1, temp2, 8], temp3 312 storei temp3, ThisArgumentOffset + 8 + TagOffset[sp, temp2, 8] 313 loadi PayloadOffset[temp1, temp2, 8], temp3 314 storei temp3, ThisArgumentOffset + 8 + PayloadOffset[sp, temp2, 8] 315 jmp .copyArgsLoop 316 317.copyArgsDone: 318 storep sp, VM::topCallFrame[vm] 319 320 makeCall(entry, temp1, temp2) 321 322 bpeq CodeBlock[cfr], 1, .calleeFramePopped 323 loadp CallerFrame[cfr], cfr 324 325.calleeFramePopped: 326 loadp Callee[cfr], temp3 # VM 327 loadp ScopeChain[cfr], temp4 # previous topCallFrame 328 storep temp4, VM::topCallFrame[temp3] 329 330 callToJavaScriptEpilogue() 331 ret 332end 333 334macro makeJavaScriptCall(entry, temp, unused) 335 addp CallerFrameAndPCSize, sp 336 checkStackPointerAlignment(t2, 0xbad0dc02) 337 if C_LOOP 338 cloopCallJSFunction entry 339 else 340 call entry 341 end 342 checkStackPointerAlignment(t2, 0xbad0dc03) 343 subp CallerFrameAndPCSize, sp 344end 345 346macro makeHostFunctionCall(entry, temp1, temp2) 347 move entry, temp1 348 if C_LOOP 349 move sp, a0 350 storep cfr, [sp] 351 storep lr, PtrSize[sp] 352 cloopCallNative temp1 353 else 354 if X86 or X86_WIN 355 # Put callee frame pointer on stack as arg0, also put it in ecx for "fastcall" targets 356 move 0, temp2 357 move temp2, 4[sp] # put 0 in ReturnPC 358 move cfr, [sp] # put caller frame pointer into callee frame since callee prologue can't 359 move sp, t2 # t2 is ecx 360 push temp2 # Push dummy arg1 361 push t2 362 else 363 move sp, a0 364 addp CallerFrameAndPCSize, sp 365 end 366 call temp1 367 if X86 or X86_WIN 368 addp 8, sp 369 else 370 subp CallerFrameAndPCSize, sp 371 end 372 end 373end 374 375_handleUncaughtException: 376 loadp ScopeChain + PayloadOffset[cfr], t3 377 andp MarkedBlockMask, t3 378 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3 379 loadp VM::callFrameForThrow[t3], cfr 380 381 # So far, we've unwound the stack to the frame just below the sentinel frame, except 382 # in the case of stack overflow in the first function called from callToJavaScript. 383 # Check if we need to pop to the sentinel frame and do the necessary clean up for 384 # returning to the caller C frame. 385 bpeq CodeBlock[cfr], 1, .handleUncaughtExceptionAlreadyIsSentinel 386 loadp CallerFrame + PayloadOffset[cfr], cfr 387.handleUncaughtExceptionAlreadyIsSentinel: 388 389 loadp Callee + PayloadOffset[cfr], t3 # VM 390 loadp ScopeChain + PayloadOffset[cfr], t5 # previous topCallFrame 391 storep t5, VM::topCallFrame[t3] 392 393 callToJavaScriptEpilogue() 394 ret 395 396macro doReturnFromHostFunction(extraStackSpace) 397 functionEpilogue(extraStackSpace) 398 ret 399end 400 401# Debugging operation if you'd like to print an operand in the instruction stream. fromWhere 402# should be an immediate integer - any integer you like; use it to identify the place you're 403# debugging from. operand should likewise be an immediate, and should identify the operand 404# in the instruction stream you'd like to print out. 405macro traceOperand(fromWhere, operand) 406 cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand) 407 move t0, PC 408 move t1, cfr 409end 410 411# Debugging operation if you'd like to print the value of an operand in the instruction 412# stream. Same as traceOperand(), but assumes that the operand is a register, and prints its 413# value. 414macro traceValue(fromWhere, operand) 415 cCall4(_llint_trace_value, cfr, PC, fromWhere, operand) 416 move t0, PC 417 move t1, cfr 418end 419 420# Call a slowPath for call opcodes. 421macro callCallSlowPath(slowPath, action) 422 storep PC, ArgumentCount + TagOffset[cfr] 423 cCall2(slowPath, cfr, PC) 424 action(t0) 425end 426 427macro callWatchdogTimerHandler(throwHandler) 428 storei PC, ArgumentCount + TagOffset[cfr] 429 cCall2(_llint_slow_path_handle_watchdog_timer, cfr, PC) 430 btpnz t0, throwHandler 431 loadi ArgumentCount + TagOffset[cfr], PC 432end 433 434macro checkSwitchToJITForLoop() 435 checkSwitchToJIT( 436 1, 437 macro () 438 storei PC, ArgumentCount + TagOffset[cfr] 439 cCall2(_llint_loop_osr, cfr, PC) 440 btpz t0, .recover 441 move t1, sp 442 jmp t0 443 .recover: 444 loadi ArgumentCount + TagOffset[cfr], PC 445 end) 446end 447 448macro loadVariable(operand, index, tag, payload) 449 loadisFromInstruction(operand, index) 450 loadi TagOffset[cfr, index, 8], tag 451 loadi PayloadOffset[cfr, index, 8], payload 452end 453 454# Index, tag, and payload must be different registers. Index is not 455# changed. 456macro loadConstantOrVariable(index, tag, payload) 457 bigteq index, FirstConstantRegisterIndex, .constant 458 loadi TagOffset[cfr, index, 8], tag 459 loadi PayloadOffset[cfr, index, 8], payload 460 jmp .done 461.constant: 462 loadp CodeBlock[cfr], payload 463 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload 464 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex, 465 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3. 466 loadp TagOffset[payload, index, 8], tag 467 loadp PayloadOffset[payload, index, 8], payload 468.done: 469end 470 471macro loadConstantOrVariableTag(index, tag) 472 bigteq index, FirstConstantRegisterIndex, .constant 473 loadi TagOffset[cfr, index, 8], tag 474 jmp .done 475.constant: 476 loadp CodeBlock[cfr], tag 477 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag 478 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex, 479 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3. 480 loadp TagOffset[tag, index, 8], tag 481.done: 482end 483 484# Index and payload may be the same register. Index may be clobbered. 485macro loadConstantOrVariable2Reg(index, tag, payload) 486 bigteq index, FirstConstantRegisterIndex, .constant 487 loadi TagOffset[cfr, index, 8], tag 488 loadi PayloadOffset[cfr, index, 8], payload 489 jmp .done 490.constant: 491 loadp CodeBlock[cfr], tag 492 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag 493 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex, 494 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3. 495 lshifti 3, index 496 addp index, tag 497 loadp PayloadOffset[tag], payload 498 loadp TagOffset[tag], tag 499.done: 500end 501 502macro loadConstantOrVariablePayloadTagCustom(index, tagCheck, payload) 503 bigteq index, FirstConstantRegisterIndex, .constant 504 tagCheck(TagOffset[cfr, index, 8]) 505 loadi PayloadOffset[cfr, index, 8], payload 506 jmp .done 507.constant: 508 loadp CodeBlock[cfr], payload 509 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload 510 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex, 511 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3. 512 tagCheck(TagOffset[payload, index, 8]) 513 loadp PayloadOffset[payload, index, 8], payload 514.done: 515end 516 517# Index and payload must be different registers. Index is not mutated. Use 518# this if you know what the tag of the variable should be. Doing the tag 519# test as part of loading the variable reduces register use, but may not 520# be faster than doing loadConstantOrVariable followed by a branch on the 521# tag. 522macro loadConstantOrVariablePayload(index, expectedTag, payload, slow) 523 loadConstantOrVariablePayloadTagCustom( 524 index, 525 macro (actualTag) bineq actualTag, expectedTag, slow end, 526 payload) 527end 528 529macro loadConstantOrVariablePayloadUnchecked(index, payload) 530 loadConstantOrVariablePayloadTagCustom( 531 index, 532 macro (actualTag) end, 533 payload) 534end 535 536macro storeStructureWithTypeInfo(cell, structure, scratch) 537 storep structure, JSCell::m_structureID[cell] 538 539 loadi Structure::m_blob + StructureIDBlob::u.words.word2[structure], scratch 540 storei scratch, JSCell::m_indexingType[cell] 541end 542 543macro writeBarrierOnOperand(cellOperand) 544 if GGC 545 loadisFromInstruction(cellOperand, t1) 546 loadConstantOrVariablePayload(t1, CellTag, t2, .writeBarrierDone) 547 checkMarkByte(t2, t1, t3, 548 macro(gcData) 549 btbnz gcData, .writeBarrierDone 550 push cfr, PC 551 # We make two extra slots because cCall2 will poke. 552 subp 8, sp 553 cCall2Void(_llint_write_barrier_slow, cfr, t2) 554 addp 8, sp 555 pop PC, cfr 556 end 557 ) 558 .writeBarrierDone: 559 end 560end 561 562macro writeBarrierOnOperands(cellOperand, valueOperand) 563 if GGC 564 loadisFromInstruction(valueOperand, t1) 565 loadConstantOrVariableTag(t1, t0) 566 bineq t0, CellTag, .writeBarrierDone 567 568 writeBarrierOnOperand(cellOperand) 569 .writeBarrierDone: 570 end 571end 572 573macro writeBarrierOnGlobalObject(valueOperand) 574 if GGC 575 loadisFromInstruction(valueOperand, t1) 576 loadConstantOrVariableTag(t1, t0) 577 bineq t0, CellTag, .writeBarrierDone 578 579 loadp CodeBlock[cfr], t3 580 loadp CodeBlock::m_globalObject[t3], t3 581 checkMarkByte(t3, t1, t2, 582 macro(gcData) 583 btbnz gcData, .writeBarrierDone 584 push cfr, PC 585 # We make two extra slots because cCall2 will poke. 586 subp 8, sp 587 cCall2Void(_llint_write_barrier_slow, cfr, t3) 588 addp 8, sp 589 pop PC, cfr 590 end 591 ) 592 .writeBarrierDone: 593 end 594end 595 596macro valueProfile(tag, payload, operand, scratch) 597 loadp operand[PC], scratch 598 storei tag, ValueProfile::m_buckets + TagOffset[scratch] 599 storei payload, ValueProfile::m_buckets + PayloadOffset[scratch] 600end 601 602 603# Entrypoints into the interpreter 604 605# Expects that CodeBlock is in t1, which is what prologue() leaves behind. 606macro functionArityCheck(doneLabel, slowPath) 607 loadi PayloadOffset + ArgumentCount[cfr], t0 608 biaeq t0, CodeBlock::m_numParameters[t1], doneLabel 609 cCall2(slowPath, cfr, PC) # This slowPath has a simple protocol: t0 = 0 => no error, t0 != 0 => error 610 btiz t0, .noError 611 move t1, cfr # t1 contains caller frame 612 jmp _llint_throw_from_slow_path_trampoline 613 614.noError: 615 # t1 points to ArityCheckData. 616 loadp CommonSlowPaths::ArityCheckData::thunkToCall[t1], t2 617 btpz t2, .proceedInline 618 619 loadp CommonSlowPaths::ArityCheckData::returnPC[t1], t5 620 loadp CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t0 621 call t2 622 if ASSERT_ENABLED 623 loadp ReturnPC[cfr], t0 624 loadp [t0], t0 625 end 626 jmp .continue 627 628.proceedInline: 629 loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t1 630 btiz t1, .continue 631 632 // Move frame up "t1 * 2" slots 633 lshiftp 1, t1 634 negi t1 635 move cfr, t3 636 loadi PayloadOffset + ArgumentCount[cfr], t2 637 addi CallFrameHeaderSlots, t2 638.copyLoop: 639 loadi PayloadOffset[t3], t0 640 storei t0, PayloadOffset[t3, t1, 8] 641 loadi TagOffset[t3], t0 642 storei t0, TagOffset[t3, t1, 8] 643 addp 8, t3 644 bsubinz 1, t2, .copyLoop 645 646 // Fill new slots with JSUndefined 647 move t1, t2 648.fillLoop: 649 move 0, t0 650 storei t0, PayloadOffset[t3, t1, 8] 651 move UndefinedTag, t0 652 storei t0, TagOffset[t3, t1, 8] 653 addp 8, t3 654 baddinz 1, t2, .fillLoop 655 656 lshiftp 3, t1 657 addp t1, cfr 658 addp t1, sp 659.continue: 660 # Reload CodeBlock and PC, since the slow_path clobbered it. 661 loadp CodeBlock[cfr], t1 662 loadp CodeBlock::m_instructions[t1], PC 663 jmp doneLabel 664end 665 666macro branchIfException(label) 667 loadp ScopeChain[cfr], t3 668 andp MarkedBlockMask, t3 669 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3 670 bieq VM::m_exception + TagOffset[t3], EmptyValueTag, .noException 671 jmp label 672.noException: 673end 674 675 676# Instruction implementations 677 678_llint_op_enter: 679 traceExecution() 680 checkStackPointerAlignment(t2, 0xdead00e1) 681 loadp CodeBlock[cfr], t2 // t2<CodeBlock> = cfr.CodeBlock 682 loadi CodeBlock::m_numVars[t2], t2 // t2<size_t> = t2<CodeBlock>.m_numVars 683 btiz t2, .opEnterDone 684 move UndefinedTag, t0 685 move 0, t1 686 negi t2 687.opEnterLoop: 688 storei t0, TagOffset[cfr, t2, 8] 689 storei t1, PayloadOffset[cfr, t2, 8] 690 addi 1, t2 691 btinz t2, .opEnterLoop 692.opEnterDone: 693 callSlowPath(_slow_path_enter) 694 dispatch(1) 695 696 697_llint_op_create_activation: 698 traceExecution() 699 loadi 4[PC], t0 700 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateActivationDone 701 callSlowPath(_llint_slow_path_create_activation) 702.opCreateActivationDone: 703 dispatch(2) 704 705 706_llint_op_init_lazy_reg: 707 traceExecution() 708 loadi 4[PC], t0 709 storei EmptyValueTag, TagOffset[cfr, t0, 8] 710 storei 0, PayloadOffset[cfr, t0, 8] 711 dispatch(2) 712 713 714_llint_op_create_arguments: 715 traceExecution() 716 loadi 4[PC], t0 717 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateArgumentsDone 718 callSlowPath(_slow_path_create_arguments) 719.opCreateArgumentsDone: 720 dispatch(2) 721 722 723_llint_op_create_this: 724 traceExecution() 725 loadi 8[PC], t0 726 loadp PayloadOffset[cfr, t0, 8], t0 727 loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_allocator[t0], t1 728 loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_structure[t0], t2 729 btpz t1, .opCreateThisSlow 730 allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow) 731 loadi 4[PC], t1 732 storei CellTag, TagOffset[cfr, t1, 8] 733 storei t0, PayloadOffset[cfr, t1, 8] 734 dispatch(4) 735 736.opCreateThisSlow: 737 callSlowPath(_slow_path_create_this) 738 dispatch(4) 739 740 741_llint_op_get_callee: 742 traceExecution() 743 loadi 4[PC], t0 744 loadp PayloadOffset + Callee[cfr], t1 745 loadpFromInstruction(2, t2) 746 bpneq t1, t2, .opGetCalleeSlow 747 storei CellTag, TagOffset[cfr, t0, 8] 748 storei t1, PayloadOffset[cfr, t0, 8] 749 dispatch(3) 750 751.opGetCalleeSlow: 752 callSlowPath(_slow_path_get_callee) 753 dispatch(3) 754 755_llint_op_to_this: 756 traceExecution() 757 loadi 4[PC], t0 758 bineq TagOffset[cfr, t0, 8], CellTag, .opToThisSlow 759 loadi PayloadOffset[cfr, t0, 8], t0 760 bbneq JSCell::m_type[t0], FinalObjectType, .opToThisSlow 761 loadpFromInstruction(2, t2) 762 bpneq JSCell::m_structureID[t0], t2, .opToThisSlow 763 dispatch(3) 764 765.opToThisSlow: 766 callSlowPath(_slow_path_to_this) 767 dispatch(3) 768 769 770_llint_op_new_object: 771 traceExecution() 772 loadpFromInstruction(3, t0) 773 loadp ObjectAllocationProfile::m_allocator[t0], t1 774 loadp ObjectAllocationProfile::m_structure[t0], t2 775 allocateJSObject(t1, t2, t0, t3, .opNewObjectSlow) 776 loadi 4[PC], t1 777 storei CellTag, TagOffset[cfr, t1, 8] 778 storei t0, PayloadOffset[cfr, t1, 8] 779 dispatch(4) 780 781.opNewObjectSlow: 782 callSlowPath(_llint_slow_path_new_object) 783 dispatch(4) 784 785 786_llint_op_mov: 787 traceExecution() 788 loadi 8[PC], t1 789 loadi 4[PC], t0 790 loadConstantOrVariable(t1, t2, t3) 791 storei t2, TagOffset[cfr, t0, 8] 792 storei t3, PayloadOffset[cfr, t0, 8] 793 dispatch(3) 794 795 796macro notifyWrite(set, valueTag, valuePayload, scratch, slow) 797 loadb VariableWatchpointSet::m_state[set], scratch 798 bieq scratch, IsInvalidated, .done 799 bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], slow 800 bineq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], slow 801.done: 802end 803 804_llint_op_captured_mov: 805 traceExecution() 806 loadi 8[PC], t1 807 loadConstantOrVariable(t1, t2, t3) 808 loadpFromInstruction(3, t0) 809 btpz t0, .opCapturedMovReady 810 notifyWrite(t0, t2, t3, t1, .opCapturedMovSlow) 811.opCapturedMovReady: 812 loadi 4[PC], t0 813 storei t2, TagOffset[cfr, t0, 8] 814 storei t3, PayloadOffset[cfr, t0, 8] 815 dispatch(4) 816 817.opCapturedMovSlow: 818 callSlowPath(_slow_path_captured_mov) 819 dispatch(4) 820 821 822_llint_op_not: 823 traceExecution() 824 loadi 8[PC], t0 825 loadi 4[PC], t1 826 loadConstantOrVariable(t0, t2, t3) 827 bineq t2, BooleanTag, .opNotSlow 828 xori 1, t3 829 storei t2, TagOffset[cfr, t1, 8] 830 storei t3, PayloadOffset[cfr, t1, 8] 831 dispatch(3) 832 833.opNotSlow: 834 callSlowPath(_slow_path_not) 835 dispatch(3) 836 837 838_llint_op_eq: 839 traceExecution() 840 loadi 12[PC], t2 841 loadi 8[PC], t0 842 loadConstantOrVariable(t2, t3, t1) 843 loadConstantOrVariable2Reg(t0, t2, t0) 844 bineq t2, t3, .opEqSlow 845 bieq t2, CellTag, .opEqSlow 846 bib t2, LowestTag, .opEqSlow 847 loadi 4[PC], t2 848 cieq t0, t1, t0 849 storei BooleanTag, TagOffset[cfr, t2, 8] 850 storei t0, PayloadOffset[cfr, t2, 8] 851 dispatch(4) 852 853.opEqSlow: 854 callSlowPath(_slow_path_eq) 855 dispatch(4) 856 857 858_llint_op_eq_null: 859 traceExecution() 860 loadi 8[PC], t0 861 loadi 4[PC], t3 862 assertNotConstant(t0) 863 loadi TagOffset[cfr, t0, 8], t1 864 loadi PayloadOffset[cfr, t0, 8], t0 865 bineq t1, CellTag, .opEqNullImmediate 866 btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opEqNullMasqueradesAsUndefined 867 move 0, t1 868 jmp .opEqNullNotImmediate 869.opEqNullMasqueradesAsUndefined: 870 loadp JSCell::m_structureID[t0], t1 871 loadp CodeBlock[cfr], t0 872 loadp CodeBlock::m_globalObject[t0], t0 873 cpeq Structure::m_globalObject[t1], t0, t1 874 jmp .opEqNullNotImmediate 875.opEqNullImmediate: 876 cieq t1, NullTag, t2 877 cieq t1, UndefinedTag, t1 878 ori t2, t1 879.opEqNullNotImmediate: 880 storei BooleanTag, TagOffset[cfr, t3, 8] 881 storei t1, PayloadOffset[cfr, t3, 8] 882 dispatch(3) 883 884 885_llint_op_neq: 886 traceExecution() 887 loadi 12[PC], t2 888 loadi 8[PC], t0 889 loadConstantOrVariable(t2, t3, t1) 890 loadConstantOrVariable2Reg(t0, t2, t0) 891 bineq t2, t3, .opNeqSlow 892 bieq t2, CellTag, .opNeqSlow 893 bib t2, LowestTag, .opNeqSlow 894 loadi 4[PC], t2 895 cineq t0, t1, t0 896 storei BooleanTag, TagOffset[cfr, t2, 8] 897 storei t0, PayloadOffset[cfr, t2, 8] 898 dispatch(4) 899 900.opNeqSlow: 901 callSlowPath(_slow_path_neq) 902 dispatch(4) 903 904 905_llint_op_neq_null: 906 traceExecution() 907 loadi 8[PC], t0 908 loadi 4[PC], t3 909 assertNotConstant(t0) 910 loadi TagOffset[cfr, t0, 8], t1 911 loadi PayloadOffset[cfr, t0, 8], t0 912 bineq t1, CellTag, .opNeqNullImmediate 913 btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opNeqNullMasqueradesAsUndefined 914 move 1, t1 915 jmp .opNeqNullNotImmediate 916.opNeqNullMasqueradesAsUndefined: 917 loadp JSCell::m_structureID[t0], t1 918 loadp CodeBlock[cfr], t0 919 loadp CodeBlock::m_globalObject[t0], t0 920 cpneq Structure::m_globalObject[t1], t0, t1 921 jmp .opNeqNullNotImmediate 922.opNeqNullImmediate: 923 cineq t1, NullTag, t2 924 cineq t1, UndefinedTag, t1 925 andi t2, t1 926.opNeqNullNotImmediate: 927 storei BooleanTag, TagOffset[cfr, t3, 8] 928 storei t1, PayloadOffset[cfr, t3, 8] 929 dispatch(3) 930 931 932macro strictEq(equalityOperation, slowPath) 933 loadi 12[PC], t2 934 loadi 8[PC], t0 935 loadConstantOrVariable(t2, t3, t1) 936 loadConstantOrVariable2Reg(t0, t2, t0) 937 bineq t2, t3, .slow 938 bib t2, LowestTag, .slow 939 bineq t2, CellTag, .notString 940 bbneq JSCell::m_type[t0], StringType, .notString 941 bbeq JSCell::m_type[t1], StringType, .slow 942.notString: 943 loadi 4[PC], t2 944 equalityOperation(t0, t1, t0) 945 storei BooleanTag, TagOffset[cfr, t2, 8] 946 storei t0, PayloadOffset[cfr, t2, 8] 947 dispatch(4) 948 949.slow: 950 callSlowPath(slowPath) 951 dispatch(4) 952end 953 954_llint_op_stricteq: 955 traceExecution() 956 strictEq(macro (left, right, result) cieq left, right, result end, _slow_path_stricteq) 957 958 959_llint_op_nstricteq: 960 traceExecution() 961 strictEq(macro (left, right, result) cineq left, right, result end, _slow_path_nstricteq) 962 963 964_llint_op_inc: 965 traceExecution() 966 loadi 4[PC], t0 967 bineq TagOffset[cfr, t0, 8], Int32Tag, .opIncSlow 968 loadi PayloadOffset[cfr, t0, 8], t1 969 baddio 1, t1, .opIncSlow 970 storei t1, PayloadOffset[cfr, t0, 8] 971 dispatch(2) 972 973.opIncSlow: 974 callSlowPath(_slow_path_inc) 975 dispatch(2) 976 977 978_llint_op_dec: 979 traceExecution() 980 loadi 4[PC], t0 981 bineq TagOffset[cfr, t0, 8], Int32Tag, .opDecSlow 982 loadi PayloadOffset[cfr, t0, 8], t1 983 bsubio 1, t1, .opDecSlow 984 storei t1, PayloadOffset[cfr, t0, 8] 985 dispatch(2) 986 987.opDecSlow: 988 callSlowPath(_slow_path_dec) 989 dispatch(2) 990 991 992_llint_op_to_number: 993 traceExecution() 994 loadi 8[PC], t0 995 loadi 4[PC], t1 996 loadConstantOrVariable(t0, t2, t3) 997 bieq t2, Int32Tag, .opToNumberIsInt 998 biaeq t2, LowestTag, .opToNumberSlow 999.opToNumberIsInt: 1000 storei t2, TagOffset[cfr, t1, 8] 1001 storei t3, PayloadOffset[cfr, t1, 8] 1002 dispatch(3) 1003 1004.opToNumberSlow: 1005 callSlowPath(_slow_path_to_number) 1006 dispatch(3) 1007 1008 1009_llint_op_negate: 1010 traceExecution() 1011 loadi 8[PC], t0 1012 loadi 4[PC], t3 1013 loadConstantOrVariable(t0, t1, t2) 1014 bineq t1, Int32Tag, .opNegateSrcNotInt 1015 btiz t2, 0x7fffffff, .opNegateSlow 1016 negi t2 1017 storei Int32Tag, TagOffset[cfr, t3, 8] 1018 storei t2, PayloadOffset[cfr, t3, 8] 1019 dispatch(3) 1020.opNegateSrcNotInt: 1021 bia t1, LowestTag, .opNegateSlow 1022 xori 0x80000000, t1 1023 storei t1, TagOffset[cfr, t3, 8] 1024 storei t2, PayloadOffset[cfr, t3, 8] 1025 dispatch(3) 1026 1027.opNegateSlow: 1028 callSlowPath(_slow_path_negate) 1029 dispatch(3) 1030 1031 1032macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath) 1033 loadi 12[PC], t2 1034 loadi 8[PC], t0 1035 loadConstantOrVariable(t2, t3, t1) 1036 loadConstantOrVariable2Reg(t0, t2, t0) 1037 bineq t2, Int32Tag, .op1NotInt 1038 bineq t3, Int32Tag, .op2NotInt 1039 loadi 4[PC], t2 1040 integerOperationAndStore(t3, t1, t0, .slow, t2) 1041 dispatch(5) 1042 1043.op1NotInt: 1044 # First operand is definitely not an int, the second operand could be anything. 1045 bia t2, LowestTag, .slow 1046 bib t3, LowestTag, .op1NotIntOp2Double 1047 bineq t3, Int32Tag, .slow 1048 ci2d t1, ft1 1049 jmp .op1NotIntReady 1050.op1NotIntOp2Double: 1051 fii2d t1, t3, ft1 1052.op1NotIntReady: 1053 loadi 4[PC], t1 1054 fii2d t0, t2, ft0 1055 doubleOperation(ft1, ft0) 1056 stored ft0, [cfr, t1, 8] 1057 dispatch(5) 1058 1059.op2NotInt: 1060 # First operand is definitely an int, the second operand is definitely not. 1061 loadi 4[PC], t2 1062 bia t3, LowestTag, .slow 1063 ci2d t0, ft0 1064 fii2d t1, t3, ft1 1065 doubleOperation(ft1, ft0) 1066 stored ft0, [cfr, t2, 8] 1067 dispatch(5) 1068 1069.slow: 1070 callSlowPath(slowPath) 1071 dispatch(5) 1072end 1073 1074macro binaryOp(integerOperation, doubleOperation, slowPath) 1075 binaryOpCustomStore( 1076 macro (int32Tag, left, right, slow, index) 1077 integerOperation(left, right, slow) 1078 storei int32Tag, TagOffset[cfr, index, 8] 1079 storei right, PayloadOffset[cfr, index, 8] 1080 end, 1081 doubleOperation, slowPath) 1082end 1083 1084_llint_op_add: 1085 traceExecution() 1086 binaryOp( 1087 macro (left, right, slow) baddio left, right, slow end, 1088 macro (left, right) addd left, right end, 1089 _slow_path_add) 1090 1091 1092_llint_op_mul: 1093 traceExecution() 1094 binaryOpCustomStore( 1095 macro (int32Tag, left, right, slow, index) 1096 const scratch = int32Tag # We know that we can reuse the int32Tag register since it has a constant. 1097 move right, scratch 1098 bmulio left, scratch, slow 1099 btinz scratch, .done 1100 bilt left, 0, slow 1101 bilt right, 0, slow 1102 .done: 1103 storei Int32Tag, TagOffset[cfr, index, 8] 1104 storei scratch, PayloadOffset[cfr, index, 8] 1105 end, 1106 macro (left, right) muld left, right end, 1107 _slow_path_mul) 1108 1109 1110_llint_op_sub: 1111 traceExecution() 1112 binaryOp( 1113 macro (left, right, slow) bsubio left, right, slow end, 1114 macro (left, right) subd left, right end, 1115 _slow_path_sub) 1116 1117 1118_llint_op_div: 1119 traceExecution() 1120 binaryOpCustomStore( 1121 macro (int32Tag, left, right, slow, index) 1122 ci2d left, ft0 1123 ci2d right, ft1 1124 divd ft0, ft1 1125 bcd2i ft1, right, .notInt 1126 storei int32Tag, TagOffset[cfr, index, 8] 1127 storei right, PayloadOffset[cfr, index, 8] 1128 jmp .done 1129 .notInt: 1130 stored ft1, [cfr, index, 8] 1131 .done: 1132 end, 1133 macro (left, right) divd left, right end, 1134 _slow_path_div) 1135 1136 1137macro bitOp(operation, slowPath, advance) 1138 loadi 12[PC], t2 1139 loadi 8[PC], t0 1140 loadConstantOrVariable(t2, t3, t1) 1141 loadConstantOrVariable2Reg(t0, t2, t0) 1142 bineq t3, Int32Tag, .slow 1143 bineq t2, Int32Tag, .slow 1144 loadi 4[PC], t2 1145 operation(t1, t0) 1146 storei t3, TagOffset[cfr, t2, 8] 1147 storei t0, PayloadOffset[cfr, t2, 8] 1148 dispatch(advance) 1149 1150.slow: 1151 callSlowPath(slowPath) 1152 dispatch(advance) 1153end 1154 1155_llint_op_lshift: 1156 traceExecution() 1157 bitOp( 1158 macro (left, right) lshifti left, right end, 1159 _slow_path_lshift, 1160 4) 1161 1162 1163_llint_op_rshift: 1164 traceExecution() 1165 bitOp( 1166 macro (left, right) rshifti left, right end, 1167 _slow_path_rshift, 1168 4) 1169 1170 1171_llint_op_urshift: 1172 traceExecution() 1173 bitOp( 1174 macro (left, right) urshifti left, right end, 1175 _slow_path_urshift, 1176 4) 1177 1178 1179_llint_op_unsigned: 1180 traceExecution() 1181 loadi 4[PC], t0 1182 loadi 8[PC], t1 1183 loadConstantOrVariablePayload(t1, Int32Tag, t2, .opUnsignedSlow) 1184 bilt t2, 0, .opUnsignedSlow 1185 storei t2, PayloadOffset[cfr, t0, 8] 1186 storei Int32Tag, TagOffset[cfr, t0, 8] 1187 dispatch(3) 1188.opUnsignedSlow: 1189 callSlowPath(_slow_path_unsigned) 1190 dispatch(3) 1191 1192 1193_llint_op_bitand: 1194 traceExecution() 1195 bitOp( 1196 macro (left, right) andi left, right end, 1197 _slow_path_bitand, 1198 5) 1199 1200 1201_llint_op_bitxor: 1202 traceExecution() 1203 bitOp( 1204 macro (left, right) xori left, right end, 1205 _slow_path_bitxor, 1206 5) 1207 1208 1209_llint_op_bitor: 1210 traceExecution() 1211 bitOp( 1212 macro (left, right) ori left, right end, 1213 _slow_path_bitor, 1214 5) 1215 1216 1217_llint_op_check_has_instance: 1218 traceExecution() 1219 loadi 12[PC], t1 1220 loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow) 1221 btbz JSCell::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow 1222 dispatch(5) 1223 1224.opCheckHasInstanceSlow: 1225 callSlowPath(_llint_slow_path_check_has_instance) 1226 dispatch(0) 1227 1228 1229_llint_op_instanceof: 1230 traceExecution() 1231 # Actually do the work. 1232 loadi 12[PC], t0 1233 loadi 4[PC], t3 1234 loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow) 1235 bbb JSCell::m_type[t1], ObjectType, .opInstanceofSlow 1236 loadi 8[PC], t0 1237 loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow) 1238 1239 # Register state: t1 = prototype, t2 = value 1240 move 1, t0 1241.opInstanceofLoop: 1242 loadp JSCell::m_structureID[t2], t2 1243 loadi Structure::m_prototype + PayloadOffset[t2], t2 1244 bpeq t2, t1, .opInstanceofDone 1245 btinz t2, .opInstanceofLoop 1246 1247 move 0, t0 1248.opInstanceofDone: 1249 storei BooleanTag, TagOffset[cfr, t3, 8] 1250 storei t0, PayloadOffset[cfr, t3, 8] 1251 dispatch(4) 1252 1253.opInstanceofSlow: 1254 callSlowPath(_llint_slow_path_instanceof) 1255 dispatch(4) 1256 1257 1258_llint_op_is_undefined: 1259 traceExecution() 1260 loadi 8[PC], t1 1261 loadi 4[PC], t0 1262 loadConstantOrVariable(t1, t2, t3) 1263 storei BooleanTag, TagOffset[cfr, t0, 8] 1264 bieq t2, CellTag, .opIsUndefinedCell 1265 cieq t2, UndefinedTag, t3 1266 storei t3, PayloadOffset[cfr, t0, 8] 1267 dispatch(3) 1268.opIsUndefinedCell: 1269 btbnz JSCell::m_flags[t3], MasqueradesAsUndefined, .opIsUndefinedMasqueradesAsUndefined 1270 move 0, t1 1271 storei t1, PayloadOffset[cfr, t0, 8] 1272 dispatch(3) 1273.opIsUndefinedMasqueradesAsUndefined: 1274 loadp JSCell::m_structureID[t3], t1 1275 loadp CodeBlock[cfr], t3 1276 loadp CodeBlock::m_globalObject[t3], t3 1277 cpeq Structure::m_globalObject[t1], t3, t1 1278 storei t1, PayloadOffset[cfr, t0, 8] 1279 dispatch(3) 1280 1281 1282_llint_op_is_boolean: 1283 traceExecution() 1284 loadi 8[PC], t1 1285 loadi 4[PC], t2 1286 loadConstantOrVariableTag(t1, t0) 1287 cieq t0, BooleanTag, t0 1288 storei BooleanTag, TagOffset[cfr, t2, 8] 1289 storei t0, PayloadOffset[cfr, t2, 8] 1290 dispatch(3) 1291 1292 1293_llint_op_is_number: 1294 traceExecution() 1295 loadi 8[PC], t1 1296 loadi 4[PC], t2 1297 loadConstantOrVariableTag(t1, t0) 1298 storei BooleanTag, TagOffset[cfr, t2, 8] 1299 addi 1, t0 1300 cib t0, LowestTag + 1, t1 1301 storei t1, PayloadOffset[cfr, t2, 8] 1302 dispatch(3) 1303 1304 1305_llint_op_is_string: 1306 traceExecution() 1307 loadi 8[PC], t1 1308 loadi 4[PC], t2 1309 loadConstantOrVariable(t1, t0, t3) 1310 storei BooleanTag, TagOffset[cfr, t2, 8] 1311 bineq t0, CellTag, .opIsStringNotCell 1312 cbeq JSCell::m_type[t3], StringType, t1 1313 storei t1, PayloadOffset[cfr, t2, 8] 1314 dispatch(3) 1315.opIsStringNotCell: 1316 storep 0, PayloadOffset[cfr, t2, 8] 1317 dispatch(3) 1318 1319 1320macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffset, objectAndStorage, tag, payload) 1321 assert(macro (ok) bigteq propertyOffset, firstOutOfLineOffset, ok end) 1322 negi propertyOffset 1323 loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage 1324 loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag 1325 loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload 1326end 1327 1328macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload) 1329 bilt propertyOffset, firstOutOfLineOffset, .isInline 1330 loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage 1331 negi propertyOffset 1332 jmp .ready 1333.isInline: 1334 addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage 1335.ready: 1336 loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag 1337 loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload 1338end 1339 1340macro storePropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, tag, payload) 1341 bilt propertyOffsetAsInt, firstOutOfLineOffset, .isInline 1342 loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage 1343 negi propertyOffsetAsInt 1344 jmp .ready 1345.isInline: 1346 addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage 1347.ready: 1348 storei tag, TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8] 1349 storei payload, PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8] 1350end 1351 1352 1353_llint_op_init_global_const: 1354 traceExecution() 1355 writeBarrierOnGlobalObject(2) 1356 loadi 8[PC], t1 1357 loadi 4[PC], t0 1358 loadConstantOrVariable(t1, t2, t3) 1359 storei t2, TagOffset[t0] 1360 storei t3, PayloadOffset[t0] 1361 dispatch(5) 1362 1363 1364# We only do monomorphic get_by_id caching for now, and we do not modify the 1365# opcode. We do, however, allow for the cache to change anytime if fails, since 1366# ping-ponging is free. At best we get lucky and the get_by_id will continue 1367# to take fast path on the new cache. At worst we take slow path, which is what 1368# we would have been doing anyway. 1369 1370macro getById(getPropertyStorage) 1371 traceExecution() 1372 loadi 8[PC], t0 1373 loadi 16[PC], t1 1374 loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow) 1375 loadi 20[PC], t2 1376 getPropertyStorage( 1377 t3, 1378 t0, 1379 macro (propertyStorage, scratch) 1380 bpneq JSCell::m_structureID[t3], t1, .opGetByIdSlow 1381 loadi 4[PC], t1 1382 loadi TagOffset[propertyStorage, t2], scratch 1383 loadi PayloadOffset[propertyStorage, t2], t2 1384 storei scratch, TagOffset[cfr, t1, 8] 1385 storei t2, PayloadOffset[cfr, t1, 8] 1386 valueProfile(scratch, t2, 32, t1) 1387 dispatch(9) 1388 end) 1389 1390 .opGetByIdSlow: 1391 callSlowPath(_llint_slow_path_get_by_id) 1392 dispatch(9) 1393end 1394 1395_llint_op_get_by_id: 1396 getById(withInlineStorage) 1397 1398 1399_llint_op_get_by_id_out_of_line: 1400 getById(withOutOfLineStorage) 1401 1402 1403_llint_op_get_array_length: 1404 traceExecution() 1405 loadi 8[PC], t0 1406 loadp 16[PC], t1 1407 loadConstantOrVariablePayload(t0, CellTag, t3, .opGetArrayLengthSlow) 1408 move t3, t2 1409 arrayProfile(t2, t1, t0) 1410 btiz t2, IsArray, .opGetArrayLengthSlow 1411 btiz t2, IndexingShapeMask, .opGetArrayLengthSlow 1412 loadi 4[PC], t1 1413 loadp JSObject::m_butterfly[t3], t0 1414 loadi -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], t0 1415 bilt t0, 0, .opGetArrayLengthSlow 1416 valueProfile(Int32Tag, t0, 32, t2) 1417 storep t0, PayloadOffset[cfr, t1, 8] 1418 storep Int32Tag, TagOffset[cfr, t1, 8] 1419 dispatch(9) 1420 1421.opGetArrayLengthSlow: 1422 callSlowPath(_llint_slow_path_get_by_id) 1423 dispatch(9) 1424 1425 1426_llint_op_get_arguments_length: 1427 traceExecution() 1428 loadi 8[PC], t0 1429 loadi 4[PC], t1 1430 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow 1431 loadi ArgumentCount + PayloadOffset[cfr], t2 1432 subi 1, t2 1433 storei Int32Tag, TagOffset[cfr, t1, 8] 1434 storei t2, PayloadOffset[cfr, t1, 8] 1435 dispatch(4) 1436 1437.opGetArgumentsLengthSlow: 1438 callSlowPath(_llint_slow_path_get_arguments_length) 1439 dispatch(4) 1440 1441 1442macro putById(getPropertyStorage) 1443 traceExecution() 1444 writeBarrierOnOperands(1, 3) 1445 loadi 4[PC], t3 1446 loadi 16[PC], t1 1447 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow) 1448 loadi 12[PC], t2 1449 getPropertyStorage( 1450 t0, 1451 t3, 1452 macro (propertyStorage, scratch) 1453 bpneq JSCell::m_structureID[t0], t1, .opPutByIdSlow 1454 loadi 20[PC], t1 1455 loadConstantOrVariable2Reg(t2, scratch, t2) 1456 storei scratch, TagOffset[propertyStorage, t1] 1457 storei t2, PayloadOffset[propertyStorage, t1] 1458 dispatch(9) 1459 end) 1460 1461 .opPutByIdSlow: 1462 callSlowPath(_llint_slow_path_put_by_id) 1463 dispatch(9) 1464end 1465 1466_llint_op_put_by_id: 1467 putById(withInlineStorage) 1468 1469 1470_llint_op_put_by_id_out_of_line: 1471 putById(withOutOfLineStorage) 1472 1473 1474macro putByIdTransition(additionalChecks, getPropertyStorage) 1475 traceExecution() 1476 writeBarrierOnOperand(1) 1477 loadi 4[PC], t3 1478 loadi 16[PC], t1 1479 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow) 1480 loadi 12[PC], t2 1481 bpneq JSCell::m_structureID[t0], t1, .opPutByIdSlow 1482 additionalChecks(t1, t3, .opPutByIdSlow) 1483 loadi 20[PC], t1 1484 getPropertyStorage( 1485 t0, 1486 t3, 1487 macro (propertyStorage, scratch) 1488 addp t1, propertyStorage, t3 1489 loadConstantOrVariable2Reg(t2, t1, t2) 1490 storei t1, TagOffset[t3] 1491 loadi 24[PC], t1 1492 storei t2, PayloadOffset[t3] 1493 storep t1, JSCell::m_structureID[t0] 1494 dispatch(9) 1495 end) 1496 1497 .opPutByIdSlow: 1498 callSlowPath(_llint_slow_path_put_by_id) 1499 dispatch(9) 1500end 1501 1502macro noAdditionalChecks(oldStructure, scratch, slowPath) 1503end 1504 1505macro structureChainChecks(oldStructure, scratch, slowPath) 1506 const protoCell = oldStructure # Reusing the oldStructure register for the proto 1507 1508 loadp 28[PC], scratch 1509 assert(macro (ok) btpnz scratch, ok end) 1510 loadp StructureChain::m_vector[scratch], scratch 1511 assert(macro (ok) btpnz scratch, ok end) 1512 bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done 1513.loop: 1514 loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell 1515 loadp JSCell::m_structureID[protoCell], oldStructure 1516 bpneq oldStructure, [scratch], slowPath 1517 addp 4, scratch 1518 bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop 1519.done: 1520end 1521 1522_llint_op_put_by_id_transition_direct: 1523 putByIdTransition(noAdditionalChecks, withInlineStorage) 1524 1525 1526_llint_op_put_by_id_transition_direct_out_of_line: 1527 putByIdTransition(noAdditionalChecks, withOutOfLineStorage) 1528 1529 1530_llint_op_put_by_id_transition_normal: 1531 putByIdTransition(structureChainChecks, withInlineStorage) 1532 1533 1534_llint_op_put_by_id_transition_normal_out_of_line: 1535 putByIdTransition(structureChainChecks, withOutOfLineStorage) 1536 1537 1538_llint_op_get_by_val: 1539 traceExecution() 1540 loadi 8[PC], t2 1541 loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow) 1542 move t0, t2 1543 loadp 16[PC], t3 1544 arrayProfile(t2, t3, t1) 1545 loadi 12[PC], t3 1546 loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow) 1547 loadp JSObject::m_butterfly[t0], t3 1548 andi IndexingShapeMask, t2 1549 bieq t2, Int32Shape, .opGetByValIsContiguous 1550 bineq t2, ContiguousShape, .opGetByValNotContiguous 1551.opGetByValIsContiguous: 1552 1553 biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds 1554 loadi TagOffset[t3, t1, 8], t2 1555 loadi PayloadOffset[t3, t1, 8], t1 1556 jmp .opGetByValDone 1557 1558.opGetByValNotContiguous: 1559 bineq t2, DoubleShape, .opGetByValNotDouble 1560 biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds 1561 loadd [t3, t1, 8], ft0 1562 bdnequn ft0, ft0, .opGetByValSlow 1563 # FIXME: This could be massively optimized. 1564 fd2ii ft0, t1, t2 1565 loadi 4[PC], t0 1566 jmp .opGetByValNotEmpty 1567 1568.opGetByValNotDouble: 1569 subi ArrayStorageShape, t2 1570 bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow 1571 biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t3], .opGetByValOutOfBounds 1572 loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2 1573 loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1 1574 1575.opGetByValDone: 1576 loadi 4[PC], t0 1577 bieq t2, EmptyValueTag, .opGetByValOutOfBounds 1578.opGetByValNotEmpty: 1579 storei t2, TagOffset[cfr, t0, 8] 1580 storei t1, PayloadOffset[cfr, t0, 8] 1581 valueProfile(t2, t1, 20, t0) 1582 dispatch(6) 1583 1584.opGetByValOutOfBounds: 1585 loadpFromInstruction(4, t0) 1586 storeb 1, ArrayProfile::m_outOfBounds[t0] 1587.opGetByValSlow: 1588 callSlowPath(_llint_slow_path_get_by_val) 1589 dispatch(6) 1590 1591 1592_llint_op_get_argument_by_val: 1593 # FIXME: At some point we should array profile this. Right now it isn't necessary 1594 # since the DFG will never turn a get_argument_by_val into a GetByVal. 1595 traceExecution() 1596 loadi 8[PC], t0 1597 loadi 12[PC], t1 1598 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow 1599 loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow) 1600 addi 1, t2 1601 loadi ArgumentCount + PayloadOffset[cfr], t1 1602 biaeq t2, t1, .opGetArgumentByValSlow 1603 loadi 4[PC], t3 1604 loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0 1605 loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1 1606 storei t0, TagOffset[cfr, t3, 8] 1607 storei t1, PayloadOffset[cfr, t3, 8] 1608 valueProfile(t0, t1, 20, t2) 1609 dispatch(6) 1610 1611.opGetArgumentByValSlow: 1612 callSlowPath(_llint_slow_path_get_argument_by_val) 1613 dispatch(6) 1614 1615 1616_llint_op_get_by_pname: 1617 traceExecution() 1618 loadi 12[PC], t0 1619 loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow) 1620 loadi 16[PC], t0 1621 bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow 1622 loadi 8[PC], t0 1623 loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow) 1624 loadi 20[PC], t0 1625 loadi PayloadOffset[cfr, t0, 8], t3 1626 loadp JSCell::m_structureID[t2], t0 1627 bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow 1628 loadi 24[PC], t0 1629 loadi [cfr, t0, 8], t0 1630 subi 1, t0 1631 biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow 1632 bilt t0, JSPropertyNameIterator::m_cachedStructureInlineCapacity[t3], .opGetByPnameInlineProperty 1633 addi firstOutOfLineOffset, t0 1634 subi JSPropertyNameIterator::m_cachedStructureInlineCapacity[t3], t0 1635.opGetByPnameInlineProperty: 1636 loadPropertyAtVariableOffset(t0, t2, t1, t3) 1637 loadi 4[PC], t0 1638 storei t1, TagOffset[cfr, t0, 8] 1639 storei t3, PayloadOffset[cfr, t0, 8] 1640 dispatch(7) 1641 1642.opGetByPnameSlow: 1643 callSlowPath(_llint_slow_path_get_by_pname) 1644 dispatch(7) 1645 1646 1647macro contiguousPutByVal(storeCallback) 1648 biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds 1649.storeResult: 1650 loadi 12[PC], t2 1651 storeCallback(t2, t1, t0, t3) 1652 dispatch(5) 1653 1654.outOfBounds: 1655 biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds 1656 loadp 16[PC], t2 1657 storeb 1, ArrayProfile::m_mayStoreToHole[t2] 1658 addi 1, t3, t2 1659 storei t2, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0] 1660 jmp .storeResult 1661end 1662 1663macro putByVal(slowPath) 1664 traceExecution() 1665 writeBarrierOnOperands(1, 3) 1666 loadi 4[PC], t0 1667 loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow) 1668 move t1, t2 1669 loadp 16[PC], t3 1670 arrayProfile(t2, t3, t0) 1671 loadi 8[PC], t0 1672 loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow) 1673 loadp JSObject::m_butterfly[t1], t0 1674 andi IndexingShapeMask, t2 1675 bineq t2, Int32Shape, .opPutByValNotInt32 1676 contiguousPutByVal( 1677 macro (operand, scratch, base, index) 1678 loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow) 1679 storei Int32Tag, TagOffset[base, index, 8] 1680 storei scratch, PayloadOffset[base, index, 8] 1681 end) 1682 1683.opPutByValNotInt32: 1684 bineq t2, DoubleShape, .opPutByValNotDouble 1685 contiguousPutByVal( 1686 macro (operand, scratch, base, index) 1687 const tag = scratch 1688 const payload = operand 1689 loadConstantOrVariable2Reg(operand, tag, payload) 1690 bineq tag, Int32Tag, .notInt 1691 ci2d payload, ft0 1692 jmp .ready 1693 .notInt: 1694 fii2d payload, tag, ft0 1695 bdnequn ft0, ft0, .opPutByValSlow 1696 .ready: 1697 stored ft0, [base, index, 8] 1698 end) 1699 1700.opPutByValNotDouble: 1701 bineq t2, ContiguousShape, .opPutByValNotContiguous 1702 contiguousPutByVal( 1703 macro (operand, scratch, base, index) 1704 const tag = scratch 1705 const payload = operand 1706 loadConstantOrVariable2Reg(operand, tag, payload) 1707 storei tag, TagOffset[base, index, 8] 1708 storei payload, PayloadOffset[base, index, 8] 1709 end) 1710 1711.opPutByValNotContiguous: 1712 bineq t2, ArrayStorageShape, .opPutByValSlow 1713 biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds 1714 bieq ArrayStorage::m_vector + TagOffset[t0, t3, 8], EmptyValueTag, .opPutByValArrayStorageEmpty 1715.opPutByValArrayStorageStoreResult: 1716 loadi 12[PC], t2 1717 loadConstantOrVariable2Reg(t2, t1, t2) 1718 storei t1, ArrayStorage::m_vector + TagOffset[t0, t3, 8] 1719 storei t2, ArrayStorage::m_vector + PayloadOffset[t0, t3, 8] 1720 dispatch(5) 1721 1722.opPutByValArrayStorageEmpty: 1723 loadp 16[PC], t1 1724 storeb 1, ArrayProfile::m_mayStoreToHole[t1] 1725 addi 1, ArrayStorage::m_numValuesInVector[t0] 1726 bib t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .opPutByValArrayStorageStoreResult 1727 addi 1, t3, t1 1728 storei t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0] 1729 jmp .opPutByValArrayStorageStoreResult 1730 1731.opPutByValOutOfBounds: 1732 loadpFromInstruction(4, t0) 1733 storeb 1, ArrayProfile::m_outOfBounds[t0] 1734.opPutByValSlow: 1735 callSlowPath(slowPath) 1736 dispatch(5) 1737end 1738 1739_llint_op_put_by_val: 1740 putByVal(_llint_slow_path_put_by_val) 1741 1742_llint_op_put_by_val_direct: 1743 putByVal(_llint_slow_path_put_by_val_direct) 1744 1745_llint_op_jmp: 1746 traceExecution() 1747 dispatchBranch(4[PC]) 1748 1749 1750macro jumpTrueOrFalse(conditionOp, slow) 1751 loadi 4[PC], t1 1752 loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow) 1753 conditionOp(t0, .target) 1754 dispatch(3) 1755 1756.target: 1757 dispatchBranch(8[PC]) 1758 1759.slow: 1760 callSlowPath(slow) 1761 dispatch(0) 1762end 1763 1764 1765macro equalNull(cellHandler, immediateHandler) 1766 loadi 4[PC], t0 1767 assertNotConstant(t0) 1768 loadi TagOffset[cfr, t0, 8], t1 1769 loadi PayloadOffset[cfr, t0, 8], t0 1770 bineq t1, CellTag, .immediate 1771 loadp JSCell::m_structureID[t0], t2 1772 cellHandler(t2, JSCell::m_flags[t0], .target) 1773 dispatch(3) 1774 1775.target: 1776 dispatchBranch(8[PC]) 1777 1778.immediate: 1779 ori 1, t1 1780 immediateHandler(t1, .target) 1781 dispatch(3) 1782end 1783 1784_llint_op_jeq_null: 1785 traceExecution() 1786 equalNull( 1787 macro (structure, value, target) 1788 btbz value, MasqueradesAsUndefined, .opJeqNullNotMasqueradesAsUndefined 1789 loadp CodeBlock[cfr], t0 1790 loadp CodeBlock::m_globalObject[t0], t0 1791 bpeq Structure::m_globalObject[structure], t0, target 1792.opJeqNullNotMasqueradesAsUndefined: 1793 end, 1794 macro (value, target) bieq value, NullTag, target end) 1795 1796 1797_llint_op_jneq_null: 1798 traceExecution() 1799 equalNull( 1800 macro (structure, value, target) 1801 btbz value, MasqueradesAsUndefined, target 1802 loadp CodeBlock[cfr], t0 1803 loadp CodeBlock::m_globalObject[t0], t0 1804 bpneq Structure::m_globalObject[structure], t0, target 1805 end, 1806 macro (value, target) bineq value, NullTag, target end) 1807 1808 1809_llint_op_jneq_ptr: 1810 traceExecution() 1811 loadi 4[PC], t0 1812 loadi 8[PC], t1 1813 loadp CodeBlock[cfr], t2 1814 loadp CodeBlock::m_globalObject[t2], t2 1815 bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch 1816 loadp JSGlobalObject::m_specialPointers[t2, t1, 4], t1 1817 bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough 1818.opJneqPtrBranch: 1819 dispatchBranch(12[PC]) 1820.opJneqPtrFallThrough: 1821 dispatch(4) 1822 1823 1824macro compare(integerCompare, doubleCompare, slowPath) 1825 loadi 4[PC], t2 1826 loadi 8[PC], t3 1827 loadConstantOrVariable(t2, t0, t1) 1828 loadConstantOrVariable2Reg(t3, t2, t3) 1829 bineq t0, Int32Tag, .op1NotInt 1830 bineq t2, Int32Tag, .op2NotInt 1831 integerCompare(t1, t3, .jumpTarget) 1832 dispatch(4) 1833 1834.op1NotInt: 1835 bia t0, LowestTag, .slow 1836 bib t2, LowestTag, .op1NotIntOp2Double 1837 bineq t2, Int32Tag, .slow 1838 ci2d t3, ft1 1839 jmp .op1NotIntReady 1840.op1NotIntOp2Double: 1841 fii2d t3, t2, ft1 1842.op1NotIntReady: 1843 fii2d t1, t0, ft0 1844 doubleCompare(ft0, ft1, .jumpTarget) 1845 dispatch(4) 1846 1847.op2NotInt: 1848 ci2d t1, ft0 1849 bia t2, LowestTag, .slow 1850 fii2d t3, t2, ft1 1851 doubleCompare(ft0, ft1, .jumpTarget) 1852 dispatch(4) 1853 1854.jumpTarget: 1855 dispatchBranch(12[PC]) 1856 1857.slow: 1858 callSlowPath(slowPath) 1859 dispatch(0) 1860end 1861 1862 1863_llint_op_switch_imm: 1864 traceExecution() 1865 loadi 12[PC], t2 1866 loadi 4[PC], t3 1867 loadConstantOrVariable(t2, t1, t0) 1868 loadp CodeBlock[cfr], t2 1869 loadp CodeBlock::m_rareData[t2], t2 1870 muli sizeof SimpleJumpTable, t3 # FIXME: would be nice to peephole this! 1871 loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2 1872 addp t3, t2 1873 bineq t1, Int32Tag, .opSwitchImmNotInt 1874 subi SimpleJumpTable::min[t2], t0 1875 biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough 1876 loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3 1877 loadi [t3, t0, 4], t1 1878 btiz t1, .opSwitchImmFallThrough 1879 dispatchBranchWithOffset(t1) 1880 1881.opSwitchImmNotInt: 1882 bib t1, LowestTag, .opSwitchImmSlow # Go to slow path if it's a double. 1883.opSwitchImmFallThrough: 1884 dispatchBranch(8[PC]) 1885 1886.opSwitchImmSlow: 1887 callSlowPath(_llint_slow_path_switch_imm) 1888 dispatch(0) 1889 1890 1891_llint_op_switch_char: 1892 traceExecution() 1893 loadi 12[PC], t2 1894 loadi 4[PC], t3 1895 loadConstantOrVariable(t2, t1, t0) 1896 loadp CodeBlock[cfr], t2 1897 loadp CodeBlock::m_rareData[t2], t2 1898 muli sizeof SimpleJumpTable, t3 1899 loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2 1900 addp t3, t2 1901 bineq t1, CellTag, .opSwitchCharFallThrough 1902 bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough 1903 bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough 1904 loadp JSString::m_value[t0], t0 1905 btpz t0, .opSwitchOnRope 1906 loadp StringImpl::m_data8[t0], t1 1907 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit 1908 loadh [t1], t0 1909 jmp .opSwitchCharReady 1910.opSwitchChar8Bit: 1911 loadb [t1], t0 1912.opSwitchCharReady: 1913 subi SimpleJumpTable::min[t2], t0 1914 biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough 1915 loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2 1916 loadi [t2, t0, 4], t1 1917 btiz t1, .opSwitchCharFallThrough 1918 dispatchBranchWithOffset(t1) 1919 1920.opSwitchCharFallThrough: 1921 dispatchBranch(8[PC]) 1922 1923.opSwitchOnRope: 1924 callSlowPath(_llint_slow_path_switch_char) 1925 dispatch(0) 1926 1927 1928_llint_op_new_func: 1929 traceExecution() 1930 btiz 12[PC], .opNewFuncUnchecked 1931 loadi 4[PC], t1 1932 bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone 1933.opNewFuncUnchecked: 1934 callSlowPath(_llint_slow_path_new_func) 1935.opNewFuncDone: 1936 dispatch(4) 1937 1938 1939_llint_op_new_captured_func: 1940 traceExecution() 1941 callSlowPath(_slow_path_new_captured_func) 1942 dispatch(4) 1943 1944 1945macro arrayProfileForCall() 1946 loadi 16[PC], t3 1947 negi t3 1948 bineq ThisArgumentOffset + TagOffset[cfr, t3, 8], CellTag, .done 1949 loadi ThisArgumentOffset + PayloadOffset[cfr, t3, 8], t0 1950 loadp JSCell::m_structureID[t0], t0 1951 loadpFromInstruction(CallOpCodeSize - 2, t1) 1952 storep t0, ArrayProfile::m_lastSeenStructureID[t1] 1953.done: 1954end 1955 1956macro doCall(slowPath) 1957 loadi 8[PC], t0 1958 loadi 20[PC], t1 1959 loadp LLIntCallLinkInfo::callee[t1], t2 1960 loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow) 1961 bineq t3, t2, .opCallSlow 1962 loadi 16[PC], t3 1963 lshifti 3, t3 1964 negi t3 1965 addp cfr, t3 # t3 contains the new value of cfr 1966 loadp JSFunction::m_scope[t2], t0 1967 storei t2, Callee + PayloadOffset[t3] 1968 storei t0, ScopeChain + PayloadOffset[t3] 1969 loadi 12[PC], t2 1970 storei PC, ArgumentCount + TagOffset[cfr] 1971 storei t2, ArgumentCount + PayloadOffset[t3] 1972 storei CellTag, Callee + TagOffset[t3] 1973 storei CellTag, ScopeChain + TagOffset[t3] 1974 addp CallerFrameAndPCSize, t3 1975 callTargetFunction(t1, t3) 1976 1977.opCallSlow: 1978 slowPathForCall(slowPath) 1979end 1980 1981 1982_llint_op_tear_off_activation: 1983 traceExecution() 1984 loadi 4[PC], t0 1985 bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationNotCreated 1986 callSlowPath(_llint_slow_path_tear_off_activation) 1987.opTearOffActivationNotCreated: 1988 dispatch(2) 1989 1990 1991_llint_op_tear_off_arguments: 1992 traceExecution() 1993 loadi 4[PC], t0 1994 addi 1, t0 # Get the unmodifiedArgumentsRegister 1995 bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated 1996 callSlowPath(_llint_slow_path_tear_off_arguments) 1997.opTearOffArgumentsNotCreated: 1998 dispatch(3) 1999 2000 2001_llint_op_ret: 2002 traceExecution() 2003 checkSwitchToJITForEpilogue() 2004 loadi 4[PC], t2 2005 loadConstantOrVariable(t2, t1, t0) 2006 doReturn() 2007 2008 2009_llint_op_ret_object_or_this: 2010 traceExecution() 2011 checkSwitchToJITForEpilogue() 2012 loadi 4[PC], t2 2013 loadConstantOrVariable(t2, t1, t0) 2014 bineq t1, CellTag, .opRetObjectOrThisNotObject 2015 bbb JSCell::m_type[t0], ObjectType, .opRetObjectOrThisNotObject 2016 doReturn() 2017 2018.opRetObjectOrThisNotObject: 2019 loadi 8[PC], t2 2020 loadConstantOrVariable(t2, t1, t0) 2021 doReturn() 2022 2023 2024_llint_op_to_primitive: 2025 traceExecution() 2026 loadi 8[PC], t2 2027 loadi 4[PC], t3 2028 loadConstantOrVariable(t2, t1, t0) 2029 bineq t1, CellTag, .opToPrimitiveIsImm 2030 bbneq JSCell::m_type[t0], StringType, .opToPrimitiveSlowCase 2031.opToPrimitiveIsImm: 2032 storei t1, TagOffset[cfr, t3, 8] 2033 storei t0, PayloadOffset[cfr, t3, 8] 2034 dispatch(3) 2035 2036.opToPrimitiveSlowCase: 2037 callSlowPath(_slow_path_to_primitive) 2038 dispatch(3) 2039 2040 2041_llint_op_next_pname: 2042 traceExecution() 2043 loadi 12[PC], t1 2044 loadi 16[PC], t2 2045 loadi PayloadOffset[cfr, t1, 8], t0 2046 bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd 2047 loadi 20[PC], t2 2048 loadi PayloadOffset[cfr, t2, 8], t2 2049 loadp JSPropertyNameIterator::m_jsStrings[t2], t3 2050 loadi [t3, t0, 8], t3 2051 addi 1, t0 2052 storei t0, PayloadOffset[cfr, t1, 8] 2053 loadi 4[PC], t1 2054 storei CellTag, TagOffset[cfr, t1, 8] 2055 storei t3, PayloadOffset[cfr, t1, 8] 2056 loadi 8[PC], t3 2057 loadi PayloadOffset[cfr, t3, 8], t3 2058 loadp JSCell::m_structureID[t3], t1 2059 bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow 2060 loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0 2061 loadp StructureChain::m_vector[t0], t0 2062 btpz [t0], .opNextPnameTarget 2063.opNextPnameCheckPrototypeLoop: 2064 bieq Structure::m_prototype + TagOffset[t1], NullTag, .opNextPnameSlow 2065 loadp Structure::m_prototype + PayloadOffset[t1], t2 2066 loadp JSCell::m_structureID[t2], t1 2067 bpneq t1, [t0], .opNextPnameSlow 2068 addp 4, t0 2069 btpnz [t0], .opNextPnameCheckPrototypeLoop 2070.opNextPnameTarget: 2071 dispatchBranch(24[PC]) 2072 2073.opNextPnameEnd: 2074 dispatch(7) 2075 2076.opNextPnameSlow: 2077 callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target. 2078 dispatch(0) 2079 2080 2081_llint_op_catch: 2082 # This is where we end up from the JIT's throw trampoline (because the 2083 # machine code return address will be set to _llint_op_catch), and from 2084 # the interpreter's throw trampoline (see _llint_throw_trampoline). 2085 # The throwing code must have known that we were throwing to the interpreter, 2086 # and have set VM::targetInterpreterPCForThrow. 2087 loadp ScopeChain + PayloadOffset[cfr], t3 2088 andp MarkedBlockMask, t3 2089 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3 2090 loadp VM::callFrameForThrow[t3], cfr 2091 restoreStackPointerAfterCall() 2092 2093 loadi VM::targetInterpreterPCForThrow[t3], PC 2094 loadi VM::m_exception + PayloadOffset[t3], t0 2095 loadi VM::m_exception + TagOffset[t3], t1 2096 storei 0, VM::m_exception + PayloadOffset[t3] 2097 storei EmptyValueTag, VM::m_exception + TagOffset[t3] 2098 loadi 4[PC], t2 2099 storei t0, PayloadOffset[cfr, t2, 8] 2100 storei t1, TagOffset[cfr, t2, 8] 2101 traceExecution() # This needs to be here because we don't want to clobber t0, t1, t2, t3 above. 2102 dispatch(2) 2103 2104 2105# Gives you the scope in t0, while allowing you to optionally perform additional checks on the 2106# scopes as they are traversed. scopeCheck() is called with two arguments: the register 2107# holding the scope, and a register that can be used for scratch. Note that this does not 2108# use t3, so you can hold stuff in t3 if need be. 2109macro getDeBruijnScope(deBruijinIndexOperand, scopeCheck) 2110 loadp ScopeChain + PayloadOffset[cfr], t0 2111 loadi deBruijinIndexOperand, t2 2112 2113 btiz t2, .done 2114 2115 loadp CodeBlock[cfr], t1 2116 bineq CodeBlock::m_codeType[t1], FunctionCode, .loop 2117 btbz CodeBlock::m_needsActivation[t1], .loop 2118 2119 loadi CodeBlock::m_activationRegister[t1], t1 2120 2121 # Need to conditionally skip over one scope. 2122 bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation 2123 scopeCheck(t0, t1) 2124 loadp JSScope::m_next[t0], t0 2125.noActivation: 2126 subi 1, t2 2127 2128 btiz t2, .done 2129.loop: 2130 scopeCheck(t0, t1) 2131 loadp JSScope::m_next[t0], t0 2132 subi 1, t2 2133 btinz t2, .loop 2134 2135.done: 2136 2137end 2138 2139_llint_op_end: 2140 traceExecution() 2141 checkSwitchToJITForEpilogue() 2142 loadi 4[PC], t0 2143 assertNotConstant(t0) 2144 loadi TagOffset[cfr, t0, 8], t1 2145 loadi PayloadOffset[cfr, t0, 8], t0 2146 doReturn() 2147 2148 2149_llint_throw_from_slow_path_trampoline: 2150 callSlowPath(_llint_slow_path_handle_exception) 2151 2152 # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so 2153 # the throw target is not necessarily interpreted code, we come to here. 2154 # This essentially emulates the JIT's throwing protocol. 2155 loadp CodeBlock[cfr], t1 2156 loadp CodeBlock::m_vm[t1], t1 2157 jmp VM::targetMachinePCForThrow[t1] 2158 2159 2160_llint_throw_during_call_trampoline: 2161 preserveReturnAddressAfterCall(t2) 2162 jmp _llint_throw_from_slow_path_trampoline 2163 2164 2165macro nativeCallTrampoline(executableOffsetToFunction) 2166 2167 functionPrologue() 2168 storep 0, CodeBlock[cfr] 2169 loadp CallerFrame[cfr], t0 2170 loadi ScopeChain + PayloadOffset[t0], t1 2171 storei CellTag, ScopeChain + TagOffset[cfr] 2172 storei t1, ScopeChain + PayloadOffset[cfr] 2173 if X86 or X86_WIN 2174 subp 8, sp # align stack pointer 2175 andp MarkedBlockMask, t1 2176 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t3 2177 storep cfr, VM::topCallFrame[t3] 2178 move cfr, t2 # t2 = ecx 2179 storep t2, [sp] 2180 loadi Callee + PayloadOffset[cfr], t1 2181 loadp JSFunction::m_executable[t1], t1 2182 checkStackPointerAlignment(t3, 0xdead0001) 2183 call executableOffsetToFunction[t1] 2184 loadp ScopeChain[cfr], t3 2185 andp MarkedBlockMask, t3 2186 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3 2187 addp 8, sp 2188 elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP or MIPS or SH4 2189 subp 8, sp # align stack pointer 2190 # t1 already contains the ScopeChain. 2191 andp MarkedBlockMask, t1 2192 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1 2193 storep cfr, VM::topCallFrame[t1] 2194 if MIPS or SH4 2195 move cfr, a0 2196 else 2197 move cfr, t0 2198 end 2199 loadi Callee + PayloadOffset[cfr], t1 2200 loadp JSFunction::m_executable[t1], t1 2201 checkStackPointerAlignment(t3, 0xdead0001) 2202 if C_LOOP 2203 cloopCallNative executableOffsetToFunction[t1] 2204 else 2205 call executableOffsetToFunction[t1] 2206 end 2207 loadp ScopeChain[cfr], t3 2208 andp MarkedBlockMask, t3 2209 loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3 2210 addp 8, sp 2211 else 2212 error 2213 end 2214 2215 functionEpilogue() 2216 bineq VM::m_exception + TagOffset[t3], EmptyValueTag, .handleException 2217 ret 2218 2219.handleException: 2220 storep cfr, VM::topCallFrame[t3] 2221 restoreStackPointerAfterCall() 2222 jmp _llint_throw_from_slow_path_trampoline 2223end 2224 2225 2226macro getGlobalObject(dst) 2227 loadp CodeBlock[cfr], t0 2228 loadp CodeBlock::m_globalObject[t0], t0 2229 loadisFromInstruction(dst, t1) 2230 storei CellTag, TagOffset[cfr, t1, 8] 2231 storei t0, PayloadOffset[cfr, t1, 8] 2232end 2233 2234macro varInjectionCheck(slowPath) 2235 loadp CodeBlock[cfr], t0 2236 loadp CodeBlock::m_globalObject[t0], t0 2237 loadp JSGlobalObject::m_varInjectionWatchpoint[t0], t0 2238 bbeq WatchpointSet::m_state[t0], IsInvalidated, slowPath 2239end 2240 2241macro resolveScope() 2242 loadp CodeBlock[cfr], t0 2243 loadisFromInstruction(4, t2) 2244 btbz CodeBlock::m_needsActivation[t0], .resolveScopeAfterActivationCheck 2245 loadis CodeBlock::m_activationRegister[t0], t1 2246 btpz PayloadOffset[cfr, t1, 8], .resolveScopeAfterActivationCheck 2247 addi 1, t2 2248 2249.resolveScopeAfterActivationCheck: 2250 loadp ScopeChain[cfr], t0 2251 btiz t2, .resolveScopeLoopEnd 2252 2253.resolveScopeLoop: 2254 loadp JSScope::m_next[t0], t0 2255 subi 1, t2 2256 btinz t2, .resolveScopeLoop 2257 2258.resolveScopeLoopEnd: 2259 loadisFromInstruction(1, t1) 2260 storei CellTag, TagOffset[cfr, t1, 8] 2261 storei t0, PayloadOffset[cfr, t1, 8] 2262end 2263 2264 2265_llint_op_resolve_scope: 2266 traceExecution() 2267 loadisFromInstruction(3, t0) 2268 2269#rGlobalProperty: 2270 bineq t0, GlobalProperty, .rGlobalVar 2271 getGlobalObject(1) 2272 dispatch(6) 2273 2274.rGlobalVar: 2275 bineq t0, GlobalVar, .rClosureVar 2276 getGlobalObject(1) 2277 dispatch(6) 2278 2279.rClosureVar: 2280 bineq t0, ClosureVar, .rGlobalPropertyWithVarInjectionChecks 2281 resolveScope() 2282 dispatch(6) 2283 2284.rGlobalPropertyWithVarInjectionChecks: 2285 bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks 2286 varInjectionCheck(.rDynamic) 2287 getGlobalObject(1) 2288 dispatch(6) 2289 2290.rGlobalVarWithVarInjectionChecks: 2291 bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks 2292 varInjectionCheck(.rDynamic) 2293 getGlobalObject(1) 2294 dispatch(6) 2295 2296.rClosureVarWithVarInjectionChecks: 2297 bineq t0, ClosureVarWithVarInjectionChecks, .rDynamic 2298 varInjectionCheck(.rDynamic) 2299 resolveScope() 2300 dispatch(6) 2301 2302.rDynamic: 2303 callSlowPath(_llint_slow_path_resolve_scope) 2304 dispatch(6) 2305 2306 2307macro loadWithStructureCheck(operand, slowPath) 2308 loadisFromInstruction(operand, t0) 2309 loadp [cfr, t0, 8], t0 2310 loadpFromInstruction(5, t1) 2311 bpneq JSCell::m_structureID[t0], t1, slowPath 2312end 2313 2314macro getProperty() 2315 loadisFromInstruction(6, t3) 2316 loadPropertyAtVariableOffset(t3, t0, t1, t2) 2317 valueProfile(t1, t2, 28, t0) 2318 loadisFromInstruction(1, t0) 2319 storei t1, TagOffset[cfr, t0, 8] 2320 storei t2, PayloadOffset[cfr, t0, 8] 2321end 2322 2323macro getGlobalVar() 2324 loadpFromInstruction(6, t0) 2325 loadp TagOffset[t0], t1 2326 loadp PayloadOffset[t0], t2 2327 valueProfile(t1, t2, 28, t0) 2328 loadisFromInstruction(1, t0) 2329 storei t1, TagOffset[cfr, t0, 8] 2330 storei t2, PayloadOffset[cfr, t0, 8] 2331end 2332 2333macro getClosureVar() 2334 loadp JSVariableObject::m_registers[t0], t0 2335 loadisFromInstruction(6, t3) 2336 loadp TagOffset[t0, t3, 8], t1 2337 loadp PayloadOffset[t0, t3, 8], t2 2338 valueProfile(t1, t2, 28, t0) 2339 loadisFromInstruction(1, t0) 2340 storei t1, TagOffset[cfr, t0, 8] 2341 storei t2, PayloadOffset[cfr, t0, 8] 2342end 2343 2344_llint_op_get_from_scope: 2345 traceExecution() 2346 loadisFromInstruction(4, t0) 2347 andi ResolveModeMask, t0 2348 2349#gGlobalProperty: 2350 bineq t0, GlobalProperty, .gGlobalVar 2351 loadWithStructureCheck(2, .gDynamic) 2352 getProperty() 2353 dispatch(8) 2354 2355.gGlobalVar: 2356 bineq t0, GlobalVar, .gClosureVar 2357 getGlobalVar() 2358 dispatch(8) 2359 2360.gClosureVar: 2361 bineq t0, ClosureVar, .gGlobalPropertyWithVarInjectionChecks 2362 loadVariable(2, t2, t1, t0) 2363 getClosureVar() 2364 dispatch(8) 2365 2366.gGlobalPropertyWithVarInjectionChecks: 2367 bineq t0, GlobalPropertyWithVarInjectionChecks, .gGlobalVarWithVarInjectionChecks 2368 loadWithStructureCheck(2, .gDynamic) 2369 getProperty() 2370 dispatch(8) 2371 2372.gGlobalVarWithVarInjectionChecks: 2373 bineq t0, GlobalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks 2374 varInjectionCheck(.gDynamic) 2375 loadVariable(2, t2, t1, t0) 2376 getGlobalVar() 2377 dispatch(8) 2378 2379.gClosureVarWithVarInjectionChecks: 2380 bineq t0, ClosureVarWithVarInjectionChecks, .gDynamic 2381 varInjectionCheck(.gDynamic) 2382 loadVariable(2, t2, t1, t0) 2383 getClosureVar() 2384 dispatch(8) 2385 2386.gDynamic: 2387 callSlowPath(_llint_slow_path_get_from_scope) 2388 dispatch(8) 2389 2390 2391macro putProperty() 2392 loadisFromInstruction(3, t1) 2393 loadConstantOrVariable(t1, t2, t3) 2394 loadisFromInstruction(6, t1) 2395 storePropertyAtVariableOffset(t1, t0, t2, t3) 2396end 2397 2398macro putGlobalVar() 2399 loadisFromInstruction(3, t0) 2400 loadConstantOrVariable(t0, t1, t2) 2401 loadpFromInstruction(5, t3) 2402 notifyWrite(t3, t1, t2, t0, .pDynamic) 2403 loadpFromInstruction(6, t0) 2404 storei t1, TagOffset[t0] 2405 storei t2, PayloadOffset[t0] 2406end 2407 2408macro putClosureVar() 2409 loadisFromInstruction(3, t1) 2410 loadConstantOrVariable(t1, t2, t3) 2411 loadp JSVariableObject::m_registers[t0], t0 2412 loadisFromInstruction(6, t1) 2413 storei t2, TagOffset[t0, t1, 8] 2414 storei t3, PayloadOffset[t0, t1, 8] 2415end 2416 2417 2418_llint_op_put_to_scope: 2419 traceExecution() 2420 loadisFromInstruction(4, t0) 2421 andi ResolveModeMask, t0 2422 2423#pGlobalProperty: 2424 bineq t0, GlobalProperty, .pGlobalVar 2425 writeBarrierOnOperands(1, 3) 2426 loadWithStructureCheck(1, .pDynamic) 2427 putProperty() 2428 dispatch(7) 2429 2430.pGlobalVar: 2431 bineq t0, GlobalVar, .pClosureVar 2432 writeBarrierOnGlobalObject(3) 2433 putGlobalVar() 2434 dispatch(7) 2435 2436.pClosureVar: 2437 bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks 2438 writeBarrierOnOperands(1, 3) 2439 loadVariable(1, t2, t1, t0) 2440 putClosureVar() 2441 dispatch(7) 2442 2443.pGlobalPropertyWithVarInjectionChecks: 2444 bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks 2445 writeBarrierOnOperands(1, 3) 2446 loadWithStructureCheck(1, .pDynamic) 2447 putProperty() 2448 dispatch(7) 2449 2450.pGlobalVarWithVarInjectionChecks: 2451 bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks 2452 writeBarrierOnGlobalObject(3) 2453 varInjectionCheck(.pDynamic) 2454 putGlobalVar() 2455 dispatch(7) 2456 2457.pClosureVarWithVarInjectionChecks: 2458 bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic 2459 writeBarrierOnOperands(1, 3) 2460 varInjectionCheck(.pDynamic) 2461 loadVariable(1, t2, t1, t0) 2462 putClosureVar() 2463 dispatch(7) 2464 2465.pDynamic: 2466 callSlowPath(_llint_slow_path_put_to_scope) 2467 dispatch(7) 2468