Revert "[turbofan] Load elimination prunes control flow based on instance type."
This reverts commit 71bcc1d960
.
Reason for revert: Regresses Octane/Box2D, among other things.
Original change's description:
> [turbofan] Load elimination prunes control flow based on instance type.
>
> Changes:
> - introduce the notion of unreachable abstract states.
>
> - reconnect unreachables states to runtime abort in effect phis (so that
> the merged states are not polluted by unreachable branches while
> preserving SSA).
>
> - mark states with failed map checks, unreachable map guars as unreachable.
>
> - add instance type to AbstractMaps, only invalidate instance type on
> mismatched effect merges.
>
>
> This results in 2-3% improvement on ARES/ML steady state.
>
> Bug: v8:6396
> Change-Id: I35b0d4482fa400ba7ee9a754f8ef1b2663ebc7dc
> Reviewed-on: https://chromium-review.googlesource.com/727761
> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#48742}
TBR=jarin@chromium.org,bmeurer@chromium.org
Change-Id: I6302b37dbf5ea781c64815ef1900681531ad7d71
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6396
Reviewed-on: https://chromium-review.googlesource.com/728440
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48763}
This commit is contained in:
parent
ff8b937ff0
commit
8f09a7511e
@ -141,7 +141,6 @@ namespace internal {
|
||||
V(kUnexpectedReturnFromFrameDropper, \
|
||||
"Unexpectedly returned from dropping frames") \
|
||||
V(kUnexpectedReturnFromThrow, "Unexpectedly returned from a throw") \
|
||||
V(kUnreachableCodeReached, "Reached unreachable code") \
|
||||
V(kVariableResolvedToWithContext, "Variable resolved to with context") \
|
||||
V(kWithStatement, "WithStatement") \
|
||||
V(kWrongFunctionContext, "Wrong context passed to function") \
|
||||
|
@ -297,6 +297,11 @@ RegionObservability RegionObservabilityOf(Operator const* op) {
|
||||
return OpParameter<RegionObservability>(op);
|
||||
}
|
||||
|
||||
ZoneHandleSet<Map> MapGuardMapsOf(Operator const* op) {
|
||||
DCHECK_EQ(IrOpcode::kMapGuard, op->opcode());
|
||||
return OpParameter<ZoneHandleSet<Map>>(op);
|
||||
}
|
||||
|
||||
Type* TypeGuardTypeOf(Operator const* op) {
|
||||
DCHECK_EQ(IrOpcode::kTypeGuard, op->opcode());
|
||||
return OpParameter<Type*>(op);
|
||||
@ -1125,6 +1130,14 @@ const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep,
|
||||
rep); // parameter
|
||||
}
|
||||
|
||||
const Operator* CommonOperatorBuilder::MapGuard(ZoneHandleSet<Map> maps) {
|
||||
return new (zone()) Operator1<ZoneHandleSet<Map>>( // --
|
||||
IrOpcode::kMapGuard, Operator::kEliminatable, // opcode
|
||||
"MapGuard", // name
|
||||
1, 1, 1, 0, 1, 0, // counts
|
||||
maps); // parameter
|
||||
}
|
||||
|
||||
const Operator* CommonOperatorBuilder::TypeGuard(Type* type) {
|
||||
return new (zone()) Operator1<Type*>( // --
|
||||
IrOpcode::kTypeGuard, Operator::kPure, // opcode
|
||||
|
@ -304,6 +304,8 @@ RegionObservability RegionObservabilityOf(Operator const*) WARN_UNUSED_RESULT;
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const ZoneVector<MachineType>* types);
|
||||
|
||||
ZoneHandleSet<Map> MapGuardMapsOf(Operator const*) WARN_UNUSED_RESULT;
|
||||
|
||||
Type* TypeGuardTypeOf(Operator const*) WARN_UNUSED_RESULT;
|
||||
|
||||
int OsrValueIndexOf(Operator const*);
|
||||
@ -417,6 +419,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
|
||||
const Operator* TailCall(const CallDescriptor* descriptor);
|
||||
const Operator* Projection(size_t index);
|
||||
const Operator* Retain();
|
||||
const Operator* MapGuard(ZoneHandleSet<Map> maps);
|
||||
const Operator* TypeGuard(Type* type);
|
||||
|
||||
// Constructs a new merge or phi operator with the same opcode as {op}, but
|
||||
|
@ -1330,7 +1330,7 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerCompareMaps(Node* node) {
|
||||
ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op()).maps();
|
||||
ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op());
|
||||
size_t const map_count = maps.size();
|
||||
Node* value = node->InputAt(0);
|
||||
|
||||
|
@ -661,8 +661,8 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
|
||||
if (Node* map = current->Get(map_field)) {
|
||||
Type* const map_type = NodeProperties::GetType(map);
|
||||
if (map_type->IsHeapConstant() &&
|
||||
params.maps().contains(
|
||||
bit_cast<Handle<Map>>(map_type->AsHeapConstant()->Value()))) {
|
||||
params.maps().contains(ZoneHandleSet<Map>(bit_cast<Handle<Map>>(
|
||||
map_type->AsHeapConstant()->Value())))) {
|
||||
current->MarkForDeletion();
|
||||
break;
|
||||
}
|
||||
@ -683,7 +683,7 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
|
||||
vobject->FieldAt(HeapObject::kMapOffset).To(&map_field)) {
|
||||
if (Node* object_map = current->Get(map_field)) {
|
||||
current->SetReplacement(LowerCompareMapsWithoutLoad(
|
||||
object_map, CompareMapsParametersOf(op).maps(), jsgraph));
|
||||
object_map, CompareMapsParametersOf(op), jsgraph));
|
||||
break;
|
||||
} else {
|
||||
// If the variable has no value, we have not reached the fixed-point
|
||||
|
@ -840,7 +840,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
for (auto receiver_map : receiver_maps) {
|
||||
maps.insert(receiver_map, graph()->zone());
|
||||
}
|
||||
this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
|
||||
this_effect = graph()->NewNode(common()->MapGuard(maps), receiver,
|
||||
this_effect, this_control);
|
||||
}
|
||||
}
|
||||
@ -1196,7 +1196,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
this_control = graph()->NewNode(common()->IfTrue(), branch);
|
||||
|
||||
// Introduce a MapGuard to learn from this on the effect chain.
|
||||
this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
|
||||
this_effect = graph()->NewNode(common()->MapGuard(maps), receiver,
|
||||
this_effect, this_control);
|
||||
}
|
||||
|
||||
|
@ -373,20 +373,9 @@ void LoadElimination::AbstractField::Print() const {
|
||||
|
||||
bool LoadElimination::AbstractMaps::Lookup(
|
||||
Node* object, ZoneHandleSet<Map>* object_maps) const {
|
||||
for (auto pair : info_for_node_) {
|
||||
if (MustAlias(object, pair.first) && pair.second.maps_valid()) {
|
||||
*object_maps = pair.second.maps();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LoadElimination::AbstractMaps::Lookup(Node* object,
|
||||
AbstractMapInfo* maps_info) const {
|
||||
for (auto pair : info_for_node_) {
|
||||
if (MustAlias(object, pair.first)) {
|
||||
*maps_info = pair.second;
|
||||
*object_maps = pair.second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -396,18 +385,10 @@ bool LoadElimination::AbstractMaps::Lookup(Node* object,
|
||||
LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill(
|
||||
const AliasStateInfo& alias_info, Zone* zone) const {
|
||||
for (auto pair : this->info_for_node_) {
|
||||
if (alias_info.MayAlias(pair.first) && pair.second.maps_valid()) {
|
||||
if (alias_info.MayAlias(pair.first)) {
|
||||
AbstractMaps* that = new (zone) AbstractMaps(zone);
|
||||
for (auto pair : this->info_for_node_) {
|
||||
if (!alias_info.MayAlias(pair.first)) {
|
||||
// Keep the elements that cannto alias.
|
||||
that->info_for_node_.insert(pair);
|
||||
} else if (pair.second.instance_type_valid()) {
|
||||
// Instance type information cannot be invalidated, so we just
|
||||
// throw away the map part.
|
||||
that->info_for_node_.insert(std::make_pair(
|
||||
pair.first, AbstractMapInfo(pair.second.instance_type())));
|
||||
}
|
||||
if (!alias_info.MayAlias(pair.first)) that->info_for_node_.insert(pair);
|
||||
}
|
||||
return that;
|
||||
}
|
||||
@ -415,137 +396,36 @@ LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill(
|
||||
return this;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMapInfo::AbstractMapInfo()
|
||||
: instance_type_(FIRST_TYPE), info_validity_(0) {}
|
||||
|
||||
LoadElimination::AbstractMapInfo::AbstractMapInfo(
|
||||
ZoneHandleSet<Map> const& maps)
|
||||
: maps_(maps), instance_type_(FIRST_TYPE), info_validity_(kMapsValid) {
|
||||
DCHECK(!maps.is_empty());
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMapInfo::AbstractMapInfo(InstanceType instance_type)
|
||||
: instance_type_(instance_type), info_validity_(kInstanceTypeValid) {}
|
||||
|
||||
LoadElimination::AbstractMapInfo::AbstractMapInfo(MapsParameterInfo const& info)
|
||||
: maps_(info.maps()),
|
||||
instance_type_(FIRST_TYPE),
|
||||
info_validity_(kMapsValid) {
|
||||
InstanceType instance_type;
|
||||
if (info.instance_type().To(&instance_type)) {
|
||||
instance_type_ = instance_type;
|
||||
info_validity_ |= kInstanceTypeValid;
|
||||
}
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMapInfo::AbstractMapInfo(
|
||||
ZoneHandleSet<Map> const& maps, InstanceType instance_type,
|
||||
Validity validity)
|
||||
: maps_(maps), instance_type_(instance_type), info_validity_(validity) {}
|
||||
|
||||
bool LoadElimination::AbstractMapInfo::operator==(
|
||||
AbstractMapInfo const& other) const {
|
||||
return info_validity_ == other.info_validity_ &&
|
||||
instance_type_ == other.instance_type_ && maps_ == other.maps_;
|
||||
}
|
||||
|
||||
bool LoadElimination::AbstractMapInfo::operator!=(
|
||||
AbstractMapInfo const& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
ZoneHandleSet<Map> const& LoadElimination::AbstractMapInfo::maps() const {
|
||||
DCHECK(info_validity_ & kMapsValid);
|
||||
return maps_;
|
||||
}
|
||||
|
||||
InstanceType LoadElimination::AbstractMapInfo::instance_type() const {
|
||||
DCHECK(info_validity_ & kInstanceTypeValid);
|
||||
return instance_type_;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMapInfo LoadElimination::AbstractMapInfo::Merge(
|
||||
AbstractMapInfo const& other) const {
|
||||
// Merge the map information and the instance type information.
|
||||
Validity validity = info_validity_ & other.info_validity_;
|
||||
ZoneHandleSet<Map> merged_maps;
|
||||
InstanceType merged_instance_type = FIRST_TYPE;
|
||||
if ((validity & kInstanceTypeValid) &&
|
||||
instance_type() == other.instance_type()) {
|
||||
merged_instance_type = instance_type_;
|
||||
} else {
|
||||
validity &= ~Validity(kInstanceTypeValid);
|
||||
}
|
||||
if ((validity & kMapsValid) && maps() == other.maps()) {
|
||||
merged_maps = maps_;
|
||||
} else {
|
||||
validity &= ~Validity(kMapsValid);
|
||||
}
|
||||
return AbstractMapInfo(merged_maps, merged_instance_type, validity);
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Merge(
|
||||
AbstractMaps const* that, Zone* zone) const {
|
||||
if (this->Equals(that)) return this;
|
||||
AbstractMaps* copy = new (zone) AbstractMaps(zone);
|
||||
for (auto this_it : this->info_for_node_) {
|
||||
Node* this_object = this_it.first;
|
||||
AbstractMapInfo const& this_maps_info = this_it.second;
|
||||
ZoneHandleSet<Map> this_maps = this_it.second;
|
||||
auto that_it = that->info_for_node_.find(this_object);
|
||||
if (that_it == that->info_for_node_.end()) continue;
|
||||
AbstractMapInfo const& that_maps_info = that_it->second;
|
||||
|
||||
// Merge the map information and the instance type information.
|
||||
AbstractMapInfo merged = this_maps_info.Merge(that_maps_info);
|
||||
if (!merged.empty()) {
|
||||
copy->info_for_node_.insert({this_object, merged});
|
||||
if (that_it != that->info_for_node_.end() && that_it->second == this_maps) {
|
||||
copy->info_for_node_.insert(this_it);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Extend(
|
||||
Node* object, AbstractMapInfo const& map_info, Zone* zone) const {
|
||||
Node* object, ZoneHandleSet<Map> maps, Zone* zone) const {
|
||||
AbstractMaps* that = new (zone) AbstractMaps(zone);
|
||||
that->info_for_node_ = this->info_for_node_;
|
||||
that->info_for_node_[object] = map_info;
|
||||
that->info_for_node_.insert(std::make_pair(object, maps));
|
||||
return that;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractMaps const*
|
||||
LoadElimination::AbstractMaps::KillMutableState(Zone* zone) const {
|
||||
for (auto pair : this->info_for_node_) {
|
||||
if (pair.second.maps_valid()) {
|
||||
// We have the map part valid, so we have to invalidate.
|
||||
AbstractMaps* that = nullptr; // Allocated lazily.
|
||||
for (auto pair : this->info_for_node_) {
|
||||
if (pair.second.instance_type_valid()) {
|
||||
if (that == nullptr) {
|
||||
that = new (zone) AbstractMaps(zone);
|
||||
}
|
||||
that->info_for_node_.insert(std::make_pair(
|
||||
pair.first, AbstractMapInfo(pair.second.instance_type())));
|
||||
}
|
||||
}
|
||||
return that;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void LoadElimination::AbstractMaps::Print() const {
|
||||
for (auto pair : info_for_node_) {
|
||||
PrintF(" #%d:%s\n", pair.first->id(), pair.first->op()->mnemonic());
|
||||
OFStream os(stdout);
|
||||
os << " #" << pair.first->id() << ":" << pair.first->op()->mnemonic()
|
||||
<< std::endl;
|
||||
if (pair.second.maps_valid()) {
|
||||
ZoneHandleSet<Map> const& maps = pair.second.maps();
|
||||
for (size_t i = 0; i < maps.size(); ++i) {
|
||||
os << " - " << Brief(*maps.at(i)) << std::endl;
|
||||
}
|
||||
}
|
||||
if (pair.second.instance_type_valid()) {
|
||||
os << " Instance type: " << pair.second.instance_type() << std::endl;
|
||||
ZoneHandleSet<Map> const& maps = pair.second;
|
||||
for (size_t i = 0; i < maps.size(); ++i) {
|
||||
os << " - " << Brief(*maps[i]) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -620,34 +500,8 @@ Node* LoadElimination::AbstractState::LookupCheck(Node* node) const {
|
||||
return this->checks_ ? this->checks_->Lookup(node) : nullptr;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractState const*
|
||||
LoadElimination::AbstractState::KillMutableState(Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AbstractMaps const* new_maps =
|
||||
maps_ ? maps_->KillMutableState(zone) : nullptr;
|
||||
|
||||
// If the state is unchanged, just return the existing one.
|
||||
if (new_maps == maps_ && checks_ == nullptr && elements_ == nullptr) {
|
||||
bool all_fields_empty = true;
|
||||
for (size_t i = 0; i < arraysize(fields_); ++i) {
|
||||
if (fields_[i] != nullptr) {
|
||||
all_fields_empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_fields_empty) return this;
|
||||
}
|
||||
|
||||
AbstractState* new_state = new (zone) AbstractState();
|
||||
new_state->maps_ = new_maps;
|
||||
return new_state;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck(
|
||||
Node* node, Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AbstractState* that = new (zone) AbstractState(*this);
|
||||
if (that->checks_) {
|
||||
that->checks_ = that->checks_->Extend(node, zone);
|
||||
@ -662,35 +516,19 @@ bool LoadElimination::AbstractState::LookupMaps(
|
||||
return this->maps_ && this->maps_->Lookup(object, object_map);
|
||||
}
|
||||
|
||||
bool LoadElimination::AbstractState::LookupMaps(
|
||||
Node* object, AbstractMapInfo* map_info) const {
|
||||
return this->maps_ && this->maps_->Lookup(object, map_info);
|
||||
}
|
||||
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::AddMaps(
|
||||
Node* object, ZoneHandleSet<Map> maps, Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
AbstractMapInfo map_info(maps);
|
||||
return AddMaps(object, map_info, zone);
|
||||
}
|
||||
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::AddMaps(
|
||||
Node* object, AbstractMapInfo const& map_info, Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AbstractState* that = new (zone) AbstractState(*this);
|
||||
if (that->maps_) {
|
||||
that->maps_ = that->maps_->Extend(object, map_info, zone);
|
||||
that->maps_ = that->maps_->Extend(object, maps, zone);
|
||||
} else {
|
||||
that->maps_ = new (zone) AbstractMaps(object, map_info, zone);
|
||||
that->maps_ = new (zone) AbstractMaps(object, maps, zone);
|
||||
}
|
||||
return that;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
|
||||
const AliasStateInfo& alias_info, Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
if (this->maps_) {
|
||||
AbstractMaps const* that_maps = this->maps_->Kill(alias_info, zone);
|
||||
if (this->maps_ != that_maps) {
|
||||
@ -704,8 +542,6 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
|
||||
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
|
||||
Node* object, Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AliasStateInfo alias_info(this, object);
|
||||
return KillMaps(alias_info, zone);
|
||||
}
|
||||
@ -723,8 +559,6 @@ LoadElimination::AbstractState::AddElement(Node* object, Node* index,
|
||||
Node* value,
|
||||
MachineRepresentation representation,
|
||||
Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AbstractState* that = new (zone) AbstractState(*this);
|
||||
if (that->elements_) {
|
||||
that->elements_ =
|
||||
@ -739,8 +573,6 @@ LoadElimination::AbstractState::AddElement(Node* object, Node* index,
|
||||
LoadElimination::AbstractState const*
|
||||
LoadElimination::AbstractState::KillElement(Node* object, Node* index,
|
||||
Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
if (this->elements_) {
|
||||
AbstractElements const* that_elements =
|
||||
this->elements_->Kill(object, index, zone);
|
||||
@ -756,8 +588,6 @@ LoadElimination::AbstractState::KillElement(Node* object, Node* index,
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
|
||||
Node* object, size_t index, Node* value, MaybeHandle<Name> name,
|
||||
Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AbstractState* that = new (zone) AbstractState(*this);
|
||||
if (that->fields_[index]) {
|
||||
that->fields_[index] =
|
||||
@ -770,8 +600,6 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
|
||||
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
|
||||
Node* object, size_t index, MaybeHandle<Name> name, Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AliasStateInfo alias_info(this, object);
|
||||
return KillField(alias_info, index, name, zone);
|
||||
}
|
||||
@ -779,8 +607,6 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
|
||||
LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
|
||||
const AliasStateInfo& alias_info, size_t index, MaybeHandle<Name> name,
|
||||
Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
if (AbstractField const* this_field = this->fields_[index]) {
|
||||
this_field = this_field->Kill(alias_info, name, zone);
|
||||
if (this->fields_[index] != this_field) {
|
||||
@ -795,8 +621,6 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
|
||||
LoadElimination::AbstractState const*
|
||||
LoadElimination::AbstractState::KillFields(Node* object, MaybeHandle<Name> name,
|
||||
Zone* zone) const {
|
||||
if (is_unreachable()) return this;
|
||||
|
||||
AliasStateInfo alias_info(this, object);
|
||||
for (size_t i = 0;; ++i) {
|
||||
if (i == arraysize(fields_)) return this;
|
||||
@ -842,10 +666,6 @@ bool LoadElimination::AliasStateInfo::MayAlias(Node* other) const {
|
||||
}
|
||||
|
||||
void LoadElimination::AbstractState::Print() const {
|
||||
if (is_unreachable()) {
|
||||
PrintF(" Unreachable\n");
|
||||
}
|
||||
|
||||
if (checks_) {
|
||||
PrintF(" checks:\n");
|
||||
checks_->Print();
|
||||
@ -866,18 +686,6 @@ void LoadElimination::AbstractState::Print() const {
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
LoadElimination::AbstractState LoadElimination::AbstractState::Empty() {
|
||||
return AbstractState();
|
||||
}
|
||||
|
||||
// static
|
||||
LoadElimination::AbstractState LoadElimination::AbstractState::Unreachable() {
|
||||
AbstractState unreachable;
|
||||
unreachable.is_unreachable_ = true;
|
||||
return unreachable;
|
||||
}
|
||||
|
||||
LoadElimination::AbstractState const*
|
||||
LoadElimination::AbstractStateForEffectNodes::Get(Node* node) const {
|
||||
size_t const id = node->id();
|
||||
@ -904,112 +712,52 @@ Reduction LoadElimination::ReduceArrayBufferWasNeutered(Node* node) {
|
||||
return UpdateState(node, state);
|
||||
}
|
||||
|
||||
// static
|
||||
LoadElimination::MapSetComparisonResult LoadElimination::CompareMapSets(
|
||||
ZoneHandleSet<Map> const& lhs, ZoneHandleSet<Map> const& rhs) {
|
||||
DCHECK(!lhs.is_empty());
|
||||
DCHECK(!rhs.is_empty());
|
||||
|
||||
MapSetComparisonResult result = rhs.contains(lhs.at(0))
|
||||
? MapSetComparisonResult::kSubset
|
||||
: MapSetComparisonResult::kDisjoint;
|
||||
|
||||
for (size_t i = 1; i < lhs.size(); i++) {
|
||||
MapSetComparisonResult current = rhs.contains(lhs.at(i))
|
||||
? MapSetComparisonResult::kSubset
|
||||
: MapSetComparisonResult::kDisjoint;
|
||||
if (current != result) {
|
||||
return MapSetComparisonResult::kOther;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LoadElimination::MapSetComparisonResult
|
||||
LoadElimination::AbstractMapInfo::Compare(AbstractMapInfo const& other) const {
|
||||
// If we have map information, decide based on that.
|
||||
if (maps_valid() && other.maps_valid()) {
|
||||
return CompareMapSets(maps(), other.maps());
|
||||
}
|
||||
// If we do not have maps, try to use the instance types.
|
||||
if (instance_type_valid() && other.instance_type_valid() &&
|
||||
instance_type() != other.instance_type()) {
|
||||
return MapSetComparisonResult::kDisjoint;
|
||||
}
|
||||
return MapSetComparisonResult::kOther;
|
||||
}
|
||||
|
||||
Reduction LoadElimination::ReduceMapGuard(Node* node) {
|
||||
AbstractMapInfo guarded_maps(MapGuardMapsOf(node->op()));
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
AbstractState const* state = node_states_.Get(effect);
|
||||
if (state == nullptr) return NoChange();
|
||||
AbstractMapInfo state_info;
|
||||
if (state->LookupMaps(object, &state_info)) {
|
||||
switch (state_info.Compare(guarded_maps)) {
|
||||
case MapSetComparisonResult::kSubset:
|
||||
return Replace(effect);
|
||||
case MapSetComparisonResult::kDisjoint:
|
||||
state = unreachable_state();
|
||||
break;
|
||||
case MapSetComparisonResult::kOther:
|
||||
break;
|
||||
}
|
||||
state = state->KillMaps(object, zone());
|
||||
// TODO(turbofan): Compute the intersection.
|
||||
}
|
||||
state = state->AddMaps(object, guarded_maps, zone());
|
||||
return UpdateState(node, state);
|
||||
}
|
||||
|
||||
Reduction LoadElimination::ReduceCheckMaps(Node* node) {
|
||||
AbstractMapInfo checked_maps(CheckMapsParametersOf(node->op()).maps_info());
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
AbstractState const* state = node_states_.Get(effect);
|
||||
if (state == nullptr) return NoChange();
|
||||
AbstractMapInfo map_info;
|
||||
if (state->LookupMaps(object, &map_info)) {
|
||||
switch (map_info.Compare(checked_maps)) {
|
||||
case MapSetComparisonResult::kSubset:
|
||||
return Replace(effect);
|
||||
case MapSetComparisonResult::kDisjoint: {
|
||||
state = unreachable_state();
|
||||
break;
|
||||
}
|
||||
case MapSetComparisonResult::kOther:
|
||||
break;
|
||||
}
|
||||
state = state->KillMaps(object, zone());
|
||||
// TODO(turbofan): Compute the intersection.
|
||||
}
|
||||
state = state->AddMaps(object, checked_maps, zone());
|
||||
return UpdateState(node, state);
|
||||
}
|
||||
|
||||
Reduction LoadElimination::ReduceCompareMaps(Node* node) {
|
||||
AbstractMapInfo compared_maps(CompareMapsParametersOf(node->op()));
|
||||
ZoneHandleSet<Map> const maps = MapGuardMapsOf(node->op());
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
Node* const effect = NodeProperties::GetEffectInput(node);
|
||||
AbstractState const* state = node_states_.Get(effect);
|
||||
if (state == nullptr) return NoChange();
|
||||
AbstractMapInfo map_info;
|
||||
if (state->LookupMaps(object, &map_info)) {
|
||||
switch (map_info.Compare(compared_maps)) {
|
||||
case MapSetComparisonResult::kSubset: {
|
||||
Node* value = jsgraph()->TrueConstant();
|
||||
ReplaceWithValue(node, value, effect);
|
||||
return Replace(value);
|
||||
}
|
||||
case MapSetComparisonResult::kDisjoint: {
|
||||
Node* value = jsgraph()->FalseConstant();
|
||||
ReplaceWithValue(node, value, effect);
|
||||
return Replace(value);
|
||||
}
|
||||
case MapSetComparisonResult::kOther:
|
||||
break;
|
||||
ZoneHandleSet<Map> object_maps;
|
||||
if (state->LookupMaps(object, &object_maps)) {
|
||||
if (maps.contains(object_maps)) return Replace(effect);
|
||||
state = state->KillMaps(object, zone());
|
||||
// TODO(turbofan): Compute the intersection.
|
||||
}
|
||||
state = state->AddMaps(object, maps, zone());
|
||||
return UpdateState(node, state);
|
||||
}
|
||||
|
||||
Reduction LoadElimination::ReduceCheckMaps(Node* node) {
|
||||
ZoneHandleSet<Map> const maps = CheckMapsParametersOf(node->op()).maps();
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
Node* const effect = NodeProperties::GetEffectInput(node);
|
||||
AbstractState const* state = node_states_.Get(effect);
|
||||
if (state == nullptr) return NoChange();
|
||||
ZoneHandleSet<Map> object_maps;
|
||||
if (state->LookupMaps(object, &object_maps)) {
|
||||
if (maps.contains(object_maps)) return Replace(effect);
|
||||
state = state->KillMaps(object, zone());
|
||||
// TODO(turbofan): Compute the intersection.
|
||||
}
|
||||
state = state->AddMaps(object, maps, zone());
|
||||
return UpdateState(node, state);
|
||||
}
|
||||
|
||||
Reduction LoadElimination::ReduceCompareMaps(Node* node) {
|
||||
ZoneHandleSet<Map> const maps = CompareMapsParametersOf(node->op());
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
Node* const effect = NodeProperties::GetEffectInput(node);
|
||||
AbstractState const* state = node_states_.Get(effect);
|
||||
if (state == nullptr) return NoChange();
|
||||
ZoneHandleSet<Map> object_maps;
|
||||
if (state->LookupMaps(object, &object_maps)) {
|
||||
if (maps.contains(object_maps)) {
|
||||
Node* value = jsgraph()->TrueConstant();
|
||||
ReplaceWithValue(node, value, effect);
|
||||
return Replace(value);
|
||||
}
|
||||
// TODO(turbofan): Compute the intersection.
|
||||
}
|
||||
return UpdateState(node, state);
|
||||
}
|
||||
@ -1089,7 +837,7 @@ Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
|
||||
// {node} is fully redundant (independent of what {source_map} is).
|
||||
return Replace(effect);
|
||||
}
|
||||
if (object_maps.contains(source_map)) {
|
||||
if (object_maps.contains(ZoneHandleSet<Map>(source_map))) {
|
||||
object_maps.remove(source_map, zone());
|
||||
object_maps.insert(target_map, zone());
|
||||
AliasStateInfo alias_info(state, object, source_map);
|
||||
@ -1338,29 +1086,9 @@ Reduction LoadElimination::ReduceEffectPhi(Node* node) {
|
||||
|
||||
// Shortcut for the case when we do not know anything about some input.
|
||||
int const input_count = node->op()->EffectInputCount();
|
||||
for (int i = 0; i < input_count; ++i) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node, i);
|
||||
AbstractState const* input_state = node_states_.Get(effect);
|
||||
if (input_state == nullptr) return NoChange();
|
||||
|
||||
if (input_state->is_unreachable()) {
|
||||
// The state is unreachable, so we connect the control to the
|
||||
// end.
|
||||
Node* input_control = NodeProperties::GetControlInput(control, i);
|
||||
effect = graph()->NewNode(jsgraph()->simplified()->RuntimeAbort(
|
||||
BailoutReason::kUnreachableCodeReached),
|
||||
effect, input_control);
|
||||
input_control =
|
||||
graph()->NewNode(common()->Throw(), effect, input_control);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), input_control);
|
||||
Revisit(graph()->end());
|
||||
|
||||
// Update the merge node with unreachable control input, and trigger
|
||||
// revisit so that dead code elimination prunes the merge and its phis.
|
||||
control->ReplaceInput(i, jsgraph()->Dead());
|
||||
Revisit(control);
|
||||
return NoChange();
|
||||
}
|
||||
for (int i = 1; i < input_count; ++i) {
|
||||
Node* const effect = NodeProperties::GetEffectInput(node, i);
|
||||
if (node_states_.Get(effect) == nullptr) return NoChange();
|
||||
}
|
||||
|
||||
// Make a copy of the first input's state and merge with the state
|
||||
@ -1398,7 +1126,7 @@ Reduction LoadElimination::ReduceOtherNode(Node* node) {
|
||||
if (state == nullptr) return NoChange();
|
||||
// Check if this {node} has some uncontrolled side effects.
|
||||
if (!node->op()->HasProperty(Operator::kNoWrite)) {
|
||||
state = state->KillMutableState(zone());
|
||||
state = empty_state();
|
||||
}
|
||||
return UpdateState(node, state);
|
||||
} else {
|
||||
@ -1508,7 +1236,7 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return state->KillMutableState(zone());
|
||||
return empty_state();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < current->op()->EffectInputCount(); ++i) {
|
||||
@ -1607,13 +1335,6 @@ int LoadElimination::FieldIndexOf(FieldAccess const& access) {
|
||||
return FieldIndexOf(access.offset);
|
||||
}
|
||||
|
||||
LoadElimination::LoadElimination(Editor* editor, JSGraph* jsgraph, Zone* zone)
|
||||
: AdvancedReducer(editor),
|
||||
empty_state_(AbstractState::Empty()),
|
||||
unreachable_state_(AbstractState::Unreachable()),
|
||||
node_states_(zone),
|
||||
jsgraph_(jsgraph) {}
|
||||
|
||||
CommonOperatorBuilder* LoadElimination::common() const {
|
||||
return jsgraph()->common();
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ class CommonOperatorBuilder;
|
||||
struct FieldAccess;
|
||||
class Graph;
|
||||
class JSGraph;
|
||||
class MapsParameterInfo;
|
||||
|
||||
class V8_EXPORT_PRIVATE LoadElimination final
|
||||
: public NON_EXPORTED_BASE(AdvancedReducer) {
|
||||
public:
|
||||
LoadElimination(Editor* editor, JSGraph* jsgraph, Zone* zone);
|
||||
LoadElimination(Editor* editor, JSGraph* jsgraph, Zone* zone)
|
||||
: AdvancedReducer(editor), node_states_(zone), jsgraph_(jsgraph) {}
|
||||
~LoadElimination() final {}
|
||||
|
||||
const char* reducer_name() const override { return "LoadElimination"; }
|
||||
@ -188,92 +188,49 @@ class V8_EXPORT_PRIVATE LoadElimination final
|
||||
|
||||
static size_t const kMaxTrackedFields = 32;
|
||||
|
||||
enum class MapSetComparisonResult {
|
||||
kSubset,
|
||||
kDisjoint,
|
||||
kOther,
|
||||
};
|
||||
|
||||
static MapSetComparisonResult CompareMapSets(ZoneHandleSet<Map> const& lhs,
|
||||
ZoneHandleSet<Map> const& rhs);
|
||||
|
||||
class AbstractMapInfo {
|
||||
public:
|
||||
enum InfoValid { kMapsValid = 1 << 0, kInstanceTypeValid = 1 << 1 };
|
||||
typedef base::Flags<InfoValid, uint8_t> Validity;
|
||||
|
||||
AbstractMapInfo();
|
||||
explicit AbstractMapInfo(ZoneHandleSet<Map> const& maps);
|
||||
explicit AbstractMapInfo(InstanceType instance_type);
|
||||
explicit AbstractMapInfo(MapsParameterInfo const& info);
|
||||
|
||||
bool operator==(AbstractMapInfo const& other) const;
|
||||
bool operator!=(AbstractMapInfo const& other) const;
|
||||
|
||||
ZoneHandleSet<Map> const& maps() const;
|
||||
InstanceType instance_type() const;
|
||||
|
||||
bool maps_valid() const { return info_validity_ & kMapsValid; }
|
||||
bool instance_type_valid() const {
|
||||
return info_validity_ & kInstanceTypeValid;
|
||||
}
|
||||
bool empty() const { return info_validity_ == 0; }
|
||||
|
||||
AbstractMapInfo Merge(AbstractMapInfo const& other) const;
|
||||
|
||||
MapSetComparisonResult Compare(AbstractMapInfo const& other) const;
|
||||
|
||||
private:
|
||||
AbstractMapInfo(ZoneHandleSet<Map> const& maps, InstanceType instance_type,
|
||||
Validity validity);
|
||||
|
||||
ZoneHandleSet<Map> maps_;
|
||||
InstanceType instance_type_;
|
||||
Validity info_validity_;
|
||||
};
|
||||
|
||||
// Abstract state to approximate the current map of an object along the
|
||||
// effect paths through the graph.
|
||||
class AbstractMaps final : public ZoneObject {
|
||||
public:
|
||||
explicit AbstractMaps(Zone* zone) : info_for_node_(zone) {}
|
||||
AbstractMaps(Node* object, AbstractMapInfo const& map_info, Zone* zone)
|
||||
AbstractMaps(Node* object, ZoneHandleSet<Map> maps, Zone* zone)
|
||||
: info_for_node_(zone) {
|
||||
info_for_node_.insert(std::make_pair(object, map_info));
|
||||
info_for_node_.insert(std::make_pair(object, maps));
|
||||
}
|
||||
|
||||
AbstractMaps const* Extend(Node* object, AbstractMapInfo const& maps,
|
||||
AbstractMaps const* Extend(Node* object, ZoneHandleSet<Map> maps,
|
||||
Zone* zone) const;
|
||||
bool Lookup(Node* object, ZoneHandleSet<Map>* object_maps) const;
|
||||
bool Lookup(Node* object, AbstractMapInfo* maps_info) const;
|
||||
AbstractMaps const* Kill(const AliasStateInfo& alias_info,
|
||||
Zone* zone) const;
|
||||
bool Equals(AbstractMaps const* that) const {
|
||||
return this == that || this->info_for_node_ == that->info_for_node_;
|
||||
}
|
||||
AbstractMaps const* Merge(AbstractMaps const* that, Zone* zone) const;
|
||||
AbstractMaps const* KillMutableState(Zone* zone) const;
|
||||
|
||||
void Print() const;
|
||||
|
||||
private:
|
||||
ZoneMap<Node*, AbstractMapInfo> info_for_node_;
|
||||
ZoneMap<Node*, ZoneHandleSet<Map>> info_for_node_;
|
||||
};
|
||||
|
||||
class AbstractState final : public ZoneObject {
|
||||
public:
|
||||
AbstractState() {
|
||||
for (size_t i = 0; i < arraysize(fields_); ++i) {
|
||||
fields_[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Equals(AbstractState const* that) const;
|
||||
void Merge(AbstractState const* that, Zone* zone);
|
||||
|
||||
AbstractState const* AddMaps(Node* object, ZoneHandleSet<Map> maps,
|
||||
Zone* zone) const;
|
||||
AbstractState const* AddMaps(Node* object, AbstractMapInfo const& map_info,
|
||||
Zone* zone) const;
|
||||
AbstractState const* KillMaps(Node* object, Zone* zone) const;
|
||||
AbstractState const* KillMaps(const AliasStateInfo& alias_info,
|
||||
Zone* zone) const;
|
||||
bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const;
|
||||
bool LookupMaps(Node* object, AbstractMapInfo* object_maps) const;
|
||||
|
||||
AbstractState const* AddField(Node* object, size_t index, Node* value,
|
||||
MaybeHandle<Name> name, Zone* zone) const;
|
||||
@ -297,28 +254,13 @@ class V8_EXPORT_PRIVATE LoadElimination final
|
||||
AbstractState const* AddCheck(Node* node, Zone* zone) const;
|
||||
Node* LookupCheck(Node* node) const;
|
||||
|
||||
AbstractState const* KillMutableState(Zone* zone) const;
|
||||
|
||||
bool is_unreachable() const { return is_unreachable_; }
|
||||
|
||||
void Print() const;
|
||||
|
||||
static AbstractState Unreachable();
|
||||
static AbstractState Empty();
|
||||
|
||||
private:
|
||||
AbstractState() : is_unreachable_(false) {
|
||||
for (size_t i = 0; i < arraysize(fields_); ++i) {
|
||||
fields_[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractChecks const* checks_ = nullptr;
|
||||
AbstractElements const* elements_ = nullptr;
|
||||
AbstractField const* fields_[kMaxTrackedFields];
|
||||
AbstractMaps const* maps_ = nullptr;
|
||||
|
||||
bool is_unreachable_;
|
||||
};
|
||||
|
||||
class AbstractStateForEffectNodes final : public ZoneObject {
|
||||
@ -362,14 +304,12 @@ class V8_EXPORT_PRIVATE LoadElimination final
|
||||
|
||||
CommonOperatorBuilder* common() const;
|
||||
AbstractState const* empty_state() const { return &empty_state_; }
|
||||
AbstractState const* unreachable_state() const { return &unreachable_state_; }
|
||||
Factory* factory() const;
|
||||
Graph* graph() const;
|
||||
JSGraph* jsgraph() const { return jsgraph_; }
|
||||
Zone* zone() const { return node_states_.zone(); }
|
||||
|
||||
AbstractState const empty_state_;
|
||||
AbstractState const unreachable_state_;
|
||||
AbstractStateForEffectNodes node_states_;
|
||||
JSGraph* const jsgraph_;
|
||||
|
||||
|
@ -362,7 +362,7 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
|
||||
case IrOpcode::kMapGuard: {
|
||||
Node* const object = GetValueInput(effect, 0);
|
||||
if (IsSame(receiver, object)) {
|
||||
*maps_return = MapGuardMapsOf(effect->op()).maps();
|
||||
*maps_return = MapGuardMapsOf(effect->op());
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
|
@ -179,40 +179,6 @@ std::ostream& operator<<(std::ostream& os, CheckMapsFlags flags) {
|
||||
return os;
|
||||
}
|
||||
|
||||
MapsParameterInfo::MapsParameterInfo(ZoneHandleSet<Map> const& maps)
|
||||
: maps_(maps), instance_type_(Nothing<InstanceType>()) {
|
||||
DCHECK_LT(0, maps.size());
|
||||
instance_type_ = Just(maps.at(0)->instance_type());
|
||||
for (size_t i = 1; i < maps.size(); ++i) {
|
||||
if (instance_type_.FromJust() != maps.at(i)->instance_type()) {
|
||||
instance_type_ = Nothing<InstanceType>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, MapsParameterInfo const& p) {
|
||||
ZoneHandleSet<Map> const& maps = p.maps();
|
||||
InstanceType instance_type;
|
||||
if (p.instance_type().To(&instance_type)) {
|
||||
os << ", " << instance_type;
|
||||
}
|
||||
for (size_t i = 0; i < maps.size(); ++i) {
|
||||
os << ", " << Brief(*maps[i]);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
bool operator==(MapsParameterInfo const& lhs, MapsParameterInfo const& rhs) {
|
||||
return lhs.maps() == rhs.maps();
|
||||
}
|
||||
|
||||
bool operator!=(MapsParameterInfo const& lhs, MapsParameterInfo const& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
size_t hash_value(MapsParameterInfo const& p) { return hash_value(p.maps()); }
|
||||
|
||||
bool operator==(CheckMapsParameters const& lhs,
|
||||
CheckMapsParameters const& rhs) {
|
||||
return lhs.flags() == rhs.flags() && lhs.maps() == rhs.maps();
|
||||
@ -223,7 +189,12 @@ size_t hash_value(CheckMapsParameters const& p) {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, CheckMapsParameters const& p) {
|
||||
return os << p.flags() << p.maps_info();
|
||||
ZoneHandleSet<Map> const& maps = p.maps();
|
||||
os << p.flags();
|
||||
for (size_t i = 0; i < maps.size(); ++i) {
|
||||
os << ", " << Brief(*maps[i]);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) {
|
||||
@ -231,14 +202,9 @@ CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) {
|
||||
return OpParameter<CheckMapsParameters>(op);
|
||||
}
|
||||
|
||||
MapsParameterInfo const& CompareMapsParametersOf(Operator const* op) {
|
||||
ZoneHandleSet<Map> const& CompareMapsParametersOf(Operator const* op) {
|
||||
DCHECK_EQ(IrOpcode::kCompareMaps, op->opcode());
|
||||
return OpParameter<MapsParameterInfo>(op);
|
||||
}
|
||||
|
||||
MapsParameterInfo const& MapGuardMapsOf(Operator const* op) {
|
||||
DCHECK_EQ(IrOpcode::kMapGuard, op->opcode());
|
||||
return OpParameter<MapsParameterInfo>(op);
|
||||
return OpParameter<ZoneHandleSet<Map>>(op);
|
||||
}
|
||||
|
||||
size_t hash_value(CheckTaggedInputMode mode) {
|
||||
@ -1006,22 +972,14 @@ const Operator* SimplifiedOperatorBuilder::CheckMaps(CheckMapsFlags flags,
|
||||
parameters); // parameter
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::MapGuard(ZoneHandleSet<Map> maps) {
|
||||
return new (zone()) Operator1<MapsParameterInfo>( // --
|
||||
IrOpcode::kMapGuard, Operator::kEliminatable, // opcode
|
||||
"MapGuard", // name
|
||||
1, 1, 1, 0, 1, 0, // counts
|
||||
MapsParameterInfo(maps)); // parameter
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::CompareMaps(
|
||||
ZoneHandleSet<Map> maps) {
|
||||
return new (zone()) Operator1<MapsParameterInfo>( // --
|
||||
IrOpcode::kCompareMaps, // opcode
|
||||
Operator::kEliminatable, // flags
|
||||
"CompareMaps", // name
|
||||
1, 1, 1, 1, 1, 0, // counts
|
||||
MapsParameterInfo(maps)); // parameter
|
||||
return new (zone()) Operator1<ZoneHandleSet<Map>>( // --
|
||||
IrOpcode::kCompareMaps, // opcode
|
||||
Operator::kEliminatable, // flags
|
||||
"CompareMaps", // name
|
||||
1, 1, 1, 1, 1, 0, // counts
|
||||
maps); // parameter
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole(
|
||||
|
@ -133,38 +133,18 @@ DEFINE_OPERATORS_FOR_FLAGS(CheckMapsFlags)
|
||||
|
||||
std::ostream& operator<<(std::ostream&, CheckMapsFlags);
|
||||
|
||||
class MapsParameterInfo {
|
||||
public:
|
||||
explicit MapsParameterInfo(ZoneHandleSet<Map> const& maps);
|
||||
|
||||
Maybe<InstanceType> instance_type() const { return instance_type_; }
|
||||
ZoneHandleSet<Map> const& maps() const { return maps_; }
|
||||
|
||||
private:
|
||||
ZoneHandleSet<Map> const maps_;
|
||||
Maybe<InstanceType> instance_type_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, MapsParameterInfo const&);
|
||||
|
||||
bool operator==(MapsParameterInfo const&, MapsParameterInfo const&);
|
||||
bool operator!=(MapsParameterInfo const&, MapsParameterInfo const&);
|
||||
|
||||
size_t hash_value(MapsParameterInfo const&);
|
||||
|
||||
// A descriptor for map checks.
|
||||
class CheckMapsParameters final {
|
||||
public:
|
||||
CheckMapsParameters(CheckMapsFlags flags, ZoneHandleSet<Map> const& maps)
|
||||
: flags_(flags), maps_info_(maps) {}
|
||||
: flags_(flags), maps_(maps) {}
|
||||
|
||||
CheckMapsFlags flags() const { return flags_; }
|
||||
ZoneHandleSet<Map> const& maps() const { return maps_info_.maps(); }
|
||||
MapsParameterInfo const& maps_info() const { return maps_info_; }
|
||||
ZoneHandleSet<Map> const& maps() const { return maps_; }
|
||||
|
||||
private:
|
||||
CheckMapsFlags const flags_;
|
||||
MapsParameterInfo const maps_info_;
|
||||
ZoneHandleSet<Map> const maps_;
|
||||
};
|
||||
|
||||
bool operator==(CheckMapsParameters const&, CheckMapsParameters const&);
|
||||
@ -176,10 +156,8 @@ std::ostream& operator<<(std::ostream&, CheckMapsParameters const&);
|
||||
CheckMapsParameters const& CheckMapsParametersOf(Operator const*)
|
||||
WARN_UNUSED_RESULT;
|
||||
|
||||
MapsParameterInfo const& MapGuardMapsOf(Operator const*) WARN_UNUSED_RESULT;
|
||||
|
||||
// Parameters for CompareMaps operator.
|
||||
MapsParameterInfo const& CompareMapsParametersOf(Operator const*)
|
||||
ZoneHandleSet<Map> const& CompareMapsParametersOf(Operator const*)
|
||||
WARN_UNUSED_RESULT;
|
||||
|
||||
// A descriptor for growing elements backing stores.
|
||||
@ -437,7 +415,6 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
const Operator* CheckBounds();
|
||||
const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>);
|
||||
const Operator* CompareMaps(ZoneHandleSet<Map>);
|
||||
const Operator* MapGuard(ZoneHandleSet<Map> maps);
|
||||
|
||||
const Operator* CheckHeapObject();
|
||||
const Operator* CheckInternalizedString();
|
||||
|
@ -96,15 +96,6 @@ class ZoneHandleSet final {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool contains(Handle<T> other) const {
|
||||
if (data_ == kEmptyTag) return false;
|
||||
if ((data_ & kTagMask) == kSingletonTag) {
|
||||
return singleton() == bit_cast<T**>(other.address());
|
||||
}
|
||||
DCHECK_EQ(kListTag, data_ & kTagMask);
|
||||
return list()->Contains(bit_cast<T**>(other.address()));
|
||||
}
|
||||
|
||||
void remove(Handle<T> handle, Zone* zone) {
|
||||
// TODO(bmeurer): Optimize this case.
|
||||
ZoneHandleSet<T> that;
|
||||
|
Loading…
Reference in New Issue
Block a user