Record the HashSet/HashMap operations in DFG/FTL/B3 and replay them in a benchmark
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGNode.cpp
1 /*
2  * Copyright (C) 2013, 2014, 2016 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()
85 {
86     ASSERT(!(flags() & NodeHasVarArgs));
87     
88     children = children.justChecks();
89     
90     setOpAndDefaultFlags(Check);
91 }
92
93 void Node::convertToIdentity()
94 {
95     RELEASE_ASSERT(child1());
96     RELEASE_ASSERT(!child2());
97     NodeFlags result = canonicalResultRepresentation(this->result());
98     setOpAndDefaultFlags(Identity);
99     setResult(result);
100 }
101
102 void Node::convertToIdentityOn(Node* child)
103 {
104     children.reset();
105     child1() = child->defaultEdge();
106     NodeFlags output = canonicalResultRepresentation(this->result());
107     NodeFlags input = canonicalResultRepresentation(child->result());
108     if (output == input) {
109         setOpAndDefaultFlags(Identity);
110         setResult(output);
111         return;
112     }
113     switch (output) {
114     case NodeResultDouble:
115         setOpAndDefaultFlags(DoubleRep);
116         switch (input) {
117         case NodeResultInt52:
118             child1().setUseKind(Int52RepUse);
119             return;
120         case NodeResultJS:
121             child1().setUseKind(NumberUse);
122             return;
123         default:
124             RELEASE_ASSERT_NOT_REACHED();
125             return;
126         }
127     case NodeResultInt52:
128         setOpAndDefaultFlags(Int52Rep);
129         switch (input) {
130         case NodeResultDouble:
131             child1().setUseKind(DoubleRepAnyIntUse);
132             return;
133         case NodeResultJS:
134             child1().setUseKind(AnyIntUse);
135             return;
136         default:
137             RELEASE_ASSERT_NOT_REACHED();
138             return;
139         }
140     case NodeResultJS:
141         setOpAndDefaultFlags(ValueRep);
142         switch (input) {
143         case NodeResultDouble:
144             child1().setUseKind(DoubleRepUse);
145             return;
146         case NodeResultInt52:
147             child1().setUseKind(Int52RepUse);
148             return;
149         default:
150             RELEASE_ASSERT_NOT_REACHED();
151             return;
152         }
153     default:
154         RELEASE_ASSERT_NOT_REACHED();
155         return;
156     }
157 }
158
159 void Node::convertToLazyJSConstant(Graph& graph, LazyJSValue value)
160 {
161     m_op = LazyJSConstant;
162     m_flags &= ~NodeMustGenerate;
163     m_opInfo = graph.m_lazyJSValues.add(value);
164     children.reset();
165 }
166
167 void Node::convertToPutHint(const PromotedLocationDescriptor& descriptor, Node* base, Node* value)
168 {
169     m_op = PutHint;
170     m_opInfo = descriptor.imm1();
171     m_opInfo2 = descriptor.imm2();
172     child1() = base->defaultEdge();
173     child2() = value->defaultEdge();
174     child3() = Edge();
175 }
176
177 void Node::convertToPutStructureHint(Node* structure)
178 {
179     ASSERT(m_op == PutStructure);
180     ASSERT(structure->castConstant<Structure*>(*structure->asCell()->vm()) == transition()->next.get());
181     convertToPutHint(StructurePLoc, child1().node(), structure);
182 }
183
184 void Node::convertToPutByOffsetHint()
185 {
186     ASSERT(m_op == PutByOffset);
187     convertToPutHint(
188         PromotedLocationDescriptor(NamedPropertyPLoc, storageAccessData().identifierNumber),
189         child2().node(), child3().node());
190 }
191
192 void Node::convertToPutClosureVarHint()
193 {
194     ASSERT(m_op == PutClosureVar);
195     convertToPutHint(
196         PromotedLocationDescriptor(ClosureVarPLoc, scopeOffset().offset()),
197         child1().node(), child2().node());
198 }
199
200 void Node::convertToDirectCall(FrozenValue* executable)
201 {
202     NodeType newOp = LastNodeType;
203     switch (op()) {
204     case Call:
205         newOp = DirectCall;
206         break;
207     case Construct:
208         newOp = DirectConstruct;
209         break;
210     case TailCallInlinedCaller:
211         newOp = DirectTailCallInlinedCaller;
212         break;
213     case TailCall:
214         newOp = DirectTailCall;
215         break;
216     default:
217         RELEASE_ASSERT_NOT_REACHED();
218         break;
219     }
220     
221     m_op = newOp;
222     m_opInfo = executable;
223 }
224
225 void Node::convertToCallDOM(Graph& graph)
226 {
227     ASSERT(op() == Call);
228     ASSERT(signature());
229
230     Edge edges[3];
231     // Skip the first one. This is callee.
232     RELEASE_ASSERT(numChildren() <= 4);
233     for (unsigned i = 1; i < numChildren(); ++i)
234         edges[i - 1] = graph.varArgChild(this, i);
235
236     setOpAndDefaultFlags(CallDOM);
237     children.setChild1(edges[0]);
238     children.setChild2(edges[1]);
239     children.setChild3(edges[2]);
240
241     if (!signature()->effect.mustGenerate())
242         clearFlags(NodeMustGenerate);
243 }
244
245 String Node::tryGetString(Graph& graph)
246 {
247     if (hasConstant())
248         return constant()->tryGetString(graph);
249     if (hasLazyJSValue())
250         return lazyJSValue().tryGetString(graph);
251     return String();
252 }
253
254 PromotedLocationDescriptor Node::promotedLocationDescriptor()
255 {
256     return PromotedLocationDescriptor(static_cast<PromotedLocationKind>(m_opInfo.as<uint32_t>()), m_opInfo2.as<uint32_t>());
257 }
258
259 } } // namespace JSC::DFG
260
261 namespace WTF {
262
263 using namespace JSC;
264 using namespace JSC::DFG;
265
266 void printInternal(PrintStream& out, SwitchKind kind)
267 {
268     switch (kind) {
269     case SwitchImm:
270         out.print("SwitchImm");
271         return;
272     case SwitchChar:
273         out.print("SwitchChar");
274         return;
275     case SwitchString:
276         out.print("SwitchString");
277         return;
278     case SwitchCell:
279         out.print("SwitchCell");
280         return;
281     }
282     RELEASE_ASSERT_NOT_REACHED();
283 }
284
285 void printInternal(PrintStream& out, Node* node)
286 {
287     if (!node) {
288         out.print("-");
289         return;
290     }
291     out.print("@", node->index());
292     if (node->hasDoubleResult())
293         out.print("<Double>");
294     else if (node->hasInt52Result())
295         out.print("<Int52>");
296 }
297
298 } // namespace WTF
299
300 #endif // ENABLE(DFG_JIT)
301