1/*
2 * Copyright (C) 2011-2018 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#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "B3SparseCollection.h"
31#include "BasicBlockLocation.h"
32#include "CodeBlock.h"
33#include "DFGAdjacencyList.h"
34#include "DFGArithMode.h"
35#include "DFGArrayMode.h"
36#include "DFGCommon.h"
37#include "DFGEpoch.h"
38#include "DFGLazyJSValue.h"
39#include "DFGMultiGetByOffsetData.h"
40#include "DFGNodeFlags.h"
41#include "DFGNodeOrigin.h"
42#include "DFGNodeType.h"
43#include "DFGObjectMaterializationData.h"
44#include "DFGOpInfo.h"
45#include "DFGRegisteredStructure.h"
46#include "DFGRegisteredStructureSet.h"
47#include "DFGTransition.h"
48#include "DFGUseKind.h"
49#include "DFGVariableAccessData.h"
50#include "GetByIdVariant.h"
51#include "JSCJSValue.h"
52#include "Operands.h"
53#include "PutByIdVariant.h"
54#include "SpeculatedType.h"
55#include "TypeLocation.h"
56#include "ValueProfile.h"
57#include <type_traits>
58#include <wtf/ListDump.h>
59#include <wtf/LoggingHashSet.h>
60
61namespace JSC {
62
63namespace DOMJIT {
64class GetterSetter;
65class CallDOMGetterSnippet;
66class Signature;
67}
68
69namespace Profiler {
70class ExecutionCounter;
71}
72
73class Snippet;
74
75namespace DFG {
76
77class Graph;
78class PromotedLocationDescriptor;
79struct BasicBlock;
80
81struct StorageAccessData {
82 PropertyOffset offset;
83 unsigned identifierNumber;
84};
85
86struct MultiPutByOffsetData {
87 unsigned identifierNumber;
88 Vector<PutByIdVariant, 2> variants;
89
90 bool writesStructures() const;
91 bool reallocatesStorage() const;
92};
93
94struct MatchStructureVariant {
95 RegisteredStructure structure;
96 bool result;
97};
98
99struct MatchStructureData {
100 Vector<MatchStructureVariant, 2> variants;
101};
102
103struct NewArrayBufferData {
104 union {
105 struct {
106 unsigned vectorLengthHint;
107 unsigned indexingMode;
108 };
109 uint64_t asQuadWord;
110 };
111};
112static_assert(sizeof(IndexingType) <= sizeof(unsigned), "");
113static_assert(sizeof(NewArrayBufferData) == sizeof(uint64_t), "");
114
115struct DataViewData {
116 union {
117 struct {
118 uint8_t byteSize;
119 bool isSigned;
120 bool isFloatingPoint; // Used for the DataViewSet node.
121 TriState isLittleEndian;
122 };
123 uint64_t asQuadWord;
124 };
125};
126static_assert(sizeof(DataViewData) == sizeof(uint64_t), "");
127
128struct BranchTarget {
129 BranchTarget()
130 : block(0)
131 , count(PNaN)
132 {
133 }
134
135 explicit BranchTarget(BasicBlock* block)
136 : block(block)
137 , count(PNaN)
138 {
139 }
140
141 void setBytecodeIndex(unsigned bytecodeIndex)
142 {
143 block = bitwise_cast<BasicBlock*>(static_cast<uintptr_t>(bytecodeIndex));
144 }
145 unsigned bytecodeIndex() const { return bitwise_cast<uintptr_t>(block); }
146
147 void dump(PrintStream&) const;
148
149 BasicBlock* block;
150 float count;
151};
152
153struct BranchData {
154 static BranchData withBytecodeIndices(
155 unsigned takenBytecodeIndex, unsigned notTakenBytecodeIndex)
156 {
157 BranchData result;
158 result.taken.block = bitwise_cast<BasicBlock*>(static_cast<uintptr_t>(takenBytecodeIndex));
159 result.notTaken.block = bitwise_cast<BasicBlock*>(static_cast<uintptr_t>(notTakenBytecodeIndex));
160 return result;
161 }
162
163 unsigned takenBytecodeIndex() const { return taken.bytecodeIndex(); }
164 unsigned notTakenBytecodeIndex() const { return notTaken.bytecodeIndex(); }
165
166 BasicBlock*& forCondition(bool condition)
167 {
168 if (condition)
169 return taken.block;
170 return notTaken.block;
171 }
172
173 BranchTarget taken;
174 BranchTarget notTaken;
175};
176
177// The SwitchData and associated data structures duplicate the information in
178// JumpTable. The DFG may ultimately end up using the JumpTable, though it may
179// instead decide to do something different - this is entirely up to the DFG.
180// These data structures give the DFG a higher-level semantic description of
181// what is going on, which will allow it to make the right decision.
182//
183// Note that there will never be multiple SwitchCases in SwitchData::cases that
184// have the same SwitchCase::value, since the bytecode's JumpTables never have
185// duplicates - since the JumpTable maps a value to a target. It's a
186// one-to-many mapping. So we may have duplicate targets, but never duplicate
187// values.
188struct SwitchCase {
189 SwitchCase()
190 {
191 }
192
193 SwitchCase(LazyJSValue value, BasicBlock* target)
194 : value(value)
195 , target(target)
196 {
197 }
198
199 static SwitchCase withBytecodeIndex(LazyJSValue value, unsigned bytecodeIndex)
200 {
201 SwitchCase result;
202 result.value = value;
203 result.target.setBytecodeIndex(bytecodeIndex);
204 return result;
205 }
206
207 LazyJSValue value;
208 BranchTarget target;
209};
210
211struct SwitchData {
212 // Initializes most fields to obviously invalid values. Anyone
213 // constructing this should make sure to initialize everything they
214 // care about manually.
215 SwitchData()
216 : switchTableIndex(UINT_MAX)
217 , kind(static_cast<SwitchKind>(-1))
218 , didUseJumpTable(false)
219 {
220 }
221
222 Vector<SwitchCase> cases;
223 BranchTarget fallThrough;
224 size_t switchTableIndex;
225 SwitchKind kind;
226 bool didUseJumpTable;
227};
228
229struct EntrySwitchData {
230 Vector<BasicBlock*> cases;
231};
232
233struct CallVarargsData {
234 int firstVarArgOffset;
235};
236
237struct LoadVarargsData {
238 VirtualRegister start; // Local for the first element. This is the first actual argument, not this.
239 VirtualRegister count; // Local for the count.
240 VirtualRegister machineStart;
241 VirtualRegister machineCount;
242 unsigned offset; // Which array element to start with. Usually this is 0.
243 unsigned mandatoryMinimum; // The number of elements on the stack that must be initialized; if the array is too short then the missing elements must get undefined. Does not include "this".
244 unsigned limit; // Maximum number of elements to load. Includes "this".
245};
246
247struct StackAccessData {
248 StackAccessData()
249 : format(DeadFlush)
250 {
251 }
252
253 StackAccessData(VirtualRegister local, FlushFormat format)
254 : local(local)
255 , format(format)
256 {
257 }
258
259 VirtualRegister local;
260 VirtualRegister machineLocal;
261 FlushFormat format;
262
263 FlushedAt flushedAt() { return FlushedAt(format, machineLocal); }
264};
265
266struct CallDOMGetterData {
267 FunctionPtr<OperationPtrTag> customAccessorGetter;
268 const DOMJIT::GetterSetter* domJIT { nullptr };
269 DOMJIT::CallDOMGetterSnippet* snippet { nullptr };
270 unsigned identifierNumber { 0 };
271};
272
273enum class BucketOwnerType : uint32_t {
274 Map,
275 Set
276};
277
278// === Node ===
279//
280// Node represents a single operation in the data flow graph.
281struct Node {
282 WTF_MAKE_FAST_ALLOCATED;
283public:
284 static const char HashSetTemplateInstantiationString[];
285
286 enum VarArgTag { VarArg };
287
288 Node() { }
289
290 Node(NodeType op, NodeOrigin nodeOrigin, const AdjacencyList& children)
291 : origin(nodeOrigin)
292 , children(children)
293 , m_virtualRegister(VirtualRegister())
294 , m_refCount(1)
295 , m_prediction(SpecNone)
296 , owner(nullptr)
297 {
298 m_misc.replacement = nullptr;
299 setOpAndDefaultFlags(op);
300 }
301
302 // Construct a node with up to 3 children, no immediate value.
303 Node(NodeType op, NodeOrigin nodeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
304 : origin(nodeOrigin)
305 , children(AdjacencyList::Fixed, child1, child2, child3)
306 , m_virtualRegister(VirtualRegister())
307 , m_refCount(1)
308 , m_prediction(SpecNone)
309 , owner(nullptr)
310 {
311 m_misc.replacement = nullptr;
312 setOpAndDefaultFlags(op);
313 ASSERT(!(m_flags & NodeHasVarArgs));
314 }
315
316 // Construct a node with up to 3 children, no immediate value.
317 Node(NodeFlags result, NodeType op, NodeOrigin nodeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
318 : origin(nodeOrigin)
319 , children(AdjacencyList::Fixed, child1, child2, child3)
320 , m_virtualRegister(VirtualRegister())
321 , m_refCount(1)
322 , m_prediction(SpecNone)
323 , owner(nullptr)
324 {
325 m_misc.replacement = nullptr;
326 setOpAndDefaultFlags(op);
327 setResult(result);
328 ASSERT(!(m_flags & NodeHasVarArgs));
329 }
330
331 // Construct a node with up to 3 children and an immediate value.
332 Node(NodeType op, NodeOrigin nodeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
333 : origin(nodeOrigin)
334 , children(AdjacencyList::Fixed, child1, child2, child3)
335 , m_virtualRegister(VirtualRegister())
336 , m_refCount(1)
337 , m_prediction(SpecNone)
338 , m_opInfo(imm.m_value)
339 , owner(nullptr)
340 {
341 m_misc.replacement = nullptr;
342 setOpAndDefaultFlags(op);
343 ASSERT(!(m_flags & NodeHasVarArgs));
344 }
345
346 // Construct a node with up to 3 children and an immediate value.
347 Node(NodeFlags result, NodeType op, NodeOrigin nodeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
348 : origin(nodeOrigin)
349 , children(AdjacencyList::Fixed, child1, child2, child3)
350 , m_virtualRegister(VirtualRegister())
351 , m_refCount(1)
352 , m_prediction(SpecNone)
353 , m_opInfo(imm.m_value)
354 , owner(nullptr)
355 {
356 m_misc.replacement = nullptr;
357 setOpAndDefaultFlags(op);
358 setResult(result);
359 ASSERT(!(m_flags & NodeHasVarArgs));
360 }
361
362 // Construct a node with up to 3 children and two immediate values.
363 Node(NodeType op, NodeOrigin nodeOrigin, OpInfo imm1, OpInfo imm2, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
364 : origin(nodeOrigin)
365 , children(AdjacencyList::Fixed, child1, child2, child3)
366 , m_virtualRegister(VirtualRegister())
367 , m_refCount(1)
368 , m_prediction(SpecNone)
369 , m_opInfo(imm1.m_value)
370 , m_opInfo2(imm2.m_value)
371 , owner(nullptr)
372 {
373 m_misc.replacement = nullptr;
374 setOpAndDefaultFlags(op);
375 ASSERT(!(m_flags & NodeHasVarArgs));
376 }
377
378 // Construct a node with a variable number of children and two immediate values.
379 Node(VarArgTag, NodeType op, NodeOrigin nodeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
380 : origin(nodeOrigin)
381 , children(AdjacencyList::Variable, firstChild, numChildren)
382 , m_virtualRegister(VirtualRegister())
383 , m_refCount(1)
384 , m_prediction(SpecNone)
385 , m_opInfo(imm1.m_value)
386 , m_opInfo2(imm2.m_value)
387 , owner(nullptr)
388 {
389 m_misc.replacement = nullptr;
390 setOpAndDefaultFlags(op);
391 ASSERT(m_flags & NodeHasVarArgs);
392 }
393
394 NodeType op() const { return static_cast<NodeType>(m_op); }
395 NodeFlags flags() const { return m_flags; }
396
397 unsigned index() const { return m_index; }
398
399 void setOp(NodeType op)
400 {
401 m_op = op;
402 }
403
404 void setFlags(NodeFlags flags)
405 {
406 m_flags = flags;
407 }
408
409 bool mergeFlags(NodeFlags flags)
410 {
411 NodeFlags newFlags = m_flags | flags;
412 if (newFlags == m_flags)
413 return false;
414 m_flags = newFlags;
415 return true;
416 }
417
418 bool filterFlags(NodeFlags flags)
419 {
420 NodeFlags newFlags = m_flags & flags;
421 if (newFlags == m_flags)
422 return false;
423 m_flags = newFlags;
424 return true;
425 }
426
427 bool clearFlags(NodeFlags flags)
428 {
429 return filterFlags(~flags);
430 }
431
432 void setResult(NodeFlags result)
433 {
434 ASSERT(!(result & ~NodeResultMask));
435 clearFlags(NodeResultMask);
436 mergeFlags(result);
437 }
438
439 NodeFlags result() const
440 {
441 return flags() & NodeResultMask;
442 }
443
444 void setOpAndDefaultFlags(NodeType op)
445 {
446 m_op = op;
447 m_flags = defaultFlags(op);
448 }
449
450 void remove(Graph&);
451 void removeWithoutChecks();
452
453 void convertToCheckStructure(RegisteredStructureSet* set)
454 {
455 setOpAndDefaultFlags(CheckStructure);
456 m_opInfo = set;
457 }
458
459 void convertToCheckStructureOrEmpty(RegisteredStructureSet* set)
460 {
461 if (SpecCellCheck & SpecEmpty)
462 setOpAndDefaultFlags(CheckStructureOrEmpty);
463 else
464 setOpAndDefaultFlags(CheckStructure);
465 m_opInfo = set;
466 }
467
468 void convertCheckStructureOrEmptyToCheckStructure()
469 {
470 ASSERT(op() == CheckStructureOrEmpty);
471 setOpAndDefaultFlags(CheckStructure);
472 }
473
474 void convertToCheckStructureImmediate(Node* structure)
475 {
476 ASSERT(op() == CheckStructure || op() == CheckStructureOrEmpty);
477 m_op = CheckStructureImmediate;
478 children.setChild1(Edge(structure, CellUse));
479 }
480
481 void replaceWith(Graph&, Node* other);
482 void replaceWithWithoutChecks(Node* other);
483
484 void convertToIdentity();
485 void convertToIdentityOn(Node*);
486
487 bool mustGenerate()
488 {
489 return m_flags & NodeMustGenerate;
490 }
491
492 bool isConstant()
493 {
494 switch (op()) {
495 case JSConstant:
496 case DoubleConstant:
497 case Int52Constant:
498 return true;
499 default:
500 return false;
501 }
502 }
503
504 bool hasConstant()
505 {
506 switch (op()) {
507 case JSConstant:
508 case DoubleConstant:
509 case Int52Constant:
510 return true;
511
512 case PhantomDirectArguments:
513 case PhantomClonedArguments:
514 // These pretend to be the empty value constant for the benefit of the DFG backend, which
515 // otherwise wouldn't take kindly to a node that doesn't compute a value.
516 return true;
517
518 default:
519 return false;
520 }
521 }
522
523 FrozenValue* constant()
524 {
525 ASSERT(hasConstant());
526
527 if (op() == PhantomDirectArguments || op() == PhantomClonedArguments) {
528 // These pretend to be the empty value constant for the benefit of the DFG backend, which
529 // otherwise wouldn't take kindly to a node that doesn't compute a value.
530 return FrozenValue::emptySingleton();
531 }
532
533 return m_opInfo.as<FrozenValue*>();
534 }
535
536 // Don't call this directly - use Graph::convertToConstant() instead!
537 void convertToConstant(FrozenValue* value)
538 {
539 if (hasDoubleResult())
540 m_op = DoubleConstant;
541 else if (hasInt52Result())
542 m_op = Int52Constant;
543 else
544 m_op = JSConstant;
545 m_flags &= ~(NodeMustGenerate | NodeHasVarArgs);
546 m_opInfo = value;
547 children.reset();
548 }
549
550 void convertToLazyJSConstant(Graph&, LazyJSValue);
551
552 void convertToConstantStoragePointer(void* pointer)
553 {
554 ASSERT(op() == GetIndexedPropertyStorage);
555 m_op = ConstantStoragePointer;
556 m_opInfo = pointer;
557 children.reset();
558 }
559
560 void convertToPutStack(StackAccessData* data)
561 {
562 m_op = PutStack;
563 m_flags |= NodeMustGenerate;
564 m_opInfo = data;
565 m_opInfo2 = OpInfoWrapper();
566 }
567
568 void convertToGetStack(StackAccessData* data)
569 {
570 m_op = GetStack;
571 m_flags &= ~NodeMustGenerate;
572 m_opInfo = data;
573 m_opInfo2 = OpInfoWrapper();
574 children.reset();
575 }
576
577 void convertToGetByOffset(StorageAccessData& data, Edge storage, Edge base)
578 {
579 ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == GetByIdDirect || m_op == GetByIdDirectFlush || m_op == MultiGetByOffset);
580 m_opInfo = &data;
581 children.setChild1(storage);
582 children.setChild2(base);
583 m_op = GetByOffset;
584 m_flags &= ~NodeMustGenerate;
585 }
586
587 void convertToMultiGetByOffset(MultiGetByOffsetData* data)
588 {
589 RELEASE_ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == GetByIdDirect || m_op == GetByIdDirectFlush);
590 m_opInfo = data;
591 child1().setUseKind(CellUse);
592 m_op = MultiGetByOffset;
593 RELEASE_ASSERT(m_flags & NodeMustGenerate);
594 }
595
596 void convertToPutByOffset(StorageAccessData& data, Edge storage, Edge base)
597 {
598 ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush || m_op == MultiPutByOffset);
599 m_opInfo = &data;
600 children.setChild3(children.child2());
601 children.setChild2(base);
602 children.setChild1(storage);
603 m_op = PutByOffset;
604 }
605
606 void convertToMultiPutByOffset(MultiPutByOffsetData* data)
607 {
608 ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush);
609 m_opInfo = data;
610 m_op = MultiPutByOffset;
611 }
612
613 void convertToPhantomNewObject()
614 {
615 ASSERT(m_op == NewObject || m_op == MaterializeNewObject);
616 m_op = PhantomNewObject;
617 m_flags &= ~NodeHasVarArgs;
618 m_flags |= NodeMustGenerate;
619 m_opInfo = OpInfoWrapper();
620 m_opInfo2 = OpInfoWrapper();
621 children = AdjacencyList();
622 }
623
624 void convertToPhantomNewFunction()
625 {
626 ASSERT(m_op == NewFunction || m_op == NewGeneratorFunction || m_op == NewAsyncFunction || m_op == NewAsyncGeneratorFunction);
627 m_op = PhantomNewFunction;
628 m_flags |= NodeMustGenerate;
629 m_opInfo = OpInfoWrapper();
630 m_opInfo2 = OpInfoWrapper();
631 children = AdjacencyList();
632 }
633
634 void convertToPhantomNewGeneratorFunction()
635 {
636 ASSERT(m_op == NewGeneratorFunction);
637 m_op = PhantomNewGeneratorFunction;
638 m_flags |= NodeMustGenerate;
639 m_opInfo = OpInfoWrapper();
640 m_opInfo2 = OpInfoWrapper();
641 children = AdjacencyList();
642 }
643
644 void convertToPhantomNewAsyncFunction()
645 {
646 ASSERT(m_op == NewAsyncFunction);
647 m_op = PhantomNewAsyncFunction;
648 m_flags |= NodeMustGenerate;
649 m_opInfo = OpInfoWrapper();
650 m_opInfo2 = OpInfoWrapper();
651 children = AdjacencyList();
652 }
653
654 void convertToPhantomNewAsyncGeneratorFunction()
655 {
656 ASSERT(m_op == NewAsyncGeneratorFunction);
657 m_op = PhantomNewAsyncGeneratorFunction;
658 m_flags |= NodeMustGenerate;
659 m_opInfo = OpInfoWrapper();
660 m_opInfo2 = OpInfoWrapper();
661 children = AdjacencyList();
662 }
663
664 void convertToPhantomCreateActivation()
665 {
666 ASSERT(m_op == CreateActivation || m_op == MaterializeCreateActivation);
667 m_op = PhantomCreateActivation;
668 m_flags &= ~NodeHasVarArgs;
669 m_flags |= NodeMustGenerate;
670 m_opInfo = OpInfoWrapper();
671 m_opInfo2 = OpInfoWrapper();
672 children = AdjacencyList();
673 }
674
675 void convertToPhantomNewRegexp()
676 {
677 ASSERT(m_op == NewRegexp);
678 setOpAndDefaultFlags(PhantomNewRegexp);
679 m_opInfo = OpInfoWrapper();
680 m_opInfo2 = OpInfoWrapper();
681 children = AdjacencyList();
682 }
683
684 void convertPhantomToPhantomLocal()
685 {
686 ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgumentDefinitely));
687 m_op = PhantomLocal;
688 m_opInfo = child1()->m_opInfo; // Copy the variableAccessData.
689 children.setChild1(Edge());
690 }
691
692 void convertFlushToPhantomLocal()
693 {
694 ASSERT(m_op == Flush);
695 m_op = PhantomLocal;
696 children = AdjacencyList();
697 }
698
699 void convertToToString()
700 {
701 ASSERT(m_op == ToPrimitive || m_op == StringValueOf);
702 m_op = ToString;
703 }
704
705 void convertToArithNegate()
706 {
707 ASSERT(m_op == ArithAbs && child1().useKind() == Int32Use);
708 m_op = ArithNegate;
709 }
710
711 void convertToCompareEqPtr(FrozenValue* cell, Edge node)
712 {
713 ASSERT(m_op == CompareStrictEq || m_op == SameValue);
714 setOpAndDefaultFlags(CompareEqPtr);
715 children.setChild1(node);
716 children.setChild2(Edge());
717 m_opInfo = cell;
718 }
719
720 void convertToNumberToStringWithValidRadixConstant(int32_t radix)
721 {
722 ASSERT(m_op == NumberToStringWithRadix);
723 ASSERT(2 <= radix && radix <= 36);
724 setOpAndDefaultFlags(NumberToStringWithValidRadixConstant);
725 children.setChild2(Edge());
726 m_opInfo = radix;
727 }
728
729 void convertToGetGlobalThis()
730 {
731 ASSERT(m_op == ToThis);
732 setOpAndDefaultFlags(GetGlobalThis);
733 children.setChild1(Edge());
734 }
735
736 void convertToCallObjectConstructor(FrozenValue* globalObject)
737 {
738 ASSERT(m_op == ToObject);
739 setOpAndDefaultFlags(CallObjectConstructor);
740 m_opInfo = globalObject;
741 }
742
743 void convertToNewStringObject(RegisteredStructure structure)
744 {
745 ASSERT(m_op == CallObjectConstructor || m_op == ToObject);
746 setOpAndDefaultFlags(NewStringObject);
747 m_opInfo = structure;
748 m_opInfo2 = OpInfoWrapper();
749 }
750
751 void convertToNewObject(RegisteredStructure structure)
752 {
753 ASSERT(m_op == CallObjectConstructor || m_op == CreateThis || m_op == ObjectCreate);
754 setOpAndDefaultFlags(NewObject);
755 children.reset();
756 m_opInfo = structure;
757 m_opInfo2 = OpInfoWrapper();
758 }
759
760 void convertToNewPromise(RegisteredStructure structure)
761 {
762 ASSERT(m_op == CreatePromise);
763 bool internal = isInternalPromise();
764 setOpAndDefaultFlags(NewPromise);
765 children.reset();
766 m_opInfo = structure;
767 m_opInfo2 = internal;
768 }
769
770 void convertToNewInternalFieldObject(NodeType newOp, RegisteredStructure structure)
771 {
772 ASSERT(m_op == CreateAsyncGenerator || m_op == CreateGenerator);
773 setOpAndDefaultFlags(newOp);
774 children.reset();
775 m_opInfo = structure;
776 m_opInfo2 = OpInfoWrapper();
777 }
778
779 void convertToNewArrayBuffer(FrozenValue* immutableButterfly);
780
781 void convertToDirectCall(FrozenValue*);
782
783 void convertToCallDOM(Graph&);
784
785 void convertToRegExpExecNonGlobalOrStickyWithoutChecks(FrozenValue* regExp);
786 void convertToRegExpMatchFastGlobalWithoutChecks(FrozenValue* regExp);
787
788 void convertToSetRegExpObjectLastIndex()
789 {
790 setOp(SetRegExpObjectLastIndex);
791 m_opInfo = false;
792 }
793
794 void convertToInById(unsigned identifierNumber)
795 {
796 ASSERT(m_op == InByVal);
797 setOpAndDefaultFlags(InById);
798 children.setChild2(Edge());
799 m_opInfo = identifierNumber;
800 m_opInfo2 = OpInfoWrapper();
801 }
802
803 JSValue asJSValue()
804 {
805 return constant()->value();
806 }
807
808 bool isInt32Constant()
809 {
810 return isConstant() && constant()->value().isInt32();
811 }
812
813 int32_t asInt32()
814 {
815 return asJSValue().asInt32();
816 }
817
818 uint32_t asUInt32()
819 {
820 return asInt32();
821 }
822
823 bool isDoubleConstant()
824 {
825 return isConstant() && constant()->value().isDouble();
826 }
827
828 bool isNumberConstant()
829 {
830 return isConstant() && constant()->value().isNumber();
831 }
832
833 double asNumber()
834 {
835 return asJSValue().asNumber();
836 }
837
838 bool isAnyIntConstant()
839 {
840 return isConstant() && constant()->value().isAnyInt();
841 }
842
843 int64_t asAnyInt()
844 {
845 return asJSValue().asAnyInt();
846 }
847
848 bool isBooleanConstant()
849 {
850 return isConstant() && constant()->value().isBoolean();
851 }
852
853 bool asBoolean()
854 {
855 return constant()->value().asBoolean();
856 }
857
858 bool isUndefinedOrNullConstant()
859 {
860 return isConstant() && constant()->value().isUndefinedOrNull();
861 }
862
863 bool isCellConstant()
864 {
865 return isConstant() && constant()->value() && constant()->value().isCell();
866 }
867
868 JSCell* asCell()
869 {
870 return constant()->value().asCell();
871 }
872
873 template<typename T>
874 T dynamicCastConstant(VM& vm)
875 {
876 if (!isCellConstant())
877 return nullptr;
878 return jsDynamicCast<T>(vm, asCell());
879 }
880
881 bool hasLazyJSValue()
882 {
883 return op() == LazyJSConstant;
884 }
885
886 LazyJSValue lazyJSValue()
887 {
888 ASSERT(hasLazyJSValue());
889 return *m_opInfo.as<LazyJSValue*>();
890 }
891
892 String tryGetString(Graph&);
893
894 JSValue initializationValueForActivation() const
895 {
896 ASSERT(op() == CreateActivation);
897 return m_opInfo2.as<FrozenValue*>()->value();
898 }
899
900 bool hasArgumentsChild()
901 {
902 switch (op()) {
903 case GetMyArgumentByVal:
904 case GetMyArgumentByValOutOfBounds:
905 case LoadVarargs:
906 case ForwardVarargs:
907 case CallVarargs:
908 case CallForwardVarargs:
909 case ConstructVarargs:
910 case ConstructForwardVarargs:
911 case TailCallVarargs:
912 case TailCallForwardVarargs:
913 case TailCallVarargsInlinedCaller:
914 case TailCallForwardVarargsInlinedCaller:
915 return true;
916 default:
917 return false;
918 }
919 }
920
921 Edge& argumentsChild()
922 {
923 switch (op()) {
924 case GetMyArgumentByVal:
925 case GetMyArgumentByValOutOfBounds:
926 case LoadVarargs:
927 case ForwardVarargs:
928 return child1();
929 case CallVarargs:
930 case CallForwardVarargs:
931 case ConstructVarargs:
932 case ConstructForwardVarargs:
933 case TailCallVarargs:
934 case TailCallForwardVarargs:
935 case TailCallVarargsInlinedCaller:
936 case TailCallForwardVarargsInlinedCaller:
937 return child3();
938 default:
939 RELEASE_ASSERT_NOT_REACHED();
940 return child1();
941 }
942 }
943
944 bool containsMovHint()
945 {
946 switch (op()) {
947 case MovHint:
948 case ZombieHint:
949 return true;
950 default:
951 return false;
952 }
953 }
954
955 bool hasVariableAccessData(Graph&);
956 bool accessesStack(Graph& graph)
957 {
958 return hasVariableAccessData(graph);
959 }
960
961 // This is useful for debugging code, where a node that should have a variable
962 // access data doesn't have one because it hasn't been initialized yet.
963 VariableAccessData* tryGetVariableAccessData()
964 {
965 VariableAccessData* result = m_opInfo.as<VariableAccessData*>();
966 if (!result)
967 return 0;
968 return result->find();
969 }
970
971 VariableAccessData* variableAccessData()
972 {
973 return m_opInfo.as<VariableAccessData*>()->find();
974 }
975
976 VirtualRegister local()
977 {
978 return variableAccessData()->local();
979 }
980
981 VirtualRegister machineLocal()
982 {
983 return variableAccessData()->machineLocal();
984 }
985
986 bool hasUnlinkedLocal()
987 {
988 switch (op()) {
989 case ExtractOSREntryLocal:
990 case MovHint:
991 case ZombieHint:
992 case KillStack:
993 return true;
994 default:
995 return false;
996 }
997 }
998
999 VirtualRegister unlinkedLocal()
1000 {
1001 ASSERT(hasUnlinkedLocal());
1002 return VirtualRegister(m_opInfo.as<int32_t>());
1003 }
1004
1005 bool hasStackAccessData()
1006 {
1007 switch (op()) {
1008 case PutStack:
1009 case GetStack:
1010 return true;
1011 default:
1012 return false;
1013 }
1014 }
1015
1016 StackAccessData* stackAccessData()
1017 {
1018 ASSERT(hasStackAccessData());
1019 return m_opInfo.as<StackAccessData*>();
1020 }
1021
1022 unsigned argumentCountIncludingThis()
1023 {
1024 ASSERT(op() == SetArgumentCountIncludingThis);
1025 return m_opInfo.as<unsigned>();
1026 }
1027
1028 bool hasPhi()
1029 {
1030 return op() == Upsilon;
1031 }
1032
1033 Node* phi()
1034 {
1035 ASSERT(hasPhi());
1036 return m_opInfo.as<Node*>();
1037 }
1038
1039 bool isStoreBarrier()
1040 {
1041 return op() == StoreBarrier || op() == FencedStoreBarrier;
1042 }
1043
1044 bool hasIdentifier()
1045 {
1046 switch (op()) {
1047 case TryGetById:
1048 case GetById:
1049 case GetByIdFlush:
1050 case GetByIdWithThis:
1051 case GetByIdDirect:
1052 case GetByIdDirectFlush:
1053 case PutById:
1054 case PutByIdFlush:
1055 case PutByIdDirect:
1056 case PutByIdWithThis:
1057 case PutGetterById:
1058 case PutSetterById:
1059 case PutGetterSetterById:
1060 case DeleteById:
1061 case InById:
1062 case GetDynamicVar:
1063 case PutDynamicVar:
1064 case ResolveScopeForHoistingFuncDeclInEval:
1065 case ResolveScope:
1066 case ToObject:
1067 return true;
1068 default:
1069 return false;
1070 }
1071 }
1072
1073 unsigned identifierNumber()
1074 {
1075 ASSERT(hasIdentifier());
1076 return m_opInfo.as<unsigned>();
1077 }
1078
1079 bool hasGetPutInfo()
1080 {
1081 switch (op()) {
1082 case GetDynamicVar:
1083 case PutDynamicVar:
1084 return true;
1085 default:
1086 return false;
1087 }
1088 }
1089
1090 unsigned getPutInfo()
1091 {
1092 ASSERT(hasGetPutInfo());
1093 return static_cast<unsigned>(m_opInfo.as<uint64_t>() >> 32);
1094 }
1095
1096 bool hasAccessorAttributes()
1097 {
1098 switch (op()) {
1099 case PutGetterById:
1100 case PutSetterById:
1101 case PutGetterSetterById:
1102 case PutGetterByVal:
1103 case PutSetterByVal:
1104 return true;
1105 default:
1106 return false;
1107 }
1108 }
1109
1110 int32_t accessorAttributes()
1111 {
1112 ASSERT(hasAccessorAttributes());
1113 switch (op()) {
1114 case PutGetterById:
1115 case PutSetterById:
1116 case PutGetterSetterById:
1117 return m_opInfo2.as<int32_t>();
1118 case PutGetterByVal:
1119 case PutSetterByVal:
1120 return m_opInfo.as<int32_t>();
1121 default:
1122 RELEASE_ASSERT_NOT_REACHED();
1123 return 0;
1124 }
1125 }
1126
1127 bool hasPromotedLocationDescriptor()
1128 {
1129 return op() == PutHint;
1130 }
1131
1132 PromotedLocationDescriptor promotedLocationDescriptor();
1133
1134 // This corrects the arithmetic node flags, so that irrelevant bits are
1135 // ignored. In particular, anything other than ArithMul or ValueMul does not need
1136 // to know if it can speculate on negative zero.
1137 NodeFlags arithNodeFlags()
1138 {
1139 NodeFlags result = m_flags & NodeArithFlagsMask;
1140 if (op() == ArithMul || op() == ArithDiv || op() == ValueDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate || op() == ValueMul || op() == ValueDiv)
1141 return result;
1142 return result & ~NodeBytecodeNeedsNegZero;
1143 }
1144
1145 bool mayHaveNonIntResult()
1146 {
1147 return m_flags & NodeMayHaveNonIntResult;
1148 }
1149
1150 bool mayHaveDoubleResult()
1151 {
1152 return m_flags & NodeMayHaveDoubleResult;
1153 }
1154
1155 bool mayHaveNonNumericResult()
1156 {
1157 return m_flags & NodeMayHaveNonNumericResult;
1158 }
1159
1160 bool mayHaveBigIntResult()
1161 {
1162 return m_flags & NodeMayHaveBigIntResult;
1163 }
1164
1165 bool hasNewArrayBufferData()
1166 {
1167 return op() == NewArrayBuffer || op() == PhantomNewArrayBuffer;
1168 }
1169
1170 NewArrayBufferData newArrayBufferData()
1171 {
1172 ASSERT(hasNewArrayBufferData());
1173 return m_opInfo2.asNewArrayBufferData();
1174 }
1175
1176 unsigned hasVectorLengthHint()
1177 {
1178 switch (op()) {
1179 case NewArray:
1180 case NewArrayBuffer:
1181 case PhantomNewArrayBuffer:
1182 return true;
1183 default:
1184 return false;
1185 }
1186 }
1187
1188 unsigned vectorLengthHint()
1189 {
1190 ASSERT(hasVectorLengthHint());
1191 if (op() == NewArray)
1192 return m_opInfo2.as<unsigned>();
1193 return newArrayBufferData().vectorLengthHint;
1194 }
1195
1196 bool hasIndexingType()
1197 {
1198 switch (op()) {
1199 case NewArray:
1200 case NewArrayWithSize:
1201 case NewArrayBuffer:
1202 case PhantomNewArrayBuffer:
1203 return true;
1204 default:
1205 return false;
1206 }
1207 }
1208
1209 BitVector* bitVector()
1210 {
1211 ASSERT(op() == NewArrayWithSpread || op() == PhantomNewArrayWithSpread);
1212 return m_opInfo.as<BitVector*>();
1213 }
1214
1215 // Return the indexing type that an array allocation *wants* to use. It may end up using a different
1216 // type if we're having a bad time. You can determine the actual indexing type by asking the global
1217 // object:
1218 //
1219 // m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())
1220 //
1221 // This will give you a Structure*, and that will have some indexing type that may be different from
1222 // the this one.
1223 IndexingType indexingType()
1224 {
1225 ASSERT(hasIndexingType());
1226 if (op() == NewArrayBuffer || op() == PhantomNewArrayBuffer)
1227 return static_cast<IndexingType>(newArrayBufferData().indexingMode) & IndexingTypeMask;
1228 return static_cast<IndexingType>(m_opInfo.as<uint32_t>());
1229 }
1230
1231 IndexingType indexingMode()
1232 {
1233 ASSERT(hasIndexingType());
1234 if (op() == NewArrayBuffer || op() == PhantomNewArrayBuffer)
1235 return static_cast<IndexingType>(newArrayBufferData().indexingMode);
1236 return static_cast<IndexingType>(m_opInfo.as<uint32_t>());
1237 }
1238
1239 bool hasTypedArrayType()
1240 {
1241 switch (op()) {
1242 case NewTypedArray:
1243 return true;
1244 default:
1245 return false;
1246 }
1247 }
1248
1249 TypedArrayType typedArrayType()
1250 {
1251 ASSERT(hasTypedArrayType());
1252 TypedArrayType result = static_cast<TypedArrayType>(m_opInfo.as<uint32_t>());
1253 ASSERT(isTypedView(result));
1254 return result;
1255 }
1256
1257 bool hasInlineCapacity()
1258 {
1259 return op() == CreateThis;
1260 }
1261
1262 unsigned inlineCapacity()
1263 {
1264 ASSERT(hasInlineCapacity());
1265 return m_opInfo.as<unsigned>();
1266 }
1267
1268 bool hasIsInternalPromise()
1269 {
1270 return op() == CreatePromise || op() == NewPromise;
1271 }
1272
1273 bool isInternalPromise()
1274 {
1275 ASSERT(hasIsInternalPromise());
1276 return m_opInfo2.as<bool>();
1277 }
1278
1279 void setIndexingType(IndexingType indexingType)
1280 {
1281 ASSERT(hasIndexingType());
1282 m_opInfo = indexingType;
1283 }
1284
1285 bool hasScopeOffset()
1286 {
1287 return op() == GetClosureVar || op() == PutClosureVar;
1288 }
1289
1290 ScopeOffset scopeOffset()
1291 {
1292 ASSERT(hasScopeOffset());
1293 return ScopeOffset(m_opInfo.as<uint32_t>());
1294 }
1295
1296 unsigned hasInternalFieldIndex()
1297 {
1298 return op() == GetInternalField || op() == PutInternalField;
1299 }
1300
1301 unsigned internalFieldIndex()
1302 {
1303 ASSERT(hasInternalFieldIndex());
1304 return m_opInfo.as<uint32_t>();
1305 }
1306
1307 bool hasDirectArgumentsOffset()
1308 {
1309 return op() == GetFromArguments || op() == PutToArguments;
1310 }
1311
1312 DirectArgumentsOffset capturedArgumentsOffset()
1313 {
1314 ASSERT(hasDirectArgumentsOffset());
1315 return DirectArgumentsOffset(m_opInfo.as<uint32_t>());
1316 }
1317
1318 bool hasRegisterPointer()
1319 {
1320 return op() == GetGlobalVar || op() == GetGlobalLexicalVariable || op() == PutGlobalVariable;
1321 }
1322
1323 WriteBarrier<Unknown>* variablePointer()
1324 {
1325 return m_opInfo.as<WriteBarrier<Unknown>*>();
1326 }
1327
1328 bool hasCallVarargsData()
1329 {
1330 switch (op()) {
1331 case CallVarargs:
1332 case CallForwardVarargs:
1333 case TailCallVarargs:
1334 case TailCallForwardVarargs:
1335 case TailCallVarargsInlinedCaller:
1336 case TailCallForwardVarargsInlinedCaller:
1337 case ConstructVarargs:
1338 case ConstructForwardVarargs:
1339 return true;
1340 default:
1341 return false;
1342 }
1343 }
1344
1345 CallVarargsData* callVarargsData()
1346 {
1347 ASSERT(hasCallVarargsData());
1348 return m_opInfo.as<CallVarargsData*>();
1349 }
1350
1351 bool hasLoadVarargsData()
1352 {
1353 return op() == LoadVarargs || op() == ForwardVarargs;
1354 }
1355
1356 LoadVarargsData* loadVarargsData()
1357 {
1358 ASSERT(hasLoadVarargsData());
1359 return m_opInfo.as<LoadVarargsData*>();
1360 }
1361
1362 InlineCallFrame* argumentsInlineCallFrame()
1363 {
1364 ASSERT(op() == GetArgumentCountIncludingThis);
1365 return m_opInfo.as<InlineCallFrame*>();
1366 }
1367
1368 bool hasQueriedType()
1369 {
1370 return op() == IsCellWithType;
1371 }
1372
1373 JSType queriedType()
1374 {
1375 static_assert(std::is_same<uint8_t, std::underlying_type<JSType>::type>::value, "Ensure that uint8_t is the underlying type for JSType.");
1376 return static_cast<JSType>(m_opInfo.as<uint32_t>());
1377 }
1378
1379 bool hasSpeculatedTypeForQuery()
1380 {
1381 return op() == IsCellWithType;
1382 }
1383
1384 Optional<SpeculatedType> speculatedTypeForQuery()
1385 {
1386 return speculationFromJSType(queriedType());
1387 }
1388
1389 bool hasResult()
1390 {
1391 return !!result();
1392 }
1393
1394 bool hasInt32Result()
1395 {
1396 return result() == NodeResultInt32;
1397 }
1398
1399 bool hasInt52Result()
1400 {
1401 return result() == NodeResultInt52;
1402 }
1403
1404 bool hasNumberResult()
1405 {
1406 return result() == NodeResultNumber;
1407 }
1408
1409 bool hasNumberOrAnyIntResult()
1410 {
1411 return hasNumberResult() || hasInt32Result() || hasInt52Result();
1412 }
1413
1414 bool hasNumericResult()
1415 {
1416 switch (op()) {
1417 case ValueSub:
1418 case ValueMul:
1419 case ValueBitAnd:
1420 case ValueBitOr:
1421 case ValueBitXor:
1422 case ValueBitNot:
1423 case ValueBitLShift:
1424 case ValueBitRShift:
1425 case ValueNegate:
1426 return true;
1427 default:
1428 return false;
1429 }
1430 }
1431
1432 bool hasDoubleResult()
1433 {
1434 return result() == NodeResultDouble;
1435 }
1436
1437 bool hasJSResult()
1438 {
1439 return result() == NodeResultJS;
1440 }
1441
1442 bool hasBooleanResult()
1443 {
1444 return result() == NodeResultBoolean;
1445 }
1446
1447 bool hasStorageResult()
1448 {
1449 return result() == NodeResultStorage;
1450 }
1451
1452 UseKind defaultUseKind()
1453 {
1454 return useKindForResult(result());
1455 }
1456
1457 Edge defaultEdge()
1458 {
1459 return Edge(this, defaultUseKind());
1460 }
1461
1462 bool isJump()
1463 {
1464 return op() == Jump;
1465 }
1466
1467 bool isBranch()
1468 {
1469 return op() == Branch;
1470 }
1471
1472 bool isSwitch() const
1473 {
1474 return op() == Switch;
1475 }
1476
1477 bool isEntrySwitch() const
1478 {
1479 return op() == EntrySwitch;
1480 }
1481
1482 bool isTerminal()
1483 {
1484 switch (op()) {
1485 case Jump:
1486 case Branch:
1487 case Switch:
1488 case EntrySwitch:
1489 case Return:
1490 case TailCall:
1491 case DirectTailCall:
1492 case TailCallVarargs:
1493 case TailCallForwardVarargs:
1494 case Unreachable:
1495 case Throw:
1496 case ThrowStaticError:
1497 return true;
1498 default:
1499 return false;
1500 }
1501 }
1502
1503 bool isFunctionTerminal()
1504 {
1505 if (isTerminal() && !numSuccessors())
1506 return true;
1507
1508 return false;
1509 }
1510
1511 // As is described in DFGNodeType.h's ForceOSRExit, this is a pseudo-terminal.
1512 // It means that execution should fall out of DFG at this point, but execution
1513 // does continue in the basic block - just in a different compiler.
1514 // FIXME: This is used for lightweight reachability decision. But this should
1515 // be replaced with AI-based reachability ideally.
1516 bool isPseudoTerminal()
1517 {
1518 switch (op()) {
1519 case ForceOSRExit:
1520 case CheckBadCell:
1521 return true;
1522 default:
1523 return false;
1524 }
1525 }
1526
1527 unsigned targetBytecodeOffsetDuringParsing()
1528 {
1529 ASSERT(isJump());
1530 return m_opInfo.as<unsigned>();
1531 }
1532
1533 BasicBlock*& targetBlock()
1534 {
1535 ASSERT(isJump());
1536 return *bitwise_cast<BasicBlock**>(&m_opInfo.u.pointer);
1537 }
1538
1539 BranchData* branchData()
1540 {
1541 ASSERT(isBranch());
1542 return m_opInfo.as<BranchData*>();
1543 }
1544
1545 SwitchData* switchData()
1546 {
1547 ASSERT(isSwitch());
1548 return m_opInfo.as<SwitchData*>();
1549 }
1550
1551 EntrySwitchData* entrySwitchData()
1552 {
1553 ASSERT(isEntrySwitch());
1554 return m_opInfo.as<EntrySwitchData*>();
1555 }
1556
1557 bool hasIntrinsic()
1558 {
1559 switch (op()) {
1560 case CPUIntrinsic:
1561 case DateGetTime:
1562 case DateGetInt32OrNaN:
1563 return true;
1564 default:
1565 return false;
1566 }
1567 }
1568
1569 Intrinsic intrinsic()
1570 {
1571 ASSERT(hasIntrinsic());
1572 return m_opInfo.as<Intrinsic>();
1573 }
1574
1575 unsigned numSuccessors()
1576 {
1577 switch (op()) {
1578 case Jump:
1579 return 1;
1580 case Branch:
1581 return 2;
1582 case Switch:
1583 return switchData()->cases.size() + 1;
1584 case EntrySwitch:
1585 return entrySwitchData()->cases.size();
1586 default:
1587 return 0;
1588 }
1589 }
1590
1591 BasicBlock*& successor(unsigned index)
1592 {
1593 if (isSwitch()) {
1594 if (index < switchData()->cases.size())
1595 return switchData()->cases[index].target.block;
1596 RELEASE_ASSERT(index == switchData()->cases.size());
1597 return switchData()->fallThrough.block;
1598 } else if (isEntrySwitch())
1599 return entrySwitchData()->cases[index];
1600
1601 switch (index) {
1602 case 0:
1603 if (isJump())
1604 return targetBlock();
1605 return branchData()->taken.block;
1606 case 1:
1607 return branchData()->notTaken.block;
1608 default:
1609 RELEASE_ASSERT_NOT_REACHED();
1610 return targetBlock();
1611 }
1612 }
1613
1614 class SuccessorsIterable {
1615 public:
1616 SuccessorsIterable()
1617 : m_terminal(nullptr)
1618 {
1619 }
1620
1621 SuccessorsIterable(Node* terminal)
1622 : m_terminal(terminal)
1623 {
1624 }
1625
1626 class iterator {
1627 public:
1628 iterator()
1629 : m_terminal(nullptr)
1630 , m_index(UINT_MAX)
1631 {
1632 }
1633
1634 iterator(Node* terminal, unsigned index)
1635 : m_terminal(terminal)
1636 , m_index(index)
1637 {
1638 }
1639
1640 BasicBlock* operator*()
1641 {
1642 return m_terminal->successor(m_index);
1643 }
1644
1645 iterator& operator++()
1646 {
1647 m_index++;
1648 return *this;
1649 }
1650
1651 bool operator==(const iterator& other) const
1652 {
1653 return m_index == other.m_index;
1654 }
1655
1656 bool operator!=(const iterator& other) const
1657 {
1658 return !(*this == other);
1659 }
1660 private:
1661 Node* m_terminal;
1662 unsigned m_index;
1663 };
1664
1665 iterator begin()
1666 {
1667 return iterator(m_terminal, 0);
1668 }
1669
1670 iterator end()
1671 {
1672 return iterator(m_terminal, m_terminal->numSuccessors());
1673 }
1674
1675 size_t size() const { return m_terminal->numSuccessors(); }
1676 BasicBlock* at(size_t index) const { return m_terminal->successor(index); }
1677 BasicBlock* operator[](size_t index) const { return at(index); }
1678
1679 private:
1680 Node* m_terminal;
1681 };
1682
1683 SuccessorsIterable successors()
1684 {
1685 return SuccessorsIterable(this);
1686 }
1687
1688 BasicBlock*& successorForCondition(bool condition)
1689 {
1690 return branchData()->forCondition(condition);
1691 }
1692
1693 bool hasHeapPrediction()
1694 {
1695 switch (op()) {
1696 case ArithAbs:
1697 case ArithRound:
1698 case ArithFloor:
1699 case ArithCeil:
1700 case ArithTrunc:
1701 case GetDirectPname:
1702 case GetById:
1703 case GetByIdFlush:
1704 case GetByIdWithThis:
1705 case GetByIdDirect:
1706 case GetByIdDirectFlush:
1707 case GetPrototypeOf:
1708 case TryGetById:
1709 case GetByVal:
1710 case GetByValWithThis:
1711 case Call:
1712 case DirectCall:
1713 case TailCallInlinedCaller:
1714 case DirectTailCallInlinedCaller:
1715 case Construct:
1716 case DirectConstruct:
1717 case CallVarargs:
1718 case CallEval:
1719 case TailCallVarargsInlinedCaller:
1720 case ConstructVarargs:
1721 case CallForwardVarargs:
1722 case TailCallForwardVarargsInlinedCaller:
1723 case GetByOffset:
1724 case MultiGetByOffset:
1725 case GetClosureVar:
1726 case GetInternalField:
1727 case GetFromArguments:
1728 case GetArgument:
1729 case ArrayPop:
1730 case ArrayPush:
1731 case RegExpExec:
1732 case RegExpExecNonGlobalOrSticky:
1733 case RegExpTest:
1734 case RegExpMatchFast:
1735 case RegExpMatchFastGlobal:
1736 case GetGlobalVar:
1737 case GetGlobalLexicalVariable:
1738 case StringReplace:
1739 case StringReplaceRegExp:
1740 case ToNumber:
1741 case ToNumeric:
1742 case ToObject:
1743 case ValueBitAnd:
1744 case ValueBitOr:
1745 case ValueBitXor:
1746 case ValueBitNot:
1747 case ValueBitLShift:
1748 case ValueBitRShift:
1749 case CallObjectConstructor:
1750 case LoadKeyFromMapBucket:
1751 case LoadValueFromMapBucket:
1752 case CallDOMGetter:
1753 case CallDOM:
1754 case ParseInt:
1755 case AtomicsAdd:
1756 case AtomicsAnd:
1757 case AtomicsCompareExchange:
1758 case AtomicsExchange:
1759 case AtomicsLoad:
1760 case AtomicsOr:
1761 case AtomicsStore:
1762 case AtomicsSub:
1763 case AtomicsXor:
1764 case GetDynamicVar:
1765 case ExtractValueFromWeakMapGet:
1766 case ToThis:
1767 case DataViewGetInt:
1768 case DataViewGetFloat:
1769 case DateGetInt32OrNaN:
1770 return true;
1771 default:
1772 return false;
1773 }
1774 }
1775
1776 SpeculatedType getHeapPrediction()
1777 {
1778 ASSERT(hasHeapPrediction());
1779 return m_opInfo2.as<SpeculatedType>();
1780 }
1781
1782 void setHeapPrediction(SpeculatedType prediction)
1783 {
1784 ASSERT(hasHeapPrediction());
1785 m_opInfo2 = prediction;
1786 }
1787
1788 SpeculatedType getForcedPrediction()
1789 {
1790 ASSERT(op() == IdentityWithProfile);
1791 return m_opInfo.as<SpeculatedType>();
1792 }
1793
1794 uint32_t catchOSREntryIndex() const
1795 {
1796 ASSERT(op() == ExtractCatchLocal);
1797 return m_opInfo.as<uint32_t>();
1798 }
1799
1800 SpeculatedType catchLocalPrediction()
1801 {
1802 ASSERT(op() == ExtractCatchLocal);
1803 return m_opInfo2.as<SpeculatedType>();
1804 }
1805
1806 bool hasCellOperand()
1807 {
1808 switch (op()) {
1809 case CheckCell:
1810 case OverridesHasInstance:
1811 case NewFunction:
1812 case NewGeneratorFunction:
1813 case NewAsyncFunction:
1814 case NewAsyncGeneratorFunction:
1815 case CreateActivation:
1816 case MaterializeCreateActivation:
1817 case NewRegexp:
1818 case NewArrayBuffer:
1819 case PhantomNewArrayBuffer:
1820 case CompareEqPtr:
1821 case CallObjectConstructor:
1822 case DirectCall:
1823 case DirectTailCall:
1824 case DirectConstruct:
1825 case DirectTailCallInlinedCaller:
1826 case RegExpExecNonGlobalOrSticky:
1827 case RegExpMatchFastGlobal:
1828 return true;
1829 default:
1830 return false;
1831 }
1832 }
1833
1834 FrozenValue* cellOperand()
1835 {
1836 ASSERT(hasCellOperand());
1837 return m_opInfo.as<FrozenValue*>();
1838 }
1839
1840 template<typename T>
1841 T castOperand()
1842 {
1843 return cellOperand()->cast<T>();
1844 }
1845
1846 void setCellOperand(FrozenValue* value)
1847 {
1848 ASSERT(hasCellOperand());
1849 m_opInfo = value;
1850 }
1851
1852 bool hasWatchpointSet()
1853 {
1854 return op() == NotifyWrite;
1855 }
1856
1857 WatchpointSet* watchpointSet()
1858 {
1859 ASSERT(hasWatchpointSet());
1860 return m_opInfo.as<WatchpointSet*>();
1861 }
1862
1863 bool hasStoragePointer()
1864 {
1865 return op() == ConstantStoragePointer;
1866 }
1867
1868 void* storagePointer()
1869 {
1870 ASSERT(hasStoragePointer());
1871 return m_opInfo.as<void*>();
1872 }
1873
1874 bool hasUidOperand()
1875 {
1876 return op() == CheckIdent;
1877 }
1878
1879 UniquedStringImpl* uidOperand()
1880 {
1881 ASSERT(hasUidOperand());
1882 return m_opInfo.as<UniquedStringImpl*>();
1883 }
1884
1885 bool hasTypeInfoOperand()
1886 {
1887 return op() == CheckTypeInfoFlags;
1888 }
1889
1890 unsigned typeInfoOperand()
1891 {
1892 ASSERT(hasTypeInfoOperand() && m_opInfo.as<uint32_t>() <= static_cast<uint32_t>(UCHAR_MAX));
1893 return m_opInfo.as<uint32_t>();
1894 }
1895
1896 bool hasTransition()
1897 {
1898 switch (op()) {
1899 case PutStructure:
1900 case AllocatePropertyStorage:
1901 case ReallocatePropertyStorage:
1902 return true;
1903 default:
1904 return false;
1905 }
1906 }
1907
1908 Transition* transition()
1909 {
1910 ASSERT(hasTransition());
1911 return m_opInfo.as<Transition*>();
1912 }
1913
1914 bool hasStructureSet()
1915 {
1916 switch (op()) {
1917 case CheckStructure:
1918 case CheckStructureOrEmpty:
1919 case CheckStructureImmediate:
1920 case MaterializeNewObject:
1921 return true;
1922 default:
1923 return false;
1924 }
1925 }
1926
1927 const RegisteredStructureSet& structureSet()
1928 {
1929 ASSERT(hasStructureSet());
1930 return *m_opInfo.as<RegisteredStructureSet*>();
1931 }
1932
1933 bool hasStructure()
1934 {
1935 switch (op()) {
1936 case ArrayifyToStructure:
1937 case NewObject:
1938 case NewPromise:
1939 case NewGenerator:
1940 case NewAsyncGenerator:
1941 case NewStringObject:
1942 return true;
1943 default:
1944 return false;
1945 }
1946 }
1947
1948 RegisteredStructure structure()
1949 {
1950 ASSERT(hasStructure());
1951 return m_opInfo.asRegisteredStructure();
1952 }
1953
1954 bool hasStorageAccessData()
1955 {
1956 switch (op()) {
1957 case GetByOffset:
1958 case PutByOffset:
1959 case GetGetterSetterByOffset:
1960 return true;
1961 default:
1962 return false;
1963 }
1964 }
1965
1966 StorageAccessData& storageAccessData()
1967 {
1968 ASSERT(hasStorageAccessData());
1969 return *m_opInfo.as<StorageAccessData*>();
1970 }
1971
1972 bool hasMultiGetByOffsetData()
1973 {
1974 return op() == MultiGetByOffset;
1975 }
1976
1977 MultiGetByOffsetData& multiGetByOffsetData()
1978 {
1979 ASSERT(hasMultiGetByOffsetData());
1980 return *m_opInfo.as<MultiGetByOffsetData*>();
1981 }
1982
1983 bool hasMultiPutByOffsetData()
1984 {
1985 return op() == MultiPutByOffset;
1986 }
1987
1988 MultiPutByOffsetData& multiPutByOffsetData()
1989 {
1990 ASSERT(hasMultiPutByOffsetData());
1991 return *m_opInfo.as<MultiPutByOffsetData*>();
1992 }
1993
1994 bool hasMatchStructureData()
1995 {
1996 return op() == MatchStructure;
1997 }
1998
1999 MatchStructureData& matchStructureData()
2000 {
2001 ASSERT(hasMatchStructureData());
2002 return *m_opInfo.as<MatchStructureData*>();
2003 }
2004
2005 bool hasObjectMaterializationData()
2006 {
2007 switch (op()) {
2008 case MaterializeNewObject:
2009 case MaterializeCreateActivation:
2010 return true;
2011
2012 default:
2013 return false;
2014 }
2015 }
2016
2017 ObjectMaterializationData& objectMaterializationData()
2018 {
2019 ASSERT(hasObjectMaterializationData());
2020 return *m_opInfo2.as<ObjectMaterializationData*>();
2021 }
2022
2023 bool isObjectAllocation()
2024 {
2025 switch (op()) {
2026 case NewObject:
2027 case MaterializeNewObject:
2028 return true;
2029 default:
2030 return false;
2031 }
2032 }
2033
2034 bool isPhantomObjectAllocation()
2035 {
2036 switch (op()) {
2037 case PhantomNewObject:
2038 return true;
2039 default:
2040 return false;
2041 }
2042 }
2043
2044 bool isActivationAllocation()
2045 {
2046 switch (op()) {
2047 case CreateActivation:
2048 case MaterializeCreateActivation:
2049 return true;
2050 default:
2051 return false;
2052 }
2053 }
2054
2055 bool isPhantomActivationAllocation()
2056 {
2057 switch (op()) {
2058 case PhantomCreateActivation:
2059 return true;
2060 default:
2061 return false;
2062 }
2063 }
2064
2065 bool isFunctionAllocation()
2066 {
2067 switch (op()) {
2068 case NewFunction:
2069 case NewGeneratorFunction:
2070 case NewAsyncGeneratorFunction:
2071 case NewAsyncFunction:
2072 return true;
2073 default:
2074 return false;
2075 }
2076 }
2077
2078 bool isPhantomFunctionAllocation()
2079 {
2080 switch (op()) {
2081 case PhantomNewFunction:
2082 case PhantomNewGeneratorFunction:
2083 case PhantomNewAsyncFunction:
2084 case PhantomNewAsyncGeneratorFunction:
2085 return true;
2086 default:
2087 return false;
2088 }
2089 }
2090
2091 bool isPhantomAllocation()
2092 {
2093 switch (op()) {
2094 case PhantomNewObject:
2095 case PhantomDirectArguments:
2096 case PhantomCreateRest:
2097 case PhantomSpread:
2098 case PhantomNewArrayWithSpread:
2099 case PhantomNewArrayBuffer:
2100 case PhantomClonedArguments:
2101 case PhantomNewFunction:
2102 case PhantomNewGeneratorFunction:
2103 case PhantomNewAsyncFunction:
2104 case PhantomNewAsyncGeneratorFunction:
2105 case PhantomCreateActivation:
2106 case PhantomNewRegexp:
2107 return true;
2108 default:
2109 return false;
2110 }
2111 }
2112
2113 bool hasArrayMode()
2114 {
2115 switch (op()) {
2116 case GetIndexedPropertyStorage:
2117 case GetArrayLength:
2118 case GetVectorLength:
2119 case InByVal:
2120 case PutByValDirect:
2121 case PutByVal:
2122 case PutByValAlias:
2123 case GetByVal:
2124 case StringCharAt:
2125 case StringCharCodeAt:
2126 case StringCodePointAt:
2127 case CheckArray:
2128 case Arrayify:
2129 case ArrayifyToStructure:
2130 case ArrayPush:
2131 case ArrayPop:
2132 case ArrayIndexOf:
2133 case HasIndexedProperty:
2134 case AtomicsAdd:
2135 case AtomicsAnd:
2136 case AtomicsCompareExchange:
2137 case AtomicsExchange:
2138 case AtomicsLoad:
2139 case AtomicsOr:
2140 case AtomicsStore:
2141 case AtomicsSub:
2142 case AtomicsXor:
2143 return true;
2144 default:
2145 return false;
2146 }
2147 }
2148
2149 ArrayMode arrayMode()
2150 {
2151 ASSERT(hasArrayMode());
2152 if (op() == ArrayifyToStructure)
2153 return ArrayMode::fromWord(m_opInfo2.as<uint32_t>());
2154 return ArrayMode::fromWord(m_opInfo.as<uint32_t>());
2155 }
2156
2157 bool setArrayMode(ArrayMode arrayMode)
2158 {
2159 ASSERT(hasArrayMode());
2160 if (this->arrayMode() == arrayMode)
2161 return false;
2162 m_opInfo = arrayMode.asWord();
2163 return true;
2164 }
2165
2166 bool hasArithMode()
2167 {
2168 switch (op()) {
2169 case ArithAbs:
2170 case ArithAdd:
2171 case ArithSub:
2172 case ArithNegate:
2173 case ArithMul:
2174 case ArithDiv:
2175 case ArithMod:
2176 case UInt32ToNumber:
2177 case DoubleAsInt32:
2178 return true;
2179 default:
2180 return false;
2181 }
2182 }
2183
2184 Arith::Mode arithMode()
2185 {
2186 ASSERT(hasArithMode());
2187 return static_cast<Arith::Mode>(m_opInfo.as<uint32_t>());
2188 }
2189
2190 void setArithMode(Arith::Mode mode)
2191 {
2192 m_opInfo = mode;
2193 }
2194
2195 bool hasArithRoundingMode()
2196 {
2197 return op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc;
2198 }
2199
2200 Arith::RoundingMode arithRoundingMode()
2201 {
2202 ASSERT(hasArithRoundingMode());
2203 return static_cast<Arith::RoundingMode>(m_opInfo.as<uint32_t>());
2204 }
2205
2206 void setArithRoundingMode(Arith::RoundingMode mode)
2207 {
2208 ASSERT(hasArithRoundingMode());
2209 m_opInfo = static_cast<uint32_t>(mode);
2210 }
2211
2212 bool hasArithUnaryType()
2213 {
2214 return op() == ArithUnary;
2215 }
2216
2217 Arith::UnaryType arithUnaryType()
2218 {
2219 ASSERT(hasArithUnaryType());
2220 return static_cast<Arith::UnaryType>(m_opInfo.as<uint32_t>());
2221 }
2222
2223 bool hasVirtualRegister()
2224 {
2225 return m_virtualRegister.isValid();
2226 }
2227
2228 VirtualRegister virtualRegister()
2229 {
2230 ASSERT(hasResult());
2231 ASSERT(m_virtualRegister.isValid());
2232 return m_virtualRegister;
2233 }
2234
2235 void setVirtualRegister(VirtualRegister virtualRegister)
2236 {
2237 ASSERT(hasResult());
2238 ASSERT(!m_virtualRegister.isValid());
2239 m_virtualRegister = virtualRegister;
2240 }
2241
2242 bool hasExecutionCounter()
2243 {
2244 return op() == CountExecution;
2245 }
2246
2247 Profiler::ExecutionCounter* executionCounter()
2248 {
2249 return m_opInfo.as<Profiler::ExecutionCounter*>();
2250 }
2251
2252 unsigned entrypointIndex()
2253 {
2254 ASSERT(op() == InitializeEntrypointArguments);
2255 return m_opInfo.as<unsigned>();
2256 }
2257
2258 DataViewData dataViewData()
2259 {
2260 ASSERT(op() == DataViewGetInt || op() == DataViewGetFloat || op() == DataViewSet);
2261 return bitwise_cast<DataViewData>(m_opInfo.as<uint64_t>());
2262 }
2263
2264 bool shouldGenerate()
2265 {
2266 return m_refCount;
2267 }
2268
2269 // Return true if the execution of this Node does not affect our ability to OSR to the FTL.
2270 // FIXME: Isn't this just like checking if the node has effects?
2271 bool isSemanticallySkippable()
2272 {
2273 return op() == CountExecution || op() == InvalidationPoint;
2274 }
2275
2276 unsigned refCount()
2277 {
2278 return m_refCount;
2279 }
2280
2281 unsigned postfixRef()
2282 {
2283 return m_refCount++;
2284 }
2285
2286 unsigned adjustedRefCount()
2287 {
2288 return mustGenerate() ? m_refCount - 1 : m_refCount;
2289 }
2290
2291 void setRefCount(unsigned refCount)
2292 {
2293 m_refCount = refCount;
2294 }
2295
2296 Edge& child1()
2297 {
2298 ASSERT(!(m_flags & NodeHasVarArgs));
2299 return children.child1();
2300 }
2301
2302 // This is useful if you want to do a fast check on the first child
2303 // before also doing a check on the opcode. Use this with care and
2304 // avoid it if possible.
2305 Edge child1Unchecked()
2306 {
2307 return children.child1Unchecked();
2308 }
2309
2310 Edge& child2()
2311 {
2312 ASSERT(!(m_flags & NodeHasVarArgs));
2313 return children.child2();
2314 }
2315
2316 Edge& child3()
2317 {
2318 ASSERT(!(m_flags & NodeHasVarArgs));
2319 return children.child3();
2320 }
2321
2322 unsigned firstChild()
2323 {
2324 ASSERT(m_flags & NodeHasVarArgs);
2325 return children.firstChild();
2326 }
2327
2328 unsigned numChildren()
2329 {
2330 ASSERT(m_flags & NodeHasVarArgs);
2331 return children.numChildren();
2332 }
2333
2334 UseKind binaryUseKind()
2335 {
2336 ASSERT(child1().useKind() == child2().useKind());
2337 return child1().useKind();
2338 }
2339
2340 bool isBinaryUseKind(UseKind left, UseKind right)
2341 {
2342 return child1().useKind() == left && child2().useKind() == right;
2343 }
2344
2345 bool isBinaryUseKind(UseKind useKind)
2346 {
2347 return isBinaryUseKind(useKind, useKind);
2348 }
2349
2350 Edge childFor(UseKind useKind)
2351 {
2352 if (child1().useKind() == useKind)
2353 return child1();
2354 if (child2().useKind() == useKind)
2355 return child2();
2356 if (child3().useKind() == useKind)
2357 return child3();
2358 return Edge();
2359 }
2360
2361 SpeculatedType prediction()
2362 {
2363 return m_prediction;
2364 }
2365
2366 bool predict(SpeculatedType prediction)
2367 {
2368 return mergeSpeculation(m_prediction, prediction);
2369 }
2370
2371 bool shouldSpeculateInt32()
2372 {
2373 return isInt32Speculation(prediction());
2374 }
2375
2376 bool shouldSpeculateNotInt32()
2377 {
2378 return isNotInt32Speculation(prediction());
2379 }
2380
2381 bool sawBooleans()
2382 {
2383 return !!(prediction() & SpecBoolean);
2384 }
2385
2386 bool shouldSpeculateInt32OrBoolean()
2387 {
2388 return isInt32OrBooleanSpeculation(prediction());
2389 }
2390
2391 bool shouldSpeculateInt32ForArithmetic()
2392 {
2393 return isInt32SpeculationForArithmetic(prediction());
2394 }
2395
2396 bool shouldSpeculateInt32OrBooleanForArithmetic()
2397 {
2398 return isInt32OrBooleanSpeculationForArithmetic(prediction());
2399 }
2400
2401 bool shouldSpeculateInt32OrBooleanExpectingDefined()
2402 {
2403 return isInt32OrBooleanSpeculationExpectingDefined(prediction());
2404 }
2405
2406 bool shouldSpeculateInt52()
2407 {
2408 // We have to include SpecInt32Only here for two reasons:
2409 // 1. We diligently write code that first checks if we should speculate Int32.
2410 // For example:
2411 // if (shouldSpeculateInt32()) ...
2412 // else if (shouldSpeculateInt52()) ...
2413 // This means we it's totally valid to speculate Int52 when we're dealing
2414 // with a type that's the union of Int32 and Int52.
2415 //
2416 // It would be a performance mistake to not include Int32 here because we obviously
2417 // have variables that are the union of Int32 and Int52 values, and it's better
2418 // to speculate Int52 than double in that situation.
2419 //
2420 // 2. We also write code where we ask if the inputs can be Int52, like if
2421 // we know via profiling that an Add overflows, we may not emit an Int32 add.
2422 // However, we only emit such an add if both inputs can be Int52, and Int32
2423 // can trivially become Int52.
2424 //
2425 return enableInt52() && isInt32OrInt52Speculation(prediction());
2426 }
2427
2428 bool shouldSpeculateDouble()
2429 {
2430 return isDoubleSpeculation(prediction());
2431 }
2432
2433 bool shouldSpeculateDoubleReal()
2434 {
2435 return isDoubleRealSpeculation(prediction());
2436 }
2437
2438 bool shouldSpeculateNumber()
2439 {
2440 return isFullNumberSpeculation(prediction());
2441 }
2442
2443 bool shouldSpeculateNumberOrBoolean()
2444 {
2445 return isFullNumberOrBooleanSpeculation(prediction());
2446 }
2447
2448 bool shouldSpeculateNumberOrBooleanExpectingDefined()
2449 {
2450 return isFullNumberOrBooleanSpeculationExpectingDefined(prediction());
2451 }
2452
2453 bool shouldSpeculateBoolean()
2454 {
2455 return isBooleanSpeculation(prediction());
2456 }
2457
2458 bool shouldSpeculateNotBoolean()
2459 {
2460 return isNotBooleanSpeculation(prediction());
2461 }
2462
2463 bool shouldSpeculateOther()
2464 {
2465 return isOtherSpeculation(prediction());
2466 }
2467
2468 bool shouldSpeculateMisc()
2469 {
2470 return isMiscSpeculation(prediction());
2471 }
2472
2473 bool shouldSpeculateStringIdent()
2474 {
2475 return isStringIdentSpeculation(prediction());
2476 }
2477
2478 bool shouldSpeculateNotStringVar()
2479 {
2480 return isNotStringVarSpeculation(prediction());
2481 }
2482
2483 bool shouldSpeculateString()
2484 {
2485 return isStringSpeculation(prediction());
2486 }
2487
2488 bool shouldSpeculateNotString()
2489 {
2490 return isNotStringSpeculation(prediction());
2491 }
2492
2493 bool shouldSpeculateStringOrOther()
2494 {
2495 return isStringOrOtherSpeculation(prediction());
2496 }
2497
2498 bool shouldSpeculateStringObject()
2499 {
2500 return isStringObjectSpeculation(prediction());
2501 }
2502
2503 bool shouldSpeculateStringOrStringObject()
2504 {
2505 return isStringOrStringObjectSpeculation(prediction());
2506 }
2507
2508 bool shouldSpeculateRegExpObject()
2509 {
2510 return isRegExpObjectSpeculation(prediction());
2511 }
2512
2513 bool shouldSpeculateSymbol()
2514 {
2515 return isSymbolSpeculation(prediction());
2516 }
2517
2518 bool shouldSpeculateBigInt()
2519 {
2520 return isBigIntSpeculation(prediction());
2521 }
2522
2523 bool shouldSpeculateFinalObject()
2524 {
2525 return isFinalObjectSpeculation(prediction());
2526 }
2527
2528 bool shouldSpeculateFinalObjectOrOther()
2529 {
2530 return isFinalObjectOrOtherSpeculation(prediction());
2531 }
2532
2533 bool shouldSpeculateArray()
2534 {
2535 return isArraySpeculation(prediction());
2536 }
2537
2538 bool shouldSpeculateFunction()
2539 {
2540 return isFunctionSpeculation(prediction());
2541 }
2542
2543 bool shouldSpeculateProxyObject()
2544 {
2545 return isProxyObjectSpeculation(prediction());
2546 }
2547
2548 bool shouldSpeculateDerivedArray()
2549 {
2550 return isDerivedArraySpeculation(prediction());
2551 }
2552
2553 bool shouldSpeculateDirectArguments()
2554 {
2555 return isDirectArgumentsSpeculation(prediction());
2556 }
2557
2558 bool shouldSpeculateScopedArguments()
2559 {
2560 return isScopedArgumentsSpeculation(prediction());
2561 }
2562
2563 bool shouldSpeculateInt8Array()
2564 {
2565 return isInt8ArraySpeculation(prediction());
2566 }
2567
2568 bool shouldSpeculateInt16Array()
2569 {
2570 return isInt16ArraySpeculation(prediction());
2571 }
2572
2573 bool shouldSpeculateInt32Array()
2574 {
2575 return isInt32ArraySpeculation(prediction());
2576 }
2577
2578 bool shouldSpeculateUint8Array()
2579 {
2580 return isUint8ArraySpeculation(prediction());
2581 }
2582
2583 bool shouldSpeculateUint8ClampedArray()
2584 {
2585 return isUint8ClampedArraySpeculation(prediction());
2586 }
2587
2588 bool shouldSpeculateUint16Array()
2589 {
2590 return isUint16ArraySpeculation(prediction());
2591 }
2592
2593 bool shouldSpeculateUint32Array()
2594 {
2595 return isUint32ArraySpeculation(prediction());
2596 }
2597
2598 bool shouldSpeculateFloat32Array()
2599 {
2600 return isFloat32ArraySpeculation(prediction());
2601 }
2602
2603 bool shouldSpeculateFloat64Array()
2604 {
2605 return isFloat64ArraySpeculation(prediction());
2606 }
2607
2608 bool shouldSpeculateArrayOrOther()
2609 {
2610 return isArrayOrOtherSpeculation(prediction());
2611 }
2612
2613 bool shouldSpeculateObject()
2614 {
2615 return isObjectSpeculation(prediction());
2616 }
2617
2618 bool shouldSpeculateObjectOrOther()
2619 {
2620 return isObjectOrOtherSpeculation(prediction());
2621 }
2622
2623 bool shouldSpeculateCell()
2624 {
2625 return isCellSpeculation(prediction());
2626 }
2627
2628 bool shouldSpeculateCellOrOther()
2629 {
2630 return isCellOrOtherSpeculation(prediction());
2631 }
2632
2633 bool shouldSpeculateNotCell()
2634 {
2635 return isNotCellSpeculation(prediction());
2636 }
2637
2638 bool shouldSpeculateUntypedForArithmetic()
2639 {
2640 return isUntypedSpeculationForArithmetic(prediction());
2641 }
2642
2643 static bool shouldSpeculateUntypedForArithmetic(Node* op1, Node* op2)
2644 {
2645 return op1->shouldSpeculateUntypedForArithmetic() || op2->shouldSpeculateUntypedForArithmetic();
2646 }
2647
2648 bool shouldSpeculateUntypedForBitOps()
2649 {
2650 return isUntypedSpeculationForBitOps(prediction());
2651 }
2652
2653 static bool shouldSpeculateUntypedForBitOps(Node* op1, Node* op2)
2654 {
2655 return op1->shouldSpeculateUntypedForBitOps() || op2->shouldSpeculateUntypedForBitOps();
2656 }
2657
2658 static bool shouldSpeculateBoolean(Node* op1, Node* op2)
2659 {
2660 return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean();
2661 }
2662
2663 static bool shouldSpeculateInt32(Node* op1, Node* op2)
2664 {
2665 return op1->shouldSpeculateInt32() && op2->shouldSpeculateInt32();
2666 }
2667
2668 static bool shouldSpeculateInt32OrBoolean(Node* op1, Node* op2)
2669 {
2670 return op1->shouldSpeculateInt32OrBoolean()
2671 && op2->shouldSpeculateInt32OrBoolean();
2672 }
2673
2674 static bool shouldSpeculateInt32OrBooleanForArithmetic(Node* op1, Node* op2)
2675 {
2676 return op1->shouldSpeculateInt32OrBooleanForArithmetic()
2677 && op2->shouldSpeculateInt32OrBooleanForArithmetic();
2678 }
2679
2680 static bool shouldSpeculateInt32OrBooleanExpectingDefined(Node* op1, Node* op2)
2681 {
2682 return op1->shouldSpeculateInt32OrBooleanExpectingDefined()
2683 && op2->shouldSpeculateInt32OrBooleanExpectingDefined();
2684 }
2685
2686 static bool shouldSpeculateInt52(Node* op1, Node* op2)
2687 {
2688 return enableInt52() && op1->shouldSpeculateInt52() && op2->shouldSpeculateInt52();
2689 }
2690
2691 static bool shouldSpeculateNumber(Node* op1, Node* op2)
2692 {
2693 return op1->shouldSpeculateNumber() && op2->shouldSpeculateNumber();
2694 }
2695
2696 static bool shouldSpeculateNumberOrBoolean(Node* op1, Node* op2)
2697 {
2698 return op1->shouldSpeculateNumberOrBoolean()
2699 && op2->shouldSpeculateNumberOrBoolean();
2700 }
2701
2702 static bool shouldSpeculateNumberOrBooleanExpectingDefined(Node* op1, Node* op2)
2703 {
2704 return op1->shouldSpeculateNumberOrBooleanExpectingDefined()
2705 && op2->shouldSpeculateNumberOrBooleanExpectingDefined();
2706 }
2707
2708 static bool shouldSpeculateSymbol(Node* op1, Node* op2)
2709 {
2710 return op1->shouldSpeculateSymbol() && op2->shouldSpeculateSymbol();
2711 }
2712
2713 static bool shouldSpeculateBigInt(Node* op1, Node* op2)
2714 {
2715 return op1->shouldSpeculateBigInt() && op2->shouldSpeculateBigInt();
2716 }
2717
2718 static bool shouldSpeculateFinalObject(Node* op1, Node* op2)
2719 {
2720 return op1->shouldSpeculateFinalObject() && op2->shouldSpeculateFinalObject();
2721 }
2722
2723 static bool shouldSpeculateArray(Node* op1, Node* op2)
2724 {
2725 return op1->shouldSpeculateArray() && op2->shouldSpeculateArray();
2726 }
2727
2728 bool canSpeculateInt32(RareCaseProfilingSource source)
2729 {
2730 return nodeCanSpeculateInt32(arithNodeFlags(), source);
2731 }
2732
2733 bool canSpeculateInt52(RareCaseProfilingSource source)
2734 {
2735 return nodeCanSpeculateInt52(arithNodeFlags(), source);
2736 }
2737
2738 RareCaseProfilingSource sourceFor(PredictionPass pass)
2739 {
2740 if (pass == PrimaryPass || child1()->sawBooleans() || (child2() && child2()->sawBooleans()))
2741 return DFGRareCase;
2742 return AllRareCases;
2743 }
2744
2745 bool canSpeculateInt32(PredictionPass pass)
2746 {
2747 return canSpeculateInt32(sourceFor(pass));
2748 }
2749
2750 bool canSpeculateInt52(PredictionPass pass)
2751 {
2752 return canSpeculateInt52(sourceFor(pass));
2753 }
2754
2755 bool hasTypeLocation()
2756 {
2757 return op() == ProfileType;
2758 }
2759
2760 TypeLocation* typeLocation()
2761 {
2762 ASSERT(hasTypeLocation());
2763 return m_opInfo.as<TypeLocation*>();
2764 }
2765
2766 bool hasBasicBlockLocation()
2767 {
2768 return op() == ProfileControlFlow;
2769 }
2770
2771 BasicBlockLocation* basicBlockLocation()
2772 {
2773 ASSERT(hasBasicBlockLocation());
2774 return m_opInfo.as<BasicBlockLocation*>();
2775 }
2776
2777 bool hasCallDOMGetterData() const
2778 {
2779 return op() == CallDOMGetter;
2780 }
2781
2782 CallDOMGetterData* callDOMGetterData()
2783 {
2784 ASSERT(hasCallDOMGetterData());
2785 return m_opInfo.as<CallDOMGetterData*>();
2786 }
2787
2788 bool hasClassInfo() const
2789 {
2790 return op() == CheckSubClass;
2791 }
2792
2793 const ClassInfo* classInfo()
2794 {
2795 return m_opInfo.as<const ClassInfo*>();
2796 }
2797
2798 bool hasSignature() const
2799 {
2800 // Note that this does not include TailCall node types intentionally.
2801 // CallDOM node types are always converted from Call.
2802 return op() == Call || op() == CallDOM;
2803 }
2804
2805 const DOMJIT::Signature* signature()
2806 {
2807 return m_opInfo.as<const DOMJIT::Signature*>();
2808 }
2809
2810 bool hasInternalMethodType() const
2811 {
2812 return op() == HasIndexedProperty;
2813 }
2814
2815 PropertySlot::InternalMethodType internalMethodType() const
2816 {
2817 ASSERT(hasInternalMethodType());
2818 return static_cast<PropertySlot::InternalMethodType>(m_opInfo2.as<uint32_t>());
2819 }
2820
2821 void setInternalMethodType(PropertySlot::InternalMethodType type)
2822 {
2823 ASSERT(hasInternalMethodType());
2824 m_opInfo2 = static_cast<uint32_t>(type);
2825 }
2826
2827 Node* replacement() const
2828 {
2829 return m_misc.replacement;
2830 }
2831
2832 void setReplacement(Node* replacement)
2833 {
2834 m_misc.replacement = replacement;
2835 }
2836
2837 Epoch epoch() const
2838 {
2839 return Epoch::fromUnsigned(m_misc.epoch);
2840 }
2841
2842 void setEpoch(Epoch epoch)
2843 {
2844 m_misc.epoch = epoch.toUnsigned();
2845 }
2846
2847 bool hasNumberOfArgumentsToSkip()
2848 {
2849 return op() == CreateRest || op() == PhantomCreateRest || op() == GetRestLength || op() == GetMyArgumentByVal || op() == GetMyArgumentByValOutOfBounds;
2850 }
2851
2852 unsigned numberOfArgumentsToSkip()
2853 {
2854 ASSERT(hasNumberOfArgumentsToSkip());
2855 return m_opInfo.as<unsigned>();
2856 }
2857
2858 bool hasArgumentIndex()
2859 {
2860 return op() == GetArgument;
2861 }
2862
2863 unsigned argumentIndex()
2864 {
2865 ASSERT(hasArgumentIndex());
2866 return m_opInfo.as<unsigned>();
2867 }
2868
2869 bool hasBucketOwnerType()
2870 {
2871 return op() == GetMapBucketNext || op() == LoadKeyFromMapBucket || op() == LoadValueFromMapBucket;
2872 }
2873
2874 BucketOwnerType bucketOwnerType()
2875 {
2876 ASSERT(hasBucketOwnerType());
2877 return m_opInfo.as<BucketOwnerType>();
2878 }
2879
2880 bool hasValidRadixConstant()
2881 {
2882 return op() == NumberToStringWithValidRadixConstant;
2883 }
2884
2885 int32_t validRadixConstant()
2886 {
2887 ASSERT(hasValidRadixConstant());
2888 return m_opInfo.as<int32_t>();
2889 }
2890
2891 bool hasIgnoreLastIndexIsWritable()
2892 {
2893 return op() == SetRegExpObjectLastIndex;
2894 }
2895
2896 bool ignoreLastIndexIsWritable()
2897 {
2898 ASSERT(hasIgnoreLastIndexIsWritable());
2899 return m_opInfo.as<uint32_t>();
2900 }
2901
2902 uint32_t errorType()
2903 {
2904 ASSERT(op() == ThrowStaticError);
2905 return m_opInfo.as<uint32_t>();
2906 }
2907
2908 bool hasCallLinkStatus()
2909 {
2910 return op() == FilterCallLinkStatus;
2911 }
2912
2913 CallLinkStatus* callLinkStatus()
2914 {
2915 ASSERT(hasCallLinkStatus());
2916 return m_opInfo.as<CallLinkStatus*>();
2917 }
2918
2919 bool hasGetByStatus()
2920 {
2921 return op() == FilterGetByStatus;
2922 }
2923
2924 GetByStatus* getByStatus()
2925 {
2926 ASSERT(hasGetByStatus());
2927 return m_opInfo.as<GetByStatus*>();
2928 }
2929
2930 bool hasInByIdStatus()
2931 {
2932 return op() == FilterInByIdStatus;
2933 }
2934
2935 InByIdStatus* inByIdStatus()
2936 {
2937 ASSERT(hasInByIdStatus());
2938 return m_opInfo.as<InByIdStatus*>();
2939 }
2940
2941 bool hasPutByIdStatus()
2942 {
2943 return op() == FilterPutByIdStatus;
2944 }
2945
2946 PutByIdStatus* putByIdStatus()
2947 {
2948 ASSERT(hasPutByIdStatus());
2949 return m_opInfo.as<PutByIdStatus*>();
2950 }
2951
2952 void dumpChildren(PrintStream& out)
2953 {
2954 if (!child1())
2955 return;
2956 out.printf("@%u", child1()->index());
2957 if (!child2())
2958 return;
2959 out.printf(", @%u", child2()->index());
2960 if (!child3())
2961 return;
2962 out.printf(", @%u", child3()->index());
2963 }
2964
2965 NodeOrigin origin;
2966
2967 // References to up to 3 children, or links to a variable length set of children.
2968 AdjacencyList children;
2969
2970private:
2971 friend class B3::SparseCollection<Node>;
2972
2973 unsigned m_index { std::numeric_limits<unsigned>::max() };
2974 unsigned m_op : 10; // real type is NodeType
2975 unsigned m_flags : 21;
2976 // The virtual register number (spill location) associated with this .
2977 VirtualRegister m_virtualRegister;
2978 // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
2979 unsigned m_refCount;
2980 // The prediction ascribed to this node after propagation.
2981 SpeculatedType m_prediction { SpecNone };
2982 // Immediate values, accesses type-checked via accessors above.
2983 struct OpInfoWrapper {
2984 OpInfoWrapper()
2985 {
2986 u.int64 = 0;
2987 }
2988 OpInfoWrapper(uint32_t intValue)
2989 {
2990 u.int64 = 0;
2991 u.int32 = intValue;
2992 }
2993 OpInfoWrapper(uint64_t intValue)
2994 {
2995 u.int64 = intValue;
2996 }
2997 OpInfoWrapper(void* pointer)
2998 {
2999 u.int64 = 0;
3000 u.pointer = pointer;
3001 }
3002 OpInfoWrapper(const void* constPointer)
3003 {
3004 u.int64 = 0;
3005 u.constPointer = constPointer;
3006 }
3007 OpInfoWrapper(RegisteredStructure structure)
3008 {
3009 u.int64 = 0;
3010 u.pointer = bitwise_cast<void*>(structure);
3011 }
3012 OpInfoWrapper& operator=(uint32_t int32)
3013 {
3014 u.int64 = 0;
3015 u.int32 = int32;
3016 return *this;
3017 }
3018 OpInfoWrapper& operator=(int32_t int32)
3019 {
3020 u.int64 = 0;
3021 u.int32 = int32;
3022 return *this;
3023 }
3024 OpInfoWrapper& operator=(uint64_t int64)
3025 {
3026 u.int64 = int64;
3027 return *this;
3028 }
3029 OpInfoWrapper& operator=(void* pointer)
3030 {
3031 u.int64 = 0;
3032 u.pointer = pointer;
3033 return *this;
3034 }
3035 OpInfoWrapper& operator=(const void* constPointer)
3036 {
3037 u.int64 = 0;
3038 u.constPointer = constPointer;
3039 return *this;
3040 }
3041 OpInfoWrapper& operator=(RegisteredStructure structure)
3042 {
3043 u.int64 = 0;
3044 u.pointer = bitwise_cast<void*>(structure);
3045 return *this;
3046 }
3047 OpInfoWrapper& operator=(NewArrayBufferData newArrayBufferData)
3048 {
3049 u.int64 = bitwise_cast<uint64_t>(newArrayBufferData);
3050 return *this;
3051 }
3052 template <typename T>
3053 ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && !std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
3054 {
3055 return static_cast<T>(u.pointer);
3056 }
3057 template <typename T>
3058 ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
3059 {
3060 return static_cast<T>(u.constPointer);
3061 }
3062 template <typename T>
3063 ALWAYS_INLINE auto as() const -> typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value) && sizeof(T) <= 4, T>::type
3064 {
3065 return static_cast<T>(u.int32);
3066 }
3067 template <typename T>
3068 ALWAYS_INLINE auto as() const -> typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value) && sizeof(T) == 8, T>::type
3069 {
3070 return static_cast<T>(u.int64);
3071 }
3072 ALWAYS_INLINE RegisteredStructure asRegisteredStructure() const
3073 {
3074 return bitwise_cast<RegisteredStructure>(u.pointer);
3075 }
3076 ALWAYS_INLINE NewArrayBufferData asNewArrayBufferData() const
3077 {
3078 return bitwise_cast<NewArrayBufferData>(u.int64);
3079 }
3080
3081 union {
3082 uint32_t int32;
3083 uint64_t int64;
3084 void* pointer;
3085 const void* constPointer;
3086 } u;
3087 };
3088 OpInfoWrapper m_opInfo;
3089 OpInfoWrapper m_opInfo2;
3090
3091 // Miscellaneous data that is usually meaningless, but can hold some analysis results
3092 // if you ask right. For example, if you do Graph::initializeNodeOwners(), Node::owner
3093 // will tell you which basic block a node belongs to. You cannot rely on this persisting
3094 // across transformations unless you do the maintenance work yourself. Other phases use
3095 // Node::replacement, but they do so manually: first you do Graph::clearReplacements()
3096 // and then you set, and use, replacement's yourself. Same thing for epoch.
3097 //
3098 // Bottom line: don't use these fields unless you initialize them yourself, or by
3099 // calling some appropriate methods that initialize them the way you want. Otherwise,
3100 // these fields are meaningless.
3101private:
3102 union {
3103 Node* replacement;
3104 unsigned epoch;
3105 } m_misc;
3106public:
3107 BasicBlock* owner;
3108};
3109
3110// Uncomment this to log NodeSet operations.
3111// typedef LoggingHashSet<Node::HashSetTemplateInstantiationString, Node*> NodeSet;
3112typedef HashSet<Node*> NodeSet;
3113
3114struct NodeComparator {
3115 template<typename NodePtrType>
3116 bool operator()(NodePtrType a, NodePtrType b) const
3117 {
3118 return a->index() < b->index();
3119 }
3120};
3121
3122template<typename T>
3123CString nodeListDump(const T& nodeList)
3124{
3125 return sortedListDump(nodeList, NodeComparator());
3126}
3127
3128template<typename T>
3129CString nodeMapDump(const T& nodeMap, DumpContext* context = 0)
3130{
3131 Vector<typename T::KeyType> keys;
3132 for (
3133 typename T::const_iterator iter = nodeMap.begin();
3134 iter != nodeMap.end(); ++iter)
3135 keys.append(iter->key);
3136 std::sort(keys.begin(), keys.end(), NodeComparator());
3137 StringPrintStream out;
3138 CommaPrinter comma;
3139 for(unsigned i = 0; i < keys.size(); ++i)
3140 out.print(comma, keys[i], "=>", inContext(nodeMap.get(keys[i]), context));
3141 return out.toCString();
3142}
3143
3144template<typename T>
3145CString nodeValuePairListDump(const T& nodeValuePairList, DumpContext* context = 0)
3146{
3147 using V = typename T::ValueType;
3148 T sortedList = nodeValuePairList;
3149 std::sort(sortedList.begin(), sortedList.end(), [](const V& a, const V& b) {
3150 return NodeComparator()(a.node, b.node);
3151 });
3152
3153 StringPrintStream out;
3154 CommaPrinter comma;
3155 for (const auto& pair : sortedList)
3156 out.print(comma, pair.node, "=>", inContext(pair.value, context));
3157 return out.toCString();
3158}
3159
3160} } // namespace JSC::DFG
3161
3162namespace WTF {
3163
3164void printInternal(PrintStream&, JSC::DFG::SwitchKind);
3165void printInternal(PrintStream&, JSC::DFG::Node*);
3166
3167inline JSC::DFG::Node* inContext(JSC::DFG::Node* node, JSC::DumpContext*) { return node; }
3168
3169template<>
3170struct LoggingHashKeyTraits<JSC::DFG::Node*> {
3171 static void print(PrintStream& out, JSC::DFG::Node* key)
3172 {
3173 out.print("bitwise_cast<::JSC::DFG::Node*>(", RawPointer(key), "lu)");
3174 }
3175};
3176
3177} // namespace WTF
3178
3179using WTF::inContext;
3180
3181#endif
3182