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