Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |