1 | /* |
2 | * Copyright (C) 2013-2018 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 "DFGNode.h" |
28 | |
29 | #if ENABLE(DFG_JIT) |
30 | |
31 | #include "DFGGraph.h" |
32 | #include "DFGPromotedHeapLocation.h" |
33 | #include "JSCInlines.h" |
34 | #include "JSImmutableButterfly.h" |
35 | |
36 | namespace JSC { namespace DFG { |
37 | |
38 | const char Node::HashSetTemplateInstantiationString[] = "::JSC::DFG::Node*" ; |
39 | |
40 | bool MultiPutByOffsetData::writesStructures() const |
41 | { |
42 | for (unsigned i = variants.size(); i--;) { |
43 | if (variants[i].writesStructures()) |
44 | return true; |
45 | } |
46 | return false; |
47 | } |
48 | |
49 | bool MultiPutByOffsetData::reallocatesStorage() const |
50 | { |
51 | for (unsigned i = variants.size(); i--;) { |
52 | if (variants[i].reallocatesStorage()) |
53 | return true; |
54 | } |
55 | return false; |
56 | } |
57 | |
58 | void BranchTarget::dump(PrintStream& out) const |
59 | { |
60 | if (!block) |
61 | return; |
62 | |
63 | out.print(*block); |
64 | |
65 | if (count == count) // If the count is not NaN, then print it. |
66 | out.print("/w:" , count); |
67 | } |
68 | |
69 | bool Node::hasVariableAccessData(Graph& graph) |
70 | { |
71 | switch (op()) { |
72 | case Phi: |
73 | return graph.m_form != SSA; |
74 | case GetLocal: |
75 | case SetLocal: |
76 | case SetArgumentDefinitely: |
77 | case SetArgumentMaybe: |
78 | case Flush: |
79 | case PhantomLocal: |
80 | return true; |
81 | default: |
82 | return false; |
83 | } |
84 | } |
85 | |
86 | void Node::remove(Graph& graph) |
87 | { |
88 | switch (op()) { |
89 | case MultiGetByOffset: { |
90 | MultiGetByOffsetData& data = multiGetByOffsetData(); |
91 | StructureSet set; |
92 | for (MultiGetByOffsetCase& getCase : data.cases) { |
93 | getCase.set().forEach( |
94 | [&] (RegisteredStructure structure) { |
95 | set.add(structure.get()); |
96 | }); |
97 | } |
98 | convertToCheckStructure(graph.addStructureSet(set)); |
99 | return; |
100 | } |
101 | |
102 | case MatchStructure: { |
103 | MatchStructureData& data = matchStructureData(); |
104 | RegisteredStructureSet set; |
105 | for (MatchStructureVariant& variant : data.variants) |
106 | set.add(variant.structure); |
107 | convertToCheckStructure(graph.addStructureSet(set)); |
108 | return; |
109 | } |
110 | |
111 | default: |
112 | if (flags() & NodeHasVarArgs) { |
113 | unsigned targetIndex = 0; |
114 | for (unsigned i = 0; i < numChildren(); ++i) { |
115 | Edge& edge = graph.varArgChild(this, i); |
116 | if (!edge) |
117 | continue; |
118 | if (edge.willHaveCheck()) { |
119 | Edge& dst = graph.varArgChild(this, targetIndex++); |
120 | std::swap(dst, edge); |
121 | continue; |
122 | } |
123 | edge = Edge(); |
124 | } |
125 | setOpAndDefaultFlags(CheckVarargs); |
126 | children.setNumChildren(targetIndex); |
127 | } else { |
128 | children = children.justChecks(); |
129 | setOpAndDefaultFlags(Check); |
130 | } |
131 | return; |
132 | } |
133 | } |
134 | |
135 | void Node::removeWithoutChecks() |
136 | { |
137 | children = AdjacencyList(); |
138 | setOpAndDefaultFlags(Check); |
139 | } |
140 | |
141 | void Node::replaceWith(Graph& graph, Node* other) |
142 | { |
143 | remove(graph); |
144 | setReplacement(other); |
145 | } |
146 | |
147 | void Node::replaceWithWithoutChecks(Node* other) |
148 | { |
149 | removeWithoutChecks(); |
150 | setReplacement(other); |
151 | } |
152 | |
153 | void Node::convertToIdentity() |
154 | { |
155 | RELEASE_ASSERT(child1()); |
156 | RELEASE_ASSERT(!child2()); |
157 | NodeFlags result = canonicalResultRepresentation(this->result()); |
158 | setOpAndDefaultFlags(Identity); |
159 | setResult(result); |
160 | } |
161 | |
162 | void Node::convertToIdentityOn(Node* child) |
163 | { |
164 | children.reset(); |
165 | clearFlags(NodeHasVarArgs); |
166 | child1() = child->defaultEdge(); |
167 | NodeFlags output = canonicalResultRepresentation(this->result()); |
168 | NodeFlags input = canonicalResultRepresentation(child->result()); |
169 | if (output == input) { |
170 | setOpAndDefaultFlags(Identity); |
171 | setResult(output); |
172 | return; |
173 | } |
174 | switch (output) { |
175 | case NodeResultDouble: |
176 | setOpAndDefaultFlags(DoubleRep); |
177 | switch (input) { |
178 | case NodeResultInt52: |
179 | child1().setUseKind(Int52RepUse); |
180 | return; |
181 | case NodeResultJS: |
182 | child1().setUseKind(NumberUse); |
183 | return; |
184 | default: |
185 | RELEASE_ASSERT_NOT_REACHED(); |
186 | return; |
187 | } |
188 | case NodeResultInt52: |
189 | setOpAndDefaultFlags(Int52Rep); |
190 | switch (input) { |
191 | case NodeResultDouble: |
192 | child1().setUseKind(DoubleRepAnyIntUse); |
193 | return; |
194 | case NodeResultJS: |
195 | child1().setUseKind(AnyIntUse); |
196 | return; |
197 | default: |
198 | RELEASE_ASSERT_NOT_REACHED(); |
199 | return; |
200 | } |
201 | case NodeResultJS: |
202 | setOpAndDefaultFlags(ValueRep); |
203 | switch (input) { |
204 | case NodeResultDouble: |
205 | child1().setUseKind(DoubleRepUse); |
206 | return; |
207 | case NodeResultInt52: |
208 | child1().setUseKind(Int52RepUse); |
209 | return; |
210 | default: |
211 | RELEASE_ASSERT_NOT_REACHED(); |
212 | return; |
213 | } |
214 | default: |
215 | RELEASE_ASSERT_NOT_REACHED(); |
216 | return; |
217 | } |
218 | } |
219 | |
220 | void Node::convertToLazyJSConstant(Graph& graph, LazyJSValue value) |
221 | { |
222 | m_op = LazyJSConstant; |
223 | m_flags &= ~NodeMustGenerate; |
224 | m_opInfo = graph.m_lazyJSValues.add(value); |
225 | children.reset(); |
226 | } |
227 | |
228 | void Node::convertToNewArrayBuffer(FrozenValue* immutableButterfly) |
229 | { |
230 | setOpAndDefaultFlags(NewArrayBuffer); |
231 | NewArrayBufferData data { }; |
232 | data.indexingMode = immutableButterfly->cast<JSImmutableButterfly*>()->indexingMode(); |
233 | data.vectorLengthHint = immutableButterfly->cast<JSImmutableButterfly*>()->toButterfly()->vectorLength(); |
234 | children.reset(); |
235 | m_opInfo = immutableButterfly; |
236 | m_opInfo2 = data.asQuadWord; |
237 | } |
238 | |
239 | void Node::convertToDirectCall(FrozenValue* executable) |
240 | { |
241 | NodeType newOp = LastNodeType; |
242 | switch (op()) { |
243 | case Call: |
244 | newOp = DirectCall; |
245 | break; |
246 | case Construct: |
247 | newOp = DirectConstruct; |
248 | break; |
249 | case TailCallInlinedCaller: |
250 | newOp = DirectTailCallInlinedCaller; |
251 | break; |
252 | case TailCall: |
253 | newOp = DirectTailCall; |
254 | break; |
255 | default: |
256 | RELEASE_ASSERT_NOT_REACHED(); |
257 | break; |
258 | } |
259 | |
260 | m_op = newOp; |
261 | m_opInfo = executable; |
262 | } |
263 | |
264 | void Node::convertToCallDOM(Graph& graph) |
265 | { |
266 | ASSERT(op() == Call); |
267 | ASSERT(signature()); |
268 | |
269 | Edge edges[3]; |
270 | // Skip the first one. This is callee. |
271 | RELEASE_ASSERT(numChildren() <= 4); |
272 | for (unsigned i = 1; i < numChildren(); ++i) |
273 | edges[i - 1] = graph.varArgChild(this, i); |
274 | |
275 | setOpAndDefaultFlags(CallDOM); |
276 | children.setChild1(edges[0]); |
277 | children.setChild2(edges[1]); |
278 | children.setChild3(edges[2]); |
279 | |
280 | if (!signature()->effect.mustGenerate()) |
281 | clearFlags(NodeMustGenerate); |
282 | } |
283 | |
284 | void Node::convertToRegExpExecNonGlobalOrStickyWithoutChecks(FrozenValue* regExp) |
285 | { |
286 | ASSERT(op() == RegExpExec); |
287 | setOpAndDefaultFlags(RegExpExecNonGlobalOrSticky); |
288 | children.child1() = Edge(children.child1().node(), KnownCellUse); |
289 | children.child2() = Edge(children.child3().node(), KnownStringUse); |
290 | children.child3() = Edge(); |
291 | m_opInfo = regExp; |
292 | } |
293 | |
294 | void Node::convertToRegExpMatchFastGlobalWithoutChecks(FrozenValue* regExp) |
295 | { |
296 | ASSERT(op() == RegExpMatchFast); |
297 | setOpAndDefaultFlags(RegExpMatchFastGlobal); |
298 | children.child1() = Edge(children.child1().node(), KnownCellUse); |
299 | children.child2() = Edge(children.child3().node(), KnownStringUse); |
300 | children.child3() = Edge(); |
301 | m_opInfo = regExp; |
302 | } |
303 | |
304 | String Node::tryGetString(Graph& graph) |
305 | { |
306 | if (hasConstant()) |
307 | return constant()->tryGetString(graph); |
308 | if (hasLazyJSValue()) |
309 | return lazyJSValue().tryGetString(graph); |
310 | return String(); |
311 | } |
312 | |
313 | PromotedLocationDescriptor Node::promotedLocationDescriptor() |
314 | { |
315 | return PromotedLocationDescriptor(static_cast<PromotedLocationKind>(m_opInfo.as<uint32_t>()), m_opInfo2.as<uint32_t>()); |
316 | } |
317 | |
318 | } } // namespace JSC::DFG |
319 | |
320 | namespace WTF { |
321 | |
322 | using namespace JSC; |
323 | using namespace JSC::DFG; |
324 | |
325 | void printInternal(PrintStream& out, SwitchKind kind) |
326 | { |
327 | switch (kind) { |
328 | case SwitchImm: |
329 | out.print("SwitchImm" ); |
330 | return; |
331 | case SwitchChar: |
332 | out.print("SwitchChar" ); |
333 | return; |
334 | case SwitchString: |
335 | out.print("SwitchString" ); |
336 | return; |
337 | case SwitchCell: |
338 | out.print("SwitchCell" ); |
339 | return; |
340 | } |
341 | RELEASE_ASSERT_NOT_REACHED(); |
342 | } |
343 | |
344 | void printInternal(PrintStream& out, Node* node) |
345 | { |
346 | if (!node) { |
347 | out.print("-" ); |
348 | return; |
349 | } |
350 | out.print("@" , node->index()); |
351 | if (node->hasDoubleResult()) |
352 | out.print("<Double>" ); |
353 | else if (node->hasInt52Result()) |
354 | out.print("<Int52>" ); |
355 | } |
356 | |
357 | } // namespace WTF |
358 | |
359 | #endif // ENABLE(DFG_JIT) |
360 | |
361 | |