]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGNode.h
JavaScriptCore-1218.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 Throw:
680 case ThrowReferenceError:
681 return true;
682 default:
683 return false;
684 }
685 }
686
687 unsigned takenBytecodeOffsetDuringParsing()
688 {
689 ASSERT(isBranch() || isJump());
690 return m_opInfo;
691 }
692
693 unsigned notTakenBytecodeOffsetDuringParsing()
694 {
695 ASSERT(isBranch());
696 return m_opInfo2;
697 }
698
699 void setTakenBlockIndex(BlockIndex blockIndex)
700 {
701 ASSERT(isBranch() || isJump());
702 m_opInfo = blockIndex;
703 }
704
705 void setNotTakenBlockIndex(BlockIndex blockIndex)
706 {
707 ASSERT(isBranch());
708 m_opInfo2 = blockIndex;
709 }
710
711 BlockIndex takenBlockIndex()
712 {
713 ASSERT(isBranch() || isJump());
714 return m_opInfo;
715 }
716
717 BlockIndex notTakenBlockIndex()
718 {
719 ASSERT(isBranch());
720 return m_opInfo2;
721 }
722
723 unsigned numSuccessors()
724 {
725 switch (op()) {
726 case Jump:
727 return 1;
728 case Branch:
729 return 2;
730 default:
731 return 0;
732 }
733 }
734
735 BlockIndex successor(unsigned index)
736 {
737 switch (index) {
738 case 0:
739 return takenBlockIndex();
740 case 1:
741 return notTakenBlockIndex();
742 default:
743 RELEASE_ASSERT_NOT_REACHED();
744 return NoBlock;
745 }
746 }
747
748 BlockIndex successorForCondition(bool condition)
749 {
750 ASSERT(isBranch());
751 return condition ? takenBlockIndex() : notTakenBlockIndex();
752 }
753
754 bool hasHeapPrediction()
755 {
756 switch (op()) {
757 case GetById:
758 case GetByIdFlush:
759 case GetByVal:
760 case GetMyArgumentByVal:
761 case GetMyArgumentByValSafe:
762 case Call:
763 case Construct:
764 case GetByOffset:
765 case GetScopedVar:
766 case Resolve:
767 case ResolveBase:
768 case ResolveBaseStrictPut:
769 case ResolveGlobal:
770 case ArrayPop:
771 case ArrayPush:
772 case RegExpExec:
773 case RegExpTest:
774 case GetGlobalVar:
775 return true;
776 default:
777 return false;
778 }
779 }
780
781 SpeculatedType getHeapPrediction()
782 {
783 ASSERT(hasHeapPrediction());
784 return static_cast<SpeculatedType>(m_opInfo2);
785 }
786
787 bool predictHeap(SpeculatedType prediction)
788 {
789 ASSERT(hasHeapPrediction());
790
791 return mergeSpeculation(m_opInfo2, prediction);
792 }
793
794 bool hasFunction()
795 {
796 switch (op()) {
797 case CheckFunction:
798 case AllocationProfileWatchpoint:
799 return true;
800 default:
801 return false;
802 }
803 }
804
805 JSCell* function()
806 {
807 ASSERT(hasFunction());
808 JSCell* result = reinterpret_cast<JSFunction*>(m_opInfo);
809 ASSERT(JSValue(result).isFunction());
810 return result;
811 }
812
813 bool hasExecutable()
814 {
815 return op() == CheckExecutable;
816 }
817
818 ExecutableBase* executable()
819 {
820 return jsCast<ExecutableBase*>(reinterpret_cast<JSCell*>(m_opInfo));
821 }
822
823 bool hasStructureTransitionData()
824 {
825 switch (op()) {
826 case PutStructure:
827 case PhantomPutStructure:
828 case AllocatePropertyStorage:
829 case ReallocatePropertyStorage:
830 return true;
831 default:
832 return false;
833 }
834 }
835
836 StructureTransitionData& structureTransitionData()
837 {
838 ASSERT(hasStructureTransitionData());
839 return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
840 }
841
842 bool hasStructureSet()
843 {
844 switch (op()) {
845 case CheckStructure:
846 case ForwardCheckStructure:
847 return true;
848 default:
849 return false;
850 }
851 }
852
853 StructureSet& structureSet()
854 {
855 ASSERT(hasStructureSet());
856 return *reinterpret_cast<StructureSet*>(m_opInfo);
857 }
858
859 bool hasStructure()
860 {
861 switch (op()) {
862 case StructureTransitionWatchpoint:
863 case ForwardStructureTransitionWatchpoint:
864 case ArrayifyToStructure:
865 case NewObject:
866 case NewStringObject:
867 return true;
868 default:
869 return false;
870 }
871 }
872
873 Structure* structure()
874 {
875 ASSERT(hasStructure());
876 return reinterpret_cast<Structure*>(m_opInfo);
877 }
878
879 bool hasStorageAccessData()
880 {
881 return op() == GetByOffset || op() == PutByOffset;
882 }
883
884 unsigned storageAccessDataIndex()
885 {
886 ASSERT(hasStorageAccessData());
887 return m_opInfo;
888 }
889
890 bool hasFunctionDeclIndex()
891 {
892 return op() == NewFunction
893 || op() == NewFunctionNoCheck;
894 }
895
896 unsigned functionDeclIndex()
897 {
898 ASSERT(hasFunctionDeclIndex());
899 return m_opInfo;
900 }
901
902 bool hasFunctionExprIndex()
903 {
904 return op() == NewFunctionExpression;
905 }
906
907 unsigned functionExprIndex()
908 {
909 ASSERT(hasFunctionExprIndex());
910 return m_opInfo;
911 }
912
913 bool hasArrayMode()
914 {
915 switch (op()) {
916 case GetIndexedPropertyStorage:
917 case GetArrayLength:
918 case PutByVal:
919 case PutByValAlias:
920 case GetByVal:
921 case StringCharAt:
922 case StringCharCodeAt:
923 case CheckArray:
924 case Arrayify:
925 case ArrayifyToStructure:
926 case ArrayPush:
927 case ArrayPop:
928 return true;
929 default:
930 return false;
931 }
932 }
933
934 ArrayMode arrayMode()
935 {
936 ASSERT(hasArrayMode());
937 if (op() == ArrayifyToStructure)
938 return ArrayMode::fromWord(m_opInfo2);
939 return ArrayMode::fromWord(m_opInfo);
940 }
941
942 bool setArrayMode(ArrayMode arrayMode)
943 {
944 ASSERT(hasArrayMode());
945 if (this->arrayMode() == arrayMode)
946 return false;
947 m_opInfo = arrayMode.asWord();
948 return true;
949 }
950
951 bool hasVirtualRegister()
952 {
953 return m_virtualRegister != InvalidVirtualRegister;
954 }
955
956 VirtualRegister virtualRegister()
957 {
958 ASSERT(hasResult());
959 ASSERT(m_virtualRegister != InvalidVirtualRegister);
960 return m_virtualRegister;
961 }
962
963 void setVirtualRegister(VirtualRegister virtualRegister)
964 {
965 ASSERT(hasResult());
966 ASSERT(m_virtualRegister == InvalidVirtualRegister);
967 m_virtualRegister = virtualRegister;
968 }
969
970 bool hasArgumentPositionStart()
971 {
972 return op() == InlineStart;
973 }
974
975 unsigned argumentPositionStart()
976 {
977 ASSERT(hasArgumentPositionStart());
978 return m_opInfo;
979 }
980
981 bool hasExecutionCounter()
982 {
983 return op() == CountExecution;
984 }
985
986 Profiler::ExecutionCounter* executionCounter()
987 {
988 return bitwise_cast<Profiler::ExecutionCounter*>(m_opInfo);
989 }
990
991 bool shouldGenerate()
992 {
993 return m_refCount;
994 }
995
996 bool willHaveCodeGenOrOSR()
997 {
998 switch (op()) {
999 case SetLocal:
1000 case MovHint:
1001 case ZombieHint:
1002 case MovHintAndCheck:
1003 case Int32ToDouble:
1004 case ForwardInt32ToDouble:
1005 case ValueToInt32:
1006 case UInt32ToNumber:
1007 case DoubleAsInt32:
1008 case PhantomArguments:
1009 return true;
1010 case Nop:
1011 return false;
1012 case Phantom:
1013 return child1().useKindUnchecked() != UntypedUse || child2().useKindUnchecked() != UntypedUse || child3().useKindUnchecked() != UntypedUse;
1014 default:
1015 return shouldGenerate();
1016 }
1017 }
1018
1019 unsigned refCount()
1020 {
1021 return m_refCount;
1022 }
1023
1024 unsigned postfixRef()
1025 {
1026 return m_refCount++;
1027 }
1028
1029 unsigned adjustedRefCount()
1030 {
1031 return mustGenerate() ? m_refCount - 1 : m_refCount;
1032 }
1033
1034 void setRefCount(unsigned refCount)
1035 {
1036 m_refCount = refCount;
1037 }
1038
1039 Edge& child1()
1040 {
1041 ASSERT(!(m_flags & NodeHasVarArgs));
1042 return children.child1();
1043 }
1044
1045 // This is useful if you want to do a fast check on the first child
1046 // before also doing a check on the opcode. Use this with care and
1047 // avoid it if possible.
1048 Edge child1Unchecked()
1049 {
1050 return children.child1Unchecked();
1051 }
1052
1053 Edge& child2()
1054 {
1055 ASSERT(!(m_flags & NodeHasVarArgs));
1056 return children.child2();
1057 }
1058
1059 Edge& child3()
1060 {
1061 ASSERT(!(m_flags & NodeHasVarArgs));
1062 return children.child3();
1063 }
1064
1065 unsigned firstChild()
1066 {
1067 ASSERT(m_flags & NodeHasVarArgs);
1068 return children.firstChild();
1069 }
1070
1071 unsigned numChildren()
1072 {
1073 ASSERT(m_flags & NodeHasVarArgs);
1074 return children.numChildren();
1075 }
1076
1077 UseKind binaryUseKind()
1078 {
1079 ASSERT(child1().useKind() == child2().useKind());
1080 return child1().useKind();
1081 }
1082
1083 bool isBinaryUseKind(UseKind useKind)
1084 {
1085 return child1().useKind() == useKind && child2().useKind() == useKind;
1086 }
1087
1088 SpeculatedType prediction()
1089 {
1090 return m_prediction;
1091 }
1092
1093 bool predict(SpeculatedType prediction)
1094 {
1095 return mergeSpeculation(m_prediction, prediction);
1096 }
1097
1098 bool shouldSpeculateInteger()
1099 {
1100 return isInt32Speculation(prediction());
1101 }
1102
1103 bool shouldSpeculateIntegerForArithmetic()
1104 {
1105 return isInt32SpeculationForArithmetic(prediction());
1106 }
1107
1108 bool shouldSpeculateIntegerExpectingDefined()
1109 {
1110 return isInt32SpeculationExpectingDefined(prediction());
1111 }
1112
1113 bool shouldSpeculateDouble()
1114 {
1115 return isDoubleSpeculation(prediction());
1116 }
1117
1118 bool shouldSpeculateDoubleForArithmetic()
1119 {
1120 return isDoubleSpeculationForArithmetic(prediction());
1121 }
1122
1123 bool shouldSpeculateNumber()
1124 {
1125 return isNumberSpeculation(prediction());
1126 }
1127
1128 bool shouldSpeculateNumberExpectingDefined()
1129 {
1130 return isNumberSpeculationExpectingDefined(prediction());
1131 }
1132
1133 bool shouldSpeculateBoolean()
1134 {
1135 return isBooleanSpeculation(prediction());
1136 }
1137
1138 bool shouldSpeculateString()
1139 {
1140 return isStringSpeculation(prediction());
1141 }
1142
1143 bool shouldSpeculateStringObject()
1144 {
1145 return isStringObjectSpeculation(prediction());
1146 }
1147
1148 bool shouldSpeculateStringOrStringObject()
1149 {
1150 return isStringOrStringObjectSpeculation(prediction());
1151 }
1152
1153 bool shouldSpeculateFinalObject()
1154 {
1155 return isFinalObjectSpeculation(prediction());
1156 }
1157
1158 bool shouldSpeculateFinalObjectOrOther()
1159 {
1160 return isFinalObjectOrOtherSpeculation(prediction());
1161 }
1162
1163 bool shouldSpeculateArray()
1164 {
1165 return isArraySpeculation(prediction());
1166 }
1167
1168 bool shouldSpeculateArguments()
1169 {
1170 return isArgumentsSpeculation(prediction());
1171 }
1172
1173 bool shouldSpeculateInt8Array()
1174 {
1175 return isInt8ArraySpeculation(prediction());
1176 }
1177
1178 bool shouldSpeculateInt16Array()
1179 {
1180 return isInt16ArraySpeculation(prediction());
1181 }
1182
1183 bool shouldSpeculateInt32Array()
1184 {
1185 return isInt32ArraySpeculation(prediction());
1186 }
1187
1188 bool shouldSpeculateUint8Array()
1189 {
1190 return isUint8ArraySpeculation(prediction());
1191 }
1192
1193 bool shouldSpeculateUint8ClampedArray()
1194 {
1195 return isUint8ClampedArraySpeculation(prediction());
1196 }
1197
1198 bool shouldSpeculateUint16Array()
1199 {
1200 return isUint16ArraySpeculation(prediction());
1201 }
1202
1203 bool shouldSpeculateUint32Array()
1204 {
1205 return isUint32ArraySpeculation(prediction());
1206 }
1207
1208 bool shouldSpeculateFloat32Array()
1209 {
1210 return isFloat32ArraySpeculation(prediction());
1211 }
1212
1213 bool shouldSpeculateFloat64Array()
1214 {
1215 return isFloat64ArraySpeculation(prediction());
1216 }
1217
1218 bool shouldSpeculateArrayOrOther()
1219 {
1220 return isArrayOrOtherSpeculation(prediction());
1221 }
1222
1223 bool shouldSpeculateObject()
1224 {
1225 return isObjectSpeculation(prediction());
1226 }
1227
1228 bool shouldSpeculateObjectOrOther()
1229 {
1230 return isObjectOrOtherSpeculation(prediction());
1231 }
1232
1233 bool shouldSpeculateCell()
1234 {
1235 return isCellSpeculation(prediction());
1236 }
1237
1238 static bool shouldSpeculateBoolean(Node* op1, Node* op2)
1239 {
1240 return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean();
1241 }
1242
1243 static bool shouldSpeculateInteger(Node* op1, Node* op2)
1244 {
1245 return op1->shouldSpeculateInteger() && op2->shouldSpeculateInteger();
1246 }
1247
1248 static bool shouldSpeculateIntegerForArithmetic(Node* op1, Node* op2)
1249 {
1250 return op1->shouldSpeculateIntegerForArithmetic() && op2->shouldSpeculateIntegerForArithmetic();
1251 }
1252
1253 static bool shouldSpeculateIntegerExpectingDefined(Node* op1, Node* op2)
1254 {
1255 return op1->shouldSpeculateIntegerExpectingDefined() && op2->shouldSpeculateIntegerExpectingDefined();
1256 }
1257
1258 static bool shouldSpeculateDoubleForArithmetic(Node* op1, Node* op2)
1259 {
1260 return op1->shouldSpeculateDoubleForArithmetic() && op2->shouldSpeculateDoubleForArithmetic();
1261 }
1262
1263 static bool shouldSpeculateNumber(Node* op1, Node* op2)
1264 {
1265 return op1->shouldSpeculateNumber() && op2->shouldSpeculateNumber();
1266 }
1267
1268 static bool shouldSpeculateNumberExpectingDefined(Node* op1, Node* op2)
1269 {
1270 return op1->shouldSpeculateNumberExpectingDefined() && op2->shouldSpeculateNumberExpectingDefined();
1271 }
1272
1273 static bool shouldSpeculateFinalObject(Node* op1, Node* op2)
1274 {
1275 return op1->shouldSpeculateFinalObject() && op2->shouldSpeculateFinalObject();
1276 }
1277
1278 static bool shouldSpeculateArray(Node* op1, Node* op2)
1279 {
1280 return op1->shouldSpeculateArray() && op2->shouldSpeculateArray();
1281 }
1282
1283 bool canSpeculateInteger()
1284 {
1285 return nodeCanSpeculateInteger(arithNodeFlags());
1286 }
1287
1288 void dumpChildren(PrintStream& out)
1289 {
1290 if (!child1())
1291 return;
1292 out.printf("@%u", child1()->index());
1293 if (!child2())
1294 return;
1295 out.printf(", @%u", child2()->index());
1296 if (!child3())
1297 return;
1298 out.printf(", @%u", child3()->index());
1299 }
1300
1301 // NB. This class must have a trivial destructor.
1302
1303 // Used to look up exception handling information (currently implemented as a bytecode index).
1304 CodeOrigin codeOrigin;
1305 // References to up to 3 children, or links to a variable length set of children.
1306 AdjacencyList children;
1307
1308 private:
1309 unsigned m_op : 10; // real type is NodeType
1310 unsigned m_flags : 22;
1311 // The virtual register number (spill location) associated with this .
1312 VirtualRegister m_virtualRegister;
1313 // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
1314 unsigned m_refCount;
1315 // Immediate values, accesses type-checked via accessors above. The first one is
1316 // big enough to store a pointer.
1317 uintptr_t m_opInfo;
1318 unsigned m_opInfo2;
1319 // The prediction ascribed to this node after propagation.
1320 SpeculatedType m_prediction;
1321
1322 public:
1323 // Fields used by various analyses.
1324 AbstractValue value;
1325 Node* replacement;
1326 };
1327
1328 } } // namespace JSC::DFG
1329
1330 namespace WTF {
1331
1332 void printInternal(PrintStream&, JSC::DFG::Node*);
1333
1334 } // namespace WTF
1335
1336 #endif
1337 #endif