bool AbstractValue::mergeOSREntryValue(Graph& graph, JSValue value) { AbstractValue oldMe = *this; if (isClear()) { FrozenValue* frozenValue = graph.freeze(value); if (frozenValue->pointsToHeap()) { m_structure = frozenValue->structure(); m_arrayModes = asArrayModes(frozenValue->structure()->indexingType()); } else { m_structure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value); m_value = value; } else { mergeSpeculation(m_type, speculationFromValue(value)); if (!!value && value.isCell()) { Structure* structure = value.asCell()->structure(); graph.registerStructure(structure); mergeArrayModes(m_arrayModes, asArrayModes(structure->indexingType())); m_structure.merge(StructureSet(structure)); } if (m_value != value) m_value = JSValue(); } checkConsistency(); assertIsRegistered(graph); return oldMe != *this; }
FiltrationResult AbstractValue::filterByValue(JSValue value) { FiltrationResult result = filter(speculationFromValue(value)); if (m_type) m_value = value; return result; }
void AbstractValue::set(Graph& graph, const FrozenValue& value, StructureClobberState clobberState) { if (!!value && value.value().isCell()) { Structure* structure = value.structure(); // FIXME: This check may not be necessary since any frozen value should have its structure // watched already. // https://bugs.webkit.org/show_bug.cgi?id=136055 if (graph.registerStructure(structure) == StructureRegisteredAndWatched) { m_structure = structure; if (clobberState == StructuresAreClobbered) { m_arrayModes = ALL_ARRAY_MODES; m_structure.clobber(); } else m_arrayModes = asArrayModes(structure->indexingType()); } else { m_structure.makeTop(); m_arrayModes = ALL_ARRAY_MODES; } } else { m_structure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value.value()); m_value = value.value(); checkConsistency(); assertIsRegistered(graph); }
FiltrationResult AbstractValue::filterByValue(const FrozenValue& value) { FiltrationResult result = filter(speculationFromValue(value.value())); if (m_type) m_value = value.value(); return result; }
void AbstractValue::set(Graph& graph, const FrozenValue& value, StructureClobberState clobberState) { if (!!value && value.value().isCell()) { Structure* structure = value.structure(); if (graph.registerStructure(structure) == StructureRegisteredAndWatched) { m_structure = structure; if (clobberState == StructuresAreClobbered) { m_arrayModes = ALL_ARRAY_MODES; m_structure.clobber(); } else m_arrayModes = asArrayModes(structure->indexingType()); } else { m_structure.makeTop(); m_arrayModes = ALL_ARRAY_MODES; } } else { m_structure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value.value()); m_value = value.value(); checkConsistency(); assertIsRegistered(graph); }
void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell, Structure* structure) { if (m_graph.watchpoints().consider(cell->structure())) return; Node* weakConstant = m_insertionSet.insertNode( indexInBlock, speculationFromValue(cell), JSConstant, origin, OpInfo(m_graph.freeze(cell))); m_insertionSet.insertNode( indexInBlock, SpecNone, CheckStructure, origin, OpInfo(m_graph.addStructureSet(structure)), Edge(weakConstant, CellUse)); }
void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell) { Node* weakConstant = m_insertionSet.insertNode( indexInBlock, speculationFromValue(cell), WeakJSConstant, origin, OpInfo(cell)); if (m_graph.watchpoints().isStillValid(cell->structure()->transitionWatchpointSet())) { m_insertionSet.insertNode( indexInBlock, SpecNone, StructureTransitionWatchpoint, origin, OpInfo(cell->structure()), Edge(weakConstant, CellUse)); return; } m_insertionSet.insertNode( indexInBlock, SpecNone, CheckStructure, origin, OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse)); }
void AbstractValue::setMostSpecific(Graph& graph, JSValue value) { if (!!value && value.isCell()) { Structure* structure = value.asCell()->structure(); m_currentKnownStructure = structure; setFuturePossibleStructure(graph, structure); m_arrayModes = asArrayModes(structure->indexingType()); } else { m_currentKnownStructure.clear(); m_futurePossibleStructure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value); m_value = value; checkConsistency(); }
void AbstractValue::setOSREntryValue(Graph& graph, const FrozenValue& value) { if (!!value && value.value().isCell()) { Structure* structure = value.structure(); graph.registerStructure(structure); m_structure = structure; m_arrayModes = asArrayModes(structure->indexingType()); } else { m_structure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value.value()); m_value = value.value(); checkConsistency(); assertIsRegistered(graph); }
bool run() { ASSERT(m_graph.m_form == ThreadedCPS); ASSERT(m_graph.m_unificationState == GloballyUnified); ASSERT(codeBlock()->numParameters() >= 1); { ConcurrentJSLocker locker(profiledBlock()->m_lock); // We only do this for the arguments at the first block. The arguments from // other entrypoints have already been populated with their predictions. auto& arguments = m_graph.m_rootToArguments.find(m_graph.block(0))->value; for (size_t arg = 0; arg < static_cast<size_t>(codeBlock()->numParameters()); ++arg) { ValueProfile& profile = profiledBlock()->valueProfileForArgument(arg); arguments[arg]->variableAccessData()->predict( profile.computeUpdatedPrediction(locker)); } } for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; if (!block->isOSRTarget) continue; if (block->bytecodeBegin != m_graph.m_plan.osrEntryBytecodeIndex()) continue; const Operands<Optional<JSValue>>& mustHandleValues = m_graph.m_plan.mustHandleValues(); for (size_t i = 0; i < mustHandleValues.size(); ++i) { int operand = mustHandleValues.operandForIndex(i); Optional<JSValue> value = mustHandleValues[i]; if (!value) continue; Node* node = block->variablesAtHead.operand(operand); if (!node) continue; ASSERT(node->accessesStack(m_graph)); node->variableAccessData()->predict(speculationFromValue(value.value())); } } return true; }
void AbstractValue::checkConsistency() const { if (!(m_type & SpecCell)) { ASSERT(m_currentKnownStructure.isClear()); ASSERT(m_futurePossibleStructure.isClear()); ASSERT(!m_arrayModes); } if (isClear()) ASSERT(!m_value); if (!!m_value) ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type); // Note that it's possible for a prediction like (Final, []). This really means that // the value is bottom and that any code that uses the value is unreachable. But // we don't want to get pedantic about this as it would only increase the computational // complexity of the code. }
bool run() { ASSERT(m_graph.m_form == ThreadedCPS); ASSERT(m_graph.m_unificationState == GloballyUnified); ASSERT(codeBlock()->numParameters() >= 1); for (size_t arg = 0; arg < static_cast<size_t>(codeBlock()->numParameters()); ++arg) { ValueProfile* profile = profiledBlock()->valueProfileForArgument(arg); if (!profile) continue; m_graph.m_arguments[arg]->variableAccessData()->predict(profile->computeUpdatedPrediction()); #if DFG_ENABLE(DEBUG_VERBOSE) dataLog( "Argument [", arg, "] prediction: ", SpeculationDump(m_graph.m_arguments[arg]->variableAccessData()->prediction()), "\n"); #endif } for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block) continue; if (!block->isOSRTarget) continue; if (block->bytecodeBegin != m_graph.m_osrEntryBytecodeIndex) continue; for (size_t i = 0; i < m_graph.m_mustHandleValues.size(); ++i) { Node* node = block->variablesAtHead.operand( m_graph.m_mustHandleValues.operandForIndex(i)); if (!node) continue; ASSERT(node->hasLocal()); node->variableAccessData()->predict( speculationFromValue(m_graph.m_mustHandleValues[i])); } } return true; }
void AbstractValue::set(Graph& graph, JSValue value) { if (!!value && value.isCell()) { m_currentKnownStructure.makeTop(); Structure* structure = value.asCell()->structure(); setFuturePossibleStructure(graph, structure); m_arrayModes = asArrayModes(structure->indexingType()); clobberArrayModes(); } else { m_currentKnownStructure.clear(); m_futurePossibleStructure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value); if (m_type == SpecInt52AsDouble) m_type = SpecInt52; m_value = value; checkConsistency(); }
bool run() { ASSERT(m_graph.m_form == ThreadedCPS); ASSERT(m_graph.m_unificationState == GloballyUnified); ASSERT(codeBlock()->numParameters() >= 1); { ConcurrentJITLocker locker(profiledBlock()->m_lock); for (size_t arg = 0; arg < static_cast<size_t>(codeBlock()->numParameters()); ++arg) { ValueProfile* profile = profiledBlock()->valueProfileForArgument(arg); if (!profile) continue; m_graph.m_arguments[arg]->variableAccessData()->predict( profile->computeUpdatedPrediction(locker)); } } for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; if (!block->isOSRTarget) continue; if (block->bytecodeBegin != m_graph.m_plan.osrEntryBytecodeIndex) continue; for (size_t i = 0; i < m_graph.m_plan.mustHandleValues.size(); ++i) { int operand = m_graph.m_plan.mustHandleValues.operandForIndex(i); Node* node = block->variablesAtHead.operand(operand); if (!node) continue; ASSERT(node->hasLocal(m_graph)); node->variableAccessData()->predict( speculationFromValue(m_graph.m_plan.mustHandleValues[i])); } } return true; }
void AbstractValue::checkConsistency() const { if (!(m_type & SpecCell)) { ASSERT(m_structure.isClear()); ASSERT(!m_arrayModes); } if (isClear()) ASSERT(!m_value); if (!!m_value) { SpeculatedType type = m_type; // This relaxes the assertion below a bit, since we don't know the representation of the // node. if (type & SpecInt52) type |= SpecInt52AsDouble; ASSERT(mergeSpeculations(type, speculationFromValue(m_value)) == type); } // Note that it's possible for a prediction like (Final, []). This really means that // the value is bottom and that any code that uses the value is unreachable. But // we don't want to get pedantic about this as it would only increase the computational // complexity of the code. }
void propagate(Node& node) { if (!node.shouldGenerate()) return; NodeType op = node.op(); NodeFlags flags = node.flags() & NodeBackPropMask; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags)); #endif bool changed = false; switch (op) { case JSConstant: case WeakJSConstant: { changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(m_compileIndex))); break; } case GetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); SpeculatedType prediction = variableAccessData->prediction(); if (prediction) changed |= mergePrediction(prediction); changed |= variableAccessData->mergeFlags(flags); break; } case SetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); changed |= variableAccessData->predict(m_graph[node.child1()].prediction()); changed |= m_graph[node.child1()].mergeFlags(variableAccessData->flags()); break; } case Flush: { // Make sure that the analysis knows that flushed locals escape. VariableAccessData* variableAccessData = node.variableAccessData(); changed |= variableAccessData->mergeFlags(NodeUsedAsValue); break; } case BitAnd: case BitOr: case BitXor: case BitRShift: case BitLShift: case BitURShift: { changed |= setPrediction(SpecInt32); flags |= NodeUsedAsInt; flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero); changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ValueToInt32: { changed |= setPrediction(SpecInt32); flags |= NodeUsedAsInt; flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero); changed |= m_graph[node.child1()].mergeFlags(flags); break; } case ArrayPop: { changed |= mergePrediction(node.getHeapPrediction()); changed |= mergeDefaultFlags(node); break; } case ArrayPush: { changed |= mergePrediction(node.getHeapPrediction()); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue); break; } case RegExpExec: case RegExpTest: { changed |= mergePrediction(node.getHeapPrediction()); changed |= mergeDefaultFlags(node); break; } case StringCharCodeAt: { changed |= mergePrediction(SpecInt32); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case ArithMod: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(SpecDouble); } flags |= NodeUsedAsValue; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case UInt32ToNumber: { if (nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(SpecNumber); changed |= m_graph[node.child1()].mergeFlags(flags); break; } case ValueAdd: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (isNumberSpeculation(left) && isNumberSpeculation(right)) { if (m_graph.addShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } else if (!(left & SpecNumber) || !(right & SpecNumber)) { // left or right is definitely something other than a number. changed |= mergePrediction(SpecString); } else changed |= mergePrediction(SpecString | SpecInt32 | SpecDouble); } if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithAdd: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.addShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithSub: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.addShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } if (isNotZero(node.child1().index()) || isNotZero(node.child2().index())) flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithNegate: if (m_graph[node.child1()].prediction()) { if (m_graph.negateShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPrediction(m_graph[node.child1()].prediction())); } changed |= m_graph[node.child1()].mergeFlags(flags); break; case ArithMin: case ArithMax: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } flags |= NodeUsedAsNumber; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithMul: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.mulShouldSpeculateInteger(node)) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } // As soon as a multiply happens, we can easily end up in the part // of the double domain where the point at which you do truncation // can change the outcome. So, ArithMul always checks for overflow // no matter what, and always forces its inputs to check as well. flags |= NodeUsedAsNumber | NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithDiv: { SpeculatedType left = m_graph[node.child1()].prediction(); SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(SpecDouble); } // As soon as a multiply happens, we can easily end up in the part // of the double domain where the point at which you do truncation // can change the outcome. So, ArithMul always checks for overflow // no matter what, and always forces its inputs to check as well. flags |= NodeUsedAsNumber | NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithSqrt: { changed |= setPrediction(SpecDouble); changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue); break; } case ArithAbs: { SpeculatedType child = m_graph[node.child1()].prediction(); if (nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(child); else changed |= setPrediction(speculatedDoubleTypeForPrediction(child)); flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); break; } case LogicalNot: case CompareLess: case CompareLessEq: case CompareGreater: case CompareGreaterEq: case CompareEq: case CompareStrictEq: case InstanceOf: case IsUndefined: case IsBoolean: case IsNumber: case IsString: case IsObject: case IsFunction: { changed |= setPrediction(SpecBoolean); changed |= mergeDefaultFlags(node); break; } case GetById: { changed |= mergePrediction(node.getHeapPrediction()); changed |= mergeDefaultFlags(node); break; } case GetByIdFlush: changed |= mergePrediction(node.getHeapPrediction()); changed |= mergeDefaultFlags(node); break; case GetByVal: { if (m_graph[node.child1()].shouldSpeculateFloat32Array() || m_graph[node.child1()].shouldSpeculateFloat64Array()) changed |= mergePrediction(SpecDouble); else changed |= mergePrediction(node.getHeapPrediction()); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case GetMyArgumentByValSafe: { changed |= mergePrediction(node.getHeapPrediction()); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case GetMyArgumentsLengthSafe: { changed |= setPrediction(SpecInt32); break; } case GetScopeRegisters: case GetButterfly: case GetIndexedPropertyStorage: case AllocatePropertyStorage: case ReallocatePropertyStorage: { changed |= setPrediction(SpecOther); changed |= mergeDefaultFlags(node); break; } case GetByOffset: { changed |= mergePrediction(node.getHeapPrediction()); changed |= mergeDefaultFlags(node); break; } case Call: case Construct: { changed |= mergePrediction(node.getHeapPrediction()); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) { Edge edge = m_graph.m_varArgChildren[childIdx]; changed |= m_graph[edge].mergeFlags(NodeUsedAsValue); } break; } case ConvertThis: { SpeculatedType prediction = m_graph[node.child1()].prediction(); if (prediction) { if (prediction & ~SpecObjectMask) { prediction &= SpecObjectMask; prediction = mergeSpeculations(prediction, SpecObjectOther); } changed |= mergePrediction(prediction); } changed |= mergeDefaultFlags(node); break; } case GetGlobalVar: { changed |= mergePrediction(node.getHeapPrediction()); break; } case PutGlobalVar: case PutGlobalVarCheck: { changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); break; } case GetScopedVar: case Resolve: case ResolveBase: case ResolveBaseStrictPut: case ResolveGlobal: { SpeculatedType prediction = node.getHeapPrediction(); changed |= mergePrediction(prediction); break; } case GetScope: { changed |= setPrediction(SpecCellOther); break; } case GetCallee: { changed |= setPrediction(SpecFunction); break; } case CreateThis: case NewObject: { changed |= setPrediction(SpecFinalObject); changed |= mergeDefaultFlags(node); break; } case NewArray: { changed |= setPrediction(SpecArray); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) { Edge edge = m_graph.m_varArgChildren[childIdx]; changed |= m_graph[edge].mergeFlags(NodeUsedAsValue); } break; } case NewArrayWithSize: { changed |= setPrediction(SpecArray); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case NewArrayBuffer: { changed |= setPrediction(SpecArray); break; } case NewRegexp: { changed |= setPrediction(SpecObjectOther); break; } case StringCharAt: { changed |= setPrediction(SpecString); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case StrCat: { changed |= setPrediction(SpecString); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber); break; } case ToPrimitive: { SpeculatedType child = m_graph[node.child1()].prediction(); if (child) { if (isObjectSpeculation(child)) { // I'd love to fold this case into the case below, but I can't, because // removing SpecObjectMask from something that only has an object // prediction and nothing else means we have an ill-formed SpeculatedType // (strong predict-none). This should be killed once we remove all traces // of static (aka weak) predictions. changed |= mergePrediction(SpecString); } else if (child & SpecObjectMask) { // Objects get turned into strings. So if the input has hints of objectness, // the output will have hinsts of stringiness. changed |= mergePrediction( mergeSpeculations(child & ~SpecObjectMask, SpecString)); } else changed |= mergePrediction(child); } changed |= m_graph[node.child1()].mergeFlags(flags); break; } case CreateActivation: { changed |= setPrediction(SpecObjectOther); break; } case CreateArguments: { // At this stage we don't try to predict whether the arguments are ours or // someone else's. We could, but we don't, yet. changed |= setPrediction(SpecArguments); break; } case NewFunction: case NewFunctionNoCheck: case NewFunctionExpression: { changed |= setPrediction(SpecFunction); break; } case PutByValAlias: case GetArrayLength: case Int32ToDouble: case DoubleAsInt32: case GetLocalUnlinked: case GetMyArgumentsLength: case GetMyArgumentByVal: case PhantomPutStructure: case PhantomArguments: case CheckArray: case Arrayify: { // This node should never be visible at this stage of compilation. It is // inserted by fixup(), which follows this phase. ASSERT_NOT_REACHED(); break; } case PutByVal: changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue); changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue); break; case PutScopedVar: case Return: case Throw: changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); break; case PutById: case PutByIdDirect: changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue); break; case PutByOffset: changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue); break; case Phi: break; #ifndef NDEBUG // These get ignored because they don't return anything. case DFG::Jump: case Branch: case Breakpoint: case CheckHasInstance: case ThrowReferenceError: case ForceOSRExit: case SetArgument: case CheckStructure: case ForwardCheckStructure: case StructureTransitionWatchpoint: case ForwardStructureTransitionWatchpoint: case CheckFunction: case PutStructure: case TearOffActivation: case TearOffArguments: case CheckNumber: case CheckArgumentsNotCreated: case GlobalVarWatchpoint: case GarbageValue: changed |= mergeDefaultFlags(node); break; // These gets ignored because it doesn't do anything. case Phantom: case InlineStart: case Nop: break; case LastNodeType: ASSERT_NOT_REACHED(); break; #else default: changed |= mergeDefaultFlags(node); break; #endif } #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog("%s\n", speculationToString(m_graph[m_compileIndex].prediction())); #endif m_changed |= changed; }