2 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include <wtf/Platform.h>
33 #include "CodeBlock.h"
34 #include "DFGArgumentPosition.h"
35 #include "DFGAssemblyHelpers.h"
36 #include "DFGBasicBlock.h"
37 #include "DFGDominators.h"
38 #include "DFGLongLivedState.h"
40 #include "DFGNodeAllocator.h"
41 #include "DFGVariadicFunction.h"
43 #include "MethodOfGettingAValueProfile.h"
44 #include <wtf/BitVector.h>
45 #include <wtf/HashMap.h>
46 #include <wtf/Vector.h>
47 #include <wtf/StdLibExtras.h>
56 struct StorageAccessData
{
58 unsigned identifierNumber
;
61 struct ResolveGlobalData
{
62 unsigned identifierNumber
;
63 ResolveOperations
* resolveOperations
;
64 PutToBaseOperation
* putToBaseOperation
;
65 unsigned resolvePropertyIndex
;
68 struct ResolveOperationData
{
69 unsigned identifierNumber
;
70 ResolveOperations
* resolveOperations
;
71 PutToBaseOperation
* putToBaseOperation
;
74 struct PutToBaseOperationData
{
75 PutToBaseOperation
* putToBaseOperation
;
78 enum AddSpeculationMode
{
80 SpeculateIntegerAndTruncateConstants
,
88 // The order may be significant for nodes with side-effects (property accesses, value conversions).
89 // Nodes that are 'dead' remain in the vector with refCount 0.
92 Graph(VM
&, CodeBlock
*, unsigned osrEntryBytecodeIndex
, const Operands
<JSValue
>& mustHandleValues
);
95 void changeChild(Edge
& edge
, Node
* newNode
)
97 edge
.setNode(newNode
);
100 void changeEdge(Edge
& edge
, Edge newEdge
)
105 void compareAndSwap(Edge
& edge
, Node
* oldNode
, Node
* newNode
)
107 if (edge
.node() != oldNode
)
109 changeChild(edge
, newNode
);
112 void compareAndSwap(Edge
& edge
, Edge oldEdge
, Edge newEdge
)
116 changeEdge(edge
, newEdge
);
119 void clearAndDerefChild(Node
* node
, unsigned index
)
121 if (!node
->children
.child(index
))
123 node
->children
.setChild(index
, Edge());
125 void clearAndDerefChild1(Node
* node
) { clearAndDerefChild(node
, 0); }
126 void clearAndDerefChild2(Node
* node
) { clearAndDerefChild(node
, 1); }
127 void clearAndDerefChild3(Node
* node
) { clearAndDerefChild(node
, 2); }
129 void performSubstitution(Node
* node
)
131 if (node
->flags() & NodeHasVarArgs
) {
132 for (unsigned childIdx
= node
->firstChild(); childIdx
< node
->firstChild() + node
->numChildren(); childIdx
++)
133 performSubstitutionForEdge(m_varArgChildren
[childIdx
]);
135 performSubstitutionForEdge(node
->child1());
136 performSubstitutionForEdge(node
->child2());
137 performSubstitutionForEdge(node
->child3());
141 void performSubstitutionForEdge(Edge
& child
)
143 // Check if this operand is actually unused.
147 // Check if there is any replacement.
148 Node
* replacement
= child
->replacement
;
152 child
.setNode(replacement
);
154 // There is definitely a replacement. Assert that the replacement does not
155 // have a replacement.
156 ASSERT(!child
->replacement
);
159 #define DFG_DEFINE_ADD_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
160 templatePre typeParams templatePost Node* addNode(SpeculatedType type valueParamsComma valueParams) \
162 Node* node = new (m_allocator) Node(valueArgs); \
163 node->predict(type); \
166 DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_ADD_NODE
)
167 #undef DFG_DEFINE_ADD_NODE
171 void convertToConstant(Node
* node
, unsigned constantNumber
)
173 if (node
->op() == GetLocal
)
176 ASSERT(!node
->hasVariableAccessData());
177 node
->convertToConstant(constantNumber
);
180 void convertToConstant(Node
* node
, JSValue value
)
182 convertToConstant(node
, m_codeBlock
->addOrFindConstant(value
));
185 // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
186 void dump(PrintStream
& = WTF::dataFile());
187 enum PhiNodeDumpMode
{ DumpLivePhisOnly
, DumpAllPhis
};
188 void dumpBlockHeader(PrintStream
&, const char* prefix
, BlockIndex
, PhiNodeDumpMode
);
189 void dump(PrintStream
&, Edge
);
190 void dump(PrintStream
&, const char* prefix
, Node
*);
191 static int amountOfNodeWhiteSpace(Node
*);
192 static void printNodeWhiteSpace(PrintStream
&, Node
*);
194 // Dump the code origin of the given node as a diff from the code origin of the
195 // preceding node. Returns true if anything was printed.
196 bool dumpCodeOrigin(PrintStream
&, const char* prefix
, Node
* previousNode
, Node
* currentNode
);
198 BlockIndex
blockIndexForBytecodeOffset(Vector
<BlockIndex
>& blocks
, unsigned bytecodeBegin
);
200 SpeculatedType
getJSConstantSpeculation(Node
* node
)
202 return speculationFromValue(node
->valueOfJSConstant(m_codeBlock
));
205 AddSpeculationMode
addSpeculationMode(Node
* add
, bool leftShouldSpeculateInteger
, bool rightShouldSpeculateInteger
)
207 ASSERT(add
->op() == ValueAdd
|| add
->op() == ArithAdd
|| add
->op() == ArithSub
);
209 Node
* left
= add
->child1().node();
210 Node
* right
= add
->child2().node();
212 if (left
->hasConstant())
213 return addImmediateShouldSpeculateInteger(add
, rightShouldSpeculateInteger
, left
);
214 if (right
->hasConstant())
215 return addImmediateShouldSpeculateInteger(add
, leftShouldSpeculateInteger
, right
);
217 return (leftShouldSpeculateInteger
&& rightShouldSpeculateInteger
&& add
->canSpeculateInteger()) ? SpeculateInteger
: DontSpeculateInteger
;
220 AddSpeculationMode
valueAddSpeculationMode(Node
* add
)
222 return addSpeculationMode(add
, add
->child1()->shouldSpeculateIntegerExpectingDefined(), add
->child2()->shouldSpeculateIntegerExpectingDefined());
225 AddSpeculationMode
arithAddSpeculationMode(Node
* add
)
227 return addSpeculationMode(add
, add
->child1()->shouldSpeculateIntegerForArithmetic(), add
->child2()->shouldSpeculateIntegerForArithmetic());
230 AddSpeculationMode
addSpeculationMode(Node
* add
)
232 if (add
->op() == ValueAdd
)
233 return valueAddSpeculationMode(add
);
235 return arithAddSpeculationMode(add
);
238 bool addShouldSpeculateInteger(Node
* add
)
240 return addSpeculationMode(add
) != DontSpeculateInteger
;
243 bool mulShouldSpeculateInteger(Node
* mul
)
245 ASSERT(mul
->op() == ArithMul
);
247 Node
* left
= mul
->child1().node();
248 Node
* right
= mul
->child2().node();
250 return Node::shouldSpeculateIntegerForArithmetic(left
, right
) && mul
->canSpeculateInteger();
253 bool negateShouldSpeculateInteger(Node
* negate
)
255 ASSERT(negate
->op() == ArithNegate
);
256 return negate
->child1()->shouldSpeculateIntegerForArithmetic() && negate
->canSpeculateInteger();
259 // Helper methods to check nodes for constants.
260 bool isConstant(Node
* node
)
262 return node
->hasConstant();
264 bool isJSConstant(Node
* node
)
266 return node
->hasConstant();
268 bool isInt32Constant(Node
* node
)
270 return node
->isInt32Constant(m_codeBlock
);
272 bool isDoubleConstant(Node
* node
)
274 return node
->isDoubleConstant(m_codeBlock
);
276 bool isNumberConstant(Node
* node
)
278 return node
->isNumberConstant(m_codeBlock
);
280 bool isBooleanConstant(Node
* node
)
282 return node
->isBooleanConstant(m_codeBlock
);
284 bool isCellConstant(Node
* node
)
286 if (!isJSConstant(node
))
288 JSValue value
= valueOfJSConstant(node
);
289 return value
.isCell() && !!value
;
291 bool isFunctionConstant(Node
* node
)
293 if (!isJSConstant(node
))
295 if (!getJSFunction(valueOfJSConstant(node
)))
299 bool isInternalFunctionConstant(Node
* node
)
301 if (!isJSConstant(node
))
303 JSValue value
= valueOfJSConstant(node
);
304 if (!value
.isCell() || !value
)
306 JSCell
* cell
= value
.asCell();
307 if (!cell
->inherits(&InternalFunction::s_info
))
311 // Helper methods get constant values from nodes.
312 JSValue
valueOfJSConstant(Node
* node
)
314 return node
->valueOfJSConstant(m_codeBlock
);
316 int32_t valueOfInt32Constant(Node
* node
)
318 return valueOfJSConstant(node
).asInt32();
320 double valueOfNumberConstant(Node
* node
)
322 return valueOfJSConstant(node
).asNumber();
324 bool valueOfBooleanConstant(Node
* node
)
326 return valueOfJSConstant(node
).asBoolean();
328 JSFunction
* valueOfFunctionConstant(Node
* node
)
330 JSCell
* function
= getJSFunction(valueOfJSConstant(node
));
332 return jsCast
<JSFunction
*>(function
);
335 static const char *opName(NodeType
);
337 StructureSet
* addStructureSet(const StructureSet
& structureSet
)
339 ASSERT(structureSet
.size());
340 m_structureSet
.append(structureSet
);
341 return &m_structureSet
.last();
344 StructureTransitionData
* addStructureTransitionData(const StructureTransitionData
& structureTransitionData
)
346 m_structureTransitionData
.append(structureTransitionData
);
347 return &m_structureTransitionData
.last();
350 JSGlobalObject
* globalObjectFor(CodeOrigin codeOrigin
)
352 return m_codeBlock
->globalObjectFor(codeOrigin
);
355 JSObject
* globalThisObjectFor(CodeOrigin codeOrigin
)
357 JSGlobalObject
* object
= globalObjectFor(codeOrigin
);
358 return object
->methodTable()->toThisObject(object
, 0);
361 ExecutableBase
* executableFor(InlineCallFrame
* inlineCallFrame
)
363 if (!inlineCallFrame
)
364 return m_codeBlock
->ownerExecutable();
366 return inlineCallFrame
->executable
.get();
369 ExecutableBase
* executableFor(const CodeOrigin
& codeOrigin
)
371 return executableFor(codeOrigin
.inlineCallFrame
);
374 CodeBlock
* baselineCodeBlockFor(const CodeOrigin
& codeOrigin
)
376 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin
, m_profiledBlock
);
379 bool hasGlobalExitSite(const CodeOrigin
& codeOrigin
, ExitKind exitKind
)
381 return baselineCodeBlockFor(codeOrigin
)->hasExitSite(FrequentExitSite(exitKind
));
384 bool hasExitSite(const CodeOrigin
& codeOrigin
, ExitKind exitKind
)
386 return baselineCodeBlockFor(codeOrigin
)->hasExitSite(FrequentExitSite(codeOrigin
.bytecodeIndex
, exitKind
));
389 int argumentsRegisterFor(const CodeOrigin
& codeOrigin
)
391 if (!codeOrigin
.inlineCallFrame
)
392 return m_codeBlock
->argumentsRegister();
394 return baselineCodeBlockForInlineCallFrame(
395 codeOrigin
.inlineCallFrame
)->argumentsRegister() +
396 codeOrigin
.inlineCallFrame
->stackOffset
;
399 int uncheckedArgumentsRegisterFor(const CodeOrigin
& codeOrigin
)
401 if (!codeOrigin
.inlineCallFrame
)
402 return m_codeBlock
->uncheckedArgumentsRegister();
404 CodeBlock
* codeBlock
= baselineCodeBlockForInlineCallFrame(
405 codeOrigin
.inlineCallFrame
);
406 if (!codeBlock
->usesArguments())
407 return InvalidVirtualRegister
;
409 return codeBlock
->argumentsRegister() +
410 codeOrigin
.inlineCallFrame
->stackOffset
;
413 int uncheckedActivationRegisterFor(const CodeOrigin
&)
415 // This will ignore CodeOrigin because we don't inline code that uses activations.
416 // Hence for inlined call frames it will return the outermost code block's
417 // activation register. This method is only used to compare the result to a local
418 // to see if we're mucking with the activation register. Hence if we return the
419 // "wrong" activation register for the frame then it will compare false, which is
421 return m_codeBlock
->uncheckedActivationRegister();
424 ValueProfile
* valueProfileFor(Node
* node
)
429 CodeBlock
* profiledBlock
= baselineCodeBlockFor(node
->codeOrigin
);
431 if (node
->hasLocal()) {
432 if (!operandIsArgument(node
->local()))
434 int argument
= operandToArgument(node
->local());
435 if (node
->variableAccessData() != m_arguments
[argument
]->variableAccessData())
437 return profiledBlock
->valueProfileForArgument(argument
);
440 if (node
->hasHeapPrediction())
441 return profiledBlock
->valueProfileForBytecodeOffset(node
->codeOrigin
.bytecodeIndexForValueProfile());
446 MethodOfGettingAValueProfile
methodOfGettingAValueProfileFor(Node
* node
)
449 return MethodOfGettingAValueProfile();
451 CodeBlock
* profiledBlock
= baselineCodeBlockFor(node
->codeOrigin
);
453 if (node
->op() == GetLocal
) {
454 return MethodOfGettingAValueProfile::fromLazyOperand(
456 LazyOperandValueProfileKey(
457 node
->codeOrigin
.bytecodeIndex
, node
->local()));
460 return MethodOfGettingAValueProfile(valueProfileFor(node
));
463 bool needsActivation() const
465 return m_codeBlock
->needsFullScopeChain() && m_codeBlock
->codeType() != GlobalCode
;
468 bool usesArguments() const
470 return m_codeBlock
->usesArguments();
473 unsigned numSuccessors(BasicBlock
* block
)
475 return block
->last()->numSuccessors();
477 BlockIndex
successor(BasicBlock
* block
, unsigned index
)
479 return block
->last()->successor(index
);
481 BlockIndex
successorForCondition(BasicBlock
* block
, bool condition
)
483 return block
->last()->successorForCondition(condition
);
486 bool isPredictedNumerical(Node
* node
)
488 return isNumerical(node
->child1().useKind()) && isNumerical(node
->child2().useKind());
491 // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing.
492 // It really means that it will not clobber the entire world. It's still up to you to
493 // carefully consider things like:
494 // - PutByVal definitely changes the array it stores to, and may even change its length.
495 // - PutByOffset definitely changes the object it stores to.
497 bool byValIsPure(Node
* node
)
499 switch (node
->arrayMode().type()) {
504 case Array::Contiguous
:
505 case Array::ArrayStorage
:
506 return !node
->arrayMode().isOutOfBounds();
507 case Array::SlowPutArrayStorage
:
508 return !node
->arrayMode().mayStoreToHole();
510 return node
->op() == GetByVal
;
511 #if USE(JSVALUE32_64)
512 case Array::Arguments
:
513 if (node
->op() == GetByVal
)
516 #endif // USE(JSVALUE32_64)
522 bool clobbersWorld(Node
* node
)
524 if (node
->flags() & NodeClobbersWorld
)
526 if (!(node
->flags() & NodeMightClobber
))
528 switch (node
->op()) {
533 case CompareGreaterEq
:
535 return !isPredictedNumerical(node
);
539 return !byValIsPure(node
);
541 switch (node
->child1().useKind()) {
542 case StringObjectUse
:
543 case StringOrStringObjectUse
:
549 RELEASE_ASSERT_NOT_REACHED();
553 RELEASE_ASSERT_NOT_REACHED();
554 return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
558 void determineReachability();
559 void resetReachability();
561 void resetExitStates();
563 unsigned varArgNumChildren(Node
* node
)
565 ASSERT(node
->flags() & NodeHasVarArgs
);
566 return node
->numChildren();
569 unsigned numChildren(Node
* node
)
571 if (node
->flags() & NodeHasVarArgs
)
572 return varArgNumChildren(node
);
573 return AdjacencyList::Size
;
576 Edge
& varArgChild(Node
* node
, unsigned index
)
578 ASSERT(node
->flags() & NodeHasVarArgs
);
579 return m_varArgChildren
[node
->firstChild() + index
];
582 Edge
& child(Node
* node
, unsigned index
)
584 if (node
->flags() & NodeHasVarArgs
)
585 return varArgChild(node
, index
);
586 return node
->children
.child(index
);
589 void voteNode(Node
* node
, unsigned ballot
)
591 switch (node
->op()) {
594 node
= node
->child1().node();
600 if (node
->op() == GetLocal
)
601 node
->variableAccessData()->vote(ballot
);
604 void voteNode(Edge edge
, unsigned ballot
)
606 voteNode(edge
.node(), ballot
);
609 void voteChildren(Node
* node
, unsigned ballot
)
611 if (node
->flags() & NodeHasVarArgs
) {
612 for (unsigned childIdx
= node
->firstChild();
613 childIdx
< node
->firstChild() + node
->numChildren();
615 if (!!m_varArgChildren
[childIdx
])
616 voteNode(m_varArgChildren
[childIdx
], ballot
);
623 voteNode(node
->child1(), ballot
);
626 voteNode(node
->child2(), ballot
);
629 voteNode(node
->child3(), ballot
);
632 template<typename T
> // T = Node* or Edge
633 void substitute(BasicBlock
& block
, unsigned startIndexInBlock
, T oldThing
, T newThing
)
635 for (unsigned indexInBlock
= startIndexInBlock
; indexInBlock
< block
.size(); ++indexInBlock
) {
636 Node
* node
= block
[indexInBlock
];
637 if (node
->flags() & NodeHasVarArgs
) {
638 for (unsigned childIdx
= node
->firstChild(); childIdx
< node
->firstChild() + node
->numChildren(); ++childIdx
) {
639 if (!!m_varArgChildren
[childIdx
])
640 compareAndSwap(m_varArgChildren
[childIdx
], oldThing
, newThing
);
646 compareAndSwap(node
->children
.child1(), oldThing
, newThing
);
649 compareAndSwap(node
->children
.child2(), oldThing
, newThing
);
652 compareAndSwap(node
->children
.child3(), oldThing
, newThing
);
656 // Use this if you introduce a new GetLocal and you know that you introduced it *before*
657 // any GetLocals in the basic block.
658 // FIXME: it may be appropriate, in the future, to generalize this to handle GetLocals
659 // introduced anywhere in the basic block.
660 void substituteGetLocal(BasicBlock
& block
, unsigned startIndexInBlock
, VariableAccessData
* variableAccessData
, Node
* newGetLocal
)
662 if (variableAccessData
->isCaptured()) {
663 // Let CSE worry about this one.
666 for (unsigned indexInBlock
= startIndexInBlock
; indexInBlock
< block
.size(); ++indexInBlock
) {
667 Node
* node
= block
[indexInBlock
];
668 bool shouldContinue
= true;
669 switch (node
->op()) {
671 if (node
->local() == variableAccessData
->local())
672 shouldContinue
= false;
677 if (node
->variableAccessData() != variableAccessData
)
679 substitute(block
, indexInBlock
, node
, newGetLocal
);
680 Node
* oldTailNode
= block
.variablesAtTail
.operand(variableAccessData
->local());
681 if (oldTailNode
== node
)
682 block
.variablesAtTail
.operand(variableAccessData
->local()) = newGetLocal
;
683 shouldContinue
= false;
696 CodeBlock
* m_codeBlock
;
697 RefPtr
<Profiler::Compilation
> m_compilation
;
698 CodeBlock
* m_profiledBlock
;
700 NodeAllocator
& m_allocator
;
702 Vector
< OwnPtr
<BasicBlock
> , 8> m_blocks
;
703 Vector
<Edge
, 16> m_varArgChildren
;
704 Vector
<StorageAccessData
> m_storageAccessData
;
705 Vector
<ResolveGlobalData
> m_resolveGlobalData
;
706 Vector
<ResolveOperationData
> m_resolveOperationsData
;
707 Vector
<PutToBaseOperationData
> m_putToBaseOperationData
;
708 Vector
<Node
*, 8> m_arguments
;
709 SegmentedVector
<VariableAccessData
, 16> m_variableAccessData
;
710 SegmentedVector
<ArgumentPosition
, 8> m_argumentPositions
;
711 SegmentedVector
<StructureSet
, 16> m_structureSet
;
712 SegmentedVector
<StructureTransitionData
, 8> m_structureTransitionData
;
713 SegmentedVector
<NewArrayBufferData
, 4> m_newArrayBufferData
;
715 HashSet
<ExecutableBase
*> m_executablesWhoseArgumentsEscaped
;
716 BitVector m_preservedVars
;
717 Dominators m_dominators
;
718 unsigned m_localVars
;
719 unsigned m_parameterSlots
;
720 unsigned m_osrEntryBytecodeIndex
;
721 Operands
<JSValue
> m_mustHandleValues
;
723 OptimizationFixpointState m_fixpointState
;
725 UnificationState m_unificationState
;
726 RefCountState m_refCountState
;
729 void handleSuccessor(Vector
<BlockIndex
, 16>& worklist
, BlockIndex blockIndex
, BlockIndex successorIndex
);
731 AddSpeculationMode
addImmediateShouldSpeculateInteger(Node
* add
, bool variableShouldSpeculateInteger
, Node
* immediate
)
733 ASSERT(immediate
->hasConstant());
735 JSValue immediateValue
= immediate
->valueOfJSConstant(m_codeBlock
);
736 if (!immediateValue
.isNumber())
737 return DontSpeculateInteger
;
739 if (!variableShouldSpeculateInteger
)
740 return DontSpeculateInteger
;
742 if (immediateValue
.isInt32())
743 return add
->canSpeculateInteger() ? SpeculateInteger
: DontSpeculateInteger
;
745 double doubleImmediate
= immediateValue
.asDouble();
746 const double twoToThe48
= 281474976710656.0;
747 if (doubleImmediate
< -twoToThe48
|| doubleImmediate
> twoToThe48
)
748 return DontSpeculateInteger
;
750 return nodeCanTruncateInteger(add
->arithNodeFlags()) ? SpeculateIntegerAndTruncateConstants
: DontSpeculateInteger
;
753 bool mulImmediateShouldSpeculateInteger(Node
* mul
, Node
* variable
, Node
* immediate
)
755 ASSERT(immediate
->hasConstant());
757 JSValue immediateValue
= immediate
->valueOfJSConstant(m_codeBlock
);
758 if (!immediateValue
.isInt32())
761 if (!variable
->shouldSpeculateIntegerForArithmetic())
764 int32_t intImmediate
= immediateValue
.asInt32();
765 // Doubles have a 53 bit mantissa so we expect a multiplication of 2^31 (the highest
766 // magnitude possible int32 value) and any value less than 2^22 to not result in any
767 // rounding in a double multiplication - hence it will be equivalent to an integer
768 // multiplication, if we are doing int32 truncation afterwards (which is what
769 // canSpeculateInteger() implies).
770 const int32_t twoToThe22
= 1 << 22;
771 if (intImmediate
<= -twoToThe22
|| intImmediate
>= twoToThe22
)
772 return mul
->canSpeculateInteger() && !nodeMayOverflow(mul
->arithNodeFlags());
774 return mul
->canSpeculateInteger();
778 class GetBytecodeBeginForBlock
{
780 GetBytecodeBeginForBlock(Graph
& graph
)
785 unsigned operator()(BlockIndex
* blockIndex
) const
787 return m_graph
.m_blocks
[*blockIndex
]->bytecodeBegin
;
794 inline BlockIndex
Graph::blockIndexForBytecodeOffset(Vector
<BlockIndex
>& linkingTargets
, unsigned bytecodeBegin
)
796 return *binarySearch
<BlockIndex
, unsigned>(linkingTargets
, linkingTargets
.size(), bytecodeBegin
, GetBytecodeBeginForBlock(*this));
799 #define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \
800 Node* _node = (node); \
801 if (_node->flags() & NodeHasVarArgs) { \
802 for (unsigned _childIdx = _node->firstChild(); \
803 _childIdx < _node->firstChild() + _node->numChildren(); \
805 if (!!(graph).m_varArgChildren[_childIdx]) \
806 thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \
809 if (!_node->child1()) { \
812 && !_node->child3()); \
815 thingToDo(_node, _node->child1()); \
817 if (!_node->child2()) { \
818 ASSERT(!_node->child3()); \
821 thingToDo(_node, _node->child2()); \
823 if (!_node->child3()) \
825 thingToDo(_node, _node->child3()); \
829 } } // namespace JSC::DFG