summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGFixupPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGFixupPhase.cpp1432
1 files changed, 500 insertions, 932 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 2b7d064b2..185f03591 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,14 +28,12 @@
#if ENABLE(DFG_JIT)
-#include "ArrayPrototype.h"
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGPhase.h"
#include "DFGPredictionPropagationPhase.h"
#include "DFGVariableAccessDataDump.h"
-#include "JSCInlines.h"
-#include "TypeLocation.h"
+#include "Operations.h"
namespace JSC { namespace DFG {
@@ -63,14 +61,12 @@ public:
m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
- fixupGetAndSetLocalsInBlock(m_graph.block(blockIndex));
+ fixupSetLocalsInBlock(m_graph.block(blockIndex));
}
for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
- injectTypeConversionsInBlock(m_graph.block(blockIndex));
-
- m_graph.m_planStage = PlanStage::AfterFixup;
-
+ fixupUntypedSetLocalsInBlock(m_graph.block(blockIndex));
+
return true;
}
@@ -94,7 +90,7 @@ private:
switch (op) {
case SetLocal: {
- // This gets handled by fixupGetAndSetLocalsInBlock().
+ // This gets handled by fixupSetLocalsInBlock().
return;
}
@@ -104,50 +100,41 @@ private:
case BitRShift:
case BitLShift:
case BitURShift: {
- fixIntConvertingEdge(node->child1());
- fixIntConvertingEdge(node->child2());
+ fixBinaryIntEdges();
break;
}
case ArithIMul: {
- fixIntConvertingEdge(node->child1());
- fixIntConvertingEdge(node->child2());
+ fixBinaryIntEdges();
node->setOp(ArithMul);
node->setArithMode(Arith::Unchecked);
node->child1().setUseKind(Int32Use);
node->child2().setUseKind(Int32Use);
break;
}
-
- case ArithClz32: {
- fixIntConvertingEdge(node->child1());
- node->setArithMode(Arith::Unchecked);
- break;
- }
case UInt32ToNumber: {
- fixIntConvertingEdge(node->child1());
+ fixIntEdge(node->child1());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->convertToIdentity();
- else if (node->canSpeculateInt32(FixupPass))
+ else if (nodeCanSpeculateInt32(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
- else {
+ else
node->setArithMode(Arith::DoOverflow);
- node->setResult(NodeResultDouble);
- }
break;
}
case ValueAdd: {
if (attemptToMakeIntegerAdd(node)) {
node->setOp(ArithAdd);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
- if (Node::shouldSpeculateNumberOrBooleanExpectingDefined(node->child1().node(), node->child2().node())) {
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
+ if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
node->setOp(ArithAdd);
- node->setResult(NodeResultDouble);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
@@ -186,15 +173,14 @@ private:
case ArithSub: {
if (attemptToMakeIntegerAdd(node))
break;
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
- node->setResult(NodeResultDouble);
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
break;
}
case ArithNegate: {
- if (m_graph.negateShouldSpeculateInt32(node, FixupPass)) {
- fixIntOrBooleanEdge(node->child1());
+ if (m_graph.negateShouldSpeculateInt32(node)) {
+ fixEdge<Int32Use>(node->child1());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -203,24 +189,22 @@ private:
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
break;
}
- if (m_graph.negateShouldSpeculateMachineInt(node, FixupPass)) {
- fixEdge<Int52RepUse>(node->child1());
+ if (m_graph.negateShouldSpeculateMachineInt(node)) {
+ fixEdge<MachineIntUse>(node->child1());
if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
else
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
- node->setResult(NodeResultInt52);
break;
}
- fixDoubleOrBooleanEdge(node->child1());
- node->setResult(NodeResultDouble);
+ fixEdge<NumberUse>(node->child1());
break;
}
case ArithMul: {
- if (m_graph.mulShouldSpeculateInt32(node, FixupPass)) {
- fixIntOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
+ if (m_graph.mulShouldSpeculateInt32(node)) {
+ fixEdge<Int32Use>(node->child1());
+ fixEdge<Int32Use>(node->child2());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -229,29 +213,27 @@ private:
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
break;
}
- if (m_graph.mulShouldSpeculateMachineInt(node, FixupPass)) {
- fixEdge<Int52RepUse>(node->child1());
- fixEdge<Int52RepUse>(node->child2());
+ if (m_graph.mulShouldSpeculateMachineInt(node)) {
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
else
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
- node->setResult(NodeResultInt52);
break;
}
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
- node->setResult(NodeResultDouble);
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
break;
}
case ArithDiv:
case ArithMod: {
- if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInt32(FixupPass)) {
- if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) {
- fixIntOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
+ if (Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32()) {
+ if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7s()) {
+ fixEdge<Int32Use>(node->child1());
+ fixEdge<Int32Use>(node->child2());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -260,125 +242,84 @@ private:
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
break;
}
+ Edge child1 = node->child1();
+ Edge child2 = node->child2();
- // This will cause conversion nodes to be inserted later.
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
-
+ injectInt32ToDoubleNode(node->child1());
+ injectInt32ToDoubleNode(node->child2());
+
// We don't need to do ref'ing on the children because we're stealing them from
// the original division.
Node* newDivision = m_insertionSet.insertNode(
- m_indexInBlock, SpecBytecodeDouble, *node);
- newDivision->setResult(NodeResultDouble);
+ m_indexInBlock, SpecDouble, *node);
node->setOp(DoubleAsInt32);
- node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge());
+ node->children.initialize(Edge(newDivision, KnownNumberUse), Edge(), Edge());
if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
else
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+
+ m_insertionSet.insertNode(m_indexInBlock + 1, SpecNone, Phantom, node->codeOrigin, child1, child2);
break;
}
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
- node->setResult(NodeResultDouble);
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
break;
}
case ArithMin:
case ArithMax: {
- if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInt32(FixupPass)) {
- fixIntOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
+ if (Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32()) {
+ fixEdge<Int32Use>(node->child1());
+ fixEdge<Int32Use>(node->child2());
break;
}
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
- node->setResult(NodeResultDouble);
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
break;
}
case ArithAbs: {
- if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic()
- && node->canSpeculateInt32(FixupPass)) {
- fixIntOrBooleanEdge(node->child1());
- break;
- }
- fixDoubleOrBooleanEdge(node->child1());
- node->setResult(NodeResultDouble);
- break;
- }
-
- case ArithPow: {
- node->setResult(NodeResultDouble);
- if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) {
- fixDoubleOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
- break;
- }
-
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
- break;
- }
-
- case ArithRound: {
- if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(FixupPass)) {
- fixIntOrBooleanEdge(node->child1());
- insertCheck<Int32Use>(m_indexInBlock, node->child1().node());
- node->convertToIdentity();
+ if (node->child1()->shouldSpeculateInt32ForArithmetic()
+ && node->canSpeculateInt32()) {
+ fixEdge<Int32Use>(node->child1());
break;
}
- fixDoubleOrBooleanEdge(node->child1());
-
- if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
- node->setResult(NodeResultInt32);
- if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
- node->setArithRoundingMode(Arith::RoundingMode::Int32);
- else
- node->setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck);
- } else {
- node->setResult(NodeResultDouble);
- node->setArithRoundingMode(Arith::RoundingMode::Double);
- }
+ fixEdge<NumberUse>(node->child1());
break;
}
case ArithSqrt:
- case ArithFRound:
case ArithSin:
- case ArithCos:
- case ArithLog: {
- fixDoubleOrBooleanEdge(node->child1());
- node->setResult(NodeResultDouble);
+ case ArithCos: {
+ fixEdge<NumberUse>(node->child1());
break;
}
case LogicalNot: {
- if (node->child1()->shouldSpeculateBoolean()) {
- if (node->child1()->result() == NodeResultBoolean) {
- // This is necessary in case we have a bytecode instruction implemented by:
- //
- // a: CompareEq(...)
- // b: LogicalNot(@a)
- //
- // In that case, CompareEq might have a side-effect. Then, we need to make
- // sure that we know that Branch does not exit.
- fixEdge<KnownBooleanUse>(node->child1());
- } else
- fixEdge<BooleanUse>(node->child1());
- } else if (node->child1()->shouldSpeculateObjectOrOther())
+ if (node->child1()->shouldSpeculateBoolean())
+ fixEdge<BooleanUse>(node->child1());
+ else if (node->child1()->shouldSpeculateObjectOrOther())
fixEdge<ObjectOrOtherUse>(node->child1());
- else if (node->child1()->shouldSpeculateInt32OrBoolean())
- fixIntOrBooleanEdge(node->child1());
+ else if (node->child1()->shouldSpeculateInt32())
+ fixEdge<Int32Use>(node->child1());
else if (node->child1()->shouldSpeculateNumber())
- fixEdge<DoubleRepUse>(node->child1());
+ fixEdge<NumberUse>(node->child1());
else if (node->child1()->shouldSpeculateString())
fixEdge<StringUse>(node->child1());
break;
}
+ case TypeOf: {
+ if (node->child1()->shouldSpeculateString())
+ fixEdge<StringUse>(node->child1());
+ else if (node->child1()->shouldSpeculateCell())
+ fixEdge<CellUse>(node->child1());
+ break;
+ }
+
case CompareEqConstant: {
break;
}
@@ -388,67 +329,70 @@ private:
case CompareLessEq:
case CompareGreater:
case CompareGreaterEq: {
- if (node->op() == CompareEq
- && Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
- fixEdge<BooleanUse>(node->child1());
- fixEdge<BooleanUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
- break;
- }
- if (Node::shouldSpeculateInt32OrBoolean(node->child1().node(), node->child2().node())) {
- fixIntOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
- node->clearFlags(NodeMustGenerate);
+ if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
+ fixEdge<Int32Use>(node->child1());
+ fixEdge<Int32Use>(node->child2());
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (enableInt52()
&& Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
- fixEdge<Int52RepUse>(node->child1());
- fixEdge<Int52RepUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
- if (Node::shouldSpeculateNumberOrBoolean(node->child1().node(), node->child2().node())) {
- fixDoubleOrBooleanEdge(node->child1());
- fixDoubleOrBooleanEdge(node->child2());
- node->clearFlags(NodeMustGenerate);
+ if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (node->op() != CompareEq)
break;
+ if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
+ fixEdge<BooleanUse>(node->child1());
+ fixEdge<BooleanUse>(node->child2());
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
+ break;
+ }
if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
fixEdge<StringIdentUse>(node->child1());
fixEdge<StringIdentUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
fixEdge<StringUse>(node->child1());
fixEdge<StringUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
fixEdge<ObjectUse>(node->child1());
fixEdge<ObjectUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
fixEdge<ObjectUse>(node->child1());
fixEdge<ObjectOrOtherUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
fixEdge<ObjectOrOtherUse>(node->child1());
fixEdge<ObjectUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
break;
}
+ case CompareStrictEqConstant: {
+ break;
+ }
+
case CompareStrictEq: {
if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
fixEdge<BooleanUse>(node->child1());
@@ -462,13 +406,13 @@ private:
}
if (enableInt52()
&& Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
- fixEdge<Int52RepUse>(node->child1());
- fixEdge<Int52RepUse>(node->child2());
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
break;
}
if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ fixEdge<NumberUse>(node->child1());
+ fixEdge<NumberUse>(node->child2());
break;
}
if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
@@ -476,58 +420,16 @@ private:
fixEdge<StringIdentUse>(node->child2());
break;
}
- if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) {
+ if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
fixEdge<StringUse>(node->child1());
fixEdge<StringUse>(node->child2());
break;
}
- WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint();
- if (masqueradesAsUndefinedWatchpoint->isStillValid()) {
-
- if (node->child1()->shouldSpeculateObject()) {
- m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
- fixEdge<ObjectUse>(node->child1());
- break;
- }
- if (node->child2()->shouldSpeculateObject()) {
- m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
- fixEdge<ObjectUse>(node->child2());
- break;
- }
-
- } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+ if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
fixEdge<ObjectUse>(node->child1());
fixEdge<ObjectUse>(node->child2());
break;
}
- if (node->child1()->shouldSpeculateMisc()) {
- fixEdge<MiscUse>(node->child1());
- break;
- }
- if (node->child2()->shouldSpeculateMisc()) {
- fixEdge<MiscUse>(node->child2());
- break;
- }
- if (node->child1()->shouldSpeculateStringIdent()
- && node->child2()->shouldSpeculateNotStringVar()) {
- fixEdge<StringIdentUse>(node->child1());
- fixEdge<NotStringVarUse>(node->child2());
- break;
- }
- if (node->child2()->shouldSpeculateStringIdent()
- && node->child1()->shouldSpeculateNotStringVar()) {
- fixEdge<StringIdentUse>(node->child2());
- fixEdge<NotStringVarUse>(node->child1());
- break;
- }
- if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
- fixEdge<StringUse>(node->child1());
- break;
- }
- if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
- fixEdge<StringUse>(node->child2());
- break;
- }
break;
}
@@ -546,84 +448,27 @@ private:
}
case GetByVal: {
- if (!node->prediction()) {
- m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
- }
-
node->setArrayMode(
node->arrayMode().refine(
- m_graph, node,
node->child1()->prediction(),
node->child2()->prediction(),
- SpecNone));
+ SpecNone, node->flags()));
blessArrayOperation(node->child1(), node->child2(), node->child3());
ArrayMode arrayMode = node->arrayMode();
switch (arrayMode.type()) {
- case Array::Contiguous:
case Array::Double:
if (arrayMode.arrayClass() == Array::OriginalArray
- && arrayMode.speculation() == Array::InBounds) {
- JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
- if (globalObject->arrayPrototypeChainIsSane()) {
- // Check if SaneChain will work on a per-type basis. Note that:
- //
- // 1) We don't want double arrays to sometimes return undefined, since
- // that would require a change to the return type and it would pessimise
- // things a lot. So, we'd only want to do that if we actually had
- // evidence that we could read from a hole. That's pretty annoying.
- // Likely the best way to handle that case is with an equivalent of
- // SaneChain for OutOfBounds. For now we just detect when Undefined and
- // NaN are indistinguishable according to backwards propagation, and just
- // use SaneChain in that case. This happens to catch a lot of cases.
- //
- // 2) We don't want int32 array loads to have to do a hole check just to
- // coerce to Undefined, since that would mean twice the checks.
- //
- // This has two implications. First, we have to do more checks than we'd
- // like. It's unfortunate that we have to do the hole check. Second,
- // some accesses that hit a hole will now need to take the full-blown
- // out-of-bounds slow path. We can fix that with:
- // https://bugs.webkit.org/show_bug.cgi?id=144668
-
- bool canDoSaneChain = false;
- switch (arrayMode.type()) {
- case Array::Contiguous:
- // This is happens to be entirely natural. We already would have
- // returned any JSValue, and now we'll return Undefined. We still do
- // the check but it doesn't require taking any kind of slow path.
- canDoSaneChain = true;
- break;
-
- case Array::Double:
- if (!(node->flags() & NodeBytecodeUsesAsOther)) {
- // Holes look like NaN already, so if the user doesn't care
- // about the difference between Undefined and NaN then we can
- // do this.
- canDoSaneChain = true;
- }
- break;
-
- default:
- break;
- }
-
- if (canDoSaneChain) {
- m_graph.watchpoints().addLazily(
- globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
- m_graph.watchpoints().addLazily(
- globalObject->objectPrototype()->structure()->transitionWatchpointSet());
- node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
- }
- }
- }
+ && arrayMode.speculation() == Array::InBounds
+ && m_graph.globalObjectFor(node->codeOrigin)->arrayPrototypeChainIsSane()
+ && !(node->flags() & NodeBytecodeUsesAsOther))
+ node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
break;
case Array::String:
if ((node->prediction() & ~SpecString)
- || m_graph.hasExitSite(node->origin.semantic, OutOfBounds))
+ || m_graph.hasExitSite(node->codeOrigin, OutOfBounds))
node->setArrayMode(arrayMode.withSpeculation(Array::OutOfBounds));
break;
@@ -631,10 +476,10 @@ private:
break;
}
- arrayMode = node->arrayMode();
- switch (arrayMode.type()) {
+ switch (node->arrayMode().type()) {
case Array::SelectUsingPredictions:
case Array::Unprofiled:
+ case Array::Undecided:
RELEASE_ASSERT_NOT_REACHED();
break;
case Array::Generic:
@@ -650,30 +495,6 @@ private:
break;
}
- switch (arrayMode.type()) {
- case Array::Double:
- if (!arrayMode.isOutOfBounds())
- node->setResult(NodeResultDouble);
- break;
-
- case Array::Float32Array:
- case Array::Float64Array:
- node->setResult(NodeResultDouble);
- break;
-
- case Array::Uint32Array:
- if (node->shouldSpeculateInt32())
- break;
- if (node->shouldSpeculateMachineInt() && enableInt52())
- node->setResult(NodeResultInt52);
- else
- node->setResult(NodeResultDouble);
- break;
-
- default:
- break;
- }
-
break;
}
@@ -686,7 +507,6 @@ private:
node->setArrayMode(
node->arrayMode().refine(
- m_graph, node,
child1->prediction(),
child2->prediction(),
child3->prediction()));
@@ -695,7 +515,6 @@ private:
switch (node->arrayMode().modeForPut().type()) {
case Array::SelectUsingPredictions:
- case Array::SelectUsingArguments:
case Array::Unprofiled:
case Array::Undecided:
RELEASE_ASSERT_NOT_REACHED();
@@ -713,11 +532,15 @@ private:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
fixEdge<Int32Use>(child3);
+ if (child3->prediction() & SpecInt52)
+ fixEdge<MachineIntUse>(child3);
+ else
+ fixEdge<Int32Use>(child3);
break;
case Array::Double:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
- fixEdge<DoubleRepRealUse>(child3);
+ fixEdge<RealNumberUse>(child3);
break;
case Array::Int8Array:
case Array::Int16Array:
@@ -729,24 +552,25 @@ private:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
if (child3->shouldSpeculateInt32())
- fixIntOrBooleanEdge(child3);
+ fixEdge<Int32Use>(child3);
else if (child3->shouldSpeculateMachineInt())
- fixEdge<Int52RepUse>(child3);
+ fixEdge<MachineIntUse>(child3);
else
- fixDoubleOrBooleanEdge(child3);
+ fixEdge<NumberUse>(child3);
break;
case Array::Float32Array:
case Array::Float64Array:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
- fixDoubleOrBooleanEdge(child3);
+ fixEdge<NumberUse>(child3);
break;
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
+ case Array::Arguments:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
- speculateForBarrier(child3);
+ insertStoreBarrier(m_indexInBlock, child1, child3);
break;
default:
fixEdge<KnownCellUse>(child1);
@@ -768,7 +592,6 @@ private:
// that would break things.
node->setArrayMode(
node->arrayMode().refine(
- m_graph, node,
node->child1()->prediction() & SpecCell,
SpecInt32,
node->child2()->prediction()));
@@ -780,11 +603,11 @@ private:
fixEdge<Int32Use>(node->child2());
break;
case Array::Double:
- fixEdge<DoubleRepRealUse>(node->child2());
+ fixEdge<RealNumberUse>(node->child2());
break;
case Array::Contiguous:
case Array::ArrayStorage:
- speculateForBarrier(node->child2());
+ insertStoreBarrier(m_indexInBlock, node->child1(), node->child2());
break;
default:
break;
@@ -806,26 +629,48 @@ private:
}
case Branch: {
- if (node->child1()->shouldSpeculateBoolean()) {
- if (node->child1()->result() == NodeResultBoolean) {
- // This is necessary in case we have a bytecode instruction implemented by:
- //
- // a: CompareEq(...)
- // b: Branch(@a)
- //
- // In that case, CompareEq might have a side-effect. Then, we need to make
- // sure that we know that Branch does not exit.
- fixEdge<KnownBooleanUse>(node->child1());
- } else
- fixEdge<BooleanUse>(node->child1());
- } else if (node->child1()->shouldSpeculateObjectOrOther())
+ if (node->child1()->shouldSpeculateBoolean())
+ fixEdge<BooleanUse>(node->child1());
+ else if (node->child1()->shouldSpeculateObjectOrOther())
fixEdge<ObjectOrOtherUse>(node->child1());
- else if (node->child1()->shouldSpeculateInt32OrBoolean())
- fixIntOrBooleanEdge(node->child1());
+ else if (node->child1()->shouldSpeculateInt32())
+ fixEdge<Int32Use>(node->child1());
else if (node->child1()->shouldSpeculateNumber())
- fixEdge<DoubleRepUse>(node->child1());
- else if (node->child1()->shouldSpeculateString())
- fixEdge<StringUse>(node->child1());
+ fixEdge<NumberUse>(node->child1());
+
+ Node* logicalNot = node->child1().node();
+ if (logicalNot->op() == LogicalNot) {
+
+ // Make sure that OSR exit can't observe the LogicalNot. If it can,
+ // then we must compute it and cannot peephole around it.
+ bool found = false;
+ bool ok = true;
+ for (unsigned i = m_indexInBlock; i--;) {
+ Node* candidate = m_block->at(i);
+ if (candidate == logicalNot) {
+ found = true;
+ break;
+ }
+ if (candidate->canExit()) {
+ ok = false;
+ found = true;
+ break;
+ }
+ }
+ ASSERT_UNUSED(found, found);
+
+ if (ok) {
+ Edge newChildEdge = logicalNot->child1();
+ if (newChildEdge->hasBooleanResult()) {
+ node->children.setChild1(newChildEdge);
+
+ BasicBlock* toBeTaken = node->notTakenBlock();
+ BasicBlock* toBeNotTaken = node->takenBlock();
+ node->setTakenBlock(toBeTaken);
+ node->setNotTakenBlock(toBeNotTaken);
+ }
+ }
+ }
break;
}
@@ -846,12 +691,6 @@ private:
else if (node->child1()->shouldSpeculateString())
fixEdge<StringUse>(node->child1());
break;
- case SwitchCell:
- if (node->child1()->shouldSpeculateCell())
- fixEdge<CellUse>(node->child1());
- // else it's fine for this to have UntypedUse; we will handle this by just making
- // non-cells take the default case.
- break;
}
break;
}
@@ -861,9 +700,8 @@ private:
break;
}
- case ToString:
- case CallStringConstructor: {
- fixupToStringOrCallStringConstructor(node);
+ case ToString: {
+ fixupToString(node);
break;
}
@@ -888,7 +726,7 @@ private:
// would have already exited by now, but insert a forced exit just to
// be safe.
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
+ m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
}
break;
case ALL_INT32_INDEXING_TYPES:
@@ -897,7 +735,7 @@ private:
break;
case ALL_DOUBLE_INDEXING_TYPES:
for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
- fixEdge<DoubleRepRealUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
+ fixEdge<RealNumberUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
break;
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -912,7 +750,7 @@ private:
case NewTypedArray: {
if (node->child1()->shouldSpeculateInt32()) {
fixEdge<Int32Use>(node->child1());
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
break;
@@ -924,9 +762,9 @@ private:
}
case ToThis: {
- ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->isStrictMode() ? StrictMode : NotStrictMode;
+ ECMAMode ecmaMode = m_graph.executableFor(node->codeOrigin)->isStrictMode() ? StrictMode : NotStrictMode;
- if (node->child1()->shouldSpeculateOther()) {
+ if (isOtherSpeculation(node->child1()->prediction())) {
if (ecmaMode == StrictMode) {
fixEdge<OtherUse>(node->child1());
node->convertToIdentity();
@@ -934,11 +772,10 @@ private:
}
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, Check, node->origin,
+ m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
Edge(node->child1().node(), OtherUse));
observeUseKindOnNode<OtherUse>(node->child1().node());
- m_graph.convertToConstant(
- node, m_graph.globalThisObjectFor(node->origin.semantic));
+ node->convertToWeakConstant(m_graph.globalThisObjectFor(node->codeOrigin));
break;
}
@@ -951,28 +788,28 @@ private:
break;
}
- case PutStructure: {
- fixEdge<KnownCellUse>(node->child1());
+ case GetMyArgumentByVal:
+ case GetMyArgumentByValSafe: {
+ fixEdge<Int32Use>(node->child1());
break;
}
- case GetClosureVar:
- case GetFromArguments: {
+ case PutStructure: {
fixEdge<KnownCellUse>(node->child1());
+ insertStoreBarrier(m_indexInBlock, node->child1());
break;
}
- case PutClosureVar:
- case PutToArguments: {
+ case PutClosureVar: {
fixEdge<KnownCellUse>(node->child1());
- speculateForBarrier(node->child2());
+ insertStoreBarrier(m_indexInBlock, node->child1(), node->child3());
break;
}
-
+
+ case GetClosureRegisters:
+ case SkipTopScope:
case SkipScope:
- case GetScope:
- case GetGetter:
- case GetSetter: {
+ case GetScope: {
fixEdge<KnownCellUse>(node->child1());
break;
}
@@ -980,6 +817,7 @@ private:
case AllocatePropertyStorage:
case ReallocatePropertyStorage: {
fixEdge<KnownCellUse>(node->child1());
+ insertStoreBarrier(m_indexInBlock + 1, node->child1());
break;
}
@@ -987,60 +825,40 @@ private:
case GetByIdFlush: {
if (!node->child1()->shouldSpeculateCell())
break;
-
- // If we hadn't exited because of BadCache, BadIndexingType, or ExoticObjectMode, then
- // leave this as a GetById.
- if (!m_graph.hasExitSite(node->origin.semantic, BadCache)
- && !m_graph.hasExitSite(node->origin.semantic, BadIndexingType)
- && !m_graph.hasExitSite(node->origin.semantic, ExoticObjectMode)) {
- auto uid = m_graph.identifiers()[node->identifierNumber()];
- if (uid == vm().propertyNames->length.impl()) {
- attemptToMakeGetArrayLength(node);
- break;
- }
- if (uid == vm().propertyNames->byteLength.impl()) {
- attemptToMakeGetTypedArrayByteLength(node);
- break;
- }
- if (uid == vm().propertyNames->byteOffset.impl()) {
- attemptToMakeGetTypedArrayByteOffset(node);
- break;
- }
+ StringImpl* impl = m_graph.identifiers()[node->identifierNumber()];
+ if (impl == vm().propertyNames->length.impl()) {
+ attemptToMakeGetArrayLength(node);
+ break;
+ }
+ if (impl == vm().propertyNames->byteLength.impl()) {
+ attemptToMakeGetTypedArrayByteLength(node);
+ break;
+ }
+ if (impl == vm().propertyNames->byteOffset.impl()) {
+ attemptToMakeGetTypedArrayByteOffset(node);
+ break;
}
fixEdge<CellUse>(node->child1());
break;
}
case PutById:
- case PutByIdFlush:
case PutByIdDirect: {
fixEdge<CellUse>(node->child1());
- speculateForBarrier(node->child2());
+ insertStoreBarrier(m_indexInBlock, node->child1(), node->child2());
break;
}
- case GetExecutable: {
- fixEdge<FunctionUse>(node->child1());
- break;
- }
-
+ case CheckExecutable:
case CheckStructure:
- case CheckCell:
+ case StructureTransitionWatchpoint:
+ case CheckFunction:
case CheckHasInstance:
case CreateThis:
case GetButterfly: {
fixEdge<CellUse>(node->child1());
break;
}
-
- case CheckIdent: {
- UniquedStringImpl* uid = node->uidOperand();
- if (uid->isSymbol())
- fixEdge<SymbolUse>(node->child1());
- else
- fixEdge<StringIdentUse>(node->child1());
- break;
- }
case Arrayify:
case ArrayifyToStructure: {
@@ -1050,34 +868,24 @@ private:
break;
}
- case GetByOffset:
- case GetGetterSetterByOffset: {
+ case GetByOffset: {
if (!node->child1()->hasStorageResult())
fixEdge<KnownCellUse>(node->child1());
fixEdge<KnownCellUse>(node->child2());
break;
}
- case MultiGetByOffset: {
- fixEdge<CellUse>(node->child1());
- break;
- }
-
case PutByOffset: {
if (!node->child1()->hasStorageResult())
fixEdge<KnownCellUse>(node->child1());
fixEdge<KnownCellUse>(node->child2());
- speculateForBarrier(node->child3());
- break;
- }
-
- case MultiPutByOffset: {
- fixEdge<CellUse>(node->child1());
- speculateForBarrier(node->child2());
+ insertStoreBarrier(m_indexInBlock, node->child2(), node->child3());
break;
}
case InstanceOf: {
+ // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
+ // check. https://bugs.webkit.org/show_bug.cgi?id=107479
if (!(node->child1()->prediction() & ~SpecCell))
fixEdge<CellUse>(node->child1());
fixEdge<CellUse>(node->child2());
@@ -1092,228 +900,93 @@ private:
break;
}
- case Check: {
- m_graph.doToChildren(
- node,
- [&] (Edge& edge) {
- switch (edge.useKind()) {
- case NumberUse:
- if (edge->shouldSpeculateInt32ForArithmetic())
- edge.setUseKind(Int32Use);
- break;
- default:
- break;
- }
- observeUseKindOnEdge(edge);
- });
- break;
- }
-
case Phantom:
- // Phantoms are meaningless past Fixup. We recreate them on-demand in the backend.
- node->remove();
- break;
-
- case FiatInt52: {
- RELEASE_ASSERT(enableInt52());
- node->convertToIdentity();
- fixEdge<Int52RepUse>(node->child1());
- node->setResult(NodeResultInt52);
+ case Identity:
+ case Check: {
+ switch (node->child1().useKind()) {
+ case NumberUse:
+ if (node->child1()->shouldSpeculateInt32ForArithmetic())
+ node->child1().setUseKind(Int32Use);
+ break;
+ default:
+ break;
+ }
+ observeUseKindOnEdge(node->child1());
break;
}
case GetArrayLength:
case Phi:
case Upsilon:
+ case GetArgument:
+ case PhantomPutStructure:
case GetIndexedPropertyStorage:
case GetTypedArrayByteOffset:
case LastNodeType:
case CheckTierUpInLoop:
case CheckTierUpAtReturn:
case CheckTierUpAndOSREnter:
- case CheckTierUpWithNestedTriggerAndOSREnter:
+ case Int52ToDouble:
+ case Int52ToValue:
case InvalidationPoint:
case CheckArray:
case CheckInBounds:
case ConstantStoragePointer:
case DoubleAsInt32:
+ case Int32ToDouble:
case ValueToInt32:
- case DoubleRep:
- case ValueRep:
- case Int52Rep:
- case Int52Constant:
- case Identity: // This should have been cleaned up.
- case BooleanToNumber:
- case PhantomNewObject:
- case PhantomNewFunction:
- case PhantomCreateActivation:
- case PhantomDirectArguments:
- case PhantomClonedArguments:
- case ForwardVarargs:
- case GetMyArgumentByVal:
- case PutHint:
- case CheckStructureImmediate:
- case MaterializeNewObject:
- case MaterializeCreateActivation:
- case PutStack:
- case KillStack:
- case GetStack:
- case StoreBarrier:
// These are just nodes that we don't currently expect to see during fixup.
// If we ever wanted to insert them prior to fixup, then we just have to create
// fixup rules for them.
- DFG_CRASH(m_graph, node, "Unexpected node during fixup");
+ RELEASE_ASSERT_NOT_REACHED();
break;
case PutGlobalVar: {
- fixEdge<CellUse>(node->child1());
- speculateForBarrier(node->child2());
+ Node* globalObjectNode = m_insertionSet.insertNode(m_indexInBlock, SpecNone, WeakJSConstant, node->codeOrigin,
+ OpInfo(m_graph.globalObjectFor(node->codeOrigin)));
+ Node* barrierNode = m_graph.addNode(SpecNone, ConditionalStoreBarrier, m_currentNode->codeOrigin,
+ Edge(globalObjectNode, KnownCellUse), Edge(node->child1().node(), UntypedUse));
+ fixupNode(barrierNode);
+ m_insertionSet.insert(m_indexInBlock, barrierNode);
+ break;
+ }
+
+ case TearOffActivation: {
+ Node* barrierNode = m_graph.addNode(SpecNone, StoreBarrierWithNullCheck, m_currentNode->codeOrigin,
+ Edge(node->child1().node(), UntypedUse));
+ fixupNode(barrierNode);
+ m_insertionSet.insert(m_indexInBlock, barrierNode);
break;
}
case IsString:
if (node->child1()->shouldSpeculateString()) {
- m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, Check, node->origin,
+ m_insertionSet.insertNode(m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
Edge(node->child1().node(), StringUse));
m_graph.convertToConstant(node, jsBoolean(true));
observeUseKindOnNode<StringUse>(node);
}
break;
-
- case IsObject:
- if (node->child1()->shouldSpeculateObject()) {
- m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, Check, node->origin,
- Edge(node->child1().node(), ObjectUse));
- m_graph.convertToConstant(node, jsBoolean(true));
- observeUseKindOnNode<ObjectUse>(node);
- }
- break;
-
- case GetEnumerableLength: {
- fixEdge<CellUse>(node->child1());
- break;
- }
- case HasGenericProperty: {
- fixEdge<CellUse>(node->child2());
- break;
- }
- case HasStructureProperty: {
- fixEdge<StringUse>(node->child2());
- fixEdge<KnownCellUse>(node->child3());
- break;
- }
- case HasIndexedProperty: {
- node->setArrayMode(
- node->arrayMode().refine(
- m_graph, node,
- node->child1()->prediction(),
- node->child2()->prediction(),
- SpecNone));
-
- blessArrayOperation(node->child1(), node->child2(), node->child3());
- fixEdge<CellUse>(node->child1());
- fixEdge<KnownInt32Use>(node->child2());
- break;
- }
- case GetDirectPname: {
- Edge& base = m_graph.varArgChild(node, 0);
- Edge& property = m_graph.varArgChild(node, 1);
- Edge& index = m_graph.varArgChild(node, 2);
- Edge& enumerator = m_graph.varArgChild(node, 3);
- fixEdge<CellUse>(base);
- fixEdge<KnownCellUse>(property);
- fixEdge<KnownInt32Use>(index);
- fixEdge<KnownCellUse>(enumerator);
- break;
- }
- case GetPropertyEnumerator: {
- fixEdge<CellUse>(node->child1());
- break;
- }
- case GetEnumeratorStructurePname: {
- fixEdge<KnownCellUse>(node->child1());
- fixEdge<KnownInt32Use>(node->child2());
- break;
- }
- case GetEnumeratorGenericPname: {
- fixEdge<KnownCellUse>(node->child1());
- fixEdge<KnownInt32Use>(node->child2());
- break;
- }
- case ToIndexString: {
- fixEdge<KnownInt32Use>(node->child1());
- break;
- }
- case ProfileType: {
- // We want to insert type checks based on the instructionTypeSet of the TypeLocation, not the globalTypeSet.
- // Because the instructionTypeSet is contained in globalTypeSet, if we produce a type check for
- // type T for the instructionTypeSet, the global type set must also have information for type T.
- // So if it the type check succeeds for type T in the instructionTypeSet, a type check for type T
- // in the globalTypeSet would've also succeeded.
- // (The other direction does not hold in general).
-
- RefPtr<TypeSet> typeSet = node->typeLocation()->m_instructionTypeSet;
- RuntimeTypeMask seenTypes = typeSet->seenTypes();
- if (typeSet->doesTypeConformTo(TypeMachineInt)) {
- if (node->child1()->shouldSpeculateInt32())
- fixEdge<Int32Use>(node->child1());
- else
- fixEdge<MachineIntUse>(node->child1());
- node->remove();
- } else if (typeSet->doesTypeConformTo(TypeNumber | TypeMachineInt)) {
- fixEdge<NumberUse>(node->child1());
- node->remove();
- } else if (typeSet->doesTypeConformTo(TypeString)) {
- fixEdge<StringUse>(node->child1());
- node->remove();
- } else if (typeSet->doesTypeConformTo(TypeBoolean)) {
- fixEdge<BooleanUse>(node->child1());
- node->remove();
- } else if (typeSet->doesTypeConformTo(TypeUndefined | TypeNull) && (seenTypes & TypeUndefined) && (seenTypes & TypeNull)) {
- fixEdge<OtherUse>(node->child1());
- node->remove();
- } else if (typeSet->doesTypeConformTo(TypeObject)) {
- StructureSet set = typeSet->structureSet();
- if (!set.isEmpty()) {
- fixEdge<CellUse>(node->child1());
- node->convertToCheckStructure(m_graph.addStructureSet(set));
- }
- }
-
- break;
- }
-
- case CreateScopedArguments:
- case CreateActivation:
- case NewFunction: {
- fixEdge<CellUse>(node->child1());
- break;
- }
#if !ASSERT_DISABLED
// Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
case SetArgument:
case JSConstant:
- case DoubleConstant:
+ case WeakJSConstant:
case GetLocal:
case GetCallee:
- case GetArgumentCount:
case Flush:
case PhantomLocal:
case GetLocalUnlinked:
+ case GetMyScope:
+ case GetClosureVar:
case GetGlobalVar:
case NotifyWrite:
+ case VariableWatchpoint:
case VarInjectionWatchpoint:
+ case AllocationProfileWatchpoint:
case Call:
case Construct:
- case CallVarargs:
- case ConstructVarargs:
- case CallForwardVarargs:
- case ConstructForwardVarargs:
- case LoadVarargs:
- case ProfileControlFlow:
case NewObject:
case NewArrayBuffer:
case NewRegexp:
@@ -1323,39 +996,58 @@ private:
case IsUndefined:
case IsBoolean:
case IsNumber:
- case IsObjectOrNull:
+ case IsObject:
case IsFunction:
- case CreateDirectArguments:
- case CreateClonedArguments:
+ case CreateActivation:
+ case CreateArguments:
+ case PhantomArguments:
+ case TearOffArguments:
+ case GetMyArgumentsLength:
+ case GetMyArgumentsLengthSafe:
+ case CheckArgumentsNotCreated:
+ case NewFunction:
+ case NewFunctionNoCheck:
+ case NewFunctionExpression:
case Jump:
case Return:
case Throw:
case ThrowReferenceError:
case CountExecution:
case ForceOSRExit:
- case CheckBadCell:
- case CheckNotEmpty:
case CheckWatchdogTimer:
case Unreachable:
case ExtractOSREntryLocal:
case LoopHint:
+ case StoreBarrier:
+ case ConditionalStoreBarrier:
+ case StoreBarrierWithNullCheck:
+ case FunctionReentryWatchpoint:
+ case TypedArrayWatchpoint:
case MovHint:
case ZombieHint:
- case BottomValue:
- case TypeOf:
break;
#else
default:
break;
#endif
}
+
+ if (!node->containsMovHint())
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, observeUntypedEdge);
+ }
+
+ void observeUntypedEdge(Node*, Edge& edge)
+ {
+ if (edge.useKind() != UntypedUse)
+ return;
+ fixEdge<UntypedUse>(edge);
}
template<UseKind useKind>
void createToString(Node* node, Edge& edge)
{
edge.setNode(m_insertionSet.insertNode(
- m_indexInBlock, SpecString, ToString, node->origin,
+ m_indexInBlock, SpecString, ToString, node->codeOrigin,
Edge(edge.node(), useKind)));
}
@@ -1364,7 +1056,7 @@ private:
{
ASSERT(arrayMode == ArrayMode(Array::Generic));
- if (!canOptimizeStringObjectAccess(node->origin.semantic))
+ if (!canOptimizeStringObjectAccess(node->codeOrigin))
return;
createToString<useKind>(node, node->child1());
@@ -1392,7 +1084,7 @@ private:
// decision process much easier.
observeUseKindOnNode<StringUse>(edge.node());
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, Check, node->origin,
+ m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
Edge(edge.node(), StringUse));
edge.setUseKind(KnownStringUse);
return;
@@ -1417,9 +1109,9 @@ private:
if (!edge)
break;
edge.setUseKind(KnownStringUse);
- JSString* string = edge->dynamicCastConstant<JSString*>();
- if (!string)
+ if (!m_graph.isConstant(edge.node()))
continue;
+ JSString* string = jsCast<JSString*>(m_graph.valueOfJSConstant(edge.node()).asCell());
if (string->length())
continue;
@@ -1451,21 +1143,21 @@ private:
}
if (node->child1()->shouldSpeculateStringObject()
- && canOptimizeStringObjectAccess(node->origin.semantic)) {
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
fixEdge<StringObjectUse>(node->child1());
node->convertToToString();
return;
}
if (node->child1()->shouldSpeculateStringOrStringObject()
- && canOptimizeStringObjectAccess(node->origin.semantic)) {
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
fixEdge<StringOrStringObjectUse>(node->child1());
node->convertToToString();
return;
}
}
- void fixupToStringOrCallStringConstructor(Node* node)
+ void fixupToString(Node* node)
{
if (node->child1()->shouldSpeculateString()) {
fixEdge<StringUse>(node->child1());
@@ -1474,13 +1166,13 @@ private:
}
if (node->child1()->shouldSpeculateStringObject()
- && canOptimizeStringObjectAccess(node->origin.semantic)) {
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
fixEdge<StringObjectUse>(node->child1());
return;
}
if (node->child1()->shouldSpeculateStringOrStringObject()
- && canOptimizeStringObjectAccess(node->origin.semantic)) {
+ && canOptimizeStringObjectAccess(node->codeOrigin)) {
fixEdge<StringOrStringObjectUse>(node->child1());
return;
}
@@ -1494,18 +1186,21 @@ private:
template<UseKind leftUseKind>
bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right)
{
+ Node* originalLeft = left.node();
+ Node* originalRight = right.node();
+
ASSERT(leftUseKind == StringUse || leftUseKind == StringObjectUse || leftUseKind == StringOrStringObjectUse);
- if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->origin.semantic))
+ if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->codeOrigin))
return false;
convertStringAddUse<leftUseKind>(node, left);
if (right->shouldSpeculateString())
convertStringAddUse<StringUse>(node, right);
- else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->origin.semantic))
+ else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
convertStringAddUse<StringObjectUse>(node, right);
- else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->origin.semantic))
+ else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
convertStringAddUse<StringOrStringObjectUse>(node, right);
else {
// At this point we know that the other operand is something weird. The semantically correct
@@ -1517,43 +1212,43 @@ private:
// anything to @right, since ToPrimitive may be effectful.
Node* toPrimitive = m_insertionSet.insertNode(
- m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive,
- node->origin, Edge(right.node()));
+ m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive, node->codeOrigin,
+ Edge(right.node()));
Node* toString = m_insertionSet.insertNode(
- m_indexInBlock, SpecString, ToString, node->origin, Edge(toPrimitive));
+ m_indexInBlock, SpecString, ToString, node->codeOrigin, Edge(toPrimitive));
fixupToPrimitive(toPrimitive);
-
- // Don't fix up ToString. ToString and ToPrimitive are originated from the same bytecode and
- // ToPrimitive may have an observable side effect. ToString should not be converted into Check
- // with speculative type check because OSR exit reproduce an observable side effect done in
- // ToPrimitive.
-
+ fixupToString(toString);
+
right.setNode(toString);
}
+ // We're doing checks up there, so we need to make sure that the
+ // *original* inputs to the addition are live up to here.
+ m_insertionSet.insertNode(
+ m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
+ Edge(originalLeft), Edge(originalRight));
+
convertToMakeRope(node);
return true;
}
- bool isStringPrototypeMethodSane(
- JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl* uid)
+ bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, StringImpl* uid)
{
unsigned attributesUnused;
- PropertyOffset offset =
- stringPrototypeStructure->getConcurrently(uid, attributesUnused);
+ JSCell* specificValue;
+ PropertyOffset offset = stringPrototypeStructure->getConcurrently(
+ vm(), uid, attributesUnused, specificValue);
if (!isValidOffset(offset))
return false;
- JSValue value = m_graph.tryGetConstantProperty(
- stringPrototype, stringPrototypeStructure, offset);
- if (!value)
+ if (!specificValue)
return false;
- JSFunction* function = jsDynamicCast<JSFunction*>(value);
- if (!function)
+ if (!specificValue->inherits(JSFunction::info()))
return false;
+ JSFunction* function = jsCast<JSFunction*>(specificValue);
if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
return false;
@@ -1571,7 +1266,7 @@ private:
JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
Structure* stringPrototypeStructure = stringPrototypeObject->structure();
- if (m_graph.registerStructure(stringPrototypeStructure) != StructureRegisteredAndWatched)
+ if (!m_graph.watchpoints().isStillValid(stringPrototypeStructure->transitionWatchpointSet()))
return false;
if (stringPrototypeStructure->isDictionary())
@@ -1582,15 +1277,15 @@ private:
// (that would call toString()). We don't want the DFG to have to distinguish
// between the two, just because that seems like it would get confusing. So we
// just require both methods to be sane.
- if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->valueOf.impl()))
+ if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->valueOf.impl()))
return false;
- if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->toString.impl()))
+ if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->toString.impl()))
return false;
return true;
}
- void fixupGetAndSetLocalsInBlock(BasicBlock* block)
+ void fixupSetLocalsInBlock(BasicBlock* block)
{
if (!block)
return;
@@ -1598,49 +1293,28 @@ private:
m_block = block;
for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
Node* node = m_currentNode = block->at(m_indexInBlock);
- if (node->op() != SetLocal && node->op() != GetLocal)
+ if (node->op() != SetLocal)
continue;
VariableAccessData* variable = node->variableAccessData();
- switch (node->op()) {
- case GetLocal:
- switch (variable->flushFormat()) {
- case FlushedDouble:
- node->setResult(NodeResultDouble);
- break;
- case FlushedInt52:
- node->setResult(NodeResultInt52);
- break;
- default:
- break;
- }
+ switch (variable->flushFormat()) {
+ case FlushedJSValue:
break;
-
- case SetLocal:
- switch (variable->flushFormat()) {
- case FlushedJSValue:
- break;
- case FlushedDouble:
- fixEdge<DoubleRepUse>(node->child1());
- break;
- case FlushedInt32:
- fixEdge<Int32Use>(node->child1());
- break;
- case FlushedInt52:
- fixEdge<Int52RepUse>(node->child1());
- break;
- case FlushedCell:
- fixEdge<CellUse>(node->child1());
- break;
- case FlushedBoolean:
- fixEdge<BooleanUse>(node->child1());
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
+ case FlushedDouble:
+ fixEdge<NumberUse>(node->child1());
+ break;
+ case FlushedInt32:
+ fixEdge<Int32Use>(node->child1());
+ break;
+ case FlushedInt52:
+ fixEdge<MachineIntUse>(node->child1());
+ break;
+ case FlushedCell:
+ fixEdge<CellUse>(node->child1());
+ break;
+ case FlushedBoolean:
+ fixEdge<BooleanUse>(node->child1());
break;
-
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -1649,38 +1323,54 @@ private:
m_insertionSet.execute(block);
}
- Node* checkArray(ArrayMode arrayMode, const NodeOrigin& origin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
+ void fixupUntypedSetLocalsInBlock(BasicBlock* block)
+ {
+ if (!block)
+ return;
+ ASSERT(block->isReachable);
+ m_block = block;
+ for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
+ Node* node = m_currentNode = block->at(m_indexInBlock);
+ if (node->op() != SetLocal)
+ continue;
+
+ if (node->child1().useKind() == UntypedUse)
+ fixEdge<UntypedUse>(node->child1());
+ }
+ m_insertionSet.execute(block);
+ }
+
+ Node* checkArray(ArrayMode arrayMode, const CodeOrigin& codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
{
ASSERT(arrayMode.isSpecific());
if (arrayMode.type() == Array::String) {
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, Check, origin, Edge(array, StringUse));
+ m_indexInBlock, SpecNone, Phantom, codeOrigin,
+ Edge(array, StringUse));
} else {
- // Note that we only need to be using a structure check if we opt for SaneChain, since
- // that needs to protect against JSArray's __proto__ being changed.
- Structure* structure = arrayMode.originalArrayStructure(m_graph, origin.semantic);
+ Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
-
+
if (arrayMode.doesConversion()) {
if (structure) {
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, ArrayifyToStructure, origin,
+ m_indexInBlock, SpecNone, ArrayifyToStructure, codeOrigin,
OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
} else {
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, Arrayify, origin,
+ m_indexInBlock, SpecNone, Arrayify, codeOrigin,
OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
}
} else {
if (structure) {
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, CheckStructure, origin,
+ m_indexInBlock, SpecNone, CheckStructure, codeOrigin,
OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
} else {
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, CheckArray, origin,
+ m_indexInBlock, SpecNone, CheckArray, codeOrigin,
OpInfo(arrayMode.asWord()), Edge(array, CellUse));
}
}
@@ -1691,11 +1381,11 @@ private:
if (arrayMode.usesButterfly()) {
return m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, GetButterfly, origin, Edge(array, CellUse));
+ m_indexInBlock, SpecNone, GetButterfly, codeOrigin, Edge(array, CellUse));
}
return m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, GetIndexedPropertyStorage, origin,
+ m_indexInBlock, SpecNone, GetIndexedPropertyStorage, codeOrigin,
OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
}
@@ -1706,7 +1396,7 @@ private:
switch (node->arrayMode().type()) {
case Array::ForceExit: {
m_insertionSet.insertNode(
- m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
+ m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
return;
}
@@ -1719,7 +1409,7 @@ private:
return;
default: {
- Node* storage = checkArray(node->arrayMode(), node->origin, base.node(), index.node());
+ Node* storage = checkArray(node->arrayMode(), node->codeOrigin, base.node(), index.node());
if (!storage)
return;
@@ -1763,35 +1453,29 @@ private:
VariableAccessData* variable = node->variableAccessData();
switch (useKind) {
case Int32Use:
- case KnownInt32Use:
if (alwaysUnboxSimplePrimitives()
|| isInt32Speculation(variable->prediction()))
m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
break;
case NumberUse:
case RealNumberUse:
- case DoubleRepUse:
- case DoubleRepRealUse:
if (variable->doubleFormatState() == UsingDoubleFormat)
m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
break;
case BooleanUse:
- case KnownBooleanUse:
if (alwaysUnboxSimplePrimitives()
|| isBooleanSpeculation(variable->prediction()))
m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
break;
- case Int52RepUse:
+ case MachineIntUse:
if (isMachineIntSpeculation(variable->prediction()))
m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
break;
case CellUse:
case KnownCellUse:
case ObjectUse:
- case FunctionUse:
case StringUse:
case KnownStringUse:
- case SymbolUse:
case StringObjectUse:
case StringOrStringObjectUse:
if (alwaysUnboxSimplePrimitives()
@@ -1803,131 +1487,179 @@ private:
}
}
+ // Set the use kind of the edge and perform any actions that need to be done for
+ // that use kind, like inserting intermediate conversion nodes. Never call this
+ // with useKind = UntypedUse explicitly; edges have UntypedUse implicitly and any
+ // edge that survives fixup and still has UntypedUse will have this method called
+ // from observeUntypedEdge(). Also, make sure that if you do change the type of an
+ // edge, you either call fixEdge() or perform the equivalent functionality
+ // yourself. Obviously, you should have a really good reason if you do the latter.
template<UseKind useKind>
void fixEdge(Edge& edge)
{
- observeUseKindOnNode<useKind>(edge.node());
- edge.setUseKind(useKind);
- }
-
- void speculateForBarrier(Edge value)
- {
- // Currently, the DFG won't take advantage of this speculation. But, we want to do it in
- // the DFG anyway because if such a speculation would be wrong, we want to know before
- // we do an expensive compile.
-
- if (value->shouldSpeculateInt32()) {
- insertCheck<Int32Use>(m_indexInBlock, value.node());
- return;
- }
-
- if (value->shouldSpeculateBoolean()) {
- insertCheck<BooleanUse>(m_indexInBlock, value.node());
- return;
- }
-
- if (value->shouldSpeculateOther()) {
- insertCheck<OtherUse>(m_indexInBlock, value.node());
- return;
- }
+ if (isDouble(useKind)) {
+ if (edge->shouldSpeculateInt32ForArithmetic()) {
+ injectInt32ToDoubleNode(edge, useKind);
+ return;
+ }
- if (value->shouldSpeculateNumber()) {
- insertCheck<NumberUse>(m_indexInBlock, value.node());
- return;
+ if (enableInt52() && edge->shouldSpeculateMachineInt()) {
+ // Make all double uses of int52 values have an intermediate Int52ToDouble.
+ // This is for the same reason as Int52ToValue (see below) except that
+ // Int8ToDouble will convert int52's that fit in an int32 into a double
+ // rather than trying to create a boxed int32 like Int52ToValue does.
+
+ Node* result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt52AsDouble, Int52ToDouble,
+ m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
+ edge = Edge(result, useKind);
+ return;
+ }
}
+
+ if (enableInt52() && useKind != MachineIntUse
+ && edge->shouldSpeculateMachineInt() && !edge->shouldSpeculateInt32()) {
+ // We make all non-int52 uses of int52 values have an intermediate Int52ToValue
+ // node to ensure that we handle this properly:
+ //
+ // a: SomeInt52
+ // b: ArithAdd(@a, ...)
+ // c: Call(..., @a)
+ // d: ArithAdd(@a, ...)
+ //
+ // Without an intermediate node and just labeling the uses, we will get:
+ //
+ // a: SomeInt52
+ // b: ArithAdd(Int52:@a, ...)
+ // c: Call(..., Untyped:@a)
+ // d: ArithAdd(Int52:@a, ...)
+ //
+ // And now the c->Untyped:@a edge will box the value of @a into a double. This
+ // is bad, because now the d->Int52:@a edge will either have to do double-to-int
+ // conversions, or will have to OSR exit unconditionally. Alternatively we could
+ // have the c->Untyped:@a edge box the value by copying rather than in-place.
+ // But these boxings are also costly so this wouldn't be great.
+ //
+ // The solution we use is to always have non-Int52 uses of predicted Int52's use
+ // an intervening Int52ToValue node:
+ //
+ // a: SomeInt52
+ // b: ArithAdd(Int52:@a, ...)
+ // x: Int52ToValue(Int52:@a)
+ // c: Call(..., Untyped:@x)
+ // d: ArithAdd(Int52:@a, ...)
+ //
+ // Note that even if we had multiple non-int52 uses of @a, the multiple
+ // Int52ToValue's would get CSE'd together. So the boxing would only happen once.
+ // At the same time, @a would continue to be represented as a native int52.
+ //
+ // An alternative would have been to insert ToNativeInt52 nodes on int52 uses of
+ // int52's. This would have handled the above example but would fall over for:
+ //
+ // a: SomeInt52
+ // b: Call(..., @a)
+ // c: ArithAdd(@a, ...)
+ //
+ // But the solution we use handles the above gracefully.
- if (value->shouldSpeculateNotCell()) {
- insertCheck<NotCellUse>(m_indexInBlock, value.node());
+ Node* result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt52, Int52ToValue,
+ m_currentNode->codeOrigin, Edge(edge.node(), UntypedUse));
+ edge = Edge(result, useKind);
return;
}
+
+ observeUseKindOnNode<useKind>(edge.node());
+
+ edge.setUseKind(useKind);
}
- template<UseKind useKind>
- void insertCheck(unsigned indexInBlock, Node* node)
+ void insertStoreBarrier(unsigned indexInBlock, Edge child1, Edge child2 = Edge())
{
- observeUseKindOnNode<useKind>(node);
- m_insertionSet.insertNode(
- indexInBlock, SpecNone, Check, m_currentNode->origin, Edge(node, useKind));
+ Node* barrierNode;
+ if (!child2)
+ barrierNode = m_graph.addNode(SpecNone, StoreBarrier, m_currentNode->codeOrigin, Edge(child1.node(), child1.useKind()));
+ else {
+ barrierNode = m_graph.addNode(SpecNone, ConditionalStoreBarrier, m_currentNode->codeOrigin,
+ Edge(child1.node(), child1.useKind()), Edge(child2.node(), child2.useKind()));
+ }
+ fixupNode(barrierNode);
+ m_insertionSet.insert(indexInBlock, barrierNode);
}
- void fixIntConvertingEdge(Edge& edge)
+ bool fixIntEdge(Edge& edge)
{
Node* node = edge.node();
- if (node->shouldSpeculateInt32OrBoolean()) {
- fixIntOrBooleanEdge(edge);
- return;
+ if (node->shouldSpeculateInt32()) {
+ fixEdge<Int32Use>(edge);
+ return false;
}
UseKind useKind;
if (node->shouldSpeculateMachineInt())
- useKind = Int52RepUse;
+ useKind = MachineIntUse;
else if (node->shouldSpeculateNumber())
- useKind = DoubleRepUse;
+ useKind = NumberUse;
+ else if (node->shouldSpeculateBoolean())
+ useKind = BooleanUse;
else
useKind = NotCellUse;
Node* newNode = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, ValueToInt32, m_currentNode->origin,
+ m_indexInBlock, SpecInt32, ValueToInt32, m_currentNode->codeOrigin,
Edge(node, useKind));
observeUseKindOnNode(node, useKind);
edge = Edge(newNode, KnownInt32Use);
+ return true;
}
- void fixIntOrBooleanEdge(Edge& edge)
+ void fixBinaryIntEdges()
{
- Node* node = edge.node();
- if (!node->sawBooleans()) {
- fixEdge<Int32Use>(edge);
- return;
- }
+ AdjacencyList children = m_currentNode->children;
- UseKind useKind;
- if (node->shouldSpeculateBoolean())
- useKind = BooleanUse;
- else
- useKind = UntypedUse;
- Node* newNode = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
- Edge(node, useKind));
- observeUseKindOnNode(node, useKind);
+ // Call fixIntEdge() on both edges.
+ bool needPhantom =
+ fixIntEdge(m_currentNode->child1()) | fixIntEdge(m_currentNode->child2());
- edge = Edge(newNode, Int32Use);
+ if (!needPhantom)
+ return;
+ m_insertionSet.insertNode(m_indexInBlock + 1, SpecNone, Phantom, m_currentNode->codeOrigin, children);
}
- void fixDoubleOrBooleanEdge(Edge& edge)
+ void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse)
{
- Node* node = edge.node();
- if (!node->sawBooleans()) {
- fixEdge<DoubleRepUse>(edge);
- return;
- }
+ Node* result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt52AsDouble, Int32ToDouble,
+ m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
- UseKind useKind;
- if (node->shouldSpeculateBoolean())
- useKind = BooleanUse;
- else
- useKind = UntypedUse;
- Node* newNode = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
- Edge(node, useKind));
- observeUseKindOnNode(node, useKind);
-
- edge = Edge(newNode, DoubleRepUse);
+ edge = Edge(result, useKind);
}
void truncateConstantToInt32(Edge& edge)
{
Node* oldNode = edge.node();
- JSValue value = oldNode->asJSValue();
+ ASSERT(oldNode->hasConstant());
+ JSValue value = m_graph.valueOfJSConstant(oldNode);
if (value.isInt32())
return;
value = jsNumber(JSC::toInt32(value.asNumber()));
ASSERT(value.isInt32());
+ unsigned constantRegister;
+ if (!codeBlock()->findConstant(value, constantRegister)) {
+ constantRegister = codeBlock()->addConstantLazily();
+ initializeLazyWriteBarrierForConstant(
+ m_graph.m_plan.writeBarriers,
+ codeBlock()->constants()[constantRegister],
+ codeBlock(),
+ constantRegister,
+ codeBlock()->ownerExecutable(),
+ value);
+ }
edge.setNode(m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, JSConstant, m_currentNode->origin,
- OpInfo(m_graph.freeze(value))));
+ m_indexInBlock, SpecInt32, JSConstant, m_currentNode->codeOrigin,
+ OpInfo(constantRegister)));
}
void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
@@ -1944,11 +1676,11 @@ private:
bool attemptToMakeIntegerAdd(Node* node)
{
- AddSpeculationMode mode = m_graph.addSpeculationMode(node, FixupPass);
+ AddSpeculationMode mode = m_graph.addSpeculationMode(node);
if (mode != DontSpeculateInt32) {
truncateConstantsIfNecessary(node, mode);
- fixIntOrBooleanEdge(node->child1());
- fixIntOrBooleanEdge(node->child2());
+ fixEdge<Int32Use>(node->child1());
+ fixEdge<Int32Use>(node->child2());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else
@@ -1957,10 +1689,9 @@ private:
}
if (m_graph.addShouldSpeculateMachineInt(node)) {
- fixEdge<Int52RepUse>(node->child1());
- fixEdge<Int52RepUse>(node->child2());
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
node->setArithMode(Arith::CheckOverflow);
- node->setResult(NodeResultInt52);
return true;
}
@@ -1971,9 +1702,9 @@ private:
{
if (!isInt32Speculation(node->prediction()))
return false;
- CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic);
+ CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->codeOrigin);
ArrayProfile* arrayProfile =
- profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex);
+ profiledBlock->getArrayProfile(node->codeOrigin.bytecodeIndex);
ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
if (arrayProfile) {
ConcurrentJITLocker locker(profiledBlock->m_lock);
@@ -1991,8 +1722,7 @@ private:
}
}
- arrayMode = arrayMode.refine(
- m_graph, node, node->child1()->prediction(), node->prediction());
+ arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
if (arrayMode.type() == Array::Generic) {
// Check if the input is something that we can't get array length for, but for which we
@@ -2026,16 +1756,16 @@ private:
}
Node* length = prependGetArrayLength(
- node->origin, node->child1().node(), ArrayMode(toArrayType(type)));
+ node->codeOrigin, node->child1().node(), ArrayMode(toArrayType(type)));
Node* shiftAmount = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, JSConstant, node->origin,
- OpInfo(m_graph.freeze(jsNumber(logElementSize(type)))));
+ m_indexInBlock, SpecInt32, JSConstant, node->codeOrigin,
+ OpInfo(m_graph.constantRegisterForConstant(jsNumber(logElementSize(type)))));
// We can use a BitLShift here because typed arrays will never have a byteLength
// that overflows int32.
node->setOp(BitLShift);
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
observeUseKindOnNode(length, Int32Use);
observeUseKindOnNode(shiftAmount, Int32Use);
node->child1() = Edge(length, Int32Use);
@@ -2046,22 +1776,22 @@ private:
void convertToGetArrayLength(Node* node, ArrayMode arrayMode)
{
node->setOp(GetArrayLength);
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
fixEdge<KnownCellUse>(node->child1());
node->setArrayMode(arrayMode);
- Node* storage = checkArray(arrayMode, node->origin, node->child1().node(), 0, lengthNeedsStorage);
+ Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage);
if (!storage)
return;
node->child2() = Edge(storage);
}
- Node* prependGetArrayLength(NodeOrigin origin, Node* child, ArrayMode arrayMode)
+ Node* prependGetArrayLength(CodeOrigin codeOrigin, Node* child, ArrayMode arrayMode)
{
- Node* storage = checkArray(arrayMode, origin, child, 0, lengthNeedsStorage);
+ Node* storage = checkArray(arrayMode, codeOrigin, child, 0, lengthNeedsStorage);
return m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, GetArrayLength, origin,
+ m_indexInBlock, SpecInt32, GetArrayLength, codeOrigin,
OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
}
@@ -2075,177 +1805,15 @@ private:
return false;
checkArray(
- ArrayMode(toArrayType(type)), node->origin, node->child1().node(),
+ ArrayMode(toArrayType(type)), node->codeOrigin, node->child1().node(),
0, neverNeedsStorage);
node->setOp(GetTypedArrayByteOffset);
- node->clearFlags(NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
fixEdge<KnownCellUse>(node->child1());
return true;
}
-
- void injectTypeConversionsInBlock(BasicBlock* block)
- {
- if (!block)
- return;
- ASSERT(block->isReachable);
- m_block = block;
- for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
- m_currentNode = block->at(m_indexInBlock);
- tryToRelaxRepresentation(m_currentNode);
- DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge);
- }
- m_insertionSet.execute(block);
- }
-
- void tryToRelaxRepresentation(Node* node)
- {
- // Some operations may be able to operate more efficiently over looser representations.
- // Identify those here. This avoids inserting a redundant representation conversion.
- // Also, for some operations, like MovHint, this is a necessary optimization: inserting
- // an otherwise-dead conversion just for a MovHint would break OSR's understanding of
- // the IR.
-
- switch (node->op()) {
- case MovHint:
- case Check:
- DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, fixEdgeRepresentation);
- break;
-
- case ValueToInt32:
- if (node->child1().useKind() == DoubleRepUse
- && !node->child1()->hasDoubleResult()) {
- node->child1().setUseKind(NumberUse);
- break;
- }
- break;
-
- default:
- break;
- }
- }
-
- void fixEdgeRepresentation(Node*, Edge& edge)
- {
- switch (edge.useKind()) {
- case DoubleRepUse:
- case DoubleRepRealUse:
- if (edge->hasDoubleResult())
- break;
-
- if (edge->hasInt52Result())
- edge.setUseKind(Int52RepUse);
- else if (edge.useKind() == DoubleRepUse)
- edge.setUseKind(NumberUse);
- break;
-
- case Int52RepUse:
- // Nothing we can really do.
- break;
-
- case UntypedUse:
- case NumberUse:
- if (edge->hasDoubleResult())
- edge.setUseKind(DoubleRepUse);
- else if (edge->hasInt52Result())
- edge.setUseKind(Int52RepUse);
- break;
-
- case RealNumberUse:
- if (edge->hasDoubleResult())
- edge.setUseKind(DoubleRepRealUse);
- else if (edge->hasInt52Result())
- edge.setUseKind(Int52RepUse);
- break;
-
- default:
- break;
- }
- }
-
- void injectTypeConversionsForEdge(Node* node, Edge& edge)
- {
- ASSERT(node == m_currentNode);
- Node* result = nullptr;
-
- switch (edge.useKind()) {
- case DoubleRepUse:
- case DoubleRepRealUse:
- case DoubleRepMachineIntUse: {
- if (edge->hasDoubleResult())
- break;
-
- if (edge->isNumberConstant()) {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecBytecodeDouble, DoubleConstant, node->origin,
- OpInfo(m_graph.freeze(jsDoubleNumber(edge->asNumber()))));
- } else if (edge->hasInt52Result()) {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin,
- Edge(edge.node(), Int52RepUse));
- } else {
- UseKind useKind;
- if (edge->shouldSpeculateDoubleReal())
- useKind = RealNumberUse;
- else if (edge->shouldSpeculateNumber())
- useKind = NumberUse;
- else
- useKind = NotCellUse;
-
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecBytecodeDouble, DoubleRep, node->origin,
- Edge(edge.node(), useKind));
- }
-
- edge.setNode(result);
- break;
- }
-
- case Int52RepUse: {
- if (edge->hasInt52Result())
- break;
-
- if (edge->isMachineIntConstant()) {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecMachineInt, Int52Constant, node->origin,
- OpInfo(edge->constant()));
- } else if (edge->hasDoubleResult()) {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
- Edge(edge.node(), DoubleRepMachineIntUse));
- } else if (edge->shouldSpeculateInt32ForArithmetic()) {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32, Int52Rep, node->origin,
- Edge(edge.node(), Int32Use));
- } else {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
- Edge(edge.node(), MachineIntUse));
- }
- edge.setNode(result);
- break;
- }
-
- default: {
- if (!edge->hasDoubleResult() && !edge->hasInt52Result())
- break;
-
- if (edge->hasDoubleResult()) {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecBytecodeDouble, ValueRep, node->origin,
- Edge(edge.node(), DoubleRepUse));
- } else {
- result = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt32 | SpecInt52AsDouble, ValueRep, node->origin,
- Edge(edge.node(), Int52RepUse));
- }
-
- edge.setNode(result);
- break;
- } }
- }
-
BasicBlock* m_block;
unsigned m_indexInBlock;
Node* m_currentNode;