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 | |
37 | namespace JSC { namespace DFG { |
38 | |
39 | class SSALoweringPhase : public Phase { |
40 | static constexpr bool verbose = false; |
41 | |
42 | public: |
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 | |
67 | private: |
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 | |
155 | bool performSSALowering(Graph& graph) |
156 | { |
157 | return runPhase<SSALoweringPhase>(graph); |
158 | } |
159 | |
160 | } } // namespace JSC::DFG |
161 | |
162 | #endif // ENABLE(DFG_JIT) |
163 | |
164 | |