| Index: src/wasm/wasm-module.cc
|
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
|
| index 6eff8f2820848bcac4b38b3ad9727cdb29bde0a8..e4188da72a3bf1b0545c5a712c18c218ff5da8ba 100644
|
| --- a/src/wasm/wasm-module.cc
|
| +++ b/src/wasm/wasm-module.cc
|
| @@ -61,12 +61,15 @@ static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
| JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter());
|
| JSArrayBuffer* buffer = *p;
|
|
|
| - void* memory = buffer->backing_store();
|
| - base::OS::Free(memory,
|
| - RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()));
|
| + if (!buffer->was_neutered()) {
|
| + void* memory = buffer->backing_store();
|
| + DCHECK(memory != nullptr);
|
| + base::OS::Free(memory,
|
| + RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()));
|
|
|
| - data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
|
| - -buffer->byte_length()->Number());
|
| + data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
|
| + -buffer->byte_length()->Number());
|
| + }
|
|
|
| GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
|
| }
|
| @@ -756,6 +759,28 @@ Handle<Script> CreateWasmScript(Isolate* isolate,
|
| }
|
| } // namespace
|
|
|
| +Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
|
| + size_t size, bool is_external,
|
| + bool enable_guard_regions) {
|
| + Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
| + JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store,
|
| + static_cast<int>(size));
|
| + buffer->set_is_neuterable(false);
|
| + buffer->set_has_guard_region(enable_guard_regions);
|
| +
|
| + if (is_external) {
|
| + // We mark the buffer as external if we allocated it here with guard
|
| + // pages. That means we need to arrange for it to be freed.
|
| +
|
| + // TODO(eholk): Finalizers may not run when the main thread is shutting
|
| + // down, which means we may leak memory here.
|
| + Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
|
| + GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
|
| + &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
|
| + }
|
| + return buffer;
|
| +}
|
| +
|
| Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
|
| bool enable_guard_regions) {
|
| if (size > (FLAG_wasm_max_mem_pages * WasmModule::kPageSize)) {
|
| @@ -781,24 +806,8 @@ Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
|
| }
|
| #endif
|
|
|
| - Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
| - JSArrayBuffer::Setup(buffer, isolate, is_external, memory,
|
| - static_cast<int>(size));
|
| - buffer->set_is_neuterable(false);
|
| - buffer->set_has_guard_region(enable_guard_regions);
|
| -
|
| - if (is_external) {
|
| - // We mark the buffer as external if we allocated it here with guard
|
| - // pages. That means we need to arrange for it to be freed.
|
| -
|
| - // TODO(eholk): Finalizers may not run when the main thread is shutting
|
| - // down, which means we may leak memory here.
|
| - Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
|
| - GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
|
| - &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
|
| - }
|
| -
|
| - return buffer;
|
| + return SetupArrayBuffer(isolate, memory, size, is_external,
|
| + enable_guard_regions);
|
| }
|
|
|
| const char* wasm::SectionName(WasmSectionCode code) {
|
| @@ -2349,25 +2358,16 @@ Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
|
| return Handle<JSArrayBuffer>::null();
|
| }
|
|
|
| - Handle<JSArrayBuffer> new_buffer;
|
| - if (!old_buffer.is_null() && old_buffer->has_guard_region()) {
|
| - // We don't move the backing store, we simply change the protection to make
|
| - // more of it accessible.
|
| - base::OS::Unprotect(old_buffer->backing_store(), new_size);
|
| - reinterpret_cast<v8::Isolate*>(isolate)
|
| - ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize);
|
| - Handle<Object> new_size_object =
|
| - isolate->factory()->NewNumberFromSize(new_size);
|
| - old_buffer->set_byte_length(*new_size_object);
|
| - new_buffer = old_buffer;
|
| - } else {
|
| - const bool enable_guard_regions = false;
|
| - 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);
|
| - }
|
| + // 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() && 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;
|
| }
|
| @@ -2387,6 +2387,30 @@ void UncheckedUpdateInstanceMemory(Isolate* isolate,
|
| old_mem_start, new_mem_start, old_size, new_size);
|
| }
|
|
|
| +void DetachArrayBuffer(Isolate* isolate, Handle<JSArrayBuffer> buffer) {
|
| + const bool has_guard_regions =
|
| + (!buffer.is_null() && buffer->has_guard_region());
|
| + void* backing_store = buffer->backing_store();
|
| + if (backing_store != nullptr) {
|
| + DCHECK(!buffer->is_neuterable());
|
| + int64_t byte_length = NumberToSize(buffer->byte_length());
|
| + buffer->set_is_neuterable(true);
|
| + if (!has_guard_regions) {
|
| + buffer->set_is_external(true);
|
| + isolate->heap()->UnregisterArrayBuffer(*buffer);
|
| + }
|
| + buffer->Neuter();
|
| + if (!has_guard_regions) {
|
| + isolate->array_buffer_allocator()->Free(backing_store, byte_length);
|
| + } else {
|
| + base::OS::Free(backing_store, RoundUp(i::wasm::kWasmMaxHeapOffset,
|
| + base::OS::CommitPageSize()));
|
| + reinterpret_cast<v8::Isolate*>(isolate)
|
| + ->AdjustAmountOfExternalAllocatedMemory(-byte_length);
|
| + }
|
| + }
|
| +}
|
| +
|
| int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate,
|
| Handle<WasmMemoryObject> receiver,
|
| uint32_t pages) {
|
| @@ -2402,12 +2426,26 @@ int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate,
|
| 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);
|
| }
|
| - Handle<JSArrayBuffer> new_buffer;
|
| if (!memory_object->has_instances_link()) {
|
| // Memory object does not have an instance associated with it, just grow
|
| uint32_t max_pages;
|
| @@ -2444,6 +2482,7 @@ int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate,
|
| }
|
| }
|
| memory_object->set_buffer(*new_buffer);
|
| + DetachArrayBuffer(isolate, old_buffer);
|
| DCHECK(old_size % WasmModule::kPageSize == 0);
|
| return (old_size / WasmModule::kPageSize);
|
| }
|
|
|