Commit 0362bc6c authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Clear reconstructible ObjectData after serialization

This is another step towards improving TSAN and test coverage of
concurrent paths.

By purging reconstructible (background-serialized or never-serialized)
ObjectData instances from the cache after serialization, we increase
ObjectData-construction activity on the background thread.

Note that this means ObjectData is no longer canonicalized - two
instances can point at the same underlying object. Losing this
property is unfortunate, but we can revert back to it once work on the
concurrency project is further advanced.

Bug: v8:7790
Change-Id: I44b1366f61dc9087cddc76939512abed17e28d61
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2844661
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74221}
parent 10c137a2
...@@ -77,22 +77,6 @@ bool IsReadOnlyHeapObject(Object object) { ...@@ -77,22 +77,6 @@ bool IsReadOnlyHeapObject(Object object) {
ReadOnlyHeap::Contains(HeapObject::cast(object))); ReadOnlyHeap::Contains(HeapObject::cast(object)));
} }
template <class T>
constexpr bool IsSerializedHeapObject() {
return false;
}
#define DEFINE_MARKER(Name, Kind) \
template <> \
constexpr bool IsSerializedHeapObject<Name>() { \
return Kind == RefSerializationKind::kSerialized; \
} \
/* The static assert is needed to avoid 'unused function' warnings. */ \
STATIC_ASSERT(IsSerializedHeapObject<Name>() == \
(Kind == RefSerializationKind::kSerialized));
HEAP_BROKER_OBJECT_LIST(DEFINE_MARKER)
#undef DEFINE_MARKER
} // namespace } // namespace
class ObjectData : public ZoneObject { class ObjectData : public ZoneObject {
...@@ -165,6 +149,31 @@ class ObjectData : public ZoneObject { ...@@ -165,6 +149,31 @@ class ObjectData : public ZoneObject {
#endif // DEBUG #endif // DEBUG
}; };
namespace {
template <class T>
constexpr RefSerializationKind RefSerializationKindOf() {
CONSTEXPR_DCHECK(false); // The default impl should never be called.
return RefSerializationKind::kSerialized;
}
#define DEFINE_REF_SERIALIZATION_KIND(Name, Kind) \
template <> \
constexpr RefSerializationKind RefSerializationKindOf<Name>() { \
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)
#undef DEFINE_REF_SERIALIZATION_KIND
template <class T>
constexpr bool IsSerializedRef() {
return RefSerializationKindOf<T>() == RefSerializationKind::kSerialized;
}
} // namespace
class HeapObjectData : public ObjectData { class HeapObjectData : public ObjectData {
public: public:
HeapObjectData(JSHeapBroker* broker, ObjectData** storage, HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
...@@ -565,7 +574,7 @@ class JSTypedArrayData : public JSObjectData { ...@@ -565,7 +574,7 @@ class JSTypedArrayData : public JSObjectData {
// TODO(v8:7790): Once JSObject is no longer serialized, also make // TODO(v8:7790): Once JSObject is no longer serialized, also make
// JSTypedArrayRef never-serialized. // JSTypedArrayRef never-serialized.
STATIC_ASSERT(IsSerializedHeapObject<JSObject>()); STATIC_ASSERT(IsSerializedRef<JSObject>());
void Serialize(JSHeapBroker* broker); void Serialize(JSHeapBroker* broker);
bool serialized() const { return serialized_; } bool serialized() const { return serialized_; }
...@@ -1185,6 +1194,14 @@ class MapData : public HeapObjectData { ...@@ -1185,6 +1194,14 @@ class MapData : public HeapObjectData {
void SerializeForElementStore(JSHeapBroker* broker); void SerializeForElementStore(JSHeapBroker* broker);
bool has_extra_serialized_data() const {
return serialized_elements_kind_generalizations_ ||
serialized_own_descriptors_ || serialized_constructor_ ||
serialized_backpointer_ || serialized_prototype_ ||
serialized_root_map_ || serialized_for_element_load_ ||
serialized_for_element_store_;
}
private: private:
// The following fields should be const in principle, but construction // The following fields should be const in principle, but construction
// requires locking the MapUpdater lock. For this reason, it's easier to // requires locking the MapUpdater lock. For this reason, it's easier to
...@@ -2519,7 +2536,10 @@ bool ObjectRef::equals(const ObjectRef& other) const { ...@@ -2519,7 +2536,10 @@ bool ObjectRef::equals(const ObjectRef& other) const {
data_->used_status = ObjectData::Usage::kOnlyIdentityUsed; data_->used_status = ObjectData::Usage::kOnlyIdentityUsed;
} }
#endif // DEBUG #endif // DEBUG
return data_ == other.data_; // TODO(jgruber): Consider going back to reference-equality on data_ once
// ObjectData objects are guaranteed to be canonicalized (see also:
// ClearReconstructibleData).
return data_->object().is_identical_to(other.data_->object());
} }
bool ObjectRef::ShouldHaveBeenSerialized() const { bool ObjectRef::ShouldHaveBeenSerialized() const {
...@@ -2820,6 +2840,27 @@ struct CreateDataFunctor<RefSerializationKind::kNeverSerialized, DataT, ...@@ -2820,6 +2840,27 @@ struct CreateDataFunctor<RefSerializationKind::kNeverSerialized, DataT,
} // namespace } // namespace
void JSHeapBroker::ClearReconstructibleData() {
RefsMap::Entry* p = refs_->Start();
while (p != nullptr) {
Address key = p->key;
ObjectData* value = p->value;
p = refs_->Next(p);
const ObjectDataKind kind = value->kind();
if (kind == ObjectDataKind::kNeverSerializedHeapObject ||
kind == ObjectDataKind::kBackgroundSerializedHeapObject ||
kind == ObjectDataKind::kUnserializedReadOnlyHeapObject) {
if (value->IsMap() &&
value->kind() == ObjectDataKind::kBackgroundSerializedHeapObject &&
value->AsMap()->has_extra_serialized_data()) {
continue;
}
// Can be reconstructed from the background thread.
CHECK_NOT_NULL(refs_->Remove(key));
}
}
}
ObjectData* JSHeapBroker::TryGetOrCreateData( ObjectData* JSHeapBroker::TryGetOrCreateData(
Handle<Object> object, bool crash_on_error, Handle<Object> object, bool crash_on_error,
ObjectRef::BackgroundSerialization background_serialization) { ObjectRef::BackgroundSerialization background_serialization) {
...@@ -3894,7 +3935,7 @@ base::Optional<ObjectRef> JSObjectRef::GetOwnConstantElement( ...@@ -3894,7 +3935,7 @@ base::Optional<ObjectRef> JSObjectRef::GetOwnConstantElement(
// guarantee consistency between `object`, `elements_kind` and `elements` // guarantee consistency between `object`, `elements_kind` and `elements`
// through other means (store/load order? locks? storing elements_kind in // through other means (store/load order? locks? storing elements_kind in
// elements.map?). // elements.map?).
STATIC_ASSERT(IsSerializedHeapObject<JSObject>()); STATIC_ASSERT(IsSerializedRef<JSObject>());
base::Optional<FixedArrayBaseRef> maybe_elements_ref = elements(); base::Optional<FixedArrayBaseRef> maybe_elements_ref = elements();
if (!maybe_elements_ref.has_value()) { if (!maybe_elements_ref.has_value()) {
...@@ -3982,7 +4023,7 @@ base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement( ...@@ -3982,7 +4023,7 @@ base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(
// TODO(jgruber,v8:7790): Remove the elements equality DCHECK below once // TODO(jgruber,v8:7790): Remove the elements equality DCHECK below once
// JSObject is no longer serialized. // JSObject is no longer serialized.
static_assert(std::is_base_of<JSObject, JSArray>::value, ""); static_assert(std::is_base_of<JSObject, JSArray>::value, "");
STATIC_ASSERT(IsSerializedHeapObject<JSObject>()); STATIC_ASSERT(IsSerializedRef<JSObject>());
// The elements_ref is passed in by callers to make explicit that it is // The elements_ref is passed in by callers to make explicit that it is
// also used outside of this function, and must match the `elements` used // also used outside of this function, and must match the `elements` used
...@@ -4247,7 +4288,7 @@ void RegExpBoilerplateDescriptionRef::Serialize() { ...@@ -4247,7 +4288,7 @@ void RegExpBoilerplateDescriptionRef::Serialize() {
// Even if the regexp boilerplate object itself is no longer serialized, // Even if the regexp boilerplate object itself is no longer serialized,
// the `data` still is and thus we need to make sure to visit it. // the `data` still is and thus we need to make sure to visit it.
// TODO(jgruber,v8:7790): Remove once it is no longer a serialized type. // TODO(jgruber,v8:7790): Remove once it is no longer a serialized type.
STATIC_ASSERT(IsSerializedHeapObject<FixedArray>()); STATIC_ASSERT(IsSerializedRef<FixedArray>());
FixedArrayRef data_ref{ FixedArrayRef data_ref{
broker(), broker()->CanonicalPersistentHandle(object()->data())}; broker(), broker()->CanonicalPersistentHandle(object()->data())};
} else { } else {
...@@ -4545,7 +4586,7 @@ void JSTypedArrayRef::Serialize() { ...@@ -4545,7 +4586,7 @@ void JSTypedArrayRef::Serialize() {
// TODO(jgruber,v8:7790): Remove once JSObject is no longer serialized. // TODO(jgruber,v8:7790): Remove once JSObject is no longer serialized.
static_assert( static_assert(
std::is_base_of<JSObject, decltype(object()->buffer())>::value, ""); std::is_base_of<JSObject, decltype(object()->buffer())>::value, "");
STATIC_ASSERT(IsSerializedHeapObject<JSObject>()); STATIC_ASSERT(IsSerializedRef<JSObject>());
JSObjectRef data_ref{ JSObjectRef data_ref{
broker(), broker()->CanonicalPersistentHandle(object()->buffer())}; broker(), broker()->CanonicalPersistentHandle(object()->buffer())};
} else { } else {
......
...@@ -261,6 +261,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -261,6 +261,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
property_access_infos_.clear(); property_access_infos_.clear();
} }
// As above, clear cached ObjectData that can be reconstructed, i.e. is
// either never-serialized or background-serialized.
void ClearReconstructibleData();
StringRef GetTypedArrayStringTag(ElementsKind kind); StringRef GetTypedArrayStringTag(ElementsKind kind);
bool ShouldBeSerializedForCompilation(const SharedFunctionInfoRef& shared, bool ShouldBeSerializedForCompilation(const SharedFunctionInfoRef& shared,
......
...@@ -1553,9 +1553,15 @@ struct SerializationPhase { ...@@ -1553,9 +1553,15 @@ struct SerializationPhase {
ContextRef(data->broker(), ContextRef(data->broker(),
data->specialization_context().FromJust().context); data->specialization_context().FromJust().context);
} }
if (FLAG_turbo_concurrent_get_property_access_info) { if (data->info()->concurrent_inlining()) {
data->broker()->ClearCachedPropertyAccessInfos(); if (FLAG_turbo_concurrent_get_property_access_info) {
data->dependencies()->ClearForConcurrentGetPropertyAccessInfo(); data->broker()->ClearCachedPropertyAccessInfos();
data->dependencies()->ClearForConcurrentGetPropertyAccessInfo();
}
if (FLAG_stress_concurrent_inlining) {
// Force re-serialization from the background thread.
data->broker()->ClearReconstructibleData();
}
} }
} }
}; };
......
...@@ -27,6 +27,10 @@ RefsMap::Entry* RefsMap::LookupOrInsert(const Address& key) { ...@@ -27,6 +27,10 @@ RefsMap::Entry* RefsMap::LookupOrInsert(const Address& key) {
[]() { return nullptr; }); []() { return nullptr; });
} }
ObjectData* RefsMap::Remove(const Address& key) {
return UnderlyingMap::Remove(key, RefsMap::Hash(key));
}
uint32_t RefsMap::Hash(Address addr) { return static_cast<uint32_t>(addr); } uint32_t RefsMap::Hash(Address addr) { return static_cast<uint32_t>(addr); }
} // namespace compiler } // namespace compiler
......
...@@ -42,6 +42,7 @@ class RefsMap ...@@ -42,6 +42,7 @@ class RefsMap
// Wrappers around methods from UnderlyingMap // Wrappers around methods from UnderlyingMap
Entry* Lookup(const Address& key) const; Entry* Lookup(const Address& key) const;
Entry* LookupOrInsert(const Address& key); Entry* LookupOrInsert(const Address& key);
ObjectData* Remove(const Address& key);
private: private:
static uint32_t Hash(Address addr); static uint32_t Hash(Address addr);
......
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