void print_var() { curr_tok = yylex(); if ( curr_tok != ID ) throw "Must be identifier"; AbstractValue *val = globalValueTable->value((*globalLexTable)[yylval].text); if ( val ) std::cout << val->toString() << std::endl; }
bool AbstractValue::isType(Graph& graph, const InferredType::Descriptor& inferredType) const { AbstractValue typeValue; typeValue.set(graph, inferredType); AbstractValue mergedValue = *this; mergedValue.merge(typeValue); return mergedValue == typeValue; }
inline bool InPlaceAbstractState::mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, Node* destinationNode, Node* sourceNode) { if (!destinationNode) return false; ASSERT_UNUSED(sourceNode, sourceNode); // FIXME: We could do some sparse conditional propagation here! return destination.merge(source); }
bool foldConstants(BasicBlock* block) { bool changed = false; m_state.beginBasicBlock(block); for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { if (!m_state.isValid()) break; Node* node = block->at(indexInBlock); bool eliminated = false; switch (node->op()) { case BooleanToNumber: { if (node->child1().useKind() == UntypedUse && !m_interpreter.needsTypeCheck(node->child1(), SpecBoolean)) node->child1().setUseKind(BooleanUse); break; } case CheckArgumentsNotCreated: { if (!isEmptySpeculation( m_state.variables().operand( m_graph.argumentsRegisterFor(node->origin.semantic)).m_type)) break; node->convertToPhantom(); eliminated = true; break; } case CheckStructure: case ArrayifyToStructure: { AbstractValue& value = m_state.forNode(node->child1()); StructureSet set; if (node->op() == ArrayifyToStructure) set = node->structure(); else set = node->structureSet(); if (value.m_currentKnownStructure.isSubsetOf(set)) { m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell. node->convertToPhantom(); eliminated = true; break; } StructureAbstractValue& structureValue = value.m_futurePossibleStructure; if (structureValue.isSubsetOf(set) && structureValue.hasSingleton()) { Structure* structure = structureValue.singleton(); m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell. AdjacencyList children = node->children; children.removeEdge(0); if (!!children.child1()) m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->origin, children); node->children.setChild2(Edge()); node->children.setChild3(Edge()); node->convertToStructureTransitionWatchpoint(structure); eliminated = true; break; } break; } case CheckArray: case Arrayify: { if (!node->arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node->child1()))) break; node->convertToPhantom(); eliminated = true; break; } case CheckFunction: { if (m_state.forNode(node->child1()).value() != node->function()) break; node->convertToPhantom(); eliminated = true; break; } case CheckInBounds: { JSValue left = m_state.forNode(node->child1()).value(); JSValue right = m_state.forNode(node->child2()).value(); if (left && right && left.isInt32() && right.isInt32() && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) { node->convertToPhantom(); eliminated = true; break; } break; } case MultiGetByOffset: { Edge childEdge = node->child1(); Node* child = childEdge.node(); MultiGetByOffsetData& data = node->multiGetByOffsetData(); Structure* structure = m_state.forNode(child).bestProvenStructure(); if (!structure) break; for (unsigned i = data.variants.size(); i--;) { const GetByIdVariant& variant = data.variants[i]; if (!variant.structureSet().contains(structure)) continue; if (variant.chain()) break; emitGetByOffset(indexInBlock, node, structure, variant, data.identifierNumber); eliminated = true; break; } break; } case MultiPutByOffset: { Edge childEdge = node->child1(); Node* child = childEdge.node(); MultiPutByOffsetData& data = node->multiPutByOffsetData(); Structure* structure = m_state.forNode(child).bestProvenStructure(); if (!structure) break; for (unsigned i = data.variants.size(); i--;) { const PutByIdVariant& variant = data.variants[i]; if (variant.oldStructure() != structure) continue; emitPutByOffset(indexInBlock, node, structure, variant, data.identifierNumber); eliminated = true; break; } break; } case GetById: case GetByIdFlush: { Edge childEdge = node->child1(); Node* child = childEdge.node(); unsigned identifierNumber = node->identifierNumber(); if (childEdge.useKind() != CellUse) break; Structure* structure = m_state.forNode(child).bestProvenStructure(); if (!structure) break; GetByIdStatus status = GetByIdStatus::computeFor( vm(), structure, m_graph.identifiers()[identifierNumber]); if (!status.isSimple() || status.numVariants() != 1) { // FIXME: We could handle prototype cases. // https://bugs.webkit.org/show_bug.cgi?id=110386 break; } emitGetByOffset(indexInBlock, node, structure, status[0], identifierNumber); eliminated = true; break; } case PutById: case PutByIdDirect: { NodeOrigin origin = node->origin; Edge childEdge = node->child1(); Node* child = childEdge.node(); unsigned identifierNumber = node->identifierNumber(); ASSERT(childEdge.useKind() == CellUse); Structure* structure = m_state.forNode(child).bestProvenStructure(); if (!structure) break; PutByIdStatus status = PutByIdStatus::computeFor( vm(), m_graph.globalObjectFor(origin.semantic), structure, m_graph.identifiers()[identifierNumber], node->op() == PutByIdDirect); if (!status.isSimple()) break; if (status.numVariants() != 1) break; emitPutByOffset(indexInBlock, node, structure, status[0], identifierNumber); eliminated = true; break; } case ToPrimitive: { if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString)) break; node->convertToIdentity(); break; } default: break; } if (eliminated) { changed = true; continue; } m_interpreter.execute(indexInBlock); if (!m_state.isValid()) { // If we invalidated then we shouldn't attempt to constant-fold. Here's an // example: // // c: JSConstant(4.2) // x: ValueToInt32(Check:Int32:@const) // // It would be correct for an analysis to assume that execution cannot // proceed past @x. Therefore, constant-folding @x could be rather bad. But, // the CFA may report that it found a constant even though it also reported // that everything has been invalidated. This will only happen in a couple of // the constant folding cases; most of them are also separately defensive // about such things. break; } if (!node->shouldGenerate() || m_state.didClobber() || node->hasConstant()) continue; JSValue value = m_state.forNode(node).value(); if (!value) continue; // Check if merging the abstract value of the constant into the abstract value // we've proven for this node wouldn't widen the proof. If it widens the proof // (i.e. says that the set contains more things in it than it previously did) // then we refuse to fold. AbstractValue oldValue = m_state.forNode(node); AbstractValue constantValue; constantValue.set(m_graph, value); constantValue.fixTypeForRepresentation(node); if (oldValue.merge(constantValue)) continue; NodeOrigin origin = node->origin; AdjacencyList children = node->children; if (node->op() == GetLocal) m_graph.dethread(); else ASSERT(!node->hasVariableAccessData(m_graph)); m_graph.convertToConstant(node, value); m_insertionSet.insertNode( indexInBlock, SpecNone, Phantom, origin, children); changed = true; } m_state.reset(); m_insertionSet.execute(block); return changed; }
bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node) { if (!node) return false; AbstractValue source; if (node->variableAccessData()->isCaptured()) { // If it's captured then we know that whatever value was stored into the variable last is the // one we care about. This is true even if the variable at tail is dead, which might happen if // the last thing we did to the variable was a GetLocal and then ended up now using the // GetLocal's result. source = inVariable; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Transfering "); source.dump(WTF::dataFile()); dataLogF(" from last access due to captured variable.\n"); #endif } else { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" It's live, node @%u.\n", node->index()); #endif switch (node->op()) { case Phi: case SetArgument: case PhantomLocal: case Flush: // The block transfers the value from head to tail. source = inVariable; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Transfering "); source.dump(WTF::dataFile()); dataLogF(" from head to tail.\n"); #endif break; case GetLocal: // The block refines the value with additional speculations. source = forNode(node); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Refining to "); source.dump(WTF::dataFile()); dataLogF("\n"); #endif break; case SetLocal: // The block sets the variable, and potentially refines it, both // before and after setting it. if (node->variableAccessData()->shouldUseDoubleFormat()) { // FIXME: This unnecessarily loses precision. source.setType(SpecDouble); } else source = forNode(node->child1()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Setting to "); source.dump(WTF::dataFile()); dataLogF("\n"); #endif break; default: RELEASE_ASSERT_NOT_REACHED(); break; } } if (destination == source) { // Abstract execution did not change the output value of the variable, for this // basic block, on this iteration. #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Not changed!\n"); #endif return false; } // Abstract execution reached a new conclusion about the speculations reached about // this variable after execution of this basic block. Update the state, and return // true to indicate that the fixpoint must go on! destination = source; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Changed!\n"); #endif return true; }
void InPlaceAbstractState::initialize() { BasicBlock* root = m_graph.block(0); root->cfaShouldRevisit = true; root->cfaHasVisited = false; root->cfaFoundConstants = false; for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) { root->valuesAtTail.argument(i).clear(); if (m_graph.m_form == SSA) { root->valuesAtHead.argument(i).makeTop(); continue; } Node* node = root->variablesAtHead.argument(i); ASSERT(node->op() == SetArgument); if (!node->variableAccessData()->shouldUnboxIfPossible()) { root->valuesAtHead.argument(i).makeTop(); continue; } SpeculatedType prediction = node->variableAccessData()->argumentAwarePrediction(); if (isInt32Speculation(prediction)) root->valuesAtHead.argument(i).setType(SpecInt32); else if (isBooleanSpeculation(prediction)) root->valuesAtHead.argument(i).setType(SpecBoolean); else if (isCellSpeculation(prediction)) root->valuesAtHead.argument(i).setType(SpecCell); else root->valuesAtHead.argument(i).makeTop(); } for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) { Node* node = root->variablesAtHead.local(i); if (node && node->variableAccessData()->isCaptured()) root->valuesAtHead.local(i).makeTop(); else root->valuesAtHead.local(i).clear(); root->valuesAtTail.local(i).clear(); } for (BlockIndex blockIndex = 1 ; blockIndex < m_graph.numBlocks(); ++blockIndex) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; ASSERT(block->isReachable); block->cfaShouldRevisit = false; block->cfaHasVisited = false; block->cfaFoundConstants = false; for (size_t i = 0; i < block->valuesAtHead.numberOfArguments(); ++i) { block->valuesAtHead.argument(i).clear(); block->valuesAtTail.argument(i).clear(); } for (size_t i = 0; i < block->valuesAtHead.numberOfLocals(); ++i) { block->valuesAtHead.local(i).clear(); block->valuesAtTail.local(i).clear(); } 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) { AbstractValue value; value.setMostSpecific(m_graph, m_graph.m_plan.mustHandleValues[i]); int operand = m_graph.m_plan.mustHandleValues.operandForIndex(i); block->valuesAtHead.operand(operand).merge(value); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF(" Initializing Block #%u, operand r%d, to ", blockIndex, operand); block->valuesAtHead.operand(operand).dump(WTF::dataFile()); dataLogF("\n"); #endif } block->cfaShouldRevisit = true; } if (m_graph.m_form == SSA) { for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; setLiveValues(block->ssa->valuesAtHead, block->ssa->liveAtHead); setLiveValues(block->ssa->valuesAtTail, block->ssa->liveAtTail); } } }
boost::shared_ptr<AbstractValue> prim(bool get) { boost::shared_ptr<AbstractValue> result; if ( get ) curr_tok = yylex(); switch ( curr_tok ) { case INT: { int32_t num; if ( !str2int32(num, (*globalLexTable)[yylval].text) ) throw "Error int convertion"; AbstractType* type = globalTypeTable->prototype("int"); result = boost::shared_ptr<AbstractValue>(type->create()); (( NumberValue<int32_t, VINT32>*)result.get())->setValue(num); curr_tok = yylex(); } break; case DOUBLE: { double num; if ( !str2double(num, (*globalLexTable)[yylval].text) ) throw "Error double convertion"; AbstractType* type = globalTypeTable->prototype("float"); result = boost::shared_ptr<AbstractValue>(type->create()); (( NumberValue<double, VDOUBLE>*)result.get())->setValue(num); curr_tok = yylex(); } break; case STRING: { AbstractType* type = globalTypeTable->prototype("string"); result = boost::shared_ptr<AbstractValue>(type->create()); ((StringValue*)result.get())->setValue((*globalLexTable)[yylval].text); } break; case ID: { std::string id = (*globalLexTable)[yylval].text; if ( !globalValueTable->exists(id) ) throw "Undefined identifier"; AbstractValue* value = globalValueTable->value(id); if (( curr_tok = yylex()) == ASSIGNMENT ) { boost::shared_ptr<AbstractValue> val = expr(true); AbstractMethod* method = value->getMethod("operator="); method->setParam(1, value); method->setParam(2, val.get()); result = (*method)(); } else result = value->clone(); } break; case MINUS: { result = prim(true); AbstractMethod* method = result.get()->getMethod("operator-u"); method->setParam(1, result.get()); result = (*method)(); } break; case LP: result = expr(true); if ( curr_tok != RP ) throw "Expected ')'"; curr_tok = yylex(); break; default: throw "Primary expected"; } return result; }
FiltrationResult AbstractValue::filter(Graph& graph, const InferredType::Descriptor& descriptor) { AbstractValue filterValue; filterValue.set(graph, descriptor); return filter(filterValue); }