| Index: src/wasm/wasm-module.cc
|
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
|
| index a25fd7b2fc0aebe1fc6b0c49b90f4e1f69bdb4fc..e48a841e45c8281733136585ff4b8bd0e6ae0d52 100644
|
| --- a/src/wasm/wasm-module.cc
|
| +++ b/src/wasm/wasm-module.cc
|
| @@ -44,62 +44,17 @@ static const int kPlaceholderMarker = 1000000000;
|
|
|
| enum JSFunctionExportInternalField {
|
| kInternalModuleInstance,
|
| - kInternalArity,
|
| - kInternalSignature
|
| + kInternalFunctionIndex
|
| };
|
|
|
| // Internal constants for the layout of the module object.
|
| enum WasmInstanceObjectFields {
|
| kWasmCompiledModule = 0,
|
| - kWasmModuleFunctionTable,
|
| - kWasmModuleCodeTable,
|
| kWasmMemObject,
|
| kWasmMemArrayBuffer,
|
| kWasmGlobalsArrayBuffer,
|
| kWasmDebugInfo,
|
| - kWasmModuleInternalFieldCount
|
| -};
|
| -
|
| -enum WasmImportData {
|
| - kImportKind, // Smi. an ExternalKind
|
| - kImportGlobalType, // Smi. Type for globals.
|
| - kImportIndex, // Smi. index for the import.
|
| - kModuleName, // String
|
| - kFunctionName, // maybe String
|
| - kOutputCount, // Smi. an uint32_t
|
| - kSignature, // ByteArray. A copy of the data in FunctionSig
|
| - kWasmImportDataSize // Sentinel value.
|
| -};
|
| -
|
| -enum WasmExportData {
|
| - kExportKind, // Smi. an ExternalKind
|
| - kExportGlobalType, // Smi. Type for globals.
|
| - kExportName, // String
|
| - kExportArity, // Smi, an int
|
| - kExportIndex, // Smi, an uint32_t
|
| - kExportedSignature, // ByteArray. A copy of the data in FunctionSig
|
| - kWasmExportDataSize // Sentinel value.
|
| -};
|
| -
|
| -enum WasmGlobalInitData {
|
| - kGlobalInitKind, // 0 = constant, 1 = global index
|
| - kGlobalInitType, // Smi. Type for globals.
|
| - kGlobalInitIndex, // Smi, an uint32_t
|
| - kGlobalInitValue, // Number.
|
| - kWasmGlobalInitDataSize
|
| -};
|
| -
|
| -enum WasmSegmentInfo {
|
| - kDestAddrKind, // 0 = constant, 1 = global index
|
| - kDestAddrValue, // Smi. an uint32_t
|
| - kSourceSize, // Smi. an uint32_t
|
| - kWasmSegmentInfoSize // Sentinel value.
|
| -};
|
| -
|
| -enum WasmIndirectFunctionTableData {
|
| - kSize, // Smi. an uint32_t
|
| - kTable, // FixedArray of indirect function table
|
| - kWasmIndirectFunctionTableDataSize // Sentinel value.
|
| + kWasmInstanceInternalFieldCount
|
| };
|
|
|
| byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
|
| @@ -110,53 +65,24 @@ uint32_t GetMinModuleMemSize(const WasmModule* module) {
|
| return WasmModule::kPageSize * module->min_mem_pages;
|
| }
|
|
|
| -void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
|
| - Handle<WasmCompiledModule> compiled_module) {
|
| - Handle<FixedArray> segments = factory->NewFixedArray(
|
| - static_cast<int>(module->data_segments.size()), TENURED);
|
| - uint32_t data_size = 0;
|
| - for (const WasmDataSegment& segment : module->data_segments) {
|
| - if (segment.source_size == 0) continue;
|
| - data_size += segment.source_size;
|
| - }
|
| - Handle<ByteArray> data = factory->NewByteArray(data_size, TENURED);
|
| -
|
| - 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.source_size == 0) continue;
|
| - Handle<ByteArray> js_segment =
|
| - factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED);
|
| - if (segment.dest_addr.kind == WasmInitExpr::kGlobalIndex) {
|
| - // The destination address is the value of a global variable.
|
| - js_segment->set_int(kDestAddrKind, 1);
|
| - uint32_t offset =
|
| - module->globals[segment.dest_addr.val.global_index].offset;
|
| - js_segment->set_int(kDestAddrValue, static_cast<int>(offset));
|
| - } else {
|
| - // The destination address is a constant.
|
| - CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind);
|
| - js_segment->set_int(kDestAddrKind, 0);
|
| - js_segment->set_int(kDestAddrValue, 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,
|
| - module->module_start + segment.source_offset,
|
| - segment.source_size);
|
| - last_insertion_pos += segment.source_size;
|
| - }
|
| - compiled_module->set_data_segments_info(segments);
|
| - compiled_module->set_data_segments(data);
|
| +MaybeHandle<String> ExtractStringFromModuleBytes(
|
| + Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
|
| + uint32_t offset, uint32_t size) {
|
| + // TODO(wasm): cache strings from modules if it's a performance win.
|
| + Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
|
| + Address raw = module_bytes->GetCharsAddress() + offset;
|
| + if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
|
| + return {}; // UTF8 decoding error for name.
|
| + return isolate->factory()->NewStringFromUtf8SubString(
|
| + module_bytes, static_cast<int>(offset), static_cast<int>(size));
|
| }
|
|
|
| -void PatchFunctionTable(Handle<Code> code,
|
| - Handle<FixedArray> old_indirect_table,
|
| - Handle<FixedArray> new_indirect_table) {
|
| +void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref,
|
| + Handle<Object> new_ref) {
|
| for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done();
|
| it.next()) {
|
| - if (it.rinfo()->target_object() == *old_indirect_table) {
|
| - it.rinfo()->set_target_object(*new_indirect_table);
|
| + if (it.rinfo()->target_object() == *old_ref) {
|
| + it.rinfo()->set_target_object(*new_ref);
|
| }
|
| }
|
| }
|
| @@ -185,33 +111,30 @@ Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) {
|
| return buffer;
|
| }
|
|
|
| -void RelocateInstanceCode(Handle<JSObject> instance, Address old_start,
|
| - Address start, uint32_t prev_size,
|
| - uint32_t new_size) {
|
| - Handle<FixedArray> functions = Handle<FixedArray>(
|
| - FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable)));
|
| - for (int i = 0; i < functions->length(); ++i) {
|
| - Handle<Code> function = Handle<Code>(Code::cast(functions->get(i)));
|
| +void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table,
|
| + Address old_start, Address start,
|
| + uint32_t prev_size, uint32_t new_size) {
|
| + for (int i = 0; i < code_table->length(); ++i) {
|
| + DCHECK(code_table->get(i)->IsCode());
|
| + Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
|
| AllowDeferredHandleDereference embedding_raw_address;
|
| int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
|
| (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
|
| - for (RelocIterator it(*function, mask); !it.done(); it.next()) {
|
| + for (RelocIterator it(*code, mask); !it.done(); it.next()) {
|
| it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size,
|
| new_size);
|
| }
|
| }
|
| }
|
|
|
| -void RelocateGlobals(Handle<JSObject> instance, Address old_start,
|
| +void RelocateGlobals(Handle<FixedArray> code_table, Address old_start,
|
| Address globals_start) {
|
| - Handle<FixedArray> functions = Handle<FixedArray>(
|
| - FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable)));
|
| - uint32_t function_count = static_cast<uint32_t>(functions->length());
|
| - for (uint32_t i = 0; i < function_count; ++i) {
|
| - Handle<Code> function = Handle<Code>(Code::cast(functions->get(i)));
|
| + for (int i = 0; i < code_table->length(); ++i) {
|
| + DCHECK(code_table->get(i)->IsCode());
|
| + Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
|
| AllowDeferredHandleDereference embedding_raw_address;
|
| int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE;
|
| - for (RelocIterator it(*function, mask); !it.done(); it.next()) {
|
| + for (RelocIterator it(*code, mask); !it.done(); it.next()) {
|
| it.rinfo()->update_wasm_global_reference(old_start, globals_start);
|
| }
|
| }
|
| @@ -265,9 +188,9 @@ bool LinkFunction(Handle<Code> unlinked,
|
| return modified;
|
| }
|
|
|
| -void FlushICache(Isolate* isolate, Handle<FixedArray> functions) {
|
| - for (int i = 0; i < functions->length(); ++i) {
|
| - Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
|
| +void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) {
|
| + for (int i = 0; i < code_table->length(); ++i) {
|
| + Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
|
| Assembler::FlushICache(isolate, code->instruction_start(),
|
| code->instruction_size());
|
| }
|
| @@ -356,69 +279,6 @@ Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
|
| return old_address;
|
| }
|
|
|
| -Handle<FixedArray> EncodeImports(Factory* factory, const WasmModule* module) {
|
| - // TODO(wasm): Encode this in one big FixedArray.
|
| - 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];
|
| - Handle<FixedArray> encoded_import =
|
| - factory->NewFixedArray(kWasmImportDataSize, TENURED);
|
| - encoded_import->set(kImportKind, Smi::FromInt(import.kind));
|
| - encoded_import->set(kImportIndex, Smi::FromInt(import.index));
|
| -
|
| - // Add the module and function name.
|
| - WasmName module_name = module->GetNameOrNull(import.module_name_offset,
|
| - import.module_name_length);
|
| - WasmName function_name = module->GetNameOrNull(import.field_name_offset,
|
| - import.field_name_length);
|
| -
|
| - Handle<String> module_name_string =
|
| - factory->InternalizeUtf8String(module_name);
|
| - encoded_import->set(kModuleName, *module_name_string);
|
| - if (!function_name.is_empty()) {
|
| - Handle<String> function_name_string =
|
| - factory->InternalizeUtf8String(function_name);
|
| - encoded_import->set(kFunctionName, *function_name_string);
|
| - }
|
| -
|
| - switch (import.kind) {
|
| - case kExternalFunction: {
|
| - // Encode the signature into the import.
|
| - 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());
|
| - encoded_import->set(
|
| - kOutputCount, Smi::FromInt(static_cast<int>(fsig->return_count())));
|
| - encoded_import->set(kSignature, *sig);
|
| - break;
|
| - }
|
| - case kExternalTable:
|
| - // Nothing extra required for imported tables.
|
| - break;
|
| - case kExternalMemory:
|
| - // Nothing extra required for imported memories.
|
| - break;
|
| - case kExternalGlobal: {
|
| - // Encode the offset and the global type into the import.
|
| - const WasmGlobal& global = module->globals[import.index];
|
| - TRACE("import[%zu].type = %s\n", i, WasmOpcodes::TypeName(global.type));
|
| - encoded_import->set(
|
| - kImportGlobalType,
|
| - Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type)));
|
| - encoded_import->set(kImportIndex, Smi::FromInt(global.offset));
|
| - break;
|
| - }
|
| - }
|
| - ret->set(static_cast<int>(i), *encoded_import);
|
| - }
|
| - return ret;
|
| -}
|
| -
|
| void InitializeParallelCompilation(
|
| Isolate* isolate, const std::vector<WasmFunction>& functions,
|
| std::vector<compiler::WasmCompilationUnit*>& compilation_units,
|
| @@ -610,15 +470,22 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
|
| WasmCompiledModule* compiled_module) {
|
| TRACE("Resetting %d\n", compiled_module->instance_id());
|
| Object* undefined = *isolate->factory()->undefined_value();
|
| - uint32_t old_mem_size = compiled_module->has_heap()
|
| - ? compiled_module->mem_size()
|
| - : compiled_module->default_mem_size();
|
| + uint32_t old_mem_size = compiled_module->mem_size();
|
| uint32_t default_mem_size = compiled_module->default_mem_size();
|
| - Object* mem_start = compiled_module->ptr_to_heap();
|
| + Object* mem_start = compiled_module->ptr_to_memory();
|
| Address old_mem_address = nullptr;
|
| Address globals_start =
|
| GetGlobalStartAddressFromCodeTemplate(undefined, owner);
|
|
|
| + // Reset function tables.
|
| + FixedArray* function_tables = nullptr;
|
| + FixedArray* empty_function_tables = nullptr;
|
| + if (compiled_module->has_function_tables()) {
|
| + function_tables = compiled_module->ptr_to_function_tables();
|
| + empty_function_tables = compiled_module->ptr_to_empty_function_tables();
|
| + compiled_module->set_ptr_to_function_tables(empty_function_tables);
|
| + }
|
| +
|
| if (old_mem_size > 0) {
|
| CHECK_NE(mem_start, undefined);
|
| old_mem_address =
|
| @@ -626,8 +493,11 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
|
| }
|
| int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) |
|
| RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) |
|
| - RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE);
|
| + RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE) |
|
| + RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
|
|
| + // Patch code to update memory references, global references, and function
|
| + // table references.
|
| Object* fct_obj = compiled_module->ptr_to_code_table();
|
| if (fct_obj != nullptr && fct_obj != undefined &&
|
| (old_mem_size > 0 || globals_start != nullptr)) {
|
| @@ -642,10 +512,17 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
|
| it.rinfo()->update_wasm_memory_reference(
|
| old_mem_address, nullptr, old_mem_size, default_mem_size);
|
| changed = true;
|
| - } else {
|
| - CHECK(RelocInfo::IsWasmGlobalReference(mode));
|
| + } else if (RelocInfo::IsWasmGlobalReference(mode)) {
|
| it.rinfo()->update_wasm_global_reference(globals_start, nullptr);
|
| changed = true;
|
| + } else if (RelocInfo::IsEmbeddedObject(mode) && function_tables) {
|
| + Object* old = it.rinfo()->target_object();
|
| + for (int i = 0; i < function_tables->length(); ++i) {
|
| + if (function_tables->get(i) == old) {
|
| + it.rinfo()->set_target_object(empty_function_tables->get(i));
|
| + changed = true;
|
| + }
|
| + }
|
| }
|
| }
|
| if (changed) {
|
| @@ -654,7 +531,7 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
|
| }
|
| }
|
| }
|
| - compiled_module->reset_heap();
|
| + compiled_module->reset_memory();
|
| }
|
|
|
| static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
| @@ -663,16 +540,16 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
| WasmCompiledModule* compiled_module = GetCompiledModule(owner);
|
| TRACE("Finalizing %d {\n", compiled_module->instance_id());
|
| Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
|
| - DCHECK(compiled_module->has_weak_module_object());
|
| - WeakCell* weak_module_obj = compiled_module->ptr_to_weak_module_object();
|
| + DCHECK(compiled_module->has_weak_wasm_module());
|
| + WeakCell* weak_wasm_module = compiled_module->ptr_to_weak_wasm_module();
|
|
|
| - // weak_module_obj may have been cleared, meaning the module object
|
| + // weak_wasm_module may have been cleared, meaning the module object
|
| // was GC-ed. In that case, there won't be any new instances created,
|
| // and we don't need to maintain the links between instances.
|
| - if (!weak_module_obj->cleared()) {
|
| - JSObject* module_obj = JSObject::cast(weak_module_obj->value());
|
| + if (!weak_wasm_module->cleared()) {
|
| + JSObject* wasm_module = JSObject::cast(weak_wasm_module->value());
|
| WasmCompiledModule* current_template =
|
| - WasmCompiledModule::cast(module_obj->GetInternalField(0));
|
| + WasmCompiledModule::cast(wasm_module->GetInternalField(0));
|
|
|
| TRACE("chain before {\n");
|
| TRACE_CHAIN(current_template);
|
| @@ -687,7 +564,7 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
| ResetCompiledModule(isolate, owner, compiled_module);
|
| } else {
|
| DCHECK(next->value()->IsFixedArray());
|
| - module_obj->SetInternalField(0, next->value());
|
| + wasm_module->SetInternalField(0, next->value());
|
| DCHECK_NULL(prev);
|
| WasmCompiledModule::cast(next->value())->reset_weak_prev_instance();
|
| }
|
| @@ -716,7 +593,7 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
| }
|
| }
|
| TRACE("chain after {\n");
|
| - TRACE_CHAIN(WasmCompiledModule::cast(module_obj->GetInternalField(0)));
|
| + TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0)));
|
| TRACE("}\n");
|
| }
|
| compiled_module->reset_weak_owning_instance();
|
| @@ -724,36 +601,6 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
| TRACE("}\n");
|
| }
|
|
|
| -Handle<FixedArray> SetupIndirectFunctionTable(
|
| - Isolate* isolate, Handle<FixedArray> wasm_functions,
|
| - Handle<FixedArray> indirect_table_template,
|
| - Handle<FixedArray> tables_to_replace) {
|
| - Factory* factory = isolate->factory();
|
| - Handle<FixedArray> cloned_indirect_tables =
|
| - factory->CopyFixedArray(indirect_table_template);
|
| - for (int i = 0; i < cloned_indirect_tables->length(); ++i) {
|
| - Handle<FixedArray> orig_metadata =
|
| - cloned_indirect_tables->GetValueChecked<FixedArray>(isolate, i);
|
| - Handle<FixedArray> cloned_metadata = factory->CopyFixedArray(orig_metadata);
|
| - cloned_indirect_tables->set(i, *cloned_metadata);
|
| -
|
| - Handle<FixedArray> orig_table =
|
| - cloned_metadata->GetValueChecked<FixedArray>(isolate, kTable);
|
| - Handle<FixedArray> cloned_table = factory->CopyFixedArray(orig_table);
|
| - cloned_metadata->set(kTable, *cloned_table);
|
| - // Patch the cloned code to refer to the cloned kTable.
|
| - Handle<FixedArray> table_to_replace =
|
| - tables_to_replace->GetValueChecked<FixedArray>(isolate, i)
|
| - ->GetValueChecked<FixedArray>(isolate, kTable);
|
| - for (int fct_index = 0; fct_index < wasm_functions->length(); ++fct_index) {
|
| - Handle<Code> wasm_function =
|
| - wasm_functions->GetValueChecked<Code>(isolate, fct_index);
|
| - PatchFunctionTable(wasm_function, table_to_replace, cloned_table);
|
| - }
|
| - }
|
| - return cloned_indirect_tables;
|
| -}
|
| -
|
| } // namespace
|
|
|
| const char* wasm::SectionName(WasmSectionCode code) {
|
| @@ -824,10 +671,11 @@ std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& pair) {
|
| }
|
|
|
| Handle<JSFunction> wasm::WrapExportCodeAsJSFunction(
|
| - Isolate* isolate, Handle<Code> export_code, Handle<String> name, int arity,
|
| - MaybeHandle<ByteArray> maybe_signature, Handle<JSObject> instance) {
|
| + Isolate* isolate, Handle<Code> export_code, Handle<String> name,
|
| + FunctionSig* sig, int func_index, Handle<JSObject> instance) {
|
| Handle<SharedFunctionInfo> shared =
|
| isolate->factory()->NewSharedFunctionInfo(name, export_code, false);
|
| + int arity = static_cast<int>(sig->parameter_count());
|
| shared->set_length(arity);
|
| shared->set_internal_formal_parameter_count(arity);
|
| Handle<JSFunction> function = isolate->factory()->NewFunction(
|
| @@ -835,13 +683,7 @@ Handle<JSFunction> wasm::WrapExportCodeAsJSFunction(
|
| function->set_shared(*shared);
|
|
|
| function->SetInternalField(kInternalModuleInstance, *instance);
|
| - // add another Internal Field as the function arity
|
| - function->SetInternalField(kInternalArity, Smi::FromInt(arity));
|
| - // add another Internal Field as the signature of the foreign function
|
| - Handle<ByteArray> signature;
|
| - if (maybe_signature.ToHandle(&signature)) {
|
| - function->SetInternalField(kInternalSignature, *signature);
|
| - }
|
| + function->SetInternalField(kInternalFunctionIndex, Smi::FromInt(func_index));
|
| return function;
|
| }
|
|
|
| @@ -857,78 +699,25 @@ Object* wasm::GetOwningWasmInstance(Code* code) {
|
| return cell->value();
|
| }
|
|
|
| -int wasm::GetNumImportedFunctions(Handle<JSObject> instance) {
|
| - // TODO(wasm): Cache this number if it ever becomes a performance problem.
|
| +WasmModule* GetCppModule(Handle<JSObject> instance) {
|
| DCHECK(IsWasmInstance(*instance));
|
| - WasmCompiledModule* compiled_module = GetCompiledModule(*instance);
|
| - Handle<FixedArray> imports =
|
| - WasmCompiledModule::cast(compiled_module)->imports();
|
| - int num_imports = imports->length();
|
| - int num_imported_functions = 0;
|
| - for (int i = 0; i < num_imports; ++i) {
|
| - FixedArray* encoded_import = FixedArray::cast(imports->get(i));
|
| - int kind = Smi::cast(encoded_import->get(kImportKind))->value();
|
| - if (kind == kExternalFunction) ++num_imported_functions;
|
| - }
|
| - return num_imported_functions;
|
| + return reinterpret_cast<WasmModuleWrapper*>(
|
| + *GetCompiledModule(*instance)->module_wrapper())
|
| + ->get();
|
| }
|
|
|
| -WasmModule::WasmModule(byte* module_start)
|
| - : module_start(module_start),
|
| - module_end(nullptr),
|
| - min_mem_pages(0),
|
| - max_mem_pages(0),
|
| - mem_export(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)) {}
|
| -
|
| -namespace {
|
| -
|
| -void EncodeInit(const WasmModule* module, Factory* factory,
|
| - Handle<FixedArray> entry, int kind_index, int value_index,
|
| - const WasmInitExpr& expr) {
|
| - entry->set(kind_index, Smi::kZero);
|
| -
|
| - Handle<Object> value;
|
| - switch (expr.kind) {
|
| - case WasmInitExpr::kGlobalIndex: {
|
| - TRACE(" kind = 1, global index %u\n", expr.val.global_index);
|
| - entry->set(kind_index, Smi::FromInt(1));
|
| - uint32_t offset = module->globals[expr.val.global_index].offset;
|
| - entry->set(value_index, Smi::FromInt(offset));
|
| - return;
|
| - }
|
| - case WasmInitExpr::kI32Const:
|
| - TRACE(" kind = 0, i32 = %d\n", expr.val.i32_const);
|
| - value = factory->NewNumber(expr.val.i32_const);
|
| - break;
|
| - case WasmInitExpr::kI64Const:
|
| - // TODO(titzer): implement initializers for i64 globals.
|
| - UNREACHABLE();
|
| - break;
|
| - case WasmInitExpr::kF32Const:
|
| - TRACE(" kind = 0, f32 = %f\n", expr.val.f32_const);
|
| - value = factory->NewNumber(expr.val.f32_const);
|
| - break;
|
| - case WasmInitExpr::kF64Const:
|
| - TRACE(" kind = 0, f64 = %lf\n", expr.val.f64_const);
|
| - value = factory->NewNumber(expr.val.f64_const);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - entry->set(value_index, *value);
|
| +int wasm::GetNumImportedFunctions(Handle<JSObject> instance) {
|
| + return static_cast<int>(GetCppModule(instance)->num_imported_functions);
|
| }
|
|
|
| -} // namespace
|
| +WasmModule::WasmModule(Zone* owned, const byte* module_start)
|
| + : owned_zone(owned),
|
| + module_start(module_start),
|
| + pending_tasks(new base::Semaphore(0)) {}
|
|
|
| MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
|
| - Isolate* isolate, ErrorThrower* thrower) const {
|
| + Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper,
|
| + ErrorThrower* thrower) const {
|
| Factory* factory = isolate->factory();
|
|
|
| MaybeHandle<WasmCompiledModule> nothing;
|
| @@ -939,20 +728,13 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
|
| temp_instance.mem_start = nullptr;
|
| temp_instance.globals_start = nullptr;
|
|
|
| - MaybeHandle<FixedArray> indirect_table =
|
| - function_tables.size()
|
| - ? factory->NewFixedArray(static_cast<int>(function_tables.size()),
|
| - TENURED)
|
| - : MaybeHandle<FixedArray>();
|
| - for (uint32_t i = 0; i < function_tables.size(); ++i) {
|
| - Handle<FixedArray> values = wasm::BuildFunctionTable(isolate, i, this);
|
| - temp_instance.function_tables[i] = values;
|
| -
|
| - Handle<FixedArray> metadata = isolate->factory()->NewFixedArray(
|
| - kWasmIndirectFunctionTableDataSize, TENURED);
|
| - metadata->set(kSize, Smi::FromInt(function_tables[i].size));
|
| - metadata->set(kTable, *values);
|
| - indirect_table.ToHandleChecked()->set(i, *metadata);
|
| + // Initialize the indirect tables with placeholders.
|
| + int function_table_count = static_cast<int>(this->function_tables.size());
|
| + Handle<FixedArray> function_tables =
|
| + factory->NewFixedArray(function_table_count);
|
| + for (int i = 0; i < function_table_count; ++i) {
|
| + temp_instance.function_tables[i] = factory->NewFixedArray(0);
|
| + function_tables->set(i, *temp_instance.function_tables[i]);
|
| }
|
|
|
| HistogramTimerScope wasm_compile_module_time_scope(
|
| @@ -1023,122 +805,30 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
|
| // serializable. Instantiation may occur off a deserialized version of this
|
| // object.
|
| Handle<WasmCompiledModule> ret =
|
| - WasmCompiledModule::New(isolate, min_mem_pages, globals_size, origin);
|
| + WasmCompiledModule::New(isolate, module_wrapper);
|
| ret->set_code_table(code_table);
|
| - if (!indirect_table.is_null()) {
|
| - ret->set_indirect_function_tables(indirect_table.ToHandleChecked());
|
| + ret->set_min_mem_pages(min_mem_pages);
|
| + if (function_table_count > 0) {
|
| + ret->set_function_tables(function_tables);
|
| + ret->set_empty_function_tables(function_tables);
|
| }
|
|
|
| - // Create and set import data.
|
| - Handle<FixedArray> imports = EncodeImports(factory, this);
|
| - ret->set_imports(imports);
|
| -
|
| - // Create and set export data.
|
| - int export_size = static_cast<int>(export_table.size());
|
| - if (export_size > 0) {
|
| - Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED);
|
| - int index = 0;
|
| - int func_index = 0;
|
| -
|
| - for (const WasmExport& exp : export_table) {
|
| - if (thrower->error()) return nothing;
|
| - Handle<FixedArray> encoded_export =
|
| - factory->NewFixedArray(kWasmExportDataSize, TENURED);
|
| - WasmName str = GetName(exp.name_offset, exp.name_length);
|
| - Handle<String> name = factory->InternalizeUtf8String(str);
|
| - encoded_export->set(kExportKind, Smi::FromInt(exp.kind));
|
| - encoded_export->set(kExportName, *name);
|
| - encoded_export->set(kExportIndex,
|
| - Smi::FromInt(static_cast<int>(exp.index)));
|
| - exports->set(index, *encoded_export);
|
| -
|
| - switch (exp.kind) {
|
| - case kExternalFunction: {
|
| - // Copy the signature and arity.
|
| - FunctionSig* funcSig = functions[exp.index].sig;
|
| - Handle<ByteArray> exportedSig = factory->NewByteArray(
|
| - static_cast<int>(funcSig->parameter_count() +
|
| - funcSig->return_count()),
|
| - TENURED);
|
| - exportedSig->copy_in(
|
| - 0, reinterpret_cast<const byte*>(funcSig->raw_data()),
|
| - exportedSig->length());
|
| - encoded_export->set(kExportedSignature, *exportedSig);
|
| - encoded_export->set(
|
| - kExportArity,
|
| - Smi::FromInt(static_cast<int>(funcSig->parameter_count())));
|
| -
|
| - // Compile a wrapper for an exported function.
|
| - Handle<Code> code =
|
| - code_table->GetValueChecked<Code>(isolate, exp.index);
|
| - Handle<Code> export_code = compiler::CompileJSToWasmWrapper(
|
| - isolate, &module_env, code, exp.index);
|
| - int code_table_index =
|
| - static_cast<int>(functions.size() + func_index);
|
| - code_table->set(code_table_index, *export_code);
|
| - encoded_export->set(kExportIndex, Smi::FromInt(code_table_index));
|
| - ++func_index;
|
| - }
|
| - case kExternalTable:
|
| - // Nothing special about exported tables.
|
| - break;
|
| - case kExternalMemory:
|
| - // Nothing special about exported tables.
|
| - break;
|
| - case kExternalGlobal: {
|
| - // Encode the global type and the global offset.
|
| - const WasmGlobal& global = globals[exp.index];
|
| - encoded_export->set(
|
| - kExportGlobalType,
|
| - Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type)));
|
| - encoded_export->set(kExportIndex, Smi::FromInt(global.offset));
|
| - break;
|
| - }
|
| - }
|
| - ++index;
|
| - }
|
| - ret->set_exports(exports);
|
| - }
|
| -
|
| - // Create and set init data.
|
| - int init_size = static_cast<int>(globals.size());
|
| - if (init_size > 0) {
|
| - Handle<FixedArray> inits = factory->NewFixedArray(init_size, TENURED);
|
| - int index = 0;
|
| - for (const WasmGlobal& global : globals) {
|
| - // Skip globals that have no initializer (e.g. imported ones).
|
| - if (global.init.kind == WasmInitExpr::kNone) continue;
|
| -
|
| - Handle<FixedArray> encoded_init =
|
| - factory->NewFixedArray(kWasmGlobalInitDataSize, TENURED);
|
| - inits->set(index, *encoded_init);
|
| - TRACE("init[%d].type = %s\n", index, WasmOpcodes::TypeName(global.type));
|
| -
|
| - encoded_init->set(
|
| - kGlobalInitType,
|
| - Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type)));
|
| - encoded_init->set(kGlobalInitIndex, Smi::FromInt(global.offset));
|
| - EncodeInit(this, factory, encoded_init, kGlobalInitKind, kGlobalInitValue,
|
| - global.init);
|
| - ++index;
|
| - }
|
| - inits->Shrink(index);
|
| - ret->set_inits(inits);
|
| + // Compile JS->WASM wrappers for exported functions.
|
| + int func_index = 0;
|
| + for (auto exp : export_table) {
|
| + if (exp.kind != kExternalFunction) continue;
|
| + Handle<Code> wasm_code =
|
| + code_table->GetValueChecked<Code>(isolate, exp.index);
|
| + Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
|
| + isolate, &module_env, wasm_code, exp.index);
|
| + int export_index = static_cast<int>(functions.size() + func_index);
|
| + code_table->set(export_index, *wrapper_code);
|
| + func_index++;
|
| }
|
|
|
| - // Record data for startup function.
|
| - if (start_function_index >= 0) {
|
| - HandleScope scope(isolate);
|
| - Handle<FixedArray> startup_data =
|
| - factory->NewFixedArray(kWasmExportDataSize, TENURED);
|
| - startup_data->set(kExportArity, Smi::kZero);
|
| - startup_data->set(kExportIndex, Smi::FromInt(start_function_index));
|
| - ret->set_startup_function(startup_data);
|
| - }
|
| -
|
| - // TODO(wasm): saving the module bytes for debugging is wasteful. We should
|
| - // consider downloading this on-demand.
|
| {
|
| + // TODO(wasm): only save the sections necessary to deserialize a
|
| + // {WasmModule}. E.g. function bodies could be omitted.
|
| size_t module_bytes_len = module_end - module_start;
|
| DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt));
|
| Vector<const uint8_t> module_bytes_vec(module_start,
|
| @@ -1150,11 +840,6 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
|
| ret->set_module_bytes(Handle<SeqOneByteString>::cast(module_bytes_string));
|
| }
|
|
|
| - Handle<ByteArray> function_name_table =
|
| - BuildFunctionNamesTable(isolate, module_env.module);
|
| - ret->set_function_names(function_name_table);
|
| - if (data_segments.size() > 0) SaveDataSegmentInfo(factory, this, ret);
|
| - DCHECK_EQ(ret->default_mem_size(), temp_instance.mem_size);
|
| return ret;
|
| }
|
|
|
| @@ -1218,6 +903,8 @@ class WasmInstanceBuilder {
|
| DCHECK(!owner.is_null());
|
| TRACE("Cloning from %d\n", original->instance_id());
|
| compiled_module_ = WasmCompiledModule::Clone(isolate_, original);
|
| + // Avoid creating too many handles in the outer scope.
|
| + HandleScope scope(isolate_);
|
|
|
| // Clone the code for WASM functions and exports.
|
| for (int i = 0; i < code_table->length(); ++i) {
|
| @@ -1246,15 +933,17 @@ class WasmInstanceBuilder {
|
| }
|
| compiled_module_->set_code_table(code_table);
|
| }
|
| + module_ = reinterpret_cast<WasmModuleWrapper*>(
|
| + *compiled_module_->module_wrapper())
|
| + ->get();
|
|
|
| //--------------------------------------------------------------------------
|
| // Allocate the instance object.
|
| //--------------------------------------------------------------------------
|
| Handle<Map> map = factory->NewMap(
|
| JS_OBJECT_TYPE,
|
| - JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
|
| + JSObject::kHeaderSize + kWasmInstanceInternalFieldCount * kPointerSize);
|
| Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED);
|
| - instance->SetInternalField(kWasmModuleCodeTable, *code_table);
|
| instance->SetInternalField(kWasmMemObject, *factory->undefined_value());
|
|
|
| //--------------------------------------------------------------------------
|
| @@ -1262,7 +951,7 @@ class WasmInstanceBuilder {
|
| //--------------------------------------------------------------------------
|
| MaybeHandle<JSArrayBuffer> old_globals;
|
| MaybeHandle<JSArrayBuffer> globals;
|
| - uint32_t globals_size = compiled_module_->globals_size();
|
| + uint32_t globals_size = module_->globals_size;
|
| if (globals_size > 0) {
|
| Handle<JSArrayBuffer> global_buffer =
|
| NewArrayBuffer(isolate_, globals_size);
|
| @@ -1276,7 +965,7 @@ class WasmInstanceBuilder {
|
| : GetGlobalStartAddressFromCodeTemplate(
|
| *factory->undefined_value(),
|
| JSObject::cast(*owner.ToHandleChecked()));
|
| - RelocateGlobals(instance, old_address,
|
| + RelocateGlobals(code_table, old_address,
|
| static_cast<Address>(global_buffer->backing_store()));
|
| instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
|
| }
|
| @@ -1290,15 +979,14 @@ class WasmInstanceBuilder {
|
| //--------------------------------------------------------------------------
|
| // Process the initialization for the module's globals.
|
| //--------------------------------------------------------------------------
|
| - ProcessInits(globals);
|
| + InitGlobals(globals);
|
|
|
| //--------------------------------------------------------------------------
|
| // Set up the memory for the new instance.
|
| //--------------------------------------------------------------------------
|
| MaybeHandle<JSArrayBuffer> old_memory;
|
| - // TODO(titzer): handle imported memory properly.
|
|
|
| - uint32_t min_mem_pages = compiled_module_->min_memory_pages();
|
| + uint32_t min_mem_pages = module_->min_mem_pages;
|
| 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.
|
|
|
| @@ -1314,16 +1002,15 @@ class WasmInstanceBuilder {
|
| static_cast<uint32_t>(memory_->byte_length()->Number());
|
| LoadDataSegments(globals, mem_start, mem_size);
|
|
|
| - uint32_t old_mem_size = compiled_module_->has_heap()
|
| - ? compiled_module_->mem_size()
|
| - : compiled_module_->default_mem_size();
|
| + uint32_t old_mem_size = compiled_module_->mem_size();
|
| Address old_mem_start =
|
| - compiled_module_->has_heap()
|
| - ? static_cast<Address>(compiled_module_->heap()->backing_store())
|
| + compiled_module_->has_memory()
|
| + ? static_cast<Address>(
|
| + compiled_module_->memory()->backing_store())
|
| : nullptr;
|
| - RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
|
| - mem_size);
|
| - compiled_module_->set_heap(memory_);
|
| + RelocateMemoryReferencesInCode(code_table, old_mem_start, mem_start,
|
| + old_mem_size, mem_size);
|
| + compiled_module_->set_memory(memory_);
|
| }
|
|
|
| //--------------------------------------------------------------------------
|
| @@ -1346,33 +1033,52 @@ class WasmInstanceBuilder {
|
| //--------------------------------------------------------------------------
|
| // 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[i] = code_table->GetValueChecked<Code>(isolate_, i);
|
| + int function_table_count =
|
| + static_cast<int>(module_->function_tables.size());
|
| + if (function_table_count > 0) {
|
| + Handle<FixedArray> old_function_tables =
|
| + compiled_module_->function_tables();
|
| + Handle<FixedArray> new_function_tables =
|
| + factory->NewFixedArray(function_table_count);
|
| + for (int index = 0; index < function_table_count; ++index) {
|
| + WasmIndirectFunctionTable& table = module_->function_tables[index];
|
| + uint32_t size = table.max_size;
|
| + Handle<FixedArray> new_table = factory->NewFixedArray(size * 2);
|
| + for (int i = 0; i < new_table->length(); ++i) {
|
| + static const int kInvalidSigIndex = -1;
|
| + // Fill the table with invalid signature indexes so that uninitialized
|
| + // entries will always fail the signature check.
|
| + new_table->set(i, Smi::FromInt(kInvalidSigIndex));
|
| + }
|
| + for (auto table_init : module_->table_inits) {
|
| + uint32_t base = EvalUint32InitExpr(globals, table_init.offset);
|
| + uint32_t table_size = static_cast<uint32_t>(new_table->length());
|
| + if (base > table_size ||
|
| + (base + table_init.entries.size() > table_size)) {
|
| + thrower_->CompileError("table initializer is out of bounds");
|
| + continue;
|
| + }
|
| + for (size_t i = 0; i < table_init.entries.size(); ++i) {
|
| + FunctionSig* sig = module_->functions[table_init.entries[i]].sig;
|
| + int32_t sig_index = table.map.Find(sig);
|
| + new_table->set(static_cast<int>(i + base), Smi::FromInt(sig_index));
|
| + new_table->set(static_cast<int>(i + base + size),
|
| + code_table->get(table_init.entries[i]));
|
| + }
|
| + }
|
| + new_function_tables->set(static_cast<int>(index), *new_table);
|
| }
|
| -
|
| - if (compiled_module_->has_indirect_function_tables()) {
|
| - Handle<FixedArray> indirect_tables_template =
|
| - compiled_module_->indirect_function_tables();
|
| - Handle<FixedArray> to_replace =
|
| - owner.is_null() ? indirect_tables_template
|
| - : handle(FixedArray::cast(
|
| - owner.ToHandleChecked()->GetInternalField(
|
| - kWasmModuleFunctionTable)));
|
| - Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
|
| - isolate_, code_table, indirect_tables_template, to_replace);
|
| - for (int i = 0; i < indirect_tables->length(); ++i) {
|
| - Handle<FixedArray> metadata =
|
| - indirect_tables->GetValueChecked<FixedArray>(isolate_, i);
|
| - uint32_t size = Smi::cast(metadata->get(kSize))->value();
|
| - Handle<FixedArray> table =
|
| - metadata->GetValueChecked<FixedArray>(isolate_, kTable);
|
| - PopulateFunctionTable(table, size, &functions);
|
| + // Patch all code that has references to the old indirect table.
|
| + for (int i = 0; i < code_table->length(); ++i) {
|
| + if (!code_table->get(i)->IsCode()) continue;
|
| + Handle<Code> code(Code::cast(code_table->get(i)), isolate_);
|
| + for (int j = 0; j < function_table_count; ++j) {
|
| + ReplaceReferenceInCode(
|
| + code, Handle<Object>(old_function_tables->get(j), isolate_),
|
| + Handle<Object>(new_function_tables->get(j), isolate_));
|
| }
|
| - instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
|
| }
|
| + compiled_module_->set_function_tables(new_function_tables);
|
| }
|
|
|
| //--------------------------------------------------------------------------
|
| @@ -1413,8 +1119,8 @@ class WasmInstanceBuilder {
|
| compiled_module_->set_weak_next_instance(
|
| link_to_original.ToHandleChecked());
|
| original.ToHandleChecked()->set_weak_prev_instance(link_to_clone);
|
| - compiled_module_->set_weak_module_object(
|
| - original.ToHandleChecked()->weak_module_object());
|
| + compiled_module_->set_weak_wasm_module(
|
| + original.ToHandleChecked()->weak_wasm_module());
|
| }
|
| module_object_->SetInternalField(0, *compiled_module_);
|
| instance->SetInternalField(kWasmCompiledModule, *compiled_module_);
|
| @@ -1433,19 +1139,15 @@ class WasmInstanceBuilder {
|
| //--------------------------------------------------------------------------
|
| // Run the start function if one was specified.
|
| //--------------------------------------------------------------------------
|
| - if (compiled_module_->has_startup_function()) {
|
| - Handle<FixedArray> startup_data = compiled_module_->startup_function();
|
| + if (module_->start_function_index >= 0) {
|
| HandleScope scope(isolate_);
|
| - int32_t start_index =
|
| - startup_data->GetValueChecked<Smi>(isolate_, kExportIndex)->value();
|
| + int start_index = module_->start_function_index;
|
| Handle<Code> startup_code =
|
| code_table->GetValueChecked<Code>(isolate_, start_index);
|
| - int arity = Smi::cast(startup_data->get(kExportArity))->value();
|
| - MaybeHandle<ByteArray> startup_signature =
|
| - startup_data->GetValue<ByteArray>(isolate_, kExportedSignature);
|
| + FunctionSig* sig = module_->functions[start_index].sig;
|
| Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction(
|
| - isolate_, startup_code, factory->InternalizeUtf8String("start"),
|
| - arity, startup_signature, instance);
|
| + isolate_, startup_code, factory->InternalizeUtf8String("start"), sig,
|
| + start_index, instance);
|
| RecordStats(isolate_, *startup_code);
|
| // Call the JS function.
|
| Handle<Object> undefined = factory->undefined_value();
|
| @@ -1471,6 +1173,7 @@ class WasmInstanceBuilder {
|
|
|
| private:
|
| Isolate* isolate_;
|
| + WasmModule* module_;
|
| ErrorThrower* thrower_;
|
| Handle<JSObject> module_object_;
|
| Handle<JSReceiver> ffi_;
|
| @@ -1534,79 +1237,65 @@ class WasmInstanceBuilder {
|
| return result;
|
| }
|
|
|
| + uint32_t EvalUint32InitExpr(MaybeHandle<JSArrayBuffer> globals,
|
| + WasmInitExpr& expr) {
|
| + switch (expr.kind) {
|
| + case WasmInitExpr::kI32Const:
|
| + return expr.val.i32_const;
|
| + case WasmInitExpr::kGlobalIndex: {
|
| + uint32_t offset = module_->globals[expr.val.global_index].offset;
|
| + return *reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals, offset));
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + return 0;
|
| + }
|
| + }
|
| +
|
| // Load data segments into the memory.
|
| void LoadDataSegments(MaybeHandle<JSArrayBuffer> globals, Address mem_addr,
|
| size_t mem_size) {
|
| - CHECK(compiled_module_->has_data_segments() ==
|
| - compiled_module_->has_data_segments_info());
|
| -
|
| - // If we have neither, we're done.
|
| - if (!compiled_module_->has_data_segments()) return;
|
| -
|
| - Handle<ByteArray> data = compiled_module_->data_segments();
|
| - Handle<FixedArray> segments = compiled_module_->data_segments_info();
|
| -
|
| - uint32_t last_extraction_pos = 0;
|
| - for (int i = 0; i < segments->length(); ++i) {
|
| - Handle<ByteArray> segment =
|
| - Handle<ByteArray>(ByteArray::cast(segments->get(i)));
|
| - uint32_t dest_addr =
|
| - static_cast<uint32_t>(segment->get_int(kDestAddrValue));
|
| - if (segment->get_int(kDestAddrKind) == 1) {
|
| - // The destination address is the value of a global variable.
|
| - dest_addr =
|
| - *reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals, dest_addr));
|
| + Handle<SeqOneByteString> module_bytes = compiled_module_->module_bytes();
|
| + for (auto segment : module_->data_segments) {
|
| + uint32_t dest_offset = EvalUint32InitExpr(globals, segment.dest_addr);
|
| + uint32_t source_size = segment.source_size;
|
| + if (dest_offset >= mem_size || source_size >= mem_size ||
|
| + dest_offset >= (mem_size - source_size)) {
|
| + thrower_->RangeError("data segment does not fit into memory");
|
| }
|
| -
|
| - uint32_t source_size =
|
| - static_cast<uint32_t>(segment->get_int(kSourceSize));
|
| - // TODO(titzer): These should be runtime errors and not CHECKs if
|
| - // dest_addr is global (and therefore initialized at linktime to an
|
| - // possibly-invalid value).
|
| - CHECK_LT(dest_addr, mem_size);
|
| - CHECK_LE(source_size, mem_size);
|
| - CHECK_LE(dest_addr, mem_size - source_size);
|
| - byte* addr = mem_addr + dest_addr;
|
| - data->copy_out(last_extraction_pos, addr, source_size);
|
| - last_extraction_pos += source_size;
|
| + byte* dest = mem_addr + dest_offset;
|
| + const byte* src = reinterpret_cast<const byte*>(
|
| + module_bytes->GetCharsAddress() + segment.source_offset);
|
| + memcpy(dest, src, source_size);
|
| }
|
| }
|
|
|
| - Handle<Code> CompileImportWrapper(int index, Handle<FixedArray> data,
|
| + Handle<Code> CompileImportWrapper(int index, const WasmImport& import,
|
| Handle<JSReceiver> target,
|
| Handle<String> module_name,
|
| MaybeHandle<String> import_name) {
|
| - // 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);
|
| -
|
| + FunctionSig* sig = module_->functions[import.index].sig;
|
| Handle<Code> code;
|
| - bool isMatch = false;
|
| + bool is_match = 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->GetDataStartAddress(),
|
| - sig_data->GetDataStartAddress(),
|
| - exportedSig->length()) == 0) {
|
| - isMatch = true;
|
| - }
|
| + // Compare signature of other exported wasm function.
|
| + Handle<JSObject> other_instance(
|
| + JSObject::cast(func->GetInternalField(kInternalModuleInstance)),
|
| + isolate_);
|
| + int func_index =
|
| + Smi::cast(func->GetInternalField(kInternalFunctionIndex))->value();
|
| + FunctionSig* other_sig =
|
| + GetCppModule(other_instance)->functions[func_index].sig;
|
| + is_match = sig->Equals(other_sig);
|
| }
|
| }
|
| - if (isMatch) {
|
| + if (is_match) {
|
| + // Signature matched. Unwrap the JS->WASM wrapper and return the naked
|
| + // WASM function code.
|
| int wasm_count = 0;
|
| int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
| for (RelocIterator it(*export_wrapper_code, mask); !it.done();
|
| @@ -1622,22 +1311,14 @@ class WasmInstanceBuilder {
|
| 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(), ZONE_NAME);
|
| - MachineRepresentation* reps =
|
| - zone.NewArray<MachineRepresentation>(sig_data_size);
|
| - memcpy(reps, sig_data->GetDataStartAddress(),
|
| - sizeof(MachineRepresentation) * sig_data_size);
|
| - FunctionSig sig(ret_count, param_count, reps);
|
| -
|
| - return compiler::CompileWasmToJSWrapper(isolate_, target, &sig, index,
|
| + // Signature mismatch. Compile a new wrapper for the new signature.
|
| + return compiler::CompileWasmToJSWrapper(isolate_, target, sig, index,
|
| module_name, import_name);
|
| }
|
| }
|
|
|
| - void WriteGlobalValue(MaybeHandle<JSArrayBuffer> globals, uint32_t offset,
|
| - Handle<Object> value, int type) {
|
| + void WriteGlobalValue(WasmGlobal& global, MaybeHandle<JSArrayBuffer> globals,
|
| + Handle<Object> value) {
|
| double num = 0;
|
| if (value->IsSmi()) {
|
| num = Smi::cast(*value)->value();
|
| @@ -1646,21 +1327,21 @@ class WasmInstanceBuilder {
|
| } else {
|
| UNREACHABLE();
|
| }
|
| - TRACE("init [globals+%u] = %lf, type = %d\n", offset, num, type);
|
| - byte* ptr = raw_buffer_ptr(globals, offset);
|
| - switch (type) {
|
| - case kLocalI32:
|
| - *reinterpret_cast<int32_t*>(ptr) = static_cast<int32_t>(num);
|
| + TRACE("init [globals+%u] = %lf, type = %s\n", global.offset, num,
|
| + WasmOpcodes::TypeName(global.type));
|
| + switch (global.type) {
|
| + case kAstI32:
|
| + *GetRawGlobalPtr<int32_t>(global, globals) = static_cast<int32_t>(num);
|
| break;
|
| - case kLocalI64:
|
| + case kAstI64:
|
| // TODO(titzer): initialization of imported i64 globals.
|
| UNREACHABLE();
|
| break;
|
| - case kLocalF32:
|
| - *reinterpret_cast<float*>(ptr) = static_cast<float>(num);
|
| + case kAstF32:
|
| + *GetRawGlobalPtr<float>(global, globals) = static_cast<float>(num);
|
| break;
|
| - case kLocalF64:
|
| - *reinterpret_cast<double*>(ptr) = num;
|
| + case kAstF64:
|
| + *GetRawGlobalPtr<double>(global, globals) = static_cast<double>(num);
|
| break;
|
| default:
|
| UNREACHABLE();
|
| @@ -1673,25 +1354,27 @@ class WasmInstanceBuilder {
|
| int ProcessImports(MaybeHandle<JSArrayBuffer> globals,
|
| Handle<FixedArray> code_table, Handle<JSObject> instance) {
|
| int num_imported_functions = 0;
|
| - if (!compiled_module_->has_imports()) return num_imported_functions;
|
| -
|
| - Handle<FixedArray> imports = compiled_module_->imports();
|
| - for (int index = 0; index < imports->length(); ++index) {
|
| - Handle<FixedArray> data =
|
| - imports->GetValueChecked<FixedArray>(isolate_, index);
|
| -
|
| + for (int index = 0; index < static_cast<int>(module_->import_table.size());
|
| + ++index) {
|
| + WasmImport& import = module_->import_table[index];
|
| Handle<String> module_name =
|
| - data->GetValueChecked<String>(isolate_, kModuleName);
|
| - MaybeHandle<String> function_name =
|
| - data->GetValue<String>(isolate_, kFunctionName);
|
| + ExtractStringFromModuleBytes(isolate_, compiled_module_,
|
| + import.module_name_offset,
|
| + import.module_name_length)
|
| + .ToHandleChecked();
|
| + Handle<String> function_name = Handle<String>::null();
|
| + if (import.field_name_length > 0) {
|
| + function_name = ExtractStringFromModuleBytes(isolate_, compiled_module_,
|
| + import.field_name_offset,
|
| + import.field_name_length)
|
| + .ToHandleChecked();
|
| + }
|
|
|
| MaybeHandle<Object> result =
|
| LookupImport(index, module_name, function_name);
|
| if (thrower_->error()) return -1;
|
|
|
| - WasmExternalKind kind = static_cast<WasmExternalKind>(
|
| - Smi::cast(data->get(kImportKind))->value());
|
| - switch (kind) {
|
| + switch (import.kind) {
|
| case kExternalFunction: {
|
| // Function imports must be callable.
|
| Handle<Object> function = result.ToHandleChecked();
|
| @@ -1702,10 +1385,9 @@ class WasmInstanceBuilder {
|
| }
|
|
|
| Handle<Code> import_wrapper = CompileImportWrapper(
|
| - index, data, Handle<JSReceiver>::cast(function), module_name,
|
| + index, import, Handle<JSReceiver>::cast(function), module_name,
|
| function_name);
|
| - int func_index = Smi::cast(data->get(kImportIndex))->value();
|
| - code_table->set(func_index, *import_wrapper);
|
| + code_table->set(num_imported_functions, *import_wrapper);
|
| RecordStats(isolate_, *import_wrapper);
|
| num_imported_functions++;
|
| break;
|
| @@ -1735,9 +1417,7 @@ class WasmInstanceBuilder {
|
| return -1;
|
| }
|
| Handle<Object> val = number.ToHandleChecked();
|
| - int offset = Smi::cast(data->get(kImportIndex))->value();
|
| - int type = Smi::cast(data->get(kImportGlobalType))->value();
|
| - WriteGlobalValue(globals, offset, val, type);
|
| + WriteGlobalValue(module_->globals[import.index], globals, val);
|
| break;
|
| }
|
| default:
|
| @@ -1748,29 +1428,49 @@ class WasmInstanceBuilder {
|
| return num_imported_functions;
|
| }
|
|
|
| + template <typename T>
|
| + T* GetRawGlobalPtr(WasmGlobal& global, MaybeHandle<JSArrayBuffer> globals) {
|
| + return reinterpret_cast<T*>(raw_buffer_ptr(globals, global.offset));
|
| + }
|
| +
|
| // Process initialization of globals.
|
| - void ProcessInits(MaybeHandle<JSArrayBuffer> globals) {
|
| - if (!compiled_module_->has_inits()) return;
|
| -
|
| - Handle<FixedArray> inits = compiled_module_->inits();
|
| - for (int index = 0; index < inits->length(); ++index) {
|
| - Handle<FixedArray> data =
|
| - inits->GetValueChecked<FixedArray>(isolate_, index);
|
| -
|
| - int offset = Smi::cast(data->get(kGlobalInitIndex))->value();
|
| - Handle<Object> val(data->get(kGlobalInitValue), isolate_);
|
| - int type = Smi::cast(data->get(kGlobalInitType))->value();
|
| - if (Smi::cast(data->get(kGlobalInitKind))->value() == 0) {
|
| - // Initialize with a constant.
|
| - WriteGlobalValue(globals, offset, val, type);
|
| - } else {
|
| - // Initialize with another global.
|
| - int old_offset = Smi::cast(*val)->value();
|
| - TRACE("init [globals+%u] = [globals+%d]\n", offset, old_offset);
|
| - int size = sizeof(int32_t);
|
| - if (type == kLocalI64 || type == kLocalF64) size = sizeof(double);
|
| - memcpy(raw_buffer_ptr(globals, offset),
|
| - raw_buffer_ptr(globals, old_offset), size);
|
| + void InitGlobals(MaybeHandle<JSArrayBuffer> globals) {
|
| + for (auto global : module_->globals) {
|
| + switch (global.init.kind) {
|
| + case WasmInitExpr::kI32Const:
|
| + *GetRawGlobalPtr<int32_t>(global, globals) =
|
| + global.init.val.i32_const;
|
| + break;
|
| + case WasmInitExpr::kI64Const:
|
| + *GetRawGlobalPtr<int64_t>(global, globals) =
|
| + global.init.val.i64_const;
|
| + break;
|
| + case WasmInitExpr::kF32Const:
|
| + *GetRawGlobalPtr<float>(global, globals) = global.init.val.f32_const;
|
| + break;
|
| + case WasmInitExpr::kF64Const:
|
| + *GetRawGlobalPtr<double>(global, globals) = global.init.val.f64_const;
|
| + break;
|
| + case WasmInitExpr::kGlobalIndex: {
|
| + // Initialize with another global.
|
| + uint32_t new_offset = global.offset;
|
| + uint32_t old_offset =
|
| + module_->globals[global.init.val.global_index].offset;
|
| + TRACE("init [globals+%u] = [globals+%d]\n", global.offset,
|
| + old_offset);
|
| + size_t size = (global.type == kAstI64 || global.type == kAstF64)
|
| + ? size = sizeof(double)
|
| + : sizeof(int32_t);
|
| + memcpy(raw_buffer_ptr(globals, new_offset),
|
| + raw_buffer_ptr(globals, old_offset), size);
|
| + break;
|
| + }
|
| + case WasmInitExpr::kNone:
|
| + // Happens with imported globals.
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| }
|
| }
|
| @@ -1795,10 +1495,10 @@ class WasmInstanceBuilder {
|
| void ProcessExports(MaybeHandle<JSArrayBuffer> globals,
|
| Handle<FixedArray> code_table,
|
| Handle<JSObject> instance) {
|
| - if (!compiled_module_->has_exports()) return;
|
| + if (module_->export_table.size() == 0) return;
|
|
|
| Handle<JSObject> exports_object = instance;
|
| - if (compiled_module_->origin() == kWasmOrigin) {
|
| + if (module_->origin == kWasmOrigin) {
|
| // Create the "exports" object.
|
| Handle<JSFunction> object_function = Handle<JSFunction>(
|
| isolate_->native_context()->object_function(), isolate_);
|
| @@ -1812,27 +1512,23 @@ class WasmInstanceBuilder {
|
| PropertyDescriptor desc;
|
| desc.set_writable(false);
|
|
|
| - Handle<FixedArray> exports = compiled_module_->exports();
|
| -
|
| - for (int i = 0; i < exports->length(); ++i) {
|
| - Handle<FixedArray> export_data =
|
| - exports->GetValueChecked<FixedArray>(isolate_, i);
|
| + int func_index = 0;
|
| + for (auto exp : module_->export_table) {
|
| Handle<String> name =
|
| - export_data->GetValueChecked<String>(isolate_, kExportName);
|
| - WasmExternalKind kind = static_cast<WasmExternalKind>(
|
| - Smi::cast(export_data->get(kExportKind))->value());
|
| - switch (kind) {
|
| + ExtractStringFromModuleBytes(isolate_, compiled_module_,
|
| + exp.name_offset, exp.name_length)
|
| + .ToHandleChecked();
|
| + switch (exp.kind) {
|
| case kExternalFunction: {
|
| // Wrap and export the code as a JSFunction.
|
| - int code_table_index =
|
| - Smi::cast(export_data->get(kExportIndex))->value();
|
| + WasmFunction& function = module_->functions[exp.index];
|
| + int export_index =
|
| + static_cast<int>(module_->functions.size() + func_index);
|
| Handle<Code> export_code =
|
| - code_table->GetValueChecked<Code>(isolate_, code_table_index);
|
| - int arity = Smi::cast(export_data->get(kExportArity))->value();
|
| - MaybeHandle<ByteArray> signature =
|
| - export_data->GetValue<ByteArray>(isolate_, kExportedSignature);
|
| + code_table->GetValueChecked<Code>(isolate_, export_index);
|
| desc.set_value(WrapExportCodeAsJSFunction(
|
| - isolate_, export_code, name, arity, signature, instance));
|
| + isolate_, export_code, name, function.sig, func_index, instance));
|
| + func_index++;
|
| break;
|
| }
|
| case kExternalTable:
|
| @@ -1859,18 +1555,17 @@ class WasmInstanceBuilder {
|
| }
|
| case kExternalGlobal: {
|
| // Export the value of the global variable as a number.
|
| - int offset = Smi::cast(export_data->get(kExportIndex))->value();
|
| - byte* ptr = raw_buffer_ptr(globals, offset);
|
| + WasmGlobal& global = module_->globals[exp.index];
|
| double num = 0;
|
| - switch (Smi::cast(export_data->get(kExportGlobalType))->value()) {
|
| - case kLocalI32:
|
| - num = *reinterpret_cast<int32_t*>(ptr);
|
| + switch (global.type) {
|
| + case kAstI32:
|
| + num = *GetRawGlobalPtr<int32_t>(global, globals);
|
| break;
|
| - case kLocalF32:
|
| - num = *reinterpret_cast<float*>(ptr);
|
| + case kAstF32:
|
| + num = *GetRawGlobalPtr<float>(global, globals);
|
| break;
|
| - case kLocalF64:
|
| - num = *reinterpret_cast<double*>(ptr);
|
| + case kAstF64:
|
| + num = *GetRawGlobalPtr<double>(global, globals);
|
| break;
|
| default:
|
| UNREACHABLE();
|
| @@ -1898,37 +1593,26 @@ class WasmInstanceBuilder {
|
| // WebAssembly.Module.
|
| MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
| ErrorThrower* thrower,
|
| - Handle<JSObject> module_object,
|
| + Handle<JSObject> wasm_module,
|
| Handle<JSReceiver> ffi,
|
| Handle<JSArrayBuffer> memory) {
|
| - WasmInstanceBuilder builder(isolate, thrower, module_object, ffi, memory);
|
| + WasmInstanceBuilder builder(isolate, thrower, wasm_module, ffi, memory);
|
| return builder.Build();
|
| }
|
|
|
| -Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate,
|
| - uint32_t min_memory_pages,
|
| - uint32_t globals_size,
|
| - ModuleOrigin origin) {
|
| +Handle<WasmCompiledModule> WasmCompiledModule::New(
|
| + Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper) {
|
| Handle<FixedArray> ret =
|
| isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
|
| - // Globals size is expected to fit into an int without overflow. This is not
|
| - // supported by the spec at the moment, however, we don't support array
|
| - // buffer sizes over 1g, so, for now, we avoid alocating a HeapNumber for
|
| - // the globals size. The CHECK guards this assumption.
|
| - CHECK_GE(static_cast<int>(globals_size), 0);
|
| - ret->set(kID_min_memory_pages,
|
| - Smi::FromInt(static_cast<int>(min_memory_pages)));
|
| - ret->set(kID_globals_size, Smi::FromInt(static_cast<int>(globals_size)));
|
| - ret->set(kID_origin, Smi::FromInt(static_cast<int>(origin)));
|
| -
|
| // WasmCompiledModule::cast would fail since module bytes are not set yet.
|
| - Handle<WasmCompiledModule> module(reinterpret_cast<WasmCompiledModule*>(*ret),
|
| - isolate);
|
| - module->Init();
|
| - return module;
|
| + Handle<WasmCompiledModule> compiled_module(
|
| + reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
|
| + compiled_module->InitId();
|
| + compiled_module->set_module_wrapper(module_wrapper);
|
| + return compiled_module;
|
| }
|
|
|
| -void WasmCompiledModule::Init() {
|
| +void WasmCompiledModule::InitId() {
|
| #if DEBUG
|
| static uint32_t instance_id_counter = 0;
|
| set(kID_instance_id, Smi::FromInt(instance_id_counter++));
|
| @@ -1972,27 +1656,26 @@ void WasmCompiledModule::PrintInstancesChain() {
|
| }
|
|
|
| Handle<Object> wasm::GetWasmFunctionNameOrNull(Isolate* isolate,
|
| - Handle<Object> wasm,
|
| + Handle<Object> instance,
|
| uint32_t func_index) {
|
| - if (!wasm->IsUndefined(isolate)) {
|
| - DCHECK(IsWasmInstance(*wasm));
|
| - WasmCompiledModule* compiled_module =
|
| - GetCompiledModule(JSObject::cast(*wasm));
|
| - Handle<ByteArray> func_names = compiled_module->function_names();
|
| - // TODO(clemens): Extract this from the module bytes; skip whole function
|
| - // name table.
|
| - Handle<Object> name;
|
| - if (GetWasmFunctionNameFromTable(func_names, func_index).ToHandle(&name)) {
|
| - return name;
|
| - }
|
| + if (!instance->IsUndefined(isolate)) {
|
| + DCHECK(IsWasmInstance(*instance));
|
| + WasmModule* module = GetCppModule(Handle<JSObject>::cast(instance));
|
| + WasmFunction& function = module->functions[func_index];
|
| + Handle<WasmCompiledModule> compiled_module(GetCompiledModule(*instance),
|
| + isolate);
|
| + MaybeHandle<String> string = ExtractStringFromModuleBytes(
|
| + isolate, compiled_module, function.name_offset, function.name_length);
|
| + if (!string.is_null()) return string.ToHandleChecked();
|
| }
|
| return isolate->factory()->null_value();
|
| }
|
|
|
| -Handle<String> wasm::GetWasmFunctionName(Isolate* isolate, Handle<Object> wasm,
|
| +Handle<String> wasm::GetWasmFunctionName(Isolate* isolate,
|
| + Handle<Object> instance,
|
| uint32_t func_index) {
|
| Handle<Object> name_or_null =
|
| - GetWasmFunctionNameOrNull(isolate, wasm, func_index);
|
| + GetWasmFunctionNameOrNull(isolate, instance, func_index);
|
| if (!name_or_null->IsNull(isolate)) {
|
| return Handle<String>::cast(name_or_null);
|
| }
|
| @@ -2004,13 +1687,12 @@ bool wasm::IsWasmInstance(Object* object) {
|
|
|
| JSObject* obj = JSObject::cast(object);
|
| Isolate* isolate = obj->GetIsolate();
|
| - if (obj->GetInternalFieldCount() != kWasmModuleInternalFieldCount) {
|
| + if (obj->GetInternalFieldCount() != kWasmInstanceInternalFieldCount) {
|
| return false;
|
| }
|
|
|
| Object* mem = obj->GetInternalField(kWasmMemArrayBuffer);
|
| - if (!obj->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() ||
|
| - !(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) ||
|
| + if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) ||
|
| !WasmCompiledModule::IsWasmCompiledModule(
|
| obj->GetInternalField(kWasmCompiledModule))) {
|
| return false;
|
| @@ -2020,27 +1702,27 @@ bool wasm::IsWasmInstance(Object* object) {
|
| return true;
|
| }
|
|
|
| -WasmCompiledModule* wasm::GetCompiledModule(JSObject* wasm) {
|
| - return WasmCompiledModule::cast(wasm->GetInternalField(kWasmCompiledModule));
|
| +WasmCompiledModule* wasm::GetCompiledModule(Object* instance) {
|
| + DCHECK(IsWasmInstance(instance));
|
| + return WasmCompiledModule::cast(
|
| + JSObject::cast(instance)->GetInternalField(kWasmCompiledModule));
|
| }
|
|
|
| -bool wasm::WasmIsAsmJs(Object* wasm, Isolate* isolate) {
|
| - if (wasm->IsUndefined(isolate)) return false;
|
| - DCHECK(IsWasmInstance(wasm));
|
| - WasmCompiledModule* compiled_module = GetCompiledModule(JSObject::cast(wasm));
|
| - return compiled_module->has_asm_js_script();
|
| +bool wasm::WasmIsAsmJs(Object* instance, Isolate* isolate) {
|
| + return IsWasmInstance(instance) &&
|
| + GetCompiledModule(JSObject::cast(instance))->has_asm_js_script();
|
| }
|
|
|
| -Handle<Script> wasm::GetAsmWasmScript(Handle<JSObject> wasm) {
|
| - DCHECK(IsWasmInstance(*wasm));
|
| - WasmCompiledModule* compiled_module = GetCompiledModule(*wasm);
|
| +Handle<Script> wasm::GetAsmWasmScript(Handle<JSObject> instance) {
|
| + DCHECK(IsWasmInstance(*instance));
|
| + WasmCompiledModule* compiled_module = GetCompiledModule(*instance);
|
| return compiled_module->asm_js_script();
|
| }
|
|
|
| -int wasm::GetAsmWasmSourcePosition(Handle<JSObject> wasm, int func_index,
|
| +int wasm::GetAsmWasmSourcePosition(Handle<JSObject> instance, int func_index,
|
| int byte_offset) {
|
| - return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(wasm), func_index,
|
| - byte_offset);
|
| + return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(instance),
|
| + func_index, byte_offset);
|
| }
|
|
|
| Handle<SeqOneByteString> wasm::GetWasmBytes(Handle<JSObject> instance) {
|
| @@ -2059,72 +1741,33 @@ Handle<WasmDebugInfo> wasm::GetDebugInfo(Handle<JSObject> instance) {
|
| return new_info;
|
| }
|
|
|
| -Handle<FixedArray> wasm::BuildFunctionTable(Isolate* isolate, uint32_t index,
|
| - const WasmModule* module) {
|
| - const WasmIndirectFunctionTable* table = &module->function_tables[index];
|
| - DCHECK_EQ(table->size, table->values.size());
|
| - DCHECK_GE(table->max_size, table->size);
|
| - Handle<FixedArray> values =
|
| - isolate->factory()->NewFixedArray(2 * table->max_size, TENURED);
|
| - for (uint32_t i = 0; i < table->size; ++i) {
|
| - const WasmFunction* function = &module->functions[table->values[i]];
|
| - int32_t index = table->map.Find(function->sig);
|
| - DCHECK_GE(index, 0);
|
| - values->set(i, Smi::FromInt(index));
|
| - values->set(i + table->max_size, Smi::FromInt(table->values[i]));
|
| - }
|
| - // Set the remaining elements to -1 (instead of "undefined"). These
|
| - // elements are accessed directly as SMIs (without a check). On 64-bit
|
| - // platforms, it is possible to have the top bits of "undefined" take
|
| - // small integer values (or zero), which are more likely to be equal to
|
| - // the signature index we check against.
|
| - for (uint32_t i = table->size; i < table->max_size; ++i) {
|
| - values->set(i, Smi::FromInt(-1));
|
| - }
|
| - return values;
|
| -}
|
| -
|
| -void wasm::PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size,
|
| - const std::vector<Handle<Code>>* code_table) {
|
| - uint32_t max_size = table->length() / 2;
|
| - for (uint32_t i = max_size; i < max_size + table_size; ++i) {
|
| - int index = Smi::cast(table->get(static_cast<int>(i)))->value();
|
| - DCHECK_GE(index, 0);
|
| - DCHECK_LT(static_cast<size_t>(index), code_table->size());
|
| - table->set(static_cast<int>(i), *(*code_table)[index]);
|
| - }
|
| -}
|
| -
|
| int wasm::GetNumberOfFunctions(Handle<JSObject> instance) {
|
| - DCHECK(IsWasmInstance(*instance));
|
| - WasmCompiledModule* compiled_module = GetCompiledModule(*instance);
|
| - ByteArray* func_names_arr = compiled_module->ptr_to_function_names();
|
| - // TODO(clemensh): this looks inside an array constructed elsewhere. Refactor.
|
| - return func_names_arr->get_int(0);
|
| + return static_cast<int>(GetCppModule(instance)->functions.size());
|
| }
|
|
|
| -Handle<JSObject> wasm::CreateCompiledModuleObject(
|
| +Handle<JSObject> wasm::CreateWasmModuleObject(
|
| Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
|
| ModuleOrigin origin) {
|
| - Handle<JSObject> module_obj;
|
| + Handle<JSObject> wasm_module;
|
| if (origin == ModuleOrigin::kWasmOrigin) {
|
| Handle<JSFunction> module_cons(
|
| isolate->native_context()->wasm_module_constructor());
|
| - module_obj = isolate->factory()->NewJSObject(module_cons);
|
| + wasm_module = isolate->factory()->NewJSObject(module_cons);
|
| } else {
|
| DCHECK(origin == ModuleOrigin::kAsmJsOrigin);
|
| Handle<Map> map = isolate->factory()->NewMap(
|
| JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
|
| - module_obj = isolate->factory()->NewJSObjectFromMap(map, TENURED);
|
| + wasm_module = isolate->factory()->NewJSObjectFromMap(map, TENURED);
|
| }
|
| - module_obj->SetInternalField(0, *compiled_module);
|
| + wasm_module->SetInternalField(0, *compiled_module);
|
| if (origin == ModuleOrigin::kWasmOrigin) {
|
| Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym());
|
| - Object::SetProperty(module_obj, module_sym, module_obj, STRICT).Check();
|
| + Object::SetProperty(wasm_module, module_sym, wasm_module, STRICT).Check();
|
| }
|
| - Handle<WeakCell> link_to_module = isolate->factory()->NewWeakCell(module_obj);
|
| - compiled_module->set_weak_module_object(link_to_module);
|
| - return module_obj;
|
| + Handle<WeakCell> link_to_module =
|
| + isolate->factory()->NewWeakCell(wasm_module);
|
| + compiled_module->set_weak_wasm_module(link_to_module);
|
| + return wasm_module;
|
| }
|
|
|
| // TODO(clemensh): origin can be inferred from asm_js_script; remove it.
|
| @@ -2134,17 +1777,23 @@ MaybeHandle<JSObject> wasm::CreateModuleObjectFromBytes(
|
| const byte* asm_js_offset_tables_start,
|
| const byte* asm_js_offset_tables_end) {
|
| MaybeHandle<JSObject> nothing;
|
| - Zone zone(isolate->allocator(), ZONE_NAME);
|
| - ModuleResult result =
|
| - DecodeWasmModule(isolate, &zone, start, end, false, origin);
|
| - std::unique_ptr<const WasmModule> decoded_module(result.val);
|
| + ModuleResult result = DecodeWasmModule(isolate, start, end, false, origin);
|
| if (result.failed()) {
|
| + if (result.val) delete result.val;
|
| thrower->CompileFailed("Wasm decoding failed", result);
|
| return nothing;
|
| }
|
| + // The {module_wrapper} will take ownership of the {WasmModule} object,
|
| + // and it will be destroyed when the GC reclaims the wrapper object.
|
| + Handle<WasmModuleWrapper> module_wrapper =
|
| + WasmModuleWrapper::New(isolate, const_cast<WasmModule*>(result.val));
|
| +
|
| + // Compile the functions of the module, producing a compiled module.
|
| MaybeHandle<WasmCompiledModule> maybe_compiled_module =
|
| - decoded_module->CompileFunctions(isolate, thrower);
|
| + result.val->CompileFunctions(isolate, module_wrapper, thrower);
|
| +
|
| if (maybe_compiled_module.is_null()) return nothing;
|
| +
|
| Handle<WasmCompiledModule> compiled_module =
|
| maybe_compiled_module.ToHandleChecked();
|
|
|
| @@ -2163,15 +1812,13 @@ MaybeHandle<JSObject> wasm::CreateModuleObjectFromBytes(
|
| compiled_module->set_asm_js_offset_tables(offset_tables);
|
| }
|
|
|
| - return CreateCompiledModuleObject(isolate, compiled_module, origin);
|
| + return CreateWasmModuleObject(isolate, compiled_module, origin);
|
| }
|
|
|
| bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start,
|
| const byte* end, ErrorThrower* thrower,
|
| ModuleOrigin origin) {
|
| - Zone zone(isolate->allocator(), ZONE_NAME);
|
| - ModuleResult result =
|
| - DecodeWasmModule(isolate, &zone, start, end, false, origin);
|
| + ModuleResult result = DecodeWasmModule(isolate, start, end, false, origin);
|
| if (result.ok()) {
|
| DCHECK_NOT_NULL(result.val);
|
| delete result.val;
|
| @@ -2193,7 +1840,7 @@ void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer) {
|
| DCHECK(IsWasmInstance(*instance));
|
| instance->SetInternalField(kWasmMemArrayBuffer, buffer);
|
| WasmCompiledModule* compiled_module = GetCompiledModule(*instance);
|
| - compiled_module->set_ptr_to_heap(buffer);
|
| + compiled_module->set_ptr_to_memory(buffer);
|
| }
|
|
|
| int32_t wasm::GetInstanceMemorySize(Isolate* isolate,
|
| @@ -2256,30 +1903,30 @@ int32_t wasm::GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance,
|
| memcpy(new_mem_start, old_mem_start, old_size);
|
| }
|
| SetInstanceMemory(instance, *buffer);
|
| - RelocateInstanceCode(instance, old_mem_start, new_mem_start, old_size,
|
| - new_size);
|
| + Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
|
| + RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
|
| + old_size, new_size);
|
| DCHECK(old_size % WasmModule::kPageSize == 0);
|
| return (old_size / WasmModule::kPageSize);
|
| }
|
|
|
| void testing::ValidateInstancesChain(Isolate* isolate,
|
| - Handle<JSObject> module_obj,
|
| + Handle<JSObject> wasm_module,
|
| int instance_count) {
|
| CHECK_GE(instance_count, 0);
|
| DisallowHeapAllocation no_gc;
|
| WasmCompiledModule* compiled_module =
|
| - WasmCompiledModule::cast(module_obj->GetInternalField(0));
|
| - CHECK_EQ(
|
| - JSObject::cast(compiled_module->ptr_to_weak_module_object()->value()),
|
| - *module_obj);
|
| + WasmCompiledModule::cast(wasm_module->GetInternalField(0));
|
| + CHECK_EQ(JSObject::cast(compiled_module->ptr_to_weak_wasm_module()->value()),
|
| + *wasm_module);
|
| Object* prev = nullptr;
|
| int found_instances = compiled_module->has_weak_owning_instance() ? 1 : 0;
|
| WasmCompiledModule* current_instance = compiled_module;
|
| while (current_instance->has_weak_next_instance()) {
|
| CHECK((prev == nullptr && !current_instance->has_weak_prev_instance()) ||
|
| current_instance->ptr_to_weak_prev_instance()->value() == prev);
|
| - CHECK_EQ(current_instance->ptr_to_weak_module_object()->value(),
|
| - *module_obj);
|
| + CHECK_EQ(current_instance->ptr_to_weak_wasm_module()->value(),
|
| + *wasm_module);
|
| CHECK(IsWasmInstance(
|
| current_instance->ptr_to_weak_owning_instance()->value()));
|
| prev = current_instance;
|
| @@ -2292,22 +1939,52 @@ void testing::ValidateInstancesChain(Isolate* isolate,
|
| }
|
|
|
| void testing::ValidateModuleState(Isolate* isolate,
|
| - Handle<JSObject> module_obj) {
|
| + Handle<JSObject> wasm_module) {
|
| DisallowHeapAllocation no_gc;
|
| WasmCompiledModule* compiled_module =
|
| - WasmCompiledModule::cast(module_obj->GetInternalField(0));
|
| - CHECK(compiled_module->has_weak_module_object());
|
| - CHECK_EQ(compiled_module->ptr_to_weak_module_object()->value(), *module_obj);
|
| + WasmCompiledModule::cast(wasm_module->GetInternalField(0));
|
| + CHECK(compiled_module->has_weak_wasm_module());
|
| + CHECK_EQ(compiled_module->ptr_to_weak_wasm_module()->value(), *wasm_module);
|
| CHECK(!compiled_module->has_weak_prev_instance());
|
| CHECK(!compiled_module->has_weak_next_instance());
|
| CHECK(!compiled_module->has_weak_owning_instance());
|
| }
|
|
|
| void testing::ValidateOrphanedInstance(Isolate* isolate,
|
| - Handle<JSObject> instance) {
|
| + Handle<JSObject> wasm_module) {
|
| DisallowHeapAllocation no_gc;
|
| - CHECK(IsWasmInstance(*instance));
|
| - WasmCompiledModule* compiled_module = GetCompiledModule(*instance);
|
| - CHECK(compiled_module->has_weak_module_object());
|
| - CHECK(compiled_module->ptr_to_weak_module_object()->cleared());
|
| + CHECK(IsWasmInstance(*wasm_module));
|
| + WasmCompiledModule* compiled_module = GetCompiledModule(*wasm_module);
|
| + CHECK(compiled_module->has_weak_wasm_module());
|
| + CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared());
|
| +}
|
| +
|
| +void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate,
|
| + Handle<FixedArray> array) {
|
| + Handle<WasmCompiledModule> compiled_module(
|
| + reinterpret_cast<WasmCompiledModule*>(*array), isolate);
|
| +
|
| + WasmModule* module = nullptr;
|
| + {
|
| + Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
|
| + // We parse the module again directly from the module bytes, so
|
| + // the underlying storage must not be moved meanwhile.
|
| + DisallowHeapAllocation no_allocation;
|
| + const byte* start =
|
| + reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
|
| + const byte* end = start + module_bytes->length();
|
| + // TODO(titzer): remember the module origin in the compiled_module
|
| + // For now, we assume serialized modules did not originate from asm.js.
|
| + ModuleResult result =
|
| + DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
|
| + CHECK(result.ok());
|
| + CHECK_NOT_NULL(result.val);
|
| + module = const_cast<WasmModule*>(result.val);
|
| + }
|
| +
|
| + Handle<WasmModuleWrapper> module_wrapper =
|
| + WasmModuleWrapper::New(isolate, module);
|
| +
|
| + compiled_module->set_module_wrapper(module_wrapper);
|
| + DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
|
| }
|
|
|