diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGAbstractState.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 87 |
1 files changed, 60 insertions, 27 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 4f02ee793..5c53f6d78 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -62,13 +62,13 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock) m_variables = basicBlock->valuesAtHead; m_haveStructures = false; for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) { - if (m_variables.argument(i).m_structure.isNeitherClearNorTop()) { + if (m_variables.argument(i).m_currentKnownStructure.isNeitherClearNorTop()) { m_haveStructures = true; break; } } for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) { - if (m_variables.local(i).m_structure.isNeitherClearNorTop()) { + if (m_variables.local(i).m_currentKnownStructure.isNeitherClearNorTop()) { m_haveStructures = true; break; } @@ -106,8 +106,6 @@ void AbstractState::initialize(Graph& graph) SpeculatedType prediction = node.variableAccessData()->prediction(); if (isInt32Speculation(prediction)) root->valuesAtHead.argument(i).set(SpecInt32); - else if (isArraySpeculation(prediction)) - root->valuesAtHead.argument(i).set(SpecArray); else if (isBooleanSpeculation(prediction)) root->valuesAtHead.argument(i).set(SpecBoolean); else if (isInt8ArraySpeculation(prediction)) @@ -160,6 +158,16 @@ void AbstractState::initialize(Graph& graph) block->valuesAtHead.local(i).clear(); block->valuesAtTail.local(i).clear(); } + if (!block->isOSRTarget) + continue; + if (block->bytecodeBegin != graph.m_osrEntryBytecodeIndex) + continue; + for (size_t i = 0; i < graph.m_mustHandleValues.size(); ++i) { + AbstractValue value; + value.setMostSpecific(graph.m_mustHandleValues[i]); + block->valuesAtHead.operand(graph.m_mustHandleValues.operandForIndex(i)).merge(value); + } + block->cfaShouldRevisit = true; } } @@ -290,10 +298,7 @@ bool AbstractState::execute(unsigned indexInBlock) SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); if (isInt32Speculation(predictedType)) speculateInt32Unary(node); - else if (isArraySpeculation(predictedType)) { - node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecArray); - } else if (isCellSpeculation(predictedType)) { + else if (isCellSpeculation(predictedType)) { node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type)); forNode(node.child1()).filter(SpecCell); } else if (isBooleanSpeculation(predictedType)) @@ -867,7 +872,7 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { + if (!m_graph[node.child2()].shouldSpeculateInteger() || (!node.child3() && !m_graph[node.child1()].shouldSpeculateArguments())) { clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; @@ -942,8 +947,7 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).set(SpecDouble); break; } - ASSERT(m_graph[node.child1()].shouldSpeculateArray()); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; @@ -962,7 +966,7 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!m_graph[child2].shouldSpeculateInteger() || !isActionableMutableArraySpeculation(m_graph[child1].prediction()) + if (!m_graph[child2].shouldSpeculateInteger() #if USE(JSVALUE32_64) || m_graph[child1].shouldSpeculateArguments() #endif @@ -1053,8 +1057,7 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(child3).filter(SpecNumber); break; } - ASSERT(m_graph[child1].shouldSpeculateArray()); - forNode(child1).filter(SpecArray); + forNode(child1).filter(SpecCell); forNode(child2).filter(SpecInt32); if (node.op() == PutByValSafe) clobberWorld(node.codeOrigin, indexInBlock); @@ -1063,13 +1066,13 @@ bool AbstractState::execute(unsigned indexInBlock) case ArrayPush: node.setCanExit(true); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).set(SpecNumber); break; case ArrayPop: node.setCanExit(true); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).makeTop(); break; @@ -1354,7 +1357,7 @@ bool AbstractState::execute(unsigned indexInBlock) case GetArrayLength: node.setCanExit(true); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).set(SpecInt32); break; @@ -1420,19 +1423,52 @@ bool AbstractState::execute(unsigned indexInBlock) case ForwardCheckStructure: { // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes). AbstractValue& value = forNode(node.child1()); + // If this structure check is attempting to prove knowledge already held in + // the futurePossibleStructure set then the constant folding phase should + // turn this into a watchpoint instead. + StructureSet& set = node.structureSet(); + if (value.m_futurePossibleStructure.isSubsetOf(set)) + m_foundConstants = true; node.setCanExit( - !value.m_structure.isSubsetOf(node.structureSet()) + !value.m_currentKnownStructure.isSubsetOf(set) || !isCellSpeculation(value.m_type)); - value.filter(node.structureSet()); + value.filter(set); + // This is likely to be unnecessary, but it's conservative, and that's a good thing. + // This is trying to avoid situations where the CFA proves that this structure check + // must fail due to a future structure proof. We have two options at that point. We + // can either compile all subsequent code as we would otherwise, or we can ensure + // that the subsequent code is never reachable. The former is correct because the + // Proof Is Infallible (TM) -- hence even if we don't force the subsequent code to + // be unreachable, it must be unreachable nonetheless. But imagine what would happen + // if the proof was borked. In the former case, we'd get really bizarre bugs where + // we assumed that the structure of this object was known even though it wasn't. In + // the latter case, we'd have a slight performance pathology because this would be + // turned into an OSR exit unnecessarily. Which would you rather have? + if (value.m_currentKnownStructure.isClear() + || value.m_futurePossibleStructure.isClear()) + m_isValid = false; m_haveStructures = true; break; } - case StructureTransitionWatchpoint: { - // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible! + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: { AbstractValue& value = forNode(node.child1()); + + // It's only valid to issue a structure transition watchpoint if we already + // know that the watchpoint covers a superset of the structures known to + // belong to the set of future structures that this value may have. + // Currently, we only issue singleton watchpoints (that check one structure) + // and our futurePossibleStructure set can only contain zero, one, or an + // infinity of structures. + ASSERT(value.m_futurePossibleStructure.isSubsetOf(StructureSet(node.structure()))); + ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad. value.filter(node.structure()); + // See comment in CheckStructure for why this is here. + if (value.m_currentKnownStructure.isClear() + || value.m_futurePossibleStructure.isClear()) + m_isValid = false; m_haveStructures = true; node.setCanExit(true); break; @@ -1453,12 +1489,9 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).clear(); // The result is not a JS value. break; case GetIndexedPropertyStorage: { + ASSERT(m_graph[node.child1()].prediction()); + ASSERT(m_graph[node.child2()].shouldSpeculateInteger()); node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise. - SpeculatedType basePrediction = m_graph[node.child2()].prediction(); - if (!(basePrediction & SpecInt32) && basePrediction) { - forNode(nodeIndex).clear(); - break; - } if (m_graph[node.child1()].shouldSpeculateArguments()) { ASSERT_NOT_REACHED(); break; @@ -1514,7 +1547,7 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).clear(); break; } - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); break; } |