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

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

Issue 2390113003: [wasm] Refactor import handling for 0xC. (Closed)
Patch Set: Add support for importing globals. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-module.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <memory> 5 #include <memory>
6 6
7 #include "src/base/atomic-utils.h" 7 #include "src/base/atomic-utils.h"
8 #include "src/code-stubs.h" 8 #include "src/code-stubs.h"
9 9
10 #include "src/macro-assembler.h" 10 #include "src/macro-assembler.h"
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/wasm/wasm-module.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698