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
36namespace JSC { namespace DFG {
37
38const char Node::HashSetTemplateInstantiationString[] = "::JSC::DFG::Node*";
39
40bool 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
49bool 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
58void 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
69bool 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
86void 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
135void Node::removeWithoutChecks()
136{
137 children = AdjacencyList();
138 setOpAndDefaultFlags(Check);
139}
140
141void Node::replaceWith(Graph& graph, Node* other)
142{
143 remove(graph);
144 setReplacement(other);
145}
146
147void Node::replaceWithWithoutChecks(Node* other)
148{
149 removeWithoutChecks();
150 setReplacement(other);
151}
152
153void 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
162void 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
220void 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
228void 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
239void 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
264void 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
284void 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
294void 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
304String 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
313PromotedLocationDescriptor 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
320namespace WTF {
321
322using namespace JSC;
323using namespace JSC::DFG;
324
325void 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
344void 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