Commit 4683d6fe authored by Jakob Gruber's avatar Jakob Gruber Committed by V8 LUCI CQ

Reland "[compiler] Consider IsPendingAllocation in Ref construction"

This is a reland of 5f0ac36c

Fixes Ref construction failures in:
- MapRef::instance_descriptors
- NativeContext reads (see also crrev.com/c/2891575)

Original change's description:
> [compiler] Consider IsPendingAllocation in Ref construction
>
> The logic in JSHeapBroker::TryGetOrCreateData assumes that parts
> of the object are safe to read. In particular, the instance type
> must be readable for the chain of `Is##Name()` type checks.
>
> This is guaranteed if
>
>  - a global memory fence happened after object initialization and
>    prior to the read by the compiler; or
>  - the object was published through a release store and read through
>    an acquire read.
>
> The former is protected by the new call to ObjectMayBeUninitialized
> (which internally calls IsPendingAllocation) in TryGetOrCreateData.
>
> The latter must be marked explicitly by calling the new
> MakeRefAssumeMemoryFence variant.
>
> Note that support in this CL is expected to be incomplete and will
> have to be extended in the future as more cases show up in which
> MakeRef calls must be converted to MakeRefAssumeMemoryFence or to
> TryMakeRef.
>
> Bug: v8:7790,v8:11711
> Change-Id: Ic2f7d9fc46e4bfc3f6bbe42816f73fc5ec174337
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2874663
> Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Georg Neis <neis@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#74474}

Bug: v8:7790,v8:11711,chromium:1207680,chromium:1207679
Change-Id: Ib3dbf59909e6982a3230dd6a67c9fb7d6ffb9ab4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2886861Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74587}
parent 97788f03
This diff is collapsed.
......@@ -228,18 +228,20 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(Handle<JSObject> object) const {
}
ObjectData* JSHeapBroker::TryGetOrCreateData(Object object,
bool crash_on_error) {
return TryGetOrCreateData(CanonicalPersistentHandle(object), crash_on_error);
GetOrCreateDataFlags flags) {
return TryGetOrCreateData(CanonicalPersistentHandle(object), flags);
}
ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object) {
ObjectData* return_value = TryGetOrCreateData(object, true);
ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object,
GetOrCreateDataFlags flags) {
ObjectData* return_value = TryGetOrCreateData(object, flags | kCrashOnError);
DCHECK_NOT_NULL(return_value);
return return_value;
}
ObjectData* JSHeapBroker::GetOrCreateData(Object object) {
return GetOrCreateData(CanonicalPersistentHandle(object));
ObjectData* JSHeapBroker::GetOrCreateData(Object object,
GetOrCreateDataFlags flags) {
return GetOrCreateData(CanonicalPersistentHandle(object), flags);
}
bool JSHeapBroker::StackHasOverflowed() const {
......@@ -251,8 +253,12 @@ bool JSHeapBroker::StackHasOverflowed() const {
}
bool JSHeapBroker::ObjectMayBeUninitialized(Handle<Object> object) const {
return !IsMainThread() && object->IsHeapObject() &&
isolate()->heap()->IsPendingAllocation(HeapObject::cast(*object));
if (!object->IsHeapObject()) return false;
return ObjectMayBeUninitialized(HeapObject::cast(*object));
}
bool JSHeapBroker::ObjectMayBeUninitialized(HeapObject object) const {
return !IsMainThread() && isolate()->heap()->IsPendingAllocation(object);
}
bool CanInlineElementAccess(MapRef const& map) {
......
......@@ -79,6 +79,18 @@ struct PropertyAccessTarget {
};
};
enum GetOrCreateDataFlag {
// If set, a failure to create the data object results in a crash.
kCrashOnError = 1 << 0,
// If set, data construction assumes that the given object is protected by
// a memory fence (e.g. acquire-release) and thus fields required for
// construction (like Object::map) are safe to read. The protection can
// extend to some other situations as well.
kAssumeMemoryFence = 1 << 1,
};
using GetOrCreateDataFlags = base::Flags<GetOrCreateDataFlag>;
DEFINE_OPERATORS_FOR_FLAGS(GetOrCreateDataFlags)
class V8_EXPORT_PRIVATE JSHeapBroker {
public:
JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled,
......@@ -151,14 +163,16 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
Handle<Object> GetRootHandle(Object object);
// Never returns nullptr.
ObjectData* GetOrCreateData(Handle<Object>);
// Like the previous but wraps argument in handle first (for convenience).
ObjectData* GetOrCreateData(Object);
ObjectData* GetOrCreateData(Handle<Object> object,
GetOrCreateDataFlags flags = {});
ObjectData* GetOrCreateData(Object object, GetOrCreateDataFlags flags = {});
// Gets data only if we have it. However, thin wrappers will be created for
// smis, read-only objects and never-serialized objects.
ObjectData* TryGetOrCreateData(Handle<Object>, bool crash_on_error = false);
ObjectData* TryGetOrCreateData(Object object, bool crash_on_error = false);
ObjectData* TryGetOrCreateData(Handle<Object> object,
GetOrCreateDataFlags flags = {});
ObjectData* TryGetOrCreateData(Object object,
GetOrCreateDataFlags flags = {});
// Check if {object} is any native context's %ArrayPrototype% or
// %ObjectPrototype%.
......@@ -370,6 +384,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
// thus safe to read from a memory safety perspective. The converse does not
// necessarily hold.
bool ObjectMayBeUninitialized(Handle<Object> object) const;
bool ObjectMayBeUninitialized(HeapObject object) const;
bool CanUseFeedback(const FeedbackNexus& nexus) const;
const ProcessedFeedback& NewInsufficientFeedback(FeedbackSlotKind kind) const;
......@@ -558,8 +573,8 @@ class V8_NODISCARD UnparkedScopeIfNeeded {
template <class T,
typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
base::Optional<typename ref_traits<T>::ref_type> TryMakeRef(
JSHeapBroker* broker, T object) {
ObjectData* data = broker->TryGetOrCreateData(object);
JSHeapBroker* broker, T object, GetOrCreateDataFlags flags = {}) {
ObjectData* data = broker->TryGetOrCreateData(object, flags);
if (data == nullptr) {
TRACE_BROKER_MISSING(broker, "ObjectData for " << Brief(object));
return {};
......@@ -570,8 +585,8 @@ base::Optional<typename ref_traits<T>::ref_type> TryMakeRef(
template <class T,
typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
base::Optional<typename ref_traits<T>::ref_type> TryMakeRef(
JSHeapBroker* broker, Handle<T> object) {
ObjectData* data = broker->TryGetOrCreateData(object);
JSHeapBroker* broker, Handle<T> object, GetOrCreateDataFlags flags = {}) {
ObjectData* data = broker->TryGetOrCreateData(object, flags);
if (data == nullptr) {
TRACE_BROKER_MISSING(broker, "ObjectData for " << Brief(*object));
return {};
......@@ -592,6 +607,20 @@ typename ref_traits<T>::ref_type MakeRef(JSHeapBroker* broker,
return TryMakeRef(broker, object).value();
}
template <class T,
typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
typename ref_traits<T>::ref_type MakeRefAssumeMemoryFence(JSHeapBroker* broker,
T object) {
return TryMakeRef(broker, object, kAssumeMemoryFence).value();
}
template <class T,
typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
typename ref_traits<T>::ref_type MakeRefAssumeMemoryFence(JSHeapBroker* broker,
Handle<T> object) {
return TryMakeRef(broker, object, kAssumeMemoryFence).value();
}
} // namespace compiler
} // namespace internal
} // namespace v8
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --expose-gc --interrupt-budget=1000 --no-lazy-feedback-allocation
var __v_5;
function __v_1() {
var PI = {
get() {}
};
function __v_5() {
Object.defineProperty(PI, 'func', {
});
'𝌆'.match();
}
__v_5(...[__v_5]);
try {
__v_1();
} catch (PI) {}
}
__v_1();
gc();
__v_1();
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