2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "FTLLowerDFGToLLVM.h"
31 #include "CodeBlockWithJITType.h"
32 #include "DFGAbstractInterpreterInlines.h"
33 #include "DFGInPlaceAbstractState.h"
34 #include "FTLAbstractHeapRepository.h"
35 #include "FTLAvailableRecovery.h"
36 #include "FTLForOSREntryJITCode.h"
37 #include "FTLFormattedValue.h"
38 #include "FTLInlineCacheSize.h"
39 #include "FTLLoweredNodeValue.h"
40 #include "FTLOutput.h"
41 #include "FTLThunks.h"
42 #include "FTLWeightedTarget.h"
43 #include "OperandsInlines.h"
44 #include "JSCInlines.h"
45 #include "VirtualRegister.h"
47 #include <wtf/ProcessID.h>
49 namespace JSC
{ namespace FTL
{
53 static std::atomic
<int> compileCounter
;
55 // Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
56 // significantly less dead code.
57 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
58 FormattedValue _ftc_lowValue = (lowValue); \
59 Edge _ftc_highValue = (highValue); \
60 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
61 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
63 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition)); \
66 class LowerDFGToLLVM
{
68 LowerDFGToLLVM(State
& state
)
69 : m_graph(state
.graph
)
71 , m_heaps(state
.context
)
72 , m_out(state
.context
)
73 , m_availability(OperandsLike
, state
.graph
.block(0)->variablesAtHead
)
74 , m_state(state
.graph
)
75 , m_interpreter(state
.graph
, m_state
)
83 if (verboseCompilationEnabled()) {
85 "jsBody_", ++compileCounter
, "_", codeBlock()->inferredName(),
86 "_", codeBlock()->hash());
90 m_graph
.m_dominators
.computeIfNecessary(m_graph
);
93 llvm
->ModuleCreateWithNameInContext(name
.data(), m_ftlState
.context
);
95 m_ftlState
.function
= addFunction(
96 m_ftlState
.module, name
.data(), functionType(m_out
.int64
));
97 setFunctionCallingConv(m_ftlState
.function
, LLVMCCallConv
);
98 if (isX86() && Options::llvmDisallowAVX()) {
99 // AVX makes V8/raytrace 80% slower. It makes Kraken/audio-oscillator 4.5x
100 // slower. It should be disabled.
101 addTargetDependentFunctionAttr(m_ftlState
.function
, "target-features", "-avx");
104 if (verboseCompilationEnabled())
105 dataLog("Function ready, beginning lowering.\n");
107 m_out
.initialize(m_ftlState
.module, m_ftlState
.function
, m_heaps
);
109 m_prologue
= FTL_NEW_BLOCK(m_out
, ("Prologue"));
110 LBasicBlock stackOverflow
= FTL_NEW_BLOCK(m_out
, ("Stack overflow"));
111 m_handleExceptions
= FTL_NEW_BLOCK(m_out
, ("Handle Exceptions"));
113 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
114 m_highBlock
= m_graph
.block(blockIndex
);
117 m_blocks
.add(m_highBlock
, FTL_NEW_BLOCK(m_out
, ("Block ", *m_highBlock
)));
120 m_out
.appendTo(m_prologue
, stackOverflow
);
121 createPhiVariables();
122 LValue capturedAlloca
= m_out
.alloca(arrayType(m_out
.int64
, m_graph
.m_nextMachineLocal
));
123 m_captured
= m_out
.add(
124 m_out
.ptrToInt(capturedAlloca
, m_out
.intPtr
),
125 m_out
.constIntPtr(m_graph
.m_nextMachineLocal
* sizeof(Register
)));
127 // We should not create any alloca's after this point, since they will cease to
128 // be mem2reg candidates.
130 m_ftlState
.capturedStackmapID
= m_stackmapIDs
++;
132 m_out
.stackmapIntrinsic(), m_out
.constInt64(m_ftlState
.capturedStackmapID
),
133 m_out
.int32Zero
, capturedAlloca
);
135 m_callFrame
= m_out
.ptrToInt(
136 m_out
.call(m_out
.frameAddressIntrinsic(), m_out
.int32Zero
), m_out
.intPtr
);
137 m_tagTypeNumber
= m_out
.constInt64(TagTypeNumber
);
138 m_tagMask
= m_out
.constInt64(TagMask
);
140 m_out
.storePtr(m_out
.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock
));
143 didOverflowStack(), rarely(stackOverflow
), usually(lowBlock(m_graph
.block(0))));
145 m_out
.appendTo(stackOverflow
, m_handleExceptions
);
146 m_out
.call(m_out
.operation(operationThrowStackOverflowError
), m_callFrame
, m_out
.constIntPtr(codeBlock()));
147 m_ftlState
.handleStackOverflowExceptionStackmapID
= m_stackmapIDs
++;
149 m_out
.stackmapIntrinsic(), m_out
.constInt64(m_ftlState
.handleStackOverflowExceptionStackmapID
),
150 m_out
.constInt32(MacroAssembler::maxJumpReplacementSize()));
153 m_out
.appendTo(m_handleExceptions
, lowBlock(m_graph
.block(0)));
154 m_ftlState
.handleExceptionStackmapID
= m_stackmapIDs
++;
156 m_out
.stackmapIntrinsic(), m_out
.constInt64(m_ftlState
.handleExceptionStackmapID
),
157 m_out
.constInt32(MacroAssembler::maxJumpReplacementSize()));
160 Vector
<BasicBlock
*> depthFirst
;
161 m_graph
.getBlocksInDepthFirstOrder(depthFirst
);
162 for (unsigned i
= 0; i
< depthFirst
.size(); ++i
)
163 compileBlock(depthFirst
[i
]);
165 if (Options::dumpLLVMIR())
166 dumpModule(m_ftlState
.module);
168 if (verboseCompilationEnabled())
169 m_ftlState
.dumpState("after lowering");
170 if (validationEnabled())
171 verifyModule(m_ftlState
.module);
176 void createPhiVariables()
178 for (BlockIndex blockIndex
= m_graph
.numBlocks(); blockIndex
--;) {
179 BasicBlock
* block
= m_graph
.block(blockIndex
);
182 for (unsigned nodeIndex
= block
->size(); nodeIndex
--;) {
183 Node
* node
= block
->at(nodeIndex
);
184 if (node
->op() != Phi
)
187 switch (node
->flags() & NodeResultMask
) {
188 case NodeResultDouble
:
189 type
= m_out
.doubleType
;
191 case NodeResultInt32
:
194 case NodeResultInt52
:
197 case NodeResultBoolean
:
198 type
= m_out
.boolean
;
204 RELEASE_ASSERT_NOT_REACHED();
207 m_phis
.add(node
, buildAlloca(m_out
.m_builder
, type
));
212 void compileBlock(BasicBlock
* block
)
217 if (verboseCompilationEnabled())
218 dataLog("Compiling block ", *block
, "\n");
222 LBasicBlock lowBlock
= m_blocks
.get(m_highBlock
);
225 for (BlockIndex nextBlockIndex
= m_highBlock
->index
+ 1; nextBlockIndex
< m_graph
.numBlocks(); ++nextBlockIndex
) {
226 m_nextHighBlock
= m_graph
.block(nextBlockIndex
);
230 m_nextLowBlock
= m_nextHighBlock
? m_blocks
.get(m_nextHighBlock
) : 0;
232 // All of this effort to find the next block gives us the ability to keep the
233 // generated IR in roughly program order. This ought not affect the performance
234 // of the generated code (since we expect LLVM to reorder things) but it will
235 // make IR dumps easier to read.
236 m_out
.appendTo(lowBlock
, m_nextLowBlock
);
238 if (Options::ftlCrashes())
239 m_out
.crashNonTerminal();
241 if (!m_highBlock
->cfaHasVisited
) {
246 initializeOSRExitStateForBlock();
249 m_state
.beginBasicBlock(m_highBlock
);
251 for (m_nodeIndex
= 0; m_nodeIndex
< m_highBlock
->size(); ++m_nodeIndex
) {
252 if (!compileNode(m_nodeIndex
))
257 bool compileNode(unsigned nodeIndex
)
259 if (!m_state
.isValid()) {
264 m_node
= m_highBlock
->at(nodeIndex
);
265 m_codeOriginForExitProfile
= m_node
->origin
.semantic
;
266 m_codeOriginForExitTarget
= m_node
->origin
.forExit
;
268 if (verboseCompilationEnabled())
269 dataLog("Lowering ", m_node
, "\n");
271 m_availableRecoveries
.resize(0);
273 bool shouldExecuteEffects
= m_interpreter
.startExecuting(m_node
);
275 switch (m_node
->op()) {
285 compileDoubleConstant();
288 compileInt52Constant();
291 compileWeakJSConstant();
293 case PhantomArguments
:
294 compilePhantomArguments();
306 compileValueToInt32();
308 case BooleanToNumber
:
309 compileBooleanToNumber();
312 compileGetArgument();
314 case ExtractOSREntryLocal
:
315 compileExtractOSREntryLocal();
326 case GetMyArgumentsLength
:
327 compileGetMyArgumentsLength();
329 case GetMyArgumentByVal
:
330 compileGetMyArgumentByVal();
347 compileArithAddOrSub();
360 compileArithMinOrMax();
375 compileArithFRound();
378 compileArithNegate();
399 compileUInt32ToNumber();
402 compileCheckStructure();
404 case StructureTransitionWatchpoint
:
405 compileStructureTransitionWatchpoint();
408 compileCheckFunction();
410 case CheckExecutable
:
411 compileCheckExecutable();
413 case ArrayifyToStructure
:
414 compileArrayifyToStructure();
417 compilePutStructure();
419 case PhantomPutStructure
:
420 compilePhantomPutStructure();
430 compileGetButterfly();
432 case ConstantStoragePointer
:
433 compileConstantStoragePointer();
435 case GetIndexedPropertyStorage
:
436 compileGetIndexedPropertyStorage();
442 compileGetArrayLength();
445 compileCheckInBounds();
468 compileNewArrayBuffer();
470 case NewArrayWithSize
:
471 compileNewArrayWithSize();
473 case GetTypedArrayByteOffset
:
474 compileGetTypedArrayByteOffset();
476 case AllocatePropertyStorage
:
477 compileAllocatePropertyStorage();
479 case ReallocatePropertyStorage
:
480 compileReallocatePropertyStorage();
486 compileToPrimitive();
492 compileStringCharAt();
494 case StringCharCodeAt
:
495 compileStringCharCodeAt();
498 compileGetByOffset();
500 case MultiGetByOffset
:
501 compileMultiGetByOffset();
504 compilePutByOffset();
506 case MultiPutByOffset
:
507 compileMultiPutByOffset();
510 compileGetGlobalVar();
513 compilePutGlobalVar();
516 compileNotifyWrite();
530 case GetClosureRegisters
:
531 compileGetClosureRegisters();
534 compileGetClosureVar();
537 compilePutClosureVar();
542 case CompareEqConstant
:
543 compileCompareEqConstant();
545 case CompareStrictEq
:
546 compileCompareStrictEq();
549 compileCompareLess();
552 compileCompareLessEq();
555 compileCompareGreater();
557 case CompareGreaterEq
:
558 compileCompareGreaterEq();
565 compileCallOrConstruct();
580 compileForceOSRExit();
583 case ThrowReferenceError
:
586 case InvalidationPoint
:
587 compileInvalidationPoint();
589 case CheckArgumentsNotCreated
:
590 compileCheckArgumentsNotCreated();
593 compileIsUndefined();
610 case CheckHasInstance
:
611 compileCheckHasInstance();
617 compileCountExecution();
620 compileStoreBarrier();
622 case StoreBarrierWithNullCheck
:
623 compileStoreBarrierWithNullCheck();
628 case VariableWatchpoint
:
629 case FunctionReentryWatchpoint
:
630 case TypedArrayWatchpoint
:
631 case AllocationProfileWatchpoint
:
634 dataLog("Unrecognized node in FTL backend:\n");
635 m_graph
.dump(WTF::dataFile(), " ", m_node
);
637 dataLog("Full graph dump:\n");
639 RELEASE_ASSERT_NOT_REACHED();
643 if (shouldExecuteEffects
)
644 m_interpreter
.executeEffects(nodeIndex
);
649 void compileUpsilon()
651 LValue destination
= m_phis
.get(m_node
->phi());
653 switch (m_node
->child1().useKind()) {
655 m_out
.set(lowDouble(m_node
->child1()), destination
);
658 m_out
.set(lowInt32(m_node
->child1()), destination
);
661 m_out
.set(lowInt52(m_node
->child1()), destination
);
664 m_out
.set(lowBoolean(m_node
->child1()), destination
);
667 m_out
.set(lowCell(m_node
->child1()), destination
);
670 m_out
.set(lowJSValue(m_node
->child1()), destination
);
673 RELEASE_ASSERT_NOT_REACHED();
680 LValue source
= m_phis
.get(m_node
);
682 switch (m_node
->flags() & NodeResultMask
) {
683 case NodeResultDouble
:
684 setDouble(m_out
.get(source
));
686 case NodeResultInt32
:
687 setInt32(m_out
.get(source
));
689 case NodeResultInt52
:
690 setInt52(m_out
.get(source
));
692 case NodeResultBoolean
:
693 setBoolean(m_out
.get(source
));
696 setJSValue(m_out
.get(source
));
699 RELEASE_ASSERT_NOT_REACHED();
704 void compileDoubleConstant()
706 setDouble(m_out
.constDouble(m_graph
.valueOfNumberConstant(m_node
)));
709 void compileInt52Constant()
711 int64_t value
= m_graph
.valueOfJSConstant(m_node
).asMachineInt();
713 setInt52(m_out
.constInt64(value
<< JSValue::int52ShiftAmount
));
714 setStrictInt52(m_out
.constInt64(value
));
717 void compileWeakJSConstant()
719 setJSValue(weakPointer(m_node
->weakConstant()));
722 void compilePhantomArguments()
724 setJSValue(m_out
.constInt64(JSValue::encode(JSValue())));
727 void compileDoubleRep()
729 switch (m_node
->child1().useKind()) {
731 LValue value
= lowJSValue(m_node
->child1(), ManualOperandSpeculation
);
732 setDouble(jsValueToDouble(m_node
->child1(), value
));
737 setDouble(strictInt52ToDouble(lowStrictInt52(m_node
->child1())));
742 RELEASE_ASSERT_NOT_REACHED();
746 void compileValueRep()
748 switch (m_node
->child1().useKind()) {
750 LValue value
= lowDouble(m_node
->child1());
752 if (m_interpreter
.needsTypeCheck(m_node
->child1(), ~SpecDoubleImpureNaN
)) {
753 value
= m_out
.select(
754 m_out
.doubleEqual(value
, value
), value
, m_out
.constDouble(PNaN
));
757 setJSValue(boxDouble(value
));
762 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node
->child1())));
767 RELEASE_ASSERT_NOT_REACHED();
771 void compileInt52Rep()
773 switch (m_node
->child1().useKind()) {
775 setStrictInt52(m_out
.signExt(lowInt32(m_node
->child1()), m_out
.int64
));
780 jsValueToStrictInt52(
781 m_node
->child1(), lowJSValue(m_node
->child1(), ManualOperandSpeculation
)));
784 case DoubleRepMachineIntUse
:
787 m_node
->child1(), lowDouble(m_node
->child1())));
791 RELEASE_ASSERT_NOT_REACHED();
795 void compileValueToInt32()
797 switch (m_node
->child1().useKind()) {
799 setInt32(m_out
.castToInt32(lowStrictInt52(m_node
->child1())));
803 setInt32(doubleToInt32(lowDouble(m_node
->child1())));
808 LoweredNodeValue value
= m_int32Values
.get(m_node
->child1().node());
809 if (isValid(value
)) {
810 setInt32(value
.value());
814 value
= m_jsValueValues
.get(m_node
->child1().node());
815 if (isValid(value
)) {
816 setInt32(numberOrNotCellToInt32(m_node
->child1(), value
.value()));
820 // We'll basically just get here for constants. But it's good to have this
821 // catch-all since we often add new representations into the mix.
823 numberOrNotCellToInt32(
825 lowJSValue(m_node
->child1(), ManualOperandSpeculation
)));
830 RELEASE_ASSERT_NOT_REACHED();
835 void compileBooleanToNumber()
837 switch (m_node
->child1().useKind()) {
839 setInt32(m_out
.zeroExt(lowBoolean(m_node
->child1()), m_out
.int32
));
844 LValue value
= lowJSValue(m_node
->child1());
846 LBasicBlock booleanCase
= FTL_NEW_BLOCK(m_out
, ("BooleanToNumber boolean case"));
847 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("BooleanToNumber continuation"));
849 ValueFromBlock notBooleanResult
= m_out
.anchor(value
);
850 m_out
.branch(isBoolean(value
), unsure(booleanCase
), unsure(continuation
));
852 LBasicBlock lastNext
= m_out
.appendTo(booleanCase
, continuation
);
853 ValueFromBlock booleanResult
= m_out
.anchor(m_out
.bitOr(
854 m_out
.zeroExt(unboxBoolean(value
), m_out
.int64
), m_tagTypeNumber
));
855 m_out
.jump(continuation
);
857 m_out
.appendTo(continuation
, lastNext
);
858 setJSValue(m_out
.phi(m_out
.int64
, booleanResult
, notBooleanResult
));
863 RELEASE_ASSERT_NOT_REACHED();
868 void compileGetArgument()
870 VariableAccessData
* variable
= m_node
->variableAccessData();
871 VirtualRegister operand
= variable
->machineLocal();
872 RELEASE_ASSERT(operand
.isArgument());
874 LValue jsValue
= m_out
.load64(addressFor(operand
));
876 switch (useKindFor(variable
->flushFormat())) {
878 speculate(BadType
, jsValueValue(jsValue
), m_node
, isNotInt32(jsValue
));
879 setInt32(unboxInt32(jsValue
));
882 speculate(BadType
, jsValueValue(jsValue
), m_node
, isNotCell(jsValue
));
886 speculate(BadType
, jsValueValue(jsValue
), m_node
, isNotBoolean(jsValue
));
887 setBoolean(unboxBoolean(jsValue
));
893 RELEASE_ASSERT_NOT_REACHED();
898 void compileExtractOSREntryLocal()
900 EncodedJSValue
* buffer
= static_cast<EncodedJSValue
*>(
901 m_ftlState
.jitCode
->ftlForOSREntry()->entryBuffer()->dataBuffer());
902 setJSValue(m_out
.load64(m_out
.absolute(buffer
+ m_node
->unlinkedLocal().toLocal())));
905 void compileGetLocal()
907 // GetLocals arise only for captured variables.
909 VariableAccessData
* variable
= m_node
->variableAccessData();
910 AbstractValue
& value
= m_state
.variables().operand(variable
->local());
912 RELEASE_ASSERT(variable
->isCaptured());
914 if (isInt32Speculation(value
.m_type
))
915 setInt32(m_out
.load32(payloadFor(variable
->machineLocal())));
917 setJSValue(m_out
.load64(addressFor(variable
->machineLocal())));
920 void compileSetLocal()
922 VariableAccessData
* variable
= m_node
->variableAccessData();
923 switch (variable
->flushFormat()) {
925 case FlushedArguments
: {
926 LValue value
= lowJSValue(m_node
->child1());
927 m_out
.store64(value
, addressFor(variable
->machineLocal()));
931 case FlushedDouble
: {
932 LValue value
= lowDouble(m_node
->child1());
933 m_out
.storeDouble(value
, addressFor(variable
->machineLocal()));
938 LValue value
= lowInt32(m_node
->child1());
939 m_out
.store32(value
, payloadFor(variable
->machineLocal()));
944 LValue value
= lowInt52(m_node
->child1());
945 m_out
.store64(value
, addressFor(variable
->machineLocal()));
950 LValue value
= lowCell(m_node
->child1());
951 m_out
.store64(value
, addressFor(variable
->machineLocal()));
955 case FlushedBoolean
: {
956 speculateBoolean(m_node
->child1());
958 lowJSValue(m_node
->child1(), ManualOperandSpeculation
),
959 addressFor(variable
->machineLocal()));
964 RELEASE_ASSERT_NOT_REACHED();
968 m_availability
.operand(variable
->local()) = Availability(variable
->flushedAt());
971 void compileMovHint()
973 ASSERT(m_node
->containsMovHint());
974 ASSERT(m_node
->op() != ZombieHint
);
976 VirtualRegister operand
= m_node
->unlinkedLocal();
977 m_availability
.operand(operand
) = Availability(m_node
->child1().node());
980 void compileZombieHint()
982 m_availability
.operand(m_node
->unlinkedLocal()) = Availability::unavailable();
985 void compilePhantom()
987 DFG_NODE_DO_TO_CHILDREN(m_graph
, m_node
, speculate
);
992 LValue value
= lowJSValue(m_node
->child1());
994 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("ToThis is cell case"));
995 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("ToThis slow case"));
996 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ToThis continuation"));
998 m_out
.branch(isCell(value
), usually(isCellCase
), rarely(slowCase
));
1000 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, slowCase
);
1001 ValueFromBlock fastResult
= m_out
.anchor(value
);
1002 m_out
.branch(isType(value
, FinalObjectType
), usually(continuation
), rarely(slowCase
));
1004 m_out
.appendTo(slowCase
, continuation
);
1005 J_JITOperation_EJ function
;
1006 if (m_graph
.isStrictModeFor(m_node
->origin
.semantic
))
1007 function
= operationToThisStrict
;
1009 function
= operationToThis
;
1010 ValueFromBlock slowResult
= m_out
.anchor(
1011 vmCall(m_out
.operation(function
), m_callFrame
, value
));
1012 m_out
.jump(continuation
);
1014 m_out
.appendTo(continuation
, lastNext
);
1015 setJSValue(m_out
.phi(m_out
.int64
, fastResult
, slowResult
));
1018 void compileValueAdd()
1020 J_JITOperation_EJJ operation
;
1021 if (!(m_state
.forNode(m_node
->child1()).m_type
& SpecFullNumber
)
1022 && !(m_state
.forNode(m_node
->child2()).m_type
& SpecFullNumber
))
1023 operation
= operationValueAddNotNumber
;
1025 operation
= operationValueAdd
;
1027 m_out
.operation(operation
), m_callFrame
,
1028 lowJSValue(m_node
->child1()), lowJSValue(m_node
->child2())));
1031 void compileArithAddOrSub()
1033 bool isSub
= m_node
->op() == ArithSub
;
1034 switch (m_node
->binaryUseKind()) {
1036 LValue left
= lowInt32(m_node
->child1());
1037 LValue right
= lowInt32(m_node
->child2());
1039 if (!shouldCheckOverflow(m_node
->arithMode())) {
1040 setInt32(isSub
? m_out
.sub(left
, right
) : m_out
.add(left
, right
));
1046 result
= m_out
.addWithOverflow32(left
, right
);
1048 if (doesKill(m_node
->child2())) {
1049 addAvailableRecovery(
1050 m_node
->child2(), SubRecovery
,
1051 m_out
.extractValue(result
, 0), left
, ValueFormatInt32
);
1052 } else if (doesKill(m_node
->child1())) {
1053 addAvailableRecovery(
1054 m_node
->child1(), SubRecovery
,
1055 m_out
.extractValue(result
, 0), right
, ValueFormatInt32
);
1058 result
= m_out
.subWithOverflow32(left
, right
);
1060 if (doesKill(m_node
->child2())) {
1061 // result = left - right
1062 // result - left = -right
1063 // right = left - result
1064 addAvailableRecovery(
1065 m_node
->child2(), SubRecovery
,
1066 left
, m_out
.extractValue(result
, 0), ValueFormatInt32
);
1067 } else if (doesKill(m_node
->child1())) {
1068 // result = left - right
1069 // result + right = left
1070 addAvailableRecovery(
1071 m_node
->child1(), AddRecovery
,
1072 m_out
.extractValue(result
, 0), right
, ValueFormatInt32
);
1076 speculate(Overflow
, noValue(), 0, m_out
.extractValue(result
, 1));
1077 setInt32(m_out
.extractValue(result
, 0));
1082 if (!m_state
.forNode(m_node
->child1()).couldBeType(SpecInt52
)
1083 && !m_state
.forNode(m_node
->child2()).couldBeType(SpecInt52
)) {
1085 LValue left
= lowWhicheverInt52(m_node
->child1(), kind
);
1086 LValue right
= lowInt52(m_node
->child2(), kind
);
1087 setInt52(isSub
? m_out
.sub(left
, right
) : m_out
.add(left
, right
), kind
);
1091 LValue left
= lowInt52(m_node
->child1());
1092 LValue right
= lowInt52(m_node
->child2());
1096 result
= m_out
.addWithOverflow64(left
, right
);
1098 if (doesKill(m_node
->child2())) {
1099 addAvailableRecovery(
1100 m_node
->child2(), SubRecovery
,
1101 m_out
.extractValue(result
, 0), left
, ValueFormatInt52
);
1102 } else if (doesKill(m_node
->child1())) {
1103 addAvailableRecovery(
1104 m_node
->child1(), SubRecovery
,
1105 m_out
.extractValue(result
, 0), right
, ValueFormatInt52
);
1108 result
= m_out
.subWithOverflow64(left
, right
);
1110 if (doesKill(m_node
->child2())) {
1111 // result = left - right
1112 // result - left = -right
1113 // right = left - result
1114 addAvailableRecovery(
1115 m_node
->child2(), SubRecovery
,
1116 left
, m_out
.extractValue(result
, 0), ValueFormatInt52
);
1117 } else if (doesKill(m_node
->child1())) {
1118 // result = left - right
1119 // result + right = left
1120 addAvailableRecovery(
1121 m_node
->child1(), AddRecovery
,
1122 m_out
.extractValue(result
, 0), right
, ValueFormatInt52
);
1126 speculate(Int52Overflow
, noValue(), 0, m_out
.extractValue(result
, 1));
1127 setInt52(m_out
.extractValue(result
, 0));
1131 case DoubleRepUse
: {
1132 LValue C1
= lowDouble(m_node
->child1());
1133 LValue C2
= lowDouble(m_node
->child2());
1135 setDouble(isSub
? m_out
.doubleSub(C1
, C2
) : m_out
.doubleAdd(C1
, C2
));
1140 RELEASE_ASSERT_NOT_REACHED();
1145 void compileArithMul()
1147 switch (m_node
->binaryUseKind()) {
1149 LValue left
= lowInt32(m_node
->child1());
1150 LValue right
= lowInt32(m_node
->child2());
1154 if (!shouldCheckOverflow(m_node
->arithMode()))
1155 result
= m_out
.mul(left
, right
);
1157 LValue overflowResult
= m_out
.mulWithOverflow32(left
, right
);
1158 speculate(Overflow
, noValue(), 0, m_out
.extractValue(overflowResult
, 1));
1159 result
= m_out
.extractValue(overflowResult
, 0);
1162 if (shouldCheckNegativeZero(m_node
->arithMode())) {
1163 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("ArithMul slow case"));
1164 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArithMul continuation"));
1167 m_out
.notZero32(result
), usually(continuation
), rarely(slowCase
));
1169 LBasicBlock lastNext
= m_out
.appendTo(slowCase
, continuation
);
1170 LValue cond
= m_out
.bitOr(m_out
.lessThan(left
, m_out
.int32Zero
), m_out
.lessThan(right
, m_out
.int32Zero
));
1171 speculate(NegativeZero
, noValue(), 0, cond
);
1172 m_out
.jump(continuation
);
1173 m_out
.appendTo(continuation
, lastNext
);
1182 LValue left
= lowWhicheverInt52(m_node
->child1(), kind
);
1183 LValue right
= lowInt52(m_node
->child2(), opposite(kind
));
1185 LValue overflowResult
= m_out
.mulWithOverflow64(left
, right
);
1186 speculate(Int52Overflow
, noValue(), 0, m_out
.extractValue(overflowResult
, 1));
1187 LValue result
= m_out
.extractValue(overflowResult
, 0);
1189 if (shouldCheckNegativeZero(m_node
->arithMode())) {
1190 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("ArithMul slow case"));
1191 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArithMul continuation"));
1194 m_out
.notZero64(result
), usually(continuation
), rarely(slowCase
));
1196 LBasicBlock lastNext
= m_out
.appendTo(slowCase
, continuation
);
1197 LValue cond
= m_out
.bitOr(m_out
.lessThan(left
, m_out
.int64Zero
), m_out
.lessThan(right
, m_out
.int64Zero
));
1198 speculate(NegativeZero
, noValue(), 0, cond
);
1199 m_out
.jump(continuation
);
1200 m_out
.appendTo(continuation
, lastNext
);
1207 case DoubleRepUse
: {
1209 m_out
.doubleMul(lowDouble(m_node
->child1()), lowDouble(m_node
->child2())));
1214 RELEASE_ASSERT_NOT_REACHED();
1219 void compileArithDiv()
1221 switch (m_node
->binaryUseKind()) {
1223 LValue numerator
= lowInt32(m_node
->child1());
1224 LValue denominator
= lowInt32(m_node
->child2());
1226 LBasicBlock unsafeDenominator
= FTL_NEW_BLOCK(m_out
, ("ArithDiv unsafe denominator"));
1227 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArithDiv continuation"));
1228 LBasicBlock done
= FTL_NEW_BLOCK(m_out
, ("ArithDiv done"));
1230 Vector
<ValueFromBlock
, 3> results
;
1232 LValue adjustedDenominator
= m_out
.add(denominator
, m_out
.int32One
);
1235 m_out
.above(adjustedDenominator
, m_out
.int32One
),
1236 usually(continuation
), rarely(unsafeDenominator
));
1238 LBasicBlock lastNext
= m_out
.appendTo(unsafeDenominator
, continuation
);
1240 LValue neg2ToThe31
= m_out
.constInt32(-2147483647-1);
1242 if (shouldCheckOverflow(m_node
->arithMode())) {
1243 LValue cond
= m_out
.bitOr(m_out
.isZero32(denominator
), m_out
.equal(numerator
, neg2ToThe31
));
1244 speculate(Overflow
, noValue(), 0, cond
);
1245 m_out
.jump(continuation
);
1247 // This is the case where we convert the result to an int after we're done. So,
1248 // if the denominator is zero, then the result should be zero.
1249 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1250 // check above) and the numerator is -2^31 then the result should be -2^31.
1252 LBasicBlock divByZero
= FTL_NEW_BLOCK(m_out
, ("ArithDiv divide by zero"));
1253 LBasicBlock notDivByZero
= FTL_NEW_BLOCK(m_out
, ("ArithDiv not divide by zero"));
1254 LBasicBlock neg2ToThe31ByNeg1
= FTL_NEW_BLOCK(m_out
, ("ArithDiv -2^31/-1"));
1257 m_out
.isZero32(denominator
), rarely(divByZero
), usually(notDivByZero
));
1259 m_out
.appendTo(divByZero
, notDivByZero
);
1260 results
.append(m_out
.anchor(m_out
.int32Zero
));
1263 m_out
.appendTo(notDivByZero
, neg2ToThe31ByNeg1
);
1265 m_out
.equal(numerator
, neg2ToThe31
),
1266 rarely(neg2ToThe31ByNeg1
), usually(continuation
));
1268 m_out
.appendTo(neg2ToThe31ByNeg1
, continuation
);
1269 results
.append(m_out
.anchor(neg2ToThe31
));
1273 m_out
.appendTo(continuation
, done
);
1275 if (shouldCheckNegativeZero(m_node
->arithMode())) {
1276 LBasicBlock zeroNumerator
= FTL_NEW_BLOCK(m_out
, ("ArithDiv zero numerator"));
1277 LBasicBlock numeratorContinuation
= FTL_NEW_BLOCK(m_out
, ("ArithDiv numerator continuation"));
1280 m_out
.isZero32(numerator
),
1281 rarely(zeroNumerator
), usually(numeratorContinuation
));
1283 LBasicBlock innerLastNext
= m_out
.appendTo(zeroNumerator
, numeratorContinuation
);
1286 NegativeZero
, noValue(), 0, m_out
.lessThan(denominator
, m_out
.int32Zero
));
1288 m_out
.jump(numeratorContinuation
);
1290 m_out
.appendTo(numeratorContinuation
, innerLastNext
);
1293 LValue result
= m_out
.div(numerator
, denominator
);
1295 if (shouldCheckOverflow(m_node
->arithMode())) {
1297 Overflow
, noValue(), 0,
1298 m_out
.notEqual(m_out
.mul(result
, denominator
), numerator
));
1301 results
.append(m_out
.anchor(result
));
1304 m_out
.appendTo(done
, lastNext
);
1306 setInt32(m_out
.phi(m_out
.int32
, results
));
1310 case DoubleRepUse
: {
1311 setDouble(m_out
.doubleDiv(
1312 lowDouble(m_node
->child1()), lowDouble(m_node
->child2())));
1317 RELEASE_ASSERT_NOT_REACHED();
1322 void compileArithMod()
1324 switch (m_node
->binaryUseKind()) {
1326 LValue numerator
= lowInt32(m_node
->child1());
1327 LValue denominator
= lowInt32(m_node
->child2());
1329 LBasicBlock unsafeDenominator
= FTL_NEW_BLOCK(m_out
, ("ArithMod unsafe denominator"));
1330 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArithMod continuation"));
1331 LBasicBlock done
= FTL_NEW_BLOCK(m_out
, ("ArithMod done"));
1333 Vector
<ValueFromBlock
, 3> results
;
1335 LValue adjustedDenominator
= m_out
.add(denominator
, m_out
.int32One
);
1338 m_out
.above(adjustedDenominator
, m_out
.int32One
),
1339 usually(continuation
), rarely(unsafeDenominator
));
1341 LBasicBlock lastNext
= m_out
.appendTo(unsafeDenominator
, continuation
);
1343 LValue neg2ToThe31
= m_out
.constInt32(-2147483647-1);
1345 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
1346 // separate case for that. But it probably doesn't matter so much.
1347 if (shouldCheckOverflow(m_node
->arithMode())) {
1348 LValue cond
= m_out
.bitOr(m_out
.isZero32(denominator
), m_out
.equal(numerator
, neg2ToThe31
));
1349 speculate(Overflow
, noValue(), 0, cond
);
1350 m_out
.jump(continuation
);
1352 // This is the case where we convert the result to an int after we're done. So,
1353 // if the denominator is zero, then the result should be result should be zero.
1354 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1355 // check above) and the numerator is -2^31 then the result should be -2^31.
1357 LBasicBlock modByZero
= FTL_NEW_BLOCK(m_out
, ("ArithMod modulo by zero"));
1358 LBasicBlock notModByZero
= FTL_NEW_BLOCK(m_out
, ("ArithMod not modulo by zero"));
1359 LBasicBlock neg2ToThe31ByNeg1
= FTL_NEW_BLOCK(m_out
, ("ArithMod -2^31/-1"));
1362 m_out
.isZero32(denominator
), rarely(modByZero
), usually(notModByZero
));
1364 m_out
.appendTo(modByZero
, notModByZero
);
1365 results
.append(m_out
.anchor(m_out
.int32Zero
));
1368 m_out
.appendTo(notModByZero
, neg2ToThe31ByNeg1
);
1370 m_out
.equal(numerator
, neg2ToThe31
),
1371 rarely(neg2ToThe31ByNeg1
), usually(continuation
));
1373 m_out
.appendTo(neg2ToThe31ByNeg1
, continuation
);
1374 results
.append(m_out
.anchor(m_out
.int32Zero
));
1378 m_out
.appendTo(continuation
, done
);
1380 LValue remainder
= m_out
.rem(numerator
, denominator
);
1382 if (shouldCheckNegativeZero(m_node
->arithMode())) {
1383 LBasicBlock negativeNumerator
= FTL_NEW_BLOCK(m_out
, ("ArithMod negative numerator"));
1384 LBasicBlock numeratorContinuation
= FTL_NEW_BLOCK(m_out
, ("ArithMod numerator continuation"));
1387 m_out
.lessThan(numerator
, m_out
.int32Zero
),
1388 unsure(negativeNumerator
), unsure(numeratorContinuation
));
1390 LBasicBlock innerLastNext
= m_out
.appendTo(negativeNumerator
, numeratorContinuation
);
1392 speculate(NegativeZero
, noValue(), 0, m_out
.isZero32(remainder
));
1394 m_out
.jump(numeratorContinuation
);
1396 m_out
.appendTo(numeratorContinuation
, innerLastNext
);
1399 results
.append(m_out
.anchor(remainder
));
1402 m_out
.appendTo(done
, lastNext
);
1404 setInt32(m_out
.phi(m_out
.int32
, results
));
1408 case DoubleRepUse
: {
1410 m_out
.doubleRem(lowDouble(m_node
->child1()), lowDouble(m_node
->child2())));
1415 RELEASE_ASSERT_NOT_REACHED();
1420 void compileArithMinOrMax()
1422 switch (m_node
->binaryUseKind()) {
1424 LValue left
= lowInt32(m_node
->child1());
1425 LValue right
= lowInt32(m_node
->child2());
1429 m_node
->op() == ArithMin
1430 ? m_out
.lessThan(left
, right
)
1431 : m_out
.lessThan(right
, left
),
1436 case DoubleRepUse
: {
1437 LValue left
= lowDouble(m_node
->child1());
1438 LValue right
= lowDouble(m_node
->child2());
1440 LBasicBlock notLessThan
= FTL_NEW_BLOCK(m_out
, ("ArithMin/ArithMax not less than"));
1441 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArithMin/ArithMax continuation"));
1443 Vector
<ValueFromBlock
, 2> results
;
1445 results
.append(m_out
.anchor(left
));
1447 m_node
->op() == ArithMin
1448 ? m_out
.doubleLessThan(left
, right
)
1449 : m_out
.doubleGreaterThan(left
, right
),
1450 unsure(continuation
), unsure(notLessThan
));
1452 LBasicBlock lastNext
= m_out
.appendTo(notLessThan
, continuation
);
1453 results
.append(m_out
.anchor(m_out
.select(
1454 m_node
->op() == ArithMin
1455 ? m_out
.doubleGreaterThanOrEqual(left
, right
)
1456 : m_out
.doubleLessThanOrEqual(left
, right
),
1457 right
, m_out
.constDouble(PNaN
))));
1458 m_out
.jump(continuation
);
1460 m_out
.appendTo(continuation
, lastNext
);
1461 setDouble(m_out
.phi(m_out
.doubleType
, results
));
1466 RELEASE_ASSERT_NOT_REACHED();
1471 void compileArithAbs()
1473 switch (m_node
->child1().useKind()) {
1475 LValue value
= lowInt32(m_node
->child1());
1477 LValue mask
= m_out
.aShr(value
, m_out
.constInt32(31));
1478 LValue result
= m_out
.bitXor(mask
, m_out
.add(mask
, value
));
1480 speculate(Overflow
, noValue(), 0, m_out
.equal(result
, m_out
.constInt32(1 << 31)));
1486 case DoubleRepUse
: {
1487 setDouble(m_out
.doubleAbs(lowDouble(m_node
->child1())));
1492 RELEASE_ASSERT_NOT_REACHED();
1497 void compileArithSin() { setDouble(m_out
.doubleSin(lowDouble(m_node
->child1()))); }
1499 void compileArithCos() { setDouble(m_out
.doubleCos(lowDouble(m_node
->child1()))); }
1501 void compileArithSqrt() { setDouble(m_out
.doubleSqrt(lowDouble(m_node
->child1()))); }
1503 void compileArithFRound()
1505 LValue floatValue
= m_out
.fpCast(lowDouble(m_node
->child1()), m_out
.floatType
);
1506 setDouble(m_out
.fpCast(floatValue
, m_out
.doubleType
));
1509 void compileArithNegate()
1511 switch (m_node
->child1().useKind()) {
1513 LValue value
= lowInt32(m_node
->child1());
1516 if (!shouldCheckOverflow(m_node
->arithMode()))
1517 result
= m_out
.neg(value
);
1518 else if (!shouldCheckNegativeZero(m_node
->arithMode())) {
1519 // We don't have a negate-with-overflow intrinsic. Hopefully this
1520 // does the trick, though.
1521 LValue overflowResult
= m_out
.subWithOverflow32(m_out
.int32Zero
, value
);
1522 speculate(Overflow
, noValue(), 0, m_out
.extractValue(overflowResult
, 1));
1523 result
= m_out
.extractValue(overflowResult
, 0);
1525 speculate(Overflow
, noValue(), 0, m_out
.testIsZero32(value
, m_out
.constInt32(0x7fffffff)));
1526 result
= m_out
.neg(value
);
1534 if (!m_state
.forNode(m_node
->child1()).couldBeType(SpecInt52
)) {
1536 LValue value
= lowWhicheverInt52(m_node
->child1(), kind
);
1537 LValue result
= m_out
.neg(value
);
1538 if (shouldCheckNegativeZero(m_node
->arithMode()))
1539 speculate(NegativeZero
, noValue(), 0, m_out
.isZero64(result
));
1540 setInt52(result
, kind
);
1544 LValue value
= lowInt52(m_node
->child1());
1545 LValue overflowResult
= m_out
.subWithOverflow64(m_out
.int64Zero
, value
);
1546 speculate(Int52Overflow
, noValue(), 0, m_out
.extractValue(overflowResult
, 1));
1547 LValue result
= m_out
.extractValue(overflowResult
, 0);
1548 speculate(NegativeZero
, noValue(), 0, m_out
.isZero64(result
));
1553 case DoubleRepUse
: {
1554 setDouble(m_out
.doubleNeg(lowDouble(m_node
->child1())));
1559 RELEASE_ASSERT_NOT_REACHED();
1564 void compileBitAnd()
1566 setInt32(m_out
.bitAnd(lowInt32(m_node
->child1()), lowInt32(m_node
->child2())));
1571 setInt32(m_out
.bitOr(lowInt32(m_node
->child1()), lowInt32(m_node
->child2())));
1574 void compileBitXor()
1576 setInt32(m_out
.bitXor(lowInt32(m_node
->child1()), lowInt32(m_node
->child2())));
1579 void compileBitRShift()
1581 setInt32(m_out
.aShr(
1582 lowInt32(m_node
->child1()),
1583 m_out
.bitAnd(lowInt32(m_node
->child2()), m_out
.constInt32(31))));
1586 void compileBitLShift()
1589 lowInt32(m_node
->child1()),
1590 m_out
.bitAnd(lowInt32(m_node
->child2()), m_out
.constInt32(31))));
1593 void compileBitURShift()
1595 setInt32(m_out
.lShr(
1596 lowInt32(m_node
->child1()),
1597 m_out
.bitAnd(lowInt32(m_node
->child2()), m_out
.constInt32(31))));
1600 void compileUInt32ToNumber()
1602 LValue value
= lowInt32(m_node
->child1());
1604 if (doesOverflow(m_node
->arithMode())) {
1605 setDouble(m_out
.unsignedToDouble(value
));
1609 speculate(Overflow
, noValue(), 0, m_out
.lessThan(value
, m_out
.int32Zero
));
1613 void compileCheckStructure()
1615 LValue cell
= lowCell(m_node
->child1());
1618 if (m_node
->child1()->op() == WeakJSConstant
)
1619 exitKind
= BadWeakConstantCache
;
1621 exitKind
= BadCache
;
1623 LValue structureID
= m_out
.load32(cell
, m_heaps
.JSCell_structureID
);
1625 if (m_node
->structureSet().size() == 1) {
1627 exitKind
, jsValueValue(cell
), 0,
1628 m_out
.notEqual(structureID
, weakStructure(m_node
->structureSet()[0])));
1632 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("CheckStructure continuation"));
1634 LBasicBlock lastNext
= m_out
.insertNewBlocksBefore(continuation
);
1635 for (unsigned i
= 0; i
< m_node
->structureSet().size() - 1; ++i
) {
1636 LBasicBlock nextStructure
= FTL_NEW_BLOCK(m_out
, ("CheckStructure nextStructure"));
1638 m_out
.equal(structureID
, weakStructure(m_node
->structureSet()[i
])),
1639 unsure(continuation
), unsure(nextStructure
));
1640 m_out
.appendTo(nextStructure
);
1644 exitKind
, jsValueValue(cell
), 0,
1645 m_out
.notEqual(structureID
, weakStructure(m_node
->structureSet().last())));
1647 m_out
.jump(continuation
);
1648 m_out
.appendTo(continuation
, lastNext
);
1651 void compileStructureTransitionWatchpoint()
1653 addWeakReference(m_node
->structure());
1654 speculateCell(m_node
->child1());
1657 void compileCheckFunction()
1659 LValue cell
= lowCell(m_node
->child1());
1662 BadFunction
, jsValueValue(cell
), m_node
->child1().node(),
1663 m_out
.notEqual(cell
, weakPointer(m_node
->function())));
1666 void compileCheckExecutable()
1668 LValue cell
= lowCell(m_node
->child1());
1671 BadExecutable
, jsValueValue(cell
), m_node
->child1().node(),
1673 m_out
.loadPtr(cell
, m_heaps
.JSFunction_executable
),
1674 weakPointer(m_node
->executable())));
1677 void compileArrayifyToStructure()
1679 LValue cell
= lowCell(m_node
->child1());
1680 LValue property
= !!m_node
->child2() ? lowInt32(m_node
->child2()) : 0;
1682 LBasicBlock unexpectedStructure
= FTL_NEW_BLOCK(m_out
, ("ArrayifyToStructure unexpected structure"));
1683 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArrayifyToStructure continuation"));
1685 LValue structureID
= m_out
.load32(cell
, m_heaps
.JSCell_structureID
);
1688 m_out
.notEqual(structureID
, weakStructure(m_node
->structure())),
1689 rarely(unexpectedStructure
), usually(continuation
));
1691 LBasicBlock lastNext
= m_out
.appendTo(unexpectedStructure
, continuation
);
1694 switch (m_node
->arrayMode().type()) {
1697 case Array::Contiguous
:
1699 Uncountable
, noValue(), 0,
1700 m_out
.aboveOrEqual(property
, m_out
.constInt32(MIN_SPARSE_ARRAY_INDEX
)));
1707 switch (m_node
->arrayMode().type()) {
1709 vmCall(m_out
.operation(operationEnsureInt32
), m_callFrame
, cell
);
1712 vmCall(m_out
.operation(operationEnsureDouble
), m_callFrame
, cell
);
1714 case Array::Contiguous
:
1715 if (m_node
->arrayMode().conversion() == Array::RageConvert
)
1716 vmCall(m_out
.operation(operationRageEnsureContiguous
), m_callFrame
, cell
);
1718 vmCall(m_out
.operation(operationEnsureContiguous
), m_callFrame
, cell
);
1720 case Array::ArrayStorage
:
1721 case Array::SlowPutArrayStorage
:
1722 vmCall(m_out
.operation(operationEnsureArrayStorage
), m_callFrame
, cell
);
1725 RELEASE_ASSERT_NOT_REACHED();
1729 structureID
= m_out
.load32(cell
, m_heaps
.JSCell_structureID
);
1731 BadIndexingType
, jsValueValue(cell
), 0,
1732 m_out
.notEqual(structureID
, weakStructure(m_node
->structure())));
1733 m_out
.jump(continuation
);
1735 m_out
.appendTo(continuation
, lastNext
);
1738 void compilePutStructure()
1740 m_ftlState
.jitCode
->common
.notifyCompilingStructureTransition(m_graph
.m_plan
, codeBlock(), m_node
);
1742 Structure
* oldStructure
= m_node
->structureTransitionData().previousStructure
;
1743 Structure
* newStructure
= m_node
->structureTransitionData().newStructure
;
1744 ASSERT_UNUSED(oldStructure
, oldStructure
->indexingType() == newStructure
->indexingType());
1745 ASSERT(oldStructure
->typeInfo().inlineTypeFlags() == newStructure
->typeInfo().inlineTypeFlags());
1746 ASSERT(oldStructure
->typeInfo().type() == newStructure
->typeInfo().type());
1748 LValue cell
= lowCell(m_node
->child1());
1750 weakStructure(newStructure
),
1751 cell
, m_heaps
.JSCell_structureID
);
1754 void compilePhantomPutStructure()
1756 m_ftlState
.jitCode
->common
.notifyCompilingStructureTransition(m_graph
.m_plan
, codeBlock(), m_node
);
1759 void compileGetById()
1761 // Pretty much the only reason why we don't also support GetByIdFlush is because:
1762 // https://bugs.webkit.org/show_bug.cgi?id=125711
1764 switch (m_node
->child1().useKind()) {
1766 setJSValue(getById(lowCell(m_node
->child1())));
1771 // This is pretty weird, since we duplicate the slow path both here and in the
1772 // code generated by the IC. We should investigate making this less bad.
1773 // https://bugs.webkit.org/show_bug.cgi?id=127830
1774 LValue value
= lowJSValue(m_node
->child1());
1776 LBasicBlock cellCase
= FTL_NEW_BLOCK(m_out
, ("GetById untyped cell case"));
1777 LBasicBlock notCellCase
= FTL_NEW_BLOCK(m_out
, ("GetById untyped not cell case"));
1778 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("GetById untyped continuation"));
1780 m_out
.branch(isCell(value
), unsure(cellCase
), unsure(notCellCase
));
1782 LBasicBlock lastNext
= m_out
.appendTo(cellCase
, notCellCase
);
1783 ValueFromBlock cellResult
= m_out
.anchor(getById(value
));
1784 m_out
.jump(continuation
);
1786 m_out
.appendTo(notCellCase
, continuation
);
1787 ValueFromBlock notCellResult
= m_out
.anchor(vmCall(
1788 m_out
.operation(operationGetById
),
1789 m_callFrame
, getUndef(m_out
.intPtr
), value
,
1790 m_out
.constIntPtr(m_graph
.identifiers()[m_node
->identifierNumber()])));
1791 m_out
.jump(continuation
);
1793 m_out
.appendTo(continuation
, lastNext
);
1794 setJSValue(m_out
.phi(m_out
.int64
, cellResult
, notCellResult
));
1799 RELEASE_ASSERT_NOT_REACHED();
1804 void compilePutById()
1806 // See above; CellUse is easier so we do only that for now.
1807 ASSERT(m_node
->child1().useKind() == CellUse
);
1809 LValue base
= lowCell(m_node
->child1());
1810 LValue value
= lowJSValue(m_node
->child2());
1811 StringImpl
* uid
= m_graph
.identifiers()[m_node
->identifierNumber()];
1813 // Arguments: id, bytes, target, numArgs, args...
1814 unsigned stackmapID
= m_stackmapIDs
++;
1816 if (Options::verboseCompilation())
1817 dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID
, "\n");
1819 LValue call
= m_out
.call(
1820 m_out
.patchpointVoidIntrinsic(),
1821 m_out
.constInt64(stackmapID
), m_out
.constInt32(sizeOfPutById()),
1822 constNull(m_out
.ref8
), m_out
.constInt32(2), base
, value
);
1823 setInstructionCallingConvention(call
, LLVMAnyRegCallConv
);
1825 m_ftlState
.putByIds
.append(PutByIdDescriptor(
1826 stackmapID
, m_node
->origin
.semantic
, uid
,
1827 m_graph
.executableFor(m_node
->origin
.semantic
)->ecmaMode(),
1828 m_node
->op() == PutByIdDirect
? Direct
: NotDirect
));
1831 void compileGetButterfly()
1833 setStorage(m_out
.loadPtr(lowCell(m_node
->child1()), m_heaps
.JSObject_butterfly
));
1836 void compileConstantStoragePointer()
1838 setStorage(m_out
.constIntPtr(m_node
->storagePointer()));
1841 void compileGetIndexedPropertyStorage()
1843 LValue cell
= lowCell(m_node
->child1());
1845 if (m_node
->arrayMode().type() == Array::String
) {
1846 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("GetIndexedPropertyStorage String slow case"));
1847 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("GetIndexedPropertyStorage String continuation"));
1849 ValueFromBlock fastResult
= m_out
.anchor(
1850 m_out
.loadPtr(cell
, m_heaps
.JSString_value
));
1853 m_out
.notNull(fastResult
.value()), usually(continuation
), rarely(slowPath
));
1855 LBasicBlock lastNext
= m_out
.appendTo(slowPath
, continuation
);
1857 ValueFromBlock slowResult
= m_out
.anchor(
1858 vmCall(m_out
.operation(operationResolveRope
), m_callFrame
, cell
));
1860 m_out
.jump(continuation
);
1862 m_out
.appendTo(continuation
, lastNext
);
1864 setStorage(m_out
.loadPtr(m_out
.phi(m_out
.intPtr
, fastResult
, slowResult
), m_heaps
.StringImpl_data
));
1868 setStorage(m_out
.loadPtr(cell
, m_heaps
.JSArrayBufferView_vector
));
1871 void compileCheckArray()
1873 Edge edge
= m_node
->child1();
1874 LValue cell
= lowCell(edge
);
1876 if (m_node
->arrayMode().alreadyChecked(m_graph
, m_node
, m_state
.forNode(edge
)))
1880 BadIndexingType
, jsValueValue(cell
), 0,
1881 m_out
.bitNot(isArrayType(cell
, m_node
->arrayMode())));
1884 void compileGetTypedArrayByteOffset()
1886 LValue basePtr
= lowCell(m_node
->child1());
1888 LBasicBlock simpleCase
= FTL_NEW_BLOCK(m_out
, ("wasteless typed array"));
1889 LBasicBlock wastefulCase
= FTL_NEW_BLOCK(m_out
, ("wasteful typed array"));
1890 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("continuation branch"));
1892 LValue baseAddress
= m_out
.addPtr(basePtr
, JSArrayBufferView::offsetOfMode());
1894 m_out
.notEqual(baseAddress
, m_out
.constIntPtr(WastefulTypedArray
)),
1895 unsure(simpleCase
), unsure(wastefulCase
));
1897 // begin simple case
1898 LBasicBlock lastNext
= m_out
.appendTo(simpleCase
, wastefulCase
);
1900 ValueFromBlock simpleOut
= m_out
.anchor(m_out
.constIntPtr(0));
1902 m_out
.jump(continuation
);
1904 // begin wasteful case
1905 m_out
.appendTo(wastefulCase
, continuation
);
1907 LValue vectorPtr
= m_out
.loadPtr(basePtr
, m_heaps
.JSArrayBufferView_vector
);
1908 LValue butterflyPtr
= m_out
.loadPtr(basePtr
, m_heaps
.JSObject_butterfly
);
1909 LValue arrayBufferPtr
= m_out
.loadPtr(butterflyPtr
, m_heaps
.Butterfly_arrayBuffer
);
1910 LValue dataPtr
= m_out
.loadPtr(arrayBufferPtr
, m_heaps
.ArrayBuffer_data
);
1912 ValueFromBlock wastefulOut
= m_out
.anchor(m_out
.sub(dataPtr
, vectorPtr
));
1914 m_out
.jump(continuation
);
1915 m_out
.appendTo(continuation
, lastNext
);
1918 setInt32(m_out
.castToInt32(m_out
.phi(m_out
.intPtr
, simpleOut
, wastefulOut
)));
1921 void compileGetMyArgumentsLength()
1923 checkArgumentsNotCreated();
1925 RELEASE_ASSERT(!m_node
->origin
.semantic
.inlineCallFrame
);
1926 setInt32(m_out
.add(m_out
.load32NonNegative(payloadFor(JSStack::ArgumentCount
)), m_out
.constInt32(-1)));
1929 void compileGetMyArgumentByVal()
1931 checkArgumentsNotCreated();
1933 CodeOrigin codeOrigin
= m_node
->origin
.semantic
;
1935 LValue zeroBasedIndex
= lowInt32(m_node
->child1());
1936 LValue oneBasedIndex
= m_out
.add(zeroBasedIndex
, m_out
.int32One
);
1939 if (codeOrigin
.inlineCallFrame
)
1940 limit
= m_out
.constInt32(codeOrigin
.inlineCallFrame
->arguments
.size());
1942 limit
= m_out
.load32(payloadFor(JSStack::ArgumentCount
));
1944 speculate(Uncountable
, noValue(), 0, m_out
.aboveOrEqual(oneBasedIndex
, limit
));
1946 SymbolTable
* symbolTable
= m_graph
.baselineCodeBlockFor(codeOrigin
)->symbolTable();
1947 if (symbolTable
->slowArguments()) {
1948 // FIXME: FTL should support activations.
1949 // https://bugs.webkit.org/show_bug.cgi?id=129576
1951 RELEASE_ASSERT_NOT_REACHED();
1955 if (codeOrigin
.inlineCallFrame
)
1956 base
= addressFor(codeOrigin
.inlineCallFrame
->arguments
[1].virtualRegister());
1958 base
= addressFor(virtualRegisterForArgument(1));
1960 LValue pointer
= m_out
.baseIndex(
1961 base
.value(), m_out
.zeroExt(zeroBasedIndex
, m_out
.intPtr
), ScaleEight
);
1962 setJSValue(m_out
.load64(TypedPointer(m_heaps
.variables
.atAnyIndex(), pointer
)));
1965 void compileGetArrayLength()
1967 switch (m_node
->arrayMode().type()) {
1970 case Array::Contiguous
: {
1971 setInt32(m_out
.load32NonNegative(lowStorage(m_node
->child2()), m_heaps
.Butterfly_publicLength
));
1975 case Array::String
: {
1976 LValue string
= lowCell(m_node
->child1());
1977 setInt32(m_out
.load32NonNegative(string
, m_heaps
.JSString_length
));
1982 if (isTypedView(m_node
->arrayMode().typedArrayType())) {
1984 m_out
.load32NonNegative(lowCell(m_node
->child1()), m_heaps
.JSArrayBufferView_length
));
1988 RELEASE_ASSERT_NOT_REACHED();
1993 void compileCheckInBounds()
1996 OutOfBounds
, noValue(), 0,
1997 m_out
.aboveOrEqual(lowInt32(m_node
->child1()), lowInt32(m_node
->child2())));
2000 void compileGetByVal()
2002 switch (m_node
->arrayMode().type()) {
2004 case Array::Contiguous
: {
2005 LValue index
= lowInt32(m_node
->child2());
2006 LValue storage
= lowStorage(m_node
->child3());
2008 IndexedAbstractHeap
& heap
= m_node
->arrayMode().type() == Array::Int32
?
2009 m_heaps
.indexedInt32Properties
: m_heaps
.indexedContiguousProperties
;
2011 if (m_node
->arrayMode().isInBounds()) {
2012 LValue result
= m_out
.load64(baseIndex(heap
, storage
, index
, m_node
->child2()));
2013 speculate(LoadFromHole
, noValue(), 0, m_out
.isZero64(result
));
2018 LValue base
= lowCell(m_node
->child1());
2020 LBasicBlock fastCase
= FTL_NEW_BLOCK(m_out
, ("GetByVal int/contiguous fast case"));
2021 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("GetByVal int/contiguous slow case"));
2022 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("GetByVal int/contiguous continuation"));
2026 index
, m_out
.load32NonNegative(storage
, m_heaps
.Butterfly_publicLength
)),
2027 rarely(slowCase
), usually(fastCase
));
2029 LBasicBlock lastNext
= m_out
.appendTo(fastCase
, slowCase
);
2031 ValueFromBlock fastResult
= m_out
.anchor(
2032 m_out
.load64(baseIndex(heap
, storage
, index
, m_node
->child2())));
2034 m_out
.isZero64(fastResult
.value()), rarely(slowCase
), usually(continuation
));
2036 m_out
.appendTo(slowCase
, continuation
);
2037 ValueFromBlock slowResult
= m_out
.anchor(
2038 vmCall(m_out
.operation(operationGetByValArrayInt
), m_callFrame
, base
, index
));
2039 m_out
.jump(continuation
);
2041 m_out
.appendTo(continuation
, lastNext
);
2042 setJSValue(m_out
.phi(m_out
.int64
, fastResult
, slowResult
));
2046 case Array::Double
: {
2047 LValue index
= lowInt32(m_node
->child2());
2048 LValue storage
= lowStorage(m_node
->child3());
2050 IndexedAbstractHeap
& heap
= m_heaps
.indexedDoubleProperties
;
2052 if (m_node
->arrayMode().isInBounds()) {
2053 LValue result
= m_out
.loadDouble(
2054 baseIndex(heap
, storage
, index
, m_node
->child2()));
2056 if (!m_node
->arrayMode().isSaneChain()) {
2058 LoadFromHole
, noValue(), 0,
2059 m_out
.doubleNotEqualOrUnordered(result
, result
));
2065 LValue base
= lowCell(m_node
->child1());
2067 LBasicBlock inBounds
= FTL_NEW_BLOCK(m_out
, ("GetByVal double in bounds"));
2068 LBasicBlock boxPath
= FTL_NEW_BLOCK(m_out
, ("GetByVal double boxing"));
2069 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("GetByVal double slow case"));
2070 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("GetByVal double continuation"));
2074 index
, m_out
.load32NonNegative(storage
, m_heaps
.Butterfly_publicLength
)),
2075 rarely(slowCase
), usually(inBounds
));
2077 LBasicBlock lastNext
= m_out
.appendTo(inBounds
, boxPath
);
2078 LValue doubleValue
= m_out
.loadDouble(
2079 baseIndex(heap
, storage
, index
, m_node
->child2()));
2081 m_out
.doubleNotEqualOrUnordered(doubleValue
, doubleValue
),
2082 rarely(slowCase
), usually(boxPath
));
2084 m_out
.appendTo(boxPath
, slowCase
);
2085 ValueFromBlock fastResult
= m_out
.anchor(boxDouble(doubleValue
));
2086 m_out
.jump(continuation
);
2088 m_out
.appendTo(slowCase
, continuation
);
2089 ValueFromBlock slowResult
= m_out
.anchor(
2090 vmCall(m_out
.operation(operationGetByValArrayInt
), m_callFrame
, base
, index
));
2091 m_out
.jump(continuation
);
2093 m_out
.appendTo(continuation
, lastNext
);
2094 setJSValue(m_out
.phi(m_out
.int64
, fastResult
, slowResult
));
2098 case Array::Generic
: {
2100 m_out
.operation(operationGetByVal
), m_callFrame
,
2101 lowJSValue(m_node
->child1()), lowJSValue(m_node
->child2())));
2105 case Array::String
: {
2106 compileStringCharAt();
2111 LValue index
= lowInt32(m_node
->child2());
2112 LValue storage
= lowStorage(m_node
->child3());
2114 TypedArrayType type
= m_node
->arrayMode().typedArrayType();
2116 if (isTypedView(type
)) {
2117 TypedPointer pointer
= TypedPointer(
2118 m_heaps
.typedArrayProperties
,
2122 m_out
.zeroExt(index
, m_out
.intPtr
),
2123 m_out
.constIntPtr(logElementSize(type
)))));
2127 switch (elementSize(type
)) {
2129 result
= m_out
.load8(pointer
);
2132 result
= m_out
.load16(pointer
);
2135 result
= m_out
.load32(pointer
);
2138 RELEASE_ASSERT_NOT_REACHED();
2141 if (elementSize(type
) < 4) {
2143 result
= m_out
.signExt(result
, m_out
.int32
);
2145 result
= m_out
.zeroExt(result
, m_out
.int32
);
2150 if (isSigned(type
)) {
2155 if (m_node
->shouldSpeculateInt32()) {
2157 Overflow
, noValue(), 0, m_out
.lessThan(result
, m_out
.int32Zero
));
2162 if (m_node
->shouldSpeculateMachineInt()) {
2163 setStrictInt52(m_out
.zeroExt(result
, m_out
.int64
));
2167 setDouble(m_out
.unsignedToFP(result
, m_out
.doubleType
));
2171 ASSERT(isFloat(type
));
2176 result
= m_out
.fpCast(m_out
.loadFloat(pointer
), m_out
.doubleType
);
2179 result
= m_out
.loadDouble(pointer
);
2182 RELEASE_ASSERT_NOT_REACHED();
2189 RELEASE_ASSERT_NOT_REACHED();
2194 void compilePutByVal()
2196 Edge child1
= m_graph
.varArgChild(m_node
, 0);
2197 Edge child2
= m_graph
.varArgChild(m_node
, 1);
2198 Edge child3
= m_graph
.varArgChild(m_node
, 2);
2199 Edge child4
= m_graph
.varArgChild(m_node
, 3);
2200 Edge child5
= m_graph
.varArgChild(m_node
, 4);
2202 switch (m_node
->arrayMode().type()) {
2203 case Array::Generic
: {
2204 V_JITOperation_EJJJ operation
;
2205 if (m_node
->op() == PutByValDirect
) {
2206 if (m_graph
.isStrictModeFor(m_node
->origin
.semantic
))
2207 operation
= operationPutByValDirectStrict
;
2209 operation
= operationPutByValDirectNonStrict
;
2211 if (m_graph
.isStrictModeFor(m_node
->origin
.semantic
))
2212 operation
= operationPutByValStrict
;
2214 operation
= operationPutByValNonStrict
;
2218 m_out
.operation(operation
), m_callFrame
,
2219 lowJSValue(child1
), lowJSValue(child2
), lowJSValue(child3
));
2227 LValue base
= lowCell(child1
);
2228 LValue index
= lowInt32(child2
);
2229 LValue storage
= lowStorage(child4
);
2231 switch (m_node
->arrayMode().type()) {
2234 case Array::Contiguous
: {
2235 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("PutByVal continuation"));
2236 LBasicBlock outerLastNext
= m_out
.appendTo(m_out
.m_block
, continuation
);
2238 switch (m_node
->arrayMode().type()) {
2240 case Array::Contiguous
: {
2241 LValue value
= lowJSValue(child3
, ManualOperandSpeculation
);
2243 if (m_node
->arrayMode().type() == Array::Int32
)
2244 FTL_TYPE_CHECK(jsValueValue(value
), child3
, SpecInt32
, isNotInt32(value
));
2246 TypedPointer elementPointer
= m_out
.baseIndex(
2247 m_node
->arrayMode().type() == Array::Int32
?
2248 m_heaps
.indexedInt32Properties
: m_heaps
.indexedContiguousProperties
,
2249 storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
2250 m_state
.forNode(child2
).m_value
);
2252 if (m_node
->op() == PutByValAlias
) {
2253 m_out
.store64(value
, elementPointer
);
2257 contiguousPutByValOutOfBounds(
2258 codeBlock()->isStrictMode()
2259 ? operationPutByValBeyondArrayBoundsStrict
2260 : operationPutByValBeyondArrayBoundsNonStrict
,
2261 base
, storage
, index
, value
, continuation
);
2263 m_out
.store64(value
, elementPointer
);
2267 case Array::Double
: {
2268 LValue value
= lowDouble(child3
);
2271 doubleValue(value
), child3
, SpecDoubleReal
,
2272 m_out
.doubleNotEqualOrUnordered(value
, value
));
2274 TypedPointer elementPointer
= m_out
.baseIndex(
2275 m_heaps
.indexedDoubleProperties
,
2276 storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
2277 m_state
.forNode(child2
).m_value
);
2279 if (m_node
->op() == PutByValAlias
) {
2280 m_out
.storeDouble(value
, elementPointer
);
2284 contiguousPutByValOutOfBounds(
2285 codeBlock()->isStrictMode()
2286 ? operationPutDoubleByValBeyondArrayBoundsStrict
2287 : operationPutDoubleByValBeyondArrayBoundsNonStrict
,
2288 base
, storage
, index
, value
, continuation
);
2290 m_out
.storeDouble(value
, elementPointer
);
2295 RELEASE_ASSERT_NOT_REACHED();
2298 m_out
.jump(continuation
);
2299 m_out
.appendTo(continuation
, outerLastNext
);
2304 TypedArrayType type
= m_node
->arrayMode().typedArrayType();
2306 if (isTypedView(type
)) {
2307 TypedPointer pointer
= TypedPointer(
2308 m_heaps
.typedArrayProperties
,
2312 m_out
.zeroExt(index
, m_out
.intPtr
),
2313 m_out
.constIntPtr(logElementSize(type
)))));
2316 LValue valueToStore
;
2320 switch (child3
.useKind()) {
2323 if (child3
.useKind() == Int32Use
)
2324 intValue
= lowInt32(child3
);
2326 intValue
= m_out
.castToInt32(lowStrictInt52(child3
));
2328 if (isClamped(type
)) {
2329 ASSERT(elementSize(type
) == 1);
2331 LBasicBlock atLeastZero
= FTL_NEW_BLOCK(m_out
, ("PutByVal int clamp atLeastZero"));
2332 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("PutByVal int clamp continuation"));
2334 Vector
<ValueFromBlock
, 2> intValues
;
2335 intValues
.append(m_out
.anchor(m_out
.int32Zero
));
2337 m_out
.lessThan(intValue
, m_out
.int32Zero
),
2338 unsure(continuation
), unsure(atLeastZero
));
2340 LBasicBlock lastNext
= m_out
.appendTo(atLeastZero
, continuation
);
2342 intValues
.append(m_out
.anchor(m_out
.select(
2343 m_out
.greaterThan(intValue
, m_out
.constInt32(255)),
2344 m_out
.constInt32(255),
2346 m_out
.jump(continuation
);
2348 m_out
.appendTo(continuation
, lastNext
);
2349 intValue
= m_out
.phi(m_out
.int32
, intValues
);
2354 case DoubleRepUse
: {
2355 LValue doubleValue
= lowDouble(child3
);
2357 if (isClamped(type
)) {
2358 ASSERT(elementSize(type
) == 1);
2360 LBasicBlock atLeastZero
= FTL_NEW_BLOCK(m_out
, ("PutByVal double clamp atLeastZero"));
2361 LBasicBlock withinRange
= FTL_NEW_BLOCK(m_out
, ("PutByVal double clamp withinRange"));
2362 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("PutByVal double clamp continuation"));
2364 Vector
<ValueFromBlock
, 3> intValues
;
2365 intValues
.append(m_out
.anchor(m_out
.int32Zero
));
2367 m_out
.doubleLessThanOrUnordered(doubleValue
, m_out
.doubleZero
),
2368 unsure(continuation
), unsure(atLeastZero
));
2370 LBasicBlock lastNext
= m_out
.appendTo(atLeastZero
, withinRange
);
2371 intValues
.append(m_out
.anchor(m_out
.constInt32(255)));
2373 m_out
.doubleGreaterThan(doubleValue
, m_out
.constDouble(255)),
2374 unsure(continuation
), unsure(withinRange
));
2376 m_out
.appendTo(withinRange
, continuation
);
2377 intValues
.append(m_out
.anchor(m_out
.fpToInt32(doubleValue
)));
2378 m_out
.jump(continuation
);
2380 m_out
.appendTo(continuation
, lastNext
);
2381 intValue
= m_out
.phi(m_out
.int32
, intValues
);
2383 intValue
= doubleToInt32(doubleValue
);
2388 RELEASE_ASSERT_NOT_REACHED();
2391 switch (elementSize(type
)) {
2393 valueToStore
= m_out
.intCast(intValue
, m_out
.int8
);
2394 refType
= m_out
.ref8
;
2397 valueToStore
= m_out
.intCast(intValue
, m_out
.int16
);
2398 refType
= m_out
.ref16
;
2401 valueToStore
= intValue
;
2402 refType
= m_out
.ref32
;
2405 RELEASE_ASSERT_NOT_REACHED();
2407 } else /* !isInt(type) */ {
2408 LValue value
= lowDouble(child3
);
2411 valueToStore
= m_out
.fpCast(value
, m_out
.floatType
);
2412 refType
= m_out
.refFloat
;
2415 valueToStore
= value
;
2416 refType
= m_out
.refDouble
;
2419 RELEASE_ASSERT_NOT_REACHED();
2423 if (m_node
->arrayMode().isInBounds() || m_node
->op() == PutByValAlias
)
2424 m_out
.store(valueToStore
, pointer
, refType
);
2426 LBasicBlock isInBounds
= FTL_NEW_BLOCK(m_out
, ("PutByVal typed array in bounds case"));
2427 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("PutByVal typed array continuation"));
2430 m_out
.aboveOrEqual(index
, lowInt32(child5
)),
2431 unsure(continuation
), unsure(isInBounds
));
2433 LBasicBlock lastNext
= m_out
.appendTo(isInBounds
, continuation
);
2434 m_out
.store(valueToStore
, pointer
, refType
);
2435 m_out
.jump(continuation
);
2437 m_out
.appendTo(continuation
, lastNext
);
2443 RELEASE_ASSERT_NOT_REACHED();
2448 void compileArrayPush()
2450 LValue base
= lowCell(m_node
->child1());
2451 LValue storage
= lowStorage(m_node
->child3());
2453 switch (m_node
->arrayMode().type()) {
2455 case Array::Contiguous
:
2456 case Array::Double
: {
2460 if (m_node
->arrayMode().type() != Array::Double
) {
2461 value
= lowJSValue(m_node
->child2(), ManualOperandSpeculation
);
2462 if (m_node
->arrayMode().type() == Array::Int32
) {
2464 jsValueValue(value
), m_node
->child2(), SpecInt32
, isNotInt32(value
));
2466 refType
= m_out
.ref64
;
2468 value
= lowDouble(m_node
->child2());
2470 doubleValue(value
), m_node
->child2(), SpecDoubleReal
,
2471 m_out
.doubleNotEqualOrUnordered(value
, value
));
2472 refType
= m_out
.refDouble
;
2475 IndexedAbstractHeap
& heap
= m_heaps
.forArrayType(m_node
->arrayMode().type());
2477 LValue prevLength
= m_out
.load32(storage
, m_heaps
.Butterfly_publicLength
);
2479 LBasicBlock fastPath
= FTL_NEW_BLOCK(m_out
, ("ArrayPush fast path"));
2480 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("ArrayPush slow path"));
2481 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArrayPush continuation"));
2485 prevLength
, m_out
.load32(storage
, m_heaps
.Butterfly_vectorLength
)),
2486 rarely(slowPath
), usually(fastPath
));
2488 LBasicBlock lastNext
= m_out
.appendTo(fastPath
, slowPath
);
2491 m_out
.baseIndex(heap
, storage
, m_out
.zeroExt(prevLength
, m_out
.intPtr
)),
2493 LValue newLength
= m_out
.add(prevLength
, m_out
.int32One
);
2494 m_out
.store32(newLength
, storage
, m_heaps
.Butterfly_publicLength
);
2496 ValueFromBlock fastResult
= m_out
.anchor(boxInt32(newLength
));
2497 m_out
.jump(continuation
);
2499 m_out
.appendTo(slowPath
, continuation
);
2501 if (m_node
->arrayMode().type() != Array::Double
)
2502 operation
= m_out
.operation(operationArrayPush
);
2504 operation
= m_out
.operation(operationArrayPushDouble
);
2505 ValueFromBlock slowResult
= m_out
.anchor(
2506 vmCall(operation
, m_callFrame
, value
, base
));
2507 m_out
.jump(continuation
);
2509 m_out
.appendTo(continuation
, lastNext
);
2510 setJSValue(m_out
.phi(m_out
.int64
, fastResult
, slowResult
));
2515 RELEASE_ASSERT_NOT_REACHED();
2520 void compileArrayPop()
2522 LValue base
= lowCell(m_node
->child1());
2523 LValue storage
= lowStorage(m_node
->child2());
2525 switch (m_node
->arrayMode().type()) {
2528 case Array::Contiguous
: {
2529 IndexedAbstractHeap
& heap
= m_heaps
.forArrayType(m_node
->arrayMode().type());
2531 LBasicBlock fastCase
= FTL_NEW_BLOCK(m_out
, ("ArrayPop fast case"));
2532 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("ArrayPop slow case"));
2533 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ArrayPop continuation"));
2535 LValue prevLength
= m_out
.load32(storage
, m_heaps
.Butterfly_publicLength
);
2537 Vector
<ValueFromBlock
, 3> results
;
2538 results
.append(m_out
.anchor(m_out
.constInt64(JSValue::encode(jsUndefined()))));
2540 m_out
.isZero32(prevLength
), rarely(continuation
), usually(fastCase
));
2542 LBasicBlock lastNext
= m_out
.appendTo(fastCase
, slowCase
);
2543 LValue newLength
= m_out
.sub(prevLength
, m_out
.int32One
);
2544 m_out
.store32(newLength
, storage
, m_heaps
.Butterfly_publicLength
);
2545 TypedPointer pointer
= m_out
.baseIndex(
2546 heap
, storage
, m_out
.zeroExt(newLength
, m_out
.intPtr
));
2547 if (m_node
->arrayMode().type() != Array::Double
) {
2548 LValue result
= m_out
.load64(pointer
);
2549 m_out
.store64(m_out
.int64Zero
, pointer
);
2550 results
.append(m_out
.anchor(result
));
2552 m_out
.notZero64(result
), usually(continuation
), rarely(slowCase
));
2554 LValue result
= m_out
.loadDouble(pointer
);
2555 m_out
.store64(m_out
.constInt64(bitwise_cast
<int64_t>(PNaN
)), pointer
);
2556 results
.append(m_out
.anchor(boxDouble(result
)));
2558 m_out
.doubleEqual(result
, result
),
2559 usually(continuation
), rarely(slowCase
));
2562 m_out
.appendTo(slowCase
, continuation
);
2563 results
.append(m_out
.anchor(vmCall(
2564 m_out
.operation(operationArrayPopAndRecoverLength
), m_callFrame
, base
)));
2565 m_out
.jump(continuation
);
2567 m_out
.appendTo(continuation
, lastNext
);
2568 setJSValue(m_out
.phi(m_out
.int64
, results
));
2573 RELEASE_ASSERT_NOT_REACHED();
2578 void compileNewObject()
2580 Structure
* structure
= m_node
->structure();
2581 size_t allocationSize
= JSFinalObject::allocationSize(structure
->inlineCapacity());
2582 MarkedAllocator
* allocator
= &vm().heap
.allocatorForObjectWithoutDestructor(allocationSize
);
2584 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("NewObject slow path"));
2585 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("NewObject continuation"));
2587 LBasicBlock lastNext
= m_out
.insertNewBlocksBefore(slowPath
);
2589 ValueFromBlock fastResult
= m_out
.anchor(allocateObject(
2590 m_out
.constIntPtr(allocator
), structure
, m_out
.intPtrZero
, slowPath
));
2592 m_out
.jump(continuation
);
2594 m_out
.appendTo(slowPath
, continuation
);
2596 ValueFromBlock slowResult
= m_out
.anchor(vmCall(
2597 m_out
.operation(operationNewObject
), m_callFrame
, m_out
.constIntPtr(structure
)));
2598 m_out
.jump(continuation
);
2600 m_out
.appendTo(continuation
, lastNext
);
2601 setJSValue(m_out
.phi(m_out
.intPtr
, fastResult
, slowResult
));
2604 void compileNewArray()
2606 // First speculate appropriately on all of the children. Do this unconditionally up here
2607 // because some of the slow paths may otherwise forget to do it. It's sort of arguable
2608 // that doing the speculations up here might be unprofitable for RA - so we can consider
2609 // sinking this to below the allocation fast path if we find that this has a lot of
2610 // register pressure.
2611 for (unsigned operandIndex
= 0; operandIndex
< m_node
->numChildren(); ++operandIndex
)
2612 speculate(m_graph
.varArgChild(m_node
, operandIndex
));
2614 JSGlobalObject
* globalObject
= m_graph
.globalObjectFor(m_node
->origin
.semantic
);
2615 Structure
* structure
= globalObject
->arrayStructureForIndexingTypeDuringAllocation(
2616 m_node
->indexingType());
2618 RELEASE_ASSERT(structure
->indexingType() == m_node
->indexingType());
2620 if (!globalObject
->isHavingABadTime() && !hasAnyArrayStorage(m_node
->indexingType())) {
2621 unsigned numElements
= m_node
->numChildren();
2623 ArrayValues arrayValues
= allocateJSArray(structure
, numElements
);
2625 for (unsigned operandIndex
= 0; operandIndex
< m_node
->numChildren(); ++operandIndex
) {
2626 Edge edge
= m_graph
.varArgChild(m_node
, operandIndex
);
2628 switch (m_node
->indexingType()) {
2629 case ALL_BLANK_INDEXING_TYPES
:
2630 case ALL_UNDECIDED_INDEXING_TYPES
:
2634 case ALL_DOUBLE_INDEXING_TYPES
:
2637 arrayValues
.butterfly
, m_heaps
.indexedDoubleProperties
[operandIndex
]);
2640 case ALL_INT32_INDEXING_TYPES
:
2641 case ALL_CONTIGUOUS_INDEXING_TYPES
:
2643 lowJSValue(edge
, ManualOperandSpeculation
),
2644 arrayValues
.butterfly
,
2645 m_heaps
.forIndexingType(m_node
->indexingType())->at(operandIndex
));
2653 setJSValue(arrayValues
.array
);
2657 if (!m_node
->numChildren()) {
2659 m_out
.operation(operationNewEmptyArray
), m_callFrame
,
2660 m_out
.constIntPtr(structure
)));
2664 size_t scratchSize
= sizeof(EncodedJSValue
) * m_node
->numChildren();
2665 ASSERT(scratchSize
);
2666 ScratchBuffer
* scratchBuffer
= vm().scratchBufferForSize(scratchSize
);
2667 EncodedJSValue
* buffer
= static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer());
2669 for (unsigned operandIndex
= 0; operandIndex
< m_node
->numChildren(); ++operandIndex
) {
2670 Edge edge
= m_graph
.varArgChild(m_node
, operandIndex
);
2672 lowJSValue(edge
, ManualOperandSpeculation
),
2673 m_out
.absolute(buffer
+ operandIndex
));
2677 m_out
.constIntPtr(scratchSize
), m_out
.absolute(scratchBuffer
->activeLengthPtr()));
2679 LValue result
= vmCall(
2680 m_out
.operation(operationNewArray
), m_callFrame
,
2681 m_out
.constIntPtr(structure
), m_out
.constIntPtr(buffer
),
2682 m_out
.constIntPtr(m_node
->numChildren()));
2684 m_out
.storePtr(m_out
.intPtrZero
, m_out
.absolute(scratchBuffer
->activeLengthPtr()));
2689 void compileNewArrayBuffer()
2691 JSGlobalObject
* globalObject
= m_graph
.globalObjectFor(m_node
->origin
.semantic
);
2692 Structure
* structure
= globalObject
->arrayStructureForIndexingTypeDuringAllocation(
2693 m_node
->indexingType());
2695 RELEASE_ASSERT(structure
->indexingType() == m_node
->indexingType());
2697 if (!globalObject
->isHavingABadTime() && !hasAnyArrayStorage(m_node
->indexingType())) {
2698 unsigned numElements
= m_node
->numConstants();
2700 ArrayValues arrayValues
= allocateJSArray(structure
, numElements
);
2702 JSValue
* data
= codeBlock()->constantBuffer(m_node
->startConstant());
2703 for (unsigned index
= 0; index
< m_node
->numConstants(); ++index
) {
2705 if (hasDouble(m_node
->indexingType()))
2706 value
= bitwise_cast
<int64_t>(data
[index
].asNumber());
2708 value
= JSValue::encode(data
[index
]);
2711 m_out
.constInt64(value
),
2712 arrayValues
.butterfly
,
2713 m_heaps
.forIndexingType(m_node
->indexingType())->at(index
));
2716 setJSValue(arrayValues
.array
);
2721 m_out
.operation(operationNewArrayBuffer
), m_callFrame
,
2722 m_out
.constIntPtr(structure
), m_out
.constIntPtr(m_node
->startConstant()),
2723 m_out
.constIntPtr(m_node
->numConstants())));
2726 void compileNewArrayWithSize()
2728 LValue publicLength
= lowInt32(m_node
->child1());
2730 JSGlobalObject
* globalObject
= m_graph
.globalObjectFor(m_node
->origin
.semantic
);
2731 Structure
* structure
= globalObject
->arrayStructureForIndexingTypeDuringAllocation(
2732 m_node
->indexingType());
2734 if (!globalObject
->isHavingABadTime() && !hasAnyArrayStorage(m_node
->indexingType())) {
2736 hasUndecided(structure
->indexingType())
2737 || hasInt32(structure
->indexingType())
2738 || hasDouble(structure
->indexingType())
2739 || hasContiguous(structure
->indexingType()));
2741 LBasicBlock fastCase
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize fast case"));
2742 LBasicBlock largeCase
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize large case"));
2743 LBasicBlock failCase
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize fail case"));
2744 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize slow case"));
2745 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize continuation"));
2748 m_out
.aboveOrEqual(publicLength
, m_out
.constInt32(MIN_SPARSE_ARRAY_INDEX
)),
2749 rarely(largeCase
), usually(fastCase
));
2751 LBasicBlock lastNext
= m_out
.appendTo(fastCase
, largeCase
);
2753 // We don't round up to BASE_VECTOR_LEN for new Array(blah).
2754 LValue vectorLength
= publicLength
;
2756 LValue payloadSize
=
2757 m_out
.shl(m_out
.zeroExt(vectorLength
, m_out
.intPtr
), m_out
.constIntPtr(3));
2759 LValue butterflySize
= m_out
.add(
2760 payloadSize
, m_out
.constIntPtr(sizeof(IndexingHeader
)));
2762 LValue endOfStorage
= allocateBasicStorageAndGetEnd(butterflySize
, failCase
);
2764 LValue butterfly
= m_out
.sub(endOfStorage
, payloadSize
);
2766 LValue object
= allocateObject
<JSArray
>(
2767 structure
, butterfly
, failCase
);
2769 m_out
.store32(publicLength
, butterfly
, m_heaps
.Butterfly_publicLength
);
2770 m_out
.store32(vectorLength
, butterfly
, m_heaps
.Butterfly_vectorLength
);
2772 if (hasDouble(m_node
->indexingType())) {
2773 LBasicBlock initLoop
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize double init loop"));
2774 LBasicBlock initDone
= FTL_NEW_BLOCK(m_out
, ("NewArrayWithSize double init done"));
2776 ValueFromBlock originalIndex
= m_out
.anchor(vectorLength
);
2777 ValueFromBlock originalPointer
= m_out
.anchor(butterfly
);
2779 m_out
.notZero32(vectorLength
), unsure(initLoop
), unsure(initDone
));
2781 LBasicBlock initLastNext
= m_out
.appendTo(initLoop
, initDone
);
2782 LValue index
= m_out
.phi(m_out
.int32
, originalIndex
);
2783 LValue pointer
= m_out
.phi(m_out
.intPtr
, originalPointer
);
2786 m_out
.constInt64(bitwise_cast
<int64_t>(PNaN
)),
2787 TypedPointer(m_heaps
.indexedDoubleProperties
.atAnyIndex(), pointer
));
2789 LValue nextIndex
= m_out
.sub(index
, m_out
.int32One
);
2790 addIncoming(index
, m_out
.anchor(nextIndex
));
2791 addIncoming(pointer
, m_out
.anchor(m_out
.add(pointer
, m_out
.intPtrEight
)));
2793 m_out
.notZero32(nextIndex
), unsure(initLoop
), unsure(initDone
));
2795 m_out
.appendTo(initDone
, initLastNext
);
2798 ValueFromBlock fastResult
= m_out
.anchor(object
);
2799 m_out
.jump(continuation
);
2801 m_out
.appendTo(largeCase
, failCase
);
2802 ValueFromBlock largeStructure
= m_out
.anchor(m_out
.constIntPtr(
2803 globalObject
->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage
)));
2804 m_out
.jump(slowCase
);
2806 m_out
.appendTo(failCase
, slowCase
);
2807 ValueFromBlock failStructure
= m_out
.anchor(m_out
.constIntPtr(structure
));
2808 m_out
.jump(slowCase
);
2810 m_out
.appendTo(slowCase
, continuation
);
2811 LValue structureValue
= m_out
.phi(
2812 m_out
.intPtr
, largeStructure
, failStructure
);
2813 ValueFromBlock slowResult
= m_out
.anchor(vmCall(
2814 m_out
.operation(operationNewArrayWithSize
),
2815 m_callFrame
, structureValue
, publicLength
));
2816 m_out
.jump(continuation
);
2818 m_out
.appendTo(continuation
, lastNext
);
2819 setJSValue(m_out
.phi(m_out
.intPtr
, fastResult
, slowResult
));
2823 LValue structureValue
= m_out
.select(
2824 m_out
.aboveOrEqual(publicLength
, m_out
.constInt32(MIN_SPARSE_ARRAY_INDEX
)),
2826 globalObject
->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage
)),
2827 m_out
.constIntPtr(structure
));
2828 setJSValue(vmCall(m_out
.operation(operationNewArrayWithSize
), m_callFrame
, structureValue
, publicLength
));
2831 void compileAllocatePropertyStorage()
2833 StructureTransitionData
& data
= m_node
->structureTransitionData();
2834 LValue object
= lowCell(m_node
->child1());
2836 setStorage(allocatePropertyStorage(object
, data
.previousStructure
));
2839 void compileReallocatePropertyStorage()
2841 StructureTransitionData
& data
= m_node
->structureTransitionData();
2842 LValue object
= lowCell(m_node
->child1());
2843 LValue oldStorage
= lowStorage(m_node
->child2());
2846 reallocatePropertyStorage(
2847 object
, oldStorage
, data
.previousStructure
, data
.newStructure
));
2850 void compileToString()
2852 switch (m_node
->child1().useKind()) {
2853 case StringObjectUse
: {
2854 LValue cell
= lowCell(m_node
->child1());
2855 speculateStringObjectForCell(m_node
->child1(), cell
);
2856 m_interpreter
.filter(m_node
->child1(), SpecStringObject
);
2858 setJSValue(m_out
.loadPtr(cell
, m_heaps
.JSWrapperObject_internalValue
));
2862 case StringOrStringObjectUse
: {
2863 LValue cell
= lowCell(m_node
->child1());
2864 LValue structureID
= m_out
.load32(cell
, m_heaps
.JSCell_structureID
);
2866 LBasicBlock notString
= FTL_NEW_BLOCK(m_out
, ("ToString StringOrStringObject not string case"));
2867 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ToString StringOrStringObject continuation"));
2869 ValueFromBlock simpleResult
= m_out
.anchor(cell
);
2871 m_out
.equal(structureID
, m_out
.constInt32(vm().stringStructure
->id())),
2872 unsure(continuation
), unsure(notString
));
2874 LBasicBlock lastNext
= m_out
.appendTo(notString
, continuation
);
2875 speculateStringObjectForStructureID(m_node
->child1(), structureID
);
2876 ValueFromBlock unboxedResult
= m_out
.anchor(
2877 m_out
.loadPtr(cell
, m_heaps
.JSWrapperObject_internalValue
));
2878 m_out
.jump(continuation
);
2880 m_out
.appendTo(continuation
, lastNext
);
2881 setJSValue(m_out
.phi(m_out
.int64
, simpleResult
, unboxedResult
));
2883 m_interpreter
.filter(m_node
->child1(), SpecString
| SpecStringObject
);
2890 if (m_node
->child1().useKind() == CellUse
)
2891 value
= lowCell(m_node
->child1());
2893 value
= lowJSValue(m_node
->child1());
2895 LBasicBlock isCell
= FTL_NEW_BLOCK(m_out
, ("ToString CellUse/UntypedUse is cell"));
2896 LBasicBlock notString
= FTL_NEW_BLOCK(m_out
, ("ToString CellUse/UntypedUse not string"));
2897 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ToString CellUse/UntypedUse continuation"));
2899 LValue isCellPredicate
;
2900 if (m_node
->child1().useKind() == CellUse
)
2901 isCellPredicate
= m_out
.booleanTrue
;
2903 isCellPredicate
= this->isCell(value
);
2904 m_out
.branch(isCellPredicate
, unsure(isCell
), unsure(notString
));
2906 LBasicBlock lastNext
= m_out
.appendTo(isCell
, notString
);
2907 ValueFromBlock simpleResult
= m_out
.anchor(value
);
2908 LValue isStringPredicate
;
2909 if (m_node
->child1()->prediction() & SpecString
) {
2910 isStringPredicate
= m_out
.equal(
2911 m_out
.load32(value
, m_heaps
.JSCell_structureID
),
2912 m_out
.constInt32(vm().stringStructure
->id()));
2914 isStringPredicate
= m_out
.booleanFalse
;
2915 m_out
.branch(isStringPredicate
, unsure(continuation
), unsure(notString
));
2917 m_out
.appendTo(notString
, continuation
);
2919 if (m_node
->child1().useKind() == CellUse
)
2920 operation
= m_out
.operation(operationToStringOnCell
);
2922 operation
= m_out
.operation(operationToString
);
2923 ValueFromBlock convertedResult
= m_out
.anchor(vmCall(operation
, m_callFrame
, value
));
2924 m_out
.jump(continuation
);
2926 m_out
.appendTo(continuation
, lastNext
);
2927 setJSValue(m_out
.phi(m_out
.int64
, simpleResult
, convertedResult
));
2932 RELEASE_ASSERT_NOT_REACHED();
2937 void compileToPrimitive()
2939 LValue value
= lowJSValue(m_node
->child1());
2941 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("ToPrimitive cell case"));
2942 LBasicBlock isObjectCase
= FTL_NEW_BLOCK(m_out
, ("ToPrimitive object case"));
2943 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ToPrimitive continuation"));
2945 Vector
<ValueFromBlock
, 3> results
;
2947 results
.append(m_out
.anchor(value
));
2948 m_out
.branch(isCell(value
), unsure(isCellCase
), unsure(continuation
));
2950 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, isObjectCase
);
2951 results
.append(m_out
.anchor(value
));
2952 m_out
.branch(isObject(value
), unsure(isObjectCase
), unsure(continuation
));
2954 m_out
.appendTo(isObjectCase
, continuation
);
2955 results
.append(m_out
.anchor(vmCall(
2956 m_out
.operation(operationToPrimitive
), m_callFrame
, value
)));
2957 m_out
.jump(continuation
);
2959 m_out
.appendTo(continuation
, lastNext
);
2960 setJSValue(m_out
.phi(m_out
.int64
, results
));
2963 void compileMakeRope()
2967 kids
[0] = lowCell(m_node
->child1());
2968 kids
[1] = lowCell(m_node
->child2());
2969 if (m_node
->child3()) {
2970 kids
[2] = lowCell(m_node
->child3());
2977 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("MakeRope slow path"));
2978 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("MakeRope continuation"));
2980 LBasicBlock lastNext
= m_out
.insertNewBlocksBefore(slowPath
);
2982 MarkedAllocator
& allocator
=
2983 vm().heap
.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString
));
2985 LValue result
= allocateCell(
2986 m_out
.constIntPtr(&allocator
),
2987 vm().stringStructure
.get(),
2990 m_out
.storePtr(m_out
.intPtrZero
, result
, m_heaps
.JSString_value
);
2991 for (unsigned i
= 0; i
< numKids
; ++i
)
2992 m_out
.storePtr(kids
[i
], result
, m_heaps
.JSRopeString_fibers
[i
]);
2993 for (unsigned i
= numKids
; i
< JSRopeString::s_maxInternalRopeLength
; ++i
)
2994 m_out
.storePtr(m_out
.intPtrZero
, result
, m_heaps
.JSRopeString_fibers
[i
]);
2995 LValue flags
= m_out
.load32(kids
[0], m_heaps
.JSString_flags
);
2996 LValue length
= m_out
.load32(kids
[0], m_heaps
.JSString_length
);
2997 for (unsigned i
= 1; i
< numKids
; ++i
) {
2998 flags
= m_out
.bitAnd(flags
, m_out
.load32(kids
[i
], m_heaps
.JSString_flags
));
2999 LValue lengthAndOverflow
= m_out
.addWithOverflow32(
3000 length
, m_out
.load32(kids
[i
], m_heaps
.JSString_length
));
3001 speculate(Uncountable
, noValue(), 0, m_out
.extractValue(lengthAndOverflow
, 1));
3002 length
= m_out
.extractValue(lengthAndOverflow
, 0);
3005 m_out
.bitAnd(m_out
.constInt32(JSString::Is8Bit
), flags
),
3006 result
, m_heaps
.JSString_flags
);
3007 m_out
.store32(length
, result
, m_heaps
.JSString_length
);
3009 ValueFromBlock fastResult
= m_out
.anchor(result
);
3010 m_out
.jump(continuation
);
3012 m_out
.appendTo(slowPath
, continuation
);
3013 ValueFromBlock slowResult
;
3016 slowResult
= m_out
.anchor(vmCall(
3017 m_out
.operation(operationMakeRope2
), m_callFrame
, kids
[0], kids
[1]));
3020 slowResult
= m_out
.anchor(vmCall(
3021 m_out
.operation(operationMakeRope3
), m_callFrame
, kids
[0], kids
[1], kids
[2]));
3024 RELEASE_ASSERT_NOT_REACHED();
3027 m_out
.jump(continuation
);
3029 m_out
.appendTo(continuation
, lastNext
);
3030 setJSValue(m_out
.phi(m_out
.int64
, fastResult
, slowResult
));
3033 void compileStringCharAt()
3035 LValue base
= lowCell(m_node
->child1());
3036 LValue index
= lowInt32(m_node
->child2());
3037 LValue storage
= lowStorage(m_node
->child3());
3039 LBasicBlock fastPath
= FTL_NEW_BLOCK(m_out
, ("GetByVal String fast path"));
3040 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("GetByVal String slow path"));
3041 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("GetByVal String continuation"));
3045 index
, m_out
.load32NonNegative(base
, m_heaps
.JSString_length
)),
3046 rarely(slowPath
), usually(fastPath
));
3048 LBasicBlock lastNext
= m_out
.appendTo(fastPath
, slowPath
);
3050 LValue stringImpl
= m_out
.loadPtr(base
, m_heaps
.JSString_value
);
3052 LBasicBlock is8Bit
= FTL_NEW_BLOCK(m_out
, ("GetByVal String 8-bit case"));
3053 LBasicBlock is16Bit
= FTL_NEW_BLOCK(m_out
, ("GetByVal String 16-bit case"));
3054 LBasicBlock bitsContinuation
= FTL_NEW_BLOCK(m_out
, ("GetByVal String bitness continuation"));
3055 LBasicBlock bigCharacter
= FTL_NEW_BLOCK(m_out
, ("GetByVal String big character"));
3059 m_out
.load32(stringImpl
, m_heaps
.StringImpl_hashAndFlags
),
3060 m_out
.constInt32(StringImpl::flagIs8Bit())),
3061 unsure(is16Bit
), unsure(is8Bit
));
3063 m_out
.appendTo(is8Bit
, is16Bit
);
3065 ValueFromBlock char8Bit
= m_out
.anchor(m_out
.zeroExt(
3066 m_out
.load8(m_out
.baseIndex(
3067 m_heaps
.characters8
,
3068 storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
3069 m_state
.forNode(m_node
->child2()).m_value
)),
3071 m_out
.jump(bitsContinuation
);
3073 m_out
.appendTo(is16Bit
, bigCharacter
);
3075 ValueFromBlock char16Bit
= m_out
.anchor(m_out
.zeroExt(
3076 m_out
.load16(m_out
.baseIndex(
3077 m_heaps
.characters16
,
3078 storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
3079 m_state
.forNode(m_node
->child2()).m_value
)),
3082 m_out
.aboveOrEqual(char16Bit
.value(), m_out
.constInt32(0x100)),
3083 rarely(bigCharacter
), usually(bitsContinuation
));
3085 m_out
.appendTo(bigCharacter
, bitsContinuation
);
3087 Vector
<ValueFromBlock
, 4> results
;
3088 results
.append(m_out
.anchor(vmCall(
3089 m_out
.operation(operationSingleCharacterString
),
3090 m_callFrame
, char16Bit
.value())));
3091 m_out
.jump(continuation
);
3093 m_out
.appendTo(bitsContinuation
, slowPath
);
3095 LValue character
= m_out
.phi(m_out
.int32
, char8Bit
, char16Bit
);
3097 LValue smallStrings
= m_out
.constIntPtr(vm().smallStrings
.singleCharacterStrings());
3099 results
.append(m_out
.anchor(m_out
.loadPtr(m_out
.baseIndex(
3100 m_heaps
.singleCharacterStrings
, smallStrings
,
3101 m_out
.zeroExt(character
, m_out
.intPtr
)))));
3102 m_out
.jump(continuation
);
3104 m_out
.appendTo(slowPath
, continuation
);
3106 if (m_node
->arrayMode().isInBounds()) {
3107 speculate(OutOfBounds
, noValue(), 0, m_out
.booleanTrue
);
3108 results
.append(m_out
.anchor(m_out
.intPtrZero
));
3110 JSGlobalObject
* globalObject
= m_graph
.globalObjectFor(m_node
->origin
.semantic
);
3112 if (globalObject
->stringPrototypeChainIsSane()) {
3113 LBasicBlock negativeIndex
= FTL_NEW_BLOCK(m_out
, ("GetByVal String negative index"));
3115 results
.append(m_out
.anchor(m_out
.constInt64(JSValue::encode(jsUndefined()))));
3117 m_out
.lessThan(index
, m_out
.int32Zero
),
3118 rarely(negativeIndex
), usually(continuation
));
3120 m_out
.appendTo(negativeIndex
, continuation
);
3123 results
.append(m_out
.anchor(vmCall(
3124 m_out
.operation(operationGetByValStringInt
), m_callFrame
, base
, index
)));
3127 m_out
.jump(continuation
);
3129 m_out
.appendTo(continuation
, lastNext
);
3130 setJSValue(m_out
.phi(m_out
.int64
, results
));
3133 void compileStringCharCodeAt()
3135 LBasicBlock is8Bit
= FTL_NEW_BLOCK(m_out
, ("StringCharCodeAt 8-bit case"));
3136 LBasicBlock is16Bit
= FTL_NEW_BLOCK(m_out
, ("StringCharCodeAt 16-bit case"));
3137 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("StringCharCodeAt continuation"));
3139 LValue base
= lowCell(m_node
->child1());
3140 LValue index
= lowInt32(m_node
->child2());
3141 LValue storage
= lowStorage(m_node
->child3());
3144 Uncountable
, noValue(), 0,
3146 index
, m_out
.load32NonNegative(base
, m_heaps
.JSString_length
)));
3148 LValue stringImpl
= m_out
.loadPtr(base
, m_heaps
.JSString_value
);
3152 m_out
.load32(stringImpl
, m_heaps
.StringImpl_hashAndFlags
),
3153 m_out
.constInt32(StringImpl::flagIs8Bit())),
3154 unsure(is16Bit
), unsure(is8Bit
));
3156 LBasicBlock lastNext
= m_out
.appendTo(is8Bit
, is16Bit
);
3158 ValueFromBlock char8Bit
= m_out
.anchor(m_out
.zeroExt(
3159 m_out
.load8(m_out
.baseIndex(
3160 m_heaps
.characters8
,
3161 storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
3162 m_state
.forNode(m_node
->child2()).m_value
)),
3164 m_out
.jump(continuation
);
3166 m_out
.appendTo(is16Bit
, continuation
);
3168 ValueFromBlock char16Bit
= m_out
.anchor(m_out
.zeroExt(
3169 m_out
.load16(m_out
.baseIndex(
3170 m_heaps
.characters16
,
3171 storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
3172 m_state
.forNode(m_node
->child2()).m_value
)),
3174 m_out
.jump(continuation
);
3176 m_out
.appendTo(continuation
, lastNext
);
3178 setInt32(m_out
.phi(m_out
.int32
, char8Bit
, char16Bit
));
3181 void compileGetByOffset()
3183 StorageAccessData
& data
=
3184 m_graph
.m_storageAccessData
[m_node
->storageAccessDataIndex()];
3186 setJSValue(loadProperty(
3187 lowStorage(m_node
->child1()), data
.identifierNumber
, data
.offset
));
3190 void compileMultiGetByOffset()
3192 LValue base
= lowCell(m_node
->child1());
3194 MultiGetByOffsetData
& data
= m_node
->multiGetByOffsetData();
3196 Vector
<LBasicBlock
, 2> blocks(data
.variants
.size());
3197 for (unsigned i
= data
.variants
.size(); i
--;)
3198 blocks
[i
] = FTL_NEW_BLOCK(m_out
, ("MultiGetByOffset case ", i
));
3199 LBasicBlock exit
= FTL_NEW_BLOCK(m_out
, ("MultiGetByOffset fail"));
3200 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("MultiGetByOffset continuation"));
3202 Vector
<SwitchCase
, 2> cases
;
3203 for (unsigned i
= data
.variants
.size(); i
--;) {
3204 GetByIdVariant variant
= data
.variants
[i
];
3205 for (unsigned j
= variant
.structureSet().size(); j
--;) {
3206 cases
.append(SwitchCase(
3207 weakStructure(variant
.structureSet()[j
]), blocks
[i
], Weight(1)));
3210 m_out
.switchInstruction(
3211 m_out
.load32(base
, m_heaps
.JSCell_structureID
), cases
, exit
, Weight(0));
3213 LBasicBlock lastNext
= m_out
.m_nextBlock
;
3215 Vector
<ValueFromBlock
, 2> results
;
3216 for (unsigned i
= data
.variants
.size(); i
--;) {
3217 m_out
.appendTo(blocks
[i
], i
+ 1 < data
.variants
.size() ? blocks
[i
+ 1] : exit
);
3219 GetByIdVariant variant
= data
.variants
[i
];
3221 if (variant
.specificValue())
3222 result
= m_out
.constInt64(JSValue::encode(variant
.specificValue()));
3224 LValue propertyBase
;
3225 if (variant
.chain())
3226 propertyBase
= weakPointer(variant
.chain()->terminalPrototype());
3228 propertyBase
= base
;
3229 if (!isInlineOffset(variant
.offset()))
3230 propertyBase
= m_out
.loadPtr(propertyBase
, m_heaps
.JSObject_butterfly
);
3231 result
= loadProperty(propertyBase
, data
.identifierNumber
, variant
.offset());
3234 results
.append(m_out
.anchor(result
));
3235 m_out
.jump(continuation
);
3238 m_out
.appendTo(exit
, continuation
);
3239 terminate(BadCache
);
3240 m_out
.unreachable();
3242 m_out
.appendTo(continuation
, lastNext
);
3243 setJSValue(m_out
.phi(m_out
.int64
, results
));
3246 void compilePutByOffset()
3248 StorageAccessData
& data
=
3249 m_graph
.m_storageAccessData
[m_node
->storageAccessDataIndex()];
3252 lowJSValue(m_node
->child3()),
3253 lowStorage(m_node
->child1()), data
.identifierNumber
, data
.offset
);
3256 void compileMultiPutByOffset()
3258 LValue base
= lowCell(m_node
->child1());
3259 LValue value
= lowJSValue(m_node
->child2());
3261 MultiPutByOffsetData
& data
= m_node
->multiPutByOffsetData();
3263 Vector
<LBasicBlock
, 2> blocks(data
.variants
.size());
3264 for (unsigned i
= data
.variants
.size(); i
--;)
3265 blocks
[i
] = FTL_NEW_BLOCK(m_out
, ("MultiPutByOffset case ", i
));
3266 LBasicBlock exit
= FTL_NEW_BLOCK(m_out
, ("MultiPutByOffset fail"));
3267 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("MultiPutByOffset continuation"));
3269 Vector
<SwitchCase
, 2> cases
;
3270 for (unsigned i
= data
.variants
.size(); i
--;) {
3271 PutByIdVariant variant
= data
.variants
[i
];
3273 SwitchCase(weakStructure(variant
.oldStructure()), blocks
[i
], Weight(1)));
3275 m_out
.switchInstruction(
3276 m_out
.load32(base
, m_heaps
.JSCell_structureID
), cases
, exit
, Weight(0));
3278 LBasicBlock lastNext
= m_out
.m_nextBlock
;
3280 for (unsigned i
= data
.variants
.size(); i
--;) {
3281 m_out
.appendTo(blocks
[i
], i
+ 1 < data
.variants
.size() ? blocks
[i
+ 1] : exit
);
3283 PutByIdVariant variant
= data
.variants
[i
];
3286 if (variant
.kind() == PutByIdVariant::Replace
) {
3287 if (isInlineOffset(variant
.offset()))
3290 storage
= m_out
.loadPtr(base
, m_heaps
.JSObject_butterfly
);
3292 m_graph
.m_plan
.transitions
.addLazily(
3293 codeBlock(), m_node
->origin
.semantic
.codeOriginOwner(),
3294 variant
.oldStructure(), variant
.newStructure());
3296 storage
= storageForTransition(
3297 base
, variant
.offset(), variant
.oldStructure(), variant
.newStructure());
3299 ASSERT(variant
.oldStructure()->indexingType() == variant
.newStructure()->indexingType());
3300 ASSERT(variant
.oldStructure()->typeInfo().inlineTypeFlags() == variant
.newStructure()->typeInfo().inlineTypeFlags());
3301 ASSERT(variant
.oldStructure()->typeInfo().type() == variant
.newStructure()->typeInfo().type());
3303 weakStructure(variant
.newStructure()), base
, m_heaps
.JSCell_structureID
);
3306 storeProperty(value
, storage
, data
.identifierNumber
, variant
.offset());
3307 m_out
.jump(continuation
);
3310 m_out
.appendTo(exit
, continuation
);
3311 terminate(BadCache
);
3312 m_out
.unreachable();
3314 m_out
.appendTo(continuation
, lastNext
);
3317 void compileGetGlobalVar()
3319 setJSValue(m_out
.load64(m_out
.absolute(m_node
->registerPointer())));
3322 void compilePutGlobalVar()
3325 lowJSValue(m_node
->child1()), m_out
.absolute(m_node
->registerPointer()));
3328 void compileNotifyWrite()
3330 VariableWatchpointSet
* set
= m_node
->variableWatchpointSet();
3332 LValue value
= lowJSValue(m_node
->child1());
3334 LBasicBlock isNotInvalidated
= FTL_NEW_BLOCK(m_out
, ("NotifyWrite not invalidated case"));
3335 LBasicBlock notifySlow
= FTL_NEW_BLOCK(m_out
, ("NotifyWrite notify slow case"));
3336 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("NotifyWrite continuation"));
3338 LValue state
= m_out
.load8(m_out
.absolute(set
->addressOfState()));
3341 m_out
.equal(state
, m_out
.constInt8(IsInvalidated
)),
3342 usually(continuation
), rarely(isNotInvalidated
));
3344 LBasicBlock lastNext
= m_out
.appendTo(isNotInvalidated
, notifySlow
);
3347 m_out
.equal(value
, m_out
.load64(m_out
.absolute(set
->addressOfInferredValue()))),
3348 unsure(continuation
), unsure(notifySlow
));
3350 m_out
.appendTo(notifySlow
, continuation
);
3352 vmCall(m_out
.operation(operationNotifyWrite
), m_callFrame
, m_out
.constIntPtr(set
), value
);
3353 m_out
.jump(continuation
);
3355 m_out
.appendTo(continuation
, lastNext
);
3358 void compileGetCallee()
3360 setJSValue(m_out
.loadPtr(addressFor(JSStack::Callee
)));
3363 void compileGetScope()
3365 setJSValue(m_out
.loadPtr(lowCell(m_node
->child1()), m_heaps
.JSFunction_scope
));
3368 void compileGetMyScope()
3370 setJSValue(m_out
.loadPtr(addressFor(
3371 m_node
->origin
.semantic
.stackOffset() + JSStack::ScopeChain
)));
3374 void compileSkipScope()
3376 setJSValue(m_out
.loadPtr(lowCell(m_node
->child1()), m_heaps
.JSScope_next
));
3379 void compileGetClosureRegisters()
3381 if (WriteBarrierBase
<Unknown
>* registers
= m_graph
.tryGetRegisters(m_node
->child1().node())) {
3382 setStorage(m_out
.constIntPtr(registers
));
3386 setStorage(m_out
.loadPtr(
3387 lowCell(m_node
->child1()), m_heaps
.JSVariableObject_registers
));
3390 void compileGetClosureVar()
3392 setJSValue(m_out
.load64(
3393 addressFor(lowStorage(m_node
->child1()), m_node
->varNumber())));
3396 void compilePutClosureVar()
3399 lowJSValue(m_node
->child3()),
3400 addressFor(lowStorage(m_node
->child2()), m_node
->varNumber()));
3403 void compileCompareEq()
3405 if (m_node
->isBinaryUseKind(Int32Use
)
3406 || m_node
->isBinaryUseKind(Int52RepUse
)
3407 || m_node
->isBinaryUseKind(DoubleRepUse
)
3408 || m_node
->isBinaryUseKind(ObjectUse
)
3409 || m_node
->isBinaryUseKind(BooleanUse
)
3410 || m_node
->isBinaryUseKind(StringIdentUse
)) {
3411 compileCompareStrictEq();
3415 if (m_node
->isBinaryUseKind(ObjectUse
, ObjectOrOtherUse
)) {
3416 compareEqObjectOrOtherToObject(m_node
->child2(), m_node
->child1());
3420 if (m_node
->isBinaryUseKind(ObjectOrOtherUse
, ObjectUse
)) {
3421 compareEqObjectOrOtherToObject(m_node
->child1(), m_node
->child2());
3425 if (m_node
->isBinaryUseKind(UntypedUse
)) {
3426 nonSpeculativeCompare(LLVMIntEQ
, operationCompareEq
);
3430 RELEASE_ASSERT_NOT_REACHED();
3433 void compileCompareEqConstant()
3435 ASSERT(m_graph
.valueOfJSConstant(m_node
->child2().node()).isNull());
3437 equalNullOrUndefined(
3438 m_node
->child1(), AllCellsAreFalse
, EqualNullOrUndefined
));
3441 void compileCompareStrictEq()
3443 if (m_node
->isBinaryUseKind(Int32Use
)) {
3445 m_out
.equal(lowInt32(m_node
->child1()), lowInt32(m_node
->child2())));
3449 if (m_node
->isBinaryUseKind(Int52RepUse
)) {
3451 LValue left
= lowWhicheverInt52(m_node
->child1(), kind
);
3452 LValue right
= lowInt52(m_node
->child2(), kind
);
3453 setBoolean(m_out
.equal(left
, right
));
3457 if (m_node
->isBinaryUseKind(DoubleRepUse
)) {
3459 m_out
.doubleEqual(lowDouble(m_node
->child1()), lowDouble(m_node
->child2())));
3463 if (m_node
->isBinaryUseKind(StringIdentUse
)) {
3465 m_out
.equal(lowStringIdent(m_node
->child1()), lowStringIdent(m_node
->child2())));
3469 if (m_node
->isBinaryUseKind(ObjectUse
)) {
3472 lowNonNullObject(m_node
->child1()),
3473 lowNonNullObject(m_node
->child2())));
3477 if (m_node
->isBinaryUseKind(BooleanUse
)) {
3479 m_out
.equal(lowBoolean(m_node
->child1()), lowBoolean(m_node
->child2())));
3483 if (m_node
->isBinaryUseKind(MiscUse
, UntypedUse
)
3484 || m_node
->isBinaryUseKind(UntypedUse
, MiscUse
)) {
3485 speculate(m_node
->child1());
3486 speculate(m_node
->child2());
3487 LValue left
= lowJSValue(m_node
->child1(), ManualOperandSpeculation
);
3488 LValue right
= lowJSValue(m_node
->child2(), ManualOperandSpeculation
);
3489 setBoolean(m_out
.equal(left
, right
));
3493 if (m_node
->isBinaryUseKind(StringIdentUse
, NotStringVarUse
)
3494 || m_node
->isBinaryUseKind(NotStringVarUse
, StringIdentUse
)) {
3495 Edge leftEdge
= m_node
->childFor(StringIdentUse
);
3496 Edge rightEdge
= m_node
->childFor(NotStringVarUse
);
3498 LValue left
= lowStringIdent(leftEdge
);
3499 LValue rightValue
= lowJSValue(rightEdge
, ManualOperandSpeculation
);
3501 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("CompareStrictEq StringIdent to NotStringVar is cell case"));
3502 LBasicBlock isStringCase
= FTL_NEW_BLOCK(m_out
, ("CompareStrictEq StringIdent to NotStringVar is string case"));
3503 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("CompareStrictEq StringIdent to NotStringVar continuation"));
3505 ValueFromBlock notCellResult
= m_out
.anchor(m_out
.booleanFalse
);
3506 m_out
.branch(isCell(rightValue
), unsure(isCellCase
), unsure(continuation
));
3508 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, isStringCase
);
3509 ValueFromBlock notStringResult
= m_out
.anchor(m_out
.booleanFalse
);
3510 m_out
.branch(isString(rightValue
), unsure(isStringCase
), unsure(continuation
));
3512 m_out
.appendTo(isStringCase
, continuation
);
3513 LValue right
= m_out
.loadPtr(rightValue
, m_heaps
.JSString_value
);
3514 speculateStringIdent(rightEdge
, rightValue
, right
);
3515 ValueFromBlock isStringResult
= m_out
.anchor(m_out
.equal(left
, right
));
3516 m_out
.jump(continuation
);
3518 m_out
.appendTo(continuation
, lastNext
);
3519 setBoolean(m_out
.phi(m_out
.boolean
, notCellResult
, notStringResult
, isStringResult
));
3523 RELEASE_ASSERT_NOT_REACHED();
3526 void compileCompareStrictEqConstant()
3528 JSValue constant
= m_graph
.valueOfJSConstant(m_node
->child2().node());
3532 lowJSValue(m_node
->child1()),
3533 m_out
.constInt64(JSValue::encode(constant
))));
3536 void compileCompareLess()
3538 compare(LLVMIntSLT
, LLVMRealOLT
, operationCompareLess
);
3541 void compileCompareLessEq()
3543 compare(LLVMIntSLE
, LLVMRealOLE
, operationCompareLessEq
);
3546 void compileCompareGreater()
3548 compare(LLVMIntSGT
, LLVMRealOGT
, operationCompareGreater
);
3551 void compileCompareGreaterEq()
3553 compare(LLVMIntSGE
, LLVMRealOGE
, operationCompareGreaterEq
);
3556 void compileLogicalNot()
3558 setBoolean(m_out
.bitNot(boolify(m_node
->child1())));
3561 void compileCallOrConstruct()
3563 int dummyThisArgument
= m_node
->op() == Call
? 0 : 1;
3564 int numPassedArgs
= m_node
->numChildren() - 1;
3565 int numArgs
= numPassedArgs
+ dummyThisArgument
;
3567 LValue callee
= lowJSValue(m_graph
.varArgChild(m_node
, 0));
3569 unsigned stackmapID
= m_stackmapIDs
++;
3571 Vector
<LValue
> arguments
;
3572 arguments
.append(m_out
.constInt64(stackmapID
));
3573 arguments
.append(m_out
.constInt32(sizeOfCall()));
3574 arguments
.append(constNull(m_out
.ref8
));
3575 arguments
.append(m_out
.constInt32(1 + JSStack::CallFrameHeaderSize
- JSStack::CallerFrameAndPCSize
+ numArgs
));
3576 arguments
.append(callee
); // callee -> %rax
3577 arguments
.append(getUndef(m_out
.int64
)); // code block
3578 arguments
.append(getUndef(m_out
.int64
)); // scope chain
3579 arguments
.append(callee
); // callee -> stack
3580 arguments
.append(m_out
.constInt64(numArgs
)); // argument count and zeros for the tag
3581 if (dummyThisArgument
)
3582 arguments
.append(getUndef(m_out
.int64
));
3583 for (int i
= 0; i
< numPassedArgs
; ++i
)
3584 arguments
.append(lowJSValue(m_graph
.varArgChild(m_node
, 1 + i
)));
3588 LValue call
= m_out
.call(m_out
.patchpointInt64Intrinsic(), arguments
);
3589 setInstructionCallingConvention(call
, LLVMWebKitJSCallConv
);
3591 m_ftlState
.jsCalls
.append(JSCall(stackmapID
, m_node
));
3598 m_out
.jump(lowBlock(m_node
->targetBlock()));
3601 void compileBranch()
3604 boolify(m_node
->child1()),
3606 lowBlock(m_node
->branchData()->taken
.block
),
3607 m_node
->branchData()->taken
.count
),
3609 lowBlock(m_node
->branchData()->notTaken
.block
),
3610 m_node
->branchData()->notTaken
.count
));
3613 void compileSwitch()
3615 SwitchData
* data
= m_node
->switchData();
3616 switch (data
->kind
) {
3618 Vector
<ValueFromBlock
, 2> intValues
;
3619 LBasicBlock switchOnInts
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchImm int case"));
3621 LBasicBlock lastNext
= m_out
.appendTo(m_out
.m_block
, switchOnInts
);
3623 switch (m_node
->child1().useKind()) {
3625 intValues
.append(m_out
.anchor(lowInt32(m_node
->child1())));
3626 m_out
.jump(switchOnInts
);
3631 LBasicBlock isInt
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchImm is int"));
3632 LBasicBlock isNotInt
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchImm is not int"));
3633 LBasicBlock isDouble
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchImm is double"));
3635 LValue boxedValue
= lowJSValue(m_node
->child1());
3636 m_out
.branch(isNotInt32(boxedValue
), unsure(isNotInt
), unsure(isInt
));
3638 LBasicBlock innerLastNext
= m_out
.appendTo(isInt
, isNotInt
);
3640 intValues
.append(m_out
.anchor(unboxInt32(boxedValue
)));
3641 m_out
.jump(switchOnInts
);
3643 m_out
.appendTo(isNotInt
, isDouble
);
3645 isCellOrMisc(boxedValue
),
3646 usually(lowBlock(data
->fallThrough
.block
)), rarely(isDouble
));
3648 m_out
.appendTo(isDouble
, innerLastNext
);
3649 LValue doubleValue
= unboxDouble(boxedValue
);
3650 LValue intInDouble
= m_out
.fpToInt32(doubleValue
);
3651 intValues
.append(m_out
.anchor(intInDouble
));
3653 m_out
.doubleEqual(m_out
.intToDouble(intInDouble
), doubleValue
),
3654 unsure(switchOnInts
), unsure(lowBlock(data
->fallThrough
.block
)));
3659 RELEASE_ASSERT_NOT_REACHED();
3663 m_out
.appendTo(switchOnInts
, lastNext
);
3664 buildSwitch(data
, m_out
.int32
, m_out
.phi(m_out
.int32
, intValues
));
3671 // FIXME: We should use something other than unsure() for the branch weight
3672 // of the fallThrough block. The main challenge is just that we have multiple
3673 // branches to fallThrough but a single count, so we would need to divvy it up
3674 // among the different lowered branches.
3675 // https://bugs.webkit.org/show_bug.cgi?id=129082
3677 switch (m_node
->child1().useKind()) {
3679 stringValue
= lowString(m_node
->child1());
3684 LValue unboxedValue
= lowJSValue(m_node
->child1());
3686 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar is cell"));
3687 LBasicBlock isStringCase
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar is string"));
3690 isNotCell(unboxedValue
),
3691 unsure(lowBlock(data
->fallThrough
.block
)), unsure(isCellCase
));
3693 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, isStringCase
);
3694 LValue cellValue
= unboxedValue
;
3696 isNotString(cellValue
),
3697 unsure(lowBlock(data
->fallThrough
.block
)), unsure(isStringCase
));
3699 m_out
.appendTo(isStringCase
, lastNext
);
3700 stringValue
= cellValue
;
3705 RELEASE_ASSERT_NOT_REACHED();
3709 LBasicBlock lengthIs1
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar length is 1"));
3710 LBasicBlock needResolution
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar resolution"));
3711 LBasicBlock resolved
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar resolved"));
3712 LBasicBlock is8Bit
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar 8bit"));
3713 LBasicBlock is16Bit
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar 16bit"));
3714 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Switch/SwitchChar continuation"));
3718 m_out
.load32NonNegative(stringValue
, m_heaps
.JSString_length
),
3720 unsure(lowBlock(data
->fallThrough
.block
)), unsure(lengthIs1
));
3722 LBasicBlock lastNext
= m_out
.appendTo(lengthIs1
, needResolution
);
3723 Vector
<ValueFromBlock
, 2> values
;
3724 LValue fastValue
= m_out
.loadPtr(stringValue
, m_heaps
.JSString_value
);
3725 values
.append(m_out
.anchor(fastValue
));
3726 m_out
.branch(m_out
.isNull(fastValue
), rarely(needResolution
), usually(resolved
));
3728 m_out
.appendTo(needResolution
, resolved
);
3729 values
.append(m_out
.anchor(
3730 vmCall(m_out
.operation(operationResolveRope
), m_callFrame
, stringValue
)));
3731 m_out
.jump(resolved
);
3733 m_out
.appendTo(resolved
, is8Bit
);
3734 LValue value
= m_out
.phi(m_out
.intPtr
, values
);
3735 LValue characterData
= m_out
.loadPtr(value
, m_heaps
.StringImpl_data
);
3737 m_out
.testNonZero32(
3738 m_out
.load32(value
, m_heaps
.StringImpl_hashAndFlags
),
3739 m_out
.constInt32(StringImpl::flagIs8Bit())),
3740 unsure(is8Bit
), unsure(is16Bit
));
3742 Vector
<ValueFromBlock
, 2> characters
;
3743 m_out
.appendTo(is8Bit
, is16Bit
);
3744 characters
.append(m_out
.anchor(
3745 m_out
.zeroExt(m_out
.load8(characterData
, m_heaps
.characters8
[0]), m_out
.int16
)));
3746 m_out
.jump(continuation
);
3748 m_out
.appendTo(is16Bit
, continuation
);
3749 characters
.append(m_out
.anchor(m_out
.load16(characterData
, m_heaps
.characters16
[0])));
3750 m_out
.jump(continuation
);
3752 m_out
.appendTo(continuation
, lastNext
);
3753 buildSwitch(data
, m_out
.int16
, m_out
.phi(m_out
.int16
, characters
));
3758 RELEASE_ASSERT_NOT_REACHED();
3762 RELEASE_ASSERT_NOT_REACHED();
3765 void compileReturn()
3767 m_out
.ret(lowJSValue(m_node
->child1()));
3770 void compileForceOSRExit()
3772 terminate(InadequateCoverage
);
3777 terminate(Uncountable
);
3780 void compileInvalidationPoint()
3782 if (verboseCompilationEnabled())
3783 dataLog(" Invalidation point with availability: ", m_availability
, "\n");
3785 m_ftlState
.jitCode
->osrExit
.append(OSRExit(
3786 UncountableInvalidation
, InvalidValueFormat
, MethodOfGettingAValueProfile(),
3787 m_codeOriginForExitTarget
, m_codeOriginForExitProfile
,
3788 m_availability
.numberOfArguments(), m_availability
.numberOfLocals()));
3789 m_ftlState
.finalizer
->osrExit
.append(OSRExitCompilationInfo());
3791 OSRExit
& exit
= m_ftlState
.jitCode
->osrExit
.last();
3792 OSRExitCompilationInfo
& info
= m_ftlState
.finalizer
->osrExit
.last();
3794 ExitArgumentList arguments
;
3796 buildExitArguments(exit
, arguments
, FormattedValue(), exit
.m_codeOrigin
);
3797 callStackmap(exit
, arguments
);
3799 info
.m_isInvalidationPoint
= true;
3802 void compileCheckArgumentsNotCreated()
3804 ASSERT(!isEmptySpeculation(
3805 m_state
.variables().operand(
3806 m_graph
.argumentsRegisterFor(m_node
->origin
.semantic
)).m_type
));
3808 checkArgumentsNotCreated();
3811 void compileIsUndefined()
3813 setBoolean(equalNullOrUndefined(m_node
->child1(), AllCellsAreFalse
, EqualUndefined
));
3816 void compileIsBoolean()
3818 setBoolean(isBoolean(lowJSValue(m_node
->child1())));
3821 void compileIsNumber()
3823 setBoolean(isNumber(lowJSValue(m_node
->child1())));
3826 void compileIsString()
3828 LValue value
= lowJSValue(m_node
->child1());
3830 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("IsString cell case"));
3831 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("IsString continuation"));
3833 ValueFromBlock notCellResult
= m_out
.anchor(m_out
.booleanFalse
);
3834 m_out
.branch(isCell(value
), unsure(isCellCase
), unsure(continuation
));
3836 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, continuation
);
3837 ValueFromBlock cellResult
= m_out
.anchor(isString(value
));
3838 m_out
.jump(continuation
);
3840 m_out
.appendTo(continuation
, lastNext
);
3841 setBoolean(m_out
.phi(m_out
.boolean
, notCellResult
, cellResult
));
3844 void compileIsObject()
3846 LValue pointerResult
= vmCall(
3847 m_out
.operation(operationIsObject
), m_callFrame
, lowJSValue(m_node
->child1()));
3848 setBoolean(m_out
.notNull(pointerResult
));
3851 void compileIsFunction()
3853 LValue pointerResult
= vmCall(
3854 m_out
.operation(operationIsFunction
), lowJSValue(m_node
->child1()));
3855 setBoolean(m_out
.notNull(pointerResult
));
3858 void compileCheckHasInstance()
3861 Uncountable
, noValue(), 0,
3863 m_out
.load8(lowCell(m_node
->child1()), m_heaps
.JSCell_typeInfoFlags
),
3864 m_out
.constInt8(ImplementsDefaultHasInstance
)));
3867 void compileInstanceOf()
3871 if (m_node
->child1().useKind() == UntypedUse
)
3872 cell
= lowJSValue(m_node
->child1());
3874 cell
= lowCell(m_node
->child1());
3876 LValue prototype
= lowCell(m_node
->child2());
3878 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("InstanceOf cell case"));
3879 LBasicBlock loop
= FTL_NEW_BLOCK(m_out
, ("InstanceOf loop"));
3880 LBasicBlock notYetInstance
= FTL_NEW_BLOCK(m_out
, ("InstanceOf not yet instance"));
3881 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("InstanceOf continuation"));
3884 if (m_node
->child1().useKind() == UntypedUse
)
3885 condition
= isCell(cell
);
3887 condition
= m_out
.booleanTrue
;
3889 ValueFromBlock notCellResult
= m_out
.anchor(m_out
.booleanFalse
);
3890 m_out
.branch(condition
, unsure(isCellCase
), unsure(continuation
));
3892 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, loop
);
3894 speculate(BadType
, noValue(), 0, isNotObject(prototype
));
3896 ValueFromBlock originalValue
= m_out
.anchor(cell
);
3899 m_out
.appendTo(loop
, notYetInstance
);
3900 LValue value
= m_out
.phi(m_out
.int64
, originalValue
);
3901 LValue structure
= loadStructure(value
);
3902 LValue currentPrototype
= m_out
.load64(structure
, m_heaps
.Structure_prototype
);
3903 ValueFromBlock isInstanceResult
= m_out
.anchor(m_out
.booleanTrue
);
3905 m_out
.equal(currentPrototype
, prototype
),
3906 unsure(continuation
), unsure(notYetInstance
));
3908 m_out
.appendTo(notYetInstance
, continuation
);
3909 ValueFromBlock notInstanceResult
= m_out
.anchor(m_out
.booleanFalse
);
3910 addIncoming(value
, m_out
.anchor(currentPrototype
));
3911 m_out
.branch(isCell(currentPrototype
), unsure(loop
), unsure(continuation
));
3913 m_out
.appendTo(continuation
, lastNext
);
3915 m_out
.phi(m_out
.boolean
, notCellResult
, isInstanceResult
, notInstanceResult
));
3918 void compileCountExecution()
3920 TypedPointer counter
= m_out
.absolute(m_node
->executionCounter()->address());
3921 m_out
.store64(m_out
.add(m_out
.load64(counter
), m_out
.constInt64(1)), counter
);
3924 void compileStoreBarrier()
3926 emitStoreBarrier(lowCell(m_node
->child1()));
3929 void compileStoreBarrierWithNullCheck()
3932 LBasicBlock isNotNull
= FTL_NEW_BLOCK(m_out
, ("Store barrier with null check value not null"));
3933 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Store barrier continuation"));
3935 LValue base
= lowJSValue(m_node
->child1());
3936 m_out
.branch(m_out
.isZero64(base
), unsure(continuation
), unsure(isNotNull
));
3937 LBasicBlock lastNext
= m_out
.appendTo(isNotNull
, continuation
);
3938 emitStoreBarrier(base
);
3939 m_out
.appendTo(continuation
, lastNext
);
3941 speculate(m_node
->child1());
3945 LValue
didOverflowStack()
3947 // This does a very simple leaf function analysis. The invariant of FTL call
3948 // frames is that the caller had already done enough of a stack check to
3949 // prove that this call frame has enough stack to run, and also enough stack
3950 // to make runtime calls. So, we only need to stack check when making calls
3951 // to other JS functions. If we don't find such calls then we don't need to
3952 // do any stack checks.
3954 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
3955 BasicBlock
* block
= m_graph
.block(blockIndex
);
3959 for (unsigned nodeIndex
= block
->size(); nodeIndex
--;) {
3960 Node
* node
= block
->at(nodeIndex
);
3962 switch (node
->op()) {
3970 m_out
.absolute(vm().addressOfFTLStackLimit())));
3978 return m_out
.booleanFalse
;
3981 LValue
numberOrNotCellToInt32(Edge edge
, LValue value
)
3983 LBasicBlock intCase
= FTL_NEW_BLOCK(m_out
, ("ValueToInt32 int case"));
3984 LBasicBlock notIntCase
= FTL_NEW_BLOCK(m_out
, ("ValueToInt32 not int case"));
3985 LBasicBlock doubleCase
= 0;
3986 LBasicBlock notNumberCase
= 0;
3987 if (edge
.useKind() == NotCellUse
) {
3988 doubleCase
= FTL_NEW_BLOCK(m_out
, ("ValueToInt32 double case"));
3989 notNumberCase
= FTL_NEW_BLOCK(m_out
, ("ValueToInt32 not number case"));
3991 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("ValueToInt32 continuation"));
3993 Vector
<ValueFromBlock
> results
;
3995 m_out
.branch(isNotInt32(value
), unsure(notIntCase
), unsure(intCase
));
3997 LBasicBlock lastNext
= m_out
.appendTo(intCase
, notIntCase
);
3998 results
.append(m_out
.anchor(unboxInt32(value
)));
3999 m_out
.jump(continuation
);
4001 if (edge
.useKind() == NumberUse
) {
4002 m_out
.appendTo(notIntCase
, continuation
);
4003 FTL_TYPE_CHECK(jsValueValue(value
), edge
, SpecBytecodeNumber
, isCellOrMisc(value
));
4004 results
.append(m_out
.anchor(doubleToInt32(unboxDouble(value
))));
4005 m_out
.jump(continuation
);
4007 m_out
.appendTo(notIntCase
, doubleCase
);
4008 m_out
.branch(isCellOrMisc(value
), unsure(notNumberCase
), unsure(doubleCase
));
4010 m_out
.appendTo(doubleCase
, notNumberCase
);
4011 results
.append(m_out
.anchor(doubleToInt32(unboxDouble(value
))));
4012 m_out
.jump(continuation
);
4014 m_out
.appendTo(notNumberCase
, continuation
);
4016 FTL_TYPE_CHECK(jsValueValue(value
), edge
, ~SpecCell
, isCell(value
));
4018 LValue specialResult
= m_out
.select(
4019 m_out
.equal(value
, m_out
.constInt64(JSValue::encode(jsBoolean(true)))),
4020 m_out
.int32One
, m_out
.int32Zero
);
4021 results
.append(m_out
.anchor(specialResult
));
4022 m_out
.jump(continuation
);
4025 m_out
.appendTo(continuation
, lastNext
);
4026 return m_out
.phi(m_out
.int32
, results
);
4029 LValue
loadProperty(LValue storage
, unsigned identifierNumber
, PropertyOffset offset
)
4031 return m_out
.load64(addressOfProperty(storage
, identifierNumber
, offset
));
4035 LValue value
, LValue storage
, unsigned identifierNumber
, PropertyOffset offset
)
4037 m_out
.store64(value
, addressOfProperty(storage
, identifierNumber
, offset
));
4040 TypedPointer
addressOfProperty(
4041 LValue storage
, unsigned identifierNumber
, PropertyOffset offset
)
4043 return m_out
.address(
4044 m_heaps
.properties
[identifierNumber
], storage
, offsetRelativeToBase(offset
));
4047 LValue
storageForTransition(
4048 LValue object
, PropertyOffset offset
,
4049 Structure
* previousStructure
, Structure
* nextStructure
)
4051 if (isInlineOffset(offset
))
4054 if (previousStructure
->outOfLineCapacity() == nextStructure
->outOfLineCapacity())
4055 return m_out
.loadPtr(object
, m_heaps
.JSObject_butterfly
);
4058 if (!previousStructure
->outOfLineCapacity())
4059 result
= allocatePropertyStorage(object
, previousStructure
);
4061 result
= reallocatePropertyStorage(
4062 object
, m_out
.loadPtr(object
, m_heaps
.JSObject_butterfly
),
4063 previousStructure
, nextStructure
);
4066 emitStoreBarrier(object
);
4071 LValue
allocatePropertyStorage(LValue object
, Structure
* previousStructure
)
4073 if (previousStructure
->couldHaveIndexingHeader()) {
4076 operationReallocateButterflyToHavePropertyStorageWithInitialCapacity
),
4077 m_callFrame
, object
);
4080 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("allocatePropertyStorage slow path"));
4081 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("allocatePropertyStorage continuation"));
4083 LBasicBlock lastNext
= m_out
.insertNewBlocksBefore(slowPath
);
4085 LValue endOfStorage
= allocateBasicStorageAndGetEnd(
4086 m_out
.constIntPtr(initialOutOfLineCapacity
* sizeof(JSValue
)), slowPath
);
4088 ValueFromBlock fastButterfly
= m_out
.anchor(
4089 m_out
.add(m_out
.constIntPtr(sizeof(IndexingHeader
)), endOfStorage
));
4091 m_out
.jump(continuation
);
4093 m_out
.appendTo(slowPath
, continuation
);
4095 ValueFromBlock slowButterfly
= m_out
.anchor(vmCall(
4096 m_out
.operation(operationAllocatePropertyStorageWithInitialCapacity
), m_callFrame
));
4098 m_out
.jump(continuation
);
4100 m_out
.appendTo(continuation
, lastNext
);
4102 LValue result
= m_out
.phi(m_out
.intPtr
, fastButterfly
, slowButterfly
);
4103 m_out
.storePtr(result
, object
, m_heaps
.JSObject_butterfly
);
4108 LValue
reallocatePropertyStorage(
4109 LValue object
, LValue oldStorage
, Structure
* previous
, Structure
* next
)
4111 size_t oldSize
= previous
->outOfLineCapacity() * sizeof(JSValue
);
4112 size_t newSize
= oldSize
* outOfLineGrowthFactor
;
4114 ASSERT_UNUSED(next
, newSize
== next
->outOfLineCapacity() * sizeof(JSValue
));
4116 if (previous
->couldHaveIndexingHeader()) {
4117 LValue newAllocSize
= m_out
.constInt64(newSize
/ sizeof(JSValue
));
4118 return vmCall(m_out
.operation(operationReallocateButterflyToGrowPropertyStorage
), m_callFrame
, object
, newAllocSize
);
4121 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("reallocatePropertyStorage slow path"));
4122 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("reallocatePropertyStorage continuation"));
4123 LBasicBlock lastNext
= m_out
.insertNewBlocksBefore(slowPath
);
4125 LValue endOfStorage
=
4126 allocateBasicStorageAndGetEnd(m_out
.constIntPtr(newSize
), slowPath
);
4128 ValueFromBlock fastButterfly
= m_out
.anchor(m_out
.add(m_out
.constIntPtr(sizeof(IndexingHeader
)), endOfStorage
));
4130 m_out
.jump(continuation
);
4132 m_out
.appendTo(slowPath
, continuation
);
4134 LValue newAllocSize
= m_out
.constInt64(newSize
/ sizeof(JSValue
));
4136 LValue storageLocation
= vmCall(m_out
.operation(operationAllocatePropertyStorage
), m_callFrame
, newAllocSize
);
4138 ValueFromBlock slowButterfly
= m_out
.anchor(storageLocation
);
4140 m_out
.jump(continuation
);
4142 m_out
.appendTo(continuation
, lastNext
);
4144 LValue result
= m_out
.phi(m_out
.intPtr
, fastButterfly
, slowButterfly
);
4146 ptrdiff_t headerSize
= -sizeof(JSValue
) - sizeof(void *);
4147 ptrdiff_t endStorage
= headerSize
- static_cast<ptrdiff_t>(oldSize
);
4149 for (ptrdiff_t offset
= headerSize
; offset
> endStorage
; offset
-= sizeof(void*)) {
4151 m_out
.loadPtr(m_out
.address(m_heaps
.properties
.atAnyNumber(), oldStorage
, offset
));
4152 m_out
.storePtr(loaded
, m_out
.address(m_heaps
.properties
.atAnyNumber(), result
, offset
));
4155 m_out
.storePtr(result
, m_out
.address(object
, m_heaps
.JSObject_butterfly
));
4160 LValue
getById(LValue base
)
4162 StringImpl
* uid
= m_graph
.identifiers()[m_node
->identifierNumber()];
4164 // Arguments: id, bytes, target, numArgs, args...
4165 unsigned stackmapID
= m_stackmapIDs
++;
4167 if (Options::verboseCompilation())
4168 dataLog(" Emitting GetById patchpoint with stackmap #", stackmapID
, "\n");
4170 LValue call
= m_out
.call(
4171 m_out
.patchpointInt64Intrinsic(),
4172 m_out
.constInt64(stackmapID
), m_out
.constInt32(sizeOfGetById()),
4173 constNull(m_out
.ref8
), m_out
.constInt32(1), base
);
4174 setInstructionCallingConvention(call
, LLVMAnyRegCallConv
);
4176 m_ftlState
.getByIds
.append(GetByIdDescriptor(stackmapID
, m_node
->origin
.semantic
, uid
));
4181 TypedPointer
baseIndex(IndexedAbstractHeap
& heap
, LValue storage
, LValue index
, Edge edge
)
4183 return m_out
.baseIndex(
4184 heap
, storage
, m_out
.zeroExt(index
, m_out
.intPtr
),
4185 m_state
.forNode(edge
).m_value
);
4189 LIntPredicate intCondition
, LRealPredicate realCondition
,
4190 S_JITOperation_EJJ helperFunction
)
4192 if (m_node
->isBinaryUseKind(Int32Use
)) {
4193 LValue left
= lowInt32(m_node
->child1());
4194 LValue right
= lowInt32(m_node
->child2());
4195 setBoolean(m_out
.icmp(intCondition
, left
, right
));
4199 if (m_node
->isBinaryUseKind(Int52RepUse
)) {
4201 LValue left
= lowWhicheverInt52(m_node
->child1(), kind
);
4202 LValue right
= lowInt52(m_node
->child2(), kind
);
4203 setBoolean(m_out
.icmp(intCondition
, left
, right
));
4207 if (m_node
->isBinaryUseKind(DoubleRepUse
)) {
4208 LValue left
= lowDouble(m_node
->child1());
4209 LValue right
= lowDouble(m_node
->child2());
4210 setBoolean(m_out
.fcmp(realCondition
, left
, right
));
4214 if (m_node
->isBinaryUseKind(UntypedUse
)) {
4215 nonSpeculativeCompare(intCondition
, helperFunction
);
4219 RELEASE_ASSERT_NOT_REACHED();
4222 void compareEqObjectOrOtherToObject(Edge leftChild
, Edge rightChild
)
4224 LValue rightCell
= lowCell(rightChild
);
4225 LValue leftValue
= lowJSValue(leftChild
, ManualOperandSpeculation
);
4227 speculateTruthyObject(rightChild
, rightCell
, SpecObject
);
4229 LBasicBlock leftCellCase
= FTL_NEW_BLOCK(m_out
, ("CompareEqObjectOrOtherToObject left cell case"));
4230 LBasicBlock leftNotCellCase
= FTL_NEW_BLOCK(m_out
, ("CompareEqObjectOrOtherToObject left not cell case"));
4231 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("CompareEqObjectOrOtherToObject continuation"));
4233 m_out
.branch(isCell(leftValue
), unsure(leftCellCase
), unsure(leftNotCellCase
));
4235 LBasicBlock lastNext
= m_out
.appendTo(leftCellCase
, leftNotCellCase
);
4236 speculateTruthyObject(leftChild
, leftValue
, SpecObject
| (~SpecCell
));
4237 ValueFromBlock cellResult
= m_out
.anchor(m_out
.equal(rightCell
, leftValue
));
4238 m_out
.jump(continuation
);
4240 m_out
.appendTo(leftNotCellCase
, continuation
);
4242 jsValueValue(leftValue
), leftChild
, SpecOther
| SpecCell
, isNotOther(leftValue
));
4243 ValueFromBlock notCellResult
= m_out
.anchor(m_out
.booleanFalse
);
4244 m_out
.jump(continuation
);
4246 m_out
.appendTo(continuation
, lastNext
);
4247 setBoolean(m_out
.phi(m_out
.boolean
, cellResult
, notCellResult
));
4250 void speculateTruthyObject(Edge edge
, LValue cell
, SpeculatedType filter
)
4252 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
4253 FTL_TYPE_CHECK(jsValueValue(cell
), edge
, filter
, isNotObject(cell
));
4257 LValue structureID
= m_out
.load32(cell
, m_heaps
.JSCell_structureID
);
4259 jsValueValue(cell
), edge
, filter
,
4260 m_out
.equal(structureID
, m_out
.constInt32(vm().stringStructure
->id())));
4262 BadType
, jsValueValue(cell
), edge
.node(),
4264 m_out
.load8(cell
, m_heaps
.JSCell_typeInfoFlags
),
4265 m_out
.constInt8(MasqueradesAsUndefined
)));
4268 void nonSpeculativeCompare(LIntPredicate intCondition
, S_JITOperation_EJJ helperFunction
)
4270 LValue left
= lowJSValue(m_node
->child1());
4271 LValue right
= lowJSValue(m_node
->child2());
4273 LBasicBlock leftIsInt
= FTL_NEW_BLOCK(m_out
, ("CompareEq untyped left is int"));
4274 LBasicBlock fastPath
= FTL_NEW_BLOCK(m_out
, ("CompareEq untyped fast path"));
4275 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("CompareEq untyped slow path"));
4276 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("CompareEq untyped continuation"));
4278 m_out
.branch(isNotInt32(left
), rarely(slowPath
), usually(leftIsInt
));
4280 LBasicBlock lastNext
= m_out
.appendTo(leftIsInt
, fastPath
);
4281 m_out
.branch(isNotInt32(right
), rarely(slowPath
), usually(fastPath
));
4283 m_out
.appendTo(fastPath
, slowPath
);
4284 ValueFromBlock fastResult
= m_out
.anchor(
4285 m_out
.icmp(intCondition
, unboxInt32(left
), unboxInt32(right
)));
4286 m_out
.jump(continuation
);
4288 m_out
.appendTo(slowPath
, continuation
);
4289 ValueFromBlock slowResult
= m_out
.anchor(m_out
.notNull(vmCall(
4290 m_out
.operation(helperFunction
), m_callFrame
, left
, right
)));
4291 m_out
.jump(continuation
);
4293 m_out
.appendTo(continuation
, lastNext
);
4294 setBoolean(m_out
.phi(m_out
.boolean
, fastResult
, slowResult
));
4297 LValue
allocateCell(LValue allocator
, Structure
* structure
, LBasicBlock slowPath
)
4299 LBasicBlock success
= FTL_NEW_BLOCK(m_out
, ("object allocation success"));
4301 LValue result
= m_out
.loadPtr(
4302 allocator
, m_heaps
.MarkedAllocator_freeListHead
);
4304 m_out
.branch(m_out
.notNull(result
), usually(success
), rarely(slowPath
));
4306 m_out
.appendTo(success
);
4309 m_out
.loadPtr(result
, m_heaps
.JSCell_freeListNext
),
4310 allocator
, m_heaps
.MarkedAllocator_freeListHead
);
4312 m_out
.store32(m_out
.constInt32(structure
->id()), result
, m_heaps
.JSCell_structureID
);
4313 m_out
.store8(m_out
.constInt8(structure
->indexingType()), result
, m_heaps
.JSCell_indexingType
);
4314 m_out
.store8(m_out
.constInt8(structure
->typeInfo().type()), result
, m_heaps
.JSCell_typeInfoType
);
4315 m_out
.store8(m_out
.constInt8(structure
->typeInfo().inlineTypeFlags()), result
, m_heaps
.JSCell_typeInfoFlags
);
4316 m_out
.store8(m_out
.constInt8(JSCell::NotMarked
), result
, m_heaps
.JSCell_gcData
);
4321 LValue
allocateObject(
4322 LValue allocator
, Structure
* structure
, LValue butterfly
, LBasicBlock slowPath
)
4324 LValue result
= allocateCell(allocator
, structure
, slowPath
);
4325 m_out
.storePtr(butterfly
, result
, m_heaps
.JSObject_butterfly
);
4329 template<typename ClassType
>
4330 LValue
allocateObject(Structure
* structure
, LValue butterfly
, LBasicBlock slowPath
)
4332 MarkedAllocator
* allocator
;
4333 size_t size
= ClassType::allocationSize(0);
4334 if (ClassType::needsDestruction
&& ClassType::hasImmortalStructure
)
4335 allocator
= &vm().heap
.allocatorForObjectWithImmortalStructureDestructor(size
);
4336 else if (ClassType::needsDestruction
)
4337 allocator
= &vm().heap
.allocatorForObjectWithNormalDestructor(size
);
4339 allocator
= &vm().heap
.allocatorForObjectWithoutDestructor(size
);
4340 return allocateObject(m_out
.constIntPtr(allocator
), structure
, butterfly
, slowPath
);
4343 // Returns a pointer to the end of the allocation.
4344 LValue
allocateBasicStorageAndGetEnd(LValue size
, LBasicBlock slowPath
)
4346 CopiedAllocator
& allocator
= vm().heap
.storageAllocator();
4348 LBasicBlock success
= FTL_NEW_BLOCK(m_out
, ("storage allocation success"));
4350 LValue remaining
= m_out
.loadPtr(m_out
.absolute(&allocator
.m_currentRemaining
));
4351 LValue newRemaining
= m_out
.sub(remaining
, size
);
4354 m_out
.lessThan(newRemaining
, m_out
.intPtrZero
),
4355 rarely(slowPath
), usually(success
));
4357 m_out
.appendTo(success
);
4359 m_out
.storePtr(newRemaining
, m_out
.absolute(&allocator
.m_currentRemaining
));
4361 m_out
.loadPtr(m_out
.absolute(&allocator
.m_currentPayloadEnd
)), newRemaining
);
4364 struct ArrayValues
{
4371 ArrayValues(LValue array
, LValue butterfly
)
4373 , butterfly(butterfly
)
4380 ArrayValues
allocateJSArray(
4381 Structure
* structure
, unsigned numElements
, LBasicBlock slowPath
)
4384 hasUndecided(structure
->indexingType())
4385 || hasInt32(structure
->indexingType())
4386 || hasDouble(structure
->indexingType())
4387 || hasContiguous(structure
->indexingType()));
4389 unsigned vectorLength
= std::max(BASE_VECTOR_LEN
, numElements
);
4391 LValue endOfStorage
= allocateBasicStorageAndGetEnd(
4392 m_out
.constIntPtr(sizeof(JSValue
) * vectorLength
+ sizeof(IndexingHeader
)),
4395 LValue butterfly
= m_out
.sub(
4396 endOfStorage
, m_out
.constIntPtr(sizeof(JSValue
) * vectorLength
));
4398 LValue object
= allocateObject
<JSArray
>(
4399 structure
, butterfly
, slowPath
);
4401 m_out
.store32(m_out
.constInt32(numElements
), butterfly
, m_heaps
.Butterfly_publicLength
);
4402 m_out
.store32(m_out
.constInt32(vectorLength
), butterfly
, m_heaps
.Butterfly_vectorLength
);
4404 if (hasDouble(structure
->indexingType())) {
4405 for (unsigned i
= numElements
; i
< vectorLength
; ++i
) {
4407 m_out
.constInt64(bitwise_cast
<int64_t>(PNaN
)),
4408 butterfly
, m_heaps
.indexedDoubleProperties
[i
]);
4412 return ArrayValues(object
, butterfly
);
4415 ArrayValues
allocateJSArray(Structure
* structure
, unsigned numElements
)
4417 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("JSArray allocation slow path"));
4418 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("JSArray allocation continuation"));
4420 LBasicBlock lastNext
= m_out
.insertNewBlocksBefore(slowPath
);
4422 ArrayValues fastValues
= allocateJSArray(structure
, numElements
, slowPath
);
4423 ValueFromBlock fastArray
= m_out
.anchor(fastValues
.array
);
4424 ValueFromBlock fastButterfly
= m_out
.anchor(fastValues
.butterfly
);
4426 m_out
.jump(continuation
);
4428 m_out
.appendTo(slowPath
, continuation
);
4430 ValueFromBlock slowArray
= m_out
.anchor(vmCall(
4431 m_out
.operation(operationNewArrayWithSize
), m_callFrame
,
4432 m_out
.constIntPtr(structure
), m_out
.constInt32(numElements
)));
4433 ValueFromBlock slowButterfly
= m_out
.anchor(
4434 m_out
.loadPtr(slowArray
.value(), m_heaps
.JSObject_butterfly
));
4436 m_out
.jump(continuation
);
4438 m_out
.appendTo(continuation
, lastNext
);
4441 m_out
.phi(m_out
.intPtr
, fastArray
, slowArray
),
4442 m_out
.phi(m_out
.intPtr
, fastButterfly
, slowButterfly
));
4445 LValue
typedArrayLength(Edge baseEdge
, ArrayMode arrayMode
, LValue base
)
4447 if (JSArrayBufferView
* view
= m_graph
.tryGetFoldableView(baseEdge
.node(), arrayMode
))
4448 return m_out
.constInt32(view
->length());
4449 return m_out
.load32NonNegative(base
, m_heaps
.JSArrayBufferView_length
);
4452 LValue
typedArrayLength(Edge baseEdge
, ArrayMode arrayMode
)
4454 return typedArrayLength(baseEdge
, arrayMode
, lowCell(baseEdge
));
4457 LValue
boolify(Edge edge
)
4459 switch (edge
.useKind()) {
4461 return lowBoolean(m_node
->child1());
4463 return m_out
.notZero32(lowInt32(m_node
->child1()));
4465 return m_out
.doubleNotEqual(lowDouble(edge
), m_out
.doubleZero
);
4466 case ObjectOrOtherUse
:
4467 return m_out
.bitNot(
4468 equalNullOrUndefined(
4469 edge
, CellCaseSpeculatesObject
, SpeculateNullOrUndefined
,
4470 ManualOperandSpeculation
));
4472 LValue stringValue
= lowString(m_node
->child1());
4473 LValue length
= m_out
.load32NonNegative(stringValue
, m_heaps
.JSString_length
);
4474 return m_out
.notEqual(length
, m_out
.int32Zero
);
4477 LValue value
= lowJSValue(m_node
->child1());
4479 LBasicBlock slowCase
= FTL_NEW_BLOCK(m_out
, ("Boolify untyped slow case"));
4480 LBasicBlock fastCase
= FTL_NEW_BLOCK(m_out
, ("Boolify untyped fast case"));
4481 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Boolify untyped continuation"));
4483 m_out
.branch(isNotBoolean(value
), rarely(slowCase
), usually(fastCase
));
4485 LBasicBlock lastNext
= m_out
.appendTo(fastCase
, slowCase
);
4486 ValueFromBlock fastResult
= m_out
.anchor(unboxBoolean(value
));
4487 m_out
.jump(continuation
);
4489 m_out
.appendTo(slowCase
, continuation
);
4490 ValueFromBlock slowResult
= m_out
.anchor(m_out
.notNull(vmCall(
4491 m_out
.operation(operationConvertJSValueToBoolean
), m_callFrame
, value
)));
4492 m_out
.jump(continuation
);
4494 m_out
.appendTo(continuation
, lastNext
);
4495 return m_out
.phi(m_out
.boolean
, fastResult
, slowResult
);
4498 RELEASE_ASSERT_NOT_REACHED();
4503 enum StringOrObjectMode
{
4505 CellCaseSpeculatesObject
4507 enum EqualNullOrUndefinedMode
{
4510 EqualNullOrUndefined
,
4511 SpeculateNullOrUndefined
4513 LValue
equalNullOrUndefined(
4514 Edge edge
, StringOrObjectMode cellMode
, EqualNullOrUndefinedMode primitiveMode
,
4515 OperandSpeculationMode operandMode
= AutomaticOperandSpeculation
)
4517 bool validWatchpoint
= masqueradesAsUndefinedWatchpointIsStillValid();
4519 LValue value
= lowJSValue(edge
, operandMode
);
4521 LBasicBlock cellCase
= FTL_NEW_BLOCK(m_out
, ("EqualNullOrUndefined cell case"));
4522 LBasicBlock primitiveCase
= FTL_NEW_BLOCK(m_out
, ("EqualNullOrUndefined primitive case"));
4523 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("EqualNullOrUndefined continuation"));
4525 m_out
.branch(isNotCell(value
), unsure(primitiveCase
), unsure(cellCase
));
4527 LBasicBlock lastNext
= m_out
.appendTo(cellCase
, primitiveCase
);
4529 Vector
<ValueFromBlock
, 3> results
;
4532 case AllCellsAreFalse
:
4534 case CellCaseSpeculatesObject
:
4536 jsValueValue(value
), edge
, (~SpecCell
) | SpecObject
,
4538 m_out
.load32(value
, m_heaps
.JSCell_structureID
),
4539 m_out
.constInt32(vm().stringStructure
->id())));
4543 if (validWatchpoint
) {
4544 results
.append(m_out
.anchor(m_out
.booleanFalse
));
4545 m_out
.jump(continuation
);
4547 LBasicBlock masqueradesCase
=
4548 FTL_NEW_BLOCK(m_out
, ("EqualNullOrUndefined masquerades case"));
4550 results
.append(m_out
.anchor(m_out
.booleanFalse
));
4554 m_out
.load8(value
, m_heaps
.JSCell_typeInfoFlags
),
4555 m_out
.constInt8(MasqueradesAsUndefined
)),
4556 rarely(masqueradesCase
), usually(continuation
));
4558 m_out
.appendTo(masqueradesCase
, primitiveCase
);
4560 LValue structure
= loadStructure(value
);
4562 results
.append(m_out
.anchor(
4564 m_out
.constIntPtr(m_graph
.globalObjectFor(m_node
->origin
.semantic
)),
4565 m_out
.loadPtr(structure
, m_heaps
.Structure_globalObject
))));
4566 m_out
.jump(continuation
);
4569 m_out
.appendTo(primitiveCase
, continuation
);
4571 LValue primitiveResult
;
4572 switch (primitiveMode
) {
4574 primitiveResult
= m_out
.equal(value
, m_out
.constInt64(ValueNull
));
4576 case EqualUndefined
:
4577 primitiveResult
= m_out
.equal(value
, m_out
.constInt64(ValueUndefined
));
4579 case EqualNullOrUndefined
:
4580 primitiveResult
= isOther(value
);
4582 case SpeculateNullOrUndefined
:
4584 jsValueValue(value
), edge
, SpecCell
| SpecOther
, isNotOther(value
));
4585 primitiveResult
= m_out
.booleanTrue
;
4588 results
.append(m_out
.anchor(primitiveResult
));
4589 m_out
.jump(continuation
);
4591 m_out
.appendTo(continuation
, lastNext
);
4593 return m_out
.phi(m_out
.boolean
, results
);
4596 template<typename FunctionType
>
4597 void contiguousPutByValOutOfBounds(
4598 FunctionType slowPathFunction
, LValue base
, LValue storage
, LValue index
, LValue value
,
4599 LBasicBlock continuation
)
4601 LValue isNotInBounds
= m_out
.aboveOrEqual(
4602 index
, m_out
.load32NonNegative(storage
, m_heaps
.Butterfly_publicLength
));
4603 if (!m_node
->arrayMode().isInBounds()) {
4604 LBasicBlock notInBoundsCase
=
4605 FTL_NEW_BLOCK(m_out
, ("PutByVal not in bounds"));
4606 LBasicBlock performStore
=
4607 FTL_NEW_BLOCK(m_out
, ("PutByVal perform store"));
4609 m_out
.branch(isNotInBounds
, unsure(notInBoundsCase
), unsure(performStore
));
4611 LBasicBlock lastNext
= m_out
.appendTo(notInBoundsCase
, performStore
);
4613 LValue isOutOfBounds
= m_out
.aboveOrEqual(
4614 index
, m_out
.load32NonNegative(storage
, m_heaps
.Butterfly_vectorLength
));
4616 if (!m_node
->arrayMode().isOutOfBounds())
4617 speculate(OutOfBounds
, noValue(), 0, isOutOfBounds
);
4619 LBasicBlock outOfBoundsCase
=
4620 FTL_NEW_BLOCK(m_out
, ("PutByVal out of bounds"));
4621 LBasicBlock holeCase
=
4622 FTL_NEW_BLOCK(m_out
, ("PutByVal hole case"));
4624 m_out
.branch(isOutOfBounds
, unsure(outOfBoundsCase
), unsure(holeCase
));
4626 LBasicBlock innerLastNext
= m_out
.appendTo(outOfBoundsCase
, holeCase
);
4629 m_out
.operation(slowPathFunction
),
4630 m_callFrame
, base
, index
, value
);
4632 m_out
.jump(continuation
);
4634 m_out
.appendTo(holeCase
, innerLastNext
);
4638 m_out
.add(index
, m_out
.int32One
),
4639 storage
, m_heaps
.Butterfly_publicLength
);
4641 m_out
.jump(performStore
);
4642 m_out
.appendTo(performStore
, lastNext
);
4646 void buildSwitch(SwitchData
* data
, LType type
, LValue switchValue
)
4648 Vector
<SwitchCase
> cases
;
4649 for (unsigned i
= 0; i
< data
->cases
.size(); ++i
) {
4650 cases
.append(SwitchCase(
4651 constInt(type
, data
->cases
[i
].value
.switchLookupValue()),
4652 lowBlock(data
->cases
[i
].target
.block
), Weight(data
->cases
[i
].target
.count
)));
4655 m_out
.switchInstruction(
4657 lowBlock(data
->fallThrough
.block
), Weight(data
->fallThrough
.count
));
4660 LValue
doubleToInt32(LValue doubleValue
, double low
, double high
, bool isSigned
= true)
4662 LBasicBlock greatEnough
= FTL_NEW_BLOCK(m_out
, ("doubleToInt32 greatEnough"));
4663 LBasicBlock withinRange
= FTL_NEW_BLOCK(m_out
, ("doubleToInt32 withinRange"));
4664 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("doubleToInt32 slowPath"));
4665 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("doubleToInt32 continuation"));
4667 Vector
<ValueFromBlock
, 2> results
;
4670 m_out
.doubleGreaterThanOrEqual(doubleValue
, m_out
.constDouble(low
)),
4671 unsure(greatEnough
), unsure(slowPath
));
4673 LBasicBlock lastNext
= m_out
.appendTo(greatEnough
, withinRange
);
4675 m_out
.doubleLessThanOrEqual(doubleValue
, m_out
.constDouble(high
)),
4676 unsure(withinRange
), unsure(slowPath
));
4678 m_out
.appendTo(withinRange
, slowPath
);
4681 fastResult
= m_out
.fpToInt32(doubleValue
);
4683 fastResult
= m_out
.fpToUInt32(doubleValue
);
4684 results
.append(m_out
.anchor(fastResult
));
4685 m_out
.jump(continuation
);
4687 m_out
.appendTo(slowPath
, continuation
);
4688 results
.append(m_out
.anchor(m_out
.call(m_out
.operation(toInt32
), doubleValue
)));
4689 m_out
.jump(continuation
);
4691 m_out
.appendTo(continuation
, lastNext
);
4692 return m_out
.phi(m_out
.int32
, results
);
4695 LValue
doubleToInt32(LValue doubleValue
)
4697 if (Output::hasSensibleDoubleToInt())
4698 return sensibleDoubleToInt32(doubleValue
);
4700 double limit
= pow(2, 31) - 1;
4701 return doubleToInt32(doubleValue
, -limit
, limit
);
4704 LValue
sensibleDoubleToInt32(LValue doubleValue
)
4706 LBasicBlock slowPath
= FTL_NEW_BLOCK(m_out
, ("sensible doubleToInt32 slow path"));
4707 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("sensible doubleToInt32 continuation"));
4709 ValueFromBlock fastResult
= m_out
.anchor(
4710 m_out
.sensibleDoubleToInt(doubleValue
));
4712 m_out
.equal(fastResult
.value(), m_out
.constInt32(0x80000000)),
4713 rarely(slowPath
), usually(continuation
));
4715 LBasicBlock lastNext
= m_out
.appendTo(slowPath
, continuation
);
4716 ValueFromBlock slowResult
= m_out
.anchor(
4717 m_out
.call(m_out
.operation(toInt32
), doubleValue
));
4718 m_out
.jump(continuation
);
4720 m_out
.appendTo(continuation
, lastNext
);
4721 return m_out
.phi(m_out
.int32
, fastResult
, slowResult
);
4724 void checkArgumentsNotCreated()
4726 CodeOrigin codeOrigin
= m_node
->origin
.semantic
;
4727 VirtualRegister argumentsRegister
= m_graph
.argumentsRegisterFor(codeOrigin
);
4728 if (isEmptySpeculation(m_state
.variables().operand(argumentsRegister
).m_type
))
4731 VirtualRegister argsReg
= m_graph
.machineArgumentsRegisterFor(codeOrigin
);
4733 ArgumentsEscaped
, noValue(), 0,
4734 m_out
.notZero64(m_out
.load64(addressFor(argsReg
))));
4738 ExitKind kind
, FormattedValue lowValue
, Node
* highValue
, LValue failCondition
)
4740 appendOSRExit(kind
, lowValue
, highValue
, failCondition
);
4743 void terminate(ExitKind kind
)
4745 speculate(kind
, noValue(), 0, m_out
.booleanTrue
);
4749 FormattedValue lowValue
, Edge highValue
, SpeculatedType typesPassedThrough
,
4750 LValue failCondition
)
4752 appendTypeCheck(lowValue
, highValue
, typesPassedThrough
, failCondition
);
4755 void appendTypeCheck(
4756 FormattedValue lowValue
, Edge highValue
, SpeculatedType typesPassedThrough
,
4757 LValue failCondition
)
4759 if (!m_interpreter
.needsTypeCheck(highValue
, typesPassedThrough
))
4761 ASSERT(mayHaveTypeCheck(highValue
.useKind()));
4762 appendOSRExit(BadType
, lowValue
, highValue
.node(), failCondition
);
4763 m_interpreter
.filter(highValue
, typesPassedThrough
);
4766 LValue
lowInt32(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4768 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| (edge
.useKind() == Int32Use
|| edge
.useKind() == KnownInt32Use
));
4770 if (edge
->hasConstant()) {
4771 JSValue value
= m_graph
.valueOfJSConstant(edge
.node());
4772 if (!value
.isInt32()) {
4773 terminate(Uncountable
);
4774 return m_out
.int32Zero
;
4776 return m_out
.constInt32(value
.asInt32());
4779 LoweredNodeValue value
= m_int32Values
.get(edge
.node());
4781 return value
.value();
4783 value
= m_strictInt52Values
.get(edge
.node());
4785 return strictInt52ToInt32(edge
, value
.value());
4787 value
= m_int52Values
.get(edge
.node());
4789 return strictInt52ToInt32(edge
, int52ToStrictInt52(value
.value()));
4791 value
= m_jsValueValues
.get(edge
.node());
4792 if (isValid(value
)) {
4793 LValue boxedResult
= value
.value();
4795 jsValueValue(boxedResult
), edge
, SpecInt32
, isNotInt32(boxedResult
));
4796 LValue result
= unboxInt32(boxedResult
);
4797 setInt32(edge
.node(), result
);
4801 RELEASE_ASSERT(!(m_state
.forNode(edge
).m_type
& SpecInt32
));
4802 terminate(Uncountable
);
4803 return m_out
.int32Zero
;
4806 enum Int52Kind
{ StrictInt52
, Int52
};
4807 LValue
lowInt52(Edge edge
, Int52Kind kind
)
4809 RELEASE_ASSERT(edge
.useKind() == Int52RepUse
);
4811 LoweredNodeValue value
;
4815 value
= m_int52Values
.get(edge
.node());
4817 return value
.value();
4819 value
= m_strictInt52Values
.get(edge
.node());
4821 return strictInt52ToInt52(value
.value());
4825 value
= m_strictInt52Values
.get(edge
.node());
4827 return value
.value();
4829 value
= m_int52Values
.get(edge
.node());
4831 return int52ToStrictInt52(value
.value());
4835 RELEASE_ASSERT(!m_state
.forNode(edge
).m_type
);
4836 terminate(Uncountable
);
4837 return m_out
.int64Zero
;
4840 LValue
lowInt52(Edge edge
)
4842 return lowInt52(edge
, Int52
);
4845 LValue
lowStrictInt52(Edge edge
)
4847 return lowInt52(edge
, StrictInt52
);
4850 bool betterUseStrictInt52(Node
* node
)
4852 return !isValid(m_int52Values
.get(node
));
4854 bool betterUseStrictInt52(Edge edge
)
4856 return betterUseStrictInt52(edge
.node());
4858 template<typename T
>
4859 Int52Kind
bestInt52Kind(T node
)
4861 return betterUseStrictInt52(node
) ? StrictInt52
: Int52
;
4863 Int52Kind
opposite(Int52Kind kind
)
4871 RELEASE_ASSERT_NOT_REACHED();
4875 LValue
lowWhicheverInt52(Edge edge
, Int52Kind
& kind
)
4877 kind
= bestInt52Kind(edge
);
4878 return lowInt52(edge
, kind
);
4881 LValue
lowCell(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4883 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| DFG::isCell(edge
.useKind()));
4885 if (edge
->op() == JSConstant
) {
4886 JSValue value
= m_graph
.valueOfJSConstant(edge
.node());
4887 if (!value
.isCell()) {
4888 terminate(Uncountable
);
4889 return m_out
.intPtrZero
;
4891 return m_out
.constIntPtr(value
.asCell());
4894 LoweredNodeValue value
= m_jsValueValues
.get(edge
.node());
4895 if (isValid(value
)) {
4896 LValue uncheckedValue
= value
.value();
4898 jsValueValue(uncheckedValue
), edge
, SpecCell
, isNotCell(uncheckedValue
));
4899 return uncheckedValue
;
4902 RELEASE_ASSERT(!(m_state
.forNode(edge
).m_type
& SpecCell
));
4903 terminate(Uncountable
);
4904 return m_out
.intPtrZero
;
4907 LValue
lowObject(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4909 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| edge
.useKind() == ObjectUse
);
4911 LValue result
= lowCell(edge
, mode
);
4912 speculateObject(edge
, result
);
4916 LValue
lowString(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4918 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| edge
.useKind() == StringUse
|| edge
.useKind() == KnownStringUse
|| edge
.useKind() == StringIdentUse
);
4920 LValue result
= lowCell(edge
, mode
);
4921 speculateString(edge
, result
);
4925 LValue
lowStringIdent(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4927 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| edge
.useKind() == StringIdentUse
);
4929 LValue string
= lowString(edge
, mode
);
4930 LValue stringImpl
= m_out
.loadPtr(string
, m_heaps
.JSString_value
);
4931 speculateStringIdent(edge
, string
, stringImpl
);
4935 LValue
lowNonNullObject(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4937 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| edge
.useKind() == ObjectUse
);
4939 LValue result
= lowCell(edge
, mode
);
4940 speculateNonNullObject(edge
, result
);
4944 LValue
lowBoolean(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4946 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| edge
.useKind() == BooleanUse
);
4948 if (edge
->hasConstant()) {
4949 JSValue value
= m_graph
.valueOfJSConstant(edge
.node());
4950 if (!value
.isBoolean()) {
4951 terminate(Uncountable
);
4952 return m_out
.booleanFalse
;
4954 return m_out
.constBool(value
.asBoolean());
4957 LoweredNodeValue value
= m_booleanValues
.get(edge
.node());
4959 return value
.value();
4961 value
= m_jsValueValues
.get(edge
.node());
4962 if (isValid(value
)) {
4963 LValue unboxedResult
= value
.value();
4965 jsValueValue(unboxedResult
), edge
, SpecBoolean
, isNotBoolean(unboxedResult
));
4966 LValue result
= unboxBoolean(unboxedResult
);
4967 setBoolean(edge
.node(), result
);
4971 RELEASE_ASSERT(!(m_state
.forNode(edge
).m_type
& SpecBoolean
));
4972 terminate(Uncountable
);
4973 return m_out
.booleanFalse
;
4976 LValue
lowDouble(Edge edge
)
4978 RELEASE_ASSERT(isDouble(edge
.useKind()));
4980 LoweredNodeValue value
= m_doubleValues
.get(edge
.node());
4982 return value
.value();
4984 RELEASE_ASSERT(!m_state
.forNode(edge
).m_type
);
4985 terminate(Uncountable
);
4986 return m_out
.doubleZero
;
4989 LValue
lowJSValue(Edge edge
, OperandSpeculationMode mode
= AutomaticOperandSpeculation
)
4991 ASSERT_UNUSED(mode
, mode
== ManualOperandSpeculation
|| edge
.useKind() == UntypedUse
);
4992 RELEASE_ASSERT(!isDouble(edge
.useKind()));
4993 RELEASE_ASSERT(edge
.useKind() != Int52RepUse
);
4995 if (edge
->hasConstant())
4996 return m_out
.constInt64(JSValue::encode(m_graph
.valueOfJSConstant(edge
.node())));
4998 LoweredNodeValue value
= m_jsValueValues
.get(edge
.node());
5000 return value
.value();
5002 value
= m_int32Values
.get(edge
.node());
5003 if (isValid(value
)) {
5004 LValue result
= boxInt32(value
.value());
5005 setJSValue(edge
.node(), result
);
5009 value
= m_booleanValues
.get(edge
.node());
5010 if (isValid(value
)) {
5011 LValue result
= boxBoolean(value
.value());
5012 setJSValue(edge
.node(), result
);
5016 RELEASE_ASSERT_NOT_REACHED();
5020 LValue
lowStorage(Edge edge
)
5022 LoweredNodeValue value
= m_storageValues
.get(edge
.node());
5024 return value
.value();
5026 LValue result
= lowCell(edge
);
5027 setStorage(edge
.node(), result
);
5031 LValue
strictInt52ToInt32(Edge edge
, LValue value
)
5033 LValue result
= m_out
.castToInt32(value
);
5035 noValue(), edge
, SpecInt32
,
5036 m_out
.notEqual(m_out
.signExt(result
, m_out
.int64
), value
));
5037 setInt32(edge
.node(), result
);
5041 LValue
strictInt52ToDouble(LValue value
)
5043 return m_out
.intToDouble(value
);
5046 LValue
strictInt52ToJSValue(LValue value
)
5048 LBasicBlock isInt32
= FTL_NEW_BLOCK(m_out
, ("strictInt52ToJSValue isInt32 case"));
5049 LBasicBlock isDouble
= FTL_NEW_BLOCK(m_out
, ("strictInt52ToJSValue isDouble case"));
5050 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("strictInt52ToJSValue continuation"));
5052 Vector
<ValueFromBlock
, 2> results
;
5054 LValue int32Value
= m_out
.castToInt32(value
);
5056 m_out
.equal(m_out
.signExt(int32Value
, m_out
.int64
), value
),
5057 unsure(isInt32
), unsure(isDouble
));
5059 LBasicBlock lastNext
= m_out
.appendTo(isInt32
, isDouble
);
5061 results
.append(m_out
.anchor(boxInt32(int32Value
)));
5062 m_out
.jump(continuation
);
5064 m_out
.appendTo(isDouble
, continuation
);
5066 results
.append(m_out
.anchor(boxDouble(m_out
.intToDouble(value
))));
5067 m_out
.jump(continuation
);
5069 m_out
.appendTo(continuation
, lastNext
);
5070 return m_out
.phi(m_out
.int64
, results
);
5073 LValue
strictInt52ToInt52(LValue value
)
5075 return m_out
.shl(value
, m_out
.constInt64(JSValue::int52ShiftAmount
));
5078 LValue
int52ToStrictInt52(LValue value
)
5080 return m_out
.aShr(value
, m_out
.constInt64(JSValue::int52ShiftAmount
));
5083 LValue
isNotInt32(LValue jsValue
)
5085 return m_out
.below(jsValue
, m_tagTypeNumber
);
5087 LValue
unboxInt32(LValue jsValue
)
5089 return m_out
.castToInt32(jsValue
);
5091 LValue
boxInt32(LValue value
)
5093 return m_out
.add(m_out
.zeroExt(value
, m_out
.int64
), m_tagTypeNumber
);
5096 LValue
isCellOrMisc(LValue jsValue
)
5098 return m_out
.testIsZero64(jsValue
, m_tagTypeNumber
);
5100 LValue
isNotCellOrMisc(LValue jsValue
)
5102 return m_out
.testNonZero64(jsValue
, m_tagTypeNumber
);
5105 LValue
unboxDouble(LValue jsValue
)
5107 return m_out
.bitCast(m_out
.add(jsValue
, m_tagTypeNumber
), m_out
.doubleType
);
5109 LValue
boxDouble(LValue doubleValue
)
5111 return m_out
.sub(m_out
.bitCast(doubleValue
, m_out
.int64
), m_tagTypeNumber
);
5113 LValue
jsValueToDouble(Edge edge
, LValue boxedValue
)
5115 LBasicBlock intCase
= FTL_NEW_BLOCK(m_out
, ("jsValueToDouble unboxing int case"));
5116 LBasicBlock doubleCase
= FTL_NEW_BLOCK(m_out
, ("jsValueToDouble unboxing double case"));
5117 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("jsValueToDouble unboxing continuation"));
5120 if (!m_interpreter
.needsTypeCheck(edge
, SpecInt32
))
5121 isNotInt32
= m_out
.booleanFalse
;
5122 else if (!m_interpreter
.needsTypeCheck(edge
, ~SpecInt32
))
5123 isNotInt32
= m_out
.booleanTrue
;
5125 isNotInt32
= this->isNotInt32(boxedValue
);
5126 m_out
.branch(isNotInt32
, unsure(doubleCase
), unsure(intCase
));
5128 LBasicBlock lastNext
= m_out
.appendTo(intCase
, doubleCase
);
5130 ValueFromBlock intToDouble
= m_out
.anchor(
5131 m_out
.intToDouble(unboxInt32(boxedValue
)));
5132 m_out
.jump(continuation
);
5134 m_out
.appendTo(doubleCase
, continuation
);
5137 jsValueValue(boxedValue
), edge
, SpecBytecodeNumber
, isCellOrMisc(boxedValue
));
5139 ValueFromBlock unboxedDouble
= m_out
.anchor(unboxDouble(boxedValue
));
5140 m_out
.jump(continuation
);
5142 m_out
.appendTo(continuation
, lastNext
);
5144 return m_out
.phi(m_out
.doubleType
, intToDouble
, unboxedDouble
);
5147 LValue
jsValueToStrictInt52(Edge edge
, LValue boxedValue
)
5149 LBasicBlock intCase
= FTL_NEW_BLOCK(m_out
, ("jsValueToInt52 unboxing int case"));
5150 LBasicBlock doubleCase
= FTL_NEW_BLOCK(m_out
, ("jsValueToInt52 unboxing double case"));
5151 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("jsValueToInt52 unboxing continuation"));
5154 if (!m_interpreter
.needsTypeCheck(edge
, SpecInt32
))
5155 isNotInt32
= m_out
.booleanFalse
;
5156 else if (!m_interpreter
.needsTypeCheck(edge
, ~SpecInt32
))
5157 isNotInt32
= m_out
.booleanTrue
;
5159 isNotInt32
= this->isNotInt32(boxedValue
);
5160 m_out
.branch(isNotInt32
, unsure(doubleCase
), unsure(intCase
));
5162 LBasicBlock lastNext
= m_out
.appendTo(intCase
, doubleCase
);
5164 ValueFromBlock intToInt52
= m_out
.anchor(
5165 m_out
.signExt(unboxInt32(boxedValue
), m_out
.int64
));
5166 m_out
.jump(continuation
);
5168 m_out
.appendTo(doubleCase
, continuation
);
5170 LValue possibleResult
= m_out
.call(
5171 m_out
.operation(operationConvertBoxedDoubleToInt52
), boxedValue
);
5173 jsValueValue(boxedValue
), edge
, SpecInt32
| SpecInt52AsDouble
,
5174 m_out
.equal(possibleResult
, m_out
.constInt64(JSValue::notInt52
)));
5176 ValueFromBlock doubleToInt52
= m_out
.anchor(possibleResult
);
5177 m_out
.jump(continuation
);
5179 m_out
.appendTo(continuation
, lastNext
);
5181 return m_out
.phi(m_out
.int64
, intToInt52
, doubleToInt52
);
5184 LValue
doubleToStrictInt52(Edge edge
, LValue value
)
5186 LValue possibleResult
= m_out
.call(
5187 m_out
.operation(operationConvertDoubleToInt52
), value
);
5189 doubleValue(value
), edge
, SpecInt52AsDouble
,
5190 m_out
.equal(possibleResult
, m_out
.constInt64(JSValue::notInt52
)));
5192 return possibleResult
;
5195 LValue
isNumber(LValue jsValue
)
5197 return isNotCellOrMisc(jsValue
);
5199 LValue
isNotNumber(LValue jsValue
)
5201 return isCellOrMisc(jsValue
);
5204 LValue
isNotCell(LValue jsValue
)
5206 return m_out
.testNonZero64(jsValue
, m_tagMask
);
5209 LValue
isCell(LValue jsValue
)
5211 return m_out
.testIsZero64(jsValue
, m_tagMask
);
5214 LValue
isNotMisc(LValue value
)
5216 return m_out
.above(value
, m_out
.constInt64(TagBitTypeOther
| TagBitBool
| TagBitUndefined
));
5219 LValue
isMisc(LValue value
)
5221 return m_out
.bitNot(isNotMisc(value
));
5224 LValue
isNotBoolean(LValue jsValue
)
5226 return m_out
.testNonZero64(
5227 m_out
.bitXor(jsValue
, m_out
.constInt64(ValueFalse
)),
5228 m_out
.constInt64(~1));
5230 LValue
isBoolean(LValue jsValue
)
5232 return m_out
.bitNot(isNotBoolean(jsValue
));
5234 LValue
unboxBoolean(LValue jsValue
)
5236 // We want to use a cast that guarantees that LLVM knows that even the integer
5237 // value is just 0 or 1. But for now we do it the dumb way.
5238 return m_out
.notZero64(m_out
.bitAnd(jsValue
, m_out
.constInt64(1)));
5240 LValue
boxBoolean(LValue value
)
5242 return m_out
.select(
5243 value
, m_out
.constInt64(ValueTrue
), m_out
.constInt64(ValueFalse
));
5246 LValue
isNotOther(LValue value
)
5248 return m_out
.notEqual(
5249 m_out
.bitAnd(value
, m_out
.constInt64(~TagBitUndefined
)),
5250 m_out
.constInt64(ValueNull
));
5252 LValue
isOther(LValue value
)
5255 m_out
.bitAnd(value
, m_out
.constInt64(~TagBitUndefined
)),
5256 m_out
.constInt64(ValueNull
));
5259 void speculate(Edge edge
)
5261 switch (edge
.useKind()) {
5265 case KnownStringUse
:
5268 ASSERT(!m_interpreter
.needsTypeCheck(edge
));
5271 speculateInt32(edge
);
5274 speculateCell(edge
);
5277 ASSERT(!m_interpreter
.needsTypeCheck(edge
));
5280 speculateMachineInt(edge
);
5283 speculateObject(edge
);
5285 case ObjectOrOtherUse
:
5286 speculateObjectOrOther(edge
);
5288 case FinalObjectUse
:
5289 speculateFinalObject(edge
);
5292 speculateString(edge
);
5294 case StringIdentUse
:
5295 speculateStringIdent(edge
);
5297 case StringObjectUse
:
5298 speculateStringObject(edge
);
5300 case StringOrStringObjectUse
:
5301 speculateStringOrStringObject(edge
);
5304 speculateNumber(edge
);
5306 case DoubleRepRealUse
:
5307 speculateDoubleReal(edge
);
5309 case DoubleRepMachineIntUse
:
5310 speculateDoubleRepMachineInt(edge
);
5313 speculateBoolean(edge
);
5315 case NotStringVarUse
:
5316 speculateNotStringVar(edge
);
5319 speculateNotCell(edge
);
5322 speculateOther(edge
);
5325 speculateMisc(edge
);
5328 dataLog("Unsupported speculation use kind: ", edge
.useKind(), "\n");
5329 RELEASE_ASSERT_NOT_REACHED();
5333 void speculate(Node
*, Edge edge
)
5338 void speculateInt32(Edge edge
)
5343 void speculateCell(Edge edge
)
5348 void speculateMachineInt(Edge edge
)
5350 if (!m_interpreter
.needsTypeCheck(edge
))
5353 jsValueToStrictInt52(edge
, lowJSValue(edge
, ManualOperandSpeculation
));
5356 LValue
isObject(LValue cell
)
5358 return m_out
.notEqual(
5359 m_out
.load32(cell
, m_heaps
.JSCell_structureID
),
5360 m_out
.constInt32(vm().stringStructure
->id()));
5363 LValue
isNotString(LValue cell
)
5365 return isObject(cell
);
5368 LValue
isString(LValue cell
)
5371 m_out
.load32(cell
, m_heaps
.JSCell_structureID
),
5372 m_out
.constInt32(vm().stringStructure
->id()));
5375 LValue
isNotObject(LValue cell
)
5377 return isString(cell
);
5380 LValue
isArrayType(LValue cell
, ArrayMode arrayMode
)
5382 switch (arrayMode
.type()) {
5385 case Array::Contiguous
: {
5386 LValue indexingType
= m_out
.load8(cell
, m_heaps
.JSCell_indexingType
);
5388 switch (arrayMode
.arrayClass()) {
5389 case Array::OriginalArray
:
5390 RELEASE_ASSERT_NOT_REACHED();
5395 m_out
.bitAnd(indexingType
, m_out
.constInt8(IsArray
| IndexingShapeMask
)),
5396 m_out
.constInt8(IsArray
| arrayMode
.shapeMask()));
5398 case Array::NonArray
:
5399 case Array::OriginalNonArray
:
5401 m_out
.bitAnd(indexingType
, m_out
.constInt8(IsArray
| IndexingShapeMask
)),
5402 m_out
.constInt8(arrayMode
.shapeMask()));
5404 case Array::PossiblyArray
:
5406 m_out
.bitAnd(indexingType
, m_out
.constInt8(IndexingShapeMask
)),
5407 m_out
.constInt8(arrayMode
.shapeMask()));
5410 RELEASE_ASSERT_NOT_REACHED();
5415 m_out
.load8(cell
, m_heaps
.JSCell_typeInfoType
),
5416 m_out
.constInt8(typeForTypedArrayType(arrayMode
.typedArrayType())));
5420 LValue
isType(LValue cell
, JSType type
)
5423 m_out
.load8(cell
, m_heaps
.JSCell_typeInfoType
),
5424 m_out
.constInt8(type
));
5427 LValue
isNotType(LValue cell
, JSType type
)
5429 return m_out
.bitNot(isType(cell
, type
));
5432 void speculateObject(Edge edge
, LValue cell
)
5434 FTL_TYPE_CHECK(jsValueValue(cell
), edge
, SpecObject
, isNotObject(cell
));
5437 void speculateObject(Edge edge
)
5439 speculateObject(edge
, lowCell(edge
));
5442 void speculateObjectOrOther(Edge edge
)
5444 if (!m_interpreter
.needsTypeCheck(edge
))
5447 LValue value
= lowJSValue(edge
);
5449 LBasicBlock cellCase
= FTL_NEW_BLOCK(m_out
, ("speculateObjectOrOther cell case"));
5450 LBasicBlock primitiveCase
= FTL_NEW_BLOCK(m_out
, ("speculateObjectOrOther primitive case"));
5451 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("speculateObjectOrOther continuation"));
5453 m_out
.branch(isNotCell(value
), unsure(primitiveCase
), unsure(cellCase
));
5455 LBasicBlock lastNext
= m_out
.appendTo(cellCase
, primitiveCase
);
5458 jsValueValue(value
), edge
, (~SpecCell
) | SpecObject
, isNotObject(value
));
5460 m_out
.jump(continuation
);
5462 m_out
.appendTo(primitiveCase
, continuation
);
5465 jsValueValue(value
), edge
, SpecCell
| SpecOther
, isNotOther(value
));
5467 m_out
.jump(continuation
);
5469 m_out
.appendTo(continuation
, lastNext
);
5472 void speculateFinalObject(Edge edge
, LValue cell
)
5475 jsValueValue(cell
), edge
, SpecFinalObject
, isNotType(cell
, FinalObjectType
));
5478 void speculateFinalObject(Edge edge
)
5480 speculateFinalObject(edge
, lowCell(edge
));
5483 void speculateString(Edge edge
, LValue cell
)
5485 FTL_TYPE_CHECK(jsValueValue(cell
), edge
, SpecString
| ~SpecCell
, isNotString(cell
));
5488 void speculateString(Edge edge
)
5490 speculateString(edge
, lowCell(edge
));
5493 void speculateStringIdent(Edge edge
, LValue string
, LValue stringImpl
)
5495 if (!m_interpreter
.needsTypeCheck(edge
, SpecStringIdent
| ~SpecString
))
5498 speculate(BadType
, jsValueValue(string
), edge
.node(), m_out
.isNull(stringImpl
));
5500 BadType
, jsValueValue(string
), edge
.node(),
5502 m_out
.load32(stringImpl
, m_heaps
.StringImpl_hashAndFlags
),
5503 m_out
.constInt32(StringImpl::flagIsAtomic())));
5504 m_interpreter
.filter(edge
, SpecStringIdent
| ~SpecString
);
5507 void speculateStringIdent(Edge edge
)
5509 lowStringIdent(edge
);
5512 void speculateStringObject(Edge edge
)
5514 if (!m_interpreter
.needsTypeCheck(edge
, SpecStringObject
))
5517 speculateStringObjectForCell(edge
, lowCell(edge
));
5518 m_interpreter
.filter(edge
, SpecStringObject
);
5521 void speculateStringOrStringObject(Edge edge
)
5523 if (!m_interpreter
.needsTypeCheck(edge
, SpecString
| SpecStringObject
))
5526 LBasicBlock notString
= FTL_NEW_BLOCK(m_out
, ("Speculate StringOrStringObject not string case"));
5527 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Speculate StringOrStringObject continuation"));
5529 LValue structureID
= m_out
.load32(lowCell(edge
), m_heaps
.JSCell_structureID
);
5531 m_out
.equal(structureID
, m_out
.constInt32(vm().stringStructure
->id())),
5532 unsure(continuation
), unsure(notString
));
5534 LBasicBlock lastNext
= m_out
.appendTo(notString
, continuation
);
5535 speculateStringObjectForStructureID(edge
, structureID
);
5536 m_out
.jump(continuation
);
5538 m_out
.appendTo(continuation
, lastNext
);
5540 m_interpreter
.filter(edge
, SpecString
| SpecStringObject
);
5543 void speculateStringObjectForCell(Edge edge
, LValue cell
)
5545 speculateStringObjectForStructureID(edge
, m_out
.load32(cell
, m_heaps
.JSCell_structureID
));
5548 void speculateStringObjectForStructureID(Edge edge
, LValue structureID
)
5550 Structure
* stringObjectStructure
=
5551 m_graph
.globalObjectFor(m_node
->origin
.semantic
)->stringObjectStructure();
5553 if (m_state
.forNode(edge
).m_currentKnownStructure
.isSubsetOf(StructureSet(stringObjectStructure
)))
5557 NotStringObject
, noValue(), 0,
5558 m_out
.notEqual(structureID
, weakStructure(stringObjectStructure
)));
5561 void speculateNonNullObject(Edge edge
, LValue cell
)
5564 jsValueValue(cell
), edge
, SpecObject
,
5566 m_out
.load32(cell
, m_heaps
.JSCell_structureID
),
5567 m_out
.constInt32(vm().stringStructure
->id())));
5568 if (masqueradesAsUndefinedWatchpointIsStillValid())
5572 BadType
, jsValueValue(cell
), edge
.node(),
5574 m_out
.load8(cell
, m_heaps
.JSCell_typeInfoFlags
),
5575 m_out
.constInt8(MasqueradesAsUndefined
)));
5578 void speculateNumber(Edge edge
)
5580 LValue value
= lowJSValue(edge
, ManualOperandSpeculation
);
5581 FTL_TYPE_CHECK(jsValueValue(value
), edge
, SpecBytecodeNumber
, isNotNumber(value
));
5584 void speculateDoubleReal(Edge edge
)
5586 // Do an early return here because lowDouble() can create a lot of control flow.
5587 if (!m_interpreter
.needsTypeCheck(edge
))
5590 LValue value
= lowDouble(edge
);
5592 doubleValue(value
), edge
, SpecDoubleReal
,
5593 m_out
.doubleNotEqualOrUnordered(value
, value
));
5596 void speculateDoubleRepMachineInt(Edge edge
)
5598 if (!m_interpreter
.needsTypeCheck(edge
))
5601 doubleToStrictInt52(edge
, lowDouble(edge
));
5604 void speculateBoolean(Edge edge
)
5609 void speculateNotStringVar(Edge edge
)
5611 if (!m_interpreter
.needsTypeCheck(edge
, ~SpecStringVar
))
5614 LValue value
= lowJSValue(edge
, ManualOperandSpeculation
);
5616 LBasicBlock isCellCase
= FTL_NEW_BLOCK(m_out
, ("Speculate NotStringVar is cell case"));
5617 LBasicBlock isStringCase
= FTL_NEW_BLOCK(m_out
, ("Speculate NotStringVar is string case"));
5618 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Speculate NotStringVar continuation"));
5620 m_out
.branch(isCell(value
), unsure(isCellCase
), unsure(continuation
));
5622 LBasicBlock lastNext
= m_out
.appendTo(isCellCase
, isStringCase
);
5623 m_out
.branch(isString(value
), unsure(isStringCase
), unsure(continuation
));
5625 m_out
.appendTo(isStringCase
, continuation
);
5626 speculateStringIdent(edge
, value
, m_out
.loadPtr(value
, m_heaps
.JSString_value
));
5627 m_out
.jump(continuation
);
5629 m_out
.appendTo(continuation
, lastNext
);
5632 void speculateNotCell(Edge edge
)
5634 if (!m_interpreter
.needsTypeCheck(edge
))
5637 LValue value
= lowJSValue(edge
, ManualOperandSpeculation
);
5638 typeCheck(jsValueValue(value
), edge
, ~SpecCell
, isCell(value
));
5641 void speculateOther(Edge edge
)
5643 if (!m_interpreter
.needsTypeCheck(edge
))
5646 LValue value
= lowJSValue(edge
, ManualOperandSpeculation
);
5647 typeCheck(jsValueValue(value
), edge
, SpecOther
, isNotOther(value
));
5650 void speculateMisc(Edge edge
)
5652 if (!m_interpreter
.needsTypeCheck(edge
))
5655 LValue value
= lowJSValue(edge
, ManualOperandSpeculation
);
5656 typeCheck(jsValueValue(value
), edge
, SpecMisc
, isNotMisc(value
));
5659 bool masqueradesAsUndefinedWatchpointIsStillValid()
5661 return m_graph
.masqueradesAsUndefinedWatchpointIsStillValid(m_node
->origin
.semantic
);
5664 LValue
loadMarkByte(LValue base
)
5666 return m_out
.load8(base
, m_heaps
.JSCell_gcData
);
5669 void emitStoreBarrier(LValue base
)
5672 LBasicBlock isMarkedAndNotRemembered
= FTL_NEW_BLOCK(m_out
, ("Store barrier is marked block"));
5673 LBasicBlock bufferHasSpace
= FTL_NEW_BLOCK(m_out
, ("Store barrier buffer has space"));
5674 LBasicBlock bufferIsFull
= FTL_NEW_BLOCK(m_out
, ("Store barrier buffer is full"));
5675 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Store barrier continuation"));
5677 // Check the mark byte.
5679 m_out
.notZero8(loadMarkByte(base
)), usually(continuation
), rarely(isMarkedAndNotRemembered
));
5681 // Append to the write barrier buffer.
5682 LBasicBlock lastNext
= m_out
.appendTo(isMarkedAndNotRemembered
, bufferHasSpace
);
5683 LValue currentBufferIndex
= m_out
.load32(m_out
.absolute(&vm().heap
.writeBarrierBuffer().m_currentIndex
));
5684 LValue bufferCapacity
= m_out
.load32(m_out
.absolute(&vm().heap
.writeBarrierBuffer().m_capacity
));
5686 m_out
.lessThan(currentBufferIndex
, bufferCapacity
),
5687 usually(bufferHasSpace
), rarely(bufferIsFull
));
5689 // Buffer has space, store to it.
5690 m_out
.appendTo(bufferHasSpace
, bufferIsFull
);
5691 LValue writeBarrierBufferBase
= m_out
.loadPtr(m_out
.absolute(&vm().heap
.writeBarrierBuffer().m_buffer
));
5692 m_out
.storePtr(base
, m_out
.baseIndex(m_heaps
.WriteBarrierBuffer_bufferContents
, writeBarrierBufferBase
, m_out
.zeroExt(currentBufferIndex
, m_out
.intPtr
), ScalePtr
));
5693 m_out
.store32(m_out
.add(currentBufferIndex
, m_out
.constInt32(1)), m_out
.absolute(&vm().heap
.writeBarrierBuffer().m_currentIndex
));
5694 m_out
.jump(continuation
);
5696 // Buffer is out of space, flush it.
5697 m_out
.appendTo(bufferIsFull
, continuation
);
5698 vmCall(m_out
.operation(operationFlushWriteBarrierBuffer
), m_callFrame
, base
, NoExceptions
);
5699 m_out
.jump(continuation
);
5701 m_out
.appendTo(continuation
, lastNext
);
5707 enum ExceptionCheckMode
{ NoExceptions
, CheckExceptions
};
5709 LValue
vmCall(LValue function
, ExceptionCheckMode mode
= CheckExceptions
)
5712 LValue result
= m_out
.call(function
);
5716 LValue
vmCall(LValue function
, LValue arg1
, ExceptionCheckMode mode
= CheckExceptions
)
5719 LValue result
= m_out
.call(function
, arg1
);
5723 LValue
vmCall(LValue function
, LValue arg1
, LValue arg2
, ExceptionCheckMode mode
= CheckExceptions
)
5726 LValue result
= m_out
.call(function
, arg1
, arg2
);
5730 LValue
vmCall(LValue function
, LValue arg1
, LValue arg2
, LValue arg3
, ExceptionCheckMode mode
= CheckExceptions
)
5733 LValue result
= m_out
.call(function
, arg1
, arg2
, arg3
);
5737 LValue
vmCall(LValue function
, LValue arg1
, LValue arg2
, LValue arg3
, LValue arg4
, ExceptionCheckMode mode
= CheckExceptions
)
5740 LValue result
= m_out
.call(function
, arg1
, arg2
, arg3
, arg4
);
5745 void callPreflight(CodeOrigin codeOrigin
)
5749 CallFrame::Location::encodeAsCodeOriginIndex(
5750 m_ftlState
.jitCode
->common
.addCodeOrigin(codeOrigin
))),
5751 tagFor(JSStack::ArgumentCount
));
5753 void callPreflight()
5755 callPreflight(m_node
->origin
.semantic
);
5758 void callCheck(ExceptionCheckMode mode
= CheckExceptions
)
5760 if (mode
== NoExceptions
)
5763 if (Options::enableExceptionFuzz())
5764 m_out
.call(m_out
.operation(operationExceptionFuzz
));
5766 LBasicBlock continuation
= FTL_NEW_BLOCK(m_out
, ("Exception check continuation"));
5769 m_out
.notZero64(m_out
.load64(m_out
.absolute(vm().addressOfException()))),
5770 rarely(m_handleExceptions
), usually(continuation
));
5772 m_out
.appendTo(continuation
);
5775 LBasicBlock
lowBlock(BasicBlock
* block
)
5777 return m_blocks
.get(block
);
5780 void initializeOSRExitStateForBlock()
5782 m_availability
= m_highBlock
->ssa
->availabilityAtHead
;
5786 ExitKind kind
, FormattedValue lowValue
, Node
* highValue
, LValue failCondition
)
5788 if (verboseCompilationEnabled()) {
5789 dataLog(" OSR exit #", m_ftlState
.jitCode
->osrExit
.size(), " with availability: ", m_availability
, "\n");
5790 if (!m_availableRecoveries
.isEmpty())
5791 dataLog(" Available recoveries: ", listDump(m_availableRecoveries
), "\n");
5794 ASSERT(m_ftlState
.jitCode
->osrExit
.size() == m_ftlState
.finalizer
->osrExit
.size());
5796 m_ftlState
.jitCode
->osrExit
.append(OSRExit(
5797 kind
, lowValue
.format(), m_graph
.methodOfGettingAValueProfileFor(highValue
),
5798 m_codeOriginForExitTarget
, m_codeOriginForExitProfile
,
5799 m_availability
.numberOfArguments(), m_availability
.numberOfLocals()));
5800 m_ftlState
.finalizer
->osrExit
.append(OSRExitCompilationInfo());
5802 OSRExit
& exit
= m_ftlState
.jitCode
->osrExit
.last();
5804 LBasicBlock lastNext
= 0;
5805 LBasicBlock continuation
= 0;
5807 LBasicBlock failCase
= FTL_NEW_BLOCK(m_out
, ("OSR exit failCase for ", m_node
));
5808 continuation
= FTL_NEW_BLOCK(m_out
, ("OSR exit continuation for ", m_node
));
5810 m_out
.branch(failCondition
, rarely(failCase
), usually(continuation
));
5812 lastNext
= m_out
.appendTo(failCase
, continuation
);
5814 emitOSRExitCall(exit
, lowValue
);
5816 m_out
.unreachable();
5818 m_out
.appendTo(continuation
, lastNext
);
5821 void emitOSRExitCall(OSRExit
& exit
, FormattedValue lowValue
)
5823 ExitArgumentList arguments
;
5825 CodeOrigin codeOrigin
= exit
.m_codeOrigin
;
5827 buildExitArguments(exit
, arguments
, lowValue
, codeOrigin
);
5829 callStackmap(exit
, arguments
);
5832 void buildExitArguments(
5833 OSRExit
& exit
, ExitArgumentList
& arguments
, FormattedValue lowValue
,
5834 CodeOrigin codeOrigin
)
5837 arguments
.append(lowValue
.value());
5839 for (unsigned i
= 0; i
< exit
.m_values
.size(); ++i
) {
5840 int operand
= exit
.m_values
.operandForIndex(i
);
5841 bool isLive
= m_graph
.isLiveInBytecode(VirtualRegister(operand
), codeOrigin
);
5843 exit
.m_values
[i
] = ExitValue::dead();
5847 Availability availability
= m_availability
[i
];
5848 FlushedAt flush
= availability
.flushedAt();
5849 switch (flush
.format()) {
5851 case ConflictingFlush
:
5852 if (availability
.hasNode()) {
5853 addExitArgumentForNode(exit
, arguments
, i
, availability
.node());
5857 if (Options::validateFTLOSRExitLiveness()) {
5858 dataLog("Expected r", operand
, " to be available but it wasn't.\n");
5859 RELEASE_ASSERT_NOT_REACHED();
5862 // This means that the DFG's DCE proved that the value is dead in bytecode
5863 // even though the bytecode liveness analysis thinks it's live. This is
5864 // acceptable since the DFG's DCE is by design more aggressive while still
5866 exit
.m_values
[i
] = ExitValue::dead();
5869 case FlushedJSValue
:
5871 case FlushedBoolean
:
5872 exit
.m_values
[i
] = ExitValue::inJSStack(flush
.virtualRegister());
5876 exit
.m_values
[i
] = ExitValue::inJSStackAsInt32(flush
.virtualRegister());
5880 exit
.m_values
[i
] = ExitValue::inJSStackAsInt52(flush
.virtualRegister());
5884 exit
.m_values
[i
] = ExitValue::inJSStackAsDouble(flush
.virtualRegister());
5887 case FlushedArguments
:
5888 exit
.m_values
[i
] = ExitValue::argumentsObjectThatWasNotCreated();
5893 if (verboseCompilationEnabled())
5894 dataLog(" Exit values: ", exit
.m_values
, "\n");
5897 void callStackmap(OSRExit
& exit
, ExitArgumentList
& arguments
)
5899 exit
.m_stackmapID
= m_stackmapIDs
++;
5900 arguments
.insert(0, m_out
.constInt32(MacroAssembler::maxJumpReplacementSize()));
5901 arguments
.insert(0, m_out
.constInt64(exit
.m_stackmapID
));
5903 m_out
.call(m_out
.stackmapIntrinsic(), arguments
);
5906 void addExitArgumentForNode(
5907 OSRExit
& exit
, ExitArgumentList
& arguments
, unsigned index
, Node
* node
)
5909 ASSERT(node
->shouldGenerate());
5910 ASSERT(node
->hasResult());
5912 if (tryToSetConstantExitArgument(exit
, index
, node
))
5915 for (unsigned i
= 0; i
< m_availableRecoveries
.size(); ++i
) {
5916 AvailableRecovery recovery
= m_availableRecoveries
[i
];
5917 if (recovery
.node() != node
)
5920 exit
.m_values
[index
] = ExitValue::recovery(
5921 recovery
.opcode(), arguments
.size(), arguments
.size() + 1,
5923 arguments
.append(recovery
.left());
5924 arguments
.append(recovery
.right());
5928 LoweredNodeValue value
= m_int32Values
.get(node
);
5929 if (isValid(value
)) {
5930 addExitArgument(exit
, arguments
, index
, ValueFormatInt32
, value
.value());
5934 value
= m_int52Values
.get(node
);
5935 if (isValid(value
)) {
5936 addExitArgument(exit
, arguments
, index
, ValueFormatInt52
, value
.value());
5940 value
= m_strictInt52Values
.get(node
);
5941 if (isValid(value
)) {
5942 addExitArgument(exit
, arguments
, index
, ValueFormatStrictInt52
, value
.value());
5946 value
= m_booleanValues
.get(node
);
5947 if (isValid(value
)) {
5948 LValue valueToPass
= m_out
.zeroExt(value
.value(), m_out
.int32
);
5949 addExitArgument(exit
, arguments
, index
, ValueFormatBoolean
, valueToPass
);
5953 value
= m_jsValueValues
.get(node
);
5954 if (isValid(value
)) {
5955 addExitArgument(exit
, arguments
, index
, ValueFormatJSValue
, value
.value());
5959 value
= m_doubleValues
.get(node
);
5960 if (isValid(value
)) {
5961 addExitArgument(exit
, arguments
, index
, ValueFormatDouble
, value
.value());
5966 dataLog("Cannot find value for node: ", node
, " while compiling exit at ", exit
.m_codeOrigin
, " in node ", m_node
, "\n");
5968 RELEASE_ASSERT_NOT_REACHED();
5971 bool tryToSetConstantExitArgument(OSRExit
& exit
, unsigned index
, Node
* node
)
5976 switch (node
->op()) {
5979 case DoubleConstant
:
5980 case WeakJSConstant
:
5981 exit
.m_values
[index
] = ExitValue::constant(m_graph
.valueOfJSConstant(node
));
5983 case PhantomArguments
:
5984 exit
.m_values
[index
] = ExitValue::argumentsObjectThatWasNotCreated();
5991 void addExitArgument(
5992 OSRExit
& exit
, ExitArgumentList
& arguments
, unsigned index
, ValueFormat format
,
5995 exit
.m_values
[index
] = ExitValue::exitArgument(ExitArgument(format
, arguments
.size()));
5996 arguments
.append(value
);
5999 bool doesKill(Edge edge
)
6001 if (edge
.doesNotKill())
6004 if (edge
->hasConstant())
6010 void addAvailableRecovery(
6011 Node
* node
, RecoveryOpcode opcode
, LValue left
, LValue right
, ValueFormat format
)
6013 m_availableRecoveries
.append(AvailableRecovery(node
, opcode
, left
, right
, format
));
6016 void addAvailableRecovery(
6017 Edge edge
, RecoveryOpcode opcode
, LValue left
, LValue right
, ValueFormat format
)
6019 addAvailableRecovery(edge
.node(), opcode
, left
, right
, format
);
6022 void setInt32(Node
* node
, LValue value
)
6024 m_int32Values
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6026 void setInt52(Node
* node
, LValue value
)
6028 m_int52Values
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6030 void setStrictInt52(Node
* node
, LValue value
)
6032 m_strictInt52Values
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6034 void setInt52(Node
* node
, LValue value
, Int52Kind kind
)
6038 setInt52(node
, value
);
6042 setStrictInt52(node
, value
);
6046 RELEASE_ASSERT_NOT_REACHED();
6048 void setJSValue(Node
* node
, LValue value
)
6050 m_jsValueValues
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6052 void setBoolean(Node
* node
, LValue value
)
6054 m_booleanValues
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6056 void setStorage(Node
* node
, LValue value
)
6058 m_storageValues
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6060 void setDouble(Node
* node
, LValue value
)
6062 m_doubleValues
.set(node
, LoweredNodeValue(value
, m_highBlock
));
6065 void setInt32(LValue value
)
6067 setInt32(m_node
, value
);
6069 void setInt52(LValue value
)
6071 setInt52(m_node
, value
);
6073 void setStrictInt52(LValue value
)
6075 setStrictInt52(m_node
, value
);
6077 void setInt52(LValue value
, Int52Kind kind
)
6079 setInt52(m_node
, value
, kind
);
6081 void setJSValue(LValue value
)
6083 setJSValue(m_node
, value
);
6085 void setBoolean(LValue value
)
6087 setBoolean(m_node
, value
);
6089 void setStorage(LValue value
)
6091 setStorage(m_node
, value
);
6093 void setDouble(LValue value
)
6095 setDouble(m_node
, value
);
6098 bool isValid(const LoweredNodeValue
& value
)
6102 if (!m_graph
.m_dominators
.dominates(value
.block(), m_highBlock
))
6107 void addWeakReference(JSCell
* target
)
6109 m_graph
.m_plan
.weakReferences
.addLazily(target
);
6112 LValue
loadStructure(LValue value
)
6114 LValue tableIndex
= m_out
.load32(value
, m_heaps
.JSCell_structureID
);
6115 LValue tableBase
= m_out
.loadPtr(
6116 m_out
.absolute(vm().heap
.structureIDTable().base()));
6117 LValue pointerIntoTable
= m_out
.baseIndex(
6118 tableBase
, m_out
.zeroExt(tableIndex
, m_out
.intPtr
), ScaleEight
);
6119 return m_out
.loadPtr(TypedPointer(m_heaps
.structureTable
, pointerIntoTable
));
6122 LValue
weakPointer(JSCell
* pointer
)
6124 addWeakReference(pointer
);
6125 return m_out
.constIntPtr(pointer
);
6128 LValue
weakStructure(Structure
* structure
)
6130 addWeakReference(structure
);
6131 return m_out
.constInt32(structure
->id());
6134 TypedPointer
addressFor(LValue base
, int operand
, ptrdiff_t offset
= 0)
6136 return m_out
.address(base
, m_heaps
.variables
[operand
], offset
);
6138 TypedPointer
payloadFor(LValue base
, int operand
)
6140 return addressFor(base
, operand
, PayloadOffset
);
6142 TypedPointer
tagFor(LValue base
, int operand
)
6144 return addressFor(base
, operand
, TagOffset
);
6146 TypedPointer
addressFor(int operand
, ptrdiff_t offset
= 0)
6148 return addressFor(VirtualRegister(operand
), offset
);
6150 TypedPointer
addressFor(VirtualRegister operand
, ptrdiff_t offset
= 0)
6152 if (operand
.isLocal())
6153 return addressFor(m_captured
, operand
.offset(), offset
);
6154 return addressFor(m_callFrame
, operand
.offset(), offset
);
6156 TypedPointer
payloadFor(int operand
)
6158 return payloadFor(VirtualRegister(operand
));
6160 TypedPointer
payloadFor(VirtualRegister operand
)
6162 return addressFor(operand
, PayloadOffset
);
6164 TypedPointer
tagFor(int operand
)
6166 return tagFor(VirtualRegister(operand
));
6168 TypedPointer
tagFor(VirtualRegister operand
)
6170 return addressFor(operand
, TagOffset
);
6173 VM
& vm() { return m_graph
.m_vm
; }
6174 CodeBlock
* codeBlock() { return m_graph
.m_codeBlock
; }
6178 AbstractHeapRepository m_heaps
;
6181 LBasicBlock m_prologue
;
6182 LBasicBlock m_handleExceptions
;
6183 HashMap
<BasicBlock
*, LBasicBlock
> m_blocks
;
6187 LValue m_tagTypeNumber
;
6190 HashMap
<Node
*, LoweredNodeValue
> m_int32Values
;
6191 HashMap
<Node
*, LoweredNodeValue
> m_strictInt52Values
;
6192 HashMap
<Node
*, LoweredNodeValue
> m_int52Values
;
6193 HashMap
<Node
*, LoweredNodeValue
> m_jsValueValues
;
6194 HashMap
<Node
*, LoweredNodeValue
> m_booleanValues
;
6195 HashMap
<Node
*, LoweredNodeValue
> m_storageValues
;
6196 HashMap
<Node
*, LoweredNodeValue
> m_doubleValues
;
6198 HashMap
<Node
*, LValue
> m_phis
;
6200 Operands
<Availability
> m_availability
;
6202 Vector
<AvailableRecovery
, 3> m_availableRecoveries
;
6204 InPlaceAbstractState m_state
;
6205 AbstractInterpreter
<InPlaceAbstractState
> m_interpreter
;
6206 BasicBlock
* m_highBlock
;
6207 BasicBlock
* m_nextHighBlock
;
6208 LBasicBlock m_nextLowBlock
;
6210 CodeOrigin m_codeOriginForExitTarget
;
6211 CodeOrigin m_codeOriginForExitProfile
;
6212 unsigned m_nodeIndex
;
6215 uint32_t m_stackmapIDs
;
6218 void lowerDFGToLLVM(State
& state
)
6220 LowerDFGToLLVM
lowering(state
);
6224 } } // namespace JSC::FTL
6226 #endif // ENABLE(FTL_JIT)