diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGFixupPhase.cpp')
| -rw-r--r-- | Source/JavaScriptCore/dfg/DFGFixupPhase.cpp | 1432 |
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; |
