[turbofan] Remove remaining uses of Class type from the compiler.
We (mis)used Type::Class to track stable field maps in the past. But that always more or less unsupport and wrong for various reasons, mostly because the class types do not really present static information and thus it is possible to violate fundamental assumptions of the type system (i.e. intersecting class types and other types produces "interesting" results). Now it is possible to finally nuke the class types completely and thus simplify (and ideally correctify) the type system further. Note to performance sheriff: We do expect to see some performance regressions from this change. This is because we do not yet have a sane replacement mechanism to track known field maps and utilize them during LoadElimination. This will be accomplished in a follow up CL. BUG=v8:5270,v8:5267 R=jarin@chromium.org Review-Url: https://codereview.chromium.org/2293343002 Cr-Commit-Position: refs/heads/master@{#39031}
This commit is contained in:
parent
9c00c88902
commit
2b93899057
@ -81,9 +81,11 @@ PropertyAccessInfo PropertyAccessInfo::DataConstant(
|
||||
PropertyAccessInfo PropertyAccessInfo::DataField(
|
||||
MapList const& receiver_maps, FieldIndex field_index,
|
||||
MachineRepresentation field_representation, Type* field_type,
|
||||
MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) {
|
||||
MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
|
||||
MaybeHandle<Map> transition_map) {
|
||||
return PropertyAccessInfo(holder, transition_map, field_index,
|
||||
field_representation, field_type, receiver_maps);
|
||||
field_representation, field_type, field_map,
|
||||
receiver_maps);
|
||||
}
|
||||
|
||||
// static
|
||||
@ -119,14 +121,15 @@ PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
|
||||
PropertyAccessInfo::PropertyAccessInfo(
|
||||
MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
|
||||
FieldIndex field_index, MachineRepresentation field_representation,
|
||||
Type* field_type, MapList const& receiver_maps)
|
||||
Type* field_type, MaybeHandle<Map> field_map, MapList const& receiver_maps)
|
||||
: kind_(kDataField),
|
||||
receiver_maps_(receiver_maps),
|
||||
transition_map_(transition_map),
|
||||
holder_(holder),
|
||||
field_index_(field_index),
|
||||
field_representation_(field_representation),
|
||||
field_type_(field_type) {}
|
||||
field_type_(field_type),
|
||||
field_map_(field_map) {}
|
||||
|
||||
bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) {
|
||||
if (this->kind_ != that->kind_) return false;
|
||||
@ -293,9 +296,10 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
Representation details_representation = details.representation();
|
||||
FieldIndex field_index = FieldIndex::ForPropertyIndex(
|
||||
*map, index, details_representation.IsDouble());
|
||||
Type* field_type = Type::Tagged();
|
||||
Type* field_type = Type::NonInternal();
|
||||
MachineRepresentation field_representation =
|
||||
MachineRepresentation::kTagged;
|
||||
MaybeHandle<Map> field_map;
|
||||
if (details_representation.IsSmi()) {
|
||||
field_type = type_cache_.kSmi;
|
||||
field_representation = MachineRepresentation::kTaggedSigned;
|
||||
@ -306,27 +310,28 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
// Extract the field type from the property details (make sure its
|
||||
// representation is TaggedPointer to reflect the heap object case).
|
||||
field_representation = MachineRepresentation::kTaggedPointer;
|
||||
field_type = descriptors->GetFieldType(number)->Convert(zone());
|
||||
if (field_type->Is(Type::None())) {
|
||||
Handle<FieldType> descriptors_field_type(
|
||||
descriptors->GetFieldType(number), isolate());
|
||||
if (descriptors_field_type->IsNone()) {
|
||||
// Store is not safe if the field type was cleared.
|
||||
if (access_mode == AccessMode::kStore) return false;
|
||||
|
||||
// The field type was cleared by the GC, so we don't know anything
|
||||
// about the contents now.
|
||||
// TODO(bmeurer): It would be awesome to make this saner in the
|
||||
// runtime/GC interaction.
|
||||
field_type = Type::Any();
|
||||
} else if (!Type::Any()->Is(field_type)) {
|
||||
} else if (descriptors_field_type->IsClass()) {
|
||||
// Add proper code dependencies in case of stable field map(s).
|
||||
field_representation = MachineRepresentation::kTaggedPointer;
|
||||
Handle<Map> field_owner_map(map->FindFieldOwner(number),
|
||||
isolate());
|
||||
dependencies()->AssumeFieldType(field_owner_map);
|
||||
|
||||
// Remember the field map, and try to infer a useful type.
|
||||
field_type = Type::For(descriptors_field_type->AsClass());
|
||||
field_map = descriptors_field_type->AsClass();
|
||||
}
|
||||
}
|
||||
*access_info = PropertyAccessInfo::DataField(
|
||||
MapList{receiver_map}, field_index, field_representation,
|
||||
field_type, holder);
|
||||
field_type, field_map, holder);
|
||||
return true;
|
||||
}
|
||||
case ACCESSOR_CONSTANT: {
|
||||
@ -484,7 +489,8 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
|
||||
Representation details_representation = details.representation();
|
||||
FieldIndex field_index = FieldIndex::ForPropertyIndex(
|
||||
*transition_map, index, details_representation.IsDouble());
|
||||
Type* field_type = Type::Tagged();
|
||||
Type* field_type = Type::NonInternal();
|
||||
MaybeHandle<Map> field_map;
|
||||
MachineRepresentation field_representation = MachineRepresentation::kTagged;
|
||||
if (details_representation.IsSmi()) {
|
||||
field_type = type_cache_.kSmi;
|
||||
@ -496,23 +502,27 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
|
||||
// Extract the field type from the property details (make sure its
|
||||
// representation is TaggedPointer to reflect the heap object case).
|
||||
field_representation = MachineRepresentation::kTaggedPointer;
|
||||
field_type =
|
||||
transition_map->instance_descriptors()->GetFieldType(number)->Convert(
|
||||
zone());
|
||||
if (field_type->Is(Type::None())) {
|
||||
Handle<FieldType> descriptors_field_type(
|
||||
transition_map->instance_descriptors()->GetFieldType(number),
|
||||
isolate());
|
||||
if (descriptors_field_type->IsNone()) {
|
||||
// Store is not safe if the field type was cleared.
|
||||
return false;
|
||||
} else if (!Type::Any()->Is(field_type)) {
|
||||
} else if (descriptors_field_type->IsClass()) {
|
||||
// Add proper code dependencies in case of stable field map(s).
|
||||
Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
|
||||
isolate());
|
||||
dependencies()->AssumeFieldType(field_owner_map);
|
||||
|
||||
// Remember the field map, and try to infer a useful type.
|
||||
field_type = Type::For(descriptors_field_type->AsClass());
|
||||
field_map = descriptors_field_type->AsClass();
|
||||
}
|
||||
}
|
||||
dependencies()->AssumeMapNotDeprecated(transition_map);
|
||||
*access_info = PropertyAccessInfo::DataField(
|
||||
MapList{map}, field_index, field_representation, field_type, holder,
|
||||
transition_map);
|
||||
MapList{map}, field_index, field_representation, field_type, field_map,
|
||||
holder, transition_map);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -71,6 +71,7 @@ class PropertyAccessInfo final {
|
||||
static PropertyAccessInfo DataField(
|
||||
MapList const& receiver_maps, FieldIndex field_index,
|
||||
MachineRepresentation field_representation, Type* field_type,
|
||||
MaybeHandle<Map> field_map = MaybeHandle<Map>(),
|
||||
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
|
||||
MaybeHandle<Map> transition_map = MaybeHandle<Map>());
|
||||
static PropertyAccessInfo AccessorConstant(MapList const& receiver_maps,
|
||||
@ -97,6 +98,7 @@ class PropertyAccessInfo final {
|
||||
MachineRepresentation field_representation() const {
|
||||
return field_representation_;
|
||||
}
|
||||
MaybeHandle<Map> field_map() const { return field_map_; }
|
||||
MapList const& receiver_maps() const { return receiver_maps_; }
|
||||
|
||||
private:
|
||||
@ -107,7 +109,8 @@ class PropertyAccessInfo final {
|
||||
PropertyAccessInfo(MaybeHandle<JSObject> holder,
|
||||
MaybeHandle<Map> transition_map, FieldIndex field_index,
|
||||
MachineRepresentation field_representation,
|
||||
Type* field_type, MapList const& receiver_maps);
|
||||
Type* field_type, MaybeHandle<Map> field_map,
|
||||
MapList const& receiver_maps);
|
||||
|
||||
Kind kind_;
|
||||
MapList receiver_maps_;
|
||||
@ -117,6 +120,7 @@ class PropertyAccessInfo final {
|
||||
FieldIndex field_index_;
|
||||
MachineRepresentation field_representation_;
|
||||
Type* field_type_;
|
||||
MaybeHandle<Map> field_map_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -112,10 +112,11 @@ Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
|
||||
} else if (property_cell_value->IsNumber()) {
|
||||
property_cell_value_type = type_cache_.kHeapNumber;
|
||||
} else {
|
||||
// TODO(turbofan): Track the property_cell_value_map on the FieldAccess
|
||||
// below and use it in LoadElimination to eliminate map checks.
|
||||
Handle<Map> property_cell_value_map(
|
||||
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
|
||||
property_cell_value_type =
|
||||
Type::Class(property_cell_value_map, graph()->zone());
|
||||
property_cell_value_type = Type::For(property_cell_value_map);
|
||||
}
|
||||
}
|
||||
Node* value = effect = graph()->NewNode(
|
||||
|
@ -906,6 +906,8 @@ JSNativeContextSpecialization::BuildPropertyAccess(
|
||||
}
|
||||
field_access.machine_type = MachineType::Float64();
|
||||
}
|
||||
// TODO(turbofan): Track the field_map (if any) on the {field_access} and
|
||||
// use it in LoadElimination to eliminate map checks.
|
||||
value = effect = graph()->NewNode(simplified()->LoadField(field_access),
|
||||
storage, effect, control);
|
||||
} else {
|
||||
@ -956,14 +958,12 @@ JSNativeContextSpecialization::BuildPropertyAccess(
|
||||
// Ensure that {value} is a HeapObject.
|
||||
value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
|
||||
value, effect, control);
|
||||
if (field_type->NumClasses() == 1) {
|
||||
Handle<Map> field_map;
|
||||
if (access_info.field_map().ToHandle(&field_map)) {
|
||||
// Emit a map check for the value.
|
||||
Node* field_map =
|
||||
jsgraph()->Constant(field_type->Classes().Current());
|
||||
effect = graph()->NewNode(simplified()->CheckMaps(1), value,
|
||||
field_map, effect, control);
|
||||
} else {
|
||||
DCHECK_EQ(0, field_type->NumClasses());
|
||||
jsgraph()->HeapConstant(field_map), effect,
|
||||
control);
|
||||
}
|
||||
} else {
|
||||
// DCHECK(field_type->Is(Type::Tagged()));
|
||||
|
@ -97,9 +97,6 @@ MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
|
||||
Handle<Map> object_map(
|
||||
Handle<HeapObject>::cast(object_type->AsConstant()->Value())->map());
|
||||
if (object_map->is_stable()) return object_map;
|
||||
} else if (object_type->IsClass()) {
|
||||
Handle<Map> object_map = object_type->AsClass()->Map();
|
||||
if (object_map->is_stable()) return object_map;
|
||||
}
|
||||
return MaybeHandle<Map>();
|
||||
}
|
||||
@ -107,11 +104,8 @@ MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
|
||||
} // namespace
|
||||
|
||||
Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
|
||||
// The CheckMaps(o, ...map...) can be eliminated if map is stable and
|
||||
// either
|
||||
// (a) o has type Constant(object) and map == object->map, or
|
||||
// (b) o has type Class(map),
|
||||
// and either
|
||||
// The CheckMaps(o, ...map...) can be eliminated if map is stable,
|
||||
// o has type Constant(object) and map == object->map, and either
|
||||
// (1) map cannot transition further, or
|
||||
// (2) we can add a code dependency on the stability of map
|
||||
// (to guard the Constant type information).
|
||||
@ -151,10 +145,8 @@ Reduction TypedOptimization::ReduceLoadField(Node* node) {
|
||||
FieldAccess const& access = FieldAccessOf(node->op());
|
||||
if (access.base_is_tagged == kTaggedBase &&
|
||||
access.offset == HeapObject::kMapOffset) {
|
||||
// We can replace LoadField[Map](o) with map if is stable and either
|
||||
// (a) o has type Constant(object) and map == object->map, or
|
||||
// (b) o has type Class(map),
|
||||
// and either
|
||||
// We can replace LoadField[Map](o) with map if is stable, and
|
||||
// o has type Constant(object) and map == object->map, and either
|
||||
// (1) map cannot transition further, or
|
||||
// (2) deoptimization is enabled and we can add a code dependency on the
|
||||
// stability of map (to guard the Constant type information).
|
||||
|
@ -1453,10 +1453,9 @@ Type* Typer::Visitor::TypeJSForInNext(Node* node) {
|
||||
|
||||
Type* Typer::Visitor::TypeJSForInPrepare(Node* node) {
|
||||
STATIC_ASSERT(Map::EnumLengthBits::kMax <= FixedArray::kMaxLength);
|
||||
Factory* const f = isolate()->factory();
|
||||
Type* const cache_type = Type::Union(
|
||||
typer_->cache_.kSmi, Type::Class(f->meta_map(), zone()), zone());
|
||||
Type* const cache_array = Type::Class(f->fixed_array_map(), zone());
|
||||
Type* const cache_type =
|
||||
Type::Union(typer_->cache_.kSmi, Type::OtherInternal(), zone());
|
||||
Type* const cache_array = Type::OtherInternal();
|
||||
Type* const cache_length = typer_->cache_.kFixedArrayLengthType;
|
||||
return Type::Tuple(cache_type, cache_array, cache_length, zone());
|
||||
}
|
||||
|
@ -764,6 +764,11 @@ class Type {
|
||||
return Of(*value, zone);
|
||||
}
|
||||
|
||||
static Type* For(i::Map* map) {
|
||||
return BitsetType::New(BitsetType::ExpandInternals(BitsetType::Lub(map)));
|
||||
}
|
||||
static Type* For(i::Handle<i::Map> map) { return For(*map); }
|
||||
|
||||
// Extraction of components.
|
||||
static Type* Representation(Type* t, Zone* zone);
|
||||
static Type* Semantic(Type* t, Zone* zone);
|
||||
|
Loading…
Reference in New Issue
Block a user