Chromium Code Reviews| Index: src/wasm/wasm-module.cc |
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
| index 2470257735299c590511fb7e82f6d4f2b4152635..2d96d45a0c40f5204eaa71e30d99d48faf74c5b0 100644 |
| --- a/src/wasm/wasm-module.cc |
| +++ b/src/wasm/wasm-module.cc |
| @@ -158,15 +158,19 @@ Object* GetOwningWasmInstance(Object* undefined, Code* code) { |
| namespace { |
| // Internal constants for the layout of the module object. |
| -const int kWasmModuleFunctionTable = 0; |
| -const int kWasmModuleCodeTable = 1; |
| -const int kWasmMemArrayBuffer = 2; |
| -const int kWasmGlobalsArrayBuffer = 3; |
| -// TODO(clemensh): Remove function name array, extract names from module bytes. |
| -const int kWasmFunctionNamesArray = 4; |
| -const int kWasmModuleBytesString = 5; |
| -const int kWasmDebugInfo = 6; |
| -const int kWasmModuleInternalFieldCount = 7; |
| +enum WasmInstanceFields { |
| + kWasmCompiledModule, |
|
bradnelson
2016/09/02 16:56:59
Optional:
Realize the default is zero, but I've so
Mircea Trofin
2016/09/02 20:55:30
Done.
|
| + kWasmModuleFunctionTable, |
| + kWasmModuleCodeTable, |
| + kWasmMemArrayBuffer, |
| + kWasmGlobalsArrayBuffer, |
| + // TODO(clemensh): Remove function name array, extract names from module |
| + // bytes. |
| + kWasmFunctionNamesArray, |
| + kWasmModuleBytesString, |
| + kWasmDebugInfo, |
| + kWasmModuleInternalFieldCount |
| +}; |
| // TODO(mtrofin): Unnecessary once we stop using JS Heap for wasm code. |
| // For now, each field is expected to have the type commented by its side. |
| @@ -194,8 +198,14 @@ enum CompiledWasmObjectFields { |
| kDataSegments, // maybe ByteArray. |
| kGlobalsSize, // Smi. an uint32_t |
| + kMemSize, // Smi.an uint32_t |
| + kMemStart, // MaybeHandle<ArrayBuffer> |
| kExportMem, // Smi. bool |
| kOrigin, // Smi. ModuleOrigin |
| + kNextInstance, // WeakCell. See compiled code cloning. |
| + kPrevInstance, // WeakCell. See compiled code cloning. |
| + kOwningInstance, // WeakCell, pointing to the owning instance. |
| + kModuleObject, // WeakCell, pointing to the module object. |
| kCompiledWasmObjectTableSize // Sentinel value. |
| }; |
| @@ -329,8 +339,9 @@ Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { |
| return buffer; |
| } |
| -void RelocateInstanceCode(Handle<JSObject> instance, Address start, |
| - uint32_t prev_size, uint32_t new_size) { |
| +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) { |
| @@ -339,7 +350,7 @@ void RelocateInstanceCode(Handle<JSObject> instance, Address start, |
| int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | |
| (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE); |
| for (RelocIterator it(*function, mask); !it.done(); it.next()) { |
| - it.rinfo()->update_wasm_memory_reference(nullptr, start, prev_size, |
| + it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size, |
| new_size); |
| } |
| } |
| @@ -361,7 +372,8 @@ Handle<JSArrayBuffer> AllocateMemory(ErrorThrower* thrower, Isolate* isolate, |
| return mem_buffer; |
| } |
| -void RelocateGlobals(Handle<JSObject> instance, Address globals_start) { |
| +void RelocateGlobals(Handle<JSObject> instance, 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()); |
| @@ -370,7 +382,7 @@ void RelocateGlobals(Handle<JSObject> instance, Address globals_start) { |
| AllowDeferredHandleDereference embedding_raw_address; |
| int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE; |
| for (RelocIterator it(*function, mask); !it.done(); it.next()) { |
| - it.rinfo()->update_wasm_global_reference(nullptr, globals_start); |
| + it.rinfo()->update_wasm_global_reference(old_start, globals_start); |
| } |
| } |
| } |
| @@ -401,40 +413,35 @@ void InitializePlaceholders(Factory* factory, |
| } |
| } |
| -bool LinkFunction(Handle<Code> unlinked, |
| - const std::vector<Handle<Code>>& code_targets, |
| - Code::Kind kind) { |
| +bool LinkFunction(Isolate* isolate, Handle<Code> unlinked, |
| + Handle<FixedArray> code_targets, |
| + Code::Kind kind = Code::WASM_FUNCTION) { |
| bool modified = false; |
| - int mode_mask = RelocInfo::kCodeTargetMask; |
| + int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); |
| AllowDeferredHandleDereference embedding_raw_address; |
| for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) { |
| - RelocInfo::Mode mode = it.rinfo()->rmode(); |
| - if (RelocInfo::IsCodeTarget(mode)) { |
| - Code* target = |
| - Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| - if (target->kind() == kind && |
| - target->constant_pool_offset() >= kPlaceholderMarker) { |
| - // Patch direct calls to placeholder code objects. |
| - uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
| - CHECK(index < code_targets.size()); |
| - Handle<Code> new_target = code_targets[index]; |
| - if (target != *new_target) { |
| - it.rinfo()->set_target_address(new_target->instruction_start(), |
| - UPDATE_WRITE_BARRIER, |
| - SKIP_ICACHE_FLUSH); |
| - modified = true; |
| - } |
| + Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| + if (target->kind() == kind && |
| + target->constant_pool_offset() >= kPlaceholderMarker) { |
| + // Patch direct calls to placeholder code objects. |
| + uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
| + CHECK(index < static_cast<uint32_t>(code_targets->length())); |
| + Handle<Code> new_target = |
| + code_targets->GetValueChecked<Code>(isolate, index); |
| + if (target != *new_target) { |
| + it.rinfo()->set_target_address(new_target->instruction_start(), |
| + UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); |
| + modified = true; |
| } |
| } |
| } |
| return modified; |
| } |
| -void LinkModuleFunctions(Isolate* isolate, |
| - std::vector<Handle<Code>>& functions) { |
| - for (size_t i = 0; i < functions.size(); ++i) { |
| - Handle<Code> code = functions[i]; |
| - LinkFunction(code, functions, Code::WASM_FUNCTION); |
| +void LinkModuleFunctions(Isolate* isolate, Handle<FixedArray> functions) { |
| + for (int i = 0; i < functions->length(); ++i) { |
| + Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); |
| + LinkFunction(isolate, code, functions); |
| } |
| } |
| @@ -453,8 +460,6 @@ void SetRuntimeSupport(Isolate* isolate, Handle<JSObject> js_object) { |
| for (int i = FLAG_skip_compiling_wasm_funcs; i < functions->length(); ++i) { |
| Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); |
| - DCHECK(code->deoptimization_data() == nullptr || |
|
bradnelson
2016/09/02 16:57:00
Why?
Mircea Trofin
2016/09/02 20:55:30
Because now the deopt will be valid, but belonging
|
| - code->deoptimization_data()->length() == 0); |
| Handle<FixedArray> deopt_data = |
| isolate->factory()->NewFixedArray(2, TENURED); |
| deopt_data->set(0, *weak_link); |
| @@ -621,6 +626,17 @@ static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) { |
| } |
| } |
| +Address GetGlobalStartAddressFromCodeTemplate(Object* undefined, |
| + JSObject* owner) { |
| + Address old_address = nullptr; |
| + Object* stored_value = owner->GetInternalField(kWasmGlobalsArrayBuffer); |
| + if (stored_value != undefined) { |
| + old_address = static_cast<Address>( |
| + JSArrayBuffer::cast(stored_value)->backing_store()); |
| + } |
| + return old_address; |
| +} |
| + |
| Handle<FixedArray> GetImportsMetadata(Factory* factory, |
| const WasmModule* module) { |
| Handle<FixedArray> ret = factory->NewFixedArray( |
| @@ -912,8 +928,9 @@ void SetDebugSupport(Factory* factory, Handle<FixedArray> compiled_module, |
| } |
| } |
| -bool SetupGlobals(Isolate* isolate, Handle<FixedArray> compiled_module, |
| - Handle<JSObject> instance, ErrorThrower* thrower) { |
| +bool SetupGlobals(Isolate* isolate, MaybeHandle<JSObject> template_owner, |
| + Handle<FixedArray> compiled_module, Handle<JSObject> instance, |
| + ErrorThrower* thrower) { |
| uint32_t globals_size = static_cast<uint32_t>( |
| Smi::cast(compiled_module->get(kGlobalsSize))->value()); |
| if (globals_size > 0) { |
| @@ -923,7 +940,13 @@ bool SetupGlobals(Isolate* isolate, Handle<FixedArray> compiled_module, |
| thrower->Error("Out of memory: wasm globals"); |
| return false; |
| } |
| - RelocateGlobals(instance, |
| + Address old_address = |
| + template_owner.is_null() |
| + ? nullptr |
| + : GetGlobalStartAddressFromCodeTemplate( |
| + *isolate->factory()->undefined_value(), |
| + JSObject::cast(*template_owner.ToHandleChecked())); |
| + RelocateGlobals(instance, old_address, |
| static_cast<Address>(globals_buffer->backing_store())); |
| instance->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer); |
| } |
| @@ -949,13 +972,72 @@ bool SetupInstanceHeap(Isolate* isolate, Handle<FixedArray> compiled_module, |
| instance->SetInternalField(kWasmMemArrayBuffer, *memory); |
| Address mem_start = static_cast<Address>(memory->backing_store()); |
| uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number()); |
| - RelocateInstanceCode(instance, mem_start, |
| - WasmModule::kPageSize * min_mem_pages, mem_size); |
| + uint32_t old_mem_size = static_cast<uint32_t>( |
| + compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize) |
| + ->value()); |
| + MaybeHandle<JSArrayBuffer> old_mem = |
| + compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart); |
| + Address old_mem_start = |
| + old_mem.is_null() |
| + ? nullptr |
| + : static_cast<Address>(old_mem.ToHandleChecked()->backing_store()); |
| + RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size, |
| + mem_size); |
| LoadDataSegments(compiled_module, mem_start, mem_size); |
| + compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize) |
| + ->set_value(static_cast<double>(mem_size)); |
| + compiled_module->set(kMemStart, *memory); |
| } |
| return true; |
| } |
| +void FixupFunctionsAndImports(Handle<FixedArray> old_functions, |
| + Handle<FixedArray> new_functions, |
| + MaybeHandle<FixedArray> maybe_old_imports, |
| + MaybeHandle<FixedArray> maybe_new_imports) { |
| + DCHECK_EQ(new_functions->length(), old_functions->length()); |
| + |
| + DisallowHeapAllocation no_gc; |
| + std::map<Code*, Code*> old_to_new_code; |
| + for (int i = 0; i < new_functions->length(); ++i) { |
| + old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)), |
| + Code::cast(new_functions->get(i)))); |
| + } |
| + DCHECK_EQ(maybe_old_imports.is_null(), maybe_new_imports.is_null()); |
| + if (!maybe_old_imports.is_null()) { |
| + Handle<FixedArray> old_imports = maybe_old_imports.ToHandleChecked(); |
| + Handle<FixedArray> new_imports = maybe_new_imports.ToHandleChecked(); |
| + DCHECK_EQ(new_imports->length(), old_imports->length()); |
| + for (int i = 0; i < new_imports->length(); ++i) { |
| + old_to_new_code.insert(std::make_pair(Code::cast(old_imports->get(i)), |
| + Code::cast(new_imports->get(i)))); |
| + } |
| + } |
| + int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); |
| + AllowDeferredHandleDereference embedding_raw_address; |
| + for (int i = 0; i < new_functions->length(); ++i) { |
| + Code* wasm_function = Code::cast(new_functions->get(i)); |
| + for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) { |
| + Code* old_code = |
| + Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| + if (old_code->kind() == Code::WASM_TO_JS_FUNCTION || |
| + old_code->kind() == Code::WASM_FUNCTION) { |
| + auto found = old_to_new_code.find(old_code); |
| + DCHECK(found != old_to_new_code.end()); |
| + Code* new_code = found->second; |
| + // Avoid redundant updates, expected for wasm functions, if we're at the |
| + // first instance. |
| + if (new_code == old_code) { |
| + DCHECK(new_code->kind() == Code::WASM_FUNCTION); |
| + continue; |
| + } |
| + it.rinfo()->set_target_address(new_code->instruction_start(), |
| + UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); |
| + } |
| + } |
| + } |
| +} |
| + |
| bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module, |
| Handle<JSObject> instance, ErrorThrower* thrower, |
| Handle<JSReceiver> ffi) { |
| @@ -974,49 +1056,14 @@ bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module, |
| } |
| RecordStats(isolate, import_code); |
| - |
| if (import_code.empty()) return true; |
| - { |
| - DisallowHeapAllocation no_gc; |
| - std::map<Code*, int> import_to_index; |
| - Handle<FixedArray> mapping = |
| - compiled_module->GetValueChecked<FixedArray>(isolate, kImportMap); |
| - for (int i = 0; i < mapping->length(); ++i) { |
| - import_to_index.insert(std::make_pair(Code::cast(mapping->get(i)), i)); |
| - } |
| - |
| - Handle<FixedArray> code_table = Handle<FixedArray>( |
| - FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable))); |
| - |
| - int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); |
| - AllowDeferredHandleDereference embedding_raw_address; |
| - for (int i = 0; i < code_table->length(); ++i) { |
| - Handle<Code> wasm_function = |
| - code_table->GetValueChecked<Code>(isolate, i); |
| - for (RelocIterator it(*wasm_function, mode_mask); !it.done(); it.next()) { |
| - Code* target = |
| - Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| - if (target->kind() == Code::WASM_TO_JS_FUNCTION) { |
| - auto found_index = import_to_index.find(target); |
| - CHECK(found_index != import_to_index.end()); |
| - int index = found_index->second; |
| - CHECK(index < static_cast<int>(import_code.size())); |
| - Handle<Code> new_target = import_code[index]; |
| - it.rinfo()->set_target_address(new_target->instruction_start(), |
| - UPDATE_WRITE_BARRIER, |
| - SKIP_ICACHE_FLUSH); |
| - } |
| - } |
| - } |
| - } |
| - Handle<FixedArray> new_mapping = |
| + Handle<FixedArray> new_imports = |
| isolate->factory()->NewFixedArray(static_cast<int>(import_code.size())); |
| - for (int i = 0; i < new_mapping->length(); ++i) { |
| - new_mapping->set(i, *import_code[i]); |
| + for (int i = 0; i < new_imports->length(); ++i) { |
| + new_imports->set(i, *import_code[i]); |
| } |
| - compiled_module->set(kImportMap, *new_mapping); |
| - |
| + compiled_module->set(kImportMap, *new_imports); |
| return true; |
| } |
| @@ -1081,6 +1128,119 @@ bool SetupExportsObject(Handle<FixedArray> compiled_module, Isolate* isolate, |
| return true; |
| } |
| +#define GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(Field) \ |
| + WeakCell* Get##Field(const FixedArray* compiled_module) { \ |
| + Object* obj = compiled_module->get(k##Field); \ |
| + DCHECK_NOT_NULL(obj); \ |
| + if (obj->IsWeakCell()) { \ |
| + return WeakCell::cast(obj); \ |
| + } else { \ |
| + return nullptr; \ |
| + } \ |
| + } |
| + |
| +GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(NextInstance) |
| +GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(PrevInstance) |
| +GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(OwningInstance) |
| +GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(ModuleObject) |
| + |
| +static void ResetCompiledModule(Isolate* isolate, JSObject* owner, |
| + FixedArray* compiled_module) { |
| + Object* undefined = *isolate->factory()->undefined_value(); |
| + Object* mem_size_obj = compiled_module->get(kMemSize); |
| + DCHECK(mem_size_obj->IsNumber()); |
| + uint32_t old_mem_size = |
| + static_cast<uint32_t>(HeapNumber::cast(mem_size_obj)->value()); |
| + Object* mem_start = compiled_module->get(kMemStart); |
| + Address old_mem_address = nullptr; |
| + Address globals_start = |
| + GetGlobalStartAddressFromCodeTemplate(undefined, owner); |
| + |
| + if (old_mem_size > 0) { |
| + CHECK_NE(mem_start, undefined); |
| + old_mem_address = |
| + static_cast<Address>(JSArrayBuffer::cast(mem_start)->backing_store()); |
| + } |
| + int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) | |
| + RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) | |
| + RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE); |
| + |
| + Object* fct_obj = compiled_module->get(kFunctions); |
| + if (fct_obj != nullptr && fct_obj != undefined && |
| + (old_mem_size > 0 || globals_start != nullptr)) { |
| + FixedArray* functions = FixedArray::cast(fct_obj); |
| + for (int i = 0; i < functions->length(); ++i) { |
| + Code* code = Code::cast(functions->get(i)); |
| + bool changed = false; |
| + for (RelocIterator it(code, mode_mask); !it.done(); it.next()) { |
| + RelocInfo::Mode mode = it.rinfo()->rmode(); |
| + if (RelocInfo::IsWasmMemoryReference(mode) || |
| + RelocInfo::IsWasmMemorySizeReference(mode)) { |
| + it.rinfo()->update_wasm_memory_reference(old_mem_address, nullptr, |
| + old_mem_size, old_mem_size); |
| + changed = true; |
| + } else { |
| + CHECK(RelocInfo::IsWasmGlobalReference(mode)); |
| + it.rinfo()->update_wasm_global_reference(globals_start, nullptr); |
| + changed = true; |
| + } |
| + } |
| + if (changed) { |
| + Assembler::FlushICache(isolate, code->instruction_start(), |
| + code->instruction_size()); |
| + } |
| + } |
| + } |
| + compiled_module->set(kOwningInstance, undefined); |
| + compiled_module->set(kMemStart, undefined); |
| +} |
| + |
| +static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { |
| + JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter()); |
| + JSObject* owner = *p; |
| + FixedArray* compiled_module = |
| + FixedArray::cast(owner->GetInternalField(kWasmCompiledModule)); |
| + Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate()); |
| + Object* undefined = *isolate->factory()->undefined_value(); |
| + WeakCell* weak_module_obj = GetModuleObject(compiled_module); |
| + DCHECK_NOT_NULL(weak_module_obj); |
| + if (!weak_module_obj->cleared()) { |
|
bradnelson
2016/09/02 16:57:00
Why?
Mircea Trofin
2016/09/02 20:55:30
It may be cleared when this happens:
var m = new W
|
| + JSObject* module_obj = JSObject::cast(weak_module_obj->value()); |
| + FixedArray* current_template = |
| + FixedArray::cast(module_obj->GetInternalField(0)); |
| + DCHECK_NULL(GetPrevInstance(current_template)); |
|
bradnelson
2016/09/02 16:57:00
Separate out the remove from chain operation?
Or c
Mircea Trofin
2016/09/02 20:55:30
There nothing else than the delete - we're called
|
| + WeakCell* next = GetNextInstance(compiled_module); |
| + WeakCell* prev = GetPrevInstance(compiled_module); |
| + |
| + if (current_template == compiled_module) { |
| + if (next == nullptr) { |
| + ResetCompiledModule(isolate, owner, compiled_module); |
| + } else { |
| + DCHECK(next->value()->IsFixedArray()); |
| + module_obj->SetInternalField(0, next->value()); |
| + DCHECK_NULL(prev); |
| + FixedArray::cast(next->value())->set(kPrevInstance, undefined); |
| + } |
| + } else { |
| + DCHECK(!(prev == nullptr && next == nullptr)); |
| + // the only reason prev or next would be cleared is if the |
| + // respective objects got collected, but if that happened, |
| + // we would have relinked the list. |
| + if (prev != nullptr) { |
| + DCHECK(!prev->cleared()); |
| + FixedArray::cast(prev->value()) |
| + ->set(kNextInstance, next == nullptr ? undefined : next); |
| + } |
| + if (next != nullptr) { |
| + DCHECK(!next->cleared()); |
| + FixedArray::cast(next->value()) |
| + ->set(kPrevInstance, prev == nullptr ? undefined : prev); |
| + } |
| + } |
| + } |
| + GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); |
| +} |
| + |
| } // namespace |
| MaybeHandle<FixedArray> WasmModule::CompileFunctions( |
| @@ -1156,6 +1316,11 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions( |
| compiled_functions->set(static_cast<int>(i), code); |
| } |
| + LinkModuleFunctions(isolate, compiled_functions); |
| + |
| + // TODO(mtrofin): do we need to flush the cache here? |
| + FlushAssemblyCache(isolate, compiled_functions); |
|
bradnelson
2016/09/02 16:56:59
Because the code has never run? Probably not.
Mircea Trofin
2016/09/02 20:55:30
Acknowledged.
|
| + |
| // Create the compiled module object, and populate with compiled functions |
| // and information needed at instantiation time. This object needs to be |
| // serializable. Instantiation may occur off a deserialized version of this |
| @@ -1251,6 +1416,10 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions( |
| ret->set(kGlobalsSize, Smi::FromInt(globals_size)); |
| ret->set(kExportMem, Smi::FromInt(mem_export)); |
| ret->set(kOrigin, Smi::FromInt(origin)); |
| + ret->set(kMemSize, |
| + *factory->NewHeapNumber( |
| + static_cast<double>(temp_instance_for_compilation.mem_size), |
| + MUTABLE, TENURED)); |
| return ret; |
| } |
| @@ -1275,7 +1444,8 @@ void PatchJSWrapper(Isolate* isolate, Handle<Code> wrapper, |
| Handle<FixedArray> SetupIndirectFunctionTable( |
| Isolate* isolate, Handle<FixedArray> wasm_functions, |
| - Handle<FixedArray> indirect_table_template) { |
| + Handle<FixedArray> indirect_table_template, |
| + Handle<FixedArray> tables_to_replace) { |
| Factory* factory = isolate->factory(); |
| Handle<FixedArray> cloned_indirect_tables = |
| factory->CopyFixedArray(indirect_table_template); |
| @@ -1290,10 +1460,13 @@ Handle<FixedArray> SetupIndirectFunctionTable( |
| Handle<FixedArray> cloned_table = factory->CopyFixedArray(orig_table); |
| cloned_metadata->set(kTable, *cloned_table); |
| // Patch the cloned code to refer to the cloned kTable. |
| - for (int i = 0; i < wasm_functions->length(); ++i) { |
| + 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, i); |
| - PatchFunctionTable(wasm_function, orig_table, cloned_table); |
| + wasm_functions->GetValueChecked<Code>(isolate, fct_index); |
| + PatchFunctionTable(wasm_function, table_to_replace, cloned_table); |
| } |
| } |
| return cloned_indirect_tables; |
| @@ -1302,7 +1475,22 @@ Handle<FixedArray> SetupIndirectFunctionTable( |
| Handle<FixedArray> CloneModuleForInstance(Isolate* isolate, |
| Handle<FixedArray> original) { |
| Factory* factory = isolate->factory(); |
| + bool is_first = |
| + original->GetValue<WeakCell>(isolate, kOwningInstance).is_null(); |
| + |
| + if (is_first) { |
| + return original; |
| + } |
| + |
| + // We insert the latest clone in front. |
| Handle<FixedArray> clone = factory->CopyFixedArray(original); |
| + Handle<WeakCell> weak_link_to_wasm_obj = |
| + original->GetValueChecked<WeakCell>(isolate, kModuleObject); |
| + |
| + clone->set(kModuleObject, *weak_link_to_wasm_obj); |
| + clone->set(kNextInstance, *factory->NewWeakCell(original)); |
| + original->set(kPrevInstance, *factory->NewWeakCell(clone)); |
| + JSObject::cast(weak_link_to_wasm_obj->value())->SetInternalField(0, *clone); |
| // Clone each wasm code object. |
| Handle<FixedArray> orig_wasm_functions = |
| @@ -1363,6 +1551,7 @@ Handle<FixedArray> CloneModuleForInstance(Isolate* isolate, |
| clone_wasm_functions->GetValueChecked<Code>(isolate, startup_fct_index); |
| PatchJSWrapper(isolate, startup_fct_clone, new_target); |
| } |
| + clone->set(kImportMap, *isolate->factory()->undefined_value()); |
| return clone; |
| } |
| @@ -1372,27 +1561,30 @@ Handle<FixedArray> CloneModuleForInstance(Isolate* isolate, |
| // * installs named properties on the object for exported functions |
| // * compiles wasm code to machine code |
| MaybeHandle<JSObject> WasmModule::Instantiate( |
| - Isolate* isolate, Handle<FixedArray> compiled_module, |
| + Isolate* isolate, Handle<FixedArray> compiled_module_template, |
| Handle<JSReceiver> ffi, Handle<JSArrayBuffer> memory) { |
| HistogramTimerScope wasm_instantiate_module_time_scope( |
| isolate->counters()->wasm_instantiate_module_time()); |
| ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
| Factory* factory = isolate->factory(); |
| - compiled_module = CloneModuleForInstance(isolate, compiled_module); |
| + Handle<FixedArray> compiled_module = |
| + CloneModuleForInstance(isolate, compiled_module_template); |
| + bool template_is_owned = |
| + GetOwningInstance(*compiled_module_template) != nullptr; |
| + |
| + MaybeHandle<JSObject> template_owner; |
| + if (template_is_owned) { |
| + Handle<WeakCell> weak_owner = |
| + compiled_module_template->GetValueChecked<WeakCell>(isolate, |
| + kOwningInstance); |
| + template_owner = handle(JSObject::cast(weak_owner->value())); |
| + } |
| // These fields are compulsory. |
| Handle<FixedArray> code_table = |
| compiled_module->GetValueChecked<FixedArray>(isolate, kFunctions); |
| - std::vector<Handle<Code>> functions( |
| - static_cast<size_t>(code_table->length())); |
| - for (int i = 0; i < code_table->length(); ++i) { |
| - functions[static_cast<size_t>(i)] = |
| - code_table->GetValueChecked<Code>(isolate, i); |
| - } |
| - LinkModuleFunctions(isolate, functions); |
| - |
| RecordStats(isolate, code_table); |
| MaybeHandle<JSObject> nothing; |
| @@ -1403,35 +1595,62 @@ MaybeHandle<JSObject> WasmModule::Instantiate( |
| Handle<JSObject> js_object = factory->NewJSObjectFromMap(map, TENURED); |
| js_object->SetInternalField(kWasmModuleCodeTable, *code_table); |
| + // Remember the old imports, for the case when we are at the first instance - |
| + // they will be |
| + // replaced with the instance's actual imports in SetupImports. |
|
bradnelson
2016/09/02 16:57:00
reflow comment
Mircea Trofin
2016/09/02 20:55:30
Done.
|
| + MaybeHandle<FixedArray> old_imports = |
| + compiled_module_template->GetValue<FixedArray>(isolate, kImportMap); |
| if (!(SetupInstanceHeap(isolate, compiled_module, js_object, memory, |
| &thrower) && |
| - SetupGlobals(isolate, compiled_module, js_object, &thrower) && |
| + SetupGlobals(isolate, template_owner, compiled_module, js_object, |
| + &thrower) && |
| SetupImports(isolate, compiled_module, js_object, &thrower, ffi) && |
| SetupExportsObject(compiled_module, isolate, js_object, &thrower))) { |
| return nothing; |
| } |
| + FixupFunctionsAndImports( |
| + compiled_module_template->GetValueChecked<FixedArray>(isolate, |
| + kFunctions), |
| + code_table, old_imports, |
| + compiled_module->GetValue<FixedArray>(isolate, kImportMap)); |
| + |
| SetDebugSupport(factory, compiled_module, js_object); |
| SetRuntimeSupport(isolate, js_object); |
| FlushAssemblyCache(isolate, code_table); |
| - MaybeHandle<FixedArray> maybe_indirect_tables = |
| - compiled_module->GetValue<FixedArray>(isolate, |
| - kTableOfIndirectFunctionTables); |
| - Handle<FixedArray> indirect_tables_template; |
| - if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) { |
| - Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable( |
| - isolate, code_table, indirect_tables_template); |
| - 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); |
| - wasm::PopulateFunctionTable(table, size, &functions); |
| + { |
| + std::vector<Handle<Code>> functions( |
| + static_cast<size_t>(code_table->length())); |
| + for (int i = 0; i < code_table->length(); ++i) { |
| + functions[static_cast<size_t>(i)] = |
| + code_table->GetValueChecked<Code>(isolate, i); |
| + } |
| + |
| + MaybeHandle<FixedArray> maybe_indirect_tables = |
| + compiled_module->GetValue<FixedArray>(isolate, |
| + kTableOfIndirectFunctionTables); |
| + Handle<FixedArray> indirect_tables_template; |
| + if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) { |
| + Handle<FixedArray> to_replace = |
| + template_owner.is_null() |
| + ? indirect_tables_template |
| + : handle(FixedArray::cast( |
| + template_owner.ToHandleChecked()->GetInternalField( |
| + kWasmModuleFunctionTable))); |
| + 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); |
| + wasm::PopulateFunctionTable(table, size, &functions); |
| + } |
| + js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); |
| } |
| - js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); |
| } |
| // Run the start function if one was specified. |
| @@ -1461,6 +1680,18 @@ MaybeHandle<JSObject> WasmModule::Instantiate( |
| } |
| DCHECK(wasm::IsWasmObject(*js_object)); |
| + |
| + if (!compiled_module->GetValue<WeakCell>(isolate, kModuleObject).is_null()) { |
| + js_object->SetInternalField(kWasmCompiledModule, *compiled_module); |
| + compiled_module->set(kOwningInstance, *factory->NewWeakCell(js_object)); |
| + |
| + Handle<Object> global_handle = |
| + isolate->global_handles()->Create(*js_object); |
| + GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), |
| + &InstanceFinalizer, |
| + v8::WeakCallbackType::kFinalizer); |
| + } |
| + |
| return js_object; |
| } |
| @@ -1648,6 +1879,8 @@ Handle<JSObject> CreateCompiledModuleObject(Isolate* isolate, |
| Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym()); |
| Object::SetProperty(module_obj, module_sym, module_obj, STRICT).Check(); |
| } |
| + compiled_module->set(kModuleObject, |
| + *isolate->factory()->NewWeakCell(module_obj)); |
| return module_obj; |
| } |
| @@ -1673,6 +1906,20 @@ MaybeHandle<JSObject> CreateModuleObjectFromBytes(Isolate* isolate, |
| origin); |
| } |
| +MaybeHandle<JSArrayBuffer> GetInstanceMemory(Isolate* isolate, |
| + Handle<JSObject> instance) { |
| + Object* mem = instance->GetInternalField(kWasmMemArrayBuffer); |
| + DCHECK(IsWasmObject(*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)); |
| + instance->SetInternalField(kWasmMemArrayBuffer, buffer); |
| +} |
| + |
| namespace testing { |
| int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, |
| @@ -1757,6 +2004,51 @@ int32_t CallFunction(Isolate* isolate, Handle<JSObject> instance, |
| return -1; |
| } |
| +void ValidateInstancesChain(Isolate* isolate, Handle<JSObject> module_obj, |
| + int instance_count) { |
| + CHECK_GE(instance_count, 0); |
| + DisallowHeapAllocation no_gc; |
| + FixedArray* compiled_module = |
| + FixedArray::cast(module_obj->GetInternalField(0)); |
| + CHECK_EQ(JSObject::cast(GetModuleObject(compiled_module)->value()), |
| + *module_obj); |
| + Object* prev = nullptr; |
| + int found_instances = GetOwningInstance(compiled_module) == nullptr ? 0 : 1; |
| + FixedArray* current_instance = compiled_module; |
| + while (GetNextInstance(current_instance) != nullptr) { |
| + CHECK((prev == nullptr && GetPrevInstance(current_instance) == nullptr) || |
| + GetPrevInstance(current_instance)->value() == prev); |
| + CHECK_EQ(GetModuleObject(current_instance)->value(), *module_obj); |
| + CHECK(IsWasmObject(GetOwningInstance(current_instance)->value())); |
| + prev = current_instance; |
| + current_instance = |
| + FixedArray::cast(GetNextInstance(current_instance)->value()); |
| + ++found_instances; |
| + CHECK_LE(found_instances, instance_count); |
| + } |
| + CHECK_EQ(found_instances, instance_count); |
| +} |
| + |
| +void ValidateModuleState(Isolate* isolate, Handle<JSObject> module_obj) { |
| + DisallowHeapAllocation no_gc; |
| + FixedArray* compiled_module = |
| + FixedArray::cast(module_obj->GetInternalField(0)); |
| + CHECK_NOT_NULL(GetModuleObject(compiled_module)); |
| + CHECK_EQ(GetModuleObject(compiled_module)->value(), *module_obj); |
| + CHECK_NULL(GetPrevInstance(compiled_module)); |
| + CHECK_NULL(GetNextInstance(compiled_module)); |
| + CHECK_NULL(GetOwningInstance(compiled_module)); |
| +} |
| + |
| +void ValidateOrphanedInstance(Isolate* isolate, Handle<JSObject> instance) { |
| + DisallowHeapAllocation no_gc; |
| + CHECK(IsWasmObject(*instance)); |
| + FixedArray* compiled_module = |
| + FixedArray::cast(instance->GetInternalField(kWasmCompiledModule)); |
| + CHECK_NOT_NULL(GetModuleObject(compiled_module)); |
| + CHECK(GetModuleObject(compiled_module)->cleared()); |
| +} |
| + |
| } // namespace testing |
| } // namespace wasm |
| } // namespace internal |