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