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