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

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

Issue 2396433008: [wasm] Add guard regions to end of WebAssembly.Memory buffers (Closed)
Patch Set: Merge branch 'master' of https://chromium.googlesource.com/v8/v8 into guard-pages Created 4 years, 1 month 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
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/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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698