]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGNode.h
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / dfg / DFGNode.h
1 /*
2 * Copyright (C) 2011, 2012, 2013 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 <wtf/Platform.h>
30
31 #if ENABLE(DFG_JIT)
32
33 #include "CodeBlock.h"
34 #include "CodeOrigin.h"
35 #include "DFGAbstractValue.h"
36 #include "DFGAdjacencyList.h"
37 #include "DFGArrayMode.h"
38 #include "DFGCommon.h"
39 #include "DFGNodeFlags.h"
40 #include "DFGNodeType.h"
41 #include "DFGVariableAccessData.h"
42 #include "JSCJSValue.h"
43 #include "Operands.h"
44 #include "SpeculatedType.h"
45 #include "StructureSet.h"
46 #include "ValueProfile.h"
47
48 namespace JSC { namespace DFG {
49
50 struct StructureTransitionData {
51 Structure* previousStructure;
52 Structure* newStructure;
53
54 StructureTransitionData() { }
55
56 StructureTransitionData(Structure* previousStructure, Structure* newStructure)
57 : previousStructure(previousStructure)
58 , newStructure(newStructure)
59 {
60 }
61 };
62
63 struct NewArrayBufferData {
64 unsigned startConstant;
65 unsigned numConstants;
66 IndexingType indexingType;
67 };
68
69 // This type used in passing an immediate argument to Node constructor;
70 // distinguishes an immediate value (typically an index into a CodeBlock data structure -
71 // a constant index, argument, or identifier) from a Node*.
72 struct OpInfo {
73 explicit OpInfo(int32_t value) : m_value(static_cast<uintptr_t>(value)) { }
74 explicit OpInfo(uint32_t value) : m_value(static_cast<uintptr_t>(value)) { }
75 #if OS(DARWIN) || USE(JSVALUE64)
76 explicit OpInfo(size_t value) : m_value(static_cast<uintptr_t>(value)) { }
77 #endif
78 explicit OpInfo(void* value) : m_value(reinterpret_cast<uintptr_t>(value)) { }
79 uintptr_t m_value;
80 };
81
82 // === Node ===
83 //
84 // Node represents a single operation in the data flow graph.
85 struct Node {
86 enum VarArgTag { VarArg };
87
88 Node() { }
89
90 Node(NodeType op, CodeOrigin codeOrigin, const AdjacencyList& children)
91 : codeOrigin(codeOrigin)
92 , children(children)
93 , m_virtualRegister(InvalidVirtualRegister)
94 , m_refCount(1)
95 , m_prediction(SpecNone)
96 {
97 setOpAndDefaultFlags(op);
98 }
99
100 // Construct a node with up to 3 children, no immediate value.
101 Node(NodeType op, CodeOrigin codeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
102 : codeOrigin(codeOrigin)
103 , children(AdjacencyList::Fixed, child1, child2, child3)
104 , m_virtualRegister(InvalidVirtualRegister)
105 , m_refCount(1)
106 , m_prediction(SpecNone)
107 {
108 setOpAndDefaultFlags(op);
109 ASSERT(!(m_flags & NodeHasVarArgs));
110 }
111
112 // Construct a node with up to 3 children and an immediate value.
113 Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
114 : codeOrigin(codeOrigin)
115 , children(AdjacencyList::Fixed, child1, child2, child3)
116 , m_virtualRegister(InvalidVirtualRegister)
117 , m_refCount(1)
118 , m_opInfo(imm.m_value)
119 , m_prediction(SpecNone)
120 {
121 setOpAndDefaultFlags(op);
122 ASSERT(!(m_flags & NodeHasVarArgs));
123 }
124
125 // Construct a node with up to 3 children and two immediate values.
126 Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
127 : codeOrigin(codeOrigin)
128 , children(AdjacencyList::Fixed, child1, child2, child3)
129 , m_virtualRegister(InvalidVirtualRegister)
130 , m_refCount(1)
131 , m_opInfo(imm1.m_value)
132 , m_opInfo2(safeCast<unsigned>(imm2.m_value))
133 , m_prediction(SpecNone)
134 {
135 setOpAndDefaultFlags(op);
136 ASSERT(!(m_flags & NodeHasVarArgs));
137 }
138
139 // Construct a node with a variable number of children and two immediate values.
140 Node(VarArgTag, NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
141 : codeOrigin(codeOrigin)
142 , children(AdjacencyList::Variable, firstChild, numChildren)
143 , m_virtualRegister(InvalidVirtualRegister)
144 , m_refCount(1)
145 , m_opInfo(imm1.m_value)
146 , m_opInfo2(safeCast<unsigned>(imm2.m_value))
147 , m_prediction(SpecNone)
148 {
149 setOpAndDefaultFlags(op);
150 ASSERT(m_flags & NodeHasVarArgs);
151 }
152
153 NodeType op() const { return static_cast<NodeType>(m_op); }
154 NodeFlags flags() const { return m_flags; }
155
156 // This is not a fast method.
157 unsigned index() const;
158
159 void setOp(NodeType op)
160 {
161 m_op = op;
162 }
163
164 void setFlags(NodeFlags flags)
165 {
166 m_flags = flags;
167 }
168
169 bool mergeFlags(NodeFlags flags)
170 {
171 ASSERT(!(flags & NodeDoesNotExit));
172 NodeFlags newFlags = m_flags | flags;
173 if (newFlags == m_flags)
174 return false;
175 m_flags = newFlags;
176 return true;
177 }
178
179 bool filterFlags(NodeFlags flags)
180 {
181 ASSERT(flags & NodeDoesNotExit);
182 NodeFlags newFlags = m_flags & flags;
183 if (newFlags == m_flags)
184 return false;
185 m_flags = newFlags;
186 return true;
187 }
188
189 bool clearFlags(NodeFlags flags)
190 {
191 return filterFlags(~flags);
192 }
193
194 void setOpAndDefaultFlags(NodeType op)
195 {
196 m_op = op;
197 m_flags = defaultFlags(op);
198 }
199
200 void setOpAndDefaultNonExitFlags(NodeType op)
201 {
202 ASSERT(!(m_flags & NodeHasVarArgs));
203 setOpAndDefaultNonExitFlagsUnchecked(op);
204 }
205
206 void setOpAndDefaultNonExitFlagsUnchecked(NodeType op)
207 {
208 m_op = op;
209 m_flags = (defaultFlags(op) & ~NodeExitsForward) | (m_flags & NodeExitsForward);
210 }
211
212 void convertToPhantom()
213 {
214 setOpAndDefaultNonExitFlags(Phantom);
215 }
216
217 void convertToPhantomUnchecked()
218 {
219 setOpAndDefaultNonExitFlagsUnchecked(Phantom);
220 }
221
222 void convertToIdentity()
223 {
224 RELEASE_ASSERT(child1());
225 RELEASE_ASSERT(!child2());
226 setOpAndDefaultNonExitFlags(Identity);
227 }
228
229 bool mustGenerate()
230 {
231 return m_flags & NodeMustGenerate;
232 }
233
234 void setCanExit(bool exits)
235 {
236 if (exits)
237 m_flags &= ~NodeDoesNotExit;
238 else
239 m_flags |= NodeDoesNotExit;
240 }
241
242 bool canExit()
243 {
244 return !(m_flags & NodeDoesNotExit);
245 }
246
247 bool isConstant()
248 {
249 return op() == JSConstant;
250 }
251
252 bool isWeakConstant()
253 {
254 return op() == WeakJSConstant;
255 }
256
257 bool isStronglyProvedConstantIn(InlineCallFrame* inlineCallFrame)
258 {
259 return isConstant() && codeOrigin.inlineCallFrame == inlineCallFrame;
260 }
261
262 bool isStronglyProvedConstantIn(const CodeOrigin& codeOrigin)
263 {
264 return isStronglyProvedConstantIn(codeOrigin.inlineCallFrame);
265 }
266
267 bool isPhantomArguments()
268 {
269 return op() == PhantomArguments;
270 }
271
272 bool hasConstant()
273 {
274 switch (op()) {
275 case JSConstant:
276 case WeakJSConstant:
277 case PhantomArguments:
278 return true;
279 default:
280 return false;
281 }
282 }
283
284 unsigned constantNumber()
285 {
286 ASSERT(isConstant());
287 return m_opInfo;
288 }
289
290 void convertToConstant(unsigned constantNumber)
291 {
292 m_op = JSConstant;
293 m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld);
294 m_opInfo = constantNumber;
295 children.reset();
296 }
297
298 void convertToWeakConstant(JSCell* cell)
299 {
300 m_op = WeakJSConstant;
301 m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld);
302 m_opInfo = bitwise_cast<uintptr_t>(cell);
303 children.reset();
304 }
305
306 void convertToGetLocalUnlinked(VirtualRegister local)
307 {
308 m_op = GetLocalUnlinked;
309 m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld);
310 m_opInfo = local;
311 children.reset();
312 }
313
314 void convertToStructureTransitionWatchpoint(Structure* structure)
315 {
316 ASSERT(m_op == CheckStructure || m_op == ForwardCheckStructure || m_op == ArrayifyToStructure);
317 m_opInfo = bitwise_cast<uintptr_t>(structure);
318 if (m_op == CheckStructure || m_op == ArrayifyToStructure)
319 m_op = StructureTransitionWatchpoint;
320 else
321 m_op = ForwardStructureTransitionWatchpoint;
322 }
323
324 void convertToStructureTransitionWatchpoint()
325 {
326 convertToStructureTransitionWatchpoint(structureSet().singletonStructure());
327 }
328
329 void convertToGetByOffset(unsigned storageAccessDataIndex, Edge storage)
330 {
331 ASSERT(m_op == GetById || m_op == GetByIdFlush);
332 m_opInfo = storageAccessDataIndex;
333 children.setChild1(storage);
334 m_op = GetByOffset;
335 m_flags &= ~NodeClobbersWorld;
336 }
337
338 void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage)
339 {
340 ASSERT(m_op == PutById || m_op == PutByIdDirect);
341 m_opInfo = storageAccessDataIndex;
342 children.setChild3(children.child2());
343 children.setChild2(children.child1());
344 children.setChild1(storage);
345 m_op = PutByOffset;
346 m_flags &= ~NodeClobbersWorld;
347 }
348
349 void convertToPhantomLocal()
350 {
351 ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgument));
352 m_op = PhantomLocal;
353 m_opInfo = child1()->m_opInfo; // Copy the variableAccessData.
354 children.setChild1(Edge());
355 }
356
357 void convertToGetLocal(VariableAccessData* variable, Node* phi)
358 {
359 ASSERT(m_op == GetLocalUnlinked);
360 m_op = GetLocal;
361 m_opInfo = bitwise_cast<uintptr_t>(variable);
362 children.setChild1(Edge(phi));
363 }
364
365 void convertToToString()
366 {
367 ASSERT(m_op == ToPrimitive);
368 m_op = ToString;
369 }
370
371 JSCell* weakConstant()
372 {
373 ASSERT(op() == WeakJSConstant);
374 return bitwise_cast<JSCell*>(m_opInfo);
375 }
376
377 JSValue valueOfJSConstant(CodeBlock* codeBlock)
378 {
379 switch (op()) {
380 case WeakJSConstant:
381 return JSValue(weakConstant());
382 case JSConstant:
383 return codeBlock->constantRegister(FirstConstantRegisterIndex + constantNumber()).get();
384 case PhantomArguments:
385 return JSValue();
386 default:
387 RELEASE_ASSERT_NOT_REACHED();
388 return JSValue(); // Have to return something in release mode.
389 }
390 }
391
392 bool isInt32Constant(CodeBlock* codeBlock)
393 {
394 return isConstant() && valueOfJSConstant(codeBlock).isInt32();
395 }
396
397 bool isDoubleConstant(CodeBlock* codeBlock)
398 {
399 bool result = isConstant() && valueOfJSConstant(codeBlock).isDouble();
400 if (result)
401 ASSERT(!isInt32Constant(codeBlock));
402 return result;
403 }
404
405 bool isNumberConstant(CodeBlock* codeBlock)
406 {
407 bool result = isConstant() && valueOfJSConstant(codeBlock).isNumber();
408 ASSERT(result == (isInt32Constant(codeBlock) || isDoubleConstant(codeBlock)));
409 return result;
410 }
411
412 bool isBooleanConstant(CodeBlock* codeBlock)
413 {
414 return isConstant() && valueOfJSConstant(codeBlock).isBoolean();
415 }
416
417 bool containsMovHint()
418 {
419 switch (op()) {
420 case SetLocal:
421 case MovHint:
422 case MovHintAndCheck:
423 case ZombieHint:
424 return true;
425 default:
426 return false;
427 }
428 }
429
430 bool hasVariableAccessData()
431 {
432 switch (op()) {
433 case GetLocal:
434 case SetLocal:
435 case MovHint:
436 case MovHintAndCheck:
437 case ZombieHint:
438 case Phi:
439 case SetArgument:
440 case Flush:
441 case PhantomLocal:
442 return true;
443 default:
444 return false;
445 }
446 }
447
448 bool hasLocal()
449 {
450 return hasVariableAccessData();
451 }
452
453 VariableAccessData* variableAccessData()
454 {
455 ASSERT(hasVariableAccessData());
456 return reinterpret_cast<VariableAccessData*>(m_opInfo)->find();
457 }
458
459 VirtualRegister local()
460 {
461 return variableAccessData()->local();
462 }
463
464 VirtualRegister unlinkedLocal()
465 {
466 ASSERT(op() == GetLocalUnlinked);
467 return static_cast<VirtualRegister>(m_opInfo);
468 }
469
470 bool hasIdentifier()
471 {
472 switch (op()) {
473 case GetById:
474 case GetByIdFlush:
475 case PutById:
476 case PutByIdDirect:
477 return true;
478 default:
479 return false;
480 }
481 }
482
483 unsigned identifierNumber()
484 {
485 ASSERT(hasIdentifier());
486 return m_opInfo;
487 }
488
489 unsigned resolveGlobalDataIndex()
490 {
491 ASSERT(op() == ResolveGlobal);
492 return m_opInfo;
493 }
494
495 unsigned resolveOperationsDataIndex()
496 {
497 ASSERT(op() == Resolve || op() == ResolveBase || op() == ResolveBaseStrictPut);
498 return m_opInfo;
499 }
500
501 bool hasArithNodeFlags()
502 {
503 switch (op()) {
504 case UInt32ToNumber:
505 case ArithAdd:
506 case ArithSub:
507 case ArithNegate:
508 case ArithMul:
509 case ArithAbs:
510 case ArithMin:
511 case ArithMax:
512 case ArithMod:
513 case ArithDiv:
514 case ValueAdd:
515 return true;
516 default:
517 return false;
518 }
519 }
520
521 // This corrects the arithmetic node flags, so that irrelevant bits are
522 // ignored. In particular, anything other than ArithMul does not need
523 // to know if it can speculate on negative zero.
524 NodeFlags arithNodeFlags()
525 {
526 NodeFlags result = m_flags & NodeArithFlagsMask;
527 if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == DoubleAsInt32)
528 return result;
529 return result & ~NodeNeedsNegZero;
530 }
531
532 bool hasConstantBuffer()
533 {
534 return op() == NewArrayBuffer;
535 }
536
537 NewArrayBufferData* newArrayBufferData()
538 {
539 ASSERT(hasConstantBuffer());
540 return reinterpret_cast<NewArrayBufferData*>(m_opInfo);
541 }
542
543 unsigned startConstant()
544 {
545 return newArrayBufferData()->startConstant;
546 }
547
548 unsigned numConstants()
549 {
550 return newArrayBufferData()->numConstants;
551 }
552
553 bool hasIndexingType()
554 {
555 switch (op()) {
556 case NewArray:
557 case NewArrayWithSize:
558 case NewArrayBuffer:
559 return true;
560 default:
561 return false;
562 }
563 }
564
565 IndexingType indexingType()
566 {
567 ASSERT(hasIndexingType());
568 if (op() == NewArrayBuffer)
569 return newArrayBufferData()->indexingType;
570 return m_opInfo;
571 }
572
573 bool hasInlineCapacity()
574 {
575 return op() == CreateThis;
576 }
577
578 unsigned inlineCapacity()
579 {
580 ASSERT(hasInlineCapacity());
581 return m_opInfo;
582 }
583
584 void setIndexingType(IndexingType indexingType)
585 {
586 ASSERT(hasIndexingType());
587 m_opInfo = indexingType;
588 }
589
590 bool hasRegexpIndex()
591 {
592 return op() == NewRegexp;
593 }
594
595 unsigned regexpIndex()
596 {
597 ASSERT(hasRegexpIndex());
598 return m_opInfo;
599 }
600
601 bool hasVarNumber()
602 {
603 return op() == GetScopedVar || op() == PutScopedVar;
604 }
605
606 unsigned varNumber()
607 {
608 ASSERT(hasVarNumber());
609 return m_opInfo;
610 }
611
612 bool hasIdentifierNumberForCheck()
613 {
614 return op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck;
615 }
616
617 unsigned identifierNumberForCheck()
618 {
619 ASSERT(hasIdentifierNumberForCheck());
620 return m_opInfo2;
621 }
622
623 bool hasRegisterPointer()
624 {
625 return op() == GetGlobalVar || op() == PutGlobalVar || op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck;
626 }
627
628 WriteBarrier<Unknown>* registerPointer()
629 {
630 return bitwise_cast<WriteBarrier<Unknown>*>(m_opInfo);
631 }
632
633 bool hasResult()
634 {
635 return m_flags & NodeResultMask;
636 }
637
638 bool hasInt32Result()
639 {
640 return (m_flags & NodeResultMask) == NodeResultInt32;
641 }
642
643 bool hasNumberResult()
644 {
645 return (m_flags & NodeResultMask) == NodeResultNumber;
646 }
647
648 bool hasJSResult()
649 {
650 return (m_flags & NodeResultMask) == NodeResultJS;
651 }
652
653 bool hasBooleanResult()
654 {
655 return (m_flags & NodeResultMask) == NodeResultBoolean;
656 }
657
658 bool hasStorageResult()
659 {
660 return (m_flags & NodeResultMask) == NodeResultStorage;
661 }
662
663 bool isJump()
664 {
665 return op() == Jump;
666 }
667
668 bool isBranch()
669 {
670 return op() == Branch;
671 }
672
673 bool isTerminal()
674 {
675 switch (op()) {
676 case Jump:
677 case Branch:
678 case Return:
679 case Unreachable:
680 return true;
681 default:
682 return false;
683 }
684 }
685
686 unsigned takenBytecodeOffsetDuringParsing()
687 {
688 ASSERT(isBranch() || isJump());
689 return m_opInfo;
690 }
691
692 unsigned notTakenBytecodeOffsetDuringParsing()
693 {
694 ASSERT(isBranch());
695 return m_opInfo2;
696 }
697
698 void setTakenBlockIndex(BlockIndex blockIndex)
699 {
700 ASSERT(isBranch() || isJump());
701 m_opInfo = blockIndex;
702 }
703
704 void setNotTakenBlockIndex(BlockIndex blockIndex)
705 {
706 ASSERT(isBranch());
707 m_opInfo2 = blockIndex;
708 }
709
710 BlockIndex takenBlockIndex()
711 {
712 ASSERT(isBranch() || isJump());
713 return m_opInfo;
714 }
715
716 BlockIndex notTakenBlockIndex()
717 {
718 ASSERT(isBranch());
719 return m_opInfo2;
720 }
721
722 unsigned numSuccessors()
723 {
724 switch (op()) {
725 case Jump:
726 return 1;
727 case Branch:
728 return 2;
729 default:
730 return 0;
731 }
732 }
733
734 BlockIndex successor(unsigned index)
735 {
736 switch (index) {
737 case 0:
738 return takenBlockIndex();
739 case 1:
740 return notTakenBlockIndex();
741 default:
742 RELEASE_ASSERT_NOT_REACHED();
743 return NoBlock;
744 }
745 }
746
747 BlockIndex successorForCondition(bool condition)
748 {
749 ASSERT(isBranch());
750 return condition ? takenBlockIndex() : notTakenBlockIndex();
751 }
752
753 bool hasHeapPrediction()
754 {
755 switch (op()) {
756 case GetById:
757 case GetByIdFlush:
758 case GetByVal:
759 case GetMyArgumentByVal:
760 case GetMyArgumentByValSafe:
761 case Call:
762 case Construct:
763 case GetByOffset:
764 case GetScopedVar:
765 case Resolve:
766 case ResolveBase:
767 case ResolveBaseStrictPut:
768 case ResolveGlobal:
769 case ArrayPop:
770 case ArrayPush:
771 case RegExpExec:
772 case RegExpTest:
773 case GetGlobalVar:
774 return true;
775 default:
776 return false;
777 }
778 }
779
780 SpeculatedType getHeapPrediction()
781 {
782 ASSERT(hasHeapPrediction());
783 return static_cast<SpeculatedType>(m_opInfo2);
784 }
785
786 bool predictHeap(SpeculatedType prediction)
787 {
788 ASSERT(hasHeapPrediction());
789
790 return mergeSpeculation(m_opInfo2, prediction);
791 }
792
793 bool hasFunction()
794 {
795 switch (op()) {
796 case CheckFunction:
797 case AllocationProfileWatchpoint:
798 return true;
799 default:
800 return false;
801 }
802 }
803
804 JSCell* function()
805 {
806 ASSERT(hasFunction());
807 JSCell* result = reinterpret_cast<JSFunction*>(m_opInfo);
808 ASSERT(JSValue(result).isFunction());
809 return result;
810 }
811
812 bool hasExecutable()
813 {
814 return op() == CheckExecutable;
815 }
816
817 ExecutableBase* executable()
818 {
819 return jsCast<ExecutableBase*>(reinterpret_cast<JSCell*>(m_opInfo));
820 }
821
822 bool hasStructureTransitionData()
823 {
824 switch (op()) {
825 case PutStructure:
826 case PhantomPutStructure:
827 case AllocatePropertyStorage:
828 case ReallocatePropertyStorage:
829 return true;
830 default:
831 return false;
832 }
833 }
834
835 StructureTransitionData& structureTransitionData()
836 {
837 ASSERT(hasStructureTransitionData());
838 return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
839 }
840
841 bool hasStructureSet()
842 {
843 switch (op()) {
844 case CheckStructure:
845 case ForwardCheckStructure:
846 return true;
847 default:
848 return false;
849 }
850 }
851
852 StructureSet& structureSet()
853 {
854 ASSERT(hasStructureSet());
855 return *reinterpret_cast<StructureSet*>(m_opInfo);
856 }
857
858 bool hasStructure()
859 {
860 switch (op()) {
861 case StructureTransitionWatchpoint:
862 case ForwardStructureTransitionWatchpoint:
863 case ArrayifyToStructure:
864 case NewObject:
865 case NewStringObject:
866 return true;
867 default:
868 return false;
869 }
870 }
871
872 Structure* structure()
873 {
874 ASSERT(hasStructure());
875 return reinterpret_cast<Structure*>(m_opInfo);
876 }
877
878 bool hasStorageAccessData()
879 {
880 return op() == GetByOffset || op() == PutByOffset;
881 }
882
883 unsigned storageAccessDataIndex()
884 {
885 ASSERT(hasStorageAccessData());
886 return m_opInfo;
887 }
888
889 bool hasFunctionDeclIndex()
890 {
891 return op() == NewFunction
892 || op() == NewFunctionNoCheck;
893 }
894
895 unsigned functionDeclIndex()
896 {
897 ASSERT(hasFunctionDeclIndex());
898 return m_opInfo;
899 }
900
901 bool hasFunctionExprIndex()
902 {
903 return op() == NewFunctionExpression;
904 }
905
906 unsigned functionExprIndex()
907 {
908 ASSERT(hasFunctionExprIndex());
909 return m_opInfo;
910 }
911
912 bool hasArrayMode()
913 {
914 switch (op()) {
915 case GetIndexedPropertyStorage:
916 case GetArrayLength:
917 case PutByVal:
918 case PutByValAlias:
919 case GetByVal:
920 case StringCharAt:
921 case StringCharCodeAt:
922 case CheckArray:
923 case Arrayify:
924 case ArrayifyToStructure:
925 case ArrayPush:
926 case ArrayPop:
927 return true;
928 default:
929 return false;
930 }
931 }
932
933 ArrayMode arrayMode()
934 {
935 ASSERT(hasArrayMode());
936 if (op() == ArrayifyToStructure)
937 return ArrayMode::fromWord(m_opInfo2);
938 return ArrayMode::fromWord(m_opInfo);
939 }
940
941 bool setArrayMode(ArrayMode arrayMode)
942 {
943 ASSERT(hasArrayMode());
944 if (this->arrayMode() == arrayMode)
945 return false;
946 m_opInfo = arrayMode.asWord();
947 return true;
948 }
949
950 bool hasVirtualRegister()
951 {
952 return m_virtualRegister != InvalidVirtualRegister;
953 }
954
955 VirtualRegister virtualRegister()
956 {
957 ASSERT(hasResult());
958 ASSERT(m_virtualRegister != InvalidVirtualRegister);
959 return m_virtualRegister;
960 }
961
962 void setVirtualRegister(VirtualRegister virtualRegister)
963 {
964 ASSERT(hasResult());
965 ASSERT(m_virtualRegister == InvalidVirtualRegister);
966 m_virtualRegister = virtualRegister;
967 }
968
969 bool hasArgumentPositionStart()
970 {
971 return op() == InlineStart;
972 }
973
974 unsigned argumentPositionStart()
975 {
976 ASSERT(hasArgumentPositionStart());
977 return m_opInfo;
978 }
979
980 bool hasExecutionCounter()
981 {
982 return op() == CountExecution;
983 }
984
985 Profiler::ExecutionCounter* executionCounter()
986 {
987 return bitwise_cast<Profiler::ExecutionCounter*>(m_opInfo);
988 }
989
990 bool shouldGenerate()
991 {
992 return m_refCount;
993 }
994
995 bool willHaveCodeGenOrOSR()
996 {
997 switch (op()) {
998 case SetLocal:
999 case MovHint:
1000 case ZombieHint:
1001 case MovHintAndCheck:
1002 case Int32ToDouble:
1003 case ForwardInt32ToDouble:
1004 case ValueToInt32:
1005 case UInt32ToNumber:
1006 case DoubleAsInt32:
1007 case PhantomArguments:
1008 return true;
1009 case Nop:
1010 return false;
1011 case Phantom:
1012 return child1().useKindUnchecked() != UntypedUse || child2().useKindUnchecked() != UntypedUse || child3().useKindUnchecked() != UntypedUse;
1013 default:
1014 return shouldGenerate();
1015 }
1016 }
1017
1018 unsigned refCount()
1019 {
1020 return m_refCount;
1021 }
1022
1023 unsigned postfixRef()
1024 {
1025 return m_refCount++;
1026 }
1027
1028 unsigned adjustedRefCount()
1029 {
1030 return mustGenerate() ? m_refCount - 1 : m_refCount;
1031 }
1032
1033 void setRefCount(unsigned refCount)
1034 {
1035 m_refCount = refCount;
1036 }
1037
1038 Edge& child1()
1039 {
1040 ASSERT(!(m_flags & NodeHasVarArgs));
1041 return children.child1();
1042 }
1043
1044 // This is useful if you want to do a fast check on the first child
1045 // before also doing a check on the opcode. Use this with care and
1046 // avoid it if possible.
1047 Edge child1Unchecked()
1048 {
1049 return children.child1Unchecked();
1050 }
1051
1052 Edge& child2()
1053 {
1054 ASSERT(!(m_flags & NodeHasVarArgs));
1055 return children.child2();
1056 }
1057
1058 Edge& child3()
1059 {
1060 ASSERT(!(m_flags & NodeHasVarArgs));
1061 return children.child3();
1062 }
1063
1064 unsigned firstChild()
1065 {
1066 ASSERT(m_flags & NodeHasVarArgs);
1067 return children.firstChild();
1068 }
1069
1070 unsigned numChildren()
1071 {
1072 ASSERT(m_flags & NodeHasVarArgs);
1073 return children.numChildren();
1074 }
1075
1076 UseKind binaryUseKind()
1077 {
1078 ASSERT(child1().useKind() == child2().useKind());
1079 return child1().useKind();
1080 }
1081
1082 bool isBinaryUseKind(UseKind useKind)
1083 {
1084 return child1().useKind() == useKind && child2().useKind() == useKind;
1085 }
1086
1087 SpeculatedType prediction()
1088 {
1089 return m_prediction;
1090 }
1091
1092 bool predict(SpeculatedType prediction)
1093 {
1094 return mergeSpeculation(m_prediction, prediction);
1095 }
1096
1097 bool shouldSpeculateInteger()
1098 {
1099 return isInt32Speculation(prediction());
1100 }
1101
1102 bool shouldSpeculateIntegerForArithmetic()
1103 {
1104 return isInt32SpeculationForArithmetic(prediction());
1105 }
1106
1107 bool shouldSpeculateIntegerExpectingDefined()
1108 {
1109 return isInt32SpeculationExpectingDefined(prediction());
1110 }
1111
1112 bool shouldSpeculateDouble()
1113 {
1114 return isDoubleSpeculation(prediction());
1115 }
1116
1117 bool shouldSpeculateDoubleForArithmetic()
1118 {
1119 return isDoubleSpeculationForArithmetic(prediction());
1120 }
1121
1122 bool shouldSpeculateNumber()
1123 {
1124 return isNumberSpeculation(prediction());
1125 }
1126
1127 bool shouldSpeculateNumberExpectingDefined()
1128 {
1129 return isNumberSpeculationExpectingDefined(prediction());
1130 }
1131
1132 bool shouldSpeculateBoolean()
1133 {
1134 return isBooleanSpeculation(prediction());
1135 }
1136
1137 bool shouldSpeculateString()
1138 {
1139 return isStringSpeculation(prediction());
1140 }
1141
1142 bool shouldSpeculateStringObject()
1143 {
1144 return isStringObjectSpeculation(prediction());
1145 }
1146
1147 bool shouldSpeculateStringOrStringObject()
1148 {
1149 return isStringOrStringObjectSpeculation(prediction());
1150 }
1151
1152 bool shouldSpeculateFinalObject()
1153 {
1154 return isFinalObjectSpeculation(prediction());
1155 }
1156
1157 bool shouldSpeculateFinalObjectOrOther()
1158 {
1159 return isFinalObjectOrOtherSpeculation(prediction());
1160 }
1161
1162 bool shouldSpeculateArray()
1163 {
1164 return isArraySpeculation(prediction());
1165 }
1166
1167 bool shouldSpeculateArguments()
1168 {
1169 return isArgumentsSpeculation(prediction());
1170 }
1171
1172 bool shouldSpeculateInt8Array()
1173 {
1174 return isInt8ArraySpeculation(prediction());
1175 }
1176
1177 bool shouldSpeculateInt16Array()
1178 {
1179 return isInt16ArraySpeculation(prediction());
1180 }
1181
1182 bool shouldSpeculateInt32Array()
1183 {
1184 return isInt32ArraySpeculation(prediction());
1185 }
1186
1187 bool shouldSpeculateUint8Array()
1188 {
1189 return isUint8ArraySpeculation(prediction());
1190 }
1191
1192 bool shouldSpeculateUint8ClampedArray()
1193 {
1194 return isUint8ClampedArraySpeculation(prediction());
1195 }
1196
1197 bool shouldSpeculateUint16Array()
1198 {
1199 return isUint16ArraySpeculation(prediction());
1200 }
1201
1202 bool shouldSpeculateUint32Array()
1203 {
1204 return isUint32ArraySpeculation(prediction());
1205 }
1206
1207 bool shouldSpeculateFloat32Array()
1208 {
1209 return isFloat32ArraySpeculation(prediction());
1210 }
1211
1212 bool shouldSpeculateFloat64Array()
1213 {
1214 return isFloat64ArraySpeculation(prediction());
1215 }
1216
1217 bool shouldSpeculateArrayOrOther()
1218 {
1219 return isArrayOrOtherSpeculation(prediction());
1220 }
1221
1222 bool shouldSpeculateObject()
1223 {
1224 return isObjectSpeculation(prediction());
1225 }
1226
1227 bool shouldSpeculateObjectOrOther()
1228 {
1229 return isObjectOrOtherSpeculation(prediction());
1230 }
1231
1232 bool shouldSpeculateCell()
1233 {
1234 return isCellSpeculation(prediction());
1235 }
1236
1237 static bool shouldSpeculateBoolean(Node* op1, Node* op2)
1238 {
1239 return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean();
1240 }
1241
1242 static bool shouldSpeculateInteger(Node* op1, Node* op2)
1243 {
1244 return op1->shouldSpeculateInteger() && op2->shouldSpeculateInteger();
1245 }
1246
1247 static bool shouldSpeculateIntegerForArithmetic(Node* op1, Node* op2)
1248 {
1249 return op1->shouldSpeculateIntegerForArithmetic() && op2->shouldSpeculateIntegerForArithmetic();
1250 }
1251
1252 static bool shouldSpeculateIntegerExpectingDefined(Node* op1, Node* op2)
1253 {
1254 return op1->shouldSpeculateIntegerExpectingDefined() && op2->shouldSpeculateIntegerExpectingDefined();
1255 }
1256
1257 static bool shouldSpeculateDoubleForArithmetic(Node* op1, Node* op2)
1258 {
1259 return op1->shouldSpeculateDoubleForArithmetic() && op2->shouldSpeculateDoubleForArithmetic();
1260 }
1261
1262 static bool shouldSpeculateNumber(Node* op1, Node* op2)
1263 {
1264 return op1->shouldSpeculateNumber() && op2->shouldSpeculateNumber();
1265 }
1266
1267 static bool shouldSpeculateNumberExpectingDefined(Node* op1, Node* op2)
1268 {
1269 return op1->shouldSpeculateNumberExpectingDefined() && op2->shouldSpeculateNumberExpectingDefined();
1270 }
1271
1272 static bool shouldSpeculateFinalObject(Node* op1, Node* op2)
1273 {
1274 return op1->shouldSpeculateFinalObject() && op2->shouldSpeculateFinalObject();
1275 }
1276
1277 static bool shouldSpeculateArray(Node* op1, Node* op2)
1278 {
1279 return op1->shouldSpeculateArray() && op2->shouldSpeculateArray();
1280 }
1281
1282 bool canSpeculateInteger()
1283 {
1284 return nodeCanSpeculateInteger(arithNodeFlags());
1285 }
1286
1287 void dumpChildren(PrintStream& out)
1288 {
1289 if (!child1())
1290 return;
1291 out.printf("@%u", child1()->index());
1292 if (!child2())
1293 return;
1294 out.printf(", @%u", child2()->index());
1295 if (!child3())
1296 return;
1297 out.printf(", @%u", child3()->index());
1298 }
1299
1300 // NB. This class must have a trivial destructor.
1301
1302 // Used to look up exception handling information (currently implemented as a bytecode index).
1303 CodeOrigin codeOrigin;
1304 // References to up to 3 children, or links to a variable length set of children.
1305 AdjacencyList children;
1306
1307 private:
1308 unsigned m_op : 10; // real type is NodeType
1309 unsigned m_flags : 22;
1310 // The virtual register number (spill location) associated with this .
1311 VirtualRegister m_virtualRegister;
1312 // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
1313 unsigned m_refCount;
1314 // Immediate values, accesses type-checked via accessors above. The first one is
1315 // big enough to store a pointer.
1316 uintptr_t m_opInfo;
1317 unsigned m_opInfo2;
1318 // The prediction ascribed to this node after propagation.
1319 SpeculatedType m_prediction;
1320
1321 public:
1322 // Fields used by various analyses.
1323 AbstractValue value;
1324 Node* replacement;
1325 };
1326
1327 } } // namespace JSC::DFG
1328
1329 namespace WTF {
1330
1331 void printInternal(PrintStream&, JSC::DFG::Node*);
1332
1333 } // namespace WTF
1334
1335 #endif
1336 #endif