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

Side by Side Diff: src/wasm/wasm-module.cc

Issue 2653183003: [wasm] Memory buffer should be detached after Memory.Grow (Closed)
Patch Set: Fix 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 unified diff | Download patch
« no previous file with comments | « no previous file | test/mjsunit/wasm/import-memory.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <memory> 5 #include <memory>
6 6
7 #include "src/assembler-inl.h" 7 #include "src/assembler-inl.h"
8 #include "src/base/adapters.h" 8 #include "src/base/adapters.h"
9 #include "src/base/atomic-utils.h" 9 #include "src/base/atomic-utils.h"
10 #include "src/code-stubs.h" 10 #include "src/code-stubs.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 it.rinfo()->set_target_object(*new_ref); 54 it.rinfo()->set_target_object(*new_ref);
55 } 55 }
56 } 56 }
57 } 57 }
58 58
59 static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) { 59 static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) {
60 DisallowHeapAllocation no_gc; 60 DisallowHeapAllocation no_gc;
61 JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter()); 61 JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter());
62 JSArrayBuffer* buffer = *p; 62 JSArrayBuffer* buffer = *p;
63 63
64 void* memory = buffer->backing_store(); 64 if (!buffer->was_neutered()) {
65 base::OS::Free(memory, 65 void* memory = buffer->backing_store();
66 RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize())); 66 DCHECK(memory != nullptr);
67 base::OS::Free(memory,
68 RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()));
67 69
68 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory( 70 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
69 -buffer->byte_length()->Number()); 71 -buffer->byte_length()->Number());
72 }
70 73
71 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); 74 GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
72 } 75 }
73 76
74 #if V8_TARGET_ARCH_64_BIT 77 #if V8_TARGET_ARCH_64_BIT
75 const bool kGuardRegionsSupported = true; 78 const bool kGuardRegionsSupported = true;
76 #else 79 #else
77 const bool kGuardRegionsSupported = false; 80 const bool kGuardRegionsSupported = false;
78 #endif 81 #endif
79 82
(...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 DCHECK(name_chars >= 0 && name_chars < kBufferSize); 752 DCHECK(name_chars >= 0 && name_chars < kBufferSize);
750 MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte( 753 MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
751 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars), 754 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
752 TENURED); 755 TENURED);
753 script->set_name(*name_str.ToHandleChecked()); 756 script->set_name(*name_str.ToHandleChecked());
754 757
755 return script; 758 return script;
756 } 759 }
757 } // namespace 760 } // namespace
758 761
762 Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
763 size_t size, bool is_external,
764 bool enable_guard_regions) {
765 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
766 JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store,
767 static_cast<int>(size));
768 buffer->set_is_neuterable(false);
769 buffer->set_has_guard_region(enable_guard_regions);
770
771 if (is_external) {
772 // We mark the buffer as external if we allocated it here with guard
773 // pages. That means we need to arrange for it to be freed.
774
775 // TODO(eholk): Finalizers may not run when the main thread is shutting
776 // down, which means we may leak memory here.
777 Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
778 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
779 &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
780 }
781 return buffer;
782 }
783
759 Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size, 784 Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
760 bool enable_guard_regions) { 785 bool enable_guard_regions) {
761 if (size > (FLAG_wasm_max_mem_pages * WasmModule::kPageSize)) { 786 if (size > (FLAG_wasm_max_mem_pages * WasmModule::kPageSize)) {
762 // TODO(titzer): lift restriction on maximum memory allocated here. 787 // TODO(titzer): lift restriction on maximum memory allocated here.
763 return Handle<JSArrayBuffer>::null(); 788 return Handle<JSArrayBuffer>::null();
764 } 789 }
765 790
766 enable_guard_regions = enable_guard_regions && kGuardRegionsSupported; 791 enable_guard_regions = enable_guard_regions && kGuardRegionsSupported;
767 792
768 bool is_external; // Set by TryAllocateBackingStore 793 bool is_external; // Set by TryAllocateBackingStore
769 void* memory = 794 void* memory =
770 TryAllocateBackingStore(isolate, size, enable_guard_regions, is_external); 795 TryAllocateBackingStore(isolate, size, enable_guard_regions, is_external);
771 796
772 if (memory == nullptr) { 797 if (memory == nullptr) {
773 return Handle<JSArrayBuffer>::null(); 798 return Handle<JSArrayBuffer>::null();
774 } 799 }
775 800
776 #if DEBUG 801 #if DEBUG
777 // Double check the API allocator actually zero-initialized the memory. 802 // Double check the API allocator actually zero-initialized the memory.
778 const byte* bytes = reinterpret_cast<const byte*>(memory); 803 const byte* bytes = reinterpret_cast<const byte*>(memory);
779 for (size_t i = 0; i < size; ++i) { 804 for (size_t i = 0; i < size; ++i) {
780 DCHECK_EQ(0, bytes[i]); 805 DCHECK_EQ(0, bytes[i]);
781 } 806 }
782 #endif 807 #endif
783 808
784 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 809 return SetupArrayBuffer(isolate, memory, size, is_external,
785 JSArrayBuffer::Setup(buffer, isolate, is_external, memory, 810 enable_guard_regions);
786 static_cast<int>(size));
787 buffer->set_is_neuterable(false);
788 buffer->set_has_guard_region(enable_guard_regions);
789
790 if (is_external) {
791 // We mark the buffer as external if we allocated it here with guard
792 // pages. That means we need to arrange for it to be freed.
793
794 // TODO(eholk): Finalizers may not run when the main thread is shutting
795 // down, which means we may leak memory here.
796 Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
797 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
798 &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
799 }
800
801 return buffer;
802 } 811 }
803 812
804 const char* wasm::SectionName(WasmSectionCode code) { 813 const char* wasm::SectionName(WasmSectionCode code) {
805 switch (code) { 814 switch (code) {
806 case kUnknownSectionCode: 815 case kUnknownSectionCode:
807 return "Unknown"; 816 return "Unknown";
808 case kTypeSectionCode: 817 case kTypeSectionCode:
809 return "Type"; 818 return "Type";
810 case kImportSectionCode: 819 case kImportSectionCode:
811 return "Import"; 820 return "Import";
(...skipping 1530 matching lines...) Expand 10 before | Expand all | Expand 10 after
2342 old_size = old_buffer->byte_length()->Number(); 2351 old_size = old_buffer->byte_length()->Number();
2343 } 2352 }
2344 DCHECK(old_size + pages * WasmModule::kPageSize <= 2353 DCHECK(old_size + pages * WasmModule::kPageSize <=
2345 std::numeric_limits<uint32_t>::max()); 2354 std::numeric_limits<uint32_t>::max());
2346 uint32_t new_size = old_size + pages * WasmModule::kPageSize; 2355 uint32_t new_size = old_size + pages * WasmModule::kPageSize;
2347 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size || 2356 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
2348 FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) { 2357 FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) {
2349 return Handle<JSArrayBuffer>::null(); 2358 return Handle<JSArrayBuffer>::null();
2350 } 2359 }
2351 2360
2352 Handle<JSArrayBuffer> new_buffer; 2361 const bool enable_guard_regions =
titzer 2017/01/26 21:35:27 Can you please add a TODO here to reimplement the
gdeepti 2017/01/26 21:41:30 Done.
2353 if (!old_buffer.is_null() && old_buffer->has_guard_region()) { 2362 !old_buffer.is_null() && old_buffer->has_guard_region();
2354 // We don't move the backing store, we simply change the protection to make 2363 Handle<JSArrayBuffer> new_buffer =
2355 // more of it accessible. 2364 NewArrayBuffer(isolate, new_size, enable_guard_regions);
2356 base::OS::Unprotect(old_buffer->backing_store(), new_size); 2365 if (new_buffer.is_null()) return new_buffer;
2357 reinterpret_cast<v8::Isolate*>(isolate) 2366 Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
2358 ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize); 2367 if (old_size != 0) {
2359 Handle<Object> new_size_object = 2368 memcpy(new_mem_start, old_mem_start, old_size);
2360 isolate->factory()->NewNumberFromSize(new_size);
2361 old_buffer->set_byte_length(*new_size_object);
2362 new_buffer = old_buffer;
2363 } else {
2364 const bool enable_guard_regions = false;
2365 new_buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions);
2366 if (new_buffer.is_null()) return new_buffer;
2367 Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
2368 if (old_size != 0) {
2369 memcpy(new_mem_start, old_mem_start, old_size);
2370 }
2371 } 2369 }
2372 return new_buffer; 2370 return new_buffer;
2373 } 2371 }
2374 2372
2375 void UncheckedUpdateInstanceMemory(Isolate* isolate, 2373 void UncheckedUpdateInstanceMemory(Isolate* isolate,
2376 Handle<WasmInstanceObject> instance, 2374 Handle<WasmInstanceObject> instance,
2377 Address old_mem_start, uint32_t old_size) { 2375 Address old_mem_start, uint32_t old_size) {
2378 DCHECK(instance->has_memory_buffer()); 2376 DCHECK(instance->has_memory_buffer());
2379 Handle<JSArrayBuffer> new_buffer(instance->memory_buffer()); 2377 Handle<JSArrayBuffer> new_buffer(instance->memory_buffer());
2380 uint32_t new_size = new_buffer->byte_length()->Number(); 2378 uint32_t new_size = new_buffer->byte_length()->Number();
2381 DCHECK(new_size <= std::numeric_limits<uint32_t>::max()); 2379 DCHECK(new_size <= std::numeric_limits<uint32_t>::max());
2382 Address new_mem_start = static_cast<Address>(new_buffer->backing_store()); 2380 Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
2383 DCHECK_NOT_NULL(new_mem_start); 2381 DCHECK_NOT_NULL(new_mem_start);
2384 Handle<FixedArray> code_table = instance->compiled_module()->code_table(); 2382 Handle<FixedArray> code_table = instance->compiled_module()->code_table();
2385 RelocateMemoryReferencesInCode( 2383 RelocateMemoryReferencesInCode(
2386 code_table, instance->compiled_module()->module()->num_imported_functions, 2384 code_table, instance->compiled_module()->module()->num_imported_functions,
2387 old_mem_start, new_mem_start, old_size, new_size); 2385 old_mem_start, new_mem_start, old_size, new_size);
2388 } 2386 }
2389 2387
2388 void DetachArrayBuffer(Isolate* isolate, Handle<JSArrayBuffer> buffer) {
2389 const bool has_guard_regions =
2390 (!buffer.is_null() && buffer->has_guard_region());
2391 void* backing_store = buffer->backing_store();
2392 if (backing_store != nullptr) {
2393 DCHECK(!buffer->is_neuterable());
2394 int64_t byte_length = NumberToSize(buffer->byte_length());
2395 buffer->set_is_neuterable(true);
2396 if (!has_guard_regions) {
2397 buffer->set_is_external(true);
2398 isolate->heap()->UnregisterArrayBuffer(*buffer);
2399 }
2400 buffer->Neuter();
2401 if (!has_guard_regions) {
2402 isolate->array_buffer_allocator()->Free(backing_store, byte_length);
2403 } else {
2404 base::OS::Free(backing_store, RoundUp(i::wasm::kWasmMaxHeapOffset,
2405 base::OS::CommitPageSize()));
2406 reinterpret_cast<v8::Isolate*>(isolate)
2407 ->AdjustAmountOfExternalAllocatedMemory(-byte_length);
2408 }
2409 }
2410 }
2411
2390 int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate, 2412 int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate,
2391 Handle<WasmMemoryObject> receiver, 2413 Handle<WasmMemoryObject> receiver,
2392 uint32_t pages) { 2414 uint32_t pages) {
2393 DCHECK(WasmJs::IsWasmMemoryObject(isolate, receiver)); 2415 DCHECK(WasmJs::IsWasmMemoryObject(isolate, receiver));
2394 Handle<WasmMemoryObject> memory_object = 2416 Handle<WasmMemoryObject> memory_object =
2395 handle(WasmMemoryObject::cast(*receiver)); 2417 handle(WasmMemoryObject::cast(*receiver));
2396 MaybeHandle<JSArrayBuffer> memory_buffer = handle(memory_object->buffer()); 2418 MaybeHandle<JSArrayBuffer> memory_buffer = handle(memory_object->buffer());
2397 Handle<JSArrayBuffer> old_buffer; 2419 Handle<JSArrayBuffer> old_buffer;
2398 uint32_t old_size = 0; 2420 uint32_t old_size = 0;
2399 Address old_mem_start = nullptr; 2421 Address old_mem_start = nullptr;
2400 if (memory_buffer.ToHandle(&old_buffer) && 2422 if (memory_buffer.ToHandle(&old_buffer) &&
2401 old_buffer->backing_store() != nullptr) { 2423 old_buffer->backing_store() != nullptr) {
2402 old_size = old_buffer->byte_length()->Number(); 2424 old_size = old_buffer->byte_length()->Number();
2403 old_mem_start = static_cast<Address>(old_buffer->backing_store()); 2425 old_mem_start = static_cast<Address>(old_buffer->backing_store());
2404 } 2426 }
2427 Handle<JSArrayBuffer> new_buffer;
2405 // Return current size if grow by 0 2428 // Return current size if grow by 0
2406 if (pages == 0) { 2429 if (pages == 0) {
2430 if (!old_buffer.is_null() && old_buffer->backing_store() != nullptr) {
2431 new_buffer = SetupArrayBuffer(isolate, old_buffer->backing_store(),
2432 old_size, old_buffer->is_external(),
2433 old_buffer->has_guard_region());
2434 memory_object->set_buffer(*new_buffer);
2435 old_buffer->set_is_neuterable(true);
2436 if (!old_buffer->has_guard_region()) {
2437 old_buffer->set_is_external(true);
2438 isolate->heap()->UnregisterArrayBuffer(*old_buffer);
2439 }
2440 // Neuter but don't free the memory because it is now being used by
2441 // new_buffer.
2442 old_buffer->Neuter();
2443 }
2407 DCHECK(old_size % WasmModule::kPageSize == 0); 2444 DCHECK(old_size % WasmModule::kPageSize == 0);
2408 return (old_size / WasmModule::kPageSize); 2445 return (old_size / WasmModule::kPageSize);
2409 } 2446 }
2410 Handle<JSArrayBuffer> new_buffer;
2411 if (!memory_object->has_instances_link()) { 2447 if (!memory_object->has_instances_link()) {
2412 // Memory object does not have an instance associated with it, just grow 2448 // Memory object does not have an instance associated with it, just grow
2413 uint32_t max_pages; 2449 uint32_t max_pages;
2414 if (memory_object->has_maximum_pages()) { 2450 if (memory_object->has_maximum_pages()) {
2415 max_pages = static_cast<uint32_t>(memory_object->maximum_pages()); 2451 max_pages = static_cast<uint32_t>(memory_object->maximum_pages());
2416 if (FLAG_wasm_max_mem_pages < max_pages) return -1; 2452 if (FLAG_wasm_max_mem_pages < max_pages) return -1;
2417 } else { 2453 } else {
2418 max_pages = FLAG_wasm_max_mem_pages; 2454 max_pages = FLAG_wasm_max_mem_pages;
2419 } 2455 }
2420 new_buffer = GrowMemoryBuffer(isolate, memory_buffer, pages, max_pages); 2456 new_buffer = GrowMemoryBuffer(isolate, memory_buffer, pages, max_pages);
(...skipping 16 matching lines...) Expand all
2437 while (instance_wrapper->has_next()) { 2473 while (instance_wrapper->has_next()) {
2438 instance_wrapper = instance_wrapper->next_wrapper(); 2474 instance_wrapper = instance_wrapper->next_wrapper();
2439 DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper)); 2475 DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
2440 Handle<WasmInstanceObject> instance = instance_wrapper->instance_object(); 2476 Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
2441 DCHECK(IsWasmInstance(*instance)); 2477 DCHECK(IsWasmInstance(*instance));
2442 SetInstanceMemory(instance, *new_buffer); 2478 SetInstanceMemory(instance, *new_buffer);
2443 UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size); 2479 UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
2444 } 2480 }
2445 } 2481 }
2446 memory_object->set_buffer(*new_buffer); 2482 memory_object->set_buffer(*new_buffer);
2483 DetachArrayBuffer(isolate, old_buffer);
2447 DCHECK(old_size % WasmModule::kPageSize == 0); 2484 DCHECK(old_size % WasmModule::kPageSize == 0);
2448 return (old_size / WasmModule::kPageSize); 2485 return (old_size / WasmModule::kPageSize);
2449 } 2486 }
2450 2487
2451 int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance, 2488 int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
2452 uint32_t pages) { 2489 uint32_t pages) {
2453 if (!IsWasmInstance(*instance)) return -1; 2490 if (!IsWasmInstance(*instance)) return -1;
2454 if (pages == 0) return GetInstanceMemorySize(isolate, instance); 2491 if (pages == 0) return GetInstanceMemorySize(isolate, instance);
2455 Handle<WasmInstanceObject> instance_obj(WasmInstanceObject::cast(*instance)); 2492 Handle<WasmInstanceObject> instance_obj(WasmInstanceObject::cast(*instance));
2456 if (!instance_obj->has_memory_object()) { 2493 if (!instance_obj->has_memory_object()) {
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
2754 Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections); 2791 Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections);
2755 JSArray::SetContent(array_object, storage); 2792 JSArray::SetContent(array_object, storage);
2756 array_object->set_length(Smi::FromInt(num_custom_sections)); 2793 array_object->set_length(Smi::FromInt(num_custom_sections));
2757 2794
2758 for (int i = 0; i < num_custom_sections; i++) { 2795 for (int i = 0; i < num_custom_sections; i++) {
2759 storage->set(i, *matching_sections[i]); 2796 storage->set(i, *matching_sections[i]);
2760 } 2797 }
2761 2798
2762 return array_object; 2799 return array_object;
2763 } 2800 }
OLDNEW
« 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