]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGGraph.h
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / dfg / DFGGraph.h
CommitLineData
14957cd0 1/*
81345200 2 * Copyright (C) 2011, 2012, 2013, 2014 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"
6fe7ccc8
A
32#include "CodeBlock.h"
33#include "DFGArgumentPosition.h"
6fe7ccc8 34#include "DFGBasicBlock.h"
93a37866
A
35#include "DFGDominators.h"
36#include "DFGLongLivedState.h"
81345200 37#include "DFGNaturalLoops.h"
6fe7ccc8 38#include "DFGNode.h"
93a37866 39#include "DFGNodeAllocator.h"
81345200
A
40#include "DFGPlan.h"
41#include "DFGScannable.h"
93a37866 42#include "JSStack.h"
6fe7ccc8 43#include "MethodOfGettingAValueProfile.h"
81345200 44#include <unordered_map>
6fe7ccc8
A
45#include <wtf/BitVector.h>
46#include <wtf/HashMap.h>
14957cd0
A
47#include <wtf/Vector.h>
48#include <wtf/StdLibExtras.h>
49
50namespace JSC {
51
52class CodeBlock;
6fe7ccc8 53class ExecState;
14957cd0
A
54
55namespace DFG {
56
6fe7ccc8 57struct StorageAccessData {
81345200 58 PropertyOffset offset;
93a37866 59 unsigned identifierNumber;
14957cd0
A
60};
61
81345200
A
62struct InlineVariableData {
63 InlineCallFrame* inlineCallFrame;
64 unsigned argumentPositionStart;
65 VariableAccessData* calleeVariable;
93a37866
A
66};
67
68enum AddSpeculationMode {
81345200
A
69 DontSpeculateInt32,
70 SpeculateInt32AndTruncateConstants,
71 SpeculateInt32
93a37866
A
72};
73
93a37866 74//
14957cd0
A
75// === Graph ===
76//
14957cd0
A
77// The order may be significant for nodes with side-effects (property accesses, value conversions).
78// Nodes that are 'dead' remain in the vector with refCount 0.
81345200 79class Graph : public virtual Scannable {
14957cd0 80public:
81345200 81 Graph(VM&, Plan&, LongLivedState&);
93a37866
A
82 ~Graph();
83
84 void changeChild(Edge& edge, Node* newNode)
14957cd0 85 {
93a37866 86 edge.setNode(newNode);
14957cd0 87 }
6fe7ccc8 88
93a37866 89 void changeEdge(Edge& edge, Edge newEdge)
14957cd0 90 {
93a37866 91 edge = newEdge;
14957cd0 92 }
93a37866
A
93
94 void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode)
6fe7ccc8 95 {
93a37866
A
96 if (edge.node() != oldNode)
97 return;
98 changeChild(edge, newNode);
6fe7ccc8
A
99 }
100
93a37866 101 void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge)
6fe7ccc8 102 {
93a37866
A
103 if (edge != oldEdge)
104 return;
105 changeEdge(edge, newEdge);
6fe7ccc8 106 }
93a37866 107
93a37866
A
108 void performSubstitution(Node* node)
109 {
110 if (node->flags() & NodeHasVarArgs) {
111 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
112 performSubstitutionForEdge(m_varArgChildren[childIdx]);
113 } else {
114 performSubstitutionForEdge(node->child1());
115 performSubstitutionForEdge(node->child2());
116 performSubstitutionForEdge(node->child3());
117 }
118 }
119
120 void performSubstitutionForEdge(Edge& child)
6fe7ccc8 121 {
93a37866
A
122 // Check if this operand is actually unused.
123 if (!child)
124 return;
125
126 // Check if there is any replacement.
81345200 127 Node* replacement = child->misc.replacement;
93a37866 128 if (!replacement)
6fe7ccc8 129 return;
93a37866
A
130
131 child.setNode(replacement);
132
133 // There is definitely a replacement. Assert that the replacement does not
134 // have a replacement.
81345200 135 ASSERT(!child->misc.replacement);
6fe7ccc8 136 }
93a37866 137
81345200
A
138 template<typename... Params>
139 Node* addNode(SpeculatedType type, Params... params)
140 {
141 Node* node = new (m_allocator) Node(params...);
142 node->predict(type);
143 return node;
93a37866 144 }
14957cd0 145
93a37866
A
146 void dethread();
147
148 void convertToConstant(Node* node, unsigned constantNumber)
14957cd0 149 {
93a37866
A
150 if (node->op() == GetLocal)
151 dethread();
152 else
81345200 153 ASSERT(!node->hasVariableAccessData(*this));
93a37866 154 node->convertToConstant(constantNumber);
14957cd0 155 }
93a37866 156
81345200
A
157 unsigned constantRegisterForConstant(JSValue value)
158 {
159 unsigned constantRegister;
160 if (!m_codeBlock->findConstant(value, constantRegister)) {
161 constantRegister = m_codeBlock->addConstantLazily();
162 initializeLazyWriteBarrierForConstant(
163 m_plan.writeBarriers,
164 m_codeBlock->constants()[constantRegister],
165 m_codeBlock,
166 constantRegister,
167 m_codeBlock->ownerExecutable(),
168 value);
169 }
170 return constantRegister;
171 }
172
93a37866 173 void convertToConstant(Node* node, JSValue value)
14957cd0 174 {
81345200
A
175 if (value.isObject())
176 node->convertToWeakConstant(value.asCell());
177 else
178 convertToConstant(node, constantRegisterForConstant(value));
14957cd0
A
179 }
180
6fe7ccc8 181 // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
81345200 182 void dump(PrintStream& = WTF::dataFile(), DumpContext* = 0);
93a37866 183 enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis };
81345200 184 void dumpBlockHeader(PrintStream&, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*);
93a37866 185 void dump(PrintStream&, Edge);
81345200 186 void dump(PrintStream&, const char* prefix, Node*, DumpContext* = 0);
93a37866
A
187 static int amountOfNodeWhiteSpace(Node*);
188 static void printNodeWhiteSpace(PrintStream&, Node*);
6fe7ccc8
A
189
190 // Dump the code origin of the given node as a diff from the code origin of the
93a37866 191 // preceding node. Returns true if anything was printed.
81345200 192 bool dumpCodeOrigin(PrintStream&, const char* prefix, Node* previousNode, Node* currentNode, DumpContext*);
6fe7ccc8 193
93a37866 194 SpeculatedType getJSConstantSpeculation(Node* node)
6fe7ccc8 195 {
93a37866 196 return speculationFromValue(node->valueOfJSConstant(m_codeBlock));
6fe7ccc8
A
197 }
198
81345200 199 AddSpeculationMode addSpeculationMode(Node* add, bool leftShouldSpeculateInt32, bool rightShouldSpeculateInt32, PredictionPass pass)
6fe7ccc8 200 {
93a37866 201 ASSERT(add->op() == ValueAdd || add->op() == ArithAdd || add->op() == ArithSub);
6fe7ccc8 202
81345200
A
203 RareCaseProfilingSource source = add->sourceFor(pass);
204
93a37866
A
205 Node* left = add->child1().node();
206 Node* right = add->child2().node();
6fe7ccc8 207
93a37866 208 if (left->hasConstant())
81345200 209 return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, left, source);
93a37866 210 if (right->hasConstant())
81345200 211 return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, right, source);
6fe7ccc8 212
81345200 213 return (leftShouldSpeculateInt32 && rightShouldSpeculateInt32 && add->canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32;
93a37866
A
214 }
215
81345200 216 AddSpeculationMode valueAddSpeculationMode(Node* add, PredictionPass pass)
93a37866 217 {
81345200
A
218 return addSpeculationMode(
219 add,
220 add->child1()->shouldSpeculateInt32OrBooleanExpectingDefined(),
221 add->child2()->shouldSpeculateInt32OrBooleanExpectingDefined(),
222 pass);
6fe7ccc8
A
223 }
224
81345200 225 AddSpeculationMode arithAddSpeculationMode(Node* add, PredictionPass pass)
6fe7ccc8 226 {
81345200
A
227 return addSpeculationMode(
228 add,
229 add->child1()->shouldSpeculateInt32OrBooleanForArithmetic(),
230 add->child2()->shouldSpeculateInt32OrBooleanForArithmetic(),
231 pass);
93a37866
A
232 }
233
81345200 234 AddSpeculationMode addSpeculationMode(Node* add, PredictionPass pass)
93a37866
A
235 {
236 if (add->op() == ValueAdd)
81345200 237 return valueAddSpeculationMode(add, pass);
93a37866 238
81345200 239 return arithAddSpeculationMode(add, pass);
6fe7ccc8
A
240 }
241
81345200 242 bool addShouldSpeculateInt32(Node* add, PredictionPass pass)
6fe7ccc8 243 {
81345200 244 return addSpeculationMode(add, pass) != DontSpeculateInt32;
93a37866
A
245 }
246
81345200
A
247 bool addShouldSpeculateMachineInt(Node* add)
248 {
249 if (!enableInt52())
250 return false;
251
252 Node* left = add->child1().node();
253 Node* right = add->child2().node();
254
255 bool speculation;
256 if (add->op() == ValueAdd)
257 speculation = Node::shouldSpeculateMachineInt(left, right);
258 else
259 speculation = Node::shouldSpeculateMachineInt(left, right);
260
261 return speculation && !hasExitSite(add, Int52Overflow);
262 }
263
264 bool mulShouldSpeculateInt32(Node* mul, PredictionPass pass)
93a37866
A
265 {
266 ASSERT(mul->op() == ArithMul);
267
268 Node* left = mul->child1().node();
269 Node* right = mul->child2().node();
270
81345200
A
271 return Node::shouldSpeculateInt32OrBooleanForArithmetic(left, right)
272 && mul->canSpeculateInt32(mul->sourceFor(pass));
273 }
274
275 bool mulShouldSpeculateMachineInt(Node* mul, PredictionPass pass)
276 {
277 ASSERT(mul->op() == ArithMul);
278
279 if (!enableInt52())
280 return false;
281
282 Node* left = mul->child1().node();
283 Node* right = mul->child2().node();
284
285 return Node::shouldSpeculateMachineInt(left, right)
286 && mul->canSpeculateInt52(pass)
287 && !hasExitSite(mul, Int52Overflow);
288 }
289
290 bool negateShouldSpeculateInt32(Node* negate, PredictionPass pass)
291 {
292 ASSERT(negate->op() == ArithNegate);
293 return negate->child1()->shouldSpeculateInt32OrBooleanForArithmetic()
294 && negate->canSpeculateInt32(pass);
93a37866
A
295 }
296
81345200 297 bool negateShouldSpeculateMachineInt(Node* negate, PredictionPass pass)
93a37866
A
298 {
299 ASSERT(negate->op() == ArithNegate);
81345200
A
300 if (!enableInt52())
301 return false;
302 return negate->child1()->shouldSpeculateMachineInt()
303 && !hasExitSite(negate, Int52Overflow)
304 && negate->canSpeculateInt52(pass);
305 }
306
307 VirtualRegister bytecodeRegisterForArgument(CodeOrigin codeOrigin, int argument)
308 {
309 return VirtualRegister(
310 codeOrigin.inlineCallFrame->stackOffset +
311 baselineCodeBlockFor(codeOrigin)->argumentIndexAfterCapture(argument));
6fe7ccc8
A
312 }
313
314 // Helper methods to check nodes for constants.
93a37866
A
315 bool isConstant(Node* node)
316 {
317 return node->hasConstant();
318 }
319 bool isJSConstant(Node* node)
6fe7ccc8 320 {
93a37866 321 return node->hasConstant();
6fe7ccc8 322 }
93a37866 323 bool isInt32Constant(Node* node)
6fe7ccc8 324 {
93a37866 325 return node->isInt32Constant(m_codeBlock);
6fe7ccc8 326 }
93a37866 327 bool isDoubleConstant(Node* node)
6fe7ccc8 328 {
93a37866 329 return node->isDoubleConstant(m_codeBlock);
6fe7ccc8 330 }
93a37866 331 bool isNumberConstant(Node* node)
6fe7ccc8 332 {
93a37866 333 return node->isNumberConstant(m_codeBlock);
6fe7ccc8 334 }
81345200
A
335 bool isMachineIntConstant(Node* node)
336 {
337 return node->isMachineIntConstant(m_codeBlock);
338 }
93a37866 339 bool isBooleanConstant(Node* node)
14957cd0 340 {
93a37866 341 return node->isBooleanConstant(m_codeBlock);
14957cd0 342 }
93a37866 343 bool isCellConstant(Node* node)
6fe7ccc8 344 {
93a37866
A
345 if (!isJSConstant(node))
346 return false;
347 JSValue value = valueOfJSConstant(node);
348 return value.isCell() && !!value;
349 }
350 bool isFunctionConstant(Node* node)
351 {
352 if (!isJSConstant(node))
353 return false;
354 if (!getJSFunction(valueOfJSConstant(node)))
355 return false;
356 return true;
6fe7ccc8 357 }
93a37866 358 bool isInternalFunctionConstant(Node* node)
6fe7ccc8 359 {
93a37866
A
360 if (!isJSConstant(node))
361 return false;
362 JSValue value = valueOfJSConstant(node);
363 if (!value.isCell() || !value)
6fe7ccc8 364 return false;
93a37866 365 JSCell* cell = value.asCell();
81345200 366 if (!cell->inherits(InternalFunction::info()))
6fe7ccc8
A
367 return false;
368 return true;
369 }
370 // Helper methods get constant values from nodes.
93a37866 371 JSValue valueOfJSConstant(Node* node)
6fe7ccc8 372 {
93a37866 373 return node->valueOfJSConstant(m_codeBlock);
6fe7ccc8 374 }
93a37866 375 int32_t valueOfInt32Constant(Node* node)
6fe7ccc8 376 {
81345200
A
377 JSValue value = valueOfJSConstant(node);
378 if (!value.isInt32()) {
379 dataLog("Value isn't int32: ", value, "\n");
380 dump();
381 RELEASE_ASSERT_NOT_REACHED();
382 }
383 return value.asInt32();
6fe7ccc8 384 }
93a37866 385 double valueOfNumberConstant(Node* node)
6fe7ccc8 386 {
93a37866 387 return valueOfJSConstant(node).asNumber();
6fe7ccc8 388 }
93a37866 389 bool valueOfBooleanConstant(Node* node)
6fe7ccc8 390 {
93a37866 391 return valueOfJSConstant(node).asBoolean();
6fe7ccc8 392 }
93a37866 393 JSFunction* valueOfFunctionConstant(Node* node)
6fe7ccc8 394 {
93a37866 395 JSCell* function = getJSFunction(valueOfJSConstant(node));
6fe7ccc8
A
396 ASSERT(function);
397 return jsCast<JSFunction*>(function);
398 }
399
400 static const char *opName(NodeType);
401
6fe7ccc8
A
402 StructureSet* addStructureSet(const StructureSet& structureSet)
403 {
404 ASSERT(structureSet.size());
405 m_structureSet.append(structureSet);
406 return &m_structureSet.last();
407 }
408
409 StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
410 {
411 m_structureTransitionData.append(structureTransitionData);
412 return &m_structureTransitionData.last();
413 }
414
93a37866
A
415 JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
416 {
417 return m_codeBlock->globalObjectFor(codeOrigin);
418 }
419
420 JSObject* globalThisObjectFor(CodeOrigin codeOrigin)
421 {
422 JSGlobalObject* object = globalObjectFor(codeOrigin);
81345200 423 return jsCast<JSObject*>(object->methodTable()->toThis(object, object->globalExec(), NotStrictMode));
93a37866
A
424 }
425
81345200 426 ScriptExecutable* executableFor(InlineCallFrame* inlineCallFrame)
93a37866
A
427 {
428 if (!inlineCallFrame)
429 return m_codeBlock->ownerExecutable();
430
431 return inlineCallFrame->executable.get();
432 }
433
81345200 434 ScriptExecutable* executableFor(const CodeOrigin& codeOrigin)
93a37866
A
435 {
436 return executableFor(codeOrigin.inlineCallFrame);
437 }
438
81345200
A
439 CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
440 {
441 if (!inlineCallFrame)
442 return m_profiledBlock;
443 return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
444 }
445
6fe7ccc8
A
446 CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
447 {
448 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
449 }
450
81345200
A
451 bool isStrictModeFor(CodeOrigin codeOrigin)
452 {
453 if (!codeOrigin.inlineCallFrame)
454 return m_codeBlock->isStrictMode();
455 return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->isStrictMode();
456 }
457
458 ECMAMode ecmaModeFor(CodeOrigin codeOrigin)
459 {
460 return isStrictModeFor(codeOrigin) ? StrictMode : NotStrictMode;
461 }
462
463 bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin)
464 {
465 return m_plan.watchpoints.isStillValid(
466 globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint());
467 }
468
93a37866
A
469 bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
470 {
471 return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind));
472 }
473
474 bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
475 {
476 return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind));
477 }
478
81345200 479 bool hasExitSite(Node* node, ExitKind exitKind)
93a37866 480 {
81345200
A
481 return hasExitSite(node->origin.semantic, exitKind);
482 }
483
484 VirtualRegister argumentsRegisterFor(InlineCallFrame* inlineCallFrame)
485 {
486 if (!inlineCallFrame)
487 return m_profiledBlock->argumentsRegister();
488
489 return VirtualRegister(baselineCodeBlockForInlineCallFrame(
490 inlineCallFrame)->argumentsRegister().offset() +
491 inlineCallFrame->stackOffset);
492 }
493
494 VirtualRegister argumentsRegisterFor(const CodeOrigin& codeOrigin)
495 {
496 return argumentsRegisterFor(codeOrigin.inlineCallFrame);
497 }
498
499 VirtualRegister machineArgumentsRegisterFor(InlineCallFrame* inlineCallFrame)
500 {
501 if (!inlineCallFrame)
93a37866
A
502 return m_codeBlock->argumentsRegister();
503
81345200 504 return inlineCallFrame->argumentsRegister;
93a37866
A
505 }
506
81345200 507 VirtualRegister machineArgumentsRegisterFor(const CodeOrigin& codeOrigin)
93a37866 508 {
81345200
A
509 return machineArgumentsRegisterFor(codeOrigin.inlineCallFrame);
510 }
511
512 VirtualRegister uncheckedArgumentsRegisterFor(InlineCallFrame* inlineCallFrame)
513 {
514 if (!inlineCallFrame)
515 return m_profiledBlock->uncheckedArgumentsRegister();
93a37866 516
81345200 517 CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
93a37866 518 if (!codeBlock->usesArguments())
81345200 519 return VirtualRegister();
93a37866 520
81345200
A
521 return VirtualRegister(codeBlock->argumentsRegister().offset() +
522 inlineCallFrame->stackOffset);
523 }
524
525 VirtualRegister uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin)
526 {
527 return uncheckedArgumentsRegisterFor(codeOrigin.inlineCallFrame);
528 }
529
530 VirtualRegister activationRegister()
531 {
532 return m_profiledBlock->activationRegister();
533 }
534
535 VirtualRegister uncheckedActivationRegister()
536 {
537 return m_profiledBlock->uncheckedActivationRegister();
538 }
539
540 VirtualRegister machineActivationRegister()
541 {
542 return m_profiledBlock->activationRegister();
93a37866
A
543 }
544
81345200 545 VirtualRegister uncheckedMachineActivationRegister()
93a37866 546 {
81345200 547 return m_profiledBlock->uncheckedActivationRegister();
93a37866
A
548 }
549
550 ValueProfile* valueProfileFor(Node* node)
6fe7ccc8 551 {
93a37866 552 if (!node)
6fe7ccc8
A
553 return 0;
554
81345200 555 CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic);
6fe7ccc8 556
81345200
A
557 if (node->op() == GetArgument)
558 return profiledBlock->valueProfileForArgument(node->local().toArgument());
559
560 if (node->hasLocal(*this)) {
561 if (m_form == SSA)
562 return 0;
563 if (!node->local().isArgument())
6fe7ccc8 564 return 0;
81345200 565 int argument = node->local().toArgument();
93a37866 566 if (node->variableAccessData() != m_arguments[argument]->variableAccessData())
6fe7ccc8
A
567 return 0;
568 return profiledBlock->valueProfileForArgument(argument);
569 }
570
93a37866 571 if (node->hasHeapPrediction())
81345200 572 return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex);
6fe7ccc8
A
573
574 return 0;
575 }
576
93a37866 577 MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* node)
14957cd0 578 {
93a37866 579 if (!node)
6fe7ccc8
A
580 return MethodOfGettingAValueProfile();
581
81345200 582 CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic);
6fe7ccc8 583
93a37866 584 if (node->op() == GetLocal) {
6fe7ccc8
A
585 return MethodOfGettingAValueProfile::fromLazyOperand(
586 profiledBlock,
587 LazyOperandValueProfileKey(
81345200 588 node->origin.semantic.bytecodeIndex, node->local()));
14957cd0 589 }
6fe7ccc8 590
93a37866 591 return MethodOfGettingAValueProfile(valueProfileFor(node));
6fe7ccc8
A
592 }
593
93a37866 594 bool usesArguments() const
6fe7ccc8 595 {
93a37866 596 return m_codeBlock->usesArguments();
6fe7ccc8 597 }
93a37866 598
81345200
A
599 BlockIndex numBlocks() const { return m_blocks.size(); }
600 BasicBlock* block(BlockIndex blockIndex) const { return m_blocks[blockIndex].get(); }
601 BasicBlock* lastBlock() const { return block(numBlocks() - 1); }
602
603 void appendBlock(PassRefPtr<BasicBlock> basicBlock)
6fe7ccc8 604 {
81345200
A
605 basicBlock->index = m_blocks.size();
606 m_blocks.append(basicBlock);
93a37866 607 }
81345200
A
608
609 void killBlock(BlockIndex blockIndex)
93a37866 610 {
81345200 611 m_blocks[blockIndex].clear();
93a37866 612 }
81345200
A
613
614 void killBlock(BasicBlock* basicBlock)
93a37866 615 {
81345200 616 killBlock(basicBlock->index);
93a37866
A
617 }
618
81345200
A
619 void killBlockAndItsContents(BasicBlock*);
620
621 void killUnreachableBlocks();
622
93a37866
A
623 bool isPredictedNumerical(Node* node)
624 {
625 return isNumerical(node->child1().useKind()) && isNumerical(node->child2().useKind());
626 }
627
628 // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing.
629 // It really means that it will not clobber the entire world. It's still up to you to
630 // carefully consider things like:
631 // - PutByVal definitely changes the array it stores to, and may even change its length.
632 // - PutByOffset definitely changes the object it stores to.
633 // - and so on.
634 bool byValIsPure(Node* node)
635 {
636 switch (node->arrayMode().type()) {
637 case Array::Generic:
638 return false;
639 case Array::Int32:
640 case Array::Double:
641 case Array::Contiguous:
642 case Array::ArrayStorage:
643 return !node->arrayMode().isOutOfBounds();
644 case Array::SlowPutArrayStorage:
645 return !node->arrayMode().mayStoreToHole();
646 case Array::String:
81345200 647 return node->op() == GetByVal && node->arrayMode().isInBounds();
93a37866
A
648#if USE(JSVALUE32_64)
649 case Array::Arguments:
650 if (node->op() == GetByVal)
651 return true;
652 return false;
653#endif // USE(JSVALUE32_64)
654 default:
655 return true;
656 }
657 }
658
659 bool clobbersWorld(Node* node)
660 {
661 if (node->flags() & NodeClobbersWorld)
662 return true;
663 if (!(node->flags() & NodeMightClobber))
664 return false;
665 switch (node->op()) {
93a37866 666 case GetByVal:
81345200 667 case PutByValDirect:
93a37866
A
668 case PutByVal:
669 case PutByValAlias:
670 return !byValIsPure(node);
671 case ToString:
672 switch (node->child1().useKind()) {
673 case StringObjectUse:
674 case StringOrStringObjectUse:
675 return false;
676 case CellUse:
677 case UntypedUse:
678 return true;
679 default:
680 RELEASE_ASSERT_NOT_REACHED();
681 return true;
682 }
683 default:
684 RELEASE_ASSERT_NOT_REACHED();
685 return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
686 }
687 }
688
689 void determineReachability();
690 void resetReachability();
691
692 void resetExitStates();
693
694 unsigned varArgNumChildren(Node* node)
695 {
696 ASSERT(node->flags() & NodeHasVarArgs);
697 return node->numChildren();
6fe7ccc8
A
698 }
699
93a37866 700 unsigned numChildren(Node* node)
6fe7ccc8 701 {
93a37866
A
702 if (node->flags() & NodeHasVarArgs)
703 return varArgNumChildren(node);
704 return AdjacencyList::Size;
6fe7ccc8 705 }
93a37866
A
706
707 Edge& varArgChild(Node* node, unsigned index)
6fe7ccc8 708 {
93a37866
A
709 ASSERT(node->flags() & NodeHasVarArgs);
710 return m_varArgChildren[node->firstChild() + index];
14957cd0 711 }
6fe7ccc8 712
93a37866
A
713 Edge& child(Node* node, unsigned index)
714 {
715 if (node->flags() & NodeHasVarArgs)
716 return varArgChild(node, index);
717 return node->children.child(index);
718 }
719
81345200 720 void voteNode(Node* node, unsigned ballot, float weight = 1)
93a37866
A
721 {
722 switch (node->op()) {
723 case ValueToInt32:
724 case UInt32ToNumber:
725 node = node->child1().node();
726 break;
727 default:
728 break;
729 }
730
731 if (node->op() == GetLocal)
81345200 732 node->variableAccessData()->vote(ballot, weight);
93a37866
A
733 }
734
81345200 735 void voteNode(Edge edge, unsigned ballot, float weight = 1)
93a37866 736 {
81345200 737 voteNode(edge.node(), ballot, weight);
93a37866
A
738 }
739
81345200 740 void voteChildren(Node* node, unsigned ballot, float weight = 1)
93a37866
A
741 {
742 if (node->flags() & NodeHasVarArgs) {
743 for (unsigned childIdx = node->firstChild();
744 childIdx < node->firstChild() + node->numChildren();
745 childIdx++) {
746 if (!!m_varArgChildren[childIdx])
81345200 747 voteNode(m_varArgChildren[childIdx], ballot, weight);
93a37866
A
748 }
749 return;
750 }
751
752 if (!node->child1())
753 return;
81345200 754 voteNode(node->child1(), ballot, weight);
93a37866
A
755 if (!node->child2())
756 return;
81345200 757 voteNode(node->child2(), ballot, weight);
93a37866
A
758 if (!node->child3())
759 return;
81345200 760 voteNode(node->child3(), ballot, weight);
93a37866
A
761 }
762
763 template<typename T> // T = Node* or Edge
764 void substitute(BasicBlock& block, unsigned startIndexInBlock, T oldThing, T newThing)
765 {
766 for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) {
767 Node* node = block[indexInBlock];
768 if (node->flags() & NodeHasVarArgs) {
769 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); ++childIdx) {
770 if (!!m_varArgChildren[childIdx])
771 compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing);
772 }
773 continue;
774 }
775 if (!node->child1())
776 continue;
777 compareAndSwap(node->children.child1(), oldThing, newThing);
778 if (!node->child2())
779 continue;
780 compareAndSwap(node->children.child2(), oldThing, newThing);
781 if (!node->child3())
782 continue;
783 compareAndSwap(node->children.child3(), oldThing, newThing);
784 }
785 }
786
787 // Use this if you introduce a new GetLocal and you know that you introduced it *before*
788 // any GetLocals in the basic block.
789 // FIXME: it may be appropriate, in the future, to generalize this to handle GetLocals
790 // introduced anywhere in the basic block.
81345200
A
791 void substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal);
792
793 void invalidateCFG();
794
795 void clearFlagsOnAllNodes(NodeFlags);
796
797 void clearReplacements();
798 void initializeNodeOwners();
799
800 void getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result);
801
802 Profiler::Compilation* compilation() { return m_plan.compilation.get(); }
803
804 DesiredIdentifiers& identifiers() { return m_plan.identifiers; }
805 DesiredWatchpoints& watchpoints() { return m_plan.watchpoints; }
806 DesiredStructureChains& chains() { return m_plan.chains; }
807
808 FullBytecodeLiveness& livenessFor(CodeBlock*);
809 FullBytecodeLiveness& livenessFor(InlineCallFrame*);
810 bool isLiveInBytecode(VirtualRegister, CodeOrigin);
811
812 unsigned frameRegisterCount();
813 unsigned stackPointerOffset();
814 unsigned requiredRegisterCountForExit();
815 unsigned requiredRegisterCountForExecutionAndExit();
816
817 JSActivation* tryGetActivation(Node*);
818 WriteBarrierBase<Unknown>* tryGetRegisters(Node*);
819
820 JSArrayBufferView* tryGetFoldableView(Node*);
821 JSArrayBufferView* tryGetFoldableView(Node*, ArrayMode);
822 JSArrayBufferView* tryGetFoldableViewForChild1(Node*);
823
824 virtual void visitChildren(SlotVisitor&) override;
93a37866
A
825
826 VM& m_vm;
81345200 827 Plan& m_plan;
6fe7ccc8
A
828 CodeBlock* m_codeBlock;
829 CodeBlock* m_profiledBlock;
93a37866
A
830
831 NodeAllocator& m_allocator;
14957cd0 832
81345200
A
833 Operands<AbstractValue> m_mustHandleAbstractValues;
834
835 Vector< RefPtr<BasicBlock> , 8> m_blocks;
6fe7ccc8
A
836 Vector<Edge, 16> m_varArgChildren;
837 Vector<StorageAccessData> m_storageAccessData;
93a37866 838 Vector<Node*, 8> m_arguments;
6fe7ccc8
A
839 SegmentedVector<VariableAccessData, 16> m_variableAccessData;
840 SegmentedVector<ArgumentPosition, 8> m_argumentPositions;
841 SegmentedVector<StructureSet, 16> m_structureSet;
842 SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
93a37866 843 SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData;
81345200
A
844 Bag<BranchData> m_branchData;
845 Bag<SwitchData> m_switchData;
846 Bag<MultiGetByOffsetData> m_multiGetByOffsetData;
847 Bag<MultiPutByOffsetData> m_multiPutByOffsetData;
848 Vector<InlineVariableData, 4> m_inlineVariableData;
849 HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness;
93a37866
A
850 bool m_hasArguments;
851 HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped;
81345200 852 BitVector m_lazyVars;
93a37866 853 Dominators m_dominators;
81345200 854 NaturalLoops m_naturalLoops;
6fe7ccc8 855 unsigned m_localVars;
81345200 856 unsigned m_nextMachineLocal;
6fe7ccc8 857 unsigned m_parameterSlots;
81345200
A
858 int m_machineCaptureStart;
859 std::unique_ptr<SlowArgument[]> m_slowArguments;
860
861#if USE(JSVALUE32_64)
862 std::unordered_map<int64_t, double*> m_doubleConstantsMap;
863 std::unique_ptr<Bag<double>> m_doubleConstants;
864#endif
93a37866
A
865
866 OptimizationFixpointState m_fixpointState;
867 GraphForm m_form;
868 UnificationState m_unificationState;
869 RefCountState m_refCountState;
14957cd0 870private:
6fe7ccc8 871
81345200
A
872 void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor);
873 void addForDepthFirstSort(Vector<BasicBlock*>& result, Vector<BasicBlock*, 16>& worklist, HashSet<BasicBlock*>& seen, BasicBlock*);
93a37866 874
81345200 875 AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate, RareCaseProfilingSource source)
6fe7ccc8 876 {
93a37866 877 ASSERT(immediate->hasConstant());
6fe7ccc8 878
93a37866 879 JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock);
81345200
A
880 if (!immediateValue.isNumber() && !immediateValue.isBoolean())
881 return DontSpeculateInt32;
6fe7ccc8 882
81345200
A
883 if (!variableShouldSpeculateInt32)
884 return DontSpeculateInt32;
6fe7ccc8 885
81345200
A
886 if (immediateValue.isInt32() || immediateValue.isBoolean())
887 return add->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32;
6fe7ccc8
A
888
889 double doubleImmediate = immediateValue.asDouble();
890 const double twoToThe48 = 281474976710656.0;
891 if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48)
81345200 892 return DontSpeculateInt32;
93a37866 893
81345200 894 return bytecodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateInt32AndTruncateConstants : DontSpeculateInt32;
93a37866 895 }
6fe7ccc8
A
896};
897
93a37866
A
898#define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \
899 Node* _node = (node); \
900 if (_node->flags() & NodeHasVarArgs) { \
901 for (unsigned _childIdx = _node->firstChild(); \
902 _childIdx < _node->firstChild() + _node->numChildren(); \
903 _childIdx++) { \
904 if (!!(graph).m_varArgChildren[_childIdx]) \
905 thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \
906 } \
907 } else { \
908 if (!_node->child1()) { \
909 ASSERT( \
910 !_node->child2() \
911 && !_node->child3()); \
912 break; \
913 } \
914 thingToDo(_node, _node->child1()); \
915 \
916 if (!_node->child2()) { \
917 ASSERT(!_node->child3()); \
918 break; \
919 } \
920 thingToDo(_node, _node->child2()); \
921 \
922 if (!_node->child3()) \
923 break; \
924 thingToDo(_node, _node->child3()); \
925 } \
926 } while (false)
927
14957cd0
A
928} } // namespace JSC::DFG
929
930#endif
931#endif