Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(682)

Unified Diff: src/wasm/wasm-module.cc

Issue 2653183003: [wasm] Memory buffer should be detached after Memory.Grow (Closed)
Patch Set: Ben's review Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/mjsunit/wasm/import-memory.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
« no previous file with comments | « no previous file | test/mjsunit/wasm/import-memory.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698