1 # Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
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.
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.
24 # First come the common protocols that both interpreters use. Note that each
25 # of these must have an ASSERT() in LLIntData.cpp
27 # Work-around for the fact that the toolchain's awareness of armv7s results in
28 # a separate slab in the fat binary, yet the offlineasm doesn't know to expect
33 # These declarations must match interpreter/JSStack.h.
34 const CallFrameHeaderSize = 48
35 const ArgumentCount = -48
36 const CallerFrame = -40
38 const ScopeChain = -24
42 const ThisArgumentOffset = -CallFrameHeaderSize - 8
44 # Some register conventions.
46 # - Use a pair of registers to represent the PC: one register for the
47 # base of the stack, and one register for the index.
48 # - The PC base (or PB for short) should be stored in the csr. It will
49 # get clobbered on calls to other JS code, but will get saved on calls
51 # - C calls are still given the Instruction* rather than the PC index.
52 # This requires an add before the call, and a sub after.
55 const tagTypeNumber = csr1
58 macro loadisFromInstruction(offset, dest)
59 loadis offset * 8[PB, PC, 8], dest
62 macro loadpFromInstruction(offset, dest)
63 loadp offset * 8[PB, PC, 8], dest
66 macro storepToInstruction(value, offset)
67 storep value, offset * 8[PB, PC, 8]
72 macro loadisFromInstruction(offset, dest)
73 loadis offset * 4[PC], dest
76 macro loadpFromInstruction(offset, dest)
77 loadp offset * 4[PC], dest
81 # Constants for reasoning about value representation.
84 const PayloadOffset = 4
87 const PayloadOffset = 0
90 # Constant for reasoning about butterflies.
92 const IndexingShapeMask = 30
93 const NoIndexingShape = 0
95 const DoubleShape = 22
96 const ContiguousShape = 26
97 const ArrayStorageShape = 28
98 const SlowPutArrayStorageShape = 30
102 const ObjectType = 17
104 # Type flags constants.
105 const MasqueradesAsUndefined = 1
106 const ImplementsHasInstance = 2
107 const ImplementsDefaultHasInstance = 8
109 # Bytecode operand constants.
110 const FirstConstantRegisterIndex = 0x40000000
112 # Code type constants.
115 const FunctionCode = 2
117 # The interpreter steals the tag word of the argument count.
118 const LLIntReturnPC = ArgumentCount + TagOffset
121 const HashFlags8BitBuffer = 64
123 # Copied from PropertyOffset.h
124 const firstOutOfLineOffset = 100
126 # From ResolveOperations.h
127 const ResolveOperationFail = 0
128 const ResolveOperationSetBaseToUndefined = 1
129 const ResolveOperationReturnScopeAsBase = 2
130 const ResolveOperationSetBaseToScope = 3
131 const ResolveOperationSetBaseToGlobal = 4
132 const ResolveOperationGetAndReturnScopedVar = 5
133 const ResolveOperationGetAndReturnGlobalVar = 6
134 const ResolveOperationGetAndReturnGlobalVarWatchable = 7
135 const ResolveOperationSkipTopScopeNode = 8
136 const ResolveOperationSkipScopes = 9
137 const ResolveOperationReturnGlobalObjectAsBase = 10
138 const ResolveOperationGetAndReturnGlobalProperty = 11
139 const ResolveOperationCheckForDynamicEntriesBeforeGlobalScope = 12
141 const PutToBaseOperationKindUninitialised = 0
142 const PutToBaseOperationKindGeneric = 1
143 const PutToBaseOperationKindReadonly = 2
144 const PutToBaseOperationKindGlobalVariablePut = 3
145 const PutToBaseOperationKindGlobalVariablePutChecked = 4
146 const PutToBaseOperationKindGlobalPropertyPut = 5
147 const PutToBaseOperationKindVariablePut = 6
149 # Allocation constants
151 const JSFinalObjectSizeClassIndex = 1
153 const JSFinalObjectSizeClassIndex = 3
156 # This must match wtf/Vector.h
157 const VectorBufferOffset = 0
159 const VectorSizeOffset = 12
161 const VectorSizeOffset = 8
165 # Some common utilities.
170 storei t0, 0xbbadbeef[]
176 macro assert(assertion)
184 macro preserveReturnAddressAfterCall(destinationRegister)
185 if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or ARM64 or MIPS
186 # In C_LOOP case, we're only preserving the bytecode vPC.
187 move lr, destinationRegister
189 stspr destinationRegister
191 pop destinationRegister
197 macro restoreReturnAddressBeforeReturn(sourceRegister)
198 if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or ARM64 or MIPS
199 # In C_LOOP case, we're only restoring the bytecode vPC.
200 move sourceRegister, lr
210 macro traceExecution()
212 callSlowPath(_llint_trace)
216 macro callTargetFunction(callLinkInfo)
218 cloopCallJSFunction LLIntCallLinkInfo::machineCodeTarget[callLinkInfo]
220 call LLIntCallLinkInfo::machineCodeTarget[callLinkInfo]
225 macro slowPathForCall(advance, slowPath)
231 cloopCallJSFunction callee
239 macro arrayProfile(structureAndIndexingType, profile, scratch)
240 const structure = structureAndIndexingType
241 const indexingType = structureAndIndexingType
243 storep structure, ArrayProfile::m_lastSeenStructure[profile]
245 loadb Structure::m_indexingType[structure], indexingType
248 macro checkSwitchToJIT(increment, action)
250 loadp CodeBlock[cfr], t0
251 baddis increment, CodeBlock::m_llintExecuteCounter + ExecutionCounter::m_counter[t0], .continue
257 macro checkSwitchToJITForEpilogue()
261 callSlowPath(_llint_replace)
265 macro assertNotConstant(index)
266 assert(macro (ok) bilt index, FirstConstantRegisterIndex, ok end)
269 macro functionForCallCodeBlockGetter(targetRegister)
270 loadp Callee[cfr], targetRegister
271 loadp JSFunction::m_executable[targetRegister], targetRegister
272 loadp FunctionExecutable::m_codeBlockForCall[targetRegister], targetRegister
275 macro functionForConstructCodeBlockGetter(targetRegister)
276 loadp Callee[cfr], targetRegister
277 loadp JSFunction::m_executable[targetRegister], targetRegister
278 loadp FunctionExecutable::m_codeBlockForConstruct[targetRegister], targetRegister
281 macro notFunctionCodeBlockGetter(targetRegister)
282 loadp CodeBlock[cfr], targetRegister
285 macro functionCodeBlockSetter(sourceRegister)
286 storep sourceRegister, CodeBlock[cfr]
289 macro notFunctionCodeBlockSetter(sourceRegister)
293 # Do the bare minimum required to execute code. Sets up the PC, leave the CodeBlock*
294 # in t1. May also trigger prologue entry OSR.
295 macro prologue(codeBlockGetter, codeBlockSetter, osrSlowPath, traceSlowPath)
296 preserveReturnAddressAfterCall(t2)
298 # Set up the call frame and check if we should OSR.
299 storep t2, ReturnPC[cfr]
301 callSlowPath(traceSlowPath)
305 baddis 5, CodeBlock::m_llintExecuteCounter + ExecutionCounter::m_counter[t1], .continue
306 cCall2(osrSlowPath, cfr, PC)
309 loadp ReturnPC[cfr], t2
310 restoreReturnAddressBeforeReturn(t2)
320 loadp CodeBlock::m_instructions[t1], PB
323 loadp CodeBlock::m_instructions[t1], PC
327 # Expects that CodeBlock is in t1, which is what prologue() leaves behind.
328 # Must call dispatch(0) after calling this.
329 macro functionInitialization(profileArgSkip)
331 # Profile the arguments. Unfortunately, we have no choice but to do this. This
332 # code is pretty horrendous because of the difference in ordering between
333 # arguments and value profiles, the desire to have a simple loop-down-to-zero
334 # loop, and the desire to use only three registers so as to preserve the PC and
335 # the code block. It is likely that this code should be rewritten in a more
336 # optimal way for architectures that have more than five registers available
337 # for arbitrary use in the interpreter.
338 loadi CodeBlock::m_numParameters[t1], t0
339 addp -profileArgSkip, t0 # Use addi because that's what has the peephole
340 assert(macro (ok) bpgteq t0, 0, ok end)
341 btpz t0, .argumentProfileDone
342 loadp CodeBlock::m_argumentValueProfiles + VectorBufferOffset[t1], t3
343 mulp sizeof ValueProfile, t0, t2 # Aaaaahhhh! Need strength reduction!
347 .argumentProfileLoop:
349 loadq ThisArgumentOffset + 8 - profileArgSkip * 8[cfr, t0], t2
350 subp sizeof ValueProfile, t3
351 storeq t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets[t3]
353 loadi ThisArgumentOffset + TagOffset + 8 - profileArgSkip * 8[cfr, t0], t2
354 subp sizeof ValueProfile, t3
355 storei t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets + TagOffset[t3]
356 loadi ThisArgumentOffset + PayloadOffset + 8 - profileArgSkip * 8[cfr, t0], t2
357 storei t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets + PayloadOffset[t3]
359 baddpnz 8, t0, .argumentProfileLoop
360 .argumentProfileDone:
363 # Check stack height.
364 loadi CodeBlock::m_numCalleeRegisters[t1], t0
365 loadp CodeBlock::m_vm[t1], t2
366 loadp VM::interpreter[t2], t2 # FIXME: Can get to the JSStack from the JITStackFrame
369 bpaeq Interpreter::m_stack + JSStack::m_end[t2], t0, .stackHeightOK
371 # Stack height check failed - need to call a slow_path.
372 callSlowPath(_llint_stack_check)
376 macro allocateJSObject(allocator, structure, result, scratch1, slowCase)
377 if ALWAYS_ALLOCATE_SLOW
380 const offsetOfFirstFreeCell =
381 MarkedAllocator::m_freeList +
382 MarkedBlock::FreeList::head
384 # Get the object from the free list.
385 loadp offsetOfFirstFreeCell[allocator], result
386 btpz result, slowCase
388 # Remove the object from the free list.
389 loadp [result], scratch1
390 storep scratch1, offsetOfFirstFreeCell[allocator]
392 # Initialize the object.
393 storep structure, JSCell::m_structure[result]
394 storep 0, JSObject::m_butterfly[result]
399 loadp ReturnPC[cfr], t2
400 loadp CallerFrame[cfr], cfr
401 restoreReturnAddressBeforeReturn(t2)
406 # Indicate the beginning of LLInt.
411 _llint_program_prologue:
412 prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
416 _llint_eval_prologue:
417 prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
421 _llint_function_for_call_prologue:
422 prologue(functionForCallCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_call, _llint_trace_prologue_function_for_call)
423 .functionForCallBegin:
424 functionInitialization(0)
428 _llint_function_for_construct_prologue:
429 prologue(functionForConstructCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_construct, _llint_trace_prologue_function_for_construct)
430 .functionForConstructBegin:
431 functionInitialization(1)
435 _llint_function_for_call_arity_check:
436 prologue(functionForCallCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_call_arityCheck, _llint_trace_arityCheck_for_call)
437 functionArityCheck(.functionForCallBegin, _llint_slow_path_call_arityCheck)
440 _llint_function_for_construct_arity_check:
441 prologue(functionForConstructCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_construct_arityCheck, _llint_trace_arityCheck_for_construct)
442 functionArityCheck(.functionForConstructBegin, _llint_slow_path_construct_arityCheck)
445 # Value-representation-specific code.
447 include LowLevelInterpreter64
449 include LowLevelInterpreter32_64
453 # Value-representation-agnostic code.
456 callSlowPath(_llint_slow_path_new_array)
460 _llint_op_new_array_with_size:
462 callSlowPath(_llint_slow_path_new_array_with_size)
466 _llint_op_new_array_buffer:
468 callSlowPath(_llint_slow_path_new_array_buffer)
472 _llint_op_new_regexp:
474 callSlowPath(_llint_slow_path_new_regexp)
480 callSlowPath(_llint_slow_path_less)
486 callSlowPath(_llint_slow_path_lesseq)
492 callSlowPath(_llint_slow_path_greater)
498 callSlowPath(_llint_slow_path_greatereq)
504 callSlowPath(_llint_slow_path_mod)
510 callSlowPath(_llint_slow_path_typeof)
516 callSlowPath(_llint_slow_path_is_object)
520 _llint_op_is_function:
522 callSlowPath(_llint_slow_path_is_function)
528 callSlowPath(_llint_slow_path_in)
531 macro getPutToBaseOperationField(scratch, scratch1, fieldOffset, fieldGetter)
532 loadpFromInstruction(4, scratch)
533 fieldGetter(fieldOffset[scratch])
536 macro moveJSValueFromRegisterWithoutProfiling(value, destBuffer, destOffsetReg)
537 storeq value, [destBuffer, destOffsetReg, 8]
541 macro moveJSValueFromRegistersWithoutProfiling(tag, payload, destBuffer, destOffsetReg)
542 storei tag, TagOffset[destBuffer, destOffsetReg, 8]
543 storei payload, PayloadOffset[destBuffer, destOffsetReg, 8]
546 macro putToBaseVariableBody(variableOffset, scratch1, scratch2, scratch3)
547 loadisFromInstruction(1, scratch1)
548 loadp PayloadOffset[cfr, scratch1, 8], scratch1
549 loadp JSVariableObject::m_registers[scratch1], scratch1
550 loadisFromInstruction(3, scratch2)
552 loadConstantOrVariable(scratch2, scratch3)
553 moveJSValueFromRegisterWithoutProfiling(scratch3, scratch1, variableOffset)
555 loadConstantOrVariable2Reg(scratch2, scratch3, scratch2) # scratch3=tag, scratch2=payload
556 moveJSValueFromRegistersWithoutProfiling(scratch3, scratch2, scratch1, variableOffset)
560 _llint_op_put_to_base_variable:
562 getPutToBaseOperationField(t0, t1, PutToBaseOperation::m_offset, macro(addr)
565 putToBaseVariableBody(t0, t1, t2, t3)
568 _llint_op_put_to_base:
570 getPutToBaseOperationField(t0, t1, 0, macro(addr)
572 bbneq PutToBaseOperation::m_kindAsUint8[t0], PutToBaseOperationKindVariablePut, .notPutToBaseVariable
573 loadis PutToBaseOperation::m_offset[t0], t0
574 putToBaseVariableBody(t0, t1, t2, t3)
576 .notPutToBaseVariable:
578 callSlowPath(_llint_slow_path_put_to_base)
581 macro getResolveOperation(resolveOperationIndex, dest)
582 loadpFromInstruction(resolveOperationIndex, dest)
583 loadp VectorBufferOffset[dest], dest
586 macro getScope(loadInitialScope, scopeCount, dest, scratch)
587 loadInitialScope(dest)
588 loadi scopeCount, scratch
592 loadp JSScope::m_next[dest], dest
599 macro moveJSValue(sourceBuffer, sourceOffsetReg, destBuffer, destOffsetReg, profileOffset, scratchRegister)
601 loadq [sourceBuffer, sourceOffsetReg, 8], scratchRegister
602 storeq scratchRegister, [destBuffer, destOffsetReg, 8]
603 loadpFromInstruction(profileOffset, destOffsetReg)
604 valueProfile(scratchRegister, destOffsetReg)
606 loadi PayloadOffset[sourceBuffer, sourceOffsetReg, 8], scratchRegister
607 storei scratchRegister, PayloadOffset[destBuffer, destOffsetReg, 8]
608 loadi TagOffset[sourceBuffer, sourceOffsetReg, 8], sourceOffsetReg
609 storei sourceOffsetReg, TagOffset[destBuffer, destOffsetReg, 8]
610 loadpFromInstruction(profileOffset, destOffsetReg)
611 valueProfile(sourceOffsetReg, scratchRegister, destOffsetReg)
615 macro moveJSValueFromSlot(slot, destBuffer, destOffsetReg, profileOffset, scratchRegister)
617 loadq [slot], scratchRegister
618 storeq scratchRegister, [destBuffer, destOffsetReg, 8]
619 loadpFromInstruction(profileOffset, destOffsetReg)
620 valueProfile(scratchRegister, destOffsetReg)
622 loadi PayloadOffset[slot], scratchRegister
623 storei scratchRegister, PayloadOffset[destBuffer, destOffsetReg, 8]
624 loadi TagOffset[slot], slot
625 storei slot, TagOffset[destBuffer, destOffsetReg, 8]
626 loadpFromInstruction(profileOffset, destOffsetReg)
627 valueProfile(slot, scratchRegister, destOffsetReg)
631 macro moveJSValueFromRegister(value, destBuffer, destOffsetReg, profileOffset)
632 storeq value, [destBuffer, destOffsetReg, 8]
633 loadpFromInstruction(profileOffset, destOffsetReg)
634 valueProfile(value, destOffsetReg)
637 macro moveJSValueFromRegisters(tag, payload, destBuffer, destOffsetReg, profileOffset)
638 storei tag, TagOffset[destBuffer, destOffsetReg, 8]
639 storei payload, PayloadOffset[destBuffer, destOffsetReg, 8]
640 loadpFromInstruction(profileOffset, destOffsetReg)
641 valueProfile(tag, payload, destOffsetReg)
644 _llint_op_resolve_global_property:
646 getResolveOperation(3, t0)
647 loadp CodeBlock[cfr], t1
648 loadp CodeBlock::m_globalObject[t1], t1
649 loadp ResolveOperation::m_structure[t0], t2
650 bpneq JSCell::m_structure[t1], t2, .llint_op_resolve_local
651 loadis ResolveOperation::m_offset[t0], t0
653 loadPropertyAtVariableOffsetKnownNotInline(t0, t1, t2)
654 loadisFromInstruction(1, t0)
655 moveJSValueFromRegister(t2, cfr, t0, 4)
657 loadPropertyAtVariableOffsetKnownNotInline(t0, t1, t2, t3)
658 loadisFromInstruction(1, t0)
659 moveJSValueFromRegisters(t2, t3, cfr, t0, 4)
663 _llint_op_resolve_global_var:
665 getResolveOperation(3, t0)
666 loadp ResolveOperation::m_registerAddress[t0], t0
667 loadisFromInstruction(1, t1)
668 moveJSValueFromSlot(t0, cfr, t1, 4, t3)
671 macro resolveScopedVarBody(resolveOperations)
672 # First ResolveOperation is to skip scope chain nodes
674 loadp ScopeChain + PayloadOffset[cfr], dest
676 ResolveOperation::m_scopesToSkip[resolveOperations], t1, t2)
677 loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers
679 # Second ResolveOperation tells us what offset to use
680 loadis ResolveOperation::m_offset + sizeof ResolveOperation[resolveOperations], t2
681 loadisFromInstruction(1, t3)
682 moveJSValue(t1, t2, cfr, t3, 4, t0)
685 _llint_op_resolve_scoped_var:
687 getResolveOperation(3, t0)
688 resolveScopedVarBody(t0)
691 _llint_op_resolve_scoped_var_on_top_scope:
693 getResolveOperation(3, t0)
695 # Load destination index
696 loadisFromInstruction(1, t3)
698 # We know we want the top scope chain entry
699 loadp ScopeChain + PayloadOffset[cfr], t1
700 loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers
702 # Second ResolveOperation tells us what offset to use
703 loadis ResolveOperation::m_offset + sizeof ResolveOperation[t0], t2
705 moveJSValue(t1, t2, cfr, t3, 4, t0)
708 _llint_op_resolve_scoped_var_with_top_scope_check:
710 getResolveOperation(3, t0)
711 # First ResolveOperation tells us what register to check
712 loadis ResolveOperation::m_activationRegister[t0], t1
714 loadp PayloadOffset[cfr, t1, 8], t1
717 btpz t1, .scopeChainNotCreated
718 loadp JSScope::m_next[t1], dest
720 .scopeChainNotCreated:
721 loadp ScopeChain + PayloadOffset[cfr], dest
724 # Second ResolveOperation tells us how many more nodes to skip
725 ResolveOperation::m_scopesToSkip + sizeof ResolveOperation[t0], t1, t2)
726 loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers
728 # Third operation tells us what offset to use
729 loadis ResolveOperation::m_offset + 2 * sizeof ResolveOperation[t0], t2
730 loadisFromInstruction(1, t3)
731 moveJSValue(t1, t2, cfr, t3, 4, t0)
735 .llint_op_resolve_local:
737 getResolveOperation(3, t0)
738 btpz t0, .noInstructions
739 loadis ResolveOperation::m_operation[t0], t1
740 bineq t1, ResolveOperationSkipScopes, .notSkipScopes
741 resolveScopedVarBody(t0)
744 bineq t1, ResolveOperationGetAndReturnGlobalVar, .notGetAndReturnGlobalVar
745 loadp ResolveOperation::m_registerAddress[t0], t0
746 loadisFromInstruction(1, t1)
747 moveJSValueFromSlot(t0, cfr, t1, 4, t3)
749 .notGetAndReturnGlobalVar:
752 callSlowPath(_llint_slow_path_resolve)
755 _llint_op_resolve_base_to_global:
757 loadp CodeBlock[cfr], t1
758 loadp CodeBlock::m_globalObject[t1], t1
759 loadisFromInstruction(1, t3)
761 moveJSValueFromRegister(t1, cfr, t3, 6)
764 moveJSValueFromRegisters(t2, t1, cfr, t3, 6)
768 _llint_op_resolve_base_to_global_dynamic:
769 jmp _llint_op_resolve_base
771 _llint_op_resolve_base_to_scope:
773 getResolveOperation(4, t0)
774 # First ResolveOperation is to skip scope chain nodes
776 loadp ScopeChain + PayloadOffset[cfr], dest
778 ResolveOperation::m_scopesToSkip[t0], t1, t2)
779 loadisFromInstruction(1, t3)
781 moveJSValueFromRegister(t1, cfr, t3, 6)
784 moveJSValueFromRegisters(t2, t1, cfr, t3, 6)
788 _llint_op_resolve_base_to_scope_with_top_scope_check:
790 getResolveOperation(4, t0)
791 # First ResolveOperation tells us what register to check
792 loadis ResolveOperation::m_activationRegister[t0], t1
794 loadp PayloadOffset[cfr, t1, 8], t1
797 btpz t1, .scopeChainNotCreated
798 loadp JSScope::m_next[t1], dest
800 .scopeChainNotCreated:
801 loadp ScopeChain + PayloadOffset[cfr], dest
804 # Second ResolveOperation tells us how many more nodes to skip
805 ResolveOperation::m_scopesToSkip + sizeof ResolveOperation[t0], t1, t2)
807 loadisFromInstruction(1, t3)
809 moveJSValueFromRegister(t1, cfr, t3, 6)
812 moveJSValueFromRegisters(t2, t1, cfr, t3, 6)
816 _llint_op_resolve_base:
818 callSlowPath(_llint_slow_path_resolve_base)
821 macro interpretResolveWithBase(opcodeLength, slowPath)
823 getResolveOperation(4, t0)
826 loadp ScopeChain[cfr], t3
828 loadis ResolveOperation::m_operation[t0], t2
830 bineq t2, ResolveOperationSkipScopes, .notSkipScopes
831 getScope(macro(dest) move t3, dest end,
832 ResolveOperation::m_scopesToSkip[t0], t1, t2)
834 addp sizeof ResolveOperation, t0, t0
835 jmp .haveCorrectScope
839 bineq t2, ResolveOperationSkipTopScopeNode, .notSkipTopScopeNode
840 loadis ResolveOperation::m_activationRegister[t0], t1
841 loadp PayloadOffset[cfr, t1, 8], t1
844 btpz t1, .scopeChainNotCreated
845 loadp JSScope::m_next[t1], dest
847 .scopeChainNotCreated:
848 loadp ScopeChain + PayloadOffset[cfr], dest
851 sizeof ResolveOperation + ResolveOperation::m_scopesToSkip[t0], t1, t2)
853 # We've handled two opcodes here
854 addp 2 * sizeof ResolveOperation, t0, t0
856 .notSkipTopScopeNode:
860 # t3 now contains the correct Scope
861 # t0 contains a pointer to the current ResolveOperation
863 loadis ResolveOperation::m_operation[t0], t2
864 # t2 contains the next instruction
866 loadisFromInstruction(1, t1)
867 # t1 now contains the index for the base register
869 bineq t2, ResolveOperationSetBaseToScope, .notSetBaseToScope
871 storeq t3, [cfr, t1, 8]
873 storei t3, PayloadOffset[cfr, t1, 8]
874 storei CellTag, TagOffset[cfr, t1, 8]
880 bineq t2, ResolveOperationSetBaseToUndefined, .notSetBaseToUndefined
882 storeq ValueUndefined, [cfr, t1, 8]
884 storei 0, PayloadOffset[cfr, t1, 8]
885 storei UndefinedTag, TagOffset[cfr, t1, 8]
889 .notSetBaseToUndefined:
890 bineq t2, ResolveOperationSetBaseToGlobal, .slowPath
891 loadp JSCell::m_structure[t3], t2
892 loadp Structure::m_globalObject[t2], t2
894 storeq t2, [cfr, t1, 8]
896 storei t2, PayloadOffset[cfr, t1, 8]
897 storei CellTag, TagOffset[cfr, t1, 8]
904 # Load the operation into t2
905 loadis ResolveOperation::m_operation + sizeof ResolveOperation[t0], t2
907 # Load the index for the value register into t1
908 loadisFromInstruction(2, t1)
910 bineq t2, ResolveOperationGetAndReturnScopedVar, .notGetAndReturnScopedVar
911 loadp JSVariableObject::m_registers[t3], t3 # t3 now contains the activation registers
913 # Second ResolveOperation tells us what offset to use
914 loadis ResolveOperation::m_offset + sizeof ResolveOperation[t0], t2
915 moveJSValue(t3, t2, cfr, t1, opcodeLength - 1, t0)
916 dispatch(opcodeLength)
918 .notGetAndReturnScopedVar:
919 bineq t2, ResolveOperationGetAndReturnGlobalProperty, .slowPath
920 callSlowPath(slowPath)
921 dispatch(opcodeLength)
924 callSlowPath(slowPath)
925 dispatch(opcodeLength)
928 _llint_op_resolve_with_base:
929 interpretResolveWithBase(7, _llint_slow_path_resolve_with_base)
932 _llint_op_resolve_with_this:
933 interpretResolveWithBase(6, _llint_slow_path_resolve_with_this)
936 macro withInlineStorage(object, propertyStorage, continuation)
937 # Indicate that the object is the property storage, and that the
938 # property storage register is unused.
939 continuation(object, propertyStorage)
942 macro withOutOfLineStorage(object, propertyStorage, continuation)
943 loadp JSObject::m_butterfly[object], propertyStorage
944 # Indicate that the propertyStorage register now points to the
945 # property storage, and that the object register may be reused
946 # if the object pointer is not needed anymore.
947 continuation(propertyStorage, object)
953 callSlowPath(_llint_slow_path_del_by_id)
957 _llint_op_del_by_val:
959 callSlowPath(_llint_slow_path_del_by_val)
963 _llint_op_put_by_index:
965 callSlowPath(_llint_slow_path_put_by_index)
969 _llint_op_put_getter_setter:
971 callSlowPath(_llint_slow_path_put_getter_setter)
978 macro (value, target) btinz value, target end,
979 _llint_slow_path_jtrue)
985 macro (value, target) btiz value, target end,
986 _llint_slow_path_jfalse)
992 macro (left, right, target) bilt left, right, target end,
993 macro (left, right, target) bdlt left, right, target end,
994 _llint_slow_path_jless)
1000 macro (left, right, target) bigteq left, right, target end,
1001 macro (left, right, target) bdgtequn left, right, target end,
1002 _llint_slow_path_jnless)
1008 macro (left, right, target) bigt left, right, target end,
1009 macro (left, right, target) bdgt left, right, target end,
1010 _llint_slow_path_jgreater)
1013 _llint_op_jngreater:
1016 macro (left, right, target) bilteq left, right, target end,
1017 macro (left, right, target) bdltequn left, right, target end,
1018 _llint_slow_path_jngreater)
1024 macro (left, right, target) bilteq left, right, target end,
1025 macro (left, right, target) bdlteq left, right, target end,
1026 _llint_slow_path_jlesseq)
1032 macro (left, right, target) bigt left, right, target end,
1033 macro (left, right, target) bdgtun left, right, target end,
1034 _llint_slow_path_jnlesseq)
1037 _llint_op_jgreatereq:
1040 macro (left, right, target) bigteq left, right, target end,
1041 macro (left, right, target) bdgteq left, right, target end,
1042 _llint_slow_path_jgreatereq)
1045 _llint_op_jngreatereq:
1048 macro (left, right, target) bilt left, right, target end,
1049 macro (left, right, target) bdltun left, right, target end,
1050 _llint_slow_path_jngreatereq)
1053 _llint_op_loop_hint:
1055 loadp JITStackFrame::vm[sp], t1
1056 loadb VM::watchdog+Watchdog::m_timerDidFire[t1], t0
1057 btbnz t0, .handleWatchdogTimer
1058 .afterWatchdogTimerCheck:
1059 checkSwitchToJITForLoop()
1061 .handleWatchdogTimer:
1062 callWatchdogTimerHandler(.throwHandler)
1063 jmp .afterWatchdogTimerCheck
1065 jmp _llint_throw_from_slow_path_trampoline
1067 _llint_op_switch_string:
1069 callSlowPath(_llint_slow_path_switch_string)
1073 _llint_op_new_func_exp:
1075 callSlowPath(_llint_slow_path_new_func_exp)
1081 arrayProfileForCall()
1082 doCall(_llint_slow_path_call)
1085 _llint_op_construct:
1087 doCall(_llint_slow_path_construct)
1090 _llint_op_call_varargs:
1092 slowPathForCall(6, _llint_slow_path_call_varargs)
1095 _llint_op_call_eval:
1098 # Eval is executed in one of two modes:
1100 # 1) We find that we're really invoking eval() in which case the
1101 # execution is perfomed entirely inside the slow_path, and it
1102 # returns the PC of a function that just returns the return value
1103 # that the eval returned.
1105 # 2) We find that we're invoking something called eval() that is not
1106 # the real eval. Then the slow_path returns the PC of the thing to
1107 # call, and we call it.
1109 # This allows us to handle two cases, which would require a total of
1110 # up to four pieces of state that cannot be easily packed into two
1111 # registers (C functions can return up to two registers, easily):
1113 # - The call frame register. This may or may not have been modified
1114 # by the slow_path, but the convention is that it returns it. It's not
1115 # totally clear if that's necessary, since the cfr is callee save.
1116 # But that's our style in this here interpreter so we stick with it.
1118 # - A bit to say if the slow_path successfully executed the eval and has
1119 # the return value, or did not execute the eval but has a PC for us
1123 # - The JS return value (two registers), or
1127 # It turns out to be easier to just always have this return the cfr
1128 # and a PC to call, and that PC may be a dummy thunk that just
1129 # returns the JS value that the eval returned.
1131 slowPathForCall(4, _llint_slow_path_call_eval)
1134 _llint_generic_return_point:
1140 callSlowPath(_llint_slow_path_strcat)
1144 _llint_op_get_pnames:
1146 callSlowPath(_llint_slow_path_get_pnames)
1147 dispatch(0) # The slow_path either advances the PC or jumps us to somewhere else.
1150 _llint_op_push_with_scope:
1152 callSlowPath(_llint_slow_path_push_with_scope)
1156 _llint_op_pop_scope:
1158 callSlowPath(_llint_slow_path_pop_scope)
1162 _llint_op_push_name_scope:
1164 callSlowPath(_llint_slow_path_push_name_scope)
1170 callSlowPath(_llint_slow_path_throw)
1174 _llint_op_throw_static_error:
1176 callSlowPath(_llint_slow_path_throw_static_error)
1180 _llint_op_profile_will_call:
1182 callSlowPath(_llint_slow_path_profile_will_call)
1186 _llint_op_profile_did_call:
1188 callSlowPath(_llint_slow_path_profile_did_call)
1194 callSlowPath(_llint_slow_path_debug)
1198 _llint_native_call_trampoline:
1199 nativeCallTrampoline(NativeExecutable::m_function)
1202 _llint_native_construct_trampoline:
1203 nativeCallTrampoline(NativeExecutable::m_constructor)
1206 # Lastly, make sure that we can link even though we don't support all opcodes.
1207 # These opcodes should never arise when using LLInt or either JIT. We assert
1210 macro notSupported()
1214 # We should use whatever the smallest possible instruction is, just to
1215 # ensure that there is a gap between instruction labels. If multiple
1216 # smallest instructions exist, we should pick the one that is most
1217 # likely result in execution being halted. Currently that is the break
1218 # instruction on all architectures we're interested in. (Break is int3
1219 # on Intel, which is 1 byte, and bkpt on ARMv7, which is 2 bytes.)
1224 _llint_op_get_by_id_chain:
1227 _llint_op_get_by_id_custom_chain:
1230 _llint_op_get_by_id_custom_proto:
1233 _llint_op_get_by_id_custom_self:
1236 _llint_op_get_by_id_generic:
1239 _llint_op_get_by_id_getter_chain:
1242 _llint_op_get_by_id_getter_proto:
1245 _llint_op_get_by_id_getter_self:
1248 _llint_op_get_by_id_proto:
1251 _llint_op_get_by_id_self:
1254 _llint_op_get_string_length:
1257 _llint_op_put_by_id_generic:
1260 _llint_op_put_by_id_replace:
1263 _llint_op_put_by_id_transition:
1266 _llint_op_init_global_const_nop:
1269 # Indicate the end of LLInt.