Index: src/wasm/wasm-module.cc |
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
index 76287ac6a2e607cf98966dd5a7589f28a7fa6717..4b5853563c391f93341b0053e7c7f6f8dc71113a 100644 |
--- a/src/wasm/wasm-module.cc |
+++ b/src/wasm/wasm-module.cc |
@@ -1172,41 +1172,40 @@ class WasmInstanceBuilder { |
//-------------------------------------------------------------------------- |
Handle<FixedArray> code_table; |
Handle<FixedArray> old_code_table; |
- Handle<JSObject> owner; |
- // If we don't clone, this will be null(). Otherwise, this will |
- // be a weak link to the original. If we lose the original to GC, |
- // this will be a cleared. We'll link the instances chain last. |
- MaybeHandle<WeakCell> link_to_original; |
+ MaybeHandle<JSObject> owner; |
TRACE("Starting new module instantiation\n"); |
{ |
- Handle<WasmCompiledModule> original( |
- WasmCompiledModule::cast(module_object_->GetInternalField(0)), |
- isolate_); |
+ // Root the owner, if any, before doing any allocations, which |
+ // may trigger GC. |
+ // Both owner and original template need to be in sync. Even |
+ // after we lose the original template handle, the code |
+ // objects we copied from it have data relative to the |
+ // instance - such as globals addresses. |
+ Handle<WasmCompiledModule> original; |
+ { |
+ DisallowHeapAllocation no_gc; |
+ original = handle( |
+ WasmCompiledModule::cast(module_object_->GetInternalField(0))); |
+ if (original->has_weak_owning_instance()) { |
+ owner = |
+ handle(JSObject::cast(original->weak_owning_instance()->value())); |
+ } |
+ } |
+ DCHECK(!original.is_null()); |
// Always make a new copy of the code_table, since the old_code_table |
// may still have placeholders for imports. |
old_code_table = original->code_table(); |
code_table = factory->CopyFixedArray(old_code_table); |
if (original->has_weak_owning_instance()) { |
- WeakCell* tmp = original->ptr_to_weak_owning_instance(); |
- DCHECK(!tmp->cleared()); |
- // There is already an owner, clone everything. |
- owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate_); |
- // Insert the latest clone in front. |
+ // Clone, but don't insert yet the clone in the instances chain. |
+ // We do that last. Since we are holding on to the owner instance, |
+ // the owner + original state used for cloning and patching |
+ // won't be mutated by possible finalizer runs. |
+ DCHECK(!owner.is_null()); |
TRACE("Cloning from %d\n", original->instance_id()); |
compiled_module_ = WasmCompiledModule::Clone(isolate_, original); |
- // Replace the strong reference to point to the new instance here. |
- // This allows any of the other instances, including the original, |
- // to be collected. |
- module_object_->SetInternalField(0, *compiled_module_); |
- compiled_module_->set_weak_module_object( |
- original->weak_module_object()); |
- link_to_original = factory->NewWeakCell(original); |
- // Don't link to original here. We remember the original |
- // as a weak link. If that link isn't clear by the time we finish |
- // instantiating this instance, then we link it at that time. |
- compiled_module_->reset_weak_next_instance(); |
// Clone the code for WASM functions and exports. |
for (int i = 0; i < code_table->length(); ++i) { |
@@ -1260,10 +1259,11 @@ class WasmInstanceBuilder { |
thrower_->Error("Out of memory: wasm globals"); |
return nothing; |
} |
- Address old_address = |
- owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate( |
- *factory->undefined_value(), |
- JSObject::cast(*owner)); |
+ Address old_address = owner.is_null() |
+ ? nullptr |
+ : GetGlobalStartAddressFromCodeTemplate( |
+ *factory->undefined_value(), |
+ JSObject::cast(*owner.ToHandleChecked())); |
RelocateGlobals(instance, old_address, |
static_cast<Address>(global_buffer->backing_store())); |
instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer); |
@@ -1346,8 +1346,9 @@ class WasmInstanceBuilder { |
compiled_module_->indirect_function_tables(); |
Handle<FixedArray> to_replace = |
owner.is_null() ? indirect_tables_template |
- : handle(FixedArray::cast(owner->GetInternalField( |
- kWasmModuleFunctionTable))); |
+ : 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) { |
@@ -1403,26 +1404,35 @@ class WasmInstanceBuilder { |
} |
{ |
- Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance); |
- |
Handle<Object> global_handle = |
isolate_->global_handles()->Create(*instance); |
Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module_); |
+ Handle<WeakCell> link_to_owning_instance = factory->NewWeakCell(instance); |
+ MaybeHandle<WeakCell> link_to_original; |
+ MaybeHandle<WasmCompiledModule> original; |
+ if (!owner.is_null()) { |
+ // prepare the data needed for publishing in a chain, but don't link |
+ // just yet, because |
+ // we want all the publishing to happen free from GC interruptions, and |
+ // so we do it in |
+ // one GC-free scope afterwards. |
+ original = handle(WasmCompiledModule::cast( |
+ owner.ToHandleChecked()->GetInternalField(kWasmCompiledModule))); |
+ link_to_original = factory->NewWeakCell(original.ToHandleChecked()); |
+ } |
+ // Publish the new instance to the instances chain. |
{ |
DisallowHeapAllocation no_gc; |
- compiled_module_->set_weak_owning_instance(link_to_owner); |
- Handle<WeakCell> next; |
- if (link_to_original.ToHandle(&next) && !next->cleared()) { |
- WasmCompiledModule* original = |
- WasmCompiledModule::cast(next->value()); |
- DCHECK(original->has_weak_owning_instance()); |
- DCHECK(!original->weak_owning_instance()->cleared()); |
- compiled_module_->set_weak_next_instance(next); |
- original->set_weak_prev_instance(link_to_clone); |
+ if (!link_to_original.is_null()) { |
+ 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_owning_instance(link_to_owner); |
+ module_object_->SetInternalField(0, *compiled_module_); |
instance->SetInternalField(kWasmCompiledModule, *compiled_module_); |
+ compiled_module_->set_weak_owning_instance(link_to_owning_instance); |
GlobalHandles::MakeWeak(global_handle.location(), |
global_handle.location(), &InstanceFinalizer, |
v8::WeakCallbackType::kFinalizer); |