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; }
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; }
FiltrationResult AbstractValue::filter(Graph& graph, const InferredType::Descriptor& descriptor) { AbstractValue filterValue; filterValue.set(graph, descriptor); return filter(filterValue); }