summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/access-info.cc
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2019-08-01 08:38:30 +0200
committerMichaël Zasso <targos@protonmail.com>2019-08-01 12:53:56 +0200
commit2dcc3665abf57c3607cebffdeeca062f5894885d (patch)
tree4f560748132edcfb4c22d6f967a7e80d23d7ea2c /deps/v8/src/compiler/access-info.cc
parent1ee47d550c6de132f06110aa13eceb7551d643b3 (diff)
downloadnode-new-2dcc3665abf57c3607cebffdeeca062f5894885d.tar.gz
deps: update V8 to 7.6.303.28
PR-URL: https://github.com/nodejs/node/pull/28016 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Refael Ackermann (רפאל פלחי) <refack@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Diffstat (limited to 'deps/v8/src/compiler/access-info.cc')
-rw-r--r--deps/v8/src/compiler/access-info.cc469
1 files changed, 276 insertions, 193 deletions
diff --git a/deps/v8/src/compiler/access-info.cc b/deps/v8/src/compiler/access-info.cc
index 3fbedb6cbb..713484f734 100644
--- a/deps/v8/src/compiler/access-info.cc
+++ b/deps/v8/src/compiler/access-info.cc
@@ -6,16 +6,16 @@
#include "src/compiler/access-info.h"
-#include "src/accessors.h"
+#include "src/builtins/accessors.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/type-cache.h"
-#include "src/counters.h"
-#include "src/field-index-inl.h"
-#include "src/field-type.h"
#include "src/ic/call-optimization.h"
-#include "src/objects-inl.h"
+#include "src/logging/counters.h"
#include "src/objects/cell-inl.h"
+#include "src/objects/field-index-inl.h"
+#include "src/objects/field-type.h"
#include "src/objects/module-inl.h"
+#include "src/objects/objects-inl.h"
#include "src/objects/struct-inl.h"
#include "src/objects/templates.h"
@@ -55,91 +55,112 @@ std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
UNREACHABLE();
}
-ElementAccessInfo::ElementAccessInfo() = default;
-
-ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps,
- ElementsKind elements_kind)
- : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {
+ElementAccessInfo::ElementAccessInfo(ZoneVector<Handle<Map>>&& receiver_maps,
+ ElementsKind elements_kind, Zone* zone)
+ : elements_kind_(elements_kind),
+ receiver_maps_(receiver_maps),
+ transition_sources_(zone) {
CHECK(!receiver_maps.empty());
}
// static
-PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps,
- MaybeHandle<JSObject> holder) {
- return PropertyAccessInfo(kNotFound, holder, receiver_maps);
+PropertyAccessInfo PropertyAccessInfo::Invalid(Zone* zone) {
+ return PropertyAccessInfo(zone);
}
// static
-PropertyAccessInfo PropertyAccessInfo::DataConstant(
- MapHandles const& receiver_maps, Handle<Object> constant,
- MaybeHandle<JSObject> holder) {
- return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
+PropertyAccessInfo PropertyAccessInfo::NotFound(Zone* zone,
+ Handle<Map> receiver_map,
+ MaybeHandle<JSObject> holder) {
+ return PropertyAccessInfo(zone, kNotFound, holder, {{receiver_map}, zone});
}
// static
PropertyAccessInfo PropertyAccessInfo::DataField(
- PropertyConstness constness, MapHandles const& receiver_maps,
- FieldIndex field_index, MachineRepresentation field_representation,
+ Zone* zone, Handle<Map> receiver_map,
+ ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
+ FieldIndex field_index, Representation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
MaybeHandle<Map> transition_map) {
- Kind kind =
- constness == PropertyConstness::kConst ? kDataConstantField : kDataField;
- return PropertyAccessInfo(kind, holder, transition_map, field_index,
+ return PropertyAccessInfo(kDataField, holder, transition_map, field_index,
field_representation, field_type, field_map,
- receiver_maps);
+ {{receiver_map}, zone}, std::move(dependencies));
+}
+
+// static
+PropertyAccessInfo PropertyAccessInfo::DataConstant(
+ Zone* zone, Handle<Map> receiver_map,
+ ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
+ FieldIndex field_index, Representation field_representation,
+ Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
+ MaybeHandle<Map> transition_map) {
+ return PropertyAccessInfo(kDataConstant, holder, transition_map, field_index,
+ field_representation, field_type, field_map,
+ {{receiver_map}, zone}, std::move(dependencies));
}
// static
PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
- MapHandles const& receiver_maps, Handle<Object> constant,
+ Zone* zone, Handle<Map> receiver_map, Handle<Object> constant,
MaybeHandle<JSObject> holder) {
- return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
+ return PropertyAccessInfo(zone, kAccessorConstant, holder, constant,
+ {{receiver_map}, zone});
}
// static
-PropertyAccessInfo PropertyAccessInfo::ModuleExport(
- MapHandles const& receiver_maps, Handle<Cell> cell) {
- return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell,
- receiver_maps);
+PropertyAccessInfo PropertyAccessInfo::ModuleExport(Zone* zone,
+ Handle<Map> receiver_map,
+ Handle<Cell> cell) {
+ return PropertyAccessInfo(zone, kModuleExport, MaybeHandle<JSObject>(), cell,
+ {{receiver_map}, zone});
}
// static
-PropertyAccessInfo PropertyAccessInfo::StringLength(
- MapHandles const& receiver_maps) {
- return PropertyAccessInfo(kStringLength, MaybeHandle<JSObject>(),
- receiver_maps);
+PropertyAccessInfo PropertyAccessInfo::StringLength(Zone* zone,
+ Handle<Map> receiver_map) {
+ return PropertyAccessInfo(zone, kStringLength, MaybeHandle<JSObject>(),
+ {{receiver_map}, zone});
}
-PropertyAccessInfo::PropertyAccessInfo()
+PropertyAccessInfo::PropertyAccessInfo(Zone* zone)
: kind_(kInvalid),
- field_representation_(MachineRepresentation::kNone),
+ receiver_maps_(zone),
+ unrecorded_dependencies_(zone),
+ field_representation_(Representation::None()),
field_type_(Type::None()) {}
-PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
- MapHandles const& receiver_maps)
+PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
+ MaybeHandle<JSObject> holder,
+ ZoneVector<Handle<Map>>&& receiver_maps)
: kind_(kind),
receiver_maps_(receiver_maps),
+ unrecorded_dependencies_(zone),
holder_(holder),
- field_representation_(MachineRepresentation::kNone),
+ field_representation_(Representation::None()),
field_type_(Type::None()) {}
-PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
+PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
+ MaybeHandle<JSObject> holder,
Handle<Object> constant,
- MapHandles const& receiver_maps)
+ ZoneVector<Handle<Map>>&& receiver_maps)
: kind_(kind),
receiver_maps_(receiver_maps),
+ unrecorded_dependencies_(zone),
constant_(constant),
holder_(holder),
- field_representation_(MachineRepresentation::kNone),
+ field_representation_(Representation::None()),
field_type_(Type::Any()) {}
PropertyAccessInfo::PropertyAccessInfo(
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
- FieldIndex field_index, MachineRepresentation field_representation,
+ FieldIndex field_index, Representation field_representation,
Type field_type, MaybeHandle<Map> field_map,
- MapHandles const& receiver_maps)
+ ZoneVector<Handle<Map>>&& receiver_maps,
+ ZoneVector<CompilationDependencies::Dependency const*>&&
+ unrecorded_dependencies)
: kind_(kind),
receiver_maps_(receiver_maps),
+ unrecorded_dependencies_(std::move(unrecorded_dependencies)),
transition_map_(transition_map),
holder_(holder),
field_index_(field_index),
@@ -157,7 +178,7 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
return that->kind_ == kInvalid;
case kDataField:
- case kDataConstantField: {
+ case kDataConstant: {
// Check if we actually access the same field (we use the
// GetFieldAccessStubKey method here just like the ICs do
// since that way we only compare the relevant bits of the
@@ -167,12 +188,13 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
switch (access_mode) {
case AccessMode::kHas:
case AccessMode::kLoad: {
- if (this->field_representation_ != that->field_representation_) {
- if (!IsAnyTagged(this->field_representation_) ||
- !IsAnyTagged(that->field_representation_)) {
+ if (!this->field_representation_.Equals(
+ that->field_representation_)) {
+ if (this->field_representation_.IsDouble() ||
+ that->field_representation_.IsDouble()) {
return false;
}
- this->field_representation_ = MachineRepresentation::kTagged;
+ this->field_representation_ = Representation::Tagged();
}
if (this->field_map_.address() != that->field_map_.address()) {
this->field_map_ = MaybeHandle<Map>();
@@ -186,7 +208,8 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
// also need to make sure that in case of transitioning stores,
// the transition targets match.
if (this->field_map_.address() != that->field_map_.address() ||
- this->field_representation_ != that->field_representation_ ||
+ !this->field_representation_.Equals(
+ that->field_representation_) ||
this->transition_map_.address() !=
that->transition_map_.address()) {
return false;
@@ -194,22 +217,25 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
break;
}
}
- // Merge the field type.
this->field_type_ =
Type::Union(this->field_type_, that->field_type_, zone);
- // Merge the receiver maps.
this->receiver_maps_.insert(this->receiver_maps_.end(),
that->receiver_maps_.begin(),
that->receiver_maps_.end());
+ this->unrecorded_dependencies_.insert(
+ this->unrecorded_dependencies_.end(),
+ that->unrecorded_dependencies_.begin(),
+ that->unrecorded_dependencies_.end());
return true;
}
return false;
}
- case kDataConstant:
case kAccessorConstant: {
// Check if we actually access the same constant.
if (this->constant_.address() == that->constant_.address()) {
+ DCHECK(this->unrecorded_dependencies_.empty());
+ DCHECK(that->unrecorded_dependencies_.empty());
this->receiver_maps_.insert(this->receiver_maps_.end(),
that->receiver_maps_.begin(),
that->receiver_maps_.end());
@@ -220,6 +246,8 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
case kNotFound:
case kStringLength: {
+ DCHECK(this->unrecorded_dependencies_.empty());
+ DCHECK(that->unrecorded_dependencies_.empty());
this->receiver_maps_.insert(this->receiver_maps_.end(),
that->receiver_maps_.begin(),
that->receiver_maps_.end());
@@ -243,65 +271,57 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
type_cache_(TypeCache::Get()),
zone_(zone) {}
-bool AccessInfoFactory::ComputeElementAccessInfo(
- Handle<Map> map, AccessMode access_mode,
- ElementAccessInfo* access_info) const {
+base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
+ Handle<Map> map, AccessMode access_mode) const {
// Check if it is safe to inline element access for the {map}.
MapRef map_ref(broker(), map);
- if (!CanInlineElementAccess(map_ref)) return false;
+ if (!CanInlineElementAccess(map_ref)) return base::nullopt;
ElementsKind const elements_kind = map_ref.elements_kind();
- *access_info = ElementAccessInfo(MapHandles{map}, elements_kind);
- return true;
+ return ElementAccessInfo({{map}, zone()}, elements_kind, zone());
}
bool AccessInfoFactory::ComputeElementAccessInfos(
- FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode,
+ ElementAccessFeedback const& processed, AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos) const {
- ElementAccessFeedback const* processed =
- FLAG_concurrent_inlining
- ? broker()->GetElementAccessFeedback(FeedbackSource(nexus))
- : broker()->ProcessFeedbackMapsForElementAccess(maps);
- if (processed == nullptr) return false;
-
if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
// For polymorphic loads of similar elements kinds (i.e. all tagged or all
// double), always use the "worst case" code without a transition. This is
// much faster than transitioning the elements to the worst case, trading a
// TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
- ElementAccessInfo access_info;
- if (ConsolidateElementLoad(*processed, &access_info)) {
- access_infos->push_back(access_info);
+ base::Optional<ElementAccessInfo> access_info =
+ ConsolidateElementLoad(processed);
+ if (access_info.has_value()) {
+ access_infos->push_back(*access_info);
return true;
}
}
- for (Handle<Map> receiver_map : processed->receiver_maps) {
+ for (Handle<Map> receiver_map : processed.receiver_maps) {
// Compute the element access information.
- ElementAccessInfo access_info;
- if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
- return false;
- }
+ base::Optional<ElementAccessInfo> access_info =
+ ComputeElementAccessInfo(receiver_map, access_mode);
+ if (!access_info.has_value()) return false;
// Collect the possible transitions for the {receiver_map}.
- for (auto transition : processed->transitions) {
+ for (auto transition : processed.transitions) {
if (transition.second.equals(receiver_map)) {
- access_info.AddTransitionSource(transition.first);
+ access_info->AddTransitionSource(transition.first);
}
}
// Schedule the access information.
- access_infos->push_back(access_info);
+ access_infos->push_back(*access_info);
}
return true;
}
PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
Handle<Map> receiver_map, Handle<Map> map, MaybeHandle<JSObject> holder,
- int number, AccessMode access_mode) const {
- DCHECK_NE(number, DescriptorArray::kNotFound);
+ int descriptor, AccessMode access_mode) const {
+ DCHECK_NE(descriptor, DescriptorArray::kNotFound);
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
- PropertyDetails const details = descriptors->GetDetails(number);
- int index = descriptors->GetFieldIndex(number);
+ PropertyDetails const details = descriptors->GetDetails(descriptor);
+ int index = descriptors->GetFieldIndex(descriptor);
Representation details_representation = details.representation();
if (details_representation.IsNone()) {
// The ICs collect feedback in PREMONOMORPHIC state already,
@@ -309,65 +329,77 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
// fields for which the representation has not yet been
// determined by the runtime. So we need to catch this case
// here and fall back to use the regular IC logic instead.
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
FieldIndex field_index =
FieldIndex::ForPropertyIndex(*map, index, details_representation);
Type field_type = Type::NonInternal();
-#ifdef V8_COMPRESS_POINTERS
- MachineRepresentation field_representation =
- MachineRepresentation::kCompressed;
-#else
- MachineRepresentation field_representation = MachineRepresentation::kTagged;
-#endif
MaybeHandle<Map> field_map;
MapRef map_ref(broker(), map);
+ ZoneVector<CompilationDependencies::Dependency const*>
+ unrecorded_dependencies(zone());
if (details_representation.IsSmi()) {
field_type = Type::SignedSmall();
-#ifdef V8_COMPRESS_POINTERS
- field_representation = MachineRepresentation::kCompressedSigned;
-#else
- field_representation = MachineRepresentation::kTaggedSigned;
-#endif
- map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
- dependencies()->DependOnFieldRepresentation(map_ref, number);
+ map_ref.SerializeOwnDescriptor(descriptor);
+ unrecorded_dependencies.push_back(
+ dependencies()->FieldRepresentationDependencyOffTheRecord(map_ref,
+ descriptor));
} else if (details_representation.IsDouble()) {
field_type = type_cache_->kFloat64;
- field_representation = MachineRepresentation::kFloat64;
} else if (details_representation.IsHeapObject()) {
// Extract the field type from the property details (make sure its
// representation is TaggedPointer to reflect the heap object case).
- field_representation = MachineRepresentation::kTaggedPointer;
- Handle<FieldType> descriptors_field_type(descriptors->GetFieldType(number),
- isolate());
+ Handle<FieldType> descriptors_field_type(
+ descriptors->GetFieldType(descriptor), isolate());
if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared.
- if (access_mode == AccessMode::kStore) return {};
+ if (access_mode == AccessMode::kStore) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
// The field type was cleared by the GC, so we don't know anything
// about the contents now.
}
- map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
- dependencies()->DependOnFieldRepresentation(map_ref, number);
+ map_ref.SerializeOwnDescriptor(descriptor);
+ unrecorded_dependencies.push_back(
+ dependencies()->FieldRepresentationDependencyOffTheRecord(map_ref,
+ descriptor));
if (descriptors_field_type->IsClass()) {
- dependencies()->DependOnFieldType(map_ref, number);
+ unrecorded_dependencies.push_back(
+ dependencies()->FieldTypeDependencyOffTheRecord(map_ref, descriptor));
// Remember the field map, and try to infer a useful type.
Handle<Map> map(descriptors_field_type->AsClass(), isolate());
field_type = Type::For(MapRef(broker(), map));
field_map = MaybeHandle<Map>(map);
}
}
- return PropertyAccessInfo::DataField(
- details.constness(), MapHandles{receiver_map}, field_index,
- field_representation, field_type, field_map, holder);
+ PropertyConstness constness;
+ if (details.IsReadOnly() && !details.IsConfigurable()) {
+ constness = PropertyConstness::kConst;
+ } else {
+ map_ref.SerializeOwnDescriptor(descriptor);
+ constness = dependencies()->DependOnFieldConstness(map_ref, descriptor);
+ }
+ switch (constness) {
+ case PropertyConstness::kMutable:
+ return PropertyAccessInfo::DataField(
+ zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
+ details_representation, field_type, field_map, holder);
+ case PropertyConstness::kConst:
+ return PropertyAccessInfo::DataConstant(
+ zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
+ details_representation, field_type, field_map, holder);
+ }
+ UNREACHABLE();
}
PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map,
- MaybeHandle<JSObject> holder, int number, AccessMode access_mode) const {
- DCHECK_NE(number, DescriptorArray::kNotFound);
+ MaybeHandle<JSObject> holder, int descriptor,
+ AccessMode access_mode) const {
+ DCHECK_NE(descriptor, DescriptorArray::kNotFound);
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
- SLOW_DCHECK(number == descriptors->Search(*name, *map));
+ SLOW_DCHECK(descriptor == descriptors->Search(*name, *map));
if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
DCHECK(map->is_prototype_map());
Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(map->prototype_info()),
@@ -375,22 +407,24 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
Handle<JSModuleNamespace> module_namespace(
JSModuleNamespace::cast(proto_info->module_namespace()), isolate());
Handle<Cell> cell(
- Cell::cast(module_namespace->module()->exports()->Lookup(
+ Cell::cast(module_namespace->module().exports().Lookup(
ReadOnlyRoots(isolate()), name, Smi::ToInt(name->GetHash()))),
isolate());
- if (cell->value()->IsTheHole(isolate())) {
+ if (cell->value().IsTheHole(isolate())) {
// This module has not been fully initialized yet.
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
- return PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell);
+ return PropertyAccessInfo::ModuleExport(zone(), receiver_map, cell);
}
if (access_mode == AccessMode::kHas) {
// HasProperty checks don't call getter/setters, existence is sufficient.
- return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
+ return PropertyAccessInfo::AccessorConstant(zone(), receiver_map,
Handle<Object>(), holder);
}
- Handle<Object> accessors(descriptors->GetStrongValue(number), isolate());
- if (!accessors->IsAccessorPair()) return {};
+ Handle<Object> accessors(descriptors->GetStrongValue(descriptor), isolate());
+ if (!accessors->IsAccessorPair()) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
Handle<Object> accessor(access_mode == AccessMode::kLoad
? Handle<AccessorPair>::cast(accessors)->getter()
: Handle<AccessorPair>::cast(accessors)->setter(),
@@ -400,16 +434,20 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
if (!optimization.is_simple_api_call() ||
optimization.IsCrossContextLazyAccessorPair(
*broker()->native_context().object(), *map)) {
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
CallOptimization::HolderLookup lookup;
holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
- if (lookup == CallOptimization::kHolderNotFound) return {};
+ if (lookup == CallOptimization::kHolderNotFound) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
holder.is_null());
DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null());
- if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) return {};
+ if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
}
if (access_mode == AccessMode::kLoad) {
Handle<Name> cached_property_name;
@@ -420,18 +458,22 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
if (!access_info.IsInvalid()) return access_info;
}
}
- return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
- accessor, holder);
+ return PropertyAccessInfo::AccessorConstant(zone(), receiver_map, accessor,
+ holder);
}
PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, AccessMode access_mode) const {
CHECK(name->IsUniqueName());
- if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) return {};
+ if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
// Check if it is safe to inline property access for the {map}.
- if (!CanInlinePropertyAccess(map)) return {};
+ if (!CanInlinePropertyAccess(map)) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
// We support fast inline cases for certain JSObject getters.
if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
@@ -451,7 +493,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
if (access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral) {
// Don't bother optimizing stores to read-only properties.
- if (details.IsReadOnly()) return {};
+ if (details.IsReadOnly()) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
if (details.kind() == kData && !holder.is_null()) {
// This is a store to a property not found on the receiver but on a
// prototype. According to ES6 section 9.1.9 [[Set]], we need to
@@ -467,20 +511,13 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} else {
DCHECK_EQ(kAccessor, details.kind());
// TODO(turbofan): Add support for general accessors?
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
} else {
DCHECK_EQ(kDescriptor, details.location());
- if (details.kind() == kData) {
- DCHECK(!FLAG_track_constant_fields);
- return PropertyAccessInfo::DataConstant(
- MapHandles{receiver_map},
- handle(descriptors->GetStrongValue(number), isolate()), holder);
- } else {
- DCHECK_EQ(kAccessor, details.kind());
- return ComputeAccessorDescriptorAccessInfo(
- receiver_map, name, map, holder, number, access_mode);
- }
+ DCHECK_EQ(kAccessor, details.kind());
+ return ComputeAccessorDescriptorAccessInfo(receiver_map, name, map,
+ holder, number, access_mode);
}
UNREACHABLE();
}
@@ -491,7 +528,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// integer indexed exotic objects (see ES6 section 9.4.5).
if (map->IsJSTypedArrayMap() && name->IsString() &&
IsSpecialIndex(String::cast(*name))) {
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
// Don't search on the prototype when storing in literals.
@@ -500,18 +537,20 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
}
// Don't lookup private symbols on the prototype chain.
- if (name->IsPrivate()) return {};
+ if (name->IsPrivate()) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
// Walk up the prototype chain.
- if (!map->prototype()->IsJSObject()) {
+ 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, broker()->native_context().object())
.ToHandle(&constructor)) {
map = handle(constructor->initial_map(), isolate());
- DCHECK(map->prototype()->IsJSObject());
- } else if (map->prototype()->IsNull(isolate())) {
+ DCHECK(map->prototype().IsJSObject());
+ } else if (map->prototype().IsNull(isolate())) {
// 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)
@@ -521,13 +560,13 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// The property was not found (access returns undefined or throws
// depending on the language mode of the load operation.
// Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
- return PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
+ return PropertyAccessInfo::NotFound(zone(), receiver_map, holder);
} else {
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
}
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
- if (map_prototype->map()->is_deprecated()) {
+ 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);
@@ -535,26 +574,30 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
map = handle(map_prototype->map(), isolate());
holder = map_prototype;
- if (!CanInlinePropertyAccess(map)) return {};
+ if (!CanInlinePropertyAccess(map)) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
// Successful lookup on prototype chain needs to guarantee that all
// the prototypes up to the holder have stable maps. Let us make sure
// the prototype maps are stable here.
CHECK(map->is_stable());
}
+ UNREACHABLE();
}
-PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
- MapHandles const& maps, Handle<Name> name, AccessMode access_mode) const {
- ZoneVector<PropertyAccessInfo> raw_access_infos(zone());
- ComputePropertyAccessInfos(maps, name, access_mode, &raw_access_infos);
- ZoneVector<PropertyAccessInfo> access_infos(zone());
- if (FinalizePropertyAccessInfos(raw_access_infos, access_mode,
- &access_infos) &&
- access_infos.size() == 1) {
- return access_infos.front();
- }
- return {};
+PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
+ ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode) const {
+ ZoneVector<PropertyAccessInfo> merged_access_infos(zone());
+ MergePropertyAccessInfos(access_infos, access_mode, &merged_access_infos);
+ if (merged_access_infos.size() == 1) {
+ PropertyAccessInfo& result = merged_access_infos.front();
+ if (!result.IsInvalid()) {
+ result.RecordDependencies(dependencies());
+ return result;
+ }
+ }
+ return PropertyAccessInfo::Invalid(zone());
}
void AccessInfoFactory::ComputePropertyAccessInfos(
@@ -566,7 +609,29 @@ void AccessInfoFactory::ComputePropertyAccessInfos(
}
}
+void PropertyAccessInfo::RecordDependencies(
+ CompilationDependencies* dependencies) {
+ for (CompilationDependencies::Dependency const* d :
+ unrecorded_dependencies_) {
+ dependencies->RecordDependency(d);
+ }
+ unrecorded_dependencies_.clear();
+}
+
bool AccessInfoFactory::FinalizePropertyAccessInfos(
+ ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode,
+ ZoneVector<PropertyAccessInfo>* result) const {
+ MergePropertyAccessInfos(access_infos, access_mode, result);
+ for (PropertyAccessInfo const& info : *result) {
+ if (info.IsInvalid()) return false;
+ }
+ for (PropertyAccessInfo& info : *result) {
+ info.RecordDependencies(dependencies());
+ }
+ return true;
+}
+
+void AccessInfoFactory::MergePropertyAccessInfos(
ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* result) const {
DCHECK(result->empty());
@@ -578,11 +643,9 @@ bool AccessInfoFactory::FinalizePropertyAccessInfos(
break;
}
}
- if (it->IsInvalid()) return false;
if (!merged) result->push_back(*it);
}
CHECK(!result->empty());
- return true;
}
namespace {
@@ -608,28 +671,26 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
} // namespace
-bool AccessInfoFactory::ConsolidateElementLoad(
- ElementAccessFeedback const& processed,
- ElementAccessInfo* access_info) const {
+base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
+ ElementAccessFeedback const& processed) const {
ElementAccessFeedback::MapIterator it = processed.all_maps(broker());
MapRef first_map = it.current();
InstanceType instance_type = first_map.instance_type();
ElementsKind elements_kind = first_map.elements_kind();
- MapHandles maps;
+ ZoneVector<Handle<Map>> maps(zone());
for (; !it.done(); it.advance()) {
MapRef map = it.current();
if (map.instance_type() != instance_type || !CanInlineElementAccess(map)) {
- return false;
+ return base::nullopt;
}
if (!GeneralizeElementsKind(elements_kind, map.elements_kind())
.To(&elements_kind)) {
- return false;
+ return base::nullopt;
}
maps.push_back(map.object());
}
- *access_info = ElementAccessInfo(maps, elements_kind);
- return true;
+ return ElementAccessInfo(std::move(maps), elements_kind, zone());
}
PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
@@ -637,15 +698,15 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
// Check for String::length field accessor.
if (map->IsStringMap()) {
if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) {
- return PropertyAccessInfo::StringLength(MapHandles{map});
+ return PropertyAccessInfo::StringLength(zone(), map);
}
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
// Check for special JSObject field accessors.
FieldIndex field_index;
if (Accessors::IsJSObjectFieldAccessor(isolate(), map, name, &field_index)) {
Type field_type = Type::NonInternal();
- MachineRepresentation field_representation = MachineRepresentation::kTagged;
+ Representation field_representation = Representation::Tagged();
if (map->IsJSArrayMap()) {
DCHECK(
Name::Equals(isolate(), isolate()->factory()->length_string(), name));
@@ -656,20 +717,19 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
// case of other arrays.
if (IsDoubleElementsKind(map->elements_kind())) {
field_type = type_cache_->kFixedDoubleArrayLengthType;
- field_representation = MachineRepresentation::kTaggedSigned;
+ field_representation = Representation::Smi();
} else if (IsFastElementsKind(map->elements_kind())) {
field_type = type_cache_->kFixedArrayLengthType;
- field_representation = MachineRepresentation::kTaggedSigned;
+ field_representation = Representation::Smi();
} else {
field_type = type_cache_->kJSArrayLengthType;
}
}
// Special fields are always mutable.
- return PropertyAccessInfo::DataField(PropertyConstness::kMutable,
- MapHandles{map}, field_index,
+ return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index,
field_representation, field_type);
}
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
PropertyAccessInfo AccessInfoFactory::LookupTransition(
@@ -677,58 +737,81 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
// Check if the {map} has a data transition with the given {name}.
Map transition =
TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE);
- if (transition.is_null()) return {};
+ if (transition.is_null()) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
Handle<Map> transition_map(transition, isolate());
int const number = transition_map->LastAdded();
PropertyDetails const details =
- transition_map->instance_descriptors()->GetDetails(number);
+ transition_map->instance_descriptors().GetDetails(number);
// Don't bother optimizing stores to read-only properties.
- if (details.IsReadOnly()) return {};
+ if (details.IsReadOnly()) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
// TODO(bmeurer): Handle transition to data constant?
- if (details.location() != kField) return {};
+ if (details.location() != kField) {
+ return PropertyAccessInfo::Invalid(zone());
+ }
int const index = details.field_index();
Representation details_representation = details.representation();
FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index,
details_representation);
Type field_type = Type::NonInternal();
MaybeHandle<Map> field_map;
- MachineRepresentation field_representation = MachineRepresentation::kTagged;
MapRef transition_map_ref(broker(), transition_map);
+ ZoneVector<CompilationDependencies::Dependency const*>
+ unrecorded_dependencies(zone());
if (details_representation.IsSmi()) {
field_type = Type::SignedSmall();
- field_representation = MachineRepresentation::kTaggedSigned;
- transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
- dependencies()->DependOnFieldRepresentation(transition_map_ref, number);
+ transition_map_ref.SerializeOwnDescriptor(number);
+ unrecorded_dependencies.push_back(
+ dependencies()->FieldRepresentationDependencyOffTheRecord(
+ transition_map_ref, number));
} else if (details_representation.IsDouble()) {
field_type = type_cache_->kFloat64;
- field_representation = MachineRepresentation::kFloat64;
} else if (details_representation.IsHeapObject()) {
// Extract the field type from the property details (make sure its
// representation is TaggedPointer to reflect the heap object case).
- field_representation = MachineRepresentation::kTaggedPointer;
Handle<FieldType> descriptors_field_type(
- transition_map->instance_descriptors()->GetFieldType(number),
- isolate());
+ transition_map->instance_descriptors().GetFieldType(number), isolate());
if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared.
- return {};
+ return PropertyAccessInfo::Invalid(zone());
}
- transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
- dependencies()->DependOnFieldRepresentation(transition_map_ref, number);
+ transition_map_ref.SerializeOwnDescriptor(number);
+ unrecorded_dependencies.push_back(
+ dependencies()->FieldRepresentationDependencyOffTheRecord(
+ transition_map_ref, number));
if (descriptors_field_type->IsClass()) {
- dependencies()->DependOnFieldType(transition_map_ref, number);
+ unrecorded_dependencies.push_back(
+ dependencies()->FieldTypeDependencyOffTheRecord(transition_map_ref,
+ number));
// Remember the field map, and try to infer a useful type.
Handle<Map> map(descriptors_field_type->AsClass(), isolate());
field_type = Type::For(MapRef(broker(), map));
field_map = MaybeHandle<Map>(map);
}
}
- dependencies()->DependOnTransition(MapRef(broker(), transition_map));
- // Transitioning stores are never stores to constant fields.
- return PropertyAccessInfo::DataField(
- PropertyConstness::kMutable, MapHandles{map}, field_index,
- field_representation, field_type, field_map, holder, transition_map);
+ unrecorded_dependencies.push_back(
+ dependencies()->TransitionDependencyOffTheRecord(
+ MapRef(broker(), transition_map)));
+ // Transitioning stores *may* store to const fields. The resulting
+ // DataConstant access infos can be distinguished from later, i.e. redundant,
+ // stores to the same constant field by the presence of a transition map.
+ switch (details.constness()) {
+ case PropertyConstness::kMutable:
+ return PropertyAccessInfo::DataField(
+ zone(), map, std::move(unrecorded_dependencies), field_index,
+ details_representation, field_type, field_map, holder,
+ transition_map);
+ case PropertyConstness::kConst:
+ return PropertyAccessInfo::DataConstant(
+ zone(), map, std::move(unrecorded_dependencies), field_index,
+ details_representation, field_type, field_map, holder,
+ transition_map);
+ }
+ UNREACHABLE();
}
} // namespace compiler