source: webkit/trunk/Source/JavaScriptCore/dfg/DFGValueRepReductionPhase.cpp

Last change on this file was 260417, checked in by Adrian Perez de Castro, 5 years ago

Non-unified build fixes late February 2020 edition
https://bugs.webkit.org/show_bug.cgi?id=210767

Unreviewed build fix.

Source/JavaScriptCore:

  • dfg/DFGValueRepReductionPhase.cpp: Add missing JSCJSValueInlines.h header.
  • jit/JITCall.cpp: Add missing SlowPathCall.h header.
  • runtime/AggregateError.cpp: Add missing JSCJSValueInlines.h, JSCellInlines.h, and

JSGlobalObjectInlines.h headers.

  • runtime/AggregateErrorConstructor.cpp: Added missing JSCJSValueInlines.h, JSCellInlines.h,

and VMInlines.h headers.

  • runtime/AggregateErrorPrototype.cpp: Added missing AggregateError.h, IdentifierInlines.h,

JSCJSValueInlines.h, JSCellInlines.h, JSGlobalObjectInlines.h, and VMInlines.h headers.

  • runtime/Intrinsic.h: Added missing wtf/Optional.h header.

Source/WebCore:

No new tests needed.

  • css/MediaQueryListEvent.cpp: Add missing wtf/IsoMallocInlines.h header.
  • css/MediaQueryMatcher.cpp: Add missing MediaQueryListEvent.h header.
  • platform/graphics/FloatQuad.cpp: Add missing wtf/text/TextStream.h header.

Source/WebKit:

  • NetworkProcess/NetworkResourceLoadMap.h: Add missing wtf/Function.h header.
File size: 12.2 KB
Line 
1/*
2 * Copyright (C) 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 "DFGValueRepReductionPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGGraph.h"
32#include "DFGInsertionSet.h"
33#include "DFGPhase.h"
34#include "DFGPhiChildren.h"
35#include "JSCJSValueInlines.h"
36
37namespace JSC { namespace DFG {
38
39class ValueRepReductionPhase : public Phase {
40 static constexpr bool verbose = false;
41
42public:
43 ValueRepReductionPhase(Graph& graph)
44 : Phase(graph, "ValueRep reduction")
45 , m_insertionSet(graph)
46 {
47 }
48
49 bool run()
50 {
51 ASSERT(m_graph.m_form == SSA);
52 return convertValueRepsToDouble();
53 }
54
55private:
56 bool convertValueRepsToDouble()
57 {
58 HashSet<Node*> candidates;
59 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
60 for (Node* node : *block) {
61 if (node->op() == ValueRep && node->child1().useKind() == DoubleRepUse)
62 candidates.add(node);
63 }
64 }
65
66 if (!candidates.size())
67 return false;
68
69 HashMap<Node*, Vector<Node*>> usersOf;
70 auto getUsersOf = [&] (Node* candidate) {
71 auto iter = usersOf.find(candidate);
72 RELEASE_ASSERT(iter != usersOf.end());
73 return iter->value;
74 };
75
76 for (BasicBlock* block : m_graph.blocksInPreOrder()) {
77 for (Node* node : *block) {
78 if (node->op() == Phi || (node->op() == ValueRep && candidates.contains(node)))
79 usersOf.add(node, Vector<Node*>());
80
81 Vector<Node*, 3> alreadyAdded;
82 m_graph.doToChildren(node, [&] (Edge edge) {
83 Node* candidate = edge.node();
84 if (alreadyAdded.contains(candidate))
85 return;
86 auto iter = usersOf.find(candidate);
87 if (iter == usersOf.end())
88 return;
89 iter->value.append(node);
90 alreadyAdded.append(candidate);
91 });
92 }
93 }
94
95 PhiChildren phiChildren(m_graph);
96
97 // - Any candidate that forwards into a Phi turns that Phi into a candidate.
98 // - Any Phi-1 that forwards into another Phi-2, where Phi-2 is a candidate,
99 // makes Phi-1 a candidate too.
100 do {
101 HashSet<Node*> eligiblePhis;
102 for (Node* candidate : candidates) {
103 if (candidate->op() == Phi) {
104 phiChildren.forAllIncomingValues(candidate, [&] (Node* incoming) {
105 if (incoming->op() == Phi)
106 eligiblePhis.add(incoming);
107 });
108 }
109
110 for (Node* user : getUsersOf(candidate)) {
111 if (user->op() == Upsilon)
112 eligiblePhis.add(user->phi());
113 }
114 }
115
116 bool sawNewCandidate = false;
117 for (Node* phi : eligiblePhis)
118 sawNewCandidate |= candidates.add(phi).isNewEntry;
119
120 if (!sawNewCandidate)
121 break;
122 } while (true);
123
124 do {
125 HashSet<Node*> toRemove;
126
127 auto isEscaped = [&] (Node* node) {
128 return !candidates.contains(node) || toRemove.contains(node);
129 };
130
131 // Escape rules are as follows:
132 // - Any non-well-known use is an escape. Currently, we allow DoubleRep, Hints, Upsilons (described below).
133 // - Any Upsilon that forwards the candidate into an escaped phi escapes the candidate.
134 // - A Phi remains a candidate as long as all values flowing into it can be made a double.
135 // Currently, this means these are valid things we support to forward into the Phi:
136 // - A JSConstant(some number "x") => DoubleConstant("x")
137 // - ValueRep(DoubleRepUse:@x) => @x
138 // - A Phi so long as that Phi is not escaped.
139 for (Node* candidate : candidates) {
140 bool ok = true;
141
142 auto dumpEscape = [&] (const char* description, Node* node) {
143 if (!verbose)
144 return;
145 dataLogLn(description);
146 dataLog(" candidate: ");
147 m_graph.dump(WTF::dataFile(), Prefix::noString, candidate);
148 dataLog(" reason: ");
149 m_graph.dump(WTF::dataFile(), Prefix::noString, node);
150 dataLogLn();
151 };
152
153 if (candidate->op() == Phi) {
154 phiChildren.forAllIncomingValues(candidate, [&] (Node* node) {
155 if (node->op() == JSConstant) {
156 if (!node->asJSValue().isNumber()) {
157 ok = false;
158 dumpEscape("Phi Incoming JSConstant not a number: ", node);
159 }
160 } else if (node->op() == ValueRep) {
161 if (node->child1().useKind() != DoubleRepUse) {
162 ok = false;
163 dumpEscape("Phi Incoming ValueRep not DoubleRepUse: ", node);
164 }
165 } else if (node->op() == Phi) {
166 if (isEscaped(node)) {
167 ok = false;
168 dumpEscape("An incoming Phi to another Phi is escaped: ", node);
169 }
170 } else {
171 ok = false;
172 dumpEscape("Unsupported incoming value to Phi: ", node);
173 }
174 });
175
176 if (!ok) {
177 toRemove.add(candidate);
178 continue;
179 }
180 }
181
182 for (Node* user : getUsersOf(candidate)) {
183 switch (user->op()) {
184 case DoubleRep:
185 if (user->child1().useKind() != RealNumberUse) {
186 ok = false;
187 dumpEscape("DoubleRep escape: ", user);
188 }
189 break;
190
191 case PutHint:
192 case MovHint:
193 break;
194
195 case Upsilon: {
196 Node* phi = user->phi();
197 if (isEscaped(phi)) {
198 dumpEscape("Upsilon of escaped phi escapes candidate: ", phi);
199 ok = false;
200 }
201 break;
202 }
203
204 default:
205 dumpEscape("Normal escape: ", user);
206 ok = false;
207 break;
208 }
209
210 if (!ok)
211 break;
212 }
213
214 if (!ok)
215 toRemove.add(candidate);
216 }
217
218 if (toRemove.isEmpty())
219 break;
220
221 for (Node* node : toRemove)
222 candidates.remove(node);
223 } while (true);
224
225 if (!candidates.size())
226 return false;
227
228 NodeOrigin originForConstant = m_graph.block(0)->at(0)->origin;
229 HashSet<Node*> doubleRepRealCheckLocations;
230
231 for (Node* candidate : candidates) {
232 if (verbose)
233 dataLogLn("Optimized: ", candidate);
234
235 Node* resultNode;
236 if (candidate->op() == Phi) {
237 resultNode = candidate;
238
239 for (Node* upsilon : phiChildren.upsilonsOf(candidate)) {
240 Node* incomingValue = upsilon->child1().node();
241 Node* newChild;
242 if (incomingValue->op() == JSConstant) {
243 double number = incomingValue->asJSValue().asNumber();
244 newChild = m_insertionSet.insertConstant(0, originForConstant, jsDoubleNumber(number), DoubleConstant);
245 } else if (incomingValue->op() == ValueRep) {
246 // We don't care about the incoming value being an impure NaN because users of
247 // this Phi are either OSR exit or DoubleRep(RealNumberUse:@phi)
248 ASSERT(incomingValue->child1().useKind() == DoubleRepUse);
249 newChild = incomingValue->child1().node();
250 } else if (incomingValue->op() == Phi)
251 newChild = incomingValue;
252 else
253 RELEASE_ASSERT_NOT_REACHED();
254
255 upsilon->child1() = Edge(newChild, DoubleRepUse);
256 }
257
258 candidate->setResult(NodeResultDouble);
259 } else if (candidate->op() == ValueRep)
260 resultNode = candidate->child1().node();
261 else
262 RELEASE_ASSERT_NOT_REACHED();
263
264 for (Node* user : getUsersOf(candidate)) {
265 switch (user->op()) {
266 case DoubleRep: {
267 ASSERT(user->child1().useKind() == RealNumberUse);
268 user->convertToIdentityOn(resultNode);
269 doubleRepRealCheckLocations.add(user);
270 break;
271 }
272
273 case PutHint:
274 user->child2() = Edge(resultNode, DoubleRepUse);
275 break;
276
277 case MovHint:
278 user->child1() = Edge(resultNode, DoubleRepUse);
279 break;
280
281 case Upsilon: {
282 Node* phi = user->phi();
283 ASSERT_UNUSED(phi, candidates.contains(phi));
284 break;
285 }
286
287 default:
288 RELEASE_ASSERT_NOT_REACHED();
289 break;
290 }
291 }
292 }
293
294 // Insert constants.
295 m_insertionSet.execute(m_graph.block(0));
296
297 // Insert checks that are needed when removing DoubleRep(RealNumber:@x)
298 if (doubleRepRealCheckLocations.size()) {
299 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
300 for (unsigned i = 0; i < block->size(); ++i) {
301 Node* node = block->at(i);
302 if (node->op() != Identity) {
303 ASSERT(!doubleRepRealCheckLocations.contains(node));
304 continue;
305 }
306 if (!doubleRepRealCheckLocations.contains(node))
307 continue;
308 m_insertionSet.insertNode(
309 i, SpecNone, Check, node->origin,
310 Edge(node->child1().node(), DoubleRepRealUse));
311 }
312
313 m_insertionSet.execute(block);
314 }
315 }
316
317 return true;
318 }
319
320 InsertionSet m_insertionSet;
321};
322
323bool performValueRepReduction(Graph& graph)
324{
325 return runPhase<ValueRepReductionPhase>(graph);
326}
327
328} } // namespace JSC::DFG
329
330#endif // ENABLE(DFG_JIT)
331
Note: See TracBrowser for help on using the repository browser.