--- /dev/null
+# Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# Some value representation constants.
+const TagBitTypeOther = 0x2
+const TagBitBool = 0x4
+const TagBitUndefined = 0x8
+const ValueEmpty = 0x0
+const ValueFalse = TagBitTypeOther | TagBitBool
+const ValueTrue = TagBitTypeOther | TagBitBool | 1
+const ValueUndefined = TagBitTypeOther | TagBitUndefined
+const ValueNull = TagBitTypeOther
+
+# Utilities.
+macro dispatch(advance)
+ addp advance, PC
+ jmp [PB, PC, 8]
+end
+
+macro dispatchInt(advance)
+ addi advance, PC
+ jmp [PB, PC, 8]
+end
+
+macro dispatchAfterCall()
+ loadi ArgumentCount + TagOffset[cfr], PC
+ loadp CodeBlock[cfr], PB
+ loadp CodeBlock::m_instructions[PB], PB
+ jmp [PB, PC, 8]
+end
+
+macro cCall2(function, arg1, arg2)
+ move arg1, t5
+ move arg2, t4
+ call function
+end
+
+# This barely works. arg3 and arg4 should probably be immediates.
+macro cCall4(function, arg1, arg2, arg3, arg4)
+ move arg1, t5
+ move arg2, t4
+ move arg3, t1
+ move arg4, t2
+ call function
+end
+
+macro prepareStateForCCall()
+ leap [PB, PC, 8], PC
+ move PB, t3
+end
+
+macro restoreStateAfterCCall()
+ move t0, PC
+ move t1, cfr
+ move t3, PB
+ subp PB, PC
+ urshiftp 3, PC
+end
+
+macro callSlowPath(slowPath)
+ prepareStateForCCall()
+ cCall2(slowPath, cfr, PC)
+ restoreStateAfterCCall()
+end
+
+macro traceOperand(fromWhere, operand)
+ prepareStateForCCall()
+ cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand)
+ restoreStateAfterCCall()
+end
+
+macro traceValue(fromWhere, operand)
+ prepareStateForCCall()
+ cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
+ restoreStateAfterCCall()
+end
+
+# Call a slow path for call call opcodes.
+macro callCallSlowPath(advance, slowPath, action)
+ addi advance, PC, t0
+ storei t0, ArgumentCount + TagOffset[cfr]
+ prepareStateForCCall()
+ cCall2(slowPath, cfr, PC)
+ move t1, cfr
+ action(t0)
+end
+
+macro checkSwitchToJITForLoop()
+ checkSwitchToJIT(
+ 1,
+ macro()
+ storei PC, ArgumentCount + TagOffset[cfr]
+ prepareStateForCCall()
+ cCall2(_llint_loop_osr, cfr, PC)
+ move t1, cfr
+ btpz t0, .recover
+ jmp t0
+ .recover:
+ move t3, PB
+ loadi ArgumentCount + TagOffset[cfr], PC
+ end)
+end
+
+# Index and value must be different registers. Index may be clobbered.
+macro loadConstantOrVariable(index, value)
+ bpgteq index, FirstConstantRegisterIndex, .constant
+ loadp [cfr, index, 8], value
+ jmp .done
+.constant:
+ loadp CodeBlock[cfr], value
+ loadp CodeBlock::m_constantRegisters + VectorBufferOffset[value], value
+ subp FirstConstantRegisterIndex, index
+ loadp [value, index, 8], value
+.done:
+end
+
+macro loadConstantOrVariableInt32(index, value, slow)
+ loadConstantOrVariable(index, value)
+ bpb value, tagTypeNumber, slow
+end
+
+macro loadConstantOrVariableCell(index, value, slow)
+ loadConstantOrVariable(index, value)
+ btpnz value, tagMask, slow
+end
+
+macro writeBarrier(value)
+ # Nothing to do, since we don't have a generational or incremental collector.
+end
+
+macro valueProfile(value, profile)
+ if VALUE_PROFILER
+ storep value, ValueProfile::m_buckets[profile]
+ end
+end
+
+
+# Entrypoints into the interpreter.
+
+# Expects that CodeBlock is in t1, which is what prologue() leaves behind.
+macro functionArityCheck(doneLabel, slow_path)
+ loadi PayloadOffset + ArgumentCount[cfr], t0
+ biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
+ prepareStateForCCall()
+ cCall2(slow_path, cfr, PC) # This slow_path has a simple protocol: t0 = 0 => no error, t0 != 0 => error
+ move t1, cfr
+ btiz t0, .continue
+ loadp JITStackFrame::globalData[sp], t1
+ loadp JSGlobalData::callFrameForThrow[t1], t0
+ jmp JSGlobalData::targetMachinePCForThrow[t1]
+.continue:
+ # Reload CodeBlock and reset PC, since the slow_path clobbered them.
+ loadp CodeBlock[cfr], t1
+ loadp CodeBlock::m_instructions[t1], PB
+ move 0, PC
+ jmp doneLabel
+end
+
+
+# Instruction implementations
+
+_llint_op_enter:
+ traceExecution()
+ loadp CodeBlock[cfr], t2
+ loadi CodeBlock::m_numVars[t2], t2
+ btiz t2, .opEnterDone
+ move ValueUndefined, t0
+.opEnterLoop:
+ subi 1, t2
+ storep t0, [cfr, t2, 8]
+ btinz t2, .opEnterLoop
+.opEnterDone:
+ dispatch(1)
+
+
+_llint_op_create_activation:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ bpneq [cfr, t0, 8], ValueEmpty, .opCreateActivationDone
+ callSlowPath(_llint_slow_path_create_activation)
+.opCreateActivationDone:
+ dispatch(2)
+
+
+_llint_op_init_lazy_reg:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ storep ValueEmpty, [cfr, t0, 8]
+ dispatch(2)
+
+
+_llint_op_create_arguments:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ bpneq [cfr, t0, 8], ValueEmpty, .opCreateArgumentsDone
+ callSlowPath(_llint_slow_path_create_arguments)
+.opCreateArgumentsDone:
+ dispatch(2)
+
+
+_llint_op_create_this:
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ assertNotConstant(t0)
+ loadp [cfr, t0, 8], t0
+ btpnz t0, tagMask, .opCreateThisSlow
+ loadp JSCell::m_structure[t0], t1
+ bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow
+ loadp JSObject::m_inheritorID[t0], t2
+ btpz t2, .opCreateThisSlow
+ allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow)
+ loadis 8[PB, PC, 8], t1
+ storep t0, [cfr, t1, 8]
+ dispatch(3)
+
+.opCreateThisSlow:
+ callSlowPath(_llint_slow_path_create_this)
+ dispatch(3)
+
+
+_llint_op_get_callee:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ loadp Callee[cfr], t1
+ storep t1, [cfr, t0, 8]
+ dispatch(2)
+
+
+_llint_op_convert_this:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ loadp [cfr, t0, 8], t0
+ btpnz t0, tagMask, .opConvertThisSlow
+ loadp JSCell::m_structure[t0], t0
+ bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
+ dispatch(2)
+
+.opConvertThisSlow:
+ callSlowPath(_llint_slow_path_convert_this)
+ dispatch(2)
+
+
+_llint_op_new_object:
+ traceExecution()
+ loadp CodeBlock[cfr], t0
+ loadp CodeBlock::m_globalObject[t0], t0
+ loadp JSGlobalObject::m_emptyObjectStructure[t0], t1
+ allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t1, t0, t2, t3, .opNewObjectSlow)
+ loadis 8[PB, PC, 8], t1
+ storep t0, [cfr, t1, 8]
+ dispatch(2)
+
+.opNewObjectSlow:
+ callSlowPath(_llint_slow_path_new_object)
+ dispatch(2)
+
+
+_llint_op_mov:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadis 8[PB, PC, 8], t0
+ loadConstantOrVariable(t1, t2)
+ storep t2, [cfr, t0, 8]
+ dispatch(3)
+
+
+_llint_op_not:
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ loadis 8[PB, PC, 8], t1
+ loadConstantOrVariable(t0, t2)
+ xorp ValueFalse, t2
+ btpnz t2, ~1, .opNotSlow
+ xorp ValueTrue, t2
+ storep t2, [cfr, t1, 8]
+ dispatch(3)
+
+.opNotSlow:
+ callSlowPath(_llint_slow_path_not)
+ dispatch(3)
+
+
+macro equalityComparison(integerComparison, slowPath)
+ traceExecution()
+ loadis 24[PB, PC, 8], t0
+ loadis 16[PB, PC, 8], t2
+ loadis 8[PB, PC, 8], t3
+ loadConstantOrVariableInt32(t0, t1, .slow)
+ loadConstantOrVariableInt32(t2, t0, .slow)
+ integerComparison(t0, t1, t0)
+ orp ValueFalse, t0
+ storep t0, [cfr, t3, 8]
+ dispatch(4)
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(4)
+end
+
+_llint_op_eq:
+ equalityComparison(
+ macro (left, right, result) cieq left, right, result end,
+ _llint_slow_path_eq)
+
+
+_llint_op_neq:
+ equalityComparison(
+ macro (left, right, result) cineq left, right, result end,
+ _llint_slow_path_neq)
+
+
+macro equalNullComparison()
+ loadis 16[PB, PC, 8], t0
+ loadp [cfr, t0, 8], t0
+ btpnz t0, tagMask, .immediate
+ loadp JSCell::m_structure[t0], t2
+ tbnz Structure::m_typeInfo + TypeInfo::m_flags[t2], MasqueradesAsUndefined, t0
+ jmp .done
+.immediate:
+ andp ~TagBitUndefined, t0
+ cpeq t0, ValueNull, t0
+.done:
+end
+
+_llint_op_eq_null:
+ traceExecution()
+ equalNullComparison()
+ loadis 8[PB, PC, 8], t1
+ orp ValueFalse, t0
+ storep t0, [cfr, t1, 8]
+ dispatch(3)
+
+
+_llint_op_neq_null:
+ traceExecution()
+ equalNullComparison()
+ loadis 8[PB, PC, 8], t1
+ xorp ValueTrue, t0
+ storep t0, [cfr, t1, 8]
+ dispatch(3)
+
+
+macro strictEq(equalityOperation, slowPath)
+ traceExecution()
+ loadis 24[PB, PC, 8], t0
+ loadis 16[PB, PC, 8], t2
+ loadConstantOrVariable(t0, t1)
+ loadConstantOrVariable(t2, t0)
+ move t0, t2
+ orp t1, t2
+ btpz t2, tagMask, .slow
+ bpaeq t0, tagTypeNumber, .leftOK
+ btpnz t0, tagTypeNumber, .slow
+.leftOK:
+ bpaeq t1, tagTypeNumber, .rightOK
+ btpnz t1, tagTypeNumber, .slow
+.rightOK:
+ equalityOperation(t0, t1, t0)
+ loadis 8[PB, PC, 8], t1
+ orp ValueFalse, t0
+ storep t0, [cfr, t1, 8]
+ dispatch(4)
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(4)
+end
+
+_llint_op_stricteq:
+ strictEq(
+ macro (left, right, result) cpeq left, right, result end,
+ _llint_slow_path_stricteq)
+
+
+_llint_op_nstricteq:
+ strictEq(
+ macro (left, right, result) cpneq left, right, result end,
+ _llint_slow_path_nstricteq)
+
+
+macro preOp(arithmeticOperation, slowPath)
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ loadp [cfr, t0, 8], t1
+ bpb t1, tagTypeNumber, .slow
+ arithmeticOperation(t1, .slow)
+ orp tagTypeNumber, t1
+ storep t1, [cfr, t0, 8]
+ dispatch(2)
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(2)
+end
+
+_llint_op_pre_inc:
+ preOp(
+ macro (value, slow) baddio 1, value, slow end,
+ _llint_slow_path_pre_inc)
+
+
+_llint_op_pre_dec:
+ preOp(
+ macro (value, slow) bsubio 1, value, slow end,
+ _llint_slow_path_pre_dec)
+
+
+macro postOp(arithmeticOperation, slowPath)
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ loadis 8[PB, PC, 8], t1
+ loadp [cfr, t0, 8], t2
+ bieq t0, t1, .done
+ bpb t2, tagTypeNumber, .slow
+ move t2, t3
+ arithmeticOperation(t3, .slow)
+ orp tagTypeNumber, t3
+ storep t2, [cfr, t1, 8]
+ storep t3, [cfr, t0, 8]
+.done:
+ dispatch(3)
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(3)
+end
+
+_llint_op_post_inc:
+ postOp(
+ macro (value, slow) baddio 1, value, slow end,
+ _llint_slow_path_post_inc)
+
+
+_llint_op_post_dec:
+ postOp(
+ macro (value, slow) bsubio 1, value, slow end,
+ _llint_slow_path_post_dec)
+
+
+_llint_op_to_jsnumber:
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ loadis 8[PB, PC, 8], t1
+ loadConstantOrVariable(t0, t2)
+ bpaeq t2, tagTypeNumber, .opToJsnumberIsImmediate
+ btpz t2, tagTypeNumber, .opToJsnumberSlow
+.opToJsnumberIsImmediate:
+ storep t2, [cfr, t1, 8]
+ dispatch(3)
+
+.opToJsnumberSlow:
+ callSlowPath(_llint_slow_path_to_jsnumber)
+ dispatch(3)
+
+
+_llint_op_negate:
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ loadis 8[PB, PC, 8], t1
+ loadConstantOrVariable(t0, t2)
+ bpb t2, tagTypeNumber, .opNegateNotInt
+ btiz t2, 0x7fffffff, .opNegateSlow
+ negi t2
+ orp tagTypeNumber, t2
+ storep t2, [cfr, t1, 8]
+ dispatch(3)
+.opNegateNotInt:
+ btpz t2, tagTypeNumber, .opNegateSlow
+ xorp 0x8000000000000000, t2
+ storep t2, [cfr, t1, 8]
+ dispatch(3)
+
+.opNegateSlow:
+ callSlowPath(_llint_slow_path_negate)
+ dispatch(3)
+
+
+macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath)
+ loadis 24[PB, PC, 8], t0
+ loadis 16[PB, PC, 8], t2
+ loadConstantOrVariable(t0, t1)
+ loadConstantOrVariable(t2, t0)
+ bpb t0, tagTypeNumber, .op1NotInt
+ bpb t1, tagTypeNumber, .op2NotInt
+ loadis 8[PB, PC, 8], t2
+ integerOperationAndStore(t1, t0, .slow, t2)
+ dispatch(5)
+
+.op1NotInt:
+ # First operand is definitely not an int, the second operand could be anything.
+ btpz t0, tagTypeNumber, .slow
+ bpaeq t1, tagTypeNumber, .op1NotIntOp2Int
+ btpz t1, tagTypeNumber, .slow
+ addp tagTypeNumber, t1
+ fp2d t1, ft1
+ jmp .op1NotIntReady
+.op1NotIntOp2Int:
+ ci2d t1, ft1
+.op1NotIntReady:
+ loadis 8[PB, PC, 8], t2
+ addp tagTypeNumber, t0
+ fp2d t0, ft0
+ doubleOperation(ft1, ft0)
+ fd2p ft0, t0
+ subp tagTypeNumber, t0
+ storep t0, [cfr, t2, 8]
+ dispatch(5)
+
+.op2NotInt:
+ # First operand is definitely an int, the second is definitely not.
+ loadis 8[PB, PC, 8], t2
+ btpz t1, tagTypeNumber, .slow
+ ci2d t0, ft0
+ addp tagTypeNumber, t1
+ fp2d t1, ft1
+ doubleOperation(ft1, ft0)
+ fd2p ft0, t0
+ subp tagTypeNumber, t0
+ storep t0, [cfr, t2, 8]
+ dispatch(5)
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(5)
+end
+
+macro binaryOp(integerOperation, doubleOperation, slowPath)
+ binaryOpCustomStore(
+ macro (left, right, slow, index)
+ integerOperation(left, right, slow)
+ orp tagTypeNumber, right
+ storep right, [cfr, index, 8]
+ end,
+ doubleOperation, slowPath)
+end
+
+_llint_op_add:
+ traceExecution()
+ binaryOp(
+ macro (left, right, slow) baddio left, right, slow end,
+ macro (left, right) addd left, right end,
+ _llint_slow_path_add)
+
+
+_llint_op_mul:
+ traceExecution()
+ binaryOpCustomStore(
+ macro (left, right, slow, index)
+ # Assume t3 is scratchable.
+ move right, t3
+ bmulio left, t3, slow
+ btinz t3, .done
+ bilt left, 0, slow
+ bilt right, 0, slow
+ .done:
+ orp tagTypeNumber, t3
+ storep t3, [cfr, index, 8]
+ end,
+ macro (left, right) muld left, right end,
+ _llint_slow_path_mul)
+
+
+_llint_op_sub:
+ traceExecution()
+ binaryOp(
+ macro (left, right, slow) bsubio left, right, slow end,
+ macro (left, right) subd left, right end,
+ _llint_slow_path_sub)
+
+
+_llint_op_div:
+ traceExecution()
+ binaryOpCustomStore(
+ macro (left, right, slow, index)
+ # Assume t3 is scratchable.
+ btiz left, slow
+ bineq left, -1, .notNeg2TwoThe31DivByNeg1
+ bieq right, -2147483648, .slow
+ .notNeg2TwoThe31DivByNeg1:
+ btinz right, .intOK
+ bilt left, 0, slow
+ .intOK:
+ move left, t3
+ move right, t0
+ cdqi
+ idivi t3
+ btinz t1, slow
+ orp tagTypeNumber, t0
+ storep t0, [cfr, index, 8]
+ end,
+ macro (left, right) divd left, right end,
+ _llint_slow_path_div)
+
+
+macro bitOp(operation, slowPath, advance)
+ loadis 24[PB, PC, 8], t0
+ loadis 16[PB, PC, 8], t2
+ loadis 8[PB, PC, 8], t3
+ loadConstantOrVariable(t0, t1)
+ loadConstantOrVariable(t2, t0)
+ bpb t0, tagTypeNumber, .slow
+ bpb t1, tagTypeNumber, .slow
+ operation(t1, t0, .slow)
+ orp tagTypeNumber, t0
+ storep t0, [cfr, t3, 8]
+ dispatch(advance)
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(advance)
+end
+
+_llint_op_lshift:
+ traceExecution()
+ bitOp(
+ macro (left, right, slow) lshifti left, right end,
+ _llint_slow_path_lshift,
+ 4)
+
+
+_llint_op_rshift:
+ traceExecution()
+ bitOp(
+ macro (left, right, slow) rshifti left, right end,
+ _llint_slow_path_rshift,
+ 4)
+
+
+_llint_op_urshift:
+ traceExecution()
+ bitOp(
+ macro (left, right, slow)
+ urshifti left, right
+ bilt right, 0, slow
+ end,
+ _llint_slow_path_urshift,
+ 4)
+
+
+_llint_op_bitand:
+ traceExecution()
+ bitOp(
+ macro (left, right, slow) andi left, right end,
+ _llint_slow_path_bitand,
+ 5)
+
+
+_llint_op_bitxor:
+ traceExecution()
+ bitOp(
+ macro (left, right, slow) xori left, right end,
+ _llint_slow_path_bitxor,
+ 5)
+
+
+_llint_op_bitor:
+ traceExecution()
+ bitOp(
+ macro (left, right, slow) ori left, right end,
+ _llint_slow_path_bitor,
+ 5)
+
+
+_llint_op_check_has_instance:
+ traceExecution()
+ loadis 8[PB, PC, 8], t1
+ loadConstantOrVariableCell(t1, t0, .opCheckHasInstanceSlow)
+ loadp JSCell::m_structure[t0], t0
+ btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow
+ dispatch(2)
+
+.opCheckHasInstanceSlow:
+ callSlowPath(_llint_slow_path_check_has_instance)
+ dispatch(2)
+
+
+_llint_op_instanceof:
+ traceExecution()
+ # Check that baseVal implements the default HasInstance behavior.
+ # FIXME: This should be deprecated.
+ loadis 24[PB, PC, 8], t1
+ loadConstantOrVariable(t1, t0)
+ loadp JSCell::m_structure[t0], t0
+ btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow
+
+ # Actually do the work.
+ loadis 32[PB, PC, 8], t0
+ loadis 8[PB, PC, 8], t3
+ loadConstantOrVariableCell(t0, t1, .opInstanceofSlow)
+ loadp JSCell::m_structure[t1], t2
+ bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opInstanceofSlow
+ loadis 16[PB, PC, 8], t0
+ loadConstantOrVariableCell(t0, t2, .opInstanceofSlow)
+
+ # Register state: t1 = prototype, t2 = value
+ move 1, t0
+.opInstanceofLoop:
+ loadp JSCell::m_structure[t2], t2
+ loadp Structure::m_prototype[t2], t2
+ bpeq t2, t1, .opInstanceofDone
+ btpz t2, tagMask, .opInstanceofLoop
+
+ move 0, t0
+.opInstanceofDone:
+ orp ValueFalse, t0
+ storep t0, [cfr, t3, 8]
+ dispatch(5)
+
+.opInstanceofSlow:
+ callSlowPath(_llint_slow_path_instanceof)
+ dispatch(5)
+
+
+_llint_op_is_undefined:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadis 8[PB, PC, 8], t2
+ loadConstantOrVariable(t1, t0)
+ btpz t0, tagMask, .opIsUndefinedCell
+ cpeq t0, ValueUndefined, t3
+ orp ValueFalse, t3
+ storep t3, [cfr, t2, 8]
+ dispatch(3)
+.opIsUndefinedCell:
+ loadp JSCell::m_structure[t0], t0
+ tbnz Structure::m_typeInfo + TypeInfo::m_flags[t0], MasqueradesAsUndefined, t1
+ orp ValueFalse, t1
+ storep t1, [cfr, t2, 8]
+ dispatch(3)
+
+
+_llint_op_is_boolean:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadis 8[PB, PC, 8], t2
+ loadConstantOrVariable(t1, t0)
+ xorp ValueFalse, t0
+ tpz t0, ~1, t0
+ orp ValueFalse, t0
+ storep t0, [cfr, t2, 8]
+ dispatch(3)
+
+
+_llint_op_is_number:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadis 8[PB, PC, 8], t2
+ loadConstantOrVariable(t1, t0)
+ tpnz t0, tagTypeNumber, t1
+ orp ValueFalse, t1
+ storep t1, [cfr, t2, 8]
+ dispatch(3)
+
+
+_llint_op_is_string:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadis 8[PB, PC, 8], t2
+ loadConstantOrVariable(t1, t0)
+ btpnz t0, tagMask, .opIsStringNotCell
+ loadp JSCell::m_structure[t0], t0
+ cbeq Structure::m_typeInfo + TypeInfo::m_type[t0], StringType, t1
+ orp ValueFalse, t1
+ storep t1, [cfr, t2, 8]
+ dispatch(3)
+.opIsStringNotCell:
+ storep ValueFalse, [cfr, t2, 8]
+ dispatch(3)
+
+
+macro resolveGlobal(size, slow)
+ # Operands are as follows:
+ # 8[PB, PC, 8] Destination for the load.
+ # 16[PB, PC, 8] Property identifier index in the code block.
+ # 24[PB, PC, 8] Structure pointer, initialized to 0 by bytecode generator.
+ # 32[PB, PC, 8] Offset in global object, initialized to 0 by bytecode generator.
+ loadp CodeBlock[cfr], t0
+ loadp CodeBlock::m_globalObject[t0], t0
+ loadp JSCell::m_structure[t0], t1
+ bpneq t1, 24[PB, PC, 8], slow
+ loadis 32[PB, PC, 8], t1
+ loadp JSObject::m_propertyStorage[t0], t0
+ loadp [t0, t1, 8], t2
+ loadis 8[PB, PC, 8], t0
+ storep t2, [cfr, t0, 8]
+ loadp (size - 1) * 8[PB, PC, 8], t0
+ valueProfile(t2, t0)
+end
+
+_llint_op_resolve_global:
+ traceExecution()
+ resolveGlobal(6, .opResolveGlobalSlow)
+ dispatch(6)
+
+.opResolveGlobalSlow:
+ callSlowPath(_llint_slow_path_resolve_global)
+ dispatch(6)
+
+
+# Gives you the scope in t0, while allowing you to optionally perform additional checks on the
+# scopes as they are traversed. scopeCheck() is called with two arguments: the register
+# holding the scope, and a register that can be used for scratch. Note that this does not
+# use t3, so you can hold stuff in t3 if need be.
+macro getScope(deBruijinIndexOperand, scopeCheck)
+ loadp ScopeChain[cfr], t0
+ loadis deBruijinIndexOperand, t2
+
+ btiz t2, .done
+
+ loadp CodeBlock[cfr], t1
+ bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
+ btbz CodeBlock::m_needsFullScopeChain[t1], .loop
+
+ loadis CodeBlock::m_activationRegister[t1], t1
+
+ # Need to conditionally skip over one scope.
+ btpz [cfr, t1, 8], .noActivation
+ scopeCheck(t0, t1)
+ loadp ScopeChainNode::next[t0], t0
+.noActivation:
+ subi 1, t2
+
+ btiz t2, .done
+.loop:
+ scopeCheck(t0, t1)
+ loadp ScopeChainNode::next[t0], t0
+ subi 1, t2
+ btinz t2, .loop
+
+.done:
+end
+
+_llint_op_resolve_global_dynamic:
+ traceExecution()
+ loadp JITStackFrame::globalData[sp], t3
+ loadp JSGlobalData::activationStructure[t3], t3
+ getScope(
+ 40[PB, PC, 8],
+ macro (scope, scratch)
+ loadp ScopeChainNode::object[scope], scratch
+ bpneq JSCell::m_structure[scratch], t3, .opResolveGlobalDynamicSuperSlow
+ end)
+ resolveGlobal(7, .opResolveGlobalDynamicSlow)
+ dispatch(7)
+
+.opResolveGlobalDynamicSuperSlow:
+ callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic)
+ dispatch(7)
+
+.opResolveGlobalDynamicSlow:
+ callSlowPath(_llint_slow_path_resolve_global_dynamic)
+ dispatch(7)
+
+
+_llint_op_get_scoped_var:
+ traceExecution()
+ # Operands are as follows:
+ # 8[PB, PC, 8] Destination for the load
+ # 16[PB, PC, 8] Index of register in the scope
+ # 24[PB, PC, 8] De Bruijin index.
+ getScope(24[PB, PC, 8], macro (scope, scratch) end)
+ loadis 8[PB, PC, 8], t1
+ loadis 16[PB, PC, 8], t2
+ loadp ScopeChainNode::object[t0], t0
+ loadp JSVariableObject::m_registers[t0], t0
+ loadp [t0, t2, 8], t3
+ storep t3, [cfr, t1, 8]
+ loadp 32[PB, PC, 8], t1
+ valueProfile(t3, t1)
+ dispatch(5)
+
+
+_llint_op_put_scoped_var:
+ traceExecution()
+ getScope(16[PB, PC, 8], macro (scope, scratch) end)
+ loadis 24[PB, PC, 8], t1
+ loadConstantOrVariable(t1, t3)
+ loadis 8[PB, PC, 8], t1
+ writeBarrier(t3)
+ loadp ScopeChainNode::object[t0], t0
+ loadp JSVariableObject::m_registers[t0], t0
+ storep t3, [t0, t1, 8]
+ dispatch(4)
+
+
+_llint_op_get_global_var:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadis 8[PB, PC, 8], t3
+ loadp CodeBlock[cfr], t0
+ loadp CodeBlock::m_globalObject[t0], t0
+ loadp JSGlobalObject::m_registers[t0], t0
+ loadp [t0, t1, 8], t2
+ storep t2, [cfr, t3, 8]
+ loadp 24[PB, PC, 8], t3
+ valueProfile(t2, t3)
+ dispatch(4)
+
+
+_llint_op_put_global_var:
+ traceExecution()
+ loadis 16[PB, PC, 8], t1
+ loadp CodeBlock[cfr], t0
+ loadp CodeBlock::m_globalObject[t0], t0
+ loadp JSGlobalObject::m_registers[t0], t0
+ loadConstantOrVariable(t1, t2)
+ loadis 8[PB, PC, 8], t1
+ writeBarrier(t2)
+ storep t2, [t0, t1, 8]
+ dispatch(3)
+
+
+_llint_op_get_by_id:
+ traceExecution()
+ # We only do monomorphic get_by_id caching for now, and we do not modify the
+ # opcode. We do, however, allow for the cache to change anytime if fails, since
+ # ping-ponging is free. At best we get lucky and the get_by_id will continue
+ # to take fast path on the new cache. At worst we take slow path, which is what
+ # we would have been doing anyway.
+ loadis 16[PB, PC, 8], t0
+ loadp 32[PB, PC, 8], t1
+ loadConstantOrVariableCell(t0, t3, .opGetByIdSlow)
+ loadis 40[PB, PC, 8], t2
+ loadp JSObject::m_propertyStorage[t3], t0
+ bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
+ loadis 8[PB, PC, 8], t1
+ loadp [t0, t2], t3
+ storep t3, [cfr, t1, 8]
+ loadp 64[PB, PC, 8], t1
+ valueProfile(t3, t1)
+ dispatch(9)
+
+.opGetByIdSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+
+
+_llint_op_get_arguments_length:
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ loadis 8[PB, PC, 8], t1
+ btpnz [cfr, t0, 8], .opGetArgumentsLengthSlow
+ loadi ArgumentCount + PayloadOffset[cfr], t2
+ subi 1, t2
+ orp tagTypeNumber, t2
+ storep t2, [cfr, t1, 8]
+ dispatch(4)
+
+.opGetArgumentsLengthSlow:
+ callSlowPath(_llint_slow_path_get_arguments_length)
+ dispatch(4)
+
+
+_llint_op_put_by_id:
+ traceExecution()
+ loadis 8[PB, PC, 8], t3
+ loadp 32[PB, PC, 8], t1
+ loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
+ loadis 24[PB, PC, 8], t2
+ loadp JSObject::m_propertyStorage[t0], t3
+ bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
+ loadis 40[PB, PC, 8], t1
+ loadConstantOrVariable(t2, t0)
+ writeBarrier(t0)
+ storep t0, [t3, t1]
+ dispatch(9)
+
+.opPutByIdSlow:
+ callSlowPath(_llint_slow_path_put_by_id)
+ dispatch(9)
+
+
+macro putByIdTransition(additionalChecks)
+ traceExecution()
+ loadis 8[PB, PC, 8], t3
+ loadp 32[PB, PC, 8], t1
+ loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
+ loadis 24[PB, PC, 8], t2
+ bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
+ additionalChecks(t1, t3, .opPutByIdSlow)
+ loadis 40[PB, PC, 8], t1
+ loadp JSObject::m_propertyStorage[t0], t3
+ addp t1, t3
+ loadConstantOrVariable(t2, t1)
+ writeBarrier(t1)
+ storep t1, [t3]
+ loadp 48[PB, PC, 8], t1
+ storep t1, JSCell::m_structure[t0]
+ dispatch(9)
+end
+
+_llint_op_put_by_id_transition_direct:
+ putByIdTransition(macro (oldStructure, scratch, slow) end)
+
+
+_llint_op_put_by_id_transition_normal:
+ putByIdTransition(
+ macro (oldStructure, scratch, slow)
+ const protoCell = oldStructure # Reusing the oldStructure register for the proto
+ loadp 56[PB, PC, 8], scratch
+ assert(macro (ok) btpnz scratch, ok end)
+ loadp StructureChain::m_vector[scratch], scratch
+ assert(macro (ok) btpnz scratch, ok end)
+ bpeq Structure::m_prototype[oldStructure], ValueNull, .done
+ .loop:
+ loadp Structure::m_prototype[oldStructure], protoCell
+ loadp JSCell::m_structure[protoCell], oldStructure
+ bpneq oldStructure, [scratch], slow
+ addp 8, scratch
+ bpneq Structure::m_prototype[oldStructure], ValueNull, .loop
+ .done:
+ end)
+
+
+_llint_op_get_by_val:
+ traceExecution()
+ loadp CodeBlock[cfr], t1
+ loadis 16[PB, PC, 8], t2
+ loadis 24[PB, PC, 8], t3
+ loadp CodeBlock::m_globalData[t1], t1
+ loadConstantOrVariableCell(t2, t0, .opGetByValSlow)
+ loadp JSGlobalData::jsArrayClassInfo[t1], t2
+ loadConstantOrVariableInt32(t3, t1, .opGetByValSlow)
+ sxi2p t1, t1
+ bpneq [t0], t2, .opGetByValSlow
+ loadp JSArray::m_storage[t0], t3
+ biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
+ loadis 8[PB, PC, 8], t0
+ loadp ArrayStorage::m_vector[t3, t1, 8], t2
+ btpz t2, .opGetByValSlow
+ storep t2, [cfr, t0, 8]
+ loadp 32[PB, PC, 8], t0
+ valueProfile(t2, t0)
+ dispatch(5)
+
+.opGetByValSlow:
+ callSlowPath(_llint_slow_path_get_by_val)
+ dispatch(5)
+
+
+_llint_op_get_argument_by_val:
+ traceExecution()
+ loadis 16[PB, PC, 8], t0
+ loadis 24[PB, PC, 8], t1
+ btpnz [cfr, t0, 8], .opGetArgumentByValSlow
+ loadConstantOrVariableInt32(t1, t2, .opGetArgumentByValSlow)
+ addi 1, t2
+ loadi ArgumentCount + PayloadOffset[cfr], t1
+ biaeq t2, t1, .opGetArgumentByValSlow
+ negi t2
+ sxi2p t2, t2
+ loadis 8[PB, PC, 8], t3
+ loadp ThisArgumentOffset[cfr, t2, 8], t0
+ storep t0, [cfr, t3, 8]
+ dispatch(5)
+
+.opGetArgumentByValSlow:
+ callSlowPath(_llint_slow_path_get_argument_by_val)
+ dispatch(5)
+
+
+_llint_op_get_by_pname:
+ traceExecution()
+ loadis 24[PB, PC, 8], t1
+ loadConstantOrVariable(t1, t0)
+ loadis 32[PB, PC, 8], t1
+ assertNotConstant(t1)
+ bpneq t0, [cfr, t1, 8], .opGetByPnameSlow
+ loadis 16[PB, PC, 8], t2
+ loadis 40[PB, PC, 8], t3
+ loadConstantOrVariableCell(t2, t0, .opGetByPnameSlow)
+ assertNotConstant(t3)
+ loadp [cfr, t3, 8], t1
+ loadp JSCell::m_structure[t0], t2
+ bpneq t2, JSPropertyNameIterator::m_cachedStructure[t1], .opGetByPnameSlow
+ loadis 48[PB, PC, 8], t3
+ loadi PayloadOffset[cfr, t3, 8], t3
+ subi 1, t3
+ biaeq t3, JSPropertyNameIterator::m_numCacheableSlots[t1], .opGetByPnameSlow
+ loadp JSObject::m_propertyStorage[t0], t0
+ loadp [t0, t3, 8], t0
+ loadis 8[PB, PC, 8], t1
+ storep t0, [cfr, t1, 8]
+ dispatch(7)
+
+.opGetByPnameSlow:
+ callSlowPath(_llint_slow_path_get_by_pname)
+ dispatch(7)
+
+
+_llint_op_put_by_val:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ loadConstantOrVariableCell(t0, t1, .opPutByValSlow)
+ loadis 16[PB, PC, 8], t0
+ loadConstantOrVariableInt32(t0, t2, .opPutByValSlow)
+ sxi2p t2, t2
+ loadp CodeBlock[cfr], t0
+ loadp CodeBlock::m_globalData[t0], t0
+ loadp JSGlobalData::jsArrayClassInfo[t0], t0
+ bpneq [t1], t0, .opPutByValSlow
+ biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
+ loadp JSArray::m_storage[t1], t0
+ btpz ArrayStorage::m_vector[t0, t2, 8], .opPutByValEmpty
+.opPutByValStoreResult:
+ loadis 24[PB, PC, 8], t3
+ loadConstantOrVariable(t3, t1)
+ writeBarrier(t1)
+ storep t1, ArrayStorage::m_vector[t0, t2, 8]
+ dispatch(4)
+
+.opPutByValEmpty:
+ addi 1, ArrayStorage::m_numValuesInVector[t0]
+ bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
+ addi 1, t2, t1
+ storei t1, ArrayStorage::m_length[t0]
+ jmp .opPutByValStoreResult
+
+.opPutByValSlow:
+ callSlowPath(_llint_slow_path_put_by_val)
+ dispatch(4)
+
+
+_llint_op_loop:
+ nop
+_llint_op_jmp:
+ traceExecution()
+ dispatchInt(8[PB, PC, 8])
+
+
+macro jumpTrueOrFalse(conditionOp, slow)
+ loadis 8[PB, PC, 8], t1
+ loadConstantOrVariable(t1, t0)
+ xorp ValueFalse, t0
+ btpnz t0, -1, .slow
+ conditionOp(t0, .target)
+ dispatch(3)
+
+.target:
+ dispatchInt(16[PB, PC, 8])
+
+.slow:
+ callSlowPath(slow)
+ dispatch(0)
+end
+
+
+macro equalNull(cellHandler, immediateHandler)
+ loadis 8[PB, PC, 8], t0
+ assertNotConstant(t0)
+ loadp [cfr, t0, 8], t0
+ btpnz t0, tagMask, .immediate
+ loadp JSCell::m_structure[t0], t2
+ cellHandler(Structure::m_typeInfo + TypeInfo::m_flags[t2], .target)
+ dispatch(3)
+
+.target:
+ dispatch(16[PB, PC, 8])
+
+.immediate:
+ andp ~TagBitUndefined, t0
+ immediateHandler(t0, .target)
+ dispatch(3)
+end
+
+_llint_op_jeq_null:
+ traceExecution()
+ equalNull(
+ macro (value, target) btbnz value, MasqueradesAsUndefined, target end,
+ macro (value, target) bpeq value, ValueNull, target end)
+
+
+_llint_op_jneq_null:
+ traceExecution()
+ equalNull(
+ macro (value, target) btbz value, MasqueradesAsUndefined, target end,
+ macro (value, target) bpneq value, ValueNull, target end)
+
+
+_llint_op_jneq_ptr:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ loadp 16[PB, PC, 8], t1
+ bpneq t1, [cfr, t0, 8], .opJneqPtrTarget
+ dispatch(4)
+
+.opJneqPtrTarget:
+ dispatchInt(24[PB, PC, 8])
+
+
+macro compare(integerCompare, doubleCompare, slowPath)
+ loadis 8[PB, PC, 8], t2
+ loadis 16[PB, PC, 8], t3
+ loadConstantOrVariable(t2, t0)
+ loadConstantOrVariable(t3, t1)
+ bpb t0, tagTypeNumber, .op1NotInt
+ bpb t1, tagTypeNumber, .op2NotInt
+ integerCompare(t0, t1, .jumpTarget)
+ dispatch(4)
+
+.op1NotInt:
+ btpz t0, tagTypeNumber, .slow
+ bpb t1, tagTypeNumber, .op1NotIntOp2NotInt
+ ci2d t1, ft1
+ jmp .op1NotIntReady
+.op1NotIntOp2NotInt:
+ btpz t1, tagTypeNumber, .slow
+ addp tagTypeNumber, t1
+ fp2d t1, ft1
+.op1NotIntReady:
+ addp tagTypeNumber, t0
+ fp2d t0, ft0
+ doubleCompare(ft0, ft1, .jumpTarget)
+ dispatch(4)
+
+.op2NotInt:
+ ci2d t0, ft0
+ btpz t1, tagTypeNumber, .slow
+ addp tagTypeNumber, t1
+ fp2d t1, ft1
+ doubleCompare(ft0, ft1, .jumpTarget)
+ dispatch(4)
+
+.jumpTarget:
+ dispatchInt(24[PB, PC, 8])
+
+.slow:
+ callSlowPath(slowPath)
+ dispatch(0)
+end
+
+
+_llint_op_switch_imm:
+ traceExecution()
+ loadis 24[PB, PC, 8], t2
+ loadis 8[PB, PC, 8], t3
+ loadConstantOrVariable(t2, t1)
+ loadp CodeBlock[cfr], t2
+ loadp CodeBlock::m_rareData[t2], t2
+ muli sizeof SimpleJumpTable, t3 # FIXME: would be nice to peephole this!
+ loadp CodeBlock::RareData::m_immediateSwitchJumpTables + VectorBufferOffset[t2], t2
+ addp t3, t2
+ bpb t1, tagTypeNumber, .opSwitchImmNotInt
+ subi SimpleJumpTable::min[t2], t1
+ biaeq t1, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
+ loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
+ loadis [t3, t1, 4], t1
+ btiz t1, .opSwitchImmFallThrough
+ dispatch(t1)
+
+.opSwitchImmNotInt:
+ btpnz t1, tagTypeNumber, .opSwitchImmSlow # Go slow if it's a double.
+.opSwitchImmFallThrough:
+ dispatchInt(16[PB, PC, 8])
+
+.opSwitchImmSlow:
+ callSlowPath(_llint_slow_path_switch_imm)
+ dispatch(0)
+
+
+_llint_op_switch_char:
+ traceExecution()
+ loadis 24[PB, PC, 8], t2
+ loadis 8[PB, PC, 8], t3
+ loadConstantOrVariable(t2, t1)
+ loadp CodeBlock[cfr], t2
+ loadp CodeBlock::m_rareData[t2], t2
+ muli sizeof SimpleJumpTable, t3
+ loadp CodeBlock::RareData::m_characterSwitchJumpTables + VectorBufferOffset[t2], t2
+ addp t3, t2
+ btpnz t1, tagMask, .opSwitchCharFallThrough
+ loadp JSCell::m_structure[t1], t0
+ bbneq Structure::m_typeInfo + TypeInfo::m_type[t0], StringType, .opSwitchCharFallThrough
+ bineq JSString::m_length[t1], 1, .opSwitchCharFallThrough
+ loadp JSString::m_value[t1], t0
+ btpz t0, .opSwitchOnRope
+ loadp StringImpl::m_data8[t0], t1
+ btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
+ loadh [t1], t0
+ jmp .opSwitchCharReady
+.opSwitchChar8Bit:
+ loadb [t1], t0
+.opSwitchCharReady:
+ subi SimpleJumpTable::min[t2], t0
+ biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
+ loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
+ loadis [t2, t0, 4], t1
+ btiz t1, .opSwitchCharFallThrough
+ dispatch(t1)
+
+.opSwitchCharFallThrough:
+ dispatchInt(16[PB, PC, 8])
+
+.opSwitchOnRope:
+ callSlowPath(_llint_slow_path_switch_char)
+ dispatch(0)
+
+
+_llint_op_new_func:
+ traceExecution()
+ btiz 24[PB, PC, 8], .opNewFuncUnchecked
+ loadis 8[PB, PC, 8], t1
+ btpnz [cfr, t1, 8], .opNewFuncDone
+.opNewFuncUnchecked:
+ callSlowPath(_llint_slow_path_new_func)
+.opNewFuncDone:
+ dispatch(4)
+
+
+macro doCall(slowPath)
+ loadis 8[PB, PC, 8], t0
+ loadp 32[PB, PC, 8], t1
+ loadp LLIntCallLinkInfo::callee[t1], t2
+ loadConstantOrVariable(t0, t3)
+ bpneq t3, t2, .opCallSlow
+ loadis 24[PB, PC, 8], t3
+ addi 6, PC
+ lshifti 3, t3
+ addp cfr, t3
+ loadp JSFunction::m_scopeChain[t2], t0
+ storep t2, Callee[t3]
+ storep t0, ScopeChain[t3]
+ loadis 16 - 48[PB, PC, 8], t2
+ storei PC, ArgumentCount + TagOffset[cfr]
+ storep cfr, CallerFrame[t3]
+ storei t2, ArgumentCount + PayloadOffset[t3]
+ move t3, cfr
+ call LLIntCallLinkInfo::machineCodeTarget[t1]
+ dispatchAfterCall()
+
+.opCallSlow:
+ slowPathForCall(6, slowPath)
+end
+
+
+_llint_op_tear_off_activation:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ loadis 16[PB, PC, 8], t1
+ btpnz [cfr, t0, 8], .opTearOffActivationCreated
+ btpz [cfr, t1, 8], .opTearOffActivationNotCreated
+.opTearOffActivationCreated:
+ callSlowPath(_llint_slow_path_tear_off_activation)
+.opTearOffActivationNotCreated:
+ dispatch(3)
+
+
+_llint_op_tear_off_arguments:
+ traceExecution()
+ loadis 8[PB, PC, 8], t0
+ subi 1, t0 # Get the unmodifiedArgumentsRegister
+ btpz [cfr, t0, 8], .opTearOffArgumentsNotCreated
+ callSlowPath(_llint_slow_path_tear_off_arguments)
+.opTearOffArgumentsNotCreated:
+ dispatch(2)
+
+
+_llint_op_ret:
+ traceExecution()
+ checkSwitchToJITForEpilogue()
+ loadis 8[PB, PC, 8], t2
+ loadConstantOrVariable(t2, t0)
+ doReturn()
+
+
+_llint_op_call_put_result:
+ loadis 8[PB, PC, 8], t2
+ loadp 16[PB, PC, 8], t3
+ storep t0, [cfr, t2, 8]
+ valueProfile(t0, t3)
+ traceExecution()
+ dispatch(3)
+
+
+_llint_op_ret_object_or_this:
+ traceExecution()
+ checkSwitchToJITForEpilogue()
+ loadis 8[PB, PC, 8], t2
+ loadConstantOrVariable(t2, t0)
+ btpnz t0, tagMask, .opRetObjectOrThisNotObject
+ loadp JSCell::m_structure[t0], t2
+ bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opRetObjectOrThisNotObject
+ doReturn()
+
+.opRetObjectOrThisNotObject:
+ loadis 16[PB, PC, 8], t2
+ loadConstantOrVariable(t2, t0)
+ doReturn()
+
+
+_llint_op_to_primitive:
+ traceExecution()
+ loadis 16[PB, PC, 8], t2
+ loadis 8[PB, PC, 8], t3
+ loadConstantOrVariable(t2, t0)
+ btpnz t0, tagMask, .opToPrimitiveIsImm
+ loadp JSCell::m_structure[t0], t2
+ bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .opToPrimitiveSlowCase
+.opToPrimitiveIsImm:
+ storep t0, [cfr, t3, 8]
+ dispatch(3)
+
+.opToPrimitiveSlowCase:
+ callSlowPath(_llint_slow_path_to_primitive)
+ dispatch(3)
+
+
+_llint_op_next_pname:
+ traceExecution()
+ loadis 24[PB, PC, 8], t1
+ loadis 32[PB, PC, 8], t2
+ assertNotConstant(t1)
+ assertNotConstant(t2)
+ loadi PayloadOffset[cfr, t1, 8], t0
+ bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
+ loadis 40[PB, PC, 8], t2
+ assertNotConstant(t2)
+ loadp [cfr, t2, 8], t2
+ loadp JSPropertyNameIterator::m_jsStrings[t2], t3
+ loadp [t3, t0, 8], t3
+ addi 1, t0
+ storei t0, PayloadOffset[cfr, t1, 8]
+ loadis 8[PB, PC, 8], t1
+ storep t3, [cfr, t1, 8]
+ loadis 16[PB, PC, 8], t3
+ assertNotConstant(t3)
+ loadp [cfr, t3, 8], t3
+ loadp JSCell::m_structure[t3], t1
+ bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
+ loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
+ loadp StructureChain::m_vector[t0], t0
+ btpz [t0], .opNextPnameTarget
+.opNextPnameCheckPrototypeLoop:
+ bpeq Structure::m_prototype[t1], ValueNull, .opNextPnameSlow
+ loadp Structure::m_prototype[t1], t2
+ loadp JSCell::m_structure[t2], t1
+ bpneq t1, [t0], .opNextPnameSlow
+ addp 8, t0
+ btpnz [t0], .opNextPnameCheckPrototypeLoop
+.opNextPnameTarget:
+ dispatchInt(48[PB, PC, 8])
+
+.opNextPnameEnd:
+ dispatch(7)
+
+.opNextPnameSlow:
+ callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
+ dispatch(0)
+
+
+_llint_op_catch:
+ # This is where we end up from the JIT's throw trampoline (because the
+ # machine code return address will be set to _llint_op_catch), and from
+ # the interpreter's throw trampoline (see _llint_throw_trampoline).
+ # The JIT throwing protocol calls for the cfr to be in t0. The throwing
+ # code must have known that we were throwing to the interpreter, and have
+ # set JSGlobalData::targetInterpreterPCForThrow.
+ move t0, cfr
+ loadp CodeBlock[cfr], PB
+ loadp CodeBlock::m_instructions[PB], PB
+ loadp JITStackFrame::globalData[sp], t3
+ loadp JSGlobalData::targetInterpreterPCForThrow[t3], PC
+ subp PB, PC
+ urshiftp 3, PC
+ loadp JSGlobalData::exception[t3], t0
+ storep 0, JSGlobalData::exception[t3]
+ loadis 8[PB, PC, 8], t2
+ storep t0, [cfr, t2, 8]
+ traceExecution()
+ dispatch(2)
+
+
+_llint_op_end:
+ traceExecution()
+ checkSwitchToJITForEpilogue()
+ loadis 8[PB, PC, 8], t0
+ assertNotConstant(t0)
+ loadp [cfr, t0, 8], t0
+ doReturn()
+
+
+_llint_throw_from_slow_path_trampoline:
+ # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so
+ # the throw target is not necessarily interpreted code, we come to here.
+ # This essentially emulates the JIT's throwing protocol.
+ loadp JITStackFrame::globalData[sp], t1
+ loadp JSGlobalData::callFrameForThrow[t1], t0
+ jmp JSGlobalData::targetMachinePCForThrow[t1]
+
+
+_llint_throw_during_call_trampoline:
+ preserveReturnAddressAfterCall(t2)
+ loadp JITStackFrame::globalData[sp], t1
+ loadp JSGlobalData::callFrameForThrow[t1], t0
+ jmp JSGlobalData::targetMachinePCForThrow[t1]
+
+
+macro nativeCallTrampoline(executableOffsetToFunction)
+ storep 0, CodeBlock[cfr]
+ loadp JITStackFrame::globalData + 8[sp], t0
+ storep cfr, JSGlobalData::topCallFrame[t0]
+ loadp CallerFrame[cfr], t0
+ loadp ScopeChain[t0], t1
+ storep t1, ScopeChain[cfr]
+ peek 0, t1
+ storep t1, ReturnPC[cfr]
+ move cfr, t5 # t5 = rdi
+ subp 16 - 8, sp
+ loadp Callee[cfr], t4 # t4 = rsi
+ loadp JSFunction::m_executable[t4], t1
+ move t0, cfr # Restore cfr to avoid loading from stack
+ call executableOffsetToFunction[t1]
+ addp 16 - 8, sp
+ loadp JITStackFrame::globalData + 8[sp], t3
+ btpnz JSGlobalData::exception[t3], .exception
+ ret
+.exception:
+ preserveReturnAddressAfterCall(t1)
+ loadi ArgumentCount + TagOffset[cfr], PC
+ loadp CodeBlock[cfr], PB
+ loadp CodeBlock::m_instructions[PB], PB
+ loadp JITStackFrame::globalData[sp], t0
+ storep cfr, JSGlobalData::topCallFrame[t0]
+ callSlowPath(_llint_throw_from_native_call)
+ jmp _llint_throw_from_slow_path_trampoline
+end
+