- Source/JavaScriptCore/ChangeLog +26 lines
Lines 1-3 Source/JavaScriptCore/ChangeLog_sec1
1
2014-01-07  Filip Pizlo  <fpizlo@apple.com>
2
3
        DFG fixup phase should be responsible for inserting ValueToInt32's as needed and it should use Phantom to keep the original values alive in case of OSR exit
4
        https://bugs.webkit.org/show_bug.cgi?id=126600
5
6
        Reviewed by NOBODY (OOPS!).
7
        
8
        This fixes an embarrassing OSR exit liveness bug. It also simplifies the code. We were
9
        already using FixupPhase as the place where conversion nodes get inserted. ValueToInt32
10
        was the only exception to that rule, and that was one of the reasons why we had this bug.
11
12
        * dfg/DFGBackwardsPropagationPhase.cpp:
13
        (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
14
        (JSC::DFG::BackwardsPropagationPhase::propagate):
15
        * dfg/DFGByteCodeParser.cpp:
16
        (JSC::DFG::ByteCodeParser::handleIntrinsic):
17
        (JSC::DFG::ByteCodeParser::parseBlock):
18
        * dfg/DFGFixupPhase.cpp:
19
        (JSC::DFG::FixupPhase::fixupNode):
20
        (JSC::DFG::FixupPhase::fixIntEdge):
21
        (JSC::DFG::FixupPhase::fixBinaryIntEdges):
22
        * dfg/DFGPredictionPropagationPhase.cpp:
23
        (JSC::DFG::PredictionPropagationPhase::propagate):
24
        * tests/stress/bit-op-value-to-int32-input-liveness.js: Added.
25
        (foo):
26
1
2014-01-07  Mark Hahnenberg  <mhahnenberg@apple.com>
27
2014-01-07  Mark Hahnenberg  <mhahnenberg@apple.com>
2
28
3
        Repatch write barrier slow path call doesn't align the stack in the presence of saved registers
29
        Repatch write barrier slow path call doesn't align the stack in the presence of saved registers
- Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp -9 / +1 lines
Lines 114-121 private: Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp_sec1
114
            
114
            
115
        case BitOr:
115
        case BitOr:
116
        case BitXor:
116
        case BitXor:
117
        case BitLShift:
117
        case BitLShift: {
118
        case ValueToInt32: {
119
            return power > 31;
118
            return power > 31;
120
        }
119
        }
121
            
120
            
Lines 205-217 private: Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp_sec2
205
            break;
204
            break;
206
        }
205
        }
207
            
206
            
208
        case ValueToInt32: {
209
            flags |= NodeBytecodeUsesAsInt;
210
            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
211
            node->child1()->mergeFlags(flags);
212
            break;
213
        }
214
            
215
        case StringCharCodeAt: {
207
        case StringCharCodeAt: {
216
            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
208
            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
217
            node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt);
209
            node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt);
- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp -49 / +25 lines
Lines 505-534 private: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec1
505
        flush(m_inlineStackTop);
505
        flush(m_inlineStackTop);
506
    }
506
    }
507
507
508
    // Get an operand, and perform a ToInt32/ToNumber conversion on it.
509
    Node* getToInt32(int operand)
510
    {
511
        return toInt32(get(VirtualRegister(operand)));
512
    }
513
514
    // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
515
    Node* toInt32(Node* node)
516
    {
517
        if (node->hasInt32Result())
518
            return node;
519
520
        // Check for numeric constants boxed as JSValues.
521
        if (canFold(node)) {
522
            JSValue v = valueOfJSConstant(node);
523
            if (v.isInt32())
524
                return getJSConstant(node->constantNumber());
525
            if (v.isNumber())
526
                return getJSConstantForValue(JSValue(JSC::toInt32(v.asNumber())));
527
        }
528
529
        return addToGraph(ValueToInt32, node);
530
    }
531
532
    // NOTE: Only use this to construct constants that arise from non-speculative
508
    // NOTE: Only use this to construct constants that arise from non-speculative
533
    // constant folding. I.e. creating constants using this if we had constant
509
    // constant folding. I.e. creating constants using this if we had constant
534
    // field inference would be a bad idea, since the bytecode parser's folding
510
    // field inference would be a bad idea, since the bytecode parser's folding
Lines 1577-1585 bool ByteCodeParser::handleIntrinsic(int Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec2
1577
        if (argumentCountIncludingThis != 2)
1553
        if (argumentCountIncludingThis != 2)
1578
            return false;
1554
            return false;
1579
1555
1580
        int thisOperand = virtualRegisterForArgument(0, registerOffset).offset();
1556
        VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
1581
        int indexOperand = virtualRegisterForArgument(1, registerOffset).offset();
1557
        VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
1582
        Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(VirtualRegister(thisOperand)), getToInt32(indexOperand));
1558
        Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(VirtualRegister(thisOperand)), get(indexOperand));
1583
1559
1584
        set(VirtualRegister(resultOperand), charCode);
1560
        set(VirtualRegister(resultOperand), charCode);
1585
        return true;
1561
        return true;
Lines 1589-1597 bool ByteCodeParser::handleIntrinsic(int Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec3
1589
        if (argumentCountIncludingThis != 2)
1565
        if (argumentCountIncludingThis != 2)
1590
            return false;
1566
            return false;
1591
1567
1592
        int thisOperand = virtualRegisterForArgument(0, registerOffset).offset();
1568
        VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
1593
        int indexOperand = virtualRegisterForArgument(1, registerOffset).offset();
1569
        VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
1594
        Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(VirtualRegister(thisOperand)), getToInt32(indexOperand));
1570
        Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(VirtualRegister(thisOperand)), get(indexOperand));
1595
1571
1596
        set(VirtualRegister(resultOperand), charCode);
1572
        set(VirtualRegister(resultOperand), charCode);
1597
        return true;
1573
        return true;
Lines 1600-1607 bool ByteCodeParser::handleIntrinsic(int Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec4
1600
        if (argumentCountIncludingThis != 2)
1576
        if (argumentCountIncludingThis != 2)
1601
            return false;
1577
            return false;
1602
1578
1603
        int indexOperand = virtualRegisterForArgument(1, registerOffset).offset();
1579
        VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
1604
        Node* charCode = addToGraph(StringFromCharCode, getToInt32(indexOperand));
1580
        Node* charCode = addToGraph(StringFromCharCode, get(indexOperand));
1605
1581
1606
        set(VirtualRegister(resultOperand), charCode);
1582
        set(VirtualRegister(resultOperand), charCode);
1607
1583
Lines 1631-1640 bool ByteCodeParser::handleIntrinsic(int Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec5
1631
    case IMulIntrinsic: {
1607
    case IMulIntrinsic: {
1632
        if (argumentCountIncludingThis != 3)
1608
        if (argumentCountIncludingThis != 3)
1633
            return false;
1609
            return false;
1634
        int leftOperand = virtualRegisterForArgument(1, registerOffset).offset();
1610
        VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset);
1635
        int rightOperand = virtualRegisterForArgument(2, registerOffset).offset();
1611
        VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset);
1636
        Node* left = getToInt32(leftOperand);
1612
        Node* left = get(leftOperand);
1637
        Node* right = getToInt32(rightOperand);
1613
        Node* right = get(rightOperand);
1638
        set(VirtualRegister(resultOperand), addToGraph(ArithIMul, left, right));
1614
        set(VirtualRegister(resultOperand), addToGraph(ArithIMul, left, right));
1639
        return true;
1615
        return true;
1640
    }
1616
    }
Lines 2053-2097 bool ByteCodeParser::parseBlock(unsigned Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec6
2053
        // === Bitwise operations ===
2029
        // === Bitwise operations ===
2054
2030
2055
        case op_bitand: {
2031
        case op_bitand: {
2056
            Node* op1 = getToInt32(currentInstruction[2].u.operand);
2032
            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
2057
            Node* op2 = getToInt32(currentInstruction[3].u.operand);
2033
            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
2058
            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitAnd, op1, op2));
2034
            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitAnd, op1, op2));
2059
            NEXT_OPCODE(op_bitand);
2035
            NEXT_OPCODE(op_bitand);
2060
        }
2036
        }
2061
2037
2062
        case op_bitor: {
2038
        case op_bitor: {
2063
            Node* op1 = getToInt32(currentInstruction[2].u.operand);
2039
            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
2064
            Node* op2 = getToInt32(currentInstruction[3].u.operand);
2040
            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
2065
            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitOr, op1, op2));
2041
            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitOr, op1, op2));
2066
            NEXT_OPCODE(op_bitor);
2042
            NEXT_OPCODE(op_bitor);
2067
        }
2043
        }
2068
2044
2069
        case op_bitxor: {
2045
        case op_bitxor: {
2070
            Node* op1 = getToInt32(currentInstruction[2].u.operand);
2046
            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
2071
            Node* op2 = getToInt32(currentInstruction[3].u.operand);
2047
            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
2072
            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitXor, op1, op2));
2048
            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitXor, op1, op2));
2073
            NEXT_OPCODE(op_bitxor);
2049
            NEXT_OPCODE(op_bitxor);
2074
        }
2050
        }
2075
2051
2076
        case op_rshift: {
2052
        case op_rshift: {
2077
            Node* op1 = getToInt32(currentInstruction[2].u.operand);
2053
            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
2078
            Node* op2 = getToInt32(currentInstruction[3].u.operand);
2054
            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
2079
            set(VirtualRegister(currentInstruction[1].u.operand),
2055
            set(VirtualRegister(currentInstruction[1].u.operand),
2080
                addToGraph(BitRShift, op1, op2));
2056
                addToGraph(BitRShift, op1, op2));
2081
            NEXT_OPCODE(op_rshift);
2057
            NEXT_OPCODE(op_rshift);
2082
        }
2058
        }
2083
2059
2084
        case op_lshift: {
2060
        case op_lshift: {
2085
            Node* op1 = getToInt32(currentInstruction[2].u.operand);
2061
            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
2086
            Node* op2 = getToInt32(currentInstruction[3].u.operand);
2062
            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
2087
            set(VirtualRegister(currentInstruction[1].u.operand),
2063
            set(VirtualRegister(currentInstruction[1].u.operand),
2088
                addToGraph(BitLShift, op1, op2));
2064
                addToGraph(BitLShift, op1, op2));
2089
            NEXT_OPCODE(op_lshift);
2065
            NEXT_OPCODE(op_lshift);
2090
        }
2066
        }
2091
2067
2092
        case op_urshift: {
2068
        case op_urshift: {
2093
            Node* op1 = getToInt32(currentInstruction[2].u.operand);
2069
            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
2094
            Node* op2 = getToInt32(currentInstruction[3].u.operand);
2070
            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
2095
            set(VirtualRegister(currentInstruction[1].u.operand),
2071
            set(VirtualRegister(currentInstruction[1].u.operand),
2096
                addToGraph(BitURShift, op1, op2));
2072
                addToGraph(BitURShift, op1, op2));
2097
            NEXT_OPCODE(op_urshift);
2073
            NEXT_OPCODE(op_urshift);
Lines 2099-2105 bool ByteCodeParser::parseBlock(unsigned Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp_sec7
2099
            
2075
            
2100
        case op_unsigned: {
2076
        case op_unsigned: {
2101
            set(VirtualRegister(currentInstruction[1].u.operand),
2077
            set(VirtualRegister(currentInstruction[1].u.operand),
2102
                makeSafe(addToGraph(UInt32ToNumber, getToInt32(currentInstruction[2].u.operand))));
2078
                makeSafe(addToGraph(UInt32ToNumber, get(VirtualRegister(currentInstruction[2].u.operand)))));
2103
            NEXT_OPCODE(op_unsigned);
2079
            NEXT_OPCODE(op_unsigned);
2104
        }
2080
        }
2105
2081
- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp -58 / +36 lines
Lines 94-117 private: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp_sec1
94
            return;
94
            return;
95
        }
95
        }
96
            
96
            
97
        case BitOr: {
98
            fixIntEdge(node->child1());
99
            fixIntEdge(node->child2());
100
            break;
101
        }
102
        case BitAnd:
97
        case BitAnd:
98
        case BitOr:
103
        case BitXor:
99
        case BitXor:
104
        case BitRShift:
100
        case BitRShift:
105
        case BitLShift:
101
        case BitLShift:
106
        case BitURShift: {
102
        case BitURShift: {
107
            fixIntEdge(node->child1());
103
            fixBinaryIntEdges();
108
            fixIntEdge(node->child2());
109
            break;
104
            break;
110
        }
105
        }
111
            
106
112
        case ArithIMul: {
107
        case ArithIMul: {
113
            fixIntEdge(node->child1());
108
            fixBinaryIntEdges();
114
            fixIntEdge(node->child2());
115
            node->setOp(ArithMul);
109
            node->setOp(ArithMul);
116
            node->setArithMode(Arith::Unchecked);
110
            node->setArithMode(Arith::Unchecked);
117
            node->child1().setUseKind(Int32Use);
111
            node->child1().setUseKind(Int32Use);
Lines 120-126 private: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp_sec2
120
        }
114
        }
121
            
115
            
122
        case UInt32ToNumber: {
116
        case UInt32ToNumber: {
123
            fixEdge<KnownInt32Use>(node->child1());
117
            fixIntEdge(node->child1());
124
            if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
118
            if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
125
                node->convertToIdentity();
119
                node->convertToIdentity();
126
            else if (nodeCanSpeculateInt32(node->arithNodeFlags()))
120
            else if (nodeCanSpeculateInt32(node->arithNodeFlags()))
Lines 130-171 private: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp_sec3
130
            break;
124
            break;
131
        }
125
        }
132
            
126
            
133
        case DoubleAsInt32: {
134
            RELEASE_ASSERT_NOT_REACHED();
135
            break;
136
        }
137
            
138
        case ValueToInt32: {
139
            if (node->child1()->shouldSpeculateInt32()) {
140
                fixEdge<Int32Use>(node->child1());
141
                node->setOpAndDefaultFlags(Identity);
142
                break;
143
            }
144
            
145
            if (node->child1()->shouldSpeculateMachineInt()) {
146
                fixEdge<MachineIntUse>(node->child1());
147
                break;
148
            }
149
            
150
            if (node->child1()->shouldSpeculateNumber()) {
151
                fixEdge<NumberUse>(node->child1());
152
                break;
153
            }
154
            
155
            if (node->child1()->shouldSpeculateBoolean()) {
156
                fixEdge<BooleanUse>(node->child1());
157
                break;
158
            }
159
            
160
            fixEdge<NotCellUse>(node->child1());
161
            break;
162
        }
163
            
164
        case Int32ToDouble: {
165
            RELEASE_ASSERT_NOT_REACHED();
166
            break;
167
        }
168
            
169
        case ValueAdd: {
127
        case ValueAdd: {
170
            if (attemptToMakeIntegerAdd(node)) {
128
            if (attemptToMakeIntegerAdd(node)) {
171
                node->setOp(ArithAdd);
129
                node->setOp(ArithAdd);
Lines 974-979 private: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp_sec4
974
        case CheckArray:
932
        case CheckArray:
975
        case CheckInBounds:
933
        case CheckInBounds:
976
        case ConstantStoragePointer:
934
        case ConstantStoragePointer:
935
        case DoubleAsInt32:
936
        case Int32ToDouble:
937
        case ValueToInt32:
977
            // These are just nodes that we don't currently expect to see during fixup.
938
            // These are just nodes that we don't currently expect to see during fixup.
978
            // If we ever wanted to insert them prior to fixup, then we just have to create
939
            // If we ever wanted to insert them prior to fixup, then we just have to create
979
            // fixup rules for them.
940
            // fixup rules for them.
Lines 1624-1646 private: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp_sec5
1624
        m_insertionSet.insert(indexInBlock, barrierNode);
1585
        m_insertionSet.insert(indexInBlock, barrierNode);
1625
    }
1586
    }
1626
1587
1627
    void fixIntEdge(Edge& edge)
1588
    bool fixIntEdge(Edge& edge)
1628
    {
1589
    {
1629
        Node* node = edge.node();
1590
        Node* node = edge.node();
1630
        if (node->op() != ValueToInt32) {
1591
        if (node->shouldSpeculateInt32()) {
1631
            fixEdge<KnownInt32Use>(edge);
1592
            fixEdge<Int32Use>(edge);
1632
            return;
1593
            return false;
1633
        }
1594
        }
1634
        
1595
        
1635
        Edge newEdge = node->child1();
1596
        UseKind useKind;
1597
        if (node->shouldSpeculateMachineInt())
1598
            useKind = MachineIntUse;
1599
        else if (node->shouldSpeculateNumber())
1600
            useKind = NumberUse;
1601
        else if (node->shouldSpeculateBoolean())
1602
            useKind = BooleanUse;
1603
        else
1604
            useKind = NotCellUse;
1605
        Node* newNode = m_insertionSet.insertNode(
1606
            m_indexInBlock, SpecInt32, ValueToInt32, m_currentNode->codeOrigin,
1607
            Edge(node, useKind));
1608
        observeUseKindOnNode(node, useKind);
1636
        
1609
        
1637
        if (newEdge.useKind() != Int32Use) {
1610
        edge = Edge(newNode, KnownInt32Use);
1638
            edge.setUseKind(KnownInt32Use);
1611
        return true;
1612
    }
1613
    
1614
    void fixBinaryIntEdges()
1615
    {
1616
        AdjacencyList children = m_currentNode->children;
1617
        bool needPhantom =
1618
            fixIntEdge(m_currentNode->child1()) | fixIntEdge(m_currentNode->child2());
1619
        if (!needPhantom)
1639
            return;
1620
            return;
1640
        }
1621
        m_insertionSet.insertNode(m_indexInBlock + 1, SpecNone, Phantom, m_currentNode->codeOrigin, children);
1641
        
1642
        ASSERT(newEdge->shouldSpeculateInt32());
1643
        edge = newEdge;
1644
    }
1622
    }
1645
    
1623
    
1646
    void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse)
1624
    void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse)
- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp -6 / +2 lines
Lines 168-178 private: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp_sec1
168
            break;
168
            break;
169
        }
169
        }
170
            
170
            
171
        case ValueToInt32: {
172
            changed |= setPrediction(SpecInt32);
173
            break;
174
        }
175
            
176
        case ArrayPop:
171
        case ArrayPop:
177
        case ArrayPush:
172
        case ArrayPush:
178
        case RegExpExec:
173
        case RegExpExec:
Lines 510-516 private: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp_sec2
510
        case InvalidationPoint:
505
        case InvalidationPoint:
511
        case Int52ToValue:
506
        case Int52ToValue:
512
        case Int52ToDouble:
507
        case Int52ToDouble:
513
        case CheckInBounds: {
508
        case CheckInBounds:
509
        case ValueToInt32: {
514
            // This node should never be visible at this stage of compilation. It is
510
            // This node should never be visible at this stage of compilation. It is
515
            // inserted by fixup(), which follows this phase.
511
            // inserted by fixup(), which follows this phase.
516
            RELEASE_ASSERT_NOT_REACHED();
512
            RELEASE_ASSERT_NOT_REACHED();
- Source/JavaScriptCore/tests/stress/bit-op-value-to-int32-input-liveness.js +20 lines
Line 0 Source/JavaScriptCore/tests/stress/bit-op-value-to-int32-input-liveness.js_sec1
1
function foo(a, b) {
2
    return a.f ^ b.f;
3
}
4
5
noInline(foo);
6
7
for (var i = 0; i < 100000; ++i) {
8
    var result = foo({f:5.5}, {f:6.5});
9
    if (result != 3)
10
        throw "Error: bad result: " + result;
11
}
12
13
var result = foo({f:"5.5"}, {f:6.5});
14
if (result != 3)
15
    throw "Error: bad result: " + result;
16
17
var result = foo({f:5.5}, {f:"6.5"});
18
if (result != 3)
19
    throw "Error: bad result: " + result;
20

Return to Bug 126600