[rab/gsab] Support RAB/GSABs in context snapshot

Bug: v8:11111, v8:12731, v8:12742
Change-Id: I2679c0e64faca25a2c16e15fd3a5c727eb941c92
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3551894
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79662}
This commit is contained in:
Shu-yu Guo 2022-03-29 14:30:36 -07:00 committed by V8 LUCI CQ
parent b8b9013541
commit 21cfbf047e
10 changed files with 110 additions and 46 deletions

View File

@ -37,16 +37,6 @@ namespace internal {
namespace {
bool RoundUpToPageSize(size_t byte_length, size_t page_size,
size_t max_allowed_byte_length, size_t* pages) {
size_t bytes_wanted = RoundUp(byte_length, page_size);
if (bytes_wanted > max_allowed_byte_length) {
return false;
}
*pages = bytes_wanted / page_size;
return true;
}
Object ConstructBuffer(Isolate* isolate, Handle<JSFunction> target,
Handle<JSReceiver> new_target, Handle<Object> length,
Handle<Object> max_length, InitializedFlag initialized) {
@ -91,21 +81,12 @@ Object ConstructBuffer(Isolate* isolate, Handle<JSFunction> target,
NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength));
}
size_t page_size = AllocatePageSize();
size_t initial_pages;
if (!RoundUpToPageSize(byte_length, page_size,
JSArrayBuffer::kMaxByteLength, &initial_pages)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
}
size_t page_size, initial_pages, max_pages;
MAYBE_RETURN(JSArrayBuffer::GetResizableBackingStorePageConfiguration(
isolate, byte_length, max_byte_length, kThrowOnError,
&page_size, &initial_pages, &max_pages),
ReadOnlyRoots(isolate).exception());
size_t max_pages;
if (!RoundUpToPageSize(max_byte_length, page_size,
JSArrayBuffer::kMaxByteLength, &max_pages)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength));
}
constexpr bool kIsWasmMemory = false;
backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory(
isolate, byte_length, max_byte_length, page_size, initial_pages,

View File

@ -147,6 +147,36 @@ size_t JSArrayBuffer::GsabByteLength(Isolate* isolate,
return buffer.GetBackingStore()->byte_length(std::memory_order_seq_cst);
}
// static
Maybe<bool> JSArrayBuffer::GetResizableBackingStorePageConfiguration(
Isolate* isolate, size_t byte_length, size_t max_byte_length,
ShouldThrow should_throw, size_t* page_size, size_t* initial_pages,
size_t* max_pages) {
DCHECK_NOT_NULL(page_size);
DCHECK_NOT_NULL(initial_pages);
DCHECK_NOT_NULL(max_pages);
*page_size = AllocatePageSize();
if (!RoundUpToPageSize(byte_length, *page_size, JSArrayBuffer::kMaxByteLength,
initial_pages)) {
if (should_throw == kDontThrow) return Nothing<bool>();
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength),
Nothing<bool>());
}
if (!RoundUpToPageSize(max_byte_length, *page_size,
JSArrayBuffer::kMaxByteLength, max_pages)) {
if (should_throw == kDontThrow) return Nothing<bool>();
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferMaxLength),
Nothing<bool>());
}
return Just(true);
}
ArrayBufferExtension* JSArrayBuffer::EnsureExtension() {
ArrayBufferExtension* extension = this->extension();
if (extension != nullptr) return extension;

View File

@ -114,6 +114,11 @@ class JSArrayBuffer
static size_t GsabByteLength(Isolate* isolate, Address raw_array_buffer);
static Maybe<bool> GetResizableBackingStorePageConfiguration(
Isolate* isolate, size_t byte_length, size_t max_byte_length,
ShouldThrow should_throw, size_t* page_size, size_t* initial_pages,
size_t* max_pages);
// Allocates an ArrayBufferExtension for this array buffer, unless it is
// already associated with an extension.
ArrayBufferExtension* EnsureExtension();

View File

@ -61,11 +61,13 @@ void ContextDeserializer::SetupOffHeapArrayBufferBackingStores() {
for (Handle<JSArrayBuffer> buffer : new_off_heap_array_buffers()) {
uint32_t store_index = buffer->GetBackingStoreRefForDeserialization();
auto bs = backing_store(store_index);
// TODO(v8:11111): Support RAB / GSAB.
CHECK(!buffer->is_resizable());
SharedFlag shared =
bs && bs->is_shared() ? SharedFlag::kShared : SharedFlag::kNotShared;
buffer->Setup(shared, ResizableFlag::kNotResizable, bs);
DCHECK_IMPLIES(bs, buffer->is_resizable() == bs->is_resizable());
ResizableFlag resizable = bs && bs->is_resizable()
? ResizableFlag::kResizable
: ResizableFlag::kNotResizable;
buffer->Setup(shared, resizable, bs);
}
}

View File

@ -1160,11 +1160,28 @@ int Deserializer<IsolateT>::ReadSingleBytecodeData(byte data,
return ReadRepeatedObject(slot_accessor, repeats);
}
case kOffHeapBackingStore: {
case kOffHeapBackingStore:
case kOffHeapResizableBackingStore: {
int byte_length = source_.GetInt();
std::unique_ptr<BackingStore> backing_store = BackingStore::Allocate(
main_thread_isolate(), byte_length, SharedFlag::kNotShared,
InitializedFlag::kUninitialized);
std::unique_ptr<BackingStore> backing_store;
if (data == kOffHeapBackingStore) {
backing_store = BackingStore::Allocate(
main_thread_isolate(), byte_length, SharedFlag::kNotShared,
InitializedFlag::kUninitialized);
} else {
int max_byte_length = source_.GetInt();
size_t page_size, initial_pages, max_pages;
Maybe<bool> result =
JSArrayBuffer::GetResizableBackingStorePageConfiguration(
nullptr, byte_length, max_byte_length, kDontThrow, &page_size,
&initial_pages, &max_pages);
DCHECK(result.FromJust());
USE(result);
constexpr bool kIsWasmMemory = false;
backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory(
main_thread_isolate(), byte_length, max_byte_length, page_size,
initial_pages, max_pages, kIsWasmMemory, SharedFlag::kNotShared);
}
CHECK_NOT_NULL(backing_store);
source_.CopyRaw(backing_store->buffer_start(), byte_length);
backing_stores_.push_back(std::move(backing_store));

View File

@ -35,8 +35,8 @@ class SerializerDeserializer : public RootVisitor {
// clang-format off
#define UNUSED_SERIALIZER_BYTE_CODES(V) \
/* Free range 0x1d..0x1f */ \
V(0x1d) V(0x1e) V(0x1f) \
/* Free range 0x1e..0x1f */ \
V(0x1e) V(0x1f) \
/* Free range 0x20..0x2f */ \
V(0x20) V(0x21) V(0x22) V(0x23) V(0x24) V(0x25) V(0x26) V(0x27) \
V(0x28) V(0x29) V(0x2a) V(0x2b) V(0x2c) V(0x2d) V(0x2e) V(0x2f) \
@ -83,7 +83,7 @@ class SerializerDeserializer : public RootVisitor {
enum Bytecode : byte {
//
// ---------- byte code range 0x00..0x1c ----------
// ---------- byte code range 0x00..0x1d ----------
//
// 0x00..0x03 Allocate new object, in specified space.
@ -114,6 +114,7 @@ class SerializerDeserializer : public RootVisitor {
kVariableRepeat,
// Used for embedder-allocated backing stores for TypedArrays.
kOffHeapBackingStore,
kOffHeapResizableBackingStore,
// Used for embedder-provided serialization data for embedder fields.
kEmbedderFieldsData,
// Raw data of variable length.

View File

@ -474,14 +474,22 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
}
uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
void* backing_store, int32_t byte_length) {
void* backing_store, int32_t byte_length, Maybe<int32_t> max_byte_length) {
const SerializerReference* reference_ptr =
serializer_->reference_map()->LookupBackingStore(backing_store);
// Serialize the off-heap backing store.
if (!reference_ptr) {
sink_->Put(kOffHeapBackingStore, "Off-heap backing store");
if (max_byte_length.IsJust()) {
sink_->Put(kOffHeapResizableBackingStore,
"Off-heap resizable backing store");
} else {
sink_->Put(kOffHeapBackingStore, "Off-heap backing store");
}
sink_->PutInt(byte_length, "length");
if (max_byte_length.IsJust()) {
sink_->PutInt(max_byte_length.FromJust(), "max length");
}
sink_->PutRaw(static_cast<byte*>(backing_store), byte_length,
"BackingStore");
DCHECK_NE(0, serializer_->seen_backing_stores_index_);
@ -504,9 +512,15 @@ void Serializer::ObjectSerializer::SerializeJSTypedArray() {
if (!typed_array->WasDetached()) {
// Explicitly serialize the backing store now.
JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array->buffer());
// We cannot store byte_length larger than int32 range in the snapshot.
// We cannot store byte_length or max_byte_length larger than int32 range
// in the snapshot.
CHECK_LE(buffer.byte_length(), std::numeric_limits<int32_t>::max());
int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
Maybe<int32_t> max_byte_length = Nothing<int32_t>();
if (buffer.is_resizable()) {
CHECK_LE(buffer.max_byte_length(), std::numeric_limits<int32_t>::max());
max_byte_length = Just(static_cast<int32_t>(buffer.max_byte_length()));
}
size_t byte_offset = typed_array->byte_offset();
// We need to calculate the backing store from the data pointer
@ -514,7 +528,8 @@ void Serializer::ObjectSerializer::SerializeJSTypedArray() {
void* backing_store = reinterpret_cast<void*>(
reinterpret_cast<Address>(typed_array->DataPtr()) - byte_offset);
uint32_t ref = SerializeBackingStore(backing_store, byte_length);
uint32_t ref =
SerializeBackingStore(backing_store, byte_length, max_byte_length);
typed_array->SetExternalBackingStoreRefForSerialization(ref);
} else {
typed_array->SetExternalBackingStoreRefForSerialization(0);
@ -526,16 +541,23 @@ void Serializer::ObjectSerializer::SerializeJSTypedArray() {
void Serializer::ObjectSerializer::SerializeJSArrayBuffer() {
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(object_);
void* backing_store = buffer->backing_store();
// We cannot store byte_length larger than int32 range in the snapshot.
// We cannot store byte_length or max_byte_length larger than int32 range in
// the snapshot.
CHECK_LE(buffer->byte_length(), std::numeric_limits<int32_t>::max());
int32_t byte_length = static_cast<int32_t>(buffer->byte_length());
Maybe<int32_t> max_byte_length = Nothing<int32_t>();
if (buffer->is_resizable()) {
CHECK_LE(buffer->max_byte_length(), std::numeric_limits<int32_t>::max());
max_byte_length = Just(static_cast<int32_t>(buffer->max_byte_length()));
}
ArrayBufferExtension* extension = buffer->extension();
// Only serialize non-empty backing stores.
if (buffer->IsEmpty()) {
buffer->SetBackingStoreRefForSerialization(kEmptyBackingStoreRefSentinel);
} else {
uint32_t ref = SerializeBackingStore(backing_store, byte_length);
uint32_t ref =
SerializeBackingStore(backing_store, byte_length, max_byte_length);
buffer->SetBackingStoreRefForSerialization(ref);
// Ensure deterministic output by setting extension to null during

View File

@ -470,7 +470,8 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
ExternalPointerTag tag);
void OutputRawData(Address up_to);
void SerializeCode(Map map, int size);
uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length);
uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length,
Maybe<int32_t> max_byte_length);
void SerializeJSTypedArray();
void SerializeJSArrayBuffer();
void SerializeExternalString();

View File

@ -659,6 +659,16 @@ V8_INLINE void ZapCode(Address addr, size_t size_in_bytes) {
std::memset(reinterpret_cast<void*>(addr), kZapByte, size_in_bytes);
}
inline bool RoundUpToPageSize(size_t byte_length, size_t page_size,
size_t max_allowed_byte_length, size_t* pages) {
size_t bytes_wanted = RoundUp(byte_length, page_size);
if (bytes_wanted > max_allowed_byte_length) {
return false;
}
*pages = bytes_wanted / page_size;
return true;
}
} // namespace internal
} // namespace v8

View File

@ -1464,11 +1464,6 @@
# Script referenced only through context-dependent SourceTextModule
# https://bugs.chromium.org/p/v8/issues/detail?id=11073
'tools/processor': [SKIP],
# TODO(v8:11111) and
# https://bugs.chromium.org/p/v8/issues/detail?id=12731
'regress/regress-crbug-1306929': [SKIP],
# https://crbug.com/v8/12742
'regress/regress-crbug-1307310': [SKIP],
}], # variant == stress_snapshot and arch == x64
##############################################################################