| Index: src/wasm/wasm-module.cc
|
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
|
| index 582e5eb07bad1ae6f6ee667c3981dc6e2c3d7121..4f0b885ee020c91fd12bc500dab0d8a9643b6aa2 100644
|
| --- a/src/wasm/wasm-module.cc
|
| +++ b/src/wasm/wasm-module.cc
|
| @@ -18,6 +18,7 @@
|
| #include "src/wasm/module-decoder.h"
|
| #include "src/wasm/wasm-debug.h"
|
| #include "src/wasm/wasm-function-name-table.h"
|
| +#include "src/wasm/wasm-js.h"
|
| #include "src/wasm/wasm-module.h"
|
| #include "src/wasm/wasm-result.h"
|
|
|
| @@ -27,6 +28,39 @@ namespace v8 {
|
| namespace internal {
|
| namespace wasm {
|
|
|
| +const char* SectionName(WasmSectionCode code) {
|
| + switch (code) {
|
| + case kUnknownSectionCode:
|
| + return "Unknown";
|
| + case kTypeSectionCode:
|
| + return "Type";
|
| + case kImportSectionCode:
|
| + return "Import";
|
| + case kFunctionSectionCode:
|
| + return "Function";
|
| + case kTableSectionCode:
|
| + return "Table";
|
| + case kMemorySectionCode:
|
| + return "Memory";
|
| + case kGlobalSectionCode:
|
| + return "Global";
|
| + case kExportSectionCode:
|
| + return "Export";
|
| + case kStartSectionCode:
|
| + return "Start";
|
| + case kCodeSectionCode:
|
| + return "Code";
|
| + case kElementSectionCode:
|
| + return "Element";
|
| + case kDataSectionCode:
|
| + return "Data";
|
| + case kNameSectionCode:
|
| + return "Name";
|
| + default:
|
| + return "<unknown>";
|
| + }
|
| +}
|
| +
|
| enum JSFunctionExportInternalField {
|
| kInternalModuleInstance,
|
| kInternalArity,
|
| @@ -35,59 +69,6 @@ enum JSFunctionExportInternalField {
|
|
|
| static const int kPlaceholderMarker = 1000000000;
|
|
|
| -static const char* wasmSections[] = {
|
| -#define F(enumerator, order, string) string,
|
| - FOR_EACH_WASM_SECTION_TYPE(F)
|
| -#undef F
|
| - "<unknown>" // entry for "Max"
|
| -};
|
| -
|
| -static uint8_t wasmSectionsLengths[]{
|
| -#define F(enumerator, order, string) sizeof(string) - 1,
|
| - FOR_EACH_WASM_SECTION_TYPE(F)
|
| -#undef F
|
| - 9 // entry for "Max"
|
| -};
|
| -
|
| -static uint8_t wasmSectionsOrders[]{
|
| -#define F(enumerator, order, string) order,
|
| - FOR_EACH_WASM_SECTION_TYPE(F)
|
| -#undef F
|
| - 0 // entry for "Max"
|
| -};
|
| -
|
| -static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
|
| - (size_t)WasmSection::Code::Max + 1,
|
| - "expected enum WasmSection::Code to be monotonic from 0");
|
| -
|
| -WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
|
| -WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; }
|
| -WasmSection::Code WasmSection::next(WasmSection::Code code) {
|
| - return (WasmSection::Code)(1 + (uint32_t)code);
|
| -}
|
| -
|
| -const char* WasmSection::getName(WasmSection::Code code) {
|
| - return wasmSections[(size_t)code];
|
| -}
|
| -
|
| -size_t WasmSection::getNameLength(WasmSection::Code code) {
|
| - return wasmSectionsLengths[(size_t)code];
|
| -}
|
| -
|
| -int WasmSection::getOrder(WasmSection::Code code) {
|
| - return wasmSectionsOrders[(size_t)code];
|
| -}
|
| -
|
| -WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) {
|
| - // TODO(jfb) Linear search, it may be better to do a common-prefix search.
|
| - for (Code i = begin(); i != end(); i = next(i)) {
|
| - if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) {
|
| - return i;
|
| - }
|
| - }
|
| - return Code::Max;
|
| -}
|
| -
|
| std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
|
| os << "WASM module with ";
|
| os << (module.min_mem_pages * module.kPageSize) << " min mem";
|
| @@ -158,7 +139,7 @@ Object* GetOwningWasmInstance(Object* undefined, Code* code) {
|
|
|
| namespace {
|
| // Internal constants for the layout of the module object.
|
| -enum WasmInstanceFields {
|
| +enum WasmInstanceObjectFields {
|
| kWasmCompiledModule = 0,
|
| kWasmModuleFunctionTable,
|
| kWasmModuleCodeTable,
|
| @@ -169,6 +150,7 @@ enum WasmInstanceFields {
|
| kWasmFunctionNamesArray,
|
| kWasmModuleBytesString,
|
| kWasmDebugInfo,
|
| + kWasmNumImportedFunctions,
|
| kWasmModuleInternalFieldCount
|
| };
|
|
|
| @@ -178,17 +160,15 @@ enum WasmInstanceFields {
|
| // the compiled module is either obtained from the current v8 instance, or from
|
| // a snapshot produced by a compatible (==identical) v8 instance, we simply
|
| // fail at instantiation time, in the face of invalid data.
|
| -enum CompiledWasmObjectFields {
|
| - kFunctions, // FixedArray of Code
|
| - kImportData, // maybe FixedArray of FixedArray respecting the
|
| - // WasmImportMetadata structure.
|
| - kImportMap, // FixedArray. The i-th element is the Code object used for
|
| - // import i
|
| - kExports, // maybe FixedArray of FixedArray of WasmExportMetadata
|
| - // structure
|
| - kStartupFunction, // maybe FixedArray of WasmExportMetadata structure
|
| +enum WasmCompiledModule {
|
| + kCodeTable, // FixedArray of Code
|
| + kImportData, // maybe FixedArray of FixedArray respecting the
|
| + // WasmImportData structure.
|
| + kExportData, // maybe FixedArray of FixedArray of WasmExportData
|
| + // structure
|
| + kStartupData, // maybe FixedArray of WasmExportData structure
|
| kTableOfIndirectFunctionTables, // maybe FixedArray of FixedArray of
|
| - // WasmIndirectFunctionTableMetadata
|
| + // WasmIndirectFunctionTableData
|
| kModuleBytes, // maybe String
|
| kFunctionNameTable, // maybe ByteArray
|
| kMinRequiredMemory, // Smi. an uint32_t
|
| @@ -197,33 +177,32 @@ enum CompiledWasmObjectFields {
|
| // WasmSegmentInfo structure
|
| kDataSegments, // maybe ByteArray.
|
|
|
| - kGlobalsSize, // Smi. an uint32_t
|
| - kMemSize, // Smi.an uint32_t
|
| - kMemStart, // MaybeHandle<ArrayBuffer>
|
| - kExportMem, // Smi. bool
|
| - kOrigin, // Smi. ModuleOrigin
|
| - kNextInstance, // WeakCell. See compiled code cloning.
|
| - kPrevInstance, // WeakCell. See compiled code cloning.
|
| - kOwningInstance, // WeakCell, pointing to the owning instance.
|
| - kModuleObject, // WeakCell, pointing to the module object.
|
| - kCompiledWasmObjectTableSize // Sentinel value.
|
| + kGlobalsSize, // Smi. an uint32_t
|
| + kMemSize, // Smi.an uint32_t
|
| + kMemStart, // MaybeHandle<ArrayBuffer>
|
| + kExportMem, // Smi. bool
|
| + kOrigin, // Smi. ModuleOrigin
|
| + kNextInstance, // WeakCell. See compiled code cloning.
|
| + kPrevInstance, // WeakCell. See compiled code cloning.
|
| + kOwningInstance, // WeakCell, pointing to the owning instance.
|
| + kModuleObject, // WeakCell, pointing to the module object.
|
| + kWasmCompiledModuleSize // Sentinel value.
|
| };
|
|
|
| -enum WasmImportMetadata {
|
| - kModuleName, // String
|
| - kFunctionName, // maybe String
|
| - kOutputCount, // Smi. an uint32_t
|
| - kSignature, // ByteArray. A copy of the data in FunctionSig
|
| - kWasmImportDataTableSize // Sentinel value.
|
| +enum WasmImportData {
|
| + kModuleName, // String
|
| + kFunctionName, // maybe String
|
| + kOutputCount, // Smi. an uint32_t
|
| + kSignature, // ByteArray. A copy of the data in FunctionSig
|
| + kWasmImportDataSize // Sentinel value.
|
| };
|
|
|
| -enum WasmExportMetadata {
|
| - kExportCode, // Code
|
| - kExportName, // String
|
| - kExportArity, // Smi, an int
|
| - kExportedFunctionIndex, // Smi, an uint32_t
|
| - kExportedSignature, // ByteArray. A copy of the data in FunctionSig
|
| - kWasmExportMetadataTableSize // Sentinel value.
|
| +enum WasmExportData {
|
| + kExportName, // String
|
| + kExportArity, // Smi, an int
|
| + kExportedFunctionIndex, // Smi, an uint32_t
|
| + kExportedSignature, // ByteArray. A copy of the data in FunctionSig
|
| + kWasmExportDataSize // Sentinel value.
|
| };
|
|
|
| enum WasmSegmentInfo {
|
| @@ -232,10 +211,10 @@ enum WasmSegmentInfo {
|
| kWasmSegmentInfoSize // Sentinel value.
|
| };
|
|
|
| -enum WasmIndirectFunctionTableMetadata {
|
| - kSize, // Smi. an uint32_t
|
| - kTable, // FixedArray of indirect function table
|
| - kWasmIndirectFunctionTableMetadataSize // Sentinel value.
|
| +enum WasmIndirectFunctionTableData {
|
| + kSize, // Smi. an uint32_t
|
| + kTable, // FixedArray of indirect function table
|
| + kWasmIndirectFunctionTableDataSize // Sentinel value.
|
| };
|
|
|
| uint32_t GetMinModuleMemSize(const WasmModule* module) {
|
| @@ -279,7 +258,6 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
|
| static_cast<int>(module->data_segments.size()), TENURED);
|
| uint32_t data_size = 0;
|
| for (const WasmDataSegment& segment : module->data_segments) {
|
| - if (!segment.init) continue;
|
| if (segment.source_size == 0) continue;
|
| data_size += segment.source_size;
|
| }
|
| @@ -288,11 +266,12 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
|
| uint32_t last_insertion_pos = 0;
|
| for (uint32_t i = 0; i < module->data_segments.size(); ++i) {
|
| const WasmDataSegment& segment = module->data_segments[i];
|
| - if (!segment.init) continue;
|
| if (segment.source_size == 0) continue;
|
| Handle<ByteArray> js_segment =
|
| factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED);
|
| - js_segment->set_int(kDestAddr, segment.dest_addr);
|
| + // TODO(titzer): add support for global offsets for dest_addr
|
| + CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind);
|
| + js_segment->set_int(kDestAddr, segment.dest_addr.val.i32_const);
|
| js_segment->set_int(kSourceSize, segment.source_size);
|
| segments->set(i, *js_segment);
|
| data->copy_in(last_insertion_pos,
|
| @@ -401,86 +380,67 @@ Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index,
|
| return code;
|
| }
|
|
|
| -// TODO(mtrofin): remove when we stop relying on placeholders.
|
| -void InitializePlaceholders(Factory* factory,
|
| - std::vector<Handle<Code>>* placeholders,
|
| - size_t size) {
|
| - DCHECK(placeholders->empty());
|
| - placeholders->reserve(size);
|
| -
|
| - for (uint32_t i = 0; i < size; ++i) {
|
| - placeholders->push_back(CreatePlaceholder(factory, i, Code::WASM_FUNCTION));
|
| - }
|
| -}
|
| -
|
| -bool LinkFunction(Isolate* isolate, Handle<Code> unlinked,
|
| - Handle<FixedArray> code_targets,
|
| - Code::Kind kind = Code::WASM_FUNCTION) {
|
| +bool LinkFunction(Handle<Code> unlinked,
|
| + std::vector<Handle<Code>>& code_table) {
|
| bool modified = false;
|
| int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
| AllowDeferredHandleDereference embedding_raw_address;
|
| for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) {
|
| - Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
|
| - if (target->kind() == kind &&
|
| - target->constant_pool_offset() >= kPlaceholderMarker) {
|
| - // Patch direct calls to placeholder code objects.
|
| - uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
|
| - CHECK(index < static_cast<uint32_t>(code_targets->length()));
|
| - Handle<Code> new_target =
|
| - code_targets->GetValueChecked<Code>(isolate, index);
|
| - if (target != *new_target) {
|
| - it.rinfo()->set_target_address(new_target->instruction_start(),
|
| - UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
|
| - modified = true;
|
| + RelocInfo::Mode mode = it.rinfo()->rmode();
|
| + if (RelocInfo::IsCodeTarget(mode)) {
|
| + Code* target =
|
| + Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
|
| + if (target->constant_pool_offset() < kPlaceholderMarker) continue;
|
| + switch (target->kind()) {
|
| + case Code::WASM_FUNCTION: // fall through
|
| + case Code::WASM_TO_JS_FUNCTION: // fall through
|
| + case Code::JS_TO_WASM_FUNCTION: {
|
| + // Patch direct calls to placeholder code objects.
|
| + uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
|
| + Handle<Code> new_target = code_table[index];
|
| + if (target != *new_target) {
|
| + it.rinfo()->set_target_address(new_target->instruction_start(),
|
| + UPDATE_WRITE_BARRIER,
|
| + SKIP_ICACHE_FLUSH);
|
| + modified = true;
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + break;
|
| }
|
| }
|
| }
|
| return modified;
|
| }
|
|
|
| -void LinkModuleFunctions(Isolate* isolate, Handle<FixedArray> functions) {
|
| - for (int i = 0; i < functions->length(); ++i) {
|
| - Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
|
| - LinkFunction(isolate, code, functions);
|
| - }
|
| -}
|
| -
|
| -void FlushAssemblyCache(Isolate* isolate, Handle<FixedArray> functions) {
|
| +void FlushICache(Isolate* isolate, Handle<FixedArray> functions) {
|
| for (int i = 0; i < functions->length(); ++i) {
|
| Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
|
| Assembler::FlushICache(isolate, code->instruction_start(),
|
| code->instruction_size());
|
| }
|
| }
|
| +} // namespace
|
|
|
| -void SetRuntimeSupport(Isolate* isolate, Handle<JSObject> js_object) {
|
| - Handle<FixedArray> functions = Handle<FixedArray>(
|
| - FixedArray::cast(js_object->GetInternalField(kWasmModuleCodeTable)));
|
| - Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(js_object);
|
| -
|
| - for (int i = FLAG_skip_compiling_wasm_funcs; i < functions->length(); ++i) {
|
| - Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
|
| - Handle<FixedArray> deopt_data =
|
| - isolate->factory()->NewFixedArray(2, TENURED);
|
| - deopt_data->set(0, *weak_link);
|
| - deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
|
| - deopt_data->set_length(2);
|
| - code->set_deoptimization_data(*deopt_data);
|
| - }
|
| +uint32_t GetNumImportedFunctions(Handle<JSObject> wasm_object) {
|
| + return static_cast<uint32_t>(
|
| + Smi::cast(wasm_object->GetInternalField(kWasmNumImportedFunctions))
|
| + ->value());
|
| }
|
|
|
| -} // namespace
|
| -
|
| WasmModule::WasmModule(byte* module_start)
|
| : module_start(module_start),
|
| module_end(nullptr),
|
| min_mem_pages(0),
|
| max_mem_pages(0),
|
| mem_export(false),
|
| - mem_external(false),
|
| start_function_index(-1),
|
| origin(kWasmOrigin),
|
| globals_size(0),
|
| + num_imported_functions(0),
|
| + num_declared_functions(0),
|
| + num_exported_functions(0),
|
| pending_tasks(new base::Semaphore(0)) {}
|
|
|
| static MaybeHandle<JSFunction> ReportFFIError(
|
| @@ -560,7 +520,7 @@ bool FetchAndExecuteCompilationUnit(
|
| DisallowHandleDereference no_deref;
|
| DisallowCodeDependencyChange no_dependency_change;
|
|
|
| - // - 1 because AtomicIntrement returns the value after the atomic increment.
|
| + // - 1 because AtomicIncrement returns the value after the atomic increment.
|
| size_t index = next_unit->Increment(1) - 1;
|
| if (index >= compilation_units->size()) {
|
| return false;
|
| @@ -569,10 +529,8 @@ bool FetchAndExecuteCompilationUnit(
|
| compiler::WasmCompilationUnit* unit = compilation_units->at(index);
|
| if (unit != nullptr) {
|
| unit->ExecuteCompilation();
|
| - {
|
| - base::LockGuard<base::Mutex> guard(result_mutex);
|
| - executed_units->push(unit);
|
| - }
|
| + base::LockGuard<base::Mutex> guard(result_mutex);
|
| + executed_units->push(unit);
|
| }
|
| return true;
|
| }
|
| @@ -615,11 +573,6 @@ static void RecordStats(Isolate* isolate, Code* code) {
|
| code->relocation_info()->length());
|
| }
|
|
|
| -static void RecordStats(Isolate* isolate,
|
| - const std::vector<Handle<Code>>& functions) {
|
| - for (Handle<Code> c : functions) RecordStats(isolate, *c);
|
| -}
|
| -
|
| static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
|
| DisallowHeapAllocation no_gc;
|
| for (int i = 0; i < functions->length(); ++i) {
|
| @@ -638,16 +591,16 @@ Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
|
| return old_address;
|
| }
|
|
|
| -Handle<FixedArray> GetImportsMetadata(Factory* factory,
|
| - const WasmModule* module) {
|
| +Handle<FixedArray> GetImportsData(Factory* factory, const WasmModule* module) {
|
| Handle<FixedArray> ret = factory->NewFixedArray(
|
| static_cast<int>(module->import_table.size()), TENURED);
|
| for (size_t i = 0; i < module->import_table.size(); ++i) {
|
| const WasmImport& import = module->import_table[i];
|
| + if (import.kind != kExternalFunction) continue;
|
| WasmName module_name = module->GetNameOrNull(import.module_name_offset,
|
| import.module_name_length);
|
| - WasmName function_name = module->GetNameOrNull(import.function_name_offset,
|
| - import.function_name_length);
|
| + WasmName function_name = module->GetNameOrNull(import.field_name_offset,
|
| + import.field_name_length);
|
|
|
| Handle<String> module_name_string =
|
| factory->InternalizeUtf8String(module_name);
|
| @@ -655,107 +608,97 @@ Handle<FixedArray> GetImportsMetadata(Factory* factory,
|
| function_name.is_empty()
|
| ? Handle<String>::null()
|
| : factory->InternalizeUtf8String(function_name);
|
| - Handle<ByteArray> sig =
|
| - factory->NewByteArray(static_cast<int>(import.sig->parameter_count() +
|
| - import.sig->return_count()),
|
| - TENURED);
|
| - sig->copy_in(0, reinterpret_cast<const byte*>(import.sig->raw_data()),
|
| + FunctionSig* fsig = module->functions[import.index].sig;
|
| + Handle<ByteArray> sig = factory->NewByteArray(
|
| + static_cast<int>(fsig->parameter_count() + fsig->return_count()),
|
| + TENURED);
|
| + sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()),
|
| sig->length());
|
| Handle<FixedArray> encoded_import =
|
| - factory->NewFixedArray(kWasmImportDataTableSize, TENURED);
|
| + factory->NewFixedArray(kWasmImportDataSize, TENURED);
|
| encoded_import->set(kModuleName, *module_name_string);
|
| if (!function_name_string.is_null()) {
|
| encoded_import->set(kFunctionName, *function_name_string);
|
| }
|
| - encoded_import->set(
|
| - kOutputCount,
|
| - Smi::FromInt(static_cast<int>(import.sig->return_count())));
|
| + encoded_import->set(kOutputCount,
|
| + Smi::FromInt(static_cast<int>(fsig->return_count())));
|
| encoded_import->set(kSignature, *sig);
|
| ret->set(static_cast<int>(i), *encoded_import);
|
| }
|
| return ret;
|
| }
|
|
|
| -bool CompileWrappersToImportedFunctions(Isolate* isolate,
|
| - const Handle<JSReceiver> ffi,
|
| - std::vector<Handle<Code>>& imports,
|
| - Handle<FixedArray> import_data,
|
| - ErrorThrower* thrower) {
|
| - uint32_t import_count = static_cast<uint32_t>(import_data->length());
|
| - if (import_count > 0) {
|
| - imports.reserve(import_count);
|
| - for (uint32_t index = 0; index < import_count; ++index) {
|
| - Handle<FixedArray> data =
|
| - import_data->GetValueChecked<FixedArray>(isolate, index);
|
| - Handle<String> module_name =
|
| - data->GetValueChecked<String>(isolate, kModuleName);
|
| - MaybeHandle<String> function_name =
|
| - data->GetValue<String>(isolate, kFunctionName);
|
| -
|
| - // TODO(mtrofin): this is an uint32_t, actually. We should rationalize
|
| - // it when we rationalize signed/unsigned stuff.
|
| - int ret_count = Smi::cast(data->get(kOutputCount))->value();
|
| - CHECK(ret_count >= 0);
|
| - Handle<ByteArray> sig_data =
|
| - data->GetValueChecked<ByteArray>(isolate, kSignature);
|
| - int sig_data_size = sig_data->length();
|
| - int param_count = sig_data_size - ret_count;
|
| - CHECK(param_count >= 0);
|
| -
|
| - MaybeHandle<JSReceiver> function = LookupFunction(
|
| - thrower, isolate->factory(), ffi, index, module_name, function_name);
|
| - if (function.is_null()) return false;
|
| - Handle<Code> code;
|
| - Handle<JSReceiver> target = function.ToHandleChecked();
|
| - bool isMatch = false;
|
| - Handle<Code> export_wrapper_code;
|
| - if (target->IsJSFunction()) {
|
| - Handle<JSFunction> func = Handle<JSFunction>::cast(target);
|
| - export_wrapper_code = handle(func->code());
|
| - if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) {
|
| - int exported_param_count =
|
| - Smi::cast(func->GetInternalField(kInternalArity))->value();
|
| - Handle<ByteArray> exportedSig = Handle<ByteArray>(
|
| - ByteArray::cast(func->GetInternalField(kInternalSignature)));
|
| - if (exported_param_count == param_count &&
|
| - exportedSig->length() == sig_data->length() &&
|
| - memcmp(exportedSig->data(), sig_data->data(),
|
| - exportedSig->length()) == 0) {
|
| - isMatch = true;
|
| - }
|
| - }
|
| +Handle<Code> CompileImportWrapper(Isolate* isolate,
|
| + const Handle<JSReceiver> ffi, int index,
|
| + Handle<FixedArray> import_data,
|
| + ErrorThrower* thrower) {
|
| + Handle<FixedArray> data =
|
| + import_data->GetValueChecked<FixedArray>(isolate, index);
|
| + Handle<String> module_name =
|
| + data->GetValueChecked<String>(isolate, kModuleName);
|
| + MaybeHandle<String> function_name =
|
| + data->GetValue<String>(isolate, kFunctionName);
|
| +
|
| + // TODO(mtrofin): this is an uint32_t, actually. We should rationalize
|
| + // it when we rationalize signed/unsigned stuff.
|
| + int ret_count = Smi::cast(data->get(kOutputCount))->value();
|
| + CHECK_GE(ret_count, 0);
|
| + Handle<ByteArray> sig_data =
|
| + data->GetValueChecked<ByteArray>(isolate, kSignature);
|
| + int sig_data_size = sig_data->length();
|
| + int param_count = sig_data_size - ret_count;
|
| + CHECK(param_count >= 0);
|
| +
|
| + MaybeHandle<JSReceiver> function = LookupFunction(
|
| + thrower, isolate->factory(), ffi, index, module_name, function_name);
|
| + if (function.is_null()) return Handle<Code>::null();
|
| + Handle<Code> code;
|
| + Handle<JSReceiver> target = function.ToHandleChecked();
|
| + bool isMatch = false;
|
| + Handle<Code> export_wrapper_code;
|
| + if (target->IsJSFunction()) {
|
| + Handle<JSFunction> func = Handle<JSFunction>::cast(target);
|
| + export_wrapper_code = handle(func->code());
|
| + if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) {
|
| + int exported_param_count =
|
| + Smi::cast(func->GetInternalField(kInternalArity))->value();
|
| + Handle<ByteArray> exportedSig = Handle<ByteArray>(
|
| + ByteArray::cast(func->GetInternalField(kInternalSignature)));
|
| + if (exported_param_count == param_count &&
|
| + exportedSig->length() == sig_data->length() &&
|
| + memcmp(exportedSig->data(), sig_data->data(),
|
| + exportedSig->length()) == 0) {
|
| + isMatch = true;
|
| }
|
| - if (isMatch) {
|
| - int wasm_count = 0;
|
| - int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
| - for (RelocIterator it(*export_wrapper_code, mask); !it.done();
|
| - it.next()) {
|
| - RelocInfo* rinfo = it.rinfo();
|
| - Address target_address = rinfo->target_address();
|
| - Code* target = Code::GetCodeFromTargetAddress(target_address);
|
| - if (target->kind() == Code::WASM_FUNCTION) {
|
| - ++wasm_count;
|
| - code = handle(target);
|
| - }
|
| - }
|
| - DCHECK(wasm_count == 1);
|
| - } else {
|
| - // Copy the signature to avoid a raw pointer into a heap object when
|
| - // GC can happen.
|
| - Zone zone(isolate->allocator());
|
| - MachineRepresentation* reps =
|
| - zone.NewArray<MachineRepresentation>(sig_data_size);
|
| - memcpy(reps, sig_data->data(),
|
| - sizeof(MachineRepresentation) * sig_data_size);
|
| - FunctionSig sig(ret_count, param_count, reps);
|
| -
|
| - code = compiler::CompileWasmToJSWrapper(isolate, target, &sig, index,
|
| - module_name, function_name);
|
| + }
|
| + }
|
| + if (isMatch) {
|
| + int wasm_count = 0;
|
| + int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
| + for (RelocIterator it(*export_wrapper_code, mask); !it.done(); it.next()) {
|
| + RelocInfo* rinfo = it.rinfo();
|
| + Address target_address = rinfo->target_address();
|
| + Code* target = Code::GetCodeFromTargetAddress(target_address);
|
| + if (target->kind() == Code::WASM_FUNCTION) {
|
| + ++wasm_count;
|
| + code = handle(target);
|
| }
|
| - imports.push_back(code);
|
| }
|
| + DCHECK(wasm_count == 1);
|
| + return code;
|
| + } else {
|
| + // Copy the signature to avoid a raw pointer into a heap object when
|
| + // GC can happen.
|
| + Zone zone(isolate->allocator());
|
| + MachineRepresentation* reps =
|
| + zone.NewArray<MachineRepresentation>(sig_data_size);
|
| + memcpy(reps, sig_data->data(),
|
| + sizeof(MachineRepresentation) * sig_data_size);
|
| + FunctionSig sig(ret_count, param_count, reps);
|
| +
|
| + return compiler::CompileWasmToJSWrapper(isolate, target, &sig, index,
|
| + module_name, function_name);
|
| }
|
| - return true;
|
| }
|
|
|
| void InitializeParallelCompilation(
|
| @@ -763,8 +706,10 @@ void InitializeParallelCompilation(
|
| std::vector<compiler::WasmCompilationUnit*>& compilation_units,
|
| ModuleEnv& module_env, ErrorThrower* thrower) {
|
| for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
|
| - compilation_units[i] = new compiler::WasmCompilationUnit(
|
| - thrower, isolate, &module_env, &functions[i], i);
|
| + const WasmFunction* func = &functions[i];
|
| + compilation_units[i] =
|
| + func->imported ? nullptr : new compiler::WasmCompilationUnit(
|
| + thrower, isolate, &module_env, func, i);
|
| }
|
| }
|
|
|
| @@ -894,8 +839,8 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module,
|
| for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
|
| i < module->functions.size(); ++i) {
|
| const WasmFunction& func = module->functions[i];
|
| + if (func.imported) continue; // Imports are compiled at instantiation time.
|
|
|
| - DCHECK_EQ(i, func.func_index);
|
| WasmName str = module->GetName(func.name_offset, func.name_length);
|
| Handle<Code> code = Handle<Code>::null();
|
| // Compile the function.
|
| @@ -911,91 +856,8 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module,
|
| }
|
| }
|
|
|
| -void SetDebugSupport(Factory* factory, Handle<FixedArray> compiled_module,
|
| - Handle<JSObject> js_object) {
|
| - Isolate* isolate = compiled_module->GetIsolate();
|
| - MaybeHandle<String> module_bytes_string =
|
| - compiled_module->GetValue<String>(isolate, kModuleBytes);
|
| - if (!module_bytes_string.is_null()) {
|
| - js_object->SetInternalField(kWasmModuleBytesString,
|
| - *module_bytes_string.ToHandleChecked());
|
| - }
|
| -
|
| - MaybeHandle<ByteArray> function_name_table =
|
| - compiled_module->GetValue<ByteArray>(isolate, kFunctionNameTable);
|
| - if (!function_name_table.is_null()) {
|
| - js_object->SetInternalField(kWasmFunctionNamesArray,
|
| - *function_name_table.ToHandleChecked());
|
| - }
|
| -}
|
| -
|
| -bool SetupGlobals(Isolate* isolate, MaybeHandle<JSObject> template_owner,
|
| - Handle<FixedArray> compiled_module, Handle<JSObject> instance,
|
| - ErrorThrower* thrower) {
|
| - uint32_t globals_size = static_cast<uint32_t>(
|
| - Smi::cast(compiled_module->get(kGlobalsSize))->value());
|
| - if (globals_size > 0) {
|
| - Handle<JSArrayBuffer> globals_buffer =
|
| - NewArrayBuffer(isolate, globals_size);
|
| - if (globals_buffer.is_null()) {
|
| - thrower->Error("Out of memory: wasm globals");
|
| - return false;
|
| - }
|
| - Address old_address =
|
| - template_owner.is_null()
|
| - ? nullptr
|
| - : GetGlobalStartAddressFromCodeTemplate(
|
| - *isolate->factory()->undefined_value(),
|
| - JSObject::cast(*template_owner.ToHandleChecked()));
|
| - RelocateGlobals(instance, old_address,
|
| - static_cast<Address>(globals_buffer->backing_store()));
|
| - instance->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool SetupInstanceHeap(Isolate* isolate, Handle<FixedArray> compiled_module,
|
| - Handle<JSObject> instance, Handle<JSArrayBuffer> memory,
|
| - ErrorThrower* thrower) {
|
| - uint32_t min_mem_pages = static_cast<uint32_t>(
|
| - Smi::cast(compiled_module->get(kMinRequiredMemory))->value());
|
| - isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
|
| - // TODO(wasm): re-enable counter for max_mem_pages when we use that field.
|
| -
|
| - if (memory.is_null() && min_mem_pages > 0) {
|
| - memory = AllocateMemory(thrower, isolate, min_mem_pages);
|
| - if (memory.is_null()) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - if (!memory.is_null()) {
|
| - instance->SetInternalField(kWasmMemArrayBuffer, *memory);
|
| - Address mem_start = static_cast<Address>(memory->backing_store());
|
| - uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number());
|
| - uint32_t old_mem_size = static_cast<uint32_t>(
|
| - compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
|
| - ->value());
|
| - MaybeHandle<JSArrayBuffer> old_mem =
|
| - compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart);
|
| - Address old_mem_start =
|
| - old_mem.is_null()
|
| - ? nullptr
|
| - : static_cast<Address>(old_mem.ToHandleChecked()->backing_store());
|
| - RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
|
| - mem_size);
|
| - LoadDataSegments(compiled_module, mem_start, mem_size);
|
| - compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
|
| - ->set_value(static_cast<double>(mem_size));
|
| - compiled_module->set(kMemStart, *memory);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
|
| - Handle<FixedArray> new_functions,
|
| - MaybeHandle<FixedArray> maybe_old_imports,
|
| - MaybeHandle<FixedArray> maybe_new_imports) {
|
| +void PatchDirectCalls(Handle<FixedArray> old_functions,
|
| + Handle<FixedArray> new_functions, int start) {
|
| DCHECK_EQ(new_functions->length(), old_functions->length());
|
|
|
| DisallowHeapAllocation no_gc;
|
| @@ -1004,19 +866,9 @@ void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
|
| old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)),
|
| Code::cast(new_functions->get(i))));
|
| }
|
| - DCHECK_EQ(maybe_old_imports.is_null(), maybe_new_imports.is_null());
|
| - if (!maybe_old_imports.is_null()) {
|
| - Handle<FixedArray> old_imports = maybe_old_imports.ToHandleChecked();
|
| - Handle<FixedArray> new_imports = maybe_new_imports.ToHandleChecked();
|
| - DCHECK_EQ(new_imports->length(), old_imports->length());
|
| - for (int i = 0; i < new_imports->length(); ++i) {
|
| - old_to_new_code.insert(std::make_pair(Code::cast(old_imports->get(i)),
|
| - Code::cast(new_imports->get(i))));
|
| - }
|
| - }
|
| int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
| AllowDeferredHandleDereference embedding_raw_address;
|
| - for (int i = 0; i < new_functions->length(); ++i) {
|
| + for (int i = start; i < new_functions->length(); ++i) {
|
| Code* wasm_function = Code::cast(new_functions->get(i));
|
| for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) {
|
| Code* old_code =
|
| @@ -1026,109 +878,16 @@ void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
|
| auto found = old_to_new_code.find(old_code);
|
| DCHECK(found != old_to_new_code.end());
|
| Code* new_code = found->second;
|
| - // Avoid redundant updates, expected for wasm functions, if we're at the
|
| - // first instance.
|
| - if (new_code == old_code) {
|
| - DCHECK(new_code->kind() == Code::WASM_FUNCTION);
|
| - continue;
|
| + if (new_code != old_code) {
|
| + it.rinfo()->set_target_address(new_code->instruction_start(),
|
| + UPDATE_WRITE_BARRIER,
|
| + SKIP_ICACHE_FLUSH);
|
| }
|
| - it.rinfo()->set_target_address(new_code->instruction_start(),
|
| - UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
|
| }
|
| }
|
| }
|
| }
|
|
|
| -bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module,
|
| - Handle<JSObject> instance, ErrorThrower* thrower,
|
| - Handle<JSReceiver> ffi) {
|
| - //-------------------------------------------------------------------------
|
| - // Compile wrappers to imported functions.
|
| - //-------------------------------------------------------------------------
|
| - std::vector<Handle<Code>> import_code;
|
| - MaybeHandle<FixedArray> maybe_import_data =
|
| - compiled_module->GetValue<FixedArray>(isolate, kImportData);
|
| - Handle<FixedArray> import_data;
|
| - if (maybe_import_data.ToHandle(&import_data)) {
|
| - if (!CompileWrappersToImportedFunctions(isolate, ffi, import_code,
|
| - import_data, thrower)) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - RecordStats(isolate, import_code);
|
| - if (import_code.empty()) return true;
|
| -
|
| - Handle<FixedArray> new_imports =
|
| - isolate->factory()->NewFixedArray(static_cast<int>(import_code.size()));
|
| - for (int i = 0; i < new_imports->length(); ++i) {
|
| - new_imports->set(i, *import_code[i]);
|
| - }
|
| - compiled_module->set(kImportMap, *new_imports);
|
| - return true;
|
| -}
|
| -
|
| -bool SetupExportsObject(Handle<FixedArray> compiled_module, Isolate* isolate,
|
| - Handle<JSObject> instance, ErrorThrower* thrower) {
|
| - Factory* factory = isolate->factory();
|
| - bool mem_export =
|
| - static_cast<bool>(Smi::cast(compiled_module->get(kExportMem))->value());
|
| - ModuleOrigin origin = static_cast<ModuleOrigin>(
|
| - Smi::cast(compiled_module->get(kOrigin))->value());
|
| -
|
| - MaybeHandle<FixedArray> maybe_exports =
|
| - compiled_module->GetValue<FixedArray>(isolate, kExports);
|
| - if (!maybe_exports.is_null() || mem_export) {
|
| - PropertyDescriptor desc;
|
| - desc.set_writable(false);
|
| -
|
| - Handle<JSObject> exports_object = instance;
|
| - if (origin == kWasmOrigin) {
|
| - // Create the "exports" object.
|
| - Handle<JSFunction> object_function = Handle<JSFunction>(
|
| - isolate->native_context()->object_function(), isolate);
|
| - exports_object = factory->NewJSObject(object_function, TENURED);
|
| - Handle<String> exports_name = factory->InternalizeUtf8String("exports");
|
| - JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
|
| - }
|
| - Handle<FixedArray> exports;
|
| - if (maybe_exports.ToHandle(&exports)) {
|
| - int exports_size = exports->length();
|
| - for (int i = 0; i < exports_size; ++i) {
|
| - if (thrower->error()) return false;
|
| - Handle<FixedArray> export_metadata =
|
| - exports->GetValueChecked<FixedArray>(isolate, i);
|
| - Handle<Code> export_code =
|
| - export_metadata->GetValueChecked<Code>(isolate, kExportCode);
|
| - RecordStats(isolate, *export_code);
|
| - Handle<String> name =
|
| - export_metadata->GetValueChecked<String>(isolate, kExportName);
|
| - int arity = Smi::cast(export_metadata->get(kExportArity))->value();
|
| - MaybeHandle<ByteArray> signature =
|
| - export_metadata->GetValue<ByteArray>(isolate, kExportedSignature);
|
| - Handle<JSFunction> function = WrapExportCodeAsJSFunction(
|
| - isolate, export_code, name, arity, signature, instance);
|
| - desc.set_value(function);
|
| - Maybe<bool> status = JSReceiver::DefineOwnProperty(
|
| - isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
|
| - if (!status.IsJust()) {
|
| - thrower->Error("export of %.*s failed.", name->length(),
|
| - name->ToCString().get());
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| - if (mem_export) {
|
| - // Export the memory as a named property.
|
| - Handle<String> name = factory->InternalizeUtf8String("memory");
|
| - Handle<JSArrayBuffer> memory = Handle<JSArrayBuffer>(
|
| - JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer)));
|
| - JSObject::AddProperty(exports_object, name, memory, READ_ONLY);
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| #define GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(Field) \
|
| WeakCell* Get##Field(const FixedArray* compiled_module) { \
|
| Object* obj = compiled_module->get(k##Field); \
|
| @@ -1166,7 +925,7 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
|
| RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) |
|
| RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE);
|
|
|
| - Object* fct_obj = compiled_module->get(kFunctions);
|
| + Object* fct_obj = compiled_module->get(kCodeTable);
|
| if (fct_obj != nullptr && fct_obj != undefined &&
|
| (old_mem_size > 0 || globals_start != nullptr)) {
|
| FixedArray* functions = FixedArray::cast(fct_obj);
|
| @@ -1253,11 +1012,11 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
|
|
|
| MaybeHandle<FixedArray> nothing;
|
|
|
| - WasmModuleInstance temp_instance_for_compilation(this);
|
| - temp_instance_for_compilation.context = isolate->native_context();
|
| - temp_instance_for_compilation.mem_size = GetMinModuleMemSize(this);
|
| - temp_instance_for_compilation.mem_start = nullptr;
|
| - temp_instance_for_compilation.globals_start = nullptr;
|
| + WasmModuleInstance temp_instance(this);
|
| + temp_instance.context = isolate->native_context();
|
| + temp_instance.mem_size = GetMinModuleMemSize(this);
|
| + temp_instance.mem_start = nullptr;
|
| + temp_instance.globals_start = nullptr;
|
|
|
| MaybeHandle<FixedArray> indirect_table =
|
| function_tables.size()
|
| @@ -1266,10 +1025,10 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
|
| : MaybeHandle<FixedArray>();
|
| for (uint32_t i = 0; i < function_tables.size(); ++i) {
|
| Handle<FixedArray> values = wasm::BuildFunctionTable(isolate, i, this);
|
| - temp_instance_for_compilation.function_tables[i] = values;
|
| + temp_instance.function_tables[i] = values;
|
|
|
| Handle<FixedArray> metadata = isolate->factory()->NewFixedArray(
|
| - kWasmIndirectFunctionTableMetadataSize, TENURED);
|
| + kWasmIndirectFunctionTableDataSize, TENURED);
|
| metadata->set(kSize, Smi::FromInt(function_tables[i].size));
|
| metadata->set(kTable, *values);
|
| indirect_table.ToHandleChecked()->set(i, *metadata);
|
| @@ -1280,77 +1039,90 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
|
|
|
| ModuleEnv module_env;
|
| module_env.module = this;
|
| - module_env.instance = &temp_instance_for_compilation;
|
| + module_env.instance = &temp_instance;
|
| module_env.origin = origin;
|
| - InitializePlaceholders(factory, &module_env.placeholders, functions.size());
|
| -
|
| - Handle<FixedArray> compiled_functions =
|
| - factory->NewFixedArray(static_cast<int>(functions.size()), TENURED);
|
| -
|
| - MaybeHandle<FixedArray> maybe_imports;
|
| - if (import_table.size() > 0) {
|
| - temp_instance_for_compilation.import_code.resize(import_table.size());
|
| - Handle<FixedArray> imports =
|
| - factory->NewFixedArray(static_cast<int>(import_table.size()));
|
| - for (uint32_t i = 0; i < import_table.size(); ++i) {
|
| - Handle<Code> placeholder =
|
| - CreatePlaceholder(factory, i, Code::WASM_TO_JS_FUNCTION);
|
| - temp_instance_for_compilation.import_code[i] = placeholder;
|
| - imports->set(i, *placeholder);
|
| - }
|
| - maybe_imports = imports;
|
| +
|
| + // The {code_table} array contains import wrappers and functions (which
|
| + // are both included in {functions.size()}, and export wrappers.
|
| + int code_table_size =
|
| + static_cast<int>(functions.size() + num_exported_functions);
|
| + Handle<FixedArray> code_table =
|
| + factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
|
| +
|
| + // Initialize the code table with placeholders.
|
| + for (uint32_t i = 0; i < functions.size(); i++) {
|
| + Code::Kind kind = Code::WASM_FUNCTION;
|
| + if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION;
|
| + Handle<Code> placeholder = CreatePlaceholder(factory, i, kind);
|
| + code_table->set(static_cast<int>(i), *placeholder);
|
| + temp_instance.function_code[i] = placeholder;
|
| }
|
| +
|
| isolate->counters()->wasm_functions_per_module()->AddSample(
|
| static_cast<int>(functions.size()));
|
| - if (FLAG_wasm_num_compilation_tasks != 0) {
|
| - CompileInParallel(isolate, this,
|
| - temp_instance_for_compilation.function_code, thrower,
|
| - &module_env);
|
| + if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
|
| + // Avoid a race condition by collecting results into a second vector.
|
| + std::vector<Handle<Code>> results;
|
| + results.reserve(temp_instance.function_code.size());
|
| + for (size_t i = 0; i < temp_instance.function_code.size(); i++) {
|
| + results.push_back(temp_instance.function_code[i]);
|
| + }
|
| + CompileInParallel(isolate, this, results, thrower, &module_env);
|
| +
|
| + for (size_t i = 0; i < results.size(); i++) {
|
| + temp_instance.function_code[i] = results[i];
|
| + }
|
| } else {
|
| - CompileSequentially(isolate, this,
|
| - temp_instance_for_compilation.function_code, thrower,
|
| + CompileSequentially(isolate, this, temp_instance.function_code, thrower,
|
| &module_env);
|
| }
|
| if (thrower->error()) return nothing;
|
|
|
| // At this point, compilation has completed. Update the code table.
|
| for (size_t i = FLAG_skip_compiling_wasm_funcs;
|
| - i < temp_instance_for_compilation.function_code.size(); ++i) {
|
| - Code* code = *temp_instance_for_compilation.function_code[i];
|
| - compiled_functions->set(static_cast<int>(i), code);
|
| + i < temp_instance.function_code.size(); ++i) {
|
| + Code* code = *temp_instance.function_code[i];
|
| + code_table->set(static_cast<int>(i), code);
|
| }
|
|
|
| - LinkModuleFunctions(isolate, compiled_functions);
|
| -
|
| - // TODO(mtrofin): do we need to flush the cache here?
|
| - FlushAssemblyCache(isolate, compiled_functions);
|
| + // Link the functions in the module.
|
| + for (size_t i = FLAG_skip_compiling_wasm_funcs;
|
| + i < temp_instance.function_code.size(); ++i) {
|
| + Handle<Code> code = temp_instance.function_code[i];
|
| + bool modified = LinkFunction(code, temp_instance.function_code);
|
| + if (modified) {
|
| + // TODO(mtrofin): do we need to flush the cache here?
|
| + Assembler::FlushICache(isolate, code->instruction_start(),
|
| + code->instruction_size());
|
| + }
|
| + }
|
|
|
| // Create the compiled module object, and populate with compiled functions
|
| // and information needed at instantiation time. This object needs to be
|
| // serializable. Instantiation may occur off a deserialized version of this
|
| // object.
|
| Handle<FixedArray> ret =
|
| - factory->NewFixedArray(kCompiledWasmObjectTableSize, TENURED);
|
| - ret->set(kFunctions, *compiled_functions);
|
| + factory->NewFixedArray(kWasmCompiledModuleSize, TENURED);
|
| + ret->set(kCodeTable, *code_table);
|
| if (!indirect_table.is_null()) {
|
| ret->set(kTableOfIndirectFunctionTables, *indirect_table.ToHandleChecked());
|
| }
|
| - if (!maybe_imports.is_null()) {
|
| - ret->set(kImportMap, *maybe_imports.ToHandleChecked());
|
| - }
|
| - Handle<FixedArray> import_data = GetImportsMetadata(factory, this);
|
| + Handle<FixedArray> import_data = GetImportsData(factory, this);
|
| ret->set(kImportData, *import_data);
|
|
|
| - // Compile export functions.
|
| - int export_size = static_cast<int>(export_table.size());
|
| - Handle<Code> startup_fct;
|
| + // Compile exported function wrappers.
|
| + int export_size = static_cast<int>(num_exported_functions);
|
| if (export_size > 0) {
|
| Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED);
|
| - for (int i = 0; i < export_size; ++i) {
|
| - Handle<FixedArray> export_metadata =
|
| - factory->NewFixedArray(kWasmExportMetadataTableSize, TENURED);
|
| - const WasmExport& exp = export_table[i];
|
| - FunctionSig* funcSig = functions[exp.func_index].sig;
|
| + int index = -1;
|
| +
|
| + for (const WasmExport& exp : export_table) {
|
| + if (exp.kind != kExternalFunction)
|
| + continue; // skip non-function exports.
|
| + index++;
|
| + Handle<FixedArray> export_data =
|
| + factory->NewFixedArray(kWasmExportDataSize, TENURED);
|
| + FunctionSig* funcSig = functions[exp.index].sig;
|
| Handle<ByteArray> exportedSig =
|
| factory->NewByteArray(static_cast<int>(funcSig->parameter_count() +
|
| funcSig->return_count()),
|
| @@ -1358,45 +1130,34 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
|
| exportedSig->copy_in(0,
|
| reinterpret_cast<const byte*>(funcSig->raw_data()),
|
| exportedSig->length());
|
| - export_metadata->set(kExportedSignature, *exportedSig);
|
| + export_data->set(kExportedSignature, *exportedSig);
|
| WasmName str = GetName(exp.name_offset, exp.name_length);
|
| Handle<String> name = factory->InternalizeUtf8String(str);
|
| - Handle<Code> code =
|
| - temp_instance_for_compilation.function_code[exp.func_index];
|
| + Handle<Code> code = code_table->GetValueChecked<Code>(isolate, exp.index);
|
| Handle<Code> export_code = compiler::CompileJSToWasmWrapper(
|
| - isolate, &module_env, code, exp.func_index);
|
| + isolate, &module_env, code, exp.index);
|
| if (thrower->error()) return nothing;
|
| - export_metadata->set(kExportCode, *export_code);
|
| - export_metadata->set(kExportName, *name);
|
| - export_metadata->set(
|
| - kExportArity, Smi::FromInt(static_cast<int>(
|
| - functions[exp.func_index].sig->parameter_count())));
|
| - export_metadata->set(kExportedFunctionIndex,
|
| - Smi::FromInt(static_cast<int>(exp.func_index)));
|
| - exports->set(i, *export_metadata);
|
| - if (exp.func_index == start_function_index) {
|
| - startup_fct = export_code;
|
| - }
|
| + export_data->set(kExportName, *name);
|
| + export_data->set(kExportArity,
|
| + Smi::FromInt(static_cast<int>(
|
| + functions[exp.index].sig->parameter_count())));
|
| + export_data->set(kExportedFunctionIndex,
|
| + Smi::FromInt(static_cast<int>(exp.index)));
|
| + exports->set(index, *export_data);
|
| + code_table->set(static_cast<int>(functions.size() + index), *export_code);
|
| }
|
| - ret->set(kExports, *exports);
|
| + ret->set(kExportData, *exports);
|
| }
|
|
|
| - // Compile startup function, if we haven't already.
|
| + // Record data for startup function.
|
| if (start_function_index >= 0) {
|
| - uint32_t index = static_cast<uint32_t>(start_function_index);
|
| HandleScope scope(isolate);
|
| - if (startup_fct.is_null()) {
|
| - Handle<Code> code = temp_instance_for_compilation.function_code[index];
|
| - DCHECK_EQ(0, functions[index].sig->parameter_count());
|
| - startup_fct =
|
| - compiler::CompileJSToWasmWrapper(isolate, &module_env, code, index);
|
| - }
|
| - Handle<FixedArray> metadata =
|
| - factory->NewFixedArray(kWasmExportMetadataTableSize, TENURED);
|
| - metadata->set(kExportCode, *startup_fct);
|
| - metadata->set(kExportArity, Smi::FromInt(0));
|
| - metadata->set(kExportedFunctionIndex, Smi::FromInt(start_function_index));
|
| - ret->set(kStartupFunction, *metadata);
|
| + Handle<FixedArray> startup_data =
|
| + factory->NewFixedArray(kWasmExportDataSize, TENURED);
|
| + startup_data->set(kExportArity, Smi::FromInt(0));
|
| + startup_data->set(kExportedFunctionIndex,
|
| + Smi::FromInt(start_function_index));
|
| + ret->set(kStartupData, *startup_data);
|
| }
|
|
|
| // TODO(wasm): saving the module bytes for debugging is wasteful. We should
|
| @@ -1421,8 +1182,7 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
|
| ret->set(kExportMem, Smi::FromInt(mem_export));
|
| ret->set(kOrigin, Smi::FromInt(origin));
|
| Handle<HeapNumber> size_as_object = factory->NewHeapNumber(
|
| - static_cast<double>(temp_instance_for_compilation.mem_size), MUTABLE,
|
| - TENURED);
|
| + static_cast<double>(temp_instance.mem_size), MUTABLE, TENURED);
|
| ret->set(kMemSize, *size_as_object);
|
| return ret;
|
| }
|
| @@ -1476,173 +1236,211 @@ Handle<FixedArray> SetupIndirectFunctionTable(
|
| return cloned_indirect_tables;
|
| }
|
|
|
| -Handle<FixedArray> CloneModuleForInstance(Isolate* isolate,
|
| - Handle<JSObject> module_object,
|
| - bool* template_is_owned,
|
| - Handle<FixedArray>* module_template) {
|
| - Factory* factory = isolate->factory();
|
| -
|
| - Handle<FixedArray> original;
|
| - for (int i = 0; i < 2; ++i) {
|
| - original = handle(FixedArray::cast(module_object->GetInternalField(0)));
|
| - if (GetOwningInstance(*original) == nullptr) {
|
| - *template_is_owned = false;
|
| - *module_template = original;
|
| - return original;
|
| - }
|
| - if (i < 1) {
|
| - isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
|
| - GarbageCollectionReason::kRuntime);
|
| - }
|
| - }
|
| - *template_is_owned = true;
|
| - *module_template = original;
|
| -
|
| - // We insert the latest clone in front.
|
| - Handle<FixedArray> clone = factory->CopyFixedArray(original);
|
| - Handle<WeakCell> weak_link_to_wasm_obj =
|
| - original->GetValueChecked<WeakCell>(isolate, kModuleObject);
|
| -
|
| - clone->set(kModuleObject, *weak_link_to_wasm_obj);
|
| - Handle<WeakCell> link_to_original = factory->NewWeakCell(original);
|
| - clone->set(kNextInstance, *link_to_original);
|
| - Handle<WeakCell> link_to_clone = factory->NewWeakCell(clone);
|
| - original->set(kPrevInstance, *link_to_clone);
|
| - JSObject::cast(weak_link_to_wasm_obj->value())->SetInternalField(0, *clone);
|
| -
|
| - // Clone each wasm code object.
|
| - Handle<FixedArray> orig_wasm_functions =
|
| - original->GetValueChecked<FixedArray>(isolate, kFunctions);
|
| - Handle<FixedArray> clone_wasm_functions =
|
| - factory->CopyFixedArray(orig_wasm_functions);
|
| - clone->set(kFunctions, *clone_wasm_functions);
|
| - for (int i = 0; i < clone_wasm_functions->length(); ++i) {
|
| - Handle<Code> orig_code =
|
| - clone_wasm_functions->GetValueChecked<Code>(isolate, i);
|
| - Handle<Code> cloned_code = factory->CopyCode(orig_code);
|
| - clone_wasm_functions->set(i, *cloned_code);
|
| - }
|
| -
|
| - MaybeHandle<FixedArray> maybe_orig_exports =
|
| - original->GetValue<FixedArray>(isolate, kExports);
|
| - Handle<FixedArray> orig_exports;
|
| - if (maybe_orig_exports.ToHandle(&orig_exports)) {
|
| - Handle<FixedArray> cloned_exports = factory->CopyFixedArray(orig_exports);
|
| - clone->set(kExports, *cloned_exports);
|
| - for (int i = 0; i < orig_exports->length(); ++i) {
|
| - Handle<FixedArray> export_metadata =
|
| - orig_exports->GetValueChecked<FixedArray>(isolate, i);
|
| - Handle<FixedArray> clone_metadata =
|
| - factory->CopyFixedArray(export_metadata);
|
| - cloned_exports->set(i, *clone_metadata);
|
| - Handle<Code> orig_code =
|
| - export_metadata->GetValueChecked<Code>(isolate, kExportCode);
|
| - Handle<Code> cloned_code = factory->CopyCode(orig_code);
|
| - clone_metadata->set(kExportCode, *cloned_code);
|
| - // TODO(wasm): This is actually a uint32_t, but since FixedArray indexes
|
| - // in int, we are taking the risk of invalid values.
|
| - int exported_fct_index =
|
| - Smi::cast(export_metadata->get(kExportedFunctionIndex))->value();
|
| - CHECK_GE(exported_fct_index, 0);
|
| - CHECK_LT(exported_fct_index, clone_wasm_functions->length());
|
| - Handle<Code> new_target = clone_wasm_functions->GetValueChecked<Code>(
|
| - isolate, exported_fct_index);
|
| - PatchJSWrapper(isolate, cloned_code, new_target);
|
| - }
|
| - }
|
| -
|
| - MaybeHandle<FixedArray> maybe_startup =
|
| - original->GetValue<FixedArray>(isolate, kStartupFunction);
|
| - if (!maybe_startup.is_null()) {
|
| - Handle<FixedArray> startup_metadata =
|
| - factory->CopyFixedArray(maybe_startup.ToHandleChecked());
|
| - Handle<Code> startup_fct_clone = factory->CopyCode(
|
| - startup_metadata->GetValueChecked<Code>(isolate, kExportCode));
|
| - startup_metadata->set(kExportCode, *startup_fct_clone);
|
| - clone->set(kStartupFunction, *startup_metadata);
|
| - // TODO(wasm): see todo above about int vs size_t indexing in FixedArray.
|
| - int startup_fct_index =
|
| - Smi::cast(startup_metadata->get(kExportedFunctionIndex))->value();
|
| - CHECK_GE(startup_fct_index, 0);
|
| - CHECK_LT(startup_fct_index, clone_wasm_functions->length());
|
| - Handle<Code> new_target =
|
| - clone_wasm_functions->GetValueChecked<Code>(isolate, startup_fct_index);
|
| - PatchJSWrapper(isolate, startup_fct_clone, new_target);
|
| - }
|
| - clone->set(kImportMap, *isolate->factory()->undefined_value());
|
| - return clone;
|
| -}
|
| -
|
| -// Instantiates a wasm module as a JSObject.
|
| -// * allocates a backing store of {mem_size} bytes.
|
| -// * installs a named property "memory" for that buffer if exported
|
| -// * installs named properties on the object for exported functions
|
| -// * compiles wasm code to machine code
|
| +// Instantiates a WASM module, creating a WebAssembly.Instance from a
|
| +// WebAssembly.Module.
|
| MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| + ErrorThrower* thrower,
|
| Handle<JSObject> module_object,
|
| Handle<JSReceiver> ffi,
|
| Handle<JSArrayBuffer> memory) {
|
| + MaybeHandle<JSObject> nothing;
|
| HistogramTimerScope wasm_instantiate_module_time_scope(
|
| isolate->counters()->wasm_instantiate_module_time());
|
| - ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
|
| Factory* factory = isolate->factory();
|
|
|
| - bool template_is_owned = false;
|
| - Handle<FixedArray> compiled_module_template;
|
| - Handle<FixedArray> compiled_module = CloneModuleForInstance(
|
| - isolate, module_object, &template_is_owned, &compiled_module_template);
|
| -
|
| - MaybeHandle<JSObject> template_owner;
|
| - if (template_is_owned) {
|
| - Handle<WeakCell> weak_owner =
|
| - compiled_module_template->GetValueChecked<WeakCell>(isolate,
|
| - kOwningInstance);
|
| - template_owner = handle(JSObject::cast(weak_owner->value()));
|
| + //--------------------------------------------------------------------------
|
| + // Reuse the compiled module (if no owner), otherwise clone.
|
| + //--------------------------------------------------------------------------
|
| + Handle<FixedArray> compiled_module;
|
| + Handle<FixedArray> code_table;
|
| + Handle<FixedArray> old_code_table;
|
| + Handle<JSObject> owner;
|
| + {
|
| + Handle<FixedArray> original(
|
| + FixedArray::cast(module_object->GetInternalField(0)), isolate);
|
| + // Always make a new copy of the code_table, since the old_code_table
|
| + // may still have placeholders for imports.
|
| + old_code_table = original->GetValueChecked<FixedArray>(isolate, kCodeTable);
|
| + code_table = factory->CopyFixedArray(old_code_table);
|
| +
|
| + WeakCell* tmp = GetOwningInstance(*original);
|
| + if (tmp != nullptr) {
|
| + // There is already an owner, clone everything.
|
| + owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate);
|
| + // Insert the latest clone in front.
|
| + compiled_module = factory->CopyFixedArray(original);
|
| + Handle<WeakCell> weak_link_to_wasm_obj =
|
| + original->GetValueChecked<WeakCell>(isolate, kModuleObject);
|
| +
|
| + compiled_module->set(kModuleObject, *weak_link_to_wasm_obj);
|
| + Handle<WeakCell> link_to_original = factory->NewWeakCell(original);
|
| + compiled_module->set(kNextInstance, *link_to_original);
|
| + Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module);
|
| + original->set(kPrevInstance, *link_to_clone);
|
| + JSObject::cast(weak_link_to_wasm_obj->value())
|
| + ->SetInternalField(0, *compiled_module);
|
| +
|
| + // Clone the code for WASM functions and exports.
|
| + for (int i = 0; i < code_table->length(); ++i) {
|
| + Handle<Code> orig_code = code_table->GetValueChecked<Code>(isolate, i);
|
| + switch (orig_code->kind()) {
|
| + case Code::WASM_TO_JS_FUNCTION:
|
| + // Imports will be overwritten with newly compiled wrappers.
|
| + break;
|
| + case Code::JS_TO_WASM_FUNCTION:
|
| + case Code::WASM_FUNCTION: {
|
| + Handle<Code> code = factory->CopyCode(orig_code);
|
| + code_table->set(i, *code);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| + RecordStats(isolate, code_table);
|
| + } else {
|
| + // There was no owner, so we can reuse the original.
|
| + compiled_module = original;
|
| + }
|
| + compiled_module->set(kCodeTable, *code_table);
|
| }
|
| - // These fields are compulsory.
|
| - Handle<FixedArray> code_table =
|
| - compiled_module->GetValueChecked<FixedArray>(isolate, kFunctions);
|
| -
|
| - RecordStats(isolate, code_table);
|
| -
|
| - MaybeHandle<JSObject> nothing;
|
|
|
| + //--------------------------------------------------------------------------
|
| + // Allocate the instance object.
|
| + //--------------------------------------------------------------------------
|
| Handle<Map> map = factory->NewMap(
|
| JS_OBJECT_TYPE,
|
| JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
|
| - Handle<JSObject> js_object = factory->NewJSObjectFromMap(map, TENURED);
|
| - js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
|
| -
|
| - // Remember the old imports, for the case when we are at the first instance -
|
| - // they will be replaced with the instance's actual imports in SetupImports.
|
| - MaybeHandle<FixedArray> old_imports =
|
| - compiled_module_template->GetValue<FixedArray>(isolate, kImportMap);
|
| - if (!(SetupInstanceHeap(isolate, compiled_module, js_object, memory,
|
| - &thrower) &&
|
| - SetupGlobals(isolate, template_owner, compiled_module, js_object,
|
| - &thrower) &&
|
| - SetupImports(isolate, compiled_module, js_object, &thrower, ffi) &&
|
| - SetupExportsObject(compiled_module, isolate, js_object, &thrower))) {
|
| - return nothing;
|
| + Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED);
|
| + instance->SetInternalField(kWasmModuleCodeTable, *code_table);
|
| +
|
| + //--------------------------------------------------------------------------
|
| + // Set up the memory for the new instance.
|
| + //--------------------------------------------------------------------------
|
| + MaybeHandle<JSArrayBuffer> old_memory;
|
| + // TODO(titzer): handle imported memory properly.
|
| +
|
| + uint32_t min_mem_pages = static_cast<uint32_t>(
|
| + Smi::cast(compiled_module->get(kMinRequiredMemory))->value());
|
| + isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
|
| + // TODO(wasm): re-enable counter for max_mem_pages when we use that field.
|
| +
|
| + if (memory.is_null() && min_mem_pages > 0) {
|
| + memory = AllocateMemory(thrower, isolate, min_mem_pages);
|
| + if (memory.is_null()) return nothing; // failed to allocate memory
|
| + }
|
| +
|
| + if (!memory.is_null()) {
|
| + instance->SetInternalField(kWasmMemArrayBuffer, *memory);
|
| + Address mem_start = static_cast<Address>(memory->backing_store());
|
| + uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number());
|
| + LoadDataSegments(compiled_module, mem_start, mem_size);
|
| +
|
| + uint32_t old_mem_size = static_cast<uint32_t>(
|
| + compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
|
| + ->value());
|
| + MaybeHandle<JSArrayBuffer> old_mem =
|
| + compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart);
|
| + Address old_mem_start =
|
| + old_mem.is_null()
|
| + ? nullptr
|
| + : static_cast<Address>(old_mem.ToHandleChecked()->backing_store());
|
| + RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
|
| + mem_size);
|
| + compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
|
| + ->set_value(static_cast<double>(mem_size));
|
| + compiled_module->set(kMemStart, *memory);
|
| }
|
|
|
| - FixupFunctionsAndImports(
|
| - compiled_module_template->GetValueChecked<FixedArray>(isolate,
|
| - kFunctions),
|
| - code_table, old_imports,
|
| - compiled_module->GetValue<FixedArray>(isolate, kImportMap));
|
| + //--------------------------------------------------------------------------
|
| + // Set up the globals for the new instance.
|
| + //--------------------------------------------------------------------------
|
| + MaybeHandle<JSArrayBuffer> old_globals;
|
| + MaybeHandle<JSArrayBuffer> globals;
|
| + uint32_t globals_size = static_cast<uint32_t>(
|
| + Smi::cast(compiled_module->get(kGlobalsSize))->value());
|
| + if (globals_size > 0) {
|
| + Handle<JSArrayBuffer> global_buffer = NewArrayBuffer(isolate, globals_size);
|
| + globals = global_buffer;
|
| + if (globals.is_null()) {
|
| + thrower->Error("Out of memory: wasm globals");
|
| + return nothing;
|
| + }
|
| + Address old_address =
|
| + owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
|
| + *isolate->factory()->undefined_value(),
|
| + JSObject::cast(*owner));
|
| + RelocateGlobals(instance, old_address,
|
| + static_cast<Address>(global_buffer->backing_store()));
|
| + instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
|
| + }
|
| +
|
| + //--------------------------------------------------------------------------
|
| + // Compile the import wrappers for the new instance.
|
| + //--------------------------------------------------------------------------
|
| + // TODO(titzer): handle imported globals and function tables.
|
| + Handle<FixedArray> import_data;
|
| + int num_imported_functions = 0;
|
| + if (compiled_module->GetValue<FixedArray>(isolate, kImportData)
|
| + .ToHandle(&import_data)) {
|
| + num_imported_functions = import_data->length();
|
| + for (int index = 0; index < num_imported_functions; index++) {
|
| + Handle<Code> import_wrapper =
|
| + CompileImportWrapper(isolate, ffi, index, import_data, thrower);
|
| + if (thrower->error()) return nothing;
|
| + code_table->set(index, *import_wrapper);
|
| + RecordStats(isolate, *import_wrapper);
|
| + }
|
| + }
|
| +
|
| + //--------------------------------------------------------------------------
|
| + // Set up the debug support for the new instance.
|
| + //--------------------------------------------------------------------------
|
| + MaybeHandle<String> module_bytes_string =
|
| + compiled_module->GetValue<String>(isolate, kModuleBytes);
|
| + if (!module_bytes_string.is_null()) {
|
| + instance->SetInternalField(kWasmModuleBytesString,
|
| + *module_bytes_string.ToHandleChecked());
|
| + }
|
|
|
| - SetDebugSupport(factory, compiled_module, js_object);
|
| - SetRuntimeSupport(isolate, js_object);
|
| + MaybeHandle<ByteArray> function_name_table =
|
| + compiled_module->GetValue<ByteArray>(isolate, kFunctionNameTable);
|
| + if (!function_name_table.is_null()) {
|
| + Handle<ByteArray> handle = function_name_table.ToHandleChecked();
|
| + instance->SetInternalField(kWasmFunctionNamesArray, *handle);
|
| + }
|
|
|
| - FlushAssemblyCache(isolate, code_table);
|
| + {
|
| + Handle<Object> handle = factory->NewNumber(num_imported_functions);
|
| + instance->SetInternalField(kWasmNumImportedFunctions, *handle);
|
| + }
|
| +
|
| + //--------------------------------------------------------------------------
|
| + // Set up the runtime support for the new instance.
|
| + //--------------------------------------------------------------------------
|
| + Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(instance);
|
| +
|
| + for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs;
|
| + i < code_table->length(); ++i) {
|
| + Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
|
| + if (code->kind() == Code::WASM_FUNCTION) {
|
| + Handle<FixedArray> deopt_data =
|
| + isolate->factory()->NewFixedArray(2, TENURED);
|
| + deopt_data->set(0, *weak_link);
|
| + deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
|
| + deopt_data->set_length(2);
|
| + code->set_deoptimization_data(*deopt_data);
|
| + }
|
| + }
|
|
|
| + //--------------------------------------------------------------------------
|
| + // Set up the indirect function tables for the new instance.
|
| + //--------------------------------------------------------------------------
|
| {
|
| std::vector<Handle<Code>> functions(
|
| static_cast<size_t>(code_table->length()));
|
| for (int i = 0; i < code_table->length(); ++i) {
|
| - functions[static_cast<size_t>(i)] =
|
| - code_table->GetValueChecked<Code>(isolate, i);
|
| + functions[i] = code_table->GetValueChecked<Code>(isolate, i);
|
| }
|
|
|
| MaybeHandle<FixedArray> maybe_indirect_tables =
|
| @@ -1651,11 +1449,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| Handle<FixedArray> indirect_tables_template;
|
| if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) {
|
| Handle<FixedArray> to_replace =
|
| - template_owner.is_null()
|
| - ? indirect_tables_template
|
| - : handle(FixedArray::cast(
|
| - template_owner.ToHandleChecked()->GetInternalField(
|
| - kWasmModuleFunctionTable)));
|
| + owner.is_null() ? indirect_tables_template
|
| + : handle(FixedArray::cast(owner->GetInternalField(
|
| + kWasmModuleFunctionTable)));
|
| Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
|
| isolate, code_table, indirect_tables_template, to_replace);
|
| for (int i = 0; i < indirect_tables->length(); ++i) {
|
| @@ -1666,24 +1462,104 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| metadata->GetValueChecked<FixedArray>(isolate, kTable);
|
| wasm::PopulateFunctionTable(table, size, &functions);
|
| }
|
| - js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
|
| + instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
|
| + }
|
| + }
|
| +
|
| + //--------------------------------------------------------------------------
|
| + // Set up the exports object for the new instance.
|
| + //--------------------------------------------------------------------------
|
| + bool mem_export =
|
| + static_cast<bool>(Smi::cast(compiled_module->get(kExportMem))->value());
|
| + ModuleOrigin origin = static_cast<ModuleOrigin>(
|
| + Smi::cast(compiled_module->get(kOrigin))->value());
|
| +
|
| + MaybeHandle<FixedArray> maybe_exports =
|
| + compiled_module->GetValue<FixedArray>(isolate, kExportData);
|
| + if (!maybe_exports.is_null() || mem_export) {
|
| + PropertyDescriptor desc;
|
| + desc.set_writable(false);
|
| +
|
| + Handle<JSObject> exports_object = instance;
|
| + if (origin == kWasmOrigin) {
|
| + // Create the "exports" object.
|
| + Handle<JSFunction> object_function = Handle<JSFunction>(
|
| + isolate->native_context()->object_function(), isolate);
|
| + exports_object = factory->NewJSObject(object_function, TENURED);
|
| + Handle<String> exports_name = factory->InternalizeUtf8String("exports");
|
| + JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
|
| + }
|
| + Handle<FixedArray> exports;
|
| + int first_export = -1;
|
| + // TODO(wasm): another iteration over the code objects.
|
| + for (int i = 0; i < code_table->length(); i++) {
|
| + Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
|
| + if (code->kind() == Code::JS_TO_WASM_FUNCTION) {
|
| + first_export = i;
|
| + break;
|
| + }
|
| + }
|
| + if (maybe_exports.ToHandle(&exports)) {
|
| + int export_size = exports->length();
|
| + for (int i = 0; i < export_size; ++i) {
|
| + Handle<FixedArray> export_data =
|
| + exports->GetValueChecked<FixedArray>(isolate, i);
|
| + Handle<String> name =
|
| + export_data->GetValueChecked<String>(isolate, kExportName);
|
| + int arity = Smi::cast(export_data->get(kExportArity))->value();
|
| + MaybeHandle<ByteArray> signature =
|
| + export_data->GetValue<ByteArray>(isolate, kExportedSignature);
|
| + Handle<Code> export_code =
|
| + code_table->GetValueChecked<Code>(isolate, first_export + i);
|
| + Handle<JSFunction> function = WrapExportCodeAsJSFunction(
|
| + isolate, export_code, name, arity, signature, instance);
|
| + desc.set_value(function);
|
| + Maybe<bool> status = JSReceiver::DefineOwnProperty(
|
| + isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
|
| + if (!status.IsJust()) {
|
| + thrower->Error("export of %.*s failed.", name->length(),
|
| + name->ToCString().get());
|
| + return nothing;
|
| + }
|
| + }
|
| + }
|
| + if (mem_export) {
|
| + // Export the memory as a named property.
|
| + Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>(
|
| + JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer)));
|
| + Handle<Object> memory_object =
|
| + WasmJs::CreateWasmMemoryObject(isolate, buffer, false, 0);
|
| + // TODO(titzer): export the memory with the correct name.
|
| + Handle<String> name = factory->InternalizeUtf8String("memory");
|
| + JSObject::AddProperty(exports_object, name, memory_object, READ_ONLY);
|
| }
|
| }
|
|
|
| + if (num_imported_functions > 0 || !owner.is_null()) {
|
| + // If the code was cloned, or new imports were compiled, patch.
|
| + PatchDirectCalls(old_code_table, code_table, num_imported_functions);
|
| + }
|
| +
|
| + FlushICache(isolate, code_table);
|
| +
|
| + //--------------------------------------------------------------------------
|
| // Run the start function if one was specified.
|
| - MaybeHandle<FixedArray> maybe_startup_fct =
|
| - compiled_module->GetValue<FixedArray>(isolate, kStartupFunction);
|
| - Handle<FixedArray> metadata;
|
| - if (maybe_startup_fct.ToHandle(&metadata)) {
|
| + //--------------------------------------------------------------------------
|
| + Handle<FixedArray> startup_data;
|
| + if (compiled_module->GetValue<FixedArray>(isolate, kStartupData)
|
| + .ToHandle(&startup_data)) {
|
| HandleScope scope(isolate);
|
| + int32_t start_index =
|
| + startup_data->GetValueChecked<Smi>(isolate, kExportedFunctionIndex)
|
| + ->value();
|
| Handle<Code> startup_code =
|
| - metadata->GetValueChecked<Code>(isolate, kExportCode);
|
| - int arity = Smi::cast(metadata->get(kExportArity))->value();
|
| + code_table->GetValueChecked<Code>(isolate, start_index);
|
| + int arity = Smi::cast(startup_data->get(kExportArity))->value();
|
| MaybeHandle<ByteArray> startup_signature =
|
| - metadata->GetValue<ByteArray>(isolate, kExportedSignature);
|
| + startup_data->GetValue<ByteArray>(isolate, kExportedSignature);
|
| Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction(
|
| isolate, startup_code, factory->InternalizeUtf8String("start"), arity,
|
| - startup_signature, js_object);
|
| + startup_signature, instance);
|
| RecordStats(isolate, *startup_code);
|
| // Call the JS function.
|
| Handle<Object> undefined = isolate->factory()->undefined_value();
|
| @@ -1691,39 +1567,25 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| Execution::Call(isolate, startup_fct, undefined, 0, nullptr);
|
|
|
| if (retval.is_null()) {
|
| - thrower.Error("WASM.instantiateModule(): start function failed");
|
| + thrower->Error("WASM.instantiateModule(): start function failed");
|
| return nothing;
|
| }
|
| }
|
|
|
| - DCHECK(wasm::IsWasmObject(*js_object));
|
| + DCHECK(wasm::IsWasmObject(*instance));
|
|
|
| if (!compiled_module->GetValue<WeakCell>(isolate, kModuleObject).is_null()) {
|
| - js_object->SetInternalField(kWasmCompiledModule, *compiled_module);
|
| - Handle<WeakCell> link_to_owner = factory->NewWeakCell(js_object);
|
| + instance->SetInternalField(kWasmCompiledModule, *compiled_module);
|
| + Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance);
|
| compiled_module->set(kOwningInstance, *link_to_owner);
|
|
|
| - Handle<Object> global_handle =
|
| - isolate->global_handles()->Create(*js_object);
|
| + Handle<Object> global_handle = isolate->global_handles()->Create(*instance);
|
| GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
|
| &InstanceFinalizer,
|
| v8::WeakCallbackType::kFinalizer);
|
| }
|
|
|
| - return js_object;
|
| -}
|
| -
|
| -// TODO(mtrofin): remove this once we move to WASM_DIRECT_CALL
|
| -Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const {
|
| - DCHECK(IsValidFunction(index));
|
| - if (!placeholders.empty()) return placeholders[index];
|
| - DCHECK_NOT_NULL(instance);
|
| - return instance->function_code[index];
|
| -}
|
| -
|
| -Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
|
| - DCHECK(IsValidImport(index));
|
| - return instance ? instance->import_code[index] : Handle<Code>::null();
|
| + return instance;
|
| }
|
|
|
| compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
|
|
|