blob: d19104119f6c539c01c2d14fac8e453eecc041fc [file] [log] [blame]
# 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)
if X86_64
move arg1, t5
move arg2, t4
call function
elsif C_LOOP
cloopCallSlowPath function, arg1, arg2
else
error
end
end
# This barely works. arg3 and arg4 should probably be immediates.
macro cCall4(function, arg1, arg2, arg3, arg4)
if X86_64
move arg1, t5
move arg2, t4
move arg3, t1
move arg4, t2
call function
elsif C_LOOP
error
else
error
end
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 // t2<CodeBlock> = cfr.CodeBlock
loadi CodeBlock::m_numVars[t2], t2 // t2<size_t> = t2<CodeBlock>.m_numVars
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()
loadp Callee[cfr], t0
loadp JSFunction::m_cachedInheritorID[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(2)
.opCreateThisSlow:
callSlowPath(_llint_slow_path_create_this)
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
loadp 16[PB, PC, 8], t1
valueProfile(t0, t1)
dispatch(3)
.opConvertThisSlow:
callSlowPath(_llint_slow_path_convert_this)
dispatch(3)
_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
btbnz Structure::m_typeInfo + TypeInfo::m_flags[t2], MasqueradesAsUndefined, .masqueradesAsUndefined
move 0, t0
jmp .done
.masqueradesAsUndefined:
loadp CodeBlock[cfr], t0
loadp CodeBlock::m_globalObject[t0], t0
cpeq Structure::m_globalObject[t2], t0, 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
btbnz Structure::m_typeInfo + TypeInfo::m_flags[t0], MasqueradesAsUndefined, .masqueradesAsUndefined
move ValueFalse, t1
storep t1, [cfr, t2, 8]
dispatch(3)
.masqueradesAsUndefined:
loadp CodeBlock[cfr], t1
loadp CodeBlock::m_globalObject[t1], t1
cpeq Structure::m_globalObject[t0], t1, t3
orp ValueFalse, t3
storep t3, [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 loadPropertyAtVariableOffsetKnownNotFinal(propertyOffsetAsPointer, objectAndStorage, value)
assert(macro (ok) bigteq propertyOffsetAsPointer, InlineStorageCapacity, ok end)
negp propertyOffsetAsPointer
loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
loadp (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffsetAsPointer, 8], value
end
macro loadPropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value)
bilt propertyOffsetAsInt, InlineStorageCapacity, .isInline
loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
negi propertyOffsetAsInt
sxi2p propertyOffsetAsInt, propertyOffsetAsInt
jmp .ready
.isInline:
addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 2) * 8, objectAndStorage
.ready:
loadp (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8], value
end
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
loadPropertyAtVariableOffset(t1, t0, 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 JSScope::m_next[t0], t0
.noActivation:
subi 1, t2
btiz t2, .done
.loop:
scopeCheck(t0, t1)
loadp JSScope::m_next[t0], t0
subi 1, t2
btinz t2, .loop
.done:
end
_llint_op_resolve_global_dynamic:
traceExecution()
loadp CodeBlock[cfr], t3
loadp CodeBlock::m_globalObject[t3], t3
loadp JSGlobalObject::m_activationStructure[t3], t3
getScope(
40[PB, PC, 8],
macro (scope, scratch)
bpneq JSCell::m_structure[scope], 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 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 JSVariableObject::m_registers[t0], t0
storep t3, [t0, t1, 8]
dispatch(4)
macro getGlobalVar(size)
traceExecution()
loadp 16[PB, PC, 8], t0
loadis 8[PB, PC, 8], t3
loadp [t0], t1
storep t1, [cfr, t3, 8]
loadp (size - 1) * 8[PB, PC, 8], t0
valueProfile(t1, t0)
dispatch(size)
end
_llint_op_get_global_var:
getGlobalVar(4)
_llint_op_get_global_var_watchable:
getGlobalVar(5)
_llint_op_put_global_var:
traceExecution()
loadis 16[PB, PC, 8], t1
loadp 8[PB, PC, 8], t0
loadConstantOrVariable(t1, t2)
writeBarrier(t2)
storep t2, [t0]
dispatch(3)
_llint_op_put_global_var_check:
traceExecution()
loadp 24[PB, PC, 8], t2
loadis 16[PB, PC, 8], t1
loadp 8[PB, PC, 8], t0
btbnz [t2], .opPutGlobalVarCheckSlow
loadConstantOrVariable(t1, t2)
writeBarrier(t2)
storep t2, [t0]
dispatch(5)
.opPutGlobalVarCheckSlow:
callSlowPath(_llint_slow_path_put_global_var_check)
dispatch(5)
macro getById(getPropertyStorage)
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
getPropertyStorage(
t3,
t0,
macro (propertyStorage, scratch)
bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
loadis 8[PB, PC, 8], t1
loadp [propertyStorage, t2], scratch
storep scratch, [cfr, t1, 8]
loadp 64[PB, PC, 8], t1
valueProfile(scratch, t1)
dispatch(9)
end)
.opGetByIdSlow:
callSlowPath(_llint_slow_path_get_by_id)
dispatch(9)
end
_llint_op_get_by_id:
getById(withInlineStorage)
_llint_op_get_by_id_out_of_line:
getById(withOutOfLineStorage)
_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)
macro putById(getPropertyStorage)
traceExecution()
loadis 8[PB, PC, 8], t3
loadp 32[PB, PC, 8], t1
loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
loadis 24[PB, PC, 8], t2
getPropertyStorage(
t0,
t3,
macro (propertyStorage, scratch)
bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
loadis 40[PB, PC, 8], t1
loadConstantOrVariable(t2, scratch)
writeBarrier(t0)
storep scratch, [propertyStorage, t1]
dispatch(9)
end)
end
_llint_op_put_by_id:
putById(withInlineStorage)
.opPutByIdSlow:
callSlowPath(_llint_slow_path_put_by_id)
dispatch(9)
_llint_op_put_by_id_out_of_line:
putById(withOutOfLineStorage)
macro putByIdTransition(additionalChecks, getPropertyStorage)
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)
loadis 40[PB, PC, 8], t1
getPropertyStorage(
t0,
t3,
macro (propertyStorage, scratch)
addp t1, propertyStorage, t3
loadConstantOrVariable(t2, t1)
writeBarrier(t1)
storep t1, [t3]
loadp 48[PB, PC, 8], t1
storep t1, JSCell::m_structure[t0]
dispatch(9)
end)
end
macro noAdditionalChecks(oldStructure, scratch)
end
macro structureChainChecks(oldStructure, scratch)
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], .opPutByIdSlow
addp 8, scratch
bpneq Structure::m_prototype[oldStructure], ValueNull, .loop
.done:
end
_llint_op_put_by_id_transition_direct:
putByIdTransition(noAdditionalChecks, withInlineStorage)
_llint_op_put_by_id_transition_direct_out_of_line:
putByIdTransition(noAdditionalChecks, withOutOfLineStorage)
_llint_op_put_by_id_transition_normal:
putByIdTransition(structureChainChecks, withInlineStorage)
_llint_op_put_by_id_transition_normal_out_of_line:
putByIdTransition(structureChainChecks, withOutOfLineStorage)
_llint_op_get_by_val:
traceExecution()
loadis 16[PB, PC, 8], t2
loadis 24[PB, PC, 8], t3
loadConstantOrVariableCell(t2, t0, .opGetByValSlow)
loadConstantOrVariableInt32(t3, t1, .opGetByValSlow)
sxi2p t1, t1
loadp JSCell::m_structure[t0], t3
loadp 32[PB, PC, 8], t2
if VALUE_PROFILER
storep t3, ArrayProfile::m_lastSeenStructure[t2]
end
loadp CodeBlock[cfr], t2
loadp CodeBlock::m_globalData[t2], t2
loadp JSGlobalData::jsArrayClassInfo[t2], t2
bpneq Structure::m_classInfo[t3], 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 40[PB, PC, 8], t0
valueProfile(t2, t0)
dispatch(6)
.opGetByValSlow:
callSlowPath(_llint_slow_path_get_by_val)
dispatch(6)
_llint_op_get_argument_by_val:
# FIXME: At some point we should array profile this. Right now it isn't necessary
# since the DFG will never turn a get_argument_by_val into a GetByVal.
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 32[PB, PC, 8], t1
loadp ThisArgumentOffset[cfr, t2, 8], t0
storep t0, [cfr, t3, 8]
valueProfile(t0, t1)
dispatch(6)
.opGetArgumentByValSlow:
callSlowPath(_llint_slow_path_get_argument_by_val)
dispatch(6)
_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
addi JSPropertyNameIterator::m_offsetBase[t1], t3
loadPropertyAtVariableOffset(t3, t0, 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 JSCell::m_structure[t1], t3
loadp 32[PB, PC, 8], t0
if VALUE_PROFILER
storep t3, ArrayProfile::m_lastSeenStructure[t0]
end
loadp CodeBlock[cfr], t0
loadp CodeBlock::m_globalData[t0], t0
loadp JSGlobalData::jsArrayClassInfo[t0], t0
bpneq Structure::m_classInfo[t3], 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(5)
.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(5)
_llint_op_loop:
traceExecution()
dispatchInt(8[PB, PC, 8])
_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(t2, 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 (structure, value, target)
btbz value, MasqueradesAsUndefined, .notMasqueradesAsUndefined
loadp CodeBlock[cfr], t0
loadp CodeBlock::m_globalObject[t0], t0
bpeq Structure::m_globalObject[structure], t0, target
.notMasqueradesAsUndefined:
end,
macro (value, target) bpeq value, ValueNull, target end)
_llint_op_jneq_null:
traceExecution()
equalNull(
macro (structure, value, target)
btbz value, MasqueradesAsUndefined, target
loadp CodeBlock[cfr], t0
loadp CodeBlock::m_globalObject[t0], t0
bpneq Structure::m_globalObject[structure], t0, 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 arrayProfileForCall()
if VALUE_PROFILER
loadis 24[PB, PC, 8], t3
loadp ThisArgumentOffset[cfr, t3, 8], t0
btpnz t0, tagMask, .done
loadp JSCell::m_structure[t0], t0
loadp 40[PB, PC, 8], t1
storep t0, ArrayProfile::m_lastSeenStructure[t1]
.done:
end
end
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_scope[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
callTargetFunction(t1)
.opCallSlow:
slowPathForCall(6, slowPath)
end
_llint_op_tear_off_activation:
traceExecution()
loadis 8[PB, PC, 8], t0
btpz [cfr, t0, 8], .opTearOffActivationNotCreated
callSlowPath(_llint_slow_path_tear_off_activation)
.opTearOffActivationNotCreated:
dispatch(2)
_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(3)
_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]
if X86_64
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
elsif C_LOOP
loadp CallerFrame[cfr], t0
loadp ScopeChain[t0], t1
storep t1, ScopeChain[cfr]
loadp JITStackFrame::globalData[sp], t3
storep cfr, JSGlobalData::topCallFrame[t3]
move t0, t2
preserveReturnAddressAfterCall(t3)
storep t3, ReturnPC[cfr]
move cfr, t0
loadp Callee[cfr], t1
loadp JSFunction::m_executable[t1], t1
move t2, cfr
cloopCallNative executableOffsetToFunction[t1]
restoreReturnAddressBeforeReturn(t3)
loadp JITStackFrame::globalData[sp], t3
else
error
end
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