Chromium Code Reviews| Index: src/wasm/wasm-module.cc |
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
| index 8f99797fdec82807362ffd31b19e2e064e85529c..e725ec16773eb6be2b95a37148cf6204517fdb51 100644 |
| --- a/src/wasm/wasm-module.cc |
| +++ b/src/wasm/wasm-module.cc |
| @@ -52,54 +52,12 @@ enum JSFunctionExportInternalField { |
| enum WasmInstanceObjectFields { |
| kWasmCompiledModule = 0, |
| kWasmModuleFunctionTable, |
| - kWasmModuleCodeTable, |
| + kWasmModuleCodeTable, // TODO(titzer): code_table is in compiled module |
| 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 +68,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) { |
| + 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 {}; |
| + Vector<const char> vec(reinterpret_cast<const char*>(raw), size); |
| + // TODO(titzer): can't GC move the underlying storage during this call? |
| + return isolate->factory()->NewStringFromUtf8(vec); |
|
Mircea Trofin
2016/10/15 17:38:40
Shouldn't we worry about GC happening when: alloca
|
| } |
| -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 +114,30 @@ Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { |
| return buffer; |
| } |
| -void RelocateInstanceCode(Handle<JSObject> instance, Address old_start, |
| +void RelocateInstanceCode(Handle<FixedArray> code_table, 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))); |
| + 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 +191,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 +282,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 +473,17 @@ 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() |
| + uint32_t old_mem_size = compiled_module->has_memory() |
| ? compiled_module->mem_size() |
| : compiled_module->default_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); |
| + // TODO(titzer): reset the function tables as well. |
| + |
| if (old_mem_size > 0) { |
| CHECK_NE(mem_start, undefined); |
| old_mem_address = |
| @@ -654,7 +519,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 +528,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 +552,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 +581,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 +589,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,24 +659,28 @@ 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> module_instance) { |
| + Isolate* isolate, Handle<Code> export_code, Handle<String> name, |
| + FunctionSig* sig, Handle<JSObject> module_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( |
| isolate->wasm_function_map(), name, export_code); |
| function->set_shared(*shared); |
| + // TODO(titzer): embed the function index and get the signature from |
| + // the underlying WasmModuleWrapper. |
| function->SetInternalField(kInternalModuleInstance, *module_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); |
| - } |
| + int size = static_cast<int>(sig->return_count() + sig->parameter_count()); |
| + Handle<ByteArray> signature = isolate->factory()->NewByteArray(size); |
| + // TODO(titzer): don't use raw_data() from FunctionSig. |
| + signature->copy_in(0, reinterpret_cast<const byte*>(sig->raw_data()), size); |
| + function->SetInternalField(kInternalSignature, *signature); |
| return function; |
| } |
| @@ -857,78 +696,25 @@ Object* wasm::GetOwningWasmInstance(Code* code) { |
| return cell->value(); |
| } |
| -int wasm::GetNumImportedFunctions(Handle<JSObject> wasm_object) { |
| - // TODO(wasm): Cache this number if it ever becomes a performance problem. |
| - DCHECK(IsWasmObject(*wasm_object)); |
| - WasmCompiledModule* compiled_module = GetCompiledModule(*wasm_object); |
| - 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; |
| +WasmModule* CppModule(Handle<JSObject> wasm_module) { |
|
Mircea Trofin
2016/10/15 17:38:40
GetCppModule? (as opposed to Create)
|
| + DCHECK(IsWasmModule(*wasm_module)); |
| + return reinterpret_cast<WasmModuleWrapper*>( |
| + *GetCompiledModule(*wasm_module)->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> wasm_module) { |
| + return static_cast<int>(CppModule(wasm_module)->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 +725,15 @@ 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. |
| + Handle<FixedArray> function_tables; |
|
Mircea Trofin
2016/10/15 17:38:40
I thought we're supposed to use MaybeHandle whenev
|
| + int function_table_count = static_cast<int>(this->function_tables.size()); |
| + if (function_table_count > 0) { |
| + 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,117 +804,23 @@ 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()); |
| - } |
| - |
| - // 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); |
| + if (function_table_count > 0) { |
| + ret->set_function_tables(function_tables); |
| } |
| - // 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); |
| + // Compile JS->WASM wrappers for exported functions. |
| + int func_index = 0; |
| + for (auto exp : export_table) { |
|
Mircea Trofin
2016/10/15 17:38:40
I know auto is allowed for iterators, but since we
|
| + 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++; |
|
Mircea Trofin
2016/10/15 17:38:40
++func_index;
|
| } |
| // TODO(wasm): saving the module bytes for debugging is wasteful. We should |
| @@ -1150,10 +837,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; |
| } |
| @@ -1164,11 +847,11 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( |
| class WasmInstanceBuilder { |
| public: |
| WasmInstanceBuilder(Isolate* isolate, ErrorThrower* thrower, |
| - Handle<JSObject> module_object, Handle<JSReceiver> ffi, |
| + Handle<JSObject> wasm_module, Handle<JSReceiver> ffi, |
| Handle<JSArrayBuffer> memory) |
| : isolate_(isolate), |
| thrower_(thrower), |
| - module_object_(module_object), |
| + wasm_module_(wasm_module), |
| ffi_(ffi), |
| memory_(memory) {} |
| @@ -1197,8 +880,8 @@ class WasmInstanceBuilder { |
| Handle<WasmCompiledModule> original; |
| { |
| DisallowHeapAllocation no_gc; |
| - original = handle( |
| - WasmCompiledModule::cast(module_object_->GetInternalField(0))); |
| + original = |
| + handle(WasmCompiledModule::cast(wasm_module_->GetInternalField(0))); |
| if (original->has_weak_owning_instance()) { |
| owner = |
| handle(JSObject::cast(original->weak_owning_instance()->value())); |
| @@ -1218,6 +901,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,13 +931,16 @@ 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 +950,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 +964,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,7 +978,7 @@ class WasmInstanceBuilder { |
| //-------------------------------------------------------------------------- |
| // Process the initialization for the module's globals. |
| //-------------------------------------------------------------------------- |
| - ProcessInits(globals); |
| + InitGlobals(globals); |
| //-------------------------------------------------------------------------- |
| // Set up the memory for the new instance. |
| @@ -1298,7 +986,7 @@ class WasmInstanceBuilder { |
| 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,17 @@ 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() |
| + uint32_t old_mem_size = compiled_module_->has_memory() |
| ? compiled_module_->mem_size() |
| : compiled_module_->default_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, |
| + RelocateInstanceCode(code_table, old_mem_start, mem_start, old_mem_size, |
| mem_size); |
| - compiled_module_->set_heap(memory_); |
| + compiled_module_->set_memory(memory_); |
| } |
| //-------------------------------------------------------------------------- |
| @@ -1346,33 +1035,47 @@ 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++) { |
|
Mircea Trofin
2016/10/15 17:38:40
++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) { |
|
Mircea Trofin
2016/10/15 17:38:40
same comment about auto as above.
|
| + // TODO(titzer): proper bounds check of the initialization. |
| + uint32_t base = EvalUint32InitExpr(globals, table_init.offset); |
| + for (size_t i = 0; i < table_init.entries.size(); i++) { |
|
Mircea Trofin
2016/10/15 17:38:40
++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++) { |
|
Mircea Trofin
2016/10/15 17:38:40
++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++) { |
|
Mircea Trofin
2016/10/15 17:38:41
++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); |
| } |
| //-------------------------------------------------------------------------- |
| @@ -1390,19 +1093,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(); |
| + int32_t 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, |
| + instance); |
| RecordStats(isolate_, *startup_code); |
| // Call the JS function. |
| Handle<Object> undefined = factory->undefined_value(); |
| @@ -1438,10 +1137,10 @@ 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_); |
| + wasm_module_->SetInternalField(0, *compiled_module_); |
| instance->SetInternalField(kWasmCompiledModule, *compiled_module_); |
| compiled_module_->set_weak_owning_instance(link_to_owning_instance); |
| GlobalHandles::MakeWeak(global_handle.location(), |
| @@ -1450,17 +1149,18 @@ class WasmInstanceBuilder { |
| } |
| } |
| - DCHECK(wasm::IsWasmObject(*instance)); |
| + DCHECK(wasm::IsWasmModule(*instance)); |
| TRACE("Finishing instance %d\n", compiled_module_->instance_id()); |
| - TRACE_CHAIN(WasmCompiledModule::cast(module_object_->GetInternalField(0))); |
| + TRACE_CHAIN(WasmCompiledModule::cast(wasm_module_->GetInternalField(0))); |
| return instance; |
| } |
| private: |
| Isolate* isolate_; |
| + WasmModule* module_; |
|
Mircea Trofin
2016/10/15 17:38:40
elsewhere, there was a CppModule API. Could we cal
|
| ErrorThrower* thrower_; |
| - Handle<JSObject> module_object_; |
| + Handle<JSObject> wasm_module_; |
| Handle<JSReceiver> ffi_; |
| Handle<JSArrayBuffer> memory_; |
| Handle<WasmCompiledModule> compiled_module_; |
| @@ -1522,57 +1222,47 @@ 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(); |
| + break; |
| + } |
| + } |
| + |
| // 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; |
| + int param_count = static_cast<int>(sig->parameter_count()); |
| Handle<Code> code; |
| bool isMatch = false; |
| @@ -1586,15 +1276,18 @@ class WasmInstanceBuilder { |
| Handle<ByteArray> exportedSig = Handle<ByteArray>( |
|
Mircea Trofin
2016/10/15 17:38:40
do we still need this, given we now have the nativ
|
| ByteArray::cast(func->GetInternalField(kInternalSignature))); |
| if (exported_param_count == param_count && |
| - exportedSig->length() == sig_data->length() && |
| - memcmp(exportedSig->GetDataStartAddress(), |
| - sig_data->GetDataStartAddress(), |
| + exportedSig->length() == |
| + (sig->return_count() + sig->parameter_count()) && |
| + // TODO(titzer): do not use raw_data() of signature. |
| + memcmp(exportedSig->GetDataStartAddress(), sig->raw_data(), |
| exportedSig->length()) == 0) { |
| isMatch = true; |
| } |
| } |
| } |
| if (isMatch) { |
| + // 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(); |
| @@ -1610,22 +1303,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()); |
| - 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(); |
| @@ -1634,21 +1319,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); |
|
Mircea Trofin
2016/10/15 17:38:40
Is this change here related, or could it be a diff
|
| 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(); |
| @@ -1661,25 +1346,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++) { |
|
Mircea Trofin
2016/10/15 17:38:40
++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_, |
|
Mircea Trofin
2016/10/15 17:38:40
ExtractString allocates each time we call it. Shou
|
| + 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(); |
| @@ -1690,10 +1377,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; |
| @@ -1723,9 +1409,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: |
| @@ -1736,29 +1420,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; |
| } |
| } |
| } |
| @@ -1783,10 +1487,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_); |
| @@ -1800,27 +1504,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) { |
|
Mircea Trofin
2016/10/15 17:38:40
same comment about auto as above.
|
| 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_, |
|
Mircea Trofin
2016/10/15 17:38:40
same comment about string interning as above
|
| + 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); |
| - desc.set_value(WrapExportCodeAsJSFunction( |
| - isolate_, export_code, name, arity, signature, instance)); |
| + code_table->GetValueChecked<Code>(isolate_, export_index); |
| + desc.set_value(WrapExportCodeAsJSFunction(isolate_, export_code, name, |
| + function.sig, instance)); |
| + func_index++; |
| break; |
| } |
| case kExternalTable: |
| @@ -1847,18 +1547,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(); |
| @@ -1886,37 +1585,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++)); |
| @@ -1960,39 +1648,39 @@ void WasmCompiledModule::PrintInstancesChain() { |
| } |
| Handle<Object> wasm::GetWasmFunctionNameOrNull(Isolate* isolate, |
| - Handle<Object> wasm, |
| + Handle<Object> wasm_module, |
| uint32_t func_index) { |
| - if (!wasm->IsUndefined(isolate)) { |
| - DCHECK(IsWasmObject(*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 (!wasm_module->IsUndefined(isolate)) { |
| + DCHECK(IsWasmModule(*wasm_module)); |
| + WasmModule* module = CppModule(Handle<JSObject>::cast(wasm_module)); |
| + WasmFunction& function = module->functions[func_index]; |
| + Handle<WasmCompiledModule> compiled_module(GetCompiledModule(*wasm_module), |
| + 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> wasm_module, |
| uint32_t func_index) { |
| Handle<Object> name_or_null = |
| - GetWasmFunctionNameOrNull(isolate, wasm, func_index); |
| + GetWasmFunctionNameOrNull(isolate, wasm_module, func_index); |
| if (!name_or_null->IsNull(isolate)) { |
| return Handle<String>::cast(name_or_null); |
| } |
| return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>"); |
| } |
| -bool wasm::IsWasmObject(Object* object) { |
| +bool wasm::IsWasmModule(Object* object) { |
| + // TODO(titzer): this can be made reliable with WebAssembly.Module brand. |
| if (!object->IsJSObject()) return false; |
| JSObject* obj = JSObject::cast(object); |
| Isolate* isolate = obj->GetIsolate(); |
| - if (obj->GetInternalFieldCount() != kWasmModuleInternalFieldCount) { |
| + if (obj->GetInternalFieldCount() != kWasmInstanceInternalFieldCount) { |
| return false; |
| } |
| @@ -2008,42 +1696,42 @@ bool wasm::IsWasmObject(Object* object) { |
| return true; |
| } |
| -WasmCompiledModule* wasm::GetCompiledModule(JSObject* wasm) { |
| - return WasmCompiledModule::cast(wasm->GetInternalField(kWasmCompiledModule)); |
| +WasmCompiledModule* wasm::GetCompiledModule(Object* wasm_module) { |
| + DCHECK(IsWasmModule(wasm_module)); |
| + return WasmCompiledModule::cast( |
| + JSObject::cast(wasm_module)->GetInternalField(kWasmCompiledModule)); |
| } |
| -bool wasm::WasmIsAsmJs(Object* wasm, Isolate* isolate) { |
| - if (wasm->IsUndefined(isolate)) return false; |
| - DCHECK(IsWasmObject(wasm)); |
| - WasmCompiledModule* compiled_module = GetCompiledModule(JSObject::cast(wasm)); |
| - return compiled_module->has_asm_js_script(); |
| +bool wasm::WasmIsAsmJs(Object* instance, Isolate* isolate) { |
| + return IsWasmModule(instance) && |
| + GetCompiledModule(JSObject::cast(instance))->has_asm_js_script(); |
| } |
| -Handle<Script> wasm::GetAsmWasmScript(Handle<JSObject> wasm) { |
| - DCHECK(IsWasmObject(*wasm)); |
| - WasmCompiledModule* compiled_module = GetCompiledModule(*wasm); |
| +Handle<Script> wasm::GetAsmWasmScript(Handle<JSObject> wasm_module) { |
| + DCHECK(IsWasmModule(*wasm_module)); |
| + WasmCompiledModule* compiled_module = GetCompiledModule(*wasm_module); |
| return compiled_module->asm_js_script(); |
| } |
| -int wasm::GetAsmWasmSourcePosition(Handle<JSObject> wasm, int func_index, |
| +int wasm::GetAsmWasmSourcePosition(Handle<JSObject> wasm_module, int func_index, |
| int byte_offset) { |
| - return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(wasm), func_index, |
| - byte_offset); |
| + return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(wasm_module), |
| + func_index, byte_offset); |
| } |
| -Handle<SeqOneByteString> wasm::GetWasmBytes(Handle<JSObject> wasm) { |
| - DCHECK(IsWasmObject(*wasm)); |
| - WasmCompiledModule* compiled_module = GetCompiledModule(*wasm); |
| +Handle<SeqOneByteString> wasm::GetWasmBytes(Handle<JSObject> wasm_module) { |
| + DCHECK(IsWasmModule(*wasm_module)); |
| + WasmCompiledModule* compiled_module = GetCompiledModule(*wasm_module); |
| return compiled_module->module_bytes(); |
| } |
| -Handle<WasmDebugInfo> wasm::GetDebugInfo(Handle<JSObject> wasm) { |
| - Handle<Object> info(wasm->GetInternalField(kWasmDebugInfo), |
| - wasm->GetIsolate()); |
| - if (!info->IsUndefined(wasm->GetIsolate())) |
| +Handle<WasmDebugInfo> wasm::GetDebugInfo(Handle<JSObject> wasm_module) { |
| + Handle<Object> info(wasm_module->GetInternalField(kWasmDebugInfo), |
| + wasm_module->GetIsolate()); |
| + if (!info->IsUndefined(wasm_module->GetIsolate())) |
| return Handle<WasmDebugInfo>::cast(info); |
| - Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(wasm); |
| - wasm->SetInternalField(kWasmDebugInfo, *new_info); |
| + Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(wasm_module); |
| + wasm_module->SetInternalField(kWasmDebugInfo, *new_info); |
| return new_info; |
| } |
| @@ -2051,7 +1739,7 @@ bool wasm::UpdateWasmModuleMemory(Handle<JSObject> object, Address old_start, |
| Address new_start, uint32_t old_size, |
| uint32_t new_size) { |
| DisallowHeapAllocation no_allocation; |
| - if (!IsWasmObject(*object)) { |
| + if (!IsWasmModule(*object)) { |
| return false; |
| } |
| @@ -2079,72 +1767,34 @@ bool wasm::UpdateWasmModuleMemory(Handle<JSObject> object, Address old_start, |
| return true; |
| } |
| -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; |
| +int wasm::GetNumberOfFunctions(Handle<JSObject> wasm_module) { |
| + WasmModule* module = CppModule(wasm_module); |
| + return static_cast<int>(module->functions.size()); |
| } |
| -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> wasm) { |
| - DCHECK(IsWasmObject(*wasm)); |
| - WasmCompiledModule* compiled_module = GetCompiledModule(*wasm); |
| - 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); |
| -} |
| - |
| -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. |
| @@ -2154,17 +1804,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()); |
| - 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->Failed("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(); |
| @@ -2183,15 +1839,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()); |
| - 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; |
| @@ -2203,17 +1857,17 @@ bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start, |
| MaybeHandle<JSArrayBuffer> wasm::GetInstanceMemory(Isolate* isolate, |
| Handle<JSObject> instance) { |
| Object* mem = instance->GetInternalField(kWasmMemArrayBuffer); |
| - DCHECK(IsWasmObject(*instance)); |
| + DCHECK(IsWasmModule(*instance)); |
| if (mem->IsUndefined(isolate)) return MaybeHandle<JSArrayBuffer>(); |
| return Handle<JSArrayBuffer>(JSArrayBuffer::cast(mem)); |
| } |
| void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer) { |
| DisallowHeapAllocation no_gc; |
| - DCHECK(IsWasmObject(*instance)); |
| + DCHECK(IsWasmModule(*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, |
| @@ -2278,25 +1932,24 @@ int32_t wasm::GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance, |
| } |
| 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( |
| - IsWasmObject(current_instance->ptr_to_weak_owning_instance()->value())); |
| + IsWasmModule(current_instance->ptr_to_weak_owning_instance()->value())); |
| prev = current_instance; |
| current_instance = WasmCompiledModule::cast( |
| current_instance->ptr_to_weak_next_instance()->value()); |
| @@ -2307,22 +1960,56 @@ 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(IsWasmObject(*instance)); |
| - WasmCompiledModule* compiled_module = GetCompiledModule(*instance); |
| - CHECK(compiled_module->has_weak_module_object()); |
| - CHECK(compiled_module->ptr_to_weak_module_object()->cleared()); |
| + CHECK(IsWasmModule(*wasm_module)); |
| + WasmCompiledModule* compiled_module = GetCompiledModule(*wasm_module); |
| + CHECK(compiled_module->has_weak_wasm_module()); |
| + CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared()); |
| +} |
| + |
| +uint32_t WasmCompiledModule::min_memory_pages() const { |
| + return reinterpret_cast<WasmModuleWrapper*>(*module_wrapper()) |
| + ->get() |
| + ->min_mem_pages; |
| +} |
| + |
| +void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate, |
| + Handle<FixedArray> array) { |
|
Mircea Trofin
2016/10/15 17:38:41
why not pass this guy as a Handle<WasmCompiledModu
|
| + 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; disable GC. |
| + 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 |
| + ModuleResult result = |
| + DecodeWasmModule(isolate, start, end, false, kWasmOrigin); |
|
Mircea Trofin
2016/10/15 17:38:40
Could you add a TODO to avoid decoding the entire
|
| + 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)); |
| } |