]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGNode.h
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGNode.h
1 /*
2 * Copyright (C) 2011, 2012 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 "DFGAdjacencyList.h"
36 #include "DFGCommon.h"
37 #include "DFGNodeFlags.h"
38 #include "DFGNodeType.h"
39 #include "DFGVariableAccessData.h"
40 #include "JSValue.h"
41 #include "Operands.h"
42 #include "PredictedType.h"
43 #include "ValueProfile.h"
44
45 namespace JSC { namespace DFG {
46
47 struct StructureTransitionData {
48 Structure* previousStructure;
49 Structure* newStructure;
50
51 StructureTransitionData() { }
52
53 StructureTransitionData(Structure* previousStructure, Structure* newStructure)
54 : previousStructure(previousStructure)
55 , newStructure(newStructure)
56 {
57 }
58 };
59
60 // This type used in passing an immediate argument to Node constructor;
61 // distinguishes an immediate value (typically an index into a CodeBlock data structure -
62 // a constant index, argument, or identifier) from a NodeIndex.
63 struct OpInfo {
64 explicit OpInfo(int32_t value) : m_value(static_cast<uintptr_t>(value)) { }
65 explicit OpInfo(uint32_t value) : m_value(static_cast<uintptr_t>(value)) { }
66 #if OS(DARWIN) || USE(JSVALUE64)
67 explicit OpInfo(size_t value) : m_value(static_cast<uintptr_t>(value)) { }
68 #endif
69 explicit OpInfo(void* value) : m_value(reinterpret_cast<uintptr_t>(value)) { }
70 uintptr_t m_value;
71 };
72
73 // === Node ===
74 //
75 // Node represents a single operation in the data flow graph.
76 struct Node {
77 enum VarArgTag { VarArg };
78
79 // Construct a node with up to 3 children, no immediate value.
80 Node(NodeType op, CodeOrigin codeOrigin, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
81 : codeOrigin(codeOrigin)
82 , children(AdjacencyList::Fixed, child1, child2, child3)
83 , m_virtualRegister(InvalidVirtualRegister)
84 , m_refCount(0)
85 , m_prediction(PredictNone)
86 {
87 setOpAndDefaultFlags(op);
88 ASSERT(!(m_flags & NodeHasVarArgs));
89 }
90
91 // Construct a node with up to 3 children and an immediate value.
92 Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
93 : codeOrigin(codeOrigin)
94 , children(AdjacencyList::Fixed, child1, child2, child3)
95 , m_virtualRegister(InvalidVirtualRegister)
96 , m_refCount(0)
97 , m_opInfo(imm.m_value)
98 , m_prediction(PredictNone)
99 {
100 setOpAndDefaultFlags(op);
101 ASSERT(!(m_flags & NodeHasVarArgs));
102 }
103
104 // Construct a node with up to 3 children and two immediate values.
105 Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
106 : codeOrigin(codeOrigin)
107 , children(AdjacencyList::Fixed, child1, child2, child3)
108 , m_virtualRegister(InvalidVirtualRegister)
109 , m_refCount(0)
110 , m_opInfo(imm1.m_value)
111 , m_opInfo2(safeCast<unsigned>(imm2.m_value))
112 , m_prediction(PredictNone)
113 {
114 setOpAndDefaultFlags(op);
115 ASSERT(!(m_flags & NodeHasVarArgs));
116 }
117
118 // Construct a node with a variable number of children and two immediate values.
119 Node(VarArgTag, NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
120 : codeOrigin(codeOrigin)
121 , children(AdjacencyList::Variable, firstChild, numChildren)
122 , m_virtualRegister(InvalidVirtualRegister)
123 , m_refCount(0)
124 , m_opInfo(imm1.m_value)
125 , m_opInfo2(safeCast<unsigned>(imm2.m_value))
126 , m_prediction(PredictNone)
127 {
128 setOpAndDefaultFlags(op);
129 ASSERT(m_flags & NodeHasVarArgs);
130 }
131
132 NodeType op() const { return static_cast<NodeType>(m_op); }
133 NodeFlags flags() const { return m_flags; }
134
135 void setOp(NodeType op)
136 {
137 m_op = op;
138 }
139
140 void setFlags(NodeFlags flags)
141 {
142 m_flags = flags;
143 }
144
145 bool mergeFlags(NodeFlags flags)
146 {
147 NodeFlags newFlags = m_flags | flags;
148 if (newFlags == m_flags)
149 return false;
150 m_flags = newFlags;
151 return true;
152 }
153
154 bool filterFlags(NodeFlags flags)
155 {
156 NodeFlags newFlags = m_flags & flags;
157 if (newFlags == m_flags)
158 return false;
159 m_flags = newFlags;
160 return true;
161 }
162
163 bool clearFlags(NodeFlags flags)
164 {
165 return filterFlags(~flags);
166 }
167
168 void setOpAndDefaultFlags(NodeType op)
169 {
170 m_op = op;
171 m_flags = defaultFlags(op);
172 }
173
174 bool mustGenerate()
175 {
176 return m_flags & NodeMustGenerate;
177 }
178
179 bool isConstant()
180 {
181 return op() == JSConstant;
182 }
183
184 bool isWeakConstant()
185 {
186 return op() == WeakJSConstant;
187 }
188
189 bool hasConstant()
190 {
191 return isConstant() || isWeakConstant();
192 }
193
194 unsigned constantNumber()
195 {
196 ASSERT(isConstant());
197 return m_opInfo;
198 }
199
200 JSCell* weakConstant()
201 {
202 return bitwise_cast<JSCell*>(m_opInfo);
203 }
204
205 JSValue valueOfJSConstant(CodeBlock* codeBlock)
206 {
207 if (op() == WeakJSConstant)
208 return JSValue(weakConstant());
209 return codeBlock->constantRegister(FirstConstantRegisterIndex + constantNumber()).get();
210 }
211
212 bool isInt32Constant(CodeBlock* codeBlock)
213 {
214 return isConstant() && valueOfJSConstant(codeBlock).isInt32();
215 }
216
217 bool isDoubleConstant(CodeBlock* codeBlock)
218 {
219 bool result = isConstant() && valueOfJSConstant(codeBlock).isDouble();
220 if (result)
221 ASSERT(!isInt32Constant(codeBlock));
222 return result;
223 }
224
225 bool isNumberConstant(CodeBlock* codeBlock)
226 {
227 bool result = isConstant() && valueOfJSConstant(codeBlock).isNumber();
228 ASSERT(result == (isInt32Constant(codeBlock) || isDoubleConstant(codeBlock)));
229 return result;
230 }
231
232 bool isBooleanConstant(CodeBlock* codeBlock)
233 {
234 return isConstant() && valueOfJSConstant(codeBlock).isBoolean();
235 }
236
237 bool hasVariableAccessData()
238 {
239 switch (op()) {
240 case GetLocal:
241 case SetLocal:
242 case Phi:
243 case SetArgument:
244 case Flush:
245 return true;
246 default:
247 return false;
248 }
249 }
250
251 bool hasLocal()
252 {
253 return hasVariableAccessData();
254 }
255
256 VariableAccessData* variableAccessData()
257 {
258 ASSERT(hasVariableAccessData());
259 return reinterpret_cast<VariableAccessData*>(m_opInfo)->find();
260 }
261
262 VirtualRegister local()
263 {
264 return variableAccessData()->local();
265 }
266
267 bool hasIdentifier()
268 {
269 switch (op()) {
270 case GetById:
271 case GetByIdFlush:
272 case PutById:
273 case PutByIdDirect:
274 case Resolve:
275 case ResolveBase:
276 case ResolveBaseStrictPut:
277 return true;
278 default:
279 return false;
280 }
281 }
282
283 unsigned identifierNumber()
284 {
285 ASSERT(hasIdentifier());
286 return m_opInfo;
287 }
288
289 unsigned resolveGlobalDataIndex()
290 {
291 ASSERT(op() == ResolveGlobal);
292 return m_opInfo;
293 }
294
295 bool hasArithNodeFlags()
296 {
297 switch (op()) {
298 case UInt32ToNumber:
299 case ArithAdd:
300 case ArithSub:
301 case ArithNegate:
302 case ArithMul:
303 case ArithAbs:
304 case ArithMin:
305 case ArithMax:
306 case ArithMod:
307 case ArithDiv:
308 case ValueAdd:
309 return true;
310 default:
311 return false;
312 }
313 }
314
315 // This corrects the arithmetic node flags, so that irrelevant bits are
316 // ignored. In particular, anything other than ArithMul does not need
317 // to know if it can speculate on negative zero.
318 NodeFlags arithNodeFlags()
319 {
320 NodeFlags result = m_flags;
321 if (op() == ArithMul || op() == ArithDiv || op() == ArithMod)
322 return result;
323 return result & ~NodeNeedsNegZero;
324 }
325
326 bool hasConstantBuffer()
327 {
328 return op() == NewArrayBuffer;
329 }
330
331 unsigned startConstant()
332 {
333 ASSERT(hasConstantBuffer());
334 return m_opInfo;
335 }
336
337 unsigned numConstants()
338 {
339 ASSERT(hasConstantBuffer());
340 return m_opInfo2;
341 }
342
343 bool hasRegexpIndex()
344 {
345 return op() == NewRegexp;
346 }
347
348 unsigned regexpIndex()
349 {
350 ASSERT(hasRegexpIndex());
351 return m_opInfo;
352 }
353
354 bool hasVarNumber()
355 {
356 return op() == GetGlobalVar || op() == PutGlobalVar || op() == GetScopedVar || op() == PutScopedVar;
357 }
358
359 unsigned varNumber()
360 {
361 ASSERT(hasVarNumber());
362 return m_opInfo;
363 }
364
365 bool hasScopeChainDepth()
366 {
367 return op() == GetScopeChain;
368 }
369
370 unsigned scopeChainDepth()
371 {
372 ASSERT(hasScopeChainDepth());
373 return m_opInfo;
374 }
375
376 bool hasResult()
377 {
378 return m_flags & NodeResultMask;
379 }
380
381 bool hasInt32Result()
382 {
383 return (m_flags & NodeResultMask) == NodeResultInt32;
384 }
385
386 bool hasNumberResult()
387 {
388 return (m_flags & NodeResultMask) == NodeResultNumber;
389 }
390
391 bool hasJSResult()
392 {
393 return (m_flags & NodeResultMask) == NodeResultJS;
394 }
395
396 bool hasBooleanResult()
397 {
398 return (m_flags & NodeResultMask) == NodeResultBoolean;
399 }
400
401 bool isJump()
402 {
403 return op() == Jump;
404 }
405
406 bool isBranch()
407 {
408 return op() == Branch;
409 }
410
411 bool isTerminal()
412 {
413 switch (op()) {
414 case Jump:
415 case Branch:
416 case Return:
417 case Throw:
418 case ThrowReferenceError:
419 return true;
420 default:
421 return false;
422 }
423 }
424
425 unsigned takenBytecodeOffsetDuringParsing()
426 {
427 ASSERT(isBranch() || isJump());
428 return m_opInfo;
429 }
430
431 unsigned notTakenBytecodeOffsetDuringParsing()
432 {
433 ASSERT(isBranch());
434 return m_opInfo2;
435 }
436
437 void setTakenBlockIndex(BlockIndex blockIndex)
438 {
439 ASSERT(isBranch() || isJump());
440 m_opInfo = blockIndex;
441 }
442
443 void setNotTakenBlockIndex(BlockIndex blockIndex)
444 {
445 ASSERT(isBranch());
446 m_opInfo2 = blockIndex;
447 }
448
449 BlockIndex takenBlockIndex()
450 {
451 ASSERT(isBranch() || isJump());
452 return m_opInfo;
453 }
454
455 BlockIndex notTakenBlockIndex()
456 {
457 ASSERT(isBranch());
458 return m_opInfo2;
459 }
460
461 bool hasHeapPrediction()
462 {
463 switch (op()) {
464 case GetById:
465 case GetByIdFlush:
466 case GetByVal:
467 case Call:
468 case Construct:
469 case GetByOffset:
470 case GetScopedVar:
471 case Resolve:
472 case ResolveBase:
473 case ResolveBaseStrictPut:
474 case ResolveGlobal:
475 case ArrayPop:
476 case ArrayPush:
477 case RegExpExec:
478 case RegExpTest:
479 case GetGlobalVar:
480 return true;
481 default:
482 return false;
483 }
484 }
485
486 PredictedType getHeapPrediction()
487 {
488 ASSERT(hasHeapPrediction());
489 return static_cast<PredictedType>(m_opInfo2);
490 }
491
492 bool predictHeap(PredictedType prediction)
493 {
494 ASSERT(hasHeapPrediction());
495
496 return mergePrediction(m_opInfo2, prediction);
497 }
498
499 bool hasFunctionCheckData()
500 {
501 return op() == CheckFunction;
502 }
503
504 JSFunction* function()
505 {
506 ASSERT(hasFunctionCheckData());
507 return reinterpret_cast<JSFunction*>(m_opInfo);
508 }
509
510 bool hasStructureTransitionData()
511 {
512 return op() == PutStructure;
513 }
514
515 StructureTransitionData& structureTransitionData()
516 {
517 ASSERT(hasStructureTransitionData());
518 return *reinterpret_cast<StructureTransitionData*>(m_opInfo);
519 }
520
521 bool hasStructureSet()
522 {
523 return op() == CheckStructure;
524 }
525
526 StructureSet& structureSet()
527 {
528 ASSERT(hasStructureSet());
529 return *reinterpret_cast<StructureSet*>(m_opInfo);
530 }
531
532 bool hasStorageAccessData()
533 {
534 return op() == GetByOffset || op() == PutByOffset;
535 }
536
537 unsigned storageAccessDataIndex()
538 {
539 ASSERT(hasStorageAccessData());
540 return m_opInfo;
541 }
542
543 bool hasFunctionDeclIndex()
544 {
545 return op() == NewFunction
546 || op() == NewFunctionNoCheck;
547 }
548
549 unsigned functionDeclIndex()
550 {
551 ASSERT(hasFunctionDeclIndex());
552 return m_opInfo;
553 }
554
555 bool hasFunctionExprIndex()
556 {
557 return op() == NewFunctionExpression;
558 }
559
560 unsigned functionExprIndex()
561 {
562 ASSERT(hasFunctionExprIndex());
563 return m_opInfo;
564 }
565
566 bool hasVirtualRegister()
567 {
568 return m_virtualRegister != InvalidVirtualRegister;
569 }
570
571 VirtualRegister virtualRegister()
572 {
573 ASSERT(hasResult());
574 ASSERT(m_virtualRegister != InvalidVirtualRegister);
575 return m_virtualRegister;
576 }
577
578 void setVirtualRegister(VirtualRegister virtualRegister)
579 {
580 ASSERT(hasResult());
581 ASSERT(m_virtualRegister == InvalidVirtualRegister);
582 m_virtualRegister = virtualRegister;
583 }
584
585 bool shouldGenerate()
586 {
587 return m_refCount;
588 }
589
590 unsigned refCount()
591 {
592 return m_refCount;
593 }
594
595 // returns true when ref count passes from 0 to 1.
596 bool ref()
597 {
598 return !m_refCount++;
599 }
600
601 unsigned adjustedRefCount()
602 {
603 return mustGenerate() ? m_refCount - 1 : m_refCount;
604 }
605
606 void setRefCount(unsigned refCount)
607 {
608 m_refCount = refCount;
609 }
610
611 // Derefs the node and returns true if the ref count reached zero.
612 // In general you don't want to use this directly; use Graph::deref
613 // instead.
614 bool deref()
615 {
616 ASSERT(m_refCount);
617 return !--m_refCount;
618 }
619
620 Edge child1()
621 {
622 ASSERT(!(m_flags & NodeHasVarArgs));
623 return children.child1();
624 }
625
626 // This is useful if you want to do a fast check on the first child
627 // before also doing a check on the opcode. Use this with care and
628 // avoid it if possible.
629 Edge child1Unchecked()
630 {
631 return children.child1Unchecked();
632 }
633
634 Edge child2()
635 {
636 ASSERT(!(m_flags & NodeHasVarArgs));
637 return children.child2();
638 }
639
640 Edge child3()
641 {
642 ASSERT(!(m_flags & NodeHasVarArgs));
643 return children.child3();
644 }
645
646 unsigned firstChild()
647 {
648 ASSERT(m_flags & NodeHasVarArgs);
649 return children.firstChild();
650 }
651
652 unsigned numChildren()
653 {
654 ASSERT(m_flags & NodeHasVarArgs);
655 return children.numChildren();
656 }
657
658 PredictedType prediction()
659 {
660 return m_prediction;
661 }
662
663 bool predict(PredictedType prediction)
664 {
665 return mergePrediction(m_prediction, prediction);
666 }
667
668 bool shouldSpeculateInteger()
669 {
670 return isInt32Prediction(prediction());
671 }
672
673 bool shouldSpeculateDouble()
674 {
675 return isDoublePrediction(prediction());
676 }
677
678 bool shouldSpeculateNumber()
679 {
680 return isNumberPrediction(prediction());
681 }
682
683 bool shouldSpeculateBoolean()
684 {
685 return isBooleanPrediction(prediction());
686 }
687
688 bool shouldSpeculateFinalObject()
689 {
690 return isFinalObjectPrediction(prediction());
691 }
692
693 bool shouldSpeculateFinalObjectOrOther()
694 {
695 return isFinalObjectOrOtherPrediction(prediction());
696 }
697
698 bool shouldSpeculateArray()
699 {
700 return isArrayPrediction(prediction());
701 }
702
703 bool shouldSpeculateInt8Array()
704 {
705 return isInt8ArrayPrediction(prediction());
706 }
707
708 bool shouldSpeculateInt16Array()
709 {
710 return isInt16ArrayPrediction(prediction());
711 }
712
713 bool shouldSpeculateInt32Array()
714 {
715 return isInt32ArrayPrediction(prediction());
716 }
717
718 bool shouldSpeculateUint8Array()
719 {
720 return isUint8ArrayPrediction(prediction());
721 }
722
723 bool shouldSpeculateUint8ClampedArray()
724 {
725 return isUint8ClampedArrayPrediction(prediction());
726 }
727
728 bool shouldSpeculateUint16Array()
729 {
730 return isUint16ArrayPrediction(prediction());
731 }
732
733 bool shouldSpeculateUint32Array()
734 {
735 return isUint32ArrayPrediction(prediction());
736 }
737
738 bool shouldSpeculateFloat32Array()
739 {
740 return isFloat32ArrayPrediction(prediction());
741 }
742
743 bool shouldSpeculateFloat64Array()
744 {
745 return isFloat64ArrayPrediction(prediction());
746 }
747
748 bool shouldSpeculateArrayOrOther()
749 {
750 return isArrayOrOtherPrediction(prediction());
751 }
752
753 bool shouldSpeculateObject()
754 {
755 return isObjectPrediction(prediction());
756 }
757
758 bool shouldSpeculateCell()
759 {
760 return isCellPrediction(prediction());
761 }
762
763 static bool shouldSpeculateInteger(Node& op1, Node& op2)
764 {
765 return op1.shouldSpeculateInteger() && op2.shouldSpeculateInteger();
766 }
767
768 static bool shouldSpeculateNumber(Node& op1, Node& op2)
769 {
770 return op1.shouldSpeculateNumber() && op2.shouldSpeculateNumber();
771 }
772
773 static bool shouldSpeculateFinalObject(Node& op1, Node& op2)
774 {
775 return op1.shouldSpeculateFinalObject() && op2.shouldSpeculateFinalObject();
776 }
777
778 static bool shouldSpeculateArray(Node& op1, Node& op2)
779 {
780 return op1.shouldSpeculateArray() && op2.shouldSpeculateArray();
781 }
782
783 bool canSpeculateInteger()
784 {
785 return nodeCanSpeculateInteger(arithNodeFlags());
786 }
787
788 void dumpChildren(FILE* out)
789 {
790 if (!child1())
791 return;
792 fprintf(out, "@%u", child1().index());
793 if (!child2())
794 return;
795 fprintf(out, ", @%u", child2().index());
796 if (!child3())
797 return;
798 fprintf(out, ", @%u", child3().index());
799 }
800
801 // Used to look up exception handling information (currently implemented as a bytecode index).
802 CodeOrigin codeOrigin;
803 // References to up to 3 children, or links to a variable length set of children.
804 AdjacencyList children;
805
806 private:
807 uint16_t m_op; // real type is NodeType
808 NodeFlags m_flags;
809 // The virtual register number (spill location) associated with this .
810 VirtualRegister m_virtualRegister;
811 // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
812 unsigned m_refCount;
813 // Immediate values, accesses type-checked via accessors above. The first one is
814 // big enough to store a pointer.
815 uintptr_t m_opInfo;
816 unsigned m_opInfo2;
817 // The prediction ascribed to this node after propagation.
818 PredictedType m_prediction;
819 };
820
821 } } // namespace JSC::DFG
822
823 #endif
824 #endif