[wasm] [cleanup] Attach methods to the object they operate on
This CL cleans up a few things: - It removes two dead declarations: WasmMemoryObject::Grow and wasm::GrowInstanceMemory. - It removes the unneeded wasm::GetInstanceMemory function (use instance->memory_buffer() directly). - It moves wasm::GetInstanceMemorySize to WasmInstanceObject::GetMemorySize. - It moves wasm::GrowInstanceMemory to WasmInstanceObject::GrowMemory. - It moves wasm::GrowWebAssemblyMemory to WasmMemoryObject::Grow. R=ahaas@chromium.org CC=gdeepti@chromium.org Change-Id: I19781ca9784f1a8e7b60955bef82e341c4f75550 Reviewed-on: https://chromium-review.googlesource.com/463167 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Deepti Gandluri <gdeepti@chromium.org> Cr-Commit-Position: refs/heads/master@{#44293}
This commit is contained in:
parent
19f655a814
commit
c32113e7eb
@ -45,10 +45,8 @@ RUNTIME_FUNCTION(Runtime_WasmMemorySize) {
|
|||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
DCHECK_EQ(0, args.length());
|
DCHECK_EQ(0, args.length());
|
||||||
|
|
||||||
Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
|
int32_t mem_size = GetWasmInstanceOnStackTop(isolate)->GetMemorySize();
|
||||||
isolate);
|
return *isolate->factory()->NewNumberFromInt(mem_size);
|
||||||
return *isolate->factory()->NewNumberFromInt(
|
|
||||||
wasm::GetInstanceMemorySize(isolate, instance));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
|
RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
|
||||||
@ -63,7 +61,7 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
|
|||||||
isolate->set_context(instance->compiled_module()->ptr_to_native_context());
|
isolate->set_context(instance->compiled_module()->ptr_to_native_context());
|
||||||
|
|
||||||
return *isolate->factory()->NewNumberFromInt(
|
return *isolate->factory()->NewNumberFromInt(
|
||||||
wasm::GrowMemory(isolate, instance, delta_pages));
|
WasmInstanceObject::GrowMemory(isolate, instance, delta_pages));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset,
|
Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset,
|
||||||
|
@ -646,8 +646,8 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
: "maximum memory size exceeded");
|
: "maximum memory size exceeded");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int32_t ret = i::wasm::GrowWebAssemblyMemory(
|
int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver,
|
||||||
i_isolate, receiver, static_cast<uint32_t>(delta_size));
|
static_cast<uint32_t>(delta_size));
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
thrower.RangeError("Unable to grow instance memory.");
|
thrower.RangeError("Unable to grow instance memory.");
|
||||||
return;
|
return;
|
||||||
|
@ -816,9 +816,10 @@ void RecordLazyCodeStats(Isolate* isolate, Code* code) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
|
Handle<JSArrayBuffer> wasm::SetupArrayBuffer(Isolate* isolate,
|
||||||
size_t size, bool is_external,
|
void* backing_store, size_t size,
|
||||||
bool enable_guard_regions) {
|
bool is_external,
|
||||||
|
bool enable_guard_regions) {
|
||||||
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
||||||
JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store,
|
JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store,
|
||||||
static_cast<int>(size));
|
static_cast<int>(size));
|
||||||
@ -2237,105 +2238,6 @@ bool wasm::IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
|
|||||||
isolate->allow_code_gen_callback()(v8::Utils::ToLocal(context));
|
isolate->allow_code_gen_callback()(v8::Utils::ToLocal(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeHandle<JSArrayBuffer> wasm::GetInstanceMemory(
|
|
||||||
Isolate* isolate, Handle<WasmInstanceObject> object) {
|
|
||||||
auto instance = Handle<WasmInstanceObject>::cast(object);
|
|
||||||
if (instance->has_memory_buffer()) {
|
|
||||||
return Handle<JSArrayBuffer>(instance->memory_buffer(), isolate);
|
|
||||||
}
|
|
||||||
return MaybeHandle<JSArrayBuffer>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// May GC, because SetSpecializationMemInfoFrom may GC
|
|
||||||
void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
|
||||||
Handle<JSArrayBuffer> buffer) {
|
|
||||||
instance->set_memory_buffer(*buffer);
|
|
||||||
WasmCompiledModule::SetSpecializationMemInfoFrom(
|
|
||||||
isolate->factory(), handle(instance->compiled_module()), buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t wasm::GetInstanceMemorySize(Isolate* isolate,
|
|
||||||
Handle<WasmInstanceObject> instance) {
|
|
||||||
DCHECK(IsWasmInstance(*instance));
|
|
||||||
MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
|
|
||||||
GetInstanceMemory(isolate, instance);
|
|
||||||
Handle<JSArrayBuffer> buffer;
|
|
||||||
if (!maybe_mem_buffer.ToHandle(&buffer)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return buffer->byte_length()->Number() / WasmModule::kPageSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t GetMaxInstanceMemoryPages(Isolate* isolate,
|
|
||||||
Handle<WasmInstanceObject> instance) {
|
|
||||||
if (instance->has_memory_object()) {
|
|
||||||
Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate);
|
|
||||||
if (memory_object->has_maximum_pages()) {
|
|
||||||
uint32_t maximum = static_cast<uint32_t>(memory_object->maximum_pages());
|
|
||||||
if (maximum < FLAG_wasm_max_mem_pages) return maximum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WasmCompiledModule* compiled_module = instance->compiled_module();
|
|
||||||
uint32_t compiled_max_pages = compiled_module->max_mem_pages();
|
|
||||||
(compiled_module->module()->is_wasm()
|
|
||||||
? isolate->counters()->wasm_wasm_max_mem_pages_count()
|
|
||||||
: isolate->counters()->wasm_asm_max_mem_pages_count())
|
|
||||||
->AddSample(compiled_max_pages);
|
|
||||||
if (compiled_max_pages != 0) return compiled_max_pages;
|
|
||||||
return FLAG_wasm_max_mem_pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
|
|
||||||
MaybeHandle<JSArrayBuffer> buffer,
|
|
||||||
uint32_t pages, uint32_t max_pages) {
|
|
||||||
Handle<JSArrayBuffer> old_buffer;
|
|
||||||
Address old_mem_start = nullptr;
|
|
||||||
uint32_t old_size = 0;
|
|
||||||
if (buffer.ToHandle(&old_buffer) && old_buffer->backing_store() != nullptr &&
|
|
||||||
old_buffer->byte_length()->IsNumber()) {
|
|
||||||
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
|
||||||
DCHECK_NOT_NULL(old_mem_start);
|
|
||||||
old_size = old_buffer->byte_length()->Number();
|
|
||||||
}
|
|
||||||
DCHECK(old_size + pages * WasmModule::kPageSize <=
|
|
||||||
std::numeric_limits<uint32_t>::max());
|
|
||||||
uint32_t new_size = old_size + pages * WasmModule::kPageSize;
|
|
||||||
if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
|
|
||||||
FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) {
|
|
||||||
return Handle<JSArrayBuffer>::null();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(gdeepti): Change the protection here instead of allocating a new
|
|
||||||
// buffer before guard regions are turned on, see issue #5886.
|
|
||||||
const bool enable_guard_regions =
|
|
||||||
(old_buffer.is_null() && EnableGuardRegions()) ||
|
|
||||||
(!old_buffer.is_null() && old_buffer->has_guard_region());
|
|
||||||
Handle<JSArrayBuffer> new_buffer =
|
|
||||||
NewArrayBuffer(isolate, new_size, enable_guard_regions);
|
|
||||||
if (new_buffer.is_null()) return new_buffer;
|
|
||||||
Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
|
|
||||||
if (old_size != 0) {
|
|
||||||
memcpy(new_mem_start, old_mem_start, old_size);
|
|
||||||
}
|
|
||||||
return new_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UncheckedUpdateInstanceMemory(Isolate* isolate,
|
|
||||||
Handle<WasmInstanceObject> instance,
|
|
||||||
Address old_mem_start, uint32_t old_size) {
|
|
||||||
DCHECK(instance->has_memory_buffer());
|
|
||||||
Handle<JSArrayBuffer> mem_buffer(instance->memory_buffer());
|
|
||||||
uint32_t new_size = mem_buffer->byte_length()->Number();
|
|
||||||
Address new_mem_start = static_cast<Address>(mem_buffer->backing_store());
|
|
||||||
DCHECK_NOT_NULL(new_mem_start);
|
|
||||||
Zone specialization_zone(isolate->allocator(), ZONE_NAME);
|
|
||||||
CodeSpecialization code_specialization(isolate, &specialization_zone);
|
|
||||||
code_specialization.RelocateMemoryReferences(old_mem_start, old_size,
|
|
||||||
new_mem_start, new_size);
|
|
||||||
code_specialization.ApplyToWholeInstance(*instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wasm::DetachWebAssemblyMemoryBuffer(Isolate* isolate,
|
void wasm::DetachWebAssemblyMemoryBuffer(Isolate* isolate,
|
||||||
Handle<JSArrayBuffer> buffer) {
|
Handle<JSArrayBuffer> buffer) {
|
||||||
int64_t byte_length =
|
int64_t byte_length =
|
||||||
@ -2363,114 +2265,6 @@ void wasm::DetachWebAssemblyMemoryBuffer(Isolate* isolate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate,
|
|
||||||
Handle<WasmMemoryObject> receiver,
|
|
||||||
uint32_t pages) {
|
|
||||||
DCHECK(WasmJs::IsWasmMemoryObject(isolate, receiver));
|
|
||||||
Handle<WasmMemoryObject> memory_object =
|
|
||||||
handle(WasmMemoryObject::cast(*receiver));
|
|
||||||
MaybeHandle<JSArrayBuffer> memory_buffer = handle(memory_object->buffer());
|
|
||||||
Handle<JSArrayBuffer> old_buffer;
|
|
||||||
uint32_t old_size = 0;
|
|
||||||
Address old_mem_start = nullptr;
|
|
||||||
// Force byte_length to 0, if byte_length fails IsNumber() check.
|
|
||||||
if (memory_buffer.ToHandle(&old_buffer) &&
|
|
||||||
old_buffer->backing_store() != nullptr &&
|
|
||||||
old_buffer->byte_length()->IsNumber()) {
|
|
||||||
old_size = old_buffer->byte_length()->Number();
|
|
||||||
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
|
||||||
}
|
|
||||||
Handle<JSArrayBuffer> new_buffer;
|
|
||||||
// Return current size if grow by 0
|
|
||||||
if (pages == 0) {
|
|
||||||
if (!old_buffer.is_null() && old_buffer->backing_store() != nullptr) {
|
|
||||||
new_buffer = SetupArrayBuffer(isolate, old_buffer->backing_store(),
|
|
||||||
old_size, old_buffer->is_external(),
|
|
||||||
old_buffer->has_guard_region());
|
|
||||||
memory_object->set_buffer(*new_buffer);
|
|
||||||
old_buffer->set_is_neuterable(true);
|
|
||||||
if (!old_buffer->has_guard_region()) {
|
|
||||||
old_buffer->set_is_external(true);
|
|
||||||
isolate->heap()->UnregisterArrayBuffer(*old_buffer);
|
|
||||||
}
|
|
||||||
// Neuter but don't free the memory because it is now being used by
|
|
||||||
// new_buffer.
|
|
||||||
old_buffer->Neuter();
|
|
||||||
}
|
|
||||||
DCHECK(old_size % WasmModule::kPageSize == 0);
|
|
||||||
return (old_size / WasmModule::kPageSize);
|
|
||||||
}
|
|
||||||
if (!memory_object->has_instances_link()) {
|
|
||||||
// Memory object does not have an instance associated with it, just grow
|
|
||||||
uint32_t max_pages;
|
|
||||||
if (memory_object->has_maximum_pages()) {
|
|
||||||
max_pages = static_cast<uint32_t>(memory_object->maximum_pages());
|
|
||||||
if (FLAG_wasm_max_mem_pages < max_pages) return -1;
|
|
||||||
} else {
|
|
||||||
max_pages = FLAG_wasm_max_mem_pages;
|
|
||||||
}
|
|
||||||
new_buffer = GrowMemoryBuffer(isolate, memory_buffer, pages, max_pages);
|
|
||||||
if (new_buffer.is_null()) return -1;
|
|
||||||
} else {
|
|
||||||
Handle<WasmInstanceWrapper> instance_wrapper(
|
|
||||||
memory_object->instances_link());
|
|
||||||
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
|
|
||||||
DCHECK(instance_wrapper->has_instance());
|
|
||||||
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
|
|
||||||
DCHECK(IsWasmInstance(*instance));
|
|
||||||
uint32_t max_pages = GetMaxInstanceMemoryPages(isolate, instance);
|
|
||||||
|
|
||||||
// Grow memory object buffer and update instances associated with it.
|
|
||||||
new_buffer = GrowMemoryBuffer(isolate, memory_buffer, pages, max_pages);
|
|
||||||
if (new_buffer.is_null()) return -1;
|
|
||||||
DCHECK(!instance_wrapper->has_previous());
|
|
||||||
SetInstanceMemory(isolate, instance, new_buffer);
|
|
||||||
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
|
|
||||||
while (instance_wrapper->has_next()) {
|
|
||||||
instance_wrapper = instance_wrapper->next_wrapper();
|
|
||||||
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
|
|
||||||
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
|
|
||||||
DCHECK(IsWasmInstance(*instance));
|
|
||||||
SetInstanceMemory(isolate, instance, new_buffer);
|
|
||||||
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memory_object->set_buffer(*new_buffer);
|
|
||||||
DCHECK(old_size % WasmModule::kPageSize == 0);
|
|
||||||
return (old_size / WasmModule::kPageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
|
||||||
uint32_t pages) {
|
|
||||||
if (!IsWasmInstance(*instance)) return -1;
|
|
||||||
if (pages == 0) return GetInstanceMemorySize(isolate, instance);
|
|
||||||
Handle<WasmInstanceObject> instance_obj(WasmInstanceObject::cast(*instance));
|
|
||||||
if (!instance_obj->has_memory_object()) {
|
|
||||||
// No other instances to grow, grow just the one.
|
|
||||||
MaybeHandle<JSArrayBuffer> instance_buffer =
|
|
||||||
GetInstanceMemory(isolate, instance);
|
|
||||||
Handle<JSArrayBuffer> old_buffer;
|
|
||||||
uint32_t old_size = 0;
|
|
||||||
Address old_mem_start = nullptr;
|
|
||||||
if (instance_buffer.ToHandle(&old_buffer) &&
|
|
||||||
old_buffer->backing_store() != nullptr) {
|
|
||||||
old_size = old_buffer->byte_length()->Number();
|
|
||||||
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
|
||||||
}
|
|
||||||
uint32_t max_pages = GetMaxInstanceMemoryPages(isolate, instance_obj);
|
|
||||||
Handle<JSArrayBuffer> buffer =
|
|
||||||
GrowMemoryBuffer(isolate, instance_buffer, pages, max_pages);
|
|
||||||
if (buffer.is_null()) return -1;
|
|
||||||
SetInstanceMemory(isolate, instance, buffer);
|
|
||||||
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
|
|
||||||
DCHECK(old_size % WasmModule::kPageSize == 0);
|
|
||||||
return (old_size / WasmModule::kPageSize);
|
|
||||||
} else {
|
|
||||||
return GrowWebAssemblyMemory(isolate, handle(instance_obj->memory_object()),
|
|
||||||
pages);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void wasm::GrowDispatchTables(Isolate* isolate,
|
void wasm::GrowDispatchTables(Isolate* isolate,
|
||||||
Handle<FixedArray> dispatch_tables,
|
Handle<FixedArray> dispatch_tables,
|
||||||
uint32_t old_size, uint32_t count) {
|
uint32_t old_size, uint32_t count) {
|
||||||
|
@ -419,24 +419,12 @@ int GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
|
|||||||
// Returns nullptr on failing to get owning instance.
|
// Returns nullptr on failing to get owning instance.
|
||||||
WasmInstanceObject* GetOwningWasmInstance(Code* code);
|
WasmInstanceObject* GetOwningWasmInstance(Code* code);
|
||||||
|
|
||||||
MaybeHandle<JSArrayBuffer> GetInstanceMemory(
|
Handle<JSArrayBuffer> NewArrayBuffer(Isolate*, size_t size,
|
||||||
Isolate* isolate, Handle<WasmInstanceObject> instance);
|
|
||||||
|
|
||||||
int32_t GetInstanceMemorySize(Isolate* isolate,
|
|
||||||
Handle<WasmInstanceObject> instance);
|
|
||||||
|
|
||||||
int32_t GrowInstanceMemory(Isolate* isolate,
|
|
||||||
Handle<WasmInstanceObject> instance, uint32_t pages);
|
|
||||||
|
|
||||||
Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
|
|
||||||
bool enable_guard_regions);
|
bool enable_guard_regions);
|
||||||
|
|
||||||
int32_t GrowWebAssemblyMemory(Isolate* isolate,
|
Handle<JSArrayBuffer> SetupArrayBuffer(Isolate*, void* backing_store,
|
||||||
Handle<WasmMemoryObject> receiver,
|
size_t size, bool is_external,
|
||||||
uint32_t pages);
|
bool enable_guard_regions);
|
||||||
|
|
||||||
int32_t GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
|
||||||
uint32_t pages);
|
|
||||||
|
|
||||||
void DetachWebAssemblyMemoryBuffer(Isolate* isolate,
|
void DetachWebAssemblyMemoryBuffer(Isolate* isolate,
|
||||||
Handle<JSArrayBuffer> buffer);
|
Handle<JSArrayBuffer> buffer);
|
||||||
|
@ -337,6 +337,64 @@ void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
|
|||||||
table->functions()->length(), count);
|
table->functions()->length(), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
|
||||||
|
Handle<JSArrayBuffer> old_buffer,
|
||||||
|
uint32_t pages, uint32_t max_pages) {
|
||||||
|
Address old_mem_start = nullptr;
|
||||||
|
uint32_t old_size = 0;
|
||||||
|
if (!old_buffer.is_null()) {
|
||||||
|
DCHECK(old_buffer->byte_length()->IsNumber());
|
||||||
|
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
||||||
|
old_size = old_buffer->byte_length()->Number();
|
||||||
|
}
|
||||||
|
DCHECK_GE(std::numeric_limits<uint32_t>::max(),
|
||||||
|
old_size + pages * WasmModule::kPageSize);
|
||||||
|
uint32_t new_size = old_size + pages * WasmModule::kPageSize;
|
||||||
|
if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
|
||||||
|
FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) {
|
||||||
|
return Handle<JSArrayBuffer>::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(gdeepti): Change the protection here instead of allocating a new
|
||||||
|
// buffer before guard regions are turned on, see issue #5886.
|
||||||
|
const bool enable_guard_regions =
|
||||||
|
(old_buffer.is_null() && EnableGuardRegions()) ||
|
||||||
|
(!old_buffer.is_null() && old_buffer->has_guard_region());
|
||||||
|
Handle<JSArrayBuffer> new_buffer =
|
||||||
|
NewArrayBuffer(isolate, new_size, enable_guard_regions);
|
||||||
|
if (new_buffer.is_null()) return new_buffer;
|
||||||
|
Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
|
||||||
|
memcpy(new_mem_start, old_mem_start, old_size);
|
||||||
|
return new_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// May GC, because SetSpecializationMemInfoFrom may GC
|
||||||
|
void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
||||||
|
Handle<JSArrayBuffer> buffer) {
|
||||||
|
instance->set_memory_buffer(*buffer);
|
||||||
|
WasmCompiledModule::SetSpecializationMemInfoFrom(
|
||||||
|
isolate->factory(), handle(instance->compiled_module()), buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UncheckedUpdateInstanceMemory(Isolate* isolate,
|
||||||
|
Handle<WasmInstanceObject> instance,
|
||||||
|
Address old_mem_start, uint32_t old_size) {
|
||||||
|
DCHECK(instance->has_memory_buffer());
|
||||||
|
Handle<JSArrayBuffer> mem_buffer(instance->memory_buffer());
|
||||||
|
uint32_t new_size = mem_buffer->byte_length()->Number();
|
||||||
|
Address new_mem_start = static_cast<Address>(mem_buffer->backing_store());
|
||||||
|
DCHECK_NOT_NULL(new_mem_start);
|
||||||
|
Zone specialization_zone(isolate->allocator(), ZONE_NAME);
|
||||||
|
CodeSpecialization code_specialization(isolate, &specialization_zone);
|
||||||
|
code_specialization.RelocateMemoryReferences(old_mem_start, old_size,
|
||||||
|
new_mem_start, new_size);
|
||||||
|
code_specialization.ApplyToWholeInstance(*instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
|
Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
|
||||||
Handle<JSArrayBuffer> buffer,
|
Handle<JSArrayBuffer> buffer,
|
||||||
int32_t maximum) {
|
int32_t maximum) {
|
||||||
@ -395,6 +453,80 @@ void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) {
|
|||||||
SetEmbedderField(kInstancesLink, *undefined);
|
SetEmbedderField(kInstancesLink, *undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
int32_t WasmMemoryObject::Grow(Isolate* isolate,
|
||||||
|
Handle<WasmMemoryObject> memory_object,
|
||||||
|
uint32_t pages) {
|
||||||
|
Handle<JSArrayBuffer> old_buffer(memory_object->buffer(), isolate);
|
||||||
|
uint32_t old_size = 0;
|
||||||
|
Address old_mem_start = nullptr;
|
||||||
|
// Force byte_length to 0, if byte_length fails IsNumber() check.
|
||||||
|
if (!old_buffer.is_null()) {
|
||||||
|
old_size = old_buffer->byte_length()->Number();
|
||||||
|
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
||||||
|
}
|
||||||
|
Handle<JSArrayBuffer> new_buffer;
|
||||||
|
// Return current size if grow by 0.
|
||||||
|
if (pages == 0) {
|
||||||
|
// Even for pages == 0, we need to attach a new JSArrayBuffer and neuter the
|
||||||
|
// old one to be spec compliant.
|
||||||
|
if (!old_buffer.is_null() && old_buffer->backing_store() != nullptr) {
|
||||||
|
new_buffer = SetupArrayBuffer(isolate, old_buffer->backing_store(),
|
||||||
|
old_size, old_buffer->is_external(),
|
||||||
|
old_buffer->has_guard_region());
|
||||||
|
memory_object->set_buffer(*new_buffer);
|
||||||
|
old_buffer->set_is_neuterable(true);
|
||||||
|
if (!old_buffer->has_guard_region()) {
|
||||||
|
old_buffer->set_is_external(true);
|
||||||
|
isolate->heap()->UnregisterArrayBuffer(*old_buffer);
|
||||||
|
}
|
||||||
|
// Neuter but don't free the memory because it is now being used by
|
||||||
|
// new_buffer.
|
||||||
|
old_buffer->Neuter();
|
||||||
|
}
|
||||||
|
DCHECK_EQ(0, old_size % WasmModule::kPageSize);
|
||||||
|
return old_size / WasmModule::kPageSize;
|
||||||
|
}
|
||||||
|
if (!memory_object->has_instances_link()) {
|
||||||
|
// Memory object does not have an instance associated with it, just grow
|
||||||
|
uint32_t max_pages;
|
||||||
|
if (memory_object->has_maximum_pages()) {
|
||||||
|
max_pages = static_cast<uint32_t>(memory_object->maximum_pages());
|
||||||
|
if (FLAG_wasm_max_mem_pages < max_pages) return -1;
|
||||||
|
} else {
|
||||||
|
max_pages = FLAG_wasm_max_mem_pages;
|
||||||
|
}
|
||||||
|
new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages);
|
||||||
|
if (new_buffer.is_null()) return -1;
|
||||||
|
} else {
|
||||||
|
Handle<WasmInstanceWrapper> instance_wrapper(
|
||||||
|
memory_object->instances_link());
|
||||||
|
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
|
||||||
|
DCHECK(instance_wrapper->has_instance());
|
||||||
|
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
|
||||||
|
DCHECK(IsWasmInstance(*instance));
|
||||||
|
uint32_t max_pages = instance->GetMaxMemoryPages();
|
||||||
|
|
||||||
|
// Grow memory object buffer and update instances associated with it.
|
||||||
|
new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages);
|
||||||
|
if (new_buffer.is_null()) return -1;
|
||||||
|
DCHECK(!instance_wrapper->has_previous());
|
||||||
|
SetInstanceMemory(isolate, instance, new_buffer);
|
||||||
|
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
|
||||||
|
while (instance_wrapper->has_next()) {
|
||||||
|
instance_wrapper = instance_wrapper->next_wrapper();
|
||||||
|
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
|
||||||
|
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
|
||||||
|
DCHECK(IsWasmInstance(*instance));
|
||||||
|
SetInstanceMemory(isolate, instance, new_buffer);
|
||||||
|
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memory_object->set_buffer(*new_buffer);
|
||||||
|
DCHECK_EQ(0, old_size % WasmModule::kPageSize);
|
||||||
|
return old_size / WasmModule::kPageSize;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
|
DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
|
||||||
WasmCompiledModule)
|
WasmCompiledModule)
|
||||||
DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer,
|
DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer,
|
||||||
@ -469,6 +601,59 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t WasmInstanceObject::GetMemorySize() {
|
||||||
|
if (!has_memory_buffer()) return 0;
|
||||||
|
uint32_t bytes = memory_buffer()->byte_length()->Number();
|
||||||
|
DCHECK_EQ(0, bytes % WasmModule::kPageSize);
|
||||||
|
return bytes / WasmModule::kPageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t WasmInstanceObject::GrowMemory(Isolate* isolate,
|
||||||
|
Handle<WasmInstanceObject> instance,
|
||||||
|
uint32_t pages) {
|
||||||
|
if (pages == 0) return instance->GetMemorySize();
|
||||||
|
if (instance->has_memory_object()) {
|
||||||
|
return WasmMemoryObject::Grow(
|
||||||
|
isolate, handle(instance->memory_object(), isolate), pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No other instances to grow, grow just the one.
|
||||||
|
uint32_t old_size = 0;
|
||||||
|
Address old_mem_start = nullptr;
|
||||||
|
Handle<JSArrayBuffer> old_buffer;
|
||||||
|
if (instance->has_memory_buffer()) {
|
||||||
|
old_buffer = handle(instance->memory_buffer(), isolate);
|
||||||
|
old_size = old_buffer->byte_length()->Number();
|
||||||
|
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
||||||
|
}
|
||||||
|
uint32_t max_pages = instance->GetMaxMemoryPages();
|
||||||
|
Handle<JSArrayBuffer> buffer =
|
||||||
|
GrowMemoryBuffer(isolate, old_buffer, pages, max_pages);
|
||||||
|
if (buffer.is_null()) return -1;
|
||||||
|
SetInstanceMemory(isolate, instance, buffer);
|
||||||
|
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
|
||||||
|
DCHECK_EQ(0, old_size % WasmModule::kPageSize);
|
||||||
|
return old_size / WasmModule::kPageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t WasmInstanceObject::GetMaxMemoryPages() {
|
||||||
|
if (has_memory_object()) {
|
||||||
|
if (memory_object()->has_maximum_pages()) {
|
||||||
|
uint32_t maximum =
|
||||||
|
static_cast<uint32_t>(memory_object()->maximum_pages());
|
||||||
|
if (maximum < FLAG_wasm_max_mem_pages) return maximum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t compiled_max_pages = compiled_module()->max_mem_pages();
|
||||||
|
Isolate* isolate = GetIsolate();
|
||||||
|
auto* histogram = (compiled_module()->module()->is_wasm()
|
||||||
|
? isolate->counters()->wasm_wasm_max_mem_pages_count()
|
||||||
|
: isolate->counters()->wasm_asm_max_mem_pages_count());
|
||||||
|
histogram->AddSample(compiled_max_pages);
|
||||||
|
if (compiled_max_pages != 0) return compiled_max_pages;
|
||||||
|
return FLAG_wasm_max_mem_pages;
|
||||||
|
}
|
||||||
|
|
||||||
WasmInstanceObject* WasmExportedFunction::instance() {
|
WasmInstanceObject* WasmExportedFunction::instance() {
|
||||||
return WasmInstanceObject::cast(GetEmbedderField(kInstance));
|
return WasmInstanceObject::cast(GetEmbedderField(kInstance));
|
||||||
}
|
}
|
||||||
|
@ -115,8 +115,7 @@ class WasmMemoryObject : public JSObject {
|
|||||||
Handle<JSArrayBuffer> buffer,
|
Handle<JSArrayBuffer> buffer,
|
||||||
int32_t maximum);
|
int32_t maximum);
|
||||||
|
|
||||||
static bool Grow(Isolate* isolate, Handle<WasmMemoryObject> memory,
|
static int32_t Grow(Isolate*, Handle<WasmMemoryObject>, uint32_t pages);
|
||||||
uint32_t count);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Representation of a WebAssembly.Instance JavaScript-level object.
|
// Representation of a WebAssembly.Instance JavaScript-level object.
|
||||||
@ -149,11 +148,16 @@ class WasmInstanceObject : public JSObject {
|
|||||||
|
|
||||||
// Get the debug info associated with the given wasm object.
|
// Get the debug info associated with the given wasm object.
|
||||||
// If no debug info exists yet, it is created automatically.
|
// If no debug info exists yet, it is created automatically.
|
||||||
static Handle<WasmDebugInfo> GetOrCreateDebugInfo(
|
static Handle<WasmDebugInfo> GetOrCreateDebugInfo(Handle<WasmInstanceObject>);
|
||||||
Handle<WasmInstanceObject> instance);
|
|
||||||
|
|
||||||
static Handle<WasmInstanceObject> New(
|
static Handle<WasmInstanceObject> New(Isolate*, Handle<WasmCompiledModule>);
|
||||||
Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
|
|
||||||
|
int32_t GetMemorySize();
|
||||||
|
|
||||||
|
static int32_t GrowMemory(Isolate*, Handle<WasmInstanceObject>,
|
||||||
|
uint32_t pages);
|
||||||
|
|
||||||
|
uint32_t GetMaxMemoryPages();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Representation of an exported WASM function.
|
// Representation of an exported WASM function.
|
||||||
|
@ -700,9 +700,7 @@ TEST(TestInterruptLoop) {
|
|||||||
ModuleOrigin::kWasmOrigin);
|
ModuleOrigin::kWasmOrigin);
|
||||||
CHECK(!instance.is_null());
|
CHECK(!instance.is_null());
|
||||||
|
|
||||||
MaybeHandle<JSArrayBuffer> maybe_memory =
|
Handle<JSArrayBuffer> memory(instance->memory_buffer(), isolate);
|
||||||
GetInstanceMemory(isolate, instance);
|
|
||||||
Handle<JSArrayBuffer> memory = maybe_memory.ToHandleChecked();
|
|
||||||
int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
|
int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
|
||||||
|
|
||||||
InterruptThread thread(isolate, memory_array);
|
InterruptThread thread(isolate, memory_array);
|
||||||
@ -1099,9 +1097,7 @@ TEST(Run_WasmModule_Buffer_Externalized_GrowMem) {
|
|||||||
isolate, &thrower, buffer.begin(), buffer.end(),
|
isolate, &thrower, buffer.begin(), buffer.end(),
|
||||||
ModuleOrigin::kWasmOrigin);
|
ModuleOrigin::kWasmOrigin);
|
||||||
CHECK(!instance.is_null());
|
CHECK(!instance.is_null());
|
||||||
MaybeHandle<JSArrayBuffer> maybe_memory =
|
Handle<JSArrayBuffer> memory(instance->memory_buffer(), isolate);
|
||||||
GetInstanceMemory(isolate, instance);
|
|
||||||
Handle<JSArrayBuffer> memory = maybe_memory.ToHandleChecked();
|
|
||||||
|
|
||||||
// Fake the Embedder flow by creating a memory object, externalize and grow.
|
// Fake the Embedder flow by creating a memory object, externalize and grow.
|
||||||
Handle<WasmMemoryObject> mem_obj =
|
Handle<WasmMemoryObject> mem_obj =
|
||||||
@ -1115,7 +1111,7 @@ TEST(Run_WasmModule_Buffer_Externalized_GrowMem) {
|
|||||||
if (!memory->has_guard_region()) v8::Utils::ToLocal(memory)->Externalize();
|
if (!memory->has_guard_region()) v8::Utils::ToLocal(memory)->Externalize();
|
||||||
void* backing_store = memory->backing_store();
|
void* backing_store = memory->backing_store();
|
||||||
uint64_t byte_length = NumberToSize(memory->byte_length());
|
uint64_t byte_length = NumberToSize(memory->byte_length());
|
||||||
uint32_t result = GrowWebAssemblyMemory(isolate, mem_obj, 4);
|
uint32_t result = WasmMemoryObject::Grow(isolate, mem_obj, 4);
|
||||||
CHECK_EQ(16, result);
|
CHECK_EQ(16, result);
|
||||||
if (!memory->has_guard_region()) {
|
if (!memory->has_guard_region()) {
|
||||||
isolate->array_buffer_allocator()->Free(backing_store, byte_length);
|
isolate->array_buffer_allocator()->Free(backing_store, byte_length);
|
||||||
|
Loading…
Reference in New Issue
Block a user