OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <memory> | 5 #include <memory> |
6 | 6 |
7 #include "src/base/atomic-utils.h" | 7 #include "src/base/atomic-utils.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 | 9 |
10 #include "src/macro-assembler.h" | 10 #include "src/macro-assembler.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 // TODO(clemensh): Remove function name array, extract names from module | 58 // TODO(clemensh): Remove function name array, extract names from module |
59 // bytes. | 59 // bytes. |
60 kWasmFunctionNamesArray, | 60 kWasmFunctionNamesArray, |
61 kWasmModuleBytesString, | 61 kWasmModuleBytesString, |
62 kWasmDebugInfo, | 62 kWasmDebugInfo, |
63 kWasmNumImportedFunctions, | 63 kWasmNumImportedFunctions, |
64 kWasmModuleInternalFieldCount | 64 kWasmModuleInternalFieldCount |
65 }; | 65 }; |
66 | 66 |
67 enum WasmImportData { | 67 enum WasmImportData { |
| 68 kImportKind, // Smi. an ExternalKind |
| 69 kImportGlobalType, // Smi. Type for globals. |
| 70 kImportIndex, // Smi. index for the import. |
68 kModuleName, // String | 71 kModuleName, // String |
69 kFunctionName, // maybe String | 72 kFunctionName, // maybe String |
70 kOutputCount, // Smi. an uint32_t | 73 kOutputCount, // Smi. an uint32_t |
71 kSignature, // ByteArray. A copy of the data in FunctionSig | 74 kSignature, // ByteArray. A copy of the data in FunctionSig |
72 kWasmImportDataSize // Sentinel value. | 75 kWasmImportDataSize // Sentinel value. |
73 }; | 76 }; |
74 | 77 |
75 enum WasmExportData { | 78 enum WasmExportData { |
76 kExportName, // String | 79 kExportKind, // Smi. an ExternalKind |
77 kExportArity, // Smi, an int | 80 kExportGlobalType, // Smi. Type for globals. |
78 kExportedFunctionIndex, // Smi, an uint32_t | 81 kExportName, // String |
79 kExportedSignature, // ByteArray. A copy of the data in FunctionSig | 82 kExportArity, // Smi, an int |
80 kWasmExportDataSize // Sentinel value. | 83 kExportIndex, // Smi, an uint32_t |
| 84 kExportedSignature, // ByteArray. A copy of the data in FunctionSig |
| 85 kWasmExportDataSize // Sentinel value. |
| 86 }; |
| 87 |
| 88 enum WasmGlobalInitData { |
| 89 kGlobalInitKind, // 0 = constant, 1 = global index |
| 90 kGlobalInitType, // Smi. Type for globals. |
| 91 kGlobalInitIndex, // Smi, an uint32_t |
| 92 kGlobalInitValue, // Number. |
| 93 kWasmGlobalInitDataSize |
81 }; | 94 }; |
82 | 95 |
83 enum WasmSegmentInfo { | 96 enum WasmSegmentInfo { |
84 kDestAddr, // Smi. an uint32_t | 97 kDestInitKind, // 0 = constant, 1 = global index |
| 98 kDestAddrValue, // Smi. an uint32_t |
85 kSourceSize, // Smi. an uint32_t | 99 kSourceSize, // Smi. an uint32_t |
86 kWasmSegmentInfoSize // Sentinel value. | 100 kWasmSegmentInfoSize // Sentinel value. |
87 }; | 101 }; |
88 | 102 |
89 enum WasmIndirectFunctionTableData { | 103 enum WasmIndirectFunctionTableData { |
90 kSize, // Smi. an uint32_t | 104 kSize, // Smi. an uint32_t |
91 kTable, // FixedArray of indirect function table | 105 kTable, // FixedArray of indirect function table |
92 kWasmIndirectFunctionTableDataSize // Sentinel value. | 106 kWasmIndirectFunctionTableDataSize // Sentinel value. |
93 }; | 107 }; |
94 | 108 |
| 109 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) { |
| 110 return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset; |
| 111 } |
| 112 |
95 uint32_t GetMinModuleMemSize(const WasmModule* module) { | 113 uint32_t GetMinModuleMemSize(const WasmModule* module) { |
96 return WasmModule::kPageSize * module->min_mem_pages; | 114 return WasmModule::kPageSize * module->min_mem_pages; |
97 } | 115 } |
98 | 116 |
99 void LoadDataSegments(Handle<WasmCompiledModule> compiled_module, | |
100 Address mem_addr, size_t mem_size) { | |
101 CHECK(compiled_module->has_data_segments() == | |
102 compiled_module->has_data_segments_info()); | |
103 | |
104 // If we have neither, we're done. | |
105 if (!compiled_module->has_data_segments()) return; | |
106 | |
107 Handle<ByteArray> data = compiled_module->data_segments(); | |
108 Handle<FixedArray> segments = compiled_module->data_segments_info(); | |
109 | |
110 uint32_t last_extraction_pos = 0; | |
111 for (int i = 0; i < segments->length(); ++i) { | |
112 Handle<ByteArray> segment = | |
113 Handle<ByteArray>(ByteArray::cast(segments->get(i))); | |
114 uint32_t dest_addr = static_cast<uint32_t>(segment->get_int(kDestAddr)); | |
115 uint32_t source_size = static_cast<uint32_t>(segment->get_int(kSourceSize)); | |
116 CHECK_LT(dest_addr, mem_size); | |
117 CHECK_LE(source_size, mem_size); | |
118 CHECK_LE(dest_addr, mem_size - source_size); | |
119 byte* addr = mem_addr + dest_addr; | |
120 data->copy_out(last_extraction_pos, addr, source_size); | |
121 last_extraction_pos += source_size; | |
122 } | |
123 } | |
124 | |
125 void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, | 117 void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, |
126 Handle<WasmCompiledModule> compiled_module) { | 118 Handle<WasmCompiledModule> compiled_module) { |
127 Handle<FixedArray> segments = factory->NewFixedArray( | 119 Handle<FixedArray> segments = factory->NewFixedArray( |
128 static_cast<int>(module->data_segments.size()), TENURED); | 120 static_cast<int>(module->data_segments.size()), TENURED); |
129 uint32_t data_size = 0; | 121 uint32_t data_size = 0; |
130 for (const WasmDataSegment& segment : module->data_segments) { | 122 for (const WasmDataSegment& segment : module->data_segments) { |
131 if (segment.source_size == 0) continue; | 123 if (segment.source_size == 0) continue; |
132 data_size += segment.source_size; | 124 data_size += segment.source_size; |
133 } | 125 } |
134 Handle<ByteArray> data = factory->NewByteArray(data_size, TENURED); | 126 Handle<ByteArray> data = factory->NewByteArray(data_size, TENURED); |
135 | 127 |
136 uint32_t last_insertion_pos = 0; | 128 uint32_t last_insertion_pos = 0; |
137 for (uint32_t i = 0; i < module->data_segments.size(); ++i) { | 129 for (uint32_t i = 0; i < module->data_segments.size(); ++i) { |
138 const WasmDataSegment& segment = module->data_segments[i]; | 130 const WasmDataSegment& segment = module->data_segments[i]; |
139 if (segment.source_size == 0) continue; | 131 if (segment.source_size == 0) continue; |
140 Handle<ByteArray> js_segment = | 132 Handle<ByteArray> js_segment = |
141 factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED); | 133 factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED); |
142 // TODO(titzer): add support for global offsets for dest_addr | 134 // TODO(titzer): add support for global offsets for dest_addr |
143 CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind); | 135 CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind); |
144 js_segment->set_int(kDestAddr, segment.dest_addr.val.i32_const); | 136 js_segment->set_int(kDestAddrValue, segment.dest_addr.val.i32_const); |
145 js_segment->set_int(kSourceSize, segment.source_size); | 137 js_segment->set_int(kSourceSize, segment.source_size); |
146 segments->set(i, *js_segment); | 138 segments->set(i, *js_segment); |
147 data->copy_in(last_insertion_pos, | 139 data->copy_in(last_insertion_pos, |
148 module->module_start + segment.source_offset, | 140 module->module_start + segment.source_offset, |
149 segment.source_size); | 141 segment.source_size); |
150 last_insertion_pos += segment.source_size; | 142 last_insertion_pos += segment.source_size; |
151 } | 143 } |
152 compiled_module->set_data_segments_info(segments); | 144 compiled_module->set_data_segments_info(segments); |
153 compiled_module->set_data_segments(data); | 145 compiled_module->set_data_segments(data); |
154 } | 146 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 AllowDeferredHandleDereference embedding_raw_address; | 190 AllowDeferredHandleDereference embedding_raw_address; |
199 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | | 191 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | |
200 (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE); | 192 (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE); |
201 for (RelocIterator it(*function, mask); !it.done(); it.next()) { | 193 for (RelocIterator it(*function, mask); !it.done(); it.next()) { |
202 it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size, | 194 it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size, |
203 new_size); | 195 new_size); |
204 } | 196 } |
205 } | 197 } |
206 } | 198 } |
207 | 199 |
208 // Allocate memory for a module instance as a new JSArrayBuffer. | |
209 Handle<JSArrayBuffer> AllocateMemory(ErrorThrower* thrower, Isolate* isolate, | |
210 uint32_t min_mem_pages) { | |
211 if (min_mem_pages > WasmModule::kMaxMemPages) { | |
212 thrower->Error("Out of memory: wasm memory too large"); | |
213 return Handle<JSArrayBuffer>::null(); | |
214 } | |
215 Handle<JSArrayBuffer> mem_buffer = | |
216 NewArrayBuffer(isolate, min_mem_pages * WasmModule::kPageSize); | |
217 | |
218 if (mem_buffer.is_null()) { | |
219 thrower->Error("Out of memory: wasm memory"); | |
220 } | |
221 return mem_buffer; | |
222 } | |
223 | |
224 void RelocateGlobals(Handle<JSObject> instance, Address old_start, | 200 void RelocateGlobals(Handle<JSObject> instance, Address old_start, |
225 Address globals_start) { | 201 Address globals_start) { |
226 Handle<FixedArray> functions = Handle<FixedArray>( | 202 Handle<FixedArray> functions = Handle<FixedArray>( |
227 FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable))); | 203 FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable))); |
228 uint32_t function_count = static_cast<uint32_t>(functions->length()); | 204 uint32_t function_count = static_cast<uint32_t>(functions->length()); |
229 for (uint32_t i = 0; i < function_count; ++i) { | 205 for (uint32_t i = 0; i < function_count; ++i) { |
230 Handle<Code> function = Handle<Code>(Code::cast(functions->get(i))); | 206 Handle<Code> function = Handle<Code>(Code::cast(functions->get(i))); |
231 AllowDeferredHandleDereference embedding_raw_address; | 207 AllowDeferredHandleDereference embedding_raw_address; |
232 int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE; | 208 int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE; |
233 for (RelocIterator it(*function, mask); !it.done(); it.next()) { | 209 for (RelocIterator it(*function, mask); !it.done(); it.next()) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 JSObject* owner) { | 344 JSObject* owner) { |
369 Address old_address = nullptr; | 345 Address old_address = nullptr; |
370 Object* stored_value = owner->GetInternalField(kWasmGlobalsArrayBuffer); | 346 Object* stored_value = owner->GetInternalField(kWasmGlobalsArrayBuffer); |
371 if (stored_value != undefined) { | 347 if (stored_value != undefined) { |
372 old_address = static_cast<Address>( | 348 old_address = static_cast<Address>( |
373 JSArrayBuffer::cast(stored_value)->backing_store()); | 349 JSArrayBuffer::cast(stored_value)->backing_store()); |
374 } | 350 } |
375 return old_address; | 351 return old_address; |
376 } | 352 } |
377 | 353 |
378 Handle<FixedArray> GetImportsData(Factory* factory, const WasmModule* module) { | 354 Handle<FixedArray> EncodeImports(Factory* factory, const WasmModule* module) { |
379 Handle<FixedArray> ret = factory->NewFixedArray( | 355 Handle<FixedArray> ret = factory->NewFixedArray( |
380 static_cast<int>(module->import_table.size()), TENURED); | 356 static_cast<int>(module->import_table.size()), TENURED); |
| 357 |
381 for (size_t i = 0; i < module->import_table.size(); ++i) { | 358 for (size_t i = 0; i < module->import_table.size(); ++i) { |
382 const WasmImport& import = module->import_table[i]; | 359 const WasmImport& import = module->import_table[i]; |
383 if (import.kind != kExternalFunction) continue; | 360 Handle<FixedArray> encoded_import = |
| 361 factory->NewFixedArray(kWasmImportDataSize, TENURED); |
| 362 encoded_import->set(kImportKind, Smi::FromInt(import.kind)); |
| 363 encoded_import->set(kImportIndex, Smi::FromInt(import.index)); |
| 364 |
| 365 // Add the module and function name. |
384 WasmName module_name = module->GetNameOrNull(import.module_name_offset, | 366 WasmName module_name = module->GetNameOrNull(import.module_name_offset, |
385 import.module_name_length); | 367 import.module_name_length); |
386 WasmName function_name = module->GetNameOrNull(import.field_name_offset, | 368 WasmName function_name = module->GetNameOrNull(import.field_name_offset, |
387 import.field_name_length); | 369 import.field_name_length); |
388 | 370 |
389 Handle<String> module_name_string = | 371 Handle<String> module_name_string = |
390 factory->InternalizeUtf8String(module_name); | 372 factory->InternalizeUtf8String(module_name); |
391 Handle<String> function_name_string = | |
392 function_name.is_empty() | |
393 ? Handle<String>::null() | |
394 : factory->InternalizeUtf8String(function_name); | |
395 FunctionSig* fsig = module->functions[import.index].sig; | |
396 Handle<ByteArray> sig = factory->NewByteArray( | |
397 static_cast<int>(fsig->parameter_count() + fsig->return_count()), | |
398 TENURED); | |
399 sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()), | |
400 sig->length()); | |
401 Handle<FixedArray> encoded_import = | |
402 factory->NewFixedArray(kWasmImportDataSize, TENURED); | |
403 encoded_import->set(kModuleName, *module_name_string); | 373 encoded_import->set(kModuleName, *module_name_string); |
404 if (!function_name_string.is_null()) { | 374 if (!function_name.is_empty()) { |
| 375 Handle<String> function_name_string = |
| 376 factory->InternalizeUtf8String(function_name); |
405 encoded_import->set(kFunctionName, *function_name_string); | 377 encoded_import->set(kFunctionName, *function_name_string); |
406 } | 378 } |
407 encoded_import->set(kOutputCount, | 379 |
408 Smi::FromInt(static_cast<int>(fsig->return_count()))); | 380 switch (import.kind) { |
409 encoded_import->set(kSignature, *sig); | 381 case kExternalFunction: { |
| 382 // Encode the signature into the import. |
| 383 FunctionSig* fsig = module->functions[import.index].sig; |
| 384 Handle<ByteArray> sig = factory->NewByteArray( |
| 385 static_cast<int>(fsig->parameter_count() + fsig->return_count()), |
| 386 TENURED); |
| 387 sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()), |
| 388 sig->length()); |
| 389 encoded_import->set( |
| 390 kOutputCount, Smi::FromInt(static_cast<int>(fsig->return_count()))); |
| 391 encoded_import->set(kSignature, *sig); |
| 392 break; |
| 393 } |
| 394 case kExternalTable: |
| 395 // Nothing extra required for imported tables. |
| 396 break; |
| 397 case kExternalMemory: |
| 398 // Nothing extra required for imported memories. |
| 399 break; |
| 400 case kExternalGlobal: { |
| 401 // Encode the offset and the global type into the import. |
| 402 const WasmGlobal& global = module->globals[import.index]; |
| 403 TRACE("import[%zu].type = %s\n", i, WasmOpcodes::TypeName(global.type)); |
| 404 encoded_import->set( |
| 405 kImportGlobalType, |
| 406 Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type))); |
| 407 encoded_import->set(kImportIndex, Smi::FromInt(global.offset)); |
| 408 break; |
| 409 } |
| 410 } |
410 ret->set(static_cast<int>(i), *encoded_import); | 411 ret->set(static_cast<int>(i), *encoded_import); |
411 } | 412 } |
412 return ret; | 413 return ret; |
413 } | 414 } |
414 | 415 |
415 static MaybeHandle<JSFunction> ReportFFIError( | |
416 ErrorThrower* thrower, const char* error, uint32_t index, | |
417 Handle<String> module_name, MaybeHandle<String> function_name) { | |
418 Handle<String> function_name_handle; | |
419 if (function_name.ToHandle(&function_name_handle)) { | |
420 thrower->Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", | |
421 index, module_name->length(), module_name->ToCString().get(), | |
422 function_name_handle->length(), | |
423 function_name_handle->ToCString().get(), error); | |
424 } else { | |
425 thrower->Error("Import #%d module=\"%.*s\" error: %s", index, | |
426 module_name->length(), module_name->ToCString().get(), | |
427 error); | |
428 } | |
429 thrower->Error("Import "); | |
430 return MaybeHandle<JSFunction>(); | |
431 } | |
432 | |
433 static MaybeHandle<JSReceiver> LookupFunction( | |
434 ErrorThrower* thrower, Factory* factory, Handle<JSReceiver> ffi, | |
435 uint32_t index, Handle<String> module_name, | |
436 MaybeHandle<String> function_name) { | |
437 if (ffi.is_null()) { | |
438 return ReportFFIError(thrower, "FFI is not an object", index, module_name, | |
439 function_name); | |
440 } | |
441 | |
442 // Look up the module first. | |
443 MaybeHandle<Object> result = Object::GetProperty(ffi, module_name); | |
444 if (result.is_null()) { | |
445 return ReportFFIError(thrower, "module not found", index, module_name, | |
446 function_name); | |
447 } | |
448 | |
449 Handle<Object> module = result.ToHandleChecked(); | |
450 | |
451 if (!module->IsJSReceiver()) { | |
452 return ReportFFIError(thrower, "module is not an object or function", index, | |
453 module_name, function_name); | |
454 } | |
455 | |
456 Handle<Object> function; | |
457 if (!function_name.is_null()) { | |
458 // Look up the function in the module. | |
459 MaybeHandle<Object> result = | |
460 Object::GetProperty(module, function_name.ToHandleChecked()); | |
461 if (result.is_null()) { | |
462 return ReportFFIError(thrower, "function not found", index, module_name, | |
463 function_name); | |
464 } | |
465 function = result.ToHandleChecked(); | |
466 } else { | |
467 // No function specified. Use the "default export". | |
468 function = module; | |
469 } | |
470 | |
471 if (!function->IsCallable()) { | |
472 return ReportFFIError(thrower, "not a callable", index, module_name, | |
473 function_name); | |
474 } | |
475 | |
476 return Handle<JSReceiver>::cast(function); | |
477 } | |
478 | |
479 Handle<Code> CompileImportWrapper(Isolate* isolate, | |
480 const Handle<JSReceiver> ffi, int index, | |
481 Handle<FixedArray> import_data, | |
482 ErrorThrower* thrower) { | |
483 Handle<FixedArray> data = | |
484 import_data->GetValueChecked<FixedArray>(isolate, index); | |
485 Handle<String> module_name = | |
486 data->GetValueChecked<String>(isolate, kModuleName); | |
487 MaybeHandle<String> function_name = | |
488 data->GetValue<String>(isolate, kFunctionName); | |
489 | |
490 // TODO(mtrofin): this is an uint32_t, actually. We should rationalize | |
491 // it when we rationalize signed/unsigned stuff. | |
492 int ret_count = Smi::cast(data->get(kOutputCount))->value(); | |
493 CHECK_GE(ret_count, 0); | |
494 Handle<ByteArray> sig_data = | |
495 data->GetValueChecked<ByteArray>(isolate, kSignature); | |
496 int sig_data_size = sig_data->length(); | |
497 int param_count = sig_data_size - ret_count; | |
498 CHECK(param_count >= 0); | |
499 | |
500 MaybeHandle<JSReceiver> function = LookupFunction( | |
501 thrower, isolate->factory(), ffi, index, module_name, function_name); | |
502 if (function.is_null()) return Handle<Code>::null(); | |
503 Handle<Code> code; | |
504 Handle<JSReceiver> target = function.ToHandleChecked(); | |
505 bool isMatch = false; | |
506 Handle<Code> export_wrapper_code; | |
507 if (target->IsJSFunction()) { | |
508 Handle<JSFunction> func = Handle<JSFunction>::cast(target); | |
509 export_wrapper_code = handle(func->code()); | |
510 if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) { | |
511 int exported_param_count = | |
512 Smi::cast(func->GetInternalField(kInternalArity))->value(); | |
513 Handle<ByteArray> exportedSig = Handle<ByteArray>( | |
514 ByteArray::cast(func->GetInternalField(kInternalSignature))); | |
515 if (exported_param_count == param_count && | |
516 exportedSig->length() == sig_data->length() && | |
517 memcmp(exportedSig->GetDataStartAddress(), | |
518 sig_data->GetDataStartAddress(), exportedSig->length()) == 0) { | |
519 isMatch = true; | |
520 } | |
521 } | |
522 } | |
523 if (isMatch) { | |
524 int wasm_count = 0; | |
525 int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | |
526 for (RelocIterator it(*export_wrapper_code, mask); !it.done(); it.next()) { | |
527 RelocInfo* rinfo = it.rinfo(); | |
528 Address target_address = rinfo->target_address(); | |
529 Code* target = Code::GetCodeFromTargetAddress(target_address); | |
530 if (target->kind() == Code::WASM_FUNCTION) { | |
531 ++wasm_count; | |
532 code = handle(target); | |
533 } | |
534 } | |
535 DCHECK(wasm_count == 1); | |
536 return code; | |
537 } else { | |
538 // Copy the signature to avoid a raw pointer into a heap object when | |
539 // GC can happen. | |
540 Zone zone(isolate->allocator()); | |
541 MachineRepresentation* reps = | |
542 zone.NewArray<MachineRepresentation>(sig_data_size); | |
543 memcpy(reps, sig_data->GetDataStartAddress(), | |
544 sizeof(MachineRepresentation) * sig_data_size); | |
545 FunctionSig sig(ret_count, param_count, reps); | |
546 | |
547 return compiler::CompileWasmToJSWrapper(isolate, target, &sig, index, | |
548 module_name, function_name); | |
549 } | |
550 } | |
551 | |
552 void InitializeParallelCompilation( | 416 void InitializeParallelCompilation( |
553 Isolate* isolate, const std::vector<WasmFunction>& functions, | 417 Isolate* isolate, const std::vector<WasmFunction>& functions, |
554 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 418 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
555 ModuleEnv& module_env, ErrorThrower* thrower) { | 419 ModuleEnv& module_env, ErrorThrower* thrower) { |
556 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { | 420 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { |
557 const WasmFunction* func = &functions[i]; | 421 const WasmFunction* func = &functions[i]; |
558 compilation_units[i] = | 422 compilation_units[i] = |
559 func->imported ? nullptr : new compiler::WasmCompilationUnit( | 423 func->imported ? nullptr : new compiler::WasmCompilationUnit( |
560 thrower, isolate, &module_env, func, i); | 424 thrower, isolate, &module_env, func, i); |
561 } | 425 } |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1001 max_mem_pages(0), | 865 max_mem_pages(0), |
1002 mem_export(false), | 866 mem_export(false), |
1003 start_function_index(-1), | 867 start_function_index(-1), |
1004 origin(kWasmOrigin), | 868 origin(kWasmOrigin), |
1005 globals_size(0), | 869 globals_size(0), |
1006 num_imported_functions(0), | 870 num_imported_functions(0), |
1007 num_declared_functions(0), | 871 num_declared_functions(0), |
1008 num_exported_functions(0), | 872 num_exported_functions(0), |
1009 pending_tasks(new base::Semaphore(0)) {} | 873 pending_tasks(new base::Semaphore(0)) {} |
1010 | 874 |
| 875 void EncodeInit(const WasmModule* module, Factory* factory, |
| 876 Handle<FixedArray> entry, int kind_index, int value_index, |
| 877 const WasmInitExpr& expr) { |
| 878 entry->set(kind_index, Smi::FromInt(0)); |
| 879 |
| 880 Handle<Object> value; |
| 881 switch (expr.kind) { |
| 882 case WasmInitExpr::kGlobalIndex: { |
| 883 TRACE(" kind = 1, global index %u\n", expr.val.global_index); |
| 884 entry->set(kind_index, Smi::FromInt(1)); |
| 885 uint32_t offset = module->globals[expr.val.global_index].offset; |
| 886 entry->set(value_index, Smi::FromInt(offset)); |
| 887 return; |
| 888 } |
| 889 case WasmInitExpr::kI32Const: |
| 890 TRACE(" kind = 0, i32 = %d\n", expr.val.i32_const); |
| 891 value = factory->NewNumber(expr.val.i32_const); |
| 892 break; |
| 893 case WasmInitExpr::kI64Const: |
| 894 // TODO(titzer): implement initializers for i64 globals. |
| 895 UNREACHABLE(); |
| 896 break; |
| 897 case WasmInitExpr::kF32Const: |
| 898 TRACE(" kind = 0, f32 = %f\n", expr.val.f32_const); |
| 899 value = factory->NewNumber(expr.val.f32_const); |
| 900 break; |
| 901 case WasmInitExpr::kF64Const: |
| 902 TRACE(" kind = 0, f64 = %lf\n", expr.val.f64_const); |
| 903 value = factory->NewNumber(expr.val.f64_const); |
| 904 break; |
| 905 default: |
| 906 UNREACHABLE(); |
| 907 } |
| 908 entry->set(value_index, *value); |
| 909 } |
| 910 |
1011 MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( | 911 MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( |
1012 Isolate* isolate, ErrorThrower* thrower) const { | 912 Isolate* isolate, ErrorThrower* thrower) const { |
1013 Factory* factory = isolate->factory(); | 913 Factory* factory = isolate->factory(); |
1014 | 914 |
1015 MaybeHandle<WasmCompiledModule> nothing; | 915 MaybeHandle<WasmCompiledModule> nothing; |
1016 | 916 |
1017 WasmModuleInstance temp_instance(this); | 917 WasmModuleInstance temp_instance(this); |
1018 temp_instance.context = isolate->native_context(); | 918 temp_instance.context = isolate->native_context(); |
1019 temp_instance.mem_size = GetMinModuleMemSize(this); | 919 temp_instance.mem_size = GetMinModuleMemSize(this); |
1020 temp_instance.mem_start = nullptr; | 920 temp_instance.mem_start = nullptr; |
(...skipping 24 matching lines...) Expand all Loading... |
1045 module_env.origin = origin; | 945 module_env.origin = origin; |
1046 | 946 |
1047 // The {code_table} array contains import wrappers and functions (which | 947 // The {code_table} array contains import wrappers and functions (which |
1048 // are both included in {functions.size()}, and export wrappers. | 948 // are both included in {functions.size()}, and export wrappers. |
1049 int code_table_size = | 949 int code_table_size = |
1050 static_cast<int>(functions.size() + num_exported_functions); | 950 static_cast<int>(functions.size() + num_exported_functions); |
1051 Handle<FixedArray> code_table = | 951 Handle<FixedArray> code_table = |
1052 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); | 952 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); |
1053 | 953 |
1054 // Initialize the code table with placeholders. | 954 // Initialize the code table with placeholders. |
1055 for (uint32_t i = 0; i < functions.size(); i++) { | 955 for (uint32_t i = 0; i < functions.size(); ++i) { |
1056 Code::Kind kind = Code::WASM_FUNCTION; | 956 Code::Kind kind = Code::WASM_FUNCTION; |
1057 if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION; | 957 if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION; |
1058 Handle<Code> placeholder = CreatePlaceholder(factory, i, kind); | 958 Handle<Code> placeholder = CreatePlaceholder(factory, i, kind); |
1059 code_table->set(static_cast<int>(i), *placeholder); | 959 code_table->set(static_cast<int>(i), *placeholder); |
1060 temp_instance.function_code[i] = placeholder; | 960 temp_instance.function_code[i] = placeholder; |
1061 } | 961 } |
1062 | 962 |
1063 isolate->counters()->wasm_functions_per_module()->AddSample( | 963 isolate->counters()->wasm_functions_per_module()->AddSample( |
1064 static_cast<int>(functions.size())); | 964 static_cast<int>(functions.size())); |
1065 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { | 965 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { |
1066 // Avoid a race condition by collecting results into a second vector. | 966 // Avoid a race condition by collecting results into a second vector. |
1067 std::vector<Handle<Code>> results; | 967 std::vector<Handle<Code>> results; |
1068 results.reserve(temp_instance.function_code.size()); | 968 results.reserve(temp_instance.function_code.size()); |
1069 for (size_t i = 0; i < temp_instance.function_code.size(); i++) { | 969 for (size_t i = 0; i < temp_instance.function_code.size(); ++i) { |
1070 results.push_back(temp_instance.function_code[i]); | 970 results.push_back(temp_instance.function_code[i]); |
1071 } | 971 } |
1072 CompileInParallel(isolate, this, results, thrower, &module_env); | 972 CompileInParallel(isolate, this, results, thrower, &module_env); |
1073 | 973 |
1074 for (size_t i = 0; i < results.size(); i++) { | 974 for (size_t i = 0; i < results.size(); ++i) { |
1075 temp_instance.function_code[i] = results[i]; | 975 temp_instance.function_code[i] = results[i]; |
1076 } | 976 } |
1077 } else { | 977 } else { |
1078 CompileSequentially(isolate, this, temp_instance.function_code, thrower, | 978 CompileSequentially(isolate, this, temp_instance.function_code, thrower, |
1079 &module_env); | 979 &module_env); |
1080 } | 980 } |
1081 if (thrower->error()) return nothing; | 981 if (thrower->error()) return nothing; |
1082 | 982 |
1083 // At this point, compilation has completed. Update the code table. | 983 // At this point, compilation has completed. Update the code table. |
1084 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 984 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
(...skipping 11 matching lines...) Expand all Loading... |
1096 // TODO(mtrofin): do we need to flush the cache here? | 996 // TODO(mtrofin): do we need to flush the cache here? |
1097 Assembler::FlushICache(isolate, code->instruction_start(), | 997 Assembler::FlushICache(isolate, code->instruction_start(), |
1098 code->instruction_size()); | 998 code->instruction_size()); |
1099 } | 999 } |
1100 } | 1000 } |
1101 | 1001 |
1102 // Create the compiled module object, and populate with compiled functions | 1002 // Create the compiled module object, and populate with compiled functions |
1103 // and information needed at instantiation time. This object needs to be | 1003 // and information needed at instantiation time. This object needs to be |
1104 // serializable. Instantiation may occur off a deserialized version of this | 1004 // serializable. Instantiation may occur off a deserialized version of this |
1105 // object. | 1005 // object. |
1106 Handle<WasmCompiledModule> ret = WasmCompiledModule::New( | 1006 Handle<WasmCompiledModule> ret = |
1107 isolate, min_mem_pages, globals_size, mem_export, origin); | 1007 WasmCompiledModule::New(isolate, min_mem_pages, globals_size, origin); |
1108 ret->set_code_table(code_table); | 1008 ret->set_code_table(code_table); |
1109 if (!indirect_table.is_null()) { | 1009 if (!indirect_table.is_null()) { |
1110 ret->set_indirect_function_tables(indirect_table.ToHandleChecked()); | 1010 ret->set_indirect_function_tables(indirect_table.ToHandleChecked()); |
1111 } | 1011 } |
1112 Handle<FixedArray> import_data = GetImportsData(factory, this); | |
1113 ret->set_import_data(import_data); | |
1114 | 1012 |
1115 // Compile exported function wrappers. | 1013 // Create and set import data. |
1116 int export_size = static_cast<int>(num_exported_functions); | 1014 Handle<FixedArray> imports = EncodeImports(factory, this); |
| 1015 ret->set_imports(imports); |
| 1016 |
| 1017 // Create and set export data. |
| 1018 int export_size = static_cast<int>(export_table.size()); |
1117 if (export_size > 0) { | 1019 if (export_size > 0) { |
1118 Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED); | 1020 Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED); |
1119 int index = -1; | 1021 int index = 0; |
| 1022 int func_index = 0; |
1120 | 1023 |
1121 for (const WasmExport& exp : export_table) { | 1024 for (const WasmExport& exp : export_table) { |
1122 if (exp.kind != kExternalFunction) | 1025 if (thrower->error()) return nothing; |
1123 continue; // skip non-function exports. | 1026 Handle<FixedArray> encoded_export = |
1124 index++; | |
1125 Handle<FixedArray> export_data = | |
1126 factory->NewFixedArray(kWasmExportDataSize, TENURED); | 1027 factory->NewFixedArray(kWasmExportDataSize, TENURED); |
1127 FunctionSig* funcSig = functions[exp.index].sig; | |
1128 Handle<ByteArray> exportedSig = | |
1129 factory->NewByteArray(static_cast<int>(funcSig->parameter_count() + | |
1130 funcSig->return_count()), | |
1131 TENURED); | |
1132 exportedSig->copy_in(0, | |
1133 reinterpret_cast<const byte*>(funcSig->raw_data()), | |
1134 exportedSig->length()); | |
1135 export_data->set(kExportedSignature, *exportedSig); | |
1136 WasmName str = GetName(exp.name_offset, exp.name_length); | 1028 WasmName str = GetName(exp.name_offset, exp.name_length); |
1137 Handle<String> name = factory->InternalizeUtf8String(str); | 1029 Handle<String> name = factory->InternalizeUtf8String(str); |
1138 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, exp.index); | 1030 encoded_export->set(kExportKind, Smi::FromInt(exp.kind)); |
1139 Handle<Code> export_code = compiler::CompileJSToWasmWrapper( | 1031 encoded_export->set(kExportName, *name); |
1140 isolate, &module_env, code, exp.index); | 1032 encoded_export->set(kExportIndex, |
1141 if (thrower->error()) return nothing; | 1033 Smi::FromInt(static_cast<int>(exp.index))); |
1142 export_data->set(kExportName, *name); | 1034 exports->set(index, *encoded_export); |
1143 export_data->set(kExportArity, | 1035 |
1144 Smi::FromInt(static_cast<int>( | 1036 switch (exp.kind) { |
1145 functions[exp.index].sig->parameter_count()))); | 1037 case kExternalFunction: { |
1146 export_data->set(kExportedFunctionIndex, | 1038 // Copy the signature and arity. |
1147 Smi::FromInt(static_cast<int>(exp.index))); | 1039 FunctionSig* funcSig = functions[exp.index].sig; |
1148 exports->set(index, *export_data); | 1040 Handle<ByteArray> exportedSig = factory->NewByteArray( |
1149 code_table->set(static_cast<int>(functions.size() + index), *export_code); | 1041 static_cast<int>(funcSig->parameter_count() + |
| 1042 funcSig->return_count()), |
| 1043 TENURED); |
| 1044 exportedSig->copy_in( |
| 1045 0, reinterpret_cast<const byte*>(funcSig->raw_data()), |
| 1046 exportedSig->length()); |
| 1047 encoded_export->set(kExportedSignature, *exportedSig); |
| 1048 encoded_export->set( |
| 1049 kExportArity, |
| 1050 Smi::FromInt(static_cast<int>(funcSig->parameter_count()))); |
| 1051 |
| 1052 // Compile a wrapper for an exported function. |
| 1053 Handle<Code> code = |
| 1054 code_table->GetValueChecked<Code>(isolate, exp.index); |
| 1055 Handle<Code> export_code = compiler::CompileJSToWasmWrapper( |
| 1056 isolate, &module_env, code, exp.index); |
| 1057 int code_table_index = |
| 1058 static_cast<int>(functions.size() + func_index); |
| 1059 code_table->set(code_table_index, *export_code); |
| 1060 encoded_export->set(kExportIndex, Smi::FromInt(code_table_index)); |
| 1061 ++func_index; |
| 1062 } |
| 1063 case kExternalTable: |
| 1064 // Nothing special about exported tables. |
| 1065 break; |
| 1066 case kExternalMemory: |
| 1067 // Nothing special about exported tables. |
| 1068 break; |
| 1069 case kExternalGlobal: { |
| 1070 // Encode the global type and the global offset. |
| 1071 const WasmGlobal& global = globals[exp.index]; |
| 1072 encoded_export->set( |
| 1073 kExportGlobalType, |
| 1074 Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type))); |
| 1075 encoded_export->set(kExportIndex, Smi::FromInt(global.offset)); |
| 1076 break; |
| 1077 } |
| 1078 } |
| 1079 ++index; |
1150 } | 1080 } |
1151 ret->set_exports(exports); | 1081 ret->set_exports(exports); |
1152 } | 1082 } |
1153 | 1083 |
| 1084 // Create and set init data. |
| 1085 int init_size = static_cast<int>(globals.size()); |
| 1086 if (init_size > 0) { |
| 1087 Handle<FixedArray> inits = factory->NewFixedArray(init_size, TENURED); |
| 1088 int index = 0; |
| 1089 for (const WasmGlobal& global : globals) { |
| 1090 // Skip globals that have no initializer (e.g. imported ones). |
| 1091 if (global.init.kind == WasmInitExpr::kNone) continue; |
| 1092 |
| 1093 Handle<FixedArray> encoded_init = |
| 1094 factory->NewFixedArray(kWasmGlobalInitDataSize, TENURED); |
| 1095 inits->set(index, *encoded_init); |
| 1096 TRACE("init[%d].type = %s\n", index, WasmOpcodes::TypeName(global.type)); |
| 1097 |
| 1098 encoded_init->set( |
| 1099 kGlobalInitType, |
| 1100 Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type))); |
| 1101 encoded_init->set(kGlobalInitIndex, Smi::FromInt(global.offset)); |
| 1102 EncodeInit(this, factory, encoded_init, kGlobalInitKind, kGlobalInitValue, |
| 1103 global.init); |
| 1104 ++index; |
| 1105 } |
| 1106 inits->Shrink(index); |
| 1107 ret->set_inits(inits); |
| 1108 } |
| 1109 |
1154 // Record data for startup function. | 1110 // Record data for startup function. |
1155 if (start_function_index >= 0) { | 1111 if (start_function_index >= 0) { |
1156 HandleScope scope(isolate); | 1112 HandleScope scope(isolate); |
1157 Handle<FixedArray> startup_data = | 1113 Handle<FixedArray> startup_data = |
1158 factory->NewFixedArray(kWasmExportDataSize, TENURED); | 1114 factory->NewFixedArray(kWasmExportDataSize, TENURED); |
1159 startup_data->set(kExportArity, Smi::FromInt(0)); | 1115 startup_data->set(kExportArity, Smi::FromInt(0)); |
1160 startup_data->set(kExportedFunctionIndex, | 1116 startup_data->set(kExportIndex, Smi::FromInt(start_function_index)); |
1161 Smi::FromInt(start_function_index)); | |
1162 ret->set_startup_function(startup_data); | 1117 ret->set_startup_function(startup_data); |
1163 } | 1118 } |
1164 | 1119 |
1165 // TODO(wasm): saving the module bytes for debugging is wasteful. We should | 1120 // TODO(wasm): saving the module bytes for debugging is wasteful. We should |
1166 // consider downloading this on-demand. | 1121 // consider downloading this on-demand. |
1167 { | 1122 { |
1168 size_t module_bytes_len = module_end - module_start; | 1123 size_t module_bytes_len = module_end - module_start; |
1169 DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt)); | 1124 DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt)); |
1170 Vector<const uint8_t> module_bytes_vec(module_start, | 1125 Vector<const uint8_t> module_bytes_vec(module_start, |
1171 static_cast<int>(module_bytes_len)); | 1126 static_cast<int>(module_bytes_len)); |
1172 Handle<String> module_bytes_string = | 1127 Handle<String> module_bytes_string = |
1173 factory->NewStringFromOneByte(module_bytes_vec, TENURED) | 1128 factory->NewStringFromOneByte(module_bytes_vec, TENURED) |
1174 .ToHandleChecked(); | 1129 .ToHandleChecked(); |
1175 ret->set_module_bytes(module_bytes_string); | 1130 ret->set_module_bytes(module_bytes_string); |
1176 } | 1131 } |
1177 | 1132 |
1178 Handle<ByteArray> function_name_table = | 1133 Handle<ByteArray> function_name_table = |
1179 BuildFunctionNamesTable(isolate, module_env.module); | 1134 BuildFunctionNamesTable(isolate, module_env.module); |
1180 ret->set_function_names(function_name_table); | 1135 ret->set_function_names(function_name_table); |
1181 if (data_segments.size() > 0) SaveDataSegmentInfo(factory, this, ret); | 1136 if (data_segments.size() > 0) SaveDataSegmentInfo(factory, this, ret); |
1182 DCHECK_EQ(ret->default_mem_size(), temp_instance.mem_size); | 1137 DCHECK_EQ(ret->default_mem_size(), temp_instance.mem_size); |
1183 return ret; | 1138 return ret; |
1184 } | 1139 } |
1185 | 1140 |
| 1141 // A helper class to simplify instantiating a module from a compiled module. |
| 1142 // It closes over the {Isolate}, the {ErrorThrower}, the {WasmCompiledModule}, |
| 1143 // etc. |
| 1144 class WasmInstanceBuilder { |
| 1145 public: |
| 1146 WasmInstanceBuilder(Isolate* isolate, ErrorThrower* thrower, |
| 1147 Handle<JSObject> module_object, Handle<JSReceiver> ffi, |
| 1148 Handle<JSArrayBuffer> memory) |
| 1149 : isolate_(isolate), |
| 1150 thrower_(thrower), |
| 1151 module_object_(module_object), |
| 1152 ffi_(ffi), |
| 1153 memory_(memory) {} |
| 1154 |
| 1155 // Build an instance, in all of its glory. |
| 1156 MaybeHandle<JSObject> Build() { |
| 1157 MaybeHandle<JSObject> nothing; |
| 1158 HistogramTimerScope wasm_instantiate_module_time_scope( |
| 1159 isolate_->counters()->wasm_instantiate_module_time()); |
| 1160 Factory* factory = isolate_->factory(); |
| 1161 |
| 1162 //-------------------------------------------------------------------------- |
| 1163 // Reuse the compiled module (if no owner), otherwise clone. |
| 1164 //-------------------------------------------------------------------------- |
| 1165 Handle<FixedArray> code_table; |
| 1166 Handle<FixedArray> old_code_table; |
| 1167 Handle<JSObject> owner; |
| 1168 // If we don't clone, this will be null(). Otherwise, this will |
| 1169 // be a weak link to the original. If we lose the original to GC, |
| 1170 // this will be a cleared. We'll link the instances chain last. |
| 1171 MaybeHandle<WeakCell> link_to_original; |
| 1172 |
| 1173 TRACE("Starting new module instantiation\n"); |
| 1174 { |
| 1175 Handle<WasmCompiledModule> original( |
| 1176 WasmCompiledModule::cast(module_object_->GetInternalField(0)), |
| 1177 isolate_); |
| 1178 // Always make a new copy of the code_table, since the old_code_table |
| 1179 // may still have placeholders for imports. |
| 1180 old_code_table = original->code_table(); |
| 1181 code_table = factory->CopyFixedArray(old_code_table); |
| 1182 |
| 1183 if (original->has_weak_owning_instance()) { |
| 1184 WeakCell* tmp = original->ptr_to_weak_owning_instance(); |
| 1185 DCHECK(!tmp->cleared()); |
| 1186 // There is already an owner, clone everything. |
| 1187 owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate_); |
| 1188 // Insert the latest clone in front. |
| 1189 TRACE("Cloning from %d\n", original->instance_id()); |
| 1190 compiled_module_ = WasmCompiledModule::Clone(isolate_, original); |
| 1191 // Replace the strong reference to point to the new instance here. |
| 1192 // This allows any of the other instances, including the original, |
| 1193 // to be collected. |
| 1194 module_object_->SetInternalField(0, *compiled_module_); |
| 1195 compiled_module_->set_weak_module_object( |
| 1196 original->weak_module_object()); |
| 1197 link_to_original = factory->NewWeakCell(original); |
| 1198 // Don't link to original here. We remember the original |
| 1199 // as a weak link. If that link isn't clear by the time we finish |
| 1200 // instantiating this instance, then we link it at that time. |
| 1201 compiled_module_->reset_weak_next_instance(); |
| 1202 |
| 1203 // Clone the code for WASM functions and exports. |
| 1204 for (int i = 0; i < code_table->length(); ++i) { |
| 1205 Handle<Code> orig_code = |
| 1206 code_table->GetValueChecked<Code>(isolate_, i); |
| 1207 switch (orig_code->kind()) { |
| 1208 case Code::WASM_TO_JS_FUNCTION: |
| 1209 // Imports will be overwritten with newly compiled wrappers. |
| 1210 break; |
| 1211 case Code::JS_TO_WASM_FUNCTION: |
| 1212 case Code::WASM_FUNCTION: { |
| 1213 Handle<Code> code = factory->CopyCode(orig_code); |
| 1214 code_table->set(i, *code); |
| 1215 break; |
| 1216 } |
| 1217 default: |
| 1218 UNREACHABLE(); |
| 1219 } |
| 1220 } |
| 1221 RecordStats(isolate_, code_table); |
| 1222 } else { |
| 1223 // There was no owner, so we can reuse the original. |
| 1224 compiled_module_ = original; |
| 1225 TRACE("Reusing existing instance %d\n", |
| 1226 compiled_module_->instance_id()); |
| 1227 } |
| 1228 compiled_module_->set_code_table(code_table); |
| 1229 } |
| 1230 |
| 1231 //-------------------------------------------------------------------------- |
| 1232 // Allocate the instance object. |
| 1233 //-------------------------------------------------------------------------- |
| 1234 Handle<Map> map = factory->NewMap( |
| 1235 JS_OBJECT_TYPE, |
| 1236 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); |
| 1237 Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED); |
| 1238 instance->SetInternalField(kWasmModuleCodeTable, *code_table); |
| 1239 |
| 1240 //-------------------------------------------------------------------------- |
| 1241 // Set up the memory for the new instance. |
| 1242 //-------------------------------------------------------------------------- |
| 1243 MaybeHandle<JSArrayBuffer> old_memory; |
| 1244 // TODO(titzer): handle imported memory properly. |
| 1245 |
| 1246 uint32_t min_mem_pages = compiled_module_->min_memory_pages(); |
| 1247 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); |
| 1248 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. |
| 1249 |
| 1250 if (memory_.is_null() && min_mem_pages > 0) { |
| 1251 memory_ = AllocateMemory(min_mem_pages); |
| 1252 if (memory_.is_null()) return nothing; // failed to allocate memory |
| 1253 } |
| 1254 |
| 1255 if (!memory_.is_null()) { |
| 1256 instance->SetInternalField(kWasmMemArrayBuffer, *memory_); |
| 1257 Address mem_start = static_cast<Address>(memory_->backing_store()); |
| 1258 uint32_t mem_size = |
| 1259 static_cast<uint32_t>(memory_->byte_length()->Number()); |
| 1260 LoadDataSegments(mem_start, mem_size); |
| 1261 |
| 1262 uint32_t old_mem_size = compiled_module_->has_heap() |
| 1263 ? compiled_module_->mem_size() |
| 1264 : compiled_module_->default_mem_size(); |
| 1265 Address old_mem_start = |
| 1266 compiled_module_->has_heap() |
| 1267 ? static_cast<Address>(compiled_module_->heap()->backing_store()) |
| 1268 : nullptr; |
| 1269 RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size, |
| 1270 mem_size); |
| 1271 compiled_module_->set_heap(memory_); |
| 1272 } |
| 1273 |
| 1274 //-------------------------------------------------------------------------- |
| 1275 // Set up the globals for the new instance. |
| 1276 //-------------------------------------------------------------------------- |
| 1277 MaybeHandle<JSArrayBuffer> old_globals; |
| 1278 MaybeHandle<JSArrayBuffer> globals; |
| 1279 uint32_t globals_size = compiled_module_->globals_size(); |
| 1280 if (globals_size > 0) { |
| 1281 Handle<JSArrayBuffer> global_buffer = |
| 1282 NewArrayBuffer(isolate_, globals_size); |
| 1283 globals = global_buffer; |
| 1284 if (globals.is_null()) { |
| 1285 thrower_->Error("Out of memory: wasm globals"); |
| 1286 return nothing; |
| 1287 } |
| 1288 Address old_address = |
| 1289 owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate( |
| 1290 *factory->undefined_value(), |
| 1291 JSObject::cast(*owner)); |
| 1292 RelocateGlobals(instance, old_address, |
| 1293 static_cast<Address>(global_buffer->backing_store())); |
| 1294 instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer); |
| 1295 } |
| 1296 |
| 1297 //-------------------------------------------------------------------------- |
| 1298 // Process the imports for the module. |
| 1299 //-------------------------------------------------------------------------- |
| 1300 int num_imported_functions = ProcessImports(globals, code_table); |
| 1301 if (num_imported_functions < 0) return nothing; |
| 1302 |
| 1303 //-------------------------------------------------------------------------- |
| 1304 // Process the initialization for the module's globals. |
| 1305 //-------------------------------------------------------------------------- |
| 1306 ProcessInits(globals); |
| 1307 |
| 1308 //-------------------------------------------------------------------------- |
| 1309 // Set up the debug support for the new instance. |
| 1310 //-------------------------------------------------------------------------- |
| 1311 // TODO(wasm): avoid referencing this stuff from the instance, use it off |
| 1312 // the compiled module instead. See the following 3 assignments: |
| 1313 if (compiled_module_->has_module_bytes()) { |
| 1314 instance->SetInternalField(kWasmModuleBytesString, |
| 1315 compiled_module_->ptr_to_module_bytes()); |
| 1316 } |
| 1317 |
| 1318 if (compiled_module_->has_function_names()) { |
| 1319 instance->SetInternalField(kWasmFunctionNamesArray, |
| 1320 compiled_module_->ptr_to_function_names()); |
| 1321 } |
| 1322 |
| 1323 { |
| 1324 Handle<Object> handle = factory->NewNumber(num_imported_functions); |
| 1325 instance->SetInternalField(kWasmNumImportedFunctions, *handle); |
| 1326 } |
| 1327 |
| 1328 //-------------------------------------------------------------------------- |
| 1329 // Set up the runtime support for the new instance. |
| 1330 //-------------------------------------------------------------------------- |
| 1331 Handle<WeakCell> weak_link = factory->NewWeakCell(instance); |
| 1332 |
| 1333 for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs; |
| 1334 i < code_table->length(); ++i) { |
| 1335 Handle<Code> code = code_table->GetValueChecked<Code>(isolate_, i); |
| 1336 if (code->kind() == Code::WASM_FUNCTION) { |
| 1337 Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED); |
| 1338 deopt_data->set(0, *weak_link); |
| 1339 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); |
| 1340 deopt_data->set_length(2); |
| 1341 code->set_deoptimization_data(*deopt_data); |
| 1342 } |
| 1343 } |
| 1344 |
| 1345 //-------------------------------------------------------------------------- |
| 1346 // Set up the indirect function tables for the new instance. |
| 1347 //-------------------------------------------------------------------------- |
| 1348 { |
| 1349 std::vector<Handle<Code>> functions( |
| 1350 static_cast<size_t>(code_table->length())); |
| 1351 for (int i = 0; i < code_table->length(); ++i) { |
| 1352 functions[i] = code_table->GetValueChecked<Code>(isolate_, i); |
| 1353 } |
| 1354 |
| 1355 if (compiled_module_->has_indirect_function_tables()) { |
| 1356 Handle<FixedArray> indirect_tables_template = |
| 1357 compiled_module_->indirect_function_tables(); |
| 1358 Handle<FixedArray> to_replace = |
| 1359 owner.is_null() ? indirect_tables_template |
| 1360 : handle(FixedArray::cast(owner->GetInternalField( |
| 1361 kWasmModuleFunctionTable))); |
| 1362 Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable( |
| 1363 isolate_, code_table, indirect_tables_template, to_replace); |
| 1364 for (int i = 0; i < indirect_tables->length(); ++i) { |
| 1365 Handle<FixedArray> metadata = |
| 1366 indirect_tables->GetValueChecked<FixedArray>(isolate_, i); |
| 1367 uint32_t size = Smi::cast(metadata->get(kSize))->value(); |
| 1368 Handle<FixedArray> table = |
| 1369 metadata->GetValueChecked<FixedArray>(isolate_, kTable); |
| 1370 PopulateFunctionTable(table, size, &functions); |
| 1371 } |
| 1372 instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); |
| 1373 } |
| 1374 } |
| 1375 |
| 1376 //-------------------------------------------------------------------------- |
| 1377 // Set up the exports object for the new instance. |
| 1378 //-------------------------------------------------------------------------- |
| 1379 ProcessExports(globals, code_table, instance); |
| 1380 |
| 1381 if (num_imported_functions > 0 || !owner.is_null()) { |
| 1382 // If the code was cloned, or new imports were compiled, patch. |
| 1383 PatchDirectCalls(old_code_table, code_table, num_imported_functions); |
| 1384 } |
| 1385 |
| 1386 FlushICache(isolate_, code_table); |
| 1387 |
| 1388 //-------------------------------------------------------------------------- |
| 1389 // Run the start function if one was specified. |
| 1390 //-------------------------------------------------------------------------- |
| 1391 if (compiled_module_->has_startup_function()) { |
| 1392 Handle<FixedArray> startup_data = compiled_module_->startup_function(); |
| 1393 HandleScope scope(isolate_); |
| 1394 int32_t start_index = |
| 1395 startup_data->GetValueChecked<Smi>(isolate_, kExportIndex)->value(); |
| 1396 Handle<Code> startup_code = |
| 1397 code_table->GetValueChecked<Code>(isolate_, start_index); |
| 1398 int arity = Smi::cast(startup_data->get(kExportArity))->value(); |
| 1399 MaybeHandle<ByteArray> startup_signature = |
| 1400 startup_data->GetValue<ByteArray>(isolate_, kExportedSignature); |
| 1401 Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction( |
| 1402 isolate_, startup_code, factory->InternalizeUtf8String("start"), |
| 1403 arity, startup_signature, instance); |
| 1404 RecordStats(isolate_, *startup_code); |
| 1405 // Call the JS function. |
| 1406 Handle<Object> undefined = factory->undefined_value(); |
| 1407 MaybeHandle<Object> retval = |
| 1408 Execution::Call(isolate_, startup_fct, undefined, 0, nullptr); |
| 1409 |
| 1410 if (retval.is_null()) { |
| 1411 thrower_->Error("WASM.instantiateModule(): start function failed"); |
| 1412 return nothing; |
| 1413 } |
| 1414 } |
| 1415 |
| 1416 DCHECK(wasm::IsWasmObject(*instance)); |
| 1417 |
| 1418 { |
| 1419 Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance); |
| 1420 |
| 1421 Handle<Object> global_handle = |
| 1422 isolate_->global_handles()->Create(*instance); |
| 1423 Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module_); |
| 1424 { |
| 1425 DisallowHeapAllocation no_gc; |
| 1426 compiled_module_->set_weak_owning_instance(link_to_owner); |
| 1427 Handle<WeakCell> next; |
| 1428 if (link_to_original.ToHandle(&next) && !next->cleared()) { |
| 1429 WasmCompiledModule* original = |
| 1430 WasmCompiledModule::cast(next->value()); |
| 1431 DCHECK(original->has_weak_owning_instance()); |
| 1432 DCHECK(!original->weak_owning_instance()->cleared()); |
| 1433 compiled_module_->set_weak_next_instance(next); |
| 1434 original->set_weak_prev_instance(link_to_clone); |
| 1435 } |
| 1436 |
| 1437 compiled_module_->set_weak_owning_instance(link_to_owner); |
| 1438 instance->SetInternalField(kWasmCompiledModule, *compiled_module_); |
| 1439 GlobalHandles::MakeWeak(global_handle.location(), |
| 1440 global_handle.location(), &InstanceFinalizer, |
| 1441 v8::WeakCallbackType::kFinalizer); |
| 1442 } |
| 1443 } |
| 1444 TRACE("Finishing instance %d\n", compiled_module_->instance_id()); |
| 1445 TRACE_CHAIN(WasmCompiledModule::cast(module_object_->GetInternalField(0))); |
| 1446 return instance; |
| 1447 } |
| 1448 |
| 1449 private: |
| 1450 Isolate* isolate_; |
| 1451 ErrorThrower* thrower_; |
| 1452 Handle<JSObject> module_object_; |
| 1453 Handle<JSReceiver> ffi_; |
| 1454 Handle<JSArrayBuffer> memory_; |
| 1455 Handle<WasmCompiledModule> compiled_module_; |
| 1456 |
| 1457 // Helper routine to print out errors with imports (FFI). |
| 1458 MaybeHandle<JSFunction> ReportFFIError(const char* error, uint32_t index, |
| 1459 Handle<String> module_name, |
| 1460 MaybeHandle<String> function_name) { |
| 1461 Handle<String> function_name_handle; |
| 1462 if (function_name.ToHandle(&function_name_handle)) { |
| 1463 thrower_->Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", |
| 1464 index, module_name->length(), |
| 1465 module_name->ToCString().get(), |
| 1466 function_name_handle->length(), |
| 1467 function_name_handle->ToCString().get(), error); |
| 1468 } else { |
| 1469 thrower_->Error("Import #%d module=\"%.*s\" error: %s", index, |
| 1470 module_name->length(), module_name->ToCString().get(), |
| 1471 error); |
| 1472 } |
| 1473 thrower_->Error("Import "); |
| 1474 return MaybeHandle<JSFunction>(); |
| 1475 } |
| 1476 |
| 1477 // Look up an import value in the {ffi_} object. |
| 1478 MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name, |
| 1479 MaybeHandle<String> import_name) { |
| 1480 if (ffi_.is_null()) { |
| 1481 return ReportFFIError("FFI is not an object", index, module_name, |
| 1482 import_name); |
| 1483 } |
| 1484 |
| 1485 // Look up the module first. |
| 1486 MaybeHandle<Object> result = Object::GetProperty(ffi_, module_name); |
| 1487 if (result.is_null()) { |
| 1488 return ReportFFIError("module not found", index, module_name, |
| 1489 import_name); |
| 1490 } |
| 1491 |
| 1492 Handle<Object> module = result.ToHandleChecked(); |
| 1493 |
| 1494 if (!import_name.is_null()) { |
| 1495 // Look up the value in the module. |
| 1496 if (!module->IsJSReceiver()) { |
| 1497 return ReportFFIError("module is not an object or function", index, |
| 1498 module_name, import_name); |
| 1499 } |
| 1500 |
| 1501 result = Object::GetProperty(module, import_name.ToHandleChecked()); |
| 1502 if (result.is_null()) { |
| 1503 return ReportFFIError("import not found", index, module_name, |
| 1504 import_name); |
| 1505 } |
| 1506 } else { |
| 1507 // No function specified. Use the "default export". |
| 1508 result = module; |
| 1509 } |
| 1510 |
| 1511 return result; |
| 1512 } |
| 1513 |
| 1514 // Load data segments into the memory. |
| 1515 void LoadDataSegments(Address mem_addr, size_t mem_size) { |
| 1516 CHECK(compiled_module_->has_data_segments() == |
| 1517 compiled_module_->has_data_segments_info()); |
| 1518 |
| 1519 // If we have neither, we're done. |
| 1520 if (!compiled_module_->has_data_segments()) return; |
| 1521 |
| 1522 Handle<ByteArray> data = compiled_module_->data_segments(); |
| 1523 Handle<FixedArray> segments = compiled_module_->data_segments_info(); |
| 1524 |
| 1525 uint32_t last_extraction_pos = 0; |
| 1526 for (int i = 0; i < segments->length(); ++i) { |
| 1527 Handle<ByteArray> segment = |
| 1528 Handle<ByteArray>(ByteArray::cast(segments->get(i))); |
| 1529 uint32_t dest_addr = |
| 1530 static_cast<uint32_t>(segment->get_int(kDestAddrValue)); |
| 1531 uint32_t source_size = |
| 1532 static_cast<uint32_t>(segment->get_int(kSourceSize)); |
| 1533 CHECK_LT(dest_addr, mem_size); |
| 1534 CHECK_LE(source_size, mem_size); |
| 1535 CHECK_LE(dest_addr, mem_size - source_size); |
| 1536 byte* addr = mem_addr + dest_addr; |
| 1537 data->copy_out(last_extraction_pos, addr, source_size); |
| 1538 last_extraction_pos += source_size; |
| 1539 } |
| 1540 } |
| 1541 |
| 1542 Handle<Code> CompileImportWrapper(int index, Handle<FixedArray> data, |
| 1543 Handle<JSReceiver> target, |
| 1544 Handle<String> module_name, |
| 1545 MaybeHandle<String> import_name) { |
| 1546 // TODO(mtrofin): this is an uint32_t, actually. We should rationalize |
| 1547 // it when we rationalize signed/unsigned stuff. |
| 1548 int ret_count = Smi::cast(data->get(kOutputCount))->value(); |
| 1549 CHECK_GE(ret_count, 0); |
| 1550 Handle<ByteArray> sig_data = |
| 1551 data->GetValueChecked<ByteArray>(isolate_, kSignature); |
| 1552 int sig_data_size = sig_data->length(); |
| 1553 int param_count = sig_data_size - ret_count; |
| 1554 CHECK(param_count >= 0); |
| 1555 |
| 1556 Handle<Code> code; |
| 1557 bool isMatch = false; |
| 1558 Handle<Code> export_wrapper_code; |
| 1559 if (target->IsJSFunction()) { |
| 1560 Handle<JSFunction> func = Handle<JSFunction>::cast(target); |
| 1561 export_wrapper_code = handle(func->code()); |
| 1562 if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) { |
| 1563 int exported_param_count = |
| 1564 Smi::cast(func->GetInternalField(kInternalArity))->value(); |
| 1565 Handle<ByteArray> exportedSig = Handle<ByteArray>( |
| 1566 ByteArray::cast(func->GetInternalField(kInternalSignature))); |
| 1567 if (exported_param_count == param_count && |
| 1568 exportedSig->length() == sig_data->length() && |
| 1569 memcmp(exportedSig->GetDataStartAddress(), |
| 1570 sig_data->GetDataStartAddress(), |
| 1571 exportedSig->length()) == 0) { |
| 1572 isMatch = true; |
| 1573 } |
| 1574 } |
| 1575 } |
| 1576 if (isMatch) { |
| 1577 int wasm_count = 0; |
| 1578 int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); |
| 1579 for (RelocIterator it(*export_wrapper_code, mask); !it.done(); |
| 1580 it.next()) { |
| 1581 RelocInfo* rinfo = it.rinfo(); |
| 1582 Address target_address = rinfo->target_address(); |
| 1583 Code* target = Code::GetCodeFromTargetAddress(target_address); |
| 1584 if (target->kind() == Code::WASM_FUNCTION) { |
| 1585 ++wasm_count; |
| 1586 code = handle(target); |
| 1587 } |
| 1588 } |
| 1589 DCHECK(wasm_count == 1); |
| 1590 return code; |
| 1591 } else { |
| 1592 // Copy the signature to avoid a raw pointer into a heap object when |
| 1593 // GC can happen. |
| 1594 Zone zone(isolate_->allocator()); |
| 1595 MachineRepresentation* reps = |
| 1596 zone.NewArray<MachineRepresentation>(sig_data_size); |
| 1597 memcpy(reps, sig_data->GetDataStartAddress(), |
| 1598 sizeof(MachineRepresentation) * sig_data_size); |
| 1599 FunctionSig sig(ret_count, param_count, reps); |
| 1600 |
| 1601 return compiler::CompileWasmToJSWrapper(isolate_, target, &sig, index, |
| 1602 module_name, import_name); |
| 1603 } |
| 1604 } |
| 1605 |
| 1606 void WriteGlobalValue(MaybeHandle<JSArrayBuffer> globals, uint32_t offset, |
| 1607 Handle<Object> value, int type) { |
| 1608 double num = 0; |
| 1609 if (value->IsSmi()) { |
| 1610 num = Smi::cast(*value)->value(); |
| 1611 } else if (value->IsHeapNumber()) { |
| 1612 num = HeapNumber::cast(*value)->value(); |
| 1613 } else { |
| 1614 UNREACHABLE(); |
| 1615 } |
| 1616 TRACE("init [globals+%u] = %lf, type = %d\n", offset, num, type); |
| 1617 byte* ptr = raw_buffer_ptr(globals, offset); |
| 1618 switch (type) { |
| 1619 case kLocalI32: |
| 1620 *reinterpret_cast<int32_t*>(ptr) = static_cast<int32_t>(num); |
| 1621 break; |
| 1622 case kLocalI64: |
| 1623 // TODO(titzer): initialization of imported i64 globals. |
| 1624 UNREACHABLE(); |
| 1625 break; |
| 1626 case kLocalF32: |
| 1627 *reinterpret_cast<float*>(ptr) = static_cast<float>(num); |
| 1628 break; |
| 1629 case kLocalF64: |
| 1630 *reinterpret_cast<double*>(ptr) = num; |
| 1631 break; |
| 1632 default: |
| 1633 UNREACHABLE(); |
| 1634 } |
| 1635 } |
| 1636 |
| 1637 // Process the imports, including functions, tables, globals, and memory, in |
| 1638 // order, loading them from the {ffi_} object. Returns the number of imported |
| 1639 // functions. |
| 1640 int ProcessImports(MaybeHandle<JSArrayBuffer> globals, |
| 1641 Handle<FixedArray> code_table) { |
| 1642 int num_imported_functions = 0; |
| 1643 if (!compiled_module_->has_imports()) return num_imported_functions; |
| 1644 |
| 1645 Handle<FixedArray> imports = compiled_module_->imports(); |
| 1646 for (int index = 0; index < imports->length(); ++index) { |
| 1647 Handle<FixedArray> data = |
| 1648 imports->GetValueChecked<FixedArray>(isolate_, index); |
| 1649 |
| 1650 Handle<String> module_name = |
| 1651 data->GetValueChecked<String>(isolate_, kModuleName); |
| 1652 MaybeHandle<String> function_name = |
| 1653 data->GetValue<String>(isolate_, kFunctionName); |
| 1654 |
| 1655 MaybeHandle<Object> result = |
| 1656 LookupImport(index, module_name, function_name); |
| 1657 if (thrower_->error()) return -1; |
| 1658 |
| 1659 WasmExternalKind kind = static_cast<WasmExternalKind>( |
| 1660 Smi::cast(data->get(kImportKind))->value()); |
| 1661 switch (kind) { |
| 1662 case kExternalFunction: { |
| 1663 // Function imports must be callable. |
| 1664 Handle<Object> function = result.ToHandleChecked(); |
| 1665 if (!function->IsCallable()) { |
| 1666 ReportFFIError("function import requires a callable", index, |
| 1667 module_name, function_name); |
| 1668 return -1; |
| 1669 } |
| 1670 |
| 1671 Handle<Code> import_wrapper = CompileImportWrapper( |
| 1672 index, data, Handle<JSReceiver>::cast(function), module_name, |
| 1673 function_name); |
| 1674 int func_index = Smi::cast(data->get(kImportIndex))->value(); |
| 1675 code_table->set(func_index, *import_wrapper); |
| 1676 RecordStats(isolate_, *import_wrapper); |
| 1677 num_imported_functions++; |
| 1678 break; |
| 1679 } |
| 1680 case kExternalTable: |
| 1681 // TODO(titzer): Table imports must be a WebAssembly.Table. |
| 1682 break; |
| 1683 case kExternalMemory: |
| 1684 // TODO(titzer): Memory imports must be a WebAssembly.Memory. |
| 1685 break; |
| 1686 case kExternalGlobal: { |
| 1687 // Global imports are converted to numbers and written into the |
| 1688 // {globals} array buffer. |
| 1689 Handle<Object> object = result.ToHandleChecked(); |
| 1690 MaybeHandle<Object> number = Object::ToNumber(object); |
| 1691 if (number.is_null()) { |
| 1692 ReportFFIError("global import could not be converted to number", |
| 1693 index, module_name, function_name); |
| 1694 return -1; |
| 1695 } |
| 1696 Handle<Object> val = number.ToHandleChecked(); |
| 1697 int offset = Smi::cast(data->get(kImportIndex))->value(); |
| 1698 int type = Smi::cast(data->get(kImportGlobalType))->value(); |
| 1699 WriteGlobalValue(globals, offset, val, type); |
| 1700 break; |
| 1701 } |
| 1702 default: |
| 1703 UNREACHABLE(); |
| 1704 break; |
| 1705 } |
| 1706 } |
| 1707 return num_imported_functions; |
| 1708 } |
| 1709 |
| 1710 // Process initialization of globals. |
| 1711 void ProcessInits(MaybeHandle<JSArrayBuffer> globals) { |
| 1712 if (!compiled_module_->has_inits()) return; |
| 1713 |
| 1714 Handle<FixedArray> inits = compiled_module_->inits(); |
| 1715 for (int index = 0; index < inits->length(); ++index) { |
| 1716 Handle<FixedArray> data = |
| 1717 inits->GetValueChecked<FixedArray>(isolate_, index); |
| 1718 |
| 1719 int offset = Smi::cast(data->get(kGlobalInitIndex))->value(); |
| 1720 Handle<Object> val(data->get(kGlobalInitValue), isolate_); |
| 1721 int type = Smi::cast(data->get(kGlobalInitType))->value(); |
| 1722 if (Smi::cast(data->get(kGlobalInitKind))->value() == 0) { |
| 1723 // Initialize with a constant. |
| 1724 WriteGlobalValue(globals, offset, val, type); |
| 1725 } else { |
| 1726 // Initialize with another global. |
| 1727 int old_offset = Smi::cast(*val)->value(); |
| 1728 TRACE("init [globals+%u] = [globals+%d]\n", offset, old_offset); |
| 1729 int size = sizeof(int32_t); |
| 1730 if (type == kLocalI64 || type == kLocalF64) size = sizeof(double); |
| 1731 memcpy(raw_buffer_ptr(globals, offset), |
| 1732 raw_buffer_ptr(globals, old_offset), size); |
| 1733 } |
| 1734 } |
| 1735 } |
| 1736 |
| 1737 // Allocate memory for a module instance as a new JSArrayBuffer. |
| 1738 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { |
| 1739 if (min_mem_pages > WasmModule::kMaxMemPages) { |
| 1740 thrower_->Error("Out of memory: wasm memory too large"); |
| 1741 return Handle<JSArrayBuffer>::null(); |
| 1742 } |
| 1743 Handle<JSArrayBuffer> mem_buffer = |
| 1744 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize); |
| 1745 |
| 1746 if (mem_buffer.is_null()) { |
| 1747 thrower_->Error("Out of memory: wasm memory"); |
| 1748 } |
| 1749 return mem_buffer; |
| 1750 } |
| 1751 |
| 1752 // Process the exports, creating wrappers for functions, tables, memories, |
| 1753 // and globals. |
| 1754 void ProcessExports(MaybeHandle<JSArrayBuffer> globals, |
| 1755 Handle<FixedArray> code_table, |
| 1756 Handle<JSObject> instance) { |
| 1757 if (!compiled_module_->has_exports()) return; |
| 1758 |
| 1759 Handle<JSObject> exports_object = instance; |
| 1760 if (compiled_module_->origin() == kWasmOrigin) { |
| 1761 // Create the "exports" object. |
| 1762 Handle<JSFunction> object_function = Handle<JSFunction>( |
| 1763 isolate_->native_context()->object_function(), isolate_); |
| 1764 exports_object = |
| 1765 isolate_->factory()->NewJSObject(object_function, TENURED); |
| 1766 Handle<String> exports_name = |
| 1767 isolate_->factory()->InternalizeUtf8String("exports"); |
| 1768 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); |
| 1769 } |
| 1770 |
| 1771 PropertyDescriptor desc; |
| 1772 desc.set_writable(false); |
| 1773 |
| 1774 Handle<FixedArray> exports = compiled_module_->exports(); |
| 1775 |
| 1776 for (int i = 0; i < exports->length(); ++i) { |
| 1777 Handle<FixedArray> export_data = |
| 1778 exports->GetValueChecked<FixedArray>(isolate_, i); |
| 1779 Handle<String> name = |
| 1780 export_data->GetValueChecked<String>(isolate_, kExportName); |
| 1781 WasmExternalKind kind = static_cast<WasmExternalKind>( |
| 1782 Smi::cast(export_data->get(kExportKind))->value()); |
| 1783 switch (kind) { |
| 1784 case kExternalFunction: { |
| 1785 // Wrap and export the code as a JSFunction. |
| 1786 int code_table_index = |
| 1787 Smi::cast(export_data->get(kExportIndex))->value(); |
| 1788 Handle<Code> export_code = |
| 1789 code_table->GetValueChecked<Code>(isolate_, code_table_index); |
| 1790 int arity = Smi::cast(export_data->get(kExportArity))->value(); |
| 1791 MaybeHandle<ByteArray> signature = |
| 1792 export_data->GetValue<ByteArray>(isolate_, kExportedSignature); |
| 1793 desc.set_value(WrapExportCodeAsJSFunction( |
| 1794 isolate_, export_code, name, arity, signature, instance)); |
| 1795 break; |
| 1796 } |
| 1797 case kExternalTable: |
| 1798 // TODO(titzer): create a WebAssembly.Table instance. |
| 1799 // TODO(titzer): should it have the same identity as an import? |
| 1800 break; |
| 1801 case kExternalMemory: { |
| 1802 // TODO(titzer): should memory have the same identity as an |
| 1803 // import? |
| 1804 Handle<JSArrayBuffer> buffer = |
| 1805 Handle<JSArrayBuffer>(JSArrayBuffer::cast( |
| 1806 instance->GetInternalField(kWasmMemArrayBuffer))); |
| 1807 desc.set_value( |
| 1808 WasmJs::CreateWasmMemoryObject(isolate_, buffer, false, 0)); |
| 1809 break; |
| 1810 } |
| 1811 case kExternalGlobal: { |
| 1812 // Export the value of the global variable as a number. |
| 1813 int offset = Smi::cast(export_data->get(kExportIndex))->value(); |
| 1814 byte* ptr = raw_buffer_ptr(globals, offset); |
| 1815 double num = 0; |
| 1816 switch (Smi::cast(export_data->get(kExportGlobalType))->value()) { |
| 1817 case kLocalI32: |
| 1818 num = *reinterpret_cast<int32_t*>(ptr); |
| 1819 break; |
| 1820 case kLocalF32: |
| 1821 num = *reinterpret_cast<float*>(ptr); |
| 1822 break; |
| 1823 case kLocalF64: |
| 1824 num = *reinterpret_cast<double*>(ptr); |
| 1825 break; |
| 1826 default: |
| 1827 UNREACHABLE(); |
| 1828 } |
| 1829 desc.set_value(isolate_->factory()->NewNumber(num)); |
| 1830 break; |
| 1831 } |
| 1832 default: |
| 1833 UNREACHABLE(); |
| 1834 break; |
| 1835 } |
| 1836 |
| 1837 Maybe<bool> status = JSReceiver::DefineOwnProperty( |
| 1838 isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR); |
| 1839 if (!status.IsJust()) { |
| 1840 thrower_->Error("export of %.*s failed.", name->length(), |
| 1841 name->ToCString().get()); |
| 1842 return; |
| 1843 } |
| 1844 } |
| 1845 } |
| 1846 }; |
| 1847 |
1186 // Instantiates a WASM module, creating a WebAssembly.Instance from a | 1848 // Instantiates a WASM module, creating a WebAssembly.Instance from a |
1187 // WebAssembly.Module. | 1849 // WebAssembly.Module. |
1188 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, | 1850 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, |
1189 ErrorThrower* thrower, | 1851 ErrorThrower* thrower, |
1190 Handle<JSObject> module_object, | 1852 Handle<JSObject> module_object, |
1191 Handle<JSReceiver> ffi, | 1853 Handle<JSReceiver> ffi, |
1192 Handle<JSArrayBuffer> memory) { | 1854 Handle<JSArrayBuffer> memory) { |
1193 MaybeHandle<JSObject> nothing; | 1855 WasmInstanceBuilder builder(isolate, thrower, module_object, ffi, memory); |
1194 HistogramTimerScope wasm_instantiate_module_time_scope( | 1856 return builder.Build(); |
1195 isolate->counters()->wasm_instantiate_module_time()); | |
1196 Factory* factory = isolate->factory(); | |
1197 | |
1198 //-------------------------------------------------------------------------- | |
1199 // Reuse the compiled module (if no owner), otherwise clone. | |
1200 //-------------------------------------------------------------------------- | |
1201 Handle<WasmCompiledModule> compiled_module; | |
1202 Handle<FixedArray> code_table; | |
1203 Handle<FixedArray> old_code_table; | |
1204 Handle<JSObject> owner; | |
1205 // If we don't clone, this will be null(). Otherwise, this will | |
1206 // be a weak link to the original. If we lose the original to GC, | |
1207 // this will be a cleared. We'll link the instances chain last. | |
1208 MaybeHandle<WeakCell> link_to_original; | |
1209 | |
1210 TRACE("Starting new module instantiation\n"); | |
1211 { | |
1212 Handle<WasmCompiledModule> original( | |
1213 WasmCompiledModule::cast(module_object->GetInternalField(0)), isolate); | |
1214 // Always make a new copy of the code_table, since the old_code_table | |
1215 // may still have placeholders for imports. | |
1216 old_code_table = original->code_table(); | |
1217 code_table = factory->CopyFixedArray(old_code_table); | |
1218 | |
1219 if (original->has_weak_owning_instance()) { | |
1220 WeakCell* tmp = original->ptr_to_weak_owning_instance(); | |
1221 DCHECK(!tmp->cleared()); | |
1222 // There is already an owner, clone everything. | |
1223 owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate); | |
1224 // Insert the latest clone in front. | |
1225 TRACE("Cloning from %d\n", original->instance_id()); | |
1226 compiled_module = WasmCompiledModule::Clone(isolate, original); | |
1227 // Replace the strong reference to point to the new instance here. | |
1228 // This allows any of the other instances, including the original, | |
1229 // to be collected. | |
1230 module_object->SetInternalField(0, *compiled_module); | |
1231 compiled_module->set_weak_module_object(original->weak_module_object()); | |
1232 link_to_original = factory->NewWeakCell(original); | |
1233 // Don't link to original here. We remember the original | |
1234 // as a weak link. If that link isn't clear by the time we finish | |
1235 // instantiating this instance, then we link it at that time. | |
1236 compiled_module->reset_weak_next_instance(); | |
1237 | |
1238 // Clone the code for WASM functions and exports. | |
1239 for (int i = 0; i < code_table->length(); ++i) { | |
1240 Handle<Code> orig_code = code_table->GetValueChecked<Code>(isolate, i); | |
1241 switch (orig_code->kind()) { | |
1242 case Code::WASM_TO_JS_FUNCTION: | |
1243 // Imports will be overwritten with newly compiled wrappers. | |
1244 break; | |
1245 case Code::JS_TO_WASM_FUNCTION: | |
1246 case Code::WASM_FUNCTION: { | |
1247 Handle<Code> code = factory->CopyCode(orig_code); | |
1248 code_table->set(i, *code); | |
1249 break; | |
1250 } | |
1251 default: | |
1252 UNREACHABLE(); | |
1253 } | |
1254 } | |
1255 RecordStats(isolate, code_table); | |
1256 } else { | |
1257 // There was no owner, so we can reuse the original. | |
1258 compiled_module = original; | |
1259 TRACE("Reusing existing instance %d\n", compiled_module->instance_id()); | |
1260 } | |
1261 compiled_module->set_code_table(code_table); | |
1262 } | |
1263 | |
1264 //-------------------------------------------------------------------------- | |
1265 // Allocate the instance object. | |
1266 //-------------------------------------------------------------------------- | |
1267 Handle<Map> map = factory->NewMap( | |
1268 JS_OBJECT_TYPE, | |
1269 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); | |
1270 Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED); | |
1271 instance->SetInternalField(kWasmModuleCodeTable, *code_table); | |
1272 | |
1273 //-------------------------------------------------------------------------- | |
1274 // Set up the memory for the new instance. | |
1275 //-------------------------------------------------------------------------- | |
1276 MaybeHandle<JSArrayBuffer> old_memory; | |
1277 // TODO(titzer): handle imported memory properly. | |
1278 | |
1279 uint32_t min_mem_pages = compiled_module->min_memory_pages(); | |
1280 isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); | |
1281 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. | |
1282 | |
1283 if (memory.is_null() && min_mem_pages > 0) { | |
1284 memory = AllocateMemory(thrower, isolate, min_mem_pages); | |
1285 if (memory.is_null()) return nothing; // failed to allocate memory | |
1286 } | |
1287 | |
1288 if (!memory.is_null()) { | |
1289 instance->SetInternalField(kWasmMemArrayBuffer, *memory); | |
1290 Address mem_start = static_cast<Address>(memory->backing_store()); | |
1291 uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number()); | |
1292 LoadDataSegments(compiled_module, mem_start, mem_size); | |
1293 | |
1294 uint32_t old_mem_size = compiled_module->has_heap() | |
1295 ? compiled_module->mem_size() | |
1296 : compiled_module->default_mem_size(); | |
1297 Address old_mem_start = | |
1298 compiled_module->has_heap() | |
1299 ? static_cast<Address>(compiled_module->heap()->backing_store()) | |
1300 : nullptr; | |
1301 RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size, | |
1302 mem_size); | |
1303 compiled_module->set_heap(memory); | |
1304 } | |
1305 | |
1306 //-------------------------------------------------------------------------- | |
1307 // Set up the globals for the new instance. | |
1308 //-------------------------------------------------------------------------- | |
1309 MaybeHandle<JSArrayBuffer> old_globals; | |
1310 MaybeHandle<JSArrayBuffer> globals; | |
1311 uint32_t globals_size = compiled_module->globals_size(); | |
1312 if (globals_size > 0) { | |
1313 Handle<JSArrayBuffer> global_buffer = NewArrayBuffer(isolate, globals_size); | |
1314 globals = global_buffer; | |
1315 if (globals.is_null()) { | |
1316 thrower->Error("Out of memory: wasm globals"); | |
1317 return nothing; | |
1318 } | |
1319 Address old_address = | |
1320 owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate( | |
1321 *isolate->factory()->undefined_value(), | |
1322 JSObject::cast(*owner)); | |
1323 RelocateGlobals(instance, old_address, | |
1324 static_cast<Address>(global_buffer->backing_store())); | |
1325 instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer); | |
1326 } | |
1327 | |
1328 //-------------------------------------------------------------------------- | |
1329 // Compile the import wrappers for the new instance. | |
1330 //-------------------------------------------------------------------------- | |
1331 // TODO(titzer): handle imported globals and function tables. | |
1332 int num_imported_functions = 0; | |
1333 if (compiled_module->has_import_data()) { | |
1334 Handle<FixedArray> import_data = compiled_module->import_data(); | |
1335 num_imported_functions = import_data->length(); | |
1336 for (int index = 0; index < num_imported_functions; index++) { | |
1337 Handle<Code> import_wrapper = | |
1338 CompileImportWrapper(isolate, ffi, index, import_data, thrower); | |
1339 if (thrower->error()) return nothing; | |
1340 code_table->set(index, *import_wrapper); | |
1341 RecordStats(isolate, *import_wrapper); | |
1342 } | |
1343 } | |
1344 | |
1345 //-------------------------------------------------------------------------- | |
1346 // Set up the debug support for the new instance. | |
1347 //-------------------------------------------------------------------------- | |
1348 // TODO(wasm): avoid referencing this stuff from the instance, use it off | |
1349 // the compiled module instead. See the following 3 assignments: | |
1350 if (compiled_module->has_module_bytes()) { | |
1351 instance->SetInternalField(kWasmModuleBytesString, | |
1352 compiled_module->ptr_to_module_bytes()); | |
1353 } | |
1354 | |
1355 if (compiled_module->has_function_names()) { | |
1356 instance->SetInternalField(kWasmFunctionNamesArray, | |
1357 compiled_module->ptr_to_function_names()); | |
1358 } | |
1359 | |
1360 { | |
1361 Handle<Object> handle = factory->NewNumber(num_imported_functions); | |
1362 instance->SetInternalField(kWasmNumImportedFunctions, *handle); | |
1363 } | |
1364 | |
1365 //-------------------------------------------------------------------------- | |
1366 // Set up the runtime support for the new instance. | |
1367 //-------------------------------------------------------------------------- | |
1368 Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(instance); | |
1369 | |
1370 for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs; | |
1371 i < code_table->length(); ++i) { | |
1372 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | |
1373 if (code->kind() == Code::WASM_FUNCTION) { | |
1374 Handle<FixedArray> deopt_data = | |
1375 isolate->factory()->NewFixedArray(2, TENURED); | |
1376 deopt_data->set(0, *weak_link); | |
1377 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); | |
1378 deopt_data->set_length(2); | |
1379 code->set_deoptimization_data(*deopt_data); | |
1380 } | |
1381 } | |
1382 | |
1383 //-------------------------------------------------------------------------- | |
1384 // Set up the indirect function tables for the new instance. | |
1385 //-------------------------------------------------------------------------- | |
1386 { | |
1387 std::vector<Handle<Code>> functions( | |
1388 static_cast<size_t>(code_table->length())); | |
1389 for (int i = 0; i < code_table->length(); ++i) { | |
1390 functions[i] = code_table->GetValueChecked<Code>(isolate, i); | |
1391 } | |
1392 | |
1393 if (compiled_module->has_indirect_function_tables()) { | |
1394 Handle<FixedArray> indirect_tables_template = | |
1395 compiled_module->indirect_function_tables(); | |
1396 Handle<FixedArray> to_replace = | |
1397 owner.is_null() ? indirect_tables_template | |
1398 : handle(FixedArray::cast(owner->GetInternalField( | |
1399 kWasmModuleFunctionTable))); | |
1400 Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable( | |
1401 isolate, code_table, indirect_tables_template, to_replace); | |
1402 for (int i = 0; i < indirect_tables->length(); ++i) { | |
1403 Handle<FixedArray> metadata = | |
1404 indirect_tables->GetValueChecked<FixedArray>(isolate, i); | |
1405 uint32_t size = Smi::cast(metadata->get(kSize))->value(); | |
1406 Handle<FixedArray> table = | |
1407 metadata->GetValueChecked<FixedArray>(isolate, kTable); | |
1408 PopulateFunctionTable(table, size, &functions); | |
1409 } | |
1410 instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); | |
1411 } | |
1412 } | |
1413 | |
1414 //-------------------------------------------------------------------------- | |
1415 // Set up the exports object for the new instance. | |
1416 //-------------------------------------------------------------------------- | |
1417 bool mem_export = compiled_module->export_memory(); | |
1418 ModuleOrigin origin = compiled_module->origin(); | |
1419 | |
1420 if (compiled_module->has_exports() || mem_export) { | |
1421 PropertyDescriptor desc; | |
1422 desc.set_writable(false); | |
1423 | |
1424 Handle<JSObject> exports_object = instance; | |
1425 if (origin == kWasmOrigin) { | |
1426 // Create the "exports" object. | |
1427 Handle<JSFunction> object_function = Handle<JSFunction>( | |
1428 isolate->native_context()->object_function(), isolate); | |
1429 exports_object = factory->NewJSObject(object_function, TENURED); | |
1430 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); | |
1431 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); | |
1432 } | |
1433 int first_export = -1; | |
1434 // TODO(wasm): another iteration over the code objects. | |
1435 for (int i = 0; i < code_table->length(); i++) { | |
1436 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | |
1437 if (code->kind() == Code::JS_TO_WASM_FUNCTION) { | |
1438 first_export = i; | |
1439 break; | |
1440 } | |
1441 } | |
1442 if (compiled_module->has_exports()) { | |
1443 Handle<FixedArray> exports = compiled_module->exports(); | |
1444 int export_size = exports->length(); | |
1445 for (int i = 0; i < export_size; ++i) { | |
1446 Handle<FixedArray> export_data = | |
1447 exports->GetValueChecked<FixedArray>(isolate, i); | |
1448 Handle<String> name = | |
1449 export_data->GetValueChecked<String>(isolate, kExportName); | |
1450 int arity = Smi::cast(export_data->get(kExportArity))->value(); | |
1451 MaybeHandle<ByteArray> signature = | |
1452 export_data->GetValue<ByteArray>(isolate, kExportedSignature); | |
1453 Handle<Code> export_code = | |
1454 code_table->GetValueChecked<Code>(isolate, first_export + i); | |
1455 Handle<JSFunction> function = WrapExportCodeAsJSFunction( | |
1456 isolate, export_code, name, arity, signature, instance); | |
1457 desc.set_value(function); | |
1458 Maybe<bool> status = JSReceiver::DefineOwnProperty( | |
1459 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); | |
1460 if (!status.IsJust()) { | |
1461 thrower->Error("export of %.*s failed.", name->length(), | |
1462 name->ToCString().get()); | |
1463 return nothing; | |
1464 } | |
1465 } | |
1466 } | |
1467 if (mem_export) { | |
1468 // Export the memory as a named property. | |
1469 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>( | |
1470 JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer))); | |
1471 Handle<Object> memory_object = | |
1472 WasmJs::CreateWasmMemoryObject(isolate, buffer, false, 0); | |
1473 // TODO(titzer): export the memory with the correct name. | |
1474 Handle<String> name = factory->InternalizeUtf8String("memory"); | |
1475 JSObject::AddProperty(exports_object, name, memory_object, READ_ONLY); | |
1476 } | |
1477 } | |
1478 | |
1479 if (num_imported_functions > 0 || !owner.is_null()) { | |
1480 // If the code was cloned, or new imports were compiled, patch. | |
1481 PatchDirectCalls(old_code_table, code_table, num_imported_functions); | |
1482 } | |
1483 | |
1484 FlushICache(isolate, code_table); | |
1485 | |
1486 //-------------------------------------------------------------------------- | |
1487 // Run the start function if one was specified. | |
1488 //-------------------------------------------------------------------------- | |
1489 if (compiled_module->has_startup_function()) { | |
1490 Handle<FixedArray> startup_data = compiled_module->startup_function(); | |
1491 HandleScope scope(isolate); | |
1492 int32_t start_index = | |
1493 startup_data->GetValueChecked<Smi>(isolate, kExportedFunctionIndex) | |
1494 ->value(); | |
1495 Handle<Code> startup_code = | |
1496 code_table->GetValueChecked<Code>(isolate, start_index); | |
1497 int arity = Smi::cast(startup_data->get(kExportArity))->value(); | |
1498 MaybeHandle<ByteArray> startup_signature = | |
1499 startup_data->GetValue<ByteArray>(isolate, kExportedSignature); | |
1500 Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction( | |
1501 isolate, startup_code, factory->InternalizeUtf8String("start"), arity, | |
1502 startup_signature, instance); | |
1503 RecordStats(isolate, *startup_code); | |
1504 // Call the JS function. | |
1505 Handle<Object> undefined = isolate->factory()->undefined_value(); | |
1506 MaybeHandle<Object> retval = | |
1507 Execution::Call(isolate, startup_fct, undefined, 0, nullptr); | |
1508 | |
1509 if (retval.is_null()) { | |
1510 thrower->Error("WASM.instantiateModule(): start function failed"); | |
1511 return nothing; | |
1512 } | |
1513 } | |
1514 | |
1515 DCHECK(wasm::IsWasmObject(*instance)); | |
1516 | |
1517 { | |
1518 Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance); | |
1519 | |
1520 Handle<Object> global_handle = isolate->global_handles()->Create(*instance); | |
1521 Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module); | |
1522 { | |
1523 DisallowHeapAllocation no_gc; | |
1524 compiled_module->set_weak_owning_instance(link_to_owner); | |
1525 Handle<WeakCell> next; | |
1526 if (link_to_original.ToHandle(&next) && !next->cleared()) { | |
1527 WasmCompiledModule* original = WasmCompiledModule::cast(next->value()); | |
1528 DCHECK(original->has_weak_owning_instance()); | |
1529 DCHECK(!original->weak_owning_instance()->cleared()); | |
1530 compiled_module->set_weak_next_instance(next); | |
1531 original->set_weak_prev_instance(link_to_clone); | |
1532 } | |
1533 | |
1534 compiled_module->set_weak_owning_instance(link_to_owner); | |
1535 instance->SetInternalField(kWasmCompiledModule, *compiled_module); | |
1536 GlobalHandles::MakeWeak(global_handle.location(), | |
1537 global_handle.location(), &InstanceFinalizer, | |
1538 v8::WeakCallbackType::kFinalizer); | |
1539 } | |
1540 } | |
1541 TRACE("Finishing instance %d\n", compiled_module->instance_id()); | |
1542 TRACE_CHAIN(WasmCompiledModule::cast(module_object->GetInternalField(0))); | |
1543 return instance; | |
1544 } | 1857 } |
1545 | 1858 |
1546 #if DEBUG | |
1547 uint32_t WasmCompiledModule::instance_id_counter_ = 0; | |
1548 #endif | |
1549 | |
1550 Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate, | 1859 Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate, |
1551 uint32_t min_memory_pages, | 1860 uint32_t min_memory_pages, |
1552 uint32_t globals_size, | 1861 uint32_t globals_size, |
1553 bool export_memory, | |
1554 ModuleOrigin origin) { | 1862 ModuleOrigin origin) { |
1555 Handle<FixedArray> ret = | 1863 Handle<FixedArray> ret = |
1556 isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED); | 1864 isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED); |
1557 // Globals size is expected to fit into an int without overflow. This is not | 1865 // Globals size is expected to fit into an int without overflow. This is not |
1558 // supported by the spec at the moment, however, we don't support array | 1866 // supported by the spec at the moment, however, we don't support array |
1559 // buffer sizes over 1g, so, for now, we avoid alocating a HeapNumber for | 1867 // buffer sizes over 1g, so, for now, we avoid alocating a HeapNumber for |
1560 // the globals size. The CHECK guards this assumption. | 1868 // the globals size. The CHECK guards this assumption. |
1561 CHECK_GE(static_cast<int>(globals_size), 0); | 1869 CHECK_GE(static_cast<int>(globals_size), 0); |
1562 ret->set(kID_min_memory_pages, | 1870 ret->set(kID_min_memory_pages, |
1563 Smi::FromInt(static_cast<int>(min_memory_pages))); | 1871 Smi::FromInt(static_cast<int>(min_memory_pages))); |
1564 ret->set(kID_globals_size, Smi::FromInt(static_cast<int>(globals_size))); | 1872 ret->set(kID_globals_size, Smi::FromInt(static_cast<int>(globals_size))); |
1565 ret->set(kID_export_memory, Smi::FromInt(static_cast<int>(export_memory))); | |
1566 ret->set(kID_origin, Smi::FromInt(static_cast<int>(origin))); | 1873 ret->set(kID_origin, Smi::FromInt(static_cast<int>(origin))); |
1567 WasmCompiledModule::cast(*ret)->Init(); | 1874 WasmCompiledModule::cast(*ret)->Init(); |
1568 return handle(WasmCompiledModule::cast(*ret)); | 1875 return handle(WasmCompiledModule::cast(*ret)); |
1569 } | 1876 } |
1570 | 1877 |
1571 void WasmCompiledModule::Init() { | 1878 void WasmCompiledModule::Init() { |
1572 #if DEBUG | 1879 #if DEBUG |
1573 set(kID_instance_id, Smi::FromInt(instance_id_counter_++)); | 1880 static uint32_t instance_id_counter = 0; |
| 1881 set(kID_instance_id, Smi::FromInt(instance_id_counter++)); |
1574 TRACE("New compiled module id: %d\n", instance_id()); | 1882 TRACE("New compiled module id: %d\n", instance_id()); |
1575 #endif | 1883 #endif |
1576 } | 1884 } |
1577 | 1885 |
1578 void WasmCompiledModule::PrintInstancesChain() { | 1886 void WasmCompiledModule::PrintInstancesChain() { |
1579 #if DEBUG | 1887 #if DEBUG |
1580 if (!FLAG_trace_wasm_instances) return; | 1888 if (!FLAG_trace_wasm_instances) return; |
1581 for (WasmCompiledModule* current = this; current != nullptr;) { | 1889 for (WasmCompiledModule* current = this; current != nullptr;) { |
1582 PrintF("->%d", current->instance_id()); | 1890 PrintF("->%d", current->instance_id()); |
1583 if (current->ptr_to_weak_next_instance() == nullptr) break; | 1891 if (current->ptr_to_weak_next_instance() == nullptr) break; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1667 if (!IsWasmObject(*object)) { | 1975 if (!IsWasmObject(*object)) { |
1668 return false; | 1976 return false; |
1669 } | 1977 } |
1670 | 1978 |
1671 // Get code table associated with the module js_object | 1979 // Get code table associated with the module js_object |
1672 Object* obj = object->GetInternalField(kWasmModuleCodeTable); | 1980 Object* obj = object->GetInternalField(kWasmModuleCodeTable); |
1673 Handle<FixedArray> code_table(FixedArray::cast(obj)); | 1981 Handle<FixedArray> code_table(FixedArray::cast(obj)); |
1674 | 1982 |
1675 // Iterate through the code objects in the code table and update relocation | 1983 // Iterate through the code objects in the code table and update relocation |
1676 // information | 1984 // information |
1677 for (int i = 0; i < code_table->length(); i++) { | 1985 for (int i = 0; i < code_table->length(); ++i) { |
1678 obj = code_table->get(i); | 1986 obj = code_table->get(i); |
1679 Handle<Code> code(Code::cast(obj)); | 1987 Handle<Code> code(Code::cast(obj)); |
1680 | 1988 |
1681 int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) | | 1989 int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) | |
1682 RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE); | 1990 RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE); |
1683 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { | 1991 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { |
1684 RelocInfo::Mode mode = it.rinfo()->rmode(); | 1992 RelocInfo::Mode mode = it.rinfo()->rmode(); |
1685 if (RelocInfo::IsWasmMemoryReference(mode) || | 1993 if (RelocInfo::IsWasmMemoryReference(mode) || |
1686 RelocInfo::IsWasmMemorySizeReference(mode)) { | 1994 RelocInfo::IsWasmMemorySizeReference(mode)) { |
1687 it.rinfo()->update_wasm_memory_reference(old_start, new_start, old_size, | 1995 it.rinfo()->update_wasm_memory_reference(old_start, new_start, old_size, |
(...skipping 14 matching lines...) Expand all Loading... |
1702 for (uint32_t i = 0; i < table->size; ++i) { | 2010 for (uint32_t i = 0; i < table->size; ++i) { |
1703 const WasmFunction* function = &module->functions[table->values[i]]; | 2011 const WasmFunction* function = &module->functions[table->values[i]]; |
1704 values->set(i, Smi::FromInt(function->sig_index)); | 2012 values->set(i, Smi::FromInt(function->sig_index)); |
1705 values->set(i + table->max_size, Smi::FromInt(table->values[i])); | 2013 values->set(i + table->max_size, Smi::FromInt(table->values[i])); |
1706 } | 2014 } |
1707 // Set the remaining elements to -1 (instead of "undefined"). These | 2015 // Set the remaining elements to -1 (instead of "undefined"). These |
1708 // elements are accessed directly as SMIs (without a check). On 64-bit | 2016 // elements are accessed directly as SMIs (without a check). On 64-bit |
1709 // platforms, it is possible to have the top bits of "undefined" take | 2017 // platforms, it is possible to have the top bits of "undefined" take |
1710 // small integer values (or zero), which are more likely to be equal to | 2018 // small integer values (or zero), which are more likely to be equal to |
1711 // the signature index we check against. | 2019 // the signature index we check against. |
1712 for (uint32_t i = table->size; i < table->max_size; i++) { | 2020 for (uint32_t i = table->size; i < table->max_size; ++i) { |
1713 values->set(i, Smi::FromInt(-1)); | 2021 values->set(i, Smi::FromInt(-1)); |
1714 } | 2022 } |
1715 return values; | 2023 return values; |
1716 } | 2024 } |
1717 | 2025 |
1718 void PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size, | 2026 void PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size, |
1719 const std::vector<Handle<Code>>* code_table) { | 2027 const std::vector<Handle<Code>>* code_table) { |
1720 uint32_t max_size = table->length() / 2; | 2028 uint32_t max_size = table->length() / 2; |
1721 for (uint32_t i = max_size; i < max_size + table_size; ++i) { | 2029 for (uint32_t i = max_size; i < max_size + table_size; ++i) { |
1722 int index = Smi::cast(table->get(static_cast<int>(i)))->value(); | 2030 int index = Smi::cast(table->get(static_cast<int>(i)))->value(); |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1916 WasmCompiledModule* compiled_module = | 2224 WasmCompiledModule* compiled_module = |
1917 WasmCompiledModule::cast(instance->GetInternalField(kWasmCompiledModule)); | 2225 WasmCompiledModule::cast(instance->GetInternalField(kWasmCompiledModule)); |
1918 CHECK(compiled_module->has_weak_module_object()); | 2226 CHECK(compiled_module->has_weak_module_object()); |
1919 CHECK(compiled_module->ptr_to_weak_module_object()->cleared()); | 2227 CHECK(compiled_module->ptr_to_weak_module_object()->cleared()); |
1920 } | 2228 } |
1921 | 2229 |
1922 } // namespace testing | 2230 } // namespace testing |
1923 } // namespace wasm | 2231 } // namespace wasm |
1924 } // namespace internal | 2232 } // namespace internal |
1925 } // namespace v8 | 2233 } // namespace v8 |
OLD | NEW |