1/*
2 * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#include "config.h"
27#include "DFGSSALoweringPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGBasicBlockInlines.h"
32#include "DFGGraph.h"
33#include "DFGInsertionSet.h"
34#include "DFGPhase.h"
35#include "JSCInlines.h"
36
37namespace JSC { namespace DFG {
38
39class SSALoweringPhase : public Phase {
40 static constexpr bool verbose = false;
41
42public:
43 SSALoweringPhase(Graph& graph)
44 : Phase(graph, "SSA lowering")
45 , m_insertionSet(graph)
46 {
47 }
48
49 bool run()
50 {
51 RELEASE_ASSERT(m_graph.m_form == SSA);
52
53 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
54 m_block = m_graph.block(blockIndex);
55 if (!m_block)
56 continue;
57 for (m_nodeIndex = 0; m_nodeIndex < m_block->size(); ++m_nodeIndex) {
58 m_node = m_block->at(m_nodeIndex);
59 handleNode();
60 }
61 m_insertionSet.execute(m_block);
62 }
63
64 return true;
65 }
66
67private:
68 void handleNode()
69 {
70 switch (m_node->op()) {
71 case AtomicsAdd:
72 case AtomicsAnd:
73 case AtomicsCompareExchange:
74 case AtomicsExchange:
75 case AtomicsLoad:
76 case AtomicsOr:
77 case AtomicsStore:
78 case AtomicsSub:
79 case AtomicsXor:
80 case HasIndexedProperty:
81 lowerBoundsCheck(m_graph.child(m_node, 0), m_graph.child(m_node, 1), m_graph.child(m_node, 2));
82 break;
83
84 case GetByVal: {
85 lowerBoundsCheck(m_graph.varArgChild(m_node, 0), m_graph.varArgChild(m_node, 1), m_graph.varArgChild(m_node, 2));
86 break;
87 }
88
89 case PutByVal:
90 case PutByValDirect: {
91 Edge base = m_graph.varArgChild(m_node, 0);
92 Edge index = m_graph.varArgChild(m_node, 1);
93 Edge storage = m_graph.varArgChild(m_node, 3);
94 if (lowerBoundsCheck(base, index, storage))
95 break;
96
97 if (m_node->arrayMode().typedArrayType() != NotTypedArray && m_node->arrayMode().isOutOfBounds()) {
98 Node* length = m_insertionSet.insertNode(
99 m_nodeIndex, SpecInt32Only, GetArrayLength, m_node->origin,
100 OpInfo(m_node->arrayMode().asWord()), base, storage);
101
102 m_graph.varArgChild(m_node, 4) = Edge(length, KnownInt32Use);
103 break;
104 }
105 break;
106 }
107
108 default:
109 break;
110 }
111 }
112
113 bool lowerBoundsCheck(Edge base, Edge index, Edge storage)
114 {
115 if (!m_node->arrayMode().permitsBoundsCheckLowering())
116 return false;
117
118 if (!m_node->arrayMode().lengthNeedsStorage())
119 storage = Edge();
120
121 NodeType op = GetArrayLength;
122 switch (m_node->arrayMode().type()) {
123 case Array::ArrayStorage:
124 case Array::SlowPutArrayStorage:
125 op = GetVectorLength;
126 break;
127 case Array::String:
128 // When we need to support this, it will require additional code since base's useKind is KnownStringUse.
129 DFG_CRASH(m_graph, m_node, "Array::String's base.useKind() is KnownStringUse");
130 break;
131 default:
132 break;
133 }
134
135 Node* length = m_insertionSet.insertNode(
136 m_nodeIndex, SpecInt32Only, op, m_node->origin,
137 OpInfo(m_node->arrayMode().asWord()), Edge(base.node(), KnownCellUse), storage);
138 Node* checkInBounds = m_insertionSet.insertNode(
139 m_nodeIndex, SpecInt32Only, CheckInBounds, m_node->origin,
140 index, Edge(length, KnownInt32Use));
141
142 AdjacencyList adjacencyList = m_graph.copyVarargChildren(m_node);
143 m_graph.m_varArgChildren.append(Edge(checkInBounds, UntypedUse));
144 adjacencyList.setNumChildren(adjacencyList.numChildren() + 1);
145 m_node->children = adjacencyList;
146 return true;
147 }
148
149 InsertionSet m_insertionSet;
150 BasicBlock* m_block;
151 unsigned m_nodeIndex;
152 Node* m_node;
153};
154
155bool performSSALowering(Graph& graph)
156{
157 return runPhase<SSALoweringPhase>(graph);
158}
159
160} } // namespace JSC::DFG
161
162#endif // ENABLE(DFG_JIT)
163
164