Commit 9a23caf0 authored by Georg Neis's avatar Georg Neis Committed by V8 LUCI CQ

[compiler] Make AllocationSite never-serialized

To get there, also:

- Refactor AllocationSite serialization as necessary.

- Make some accessors on AllocationSite atomic.

- Add JSObjectRef::raw_properties_or_hash().

- Eliminate use of IsFastLiteral in JSCallReducer. It isn't really
  needed there and we want to have only a single piece of code
  traversing boilerplates. (We still have a separate traversal in the
  serializer but that will be removed soon.)

- Merge IsFastLiteral checks into JSCreateLowering's
  TryAllocateFastLiteral.
  Note: TryAllocateFastLiteral doesn't explicitly look at the
  boilerplate's elements kind beyond bailing out for
  DICTIONARY_ELEMENTS in the beginning. After that it looks only at
  the backing store instance type. There is no room for confusion
  because, while elements kind transitions can generally happen
  concurrently to TryAllocateFastLiteral, boilerplates can never
  transition to DICTIONARY_ELEMENTS (added a CHECK for that).

- Slightly adapt CompilationDependencies and remove obsolete comments.

- Fix JSHeapBroker::ClearReconstructibleData (clearing of Refs in
  stress mode) to exclude JSObjectRefs with extra data.

Bug: v8:7790
Change-Id: Iee1232d01e04bcd00db04d48f6e82064fce6ff62
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3008894
Commit-Queue: Georg Neis <neis@chromium.org>
Auto-Submit: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75656}
parent 433ff6b9
...@@ -25,8 +25,6 @@ CompilationDependencies::CompilationDependencies(JSHeapBroker* broker, ...@@ -25,8 +25,6 @@ CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
class InitialMapDependency final : public CompilationDependency { class InitialMapDependency final : public CompilationDependency {
public: public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the initial map.
InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map) InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map)
: function_(function), initial_map_(initial_map) { : function_(function), initial_map_(initial_map) {
DCHECK(function_.has_initial_map()); DCHECK(function_.has_initial_map());
...@@ -53,8 +51,6 @@ class InitialMapDependency final : public CompilationDependency { ...@@ -53,8 +51,6 @@ class InitialMapDependency final : public CompilationDependency {
class PrototypePropertyDependency final : public CompilationDependency { class PrototypePropertyDependency final : public CompilationDependency {
public: public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the prototype.
PrototypePropertyDependency(const JSFunctionRef& function, PrototypePropertyDependency(const JSFunctionRef& function,
const ObjectRef& prototype) const ObjectRef& prototype)
: function_(function), prototype_(prototype) { : function_(function), prototype_(prototype) {
...@@ -362,13 +358,9 @@ class TransitionDependency final : public CompilationDependency { ...@@ -362,13 +358,9 @@ class TransitionDependency final : public CompilationDependency {
class PretenureModeDependency final : public CompilationDependency { class PretenureModeDependency final : public CompilationDependency {
public: public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the mode.
PretenureModeDependency(const AllocationSiteRef& site, PretenureModeDependency(const AllocationSiteRef& site,
AllocationType allocation) AllocationType allocation)
: site_(site), allocation_(allocation) { : site_(site), allocation_(allocation) {}
DCHECK_EQ(allocation, site_.GetAllocationType());
}
bool IsValid() const override { bool IsValid() const override {
return allocation_ == site_.object()->GetAllocationType(); return allocation_ == site_.object()->GetAllocationType();
...@@ -392,8 +384,6 @@ class PretenureModeDependency final : public CompilationDependency { ...@@ -392,8 +384,6 @@ class PretenureModeDependency final : public CompilationDependency {
class FieldRepresentationDependency final : public CompilationDependency { class FieldRepresentationDependency final : public CompilationDependency {
public: public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the representation.
FieldRepresentationDependency(const MapRef& owner, InternalIndex descriptor, FieldRepresentationDependency(const MapRef& owner, InternalIndex descriptor,
Representation representation) Representation representation)
: owner_(owner), : owner_(owner),
...@@ -437,8 +427,6 @@ class FieldRepresentationDependency final : public CompilationDependency { ...@@ -437,8 +427,6 @@ class FieldRepresentationDependency final : public CompilationDependency {
class FieldTypeDependency final : public CompilationDependency { class FieldTypeDependency final : public CompilationDependency {
public: public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the type.
FieldTypeDependency(const MapRef& owner, InternalIndex descriptor, FieldTypeDependency(const MapRef& owner, InternalIndex descriptor,
const ObjectRef& type) const ObjectRef& type)
: owner_(owner), descriptor_(descriptor), type_(type) {} : owner_(owner), descriptor_(descriptor), type_(type) {}
...@@ -556,14 +544,9 @@ class ProtectorDependency final : public CompilationDependency { ...@@ -556,14 +544,9 @@ class ProtectorDependency final : public CompilationDependency {
class ElementsKindDependency final : public CompilationDependency { class ElementsKindDependency final : public CompilationDependency {
public: public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the elements kind.
ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind) ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
: site_(site), kind_(kind) { : site_(site), kind_(kind) {
DCHECK(AllocationSite::ShouldTrack(kind_)); DCHECK(AllocationSite::ShouldTrack(kind_));
DCHECK_EQ(kind_, site_.PointsToLiteral()
? site_.boilerplate().value().map().elements_kind()
: site_.GetElementsKind());
} }
bool IsValid() const override { bool IsValid() const override {
...@@ -686,7 +669,7 @@ void CompilationDependencies::DependOnConstantInDictionaryPrototypeChain( ...@@ -686,7 +669,7 @@ void CompilationDependencies::DependOnConstantInDictionaryPrototypeChain(
AllocationType CompilationDependencies::DependOnPretenureMode( AllocationType CompilationDependencies::DependOnPretenureMode(
const AllocationSiteRef& site) { const AllocationSiteRef& site) {
DCHECK(!site.IsNeverSerializedHeapObject()); if (!FLAG_allocation_site_pretenuring) return AllocationType::kYoung;
AllocationType allocation = site.GetAllocationType(); AllocationType allocation = site.GetAllocationType();
RecordDependency(zone_->New<PretenureModeDependency>(site, allocation)); RecordDependency(zone_->New<PretenureModeDependency>(site, allocation));
return allocation; return allocation;
...@@ -769,8 +752,6 @@ bool CompilationDependencies::DependOnPromiseThenProtector() { ...@@ -769,8 +752,6 @@ bool CompilationDependencies::DependOnPromiseThenProtector() {
void CompilationDependencies::DependOnElementsKind( void CompilationDependencies::DependOnElementsKind(
const AllocationSiteRef& site) { const AllocationSiteRef& site) {
DCHECK(!site.IsNeverSerializedHeapObject());
// Do nothing if the object doesn't have any useful element transitions left.
ElementsKind kind = site.PointsToLiteral() ElementsKind kind = site.PointsToLiteral()
? site.boilerplate().value().map().elements_kind() ? site.boilerplate().value().map().elements_kind()
: site.GetElementsKind(); : site.GetElementsKind();
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/flags/flags.h" #include "src/flags/flags.h"
#include "src/objects/js-objects.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -74,6 +75,14 @@ inline std::ostream& operator<<(std::ostream& os, ...@@ -74,6 +75,14 @@ inline std::ostream& operator<<(std::ostream& os,
return os; return os;
} }
// Maximum depth and total number of elements and properties for literal
// graphs to be considered for fast deep-copying. The limit is chosen to
// match the maximum number of inobject properties, to ensure that the
// performance of using object literals is not worse than using constructor
// functions, see crbug.com/v8/6211 for details.
const int kMaxFastLiteralDepth = 3;
const int kMaxFastLiteralProperties = JSObject::kMaxInObjectProperties;
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
This diff is collapsed.
...@@ -105,7 +105,7 @@ enum class RefSerializationKind { ...@@ -105,7 +105,7 @@ enum class RefSerializationKind {
V(JSObject, RefSerializationKind::kBackgroundSerialized) \ V(JSObject, RefSerializationKind::kBackgroundSerialized) \
/* Subtypes of HeapObject */ \ /* Subtypes of HeapObject */ \
V(AccessorInfo, RefSerializationKind::kNeverSerialized) \ V(AccessorInfo, RefSerializationKind::kNeverSerialized) \
V(AllocationSite, RefSerializationKind::kSerialized) \ V(AllocationSite, RefSerializationKind::kNeverSerialized) \
V(ArrayBoilerplateDescription, RefSerializationKind::kNeverSerialized) \ V(ArrayBoilerplateDescription, RefSerializationKind::kNeverSerialized) \
V(BigInt, RefSerializationKind::kBackgroundSerialized) \ V(BigInt, RefSerializationKind::kBackgroundSerialized) \
V(CallHandlerInfo, RefSerializationKind::kNeverSerialized) \ V(CallHandlerInfo, RefSerializationKind::kNeverSerialized) \
...@@ -319,6 +319,8 @@ class JSObjectRef : public JSReceiverRef { ...@@ -319,6 +319,8 @@ class JSObjectRef : public JSReceiverRef {
Handle<JSObject> object() const; Handle<JSObject> object() const;
base::Optional<ObjectRef> raw_properties_or_hash() const;
// Usable only for in-object properties. Only use this if the underlying // Usable only for in-object properties. Only use this if the underlying
// value can be an uninitialized-sentinel, or if HeapNumber construction must // value can be an uninitialized-sentinel, or if HeapNumber construction must
// be avoided for some reason. Otherwise, use the higher-level // be avoided for some reason. Otherwise, use the higher-level
...@@ -368,6 +370,8 @@ class JSObjectRef : public JSReceiverRef { ...@@ -368,6 +370,8 @@ class JSObjectRef : public JSReceiverRef {
void SerializeObjectCreateMap(); void SerializeObjectCreateMap();
base::Optional<MapRef> GetObjectCreateMap() const; base::Optional<MapRef> GetObjectCreateMap() const;
void SerializeAsBoilerplateRecursive();
}; };
class JSDataViewRef : public JSObjectRef { class JSDataViewRef : public JSObjectRef {
...@@ -617,18 +621,9 @@ class AllocationSiteRef : public HeapObjectRef { ...@@ -617,18 +621,9 @@ class AllocationSiteRef : public HeapObjectRef {
AllocationType GetAllocationType() const; AllocationType GetAllocationType() const;
ObjectRef nested_site() const; ObjectRef nested_site() const;
// {IsFastLiteral} determines whether the given array or object literal void SerializeRecursive();
// boilerplate satisfies all limits to be considered for fast deep-copying
// and computes the total size of all objects that are part of the graph.
//
// If PointsToLiteral() is false, then IsFastLiteral() is also false.
bool IsFastLiteral() const;
void SerializeBoilerplate();
// We only serialize boilerplate if IsFastLiteral is true.
base::Optional<JSObjectRef> boilerplate() const; base::Optional<JSObjectRef> boilerplate() const;
ElementsKind GetElementsKind() const; ElementsKind GetElementsKind() const;
bool CanInlineCall() const; bool CanInlineCall() const;
}; };
......
...@@ -4198,7 +4198,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread( ...@@ -4198,7 +4198,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
int new_argument_count; int new_argument_count;
// Find array length and elements' kind from the feedback's allocation // Find array length and elements' kind from the feedback's allocation
// site's boilerplate JSArray.. // site's boilerplate JSArray.
JSCreateLiteralOpNode args_node(arguments_list); JSCreateLiteralOpNode args_node(arguments_list);
CreateLiteralParameters const& args_params = args_node.Parameters(); CreateLiteralParameters const& args_params = args_node.Parameters();
const FeedbackSource& array_feedback = args_params.feedback(); const FeedbackSource& array_feedback = args_params.feedback();
...@@ -4207,8 +4207,6 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread( ...@@ -4207,8 +4207,6 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
if (feedback.IsInsufficient()) return NoChange(); if (feedback.IsInsufficient()) return NoChange();
AllocationSiteRef site = feedback.AsLiteral().value(); AllocationSiteRef site = feedback.AsLiteral().value();
if (!site.IsFastLiteral()) return NoChange();
base::Optional<JSArrayRef> boilerplate_array = base::Optional<JSArrayRef> boilerplate_array =
site.boilerplate()->AsJSArray(); site.boilerplate()->AsJSArray();
int const array_length = boilerplate_array->GetBoilerplateLength().AsSmi(); int const array_length = boilerplate_array->GetBoilerplateLength().AsSmi();
......
...@@ -1095,27 +1095,18 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) { ...@@ -1095,27 +1095,18 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback()); broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback());
if (!feedback.IsInsufficient()) { if (!feedback.IsInsufficient()) {
AllocationSiteRef site = feedback.AsLiteral().value(); AllocationSiteRef site = feedback.AsLiteral().value();
if (site.IsFastLiteral()) { if (!site.boilerplate().has_value()) return NoChange();
AllocationType allocation = FLAG_allocation_site_pretenuring AllocationType allocation = dependencies()->DependOnPretenureMode(site);
? site.GetAllocationType() int max_properties = kMaxFastLiteralProperties;
: AllocationType::kYoung; base::Optional<Node*> maybe_value =
JSObjectRef boilerplate = site.boilerplate().value(); TryAllocateFastLiteral(effect, control, *site.boilerplate(), allocation,
base::Optional<Node*> maybe_value = kMaxFastLiteralDepth, &max_properties);
TryAllocateFastLiteral(effect, control, boilerplate, allocation); if (!maybe_value.has_value()) return NoChange();
if (!maybe_value.has_value()) { dependencies()->DependOnElementsKinds(site);
TRACE_BROKER_MISSING(broker(), "bound argument"); Node* value = effect = maybe_value.value();
return NoChange(); ReplaceWithValue(node, value, effect, control);
} return Replace(value);
if (FLAG_allocation_site_pretenuring) {
CHECK_EQ(dependencies()->DependOnPretenureMode(site), allocation);
}
dependencies()->DependOnElementsKinds(site);
Node* value = effect = maybe_value.value();
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
} }
return NoChange(); return NoChange();
} }
...@@ -1660,20 +1651,48 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control, ...@@ -1660,20 +1651,48 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral( base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral(
Node* effect, Node* control, JSObjectRef boilerplate, Node* effect, Node* control, JSObjectRef boilerplate,
AllocationType allocation) { AllocationType allocation, int max_depth, int* max_properties) {
DCHECK_GE(max_depth, 0);
DCHECK_GE(*max_properties, 0);
if (max_depth == 0) return {};
// Prevent concurrent migrations of boilerplate objects. // Prevent concurrent migrations of boilerplate objects.
JSHeapBroker::BoilerplateMigrationGuardIfNeeded boilerplate_access_guard( JSHeapBroker::BoilerplateMigrationGuardIfNeeded boilerplate_access_guard(
broker()); broker());
// Now that we hold the migration lock, get the current map. // Now that we hold the migration lock, get the current map.
MapRef boilerplate_map = boilerplate.map(); MapRef boilerplate_map = boilerplate.map();
base::Optional<MapRef> current_boilerplate_map = {
boilerplate.map_direct_read(); base::Optional<MapRef> current_boilerplate_map =
boilerplate.map_direct_read();
if (!current_boilerplate_map.has_value() ||
!current_boilerplate_map->equals(boilerplate_map)) {
return {};
}
}
// Bail out if the boilerplate map has been deprecated. The map could of
// course be deprecated at some point after the line below, but it's not a
// correctness issue -- it only means the literal won't be created with the
// most up to date map(s).
if (boilerplate_map.is_deprecated()) return {};
if (!current_boilerplate_map.has_value() || // We currently only support in-object properties.
!current_boilerplate_map.value().equals(boilerplate_map)) { if (boilerplate.map().elements_kind() == DICTIONARY_ELEMENTS ||
boilerplate.map().is_dictionary_map() ||
!boilerplate.raw_properties_or_hash().has_value()) {
return {}; return {};
} }
{
ObjectRef properties = *boilerplate.raw_properties_or_hash();
bool const empty = properties.IsSmi() ||
properties.equals(MakeRef<Object>(
broker(), factory()->empty_fixed_array())) ||
properties.equals(MakeRef<Object>(
broker(), factory()->empty_property_array()));
if (!empty) return {};
}
// Compute the in-object properties to store first (might have effects). // Compute the in-object properties to store first (might have effects).
ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone()); ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone());
...@@ -1684,6 +1703,8 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral( ...@@ -1684,6 +1703,8 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral(
boilerplate_map.GetPropertyDetails(i); boilerplate_map.GetPropertyDetails(i);
if (property_details.location() != kField) continue; if (property_details.location() != kField) continue;
DCHECK_EQ(kData, property_details.kind()); DCHECK_EQ(kData, property_details.kind());
if ((*max_properties)-- == 0) return {};
NameRef property_name = boilerplate_map.GetPropertyKey(i); NameRef property_name = boilerplate_map.GetPropertyKey(i);
FieldIndex index = boilerplate_map.GetFieldIndexFor(i); FieldIndex index = boilerplate_map.GetFieldIndexFor(i);
ConstFieldInfo const_field_info(boilerplate_map.object()); ConstFieldInfo const_field_info(boilerplate_map.object());
...@@ -1730,8 +1751,9 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral( ...@@ -1730,8 +1751,9 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral(
Node* value; Node* value;
if (boilerplate_value.IsJSObject()) { if (boilerplate_value.IsJSObject()) {
JSObjectRef boilerplate_object = boilerplate_value.AsJSObject(); JSObjectRef boilerplate_object = boilerplate_value.AsJSObject();
base::Optional<Node*> maybe_value = TryAllocateFastLiteral( base::Optional<Node*> maybe_value =
effect, control, boilerplate_object, allocation); TryAllocateFastLiteral(effect, control, boilerplate_object,
allocation, max_depth - 1, max_properties);
if (!maybe_value.has_value()) return {}; if (!maybe_value.has_value()) return {};
value = effect = maybe_value.value(); value = effect = maybe_value.value();
} else if (property_details.representation().IsDouble()) { } else if (property_details.representation().IsDouble()) {
...@@ -1770,8 +1792,8 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral( ...@@ -1770,8 +1792,8 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral(
} }
// Setup the elements backing store. // Setup the elements backing store.
base::Optional<Node*> maybe_elements = base::Optional<Node*> maybe_elements = TryAllocateFastLiteralElements(
TryAllocateFastLiteralElements(effect, control, boilerplate, allocation); effect, control, boilerplate, allocation, max_depth, max_properties);
if (!maybe_elements.has_value()) return {}; if (!maybe_elements.has_value()) return {};
Node* elements = maybe_elements.value(); Node* elements = maybe_elements.value();
if (elements->op()->EffectOutputCount() > 0) effect = elements; if (elements->op()->EffectOutputCount() > 0) effect = elements;
...@@ -1798,7 +1820,10 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral( ...@@ -1798,7 +1820,10 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral(
base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements( base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements(
Node* effect, Node* control, JSObjectRef boilerplate, Node* effect, Node* control, JSObjectRef boilerplate,
AllocationType allocation) { AllocationType allocation, int max_depth, int* max_properties) {
DCHECK_GT(max_depth, 0);
DCHECK_GE(*max_properties, 0);
base::Optional<FixedArrayBaseRef> maybe_boilerplate_elements = base::Optional<FixedArrayBaseRef> maybe_boilerplate_elements =
boilerplate.elements(kRelaxedLoad); boilerplate.elements(kRelaxedLoad);
if (!maybe_boilerplate_elements.has_value()) return {}; if (!maybe_boilerplate_elements.has_value()) return {};
...@@ -1812,34 +1837,36 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements( ...@@ -1812,34 +1837,36 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements(
!boilerplate.IsElementsTenured(boilerplate_elements)) { !boilerplate.IsElementsTenured(boilerplate_elements)) {
return {}; return {};
} }
return jsgraph()->HeapConstant(boilerplate_elements.object()); return jsgraph()->Constant(boilerplate_elements);
} }
// Compute the elements to store first (might have effects). // Compute the elements to store first (might have effects).
ZoneVector<Node*> elements_values(elements_length, zone()); ZoneVector<Node*> elements_values(elements_length, zone());
if (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) { if (boilerplate_elements.IsFixedDoubleArray()) {
int const size = FixedDoubleArray::SizeFor(boilerplate_elements.length());
if (size > kMaxRegularHeapObjectSize) return {};
FixedDoubleArrayRef elements = boilerplate_elements.AsFixedDoubleArray(); FixedDoubleArrayRef elements = boilerplate_elements.AsFixedDoubleArray();
for (int i = 0; i < elements_length; ++i) { for (int i = 0; i < elements_length; ++i) {
Float64 value = elements.GetFromImmutableFixedDoubleArray(i); Float64 value = elements.GetFromImmutableFixedDoubleArray(i);
if (value.is_hole_nan()) { elements_values[i] = value.is_hole_nan()
elements_values[i] = jsgraph()->TheHoleConstant(); ? jsgraph()->TheHoleConstant()
} else { : jsgraph()->Constant(value.get_scalar());
elements_values[i] = jsgraph()->Constant(value.get_scalar());
}
} }
} else { } else {
FixedArrayRef elements = boilerplate_elements.AsFixedArray(); FixedArrayRef elements = boilerplate_elements.AsFixedArray();
for (int i = 0; i < elements_length; ++i) { for (int i = 0; i < elements_length; ++i) {
base::Optional<ObjectRef> maybe_element_value = elements.TryGet(i); if ((*max_properties)-- == 0) return {};
if (!maybe_element_value.has_value()) return {}; base::Optional<ObjectRef> element_value = elements.TryGet(i);
ObjectRef element_value = maybe_element_value.value(); if (!element_value.has_value()) return {};
if (element_value.IsJSObject()) { if (element_value->IsJSObject()) {
base::Optional<Node*> maybe_value = TryAllocateFastLiteral( base::Optional<Node*> object =
effect, control, element_value.AsJSObject(), allocation); TryAllocateFastLiteral(effect, control, element_value->AsJSObject(),
if (!maybe_value.has_value()) return {}; allocation, max_depth - 1, max_properties);
elements_values[i] = effect = maybe_value.value(); if (!object.has_value()) return {};
elements_values[i] = effect = *object;
} else { } else {
elements_values[i] = jsgraph()->Constant(element_value); elements_values[i] = jsgraph()->Constant(*element_value);
} }
} }
} }
...@@ -1848,10 +1875,9 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements( ...@@ -1848,10 +1875,9 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements(
AllocationBuilder ab(jsgraph(), effect, control); AllocationBuilder ab(jsgraph(), effect, control);
CHECK(ab.CanAllocateArray(elements_length, elements_map, allocation)); CHECK(ab.CanAllocateArray(elements_length, elements_map, allocation));
ab.AllocateArray(elements_length, elements_map, allocation); ab.AllocateArray(elements_length, elements_map, allocation);
ElementAccess const access = ElementAccess const access = boilerplate_elements.IsFixedDoubleArray()
(elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) ? AccessBuilder::ForFixedDoubleArrayElement()
? AccessBuilder::ForFixedDoubleArrayElement() : AccessBuilder::ForFixedArrayElement();
: AccessBuilder::ForFixedArrayElement();
for (int i = 0; i < elements_length; ++i) { for (int i = 0; i < elements_length; ++i) {
ab.Store(access, jsgraph()->Constant(i), elements_values[i]); ab.Store(access, jsgraph()->Constant(i), elements_values[i]);
} }
......
...@@ -99,10 +99,12 @@ class V8_EXPORT_PRIVATE JSCreateLowering final ...@@ -99,10 +99,12 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
bool* has_aliased_arguments); bool* has_aliased_arguments);
base::Optional<Node*> TryAllocateFastLiteral(Node* effect, Node* control, base::Optional<Node*> TryAllocateFastLiteral(Node* effect, Node* control,
JSObjectRef boilerplate, JSObjectRef boilerplate,
AllocationType allocation); AllocationType allocation,
int max_depth,
int* max_properties);
base::Optional<Node*> TryAllocateFastLiteralElements( base::Optional<Node*> TryAllocateFastLiteralElements(
Node* effect, Node* control, JSObjectRef boilerplate, Node* effect, Node* control, JSObjectRef boilerplate,
AllocationType allocation); AllocationType allocation, int max_depth, int* max_properties);
Node* AllocateElements(Node* effect, Node* control, Node* AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind, int capacity, ElementsKind elements_kind, int capacity,
......
...@@ -762,12 +762,8 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForArrayOrObjectLiteral( ...@@ -762,12 +762,8 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForArrayOrObjectLiteral(
return NewInsufficientFeedback(nexus.kind()); return NewInsufficientFeedback(nexus.kind());
} }
AllocationSiteRef site = AllocationSiteRef site = MakeRef(this, AllocationSite::cast(object));
MakeRef(this, handle(AllocationSite::cast(object), isolate())); if (site.PointsToLiteral()) site.SerializeRecursive();
if (site.IsFastLiteral()) {
site.SerializeBoilerplate();
}
return *zone()->New<LiteralFeedback>(site, nexus.kind()); return *zone()->New<LiteralFeedback>(site, nexus.kind());
} }
......
...@@ -30,7 +30,7 @@ ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object, ...@@ -30,7 +30,7 @@ ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object,
RELEASE_ACQUIRE_ACCESSORS(AllocationSite, transition_info_or_boilerplate, RELEASE_ACQUIRE_ACCESSORS(AllocationSite, transition_info_or_boilerplate,
Object, kTransitionInfoOrBoilerplateOffset) Object, kTransitionInfoOrBoilerplateOffset)
ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset) ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset) RELAXED_INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset)
INT32_ACCESSORS(AllocationSite, pretenure_create_count, INT32_ACCESSORS(AllocationSite, pretenure_create_count,
kPretenureCreateCountOffset) kPretenureCreateCountOffset)
ACCESSORS(AllocationSite, dependent_code, DependentCode, kDependentCodeOffset) ACCESSORS(AllocationSite, dependent_code, DependentCode, kDependentCodeOffset)
...@@ -55,12 +55,13 @@ void AllocationSite::set_boilerplate(JSObject value, ReleaseStoreTag tag, ...@@ -55,12 +55,13 @@ void AllocationSite::set_boilerplate(JSObject value, ReleaseStoreTag tag,
int AllocationSite::transition_info() const { int AllocationSite::transition_info() const {
DCHECK(!PointsToLiteral()); DCHECK(!PointsToLiteral());
return Smi::cast(transition_info_or_boilerplate()).value(); return Smi::cast(transition_info_or_boilerplate(kAcquireLoad)).value();
} }
void AllocationSite::set_transition_info(int value) { void AllocationSite::set_transition_info(int value) {
DCHECK(!PointsToLiteral()); DCHECK(!PointsToLiteral());
set_transition_info_or_boilerplate(Smi::FromInt(value), SKIP_WRITE_BARRIER); set_transition_info_or_boilerplate(Smi::FromInt(value), kReleaseStore,
SKIP_WRITE_BARRIER);
} }
bool AllocationSite::HasWeakNext() const { bool AllocationSite::HasWeakNext() const {
...@@ -113,7 +114,7 @@ void AllocationSite::SetDoNotInlineCall() { ...@@ -113,7 +114,7 @@ void AllocationSite::SetDoNotInlineCall() {
} }
bool AllocationSite::PointsToLiteral() const { bool AllocationSite::PointsToLiteral() const {
Object raw_value = transition_info_or_boilerplate(); Object raw_value = transition_info_or_boilerplate(kAcquireLoad);
DCHECK_EQ(!raw_value.IsSmi(), DCHECK_EQ(!raw_value.IsSmi(),
raw_value.IsJSArray() || raw_value.IsJSObject()); raw_value.IsJSArray() || raw_value.IsJSObject());
return !raw_value.IsSmi(); return !raw_value.IsSmi();
...@@ -234,6 +235,7 @@ bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site, ...@@ -234,6 +235,7 @@ bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
is_nested ? "(nested)" : " ", ElementsKindToString(kind), is_nested ? "(nested)" : " ", ElementsKindToString(kind),
ElementsKindToString(to_kind)); ElementsKindToString(to_kind));
} }
CHECK_NE(to_kind, DICTIONARY_ELEMENTS);
JSObject::TransitionElementsKind(boilerplate, to_kind); JSObject::TransitionElementsKind(boilerplate, to_kind);
site->dependent_code().DeoptimizeDependentCodeGroup( site->dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kAllocationSiteTransitionChangedGroup); DependentCode::kAllocationSiteTransitionChangedGroup);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment