diff --git a/crates/environ/src/component/dfg.rs b/crates/environ/src/component/dfg.rs index 4b059177e8..7aa35d603d 100644 --- a/crates/environ/src/component/dfg.rs +++ b/crates/environ/src/component/dfg.rs @@ -352,6 +352,7 @@ enum RuntimeInstance { impl LinearizeDfg<'_> { fn instantiate(&mut self, instance: InstanceId, args: &Instance) { + log::trace!("creating instance {instance:?}"); let instantiation = match args { Instance::Static(index, args) => InstantiateModule::Static( *index, @@ -500,8 +501,10 @@ impl LinearizeDfg<'_> { where T: Clone, { + let instance = export.instance; + log::trace!("referencing export of {instance:?}"); info::CoreExport { - instance: self.runtime_instances[&RuntimeInstance::Normal(export.instance)], + instance: self.runtime_instances[&RuntimeInstance::Normal(instance)], item: export.item.clone(), } } diff --git a/crates/environ/src/component/translate/adapt.rs b/crates/environ/src/component/translate/adapt.rs index ab5b7e4034..7289bb5558 100644 --- a/crates/environ/src/component/translate/adapt.rs +++ b/crates/environ/src/component/translate/adapt.rs @@ -296,7 +296,7 @@ impl PartitionAdapterModules { // didn't depend on anything in that module itself or it will be added // to a fresh module if this adapter depended on something that the // current adapter module created. - log::debug!("adding {id:?} to adapter module {adapter:#?}"); + log::debug!("adding {id:?} to adapter module"); self.next_module.adapters.push(id); } @@ -319,9 +319,12 @@ impl PartitionAdapterModules { // If this adapter is already defined then we can safely depend // on it with no consequences. if self.defined_items.contains(&Def::Adapter(*id)) { + log::debug!("using existing adapter {id:?} "); return; } + log::debug!("splitting module needing {id:?} "); + // .. otherwise we found a case of an adapter depending on an // adapter-module-in-progress meaning that the current adapter // module must be completed and then a new one is started. @@ -337,16 +340,33 @@ impl PartitionAdapterModules { } fn core_export(&mut self, dfg: &dfg::ComponentDfg, export: &dfg::CoreExport) { - // If this instance has already been visited that means it can already - // be defined for this adapter module, so nothing else needs to be done. - if !self.defined_items.insert(Def::Instance(export.instance)) { - return; + // When an adapter depends on an exported item it actually depends on + // the instance of that exported item. The caveat here is that the + // adapter not only depends on that particular instance, but also all + // prior instances to that instance as well because instance + // instantiation order is fixed and cannot change. + // + // To model this the instance index space is looped over here and while + // an instance hasn't been visited it's visited. Note that if an + // instance has already been visited then all prior instances have + // already been visited so there's no need to continue. + let mut instance = export.instance; + while self.defined_items.insert(Def::Instance(instance)) { + self.instance(dfg, instance); + if instance.as_u32() == 0 { + break; + } + instance = dfg::InstanceId::from_u32(instance.as_u32() - 1); } + } + + fn instance(&mut self, dfg: &dfg::ComponentDfg, instance: dfg::InstanceId) { + log::debug!("visiting instance {instance:?}"); // ... otherwise if this is the first timet he instance has been seen // then the instances own arguments are recursively visited to find // transitive dependencies on adapters. - match &dfg.instances[export.instance] { + match &dfg.instances[instance] { dfg::Instance::Static(_, args) => { for arg in args.iter() { self.core_def(dfg, arg); diff --git a/tests/misc_testsuite/component-model/fused.wast b/tests/misc_testsuite/component-model/fused.wast index 6d326da6e2..6de762471e 100644 --- a/tests/misc_testsuite/component-model/fused.wast +++ b/tests/misc_testsuite/component-model/fused.wast @@ -1393,3 +1393,44 @@ ) (instance (instantiate $c2 (with "" (instance $c1)))) ) + +;; Adapters are used slightly out-of-order here to stress the internals of +;; dependencies between adapters. +(component + (core module $m + (func (export "execute")) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (memory (export "memory") 1) + ) + + (component $root + (core instance $m (instantiate $m)) + (func (export "execute") + (canon lift (core func $m "execute")) + ) + ) + (component $c + (import "backend" (instance $i + (export "execute" (func)) + )) + (core module $shim2 (import "" "0" (func))) + (core instance $m (instantiate $m)) + + ;; This adapter, when fused with itself on the second instantiation of this + ;; component, will dependend on the prior instance `$m` so it which means + ;; that the adapter module containing this must be placed in the right + ;; location. + (core func $execute + (canon lower (func $i "execute") (memory $m "memory") (realloc (func $m "realloc"))) + ) + (core instance (instantiate $shim2 + (with "" (instance + (export "0" (func $execute)) + )) + )) + (func (export "execute") (canon lift (core func $m "execute"))) + ) + (instance $root (instantiate $root)) + (instance $c1 (instantiate $c (with "backend" (instance $root)))) + (instance $c2 (instantiate $c (with "backend" (instance $c1)))) +)