Commit 09f374ac authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Make FixedDoubleArrayRefs never-serialized

FixedDoubleArrays are a special case:

1 The reads are 64-bit and unaligned, thus use memcpy underneath.
2 The compiler only reads FDArray values for (constant) boilerplate
  elements.

1) makes proper atomic reads tricky-to-impossible without a lock.
Luckily, 2) means we know that the array values are immutable after
initialization, thus we can simply do a non-atomic read from the
compiler thread.

Bug: v8:7790
Change-Id: I39698d867543ce2214a2148511c5d90ced6364b3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2848410
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74226}
parent 99c04341
...@@ -444,7 +444,7 @@ class ElementsKindDependency final : public CompilationDependency { ...@@ -444,7 +444,7 @@ class ElementsKindDependency final : public CompilationDependency {
bool IsValid() const override { bool IsValid() const override {
Handle<AllocationSite> site = site_.object(); Handle<AllocationSite> site = site_.object();
ElementsKind kind = site->PointsToLiteral() ElementsKind kind = site->PointsToLiteral()
? site->boilerplate().GetElementsKind() ? site->boilerplate(kAcquireLoad).GetElementsKind()
: site->GetElementsKind(); : site->GetElementsKind();
return kind_ == kind; return kind_ == kind;
} }
......
...@@ -157,13 +157,11 @@ constexpr RefSerializationKind RefSerializationKindOf() { ...@@ -157,13 +157,11 @@ constexpr RefSerializationKind RefSerializationKindOf() {
return RefSerializationKind::kSerialized; return RefSerializationKind::kSerialized;
} }
#define DEFINE_REF_SERIALIZATION_KIND(Name, Kind) \ #define DEFINE_REF_SERIALIZATION_KIND(Name, Kind) \
template <> \ template <> \
constexpr RefSerializationKind RefSerializationKindOf<Name>() { \ constexpr RefSerializationKind RefSerializationKindOf<Name>() { \
return Kind; \ return Kind; \
} \ }
/* The static assert is needed to avoid 'unused function' warnings. */ \
STATIC_ASSERT(RefSerializationKindOf<Name>() == Kind);
HEAP_BROKER_OBJECT_LIST(DEFINE_REF_SERIALIZATION_KIND) HEAP_BROKER_OBJECT_LIST(DEFINE_REF_SERIALIZATION_KIND)
#undef DEFINE_REF_SERIALIZATION_KIND #undef DEFINE_REF_SERIALIZATION_KIND
...@@ -172,6 +170,21 @@ constexpr bool IsSerializedRef() { ...@@ -172,6 +170,21 @@ constexpr bool IsSerializedRef() {
return RefSerializationKindOf<T>() == RefSerializationKind::kSerialized; return RefSerializationKindOf<T>() == RefSerializationKind::kSerialized;
} }
RefSerializationKind RefSerializationKindOf(ObjectData* const data) {
Object o = *data->object();
if (o.IsSmi()) {
return RefSerializationKind::kNeverSerialized;
#define DEFINE_REF_SERIALIZATION_KIND(Name, Kind) \
} \
/* NOLINTNEXTLINE(readability/braces) */ \
else if (o.Is##Name()) { \
return RefSerializationKindOf<Name>();
HEAP_BROKER_OBJECT_LIST(DEFINE_REF_SERIALIZATION_KIND)
#undef DEFINE_REF_SERIALIZATION_KIND
}
UNREACHABLE();
}
} // namespace } // namespace
class HeapObjectData : public ObjectData { class HeapObjectData : public ObjectData {
...@@ -1259,7 +1272,7 @@ AllocationSiteData::AllocationSiteData(JSHeapBroker* broker, ...@@ -1259,7 +1272,7 @@ AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
GetAllocationType_(object->GetAllocationType()) { GetAllocationType_(object->GetAllocationType()) {
if (PointsToLiteral_) { if (PointsToLiteral_) {
IsFastLiteral_ = IsInlinableFastLiteral( IsFastLiteral_ = IsInlinableFastLiteral(
handle(object->boilerplate(), broker->isolate())); handle(object->boilerplate(kAcquireLoad), broker->isolate()));
} else { } else {
GetElementsKind_ = object->GetElementsKind(); GetElementsKind_ = object->GetElementsKind();
CanInlineCall_ = object->CanInlineCall(); CanInlineCall_ = object->CanInlineCall();
...@@ -1275,7 +1288,7 @@ void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) { ...@@ -1275,7 +1288,7 @@ void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) {
CHECK(IsFastLiteral_); CHECK(IsFastLiteral_);
DCHECK_NULL(boilerplate_); DCHECK_NULL(boilerplate_);
boilerplate_ = broker->GetOrCreateData(site->boilerplate()); boilerplate_ = broker->GetOrCreateData(site->boilerplate(kAcquireLoad));
if (!boilerplate_->should_access_heap()) { if (!boilerplate_->should_access_heap()) {
boilerplate_->AsJSObject()->SerializeAsBoilerplate(broker); boilerplate_->AsJSObject()->SerializeAsBoilerplate(broker);
} }
...@@ -1792,41 +1805,14 @@ void FixedArrayData::SerializeContents(JSHeapBroker* broker) { ...@@ -1792,41 +1805,14 @@ void FixedArrayData::SerializeContents(JSHeapBroker* broker) {
class FixedDoubleArrayData : public FixedArrayBaseData { class FixedDoubleArrayData : public FixedArrayBaseData {
public: public:
FixedDoubleArrayData(JSHeapBroker* broker, ObjectData** storage, FixedDoubleArrayData(
Handle<FixedDoubleArray> object); JSHeapBroker* broker, ObjectData** storage,
Handle<FixedDoubleArray> object,
// Serializes all elements of the fixed array. ObjectDataKind kind = ObjectDataKind::kNeverSerializedHeapObject)
void SerializeContents(JSHeapBroker* broker); : FixedArrayBaseData(broker, storage, object, kind) {
DCHECK(!broker->is_concurrent_inlining());
Float64 Get(int i) const;
private:
bool serialized_contents_ = false;
ZoneVector<Float64> contents_;
};
FixedDoubleArrayData::FixedDoubleArrayData(JSHeapBroker* broker,
ObjectData** storage,
Handle<FixedDoubleArray> object)
: FixedArrayBaseData(broker, storage, object,
ObjectDataKind::kSerializedHeapObject),
contents_(broker->zone()) {}
void FixedDoubleArrayData::SerializeContents(JSHeapBroker* broker) {
if (serialized_contents_) return;
serialized_contents_ = true;
TraceScope tracer(broker, this, "FixedDoubleArrayData::SerializeContents");
Handle<FixedDoubleArray> self = Handle<FixedDoubleArray>::cast(object());
CHECK_EQ(self->length(), length());
CHECK(contents_.empty());
contents_.reserve(static_cast<size_t>(length()));
for (int i = 0; i < length(); i++) {
contents_.push_back(Float64::FromBits(self->get_representation(i)));
} }
TRACE(broker, "Copied " << contents_.size() << " elements"); };
}
class BytecodeArrayData : public FixedArrayBaseData { class BytecodeArrayData : public FixedArrayBaseData {
public: public:
...@@ -2458,8 +2444,6 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, ...@@ -2458,8 +2444,6 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
} else { } else {
CHECK(boilerplate->HasDoubleElements()); CHECK(boilerplate->HasDoubleElements());
CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize); CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize);
DCHECK_EQ(elements_->kind(), ObjectDataKind::kSerializedHeapObject);
elements_->AsFixedDoubleArray()->SerializeContents(broker);
} }
// TODO(turbofan): Do we want to support out-of-object properties? // TODO(turbofan): Do we want to support out-of-object properties?
...@@ -2846,10 +2830,9 @@ void JSHeapBroker::ClearReconstructibleData() { ...@@ -2846,10 +2830,9 @@ void JSHeapBroker::ClearReconstructibleData() {
Address key = p->key; Address key = p->key;
ObjectData* value = p->value; ObjectData* value = p->value;
p = refs_->Next(p); p = refs_->Next(p);
const ObjectDataKind kind = value->kind(); const auto kind = RefSerializationKindOf(value);
if (kind == ObjectDataKind::kNeverSerializedHeapObject || if (kind == RefSerializationKind::kNeverSerialized ||
kind == ObjectDataKind::kBackgroundSerializedHeapObject || kind == RefSerializationKind::kBackgroundSerialized) {
kind == ObjectDataKind::kUnserializedReadOnlyHeapObject) {
if (value->IsMap() && if (value->IsMap() &&
value->kind() == ObjectDataKind::kBackgroundSerializedHeapObject && value->kind() == ObjectDataKind::kBackgroundSerializedHeapObject &&
value->AsMap()->has_extra_serialized_data()) { value->AsMap()->has_extra_serialized_data()) {
...@@ -3101,7 +3084,7 @@ bool AllocationSiteRef::IsFastLiteral() const { ...@@ -3101,7 +3084,7 @@ bool AllocationSiteRef::IsFastLiteral() const {
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
CHECK_NE(data_->kind(), ObjectDataKind::kNeverSerializedHeapObject); CHECK_NE(data_->kind(), ObjectDataKind::kNeverSerializedHeapObject);
return IsInlinableFastLiteral( return IsInlinableFastLiteral(
handle(object()->boilerplate(), broker()->isolate())); handle(object()->boilerplate(kAcquireLoad), broker()->isolate()));
} }
return data()->AsAllocationSite()->IsFastLiteral(); return data()->AsAllocationSite()->IsFastLiteral();
} }
...@@ -3277,12 +3260,10 @@ ObjectRef FixedArrayRef::get(int i) const { ...@@ -3277,12 +3260,10 @@ ObjectRef FixedArrayRef::get(int i) const {
return ObjectRef(broker(), data()->AsFixedArray()->Get(i)); return ObjectRef(broker(), data()->AsFixedArray()->Get(i));
} }
Float64 FixedDoubleArrayRef::get(int i) const { Float64 FixedDoubleArrayRef::GetFromImmutableFixedDoubleArray(int i) const {
if (data_->should_access_heap()) { STATIC_ASSERT(RefSerializationKindOf<FixedDoubleArray>() ==
return Float64::FromBits(object()->get_representation(i)); RefSerializationKind::kNeverSerialized);
} else { return Float64::FromBits(object()->get_representation(i));
return data()->AsFixedDoubleArray()->Get(i);
}
} }
Handle<ByteArray> BytecodeArrayRef::SourcePositionTable() const { Handle<ByteArray> BytecodeArrayRef::SourcePositionTable() const {
...@@ -4155,8 +4136,8 @@ HeapObjectType HeapObjectRef::GetHeapObjectType() const { ...@@ -4155,8 +4136,8 @@ HeapObjectType HeapObjectRef::GetHeapObjectType() const {
} }
base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const { base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const {
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
return JSObjectRef( return JSObjectRef(broker(), broker()->CanonicalPersistentHandle(
broker(), broker()->CanonicalPersistentHandle(object()->boilerplate())); object()->boilerplate(kAcquireLoad)));
} }
ObjectData* boilerplate = data()->AsAllocationSite()->boilerplate(); ObjectData* boilerplate = data()->AsAllocationSite()->boilerplate();
if (boilerplate) { if (boilerplate) {
...@@ -4194,11 +4175,6 @@ ObjectData* FixedArrayData::Get(int i) const { ...@@ -4194,11 +4175,6 @@ ObjectData* FixedArrayData::Get(int i) const {
return contents_[i]; return contents_[i];
} }
Float64 FixedDoubleArrayData::Get(int i) const {
CHECK_LT(i, static_cast<int>(contents_.size()));
return contents_[i];
}
PropertyDetails DescriptorArrayRef::GetPropertyDetails( PropertyDetails DescriptorArrayRef::GetPropertyDetails(
InternalIndex descriptor_index) const { InternalIndex descriptor_index) const {
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
......
...@@ -100,7 +100,7 @@ enum class RefSerializationKind { ...@@ -100,7 +100,7 @@ enum class RefSerializationKind {
/* Subtypes of FixedArrayBase */ \ /* Subtypes of FixedArrayBase */ \
V(BytecodeArray, RefSerializationKind::kNeverSerialized) \ V(BytecodeArray, RefSerializationKind::kNeverSerialized) \
V(FixedArray, RefSerializationKind::kSerialized) \ V(FixedArray, RefSerializationKind::kSerialized) \
V(FixedDoubleArray, RefSerializationKind::kSerialized) \ V(FixedDoubleArray, RefSerializationKind::kNeverSerialized) \
/* Subtypes of Name */ \ /* Subtypes of Name */ \
V(String, RefSerializationKind::kNeverSerialized) \ V(String, RefSerializationKind::kNeverSerialized) \
V(Symbol, RefSerializationKind::kNeverSerialized) \ V(Symbol, RefSerializationKind::kNeverSerialized) \
...@@ -786,7 +786,10 @@ class FixedDoubleArrayRef : public FixedArrayBaseRef { ...@@ -786,7 +786,10 @@ class FixedDoubleArrayRef : public FixedArrayBaseRef {
Handle<FixedDoubleArray> object() const; Handle<FixedDoubleArray> object() const;
Float64 get(int i) const; // Due to 64-bit unaligned reads, only usable for
// immutable-after-initialization FixedDoubleArrays protected by
// acquire-release semantics (such as boilerplate elements).
Float64 GetFromImmutableFixedDoubleArray(int i) const;
}; };
class BytecodeArrayRef : public FixedArrayBaseRef { class BytecodeArrayRef : public FixedArrayBaseRef {
......
...@@ -1763,7 +1763,7 @@ Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control, ...@@ -1763,7 +1763,7 @@ Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control,
if (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) { if (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) {
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.get(i); Float64 value = elements.GetFromImmutableFixedDoubleArray(i);
if (value.is_hole_nan()) { if (value.is_hole_nan()) {
elements_values[i] = jsgraph()->TheHoleConstant(); elements_values[i] = jsgraph()->TheHoleConstant();
} else { } else {
......
...@@ -1553,15 +1553,13 @@ struct SerializationPhase { ...@@ -1553,15 +1553,13 @@ struct SerializationPhase {
ContextRef(data->broker(), ContextRef(data->broker(),
data->specialization_context().FromJust().context); data->specialization_context().FromJust().context);
} }
if (data->info()->concurrent_inlining()) { if (FLAG_turbo_concurrent_get_property_access_info) {
if (FLAG_turbo_concurrent_get_property_access_info) { data->broker()->ClearCachedPropertyAccessInfos();
data->broker()->ClearCachedPropertyAccessInfos(); data->dependencies()->ClearForConcurrentGetPropertyAccessInfo();
data->dependencies()->ClearForConcurrentGetPropertyAccessInfo(); }
} if (FLAG_stress_concurrent_inlining) {
if (FLAG_stress_concurrent_inlining) { // Force re-serialization from the background thread.
// Force re-serialization from the background thread. data->broker()->ClearReconstructibleData();
data->broker()->ClearReconstructibleData();
}
} }
} }
}; };
......
...@@ -27,6 +27,8 @@ CAST_ACCESSOR(AllocationSite) ...@@ -27,6 +27,8 @@ CAST_ACCESSOR(AllocationSite)
ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object, ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object,
kTransitionInfoOrBoilerplateOffset) kTransitionInfoOrBoilerplateOffset)
RELEASE_ACQUIRE_ACCESSORS(AllocationSite, transition_info_or_boilerplate,
Object, kTransitionInfoOrBoilerplateOffset)
ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset) ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset) INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset)
INT32_ACCESSORS(AllocationSite, pretenure_create_count, INT32_ACCESSORS(AllocationSite, pretenure_create_count,
...@@ -41,8 +43,14 @@ JSObject AllocationSite::boilerplate() const { ...@@ -41,8 +43,14 @@ JSObject AllocationSite::boilerplate() const {
return JSObject::cast(transition_info_or_boilerplate()); return JSObject::cast(transition_info_or_boilerplate());
} }
void AllocationSite::set_boilerplate(JSObject object, WriteBarrierMode mode) { JSObject AllocationSite::boilerplate(AcquireLoadTag tag) const {
set_transition_info_or_boilerplate(object, mode); DCHECK(PointsToLiteral());
return JSObject::cast(transition_info_or_boilerplate(tag));
}
void AllocationSite::set_boilerplate(JSObject value, ReleaseStoreTag tag,
WriteBarrierMode mode) {
set_transition_info_or_boilerplate(value, tag, mode);
} }
int AllocationSite::transition_info() const { int AllocationSite::transition_info() const {
......
...@@ -40,7 +40,9 @@ class AllocationSite : public Struct { ...@@ -40,7 +40,9 @@ class AllocationSite : public Struct {
// Contains either a Smi-encoded bitfield or a boilerplate. If it's a Smi the // Contains either a Smi-encoded bitfield or a boilerplate. If it's a Smi the
// AllocationSite is for a constructed Array. // AllocationSite is for a constructed Array.
DECL_ACCESSORS(transition_info_or_boilerplate, Object) DECL_ACCESSORS(transition_info_or_boilerplate, Object)
DECL_ACCESSORS(boilerplate, JSObject) DECL_RELEASE_ACQUIRE_ACCESSORS(transition_info_or_boilerplate, Object)
DECL_GETTER(boilerplate, JSObject)
DECL_RELEASE_ACQUIRE_ACCESSORS(boilerplate, JSObject)
DECL_INT_ACCESSORS(transition_info) DECL_INT_ACCESSORS(transition_info)
// nested_site threads a list of sites that represent nested literals // nested_site threads a list of sites that represent nested literals
......
...@@ -291,7 +291,7 @@ class AllocationSiteCreationContext : public AllocationSiteContext { ...@@ -291,7 +291,7 @@ class AllocationSiteCreationContext : public AllocationSiteContext {
} }
void ExitScope(Handle<AllocationSite> scope_site, Handle<JSObject> object) { void ExitScope(Handle<AllocationSite> scope_site, Handle<JSObject> object) {
if (object.is_null()) return; if (object.is_null()) return;
scope_site->set_boilerplate(*object); scope_site->set_boilerplate(*object, kReleaseStore);
if (FLAG_trace_creation_allocation_sites) { if (FLAG_trace_creation_allocation_sites) {
bool top_level = bool top_level =
!scope_site.is_null() && top().is_identical_to(scope_site); !scope_site.is_null() && top().is_identical_to(scope_site);
......
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