Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Unified Diff: src/compiler/js-native-context-specialization.cc

Issue 1416973014: [turbofan] Move PropertyAccessInfo and friends to a separate file. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add missing factory() method. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/property-access-info.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-native-context-specialization.cc
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
index d96cf15b6e3438c9e1bc356cecacb5351b7a11cd..3c2c4f4ef67e9088cb9651854f144e46a7046591 100644
--- a/src/compiler/js-native-context-specialization.cc
+++ b/src/compiler/js-native-context-specialization.cc
@@ -39,7 +39,8 @@ JSNativeContextSpecialization::JSNativeContextSpecialization(
native_context_(global_object->native_context(), isolate()),
dependencies_(dependencies),
zone_(zone),
- type_cache_(TypeCache::Get()) {}
+ type_cache_(TypeCache::Get()),
+ access_info_factory_(dependencies, native_context(), graph()->zone()) {}
Reduction JSNativeContextSpecialization::Reduce(Node* node) {
@@ -298,319 +299,6 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
}
-// This class encapsulates all information required to access a certain
-// object property, either on the object itself or on the prototype chain.
-class JSNativeContextSpecialization::PropertyAccessInfo final {
- public:
- enum Kind { kInvalid, kDataConstant, kDataField, kTransitionToField };
-
- static PropertyAccessInfo DataConstant(Type* receiver_type,
- Handle<Object> constant,
- MaybeHandle<JSObject> holder) {
- return PropertyAccessInfo(holder, constant, receiver_type);
- }
- static PropertyAccessInfo DataField(
- Type* receiver_type, FieldIndex field_index, Type* field_type,
- MaybeHandle<JSObject> holder = MaybeHandle<JSObject>()) {
- return PropertyAccessInfo(holder, field_index, field_type, receiver_type);
- }
- static PropertyAccessInfo TransitionToField(Type* receiver_type,
- FieldIndex field_index,
- Type* field_type,
- Handle<Map> transition_map,
- MaybeHandle<JSObject> holder) {
- return PropertyAccessInfo(holder, transition_map, field_index, field_type,
- receiver_type);
- }
-
- PropertyAccessInfo() : kind_(kInvalid) {}
- PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
- Type* receiver_type)
- : kind_(kDataConstant),
- receiver_type_(receiver_type),
- constant_(constant),
- holder_(holder) {}
- PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index,
- Type* field_type, Type* receiver_type)
- : kind_(kDataField),
- receiver_type_(receiver_type),
- holder_(holder),
- field_index_(field_index),
- field_type_(field_type) {}
- PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Map> transition_map,
- FieldIndex field_index, Type* field_type,
- Type* receiver_type)
- : kind_(kTransitionToField),
- receiver_type_(receiver_type),
- transition_map_(transition_map),
- holder_(holder),
- field_index_(field_index),
- field_type_(field_type) {}
-
- bool IsDataConstant() const { return kind() == kDataConstant; }
- bool IsDataField() const { return kind() == kDataField; }
- bool IsTransitionToField() const { return kind() == kTransitionToField; }
-
- Kind kind() const { return kind_; }
- MaybeHandle<JSObject> holder() const { return holder_; }
- Handle<Object> constant() const { return constant_; }
- Handle<Object> transition_map() const { return transition_map_; }
- FieldIndex field_index() const { return field_index_; }
- Type* field_type() const { return field_type_; }
- Type* receiver_type() const { return receiver_type_; }
-
- private:
- Kind kind_;
- Type* receiver_type_;
- Handle<Object> constant_;
- Handle<Map> transition_map_;
- MaybeHandle<JSObject> holder_;
- FieldIndex field_index_;
- Type* field_type_ = Type::Any();
-};
-
-
-namespace {
-
-bool CanInlinePropertyAccess(Handle<Map> map) {
- // TODO(bmeurer): Do something about the number stuff.
- if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
- if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
- return map->IsJSObjectMap() && !map->is_dictionary_map() &&
- !map->has_named_interceptor() &&
- // TODO(verwaest): Whitelist contexts to which we have access.
- !map->is_access_check_needed();
-}
-
-} // namespace
-
-
-bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
- Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
- PropertyAccessInfo* access_info) {
- // Check if it is safe to inline property access for the {map}.
- if (!CanInlinePropertyAccess(map)) return false;
-
- // Compute the receiver type.
- Handle<Map> receiver_map = map;
- Type* receiver_type = Type::Class(receiver_map, graph()->zone());
-
- // We support fast inline cases for certain JSObject getters.
- if (access_mode == kLoad) {
- // Check for special JSObject field accessors.
- int offset;
- if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
- FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
- Type* field_type = Type::Tagged();
- if (map->IsStringMap()) {
- DCHECK(Name::Equals(factory()->length_string(), name));
- // The String::length property is always a smi in the range
- // [0, String::kMaxLength].
- field_type = type_cache_.kStringLengthType;
- } else if (map->IsJSArrayMap()) {
- DCHECK(Name::Equals(factory()->length_string(), name));
- // The JSArray::length property is a smi in the range
- // [0, FixedDoubleArray::kMaxLength] in case of fast double
- // elements, a smi in the range [0, FixedArray::kMaxLength]
- // in case of other fast elements, and [0, kMaxUInt32] in
- // case of other arrays.
- if (IsFastDoubleElementsKind(map->elements_kind())) {
- field_type = type_cache_.kFixedDoubleArrayLengthType;
- } else if (IsFastElementsKind(map->elements_kind())) {
- field_type = type_cache_.kFixedArrayLengthType;
- } else {
- field_type = type_cache_.kJSArrayLengthType;
- }
- }
- *access_info =
- PropertyAccessInfo::DataField(receiver_type, field_index, field_type);
- return true;
- }
- }
-
- MaybeHandle<JSObject> holder;
- while (true) {
- // Lookup the named property on the {map}.
- Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
- int const number = descriptors->SearchWithCache(*name, *map);
- if (number != DescriptorArray::kNotFound) {
- PropertyDetails const details = descriptors->GetDetails(number);
- if (access_mode == kStore) {
- // Don't bother optimizing stores to read-only properties.
- if (details.IsReadOnly()) {
- return false;
- }
- // Check for store to data property on a prototype.
- if (details.kind() == kData && !holder.is_null()) {
- // We need to add the data field to the receiver. Leave the loop
- // and check whether we already have a transition for this field.
- // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
- break;
- }
- }
- if (details.type() == DATA_CONSTANT) {
- *access_info = PropertyAccessInfo::DataConstant(
- receiver_type, handle(descriptors->GetValue(number), isolate()),
- holder);
- return true;
- } else if (details.type() == DATA) {
- int index = descriptors->GetFieldIndex(number);
- Representation field_representation = details.representation();
- FieldIndex field_index = FieldIndex::ForPropertyIndex(
- *map, index, field_representation.IsDouble());
- Type* field_type = Type::Tagged();
- if (field_representation.IsSmi()) {
- field_type = type_cache_.kSmi;
- } else if (field_representation.IsDouble()) {
- field_type = type_cache_.kFloat64;
- } else if (field_representation.IsHeapObject()) {
- // Extract the field type from the property details (make sure its
- // representation is TaggedPointer to reflect the heap object case).
- field_type = Type::Intersect(
- Type::Convert<HeapType>(
- handle(descriptors->GetFieldType(number), isolate()),
- graph()->zone()),
- Type::TaggedPointer(), graph()->zone());
- if (field_type->Is(Type::None())) {
- // Store is not safe if the field type was cleared.
- if (access_mode == 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::TaggedPointer();
- } else if (!Type::Any()->Is(field_type)) {
- // Add proper code dependencies in case of stable field map(s).
- Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate());
- dependencies()->AssumeFieldType(field_owner_map);
- }
- DCHECK(field_type->Is(Type::TaggedPointer()));
- }
- *access_info = PropertyAccessInfo::DataField(receiver_type, field_index,
- field_type, holder);
- return true;
- } else {
- // TODO(bmeurer): Add support for accessors.
- return false;
- }
- }
-
- // Don't search on the prototype chain for special indices in case of
- // integer indexed exotic objects (see ES6 section 9.4.5).
- if (map->IsJSTypedArrayMap() && name->IsString() &&
- IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
- return false;
- }
-
- // Don't lookup private symbols on the prototype chain.
- if (name->IsPrivate()) return false;
-
- // Walk up the prototype chain.
- if (!map->prototype()->IsJSObject()) {
- // Perform the implicit ToObject for primitives here.
- // Implemented according to ES6 section 7.3.2 GetV (V, P).
- Handle<JSFunction> constructor;
- if (Map::GetConstructorFunction(map, native_context())
- .ToHandle(&constructor)) {
- map = handle(constructor->initial_map(), isolate());
- DCHECK(map->prototype()->IsJSObject());
- } else if (map->prototype()->IsNull()) {
- // Store to property not found on the receiver or any prototype, we need
- // to transition to a new data property.
- // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
- if (access_mode == kStore) {
- break;
- }
- // TODO(bmeurer): Handle the not found case if the prototype is null.
- return false;
- } else {
- return false;
- }
- }
- Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
- if (map_prototype->map()->is_deprecated()) {
- // Try to migrate the prototype object so we don't embed the deprecated
- // map into the optimized code.
- JSObject::TryMigrateInstance(map_prototype);
- }
- map = handle(map_prototype->map(), isolate());
- holder = map_prototype;
-
- // Check if it is safe to inline property access for the {map}.
- if (!CanInlinePropertyAccess(map)) return false;
- }
- DCHECK_EQ(kStore, access_mode);
-
- // Check if the {receiver_map} has a data transition with the given {name}.
- if (receiver_map->unused_property_fields() == 0) return false;
- if (Map* transition = TransitionArray::SearchTransition(*receiver_map, kData,
- *name, NONE)) {
- Handle<Map> transition_map(transition, isolate());
- int const number = transition_map->LastAdded();
- PropertyDetails const details =
- transition_map->instance_descriptors()->GetDetails(number);
- // Don't bother optimizing stores to read-only properties.
- if (details.IsReadOnly()) return false;
- // TODO(bmeurer): Handle transition to data constant?
- if (details.type() != DATA) return false;
- int const index = details.field_index();
- Representation field_representation = details.representation();
- FieldIndex field_index = FieldIndex::ForPropertyIndex(
- *transition_map, index, field_representation.IsDouble());
- Type* field_type = Type::Tagged();
- if (field_representation.IsSmi()) {
- field_type = type_cache_.kSmi;
- } else if (field_representation.IsDouble()) {
- // TODO(bmeurer): Add support for storing to double fields.
- return false;
- } else if (field_representation.IsHeapObject()) {
- // Extract the field type from the property details (make sure its
- // representation is TaggedPointer to reflect the heap object case).
- field_type = Type::Intersect(
- Type::Convert<HeapType>(
- handle(
- transition_map->instance_descriptors()->GetFieldType(number),
- isolate()),
- graph()->zone()),
- Type::TaggedPointer(), graph()->zone());
- if (field_type->Is(Type::None())) {
- // Store is not safe if the field type was cleared.
- return false;
- } else if (!Type::Any()->Is(field_type)) {
- // 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);
- }
- DCHECK(field_type->Is(Type::TaggedPointer()));
- }
- dependencies()->AssumeMapNotDeprecated(transition_map);
- *access_info = PropertyAccessInfo::TransitionToField(
- receiver_type, field_index, field_type, transition_map, holder);
- return true;
- }
- return false;
-}
-
-
-bool JSNativeContextSpecialization::ComputePropertyAccessInfos(
- MapHandleList const& maps, Handle<Name> name,
- PropertyAccessMode access_mode,
- ZoneVector<PropertyAccessInfo>* access_infos) {
- for (Handle<Map> map : maps) {
- if (Map::TryUpdate(map).ToHandle(&map)) {
- PropertyAccessInfo access_info;
- if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
- return false;
- }
- access_infos->push_back(access_info);
- }
- }
- return true;
-}
-
-
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandleList const& receiver_maps,
Handle<Name> name, PropertyAccessMode access_mode) {
@@ -626,8 +314,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Compute property access infos for the receiver maps.
ZoneVector<PropertyAccessInfo> access_infos(zone());
- if (!ComputePropertyAccessInfos(receiver_maps, name, access_mode,
- &access_infos)) {
+ if (!access_info_factory().ComputePropertyAccessInfos(
+ receiver_maps, name, access_mode, &access_infos)) {
return NoChange();
}
@@ -711,7 +399,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Generate the actual property access.
if (access_info.IsDataConstant()) {
this_value = jsgraph()->Constant(access_info.constant());
- if (access_mode == kStore) {
+ if (access_mode == PropertyAccessMode::kStore) {
Node* check = graph()->NewNode(
simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
@@ -720,10 +408,11 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
this_control = graph()->NewNode(common()->IfTrue(), branch);
}
} else {
- DCHECK(access_info.IsDataField() || access_info.IsTransitionToField());
+ DCHECK(access_info.IsDataField());
FieldIndex const field_index = access_info.field_index();
Type* const field_type = access_info.field_type();
- if (access_mode == kLoad && access_info.holder().ToHandle(&holder)) {
+ if (access_mode == PropertyAccessMode::kLoad &&
+ access_info.holder().ToHandle(&holder)) {
this_receiver = jsgraph()->Constant(holder);
}
Node* this_storage = this_receiver;
@@ -745,12 +434,12 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
}
field_access.machine_type = kMachFloat64;
}
- if (access_mode == kLoad) {
+ if (access_mode == PropertyAccessMode::kLoad) {
this_value = this_effect =
graph()->NewNode(simplified()->LoadField(field_access),
this_storage, this_effect, this_control);
} else {
- DCHECK_EQ(kStore, access_mode);
+ DCHECK_EQ(PropertyAccessMode::kStore, access_mode);
if (field_type->Is(Type::UntaggedFloat64())) {
Node* check =
graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
@@ -806,17 +495,17 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
} else {
DCHECK(field_type->Is(Type::Tagged()));
}
- if (access_info.IsTransitionToField()) {
+ Handle<Map> transition_map;
+ if (access_info.transition_map().ToHandle(&transition_map)) {
this_effect = graph()->NewNode(common()->BeginRegion(), this_effect);
this_effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
- jsgraph()->Constant(access_info.transition_map()), this_effect,
- this_control);
+ jsgraph()->Constant(transition_map), this_effect, this_control);
}
this_effect = graph()->NewNode(simplified()->StoreField(field_access),
this_storage, this_value, this_effect,
this_control);
- if (access_info.IsTransitionToField()) {
+ if (!access_info.transition_map().is_null()) {
this_effect =
graph()->NewNode(common()->FinishRegion(),
jsgraph()->UndefinedConstant(), this_effect);
@@ -893,7 +582,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
DCHECK_LT(0, receiver_maps.length());
// Try to lower the named access based on the {receiver_maps}.
- return ReduceNamedAccess(node, value, receiver_maps, p.name(), kLoad);
+ return ReduceNamedAccess(node, value, receiver_maps, p.name(),
+ PropertyAccessMode::kLoad);
}
@@ -910,7 +600,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
DCHECK_LT(0, receiver_maps.length());
// Try to lower the named access based on the {receiver_maps}.
- return ReduceNamedAccess(node, value, receiver_maps, p.name(), kStore);
+ return ReduceNamedAccess(node, value, receiver_maps, p.name(),
+ PropertyAccessMode::kStore);
}
@@ -924,7 +615,7 @@ bool JSNativeContextSpecialization::LookupInScriptContextTable(
Handle<Name> name, ScriptContextTableLookupResult* result) {
if (!name->IsString()) return false;
Handle<ScriptContextTable> script_context_table(
- global_object()->native_context()->script_context_table());
+ native_context()->script_context_table());
ScriptContextTable::LookupResult lookup_result;
if (!ScriptContextTable::Lookup(script_context_table,
Handle<String>::cast(name), &lookup_result)) {
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/property-access-info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698