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 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
107 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, | 107 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, |
108 Handle<Object> new_ref) { | 108 Handle<Object> new_ref) { |
109 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); | 109 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); |
110 it.next()) { | 110 it.next()) { |
111 if (it.rinfo()->target_object() == *old_ref) { | 111 if (it.rinfo()->target_object() == *old_ref) { |
112 it.rinfo()->set_target_object(*new_ref); | 112 it.rinfo()->set_target_object(*new_ref); |
113 } | 113 } |
114 } | 114 } |
115 } | 115 } |
116 | 116 |
117 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { | 117 #if V8_HOST_ARCH_64_BIT |
118 if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) { | 118 static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) { |
119 // TODO(titzer): lift restriction on maximum memory allocated here. | 119 JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter()); |
120 return Handle<JSArrayBuffer>::null(); | 120 JSArrayBuffer* buffer = *p; |
121 } | |
122 void* memory = isolate->array_buffer_allocator()->Allocate(size); | |
123 if (memory == nullptr) { | |
124 return Handle<JSArrayBuffer>::null(); | |
125 } | |
126 | 121 |
127 #if DEBUG | 122 void* memory = buffer->backing_store(); |
128 // Double check the API allocator actually zero-initialized the memory. | 123 base::OS::Free(memory, |
129 const byte* bytes = reinterpret_cast<const byte*>(memory); | 124 RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize())); |
130 for (size_t i = 0; i < size; ++i) { | 125 |
131 DCHECK_EQ(0, bytes[i]); | 126 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory( |
132 } | 127 -buffer->byte_length()->Number()); |
128 | |
129 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); | |
130 } | |
133 #endif | 131 #endif |
134 | 132 |
135 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); | 133 void* TryAllocateBackingStore(Isolate* isolate, size_t size, bool guard) { |
136 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size)); | 134 if (guard) { |
titzer
2016/11/07 19:54:53
I think this needs to be TARGET_ARCH.
How about g
Eric Holk
2016/11/08 23:58:15
Done. I also updated the help text for --wasm_guar
| |
137 buffer->set_is_neuterable(false); | 135 #if V8_HOST_ARCH_64_BIT |
138 return buffer; | 136 void* memory; |
137 // TODO(eholk): On Windows we want to make sure we don't commit the guard | |
138 // pages yet. | |
139 | |
140 // We always allocate the largest possible offset into the heap, so the | |
141 // addressable memory after the guard page can be made inaccessible. | |
142 const size_t alloc_size = | |
143 RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()); | |
144 DCHECK_EQ(0, size % base::OS::CommitPageSize()); | |
145 | |
146 size_t allocated_size = 0; | |
147 const bool is_executable = false; | |
148 memory = base::OS::Allocate(alloc_size, &allocated_size, is_executable); | |
149 if (allocated_size < alloc_size) { | |
150 base::OS::Free(memory, allocated_size); | |
151 return nullptr; | |
152 } | |
153 | |
154 if (memory == nullptr) { | |
155 return nullptr; | |
156 } | |
157 | |
158 byte* bytes = reinterpret_cast<byte*>(memory); | |
159 base::OS::Guard(bytes + size, alloc_size - size); | |
160 | |
161 reinterpret_cast<v8::Isolate*>(isolate) | |
162 ->AdjustAmountOfExternalAllocatedMemory(size); | |
163 | |
164 return memory; | |
165 #else | |
166 DCHECK(false && "Guard pages are not supported on 32-bit systems"); | |
167 return nullptr; | |
168 #endif | |
169 } else { | |
170 void* memory = isolate->array_buffer_allocator()->Allocate(size); | |
171 return memory; | |
172 } | |
139 } | 173 } |
140 | 174 |
141 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, | 175 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, |
142 Address old_start, Address start, | 176 Address old_start, Address start, |
143 uint32_t prev_size, uint32_t new_size) { | 177 uint32_t prev_size, uint32_t new_size) { |
144 for (int i = 0; i < code_table->length(); ++i) { | 178 for (int i = 0; i < code_table->length(); ++i) { |
145 DCHECK(code_table->get(i)->IsCode()); | 179 DCHECK(code_table->get(i)->IsCode()); |
146 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); | 180 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); |
147 AllowDeferredHandleDereference embedding_raw_address; | 181 AllowDeferredHandleDereference embedding_raw_address; |
148 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | | 182 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | |
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0))); | 658 TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0))); |
625 TRACE("}\n"); | 659 TRACE("}\n"); |
626 } | 660 } |
627 compiled_module->reset_weak_owning_instance(); | 661 compiled_module->reset_weak_owning_instance(); |
628 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); | 662 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); |
629 TRACE("}\n"); | 663 TRACE("}\n"); |
630 } | 664 } |
631 | 665 |
632 } // namespace | 666 } // namespace |
633 | 667 |
668 Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size, | |
669 bool enable_guard_regions) { | |
titzer
2016/11/07 19:54:52
I like this name better. Can we make the header fi
Eric Holk
2016/11/08 23:58:15
Done.
| |
670 if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) { | |
671 // TODO(titzer): lift restriction on maximum memory allocated here. | |
672 return Handle<JSArrayBuffer>::null(); | |
673 } | |
674 | |
675 void* memory = TryAllocateBackingStore(isolate, size, enable_guard_regions); | |
676 bool is_external = enable_guard_regions; | |
titzer
2016/11/07 19:54:52
What about making is_external a return value from
Eric Holk
2016/11/08 23:58:15
Done, although it seems like V8_TARGET_ARCH_64_BIT
| |
677 | |
678 if (memory == nullptr) { | |
679 return Handle<JSArrayBuffer>::null(); | |
680 } | |
681 | |
682 #if DEBUG | |
683 // Double check the API allocator actually zero-initialized the memory. | |
684 const byte* bytes = reinterpret_cast<const byte*>(memory); | |
685 for (size_t i = 0; i < size; ++i) { | |
686 DCHECK_EQ(0, bytes[i]); | |
687 } | |
688 #endif | |
689 | |
690 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); | |
691 JSArrayBuffer::Setup(buffer, isolate, is_external, memory, | |
692 static_cast<int>(size)); | |
693 buffer->set_is_neuterable(false); | |
694 buffer->set_has_guard_region(enable_guard_regions); | |
695 | |
696 #if V8_HOST_ARCH_64_BIT | |
697 if (is_external) { | |
698 // We mark the buffer as external if we allocated it here with guard | |
699 // pages. That means we need to arrange for it to be freed. | |
700 | |
701 // TODO(eholk): Finalizers may not run when the main thread is shutting | |
702 // down, which means we may leak memory here. | |
703 Handle<Object> global_handle = isolate->global_handles()->Create(*buffer); | |
704 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), | |
705 &MemoryFinalizer, v8::WeakCallbackType::kFinalizer); | |
706 } | |
707 #endif | |
708 | |
709 return buffer; | |
710 } | |
711 | |
634 const char* wasm::SectionName(WasmSectionCode code) { | 712 const char* wasm::SectionName(WasmSectionCode code) { |
635 switch (code) { | 713 switch (code) { |
636 case kUnknownSectionCode: | 714 case kUnknownSectionCode: |
637 return "Unknown"; | 715 return "Unknown"; |
638 case kTypeSectionCode: | 716 case kTypeSectionCode: |
639 return "Type"; | 717 return "Type"; |
640 case kImportSectionCode: | 718 case kImportSectionCode: |
641 return "Import"; | 719 return "Import"; |
642 case kFunctionSectionCode: | 720 case kFunctionSectionCode: |
643 return "Function"; | 721 return "Function"; |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1069 Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED); | 1147 Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED); |
1070 instance->SetInternalField(kWasmMemObject, | 1148 instance->SetInternalField(kWasmMemObject, |
1071 isolate_->heap()->undefined_value()); | 1149 isolate_->heap()->undefined_value()); |
1072 | 1150 |
1073 //-------------------------------------------------------------------------- | 1151 //-------------------------------------------------------------------------- |
1074 // Set up the globals for the new instance. | 1152 // Set up the globals for the new instance. |
1075 //-------------------------------------------------------------------------- | 1153 //-------------------------------------------------------------------------- |
1076 MaybeHandle<JSArrayBuffer> old_globals; | 1154 MaybeHandle<JSArrayBuffer> old_globals; |
1077 uint32_t globals_size = module_->globals_size; | 1155 uint32_t globals_size = module_->globals_size; |
1078 if (globals_size > 0) { | 1156 if (globals_size > 0) { |
1157 const bool enable_guard_regions = false; | |
1079 Handle<JSArrayBuffer> global_buffer = | 1158 Handle<JSArrayBuffer> global_buffer = |
1080 NewArrayBuffer(isolate_, globals_size); | 1159 NewArrayBuffer(isolate_, globals_size, enable_guard_regions); |
1081 globals_ = global_buffer; | 1160 globals_ = global_buffer; |
1082 if (globals_.is_null()) { | 1161 if (globals_.is_null()) { |
1083 thrower_->RangeError("Out of memory: wasm globals"); | 1162 thrower_->RangeError("Out of memory: wasm globals"); |
1084 return nothing; | 1163 return nothing; |
1085 } | 1164 } |
1086 Address old_address = owner.is_null() | 1165 Address old_address = owner.is_null() |
1087 ? nullptr | 1166 ? nullptr |
1088 : GetGlobalStartAddressFromCodeTemplate( | 1167 : GetGlobalStartAddressFromCodeTemplate( |
1089 isolate_->heap()->undefined_value(), | 1168 isolate_->heap()->undefined_value(), |
1090 JSObject::cast(*owner.ToHandleChecked())); | 1169 JSObject::cast(*owner.ToHandleChecked())); |
(...skipping 30 matching lines...) Expand all Loading... | |
1121 //-------------------------------------------------------------------------- | 1200 //-------------------------------------------------------------------------- |
1122 MaybeHandle<JSArrayBuffer> old_memory; | 1201 MaybeHandle<JSArrayBuffer> old_memory; |
1123 | 1202 |
1124 uint32_t min_mem_pages = module_->min_mem_pages; | 1203 uint32_t min_mem_pages = module_->min_mem_pages; |
1125 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); | 1204 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); |
1126 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. | 1205 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. |
1127 | 1206 |
1128 if (!memory_.is_null()) { | 1207 if (!memory_.is_null()) { |
1129 // Set externally passed ArrayBuffer non neuterable. | 1208 // Set externally passed ArrayBuffer non neuterable. |
1130 memory_->set_is_neuterable(false); | 1209 memory_->set_is_neuterable(false); |
1210 | |
1211 DCHECK_IMPLIES(FLAG_wasm_guard_pages, module_->origin == kAsmJsOrigin || | |
1212 memory_->has_guard_region()); | |
1131 } else if (min_mem_pages > 0) { | 1213 } else if (min_mem_pages > 0) { |
1132 memory_ = AllocateMemory(min_mem_pages); | 1214 memory_ = AllocateMemory(min_mem_pages); |
1133 if (memory_.is_null()) return nothing; // failed to allocate memory | 1215 if (memory_.is_null()) return nothing; // failed to allocate memory |
1134 } | 1216 } |
1135 | 1217 |
1136 if (!memory_.is_null()) { | 1218 if (!memory_.is_null()) { |
1137 instance->SetInternalField(kWasmMemArrayBuffer, *memory_); | 1219 instance->SetInternalField(kWasmMemArrayBuffer, *memory_); |
1138 Address mem_start = static_cast<Address>(memory_->backing_store()); | 1220 Address mem_start = static_cast<Address>(memory_->backing_store()); |
1139 uint32_t mem_size = | 1221 uint32_t mem_size = |
1140 static_cast<uint32_t>(memory_->byte_length()->Number()); | 1222 static_cast<uint32_t>(memory_->byte_length()->Number()); |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1572 } | 1654 } |
1573 } | 1655 } |
1574 } | 1656 } |
1575 | 1657 |
1576 // Allocate memory for a module instance as a new JSArrayBuffer. | 1658 // Allocate memory for a module instance as a new JSArrayBuffer. |
1577 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { | 1659 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { |
1578 if (min_mem_pages > WasmModule::kV8MaxPages) { | 1660 if (min_mem_pages > WasmModule::kV8MaxPages) { |
1579 thrower_->RangeError("Out of memory: wasm memory too large"); | 1661 thrower_->RangeError("Out of memory: wasm memory too large"); |
1580 return Handle<JSArrayBuffer>::null(); | 1662 return Handle<JSArrayBuffer>::null(); |
1581 } | 1663 } |
1582 Handle<JSArrayBuffer> mem_buffer = | 1664 const bool enable_guard_regions = FLAG_wasm_guard_pages; |
1583 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize); | 1665 Handle<JSArrayBuffer> mem_buffer = NewArrayBuffer( |
1666 isolate_, min_mem_pages * WasmModule::kPageSize, enable_guard_regions); | |
1584 | 1667 |
1585 if (mem_buffer.is_null()) { | 1668 if (mem_buffer.is_null()) { |
1586 thrower_->RangeError("Out of memory: wasm memory"); | 1669 thrower_->RangeError("Out of memory: wasm memory"); |
1587 } | 1670 } |
1588 return mem_buffer; | 1671 return mem_buffer; |
1589 } | 1672 } |
1590 | 1673 |
1591 // Process the exports, creating wrappers for functions, tables, memories, | 1674 // Process the exports, creating wrappers for functions, tables, memories, |
1592 // and globals. | 1675 // and globals. |
1593 void ProcessExports(Handle<FixedArray> code_table, | 1676 void ProcessExports(Handle<FixedArray> code_table, |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2134 // "undefined" case above. | 2217 // "undefined" case above. |
2135 DCHECK_NOT_NULL(old_mem_start); | 2218 DCHECK_NOT_NULL(old_mem_start); |
2136 DCHECK(old_size + pages * WasmModule::kPageSize <= | 2219 DCHECK(old_size + pages * WasmModule::kPageSize <= |
2137 std::numeric_limits<uint32_t>::max()); | 2220 std::numeric_limits<uint32_t>::max()); |
2138 new_size = old_size + pages * WasmModule::kPageSize; | 2221 new_size = old_size + pages * WasmModule::kPageSize; |
2139 } | 2222 } |
2140 | 2223 |
2141 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) { | 2224 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) { |
2142 return -1; | 2225 return -1; |
2143 } | 2226 } |
2144 Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size); | 2227 |
2145 if (buffer.is_null()) return -1; | 2228 Handle<JSArrayBuffer> buffer; |
2146 Address new_mem_start = static_cast<Address>(buffer->backing_store()); | 2229 |
2147 if (old_size != 0) { | 2230 if (FLAG_wasm_guard_pages && !old_buffer.is_null()) { |
titzer
2016/11/07 19:54:53
How about !old_buffer.is_null() and old_buffer.has
Eric Holk
2016/11/08 23:58:15
Done.
| |
2148 memcpy(new_mem_start, old_mem_start, old_size); | 2231 base::OS::Unprotect(old_buffer->backing_store(), new_size); |
titzer
2016/11/07 19:54:53
Add a comment that we aren't moving the memory her
Eric Holk
2016/11/08 23:58:15
Done.
| |
2232 reinterpret_cast<v8::Isolate*>(isolate) | |
2233 ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize); | |
2234 Handle<Object> new_size_object = | |
2235 isolate->factory()->NewNumberFromSize(new_size); | |
2236 old_buffer->set_byte_length(*new_size_object); | |
2237 | |
2238 SetInstanceMemory(instance, *old_buffer); | |
2239 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); | |
2240 RelocateMemoryReferencesInCode(code_table, old_mem_start, old_mem_start, | |
2241 old_size, new_size); | |
2242 buffer = old_buffer; | |
2243 } else { | |
2244 const bool enable_guard_regions = FLAG_wasm_guard_pages; | |
2245 buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions); | |
2246 if (buffer.is_null()) return -1; | |
2247 Address new_mem_start = static_cast<Address>(buffer->backing_store()); | |
2248 if (old_size != 0) { | |
2249 memcpy(new_mem_start, old_mem_start, old_size); | |
2250 } | |
2251 SetInstanceMemory(instance, *buffer); | |
2252 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); | |
2253 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start, | |
2254 old_size, new_size); | |
2149 } | 2255 } |
2150 SetInstanceMemory(instance, *buffer); | 2256 |
2151 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); | |
2152 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start, | |
2153 old_size, new_size); | |
2154 Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), | 2257 Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), |
2155 isolate); | 2258 isolate); |
2156 if (!memory_object->IsUndefined(isolate)) { | 2259 if (!memory_object->IsUndefined(isolate)) { |
2157 WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer); | 2260 WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer); |
2158 } | 2261 } |
2159 | 2262 |
2160 DCHECK(old_size % WasmModule::kPageSize == 0); | 2263 DCHECK(old_size % WasmModule::kPageSize == 0); |
2161 return (old_size / WasmModule::kPageSize); | 2264 return (old_size / WasmModule::kPageSize); |
2162 } | 2265 } |
2163 | 2266 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2232 CHECK_NOT_NULL(result.val); | 2335 CHECK_NOT_NULL(result.val); |
2233 module = const_cast<WasmModule*>(result.val); | 2336 module = const_cast<WasmModule*>(result.val); |
2234 } | 2337 } |
2235 | 2338 |
2236 Handle<WasmModuleWrapper> module_wrapper = | 2339 Handle<WasmModuleWrapper> module_wrapper = |
2237 WasmModuleWrapper::New(isolate, module); | 2340 WasmModuleWrapper::New(isolate, module); |
2238 | 2341 |
2239 compiled_module->set_module_wrapper(module_wrapper); | 2342 compiled_module->set_module_wrapper(module_wrapper); |
2240 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); | 2343 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); |
2241 } | 2344 } |
OLD | NEW |