| 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/base/atomic-utils.h" | 7 #include "src/base/atomic-utils.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 | 9 |
| 10 #include "src/macro-assembler.h" | 10 #include "src/macro-assembler.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, | 79 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, |
| 80 Handle<Object> new_ref) { | 80 Handle<Object> new_ref) { |
| 81 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); | 81 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); |
| 82 it.next()) { | 82 it.next()) { |
| 83 if (it.rinfo()->target_object() == *old_ref) { | 83 if (it.rinfo()->target_object() == *old_ref) { |
| 84 it.rinfo()->set_target_object(*new_ref); | 84 it.rinfo()->set_target_object(*new_ref); |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 } | 87 } |
| 88 | 88 |
| 89 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { | 89 #if V8_HOST_ARCH_64_BIT |
| 90 if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) { | 90 static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) { |
| 91 // TODO(titzer): lift restriction on maximum memory allocated here. | 91 JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter()); |
| 92 return Handle<JSArrayBuffer>::null(); | 92 JSArrayBuffer* buffer = *p; |
| 93 } | |
| 94 void* memory = isolate->array_buffer_allocator()->Allocate(size); | |
| 95 if (memory == nullptr) { | |
| 96 return Handle<JSArrayBuffer>::null(); | |
| 97 } | |
| 98 | 93 |
| 99 #if DEBUG | 94 void* memory = buffer->backing_store(); |
| 100 // Double check the API allocator actually zero-initialized the memory. | 95 base::OS::Free(memory, kWasmMaxHeapOffset); |
| 101 const byte* bytes = reinterpret_cast<const byte*>(memory); | 96 |
| 102 for (size_t i = 0; i < size; ++i) { | 97 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory( |
| 103 DCHECK_EQ(0, bytes[i]); | 98 -buffer->byte_length()->Number()); |
| 104 } | 99 |
| 100 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); |
| 101 } |
| 105 #endif | 102 #endif |
| 106 | 103 |
| 107 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); | 104 void* AllocateBackingStore(Isolate* isolate, size_t size, bool guard) { |
| 108 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size)); | 105 if (guard) { |
| 109 buffer->set_is_neuterable(false); | 106 #if V8_HOST_ARCH_64_BIT |
| 110 return buffer; | 107 void* memory; |
| 108 // TODO(eholk): On Windows we want to make sure we don't commit the guard |
| 109 // pages yet. |
| 110 |
| 111 // We always allocate the largest possible offset into the heap, so the |
| 112 // addressable memory after the guard page can be make inaccessible. |
| 113 const size_t alloc_size = kWasmMaxHeapOffset; |
| 114 DCHECK(size % base::OS::CommitPageSize() == 0); |
| 115 |
| 116 size_t allocated_size = 0; |
| 117 const bool is_executable = false; |
| 118 memory = base::OS::Allocate(alloc_size, &allocated_size, is_executable); |
| 119 if (allocated_size < alloc_size) { |
| 120 base::OS::Free(memory, allocated_size); |
| 121 return nullptr; |
| 122 } |
| 123 |
| 124 if (memory == nullptr) { |
| 125 return nullptr; |
| 126 } |
| 127 |
| 128 byte* bytes = reinterpret_cast<byte*>(memory); |
| 129 base::OS::Guard(bytes + size, alloc_size - size); |
| 130 |
| 131 reinterpret_cast<v8::Isolate*>(isolate) |
| 132 ->AdjustAmountOfExternalAllocatedMemory(size); |
| 133 |
| 134 return memory; |
| 135 #else |
| 136 DCHECK(false && "Guard pages are not supported on 32-bit systems"); |
| 137 #endif |
| 138 } else { |
| 139 void* memory = isolate->array_buffer_allocator()->Allocate(size); |
| 140 return memory; |
| 141 } |
| 111 } | 142 } |
| 112 | 143 |
| 113 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, | 144 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, |
| 114 Address old_start, Address start, | 145 Address old_start, Address start, |
| 115 uint32_t prev_size, uint32_t new_size) { | 146 uint32_t prev_size, uint32_t new_size) { |
| 116 for (int i = 0; i < code_table->length(); ++i) { | 147 for (int i = 0; i < code_table->length(); ++i) { |
| 117 DCHECK(code_table->get(i)->IsCode()); | 148 DCHECK(code_table->get(i)->IsCode()); |
| 118 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); | 149 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); |
| 119 AllowDeferredHandleDereference embedding_raw_address; | 150 AllowDeferredHandleDereference embedding_raw_address; |
| 120 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | | 151 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | |
| (...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0))); | 626 TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0))); |
| 596 TRACE("}\n"); | 627 TRACE("}\n"); |
| 597 } | 628 } |
| 598 compiled_module->reset_weak_owning_instance(); | 629 compiled_module->reset_weak_owning_instance(); |
| 599 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); | 630 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); |
| 600 TRACE("}\n"); | 631 TRACE("}\n"); |
| 601 } | 632 } |
| 602 | 633 |
| 603 } // namespace | 634 } // namespace |
| 604 | 635 |
| 636 Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size, |
| 637 bool guard) { |
| 638 if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) { |
| 639 // TODO(titzer): lift restriction on maximum memory allocated here. |
| 640 return Handle<JSArrayBuffer>::null(); |
| 641 } |
| 642 |
| 643 void* memory = AllocateBackingStore(isolate, size, guard); |
| 644 bool is_external = guard; |
| 645 |
| 646 if (memory == nullptr) { |
| 647 return Handle<JSArrayBuffer>::null(); |
| 648 } |
| 649 |
| 650 #if DEBUG |
| 651 // Double check the API allocator actually zero-initialized the memory. |
| 652 const byte* bytes = reinterpret_cast<const byte*>(memory); |
| 653 for (size_t i = 0; i < size; ++i) { |
| 654 DCHECK_EQ(0, bytes[i]); |
| 655 } |
| 656 #endif |
| 657 |
| 658 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
| 659 JSArrayBuffer::Setup(buffer, isolate, is_external, memory, |
| 660 static_cast<int>(size)); |
| 661 buffer->set_is_neuterable(false); |
| 662 buffer->set_has_guard_region(guard); |
| 663 |
| 664 #if V8_HOST_ARCH_64_BIT |
| 665 if (is_external) { |
| 666 // We mark the buffer as external if we allocated it here with guard |
| 667 // pages. That means we need to arrange for it to be freed. |
| 668 |
| 669 // TODO(eholk): Finalizers may not run when the main thread is shutting |
| 670 // down, which means we may leak memory here. |
| 671 Handle<Object> global_handle = isolate->global_handles()->Create(*buffer); |
| 672 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), |
| 673 &MemoryFinalizer, v8::WeakCallbackType::kFinalizer); |
| 674 } |
| 675 #endif |
| 676 |
| 677 return buffer; |
| 678 } |
| 679 |
| 605 const char* wasm::SectionName(WasmSectionCode code) { | 680 const char* wasm::SectionName(WasmSectionCode code) { |
| 606 switch (code) { | 681 switch (code) { |
| 607 case kUnknownSectionCode: | 682 case kUnknownSectionCode: |
| 608 return "Unknown"; | 683 return "Unknown"; |
| 609 case kTypeSectionCode: | 684 case kTypeSectionCode: |
| 610 return "Type"; | 685 return "Type"; |
| 611 case kImportSectionCode: | 686 case kImportSectionCode: |
| 612 return "Import"; | 687 return "Import"; |
| 613 case kFunctionSectionCode: | 688 case kFunctionSectionCode: |
| 614 return "Function"; | 689 return "Function"; |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 instance->SetInternalField(kWasmMemObject, | 1021 instance->SetInternalField(kWasmMemObject, |
| 947 isolate_->heap()->undefined_value()); | 1022 isolate_->heap()->undefined_value()); |
| 948 | 1023 |
| 949 //-------------------------------------------------------------------------- | 1024 //-------------------------------------------------------------------------- |
| 950 // Set up the globals for the new instance. | 1025 // Set up the globals for the new instance. |
| 951 //-------------------------------------------------------------------------- | 1026 //-------------------------------------------------------------------------- |
| 952 MaybeHandle<JSArrayBuffer> old_globals; | 1027 MaybeHandle<JSArrayBuffer> old_globals; |
| 953 MaybeHandle<JSArrayBuffer> globals; | 1028 MaybeHandle<JSArrayBuffer> globals; |
| 954 uint32_t globals_size = module_->globals_size; | 1029 uint32_t globals_size = module_->globals_size; |
| 955 if (globals_size > 0) { | 1030 if (globals_size > 0) { |
| 1031 const bool guard = false; |
| 956 Handle<JSArrayBuffer> global_buffer = | 1032 Handle<JSArrayBuffer> global_buffer = |
| 957 NewArrayBuffer(isolate_, globals_size); | 1033 NewArrayBuffer(isolate_, globals_size, guard); |
| 958 globals = global_buffer; | 1034 globals = global_buffer; |
| 959 if (globals.is_null()) { | 1035 if (globals.is_null()) { |
| 960 thrower_->RangeError("Out of memory: wasm globals"); | 1036 thrower_->RangeError("Out of memory: wasm globals"); |
| 961 return nothing; | 1037 return nothing; |
| 962 } | 1038 } |
| 963 Address old_address = owner.is_null() | 1039 Address old_address = owner.is_null() |
| 964 ? nullptr | 1040 ? nullptr |
| 965 : GetGlobalStartAddressFromCodeTemplate( | 1041 : GetGlobalStartAddressFromCodeTemplate( |
| 966 isolate_->heap()->undefined_value(), | 1042 isolate_->heap()->undefined_value(), |
| 967 JSObject::cast(*owner.ToHandleChecked())); | 1043 JSObject::cast(*owner.ToHandleChecked())); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 986 //-------------------------------------------------------------------------- | 1062 //-------------------------------------------------------------------------- |
| 987 MaybeHandle<JSArrayBuffer> old_memory; | 1063 MaybeHandle<JSArrayBuffer> old_memory; |
| 988 | 1064 |
| 989 uint32_t min_mem_pages = module_->min_mem_pages; | 1065 uint32_t min_mem_pages = module_->min_mem_pages; |
| 990 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); | 1066 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); |
| 991 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. | 1067 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. |
| 992 | 1068 |
| 993 if (!memory_.is_null()) { | 1069 if (!memory_.is_null()) { |
| 994 // Set externally passed ArrayBuffer non neuterable. | 1070 // Set externally passed ArrayBuffer non neuterable. |
| 995 memory_->set_is_neuterable(false); | 1071 memory_->set_is_neuterable(false); |
| 1072 |
| 1073 DCHECK_IMPLIES(FLAG_wasm_guard_pages, module_->origin == kAsmJsOrigin || |
| 1074 memory_->has_guard_region()); |
| 996 } else if (min_mem_pages > 0) { | 1075 } else if (min_mem_pages > 0) { |
| 997 memory_ = AllocateMemory(min_mem_pages); | 1076 memory_ = AllocateMemory(min_mem_pages); |
| 998 if (memory_.is_null()) return nothing; // failed to allocate memory | 1077 if (memory_.is_null()) return nothing; // failed to allocate memory |
| 999 } | 1078 } |
| 1000 | 1079 |
| 1001 if (!memory_.is_null()) { | 1080 if (!memory_.is_null()) { |
| 1002 instance->SetInternalField(kWasmMemArrayBuffer, *memory_); | 1081 instance->SetInternalField(kWasmMemArrayBuffer, *memory_); |
| 1003 Address mem_start = static_cast<Address>(memory_->backing_store()); | 1082 Address mem_start = static_cast<Address>(memory_->backing_store()); |
| 1004 uint32_t mem_size = | 1083 uint32_t mem_size = |
| 1005 static_cast<uint32_t>(memory_->byte_length()->Number()); | 1084 static_cast<uint32_t>(memory_->byte_length()->Number()); |
| (...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1500 } | 1579 } |
| 1501 } | 1580 } |
| 1502 } | 1581 } |
| 1503 | 1582 |
| 1504 // Allocate memory for a module instance as a new JSArrayBuffer. | 1583 // Allocate memory for a module instance as a new JSArrayBuffer. |
| 1505 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { | 1584 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { |
| 1506 if (min_mem_pages > WasmModule::kMaxMemPages) { | 1585 if (min_mem_pages > WasmModule::kMaxMemPages) { |
| 1507 thrower_->RangeError("Out of memory: wasm memory too large"); | 1586 thrower_->RangeError("Out of memory: wasm memory too large"); |
| 1508 return Handle<JSArrayBuffer>::null(); | 1587 return Handle<JSArrayBuffer>::null(); |
| 1509 } | 1588 } |
| 1589 const bool guard = FLAG_wasm_guard_pages; |
| 1510 Handle<JSArrayBuffer> mem_buffer = | 1590 Handle<JSArrayBuffer> mem_buffer = |
| 1511 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize); | 1591 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize, guard); |
| 1512 | 1592 |
| 1513 if (mem_buffer.is_null()) { | 1593 if (mem_buffer.is_null()) { |
| 1514 thrower_->RangeError("Out of memory: wasm memory"); | 1594 thrower_->RangeError("Out of memory: wasm memory"); |
| 1515 } | 1595 } |
| 1516 return mem_buffer; | 1596 return mem_buffer; |
| 1517 } | 1597 } |
| 1518 | 1598 |
| 1519 // Process the exports, creating wrappers for functions, tables, memories, | 1599 // Process the exports, creating wrappers for functions, tables, memories, |
| 1520 // and globals. | 1600 // and globals. |
| 1521 void ProcessExports(MaybeHandle<JSArrayBuffer> globals, | 1601 void ProcessExports(MaybeHandle<JSArrayBuffer> globals, |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 // "undefined" case above. | 2072 // "undefined" case above. |
| 1993 DCHECK_NOT_NULL(old_mem_start); | 2073 DCHECK_NOT_NULL(old_mem_start); |
| 1994 DCHECK(old_size + pages * WasmModule::kPageSize <= | 2074 DCHECK(old_size + pages * WasmModule::kPageSize <= |
| 1995 std::numeric_limits<uint32_t>::max()); | 2075 std::numeric_limits<uint32_t>::max()); |
| 1996 new_size = old_size + pages * WasmModule::kPageSize; | 2076 new_size = old_size + pages * WasmModule::kPageSize; |
| 1997 } | 2077 } |
| 1998 | 2078 |
| 1999 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) { | 2079 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) { |
| 2000 return -1; | 2080 return -1; |
| 2001 } | 2081 } |
| 2002 Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size); | 2082 |
| 2003 if (buffer.is_null()) return -1; | 2083 Handle<JSArrayBuffer> buffer; |
| 2004 Address new_mem_start = static_cast<Address>(buffer->backing_store()); | 2084 |
| 2005 if (old_size != 0) { | 2085 if (FLAG_wasm_guard_pages && !old_buffer.is_null()) { |
| 2006 memcpy(new_mem_start, old_mem_start, old_size); | 2086 base::OS::Unprotect(old_buffer->backing_store(), new_size); |
| 2087 reinterpret_cast<v8::Isolate*>(isolate) |
| 2088 ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize); |
| 2089 Handle<Object> new_size_object = |
| 2090 isolate->factory()->NewNumberFromSize(new_size); |
| 2091 old_buffer->set_byte_length(*new_size_object); |
| 2092 |
| 2093 SetInstanceMemory(instance, *old_buffer); |
| 2094 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); |
| 2095 RelocateMemoryReferencesInCode(code_table, old_mem_start, old_mem_start, |
| 2096 old_size, new_size); |
| 2097 buffer = old_buffer; |
| 2098 } else { |
| 2099 const bool guard = FLAG_wasm_guard_pages; |
| 2100 buffer = NewArrayBuffer(isolate, new_size, guard); |
| 2101 if (buffer.is_null()) return -1; |
| 2102 Address new_mem_start = static_cast<Address>(buffer->backing_store()); |
| 2103 if (old_size != 0) { |
| 2104 memcpy(new_mem_start, old_mem_start, old_size); |
| 2105 } |
| 2106 SetInstanceMemory(instance, *buffer); |
| 2107 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); |
| 2108 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start, |
| 2109 old_size, new_size); |
| 2007 } | 2110 } |
| 2008 SetInstanceMemory(instance, *buffer); | 2111 |
| 2009 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); | |
| 2010 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start, | |
| 2011 old_size, new_size); | |
| 2012 Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), | 2112 Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), |
| 2013 isolate); | 2113 isolate); |
| 2014 if (!memory_object->IsUndefined(isolate)) { | 2114 if (!memory_object->IsUndefined(isolate)) { |
| 2015 WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer); | 2115 WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer); |
| 2016 } | 2116 } |
| 2017 | 2117 |
| 2018 DCHECK(old_size % WasmModule::kPageSize == 0); | 2118 DCHECK(old_size % WasmModule::kPageSize == 0); |
| 2019 return (old_size / WasmModule::kPageSize); | 2119 return (old_size / WasmModule::kPageSize); |
| 2020 } | 2120 } |
| 2021 | 2121 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 CHECK_NOT_NULL(result.val); | 2190 CHECK_NOT_NULL(result.val); |
| 2091 module = const_cast<WasmModule*>(result.val); | 2191 module = const_cast<WasmModule*>(result.val); |
| 2092 } | 2192 } |
| 2093 | 2193 |
| 2094 Handle<WasmModuleWrapper> module_wrapper = | 2194 Handle<WasmModuleWrapper> module_wrapper = |
| 2095 WasmModuleWrapper::New(isolate, module); | 2195 WasmModuleWrapper::New(isolate, module); |
| 2096 | 2196 |
| 2097 compiled_module->set_module_wrapper(module_wrapper); | 2197 compiled_module->set_module_wrapper(module_wrapper); |
| 2098 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); | 2198 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); |
| 2099 } | 2199 } |
| OLD | NEW |