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" |
11 #include "src/objects.h" | 11 #include "src/objects.h" |
12 #include "src/property-descriptor.h" | 12 #include "src/property-descriptor.h" |
13 #include "src/simulator.h" | 13 #include "src/simulator.h" |
14 #include "src/snapshot/snapshot.h" | 14 #include "src/snapshot/snapshot.h" |
15 #include "src/v8.h" | 15 #include "src/v8.h" |
16 | 16 |
17 #include "src/wasm/ast-decoder.h" | 17 #include "src/wasm/ast-decoder.h" |
18 #include "src/wasm/module-decoder.h" | 18 #include "src/wasm/module-decoder.h" |
19 #include "src/wasm/wasm-debug.h" | 19 #include "src/wasm/wasm-debug.h" |
20 #include "src/wasm/wasm-function-name-table.h" | 20 #include "src/wasm/wasm-function-name-table.h" |
21 #include "src/wasm/wasm-module.h" | 21 #include "src/wasm/wasm-module.h" |
22 #include "src/wasm/wasm-result.h" | 22 #include "src/wasm/wasm-result.h" |
23 | 23 |
24 #include "src/compiler/wasm-compiler.h" | 24 #include "src/compiler/wasm-compiler.h" |
25 | 25 |
26 namespace v8 { | 26 namespace v8 { |
27 namespace internal { | 27 namespace internal { |
28 namespace wasm { | 28 namespace wasm { |
29 | 29 |
30 const char* SectionName(WasmSectionCode code) { | |
31 switch (code) { | |
32 case kUnknownSectionCode: | |
33 return "Unknown"; | |
34 case kTypeSectionCode: | |
35 return "Type"; | |
36 case kImportSectionCode: | |
37 return "Import"; | |
38 case kFunctionSectionCode: | |
39 return "Function"; | |
40 case kTableSectionCode: | |
41 return "Table"; | |
42 case kMemorySectionCode: | |
43 return "Memory"; | |
44 case kGlobalSectionCode: | |
45 return "Global"; | |
46 case kExportSectionCode: | |
47 return "Export"; | |
48 case kStartSectionCode: | |
49 return "Start"; | |
50 case kCodeSectionCode: | |
51 return "Code"; | |
52 case kElementSectionCode: | |
53 return "Element"; | |
54 case kDataSectionCode: | |
55 return "Data"; | |
56 case kNameSectionCode: | |
57 return "Name"; | |
58 default: | |
59 return "<unknown>"; | |
60 } | |
61 } | |
62 | |
30 enum JSFunctionExportInternalField { | 63 enum JSFunctionExportInternalField { |
31 kInternalModuleInstance, | 64 kInternalModuleInstance, |
32 kInternalArity, | 65 kInternalArity, |
33 kInternalSignature | 66 kInternalSignature |
34 }; | 67 }; |
35 | 68 |
36 static const int kPlaceholderMarker = 1000000000; | 69 static const int kPlaceholderMarker = 1000000000; |
37 | 70 |
38 static const char* wasmSections[] = { | |
39 #define F(enumerator, order, string) string, | |
40 FOR_EACH_WASM_SECTION_TYPE(F) | |
41 #undef F | |
42 "<unknown>" // entry for "Max" | |
43 }; | |
44 | |
45 static uint8_t wasmSectionsLengths[]{ | |
46 #define F(enumerator, order, string) sizeof(string) - 1, | |
47 FOR_EACH_WASM_SECTION_TYPE(F) | |
48 #undef F | |
49 9 // entry for "Max" | |
50 }; | |
51 | |
52 static uint8_t wasmSectionsOrders[]{ | |
53 #define F(enumerator, order, string) order, | |
54 FOR_EACH_WASM_SECTION_TYPE(F) | |
55 #undef F | |
56 0 // entry for "Max" | |
57 }; | |
58 | |
59 static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) == | |
60 (size_t)WasmSection::Code::Max + 1, | |
61 "expected enum WasmSection::Code to be monotonic from 0"); | |
62 | |
63 WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; } | |
64 WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; } | |
65 WasmSection::Code WasmSection::next(WasmSection::Code code) { | |
66 return (WasmSection::Code)(1 + (uint32_t)code); | |
67 } | |
68 | |
69 const char* WasmSection::getName(WasmSection::Code code) { | |
70 return wasmSections[(size_t)code]; | |
71 } | |
72 | |
73 size_t WasmSection::getNameLength(WasmSection::Code code) { | |
74 return wasmSectionsLengths[(size_t)code]; | |
75 } | |
76 | |
77 int WasmSection::getOrder(WasmSection::Code code) { | |
78 return wasmSectionsOrders[(size_t)code]; | |
79 } | |
80 | |
81 WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) { | |
82 // TODO(jfb) Linear search, it may be better to do a common-prefix search. | |
83 for (Code i = begin(); i != end(); i = next(i)) { | |
84 if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) { | |
85 return i; | |
86 } | |
87 } | |
88 return Code::Max; | |
89 } | |
90 | |
91 std::ostream& operator<<(std::ostream& os, const WasmModule& module) { | 71 std::ostream& operator<<(std::ostream& os, const WasmModule& module) { |
92 os << "WASM module with "; | 72 os << "WASM module with "; |
93 os << (module.min_mem_pages * module.kPageSize) << " min mem"; | 73 os << (module.min_mem_pages * module.kPageSize) << " min mem"; |
94 os << (module.max_mem_pages * module.kPageSize) << " max mem"; | 74 os << (module.max_mem_pages * module.kPageSize) << " max mem"; |
95 os << module.functions.size() << " functions"; | 75 os << module.functions.size() << " functions"; |
96 os << module.functions.size() << " globals"; | 76 os << module.functions.size() << " globals"; |
97 os << module.functions.size() << " data segments"; | 77 os << module.functions.size() << " data segments"; |
98 return os; | 78 return os; |
99 } | 79 } |
100 | 80 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 DCHECK_NOT_NULL(deopt_data); | 131 DCHECK_NOT_NULL(deopt_data); |
152 DCHECK(deopt_data->length() == 2); | 132 DCHECK(deopt_data->length() == 2); |
153 Object* weak_link = deopt_data->get(0); | 133 Object* weak_link = deopt_data->get(0); |
154 if (weak_link == undefined) return undefined; | 134 if (weak_link == undefined) return undefined; |
155 WeakCell* cell = WeakCell::cast(weak_link); | 135 WeakCell* cell = WeakCell::cast(weak_link); |
156 return cell->value(); | 136 return cell->value(); |
157 } | 137 } |
158 | 138 |
159 namespace { | 139 namespace { |
160 // Internal constants for the layout of the module object. | 140 // Internal constants for the layout of the module object. |
161 enum WasmInstanceFields { | 141 enum WasmInstanceObjectFields { |
162 kWasmCompiledModule = 0, | 142 kWasmCompiledModule = 0, |
163 kWasmModuleFunctionTable, | 143 kWasmModuleFunctionTable, |
164 kWasmModuleCodeTable, | 144 kWasmModuleCodeTable, |
165 kWasmMemArrayBuffer, | 145 kWasmMemArrayBuffer, |
166 kWasmGlobalsArrayBuffer, | 146 kWasmGlobalsArrayBuffer, |
167 // TODO(clemensh): Remove function name array, extract names from module | 147 // TODO(clemensh): Remove function name array, extract names from module |
168 // bytes. | 148 // bytes. |
169 kWasmFunctionNamesArray, | 149 kWasmFunctionNamesArray, |
170 kWasmModuleBytesString, | 150 kWasmModuleBytesString, |
171 kWasmDebugInfo, | 151 kWasmDebugInfo, |
152 kWasmNumImportedFunctions, | |
172 kWasmModuleInternalFieldCount | 153 kWasmModuleInternalFieldCount |
173 }; | 154 }; |
174 | 155 |
175 // TODO(mtrofin): Unnecessary once we stop using JS Heap for wasm code. | 156 // TODO(mtrofin): Unnecessary once we stop using JS Heap for wasm code. |
176 // For now, each field is expected to have the type commented by its side. | 157 // For now, each field is expected to have the type commented by its side. |
177 // The elements typed as "maybe" are optional. The others are mandatory. Since | 158 // The elements typed as "maybe" are optional. The others are mandatory. Since |
178 // the compiled module is either obtained from the current v8 instance, or from | 159 // the compiled module is either obtained from the current v8 instance, or from |
179 // a snapshot produced by a compatible (==identical) v8 instance, we simply | 160 // a snapshot produced by a compatible (==identical) v8 instance, we simply |
180 // fail at instantiation time, in the face of invalid data. | 161 // fail at instantiation time, in the face of invalid data. |
181 enum CompiledWasmObjectFields { | 162 enum WasmCompiledModuleFields { |
182 kFunctions, // FixedArray of Code | 163 kCodeTable, // FixedArray of Code |
183 kImportData, // maybe FixedArray of FixedArray respecting the | 164 kImportData, // maybe FixedArray of FixedArray respecting the |
184 // WasmImportMetadata structure. | 165 // WasmImportData structure. |
185 kImportMap, // FixedArray. The i-th element is the Code object used for | 166 kExportData, // maybe FixedArray of FixedArray of WasmExportData |
186 // import i | 167 // structure |
187 kExports, // maybe FixedArray of FixedArray of WasmExportMetadata | 168 kStartupData, // maybe FixedArray of WasmExportData structure |
188 // structure | |
189 kStartupFunction, // maybe FixedArray of WasmExportMetadata structure | |
190 kTableOfIndirectFunctionTables, // maybe FixedArray of FixedArray of | 169 kTableOfIndirectFunctionTables, // maybe FixedArray of FixedArray of |
191 // WasmIndirectFunctionTableMetadata | 170 // WasmIndirectFunctionTableData |
192 kModuleBytes, // maybe String | 171 kModuleBytes, // maybe String |
193 kFunctionNameTable, // maybe ByteArray | 172 kFunctionNameTable, // maybe ByteArray |
194 kMinRequiredMemory, // Smi. an uint32_t | 173 kMinRequiredMemory, // Smi. an uint32_t |
195 // The following 2 are either together present or absent: | 174 // The following 2 are either together present or absent: |
196 kDataSegmentsInfo, // maybe FixedArray of FixedArray respecting the | 175 kDataSegmentsInfo, // maybe FixedArray of FixedArray respecting the |
197 // WasmSegmentInfo structure | 176 // WasmSegmentInfo structure |
198 kDataSegments, // maybe ByteArray. | 177 kDataSegments, // maybe ByteArray. |
199 | 178 |
200 kGlobalsSize, // Smi. an uint32_t | 179 kGlobalsSize, // Smi. an uint32_t |
201 kMemSize, // Smi.an uint32_t | 180 kMemSize, // Smi.an uint32_t |
202 kMemStart, // MaybeHandle<ArrayBuffer> | 181 kMemStart, // MaybeHandle<ArrayBuffer> |
203 kExportMem, // Smi. bool | 182 kExportMem, // Smi. bool |
204 kOrigin, // Smi. ModuleOrigin | 183 kOrigin, // Smi. ModuleOrigin |
205 kNextInstance, // WeakCell. See compiled code cloning. | 184 kNextInstance, // WeakCell. See compiled code cloning. |
206 kPrevInstance, // WeakCell. See compiled code cloning. | 185 kPrevInstance, // WeakCell. See compiled code cloning. |
207 kOwningInstance, // WeakCell, pointing to the owning instance. | 186 kOwningInstance, // WeakCell, pointing to the owning instance. |
208 kModuleObject, // WeakCell, pointing to the module object. | 187 kModuleObject, // WeakCell, pointing to the module object. |
209 kCompiledWasmObjectTableSize // Sentinel value. | 188 kCompiledWasmObjectTableSize // Sentinel value. |
210 }; | 189 }; |
211 | 190 |
212 enum WasmImportMetadata { | 191 enum WasmImportData { |
213 kModuleName, // String | 192 kModuleName, // String |
214 kFunctionName, // maybe String | 193 kFunctionName, // maybe String |
215 kOutputCount, // Smi. an uint32_t | 194 kOutputCount, // Smi. an uint32_t |
216 kSignature, // ByteArray. A copy of the data in FunctionSig | 195 kSignature, // ByteArray. A copy of the data in FunctionSig |
217 kWasmImportDataTableSize // Sentinel value. | 196 kWasmImportDataTableSize // Sentinel value. |
218 }; | 197 }; |
219 | 198 |
220 enum WasmExportMetadata { | 199 enum WasmExportData { |
221 kExportCode, // Code | 200 kExportName, // String |
222 kExportName, // String | 201 kExportArity, // Smi, an int |
223 kExportArity, // Smi, an int | 202 kExportedFunctionIndex, // Smi, an uint32_t |
224 kExportedFunctionIndex, // Smi, an uint32_t | 203 kExportedSignature, // ByteArray. A copy of the data in FunctionSig |
225 kExportedSignature, // ByteArray. A copy of the data in FunctionSig | 204 kWasmExportDataTableSize // Sentinel value. |
226 kWasmExportMetadataTableSize // Sentinel value. | |
227 }; | 205 }; |
228 | 206 |
229 enum WasmSegmentInfo { | 207 enum WasmSegmentInfo { |
230 kDestAddr, // Smi. an uint32_t | 208 kDestAddr, // Smi. an uint32_t |
231 kSourceSize, // Smi. an uint32_t | 209 kSourceSize, // Smi. an uint32_t |
232 kWasmSegmentInfoSize // Sentinel value. | 210 kWasmSegmentInfoSize // Sentinel value. |
233 }; | 211 }; |
234 | 212 |
235 enum WasmIndirectFunctionTableMetadata { | 213 enum WasmIndirectFunctionTableData { |
236 kSize, // Smi. an uint32_t | 214 kSize, // Smi. an uint32_t |
237 kTable, // FixedArray of indirect function table | 215 kTable, // FixedArray of indirect function table |
238 kWasmIndirectFunctionTableMetadataSize // Sentinel value. | 216 kWasmIndirectFunctionTableDataSize // Sentinel value. |
239 }; | 217 }; |
240 | 218 |
241 uint32_t GetMinModuleMemSize(const WasmModule* module) { | 219 uint32_t GetMinModuleMemSize(const WasmModule* module) { |
242 return WasmModule::kPageSize * module->min_mem_pages; | 220 return WasmModule::kPageSize * module->min_mem_pages; |
243 } | 221 } |
244 | 222 |
245 void LoadDataSegments(Handle<FixedArray> compiled_module, Address mem_addr, | 223 void LoadDataSegments(Handle<FixedArray> compiled_module, Address mem_addr, |
246 size_t mem_size) { | 224 size_t mem_size) { |
247 Isolate* isolate = compiled_module->GetIsolate(); | 225 Isolate* isolate = compiled_module->GetIsolate(); |
248 MaybeHandle<ByteArray> maybe_data = | 226 MaybeHandle<ByteArray> maybe_data = |
(...skipping 23 matching lines...) Expand all Loading... | |
272 last_extraction_pos += source_size; | 250 last_extraction_pos += source_size; |
273 } | 251 } |
274 } | 252 } |
275 | 253 |
276 void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, | 254 void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, |
277 Handle<FixedArray> compiled_module) { | 255 Handle<FixedArray> compiled_module) { |
278 Handle<FixedArray> segments = factory->NewFixedArray( | 256 Handle<FixedArray> segments = factory->NewFixedArray( |
279 static_cast<int>(module->data_segments.size()), TENURED); | 257 static_cast<int>(module->data_segments.size()), TENURED); |
280 uint32_t data_size = 0; | 258 uint32_t data_size = 0; |
281 for (const WasmDataSegment& segment : module->data_segments) { | 259 for (const WasmDataSegment& segment : module->data_segments) { |
282 if (!segment.init) continue; | |
283 if (segment.source_size == 0) continue; | 260 if (segment.source_size == 0) continue; |
284 data_size += segment.source_size; | 261 data_size += segment.source_size; |
285 } | 262 } |
286 Handle<ByteArray> data = factory->NewByteArray(data_size, TENURED); | 263 Handle<ByteArray> data = factory->NewByteArray(data_size, TENURED); |
287 | 264 |
288 uint32_t last_insertion_pos = 0; | 265 uint32_t last_insertion_pos = 0; |
289 for (uint32_t i = 0; i < module->data_segments.size(); ++i) { | 266 for (uint32_t i = 0; i < module->data_segments.size(); ++i) { |
290 const WasmDataSegment& segment = module->data_segments[i]; | 267 const WasmDataSegment& segment = module->data_segments[i]; |
291 if (!segment.init) continue; | |
292 if (segment.source_size == 0) continue; | 268 if (segment.source_size == 0) continue; |
293 Handle<ByteArray> js_segment = | 269 Handle<ByteArray> js_segment = |
294 factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED); | 270 factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED); |
295 js_segment->set_int(kDestAddr, segment.dest_addr); | 271 // TODO(titzer): add support for global offsets for dest_addr |
272 CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind); | |
273 js_segment->set_int(kDestAddr, segment.dest_addr.val.i32_const); | |
296 js_segment->set_int(kSourceSize, segment.source_size); | 274 js_segment->set_int(kSourceSize, segment.source_size); |
297 segments->set(i, *js_segment); | 275 segments->set(i, *js_segment); |
298 data->copy_in(last_insertion_pos, | 276 data->copy_in(last_insertion_pos, |
299 module->module_start + segment.source_offset, | 277 module->module_start + segment.source_offset, |
300 segment.source_size); | 278 segment.source_size); |
301 last_insertion_pos += segment.source_size; | 279 last_insertion_pos += segment.source_size; |
302 } | 280 } |
303 compiled_module->set(kDataSegmentsInfo, *segments); | 281 compiled_module->set(kDataSegmentsInfo, *segments); |
304 compiled_module->set(kDataSegments, *data); | 282 compiled_module->set(kDataSegments, *data); |
305 } | 283 } |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
394 // TODO(titzer): placeholder code objects are somewhat dangerous. | 372 // TODO(titzer): placeholder code objects are somewhat dangerous. |
395 static byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. | 373 static byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. |
396 static CodeDesc desc = { | 374 static CodeDesc desc = { |
397 buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr}; | 375 buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr}; |
398 Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind), | 376 Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind), |
399 Handle<Object>::null()); | 377 Handle<Object>::null()); |
400 code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker); | 378 code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker); |
401 return code; | 379 return code; |
402 } | 380 } |
403 | 381 |
404 // TODO(mtrofin): remove when we stop relying on placeholders. | 382 bool LinkFunction(Handle<Code> unlinked, |
405 void InitializePlaceholders(Factory* factory, | 383 std::vector<Handle<Code>>& code_table) { |
406 std::vector<Handle<Code>>* placeholders, | |
407 size_t size) { | |
408 DCHECK(placeholders->empty()); | |
409 placeholders->reserve(size); | |
410 | |
411 for (uint32_t i = 0; i < size; ++i) { | |
412 placeholders->push_back(CreatePlaceholder(factory, i, Code::WASM_FUNCTION)); | |
413 } | |
414 } | |
415 | |
416 bool LinkFunction(Isolate* isolate, Handle<Code> unlinked, | |
417 Handle<FixedArray> code_targets, | |
418 Code::Kind kind = Code::WASM_FUNCTION) { | |
419 bool modified = false; | 384 bool modified = false; |
420 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | 385 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); |
421 AllowDeferredHandleDereference embedding_raw_address; | 386 AllowDeferredHandleDereference embedding_raw_address; |
422 for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) { | 387 for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) { |
423 Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | 388 RelocInfo::Mode mode = it.rinfo()->rmode(); |
424 if (target->kind() == kind && | 389 if (RelocInfo::IsCodeTarget(mode)) { |
425 target->constant_pool_offset() >= kPlaceholderMarker) { | 390 Code* target = |
426 // Patch direct calls to placeholder code objects. | 391 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
427 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; | 392 if (target->constant_pool_offset() < kPlaceholderMarker) continue; |
428 CHECK(index < static_cast<uint32_t>(code_targets->length())); | 393 switch (target->kind()) { |
429 Handle<Code> new_target = | 394 case Code::WASM_FUNCTION: // fall through |
430 code_targets->GetValueChecked<Code>(isolate, index); | 395 case Code::WASM_TO_JS_FUNCTION: // fall through |
431 if (target != *new_target) { | 396 case Code::JS_TO_WASM_FUNCTION: { |
432 it.rinfo()->set_target_address(new_target->instruction_start(), | 397 // Patch direct calls to placeholder code objects. |
433 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); | 398 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
434 modified = true; | 399 Handle<Code> new_target = code_table[index]; |
400 if (target != *new_target) { | |
401 it.rinfo()->set_target_address(new_target->instruction_start(), | |
402 UPDATE_WRITE_BARRIER, | |
403 SKIP_ICACHE_FLUSH); | |
404 modified = true; | |
405 } | |
406 break; | |
407 } | |
408 default: | |
409 break; | |
435 } | 410 } |
436 } | 411 } |
437 } | 412 } |
438 return modified; | 413 return modified; |
439 } | 414 } |
440 | 415 |
441 void LinkModuleFunctions(Isolate* isolate, Handle<FixedArray> functions) { | 416 void FlushICache(Isolate* isolate, Handle<FixedArray> functions) { |
442 for (int i = 0; i < functions->length(); ++i) { | |
443 Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); | |
444 LinkFunction(isolate, code, functions); | |
445 } | |
446 } | |
447 | |
448 void FlushAssemblyCache(Isolate* isolate, Handle<FixedArray> functions) { | |
449 for (int i = 0; i < functions->length(); ++i) { | 417 for (int i = 0; i < functions->length(); ++i) { |
450 Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); | 418 Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); |
451 Assembler::FlushICache(isolate, code->instruction_start(), | 419 Assembler::FlushICache(isolate, code->instruction_start(), |
452 code->instruction_size()); | 420 code->instruction_size()); |
453 } | 421 } |
454 } | 422 } |
423 } // namespace | |
455 | 424 |
456 void SetRuntimeSupport(Isolate* isolate, Handle<JSObject> js_object) { | 425 uint32_t GetNumImportedFunctions(Handle<JSObject> wasm_object) { |
457 Handle<FixedArray> functions = Handle<FixedArray>( | 426 return static_cast<uint32_t>( |
458 FixedArray::cast(js_object->GetInternalField(kWasmModuleCodeTable))); | 427 Smi::cast(wasm_object->GetInternalField(kWasmNumImportedFunctions)) |
459 Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(js_object); | 428 ->value()); |
460 | |
461 for (int i = FLAG_skip_compiling_wasm_funcs; i < functions->length(); ++i) { | |
462 Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); | |
463 Handle<FixedArray> deopt_data = | |
464 isolate->factory()->NewFixedArray(2, TENURED); | |
465 deopt_data->set(0, *weak_link); | |
466 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); | |
467 deopt_data->set_length(2); | |
468 code->set_deoptimization_data(*deopt_data); | |
469 } | |
470 } | 429 } |
471 | 430 |
472 } // namespace | |
473 | |
474 WasmModule::WasmModule(byte* module_start) | 431 WasmModule::WasmModule(byte* module_start) |
475 : module_start(module_start), | 432 : module_start(module_start), |
476 module_end(nullptr), | 433 module_end(nullptr), |
477 min_mem_pages(0), | 434 min_mem_pages(0), |
478 max_mem_pages(0), | 435 max_mem_pages(0), |
479 mem_export(false), | 436 mem_export(false), |
480 mem_external(false), | |
481 start_function_index(-1), | 437 start_function_index(-1), |
482 origin(kWasmOrigin), | 438 origin(kWasmOrigin), |
483 globals_size(0), | 439 globals_size(0), |
440 num_imported_functions(0), | |
441 num_declared_functions(0), | |
442 num_exported_functions(0), | |
484 pending_tasks(new base::Semaphore(0)) {} | 443 pending_tasks(new base::Semaphore(0)) {} |
485 | 444 |
486 static MaybeHandle<JSFunction> ReportFFIError( | 445 static MaybeHandle<JSFunction> ReportFFIError( |
487 ErrorThrower& thrower, const char* error, uint32_t index, | 446 ErrorThrower& thrower, const char* error, uint32_t index, |
488 Handle<String> module_name, MaybeHandle<String> function_name) { | 447 Handle<String> module_name, MaybeHandle<String> function_name) { |
489 Handle<String> function_name_handle; | 448 Handle<String> function_name_handle; |
490 if (function_name.ToHandle(&function_name_handle)) { | 449 if (function_name.ToHandle(&function_name_handle)) { |
491 thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", | 450 thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", |
492 index, module_name->length(), module_name->ToCString().get(), | 451 index, module_name->length(), module_name->ToCString().get(), |
493 function_name_handle->length(), | 452 function_name_handle->length(), |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
552 bool FetchAndExecuteCompilationUnit( | 511 bool FetchAndExecuteCompilationUnit( |
553 Isolate* isolate, | 512 Isolate* isolate, |
554 std::vector<compiler::WasmCompilationUnit*>* compilation_units, | 513 std::vector<compiler::WasmCompilationUnit*>* compilation_units, |
555 std::queue<compiler::WasmCompilationUnit*>* executed_units, | 514 std::queue<compiler::WasmCompilationUnit*>* executed_units, |
556 base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) { | 515 base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) { |
557 DisallowHeapAllocation no_allocation; | 516 DisallowHeapAllocation no_allocation; |
558 DisallowHandleAllocation no_handles; | 517 DisallowHandleAllocation no_handles; |
559 DisallowHandleDereference no_deref; | 518 DisallowHandleDereference no_deref; |
560 DisallowCodeDependencyChange no_dependency_change; | 519 DisallowCodeDependencyChange no_dependency_change; |
561 | 520 |
562 // - 1 because AtomicIntrement returns the value after the atomic increment. | 521 // - 1 because AtomicIncrement returns the value after the atomic increment. |
563 size_t index = next_unit->Increment(1) - 1; | 522 size_t index = next_unit->Increment(1) - 1; |
564 if (index >= compilation_units->size()) { | 523 if (index >= compilation_units->size()) { |
565 return false; | 524 return false; |
566 } | 525 } |
567 | 526 |
568 compiler::WasmCompilationUnit* unit = compilation_units->at(index); | 527 compiler::WasmCompilationUnit* unit = compilation_units->at(index); |
569 if (unit != nullptr) { | 528 if (unit != nullptr) { |
570 unit->ExecuteCompilation(); | 529 unit->ExecuteCompilation(); |
571 { | 530 base::LockGuard<base::Mutex> guard(result_mutex); |
572 base::LockGuard<base::Mutex> guard(result_mutex); | 531 executed_units->push(unit); |
573 executed_units->push(unit); | |
574 } | |
575 } | 532 } |
576 return true; | 533 return true; |
577 } | 534 } |
578 | 535 |
579 class WasmCompilationTask : public CancelableTask { | 536 class WasmCompilationTask : public CancelableTask { |
580 public: | 537 public: |
581 WasmCompilationTask( | 538 WasmCompilationTask( |
582 Isolate* isolate, | 539 Isolate* isolate, |
583 std::vector<compiler::WasmCompilationUnit*>* compilation_units, | 540 std::vector<compiler::WasmCompilationUnit*>* compilation_units, |
584 std::queue<compiler::WasmCompilationUnit*>* executed_units, | 541 std::queue<compiler::WasmCompilationUnit*>* executed_units, |
(...skipping 22 matching lines...) Expand all Loading... | |
607 base::Mutex* result_mutex_; | 564 base::Mutex* result_mutex_; |
608 base::AtomicNumber<size_t>* next_unit_; | 565 base::AtomicNumber<size_t>* next_unit_; |
609 }; | 566 }; |
610 | 567 |
611 static void RecordStats(Isolate* isolate, Code* code) { | 568 static void RecordStats(Isolate* isolate, Code* code) { |
612 isolate->counters()->wasm_generated_code_size()->Increment(code->body_size()); | 569 isolate->counters()->wasm_generated_code_size()->Increment(code->body_size()); |
613 isolate->counters()->wasm_reloc_size()->Increment( | 570 isolate->counters()->wasm_reloc_size()->Increment( |
614 code->relocation_info()->length()); | 571 code->relocation_info()->length()); |
615 } | 572 } |
616 | 573 |
617 static void RecordStats(Isolate* isolate, | |
618 const std::vector<Handle<Code>>& functions) { | |
619 for (Handle<Code> c : functions) RecordStats(isolate, *c); | |
620 } | |
621 | |
622 static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) { | 574 static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) { |
623 DisallowHeapAllocation no_gc; | 575 DisallowHeapAllocation no_gc; |
624 for (int i = 0; i < functions->length(); ++i) { | 576 for (int i = 0; i < functions->length(); ++i) { |
625 RecordStats(isolate, Code::cast(functions->get(i))); | 577 RecordStats(isolate, Code::cast(functions->get(i))); |
626 } | 578 } |
627 } | 579 } |
628 | 580 |
629 Address GetGlobalStartAddressFromCodeTemplate(Object* undefined, | 581 Address GetGlobalStartAddressFromCodeTemplate(Object* undefined, |
630 JSObject* owner) { | 582 JSObject* owner) { |
631 Address old_address = nullptr; | 583 Address old_address = nullptr; |
632 Object* stored_value = owner->GetInternalField(kWasmGlobalsArrayBuffer); | 584 Object* stored_value = owner->GetInternalField(kWasmGlobalsArrayBuffer); |
633 if (stored_value != undefined) { | 585 if (stored_value != undefined) { |
634 old_address = static_cast<Address>( | 586 old_address = static_cast<Address>( |
635 JSArrayBuffer::cast(stored_value)->backing_store()); | 587 JSArrayBuffer::cast(stored_value)->backing_store()); |
636 } | 588 } |
637 return old_address; | 589 return old_address; |
638 } | 590 } |
639 | 591 |
640 Handle<FixedArray> GetImportsMetadata(Factory* factory, | 592 Handle<FixedArray> GetImportsData(Factory* factory, const WasmModule* module) { |
641 const WasmModule* module) { | |
642 Handle<FixedArray> ret = factory->NewFixedArray( | 593 Handle<FixedArray> ret = factory->NewFixedArray( |
643 static_cast<int>(module->import_table.size()), TENURED); | 594 static_cast<int>(module->import_table.size()), TENURED); |
644 for (size_t i = 0; i < module->import_table.size(); ++i) { | 595 for (size_t i = 0; i < module->import_table.size(); ++i) { |
645 const WasmImport& import = module->import_table[i]; | 596 const WasmImport& import = module->import_table[i]; |
597 if (import.kind != kExternalFunction) continue; | |
646 WasmName module_name = module->GetNameOrNull(import.module_name_offset, | 598 WasmName module_name = module->GetNameOrNull(import.module_name_offset, |
647 import.module_name_length); | 599 import.module_name_length); |
648 WasmName function_name = module->GetNameOrNull(import.function_name_offset, | 600 WasmName function_name = module->GetNameOrNull(import.field_name_offset, |
649 import.function_name_length); | 601 import.field_name_length); |
650 | 602 |
651 Handle<String> module_name_string = | 603 Handle<String> module_name_string = |
652 factory->InternalizeUtf8String(module_name); | 604 factory->InternalizeUtf8String(module_name); |
653 Handle<String> function_name_string = | 605 Handle<String> function_name_string = |
654 function_name.is_empty() | 606 function_name.is_empty() |
655 ? Handle<String>::null() | 607 ? Handle<String>::null() |
656 : factory->InternalizeUtf8String(function_name); | 608 : factory->InternalizeUtf8String(function_name); |
657 Handle<ByteArray> sig = | 609 FunctionSig* fsig = module->functions[import.index].sig; |
658 factory->NewByteArray(static_cast<int>(import.sig->parameter_count() + | 610 Handle<ByteArray> sig = factory->NewByteArray( |
659 import.sig->return_count()), | 611 static_cast<int>(fsig->parameter_count() + fsig->return_count()), |
660 TENURED); | 612 TENURED); |
661 sig->copy_in(0, reinterpret_cast<const byte*>(import.sig->raw_data()), | 613 sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()), |
662 sig->length()); | 614 sig->length()); |
663 Handle<FixedArray> encoded_import = | 615 Handle<FixedArray> encoded_import = |
664 factory->NewFixedArray(kWasmImportDataTableSize, TENURED); | 616 factory->NewFixedArray(kWasmImportDataTableSize, TENURED); |
665 encoded_import->set(kModuleName, *module_name_string); | 617 encoded_import->set(kModuleName, *module_name_string); |
666 if (!function_name_string.is_null()) { | 618 if (!function_name_string.is_null()) { |
667 encoded_import->set(kFunctionName, *function_name_string); | 619 encoded_import->set(kFunctionName, *function_name_string); |
668 } | 620 } |
669 encoded_import->set( | 621 encoded_import->set(kOutputCount, |
670 kOutputCount, | 622 Smi::FromInt(static_cast<int>(fsig->return_count()))); |
671 Smi::FromInt(static_cast<int>(import.sig->return_count()))); | |
672 encoded_import->set(kSignature, *sig); | 623 encoded_import->set(kSignature, *sig); |
673 ret->set(static_cast<int>(i), *encoded_import); | 624 ret->set(static_cast<int>(i), *encoded_import); |
674 } | 625 } |
675 return ret; | 626 return ret; |
676 } | 627 } |
677 | 628 |
678 bool CompileWrappersToImportedFunctions(Isolate* isolate, | 629 Handle<Code> CompileImportWrapper(Isolate* isolate, |
679 const Handle<JSReceiver> ffi, | 630 const Handle<JSReceiver> ffi, int index, |
680 std::vector<Handle<Code>>& imports, | 631 Handle<FixedArray> import_data, |
681 Handle<FixedArray> import_data, | 632 ErrorThrower* thrower) { |
682 ErrorThrower* thrower) { | 633 Handle<FixedArray> data = |
683 uint32_t import_count = static_cast<uint32_t>(import_data->length()); | 634 import_data->GetValueChecked<FixedArray>(isolate, index); |
684 if (import_count > 0) { | 635 Handle<String> module_name = |
685 imports.reserve(import_count); | 636 data->GetValueChecked<String>(isolate, kModuleName); |
686 for (uint32_t index = 0; index < import_count; ++index) { | 637 MaybeHandle<String> function_name = |
687 Handle<FixedArray> data = | 638 data->GetValue<String>(isolate, kFunctionName); |
688 import_data->GetValueChecked<FixedArray>(isolate, index); | |
689 Handle<String> module_name = | |
690 data->GetValueChecked<String>(isolate, kModuleName); | |
691 MaybeHandle<String> function_name = | |
692 data->GetValue<String>(isolate, kFunctionName); | |
693 | 639 |
694 // TODO(mtrofin): this is an uint32_t, actually. We should rationalize | 640 // TODO(mtrofin): this is an uint32_t, actually. We should rationalize |
695 // it when we rationalize signed/unsigned stuff. | 641 // it when we rationalize signed/unsigned stuff. |
696 int ret_count = Smi::cast(data->get(kOutputCount))->value(); | 642 int ret_count = Smi::cast(data->get(kOutputCount))->value(); |
697 CHECK(ret_count >= 0); | 643 CHECK_GE(ret_count, 0); |
698 Handle<ByteArray> sig_data = | 644 Handle<ByteArray> sig_data = |
699 data->GetValueChecked<ByteArray>(isolate, kSignature); | 645 data->GetValueChecked<ByteArray>(isolate, kSignature); |
700 int sig_data_size = sig_data->length(); | 646 int sig_data_size = sig_data->length(); |
701 int param_count = sig_data_size - ret_count; | 647 int param_count = sig_data_size - ret_count; |
702 CHECK(param_count >= 0); | 648 CHECK(param_count >= 0); |
703 | 649 |
704 MaybeHandle<JSReceiver> function = LookupFunction( | 650 MaybeHandle<JSReceiver> function = LookupFunction( |
705 *thrower, isolate->factory(), ffi, index, module_name, function_name); | 651 *thrower, isolate->factory(), ffi, index, module_name, function_name); |
706 if (function.is_null()) return false; | 652 if (function.is_null()) return Handle<Code>::null(); |
707 Handle<Code> code; | 653 Handle<Code> code; |
708 Handle<JSReceiver> target = function.ToHandleChecked(); | 654 Handle<JSReceiver> target = function.ToHandleChecked(); |
709 bool isMatch = false; | 655 bool isMatch = false; |
710 Handle<Code> export_wrapper_code; | 656 Handle<Code> export_wrapper_code; |
711 if (target->IsJSFunction()) { | 657 if (target->IsJSFunction()) { |
712 Handle<JSFunction> func = Handle<JSFunction>::cast(target); | 658 Handle<JSFunction> func = Handle<JSFunction>::cast(target); |
713 export_wrapper_code = handle(func->code()); | 659 export_wrapper_code = handle(func->code()); |
714 if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) { | 660 if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) { |
715 int exported_param_count = | 661 int exported_param_count = |
716 Smi::cast(func->GetInternalField(kInternalArity))->value(); | 662 Smi::cast(func->GetInternalField(kInternalArity))->value(); |
717 Handle<ByteArray> exportedSig = Handle<ByteArray>( | 663 Handle<ByteArray> exportedSig = Handle<ByteArray>( |
718 ByteArray::cast(func->GetInternalField(kInternalSignature))); | 664 ByteArray::cast(func->GetInternalField(kInternalSignature))); |
719 if (exported_param_count == param_count && | 665 if (exported_param_count == param_count && |
720 exportedSig->length() == sig_data->length() && | 666 exportedSig->length() == sig_data->length() && |
721 memcmp(exportedSig->data(), sig_data->data(), | 667 memcmp(exportedSig->data(), sig_data->data(), |
722 exportedSig->length()) == 0) { | 668 exportedSig->length()) == 0) { |
723 isMatch = true; | 669 isMatch = true; |
724 } | |
725 } | |
726 } | 670 } |
727 if (isMatch) { | |
728 int wasm_count = 0; | |
729 int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | |
730 for (RelocIterator it(*export_wrapper_code, mask); !it.done(); | |
731 it.next()) { | |
732 RelocInfo* rinfo = it.rinfo(); | |
733 Address target_address = rinfo->target_address(); | |
734 Code* target = Code::GetCodeFromTargetAddress(target_address); | |
735 if (target->kind() == Code::WASM_FUNCTION) { | |
736 ++wasm_count; | |
737 code = handle(target); | |
738 } | |
739 } | |
740 DCHECK(wasm_count == 1); | |
741 } else { | |
742 // Copy the signature to avoid a raw pointer into a heap object when | |
743 // GC can happen. | |
744 Zone zone(isolate->allocator()); | |
745 MachineRepresentation* reps = | |
746 zone.NewArray<MachineRepresentation>(sig_data_size); | |
747 memcpy(reps, sig_data->data(), | |
748 sizeof(MachineRepresentation) * sig_data_size); | |
749 FunctionSig sig(ret_count, param_count, reps); | |
750 | |
751 code = compiler::CompileWasmToJSWrapper(isolate, target, &sig, index, | |
752 module_name, function_name); | |
753 } | |
754 imports.push_back(code); | |
755 } | 671 } |
756 } | 672 } |
757 return true; | 673 if (isMatch) { |
674 int wasm_count = 0; | |
675 int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | |
676 for (RelocIterator it(*export_wrapper_code, mask); !it.done(); it.next()) { | |
677 RelocInfo* rinfo = it.rinfo(); | |
678 Address target_address = rinfo->target_address(); | |
679 Code* target = Code::GetCodeFromTargetAddress(target_address); | |
680 if (target->kind() == Code::WASM_FUNCTION) { | |
681 ++wasm_count; | |
682 code = handle(target); | |
683 } | |
684 } | |
685 DCHECK(wasm_count == 1); | |
686 return code; | |
687 } else { | |
688 // Copy the signature to avoid a raw pointer into a heap object when | |
689 // GC can happen. | |
690 Zone zone(isolate->allocator()); | |
691 MachineRepresentation* reps = | |
692 zone.NewArray<MachineRepresentation>(sig_data_size); | |
693 memcpy(reps, sig_data->data(), | |
694 sizeof(MachineRepresentation) * sig_data_size); | |
695 FunctionSig sig(ret_count, param_count, reps); | |
696 | |
697 return compiler::CompileWasmToJSWrapper(isolate, target, &sig, index, | |
698 module_name, function_name); | |
699 } | |
758 } | 700 } |
759 | 701 |
760 void InitializeParallelCompilation( | 702 void InitializeParallelCompilation( |
761 Isolate* isolate, const std::vector<WasmFunction>& functions, | 703 Isolate* isolate, const std::vector<WasmFunction>& functions, |
762 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 704 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
763 ModuleEnv& module_env, ErrorThrower& thrower) { | 705 ModuleEnv& module_env, ErrorThrower& thrower) { |
764 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { | 706 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { |
765 compilation_units[i] = new compiler::WasmCompilationUnit( | 707 const WasmFunction* func = &functions[i]; |
766 &thrower, isolate, &module_env, &functions[i], i); | 708 compilation_units[i] = |
709 func->imported ? nullptr : new compiler::WasmCompilationUnit( | |
710 &thrower, isolate, &module_env, func, i); | |
767 } | 711 } |
768 } | 712 } |
769 | 713 |
770 uint32_t* StartCompilationTasks( | 714 uint32_t* StartCompilationTasks( |
771 Isolate* isolate, | 715 Isolate* isolate, |
772 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 716 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
773 std::queue<compiler::WasmCompilationUnit*>& executed_units, | 717 std::queue<compiler::WasmCompilationUnit*>& executed_units, |
774 base::Semaphore* pending_tasks, base::Mutex& result_mutex, | 718 base::Semaphore* pending_tasks, base::Mutex& result_mutex, |
775 base::AtomicNumber<size_t>& next_unit) { | 719 base::AtomicNumber<size_t>& next_unit) { |
776 const size_t num_tasks = | 720 const size_t num_tasks = |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
886 } | 830 } |
887 | 831 |
888 void CompileSequentially(Isolate* isolate, const WasmModule* module, | 832 void CompileSequentially(Isolate* isolate, const WasmModule* module, |
889 std::vector<Handle<Code>>& functions, | 833 std::vector<Handle<Code>>& functions, |
890 ErrorThrower* thrower, ModuleEnv* module_env) { | 834 ErrorThrower* thrower, ModuleEnv* module_env) { |
891 DCHECK(!thrower->error()); | 835 DCHECK(!thrower->error()); |
892 | 836 |
893 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; | 837 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; |
894 i < module->functions.size(); ++i) { | 838 i < module->functions.size(); ++i) { |
895 const WasmFunction& func = module->functions[i]; | 839 const WasmFunction& func = module->functions[i]; |
840 if (func.imported) continue; // Imports are compiled at instantiation time. | |
896 | 841 |
897 DCHECK_EQ(i, func.func_index); | |
898 WasmName str = module->GetName(func.name_offset, func.name_length); | 842 WasmName str = module->GetName(func.name_offset, func.name_length); |
899 Handle<Code> code = Handle<Code>::null(); | 843 Handle<Code> code = Handle<Code>::null(); |
900 // Compile the function. | 844 // Compile the function. |
901 code = compiler::WasmCompilationUnit::CompileWasmFunction( | 845 code = compiler::WasmCompilationUnit::CompileWasmFunction( |
902 thrower, isolate, module_env, &func); | 846 thrower, isolate, module_env, &func); |
903 if (code.is_null()) { | 847 if (code.is_null()) { |
904 thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(), | 848 thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(), |
905 str.start()); | 849 str.start()); |
906 break; | 850 break; |
907 } | 851 } |
908 // Install the code into the linker table. | 852 // Install the code into the linker table. |
909 functions[i] = code; | 853 functions[i] = code; |
910 } | 854 } |
911 } | 855 } |
912 | 856 |
913 void SetDebugSupport(Factory* factory, Handle<FixedArray> compiled_module, | 857 void PatchDirectCalls(Handle<FixedArray> old_functions, |
914 Handle<JSObject> js_object) { | 858 Handle<FixedArray> new_functions, int start) { |
915 Isolate* isolate = compiled_module->GetIsolate(); | |
916 MaybeHandle<String> module_bytes_string = | |
917 compiled_module->GetValue<String>(isolate, kModuleBytes); | |
918 if (!module_bytes_string.is_null()) { | |
919 js_object->SetInternalField(kWasmModuleBytesString, | |
920 *module_bytes_string.ToHandleChecked()); | |
921 } | |
922 | |
923 MaybeHandle<ByteArray> function_name_table = | |
924 compiled_module->GetValue<ByteArray>(isolate, kFunctionNameTable); | |
925 if (!function_name_table.is_null()) { | |
926 js_object->SetInternalField(kWasmFunctionNamesArray, | |
927 *function_name_table.ToHandleChecked()); | |
928 } | |
929 } | |
930 | |
931 bool SetupGlobals(Isolate* isolate, MaybeHandle<JSObject> template_owner, | |
932 Handle<FixedArray> compiled_module, Handle<JSObject> instance, | |
933 ErrorThrower* thrower) { | |
934 uint32_t globals_size = static_cast<uint32_t>( | |
935 Smi::cast(compiled_module->get(kGlobalsSize))->value()); | |
936 if (globals_size > 0) { | |
937 Handle<JSArrayBuffer> globals_buffer = | |
938 NewArrayBuffer(isolate, globals_size); | |
939 if (globals_buffer.is_null()) { | |
940 thrower->Error("Out of memory: wasm globals"); | |
941 return false; | |
942 } | |
943 Address old_address = | |
944 template_owner.is_null() | |
945 ? nullptr | |
946 : GetGlobalStartAddressFromCodeTemplate( | |
947 *isolate->factory()->undefined_value(), | |
948 JSObject::cast(*template_owner.ToHandleChecked())); | |
949 RelocateGlobals(instance, old_address, | |
950 static_cast<Address>(globals_buffer->backing_store())); | |
951 instance->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer); | |
952 } | |
953 return true; | |
954 } | |
955 | |
956 bool SetupInstanceHeap(Isolate* isolate, Handle<FixedArray> compiled_module, | |
957 Handle<JSObject> instance, Handle<JSArrayBuffer> memory, | |
958 ErrorThrower* thrower) { | |
959 uint32_t min_mem_pages = static_cast<uint32_t>( | |
960 Smi::cast(compiled_module->get(kMinRequiredMemory))->value()); | |
961 isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); | |
962 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. | |
963 | |
964 if (memory.is_null() && min_mem_pages > 0) { | |
965 memory = AllocateMemory(thrower, isolate, min_mem_pages); | |
966 if (memory.is_null()) { | |
967 return false; | |
968 } | |
969 } | |
970 | |
971 if (!memory.is_null()) { | |
972 instance->SetInternalField(kWasmMemArrayBuffer, *memory); | |
973 Address mem_start = static_cast<Address>(memory->backing_store()); | |
974 uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number()); | |
975 uint32_t old_mem_size = static_cast<uint32_t>( | |
976 compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize) | |
977 ->value()); | |
978 MaybeHandle<JSArrayBuffer> old_mem = | |
979 compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart); | |
980 Address old_mem_start = | |
981 old_mem.is_null() | |
982 ? nullptr | |
983 : static_cast<Address>(old_mem.ToHandleChecked()->backing_store()); | |
984 RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size, | |
985 mem_size); | |
986 LoadDataSegments(compiled_module, mem_start, mem_size); | |
987 compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize) | |
988 ->set_value(static_cast<double>(mem_size)); | |
989 compiled_module->set(kMemStart, *memory); | |
990 } | |
991 return true; | |
992 } | |
993 | |
994 void FixupFunctionsAndImports(Handle<FixedArray> old_functions, | |
995 Handle<FixedArray> new_functions, | |
996 MaybeHandle<FixedArray> maybe_old_imports, | |
997 MaybeHandle<FixedArray> maybe_new_imports) { | |
998 DCHECK_EQ(new_functions->length(), old_functions->length()); | 859 DCHECK_EQ(new_functions->length(), old_functions->length()); |
999 | 860 |
1000 DisallowHeapAllocation no_gc; | 861 DisallowHeapAllocation no_gc; |
1001 std::map<Code*, Code*> old_to_new_code; | 862 std::map<Code*, Code*> old_to_new_code; |
1002 for (int i = 0; i < new_functions->length(); ++i) { | 863 for (int i = 0; i < new_functions->length(); ++i) { |
1003 old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)), | 864 old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)), |
1004 Code::cast(new_functions->get(i)))); | 865 Code::cast(new_functions->get(i)))); |
1005 } | 866 } |
1006 DCHECK_EQ(maybe_old_imports.is_null(), maybe_new_imports.is_null()); | |
1007 if (!maybe_old_imports.is_null()) { | |
1008 Handle<FixedArray> old_imports = maybe_old_imports.ToHandleChecked(); | |
1009 Handle<FixedArray> new_imports = maybe_new_imports.ToHandleChecked(); | |
1010 DCHECK_EQ(new_imports->length(), old_imports->length()); | |
1011 for (int i = 0; i < new_imports->length(); ++i) { | |
1012 old_to_new_code.insert(std::make_pair(Code::cast(old_imports->get(i)), | |
1013 Code::cast(new_imports->get(i)))); | |
1014 } | |
1015 } | |
1016 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | 867 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); |
1017 AllowDeferredHandleDereference embedding_raw_address; | 868 AllowDeferredHandleDereference embedding_raw_address; |
1018 for (int i = 0; i < new_functions->length(); ++i) { | 869 for (int i = start; i < new_functions->length(); ++i) { |
1019 Code* wasm_function = Code::cast(new_functions->get(i)); | 870 Code* wasm_function = Code::cast(new_functions->get(i)); |
1020 for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) { | 871 for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) { |
1021 Code* old_code = | 872 Code* old_code = |
1022 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | 873 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
1023 if (old_code->kind() == Code::WASM_TO_JS_FUNCTION || | 874 if (old_code->kind() == Code::WASM_TO_JS_FUNCTION || |
1024 old_code->kind() == Code::WASM_FUNCTION) { | 875 old_code->kind() == Code::WASM_FUNCTION) { |
1025 auto found = old_to_new_code.find(old_code); | 876 auto found = old_to_new_code.find(old_code); |
1026 DCHECK(found != old_to_new_code.end()); | 877 DCHECK(found != old_to_new_code.end()); |
1027 Code* new_code = found->second; | 878 Code* new_code = found->second; |
1028 // Avoid redundant updates, expected for wasm functions, if we're at the | 879 if (new_code != old_code) { |
1029 // first instance. | 880 it.rinfo()->set_target_address(new_code->instruction_start(), |
1030 if (new_code == old_code) { | 881 UPDATE_WRITE_BARRIER, |
1031 DCHECK(new_code->kind() == Code::WASM_FUNCTION); | 882 SKIP_ICACHE_FLUSH); |
1032 continue; | |
1033 } | 883 } |
1034 it.rinfo()->set_target_address(new_code->instruction_start(), | |
1035 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); | |
1036 } | 884 } |
1037 } | 885 } |
1038 } | 886 } |
1039 } | 887 } |
1040 | 888 |
1041 bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module, | |
1042 Handle<JSObject> instance, ErrorThrower* thrower, | |
1043 Handle<JSReceiver> ffi) { | |
1044 //------------------------------------------------------------------------- | |
1045 // Compile wrappers to imported functions. | |
1046 //------------------------------------------------------------------------- | |
1047 std::vector<Handle<Code>> import_code; | |
1048 MaybeHandle<FixedArray> maybe_import_data = | |
1049 compiled_module->GetValue<FixedArray>(isolate, kImportData); | |
1050 Handle<FixedArray> import_data; | |
1051 if (maybe_import_data.ToHandle(&import_data)) { | |
1052 if (!CompileWrappersToImportedFunctions(isolate, ffi, import_code, | |
1053 import_data, thrower)) { | |
1054 return false; | |
1055 } | |
1056 } | |
1057 | |
1058 RecordStats(isolate, import_code); | |
1059 if (import_code.empty()) return true; | |
1060 | |
1061 Handle<FixedArray> new_imports = | |
1062 isolate->factory()->NewFixedArray(static_cast<int>(import_code.size())); | |
1063 for (int i = 0; i < new_imports->length(); ++i) { | |
1064 new_imports->set(i, *import_code[i]); | |
1065 } | |
1066 compiled_module->set(kImportMap, *new_imports); | |
1067 return true; | |
1068 } | |
1069 | |
1070 bool SetupExportsObject(Handle<FixedArray> compiled_module, Isolate* isolate, | |
1071 Handle<JSObject> instance, ErrorThrower* thrower) { | |
1072 Factory* factory = isolate->factory(); | |
1073 bool mem_export = | |
1074 static_cast<bool>(Smi::cast(compiled_module->get(kExportMem))->value()); | |
1075 ModuleOrigin origin = static_cast<ModuleOrigin>( | |
1076 Smi::cast(compiled_module->get(kOrigin))->value()); | |
1077 | |
1078 MaybeHandle<FixedArray> maybe_exports = | |
1079 compiled_module->GetValue<FixedArray>(isolate, kExports); | |
1080 if (!maybe_exports.is_null() || mem_export) { | |
1081 PropertyDescriptor desc; | |
1082 desc.set_writable(false); | |
1083 | |
1084 Handle<JSObject> exports_object = instance; | |
1085 if (origin == kWasmOrigin) { | |
1086 // Create the "exports" object. | |
1087 Handle<JSFunction> object_function = Handle<JSFunction>( | |
1088 isolate->native_context()->object_function(), isolate); | |
1089 exports_object = factory->NewJSObject(object_function, TENURED); | |
1090 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); | |
1091 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); | |
1092 } | |
1093 Handle<FixedArray> exports; | |
1094 if (maybe_exports.ToHandle(&exports)) { | |
1095 int exports_size = exports->length(); | |
1096 for (int i = 0; i < exports_size; ++i) { | |
1097 if (thrower->error()) return false; | |
1098 Handle<FixedArray> export_metadata = | |
1099 exports->GetValueChecked<FixedArray>(isolate, i); | |
1100 Handle<Code> export_code = | |
1101 export_metadata->GetValueChecked<Code>(isolate, kExportCode); | |
1102 RecordStats(isolate, *export_code); | |
1103 Handle<String> name = | |
1104 export_metadata->GetValueChecked<String>(isolate, kExportName); | |
1105 int arity = Smi::cast(export_metadata->get(kExportArity))->value(); | |
1106 MaybeHandle<ByteArray> signature = | |
1107 export_metadata->GetValue<ByteArray>(isolate, kExportedSignature); | |
1108 Handle<JSFunction> function = WrapExportCodeAsJSFunction( | |
1109 isolate, export_code, name, arity, signature, instance); | |
1110 desc.set_value(function); | |
1111 Maybe<bool> status = JSReceiver::DefineOwnProperty( | |
1112 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); | |
1113 if (!status.IsJust()) { | |
1114 thrower->Error("export of %.*s failed.", name->length(), | |
1115 name->ToCString().get()); | |
1116 return false; | |
1117 } | |
1118 } | |
1119 } | |
1120 if (mem_export) { | |
1121 // Export the memory as a named property. | |
1122 Handle<String> name = factory->InternalizeUtf8String("memory"); | |
1123 Handle<JSArrayBuffer> memory = Handle<JSArrayBuffer>( | |
1124 JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer))); | |
1125 JSObject::AddProperty(exports_object, name, memory, READ_ONLY); | |
1126 } | |
1127 } | |
1128 return true; | |
1129 } | |
1130 | |
1131 #define GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(Field) \ | 889 #define GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(Field) \ |
1132 WeakCell* Get##Field(const FixedArray* compiled_module) { \ | 890 WeakCell* Get##Field(const FixedArray* compiled_module) { \ |
1133 Object* obj = compiled_module->get(k##Field); \ | 891 Object* obj = compiled_module->get(k##Field); \ |
1134 DCHECK_NOT_NULL(obj); \ | 892 DCHECK_NOT_NULL(obj); \ |
1135 if (obj->IsWeakCell()) { \ | 893 if (obj->IsWeakCell()) { \ |
1136 return WeakCell::cast(obj); \ | 894 return WeakCell::cast(obj); \ |
1137 } else { \ | 895 } else { \ |
1138 return nullptr; \ | 896 return nullptr; \ |
1139 } \ | 897 } \ |
1140 } | 898 } |
(...skipping 17 matching lines...) Expand all Loading... | |
1158 | 916 |
1159 if (old_mem_size > 0) { | 917 if (old_mem_size > 0) { |
1160 CHECK_NE(mem_start, undefined); | 918 CHECK_NE(mem_start, undefined); |
1161 old_mem_address = | 919 old_mem_address = |
1162 static_cast<Address>(JSArrayBuffer::cast(mem_start)->backing_store()); | 920 static_cast<Address>(JSArrayBuffer::cast(mem_start)->backing_store()); |
1163 } | 921 } |
1164 int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) | | 922 int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) | |
1165 RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) | | 923 RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) | |
1166 RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE); | 924 RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE); |
1167 | 925 |
1168 Object* fct_obj = compiled_module->get(kFunctions); | 926 Object* fct_obj = compiled_module->get(kCodeTable); |
1169 if (fct_obj != nullptr && fct_obj != undefined && | 927 if (fct_obj != nullptr && fct_obj != undefined && |
1170 (old_mem_size > 0 || globals_start != nullptr)) { | 928 (old_mem_size > 0 || globals_start != nullptr)) { |
1171 FixedArray* functions = FixedArray::cast(fct_obj); | 929 FixedArray* functions = FixedArray::cast(fct_obj); |
1172 for (int i = 0; i < functions->length(); ++i) { | 930 for (int i = 0; i < functions->length(); ++i) { |
1173 Code* code = Code::cast(functions->get(i)); | 931 Code* code = Code::cast(functions->get(i)); |
1174 bool changed = false; | 932 bool changed = false; |
1175 for (RelocIterator it(code, mode_mask); !it.done(); it.next()) { | 933 for (RelocIterator it(code, mode_mask); !it.done(); it.next()) { |
1176 RelocInfo::Mode mode = it.rinfo()->rmode(); | 934 RelocInfo::Mode mode = it.rinfo()->rmode(); |
1177 if (RelocInfo::IsWasmMemoryReference(mode) || | 935 if (RelocInfo::IsWasmMemoryReference(mode) || |
1178 RelocInfo::IsWasmMemorySizeReference(mode)) { | 936 RelocInfo::IsWasmMemorySizeReference(mode)) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1261 MaybeHandle<FixedArray> indirect_table = | 1019 MaybeHandle<FixedArray> indirect_table = |
1262 function_tables.size() | 1020 function_tables.size() |
1263 ? factory->NewFixedArray(static_cast<int>(function_tables.size()), | 1021 ? factory->NewFixedArray(static_cast<int>(function_tables.size()), |
1264 TENURED) | 1022 TENURED) |
1265 : MaybeHandle<FixedArray>(); | 1023 : MaybeHandle<FixedArray>(); |
1266 for (uint32_t i = 0; i < function_tables.size(); ++i) { | 1024 for (uint32_t i = 0; i < function_tables.size(); ++i) { |
1267 Handle<FixedArray> values = wasm::BuildFunctionTable(isolate, i, this); | 1025 Handle<FixedArray> values = wasm::BuildFunctionTable(isolate, i, this); |
1268 temp_instance_for_compilation.function_tables[i] = values; | 1026 temp_instance_for_compilation.function_tables[i] = values; |
1269 | 1027 |
1270 Handle<FixedArray> metadata = isolate->factory()->NewFixedArray( | 1028 Handle<FixedArray> metadata = isolate->factory()->NewFixedArray( |
1271 kWasmIndirectFunctionTableMetadataSize, TENURED); | 1029 kWasmIndirectFunctionTableDataSize, TENURED); |
1272 metadata->set(kSize, Smi::FromInt(function_tables[i].size)); | 1030 metadata->set(kSize, Smi::FromInt(function_tables[i].size)); |
1273 metadata->set(kTable, *values); | 1031 metadata->set(kTable, *values); |
1274 indirect_table.ToHandleChecked()->set(i, *metadata); | 1032 indirect_table.ToHandleChecked()->set(i, *metadata); |
1275 } | 1033 } |
1276 | 1034 |
1277 HistogramTimerScope wasm_compile_module_time_scope( | 1035 HistogramTimerScope wasm_compile_module_time_scope( |
1278 isolate->counters()->wasm_compile_module_time()); | 1036 isolate->counters()->wasm_compile_module_time()); |
1279 | 1037 |
1280 ModuleEnv module_env; | 1038 ModuleEnv module_env; |
1281 module_env.module = this; | 1039 module_env.module = this; |
1282 module_env.instance = &temp_instance_for_compilation; | 1040 module_env.instance = &temp_instance_for_compilation; |
1283 module_env.origin = origin; | 1041 module_env.origin = origin; |
1284 InitializePlaceholders(factory, &module_env.placeholders, functions.size()); | |
1285 | 1042 |
1286 Handle<FixedArray> compiled_functions = | 1043 // The {code_table} array contains import wrappers, functions, export |
1287 factory->NewFixedArray(static_cast<int>(functions.size()), TENURED); | 1044 // wrappers, and the start function wrapper. |
1045 int code_table_size = | |
1046 static_cast<int>(functions.size() + num_exported_functions); | |
1047 Handle<FixedArray> code_table = | |
1048 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); | |
1288 | 1049 |
1289 MaybeHandle<FixedArray> maybe_imports; | 1050 // Initialize the code table with placeholders. |
1290 if (import_table.size() > 0) { | 1051 for (uint32_t i = 0; i < functions.size(); i++) { |
1291 temp_instance_for_compilation.import_code.resize(import_table.size()); | 1052 Code::Kind kind = Code::WASM_FUNCTION; |
1292 Handle<FixedArray> imports = | 1053 if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION; |
1293 factory->NewFixedArray(static_cast<int>(import_table.size())); | 1054 Handle<Code> placeholder = CreatePlaceholder(factory, i, kind); |
1294 for (uint32_t i = 0; i < import_table.size(); ++i) { | 1055 code_table->set(static_cast<int>(i), *placeholder); |
1295 Handle<Code> placeholder = | 1056 temp_instance_for_compilation.function_code[i] = placeholder; |
1296 CreatePlaceholder(factory, i, Code::WASM_TO_JS_FUNCTION); | |
1297 temp_instance_for_compilation.import_code[i] = placeholder; | |
1298 imports->set(i, *placeholder); | |
1299 } | |
1300 maybe_imports = imports; | |
1301 } | 1057 } |
1058 | |
1302 isolate->counters()->wasm_functions_per_module()->AddSample( | 1059 isolate->counters()->wasm_functions_per_module()->AddSample( |
1303 static_cast<int>(functions.size())); | 1060 static_cast<int>(functions.size())); |
1304 if (FLAG_wasm_num_compilation_tasks != 0) { | 1061 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { |
1305 CompileInParallel(isolate, this, | 1062 CompileInParallel(isolate, this, |
1306 temp_instance_for_compilation.function_code, thrower, | 1063 temp_instance_for_compilation.function_code, thrower, |
1307 &module_env); | 1064 &module_env); |
1308 } else { | 1065 } else { |
1309 CompileSequentially(isolate, this, | 1066 CompileSequentially(isolate, this, |
1310 temp_instance_for_compilation.function_code, thrower, | 1067 temp_instance_for_compilation.function_code, thrower, |
1311 &module_env); | 1068 &module_env); |
1312 } | 1069 } |
1313 if (thrower->error()) return nothing; | 1070 if (thrower->error()) return nothing; |
1314 | 1071 |
1315 // At this point, compilation has completed. Update the code table. | 1072 // At this point, compilation has completed. Update the code table. |
1316 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 1073 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
1317 i < temp_instance_for_compilation.function_code.size(); ++i) { | 1074 i < temp_instance_for_compilation.function_code.size(); ++i) { |
1318 Code* code = *temp_instance_for_compilation.function_code[i]; | 1075 Code* code = *temp_instance_for_compilation.function_code[i]; |
1319 compiled_functions->set(static_cast<int>(i), code); | 1076 code_table->set(static_cast<int>(i), code); |
1320 } | 1077 } |
1321 | 1078 |
1322 LinkModuleFunctions(isolate, compiled_functions); | 1079 // Link the functions in the module. |
1323 | 1080 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
1324 // TODO(mtrofin): do we need to flush the cache here? | 1081 i < temp_instance_for_compilation.function_code.size(); ++i) { |
1325 FlushAssemblyCache(isolate, compiled_functions); | 1082 Handle<Code> code = temp_instance_for_compilation.function_code[i]; |
1083 bool modified = | |
1084 LinkFunction(code, temp_instance_for_compilation.function_code); | |
1085 if (modified) { | |
1086 // TODO(mtrofin): do we need to flush the cache here? | |
1087 Assembler::FlushICache(isolate, code->instruction_start(), | |
1088 code->instruction_size()); | |
1089 } | |
1090 } | |
1326 | 1091 |
1327 // Create the compiled module object, and populate with compiled functions | 1092 // Create the compiled module object, and populate with compiled functions |
1328 // and information needed at instantiation time. This object needs to be | 1093 // and information needed at instantiation time. This object needs to be |
1329 // serializable. Instantiation may occur off a deserialized version of this | 1094 // serializable. Instantiation may occur off a deserialized version of this |
1330 // object. | 1095 // object. |
1331 Handle<FixedArray> ret = | 1096 Handle<FixedArray> ret = |
1332 factory->NewFixedArray(kCompiledWasmObjectTableSize, TENURED); | 1097 factory->NewFixedArray(kCompiledWasmObjectTableSize, TENURED); |
1333 ret->set(kFunctions, *compiled_functions); | 1098 ret->set(kCodeTable, *code_table); |
1334 if (!indirect_table.is_null()) { | 1099 if (!indirect_table.is_null()) { |
1335 ret->set(kTableOfIndirectFunctionTables, *indirect_table.ToHandleChecked()); | 1100 ret->set(kTableOfIndirectFunctionTables, *indirect_table.ToHandleChecked()); |
1336 } | 1101 } |
1337 if (!maybe_imports.is_null()) { | 1102 Handle<FixedArray> import_data = GetImportsData(factory, this); |
1338 ret->set(kImportMap, *maybe_imports.ToHandleChecked()); | |
1339 } | |
1340 Handle<FixedArray> import_data = GetImportsMetadata(factory, this); | |
1341 ret->set(kImportData, *import_data); | 1103 ret->set(kImportData, *import_data); |
1342 | 1104 |
1343 // Compile export functions. | 1105 // Compile exported function wrappers. |
1344 int export_size = static_cast<int>(export_table.size()); | 1106 int export_size = static_cast<int>(num_exported_functions); |
1345 Handle<Code> startup_fct; | |
1346 if (export_size > 0) { | 1107 if (export_size > 0) { |
1347 Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED); | 1108 Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED); |
1348 for (int i = 0; i < export_size; ++i) { | 1109 int index = -1; |
1349 Handle<FixedArray> export_metadata = | 1110 |
1350 factory->NewFixedArray(kWasmExportMetadataTableSize, TENURED); | 1111 for (const WasmExport& exp : export_table) { |
1351 const WasmExport& exp = export_table[i]; | 1112 if (exp.kind != kExternalFunction) |
1352 FunctionSig* funcSig = functions[exp.func_index].sig; | 1113 continue; // skip non-function exports. |
1114 index++; | |
1115 Handle<FixedArray> export_data = | |
1116 factory->NewFixedArray(kWasmExportDataTableSize, TENURED); | |
1117 FunctionSig* funcSig = functions[exp.index].sig; | |
1353 Handle<ByteArray> exportedSig = | 1118 Handle<ByteArray> exportedSig = |
1354 factory->NewByteArray(static_cast<int>(funcSig->parameter_count() + | 1119 factory->NewByteArray(static_cast<int>(funcSig->parameter_count() + |
1355 funcSig->return_count()), | 1120 funcSig->return_count()), |
1356 TENURED); | 1121 TENURED); |
1357 exportedSig->copy_in(0, | 1122 exportedSig->copy_in(0, |
1358 reinterpret_cast<const byte*>(funcSig->raw_data()), | 1123 reinterpret_cast<const byte*>(funcSig->raw_data()), |
1359 exportedSig->length()); | 1124 exportedSig->length()); |
1360 export_metadata->set(kExportedSignature, *exportedSig); | 1125 export_data->set(kExportedSignature, *exportedSig); |
1361 WasmName str = GetName(exp.name_offset, exp.name_length); | 1126 WasmName str = GetName(exp.name_offset, exp.name_length); |
1362 Handle<String> name = factory->InternalizeUtf8String(str); | 1127 Handle<String> name = factory->InternalizeUtf8String(str); |
1363 Handle<Code> code = | 1128 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, exp.index); |
1364 temp_instance_for_compilation.function_code[exp.func_index]; | |
1365 Handle<Code> export_code = compiler::CompileJSToWasmWrapper( | 1129 Handle<Code> export_code = compiler::CompileJSToWasmWrapper( |
1366 isolate, &module_env, code, exp.func_index); | 1130 isolate, &module_env, code, exp.index); |
1367 if (thrower->error()) return nothing; | 1131 if (thrower->error()) return nothing; |
1368 export_metadata->set(kExportCode, *export_code); | 1132 export_data->set(kExportName, *name); |
1369 export_metadata->set(kExportName, *name); | 1133 export_data->set(kExportArity, |
1370 export_metadata->set( | 1134 Smi::FromInt(static_cast<int>( |
1371 kExportArity, Smi::FromInt(static_cast<int>( | 1135 functions[exp.index].sig->parameter_count()))); |
1372 functions[exp.func_index].sig->parameter_count()))); | 1136 export_data->set(kExportedFunctionIndex, |
1373 export_metadata->set(kExportedFunctionIndex, | 1137 Smi::FromInt(static_cast<int>(exp.index))); |
1374 Smi::FromInt(static_cast<int>(exp.func_index))); | 1138 exports->set(index, *export_data); |
1375 exports->set(i, *export_metadata); | 1139 code_table->set(static_cast<int>(functions.size() + index), *export_code); |
1376 if (exp.func_index == start_function_index) { | |
1377 startup_fct = export_code; | |
1378 } | |
1379 } | 1140 } |
1380 ret->set(kExports, *exports); | 1141 ret->set(kExportData, *exports); |
1381 } | 1142 } |
1382 | 1143 |
1383 // Compile startup function, if we haven't already. | 1144 // Record data for startup function. |
1384 if (start_function_index >= 0) { | 1145 if (start_function_index >= 0) { |
1385 uint32_t index = static_cast<uint32_t>(start_function_index); | |
1386 HandleScope scope(isolate); | 1146 HandleScope scope(isolate); |
1387 if (startup_fct.is_null()) { | 1147 Handle<FixedArray> startup_data = |
1388 Handle<Code> code = temp_instance_for_compilation.function_code[index]; | 1148 factory->NewFixedArray(kWasmExportDataTableSize, TENURED); |
1389 DCHECK_EQ(0, functions[index].sig->parameter_count()); | 1149 startup_data->set(kExportArity, Smi::FromInt(0)); |
1390 startup_fct = | 1150 startup_data->set(kExportedFunctionIndex, |
1391 compiler::CompileJSToWasmWrapper(isolate, &module_env, code, index); | 1151 Smi::FromInt(start_function_index)); |
1392 } | 1152 ret->set(kStartupData, *startup_data); |
1393 Handle<FixedArray> metadata = | |
1394 factory->NewFixedArray(kWasmExportMetadataTableSize, TENURED); | |
1395 metadata->set(kExportCode, *startup_fct); | |
1396 metadata->set(kExportArity, Smi::FromInt(0)); | |
1397 metadata->set(kExportedFunctionIndex, Smi::FromInt(start_function_index)); | |
1398 ret->set(kStartupFunction, *metadata); | |
1399 } | 1153 } |
1400 | 1154 |
1401 // TODO(wasm): saving the module bytes for debugging is wasteful. We should | 1155 // TODO(wasm): saving the module bytes for debugging is wasteful. We should |
1402 // consider downloading this on-demand. | 1156 // consider downloading this on-demand. |
1403 { | 1157 { |
1404 size_t module_bytes_len = module_end - module_start; | 1158 size_t module_bytes_len = module_end - module_start; |
1405 DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt)); | 1159 DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt)); |
1406 Vector<const uint8_t> module_bytes_vec(module_start, | 1160 Vector<const uint8_t> module_bytes_vec(module_start, |
1407 static_cast<int>(module_bytes_len)); | 1161 static_cast<int>(module_bytes_len)); |
1408 Handle<String> module_bytes_string = | 1162 Handle<String> module_bytes_string = |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1468 ->GetValueChecked<FixedArray>(isolate, kTable); | 1222 ->GetValueChecked<FixedArray>(isolate, kTable); |
1469 for (int fct_index = 0; fct_index < wasm_functions->length(); ++fct_index) { | 1223 for (int fct_index = 0; fct_index < wasm_functions->length(); ++fct_index) { |
1470 Handle<Code> wasm_function = | 1224 Handle<Code> wasm_function = |
1471 wasm_functions->GetValueChecked<Code>(isolate, fct_index); | 1225 wasm_functions->GetValueChecked<Code>(isolate, fct_index); |
1472 PatchFunctionTable(wasm_function, table_to_replace, cloned_table); | 1226 PatchFunctionTable(wasm_function, table_to_replace, cloned_table); |
1473 } | 1227 } |
1474 } | 1228 } |
1475 return cloned_indirect_tables; | 1229 return cloned_indirect_tables; |
1476 } | 1230 } |
1477 | 1231 |
1478 Handle<FixedArray> CloneModuleForInstance(Isolate* isolate, | 1232 // Instantiates a WASM module, creating a WebAssembly.Instance from a |
1479 Handle<JSObject> module_object, | 1233 // WebAssembly.Module. |
1480 bool* template_is_owned, | |
1481 Handle<FixedArray>* module_template) { | |
1482 Factory* factory = isolate->factory(); | |
1483 | |
1484 Handle<FixedArray> original; | |
1485 for (int i = 0; i < 2; ++i) { | |
1486 original = handle(FixedArray::cast(module_object->GetInternalField(0))); | |
1487 if (GetOwningInstance(*original) == nullptr) { | |
1488 *template_is_owned = false; | |
1489 *module_template = original; | |
1490 return original; | |
1491 } | |
1492 if (i < 1) { | |
1493 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | |
1494 GarbageCollectionReason::kRuntime); | |
1495 } | |
1496 } | |
1497 *template_is_owned = true; | |
1498 *module_template = original; | |
1499 | |
1500 // We insert the latest clone in front. | |
1501 Handle<FixedArray> clone = factory->CopyFixedArray(original); | |
1502 Handle<WeakCell> weak_link_to_wasm_obj = | |
1503 original->GetValueChecked<WeakCell>(isolate, kModuleObject); | |
1504 | |
1505 clone->set(kModuleObject, *weak_link_to_wasm_obj); | |
1506 Handle<WeakCell> link_to_original = factory->NewWeakCell(original); | |
1507 clone->set(kNextInstance, *link_to_original); | |
1508 Handle<WeakCell> link_to_clone = factory->NewWeakCell(clone); | |
1509 original->set(kPrevInstance, *link_to_clone); | |
1510 JSObject::cast(weak_link_to_wasm_obj->value())->SetInternalField(0, *clone); | |
1511 | |
1512 // Clone each wasm code object. | |
1513 Handle<FixedArray> orig_wasm_functions = | |
1514 original->GetValueChecked<FixedArray>(isolate, kFunctions); | |
1515 Handle<FixedArray> clone_wasm_functions = | |
1516 factory->CopyFixedArray(orig_wasm_functions); | |
1517 clone->set(kFunctions, *clone_wasm_functions); | |
1518 for (int i = 0; i < clone_wasm_functions->length(); ++i) { | |
1519 Handle<Code> orig_code = | |
1520 clone_wasm_functions->GetValueChecked<Code>(isolate, i); | |
1521 Handle<Code> cloned_code = factory->CopyCode(orig_code); | |
1522 clone_wasm_functions->set(i, *cloned_code); | |
1523 } | |
1524 | |
1525 MaybeHandle<FixedArray> maybe_orig_exports = | |
1526 original->GetValue<FixedArray>(isolate, kExports); | |
1527 Handle<FixedArray> orig_exports; | |
1528 if (maybe_orig_exports.ToHandle(&orig_exports)) { | |
1529 Handle<FixedArray> cloned_exports = factory->CopyFixedArray(orig_exports); | |
1530 clone->set(kExports, *cloned_exports); | |
1531 for (int i = 0; i < orig_exports->length(); ++i) { | |
1532 Handle<FixedArray> export_metadata = | |
1533 orig_exports->GetValueChecked<FixedArray>(isolate, i); | |
1534 Handle<FixedArray> clone_metadata = | |
1535 factory->CopyFixedArray(export_metadata); | |
1536 cloned_exports->set(i, *clone_metadata); | |
1537 Handle<Code> orig_code = | |
1538 export_metadata->GetValueChecked<Code>(isolate, kExportCode); | |
1539 Handle<Code> cloned_code = factory->CopyCode(orig_code); | |
1540 clone_metadata->set(kExportCode, *cloned_code); | |
1541 // TODO(wasm): This is actually a uint32_t, but since FixedArray indexes | |
1542 // in int, we are taking the risk of invalid values. | |
1543 int exported_fct_index = | |
1544 Smi::cast(export_metadata->get(kExportedFunctionIndex))->value(); | |
1545 CHECK_GE(exported_fct_index, 0); | |
1546 CHECK_LT(exported_fct_index, clone_wasm_functions->length()); | |
1547 Handle<Code> new_target = clone_wasm_functions->GetValueChecked<Code>( | |
1548 isolate, exported_fct_index); | |
1549 PatchJSWrapper(isolate, cloned_code, new_target); | |
1550 } | |
1551 } | |
1552 | |
1553 MaybeHandle<FixedArray> maybe_startup = | |
1554 original->GetValue<FixedArray>(isolate, kStartupFunction); | |
1555 if (!maybe_startup.is_null()) { | |
1556 Handle<FixedArray> startup_metadata = | |
1557 factory->CopyFixedArray(maybe_startup.ToHandleChecked()); | |
1558 Handle<Code> startup_fct_clone = factory->CopyCode( | |
1559 startup_metadata->GetValueChecked<Code>(isolate, kExportCode)); | |
1560 startup_metadata->set(kExportCode, *startup_fct_clone); | |
1561 clone->set(kStartupFunction, *startup_metadata); | |
1562 // TODO(wasm): see todo above about int vs size_t indexing in FixedArray. | |
1563 int startup_fct_index = | |
1564 Smi::cast(startup_metadata->get(kExportedFunctionIndex))->value(); | |
1565 CHECK_GE(startup_fct_index, 0); | |
1566 CHECK_LT(startup_fct_index, clone_wasm_functions->length()); | |
1567 Handle<Code> new_target = | |
1568 clone_wasm_functions->GetValueChecked<Code>(isolate, startup_fct_index); | |
1569 PatchJSWrapper(isolate, startup_fct_clone, new_target); | |
1570 } | |
1571 clone->set(kImportMap, *isolate->factory()->undefined_value()); | |
1572 return clone; | |
1573 } | |
1574 | |
1575 // Instantiates a wasm module as a JSObject. | |
1576 // * allocates a backing store of {mem_size} bytes. | |
1577 // * installs a named property "memory" for that buffer if exported | |
1578 // * installs named properties on the object for exported functions | |
1579 // * compiles wasm code to machine code | |
1580 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, | 1234 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, |
1581 Handle<JSObject> module_object, | 1235 Handle<JSObject> module_object, |
1582 Handle<JSReceiver> ffi, | 1236 Handle<JSReceiver> ffi, |
1583 Handle<JSArrayBuffer> memory) { | 1237 Handle<JSArrayBuffer> memory) { |
1238 MaybeHandle<JSObject> nothing; | |
1584 HistogramTimerScope wasm_instantiate_module_time_scope( | 1239 HistogramTimerScope wasm_instantiate_module_time_scope( |
1585 isolate->counters()->wasm_instantiate_module_time()); | 1240 isolate->counters()->wasm_instantiate_module_time()); |
1586 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); | 1241 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
1587 Factory* factory = isolate->factory(); | 1242 Factory* factory = isolate->factory(); |
1588 | 1243 |
1589 bool template_is_owned = false; | 1244 //-------------------------------------------------------------------------- |
1590 Handle<FixedArray> compiled_module_template; | 1245 // Reuse the compiled module (if no owner), otherwise clone. |
1591 Handle<FixedArray> compiled_module = CloneModuleForInstance( | 1246 //-------------------------------------------------------------------------- |
1592 isolate, module_object, &template_is_owned, &compiled_module_template); | 1247 Handle<FixedArray> compiled_module; |
1593 | 1248 Handle<FixedArray> code_table; |
1594 MaybeHandle<JSObject> template_owner; | 1249 Handle<FixedArray> old_code_table; |
1595 if (template_is_owned) { | 1250 Handle<JSObject> owner; |
1596 Handle<WeakCell> weak_owner = | 1251 { |
1597 compiled_module_template->GetValueChecked<WeakCell>(isolate, | 1252 Handle<FixedArray> original( |
1598 kOwningInstance); | 1253 FixedArray::cast(module_object->GetInternalField(0)), isolate); |
1599 template_owner = handle(JSObject::cast(weak_owner->value())); | 1254 // Always make a new copy of the code_table, since the old_code_table |
1600 } | 1255 // may still have placeholders for imports. |
1601 // These fields are compulsory. | 1256 old_code_table = original->GetValueChecked<FixedArray>(isolate, kCodeTable); |
1602 Handle<FixedArray> code_table = | 1257 code_table = factory->CopyFixedArray(old_code_table); |
1603 compiled_module->GetValueChecked<FixedArray>(isolate, kFunctions); | 1258 |
1604 | 1259 WeakCell* tmp = GetOwningInstance(*original); |
1605 RecordStats(isolate, code_table); | 1260 if (tmp != nullptr) { |
1606 | 1261 // There is already an owner, clone everything. |
Mircea Trofin
2016/09/15 15:12:22
See go/wasminstantiation. You need to GC if it's n
| |
1607 MaybeHandle<JSObject> nothing; | 1262 owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate); |
1608 | 1263 // Insert the latest clone in front. |
1264 compiled_module = factory->CopyFixedArray(original); | |
1265 Handle<WeakCell> weak_link_to_wasm_obj = | |
1266 original->GetValueChecked<WeakCell>(isolate, kModuleObject); | |
1267 | |
1268 compiled_module->set(kModuleObject, *weak_link_to_wasm_obj); | |
1269 Handle<WeakCell> link_to_original = factory->NewWeakCell(original); | |
1270 compiled_module->set(kNextInstance, *link_to_original); | |
1271 Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module); | |
1272 original->set(kPrevInstance, *link_to_clone); | |
1273 JSObject::cast(weak_link_to_wasm_obj->value()) | |
1274 ->SetInternalField(0, *compiled_module); | |
1275 | |
1276 // Clone the code for WASM functions and exports. | |
1277 for (int i = 0; i < code_table->length(); ++i) { | |
1278 Handle<Code> orig_code = code_table->GetValueChecked<Code>(isolate, i); | |
1279 switch (orig_code->kind()) { | |
1280 case Code::WASM_TO_JS_FUNCTION: | |
1281 // Imports will be overwritten with newly compiled wrappers. | |
1282 break; | |
1283 case Code::JS_TO_WASM_FUNCTION: | |
1284 case Code::WASM_FUNCTION: | |
1285 code_table->set(i, *factory->CopyCode(orig_code)); | |
1286 break; | |
1287 default: | |
1288 UNREACHABLE(); | |
1289 } | |
1290 } | |
1291 RecordStats(isolate, code_table); | |
1292 } else { | |
1293 // There was no owner, so we can reuse the original. | |
1294 compiled_module = original; | |
1295 } | |
1296 compiled_module->set(kCodeTable, *code_table); | |
1297 } | |
1298 | |
1299 //-------------------------------------------------------------------------- | |
1300 // Allocate the instance object. | |
1301 //-------------------------------------------------------------------------- | |
1609 Handle<Map> map = factory->NewMap( | 1302 Handle<Map> map = factory->NewMap( |
1610 JS_OBJECT_TYPE, | 1303 JS_OBJECT_TYPE, |
1611 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); | 1304 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); |
1612 Handle<JSObject> js_object = factory->NewJSObjectFromMap(map, TENURED); | 1305 Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED); |
1613 js_object->SetInternalField(kWasmModuleCodeTable, *code_table); | 1306 instance->SetInternalField(kWasmModuleCodeTable, *code_table); |
1614 | 1307 |
1615 // Remember the old imports, for the case when we are at the first instance - | 1308 //-------------------------------------------------------------------------- |
1616 // they will be replaced with the instance's actual imports in SetupImports. | 1309 // Set up the memory for the new module. |
1617 MaybeHandle<FixedArray> old_imports = | 1310 //-------------------------------------------------------------------------- |
Mircea Trofin
2016/09/15 15:12:22
I'm worried about it all being in one place, and e
| |
1618 compiled_module_template->GetValue<FixedArray>(isolate, kImportMap); | 1311 MaybeHandle<JSArrayBuffer> old_memory; |
1619 if (!(SetupInstanceHeap(isolate, compiled_module, js_object, memory, | 1312 // TODO(titzer): handle imported memory properly. |
1620 &thrower) && | 1313 |
1621 SetupGlobals(isolate, template_owner, compiled_module, js_object, | 1314 uint32_t min_mem_pages = static_cast<uint32_t>( |
1622 &thrower) && | 1315 Smi::cast(compiled_module->get(kMinRequiredMemory))->value()); |
1623 SetupImports(isolate, compiled_module, js_object, &thrower, ffi) && | 1316 isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); |
1624 SetupExportsObject(compiled_module, isolate, js_object, &thrower))) { | 1317 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. |
1625 return nothing; | 1318 |
1626 } | 1319 if (memory.is_null() && min_mem_pages > 0) { |
1627 | 1320 memory = AllocateMemory(&thrower, isolate, min_mem_pages); |
1628 FixupFunctionsAndImports( | 1321 if (memory.is_null()) return nothing; // failed to allocate memory |
1629 compiled_module_template->GetValueChecked<FixedArray>(isolate, | 1322 } |
1630 kFunctions), | 1323 |
1631 code_table, old_imports, | 1324 if (!memory.is_null()) { |
1632 compiled_module->GetValue<FixedArray>(isolate, kImportMap)); | 1325 instance->SetInternalField(kWasmMemArrayBuffer, *memory); |
1633 | 1326 Address mem_start = static_cast<Address>(memory->backing_store()); |
1634 SetDebugSupport(factory, compiled_module, js_object); | 1327 uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number()); |
1635 SetRuntimeSupport(isolate, js_object); | 1328 LoadDataSegments(compiled_module, mem_start, mem_size); |
1636 | 1329 |
1637 FlushAssemblyCache(isolate, code_table); | 1330 uint32_t old_mem_size = static_cast<uint32_t>( |
1638 | 1331 compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize) |
1332 ->value()); | |
1333 MaybeHandle<JSArrayBuffer> old_mem = | |
1334 compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart); | |
1335 Address old_mem_start = | |
1336 old_mem.is_null() | |
1337 ? nullptr | |
1338 : static_cast<Address>(old_mem.ToHandleChecked()->backing_store()); | |
1339 RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size, | |
1340 mem_size); | |
1341 compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize) | |
1342 ->set_value(static_cast<double>(mem_size)); | |
1343 compiled_module->set(kMemStart, *memory); | |
1344 } | |
1345 | |
1346 //-------------------------------------------------------------------------- | |
1347 // Set up the globals for the new module. | |
1348 //-------------------------------------------------------------------------- | |
1349 MaybeHandle<JSArrayBuffer> old_globals; | |
1350 MaybeHandle<JSArrayBuffer> globals; | |
1351 uint32_t globals_size = static_cast<uint32_t>( | |
1352 Smi::cast(compiled_module->get(kGlobalsSize))->value()); | |
1353 if (globals_size > 0) { | |
1354 Handle<JSArrayBuffer> global_buffer = NewArrayBuffer(isolate, globals_size); | |
1355 globals = global_buffer; | |
1356 if (globals.is_null()) { | |
1357 thrower.Error("Out of memory: wasm globals"); | |
1358 return nothing; | |
1359 } | |
1360 Address old_address = | |
1361 owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate( | |
1362 *isolate->factory()->undefined_value(), | |
1363 JSObject::cast(*owner)); | |
1364 RelocateGlobals(instance, old_address, | |
1365 static_cast<Address>(global_buffer->backing_store())); | |
1366 instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer); | |
1367 } | |
1368 | |
1369 //-------------------------------------------------------------------------- | |
1370 // Compile the import wrappers for the new module. | |
1371 //-------------------------------------------------------------------------- | |
1372 // TODO(titzer): handle imported globals and function tables. | |
1373 Handle<FixedArray> import_data; | |
1374 int num_imported_functions = 0; | |
1375 if (compiled_module->GetValue<FixedArray>(isolate, kImportData) | |
1376 .ToHandle(&import_data)) { | |
1377 num_imported_functions = import_data->length(); | |
1378 for (int index = 0; index < num_imported_functions; index++) { | |
1379 Handle<Code> import_wrapper = | |
1380 CompileImportWrapper(isolate, ffi, index, import_data, &thrower); | |
1381 if (thrower.error()) return nothing; | |
1382 code_table->set(index, *import_wrapper); | |
1383 RecordStats(isolate, *import_wrapper); | |
1384 } | |
1385 } | |
1386 | |
1387 //-------------------------------------------------------------------------- | |
1388 // Set up the debug support for the new module. | |
1389 //-------------------------------------------------------------------------- | |
1390 MaybeHandle<String> module_bytes_string = | |
1391 compiled_module->GetValue<String>(isolate, kModuleBytes); | |
1392 if (!module_bytes_string.is_null()) { | |
1393 instance->SetInternalField(kWasmModuleBytesString, | |
1394 *module_bytes_string.ToHandleChecked()); | |
1395 } | |
1396 | |
1397 MaybeHandle<ByteArray> function_name_table = | |
1398 compiled_module->GetValue<ByteArray>(isolate, kFunctionNameTable); | |
1399 if (!function_name_table.is_null()) { | |
1400 instance->SetInternalField(kWasmFunctionNamesArray, | |
1401 *function_name_table.ToHandleChecked()); | |
1402 } | |
1403 | |
1404 instance->SetInternalField(kWasmNumImportedFunctions, | |
1405 *factory->NewNumber(num_imported_functions)); | |
1406 | |
1407 //-------------------------------------------------------------------------- | |
1408 // Set up the runtime support for the new module. | |
1409 //-------------------------------------------------------------------------- | |
1410 Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(instance); | |
1411 | |
1412 for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs; | |
1413 i < code_table->length(); ++i) { | |
1414 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | |
1415 if (code->kind() == Code::WASM_FUNCTION) { | |
1416 Handle<FixedArray> deopt_data = | |
1417 isolate->factory()->NewFixedArray(2, TENURED); | |
1418 deopt_data->set(0, *weak_link); | |
1419 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); | |
1420 deopt_data->set_length(2); | |
1421 code->set_deoptimization_data(*deopt_data); | |
1422 } | |
1423 } | |
1424 | |
1425 //-------------------------------------------------------------------------- | |
1426 // Set up the indirect function tables for the new module. | |
1427 //-------------------------------------------------------------------------- | |
1639 { | 1428 { |
1640 std::vector<Handle<Code>> functions( | 1429 std::vector<Handle<Code>> functions( |
1641 static_cast<size_t>(code_table->length())); | 1430 static_cast<size_t>(code_table->length())); |
1642 for (int i = 0; i < code_table->length(); ++i) { | 1431 for (int i = 0; i < code_table->length(); ++i) { |
1643 functions[static_cast<size_t>(i)] = | 1432 functions[i] = code_table->GetValueChecked<Code>(isolate, i); |
1644 code_table->GetValueChecked<Code>(isolate, i); | |
1645 } | 1433 } |
1646 | 1434 |
1647 MaybeHandle<FixedArray> maybe_indirect_tables = | 1435 MaybeHandle<FixedArray> maybe_indirect_tables = |
1648 compiled_module->GetValue<FixedArray>(isolate, | 1436 compiled_module->GetValue<FixedArray>(isolate, |
1649 kTableOfIndirectFunctionTables); | 1437 kTableOfIndirectFunctionTables); |
1650 Handle<FixedArray> indirect_tables_template; | 1438 Handle<FixedArray> indirect_tables_template; |
1651 if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) { | 1439 if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) { |
1652 Handle<FixedArray> to_replace = | 1440 Handle<FixedArray> to_replace = |
1653 template_owner.is_null() | 1441 owner.is_null() ? indirect_tables_template |
1654 ? indirect_tables_template | 1442 : handle(FixedArray::cast(owner->GetInternalField( |
1655 : handle(FixedArray::cast( | 1443 kWasmModuleFunctionTable))); |
1656 template_owner.ToHandleChecked()->GetInternalField( | |
1657 kWasmModuleFunctionTable))); | |
1658 Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable( | 1444 Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable( |
1659 isolate, code_table, indirect_tables_template, to_replace); | 1445 isolate, code_table, indirect_tables_template, to_replace); |
1660 for (int i = 0; i < indirect_tables->length(); ++i) { | 1446 for (int i = 0; i < indirect_tables->length(); ++i) { |
1661 Handle<FixedArray> metadata = | 1447 Handle<FixedArray> metadata = |
1662 indirect_tables->GetValueChecked<FixedArray>(isolate, i); | 1448 indirect_tables->GetValueChecked<FixedArray>(isolate, i); |
1663 uint32_t size = Smi::cast(metadata->get(kSize))->value(); | 1449 uint32_t size = Smi::cast(metadata->get(kSize))->value(); |
1664 Handle<FixedArray> table = | 1450 Handle<FixedArray> table = |
1665 metadata->GetValueChecked<FixedArray>(isolate, kTable); | 1451 metadata->GetValueChecked<FixedArray>(isolate, kTable); |
1666 wasm::PopulateFunctionTable(table, size, &functions); | 1452 wasm::PopulateFunctionTable(table, size, &functions); |
1667 } | 1453 } |
1668 js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); | 1454 instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); |
1669 } | 1455 } |
1670 } | 1456 } |
1671 | 1457 |
1458 //-------------------------------------------------------------------------- | |
1459 // Set up the exports for the object. | |
1460 //-------------------------------------------------------------------------- | |
1461 bool mem_export = | |
1462 static_cast<bool>(Smi::cast(compiled_module->get(kExportMem))->value()); | |
1463 ModuleOrigin origin = static_cast<ModuleOrigin>( | |
1464 Smi::cast(compiled_module->get(kOrigin))->value()); | |
1465 | |
1466 MaybeHandle<FixedArray> maybe_exports = | |
1467 compiled_module->GetValue<FixedArray>(isolate, kExportData); | |
1468 if (!maybe_exports.is_null() || mem_export) { | |
1469 PropertyDescriptor desc; | |
1470 desc.set_writable(false); | |
1471 | |
1472 Handle<JSObject> exports_object = instance; | |
1473 if (origin == kWasmOrigin) { | |
1474 // Create the "exports" object. | |
1475 Handle<JSFunction> object_function = Handle<JSFunction>( | |
1476 isolate->native_context()->object_function(), isolate); | |
1477 exports_object = factory->NewJSObject(object_function, TENURED); | |
1478 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); | |
1479 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); | |
1480 } | |
1481 Handle<FixedArray> exports; | |
1482 int first_export = -1; | |
1483 // TODO(wasm): another iteration over the code objects. | |
1484 for (int i = 0; i < code_table->length(); i++) { | |
1485 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | |
1486 if (code->kind() == Code::JS_TO_WASM_FUNCTION) { | |
1487 first_export = i; | |
1488 break; | |
1489 } | |
1490 } | |
1491 if (maybe_exports.ToHandle(&exports)) { | |
1492 int export_size = exports->length(); | |
1493 for (int i = 0; i < export_size; ++i) { | |
1494 Handle<FixedArray> export_data = | |
1495 exports->GetValueChecked<FixedArray>(isolate, i); | |
1496 Handle<String> name = | |
1497 export_data->GetValueChecked<String>(isolate, kExportName); | |
1498 int arity = Smi::cast(export_data->get(kExportArity))->value(); | |
1499 MaybeHandle<ByteArray> signature = | |
1500 export_data->GetValue<ByteArray>(isolate, kExportedSignature); | |
1501 Handle<Code> export_code = | |
1502 code_table->GetValueChecked<Code>(isolate, first_export + i); | |
1503 Handle<JSFunction> function = WrapExportCodeAsJSFunction( | |
1504 isolate, export_code, name, arity, signature, instance); | |
1505 desc.set_value(function); | |
1506 Maybe<bool> status = JSReceiver::DefineOwnProperty( | |
1507 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); | |
1508 if (!status.IsJust()) { | |
1509 thrower.Error("export of %.*s failed.", name->length(), | |
1510 name->ToCString().get()); | |
1511 return nothing; | |
1512 } | |
1513 } | |
1514 } | |
1515 if (mem_export) { | |
1516 // Export the memory as a named property. | |
1517 Handle<String> name = factory->InternalizeUtf8String("memory"); | |
1518 Handle<JSArrayBuffer> memory = Handle<JSArrayBuffer>( | |
1519 JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer))); | |
1520 JSObject::AddProperty(exports_object, name, memory, READ_ONLY); | |
1521 } | |
1522 } | |
1523 | |
1524 if (num_imported_functions > 0 || !owner.is_null()) { | |
1525 // If the code was cloned, or new imports were compiled, patch. | |
1526 PatchDirectCalls(old_code_table, code_table, num_imported_functions); | |
1527 } | |
1528 | |
1529 FlushICache(isolate, code_table); | |
1530 | |
1531 //-------------------------------------------------------------------------- | |
1672 // Run the start function if one was specified. | 1532 // Run the start function if one was specified. |
1673 MaybeHandle<FixedArray> maybe_startup_fct = | 1533 //-------------------------------------------------------------------------- |
1674 compiled_module->GetValue<FixedArray>(isolate, kStartupFunction); | 1534 Handle<FixedArray> startup_data; |
1675 Handle<FixedArray> metadata; | 1535 if (compiled_module->GetValue<FixedArray>(isolate, kStartupData) |
1676 if (maybe_startup_fct.ToHandle(&metadata)) { | 1536 .ToHandle(&startup_data)) { |
1677 HandleScope scope(isolate); | 1537 HandleScope scope(isolate); |
1538 int32_t start_index = | |
1539 startup_data->GetValueChecked<Smi>(isolate, kExportedFunctionIndex) | |
1540 ->value(); | |
1678 Handle<Code> startup_code = | 1541 Handle<Code> startup_code = |
1679 metadata->GetValueChecked<Code>(isolate, kExportCode); | 1542 code_table->GetValueChecked<Code>(isolate, start_index); |
1680 int arity = Smi::cast(metadata->get(kExportArity))->value(); | 1543 int arity = Smi::cast(startup_data->get(kExportArity))->value(); |
1681 MaybeHandle<ByteArray> startup_signature = | 1544 MaybeHandle<ByteArray> startup_signature = |
1682 metadata->GetValue<ByteArray>(isolate, kExportedSignature); | 1545 startup_data->GetValue<ByteArray>(isolate, kExportedSignature); |
1683 Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction( | 1546 Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction( |
1684 isolate, startup_code, factory->InternalizeUtf8String("start"), arity, | 1547 isolate, startup_code, factory->InternalizeUtf8String("start"), arity, |
1685 startup_signature, js_object); | 1548 startup_signature, instance); |
1686 RecordStats(isolate, *startup_code); | 1549 RecordStats(isolate, *startup_code); |
1687 // Call the JS function. | 1550 // Call the JS function. |
1688 Handle<Object> undefined = isolate->factory()->undefined_value(); | 1551 Handle<Object> undefined = isolate->factory()->undefined_value(); |
1689 MaybeHandle<Object> retval = | 1552 MaybeHandle<Object> retval = |
1690 Execution::Call(isolate, startup_fct, undefined, 0, nullptr); | 1553 Execution::Call(isolate, startup_fct, undefined, 0, nullptr); |
1691 | 1554 |
1692 if (retval.is_null()) { | 1555 if (retval.is_null()) { |
1693 thrower.Error("WASM.instantiateModule(): start function failed"); | 1556 thrower.Error("WASM.instantiateModule(): start function failed"); |
1694 return nothing; | 1557 return nothing; |
1695 } | 1558 } |
1696 } | 1559 } |
1697 | 1560 |
1698 DCHECK(wasm::IsWasmObject(*js_object)); | 1561 DCHECK(wasm::IsWasmObject(*instance)); |
1699 | 1562 |
1700 if (!compiled_module->GetValue<WeakCell>(isolate, kModuleObject).is_null()) { | 1563 if (!compiled_module->GetValue<WeakCell>(isolate, kModuleObject).is_null()) { |
1701 js_object->SetInternalField(kWasmCompiledModule, *compiled_module); | 1564 instance->SetInternalField(kWasmCompiledModule, *compiled_module); |
1702 Handle<WeakCell> link_to_owner = factory->NewWeakCell(js_object); | 1565 Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance); |
1703 compiled_module->set(kOwningInstance, *link_to_owner); | 1566 compiled_module->set(kOwningInstance, *link_to_owner); |
1704 | 1567 |
1705 Handle<Object> global_handle = | 1568 Handle<Object> global_handle = isolate->global_handles()->Create(*instance); |
1706 isolate->global_handles()->Create(*js_object); | |
1707 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), | 1569 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), |
1708 &InstanceFinalizer, | 1570 &InstanceFinalizer, |
1709 v8::WeakCallbackType::kFinalizer); | 1571 v8::WeakCallbackType::kFinalizer); |
1710 } | 1572 } |
1711 | 1573 |
1712 return js_object; | 1574 return instance; |
1713 } | |
1714 | |
1715 // TODO(mtrofin): remove this once we move to WASM_DIRECT_CALL | |
1716 Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const { | |
1717 DCHECK(IsValidFunction(index)); | |
1718 if (!placeholders.empty()) return placeholders[index]; | |
1719 DCHECK_NOT_NULL(instance); | |
1720 return instance->function_code[index]; | |
1721 } | |
1722 | |
1723 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { | |
1724 DCHECK(IsValidImport(index)); | |
1725 return instance ? instance->import_code[index] : Handle<Code>::null(); | |
1726 } | 1575 } |
1727 | 1576 |
1728 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, | 1577 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, |
1729 uint32_t index) { | 1578 uint32_t index) { |
1730 DCHECK(IsValidFunction(index)); | 1579 DCHECK(IsValidFunction(index)); |
1731 // Always make a direct call to whatever is in the table at that location. | 1580 // Always make a direct call to whatever is in the table at that location. |
1732 // A wrapper will be generated for FFI calls. | 1581 // A wrapper will be generated for FFI calls. |
1733 const WasmFunction* function = &module->functions[index]; | 1582 const WasmFunction* function = &module->functions[index]; |
1734 return GetWasmCallDescriptor(zone, function->sig); | 1583 return GetWasmCallDescriptor(zone, function->sig); |
1735 } | 1584 } |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1986 FixedArray* compiled_module = | 1835 FixedArray* compiled_module = |
1987 FixedArray::cast(instance->GetInternalField(kWasmCompiledModule)); | 1836 FixedArray::cast(instance->GetInternalField(kWasmCompiledModule)); |
1988 CHECK_NOT_NULL(GetModuleObject(compiled_module)); | 1837 CHECK_NOT_NULL(GetModuleObject(compiled_module)); |
1989 CHECK(GetModuleObject(compiled_module)->cleared()); | 1838 CHECK(GetModuleObject(compiled_module)->cleared()); |
1990 } | 1839 } |
1991 | 1840 |
1992 } // namespace testing | 1841 } // namespace testing |
1993 } // namespace wasm | 1842 } // namespace wasm |
1994 } // namespace internal | 1843 } // namespace internal |
1995 } // namespace v8 | 1844 } // namespace v8 |
OLD | NEW |