DFG should inline Array.push and Array.pop
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGNode.h
1 /*
2  * Copyright (C) 2011 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 #ifndef DFGNode_h
27 #define DFGNode_h
28
29 #include "DFGStructureSet.h"
30 #include <wtf/BoundsCheckedPointer.h>
31 #include <wtf/Platform.h>
32 #include <wtf/UnionFind.h>
33
34 // Emit various logging information for debugging, including dumping the dataflow graphs.
35 #define ENABLE_DFG_DEBUG_VERBOSE 0
36 // Emit dumps during propagation, in addition to just after.
37 #define ENABLE_DFG_DEBUG_PROPAGATION_VERBOSE 0
38 // Emit logging for OSR exit value recoveries at every node, not just nodes that
39 // actually has speculation checks.
40 #define ENABLE_DFG_VERBOSE_VALUE_RECOVERIES 0
41 // Enable generation of dynamic checks into the instruction stream.
42 #if !ASSERT_DISABLED
43 #define ENABLE_DFG_JIT_ASSERT 1
44 #else
45 #define ENABLE_DFG_JIT_ASSERT 0
46 #endif
47 // Consistency check contents compiler data structures.
48 #define ENABLE_DFG_CONSISTENCY_CHECK 0
49 // Emit a breakpoint into the head of every generated function, to aid debugging in GDB.
50 #define ENABLE_DFG_JIT_BREAK_ON_EVERY_FUNCTION 0
51 // Emit a breakpoint into the head of every generated node, to aid debugging in GDB.
52 #define ENABLE_DFG_JIT_BREAK_ON_EVERY_BLOCK 0
53 // Emit a breakpoint into the head of every generated node, to aid debugging in GDB.
54 #define ENABLE_DFG_JIT_BREAK_ON_EVERY_NODE 0
55 // Emit a breakpoint into the speculation failure code.
56 #define ENABLE_DFG_JIT_BREAK_ON_SPECULATION_FAILURE 0
57 // Log every speculation failure.
58 #define ENABLE_DFG_VERBOSE_SPECULATION_FAILURE 0
59 // Disable the DFG JIT without having to touch Platform.h!
60 #define DFG_DEBUG_LOCAL_DISBALE 0
61 // Enable OSR entry from baseline JIT.
62 #define ENABLE_DFG_OSR_ENTRY ENABLE_DFG_JIT
63 // Generate stats on how successful we were in making use of the DFG jit, and remaining on the hot path.
64 #define ENABLE_DFG_SUCCESS_STATS 0
65
66
67 #if ENABLE(DFG_JIT)
68
69 #include "CodeBlock.h"
70 #include "JSValue.h"
71 #include "PredictedType.h"
72 #include "ValueProfile.h"
73 #include <wtf/Vector.h>
74
75 namespace JSC { namespace DFG {
76
77 // Type for a virtual register number (spill location).
78 // Using an enum to make this type-checked at compile time, to avert programmer errors.
79 enum VirtualRegister { InvalidVirtualRegister = -1 };
80 COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit);
81
82 // Type for a reference to another node in the graph.
83 typedef uint32_t NodeIndex;
84 static const NodeIndex NoNode = UINT_MAX;
85
86 // Information used to map back from an exception to any handler/source information,
87 // and to implement OSR.
88 // (Presently implemented as a bytecode index).
89 class CodeOrigin {
90 public:
91     CodeOrigin()
92         : m_bytecodeIndex(std::numeric_limits<uint32_t>::max())
93     {
94     }
95     
96     explicit CodeOrigin(uint32_t bytecodeIndex)
97         : m_bytecodeIndex(bytecodeIndex)
98     {
99     }
100     
101     bool isSet() const { return m_bytecodeIndex != std::numeric_limits<uint32_t>::max(); }
102     
103     uint32_t bytecodeIndex() const
104     {
105         ASSERT(isSet());
106         return m_bytecodeIndex;
107     }
108     
109 private:
110     uint32_t m_bytecodeIndex;
111 };
112
113 class VariableAccessData: public UnionFind<VariableAccessData> {
114 public:
115     VariableAccessData()
116         : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
117         , m_prediction(PredictNone)
118     {
119     }
120     
121     VariableAccessData(VirtualRegister local)
122         : m_local(local)
123         , m_prediction(PredictNone)
124     {
125     }
126     
127     VirtualRegister local()
128     {
129         ASSERT(m_local == find()->m_local);
130         return m_local;
131     }
132     
133     int operand()
134     {
135         return static_cast<int>(local());
136     }
137     
138     bool predict(PredictedType prediction)
139     {
140         return mergePrediction(find()->m_prediction, prediction);
141     }
142     
143     PredictedType prediction()
144     {
145         return find()->m_prediction;
146     }
147     
148 private:
149     // This is slightly space-inefficient, since anything we're unified with
150     // will have the same operand and should have the same prediction. But
151     // putting them here simplifies the code, and we don't expect DFG space
152     // usage for variable access nodes do be significant.
153
154     VirtualRegister m_local;
155     PredictedType m_prediction;
156 };
157
158 struct StructureTransitionData {
159     Structure* previousStructure;
160     Structure* newStructure;
161     
162     StructureTransitionData() { }
163     
164     StructureTransitionData(Structure* previousStructure, Structure* newStructure)
165         : previousStructure(previousStructure)
166         , newStructure(newStructure)
167     {
168     }
169 };
170
171 typedef unsigned ArithNodeFlags;
172 #define NodeUseBottom      0x00
173 #define NodeUsedAsNumber   0x01
174 #define NodeNeedsNegZero   0x02
175 #define NodeUsedAsMask     0x03
176 #define NodeMayOverflow    0x04
177 #define NodeMayNegZero     0x08
178 #define NodeBehaviorMask   0x0c
179
180 static inline bool nodeUsedAsNumber(ArithNodeFlags flags)
181 {
182     return !!(flags & NodeUsedAsNumber);
183 }
184
185 static inline bool nodeCanTruncateInteger(ArithNodeFlags flags)
186 {
187     return !nodeUsedAsNumber(flags);
188 }
189
190 static inline bool nodeCanIgnoreNegativeZero(ArithNodeFlags flags)
191 {
192     return !(flags & NodeNeedsNegZero);
193 }
194
195 static inline bool nodeCanSpeculateInteger(ArithNodeFlags flags)
196 {
197     if (flags & NodeMayOverflow)
198         return !nodeUsedAsNumber(flags);
199     
200     if (flags & NodeMayNegZero)
201         return nodeCanIgnoreNegativeZero(flags);
202     
203     return true;
204 }
205
206 #ifndef NDEBUG
207 static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
208 {
209     if (!flags)
210         return "<empty>";
211
212     static const int size = 64;
213     static char description[size];
214     BoundsCheckedPointer<char> ptr(description, size);
215     
216     bool hasPrinted = false;
217     
218     if (flags & NodeUsedAsNumber) {
219         ptr.strcat("UsedAsNum");
220         hasPrinted = true;
221     }
222     
223     if (flags & NodeNeedsNegZero) {
224         if (hasPrinted)
225             ptr.strcat("|");
226         ptr.strcat("NeedsNegZero");
227         hasPrinted = true;
228     }
229     
230     if (flags & NodeMayOverflow) {
231         if (hasPrinted)
232             ptr.strcat("|");
233         ptr.strcat("MayOverflow");
234         hasPrinted = true;
235     }
236     
237     if (flags & NodeMayNegZero) {
238         if (hasPrinted)
239             ptr.strcat("|");
240         ptr.strcat("MayNegZero");
241         hasPrinted = true;
242     }
243     
244     *ptr++ = 0;
245     
246     return description;
247 }
248 #endif
249
250 // Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
251 // and some additional informative flags (must generate, is constant, etc).
252 #define NodeIdMask           0xFFF
253 #define NodeResultMask      0xF000
254 #define NodeMustGenerate   0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE.
255 #define NodeIsConstant     0x20000
256 #define NodeIsJump         0x40000
257 #define NodeIsBranch       0x80000
258 #define NodeIsTerminal    0x100000
259 #define NodeHasVarArgs    0x200000
260 #define NodeClobbersWorld 0x400000
261 #define NodeMightClobber  0x800000
262
263 // These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result.
264 #define NodeResultJS        0x1000
265 #define NodeResultNumber    0x2000
266 #define NodeResultInt32     0x3000
267 #define NodeResultBoolean   0x4000
268 #define NodeResultStorage   0x5000
269
270 // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
271 #define FOR_EACH_DFG_OP(macro) \
272     /* Nodes for constants. */\
273     macro(JSConstant, NodeResultJS) \
274     \
275     /* Nodes for handling functions (both as call and as construct). */\
276     macro(ConvertThis, NodeResultJS) \
277     macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
278     macro(GetCallee, NodeResultJS) \
279     \
280     /* Nodes for local variable access. */\
281     macro(GetLocal, NodeResultJS) \
282     macro(SetLocal, 0) \
283     macro(Phantom, NodeMustGenerate) \
284     macro(Phi, 0) \
285     \
286     /* Marker for arguments being set. */\
287     macro(SetArgument, 0) \
288     \
289     /* Nodes for bitwise operations. */\
290     macro(BitAnd, NodeResultInt32) \
291     macro(BitOr, NodeResultInt32) \
292     macro(BitXor, NodeResultInt32) \
293     macro(BitLShift, NodeResultInt32) \
294     macro(BitRShift, NodeResultInt32) \
295     macro(BitURShift, NodeResultInt32) \
296     /* Bitwise operators call ToInt32 on their operands. */\
297     macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \
298     /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
299     macro(UInt32ToNumber, NodeResultNumber) \
300     \
301     /* Nodes for arithmetic operations. */\
302     macro(ArithAdd, NodeResultNumber) \
303     macro(ArithSub, NodeResultNumber) \
304     macro(ArithMul, NodeResultNumber) \
305     macro(ArithDiv, NodeResultNumber) \
306     macro(ArithMod, NodeResultNumber) \
307     macro(ArithAbs, NodeResultNumber) \
308     macro(ArithMin, NodeResultNumber) \
309     macro(ArithMax, NodeResultNumber) \
310     macro(ArithSqrt, NodeResultNumber) \
311     /* Arithmetic operators call ToNumber on their operands. */\
312     macro(ValueToNumber, NodeResultNumber | NodeMustGenerate) \
313     \
314     /* A variant of ValueToNumber, which a hint that the parents will always use this as a double. */\
315     macro(ValueToDouble, NodeResultNumber | NodeMustGenerate) \
316     \
317     /* Add of values may either be arithmetic, or result in string concatenation. */\
318     macro(ValueAdd, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
319     \
320     /* Property access. */\
321     /* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\
322     /* Since a put to 'length' may invalidate optimizations here, */\
323     /* this must be the directly subsequent property put. */\
324     macro(GetByVal, NodeResultJS | NodeMustGenerate) \
325     macro(PutByVal, NodeMustGenerate | NodeClobbersWorld) \
326     macro(PutByValAlias, NodeMustGenerate | NodeClobbersWorld) \
327     macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
328     macro(PutById, NodeMustGenerate | NodeClobbersWorld) \
329     macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \
330     macro(CheckStructure, NodeMustGenerate) \
331     macro(PutStructure, NodeMustGenerate | NodeClobbersWorld) \
332     macro(GetPropertyStorage, NodeResultStorage) \
333     macro(GetByOffset, NodeResultJS) \
334     macro(PutByOffset, NodeMustGenerate | NodeClobbersWorld) \
335     macro(GetArrayLength, NodeResultInt32) \
336     macro(GetStringLength, NodeResultInt32) \
337     macro(GetMethod, NodeResultJS | NodeMustGenerate) \
338     macro(CheckMethod, NodeResultJS | NodeMustGenerate) \
339     macro(GetScopeChain, NodeResultJS) \
340     macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \
341     macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \
342     macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
343     macro(PutGlobalVar, NodeMustGenerate | NodeClobbersWorld) \
344     \
345     /* Optimizations for array mutation. */\
346     macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
347     macro(ArrayPop, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
348     \
349     /* Nodes for comparison operations. */\
350     macro(CompareLess, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
351     macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
352     macro(CompareGreater, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
353     macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
354     macro(CompareEq, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
355     macro(CompareStrictEq, NodeResultBoolean) \
356     \
357     /* Calls. */\
358     macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
359     macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
360     \
361     /* Allocations. */\
362     macro(NewObject, NodeResultJS) \
363     macro(NewArray, NodeResultJS | NodeHasVarArgs) \
364     macro(NewArrayBuffer, NodeResultJS) \
365     macro(NewRegexp, NodeResultJS) \
366     \
367     /* Resolve nodes. */\
368     macro(Resolve, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
369     macro(ResolveBase, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
370     macro(ResolveBaseStrictPut, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
371     macro(ResolveGlobal, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
372     \
373     /* Nodes for misc operations. */\
374     macro(Breakpoint, NodeMustGenerate | NodeClobbersWorld) \
375     macro(CheckHasInstance, NodeMustGenerate) \
376     macro(InstanceOf, NodeResultBoolean) \
377     macro(LogicalNot, NodeResultBoolean | NodeMightClobber) \
378     macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
379     macro(StrCat, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
380     \
381     /* Block terminals. */\
382     macro(Jump, NodeMustGenerate | NodeIsTerminal | NodeIsJump) \
383     macro(Branch, NodeMustGenerate | NodeIsTerminal | NodeIsBranch) \
384     macro(Return, NodeMustGenerate | NodeIsTerminal) \
385     macro(Throw, NodeMustGenerate | NodeIsTerminal) \
386     macro(ThrowReferenceError, NodeMustGenerate | NodeIsTerminal) \
387     \
388     /* This is a pseudo-terminal. It means that execution should fall out of DFG at */\
389     /* this point, but execution does continue in the basic block - just in a */\
390     /* different compiler. */\
391     macro(ForceOSRExit, NodeMustGenerate)
392
393 // This enum generates a monotonically increasing id for all Node types,
394 // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
395 enum NodeId {
396 #define DFG_OP_ENUM(opcode, flags) opcode##_id,
397     FOR_EACH_DFG_OP(DFG_OP_ENUM)
398 #undef DFG_OP_ENUM
399     LastNodeId
400 };
401
402 // Entries in this enum describe all Node types.
403 // The enum value contains a monotonically increasing id, a result type, and additional flags.
404 enum NodeType {
405 #define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags),
406     FOR_EACH_DFG_OP(DFG_OP_ENUM)
407 #undef DFG_OP_ENUM
408 };
409
410 // This type used in passing an immediate argument to Node constructor;
411 // distinguishes an immediate value (typically an index into a CodeBlock data structure - 
412 // a constant index, argument, or identifier) from a NodeIndex.
413 struct OpInfo {
414     explicit OpInfo(int32_t value) : m_value(static_cast<uintptr_t>(value)) { }
415     explicit OpInfo(uint32_t value) : m_value(static_cast<uintptr_t>(value)) { }
416 #if OS(DARWIN) || USE(JSVALUE64)
417     explicit OpInfo(size_t value) : m_value(static_cast<uintptr_t>(value)) { }
418 #endif
419     explicit OpInfo(void* value) : m_value(reinterpret_cast<uintptr_t>(value)) { }
420     uintptr_t m_value;
421 };
422
423 // === Node ===
424 //
425 // Node represents a single operation in the data flow graph.
426 struct Node {
427     enum VarArgTag { VarArg };
428
429     // Construct a node with up to 3 children, no immediate value.
430     Node(NodeType op, CodeOrigin codeOrigin, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
431         : op(op)
432         , codeOrigin(codeOrigin)
433         , m_virtualRegister(InvalidVirtualRegister)
434         , m_refCount(0)
435         , m_prediction(PredictNone)
436     {
437         ASSERT(!(op & NodeHasVarArgs));
438         ASSERT(!hasArithNodeFlags());
439         children.fixed.child1 = child1;
440         children.fixed.child2 = child2;
441         children.fixed.child3 = child3;
442     }
443
444     // Construct a node with up to 3 children and an immediate value.
445     Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
446         : op(op)
447         , codeOrigin(codeOrigin)
448         , m_virtualRegister(InvalidVirtualRegister)
449         , m_refCount(0)
450         , m_opInfo(imm.m_value)
451         , m_prediction(PredictNone)
452     {
453         ASSERT(!(op & NodeHasVarArgs));
454         children.fixed.child1 = child1;
455         children.fixed.child2 = child2;
456         children.fixed.child3 = child3;
457     }
458
459     // Construct a node with up to 3 children and two immediate values.
460     Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
461         : op(op)
462         , codeOrigin(codeOrigin)
463         , m_virtualRegister(InvalidVirtualRegister)
464         , m_refCount(0)
465         , m_opInfo(imm1.m_value)
466         , m_opInfo2(safeCast<unsigned>(imm2.m_value))
467         , m_prediction(PredictNone)
468     {
469         ASSERT(!(op & NodeHasVarArgs));
470         children.fixed.child1 = child1;
471         children.fixed.child2 = child2;
472         children.fixed.child3 = child3;
473     }
474     
475     // Construct a node with a variable number of children and two immediate values.
476     Node(VarArgTag, NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
477         : op(op)
478         , codeOrigin(codeOrigin)
479         , m_virtualRegister(InvalidVirtualRegister)
480         , m_refCount(0)
481         , m_opInfo(imm1.m_value)
482         , m_opInfo2(safeCast<unsigned>(imm2.m_value))
483         , m_prediction(PredictNone)
484     {
485         ASSERT(op & NodeHasVarArgs);
486         children.variable.firstChild = firstChild;
487         children.variable.numChildren = numChildren;
488     }
489
490     bool mustGenerate()
491     {
492         return op & NodeMustGenerate;
493     }
494
495     bool isConstant()
496     {
497         return op == JSConstant;
498     }
499     
500     bool hasConstant()
501     {
502         return isConstant() || hasMethodCheckData();
503     }
504
505     unsigned constantNumber()
506     {
507         ASSERT(isConstant());
508         return m_opInfo;
509     }
510     
511     // NOTE: this only works for JSConstant nodes.
512     JSValue valueOfJSConstantNode(CodeBlock* codeBlock)
513     {
514         return codeBlock->constantRegister(FirstConstantRegisterIndex + constantNumber()).get();
515     }
516
517     bool isInt32Constant(CodeBlock* codeBlock)
518     {
519         return isConstant() && valueOfJSConstantNode(codeBlock).isInt32();
520     }
521     
522     bool isDoubleConstant(CodeBlock* codeBlock)
523     {
524         bool result = isConstant() && valueOfJSConstantNode(codeBlock).isDouble();
525         if (result)
526             ASSERT(!isInt32Constant(codeBlock));
527         return result;
528     }
529     
530     bool isNumberConstant(CodeBlock* codeBlock)
531     {
532         bool result = isConstant() && valueOfJSConstantNode(codeBlock).isNumber();
533         ASSERT(result == (isInt32Constant(codeBlock) || isDoubleConstant(codeBlock)));
534         return result;
535     }
536     
537     bool isBooleanConstant(CodeBlock* codeBlock)
538     {
539         return isConstant() && valueOfJSConstantNode(codeBlock).isBoolean();
540     }
541     
542     bool hasVariableAccessData()
543     {
544         switch (op) {
545         case GetLocal:
546         case SetLocal:
547         case Phi:
548         case SetArgument:
549             return true;
550         default:
551             return false;
552         }
553     }
554     
555     bool hasLocal()
556     {
557         return hasVariableAccessData();
558     }
559     
560     VariableAccessData* variableAccessData()
561     {
562         return reinterpret_cast<VariableAccessData*>(m_opInfo)->find();
563     }
564     
565     VirtualRegister local()
566     {
567         return variableAccessData()->local();
568     }
569
570 #if !ASSERT_DISABLED
571     bool hasIdentifier()
572     {
573         switch (op) {
574         case GetById:
575         case PutById:
576         case PutByIdDirect:
577         case GetMethod:
578         case CheckMethod:
579         case Resolve:
580         case ResolveBase:
581         case ResolveBaseStrictPut:
582             return true;
583         default:
584             return false;
585         }
586     }
587 #endif
588
589     unsigned identifierNumber()
590     {
591         ASSERT(hasIdentifier());
592         return m_opInfo;
593     }
594     
595     unsigned resolveGlobalDataIndex()
596     {
597         ASSERT(op == ResolveGlobal);
598         return m_opInfo;
599     }
600
601     bool hasArithNodeFlags()
602     {
603         switch (op) {
604         case ValueToNumber:
605         case ValueToDouble:
606         case UInt32ToNumber:
607         case ArithAdd:
608         case ArithSub:
609         case ArithMul:
610         case ArithAbs:
611         case ArithMin:
612         case ArithMax:
613         case ArithMod:
614         case ArithDiv:
615         case ValueAdd:
616             return true;
617         default:
618             return false;
619         }
620     }
621     
622     ArithNodeFlags rawArithNodeFlags()
623     {
624         ASSERT(hasArithNodeFlags());
625         return m_opInfo;
626     }
627     
628     // This corrects the arithmetic node flags, so that irrelevant bits are
629     // ignored. In particular, anything other than ArithMul does not need
630     // to know if it can speculate on negative zero.
631     ArithNodeFlags arithNodeFlags()
632     {
633         ArithNodeFlags result = rawArithNodeFlags();
634         if (op == ArithMul)
635             return result;
636         return result & ~NodeNeedsNegZero;
637     }
638     
639     ArithNodeFlags arithNodeFlagsForCompare()
640     {
641         if (hasArithNodeFlags())
642             return arithNodeFlags();
643         return 0;
644     }
645     
646     void setArithNodeFlag(ArithNodeFlags flags)
647     {
648         ASSERT(hasArithNodeFlags());
649         m_opInfo = flags;
650     }
651     
652     bool mergeArithNodeFlags(ArithNodeFlags flags)
653     {
654         if (!hasArithNodeFlags())
655             return false;
656         ArithNodeFlags newFlags = m_opInfo | flags;
657         if (newFlags == m_opInfo)
658             return false;
659         m_opInfo = newFlags;
660         return true;
661     }
662     
663     bool hasConstantBuffer()
664     {
665         return op == NewArrayBuffer;
666     }
667     
668     unsigned startConstant()
669     {
670         ASSERT(hasConstantBuffer());
671         return m_opInfo;
672     }
673     
674     unsigned numConstants()
675     {
676         ASSERT(hasConstantBuffer());
677         return m_opInfo2;
678     }
679     
680     bool hasRegexpIndex()
681     {
682         return op == NewRegexp;
683     }
684     
685     unsigned regexpIndex()
686     {
687         ASSERT(hasRegexpIndex());
688         return m_opInfo;
689     }
690     
691     bool hasVarNumber()
692     {
693         return op == GetGlobalVar || op == PutGlobalVar || op == GetScopedVar || op == PutScopedVar;
694     }
695
696     unsigned varNumber()
697     {
698         ASSERT(hasVarNumber());
699         return m_opInfo;
700     }
701
702     bool hasScopeChainDepth()
703     {
704         return op == GetScopeChain;
705     }
706     
707     unsigned scopeChainDepth()
708     {
709         ASSERT(hasScopeChainDepth());
710         return m_opInfo;
711     }
712
713     bool hasResult()
714     {
715         return op & NodeResultMask;
716     }
717
718     bool hasInt32Result()
719     {
720         return (op & NodeResultMask) == NodeResultInt32;
721     }
722     
723     bool hasNumberResult()
724     {
725         return (op & NodeResultMask) == NodeResultNumber;
726     }
727     
728     bool hasJSResult()
729     {
730         return (op & NodeResultMask) == NodeResultJS;
731     }
732     
733     bool hasBooleanResult()
734     {
735         return (op & NodeResultMask) == NodeResultBoolean;
736     }
737
738     bool isJump()
739     {
740         return op & NodeIsJump;
741     }
742
743     bool isBranch()
744     {
745         return op & NodeIsBranch;
746     }
747
748     bool isTerminal()
749     {
750         return op & NodeIsTerminal;
751     }
752
753     unsigned takenBytecodeOffset()
754     {
755         ASSERT(isBranch() || isJump());
756         return m_opInfo;
757     }
758
759     unsigned notTakenBytecodeOffset()
760     {
761         ASSERT(isBranch());
762         return m_opInfo2;
763     }
764     
765     bool hasHeapPrediction()
766     {
767         switch (op) {
768         case GetById:
769         case GetMethod:
770         case GetByVal:
771         case Call:
772         case Construct:
773         case GetByOffset:
774         case GetScopedVar:
775         case Resolve:
776         case ResolveBase:
777         case ResolveBaseStrictPut:
778         case ResolveGlobal:
779         case ArrayPop:
780         case ArrayPush:
781             return true;
782         default:
783             return false;
784         }
785     }
786     
787     PredictedType getHeapPrediction()
788     {
789         ASSERT(hasHeapPrediction());
790         return static_cast<PredictedType>(m_opInfo2);
791     }
792     
793     bool predictHeap(PredictedType prediction)
794     {
795         ASSERT(hasHeapPrediction());
796         
797         return mergePrediction(m_opInfo2, prediction);
798     }
799     
800     bool hasMethodCheckData()
801     {
802         return op == CheckMethod;
803     }
804     
805     unsigned methodCheckDataIndex()
806     {
807         ASSERT(hasMethodCheckData());
808         return m_opInfo2;
809     }
810     
811     bool hasStructureTransitionData()
812     {
813         return op == PutStructure;
814     }
815     
816     StructureTransitionData& structureTransitionData()
817     {
818         ASSERT(hasStructureTransitionData());
819         return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
820     }
821     
822     bool hasStructureSet()
823     {
824         return op == CheckStructure;
825     }
826     
827     StructureSet& structureSet()
828     {
829         ASSERT(hasStructureSet());
830         return *reinterpret_cast<StructureSet*>(m_opInfo);
831     }
832     
833     bool hasStorageAccessData()
834     {
835         return op == GetByOffset || op == PutByOffset;
836     }
837     
838     unsigned storageAccessDataIndex()
839     {
840         return m_opInfo;
841     }
842     
843     bool hasVirtualRegister()
844     {
845         return m_virtualRegister != InvalidVirtualRegister;
846     }
847     
848     VirtualRegister virtualRegister()
849     {
850         ASSERT(hasResult());
851         ASSERT(m_virtualRegister != InvalidVirtualRegister);
852         return m_virtualRegister;
853     }
854
855     void setVirtualRegister(VirtualRegister virtualRegister)
856     {
857         ASSERT(hasResult());
858         ASSERT(m_virtualRegister == InvalidVirtualRegister);
859         m_virtualRegister = virtualRegister;
860     }
861
862     bool shouldGenerate()
863     {
864         return m_refCount && op != Phi;
865     }
866
867     unsigned refCount()
868     {
869         return m_refCount;
870     }
871
872     // returns true when ref count passes from 0 to 1.
873     bool ref()
874     {
875         return !m_refCount++;
876     }
877
878     unsigned adjustedRefCount()
879     {
880         return mustGenerate() ? m_refCount - 1 : m_refCount;
881     }
882     
883     void setRefCount(unsigned refCount)
884     {
885         m_refCount = refCount;
886     }
887     
888     NodeIndex child1()
889     {
890         ASSERT(!(op & NodeHasVarArgs));
891         return children.fixed.child1;
892     }
893     
894     // This is useful if you want to do a fast check on the first child
895     // before also doing a check on the opcode. Use this with care and
896     // avoid it if possible.
897     NodeIndex child1Unchecked()
898     {
899         return children.fixed.child1;
900     }
901
902     NodeIndex child2()
903     {
904         ASSERT(!(op & NodeHasVarArgs));
905         return children.fixed.child2;
906     }
907
908     NodeIndex child3()
909     {
910         ASSERT(!(op & NodeHasVarArgs));
911         return children.fixed.child3;
912     }
913     
914     unsigned firstChild()
915     {
916         ASSERT(op & NodeHasVarArgs);
917         return children.variable.firstChild;
918     }
919     
920     unsigned numChildren()
921     {
922         ASSERT(op & NodeHasVarArgs);
923         return children.variable.numChildren;
924     }
925     
926     PredictedType prediction()
927     {
928         return m_prediction;
929     }
930     
931     bool predict(PredictedType prediction)
932     {
933         return mergePrediction(m_prediction, prediction);
934     }
935     
936     // This enum value describes the type of the node.
937     NodeType op;
938     // Used to look up exception handling information (currently implemented as a bytecode index).
939     CodeOrigin codeOrigin;
940     // References to up to 3 children (0 for no child).
941     union {
942         struct {
943             NodeIndex child1, child2, child3;
944         } fixed;
945         struct {
946             unsigned firstChild;
947             unsigned numChildren;
948         } variable;
949     } children;
950
951 private:
952     // The virtual register number (spill location) associated with this .
953     VirtualRegister m_virtualRegister;
954     // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
955     unsigned m_refCount;
956     // Immediate values, accesses type-checked via accessors above. The first one is
957     // big enough to store a pointer.
958     uintptr_t m_opInfo;
959     unsigned m_opInfo2;
960     // The prediction ascribed to this node after propagation.
961     PredictedType m_prediction;
962 };
963
964 } } // namespace JSC::DFG
965
966 #endif
967 #endif