2 * Copyright (C) 2013 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 "FTLExitThunkGenerator.h"
36 #include "FTLForOSREntryJITCode.h"
37 #include "FTLFormattedValue.h"
38 #include "FTLLoweredNodeValue.h"
39 #include "FTLOutput.h"
40 #include "FTLThunks.h"
41 #include "FTLValueSource.h"
42 #include "LinkBuffer.h"
43 #include "OperandsInlines.h"
44 #include "Operations.h"
45 #include "VirtualRegister.h"
47 #include <wtf/ProcessID.h>
49 namespace JSC { namespace FTL {
53 static 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_valueSources(OperandsLike, state.graph.block(0)->variablesAtHead)
74 , m_lastSetOperand(VirtualRegister())
75 , m_exitThunkGenerator(state)
76 , m_state(state.graph)
77 , m_interpreter(state.graph, m_state)
84 if (verboseCompilationEnabled()) {
86 "jsBody_", atomicIncrement(&compileCounter), "_", codeBlock()->inferredName(),
87 "_", codeBlock()->hash());
91 m_graph.m_dominators.computeIfNecessary(m_graph);
94 LLVMModuleCreateWithNameInContext(name.data(), m_ftlState.context);
96 m_ftlState.function = addFunction(
97 m_ftlState.module, name.data(), functionType(m_out.int64, m_out.intPtr));
98 setFunctionCallingConv(m_ftlState.function, LLVMCCallConv);
100 m_out.initialize(m_ftlState.module, m_ftlState.function, m_heaps);
102 m_prologue = appendBasicBlock(m_ftlState.context, m_ftlState.function);
103 m_out.appendTo(m_prologue);
104 createPhiVariables();
106 m_initialization = appendBasicBlock(m_ftlState.context, m_ftlState.function);
108 m_callFrame = m_out.param(0);
109 m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
110 m_tagMask = m_out.constInt64(TagMask);
112 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
113 m_highBlock = m_graph.block(blockIndex);
116 m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
119 Vector<BasicBlock*> depthFirst;
120 m_graph.getBlocksInDepthFirstOrder(depthFirst);
121 for (unsigned i = 0; i < depthFirst.size(); ++i)
122 compileBlock(depthFirst[i]);
124 // And now complete the initialization block.
125 linkOSRExitsAndCompleteInitializationBlocks();
127 if (Options::dumpLLVMIR())
128 dumpModule(m_ftlState.module);
130 if (verboseCompilationEnabled())
131 m_ftlState.dumpState("after lowering");
132 if (validationEnabled())
133 verifyModule(m_ftlState.module);
138 void createPhiVariables()
140 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
141 BasicBlock* block = m_graph.block(blockIndex);
144 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
145 Node* node = block->at(nodeIndex);
146 if (node->op() != Phi)
149 switch (node->flags() & NodeResultMask) {
150 case NodeResultNumber:
151 type = m_out.doubleType;
153 case NodeResultInt32:
156 case NodeResultInt52:
159 case NodeResultBoolean:
160 type = m_out.boolean;
166 RELEASE_ASSERT_NOT_REACHED();
169 m_phis.add(node, buildAlloca(m_out.m_builder, type));
174 void compileBlock(BasicBlock* block)
179 if (verboseCompilationEnabled())
180 dataLog("Compiling block ", *block, "\n");
184 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
187 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
188 m_nextHighBlock = m_graph.block(nextBlockIndex);
192 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
194 // All of this effort to find the next block gives us the ability to keep the
195 // generated IR in roughly program order. This ought not affect the performance
196 // of the generated code (since we expect LLVM to reorder things) but it will
197 // make IR dumps easier to read.
198 m_out.appendTo(lowBlock, m_nextLowBlock);
200 if (Options::ftlCrashes())
201 m_out.crashNonTerminal();
203 if (!m_highBlock->cfaHasVisited) {
208 initializeOSRExitStateForBlock();
210 m_live = block->ssa->liveAtHead;
213 m_state.beginBasicBlock(m_highBlock);
215 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
216 if (!compileNode(m_nodeIndex))
221 bool compileNode(unsigned nodeIndex)
223 if (!m_state.isValid()) {
228 m_node = m_highBlock->at(nodeIndex);
229 m_codeOriginForExitProfile = m_node->codeOrigin;
230 m_codeOriginForExitTarget = m_node->codeOriginForExitTarget;
232 if (verboseCompilationEnabled())
233 dataLog("Lowering ", m_node, "\n");
235 bool shouldExecuteEffects = m_interpreter.startExecuting(m_node);
237 m_direction = (m_node->flags() & NodeExitsForward) ? ForwardSpeculation : BackwardSpeculation;
239 switch (m_node->op()) {
249 compileWeakJSConstant();
252 compileGetArgument();
254 case ExtractOSREntryLocal:
255 compileExtractOSREntryLocal();
269 case MovHintAndCheck:
270 compileMovHintAndCheck();
298 compileArithMinOrMax();
304 compileArithNegate();
325 compileUInt32ToNumber();
328 compileInt32ToDouble();
331 compileCheckStructure();
333 case StructureTransitionWatchpoint:
334 compileStructureTransitionWatchpoint();
336 case ArrayifyToStructure:
337 compileArrayifyToStructure();
340 compilePutStructure();
342 case PhantomPutStructure:
343 compilePhantomPutStructure();
346 compileGetButterfly();
348 case GetIndexedPropertyStorage:
349 compileGetIndexedPropertyStorage();
355 compileGetArrayLength();
365 compileGetByOffset();
368 compilePutByOffset();
371 compileGetGlobalVar();
374 compilePutGlobalVar();
376 case GlobalVarWatchpoint:
377 compileGlobalVarWatchpoint();
385 case GetClosureRegisters:
386 compileGetClosureRegisters();
389 compileGetClosureVar();
392 compilePutClosureVar();
397 case CompareEqConstant:
398 compileCompareEqConstant();
400 case CompareStrictEq:
401 compileCompareStrictEq();
403 case CompareStrictEqConstant:
404 compileCompareStrictEqConstant();
407 compileCompareLess();
410 compileCompareLessEq();
413 compileCompareGreater();
415 case CompareGreaterEq:
416 compileCompareGreaterEq();
423 compileCallOrConstruct();
438 compileForceOSRExit();
441 RELEASE_ASSERT_NOT_REACHED();
445 if (m_node->shouldGenerate())
446 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, use);
448 if (m_node->adjustedRefCount())
451 if (shouldExecuteEffects)
452 m_interpreter.executeEffects(nodeIndex);
457 void compileUpsilon()
459 LValue destination = m_phis.get(m_node->phi());
461 switch (m_node->child1().useKind()) {
463 m_out.set(lowDouble(m_node->child1()), destination);
466 m_out.set(lowInt32(m_node->child1()), destination);
469 m_out.set(lowInt52(m_node->child1()), destination);
472 m_out.set(lowBoolean(m_node->child1()), destination);
475 m_out.set(lowCell(m_node->child1()), destination);
478 m_out.set(lowJSValue(m_node->child1()), destination);
481 RELEASE_ASSERT_NOT_REACHED();
488 LValue source = m_phis.get(m_node);
490 switch (m_node->flags() & NodeResultMask) {
491 case NodeResultNumber:
492 setDouble(m_out.get(source));
494 case NodeResultInt32:
495 setInt32(m_out.get(source));
497 case NodeResultInt52:
498 setInt52(m_out.get(source));
500 case NodeResultBoolean:
501 setBoolean(m_out.get(source));
504 setJSValue(m_out.get(source));
507 RELEASE_ASSERT_NOT_REACHED();
512 void compileJSConstant()
514 JSValue value = m_graph.valueOfJSConstant(m_node);
515 if (value.isDouble())
516 setDouble(m_out.constDouble(value.asDouble()));
518 setJSValue(m_out.constInt64(JSValue::encode(value)));
521 void compileWeakJSConstant()
523 setJSValue(weakPointer(m_node->weakConstant()));
526 void compileGetArgument()
528 VariableAccessData* variable = m_node->variableAccessData();
529 VirtualRegister operand = variable->local();
531 LValue jsValue = m_out.load64(addressFor(operand));
533 switch (useKindFor(variable->flushFormat())) {
535 speculateBackward(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue));
536 setInt32(unboxInt32(jsValue));
539 speculateBackward(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue));
543 speculateBackward(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue));
544 setBoolean(unboxBoolean(jsValue));
550 RELEASE_ASSERT_NOT_REACHED();
555 void compileExtractOSREntryLocal()
557 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
558 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
559 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
562 void compileGetLocal()
564 // GetLocals arise only for captured variables.
566 VariableAccessData* variable = m_node->variableAccessData();
567 AbstractValue& value = m_state.variables().operand(variable->local());
569 RELEASE_ASSERT(variable->isCaptured());
571 if (isInt32Speculation(value.m_type))
572 setInt32(m_out.load32(payloadFor(variable->local())));
574 setJSValue(m_out.load64(addressFor(variable->local())));
577 void compileSetLocal()
579 observeMovHint(m_node);
581 VariableAccessData* variable = m_node->variableAccessData();
582 switch (variable->flushFormat()) {
583 case FlushedJSValue: {
584 LValue value = lowJSValue(m_node->child1());
585 m_out.store64(value, addressFor(variable->local()));
586 m_valueSources.operand(variable->local()) = ValueSource(ValueInJSStack);
590 case FlushedDouble: {
591 LValue value = lowDouble(m_node->child1());
592 m_out.storeDouble(value, addressFor(variable->local()));
593 m_valueSources.operand(variable->local()) = ValueSource(DoubleInJSStack);
598 LValue value = lowInt32(m_node->child1());
599 m_out.store32(value, payloadFor(variable->local()));
600 m_valueSources.operand(variable->local()) = ValueSource(Int32InJSStack);
605 LValue value = lowInt52(m_node->child1());
606 m_out.store64(value, addressFor(variable->local()));
607 m_valueSources.operand(variable->local()) = ValueSource(Int52InJSStack);
612 LValue value = lowCell(m_node->child1());
613 m_out.store64(value, addressFor(variable->local()));
614 m_valueSources.operand(variable->local()) = ValueSource(ValueInJSStack);
618 case FlushedBoolean: {
619 speculateBoolean(m_node->child1());
621 lowJSValue(m_node->child1(), ManualOperandSpeculation),
622 addressFor(variable->local()));
623 m_valueSources.operand(variable->local()) = ValueSource(ValueInJSStack);
628 RELEASE_ASSERT_NOT_REACHED();
631 RELEASE_ASSERT_NOT_REACHED();
634 void compileMovHint()
636 observeMovHint(m_node);
639 void compileZombieHint()
641 VariableAccessData* data = m_node->variableAccessData();
642 m_lastSetOperand = data->local();
643 m_valueSources.operand(data->local()) = ValueSource(SourceIsDead);
646 void compileMovHintAndCheck()
648 observeMovHint(m_node);
649 speculate(m_node->child1());
652 void compilePhantom()
654 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
659 switch (m_node->binaryUseKind()) {
661 LValue left = lowInt32(m_node->child1());
662 LValue right = lowInt32(m_node->child2());
664 if (bytecodeCanTruncateInteger(m_node->arithNodeFlags())) {
665 setInt32(m_out.add(left, right));
669 LValue result = m_out.addWithOverflow32(left, right);
670 speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
671 setInt32(m_out.extractValue(result, 0));
675 case MachineIntUse: {
676 if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)
677 && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) {
679 LValue left = lowWhicheverInt52(m_node->child1(), kind);
680 LValue right = lowInt52(m_node->child2(), kind);
681 setInt52(m_out.add(left, right), kind);
685 LValue left = lowInt52(m_node->child1());
686 LValue right = lowInt52(m_node->child2());
687 LValue result = m_out.addWithOverflow64(left, right);
688 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
689 setInt52(m_out.extractValue(result, 0));
695 m_out.doubleAdd(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
700 RELEASE_ASSERT_NOT_REACHED();
705 void compileArithSub()
707 switch (m_node->binaryUseKind()) {
709 LValue left = lowInt32(m_node->child1());
710 LValue right = lowInt32(m_node->child2());
712 if (bytecodeCanTruncateInteger(m_node->arithNodeFlags())) {
713 setInt32(m_out.sub(left, right));
717 LValue result = m_out.subWithOverflow32(left, right);
718 speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
719 setInt32(m_out.extractValue(result, 0));
723 case MachineIntUse: {
724 if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)
725 && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) {
727 LValue left = lowWhicheverInt52(m_node->child1(), kind);
728 LValue right = lowInt52(m_node->child2(), kind);
729 setInt52(m_out.sub(left, right), kind);
733 LValue left = lowInt52(m_node->child1());
734 LValue right = lowInt52(m_node->child2());
735 LValue result = m_out.subWithOverflow64(left, right);
736 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
737 setInt52(m_out.extractValue(result, 0));
743 m_out.doubleSub(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
748 RELEASE_ASSERT_NOT_REACHED();
753 void compileArithMul()
755 switch (m_node->binaryUseKind()) {
757 LValue left = lowInt32(m_node->child1());
758 LValue right = lowInt32(m_node->child2());
761 if (bytecodeCanTruncateInteger(m_node->arithNodeFlags()))
762 result = m_out.mul(left, right);
764 LValue overflowResult = m_out.mulWithOverflow32(left, right);
765 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
766 result = m_out.extractValue(overflowResult, 0);
769 if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
770 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
771 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
773 m_out.branch(m_out.notZero32(result), continuation, slowCase);
775 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
776 speculate(NegativeZero, noValue(), 0, m_out.lessThan(left, m_out.int32Zero));
777 speculate(NegativeZero, noValue(), 0, m_out.lessThan(right, m_out.int32Zero));
778 m_out.jump(continuation);
779 m_out.appendTo(continuation, lastNext);
786 case MachineIntUse: {
788 LValue left = lowWhicheverInt52(m_node->child1(), kind);
789 LValue right = lowInt52(m_node->child2(), opposite(kind));
791 LValue overflowResult = m_out.mulWithOverflow64(left, right);
792 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
793 LValue result = m_out.extractValue(overflowResult, 0);
795 if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
796 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
797 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
799 m_out.branch(m_out.notZero64(result), continuation, slowCase);
801 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
802 speculate(NegativeZero, noValue(), 0, m_out.lessThan(left, m_out.int64Zero));
803 speculate(NegativeZero, noValue(), 0, m_out.lessThan(right, m_out.int64Zero));
804 m_out.jump(continuation);
805 m_out.appendTo(continuation, lastNext);
814 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
819 RELEASE_ASSERT_NOT_REACHED();
824 void compileArithDiv()
826 switch (m_node->binaryUseKind()) {
828 LValue numerator = lowInt32(m_node->child1());
829 LValue denominator = lowInt32(m_node->child2());
831 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
832 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
833 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDiv done"));
835 Vector<ValueFromBlock, 3> results;
837 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
839 m_out.branch(m_out.above(adjustedDenominator, m_out.int32One), continuation, unsafeDenominator);
841 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
843 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
845 if (bytecodeUsesAsNumber(m_node->arithNodeFlags())) {
846 speculate(Overflow, noValue(), 0, m_out.isZero32(denominator));
847 speculate(Overflow, noValue(), 0, m_out.equal(numerator, neg2ToThe31));
848 m_out.jump(continuation);
850 // This is the case where we convert the result to an int after we're done. So,
851 // if the denominator is zero, then the result should be result should be zero.
852 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
853 // check above) and the numerator is -2^31 then the result should be -2^31.
855 LBasicBlock divByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv divide by zero"));
856 LBasicBlock notDivByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv not divide by zero"));
857 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithDiv -2^31/-1"));
859 m_out.branch(m_out.isZero32(denominator), divByZero, notDivByZero);
861 m_out.appendTo(divByZero, notDivByZero);
862 results.append(m_out.anchor(m_out.int32Zero));
865 m_out.appendTo(notDivByZero, neg2ToThe31ByNeg1);
866 m_out.branch(m_out.equal(numerator, neg2ToThe31), neg2ToThe31ByNeg1, continuation);
868 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
869 results.append(m_out.anchor(neg2ToThe31));
873 m_out.appendTo(continuation, done);
875 if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
876 LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
877 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
879 m_out.branch(m_out.isZero32(numerator), zeroNumerator, numeratorContinuation);
881 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
884 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
886 m_out.jump(numeratorContinuation);
888 m_out.appendTo(numeratorContinuation, innerLastNext);
891 LValue divisionResult = m_out.div(numerator, denominator);
893 if (bytecodeUsesAsNumber(m_node->arithNodeFlags())) {
895 Overflow, noValue(), 0,
896 m_out.notEqual(m_out.mul(divisionResult, denominator), numerator));
899 results.append(m_out.anchor(divisionResult));
902 m_out.appendTo(done, lastNext);
904 setInt32(m_out.phi(m_out.int32, results));
910 m_out.doubleDiv(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
915 RELEASE_ASSERT_NOT_REACHED();
920 void compileArithMod()
922 switch (m_node->binaryUseKind()) {
924 LValue numerator = lowInt32(m_node->child1());
925 LValue denominator = lowInt32(m_node->child2());
927 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
928 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
929 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod done"));
931 Vector<ValueFromBlock, 3> results;
933 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
935 m_out.branch(m_out.above(adjustedDenominator, m_out.int32One), continuation, unsafeDenominator);
937 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
939 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
941 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
942 // separate case for that. But it probably doesn't matter so much.
943 if (bytecodeUsesAsNumber(m_node->arithNodeFlags())) {
944 speculate(Overflow, noValue(), 0, m_out.isZero32(denominator));
945 speculate(Overflow, noValue(), 0, m_out.equal(numerator, neg2ToThe31));
946 m_out.jump(continuation);
948 // This is the case where we convert the result to an int after we're done. So,
949 // if the denominator is zero, then the result should be result should be zero.
950 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
951 // check above) and the numerator is -2^31 then the result should be -2^31.
953 LBasicBlock modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
954 LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
955 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
957 m_out.branch(m_out.isZero32(denominator), modByZero, notModByZero);
959 m_out.appendTo(modByZero, notModByZero);
960 results.append(m_out.anchor(m_out.int32Zero));
963 m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
964 m_out.branch(m_out.equal(numerator, neg2ToThe31), neg2ToThe31ByNeg1, continuation);
966 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
967 results.append(m_out.anchor(m_out.int32Zero));
971 m_out.appendTo(continuation, done);
973 LValue remainder = m_out.rem(numerator, denominator);
975 if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
976 LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
977 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
980 m_out.lessThan(numerator, m_out.int32Zero),
981 negativeNumerator, numeratorContinuation);
983 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
985 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
987 m_out.jump(numeratorContinuation);
989 m_out.appendTo(numeratorContinuation, innerLastNext);
992 results.append(m_out.anchor(remainder));
995 m_out.appendTo(done, lastNext);
997 setInt32(m_out.phi(m_out.int32, results));
1003 m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1008 RELEASE_ASSERT_NOT_REACHED();
1013 void compileArithMinOrMax()
1015 switch (m_node->binaryUseKind()) {
1017 LValue left = lowInt32(m_node->child1());
1018 LValue right = lowInt32(m_node->child2());
1022 m_node->op() == ArithMin
1023 ? m_out.lessThan(left, right)
1024 : m_out.lessThan(right, left),
1030 LValue left = lowDouble(m_node->child1());
1031 LValue right = lowDouble(m_node->child2());
1033 LBasicBlock notLessThan = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax not less than"));
1034 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax continuation"));
1036 Vector<ValueFromBlock, 2> results;
1038 results.append(m_out.anchor(left));
1040 m_node->op() == ArithMin
1041 ? m_out.doubleLessThan(left, right)
1042 : m_out.doubleGreaterThan(left, right),
1043 continuation, notLessThan);
1045 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
1046 results.append(m_out.anchor(m_out.select(
1047 m_node->op() == ArithMin
1048 ? m_out.doubleGreaterThanOrEqual(left, right)
1049 : m_out.doubleLessThanOrEqual(left, right),
1050 right, m_out.constDouble(0.0 / 0.0))));
1051 m_out.jump(continuation);
1053 m_out.appendTo(continuation, lastNext);
1054 setDouble(m_out.phi(m_out.doubleType, results));
1059 RELEASE_ASSERT_NOT_REACHED();
1064 void compileArithAbs()
1066 switch (m_node->child1().useKind()) {
1068 LValue value = lowInt32(m_node->child1());
1070 LValue mask = m_out.aShr(value, m_out.constInt32(31));
1071 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
1073 speculate(Overflow, noValue(), 0, m_out.equal(result, m_out.constInt32(1 << 31)));
1080 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
1085 RELEASE_ASSERT_NOT_REACHED();
1090 void compileArithNegate()
1092 switch (m_node->child1().useKind()) {
1094 LValue value = lowInt32(m_node->child1());
1097 if (bytecodeCanTruncateInteger(m_node->arithNodeFlags()))
1098 result = m_out.neg(value);
1099 else if (bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
1100 // We don't have a negate-with-overflow intrinsic. Hopefully this
1101 // does the trick, though.
1102 LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
1103 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1104 result = m_out.extractValue(overflowResult, 0);
1106 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
1107 result = m_out.neg(value);
1114 case MachineIntUse: {
1115 if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)) {
1117 LValue value = lowWhicheverInt52(m_node->child1(), kind);
1118 LValue result = m_out.neg(value);
1119 if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags()))
1120 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1121 setInt52(result, kind);
1125 LValue value = lowInt52(m_node->child1());
1126 LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
1127 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1128 LValue result = m_out.extractValue(overflowResult, 0);
1129 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1135 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
1140 RELEASE_ASSERT_NOT_REACHED();
1145 void compileBitAnd()
1147 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1152 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1155 void compileBitXor()
1157 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1160 void compileBitRShift()
1162 setInt32(m_out.aShr(
1163 lowInt32(m_node->child1()),
1164 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1167 void compileBitLShift()
1170 lowInt32(m_node->child1()),
1171 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1174 void compileBitURShift()
1176 setInt32(m_out.lShr(
1177 lowInt32(m_node->child1()),
1178 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1181 void compileUInt32ToNumber()
1183 LValue value = lowInt32(m_node->child1());
1185 if (!nodeCanSpeculateInt32(m_node->arithNodeFlags())) {
1186 setDouble(m_out.unsignedToDouble(value));
1191 Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero),
1192 FormattedValue(ValueFormatUInt32, value));
1196 void compileInt32ToDouble()
1198 // This node is tricky to compile in the DFG backend because it tries to
1199 // avoid converting child1 to a double in-place, as that would make subsequent
1200 // int uses of of child1 fail. But the FTL needs no such special magic, since
1201 // unlike the DFG backend, the FTL allows each node to have multiple
1202 // contemporaneous low-level representations. So, this gives child1 a double
1203 // representation and then forwards that representation to m_node.
1205 setDouble(lowDouble(m_node->child1()));
1208 void compileCheckStructure()
1210 LValue cell = lowCell(m_node->child1());
1213 if (m_node->child1()->op() == WeakJSConstant)
1214 exitKind = BadWeakConstantCache;
1216 exitKind = BadCache;
1218 LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
1220 if (m_node->structureSet().size() == 1) {
1222 exitKind, jsValueValue(cell), 0,
1223 m_out.notEqual(structure, weakPointer(m_node->structureSet()[0])));
1227 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CheckStructure continuation"));
1229 LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
1230 for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) {
1231 LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("CheckStructure nextStructure"));
1233 m_out.equal(structure, weakPointer(m_node->structureSet()[i])),
1234 continuation, nextStructure);
1235 m_out.appendTo(nextStructure);
1239 exitKind, jsValueValue(cell), 0,
1240 m_out.notEqual(structure, weakPointer(m_node->structureSet().last())));
1242 m_out.jump(continuation);
1243 m_out.appendTo(continuation, lastNext);
1246 void compileStructureTransitionWatchpoint()
1248 addWeakReference(m_node->structure());
1250 // FIXME: Implement structure transition watchpoints.
1251 // https://bugs.webkit.org/show_bug.cgi?id=113647
1253 speculateCell(m_node->child1());
1256 void compileArrayifyToStructure()
1258 LValue cell = lowCell(m_node->child1());
1259 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
1261 LBasicBlock unexpectedStructure = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure unexpected structure"));
1262 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure continuation"));
1264 LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
1267 m_out.notEqual(structure, weakPointer(m_node->structure())),
1268 unexpectedStructure, continuation);
1270 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
1273 switch (m_node->arrayMode().type()) {
1276 case Array::Contiguous:
1278 Uncountable, noValue(), 0,
1279 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
1286 switch (m_node->arrayMode().type()) {
1288 vmCall(m_out.operation(operationEnsureInt32), m_callFrame, cell);
1291 vmCall(m_out.operation(operationEnsureDouble), m_callFrame, cell);
1293 case Array::Contiguous:
1294 if (m_node->arrayMode().conversion() == Array::RageConvert)
1295 vmCall(m_out.operation(operationRageEnsureContiguous), m_callFrame, cell);
1297 vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell);
1299 case Array::ArrayStorage:
1300 case Array::SlowPutArrayStorage:
1301 vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
1304 RELEASE_ASSERT_NOT_REACHED();
1308 structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
1310 BadIndexingType, jsValueValue(cell), 0,
1311 m_out.notEqual(structure, weakPointer(m_node->structure())));
1312 m_out.jump(continuation);
1314 m_out.appendTo(continuation, lastNext);
1317 void compilePutStructure()
1319 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
1322 m_out.constIntPtr(m_node->structureTransitionData().newStructure),
1323 lowCell(m_node->child1()), m_heaps.JSCell_structure);
1326 void compilePhantomPutStructure()
1328 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
1331 void compileGetButterfly()
1333 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly));
1336 void compileGetIndexedPropertyStorage()
1338 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_vector));
1341 void compileCheckArray()
1343 Edge edge = m_node->child1();
1344 LValue cell = lowCell(edge);
1346 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, m_state.forNode(edge)))
1350 BadIndexingType, jsValueValue(cell), 0,
1351 m_out.bitNot(isArrayType(cell, m_node->arrayMode())));
1354 void compileGetArrayLength()
1356 switch (m_node->arrayMode().type()) {
1359 case Array::Contiguous: {
1360 setInt32(m_out.load32(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
1365 if (isTypedView(m_node->arrayMode().typedArrayType())) {
1367 m_out.load32(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
1371 RELEASE_ASSERT_NOT_REACHED();
1376 void compileGetByVal()
1378 LValue index = lowInt32(m_node->child2());
1379 LValue storage = lowStorage(m_node->child3());
1381 switch (m_node->arrayMode().type()) {
1383 case Array::Contiguous: {
1384 if (m_node->arrayMode().isInBounds()) {
1386 OutOfBounds, noValue(), 0,
1388 index, m_out.load32(storage, m_heaps.Butterfly_publicLength)));
1390 LValue result = m_out.load64(m_out.baseIndex(
1391 m_node->arrayMode().type() == Array::Int32 ?
1392 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
1393 storage, m_out.zeroExt(index, m_out.intPtr),
1394 m_state.forNode(m_node->child2()).m_value));
1395 speculate(LoadFromHole, noValue(), 0, m_out.isZero64(result));
1400 // FIXME: Implement hole/OOB loads in the FTL.
1401 // https://bugs.webkit.org/show_bug.cgi?id=118077
1402 RELEASE_ASSERT_NOT_REACHED();
1406 case Array::Double: {
1407 if (m_node->arrayMode().isInBounds()) {
1408 if (m_node->arrayMode().isSaneChain()) {
1409 // FIXME: Implement structure transition watchpoints.
1410 // https://bugs.webkit.org/show_bug.cgi?id=113647
1414 OutOfBounds, noValue(), 0,
1416 index, m_out.load32(storage, m_heaps.Butterfly_publicLength)));
1418 LValue result = m_out.loadDouble(m_out.baseIndex(
1419 m_heaps.indexedDoubleProperties,
1420 storage, m_out.zeroExt(index, m_out.intPtr),
1421 m_state.forNode(m_node->child2()).m_value));
1423 if (!m_node->arrayMode().isSaneChain()) {
1425 LoadFromHole, noValue(), 0,
1426 m_out.doubleNotEqualOrUnordered(result, result));
1432 // FIXME: Implement hole/OOB loads in the FTL.
1433 // https://bugs.webkit.org/show_bug.cgi?id=118077
1434 RELEASE_ASSERT_NOT_REACHED();
1439 TypedArrayType type = m_node->arrayMode().typedArrayType();
1441 if (isTypedView(type)) {
1442 LValue array = lowCell(m_node->child1());
1445 OutOfBounds, noValue(), 0,
1447 index, m_out.load32(array, m_heaps.JSArrayBufferView_length)));
1449 TypedPointer pointer = TypedPointer(
1450 m_heaps.typedArrayProperties,
1454 m_out.zeroExt(index, m_out.intPtr),
1455 m_out.constIntPtr(logElementSize(type)))));
1459 switch (elementSize(type)) {
1461 result = m_out.load8(pointer);
1464 result = m_out.load16(pointer);
1467 result = m_out.load32(pointer);
1470 RELEASE_ASSERT_NOT_REACHED();
1473 if (elementSize(type) < 4) {
1475 result = m_out.signExt(result, m_out.int32);
1477 result = m_out.zeroExt(result, m_out.int32);
1482 if (isSigned(type)) {
1487 if (m_node->shouldSpeculateInt32()) {
1489 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero),
1490 uInt32Value(result));
1495 setDouble(m_out.unsignedToFP(result, m_out.doubleType));
1499 ASSERT(isFloat(type));
1504 result = m_out.fpCast(m_out.loadFloat(pointer), m_out.doubleType);
1507 result = m_out.loadDouble(pointer);
1510 RELEASE_ASSERT_NOT_REACHED();
1513 result = m_out.select(
1514 m_out.doubleEqual(result, result), result, m_out.constDouble(QNaN));
1519 RELEASE_ASSERT_NOT_REACHED();
1524 void compilePutByVal()
1526 Edge child1 = m_graph.varArgChild(m_node, 0);
1527 Edge child2 = m_graph.varArgChild(m_node, 1);
1528 Edge child3 = m_graph.varArgChild(m_node, 2);
1529 Edge child4 = m_graph.varArgChild(m_node, 3);
1531 LValue base = lowCell(child1);
1532 LValue index = lowInt32(child2);
1533 LValue storage = lowStorage(child4);
1535 switch (m_node->arrayMode().type()) {
1538 case Array::Contiguous: {
1539 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal continuation"));
1540 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
1542 switch (m_node->arrayMode().type()) {
1544 case Array::Contiguous: {
1545 LValue value = lowJSValue(child3, ManualOperandSpeculation);
1547 if (m_node->arrayMode().type() == Array::Int32)
1548 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32, isNotInt32(value));
1550 TypedPointer elementPointer = m_out.baseIndex(
1551 m_node->arrayMode().type() == Array::Int32 ?
1552 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
1553 storage, m_out.zeroExt(index, m_out.intPtr),
1554 m_state.forNode(child2).m_value);
1556 if (m_node->op() == PutByValAlias) {
1557 m_out.store64(value, elementPointer);
1561 contiguousPutByValOutOfBounds(
1562 codeBlock()->isStrictMode()
1563 ? operationPutByValBeyondArrayBoundsStrict
1564 : operationPutByValBeyondArrayBoundsNonStrict,
1565 base, storage, index, value, continuation);
1567 m_out.store64(value, elementPointer);
1571 case Array::Double: {
1572 LValue value = lowDouble(child3);
1575 doubleValue(value), child3, SpecFullRealNumber,
1576 m_out.doubleNotEqualOrUnordered(value, value));
1578 TypedPointer elementPointer = m_out.baseIndex(
1579 m_heaps.indexedDoubleProperties,
1580 storage, m_out.zeroExt(index, m_out.intPtr),
1581 m_state.forNode(child2).m_value);
1583 if (m_node->op() == PutByValAlias) {
1584 m_out.storeDouble(value, elementPointer);
1588 contiguousPutByValOutOfBounds(
1589 codeBlock()->isStrictMode()
1590 ? operationPutDoubleByValBeyondArrayBoundsStrict
1591 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
1592 base, storage, index, value, continuation);
1594 m_out.storeDouble(value, elementPointer);
1599 RELEASE_ASSERT_NOT_REACHED();
1602 m_out.jump(continuation);
1603 m_out.appendTo(continuation, outerLastNext);
1608 TypedArrayType type = m_node->arrayMode().typedArrayType();
1610 if (isTypedView(type)) {
1611 if (m_node->op() == PutByVal) {
1613 OutOfBounds, noValue(), 0,
1615 index, m_out.load32(base, m_heaps.JSArrayBufferView_length)));
1618 TypedPointer pointer = TypedPointer(
1619 m_heaps.typedArrayProperties,
1623 m_out.zeroExt(index, m_out.intPtr),
1624 m_out.constIntPtr(logElementSize(type)))));
1628 switch (child3.useKind()) {
1630 intValue = lowInt32(child3);
1631 if (isClamped(type)) {
1632 ASSERT(elementSize(type) == 1);
1634 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp atLeastZero"));
1635 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp continuation"));
1637 Vector<ValueFromBlock, 2> intValues;
1638 intValues.append(m_out.anchor(m_out.int32Zero));
1640 m_out.lessThan(intValue, m_out.int32Zero),
1641 continuation, atLeastZero);
1643 LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation);
1645 intValues.append(m_out.anchor(m_out.select(
1646 m_out.greaterThan(intValue, m_out.constInt32(255)),
1647 m_out.constInt32(255),
1649 m_out.jump(continuation);
1651 m_out.appendTo(continuation, lastNext);
1652 intValue = m_out.phi(m_out.int32, intValues);
1658 LValue doubleValue = lowDouble(child3);
1660 if (isClamped(type)) {
1661 ASSERT(elementSize(type) == 1);
1663 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp atLeastZero"));
1664 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp withinRange"));
1665 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp continuation"));
1667 Vector<ValueFromBlock, 3> intValues;
1668 intValues.append(m_out.anchor(m_out.int32Zero));
1670 m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero),
1671 continuation, atLeastZero);
1673 LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange);
1674 intValues.append(m_out.anchor(m_out.constInt32(255)));
1676 m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)),
1677 continuation, withinRange);
1679 m_out.appendTo(withinRange, continuation);
1680 intValues.append(m_out.anchor(m_out.fpToInt32(doubleValue)));
1681 m_out.jump(continuation);
1683 m_out.appendTo(continuation, lastNext);
1684 intValue = m_out.phi(m_out.int32, intValues);
1685 } else if (isSigned(type))
1686 intValue = doubleToInt32(doubleValue);
1688 intValue = doubleToUInt32(doubleValue);
1693 RELEASE_ASSERT_NOT_REACHED();
1696 switch (elementSize(type)) {
1698 m_out.store8(m_out.intCast(intValue, m_out.int8), pointer);
1701 m_out.store16(m_out.intCast(intValue, m_out.int16), pointer);
1704 m_out.store32(intValue, pointer);
1707 RELEASE_ASSERT_NOT_REACHED();
1713 ASSERT(isFloat(type));
1715 LValue value = lowDouble(child3);
1718 m_out.storeFloat(m_out.fpCast(value, m_out.floatType), pointer);
1721 m_out.storeDouble(value, pointer);
1724 RELEASE_ASSERT_NOT_REACHED();
1729 RELEASE_ASSERT_NOT_REACHED();
1734 void compileGetByOffset()
1736 StorageAccessData& data =
1737 m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
1742 m_heaps.properties[data.identifierNumber],
1743 lowStorage(m_node->child1()),
1744 offsetRelativeToBase(data.offset))));
1747 void compilePutByOffset()
1749 StorageAccessData& data =
1750 m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
1753 lowJSValue(m_node->child3()),
1755 m_heaps.properties[data.identifierNumber],
1756 lowStorage(m_node->child1()),
1757 offsetRelativeToBase(data.offset)));
1760 void compileGetGlobalVar()
1762 setJSValue(m_out.load64(m_out.absolute(m_node->registerPointer())));
1765 void compilePutGlobalVar()
1768 lowJSValue(m_node->child1()), m_out.absolute(m_node->registerPointer()));
1771 void compileGlobalVarWatchpoint()
1773 // FIXME: Implement watchpoints.
1774 // https://bugs.webkit.org/show_bug.cgi?id=113647
1777 void compileGetMyScope()
1779 setJSValue(m_out.loadPtr(addressFor(
1780 m_node->codeOrigin.stackOffset() + JSStack::ScopeChain)));
1783 void compileSkipScope()
1785 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next));
1788 void compileGetClosureRegisters()
1790 setStorage(m_out.loadPtr(
1791 lowCell(m_node->child1()), m_heaps.JSVariableObject_registers));
1794 void compileGetClosureVar()
1796 setJSValue(m_out.load64(
1797 addressFor(lowStorage(m_node->child1()), m_node->varNumber())));
1800 void compilePutClosureVar()
1803 lowJSValue(m_node->child3()),
1804 addressFor(lowStorage(m_node->child2()), m_node->varNumber()));
1807 void compileCompareEq()
1809 if (m_node->isBinaryUseKind(Int32Use)
1810 || m_node->isBinaryUseKind(MachineIntUse)
1811 || m_node->isBinaryUseKind(NumberUse)
1812 || m_node->isBinaryUseKind(ObjectUse)) {
1813 compileCompareStrictEq();
1817 RELEASE_ASSERT_NOT_REACHED();
1820 void compileCompareEqConstant()
1822 ASSERT(m_graph.valueOfJSConstant(m_node->child2().node()).isNull());
1823 masqueradesAsUndefinedWatchpointIfIsStillValid();
1825 equalNullOrUndefined(
1826 m_node->child1(), AllCellsAreFalse, EqualNullOrUndefined));
1829 void compileCompareStrictEq()
1831 if (m_node->isBinaryUseKind(Int32Use)) {
1833 m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1837 if (m_node->isBinaryUseKind(MachineIntUse)) {
1839 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1840 LValue right = lowInt52(m_node->child2(), kind);
1841 setBoolean(m_out.equal(left, right));
1845 if (m_node->isBinaryUseKind(NumberUse)) {
1847 m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1851 if (m_node->isBinaryUseKind(ObjectUse)) {
1852 masqueradesAsUndefinedWatchpointIfIsStillValid();
1855 lowNonNullObject(m_node->child1()),
1856 lowNonNullObject(m_node->child2())));
1860 RELEASE_ASSERT_NOT_REACHED();
1863 void compileCompareStrictEqConstant()
1865 JSValue constant = m_graph.valueOfJSConstant(m_node->child2().node());
1867 if (constant.isUndefinedOrNull()
1868 && !masqueradesAsUndefinedWatchpointIfIsStillValid()) {
1869 if (constant.isNull()) {
1870 setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualNull));
1874 ASSERT(constant.isUndefined());
1875 setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualUndefined));
1881 lowJSValue(m_node->child1()),
1882 m_out.constInt64(JSValue::encode(constant))));
1885 void compileCompareLess()
1887 if (m_node->isBinaryUseKind(Int32Use)) {
1889 m_out.lessThan(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1893 if (m_node->isBinaryUseKind(MachineIntUse)) {
1895 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1896 LValue right = lowInt52(m_node->child2(), kind);
1897 setBoolean(m_out.lessThan(left, right));
1901 if (m_node->isBinaryUseKind(NumberUse)) {
1903 m_out.doubleLessThan(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1907 RELEASE_ASSERT_NOT_REACHED();
1910 void compileCompareLessEq()
1912 if (m_node->isBinaryUseKind(Int32Use)) {
1914 m_out.lessThanOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1918 if (m_node->isBinaryUseKind(MachineIntUse)) {
1920 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1921 LValue right = lowInt52(m_node->child2(), kind);
1922 setBoolean(m_out.lessThanOrEqual(left, right));
1926 if (m_node->isBinaryUseKind(NumberUse)) {
1928 m_out.doubleLessThanOrEqual(
1929 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1933 RELEASE_ASSERT_NOT_REACHED();
1936 void compileCompareGreater()
1938 if (m_node->isBinaryUseKind(Int32Use)) {
1940 m_out.greaterThan(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1944 if (m_node->isBinaryUseKind(MachineIntUse)) {
1946 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1947 LValue right = lowInt52(m_node->child2(), kind);
1948 setBoolean(m_out.greaterThan(left, right));
1952 if (m_node->isBinaryUseKind(NumberUse)) {
1954 m_out.doubleGreaterThan(
1955 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1959 RELEASE_ASSERT_NOT_REACHED();
1962 void compileCompareGreaterEq()
1964 if (m_node->isBinaryUseKind(Int32Use)) {
1966 m_out.greaterThanOrEqual(
1967 lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1971 if (m_node->isBinaryUseKind(MachineIntUse)) {
1973 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1974 LValue right = lowInt52(m_node->child2(), kind);
1975 setBoolean(m_out.greaterThanOrEqual(left, right));
1979 if (m_node->isBinaryUseKind(NumberUse)) {
1981 m_out.doubleGreaterThanOrEqual(
1982 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1986 RELEASE_ASSERT_NOT_REACHED();
1989 void compileLogicalNot()
1991 setBoolean(m_out.bitNot(boolify(m_node->child1())));
1994 void compileCallOrConstruct()
1996 // FIXME: This is unacceptably slow.
1997 // https://bugs.webkit.org/show_bug.cgi?id=113621
1999 J_DFGOperation_E function =
2000 m_node->op() == Call ? operationFTLCall : operationFTLConstruct;
2002 int dummyThisArgument = m_node->op() == Call ? 0 : 1;
2004 int numPassedArgs = m_node->numChildren() - 1;
2006 LValue calleeFrame = m_out.add(
2008 m_out.constIntPtr(sizeof(Register) * virtualRegisterForLocal(codeBlock()->m_numCalleeRegisters).offset()));
2011 m_out.constInt32(numPassedArgs + dummyThisArgument),
2012 payloadFor(calleeFrame, JSStack::ArgumentCount));
2013 m_out.store64(m_callFrame, addressFor(calleeFrame, JSStack::CallerFrame));
2015 lowJSValue(m_graph.varArgChild(m_node, 0)),
2016 addressFor(calleeFrame, JSStack::Callee));
2018 for (int i = 0; i < numPassedArgs; ++i) {
2020 lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
2021 addressFor(calleeFrame, virtualRegisterForArgument(i + dummyThisArgument).offset()));
2024 setJSValue(vmCall(m_out.operation(function), calleeFrame));
2029 m_out.jump(lowBlock(m_node->takenBlock()));
2032 void compileBranch()
2035 boolify(m_node->child1()),
2036 lowBlock(m_node->takenBlock()),
2037 lowBlock(m_node->notTakenBlock()));
2040 void compileSwitch()
2042 SwitchData* data = m_node->switchData();
2043 switch (data->kind) {
2045 Vector<ValueFromBlock, 2> intValues;
2046 LBasicBlock switchOnInts = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm int case"));
2048 LBasicBlock lastNext = m_out.appendTo(m_out.m_block, switchOnInts);
2050 switch (m_node->child1().useKind()) {
2052 intValues.append(m_out.anchor(lowInt32(m_node->child1())));
2053 m_out.jump(switchOnInts);
2058 LBasicBlock isInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is int"));
2059 LBasicBlock isNotInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is not int"));
2060 LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is double"));
2062 LValue boxedValue = lowJSValue(m_node->child1());
2063 m_out.branch(isNotInt32(boxedValue), isNotInt, isInt);
2065 LBasicBlock innerLastNext = m_out.appendTo(isInt, isNotInt);
2067 intValues.append(m_out.anchor(unboxInt32(boxedValue)));
2068 m_out.jump(switchOnInts);
2070 m_out.appendTo(isNotInt, isDouble);
2072 isCellOrMisc(boxedValue), lowBlock(data->fallThrough), isDouble);
2074 m_out.appendTo(isDouble, innerLastNext);
2075 LValue doubleValue = unboxDouble(boxedValue);
2076 LValue intInDouble = m_out.fpToInt32(doubleValue);
2077 intValues.append(m_out.anchor(intInDouble));
2079 m_out.doubleEqual(m_out.intToDouble(intInDouble), doubleValue),
2080 switchOnInts, lowBlock(data->fallThrough));
2085 RELEASE_ASSERT_NOT_REACHED();
2089 m_out.appendTo(switchOnInts, lastNext);
2090 buildSwitch(data, m_out.int32, m_out.phi(m_out.int32, intValues));
2097 switch (m_node->child1().useKind()) {
2099 stringValue = lowString(m_node->child1());
2104 LValue unboxedValue = lowJSValue(m_node->child1());
2106 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is cell"));
2107 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is string"));
2110 isNotCell(unboxedValue), lowBlock(data->fallThrough), isCellCase);
2112 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
2113 LValue cellValue = unboxedValue;
2114 m_out.branch(isNotString(cellValue), lowBlock(data->fallThrough), isStringCase);
2116 m_out.appendTo(isStringCase, lastNext);
2117 stringValue = cellValue;
2122 RELEASE_ASSERT_NOT_REACHED();
2126 LBasicBlock lengthIs1 = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar length is 1"));
2127 LBasicBlock needResolution = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolution"));
2128 LBasicBlock resolved = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolved"));
2129 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 8bit"));
2130 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 16bit"));
2131 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar continuation"));
2135 m_out.load32(stringValue, m_heaps.JSString_length),
2137 lowBlock(data->fallThrough), lengthIs1);
2139 LBasicBlock lastNext = m_out.appendTo(lengthIs1, needResolution);
2140 Vector<ValueFromBlock, 2> values;
2141 LValue fastValue = m_out.loadPtr(stringValue, m_heaps.JSString_value);
2142 values.append(m_out.anchor(fastValue));
2143 m_out.branch(m_out.isNull(fastValue), needResolution, resolved);
2145 m_out.appendTo(needResolution, resolved);
2146 values.append(m_out.anchor(
2147 vmCall(m_out.operation(operationResolveRope), m_callFrame, stringValue)));
2148 m_out.jump(resolved);
2150 m_out.appendTo(resolved, is8Bit);
2151 LValue value = m_out.phi(m_out.intPtr, values);
2152 LValue characterData = m_out.loadPtr(value, m_heaps.StringImpl_data);
2154 m_out.testNonZero32(
2155 m_out.load32(value, m_heaps.StringImpl_hashAndFlags),
2156 m_out.constInt32(StringImpl::flagIs8Bit())),
2159 Vector<ValueFromBlock, 2> characters;
2160 m_out.appendTo(is8Bit, is16Bit);
2161 characters.append(m_out.anchor(
2162 m_out.zeroExt(m_out.load8(characterData, m_heaps.characters8[0]), m_out.int16)));
2163 m_out.jump(continuation);
2165 m_out.appendTo(is16Bit, continuation);
2166 characters.append(m_out.anchor(m_out.load16(characterData, m_heaps.characters16[0])));
2167 m_out.jump(continuation);
2169 m_out.appendTo(continuation, lastNext);
2170 buildSwitch(data, m_out.int16, m_out.phi(m_out.int16, characters));
2175 RELEASE_ASSERT_NOT_REACHED();
2179 RELEASE_ASSERT_NOT_REACHED();
2182 void compileReturn()
2184 // FIXME: have a real epilogue when we switch to using our calling convention.
2185 // https://bugs.webkit.org/show_bug.cgi?id=113621
2186 m_out.ret(lowJSValue(m_node->child1()));
2189 void compileForceOSRExit()
2191 terminate(InadequateCoverage);
2194 LValue boolify(Edge edge)
2196 switch (edge.useKind()) {
2198 return lowBoolean(m_node->child1());
2200 return m_out.notZero32(lowInt32(m_node->child1()));
2202 return m_out.doubleNotEqual(lowDouble(edge), m_out.doubleZero);
2203 case ObjectOrOtherUse:
2204 return m_out.bitNot(
2205 equalNullOrUndefined(
2206 edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined,
2207 ManualOperandSpeculation));
2209 RELEASE_ASSERT_NOT_REACHED();
2214 enum StringOrObjectMode {
2216 CellCaseSpeculatesObject
2218 enum EqualNullOrUndefinedMode {
2221 EqualNullOrUndefined,
2222 SpeculateNullOrUndefined
2224 LValue equalNullOrUndefined(
2225 Edge edge, StringOrObjectMode cellMode, EqualNullOrUndefinedMode primitiveMode,
2226 OperandSpeculationMode operandMode = AutomaticOperandSpeculation)
2228 bool validWatchpoint = masqueradesAsUndefinedWatchpointIfIsStillValid();
2230 LValue value = lowJSValue(edge, operandMode);
2232 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined cell case"));
2233 LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined primitive case"));
2234 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined continuation"));
2236 m_out.branch(isNotCell(value), primitiveCase, cellCase);
2238 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
2240 Vector<ValueFromBlock, 3> results;
2243 case AllCellsAreFalse:
2245 case CellCaseSpeculatesObject:
2247 jsValueValue(value), edge, (~SpecCell) | SpecObject,
2249 m_out.loadPtr(value, m_heaps.JSCell_structure),
2250 m_out.constIntPtr(vm().stringStructure.get())));
2254 if (validWatchpoint) {
2255 results.append(m_out.anchor(m_out.booleanFalse));
2256 m_out.jump(continuation);
2258 LBasicBlock masqueradesCase =
2259 FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined masquerades case"));
2261 LValue structure = m_out.loadPtr(value, m_heaps.JSCell_structure);
2263 results.append(m_out.anchor(m_out.booleanFalse));
2267 m_out.load8(structure, m_heaps.Structure_typeInfoFlags),
2268 m_out.constInt8(MasqueradesAsUndefined)),
2269 masqueradesCase, continuation);
2271 m_out.appendTo(masqueradesCase, primitiveCase);
2273 results.append(m_out.anchor(
2275 m_out.constIntPtr(m_graph.globalObjectFor(m_node->codeOrigin)),
2276 m_out.loadPtr(structure, m_heaps.Structure_globalObject))));
2277 m_out.jump(continuation);
2280 m_out.appendTo(primitiveCase, continuation);
2282 LValue primitiveResult;
2283 switch (primitiveMode) {
2285 primitiveResult = m_out.equal(value, m_out.constInt64(ValueNull));
2287 case EqualUndefined:
2288 primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined));
2290 case EqualNullOrUndefined:
2291 primitiveResult = m_out.equal(
2292 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
2293 m_out.constInt64(ValueNull));
2295 case SpeculateNullOrUndefined:
2297 jsValueValue(value), edge, SpecCell | SpecOther,
2299 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
2300 m_out.constInt64(ValueNull)));
2301 primitiveResult = m_out.booleanTrue;
2304 results.append(m_out.anchor(primitiveResult));
2305 m_out.jump(continuation);
2307 m_out.appendTo(continuation, lastNext);
2309 return m_out.phi(m_out.boolean, results);
2312 template<typename FunctionType>
2313 void contiguousPutByValOutOfBounds(
2314 FunctionType slowPathFunction,
2315 LValue base, LValue storage, LValue index, LValue value,
2316 LBasicBlock continuation)
2318 LValue isNotInBounds = m_out.aboveOrEqual(
2319 index, m_out.load32(storage, m_heaps.Butterfly_publicLength));
2320 if (m_node->arrayMode().isInBounds())
2321 speculate(StoreToHoleOrOutOfBounds, noValue(), 0, isNotInBounds);
2323 LBasicBlock notInBoundsCase =
2324 FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds"));
2325 LBasicBlock performStore =
2326 FTL_NEW_BLOCK(m_out, ("PutByVal perform store"));
2328 m_out.branch(isNotInBounds, notInBoundsCase, performStore);
2330 LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore);
2332 LValue isOutOfBounds = m_out.aboveOrEqual(
2333 index, m_out.load32(storage, m_heaps.Butterfly_vectorLength));
2335 if (!m_node->arrayMode().isOutOfBounds())
2336 speculate(OutOfBounds, noValue(), 0, isOutOfBounds);
2338 LBasicBlock outOfBoundsCase =
2339 FTL_NEW_BLOCK(m_out, ("PutByVal out of bounds"));
2340 LBasicBlock holeCase =
2341 FTL_NEW_BLOCK(m_out, ("PutByVal hole case"));
2343 m_out.branch(isOutOfBounds, outOfBoundsCase, holeCase);
2345 LBasicBlock innerLastNext = m_out.appendTo(outOfBoundsCase, holeCase);
2348 m_out.operation(slowPathFunction),
2349 m_callFrame, base, index, value);
2351 m_out.jump(continuation);
2353 m_out.appendTo(holeCase, innerLastNext);
2357 m_out.add(index, m_out.int32One),
2358 storage, m_heaps.Butterfly_publicLength);
2360 m_out.jump(performStore);
2361 m_out.appendTo(performStore, lastNext);
2365 void buildSwitch(SwitchData* data, LType type, LValue switchValue)
2367 Vector<SwitchCase> cases;
2368 for (unsigned i = 0; i < data->cases.size(); ++i) {
2369 cases.append(SwitchCase(
2370 constInt(type, data->cases[i].value.switchLookupValue()),
2371 lowBlock(data->cases[i].target)));
2374 m_out.switchInstruction(switchValue, cases, lowBlock(data->fallThrough));
2377 LValue doubleToInt32(LValue doubleValue, double low, double high, bool isSigned = true)
2379 // FIXME: Optimize double-to-int conversions.
2380 // <rdar://problem/14938465>
2382 LBasicBlock greatEnough = FTL_NEW_BLOCK(m_out, ("doubleToInt32 greatEnough"));
2383 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("doubleToInt32 withinRange"));
2384 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("doubleToInt32 slowPath"));
2385 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("doubleToInt32 continuation"));
2387 Vector<ValueFromBlock, 2> results;
2390 m_out.greaterThanOrEqual(doubleValue, m_out.constDouble(low)),
2391 greatEnough, slowPath);
2393 LBasicBlock lastNext = m_out.appendTo(greatEnough, withinRange);
2395 m_out.lessThanOrEqual(doubleValue, m_out.constDouble(high)),
2396 withinRange, slowPath);
2398 m_out.appendTo(withinRange, slowPath);
2401 fastResult = m_out.fpToInt32(doubleValue);
2403 fastResult = m_out.fpToUInt32(doubleValue);
2404 results.append(m_out.anchor(fastResult));
2405 m_out.jump(continuation);
2407 m_out.appendTo(slowPath, continuation);
2408 results.append(m_out.anchor(m_out.call(m_out.operation(toInt32), doubleValue)));
2409 m_out.jump(continuation);
2411 m_out.appendTo(continuation, lastNext);
2412 return m_out.phi(m_out.int32, results);
2415 LValue doubleToInt32(LValue doubleValue)
2417 double limit = pow(2, 31) - 1;
2418 return doubleToInt32(doubleValue, -limit, limit);
2421 LValue doubleToUInt32(LValue doubleValue)
2423 return doubleToInt32(doubleValue, 0, pow(2, 32) - 1, false);
2426 void speculateBackward(
2427 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
2430 kind, lowValue, highValue, failCondition, BackwardSpeculation, FormattedValue());
2433 void speculateForward(
2434 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,
2435 const FormattedValue& recovery)
2438 kind, lowValue, highValue, failCondition, ForwardSpeculation, recovery);
2442 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
2445 kind, lowValue, highValue, failCondition, m_direction, FormattedValue());
2448 void terminate(ExitKind kind)
2450 speculate(kind, noValue(), 0, m_out.booleanTrue);
2453 void backwardTypeCheck(
2454 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
2455 LValue failCondition)
2458 lowValue, highValue, typesPassedThrough, failCondition, BackwardSpeculation,
2462 void forwardTypeCheck(
2463 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
2464 LValue failCondition)
2467 lowValue, highValue, typesPassedThrough, failCondition, ForwardSpeculation,
2472 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
2473 LValue failCondition)
2476 lowValue, highValue, typesPassedThrough, failCondition, m_direction,
2480 void appendTypeCheck(
2481 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
2482 LValue failCondition, SpeculationDirection direction, FormattedValue recovery)
2484 if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
2486 ASSERT(mayHaveTypeCheck(highValue.useKind()));
2487 appendOSRExit(BadType, lowValue, highValue.node(), failCondition, direction, recovery);
2488 m_interpreter.filter(highValue, typesPassedThrough);
2491 LValue lowInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2493 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
2495 if (edge->hasConstant()) {
2496 JSValue value = m_graph.valueOfJSConstant(edge.node());
2497 if (!value.isInt32()) {
2498 terminate(Uncountable);
2499 return m_out.int32Zero;
2501 return m_out.constInt32(value.asInt32());
2504 LoweredNodeValue value = m_int32Values.get(edge.node());
2506 return value.value();
2508 value = m_strictInt52Values.get(edge.node());
2510 return strictInt52ToInt32(edge, value.value());
2512 value = m_int52Values.get(edge.node());
2514 return strictInt52ToInt32(edge, int52ToStrictInt52(value.value()));
2516 value = m_jsValueValues.get(edge.node());
2517 if (isValid(value)) {
2518 LValue boxedResult = value.value();
2520 jsValueValue(boxedResult), edge, SpecInt32, isNotInt32(boxedResult));
2521 LValue result = unboxInt32(boxedResult);
2522 setInt32(edge.node(), result);
2526 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt32));
2527 terminate(Uncountable);
2528 return m_out.int32Zero;
2531 enum Int52Kind { StrictInt52, Int52 };
2532 LValue lowInt52(Edge edge, Int52Kind kind, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2534 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
2536 if (edge->hasConstant()) {
2537 JSValue value = m_graph.valueOfJSConstant(edge.node());
2538 if (!value.isMachineInt()) {
2539 terminate(Uncountable);
2540 return m_out.int64Zero;
2542 int64_t result = value.asMachineInt();
2544 result <<= JSValue::int52ShiftAmount;
2545 return m_out.constInt64(result);
2548 LoweredNodeValue value;
2552 value = m_int52Values.get(edge.node());
2554 return value.value();
2556 value = m_strictInt52Values.get(edge.node());
2558 return strictInt52ToInt52(value.value());
2562 value = m_strictInt52Values.get(edge.node());
2564 return value.value();
2566 value = m_int52Values.get(edge.node());
2568 return int52ToStrictInt52(value.value());
2572 value = m_int32Values.get(edge.node());
2573 if (isValid(value)) {
2574 return setInt52WithStrictValue(
2575 edge.node(), m_out.signExt(value.value(), m_out.int64), kind);
2578 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt52));
2580 value = m_jsValueValues.get(edge.node());
2581 if (isValid(value)) {
2582 LValue boxedResult = value.value();
2584 jsValueValue(boxedResult), edge, SpecMachineInt, isNotInt32(boxedResult));
2585 return setInt52WithStrictValue(
2586 edge.node(), m_out.signExt(unboxInt32(boxedResult), m_out.int64), kind);
2589 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecMachineInt));
2590 terminate(Uncountable);
2591 return m_out.int64Zero;
2594 LValue lowInt52(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2596 return lowInt52(edge, Int52, mode);
2599 LValue lowStrictInt52(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2601 return lowInt52(edge, StrictInt52, mode);
2604 bool betterUseStrictInt52(Node* node)
2606 return !isValid(m_int52Values.get(node));
2608 bool betterUseStrictInt52(Edge edge)
2610 return betterUseStrictInt52(edge.node());
2612 template<typename T>
2613 Int52Kind bestInt52Kind(T node)
2615 return betterUseStrictInt52(node) ? StrictInt52 : Int52;
2617 Int52Kind opposite(Int52Kind kind)
2625 RELEASE_ASSERT_NOT_REACHED();
2628 LValue lowWhicheverInt52(Edge edge, Int52Kind& kind, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2630 kind = bestInt52Kind(edge);
2631 return lowInt52(edge, kind, mode);
2634 LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2636 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isCell(edge.useKind()));
2638 if (edge->op() == JSConstant) {
2639 JSValue value = m_graph.valueOfJSConstant(edge.node());
2640 if (!value.isCell()) {
2641 terminate(Uncountable);
2642 return m_out.intPtrZero;
2644 return m_out.constIntPtr(value.asCell());
2647 LoweredNodeValue value = m_jsValueValues.get(edge.node());
2648 if (isValid(value)) {
2649 LValue uncheckedValue = value.value();
2651 jsValueValue(uncheckedValue), edge, SpecCell, isNotCell(uncheckedValue));
2652 return uncheckedValue;
2655 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecCell));
2656 terminate(Uncountable);
2657 return m_out.intPtrZero;
2660 LValue lowObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2662 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
2664 LValue result = lowCell(edge, mode);
2665 speculateObject(edge, result);
2669 LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2671 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringUse || edge.useKind() == KnownStringUse);
2673 LValue result = lowCell(edge, mode);
2674 speculateString(edge, result);
2678 LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2680 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
2682 LValue result = lowCell(edge, mode);
2683 speculateNonNullObject(edge, result);
2687 LValue lowBoolean(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2689 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
2691 if (edge->hasConstant()) {
2692 JSValue value = m_graph.valueOfJSConstant(edge.node());
2693 if (!value.isBoolean()) {
2694 terminate(Uncountable);
2695 return m_out.booleanFalse;
2697 return m_out.constBool(value.asBoolean());
2700 LoweredNodeValue value = m_booleanValues.get(edge.node());
2702 return value.value();
2704 value = m_jsValueValues.get(edge.node());
2705 if (isValid(value)) {
2706 LValue unboxedResult = value.value();
2708 jsValueValue(unboxedResult), edge, SpecBoolean, isNotBoolean(unboxedResult));
2709 LValue result = unboxBoolean(unboxedResult);
2710 setBoolean(edge.node(), result);
2714 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean));
2715 terminate(Uncountable);
2716 return m_out.booleanFalse;
2719 LValue lowDouble(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2721 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isDouble(edge.useKind()));
2723 if (edge->hasConstant()) {
2724 JSValue value = m_graph.valueOfJSConstant(edge.node());
2725 if (!value.isNumber()) {
2726 terminate(Uncountable);
2727 return m_out.doubleZero;
2729 return m_out.constDouble(value.asNumber());
2732 LoweredNodeValue value = m_doubleValues.get(edge.node());
2734 return value.value();
2736 value = m_int32Values.get(edge.node());
2737 if (isValid(value)) {
2738 LValue result = m_out.intToDouble(value.value());
2739 setDouble(edge.node(), result);
2743 value = m_strictInt52Values.get(edge.node());
2745 return strictInt52ToDouble(edge, value.value());
2747 value = m_int52Values.get(edge.node());
2749 return strictInt52ToDouble(edge, int52ToStrictInt52(value.value()));
2751 value = m_jsValueValues.get(edge.node());
2752 if (isValid(value)) {
2753 LValue boxedResult = value.value();
2755 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("Double unboxing int case"));
2756 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Double unboxing double case"));
2757 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Double unboxing continuation"));
2759 m_out.branch(isNotInt32(boxedResult), doubleCase, intCase);
2761 LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
2763 ValueFromBlock intToDouble = m_out.anchor(
2764 m_out.intToDouble(unboxInt32(boxedResult)));
2765 m_out.jump(continuation);
2767 m_out.appendTo(doubleCase, continuation);
2770 jsValueValue(boxedResult), edge, SpecFullNumber, isCellOrMisc(boxedResult));
2772 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedResult));
2773 m_out.jump(continuation);
2775 m_out.appendTo(continuation, lastNext);
2777 LValue result = m_out.phi(m_out.doubleType, intToDouble, unboxedDouble);
2779 setDouble(edge.node(), result);
2783 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecFullNumber));
2784 terminate(Uncountable);
2785 return m_out.doubleZero;
2788 LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
2790 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
2792 if (edge->hasConstant())
2793 return m_out.constInt64(JSValue::encode(m_graph.valueOfJSConstant(edge.node())));
2795 LoweredNodeValue value = m_jsValueValues.get(edge.node());
2797 return value.value();
2799 value = m_int32Values.get(edge.node());
2800 if (isValid(value)) {
2801 LValue result = boxInt32(value.value());
2802 setJSValue(edge.node(), result);
2806 value = m_strictInt52Values.get(edge.node());
2808 return strictInt52ToJSValue(value.value());
2810 value = m_int52Values.get(edge.node());
2812 return strictInt52ToJSValue(int52ToStrictInt52(value.value()));
2814 value = m_booleanValues.get(edge.node());
2815 if (isValid(value)) {
2816 LValue result = boxBoolean(value.value());
2817 setJSValue(edge.node(), result);
2821 value = m_doubleValues.get(edge.node());
2822 if (isValid(value)) {
2823 LValue result = boxDouble(value.value());
2824 setJSValue(edge.node(), result);
2828 RELEASE_ASSERT_NOT_REACHED();
2832 LValue lowStorage(Edge edge)
2834 LoweredNodeValue value = m_storageValues.get(edge.node());
2836 return value.value();
2838 LValue result = lowCell(edge);
2839 setStorage(edge.node(), result);
2843 LValue strictInt52ToInt32(Edge edge, LValue value)
2845 LValue result = m_out.castToInt32(value);
2847 noValue(), edge, SpecInt32,
2848 m_out.notEqual(m_out.signExt(result, m_out.int64), value));
2849 setInt32(edge.node(), result);
2853 LValue strictInt52ToDouble(Edge edge, LValue value)
2855 LValue result = m_out.intToDouble(value);
2856 setDouble(edge.node(), result);
2860 LValue strictInt52ToJSValue(LValue value)
2862 LBasicBlock isInt32 = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isInt32 case"));
2863 LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isDouble case"));
2864 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue continuation"));
2866 Vector<ValueFromBlock, 2> results;
2868 LValue int32Value = m_out.castToInt32(value);
2870 m_out.equal(m_out.signExt(int32Value, m_out.int64), value),
2873 LBasicBlock lastNext = m_out.appendTo(isInt32, isDouble);
2875 results.append(m_out.anchor(boxInt32(int32Value)));
2876 m_out.jump(continuation);
2878 m_out.appendTo(isDouble, continuation);
2880 results.append(m_out.anchor(boxDouble(m_out.intToDouble(value))));
2881 m_out.jump(continuation);
2883 m_out.appendTo(continuation, lastNext);
2884 return m_out.phi(m_out.int64, results);
2887 LValue setInt52WithStrictValue(Node* node, LValue value, Int52Kind kind)
2891 setStrictInt52(node, value);
2895 value = strictInt52ToInt52(value);
2896 setInt52(node, value);
2900 RELEASE_ASSERT_NOT_REACHED();
2904 LValue strictInt52ToInt52(LValue value)
2906 return m_out.shl(value, m_out.constInt64(JSValue::int52ShiftAmount));
2909 LValue int52ToStrictInt52(LValue value)
2911 return m_out.aShr(value, m_out.constInt64(JSValue::int52ShiftAmount));
2914 LValue isNotInt32(LValue jsValue)
2916 return m_out.below(jsValue, m_tagTypeNumber);
2918 LValue unboxInt32(LValue jsValue)
2920 return m_out.castToInt32(jsValue);
2922 LValue boxInt32(LValue value)
2924 return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
2927 LValue isCellOrMisc(LValue jsValue)
2929 return m_out.testIsZero64(jsValue, m_tagTypeNumber);
2931 LValue unboxDouble(LValue jsValue)
2933 return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), m_out.doubleType);
2935 LValue boxDouble(LValue doubleValue)
2937 return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
2940 LValue isNotCell(LValue jsValue)
2942 return m_out.testNonZero64(jsValue, m_tagMask);
2945 LValue isNotBoolean(LValue jsValue)
2947 return m_out.testNonZero64(
2948 m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)),
2949 m_out.constInt64(~1));
2951 LValue unboxBoolean(LValue jsValue)
2953 // We want to use a cast that guarantees that LLVM knows that even the integer
2954 // value is just 0 or 1. But for now we do it the dumb way.
2955 return m_out.notZero64(m_out.bitAnd(jsValue, m_out.constInt64(1)));
2957 LValue boxBoolean(LValue value)
2959 return m_out.select(
2960 value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse));
2963 void speculate(Edge edge)
2965 switch (edge.useKind()) {
2969 case KnownNumberUse:
2970 ASSERT(!m_interpreter.needsTypeCheck(edge));
2973 speculateInt32(edge);
2976 speculateCell(edge);
2979 ASSERT(!m_interpreter.needsTypeCheck(edge));
2982 speculateObject(edge);
2984 case ObjectOrOtherUse:
2985 speculateObjectOrOther(edge);
2988 speculateString(edge);
2991 speculateRealNumber(edge);
2994 speculateNumber(edge);
2997 speculateBoolean(edge);
3000 dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
3001 RELEASE_ASSERT_NOT_REACHED();
3005 void speculate(Node*, Edge edge)
3010 void speculateInt32(Edge edge)
3015 void speculateCell(Edge edge)
3020 LValue isObject(LValue cell)
3022 return m_out.notEqual(
3023 m_out.loadPtr(cell, m_heaps.JSCell_structure),
3024 m_out.constIntPtr(vm().stringStructure.get()));
3027 LValue isNotString(LValue cell)
3029 return isObject(cell);
3032 LValue isString(LValue cell)
3035 m_out.loadPtr(cell, m_heaps.JSCell_structure),
3036 m_out.constIntPtr(vm().stringStructure.get()));
3039 LValue isNotObject(LValue cell)
3041 return isString(cell);
3044 LValue isArrayType(LValue cell, ArrayMode arrayMode)
3046 switch (arrayMode.type()) {
3049 case Array::Contiguous: {
3050 LValue indexingType = m_out.load8(
3051 m_out.loadPtr(cell, m_heaps.JSCell_structure),
3052 m_heaps.Structure_indexingType);
3054 switch (arrayMode.arrayClass()) {
3055 case Array::OriginalArray:
3056 RELEASE_ASSERT_NOT_REACHED();
3061 m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)),
3062 m_out.constInt8(IsArray | arrayMode.shapeMask()));
3066 m_out.bitAnd(indexingType, m_out.constInt8(IndexingShapeMask)),
3067 m_out.constInt8(arrayMode.shapeMask()));
3072 return hasClassInfo(cell, classInfoForType(arrayMode.typedArrayType()));
3076 LValue hasClassInfo(LValue cell, const ClassInfo* classInfo)
3080 m_out.loadPtr(cell, m_heaps.JSCell_structure),
3081 m_heaps.Structure_classInfo),
3082 m_out.constIntPtr(classInfo));
3085 void speculateObject(Edge edge, LValue cell)
3087 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
3090 void speculateObject(Edge edge)
3092 speculateObject(edge, lowCell(edge));
3095 void speculateObjectOrOther(Edge edge)
3097 if (!m_interpreter.needsTypeCheck(edge))
3100 LValue value = lowJSValue(edge);
3102 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case"));
3103 LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case"));
3104 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation"));
3106 m_out.branch(isNotCell(value), primitiveCase, cellCase);
3108 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
3111 jsValueValue(value), edge, (~SpecCell) | SpecObject,
3113 m_out.loadPtr(value, m_heaps.JSCell_structure),
3114 m_out.constIntPtr(vm().stringStructure.get())));
3116 m_out.jump(continuation);
3118 m_out.appendTo(primitiveCase, continuation);
3121 jsValueValue(value), edge, SpecCell | SpecOther,
3123 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
3124 m_out.constInt64(ValueNull)));
3126 m_out.jump(continuation);
3128 m_out.appendTo(continuation, lastNext);
3131 void speculateString(Edge edge, LValue cell)
3133 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString, isNotString(cell));
3136 void speculateString(Edge edge)
3138 speculateString(edge, lowCell(edge));
3141 void speculateNonNullObject(Edge edge, LValue cell)
3143 LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
3145 jsValueValue(cell), edge, SpecObject,
3146 m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())));
3147 if (masqueradesAsUndefinedWatchpointIfIsStillValid())
3151 BadType, jsValueValue(cell), edge.node(),
3153 m_out.load8(structure, m_heaps.Structure_typeInfoFlags),
3154 m_out.constInt8(MasqueradesAsUndefined)));
3157 void speculateNumber(Edge edge)
3159 // Do an early return here because lowDouble() can create a lot of control flow.
3160 if (!m_interpreter.needsTypeCheck(edge))
3166 void speculateRealNumber(Edge edge)
3168 // Do an early return here because lowDouble() can create a lot of control flow.
3169 if (!m_interpreter.needsTypeCheck(edge))
3172 LValue value = lowDouble(edge);
3174 doubleValue(value), edge, SpecFullRealNumber,
3175 m_out.doubleNotEqualOrUnordered(value, value));
3178 void speculateBoolean(Edge edge)
3183 bool masqueradesAsUndefinedWatchpointIsStillValid()
3185 return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin);
3188 bool masqueradesAsUndefinedWatchpointIfIsStillValid()
3190 if (!masqueradesAsUndefinedWatchpointIsStillValid())
3193 // FIXME: Implement masquerades-as-undefined watchpoints.
3194 // https://bugs.webkit.org/show_bug.cgi?id=113647
3198 enum ExceptionCheckMode { NoExceptions, CheckExceptions };
3200 LValue vmCall(LValue function, ExceptionCheckMode mode = CheckExceptions)
3203 LValue result = m_out.call(function);
3207 LValue vmCall(LValue function, LValue arg1, ExceptionCheckMode mode = CheckExceptions)
3210 LValue result = m_out.call(function, arg1);
3214 LValue vmCall(LValue function, LValue arg1, LValue arg2, ExceptionCheckMode mode = CheckExceptions)
3217 LValue result = m_out.call(function, arg1, arg2);
3221 LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, ExceptionCheckMode mode = CheckExceptions)
3224 LValue result = m_out.call(function, arg1, arg2, arg3);
3228 LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, ExceptionCheckMode mode = CheckExceptions)
3231 LValue result = m_out.call(function, arg1, arg2, arg3, arg4);
3236 void callPreflight(CodeOrigin codeOrigin)
3240 CallFrame::Location::encodeAsCodeOriginIndex(
3241 m_ftlState.jitCode->common.addCodeOrigin(codeOrigin))),
3242 tagFor(JSStack::ArgumentCount));
3244 void callPreflight()
3246 callPreflight(m_node->codeOrigin);
3249 void callCheck(ExceptionCheckMode mode = CheckExceptions)
3251 if (mode == NoExceptions)
3254 LBasicBlock didHaveException = FTL_NEW_BLOCK(m_out, ("Did have exception"));
3255 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation"));
3258 m_out.notZero64(m_out.load64(m_out.absolute(vm().addressOfException()))),
3259 didHaveException, continuation);
3261 LBasicBlock lastNext = m_out.appendTo(didHaveException, continuation);
3262 // FIXME: Handle exceptions. https://bugs.webkit.org/show_bug.cgi?id=113622
3265 m_out.appendTo(continuation, lastNext);
3268 bool isLive(Node* node)
3270 return m_live.contains(node);
3275 ASSERT(edge->hasResult());
3276 if (!edge.doesKill())
3278 m_live.remove(edge.node());
3281 // Wrapper used only for DFG_NODE_DO_TO_CHILDREN
3282 void use(Node*, Edge edge)
3287 LBasicBlock lowBlock(BasicBlock* block)
3289 return m_blocks.get(block);
3292 void initializeOSRExitStateForBlock()
3294 for (unsigned i = m_valueSources.size(); i--;) {
3295 FlushFormat format = m_highBlock->ssa->flushFormatAtHead[i];
3298 // Must consider available nodes instead.
3299 Node* node = m_highBlock->ssa->availabilityAtHead[i];
3301 m_valueSources[i] = ValueSource(SourceIsDead);
3305 m_valueSources[i] = ValueSource(node);
3310 m_valueSources[i] = ValueSource(Int32InJSStack);
3314 m_valueSources[i] = ValueSource(Int52InJSStack);
3318 m_valueSources[i] = ValueSource(DoubleInJSStack);
3322 case FlushedBoolean:
3323 case FlushedJSValue:
3324 m_valueSources[i] = ValueSource(ValueInJSStack);
3331 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,
3332 SpeculationDirection direction, FormattedValue recovery)
3334 if (Options::ftlTrapsOnOSRExit()) {
3335 LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
3336 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
3338 m_out.branch(failCondition, failCase, continuation);
3340 LBasicBlock lastNext = m_out.appendTo(failCase, continuation);
3342 m_out.unreachable();
3344 m_out.appendTo(continuation, lastNext);
3348 if (verboseCompilationEnabled())
3349 dataLog(" OSR exit with value sources: ", m_valueSources, "\n");
3351 ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.osrExit.size());
3352 unsigned index = m_ftlState.osrExit.size();
3354 m_ftlState.jitCode->osrExit.append(OSRExit(
3355 kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
3356 m_codeOriginForExitTarget, m_codeOriginForExitProfile, m_lastSetOperand.offset(),
3357 m_valueSources.numberOfArguments(), m_valueSources.numberOfLocals()));
3358 m_ftlState.osrExit.append(OSRExitCompilationInfo());
3360 OSRExit& exit = m_ftlState.jitCode->osrExit.last();
3361 OSRExitCompilationInfo& info = m_ftlState.osrExit.last();
3363 LBasicBlock lastNext = 0;
3364 LBasicBlock continuation = 0;
3366 if (!Options::useLLVMOSRExitIntrinsic()) {
3367 LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
3368 continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
3370 m_out.branch(failCondition, failCase, continuation);
3372 m_out.appendTo(m_prologue);
3373 info.m_thunkAddress = buildAlloca(m_out.m_builder, m_out.intPtr);
3375 lastNext = m_out.appendTo(failCase, continuation);
3378 if (Options::ftlOSRExitOmitsMarshalling()) {
3381 m_out.get(info.m_thunkAddress),
3382 pointerType(functionType(m_out.voidType))));
3384 emitOSRExitCall(failCondition, index, exit, info, lowValue, direction, recovery);
3386 if (!Options::useLLVMOSRExitIntrinsic()) {
3387 m_out.unreachable();
3389 m_out.appendTo(continuation, lastNext);
3391 m_exitThunkGenerator.emitThunk(index);
3395 void emitOSRExitCall(
3396 LValue failCondition, unsigned index, OSRExit& exit, OSRExitCompilationInfo& info,
3397 FormattedValue lowValue, SpeculationDirection direction, FormattedValue recovery)
3399 ExitArgumentList arguments;
3401 if (Options::useLLVMOSRExitIntrinsic()) {
3402 arguments.append(failCondition);
3403 arguments.append(m_out.constInt32(index));
3406 arguments.append(m_callFrame);
3408 arguments.append(lowValue.value());
3410 for (unsigned i = 0; i < exit.m_values.size(); ++i) {
3411 ValueSource source = m_valueSources[i];
3413 switch (source.kind()) {
3414 case ValueInJSStack:
3415 exit.m_values[i] = ExitValue::inJSStack();
3417 case Int32InJSStack:
3418 exit.m_values[i] = ExitValue::inJSStackAsInt32();
3420 case Int52InJSStack:
3421 exit.m_values[i] = ExitValue::inJSStackAsInt52();
3423 case DoubleInJSStack:
3424 exit.m_values[i] = ExitValue::inJSStackAsDouble();
3427 exit.m_values[i] = ExitValue::dead();
3430 addExitArgumentForNode(exit, arguments, i, source.node());
3433 RELEASE_ASSERT_NOT_REACHED();
3438 if (verboseCompilationEnabled())
3439 dataLog(" Exit values: ", exit.m_values, "\n");
3441 if (direction == ForwardSpeculation) {
3443 exit.convertToForward(m_highBlock, m_node, m_nodeIndex, recovery, arguments);
3446 // So, the really lame thing here is that we have to build an LLVM function type.
3448 Vector<LType, 16> argumentTypes;
3449 for (unsigned i = 0; i < arguments.size(); ++i)
3450 argumentTypes.append(typeOf(arguments[i]));
3452 if (Options::useLLVMOSRExitIntrinsic()) {
3453 m_out.call(m_out.osrExitIntrinsic(), arguments);
3459 m_out.get(info.m_thunkAddress),
3460 pointerType(functionType(m_out.voidType, argumentTypes))),
3464 void addExitArgumentForNode(
3465 OSRExit& exit, ExitArgumentList& arguments, unsigned index, Node* node)
3467 ASSERT(node->shouldGenerate());
3468 ASSERT(node->hasResult());
3470 if (tryToSetConstantExitArgument(exit, index, node))
3473 if (!isLive(node)) {
3476 if (permitsOSRBackwardRewiring(node->op())) {
3477 node = node->child1().node();
3478 if (tryToSetConstantExitArgument(exit, index, node))
3486 unsigned bestScore = 0;
3488 HashSet<Node*>::iterator iter = m_live.begin();
3489 HashSet<Node*>::iterator end = m_live.end();
3490 for (; iter != end; ++iter) {
3491 Node* candidate = *iter;
3492 if (candidate->flags() & NodeHasVarArgs)
3494 if (!candidate->child1())
3496 if (candidate->child1() != node)
3498 unsigned myScore = forwardRewiringSelectionScore(candidate->op());
3499 if (myScore <= bestScore)
3501 bestNode = candidate;
3502 bestScore = myScore;
3506 ASSERT(isLive(bestNode));
3513 exit.m_values[index] = ExitValue::dead();
3518 ASSERT(isLive(node));
3520 LoweredNodeValue value = m_int32Values.get(node);
3521 if (isValid(value)) {
3522 addExitArgument(exit, arguments, index, ValueFormatInt32, value.value());
3526 value = m_int52Values.get(node);
3527 if (isValid(value)) {
3528 addExitArgument(exit, arguments, index, ValueFormatInt52, value.value());
3532 value = m_strictInt52Values.get(node);
3533 if (isValid(value)) {
3534 addExitArgument(exit, arguments, index, ValueFormatStrictInt52, value.value());
3538 value = m_booleanValues.get(node);
3539 if (isValid(value)) {
3540 addExitArgument(exit, arguments, index, ValueFormatBoolean, value.value());
3544 value = m_jsValueValues.get(node);
3545 if (isValid(value)) {
3546 addExitArgument(exit, arguments, index, ValueFormatJSValue, value.value());
3550 value = m_doubleValues.get(node);
3551 if (isValid(value)) {
3552 addExitArgument(exit, arguments, index, ValueFormatDouble, value.value());
3556 dataLog("Cannot find value for node: ", node, "\n");
3557 RELEASE_ASSERT_NOT_REACHED();
3560 bool tryToSetConstantExitArgument(OSRExit& exit, unsigned index, Node* node)
3565 switch (node->op()) {
3567 case WeakJSConstant:
3568 exit.m_values[index] = ExitValue::constant(m_graph.valueOfJSConstant(node));
3570 case PhantomArguments:
3571 // FIXME: implement PhantomArguments.
3572 // https://bugs.webkit.org/show_bug.cgi?id=113986
3573 RELEASE_ASSERT_NOT_REACHED();
3580 void addExitArgument(
3581 OSRExit& exit, ExitArgumentList& arguments, unsigned index, ValueFormat format,
3584 exit.m_values[index] = ExitValue::exitArgument(ExitArgument(format, arguments.size()));
3585 arguments.append(value);
3588 void linkOSRExitsAndCompleteInitializationBlocks()
3590 MacroAssemblerCodeRef osrExitThunk =
3591 vm().getCTIStub(osrExitGenerationThunkGenerator);
3592 CodeLocationLabel target = CodeLocationLabel(osrExitThunk.code());
3594 m_out.appendTo(m_prologue);
3595 m_out.jump(m_initialization);
3597 m_out.appendTo(m_initialization);
3599 if (m_exitThunkGenerator.didThings()) {
3600 OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(
3601 vm(), &m_exitThunkGenerator, m_ftlState.graph.m_codeBlock,
3602 JITCompilationMustSucceed));
3604 ASSERT(m_ftlState.osrExit.size() == m_ftlState.jitCode->osrExit.size());
3606 for (unsigned i = 0; i < m_ftlState.osrExit.size(); ++i) {
3607 OSRExitCompilationInfo& info = m_ftlState.osrExit[i];
3608 OSRExit& exit = m_ftlState.jitCode->osrExit[i];
3610 linkBuffer->link(info.m_thunkJump, target);