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
......
...@@ -435,7 +435,8 @@ class JSObjectData : public JSReceiverData { ...@@ -435,7 +435,8 @@ class JSObjectData : public JSReceiverData {
ObjectDataKind kind = kSerializedHeapObject); ObjectDataKind kind = kSerializedHeapObject);
// Recursive serialization of all reachable JSObjects. // Recursive serialization of all reachable JSObjects.
void SerializeAsBoilerplate(JSHeapBroker* broker); bool SerializeAsBoilerplateRecursive(JSHeapBroker* broker,
int max_depth = kMaxFastLiteralDepth);
ObjectData* GetInobjectField(int property_index) const; ObjectData* GetInobjectField(int property_index) const;
// Shallow serialization of {elements}. // Shallow serialization of {elements}.
...@@ -443,6 +444,8 @@ class JSObjectData : public JSReceiverData { ...@@ -443,6 +444,8 @@ class JSObjectData : public JSReceiverData {
bool serialized_elements() const { return serialized_elements_; } bool serialized_elements() const { return serialized_elements_; }
ObjectData* elements() const; ObjectData* elements() const;
ObjectData* raw_properties_or_hash() const { return raw_properties_or_hash_; }
void SerializeObjectCreateMap(JSHeapBroker* broker); void SerializeObjectCreateMap(JSHeapBroker* broker);
// Can be nullptr. // Can be nullptr.
...@@ -468,10 +471,14 @@ class JSObjectData : public JSReceiverData { ...@@ -468,10 +471,14 @@ class JSObjectData : public JSReceiverData {
// This method is only used to assert our invariants. // This method is only used to assert our invariants.
bool cow_or_empty_elements_tenured() const; bool cow_or_empty_elements_tenured() const;
private: bool has_extra_serialized_data() const {
void SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, int max_depths); return serialized_as_boilerplate_ || serialized_elements_ ||
serialized_object_create_map_;
}
private:
ObjectData* elements_ = nullptr; ObjectData* elements_ = nullptr;
ObjectData* raw_properties_or_hash_ = nullptr;
bool cow_or_empty_elements_tenured_ = false; bool cow_or_empty_elements_tenured_ = false;
// The {serialized_as_boilerplate} flag is set when all recursively // The {serialized_as_boilerplate} flag is set when all recursively
// reachable JSObjects are serialized. // reachable JSObjects are serialized.
...@@ -953,94 +960,6 @@ class InternalizedStringData : public StringData { ...@@ -953,94 +960,6 @@ class InternalizedStringData : public StringData {
} }
}; };
namespace {
bool IsFastLiteralHelper(Handle<JSObject> boilerplate, int max_depth,
int* max_properties) {
DCHECK_GE(max_depth, 0);
DCHECK_GE(*max_properties, 0);
// Check for too deep nesting.
if (max_depth == 0) return false;
Isolate* const isolate = boilerplate->GetIsolate();
// If the boilerplate map has been deprecated, bailout of fast literal
// optimization. The map could be deprecated at some point after the line
// below, but it's not a correctness issue -- it only means the literal isn't
// created with the most up to date map(s).
if (boilerplate->map().is_deprecated()) return false;
// Check the elements.
Handle<FixedArrayBase> elements(boilerplate->elements(), isolate);
if (elements->length() > 0 &&
elements->map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) {
if (boilerplate->HasSmiOrObjectElements()) {
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
int length = elements->length();
for (int i = 0; i < length; i++) {
if ((*max_properties)-- == 0) return false;
Handle<Object> value(fast_elements->get(i), isolate);
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
if (!IsFastLiteralHelper(value_object, max_depth - 1,
max_properties)) {
return false;
}
}
}
} else if (boilerplate->HasDoubleElements()) {
if (elements->Size() > kMaxRegularHeapObjectSize) return false;
} else {
return false;
}
}
// TODO(turbofan): Do we want to support out-of-object properties?
if (!(boilerplate->HasFastProperties() &&
boilerplate->property_array().length() == 0)) {
return false;
}
// Check the in-object properties.
Handle<DescriptorArray> descriptors(
boilerplate->map().instance_descriptors(isolate, kRelaxedLoad), isolate);
for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) {
PropertyDetails details = descriptors->GetDetails(i);
if (details.location() != kField) continue;
DCHECK_EQ(kData, details.kind());
if ((*max_properties)-- == 0) return false;
FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
if (!IsFastLiteralHelper(value_object, max_depth - 1, max_properties)) {
return false;
}
}
}
return true;
}
// 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;
// Determines whether the given array or object literal 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.
bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) {
int max_properties = kMaxFastLiteralProperties;
return IsFastLiteralHelper(boilerplate, kMaxFastLiteralDepth,
&max_properties);
}
} // namespace
class AccessorInfoData : public HeapObjectData { class AccessorInfoData : public HeapObjectData {
public: public:
AccessorInfoData(JSHeapBroker* broker, ObjectData** storage, AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
...@@ -1051,12 +970,11 @@ class AllocationSiteData : public HeapObjectData { ...@@ -1051,12 +970,11 @@ class AllocationSiteData : public HeapObjectData {
public: public:
AllocationSiteData(JSHeapBroker* broker, ObjectData** storage, AllocationSiteData(JSHeapBroker* broker, ObjectData** storage,
Handle<AllocationSite> object); Handle<AllocationSite> object);
void SerializeBoilerplate(JSHeapBroker* broker); void Serialize(JSHeapBroker* broker);
bool PointsToLiteral() const { return PointsToLiteral_; } bool PointsToLiteral() const { return PointsToLiteral_; }
AllocationType GetAllocationType() const { return GetAllocationType_; } AllocationType GetAllocationType() const { return GetAllocationType_; }
ObjectData* nested_site() const { return nested_site_; } ObjectData* nested_site() const { return nested_site_; }
bool IsFastLiteral() const { return IsFastLiteral_; }
ObjectData* boilerplate() const { return boilerplate_; } ObjectData* boilerplate() const { return boilerplate_; }
// These are only valid if PointsToLiteral is false. // These are only valid if PointsToLiteral is false.
...@@ -1067,11 +985,10 @@ class AllocationSiteData : public HeapObjectData { ...@@ -1067,11 +985,10 @@ class AllocationSiteData : public HeapObjectData {
bool const PointsToLiteral_; bool const PointsToLiteral_;
AllocationType const GetAllocationType_; AllocationType const GetAllocationType_;
ObjectData* nested_site_ = nullptr; ObjectData* nested_site_ = nullptr;
bool IsFastLiteral_ = false;
ObjectData* boilerplate_ = nullptr; ObjectData* boilerplate_ = nullptr;
ElementsKind GetElementsKind_ = NO_ELEMENTS; ElementsKind GetElementsKind_ = NO_ELEMENTS;
bool CanInlineCall_ = false; bool CanInlineCall_ = false;
bool serialized_boilerplate_ = false; bool serialized_ = false;
}; };
class BigIntData : public HeapObjectData { class BigIntData : public HeapObjectData {
...@@ -1244,34 +1161,27 @@ AllocationSiteData::AllocationSiteData(JSHeapBroker* broker, ...@@ -1244,34 +1161,27 @@ AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
: HeapObjectData(broker, storage, object), : HeapObjectData(broker, storage, object),
PointsToLiteral_(object->PointsToLiteral()), PointsToLiteral_(object->PointsToLiteral()),
GetAllocationType_(object->GetAllocationType()) { GetAllocationType_(object->GetAllocationType()) {
if (PointsToLiteral_) { DCHECK(!broker->is_concurrent_inlining());
IsFastLiteral_ = IsInlinableFastLiteral( if (!PointsToLiteral_) {
handle(object->boilerplate(kAcquireLoad), broker->isolate()));
} else {
GetElementsKind_ = object->GetElementsKind(); GetElementsKind_ = object->GetElementsKind();
CanInlineCall_ = object->CanInlineCall(); CanInlineCall_ = object->CanInlineCall();
} }
} }
void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) { void AllocationSiteData::Serialize(JSHeapBroker* broker) {
if (serialized_boilerplate_) return; if (serialized_) return;
serialized_boilerplate_ = true; serialized_ = true;
TraceScope tracer(broker, this, "AllocationSiteData::SerializeBoilerplate"); TraceScope tracer(broker, this, "AllocationSiteData::Serialize");
Handle<AllocationSite> site = Handle<AllocationSite>::cast(object()); Handle<AllocationSite> site = Handle<AllocationSite>::cast(object());
CHECK(IsFastLiteral_); if (PointsToLiteral_) {
DCHECK_NULL(boilerplate_); DCHECK_NULL(boilerplate_);
boilerplate_ = broker->GetOrCreateData(site->boilerplate(kAcquireLoad)); boilerplate_ = broker->GetOrCreateData(site->boilerplate(kAcquireLoad));
if (!boilerplate_->should_access_heap()) {
boilerplate_->AsJSObject()->SerializeAsBoilerplate(broker);
} }
DCHECK_NULL(nested_site_); DCHECK_NULL(nested_site_);
nested_site_ = broker->GetOrCreateData(site->nested_site()); nested_site_ = broker->GetOrCreateData(site->nested_site());
if (nested_site_->IsAllocationSite() && !nested_site_->should_access_heap()) {
nested_site_->AsAllocationSite()->SerializeBoilerplate(broker);
}
} }
HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage, HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
...@@ -2125,10 +2035,6 @@ ObjectData* JSObjectData::elements() const { ...@@ -2125,10 +2035,6 @@ ObjectData* JSObjectData::elements() const {
return elements_; return elements_;
} }
void JSObjectData::SerializeAsBoilerplate(JSHeapBroker* broker) {
SerializeRecursiveAsBoilerplate(broker, kMaxFastLiteralDepth);
}
void JSObjectData::SerializeElements(JSHeapBroker* broker) { void JSObjectData::SerializeElements(JSHeapBroker* broker) {
if (serialized_elements_) return; if (serialized_elements_) return;
serialized_elements_ = true; serialized_elements_ = true;
...@@ -2237,18 +2143,17 @@ void MapData::SerializeRootMap(JSHeapBroker* broker) { ...@@ -2237,18 +2143,17 @@ void MapData::SerializeRootMap(JSHeapBroker* broker) {
ObjectData* MapData::FindRootMap() const { return root_map_; } ObjectData* MapData::FindRootMap() const { return root_map_; }
void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, bool JSObjectData::SerializeAsBoilerplateRecursive(JSHeapBroker* broker,
int depth) { int max_depth) {
if (serialized_as_boilerplate_) return; if (serialized_as_boilerplate_) return true;
serialized_as_boilerplate_ = true; // If serialization succeeds, we set this to true at the end.
TraceScope tracer(broker, this, TraceScope tracer(broker, this,
"JSObjectData::SerializeRecursiveAsBoilerplate"); "JSObjectData::SerializeAsBoilerplateRecursive");
Handle<JSObject> boilerplate = Handle<JSObject>::cast(object()); Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
// We only serialize boilerplates that pass the IsInlinableFastLiteral DCHECK_GE(max_depth, 0);
// check, so we only do a check on the depth here. if (max_depth == 0) return false;
CHECK_GT(depth, 0);
// Serialize the elements. // Serialize the elements.
Isolate* const isolate = broker->isolate(); Isolate* const isolate = broker->isolate();
...@@ -2264,41 +2169,24 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, ...@@ -2264,41 +2169,24 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
cow_or_empty_elements_tenured_ = !ObjectInYoungGeneration(*elements_object); cow_or_empty_elements_tenured_ = !ObjectInYoungGeneration(*elements_object);
} }
DCHECK_NULL(elements_); raw_properties_or_hash_ =
DCHECK(!serialized_elements_); broker->GetOrCreateData(boilerplate->raw_properties_or_hash());
serialized_elements_ = true; serialized_elements_ = true;
elements_ = broker->GetOrCreateData(elements_object); elements_ = broker->GetOrCreateData(elements_object);
DCHECK(elements_->IsFixedArrayBase()); DCHECK(elements_->IsFixedArrayBase());
if (empty_or_cow || elements_->should_access_heap()) { if (!boilerplate->HasFastProperties() ||
// No need to do anything here. Empty or copy-on-write elements boilerplate->property_array().length() != 0) {
// do not need to be serialized because we only need to store the elements return false;
// reference to the allocated object.
} else if (boilerplate->HasSmiOrObjectElements()) {
Handle<FixedArray> fast_elements =
Handle<FixedArray>::cast(elements_object);
int length = elements_object->length();
for (int i = 0; i < length; i++) {
Handle<Object> value(fast_elements->get(i), isolate);
if (value->IsJSObject()) {
ObjectData* value_data = broker->GetOrCreateData(value);
if (!value_data->should_access_heap()) {
value_data->AsJSObject()->SerializeRecursiveAsBoilerplate(broker,
depth - 1);
}
}
}
} else {
CHECK(boilerplate->HasDoubleElements());
CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize);
} }
// TODO(turbofan): Do we want to support out-of-object properties? if (!map()->should_access_heap()) {
CHECK(boilerplate->HasFastProperties() && map()->AsMap()->SerializeOwnDescriptors(broker);
boilerplate->property_array().length() == 0); }
CHECK_EQ(inobject_fields_.size(), 0u);
// Check the in-object properties. // Check the in-object properties.
inobject_fields_.clear();
Handle<DescriptorArray> descriptors( Handle<DescriptorArray> descriptors(
boilerplate->map().instance_descriptors(isolate), isolate); boilerplate->map().instance_descriptors(isolate), isolate);
for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) { for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) {
...@@ -2313,21 +2201,47 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, ...@@ -2313,21 +2201,47 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
static_cast<int>(inobject_fields_.size())); static_cast<int>(inobject_fields_.size()));
Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate); Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
ObjectData* value_data = broker->GetOrCreateData(value); ObjectData* value_data = broker->GetOrCreateData(value);
inobject_fields_.push_back(value_data);
if (value_data->IsJSObject() && !value_data->should_access_heap()) { if (value_data->IsJSObject() && !value_data->should_access_heap()) {
value_data->AsJSObject()->SerializeRecursiveAsBoilerplate(broker, if (!value_data->AsJSObject()->SerializeAsBoilerplateRecursive(
depth - 1); broker, max_depth - 1))
return false;
} }
inobject_fields_.push_back(value_data);
} }
TRACE(broker, "Copied " << inobject_fields_.size() << " in-object fields"); TRACE(broker, "Copied " << inobject_fields_.size() << " in-object fields");
if (!map()->should_access_heap()) { if (empty_or_cow || elements_->should_access_heap()) {
map()->AsMap()->SerializeOwnDescriptors(broker); // No need to do anything here. Empty or copy-on-write elements
// do not need to be serialized because we only need to store the elements
// reference to the allocated object.
} else if (boilerplate->HasSmiOrObjectElements()) {
Handle<FixedArray> fast_elements =
Handle<FixedArray>::cast(elements_object);
int length = elements_object->length();
for (int i = 0; i < length; i++) {
Handle<Object> value(fast_elements->get(i), isolate);
if (value->IsJSObject()) {
ObjectData* value_data = broker->GetOrCreateData(value);
if (!value_data->should_access_heap()) {
if (!value_data->AsJSObject()->SerializeAsBoilerplateRecursive(
broker, max_depth - 1)) {
return false;
}
}
}
}
} else {
if (!boilerplate->HasDoubleElements()) return false;
int const size = FixedDoubleArray::SizeFor(elements_object->length());
if (size > kMaxRegularHeapObjectSize) return false;
} }
if (IsJSArray() && !broker->is_concurrent_inlining()) { if (IsJSArray() && !broker->is_concurrent_inlining()) {
AsJSArray()->Serialize(broker); AsJSArray()->Serialize(broker);
} }
serialized_as_boilerplate_ = true;
return true;
} }
#ifdef DEBUG #ifdef DEBUG
...@@ -2632,6 +2546,11 @@ void JSHeapBroker::ClearReconstructibleData() { ...@@ -2632,6 +2546,11 @@ void JSHeapBroker::ClearReconstructibleData() {
value->AsMap()->has_extra_serialized_data()) { value->AsMap()->has_extra_serialized_data()) {
continue; continue;
} }
if (value->IsJSObject() &&
value->kind() == ObjectDataKind::kBackgroundSerializedHeapObject &&
value->AsJSObject()->has_extra_serialized_data()) {
continue;
}
// Can be reconstructed from the background thread. // Can be reconstructed from the background thread.
CHECK_NOT_NULL(refs_->Remove(key)); CHECK_NOT_NULL(refs_->Remove(key));
} }
...@@ -2836,6 +2755,13 @@ FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const { ...@@ -2836,6 +2755,13 @@ FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const {
data()->AsFeedbackVector()->GetClosureFeedbackCell(broker(), index)); data()->AsFeedbackVector()->GetClosureFeedbackCell(broker(), index));
} }
base::Optional<ObjectRef> JSObjectRef::raw_properties_or_hash() const {
if (data_->should_access_heap()) {
return TryMakeRef(broker(), object()->raw_properties_or_hash());
}
return ObjectRef(broker(), data()->AsJSObject()->raw_properties_or_hash());
}
base::Optional<ObjectRef> JSObjectRef::RawInobjectPropertyAt( base::Optional<ObjectRef> JSObjectRef::RawInobjectPropertyAt(
FieldIndex index) const { FieldIndex index) const {
CHECK(index.is_inobject()); CHECK(index.is_inobject());
...@@ -2864,19 +2790,23 @@ base::Optional<ObjectRef> JSObjectRef::RawInobjectPropertyAt( ...@@ -2864,19 +2790,23 @@ base::Optional<ObjectRef> JSObjectRef::RawInobjectPropertyAt(
object_data->GetInobjectField(index.property_index())); object_data->GetInobjectField(index.property_index()));
} }
bool AllocationSiteRef::IsFastLiteral() const { void JSObjectRef::SerializeAsBoilerplateRecursive() {
if (data_->should_access_heap()) {
CHECK_NE(data_->kind(), ObjectDataKind::kNeverSerializedHeapObject);
return IsInlinableFastLiteral(
handle(object()->boilerplate(kAcquireLoad), broker()->isolate()));
}
return data()->AsAllocationSite()->IsFastLiteral();
}
void AllocationSiteRef::SerializeBoilerplate() {
if (data_->should_access_heap()) return; if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsAllocationSite()->SerializeBoilerplate(broker()); data()->AsJSObject()->SerializeAsBoilerplateRecursive(broker());
}
void AllocationSiteRef::SerializeRecursive() {
if (!data_->should_access_heap()) {
data()->AsAllocationSite()->Serialize(broker());
}
if (boilerplate().has_value()) {
boilerplate()->SerializeAsBoilerplateRecursive();
}
if (nested_site().IsAllocationSite()) {
nested_site().AsAllocationSite().SerializeRecursive();
}
} }
void JSObjectRef::SerializeElements() { void JSObjectRef::SerializeElements() {
...@@ -3020,6 +2950,7 @@ base::Optional<ObjectRef> FixedArrayRef::TryGet(int i) const { ...@@ -3020,6 +2950,7 @@ base::Optional<ObjectRef> FixedArrayRef::TryGet(int i) const {
Float64 FixedDoubleArrayRef::GetFromImmutableFixedDoubleArray(int i) const { Float64 FixedDoubleArrayRef::GetFromImmutableFixedDoubleArray(int i) const {
STATIC_ASSERT(ref_traits<FixedDoubleArray>::ref_serialization_kind == STATIC_ASSERT(ref_traits<FixedDoubleArray>::ref_serialization_kind ==
RefSerializationKind::kNeverSerialized); RefSerializationKind::kNeverSerialized);
CHECK(data_->should_access_heap());
return Float64::FromBits(object()->get_representation(i)); return Float64::FromBits(object()->get_representation(i));
} }
...@@ -3938,15 +3869,13 @@ HeapObjectType HeapObjectRef::GetHeapObjectType() const { ...@@ -3938,15 +3869,13 @@ HeapObjectType HeapObjectRef::GetHeapObjectType() const {
} }
base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const { base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const {
if (!PointsToLiteral()) return {};
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
return TryMakeRef(broker(), object()->boilerplate(kAcquireLoad)); return TryMakeRef(broker(), object()->boilerplate(kAcquireLoad));
} }
ObjectData* boilerplate = data()->AsAllocationSite()->boilerplate(); ObjectData* boilerplate = data()->AsAllocationSite()->boilerplate();
if (boilerplate) { if (boilerplate == nullptr) return {};
return JSObjectRef(broker(), boilerplate); return JSObjectRef(broker(), boilerplate);
} else {
return base::nullopt;
}
} }
base::Optional<FixedArrayBaseRef> JSObjectRef::elements( base::Optional<FixedArrayBaseRef> JSObjectRef::elements(
......
...@@ -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;
JSObjectRef boilerplate = site.boilerplate().value();
base::Optional<Node*> maybe_value = base::Optional<Node*> maybe_value =
TryAllocateFastLiteral(effect, control, boilerplate, allocation); TryAllocateFastLiteral(effect, control, *site.boilerplate(), allocation,
if (!maybe_value.has_value()) { kMaxFastLiteralDepth, &max_properties);
TRACE_BROKER_MISSING(broker(), "bound argument"); if (!maybe_value.has_value()) return NoChange();
return NoChange();
}
if (FLAG_allocation_site_pretenuring) {
CHECK_EQ(dependencies()->DependOnPretenureMode(site), allocation);
}
dependencies()->DependOnElementsKinds(site); dependencies()->DependOnElementsKinds(site);
Node* value = effect = maybe_value.value(); Node* value = effect = maybe_value.value();
ReplaceWithValue(node, value, effect, control); ReplaceWithValue(node, value, effect, control);
return Replace(value); 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 = base::Optional<MapRef> current_boilerplate_map =
boilerplate.map_direct_read(); boilerplate.map_direct_read();
if (!current_boilerplate_map.has_value() || if (!current_boilerplate_map.has_value() ||
!current_boilerplate_map.value().equals(boilerplate_map)) { !current_boilerplate_map->equals(boilerplate_map)) {
return {}; 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 {};
// We currently only support in-object properties.
if (boilerplate.map().elements_kind() == DICTIONARY_ELEMENTS ||
boilerplate.map().is_dictionary_map() ||
!boilerplate.raw_properties_or_hash().has_value()) {
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,8 +1875,7 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements( ...@@ -1848,8 +1875,7 @@ 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) {
......
...@@ -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