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