]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGGraph.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGGraph.h
CommitLineData
14957cd0 1/*
ed1e77d3 2 * Copyright (C) 2011-2015 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
29#if ENABLE(DFG_JIT)
30
81345200 31#include "AssemblyHelpers.h"
ed1e77d3 32#include "BytecodeLivenessAnalysisInlines.h"
6fe7ccc8
A
33#include "CodeBlock.h"
34#include "DFGArgumentPosition.h"
6fe7ccc8 35#include "DFGBasicBlock.h"
93a37866 36#include "DFGDominators.h"
ed1e77d3 37#include "DFGFrozenValue.h"
93a37866 38#include "DFGLongLivedState.h"
81345200 39#include "DFGNaturalLoops.h"
6fe7ccc8 40#include "DFGNode.h"
93a37866 41#include "DFGNodeAllocator.h"
81345200 42#include "DFGPlan.h"
ed1e77d3 43#include "DFGPrePostNumbering.h"
81345200 44#include "DFGScannable.h"
ed1e77d3 45#include "FullBytecodeLiveness.h"
93a37866 46#include "JSStack.h"
6fe7ccc8 47#include "MethodOfGettingAValueProfile.h"
81345200 48#include <unordered_map>
6fe7ccc8
A
49#include <wtf/BitVector.h>
50#include <wtf/HashMap.h>
14957cd0
A
51#include <wtf/Vector.h>
52#include <wtf/StdLibExtras.h>
53
54namespace JSC {
55
56class CodeBlock;
6fe7ccc8 57class ExecState;
14957cd0
A
58
59namespace DFG {
60
ed1e77d3
A
61#define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \
62 Node* _node = (node); \
63 if (_node->flags() & NodeHasVarArgs) { \
64 for (unsigned _childIdx = _node->firstChild(); \
65 _childIdx < _node->firstChild() + _node->numChildren(); \
66 _childIdx++) { \
67 if (!!(graph).m_varArgChildren[_childIdx]) \
68 thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \
69 } \
70 } else { \
71 if (!_node->child1()) { \
72 ASSERT( \
73 !_node->child2() \
74 && !_node->child3()); \
75 break; \
76 } \
77 thingToDo(_node, _node->child1()); \
78 \
79 if (!_node->child2()) { \
80 ASSERT(!_node->child3()); \
81 break; \
82 } \
83 thingToDo(_node, _node->child2()); \
84 \
85 if (!_node->child3()) \
86 break; \
87 thingToDo(_node, _node->child3()); \
88 } \
89 } while (false)
90
91#define DFG_ASSERT(graph, node, assertion) do { \
92 if (!!(assertion)) \
93 break; \
94 (graph).handleAssertionFailure( \
95 (node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
96 } while (false)
97
98#define DFG_CRASH(graph, node, reason) do { \
99 (graph).handleAssertionFailure( \
100 (node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, (reason)); \
101 } while (false)
14957cd0 102
81345200
A
103struct InlineVariableData {
104 InlineCallFrame* inlineCallFrame;
105 unsigned argumentPositionStart;
106 VariableAccessData* calleeVariable;
93a37866
A
107};
108
109enum AddSpeculationMode {
81345200
A
110 DontSpeculateInt32,
111 SpeculateInt32AndTruncateConstants,
112 SpeculateInt32
93a37866
A
113};
114
93a37866 115//
14957cd0
A
116// === Graph ===
117//
14957cd0
A
118// The order may be significant for nodes with side-effects (property accesses, value conversions).
119// Nodes that are 'dead' remain in the vector with refCount 0.
81345200 120class Graph : public virtual Scannable {
14957cd0 121public:
81345200 122 Graph(VM&, Plan&, LongLivedState&);
93a37866
A
123 ~Graph();
124
125 void changeChild(Edge& edge, Node* newNode)
14957cd0 126 {
93a37866 127 edge.setNode(newNode);
14957cd0 128 }
6fe7ccc8 129
93a37866 130 void changeEdge(Edge& edge, Edge newEdge)
14957cd0 131 {
93a37866 132 edge = newEdge;
14957cd0 133 }
93a37866
A
134
135 void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode)
6fe7ccc8 136 {
93a37866
A
137 if (edge.node() != oldNode)
138 return;
139 changeChild(edge, newNode);
6fe7ccc8
A
140 }
141
93a37866 142 void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge)
6fe7ccc8 143 {
93a37866
A
144 if (edge != oldEdge)
145 return;
146 changeEdge(edge, newEdge);
6fe7ccc8 147 }
93a37866 148
93a37866
A
149 void performSubstitution(Node* node)
150 {
151 if (node->flags() & NodeHasVarArgs) {
152 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
153 performSubstitutionForEdge(m_varArgChildren[childIdx]);
154 } else {
155 performSubstitutionForEdge(node->child1());
156 performSubstitutionForEdge(node->child2());
157 performSubstitutionForEdge(node->child3());
158 }
159 }
160
161 void performSubstitutionForEdge(Edge& child)
6fe7ccc8 162 {
93a37866
A
163 // Check if this operand is actually unused.
164 if (!child)
165 return;
166
167 // Check if there is any replacement.
ed1e77d3 168 Node* replacement = child->replacement();
93a37866 169 if (!replacement)
6fe7ccc8 170 return;
93a37866
A
171
172 child.setNode(replacement);
173
174 // There is definitely a replacement. Assert that the replacement does not
175 // have a replacement.
ed1e77d3 176 ASSERT(!child->replacement());
6fe7ccc8 177 }
93a37866 178
81345200
A
179 template<typename... Params>
180 Node* addNode(SpeculatedType type, Params... params)
181 {
182 Node* node = new (m_allocator) Node(params...);
183 node->predict(type);
184 return node;
93a37866 185 }
14957cd0 186
93a37866
A
187 void dethread();
188
ed1e77d3
A
189 FrozenValue* freeze(JSValue); // We use weak freezing by default.
190 FrozenValue* freezeStrong(JSValue); // Shorthand for freeze(value)->strengthenTo(StrongValue).
191
192 void convertToConstant(Node* node, FrozenValue* value);
193 void convertToConstant(Node* node, JSValue value);
194 void convertToStrongConstant(Node* node, JSValue value);
195
196 StructureRegistrationResult registerStructure(Structure* structure);
197 void assertIsRegistered(Structure* structure);
81345200 198
6fe7ccc8 199 // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
81345200 200 void dump(PrintStream& = WTF::dataFile(), DumpContext* = 0);
ed1e77d3
A
201
202 bool terminalsAreValid();
203
93a37866 204 enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis };
81345200 205 void dumpBlockHeader(PrintStream&, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*);
93a37866 206 void dump(PrintStream&, Edge);
81345200 207 void dump(PrintStream&, const char* prefix, Node*, DumpContext* = 0);
93a37866
A
208 static int amountOfNodeWhiteSpace(Node*);
209 static void printNodeWhiteSpace(PrintStream&, Node*);
6fe7ccc8
A
210
211 // Dump the code origin of the given node as a diff from the code origin of the
93a37866 212 // preceding node. Returns true if anything was printed.
81345200 213 bool dumpCodeOrigin(PrintStream&, const char* prefix, Node* previousNode, Node* currentNode, DumpContext*);
6fe7ccc8 214
81345200 215 AddSpeculationMode addSpeculationMode(Node* add, bool leftShouldSpeculateInt32, bool rightShouldSpeculateInt32, PredictionPass pass)
6fe7ccc8 216 {
93a37866 217 ASSERT(add->op() == ValueAdd || add->op() == ArithAdd || add->op() == ArithSub);
6fe7ccc8 218
81345200
A
219 RareCaseProfilingSource source = add->sourceFor(pass);
220
93a37866
A
221 Node* left = add->child1().node();
222 Node* right = add->child2().node();
6fe7ccc8 223
93a37866 224 if (left->hasConstant())
ed1e77d3 225 return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, right, left, source);
93a37866 226 if (right->hasConstant())
ed1e77d3 227 return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, left, right, source);
6fe7ccc8 228
81345200 229 return (leftShouldSpeculateInt32 && rightShouldSpeculateInt32 && add->canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32;
93a37866
A
230 }
231
81345200 232 AddSpeculationMode valueAddSpeculationMode(Node* add, PredictionPass pass)
93a37866 233 {
81345200
A
234 return addSpeculationMode(
235 add,
236 add->child1()->shouldSpeculateInt32OrBooleanExpectingDefined(),
237 add->child2()->shouldSpeculateInt32OrBooleanExpectingDefined(),
238 pass);
6fe7ccc8
A
239 }
240
81345200 241 AddSpeculationMode arithAddSpeculationMode(Node* add, PredictionPass pass)
6fe7ccc8 242 {
81345200
A
243 return addSpeculationMode(
244 add,
245 add->child1()->shouldSpeculateInt32OrBooleanForArithmetic(),
246 add->child2()->shouldSpeculateInt32OrBooleanForArithmetic(),
247 pass);
93a37866
A
248 }
249
81345200 250 AddSpeculationMode addSpeculationMode(Node* add, PredictionPass pass)
93a37866
A
251 {
252 if (add->op() == ValueAdd)
81345200 253 return valueAddSpeculationMode(add, pass);
93a37866 254
81345200 255 return arithAddSpeculationMode(add, pass);
6fe7ccc8
A
256 }
257
81345200 258 bool addShouldSpeculateInt32(Node* add, PredictionPass pass)
6fe7ccc8 259 {
81345200 260 return addSpeculationMode(add, pass) != DontSpeculateInt32;
93a37866
A
261 }
262
81345200
A
263 bool addShouldSpeculateMachineInt(Node* add)
264 {
265 if (!enableInt52())
266 return false;
267
268 Node* left = add->child1().node();
269 Node* right = add->child2().node();
270
ed1e77d3 271 bool speculation = Node::shouldSpeculateMachineInt(left, right);
81345200
A
272 return speculation && !hasExitSite(add, Int52Overflow);
273 }
274
275 bool mulShouldSpeculateInt32(Node* mul, PredictionPass pass)
93a37866
A
276 {
277 ASSERT(mul->op() == ArithMul);
278
279 Node* left = mul->child1().node();
280 Node* right = mul->child2().node();
281
81345200
A
282 return Node::shouldSpeculateInt32OrBooleanForArithmetic(left, right)
283 && mul->canSpeculateInt32(mul->sourceFor(pass));
284 }
285
286 bool mulShouldSpeculateMachineInt(Node* mul, PredictionPass pass)
287 {
288 ASSERT(mul->op() == ArithMul);
289
290 if (!enableInt52())
291 return false;
292
293 Node* left = mul->child1().node();
294 Node* right = mul->child2().node();
295
296 return Node::shouldSpeculateMachineInt(left, right)
297 && mul->canSpeculateInt52(pass)
298 && !hasExitSite(mul, Int52Overflow);
299 }
300
301 bool negateShouldSpeculateInt32(Node* negate, PredictionPass pass)
302 {
303 ASSERT(negate->op() == ArithNegate);
304 return negate->child1()->shouldSpeculateInt32OrBooleanForArithmetic()
305 && negate->canSpeculateInt32(pass);
93a37866
A
306 }
307
81345200 308 bool negateShouldSpeculateMachineInt(Node* negate, PredictionPass pass)
93a37866
A
309 {
310 ASSERT(negate->op() == ArithNegate);
81345200
A
311 if (!enableInt52())
312 return false;
313 return negate->child1()->shouldSpeculateMachineInt()
314 && !hasExitSite(negate, Int52Overflow)
315 && negate->canSpeculateInt52(pass);
316 }
ed1e77d3
A
317
318 bool roundShouldSpeculateInt32(Node* arithRound, PredictionPass pass)
81345200 319 {
ed1e77d3
A
320 ASSERT(arithRound->op() == ArithRound);
321 return arithRound->canSpeculateInt32(pass) && !hasExitSite(arithRound->origin.semantic, Overflow) && !hasExitSite(arithRound->origin.semantic, NegativeZero);
6fe7ccc8
A
322 }
323
6fe7ccc8
A
324 static const char *opName(NodeType);
325
6fe7ccc8
A
326 StructureSet* addStructureSet(const StructureSet& structureSet)
327 {
328 ASSERT(structureSet.size());
329 m_structureSet.append(structureSet);
330 return &m_structureSet.last();
331 }
332
93a37866
A
333 JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
334 {
335 return m_codeBlock->globalObjectFor(codeOrigin);
336 }
337
338 JSObject* globalThisObjectFor(CodeOrigin codeOrigin)
339 {
340 JSGlobalObject* object = globalObjectFor(codeOrigin);
81345200 341 return jsCast<JSObject*>(object->methodTable()->toThis(object, object->globalExec(), NotStrictMode));
93a37866
A
342 }
343
81345200 344 ScriptExecutable* executableFor(InlineCallFrame* inlineCallFrame)
93a37866
A
345 {
346 if (!inlineCallFrame)
347 return m_codeBlock->ownerExecutable();
348
349 return inlineCallFrame->executable.get();
350 }
351
81345200 352 ScriptExecutable* executableFor(const CodeOrigin& codeOrigin)
93a37866
A
353 {
354 return executableFor(codeOrigin.inlineCallFrame);
355 }
356
81345200
A
357 CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
358 {
359 if (!inlineCallFrame)
360 return m_profiledBlock;
361 return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
362 }
363
6fe7ccc8
A
364 CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
365 {
366 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
367 }
368
ed1e77d3
A
369 SymbolTable* symbolTableFor(InlineCallFrame* inlineCallFrame)
370 {
371 return baselineCodeBlockFor(inlineCallFrame)->symbolTable();
372 }
373
374 SymbolTable* symbolTableFor(const CodeOrigin& codeOrigin)
375 {
376 return symbolTableFor(codeOrigin.inlineCallFrame);
377 }
378
81345200
A
379 bool isStrictModeFor(CodeOrigin codeOrigin)
380 {
381 if (!codeOrigin.inlineCallFrame)
382 return m_codeBlock->isStrictMode();
383 return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->isStrictMode();
384 }
385
386 ECMAMode ecmaModeFor(CodeOrigin codeOrigin)
387 {
388 return isStrictModeFor(codeOrigin) ? StrictMode : NotStrictMode;
389 }
390
391 bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin)
392 {
ed1e77d3 393 return globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid();
81345200
A
394 }
395
93a37866
A
396 bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
397 {
398 return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind));
399 }
400
401 bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
402 {
403 return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind));
404 }
405
81345200 406 bool hasExitSite(Node* node, ExitKind exitKind)
93a37866 407 {
81345200
A
408 return hasExitSite(node->origin.semantic, exitKind);
409 }
410
81345200
A
411 VirtualRegister activationRegister()
412 {
413 return m_profiledBlock->activationRegister();
414 }
415
416 VirtualRegister uncheckedActivationRegister()
417 {
418 return m_profiledBlock->uncheckedActivationRegister();
419 }
420
421 VirtualRegister machineActivationRegister()
422 {
423 return m_profiledBlock->activationRegister();
93a37866
A
424 }
425
81345200 426 VirtualRegister uncheckedMachineActivationRegister()
93a37866 427 {
81345200 428 return m_profiledBlock->uncheckedActivationRegister();
93a37866
A
429 }
430
ed1e77d3
A
431 ValueProfile* valueProfileFor(Node*);
432 MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node*);
93a37866 433
81345200
A
434 BlockIndex numBlocks() const { return m_blocks.size(); }
435 BasicBlock* block(BlockIndex blockIndex) const { return m_blocks[blockIndex].get(); }
436 BasicBlock* lastBlock() const { return block(numBlocks() - 1); }
437
438 void appendBlock(PassRefPtr<BasicBlock> basicBlock)
6fe7ccc8 439 {
81345200
A
440 basicBlock->index = m_blocks.size();
441 m_blocks.append(basicBlock);
93a37866 442 }
81345200
A
443
444 void killBlock(BlockIndex blockIndex)
93a37866 445 {
ed1e77d3 446 m_blocks[blockIndex] = nullptr;
93a37866 447 }
81345200
A
448
449 void killBlock(BasicBlock* basicBlock)
93a37866 450 {
81345200 451 killBlock(basicBlock->index);
93a37866
A
452 }
453
81345200
A
454 void killBlockAndItsContents(BasicBlock*);
455
456 void killUnreachableBlocks();
457
93a37866
A
458 void determineReachability();
459 void resetReachability();
460
ed1e77d3 461 void computeRefCounts();
93a37866
A
462
463 unsigned varArgNumChildren(Node* node)
464 {
465 ASSERT(node->flags() & NodeHasVarArgs);
466 return node->numChildren();
6fe7ccc8
A
467 }
468
93a37866 469 unsigned numChildren(Node* node)
6fe7ccc8 470 {
93a37866
A
471 if (node->flags() & NodeHasVarArgs)
472 return varArgNumChildren(node);
473 return AdjacencyList::Size;
6fe7ccc8 474 }
93a37866
A
475
476 Edge& varArgChild(Node* node, unsigned index)
6fe7ccc8 477 {
93a37866
A
478 ASSERT(node->flags() & NodeHasVarArgs);
479 return m_varArgChildren[node->firstChild() + index];
14957cd0 480 }
6fe7ccc8 481
93a37866
A
482 Edge& child(Node* node, unsigned index)
483 {
484 if (node->flags() & NodeHasVarArgs)
485 return varArgChild(node, index);
486 return node->children.child(index);
487 }
488
81345200 489 void voteNode(Node* node, unsigned ballot, float weight = 1)
93a37866
A
490 {
491 switch (node->op()) {
492 case ValueToInt32:
493 case UInt32ToNumber:
494 node = node->child1().node();
495 break;
496 default:
497 break;
498 }
499
500 if (node->op() == GetLocal)
81345200 501 node->variableAccessData()->vote(ballot, weight);
93a37866
A
502 }
503
81345200 504 void voteNode(Edge edge, unsigned ballot, float weight = 1)
93a37866 505 {
81345200 506 voteNode(edge.node(), ballot, weight);
93a37866
A
507 }
508
81345200 509 void voteChildren(Node* node, unsigned ballot, float weight = 1)
93a37866
A
510 {
511 if (node->flags() & NodeHasVarArgs) {
512 for (unsigned childIdx = node->firstChild();
513 childIdx < node->firstChild() + node->numChildren();
514 childIdx++) {
515 if (!!m_varArgChildren[childIdx])
81345200 516 voteNode(m_varArgChildren[childIdx], ballot, weight);
93a37866
A
517 }
518 return;
519 }
520
521 if (!node->child1())
522 return;
81345200 523 voteNode(node->child1(), ballot, weight);
93a37866
A
524 if (!node->child2())
525 return;
81345200 526 voteNode(node->child2(), ballot, weight);
93a37866
A
527 if (!node->child3())
528 return;
81345200 529 voteNode(node->child3(), ballot, weight);
93a37866
A
530 }
531
532 template<typename T> // T = Node* or Edge
533 void substitute(BasicBlock& block, unsigned startIndexInBlock, T oldThing, T newThing)
534 {
535 for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) {
536 Node* node = block[indexInBlock];
537 if (node->flags() & NodeHasVarArgs) {
538 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); ++childIdx) {
539 if (!!m_varArgChildren[childIdx])
540 compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing);
541 }
542 continue;
543 }
544 if (!node->child1())
545 continue;
546 compareAndSwap(node->children.child1(), oldThing, newThing);
547 if (!node->child2())
548 continue;
549 compareAndSwap(node->children.child2(), oldThing, newThing);
550 if (!node->child3())
551 continue;
552 compareAndSwap(node->children.child3(), oldThing, newThing);
553 }
554 }
555
556 // Use this if you introduce a new GetLocal and you know that you introduced it *before*
557 // any GetLocals in the basic block.
558 // FIXME: it may be appropriate, in the future, to generalize this to handle GetLocals
559 // introduced anywhere in the basic block.
81345200
A
560 void substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal);
561
562 void invalidateCFG();
563
564 void clearFlagsOnAllNodes(NodeFlags);
565
566 void clearReplacements();
ed1e77d3 567 void clearEpochs();
81345200
A
568 void initializeNodeOwners();
569
ed1e77d3
A
570 BlockList blocksInPreOrder();
571 BlockList blocksInPostOrder();
572
573 class NaturalBlockIterable {
574 public:
575 NaturalBlockIterable()
576 : m_graph(nullptr)
577 {
578 }
579
580 NaturalBlockIterable(Graph& graph)
581 : m_graph(&graph)
582 {
583 }
584
585 class iterator {
586 public:
587 iterator()
588 : m_graph(nullptr)
589 , m_index(0)
590 {
591 }
592
593 iterator(Graph& graph, BlockIndex index)
594 : m_graph(&graph)
595 , m_index(findNext(index))
596 {
597 }
598
599 BasicBlock *operator*()
600 {
601 return m_graph->block(m_index);
602 }
603
604 iterator& operator++()
605 {
606 m_index = findNext(m_index + 1);
607 return *this;
608 }
609
610 bool operator==(const iterator& other) const
611 {
612 return m_index == other.m_index;
613 }
614
615 bool operator!=(const iterator& other) const
616 {
617 return !(*this == other);
618 }
619
620 private:
621 BlockIndex findNext(BlockIndex index)
622 {
623 while (index < m_graph->numBlocks() && !m_graph->block(index))
624 index++;
625 return index;
626 }
627
628 Graph* m_graph;
629 BlockIndex m_index;
630 };
631
632 iterator begin()
633 {
634 return iterator(*m_graph, 0);
635 }
636
637 iterator end()
638 {
639 return iterator(*m_graph, m_graph->numBlocks());
640 }
641
642 private:
643 Graph* m_graph;
644 };
645
646 NaturalBlockIterable blocksInNaturalOrder()
647 {
648 return NaturalBlockIterable(*this);
649 }
650
651 template<typename ChildFunctor>
652 void doToChildrenWithNode(Node* node, const ChildFunctor& functor)
653 {
654 DFG_NODE_DO_TO_CHILDREN(*this, node, functor);
655 }
656
657 template<typename ChildFunctor>
658 void doToChildren(Node* node, const ChildFunctor& functor)
659 {
660 doToChildrenWithNode(
661 node,
662 [&functor] (Node*, Edge& edge) {
663 functor(edge);
664 });
665 }
666
667 bool uses(Node* node, Node* child)
668 {
669 bool result = false;
670 doToChildren(node, [&] (Edge edge) { result |= edge == child; });
671 return result;
672 }
81345200
A
673
674 Profiler::Compilation* compilation() { return m_plan.compilation.get(); }
675
676 DesiredIdentifiers& identifiers() { return m_plan.identifiers; }
677 DesiredWatchpoints& watchpoints() { return m_plan.watchpoints; }
81345200
A
678
679 FullBytecodeLiveness& livenessFor(CodeBlock*);
680 FullBytecodeLiveness& livenessFor(InlineCallFrame*);
ed1e77d3
A
681
682 // Quickly query if a single local is live at the given point. This is faster than calling
683 // forAllLiveInBytecode() if you will only query one local. But, if you want to know all of the
684 // locals live, then calling this for each local is much slower than forAllLiveInBytecode().
81345200
A
685 bool isLiveInBytecode(VirtualRegister, CodeOrigin);
686
ed1e77d3
A
687 // Quickly get all of the non-argument locals live at the given point. This doesn't give you
688 // any arguments because those are all presumed live. You can call forAllLiveInBytecode() to
689 // also get the arguments. This is much faster than calling isLiveInBytecode() for each local.
690 template<typename Functor>
691 void forAllLocalsLiveInBytecode(CodeOrigin codeOrigin, const Functor& functor)
692 {
693 // Support for not redundantly reporting arguments. Necessary because in case of a varargs
694 // call, only the callee knows that arguments are live while in the case of a non-varargs
695 // call, both callee and caller will see the variables live.
696 VirtualRegister exclusionStart;
697 VirtualRegister exclusionEnd;
698
699 for (;;) {
700 InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
701 VirtualRegister stackOffset(inlineCallFrame ? inlineCallFrame->stackOffset : 0);
702
703 if (inlineCallFrame) {
704 if (inlineCallFrame->isClosureCall)
705 functor(stackOffset + JSStack::Callee);
706 if (inlineCallFrame->isVarargs())
707 functor(stackOffset + JSStack::ArgumentCount);
708 }
709
710 CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame);
711 FullBytecodeLiveness& fullLiveness = livenessFor(codeBlock);
712 const FastBitVector& liveness = fullLiveness.getLiveness(codeOrigin.bytecodeIndex);
713 for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
714 VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal);
715
716 // Don't report if our callee already reported.
717 if (reg >= exclusionStart && reg < exclusionEnd)
718 continue;
719
720 if (liveness.get(relativeLocal))
721 functor(reg);
722 }
723
724 if (!inlineCallFrame)
725 break;
726
727 // Arguments are always live. This would be redundant if it wasn't for our
728 // op_call_varargs inlining. See the comment above.
729 exclusionStart = stackOffset + CallFrame::argumentOffsetIncludingThis(0);
730 exclusionEnd = stackOffset + CallFrame::argumentOffsetIncludingThis(inlineCallFrame->arguments.size());
731
732 // We will always have a "this" argument and exclusionStart should be a smaller stack
733 // offset than exclusionEnd.
734 ASSERT(exclusionStart < exclusionEnd);
735
736 for (VirtualRegister reg = exclusionStart; reg < exclusionEnd; reg += 1)
737 functor(reg);
738
739 codeOrigin = inlineCallFrame->caller;
740 }
741 }
742
743 // Get a BitVector of all of the non-argument locals live right now. This is mostly useful if
744 // you want to compare two sets of live locals from two different CodeOrigins.
745 BitVector localsLiveInBytecode(CodeOrigin);
746
747 // Tells you all of the arguments and locals live at the given CodeOrigin. This is a small
748 // extension to forAllLocalsLiveInBytecode(), since all arguments are always presumed live.
749 template<typename Functor>
750 void forAllLiveInBytecode(CodeOrigin codeOrigin, const Functor& functor)
751 {
752 forAllLocalsLiveInBytecode(codeOrigin, functor);
753
754 // Report all arguments as being live.
755 for (unsigned argument = block(0)->variablesAtHead.numberOfArguments(); argument--;)
756 functor(virtualRegisterForArgument(argument));
757 }
758
759 BytecodeKills& killsFor(CodeBlock*);
760 BytecodeKills& killsFor(InlineCallFrame*);
761
81345200
A
762 unsigned frameRegisterCount();
763 unsigned stackPointerOffset();
764 unsigned requiredRegisterCountForExit();
765 unsigned requiredRegisterCountForExecutionAndExit();
766
ed1e77d3
A
767 JSValue tryGetConstantProperty(JSValue base, const StructureSet&, PropertyOffset);
768 JSValue tryGetConstantProperty(JSValue base, Structure*, PropertyOffset);
769 JSValue tryGetConstantProperty(JSValue base, const StructureAbstractValue&, PropertyOffset);
770 JSValue tryGetConstantProperty(const AbstractValue&, PropertyOffset);
771
772 JSValue tryGetConstantClosureVar(JSValue base, ScopeOffset);
773 JSValue tryGetConstantClosureVar(const AbstractValue&, ScopeOffset);
774 JSValue tryGetConstantClosureVar(Node*, ScopeOffset);
81345200 775
ed1e77d3
A
776 JSArrayBufferView* tryGetFoldableView(JSValue);
777 JSArrayBufferView* tryGetFoldableView(JSValue, ArrayMode arrayMode);
778
779 void registerFrozenValues();
81345200
A
780
781 virtual void visitChildren(SlotVisitor&) override;
93a37866 782
ed1e77d3
A
783 NO_RETURN_DUE_TO_CRASH void handleAssertionFailure(
784 std::nullptr_t, const char* file, int line, const char* function,
785 const char* assertion);
786 NO_RETURN_DUE_TO_CRASH void handleAssertionFailure(
787 Node*, const char* file, int line, const char* function,
788 const char* assertion);
789 NO_RETURN_DUE_TO_CRASH void handleAssertionFailure(
790 BasicBlock*, const char* file, int line, const char* function,
791 const char* assertion);
792
793 bool hasDebuggerEnabled() const { return m_hasDebuggerEnabled; }
794
93a37866 795 VM& m_vm;
81345200 796 Plan& m_plan;
6fe7ccc8
A
797 CodeBlock* m_codeBlock;
798 CodeBlock* m_profiledBlock;
93a37866
A
799
800 NodeAllocator& m_allocator;
14957cd0 801
81345200 802 Vector< RefPtr<BasicBlock> , 8> m_blocks;
6fe7ccc8 803 Vector<Edge, 16> m_varArgChildren;
ed1e77d3
A
804
805 HashMap<EncodedJSValue, FrozenValue*, EncodedJSValueHash, EncodedJSValueHashTraits> m_frozenValueMap;
806 Bag<FrozenValue> m_frozenValues;
807
808 Vector<uint32_t> m_uint32ValuesInUse;
809
810 Bag<StorageAccessData> m_storageAccessData;
811
812 // In CPS, this is all of the SetArgument nodes for the arguments in the machine code block
813 // that survived DCE. All of them except maybe "this" will survive DCE, because of the Flush
814 // nodes.
815 //
816 // In SSA, this is all of the GetStack nodes for the arguments in the machine code block that
817 // may have some speculation in the prologue and survived DCE. Note that to get the speculation
818 // for an argument in SSA, you must use m_argumentFormats, since we still have to speculate
819 // even if the argument got killed. For example:
820 //
821 // function foo(x) {
822 // var tmp = x + 1;
823 // }
824 //
825 // Assume that x is always int during profiling. The ArithAdd for "x + 1" will be dead and will
826 // have a proven check for the edge to "x". So, we will not insert a Check node and we will
827 // kill the GetStack for "x". But, we must do the int check in the progolue, because that's the
828 // thing we used to allow DCE of ArithAdd. Otherwise the add could be impure:
829 //
830 // var o = {
831 // valueOf: function() { do side effects; }
832 // };
833 // foo(o);
834 //
835 // If we DCE the ArithAdd and we remove the int check on x, then this won't do the side
836 // effects.
93a37866 837 Vector<Node*, 8> m_arguments;
ed1e77d3
A
838
839 // In CPS, this is meaningless. In SSA, this is the argument speculation that we've locked in.
840 Vector<FlushFormat> m_argumentFormats;
841
6fe7ccc8
A
842 SegmentedVector<VariableAccessData, 16> m_variableAccessData;
843 SegmentedVector<ArgumentPosition, 8> m_argumentPositions;
844 SegmentedVector<StructureSet, 16> m_structureSet;
ed1e77d3 845 Bag<Transition> m_transitions;
93a37866 846 SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData;
81345200
A
847 Bag<BranchData> m_branchData;
848 Bag<SwitchData> m_switchData;
849 Bag<MultiGetByOffsetData> m_multiGetByOffsetData;
850 Bag<MultiPutByOffsetData> m_multiPutByOffsetData;
ed1e77d3
A
851 Bag<ObjectMaterializationData> m_objectMaterializationData;
852 Bag<CallVarargsData> m_callVarargsData;
853 Bag<LoadVarargsData> m_loadVarargsData;
854 Bag<StackAccessData> m_stackAccessData;
81345200
A
855 Vector<InlineVariableData, 4> m_inlineVariableData;
856 HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness;
ed1e77d3 857 HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>> m_bytecodeKills;
93a37866 858 Dominators m_dominators;
ed1e77d3 859 PrePostNumbering m_prePostNumbering;
81345200 860 NaturalLoops m_naturalLoops;
6fe7ccc8 861 unsigned m_localVars;
81345200 862 unsigned m_nextMachineLocal;
6fe7ccc8 863 unsigned m_parameterSlots;
81345200
A
864
865#if USE(JSVALUE32_64)
866 std::unordered_map<int64_t, double*> m_doubleConstantsMap;
867 std::unique_ptr<Bag<double>> m_doubleConstants;
868#endif
93a37866
A
869
870 OptimizationFixpointState m_fixpointState;
ed1e77d3 871 StructureRegistrationState m_structureRegistrationState;
93a37866
A
872 GraphForm m_form;
873 UnificationState m_unificationState;
ed1e77d3 874 PlanStage m_planStage { PlanStage::Initial };
93a37866 875 RefCountState m_refCountState;
ed1e77d3 876 bool m_hasDebuggerEnabled;
14957cd0 877private:
6fe7ccc8 878
81345200 879 void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor);
93a37866 880
ed1e77d3 881 AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* operand, Node*immediate, RareCaseProfilingSource source)
6fe7ccc8 882 {
93a37866 883 ASSERT(immediate->hasConstant());
6fe7ccc8 884
ed1e77d3 885 JSValue immediateValue = immediate->asJSValue();
81345200
A
886 if (!immediateValue.isNumber() && !immediateValue.isBoolean())
887 return DontSpeculateInt32;
6fe7ccc8 888
81345200
A
889 if (!variableShouldSpeculateInt32)
890 return DontSpeculateInt32;
ed1e77d3
A
891
892 // Integer constants can be typed Double if they are written like a double in the source code (e.g. 42.0).
893 // In that case, we stay conservative unless the other operand was explicitly typed as integer.
894 NodeFlags operandResultType = operand->result();
895 if (operandResultType != NodeResultInt32 && immediateValue.isDouble())
896 return DontSpeculateInt32;
6fe7ccc8 897
ed1e77d3 898 if (immediateValue.isBoolean() || jsNumber(immediateValue.asNumber()).isInt32())
81345200 899 return add->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32;
6fe7ccc8
A
900
901 double doubleImmediate = immediateValue.asDouble();
902 const double twoToThe48 = 281474976710656.0;
903 if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48)
81345200 904 return DontSpeculateInt32;
93a37866 905
81345200 906 return bytecodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateInt32AndTruncateConstants : DontSpeculateInt32;
93a37866 907 }
6fe7ccc8
A
908};
909
14957cd0
A
910} } // namespace JSC::DFG
911
912#endif
913#endif