]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 A |
1 | /* |
2 | * Copyright (C) 2012 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 "DFGFixupPhase.h" | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "DFGGraph.h" | |
32 | #include "DFGInsertionSet.h" | |
33 | #include "DFGPhase.h" | |
34 | ||
35 | namespace JSC { namespace DFG { | |
36 | ||
37 | class FixupPhase : public Phase { | |
38 | public: | |
39 | FixupPhase(Graph& graph) | |
40 | : Phase(graph, "fixup") | |
41 | { | |
42 | } | |
43 | ||
44 | void run() | |
45 | { | |
46 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) | |
47 | fixupBlock(m_graph.m_blocks[blockIndex].get()); | |
48 | } | |
49 | ||
50 | private: | |
51 | void fixupBlock(BasicBlock* block) | |
52 | { | |
53 | for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) { | |
54 | m_compileIndex = block->at(m_indexInBlock); | |
55 | fixupNode(m_graph[m_compileIndex]); | |
56 | } | |
57 | m_insertionSet.execute(*block); | |
58 | } | |
59 | ||
60 | void fixupNode(Node& node) | |
61 | { | |
62 | if (!node.shouldGenerate()) | |
63 | return; | |
64 | ||
65 | NodeType op = node.op(); | |
66 | ||
67 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) | |
68 | dataLog(" %s @%u: ", Graph::opName(op), m_compileIndex); | |
69 | #endif | |
70 | ||
71 | switch (op) { | |
72 | case GetById: { | |
73 | if (!isInt32Prediction(m_graph[m_compileIndex].prediction())) | |
74 | break; | |
75 | if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length) | |
76 | break; | |
77 | bool isArray = isArrayPrediction(m_graph[node.child1()].prediction()); | |
78 | bool isString = isStringPrediction(m_graph[node.child1()].prediction()); | |
79 | bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array(); | |
80 | bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); | |
81 | bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); | |
82 | bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array(); | |
83 | bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray(); | |
84 | bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array(); | |
85 | bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array(); | |
86 | bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array(); | |
87 | bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array(); | |
88 | if (!isArray && !isString && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint8ClampedArray && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array) | |
89 | break; | |
90 | ||
91 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) | |
92 | dataLog(" @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength"); | |
93 | #endif | |
94 | if (isArray) | |
95 | node.setOp(GetArrayLength); | |
96 | else if (isString) | |
97 | node.setOp(GetStringLength); | |
98 | else if (isInt8Array) | |
99 | node.setOp(GetInt8ArrayLength); | |
100 | else if (isInt16Array) | |
101 | node.setOp(GetInt16ArrayLength); | |
102 | else if (isInt32Array) | |
103 | node.setOp(GetInt32ArrayLength); | |
104 | else if (isUint8Array) | |
105 | node.setOp(GetUint8ArrayLength); | |
106 | else if (isUint8ClampedArray) | |
107 | node.setOp(GetUint8ClampedArrayLength); | |
108 | else if (isUint16Array) | |
109 | node.setOp(GetUint16ArrayLength); | |
110 | else if (isUint32Array) | |
111 | node.setOp(GetUint32ArrayLength); | |
112 | else if (isFloat32Array) | |
113 | node.setOp(GetFloat32ArrayLength); | |
114 | else if (isFloat64Array) | |
115 | node.setOp(GetFloat64ArrayLength); | |
116 | else | |
117 | ASSERT_NOT_REACHED(); | |
118 | // No longer MustGenerate | |
119 | ASSERT(node.flags() & NodeMustGenerate); | |
120 | node.clearFlags(NodeMustGenerate); | |
121 | m_graph.deref(m_compileIndex); | |
122 | break; | |
123 | } | |
124 | case GetIndexedPropertyStorage: { | |
125 | PredictedType basePrediction = m_graph[node.child2()].prediction(); | |
126 | if (!(basePrediction & PredictInt32) && basePrediction) { | |
127 | node.setOpAndDefaultFlags(Nop); | |
128 | m_graph.clearAndDerefChild1(node); | |
129 | m_graph.clearAndDerefChild2(node); | |
130 | m_graph.clearAndDerefChild3(node); | |
131 | node.setRefCount(0); | |
132 | } | |
133 | break; | |
134 | } | |
135 | case GetByVal: | |
136 | case StringCharAt: | |
137 | case StringCharCodeAt: { | |
138 | if (!!node.child3() && m_graph[node.child3()].op() == Nop) | |
139 | node.children.child3() = Edge(); | |
140 | break; | |
141 | } | |
142 | ||
143 | case ValueToInt32: { | |
144 | if (m_graph[node.child1()].shouldSpeculateNumber()) { | |
145 | node.clearFlags(NodeMustGenerate); | |
146 | m_graph.deref(m_compileIndex); | |
147 | } | |
148 | break; | |
149 | } | |
150 | ||
151 | case BitAnd: | |
152 | case BitOr: | |
153 | case BitXor: | |
154 | case BitRShift: | |
155 | case BitLShift: | |
156 | case BitURShift: { | |
157 | fixIntEdge(node.children.child1()); | |
158 | fixIntEdge(node.children.child2()); | |
159 | break; | |
160 | } | |
161 | ||
162 | case CompareEq: | |
163 | case CompareLess: | |
164 | case CompareLessEq: | |
165 | case CompareGreater: | |
166 | case CompareGreaterEq: | |
167 | case CompareStrictEq: { | |
168 | if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])) | |
169 | break; | |
170 | if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) | |
171 | break; | |
172 | fixDoubleEdge(0); | |
173 | fixDoubleEdge(1); | |
174 | break; | |
175 | } | |
176 | ||
177 | case LogicalNot: { | |
178 | if (m_graph[node.child1()].shouldSpeculateInteger()) | |
179 | break; | |
180 | if (!m_graph[node.child1()].shouldSpeculateNumber()) | |
181 | break; | |
182 | fixDoubleEdge(0); | |
183 | break; | |
184 | } | |
185 | ||
186 | case Branch: { | |
187 | if (!m_graph[node.child1()].shouldSpeculateInteger() | |
188 | && m_graph[node.child1()].shouldSpeculateNumber()) | |
189 | fixDoubleEdge(0); | |
190 | ||
191 | Node& myNode = m_graph[m_compileIndex]; // reload because the graph may have changed | |
192 | Edge logicalNotEdge = myNode.child1(); | |
193 | Node& logicalNot = m_graph[logicalNotEdge]; | |
194 | if (logicalNot.op() == LogicalNot | |
195 | && logicalNot.adjustedRefCount() == 1) { | |
196 | Edge newChildEdge = logicalNot.child1(); | |
197 | if (m_graph[newChildEdge].hasBooleanResult()) { | |
198 | m_graph.ref(newChildEdge); | |
199 | m_graph.deref(logicalNotEdge); | |
200 | myNode.children.setChild1(newChildEdge); | |
201 | ||
202 | BlockIndex toBeTaken = myNode.notTakenBlockIndex(); | |
203 | BlockIndex toBeNotTaken = myNode.takenBlockIndex(); | |
204 | myNode.setTakenBlockIndex(toBeTaken); | |
205 | myNode.setNotTakenBlockIndex(toBeNotTaken); | |
206 | } | |
207 | } | |
208 | break; | |
209 | } | |
210 | ||
211 | case SetLocal: { | |
212 | if (m_graph.isCaptured(node.local())) | |
213 | break; | |
214 | if (!node.variableAccessData()->shouldUseDoubleFormat()) | |
215 | break; | |
216 | fixDoubleEdge(0); | |
217 | break; | |
218 | } | |
219 | ||
220 | case ArithAdd: | |
221 | case ValueAdd: { | |
222 | if (m_graph.addShouldSpeculateInteger(node)) | |
223 | break; | |
224 | if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) | |
225 | break; | |
226 | fixDoubleEdge(0); | |
227 | fixDoubleEdge(1); | |
228 | break; | |
229 | } | |
230 | ||
231 | case ArithSub: { | |
232 | if (m_graph.addShouldSpeculateInteger(node) | |
233 | && node.canSpeculateInteger()) | |
234 | break; | |
235 | fixDoubleEdge(0); | |
236 | fixDoubleEdge(1); | |
237 | break; | |
238 | } | |
239 | ||
240 | case ArithNegate: { | |
241 | if (m_graph.negateShouldSpeculateInteger(node)) | |
242 | break; | |
243 | fixDoubleEdge(0); | |
244 | break; | |
245 | } | |
246 | ||
247 | case ArithMin: | |
248 | case ArithMax: | |
249 | case ArithMul: | |
250 | case ArithMod: { | |
251 | if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) | |
252 | && node.canSpeculateInteger()) | |
253 | break; | |
254 | fixDoubleEdge(0); | |
255 | fixDoubleEdge(1); | |
256 | break; | |
257 | } | |
258 | ||
259 | case ArithDiv: { | |
260 | if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]) | |
261 | && node.canSpeculateInteger()) { | |
262 | if (isX86()) | |
263 | break; | |
264 | fixDoubleEdge(0); | |
265 | fixDoubleEdge(1); | |
266 | ||
267 | Node& oldDivision = m_graph[m_compileIndex]; | |
268 | ||
269 | Node newDivision = oldDivision; | |
270 | newDivision.setRefCount(2); | |
271 | newDivision.predict(PredictDouble); | |
272 | NodeIndex newDivisionIndex = m_graph.size(); | |
273 | ||
274 | oldDivision.setOp(DoubleAsInt32); | |
275 | oldDivision.children.initialize(Edge(newDivisionIndex, DoubleUse), Edge(), Edge()); | |
276 | ||
277 | m_graph.append(newDivision); | |
278 | m_insertionSet.append(m_indexInBlock, newDivisionIndex); | |
279 | ||
280 | break; | |
281 | } | |
282 | fixDoubleEdge(0); | |
283 | fixDoubleEdge(1); | |
284 | break; | |
285 | } | |
286 | ||
287 | case ArithAbs: { | |
288 | if (m_graph[node.child1()].shouldSpeculateInteger() | |
289 | && node.canSpeculateInteger()) | |
290 | break; | |
291 | fixDoubleEdge(0); | |
292 | break; | |
293 | } | |
294 | ||
295 | case ArithSqrt: { | |
296 | fixDoubleEdge(0); | |
297 | break; | |
298 | } | |
299 | ||
300 | case PutByVal: { | |
301 | if (!m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) | |
302 | break; | |
303 | if (!m_graph[node.child2()].shouldSpeculateInteger()) | |
304 | break; | |
305 | if (isActionableIntMutableArrayPrediction(m_graph[node.child1()].prediction())) { | |
306 | if (m_graph[node.child3()].isConstant()) | |
307 | break; | |
308 | if (m_graph[node.child3()].shouldSpeculateInteger()) | |
309 | break; | |
310 | fixDoubleEdge(2); | |
311 | break; | |
312 | } | |
313 | if (isActionableFloatMutableArrayPrediction(m_graph[node.child1()].prediction())) { | |
314 | fixDoubleEdge(2); | |
315 | break; | |
316 | } | |
317 | break; | |
318 | } | |
319 | ||
320 | default: | |
321 | break; | |
322 | } | |
323 | ||
324 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) | |
325 | if (!(node.flags() & NodeHasVarArgs)) { | |
326 | dataLog("new children: "); | |
327 | node.dumpChildren(WTF::dataFile()); | |
328 | } | |
329 | dataLog("\n"); | |
330 | #endif | |
331 | } | |
332 | ||
333 | void fixIntEdge(Edge& edge) | |
334 | { | |
335 | Node& node = m_graph[edge]; | |
336 | if (node.op() != ValueToInt32) | |
337 | return; | |
338 | ||
339 | if (!m_graph[node.child1()].shouldSpeculateInteger()) | |
340 | return; | |
341 | ||
342 | Edge oldEdge = edge; | |
343 | Edge newEdge = node.child1(); | |
344 | ||
345 | m_graph.ref(newEdge); | |
346 | m_graph.deref(oldEdge); | |
347 | ||
348 | edge = newEdge; | |
349 | } | |
350 | ||
351 | void fixDoubleEdge(unsigned childIndex) | |
352 | { | |
353 | Node& source = m_graph[m_compileIndex]; | |
354 | Edge& edge = source.children.child(childIndex); | |
355 | ||
356 | if (!m_graph[edge].shouldSpeculateInteger()) { | |
357 | edge.setUseKind(DoubleUse); | |
358 | return; | |
359 | } | |
360 | ||
361 | NodeIndex resultIndex = (NodeIndex)m_graph.size(); | |
362 | ||
363 | #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) | |
364 | dataLog("(replacing @%u->@%u with @%u->@%u) ", | |
365 | m_compileIndex, edge.index(), m_compileIndex, resultIndex); | |
366 | #endif | |
367 | ||
368 | // Fix the edge up here because it's a reference that will be clobbered by | |
369 | // the append() below. | |
370 | NodeIndex oldIndex = edge.index(); | |
371 | edge = Edge(resultIndex, DoubleUse); | |
372 | ||
373 | m_graph.append(Node(Int32ToDouble, source.codeOrigin, oldIndex)); | |
374 | m_insertionSet.append(m_indexInBlock, resultIndex); | |
375 | ||
376 | Node& int32ToDouble = m_graph[resultIndex]; | |
377 | int32ToDouble.predict(PredictDouble); | |
378 | int32ToDouble.ref(); | |
379 | } | |
380 | ||
381 | unsigned m_indexInBlock; | |
382 | NodeIndex m_compileIndex; | |
383 | InsertionSet<NodeIndex> m_insertionSet; | |
384 | }; | |
385 | ||
386 | void performFixup(Graph& graph) | |
387 | { | |
388 | runPhase<FixupPhase>(graph); | |
389 | } | |
390 | ||
391 | } } // namespace JSC::DFG | |
392 | ||
393 | #endif // ENABLE(DFG_JIT) | |
394 |