[sandbox] Store waiter queue node of JS Atomic.Mutex in shared table

The waiter queue node of JS Atomics.Mutex is now stored in the shared
external pointer table.

Bug: v8:12547
Change-Id: I2f4ce1c705d5e710b49872942702f60edf6c4043
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3721696
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81380}
This commit is contained in:
Patrick Thier 2022-06-24 08:14:34 +00:00 committed by V8 LUCI CQ
parent 39f6787a19
commit 8933f9fe8e
5 changed files with 21 additions and 15 deletions

View File

@ -308,10 +308,10 @@ constexpr uint64_t kExternalPointerTagShift = 48;
enum ExternalPointerTag : uint64_t {
kExternalPointerNullTag = MAKE_TAG(0b0000000000000000),
kExternalPointerFreeEntryTag = MAKE_TAG(0b0111111100000000),
kWaiterQueueNodeTag = MAKE_TAG(0b1000000111111111),
// Begin shared external object tags
// Update kSharedExternalObjectMask and kSharedExternalObjectTag when new
// tags are shared.
kWaiterQueueNodeTag = MAKE_TAG(0b1000000111111111),
kExternalStringResourceTag = MAKE_TAG(0b1000001011111111),
kExternalStringResourceDataTag = MAKE_TAG(0b1000001101111111),
// End shared external object tags
@ -330,8 +330,8 @@ enum ExternalPointerTag : uint64_t {
// Shared external pointers can be access from shared isolates. They are stored
// in a shared external pointer table.
constexpr uint64_t kSharedExternalObjectMask = MAKE_TAG(0b1111111001111111);
constexpr uint64_t kSharedExternalObjectTag = MAKE_TAG(0b1000001001111111);
constexpr uint64_t kSharedExternalObjectMask = MAKE_TAG(0b1111110001111111);
constexpr uint64_t kSharedExternalObjectTag = MAKE_TAG(0b1000000001111111);
#undef MAKE_TAG

View File

@ -3559,7 +3559,7 @@ void Isolate::Deinit() {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
external_pointer_table().TearDown();
if (OwnsStringTables()) {
if (owns_shareable_data()) {
shared_external_pointer_table().TearDown();
delete isolate_data_.shared_external_pointer_table_;
isolate_data_.shared_external_pointer_table_ = nullptr;
@ -4120,7 +4120,7 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data,
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
external_pointer_table().Init(this);
if (OwnsStringTables()) {
if (owns_shareable_data()) {
isolate_data_.shared_external_pointer_table_ = new ExternalPointerTable();
shared_external_pointer_table().Init(this);
} else {
@ -5762,19 +5762,18 @@ void Isolate::DetachFromSharedIsolate() {
ExternalPointer_t Isolate::EncodeWaiterQueueNodeAsExternalPointer(
Address node) {
DCHECK_NE(kNullAddress, node);
Isolate* shared = shared_isolate();
uint32_t index;
ExternalPointer_t ext;
if (waiter_queue_node_external_pointer_.IsJust()) {
ext = waiter_queue_node_external_pointer_.FromJust();
index = ext >> kExternalPointerIndexShift;
} else {
index = shared->external_pointer_table().Allocate();
index = shared_external_pointer_table().Allocate();
ext = index << kExternalPointerIndexShift;
waiter_queue_node_external_pointer_ = Just(ext);
}
DCHECK_NE(0, index);
shared->external_pointer_table().Set(index, node, kWaiterQueueNodeTag);
shared_external_pointer_table().Set(index, node, kWaiterQueueNodeTag);
return ext;
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS

View File

@ -2002,10 +2002,14 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
DCHECK_NULL(shared_isolate_);
DCHECK(!attached_to_shared_isolate_);
shared_isolate_ = shared_isolate;
owns_shareable_data_ = false;
}
GlobalSafepoint* global_safepoint() const { return global_safepoint_.get(); }
bool owns_shareable_data() { return owns_shareable_data_; }
// TODO(pthier): Unify with owns_shareable_data() once the flag
// --shared-string-table is removed.
bool OwnsStringTables() { return !FLAG_shared_string_table || is_shared(); }
#if USE_SIMULATOR
@ -2271,6 +2275,10 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
// favor memory over runtime performance.
bool memory_savings_mode_active_ = false;
// Indicates wether the isolate owns shareable data.
// Only false for client isolates attached to a shared isolate.
bool owns_shareable_data_ = true;
#ifdef V8_EXTERNAL_CODE_SPACE
// Base address of the pointer compression cage containing external code
// space, when external code space is enabled.

View File

@ -2083,11 +2083,11 @@ void MarkCompactCollector::MarkObjectsFromClientHeaps() {
// Custom marking for the external pointer table entry used to hold
// client Isolates' WaiterQueueNode, which is used by JS mutexes and
// condition variables.
DCHECK(!IsExternalPointerTagShareable(kWaiterQueueNodeTag));
DCHECK(IsExternalPointerTagShareable(kWaiterQueueNodeTag));
ExternalPointer_t waiter_queue_ext;
if (client->GetWaiterQueueNodeExternalPointer().To(&waiter_queue_ext)) {
uint32_t index = waiter_queue_ext >> kExternalPointerIndexShift;
client->shared_isolate()->external_pointer_table().Mark(index);
client->shared_external_pointer_table().Mark(index);
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
});
@ -2747,7 +2747,7 @@ void MarkCompactCollector::ClearNonLiveReferences() {
TRACE_GC(heap()->tracer(),
GCTracer::Scope::MC_SWEEP_EXTERNAL_POINTER_TABLE);
isolate()->external_pointer_table().Sweep(isolate());
if (isolate()->OwnsStringTables()) {
if (isolate()->owns_shareable_data()) {
isolate()->shared_external_pointer_table().Sweep(isolate());
}
}

View File

@ -22,7 +22,7 @@ namespace detail {
// list per waiter (i.e. mutex or condition variable). There is a per-thread
// node allocated on the stack when the thread goes to sleep during waiting. In
// the case of sandboxed pointers, the access to the on-stack node is indirected
// through the shared Isolate's external pointer table.
// through the shared external pointer table.
class V8_NODISCARD WaiterQueueNode final {
public:
template <typename T>
@ -47,14 +47,13 @@ class V8_NODISCARD WaiterQueueNode final {
static WaiterQueueNode* DestructivelyDecodeHead(Isolate* requester,
typename T::StateT state) {
#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
Isolate* shared_isolate = requester->shared_isolate();
ExternalPointer_t ptr =
static_cast<ExternalPointer_t>(state & T::kWaiterQueueHeadMask);
if (ptr == 0) return nullptr;
// The external pointer is cleared after decoding to prevent reuse by
// multiple mutexes in case of heap corruption.
return reinterpret_cast<WaiterQueueNode*>(DecodeAndClearExternalPointer(
shared_isolate, ptr, kWaiterQueueNodeTag));
return reinterpret_cast<WaiterQueueNode*>(
DecodeAndClearExternalPointer(requester, ptr, kWaiterQueueNodeTag));
#else
return base::bit_cast<WaiterQueueNode*>(state & T::kWaiterQueueHeadMask);
#endif // V8_SANDBOXED_EXTERNAL_POINTERS