]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGGraph.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / dfg / DFGGraph.h
CommitLineData
14957cd0 1/*
93a37866 2 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
14957cd0
A
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef DFGGraph_h
27#define DFGGraph_h
28
93a37866
A
29#include <wtf/Platform.h>
30
14957cd0
A
31#if ENABLE(DFG_JIT)
32
6fe7ccc8
A
33#include "CodeBlock.h"
34#include "DFGArgumentPosition.h"
35#include "DFGAssemblyHelpers.h"
36#include "DFGBasicBlock.h"
93a37866
A
37#include "DFGDominators.h"
38#include "DFGLongLivedState.h"
6fe7ccc8 39#include "DFGNode.h"
93a37866
A
40#include "DFGNodeAllocator.h"
41#include "DFGVariadicFunction.h"
42#include "JSStack.h"
6fe7ccc8 43#include "MethodOfGettingAValueProfile.h"
6fe7ccc8
A
44#include <wtf/BitVector.h>
45#include <wtf/HashMap.h>
14957cd0
A
46#include <wtf/Vector.h>
47#include <wtf/StdLibExtras.h>
48
49namespace JSC {
50
51class CodeBlock;
6fe7ccc8 52class ExecState;
14957cd0
A
53
54namespace DFG {
55
6fe7ccc8
A
56struct StorageAccessData {
57 size_t offset;
58 unsigned identifierNumber;
14957cd0
A
59};
60
6fe7ccc8
A
61struct ResolveGlobalData {
62 unsigned identifierNumber;
93a37866
A
63 ResolveOperations* resolveOperations;
64 PutToBaseOperation* putToBaseOperation;
65 unsigned resolvePropertyIndex;
66};
67
68struct ResolveOperationData {
69 unsigned identifierNumber;
70 ResolveOperations* resolveOperations;
71 PutToBaseOperation* putToBaseOperation;
14957cd0
A
72};
73
93a37866
A
74struct PutToBaseOperationData {
75 PutToBaseOperation* putToBaseOperation;
76};
77
78enum AddSpeculationMode {
79 DontSpeculateInteger,
80 SpeculateIntegerAndTruncateConstants,
81 SpeculateInteger
82};
83
84
85//
14957cd0
A
86// === Graph ===
87//
14957cd0
A
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.
93a37866 90class Graph {
14957cd0 91public:
93a37866
A
92 Graph(VM&, CodeBlock*, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues);
93 ~Graph();
94
95 void changeChild(Edge& edge, Node* newNode)
14957cd0 96 {
93a37866 97 edge.setNode(newNode);
14957cd0 98 }
6fe7ccc8 99
93a37866 100 void changeEdge(Edge& edge, Edge newEdge)
14957cd0 101 {
93a37866 102 edge = newEdge;
14957cd0 103 }
93a37866
A
104
105 void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode)
6fe7ccc8 106 {
93a37866
A
107 if (edge.node() != oldNode)
108 return;
109 changeChild(edge, newNode);
6fe7ccc8
A
110 }
111
93a37866 112 void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge)
6fe7ccc8 113 {
93a37866
A
114 if (edge != oldEdge)
115 return;
116 changeEdge(edge, newEdge);
6fe7ccc8 117 }
93a37866
A
118
119 void clearAndDerefChild(Node* node, unsigned index)
6fe7ccc8 120 {
93a37866
A
121 if (!node->children.child(index))
122 return;
123 node->children.setChild(index, Edge());
6fe7ccc8 124 }
93a37866
A
125 void clearAndDerefChild1(Node* node) { clearAndDerefChild(node, 0); }
126 void clearAndDerefChild2(Node* node) { clearAndDerefChild(node, 1); }
127 void clearAndDerefChild3(Node* node) { clearAndDerefChild(node, 2); }
6fe7ccc8 128
93a37866
A
129 void performSubstitution(Node* node)
130 {
131 if (node->flags() & NodeHasVarArgs) {
132 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
133 performSubstitutionForEdge(m_varArgChildren[childIdx]);
134 } else {
135 performSubstitutionForEdge(node->child1());
136 performSubstitutionForEdge(node->child2());
137 performSubstitutionForEdge(node->child3());
138 }
139 }
140
141 void performSubstitutionForEdge(Edge& child)
6fe7ccc8 142 {
93a37866
A
143 // Check if this operand is actually unused.
144 if (!child)
145 return;
146
147 // Check if there is any replacement.
148 Node* replacement = child->replacement;
149 if (!replacement)
6fe7ccc8 150 return;
93a37866
A
151
152 child.setNode(replacement);
153
154 // There is definitely a replacement. Assert that the replacement does not
155 // have a replacement.
156 ASSERT(!child->replacement);
6fe7ccc8 157 }
93a37866
A
158
159#define DFG_DEFINE_ADD_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
160 templatePre typeParams templatePost Node* addNode(SpeculatedType type valueParamsComma valueParams) \
161 { \
162 Node* node = new (m_allocator) Node(valueArgs); \
163 node->predict(type); \
164 return node; \
165 }
166 DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_ADD_NODE)
167#undef DFG_DEFINE_ADD_NODE
14957cd0 168
93a37866
A
169 void dethread();
170
171 void convertToConstant(Node* node, unsigned constantNumber)
14957cd0 172 {
93a37866
A
173 if (node->op() == GetLocal)
174 dethread();
175 else
176 ASSERT(!node->hasVariableAccessData());
177 node->convertToConstant(constantNumber);
14957cd0 178 }
93a37866
A
179
180 void convertToConstant(Node* node, JSValue value)
14957cd0 181 {
93a37866 182 convertToConstant(node, m_codeBlock->addOrFindConstant(value));
14957cd0
A
183 }
184
6fe7ccc8 185 // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
93a37866
A
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*);
6fe7ccc8
A
193
194 // Dump the code origin of the given node as a diff from the code origin of the
93a37866
A
195 // preceding node. Returns true if anything was printed.
196 bool dumpCodeOrigin(PrintStream&, const char* prefix, Node* previousNode, Node* currentNode);
6fe7ccc8
A
197
198 BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin);
199
93a37866 200 SpeculatedType getJSConstantSpeculation(Node* node)
6fe7ccc8 201 {
93a37866 202 return speculationFromValue(node->valueOfJSConstant(m_codeBlock));
6fe7ccc8
A
203 }
204
93a37866 205 AddSpeculationMode addSpeculationMode(Node* add, bool leftShouldSpeculateInteger, bool rightShouldSpeculateInteger)
6fe7ccc8 206 {
93a37866 207 ASSERT(add->op() == ValueAdd || add->op() == ArithAdd || add->op() == ArithSub);
6fe7ccc8 208
93a37866
A
209 Node* left = add->child1().node();
210 Node* right = add->child2().node();
6fe7ccc8 211
93a37866
A
212 if (left->hasConstant())
213 return addImmediateShouldSpeculateInteger(add, rightShouldSpeculateInteger, left);
214 if (right->hasConstant())
215 return addImmediateShouldSpeculateInteger(add, leftShouldSpeculateInteger, right);
6fe7ccc8 216
93a37866
A
217 return (leftShouldSpeculateInteger && rightShouldSpeculateInteger && add->canSpeculateInteger()) ? SpeculateInteger : DontSpeculateInteger;
218 }
219
220 AddSpeculationMode valueAddSpeculationMode(Node* add)
221 {
222 return addSpeculationMode(add, add->child1()->shouldSpeculateIntegerExpectingDefined(), add->child2()->shouldSpeculateIntegerExpectingDefined());
6fe7ccc8
A
223 }
224
93a37866 225 AddSpeculationMode arithAddSpeculationMode(Node* add)
6fe7ccc8 226 {
93a37866
A
227 return addSpeculationMode(add, add->child1()->shouldSpeculateIntegerForArithmetic(), add->child2()->shouldSpeculateIntegerForArithmetic());
228 }
229
230 AddSpeculationMode addSpeculationMode(Node* add)
231 {
232 if (add->op() == ValueAdd)
233 return valueAddSpeculationMode(add);
234
235 return arithAddSpeculationMode(add);
6fe7ccc8
A
236 }
237
93a37866 238 bool addShouldSpeculateInteger(Node* add)
6fe7ccc8 239 {
93a37866
A
240 return addSpeculationMode(add) != DontSpeculateInteger;
241 }
242
243 bool mulShouldSpeculateInteger(Node* mul)
244 {
245 ASSERT(mul->op() == ArithMul);
246
247 Node* left = mul->child1().node();
248 Node* right = mul->child2().node();
249
250 return Node::shouldSpeculateIntegerForArithmetic(left, right) && mul->canSpeculateInteger();
251 }
252
253 bool negateShouldSpeculateInteger(Node* negate)
254 {
255 ASSERT(negate->op() == ArithNegate);
256 return negate->child1()->shouldSpeculateIntegerForArithmetic() && negate->canSpeculateInteger();
6fe7ccc8
A
257 }
258
259 // Helper methods to check nodes for constants.
93a37866
A
260 bool isConstant(Node* node)
261 {
262 return node->hasConstant();
263 }
264 bool isJSConstant(Node* node)
6fe7ccc8 265 {
93a37866 266 return node->hasConstant();
6fe7ccc8 267 }
93a37866 268 bool isInt32Constant(Node* node)
6fe7ccc8 269 {
93a37866 270 return node->isInt32Constant(m_codeBlock);
6fe7ccc8 271 }
93a37866 272 bool isDoubleConstant(Node* node)
6fe7ccc8 273 {
93a37866 274 return node->isDoubleConstant(m_codeBlock);
6fe7ccc8 275 }
93a37866 276 bool isNumberConstant(Node* node)
6fe7ccc8 277 {
93a37866 278 return node->isNumberConstant(m_codeBlock);
6fe7ccc8 279 }
93a37866 280 bool isBooleanConstant(Node* node)
14957cd0 281 {
93a37866 282 return node->isBooleanConstant(m_codeBlock);
14957cd0 283 }
93a37866 284 bool isCellConstant(Node* node)
6fe7ccc8 285 {
93a37866
A
286 if (!isJSConstant(node))
287 return false;
288 JSValue value = valueOfJSConstant(node);
289 return value.isCell() && !!value;
290 }
291 bool isFunctionConstant(Node* node)
292 {
293 if (!isJSConstant(node))
294 return false;
295 if (!getJSFunction(valueOfJSConstant(node)))
296 return false;
297 return true;
6fe7ccc8 298 }
93a37866 299 bool isInternalFunctionConstant(Node* node)
6fe7ccc8 300 {
93a37866
A
301 if (!isJSConstant(node))
302 return false;
303 JSValue value = valueOfJSConstant(node);
304 if (!value.isCell() || !value)
6fe7ccc8 305 return false;
93a37866
A
306 JSCell* cell = value.asCell();
307 if (!cell->inherits(&InternalFunction::s_info))
6fe7ccc8
A
308 return false;
309 return true;
310 }
311 // Helper methods get constant values from nodes.
93a37866 312 JSValue valueOfJSConstant(Node* node)
6fe7ccc8 313 {
93a37866 314 return node->valueOfJSConstant(m_codeBlock);
6fe7ccc8 315 }
93a37866 316 int32_t valueOfInt32Constant(Node* node)
6fe7ccc8 317 {
93a37866 318 return valueOfJSConstant(node).asInt32();
6fe7ccc8 319 }
93a37866 320 double valueOfNumberConstant(Node* node)
6fe7ccc8 321 {
93a37866 322 return valueOfJSConstant(node).asNumber();
6fe7ccc8 323 }
93a37866 324 bool valueOfBooleanConstant(Node* node)
6fe7ccc8 325 {
93a37866 326 return valueOfJSConstant(node).asBoolean();
6fe7ccc8 327 }
93a37866 328 JSFunction* valueOfFunctionConstant(Node* node)
6fe7ccc8 329 {
93a37866 330 JSCell* function = getJSFunction(valueOfJSConstant(node));
6fe7ccc8
A
331 ASSERT(function);
332 return jsCast<JSFunction*>(function);
333 }
334
335 static const char *opName(NodeType);
336
6fe7ccc8
A
337 StructureSet* addStructureSet(const StructureSet& structureSet)
338 {
339 ASSERT(structureSet.size());
340 m_structureSet.append(structureSet);
341 return &m_structureSet.last();
342 }
343
344 StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
345 {
346 m_structureTransitionData.append(structureTransitionData);
347 return &m_structureTransitionData.last();
348 }
349
93a37866
A
350 JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
351 {
352 return m_codeBlock->globalObjectFor(codeOrigin);
353 }
354
355 JSObject* globalThisObjectFor(CodeOrigin codeOrigin)
356 {
357 JSGlobalObject* object = globalObjectFor(codeOrigin);
358 return object->methodTable()->toThisObject(object, 0);
359 }
360
361 ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame)
362 {
363 if (!inlineCallFrame)
364 return m_codeBlock->ownerExecutable();
365
366 return inlineCallFrame->executable.get();
367 }
368
369 ExecutableBase* executableFor(const CodeOrigin& codeOrigin)
370 {
371 return executableFor(codeOrigin.inlineCallFrame);
372 }
373
6fe7ccc8
A
374 CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
375 {
376 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
377 }
378
93a37866
A
379 bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
380 {
381 return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind));
382 }
383
384 bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
385 {
386 return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind));
387 }
388
389 int argumentsRegisterFor(const CodeOrigin& codeOrigin)
390 {
391 if (!codeOrigin.inlineCallFrame)
392 return m_codeBlock->argumentsRegister();
393
394 return baselineCodeBlockForInlineCallFrame(
395 codeOrigin.inlineCallFrame)->argumentsRegister() +
396 codeOrigin.inlineCallFrame->stackOffset;
397 }
398
399 int uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin)
400 {
401 if (!codeOrigin.inlineCallFrame)
402 return m_codeBlock->uncheckedArgumentsRegister();
403
404 CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(
405 codeOrigin.inlineCallFrame);
406 if (!codeBlock->usesArguments())
407 return InvalidVirtualRegister;
408
409 return codeBlock->argumentsRegister() +
410 codeOrigin.inlineCallFrame->stackOffset;
411 }
412
413 int uncheckedActivationRegisterFor(const CodeOrigin&)
414 {
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
420 // what we wanted.
421 return m_codeBlock->uncheckedActivationRegister();
422 }
423
424 ValueProfile* valueProfileFor(Node* node)
6fe7ccc8 425 {
93a37866 426 if (!node)
6fe7ccc8
A
427 return 0;
428
93a37866 429 CodeBlock* profiledBlock = baselineCodeBlockFor(node->codeOrigin);
6fe7ccc8 430
93a37866
A
431 if (node->hasLocal()) {
432 if (!operandIsArgument(node->local()))
6fe7ccc8 433 return 0;
93a37866
A
434 int argument = operandToArgument(node->local());
435 if (node->variableAccessData() != m_arguments[argument]->variableAccessData())
6fe7ccc8
A
436 return 0;
437 return profiledBlock->valueProfileForArgument(argument);
438 }
439
93a37866
A
440 if (node->hasHeapPrediction())
441 return profiledBlock->valueProfileForBytecodeOffset(node->codeOrigin.bytecodeIndexForValueProfile());
6fe7ccc8
A
442
443 return 0;
444 }
445
93a37866 446 MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* node)
14957cd0 447 {
93a37866 448 if (!node)
6fe7ccc8
A
449 return MethodOfGettingAValueProfile();
450
93a37866 451 CodeBlock* profiledBlock = baselineCodeBlockFor(node->codeOrigin);
6fe7ccc8 452
93a37866 453 if (node->op() == GetLocal) {
6fe7ccc8
A
454 return MethodOfGettingAValueProfile::fromLazyOperand(
455 profiledBlock,
456 LazyOperandValueProfileKey(
93a37866 457 node->codeOrigin.bytecodeIndex, node->local()));
14957cd0 458 }
6fe7ccc8 459
93a37866 460 return MethodOfGettingAValueProfile(valueProfileFor(node));
6fe7ccc8
A
461 }
462
463 bool needsActivation() const
464 {
6fe7ccc8 465 return m_codeBlock->needsFullScopeChain() && m_codeBlock->codeType() != GlobalCode;
6fe7ccc8
A
466 }
467
93a37866 468 bool usesArguments() const
6fe7ccc8 469 {
93a37866 470 return m_codeBlock->usesArguments();
6fe7ccc8 471 }
93a37866
A
472
473 unsigned numSuccessors(BasicBlock* block)
6fe7ccc8 474 {
93a37866
A
475 return block->last()->numSuccessors();
476 }
477 BlockIndex successor(BasicBlock* block, unsigned index)
478 {
479 return block->last()->successor(index);
480 }
481 BlockIndex successorForCondition(BasicBlock* block, bool condition)
482 {
483 return block->last()->successorForCondition(condition);
484 }
485
486 bool isPredictedNumerical(Node* node)
487 {
488 return isNumerical(node->child1().useKind()) && isNumerical(node->child2().useKind());
489 }
490
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.
496 // - and so on.
497 bool byValIsPure(Node* node)
498 {
499 switch (node->arrayMode().type()) {
500 case Array::Generic:
501 return false;
502 case Array::Int32:
503 case Array::Double:
504 case Array::Contiguous:
505 case Array::ArrayStorage:
506 return !node->arrayMode().isOutOfBounds();
507 case Array::SlowPutArrayStorage:
508 return !node->arrayMode().mayStoreToHole();
509 case Array::String:
510 return node->op() == GetByVal;
511#if USE(JSVALUE32_64)
512 case Array::Arguments:
513 if (node->op() == GetByVal)
514 return true;
515 return false;
516#endif // USE(JSVALUE32_64)
517 default:
518 return true;
519 }
520 }
521
522 bool clobbersWorld(Node* node)
523 {
524 if (node->flags() & NodeClobbersWorld)
525 return true;
526 if (!(node->flags() & NodeMightClobber))
527 return false;
528 switch (node->op()) {
529 case ValueAdd:
530 case CompareLess:
531 case CompareLessEq:
532 case CompareGreater:
533 case CompareGreaterEq:
534 case CompareEq:
535 return !isPredictedNumerical(node);
536 case GetByVal:
537 case PutByVal:
538 case PutByValAlias:
539 return !byValIsPure(node);
540 case ToString:
541 switch (node->child1().useKind()) {
542 case StringObjectUse:
543 case StringOrStringObjectUse:
544 return false;
545 case CellUse:
546 case UntypedUse:
547 return true;
548 default:
549 RELEASE_ASSERT_NOT_REACHED();
550 return true;
551 }
552 default:
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.
555 }
556 }
557
558 void determineReachability();
559 void resetReachability();
560
561 void resetExitStates();
562
563 unsigned varArgNumChildren(Node* node)
564 {
565 ASSERT(node->flags() & NodeHasVarArgs);
566 return node->numChildren();
6fe7ccc8
A
567 }
568
93a37866 569 unsigned numChildren(Node* node)
6fe7ccc8 570 {
93a37866
A
571 if (node->flags() & NodeHasVarArgs)
572 return varArgNumChildren(node);
573 return AdjacencyList::Size;
6fe7ccc8 574 }
93a37866
A
575
576 Edge& varArgChild(Node* node, unsigned index)
6fe7ccc8 577 {
93a37866
A
578 ASSERT(node->flags() & NodeHasVarArgs);
579 return m_varArgChildren[node->firstChild() + index];
14957cd0 580 }
6fe7ccc8 581
93a37866
A
582 Edge& child(Node* node, unsigned index)
583 {
584 if (node->flags() & NodeHasVarArgs)
585 return varArgChild(node, index);
586 return node->children.child(index);
587 }
588
589 void voteNode(Node* node, unsigned ballot)
590 {
591 switch (node->op()) {
592 case ValueToInt32:
593 case UInt32ToNumber:
594 node = node->child1().node();
595 break;
596 default:
597 break;
598 }
599
600 if (node->op() == GetLocal)
601 node->variableAccessData()->vote(ballot);
602 }
603
604 void voteNode(Edge edge, unsigned ballot)
605 {
606 voteNode(edge.node(), ballot);
607 }
608
609 void voteChildren(Node* node, unsigned ballot)
610 {
611 if (node->flags() & NodeHasVarArgs) {
612 for (unsigned childIdx = node->firstChild();
613 childIdx < node->firstChild() + node->numChildren();
614 childIdx++) {
615 if (!!m_varArgChildren[childIdx])
616 voteNode(m_varArgChildren[childIdx], ballot);
617 }
618 return;
619 }
620
621 if (!node->child1())
622 return;
623 voteNode(node->child1(), ballot);
624 if (!node->child2())
625 return;
626 voteNode(node->child2(), ballot);
627 if (!node->child3())
628 return;
629 voteNode(node->child3(), ballot);
630 }
631
632 template<typename T> // T = Node* or Edge
633 void substitute(BasicBlock& block, unsigned startIndexInBlock, T oldThing, T newThing)
634 {
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);
641 }
642 continue;
643 }
644 if (!node->child1())
645 continue;
646 compareAndSwap(node->children.child1(), oldThing, newThing);
647 if (!node->child2())
648 continue;
649 compareAndSwap(node->children.child2(), oldThing, newThing);
650 if (!node->child3())
651 continue;
652 compareAndSwap(node->children.child3(), oldThing, newThing);
653 }
654 }
655
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)
661 {
662 if (variableAccessData->isCaptured()) {
663 // Let CSE worry about this one.
664 return;
665 }
666 for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) {
667 Node* node = block[indexInBlock];
668 bool shouldContinue = true;
669 switch (node->op()) {
670 case SetLocal: {
671 if (node->local() == variableAccessData->local())
672 shouldContinue = false;
673 break;
674 }
675
676 case GetLocal: {
677 if (node->variableAccessData() != variableAccessData)
678 continue;
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;
684 break;
685 }
686
687 default:
688 break;
689 }
690 if (!shouldContinue)
691 break;
692 }
693 }
694
695 VM& m_vm;
6fe7ccc8 696 CodeBlock* m_codeBlock;
93a37866 697 RefPtr<Profiler::Compilation> m_compilation;
6fe7ccc8 698 CodeBlock* m_profiledBlock;
93a37866
A
699
700 NodeAllocator& m_allocator;
14957cd0
A
701
702 Vector< OwnPtr<BasicBlock> , 8> m_blocks;
6fe7ccc8
A
703 Vector<Edge, 16> m_varArgChildren;
704 Vector<StorageAccessData> m_storageAccessData;
705 Vector<ResolveGlobalData> m_resolveGlobalData;
93a37866
A
706 Vector<ResolveOperationData> m_resolveOperationsData;
707 Vector<PutToBaseOperationData> m_putToBaseOperationData;
708 Vector<Node*, 8> m_arguments;
6fe7ccc8
A
709 SegmentedVector<VariableAccessData, 16> m_variableAccessData;
710 SegmentedVector<ArgumentPosition, 8> m_argumentPositions;
711 SegmentedVector<StructureSet, 16> m_structureSet;
712 SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
93a37866
A
713 SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData;
714 bool m_hasArguments;
715 HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped;
6fe7ccc8 716 BitVector m_preservedVars;
93a37866 717 Dominators m_dominators;
6fe7ccc8
A
718 unsigned m_localVars;
719 unsigned m_parameterSlots;
93a37866
A
720 unsigned m_osrEntryBytecodeIndex;
721 Operands<JSValue> m_mustHandleValues;
722
723 OptimizationFixpointState m_fixpointState;
724 GraphForm m_form;
725 UnificationState m_unificationState;
726 RefCountState m_refCountState;
14957cd0 727private:
6fe7ccc8 728
93a37866
A
729 void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
730
731 AddSpeculationMode addImmediateShouldSpeculateInteger(Node* add, bool variableShouldSpeculateInteger, Node* immediate)
6fe7ccc8 732 {
93a37866 733 ASSERT(immediate->hasConstant());
6fe7ccc8 734
93a37866 735 JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock);
6fe7ccc8 736 if (!immediateValue.isNumber())
93a37866 737 return DontSpeculateInteger;
6fe7ccc8 738
93a37866
A
739 if (!variableShouldSpeculateInteger)
740 return DontSpeculateInteger;
6fe7ccc8
A
741
742 if (immediateValue.isInt32())
93a37866 743 return add->canSpeculateInteger() ? SpeculateInteger : DontSpeculateInteger;
6fe7ccc8
A
744
745 double doubleImmediate = immediateValue.asDouble();
746 const double twoToThe48 = 281474976710656.0;
747 if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48)
93a37866 748 return DontSpeculateInteger;
6fe7ccc8 749
93a37866 750 return nodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateIntegerAndTruncateConstants : DontSpeculateInteger;
6fe7ccc8
A
751 }
752
93a37866
A
753 bool mulImmediateShouldSpeculateInteger(Node* mul, Node* variable, Node* immediate)
754 {
755 ASSERT(immediate->hasConstant());
756
757 JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock);
758 if (!immediateValue.isInt32())
759 return false;
760
761 if (!variable->shouldSpeculateIntegerForArithmetic())
762 return false;
763
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());
773
774 return mul->canSpeculateInteger();
775 }
6fe7ccc8
A
776};
777
778class GetBytecodeBeginForBlock {
779public:
780 GetBytecodeBeginForBlock(Graph& graph)
781 : m_graph(graph)
782 {
783 }
784
785 unsigned operator()(BlockIndex* blockIndex) const
786 {
787 return m_graph.m_blocks[*blockIndex]->bytecodeBegin;
788 }
14957cd0 789
6fe7ccc8
A
790private:
791 Graph& m_graph;
14957cd0
A
792};
793
6fe7ccc8
A
794inline BlockIndex Graph::blockIndexForBytecodeOffset(Vector<BlockIndex>& linkingTargets, unsigned bytecodeBegin)
795{
93a37866 796 return *binarySearch<BlockIndex, unsigned>(linkingTargets, linkingTargets.size(), bytecodeBegin, GetBytecodeBeginForBlock(*this));
6fe7ccc8
A
797}
798
93a37866
A
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(); \
804 _childIdx++) { \
805 if (!!(graph).m_varArgChildren[_childIdx]) \
806 thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \
807 } \
808 } else { \
809 if (!_node->child1()) { \
810 ASSERT( \
811 !_node->child2() \
812 && !_node->child3()); \
813 break; \
814 } \
815 thingToDo(_node, _node->child1()); \
816 \
817 if (!_node->child2()) { \
818 ASSERT(!_node->child3()); \
819 break; \
820 } \
821 thingToDo(_node, _node->child2()); \
822 \
823 if (!_node->child3()) \
824 break; \
825 thingToDo(_node, _node->child3()); \
826 } \
827 } while (false)
828
14957cd0
A
829} } // namespace JSC::DFG
830
831#endif
832#endif