Repository: bytecodealliance/wasm-tools
Pull request #1839 (2024-10-01 23:19:25)

Enhance `print` and `validate` fuzzers
This commit updates these two fuzzers, which just have random bytes thrown at them, to additionally fuzz various config options in `wasmprinter`. The `validate` fuzzer in particular is going to be interesting since it creates "halfway invalid" modules where the structure is valid and random bytes may be thrown in a function body. That should stress various bits and pieces of the internals of `wasmprinter` in addition to `wasmparser`.

alexcrichton: I've confirmed that the `validate` fuzzer quickly finds https://github.com/bytecodealliance/wasm-tools/issues/1838 locally as well with this change too.

Patch:
diff --git a/README.md b/README.md
index a26989b2..b3c19d5f 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ $ wasm-tools help
 
 # Examples
 
-Basic validation/printing:
+Basic validation/printing/parsing:
 
 ```sh
 # Validate a WebAssembly file
@@ -66,6 +66,9 @@ $ wasm-tools print foo.wasm
 
 # Convert a binary module to text
 $ wasm-tools print foo.wasm -o foo.wat
+
+# Convert a text module to binary
+$ wasm-tools parse foo.wat -o foo.wasm
 ```
 
 Simple mutation as well as piping commands together:
@@ -168,6 +171,45 @@ The `wasm-tools` CLI contains useful tools for debugging WebAssembly modules and
 components. The various subcommands all have `--help` explainer texts to
 describe more about their functionality as well.
 
+# WebAssembly proposals
+
+This repository strives to implement any standardized proposal to WebAssembly.
+All proposals that are [Stage 4+](https://github.com/WebAssembly/proposals) are
+enabled by default in validation. Support in the text format is always enabled
+at all times for all proposals.
+
+Currently implemented proposals in this repository that are stage 4+ are:
+
+* [x] [annotations](https://github.com/WebAssembly/annotations)
+* [x] [branch-hinting](https://github.com/WebAssembly/branch-hinting)
+* [x] [bulk-memory](https://github.com/WebAssembly/bulk-memory-operations)
+* [x] [exceptions](https://github.com/WebAssembly/exceptions)
+* [x] [extended-const](https://github.com/WebAssembly/extended-const)
+* [x] [function-references](https://github.com/WebAssembly/function-references)
+* [x] [gc](https://github.com/WebAssembly/gc)
+* [x] [memory64](https://github.com/WebAssembly/memory64)
+* [x] [multi-memory](https://github.com/WebAssembly/multi-memory)
+* [x] [multi-value](https://github.com/WebAssembly/multi-value)
+* [x] [mutable-global](https://github.com/WebAssembly/mutable-global)
+* [x] [reference-types](https://github.com/WebAssembly/reference-types)
+* [x] [relaxed-simd](https://github.com/WebAssembly/relaxed-simd)
+* [x] [saturating-float-to-int](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)
+* [x] [sign-extension-ops](https://github.com/WebAssembly/sign-extension-ops)
+* [x] [simd](https://github.com/WebAssembly/simd)
+* [x] [tail-call](https://github.com/WebAssembly/tail-call)
+* [x] [threads](https://github.com/WebAssembly/threads)
+
+These proposals are implemented but have not yet reached stage 4. This means
+they are disabled by default in validation and their implementation may change
+over time as the proposal evolves. Additionally the proposal may also have
+changed since these proposals were implemented, so there may be a mismatch too.
+
+* [x] [component-model](https://github.com/WebAssembly/component-model)
+* [x] [custom-page-sizes](https://github.com/WebAssembly/custom-page-sizes)
+* [x] [memory-control](https://github.com/WebAssembly/memory-control)
+* [x] [shared-everything-threads](https://github.com/WebAssembly/shared-everything-threads)
+* [x] [stack-switching](https://github.com/WebAssembly/stack-switching)
+
 # Libraries
 
 As mentioned above many of the tools of the `wasm-tools` CLI have libraries
diff --git a/crates/wasm-compose/src/composer.rs b/crates/wasm-compose/src/composer.rs
index c2bc1644..a02a39b3 100644
--- a/crates/wasm-compose/src/composer.rs
+++ b/crates/wasm-compose/src/composer.rs
@@ -249,7 +249,7 @@ impl<'a> CompositionGraphBuilder<'a> {
 
         match component.export_by_name(export) {
             Some((export_index, kind, index)) if kind == ComponentExternalKind::Instance => {
-                let export_ty = component.types.component_instance_at(index);
+                let export_ty = component.types.as_ref().component_instance_at(index);
 
                 if self.graph.try_connection(
                     component_id,
@@ -289,6 +289,7 @@ impl<'a> CompositionGraphBuilder<'a> {
                 name,
                 component
                     .types
+                    .as_ref()
                     .component_any_type_at(index)
                     .unwrap_instance(),
             ),
diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs
index 468ceb97..e5336607 100644
--- a/crates/wasm-compose/src/encoding.rs
+++ b/crates/wasm-compose/src/encoding.rs
@@ -1177,7 +1177,7 @@ impl DependencyRegistrar<'_, '_> {
 
         // Recurse for aliases to see edges across components, and otherwise
         // recurse on the structure of the type below.
-        if let Some(ty) = self.types.peel_alias(ty) {
+        if let Some(ty) = self.types.as_ref().peel_alias(ty) {
             return self.ty(ty);
         }
 
diff --git a/crates/wasm-compose/src/graph.rs b/crates/wasm-compose/src/graph.rs
index 43b91019..92a51ed7 100644
--- a/crates/wasm-compose/src/graph.rs
+++ b/crates/wasm-compose/src/graph.rs
@@ -258,7 +258,10 @@ impl<'a> Component<'a> {
         index: ExportIndex,
     ) -> Option<(&str, ComponentEntityType)> {
         let (name, _kind, _index) = self.export(index)?;
-        Some((name, self.types.component_entity_type_of_export(name)?))
+        Some((
+            name,
+            self.types.as_ref().component_entity_type_of_export(name)?,
+        ))
     }
 
     pub(crate) fn import_entity_type(
@@ -266,7 +269,10 @@ impl<'a> Component<'a> {
         index: ImportIndex,
     ) -> Option<(&str, ComponentEntityType)> {
         let (name, _ty) = self.import(index)?;
-        Some((name, self.types.component_entity_type_of_import(name)?))
+        Some((
+            name,
+            self.types.as_ref().component_entity_type_of_import(name)?,
+        ))
     }
 
     /// Finds a compatible instance export on the component for the given instance type.
@@ -286,7 +292,9 @@ impl<'a> Component<'a> {
 
                 graph.try_connection(
                     export_component_id,
-                    ComponentEntityType::Instance(self.types.component_instance_at(*index)),
+                    ComponentEntityType::Instance(
+                        self.types.as_ref().component_instance_at(*index),
+                    ),
                     self.types(),
                     ComponentEntityType::Instance(ty),
                     types,
@@ -563,6 +571,7 @@ impl<'a> CompositionGraph<'a> {
             for import_name in component.imports.keys() {
                 let ty = component
                     .types
+                    .as_ref()
                     .component_entity_type_of_import(import_name)
                     .unwrap();
 
diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs
index c9eb9142..6b69b7a4 100644
--- a/crates/wasm-smith/src/core.rs
+++ b/crates/wasm-smith/src/core.rs
@@ -1761,6 +1761,7 @@ impl Module {
         }
 
         // For each export, add necessary prerequisites to the module.
+        let exports_types = exports_types.as_ref();
         for export in required_exports {
             let new_index = match exports_types
                 .entity_type_from_export(&export)
diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs
index 68291970..8ee9b0ac 100644
--- a/crates/wasmparser/src/validator.rs
+++ b/crates/wasmparser/src/validator.rs
@@ -402,7 +402,7 @@ impl Validator {
     ///
     /// // Validate the first Wasm module and get the ID of its type.
     /// let types = validator.validate_all(&wasm1)?;
-    /// let id1 = types.core_type_at(0);
+    /// let id1 = types.as_ref().core_type_at(0);
     ///
     /// // Reset the validator so we can parse the second wasm module inside
     /// // this validator's same context.
@@ -411,7 +411,7 @@ impl Validator {
     /// // Validate the second Wasm module and get the ID of its second type,
     /// // which is the same type as the first Wasm module's only type.
     /// let types = validator.validate_all(&wasm2)?;
-    /// let id2 = types.core_type_at(1);
+    /// let id2 = types.as_ref().core_type_at(1);
     ///
     /// // Because both modules were processed in the same `Validator`, they
     /// // share the same types context and therefore the same type defined
@@ -1530,12 +1530,13 @@ mod tests {
             Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
 
         let types = validator.validate_all(&bytes)?;
+        let types = types.as_ref();
 
-        assert_eq!(types.type_count(), 2);
+        assert_eq!(types.core_type_count(), 2);
         assert_eq!(types.memory_count(), 1);
         assert_eq!(types.table_count(), 1);
         assert_eq!(types.global_count(), 1);
-        assert_eq!(types.core_function_count(), 1);
+        assert_eq!(types.function_count(), 1);
         assert_eq!(types.tag_count(), 1);
         assert_eq!(types.element_count(), 1);
         assert_eq!(types.module_count(), 0);
@@ -1621,6 +1622,7 @@ mod tests {
             Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
 
         let types = validator.validate_all(&bytes)?;
+        let types = types.as_ref();
 
         let t_id = types.component_defined_type_at(0);
         let a1_id = types.component_defined_type_at(1);
@@ -1654,6 +1656,7 @@ mod tests {
             Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
 
         let types = validator.validate_all(&bytes)?;
+        let types = types.as_ref();
 
         let t_id = types.component_defined_type_at(0);
         let a1_id = types.component_defined_type_at(1);
diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs
index 68ae2021..82609957 100644
--- a/crates/wasmparser/src/validator/types.rs
+++ b/crates/wasmparser/src/validator/types.rs
@@ -244,18 +244,6 @@ macro_rules! define_type_id {
     };
 }
 
-/// A core WebAssembly type, in the core WebAssembly types index space.
-pub enum CoreType {
-    /// A sub type.
-    Sub(SubType),
-
-    /// A module type.
-    ///
-    /// Does not actually appear in core Wasm at the moment. Only used for the
-    /// core types index space within components.
-    Module(ModuleType),
-}
-
 /// Represents a unique identifier for a core type type known to a
 /// [`crate::Validator`].
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -303,36 +291,6 @@ impl TypeData for SubType {
     }
 }
 
-impl CoreType {
-    /// Get the underlying `SubType` or panic.
-    pub fn unwrap_sub(&self) -> &SubType {
-        match self {
-            CoreType::Sub(s) => s,
-            CoreType::Module(_) => panic!("`unwrap_sub` on module type"),
-        }
-    }
-
-    /// Get the underlying `FuncType` within this `SubType` or panic.
-    pub fn unwrap_func(&self) -> &FuncType {
-        match &self.unwrap_sub().composite_type.inner {
-            CompositeInnerType::Func(f) => f,
-            CompositeInnerType::Array(_)
-            | CompositeInnerType::Struct(_)
-            | CompositeInnerType::Cont(_) => {
-                panic!("`unwrap_func` on non-func composite type")
-            }
-        }
-    }
-
-    /// Get the underlying `ModuleType` or panic.
-    pub fn unwrap_module(&self) -> &ModuleType {
-        match self {
-            CoreType::Module(m) => m,
-            CoreType::Sub(_) => panic!("`unwrap_module` on a subtype"),
-        }
-    }
-}
-
 macro_rules! define_wrapper_id {
     (
         $(#[$outer_attrs:meta])*
@@ -457,7 +415,7 @@ impl AnyTypeId {
     pub fn peel_alias(&self, types: &Types) -> Option<Self> {
         match *self {
             Self::Core(id) => id.peel_alias(types).map(Self::Core),
-            Self::Component(id) => types.peel_alias(id).map(Self::Component),
+            Self::Component(id) => types.as_ref().peel_alias(id).map(Self::Component),
         }
     }
 }
@@ -482,7 +440,7 @@ impl ComponentCoreTypeId {
     pub fn peel_alias(&self, types: &Types) -> Option<Self> {
         match *self {
             Self::Sub(_) => None,
-            Self::Module(id) => types.peel_alias(id).map(Self::Module),
+            Self::Module(id) => types.as_ref().peel_alias(id).map(Self::Module),
         }
     }
 }
@@ -1884,6 +1842,14 @@ impl<'a> TypesRef<'a> {
         }
     }
 
+    /// Gets the count of imported, exported, or aliased values.
+    pub fn value_count(&self) -> usize {
+        match &self.kind {
+            TypesRefKind::Module(_) => 0,
+            TypesRefKind::Component(component) => component.values.len(),
+        }
+    }
+
     /// Gets the entity type for the given import.
     pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
         match &self.kind {
@@ -2010,14 +1976,8 @@ impl Types {
         }
     }
 
-    /// Get the id of the validator that these types are associated with.
-    #[inline]
-    pub fn id(&self) -> ValidatorId {
-        self.id
-    }
-
-    /// Gets a reference to this validation type information.
-    pub fn as_ref(&self) -> TypesRef {
+    /// Return a [`TypesRef`] through which types can be inspected.
+    pub fn as_ref(&self) -> TypesRef<'_> {
         TypesRef {
             id: self.id,
             list: &self.list,
@@ -2027,302 +1987,6 @@ impl Types {
             },
         }
     }
-
-    /// Gets a type based on its type id.
-    ///
-    /// Returns `None` if the type id is unknown.
-    pub fn get<T>(&self, id: T) -> Option<&T::Data>
-    where
-        T: TypeIdentifier,
-    {
-        self.as_ref().get(id)
-    }
-
-    /// Gets a core WebAssembly type at the given type index.
-    ///
-    /// Note that this is in contrast to [`TypesRef::component_type_at`] which
-    /// gets a component type from its index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid function index.
-    pub fn core_type_at(&self, index: u32) -> ComponentCoreTypeId {
-        self.as_ref().core_type_at(index)
-    }
-
-    /// Gets a component WebAssembly type at the given type index.
-    ///
-    /// Note that this is in contrast to [`TypesRef::core_type_at`] which gets a
-    /// core type from its index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid type index.
-    pub fn component_any_type_at(&self, index: u32) -> ComponentAnyTypeId {
-        self.as_ref().component_any_type_at(index)
-    }
-
-    /// Gets a component type at the given type index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid component type index.
-    pub fn component_type_at(&self, index: u32) -> ComponentTypeId {
-        self.as_ref().component_type_at(index)
-    }
-
-    /// Gets a component type from the given component type index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid defined type index or if this type
-    /// information represents a core module.
-    pub fn component_defined_type_at(&self, index: u32) -> ComponentDefinedTypeId {
-        self.as_ref().component_defined_type_at(index)
-    }
-
-    /// Gets the count of core types.
-    pub fn type_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(module) => module.types.len(),
-            TypesKind::Component(component) => component.core_types.len(),
-        }
-    }
-
-    /// Gets the type of a table at the given table index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid function index.
-    pub fn table_at(&self, index: u32) -> TableType {
-        self.as_ref().table_at(index)
-    }
-
-    /// Gets the count of imported and defined tables.
-    pub fn table_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(module) => module.tables.len(),
-            TypesKind::Component(component) => component.core_tables.len(),
-        }
-    }
-
-    /// Gets the type of a memory at the given memory index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid function index.
-    pub fn memory_at(&self, index: u32) -> MemoryType {
-        self.as_ref().memory_at(index)
-    }
-
-    /// Gets the count of imported and defined memories.
-    pub fn memory_count(&self) -> u32 {
-        self.as_ref().memory_count()
-    }
-
-    /// Gets the type of a global at the given global index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid function index.
-    pub fn global_at(&self, index: u32) -> GlobalType {
-        self.as_ref().global_at(index)
-    }
-
-    /// Gets the count of imported and defined globals.
-    pub fn global_count(&self) -> u32 {
-        self.as_ref().global_count()
-    }
-
-    /// Gets the type of a tag at the given tag index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid function index.
-    pub fn tag_at(&self, index: u32) -> CoreTypeId {
-        self.as_ref().tag_at(index)
-    }
-
-    /// Gets the count of imported and defined tags.
-    pub fn tag_count(&self) -> u32 {
-        self.as_ref().tag_count()
-    }
-
-    /// Gets the type of a core function at the given function index.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `index` is not a valid function index.
-    pub fn core_function_at(&self, index: u32) -> CoreTypeId {
-        self.as_ref().core_function_at(index)
-    }
-
-    /// Gets the count of core functions defined so far.
-    ///
-    /// Note that this includes imported functions, defined functions, and for
-    /// components lowered/aliased functions.
-    pub fn core_function_count(&self) -> u32 {
-        self.as_ref().function_count()
-    }
-
-    /// Gets the type of an element segment at the given element segment index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds.
-    pub fn element_at(&self, index: u32) -> RefType {
-        self.as_ref().element_at(index)
-    }
-
-    /// Gets the count of element segments.
-    pub fn element_count(&self) -> u32 {
-        self.as_ref().element_count()
-    }
-
-    /// Gets the type of a component function at the given function index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds or if this type
-    /// information represents a core module.
-    pub fn component_function_at(&self, index: u32) -> ComponentFuncTypeId {
-        self.as_ref().component_function_at(index)
-    }
-
-    /// Gets the count of imported, exported, or aliased component functions.
-    pub fn component_function_count(&self) -> u32 {
-        self.as_ref().component_function_count()
-    }
-
-    /// Gets the type of a module at the given module index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds or if this type
-    /// information represents a core module.
-    pub fn module_at(&self, index: u32) -> ComponentCoreModuleTypeId {
-        self.as_ref().module_at(index)
-    }
-
-    /// Gets the count of imported, exported, or aliased modules.
-    pub fn module_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(_) => 0,
-            TypesKind::Component(component) => component.core_modules.len(),
-        }
-    }
-
-    /// Gets the type of a module instance at the given module instance index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds or if this type
-    /// information represents a core module.
-    pub fn core_instance_at(&self, index: u32) -> ComponentCoreInstanceTypeId {
-        self.as_ref().core_instance_at(index)
-    }
-
-    /// Gets the count of imported, exported, or aliased core module instances.
-    pub fn core_instance_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(_) => 0,
-            TypesKind::Component(component) => component.core_instances.len(),
-        }
-    }
-
-    /// Gets the type of a component at the given component index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds or if this type
-    /// information represents a core module.
-    pub fn component_at(&self, index: u32) -> ComponentTypeId {
-        self.as_ref().component_at(index)
-    }
-
-    /// Gets the count of imported, exported, or aliased components.
-    pub fn component_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(_) => 0,
-            TypesKind::Component(component) => component.components.len(),
-        }
-    }
-
-    /// Gets the type of an component instance at the given component instance index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds or if this type
-    /// information represents a core module.
-    pub fn component_instance_at(&self, index: u32) -> ComponentInstanceTypeId {
-        self.as_ref().component_instance_at(index)
-    }
-
-    /// Gets the count of imported, exported, or aliased component instances.
-    pub fn component_instance_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(_) => 0,
-            TypesKind::Component(component) => component.instances.len(),
-        }
-    }
-
-    /// Gets the type of a value at the given value index.
-    ///
-    /// # Panics
-    ///
-    /// This will panic if the `index` provided is out of bounds or if this type
-    /// information represents a core module.
-    pub fn value_at(&self, index: u32) -> ComponentValType {
-        self.as_ref().value_at(index)
-    }
-
-    /// Gets the count of imported, exported, or aliased values.
-    pub fn value_count(&self) -> usize {
-        match &self.kind {
-            TypesKind::Module(_) => 0,
-            TypesKind::Component(component) => component.values.len(),
-        }
-    }
-
-    /// Gets the entity type from the given import.
-    pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
-        self.as_ref().entity_type_from_import(import)
-    }
-
-    /// Gets the entity type from the given export.
-    pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> {
-        self.as_ref().entity_type_from_export(export)
-    }
-
-    /// Gets the component entity type for the given component import name.
-    pub fn component_entity_type_of_import(&self, name: &str) -> Option<ComponentEntityType> {
-        self.as_ref().component_entity_type_of_import(name)
-    }
-
-    /// Gets the component entity type for the given component export name.
-    pub fn component_entity_type_of_export(&self, name: &str) -> Option<ComponentEntityType> {
-        self.as_ref().component_entity_type_of_export(name)
-    }
-
-    /// Attempts to lookup the type id that `ty` is an alias of.
-    ///
-    /// Returns `None` if `ty` wasn't listed as aliasing a prior type.
-    pub fn peel_alias<T>(&self, ty: T) -> Option<T>
-    where
-        T: Aliasable,
-    {
-        self.list.peel_alias(ty)
-    }
-
-    /// Same as [`TypesRef::core_imports`]
-    pub fn core_imports<'a>(&self) -> Option<impl Iterator<Item = (&str, &str, EntityType)> + '_> {
-        self.as_ref().core_imports()
-    }
-
-    /// Same as [`TypesRef::core_exports`]
-    pub fn core_exports(&self) -> Option<impl Iterator<Item = (&str, EntityType)> + '_> {
-        self.as_ref().core_exports()
-    }
 }
 
 impl<T> Index<T> for Types
diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs
index 4105d7de..a4321c3a 100644
--- a/crates/wasmprinter/src/lib.rs
+++ b/crates/wasmprinter/src/lib.rs
@@ -48,7 +48,7 @@ pub fn print_bytes(wasm: impl AsRef<[u8]>) -> Result<String> {
 ///
 /// This structure is used to control the overal structure of how wasm binaries
 /// are printed and tweaks various ways that configures the output.
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct Config {
     print_offsets: bool,
     print_skeleton: bool,
diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs
index 037ff449..689c469b 100644
--- a/crates/wasmprinter/src/operator.rs
+++ b/crates/wasmprinter/src/operator.rs
@@ -1699,13 +1699,16 @@ impl<'printer, 'state, 'a, 'b> PrintOperatorFolded<'printer, 'state, 'a, 'b> {
     }
 
     fn push_if(&mut self, ty: BlockType, plain: String) -> Result<()> {
-        let mut predicate = vec![self
+        let mut predicate = Vec::new();
+        if let Some(phrase) = self
             .control
             .last_mut()
-            .expect("no enclosing block")
+            .ok_or_else(|| anyhow!("no enclosing block"))?
             .folded
             .pop()
-            .expect("no predicate")];
+        {
+            predicate.push(phrase)
+        }
         if let Some(hint) = self.branch_hint.take() {
             predicate.push(hint);
         }
@@ -1826,7 +1829,7 @@ impl<'printer, 'state, 'a, 'b> PrintOperatorFolded<'printer, 'state, 'a, 'b> {
 
         self.control
             .last_mut()
-            .expect("end without outer block")
+            .ok_or_else(|| anyhow!("end without outer block"))?
             .folded
             .push(inst);
         Ok(())
diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs
index 6a3cbb45..78980e73 100644
--- a/crates/wit-component/src/dummy.rs
+++ b/crates/wit-component/src/dummy.rs
@@ -1,8 +1,11 @@
 use wit_parser::abi::{AbiVariant, WasmType};
-use wit_parser::{Function, Resolve, TypeDefKind, TypeId, WorldId, WorldItem};
+use wit_parser::{
+    Function, Mangling, Resolve, ResourceIntrinsic, TypeDefKind, TypeId, WasmExport, WasmImport,
+    WorldId, WorldItem, WorldKey,
+};
 
 /// Generate a dummy implementation core Wasm module for a given WIT document
-pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
+pub fn dummy_module(resolve: &Resolve, world: WorldId, mangling: Mangling) -> Vec<u8> {
     let world = &resolve.worlds[world];
     let mut wat = String::new();
     wat.push_str("(module\n");
@@ -11,27 +14,41 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
             WorldItem::Function(func) => {
                 let sig = resolve.wasm_signature(AbiVariant::GuestImport, func);
 
-                wat.push_str(&format!("(import \"$root\" \"{}\" (func", func.name));
+                let (module, name) = resolve.wasm_import_name(
+                    mangling,
+                    WasmImport::Func {
+                        interface: None,
+                        func,
+                    },
+                );
+
+                wat.push_str(&format!("(import {module:?} {name:?} (func"));
                 push_tys(&mut wat, "param", &sig.params);
                 push_tys(&mut wat, "result", &sig.results);
                 wat.push_str("))\n");
             }
             WorldItem::Interface { id: import, .. } => {
-                let name = resolve.name_world_key(name);
                 for (_, func) in resolve.interfaces[*import].functions.iter() {
                     let sig = resolve.wasm_signature(AbiVariant::GuestImport, func);
 
-                    wat.push_str(&format!("(import \"{name}\" \"{}\" (func", func.name));
+                    let (module, name) = resolve.wasm_import_name(
+                        mangling,
+                        WasmImport::Func {
+                            interface: Some(name),
+                            func,
+                        },
+                    );
+                    wat.push_str(&format!("(import {module:?} {name:?} (func"));
                     push_tys(&mut wat, "param", &sig.params);
                     push_tys(&mut wat, "result", &sig.results);
                     wat.push_str("))\n");
                 }
                 for (_, ty) in resolve.interfaces[*import].types.iter() {
-                    push_resource_func_imports(&mut wat, resolve, &name, *ty);
+                    push_resource_func_imports(&mut wat, resolve, Some(name), *ty, mangling);
                 }
             }
             WorldItem::Type(id) => {
-                push_resource_func_imports(&mut wat, resolve, "$root", *id);
+                push_resource_func_imports(&mut wat, resolve, None, *id, mangling);
             }
         }
     }
@@ -42,77 +59,136 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
             WorldItem::Interface { id, .. } => *id,
             _ => continue,
         };
-        let module = format!("[export]{}", resolve.name_world_key(name));
-        for (name, ty) in resolve.interfaces[export].types.iter() {
-            let ty = &resolve.types[*ty];
+        for resource in resolve.interfaces[export].types.values().copied() {
+            let ty = &resolve.types[resource];
             match ty.kind {
                 TypeDefKind::Resource => {}
                 _ => continue,
             }
-            wat.push_str(&format!(
-                "\
-(import \"{module}\" \"[resource-drop]{name}\" (func (param i32)))
-(import \"{module}\" \"[resource-new]{name}\" (func (param i32) (result i32)))
-(import \"{module}\" \"[resource-rep]{name}\" (func (param i32) (result i32)))
-                "
-            ));
+            let intrinsics = [
+                (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
+                (
+                    ResourceIntrinsic::ExportedNew,
+                    "(func (param i32) (result i32))",
+                ),
+                (
+                    ResourceIntrinsic::ExportedRep,
+                    "(func (param i32) (result i32))",
+                ),
+            ];
+            for (intrinsic, sig) in intrinsics {
+                let (module, name) = resolve.wasm_import_name(
+                    mangling,
+                    WasmImport::ResourceIntrinsic {
+                        interface: Some(name),
+                        resource,
+                        intrinsic,
+                    },
+                );
+                wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
+            }
         }
     }
 
     for (name, export) in world.exports.iter() {
         match export {
             WorldItem::Function(func) => {
-                push_func(&mut wat, &func.name, resolve, func);
+                push_func_export(&mut wat, resolve, None, func, mangling);
             }
             WorldItem::Interface { id: export, .. } => {
-                let name = resolve.name_world_key(name);
                 for (_, func) in resolve.interfaces[*export].functions.iter() {
-                    let name = func.core_export_name(Some(&name));
-                    push_func(&mut wat, &name, resolve, func);
+                    push_func_export(&mut wat, resolve, Some(name), func, mangling);
                 }
 
                 // Feign destructors for any resource that this interface
                 // exports
-                for (resource_name, ty) in resolve.interfaces[*export].types.iter() {
-                    let ty = &resolve.types[*ty];
+                for resource in resolve.interfaces[*export].types.values().copied() {
+                    let ty = &resolve.types[resource];
                     match ty.kind {
                         TypeDefKind::Resource => {}
                         _ => continue,
                     }
-                    wat.push_str(&format!(
-                        "(func (export \"{name}#[dtor]{resource_name}\") (param i32))"
-                    ));
+                    let name = resolve.wasm_export_name(
+                        mangling,
+                        WasmExport::ResourceDtor {
+                            interface: name,
+                            resource,
+                        },
+                    );
+                    wat.push_str(&format!("(func (export {name:?}) (param i32))"));
                 }
             }
             WorldItem::Type(_) => {}
         }
     }
 
-    wat.push_str("(memory (export \"memory\") 0)\n");
-    wat.push_str(
-        "(func (export \"cabi_realloc\") (param i32 i32 i32 i32) (result i32) unreachable)\n",
-    );
+    let memory = resolve.wasm_export_name(mangling, WasmExport::Memory);
+    wat.push_str(&format!("(memory (export {memory:?}) 0)\n"));
+    let realloc = resolve.wasm_export_name(mangling, WasmExport::Realloc);
+    wat.push_str(&format!(
+        "(func (export {realloc:?}) (param i32 i32 i32 i32) (result i32) unreachable)\n"
+    ));
+    let initialize = resolve.wasm_export_name(mangling, WasmExport::Initialize);
+    wat.push_str(&format!("(func (export {initialize:?}))"));
     wat.push_str(")\n");
 
     return wat::parse_str(&wat).unwrap();
 
-    fn push_resource_func_imports(wat: &mut String, resolve: &Resolve, module: &str, ty: TypeId) {
-        let ty = &resolve.types[ty];
+    fn push_resource_func_imports(
+        wat: &mut String,
+        resolve: &Resolve,
+        interface: Option<&WorldKey>,
+        resource: TypeId,
+        mangling: Mangling,
+    ) {
+        let ty = &resolve.types[resource];
         match ty.kind {
             TypeDefKind::Resource => {}
             _ => return,
         }
-        let name = ty.name.as_ref().unwrap();
-        wat.push_str(&format!("(import \"{module}\" \"[resource-drop]{name}\""));
-        wat.push_str(" (func (param i32)))\n");
+        let (module, name) = resolve.wasm_import_name(
+            mangling,
+            WasmImport::ResourceIntrinsic {
+                interface,
+                resource,
+                intrinsic: ResourceIntrinsic::ImportedDrop,
+            },
+        );
+        wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
     }
 
-    fn push_func(wat: &mut String, name: &str, resolve: &Resolve, func: &Function) {
+    fn push_func_export(
+        wat: &mut String,
+        resolve: &Resolve,
+        interface: Option<&WorldKey>,
+        func: &Function,
+        mangling: Mangling,
+    ) {
         let sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
+        let name = resolve.wasm_export_name(
+            mangling,
+            WasmExport::Func {
+                interface,
+                func,
+                post_return: false,
+            },
+        );
         wat.push_str(&format!("(func (export \"{name}\")"));
         push_tys(wat, "param", &sig.params);
         push_tys(wat, "result", &sig.results);
         wat.push_str(" unreachable)\n");
+
+        let name = resolve.wasm_export_name(
+            mangling,
+            WasmExport::Func {
+                interface,
+                func,
+                post_return: true,
+            },
+        );
+        wat.push_str(&format!("(func (export \"{name}\")"));
+        push_tys(wat, "param", &sig.results);
+        wat.push_str(")\n");
     }
 
     fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs
index 19dd7605..51a45cff 100644
--- a/crates/wit-component/src/encoding.rs
+++ b/crates/wit-component/src/encoding.rs
@@ -72,7 +72,7 @@
 //! component model.
 
 use crate::metadata::{self, Bindgen, ModuleMetadata};
-use crate::validation::{Export, ExportMap, Import, ImportInstance, ImportMap, RESOURCE_DROP};
+use crate::validation::{Export, ExportMap, Import, ImportInstance, ImportMap};
 use crate::StringEncoding;
 use anyhow::{anyhow, bail, Context, Result};
 use indexmap::{IndexMap, IndexSet};
@@ -615,7 +615,39 @@ impl<'a> EncodingState<'a> {
             CustomModule::Main => &self.info.encoder.main_module_exports,
             CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
         };
+        if exports.is_empty() {
+            return Ok(());
+        }
+
+        let mut interface_func_core_names = IndexMap::new();
+        let mut world_func_core_names = IndexMap::new();
+        for (core_name, export) in self.info.exports_for(module).iter() {
+            match export {
+                Export::WorldFunc(name) => {
+                    let prev = world_func_core_names.insert(name, core_name);
+                    assert!(prev.is_none());
+                }
+                Export::InterfaceFunc(id, name) => {
+                    let prev = interface_func_core_names
+                        .entry(id)
+                        .or_insert(IndexMap::new())
+                        .insert(name.as_str(), core_name);
+                    assert!(prev.is_none());
+                }
+                Export::WorldFuncPostReturn(..)
+                | Export::InterfaceFuncPostReturn(..)
+                | Export::ResourceDtor(..)
+                | Export::Memory
+                | Export::GeneralPurposeRealloc
+                | Export::GeneralPurposeExportRealloc
+                | Export::GeneralPurposeImportRealloc
+                | Export::Initialize
+                | Export::ReallocForAdapter => continue,
+            }
+        }
+
         let world = &resolve.worlds[self.info.encoder.metadata.world];
+
         for export_name in exports {
             let export_string = resolve.name_world_key(export_name);
             match &world.exports[export_name] {
@@ -623,13 +655,20 @@ impl<'a> EncodingState<'a> {
                     let ty = self
                         .root_import_type_encoder(None)
                         .encode_func_type(resolve, func)?;
-                    let core_name = func.core_export_name(None);
-                    let idx = self.encode_lift(module, &core_name, None, func, ty)?;
+                    let core_name = world_func_core_names[&func.name];
+                    let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
                     self.component
                         .export(&export_string, ComponentExportKind::Func, idx, None);
                 }
                 WorldItem::Interface { id, .. } => {
-                    self.encode_interface_export(&export_string, module, *id)?;
+                    let core_names = interface_func_core_names.get(id);
+                    self.encode_interface_export(
+                        &export_string,
+                        module,
+                        export_name,
+                        *id,
+                        core_names,
+                    )?;
                 }
                 WorldItem::Type(_) => unreachable!(),
             }
@@ -642,7 +681,9 @@ impl<'a> EncodingState<'a> {
         &mut self,
         export_name: &str,
         module: CustomModule<'_>,
+        key: &WorldKey,
         export: InterfaceId,
+        interface_func_core_names: Option<&IndexMap<&str, &str>>,
     ) -> Result<()> {
         log::trace!("encode interface export `{export_name}`");
         let resolve = &self.info.encoder.metadata.resolve;
@@ -656,11 +697,9 @@ impl<'a> EncodingState<'a> {
         let mut imports = Vec::new();
         let mut root = self.root_export_type_encoder(Some(export));
         for (_, func) in &resolve.interfaces[export].functions {
-            let core_name = func.core_export_name(Some(export_name));
+            let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
             let ty = root.encode_func_type(resolve, func)?;
-            let func_index = root
-                .state
-                .encode_lift(module, &core_name, Some(export), func, ty)?;
+            let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
             imports.push((
                 import_func_name(func),
                 ComponentExportKind::Func,
@@ -953,7 +992,7 @@ impl<'a> EncodingState<'a> {
         &mut self,
         module: CustomModule<'_>,
         core_name: &str,
-        interface: Option<InterfaceId>,
+        key: &WorldKey,
         func: &Function,
         ty: u32,
     ) -> Result<u32> {
@@ -964,16 +1003,19 @@ impl<'a> EncodingState<'a> {
 
         let options = RequiredOptions::for_export(resolve, func);
 
-        let encoding = metadata.export_encodings[core_name];
+        let encoding = metadata
+            .export_encodings
+            .get(resolve, key, &func.name)
+            .unwrap();
         let exports = self.info.exports_for(module);
         let realloc_index = exports
-            .export_realloc_for(interface, func)
+            .export_realloc_for(key, func)
             .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func));
         let mut options = options
             .into_iter(encoding, self.memory_index, realloc_index)?
             .collect::<Vec<_>>();
 
-        if let Some(post_return) = exports.post_return(interface, func) {
+        if let Some(post_return) = exports.post_return(key, func) {
             let post_return = self.core_alias_export(instance_index, post_return, ExportKind::Func);
             options.push(CanonicalOption::PostReturn(post_return));
         }
@@ -1346,7 +1388,7 @@ impl<'a> EncodingState<'a> {
         log::trace!("attempting to materialize import of `{module}::{field}` for {for_module:?}");
         let resolve = &self.info.encoder.metadata.resolve;
         let name_tmp;
-        let (key, name) = match import {
+        let (key, name, interface_key) = match import {
             // Main module dependencies on an adapter in use are done with an
             // indirection here, so load the shim function and use that.
             Import::AdapterExport(_) => {
@@ -1413,18 +1455,17 @@ impl<'a> EncodingState<'a> {
             // through to the code below. This is where these are connected to a
             // WIT `ImportedInterface` one way or another with the name that was
             // detected during validation.
-            Import::ImportedResourceDrop(key, id) => {
+            Import::ImportedResourceDrop(key, iface, id) => {
                 let ty = &resolve.types[*id];
                 let name = ty.name.as_ref().unwrap();
-                name_tmp = format!("{RESOURCE_DROP}{name}");
-                (key.as_ref(), &name_tmp)
+                name_tmp = format!("{name}_drop");
+                (key, &name_tmp, iface.map(|_| resolve.name_world_key(key)))
             }
-            Import::WorldFunc(name) => (None, name),
-            Import::InterfaceFunc(key, _, name) => (Some(key), name),
+            Import::WorldFunc(key, name) => (key, name, None),
+            Import::InterfaceFunc(key, _, name) => (key, name, Some(resolve.name_world_key(key))),
         };
 
-        let interface = key.map(|key| resolve.name_world_key(key));
-        let import = &self.info.import_map[&interface];
+        let import = &self.info.import_map[&interface_key];
         let (index, _, lowering) = import.lowerings.get_full(name).unwrap();
         let metadata = self.info.module_metadata_for(for_module);
 
@@ -1447,12 +1488,12 @@ impl<'a> EncodingState<'a> {
             // created, so the specific export is loaded here and used as an
             // import.
             Lowering::Indirect { .. } => {
-                let encoding = metadata.import_encodings[&(module.to_string(), field.to_string())];
+                let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
                 self.core_alias_export(
                     self.shim_instance_index
                         .expect("shim should be instantiated"),
                     &shims.shims[&ShimKind::IndirectLowering {
-                        interface: interface.clone(),
+                        interface: interface_key,
                         index,
                         realloc: for_module,
                         encoding,
@@ -1663,7 +1704,7 @@ impl<'a> Shims<'a> {
         let resolve = &world.encoder.metadata.resolve;
 
         for (module, field, import) in module_imports.imports() {
-            let (key, name) = match import {
+            let (key, name, interface_key) = match import {
                 // These imports don't require shims, they can be satisfied
                 // as-needed when required.
                 Import::ImportedResourceDrop(..)
@@ -1713,11 +1754,12 @@ impl<'a> Shims<'a> {
                 // WIT-level functions may require an indirection, so yield some
                 // metadata out of this `match` to the loop below to figure that
                 // out.
-                Import::InterfaceFunc(key, _, name) => (Some(key), name),
-                Import::WorldFunc(name) => (None, name),
+                Import::InterfaceFunc(key, _, name) => {
+                    (key, name, Some(resolve.name_world_key(key)))
+                }
+                Import::WorldFunc(key, name) => (key, name, None),
             };
-            let key = key.map(|key| resolve.name_world_key(key));
-            let interface = &world.import_map[&key];
+            let interface = &world.import_map[&interface_key];
             let (index, _, lowering) = interface.lowerings.get_full(name).unwrap();
             let shim_name = self.shims.len().to_string();
             match lowering {
@@ -1727,9 +1769,9 @@ impl<'a> Shims<'a> {
                     log::debug!(
                         "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
                     );
-                    let encoding = *metadata
+                    let encoding = metadata
                         .import_encodings
-                        .get(&(module.to_string(), field.to_string()))
+                        .get(resolve, key, name)
                         .ok_or_else(|| {
                             anyhow::anyhow!(
                                 "missing component metadata for import of \
@@ -1741,7 +1783,7 @@ impl<'a> Shims<'a> {
                         debug_name: format!("indirect-{module}-{field}"),
                         options: *options,
                         kind: ShimKind::IndirectLowering {
-                            interface: key,
+                            interface: interface_key,
                             index,
                             realloc: for_module,
                             encoding,
@@ -1836,7 +1878,7 @@ pub struct LibraryInfo {
 }
 
 /// Represents an adapter or library to be instantiated as part of the component
-struct Adapter {
+pub(super) struct Adapter {
     /// The wasm of the module itself, with `component-type` sections stripped
     wasm: Vec<u8>,
 
@@ -1858,13 +1900,14 @@ struct Adapter {
 #[derive(Default)]
 pub struct ComponentEncoder {
     module: Vec<u8>,
-    metadata: Bindgen,
+    pub(super) metadata: Bindgen,
     validate: bool,
-    main_module_exports: IndexSet<WorldKey>,
-    adapters: IndexMap<String, Adapter>,
+    pub(super) main_module_exports: IndexSet<WorldKey>,
+    pub(super) adapters: IndexMap<String, Adapter>,
     import_name_map: HashMap<String, String>,
     realloc_via_memory_grow: bool,
     merge_imports_based_on_semver: Option<bool>,
+    pub(super) reject_legacy_names: bool,
 }
 
 impl ComponentEncoder {
@@ -1917,6 +1960,19 @@ impl ComponentEncoder {
         self
     }
 
+    /// Sets whether to reject the historical mangling/name scheme for core wasm
+    /// imports/exports as they map to the component model.
+    ///
+    /// The `wit-component` crate supported a different set of names prior to
+    /// WebAssembly/component-model#378 and this can be used to disable this
+    /// support.
+    ///
+    /// This is disabled by default.
+    pub fn reject_legacy_names(mut self, reject: bool) -> Self {
+        self.reject_legacy_names = reject;
+        self
+    }
+
     /// Specifies a new adapter which is used to translate from a historical
     /// wasm ABI to the canonical ABI and the `interface` provided.
     ///
@@ -2116,6 +2172,7 @@ impl ComponentWorld<'_> {
 mod test {
     use super::*;
     use crate::{dummy_module, embed_component_metadata};
+    use wit_parser::Mangling;
 
     #[test]
     fn it_renames_imports() {
@@ -2141,7 +2198,7 @@ world test {
             .unwrap();
         let world = resolve.select_world(pkg, None).unwrap();
 
-        let mut module = dummy_module(&resolve, world);
+        let mut module = dummy_module(&resolve, world, Mangling::Standard32);
 
         embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
 
diff --git a/crates/wit-component/src/encoding/world.rs b/crates/wit-component/src/encoding/world.rs
index d969e397..acf126a1 100644
--- a/crates/wit-component/src/encoding/world.rs
+++ b/crates/wit-component/src/encoding/world.rs
@@ -1,14 +1,13 @@
 use super::{Adapter, ComponentEncoder, LibraryInfo, RequiredOptions};
 use crate::validation::{
-    validate_adapter_module, validate_module, Import, ImportMap, ValidatedModule, RESOURCE_DROP,
+    validate_adapter_module, validate_module, Import, ImportMap, ValidatedModule,
 };
 use anyhow::{Context, Result};
 use indexmap::{IndexMap, IndexSet};
 use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
-use wasmparser::FuncType;
 use wit_parser::{
-    abi::{AbiVariant, WasmSignature, WasmType},
+    abi::{AbiVariant, WasmSignature},
     Function, InterfaceId, LiveTypes, Resolve, TypeDefKind, TypeId, TypeOwner, WorldId, WorldItem,
     WorldKey,
 };
@@ -64,18 +63,7 @@ pub enum Lowering {
 
 impl<'a> ComponentWorld<'a> {
     pub fn new(encoder: &'a ComponentEncoder) -> Result<Self> {
-        let adapters = encoder
-            .adapters
-            .keys()
-            .map(|s| s.as_str())
-            .collect::<IndexSet<_>>();
-        let info = validate_module(
-            &encoder.module,
-            &encoder.metadata,
-            &encoder.main_module_exports,
-            &adapters,
-        )
-        .context("module was not valid")?;
+        let info = validate_module(encoder, &encoder.module).context("module was not valid")?;
 
         let mut ret = ComponentWorld {
             encoder,
@@ -86,7 +74,7 @@ impl<'a> ComponentWorld<'a> {
             exports_used: HashMap::new(),
         };
 
-        ret.process_adapters(&adapters)?;
+        ret.process_adapters()?;
         ret.process_imports()?;
         ret.process_exports_used();
         ret.process_live_type_imports();
@@ -98,7 +86,7 @@ impl<'a> ComponentWorld<'a> {
     /// adapters and figure out what functions are required from the
     /// adapter itself, either because the functions are imported by the
     /// main module or they're part of the adapter's exports.
-    fn process_adapters(&mut self, adapters: &IndexSet<&str>) -> Result<()> {
+    fn process_adapters(&mut self) -> Result<()> {
         let resolve = &self.encoder.metadata.resolve;
         let world = self.encoder.metadata.world;
         for (
@@ -130,12 +118,49 @@ impl<'a> ComponentWorld<'a> {
             let wasm = if library_info.is_some() {
                 Cow::Borrowed(wasm as &[u8])
             } else {
-                let required = self.required_adapter_exports(
-                    resolve,
-                    world,
-                    required_exports,
+                // Without `library_info` this means that this is an adapter.
+                // The goal of the adapter is to provide a suite of symbols that
+                // can be imported, but not all symbols may be imported. Here
+                // the module is trimmed down to only what's needed by the
+                // original main module.
+                //
+                // The main module requires `required_by_import` above, but
+                // adapters may themselves also export WIT items. To handle this
+                // the sequence of operations here are:
+                //
+                // 1. First the adapter is validated as-is. This ensures that
+                //    everything looks good before GC.
+                // 2. The metadata from step (1) is used to determine the set of
+                //    WIT-level exports that are needed. This includes things
+                //    like realloc functions and such.
+                // 3. The set of WIT-level functions from (2) is unioned with
+                //    `required_by_import` to create the set of required exports
+                //    of the adapter.
+                // 4. This set of exports is used to delete some exports of the
+                //    adapter and then perform a GC pass.
+                //
+                // Finally at the end of all of this the
+                // `validate_adapter_module` method is called for a second time
+                // on the minimized adapter. This is done because deleting
+                // imports may have deleted some imports which means that the
+                // final component may not need to import as many interfaces.
+                let info = validate_adapter_module(
+                    self.encoder,
+                    &wasm,
                     &required_by_import,
-                );
+                    required_exports,
+                    library_info.as_ref(),
+                )
+                .with_context(|| {
+                    format!("failed to validate the imports of the adapter module `{name}`")
+                })?;
+                let mut required = IndexSet::new();
+                for (name, _ty) in required_by_import.iter() {
+                    required.insert(name.to_string());
+                }
+                for (name, _export) in info.exports.iter() {
+                    required.insert(name.to_string());
+                }
 
                 Cow::Owned(
                     crate::gc::run(
@@ -151,13 +176,11 @@ impl<'a> ComponentWorld<'a> {
                 )
             };
             let info = validate_adapter_module(
+                self.encoder,
                 &wasm,
-                resolve,
-                world,
                 &required_by_import,
                 required_exports,
                 library_info.as_ref(),
-                adapters,
             )
             .with_context(|| {
                 format!("failed to validate the imports of the minimized adapter module `{name}`")
@@ -174,64 +197,6 @@ impl<'a> ComponentWorld<'a> {
         Ok(())
     }
 
-    /// Returns the set of functions required to be exported from an adapter,
-    /// either because they're exported from the adapter's world or because
-    /// they're required as an import to the main module.
-    fn required_adapter_exports<'r>(
-        &self,
-        resolve: &'r Resolve,
-        world: WorldId,
-        required_exports: &IndexSet<WorldKey>,
-        required_by_import: &IndexMap<String, FuncType>,
-    ) -> IndexMap<String, (FuncType, Option<&'r Function>)> {
-        use wasmparser::ValType;
-
-        let mut required = IndexMap::new();
-        for (name, ty) in required_by_import {
-            required.insert(name.to_string(), (ty.clone(), None));
-        }
-        let mut add_func = |func: &'r Function, name: Option<&str>| {
-            let name = func.core_export_name(name);
-            let ty = resolve.wasm_signature(AbiVariant::GuestExport, func);
-            let prev = required.insert(
-                name.into_owned(),
-                (
-                    wasmparser::FuncType::new(
-                        ty.params.iter().map(to_valty),
-                        ty.results.iter().map(to_valty),
-                    ),
-                    Some(func),
-                ),
-            );
-            assert!(prev.is_none());
-        };
-        for name in required_exports {
-            match &resolve.worlds[world].exports[name] {
-                WorldItem::Function(func) => add_func(func, None),
-                WorldItem::Interface { id, .. } => {
-                    let name = resolve.name_world_key(name);
-                    for (_, func) in resolve.interfaces[*id].functions.iter() {
-                        add_func(func, Some(&name));
-                    }
-                }
-                WorldItem::Type(_) => {}
-            }
-        }
-        return required;
-
-        fn to_valty(ty: &WasmType) -> ValType {
-            match ty {
-                WasmType::I32 => ValType::I32,
-                WasmType::I64 => ValType::I64,
-                WasmType::F32 => ValType::F32,
-                WasmType::F64 => ValType::F64,
-                WasmType::Pointer => ValType::I32,
-                WasmType::PointerOrI64 => ValType::I64,
-                WasmType::Length => ValType::I32,
-            }
-        }
-    }
-
     /// Fills out the `import_map` field of `self` by determining the live
     /// functions from all imports. This additionally classifies imported
     /// functions into direct or indirect lowerings for managing shims.
@@ -250,7 +215,7 @@ impl<'a> ComponentWorld<'a> {
             .chain(self.info.imports.imports())
         {
             match import {
-                Import::WorldFunc(name) => {
+                Import::WorldFunc(_, name) => {
                     required
                         .interface_funcs
                         .entry(None)
@@ -264,7 +229,7 @@ impl<'a> ComponentWorld<'a> {
                         .or_default()
                         .insert(name);
                 }
-                Import::ImportedResourceDrop(_, id) => {
+                Import::ImportedResourceDrop(_, _, id) => {
                     required.resource_drops.insert(*id);
                 }
                 _ => {}
@@ -481,7 +446,7 @@ impl ImportedInterface {
         let name = ty.name.as_deref().expect("resources must be named");
 
         if required.resource_drops.contains(&id) {
-            let name = format!("{RESOURCE_DROP}{name}");
+            let name = format!("{name}_drop");
             let prev = self.lowerings.insert(name, Lowering::ResourceDrop(id));
             assert!(prev.is_none());
         }
diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs
index 95b40bc8..4e57fd5a 100644
--- a/crates/wit-component/src/gc.rs
+++ b/crates/wit-component/src/gc.rs
@@ -19,9 +19,9 @@ const PAGE_SIZE: i32 = 64 * 1024;
 ///
 /// This internally performs a "gc" pass after removing exports to ensure that
 /// the resulting module imports the minimal set of functions necessary.
-pub fn run<T>(
+pub fn run(
     wasm: &[u8],
-    required: &IndexMap<String, T>,
+    required: &IndexSet<String>,
     main_module_realloc: Option<&str>,
 ) -> Result<Vec<u8>> {
     assert!(!required.is_empty());
@@ -31,21 +31,14 @@ pub fn run<T>(
 
     // Make sure that all required names are present in the module, and then
     // remove all names that are not required.
-    for (name, _ty) in required {
+    for name in required {
         if !module.exports.contains_key(name.as_str()) {
             bail!("adapter module does not have export `{name}`")
         }
     }
     let mut not_required = IndexSet::new();
     for name in module.exports.keys().copied() {
-        // If we need `name` then we also need cabi_post_`name`:
-        let name = if let Some(suffix) = name.strip_prefix("cabi_post_") {
-            suffix
-        } else {
-            name
-        };
-
-        if !required.contains_key(name) && !always_keep(name) {
+        if !required.contains(name) {
             not_required.insert(name);
         }
     }
@@ -57,15 +50,6 @@ pub fn run<T>(
     module.encode(main_module_realloc)
 }
 
-fn always_keep(name: &str) -> bool {
-    match name {
-        // Explicitly keep `cabi_realloc` if it's there in case an interface
-        // needs it for a lowering.
-        "cabi_realloc" | "cabi_import_realloc" | "cabi_export_realloc" => true,
-        _ => false,
-    }
-}
-
 /// This function generates a Wasm function body which implements `cabi_realloc` in terms of `memory.grow`.  It
 /// only accepts new, page-sized allocations.
 fn realloc_via_memory_grow() -> wasm_encoder::Function {
diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs
index 18b2608d..7eaf5a68 100644
--- a/crates/wit-component/src/metadata.rs
+++ b/crates/wit-component/src/metadata.rs
@@ -41,7 +41,6 @@
 //! The dual of `encode` is the `decode_custom_section` fucntion which decodes
 //! the three arguments originally passed to `encode`.
 
-use crate::validation::BARE_FUNC_MODULE_NAME;
 use crate::{DecodedWasm, StringEncoding};
 use anyhow::{bail, Context, Result};
 use indexmap::{IndexMap, IndexSet};
@@ -112,11 +111,105 @@ impl Default for Bindgen {
 pub struct ModuleMetadata {
     /// Per-function options imported into the core wasm module, currently only
     /// related to string encoding.
-    pub import_encodings: IndexMap<(String, String), StringEncoding>,
+    pub import_encodings: EncodingMap,
 
     /// Per-function options exported from the core wasm module, currently only
     /// related to string encoding.
-    pub export_encodings: IndexMap<String, StringEncoding>,
+    pub export_encodings: EncodingMap,
+}
+
+/// Internal map that keeps track of encodings for various world imports and
+/// exports.
+///
+/// Stored in [`ModuleMetadata`].
+#[derive(Default)]
+pub struct EncodingMap {
+    /// A map of an "identifying string" for world items to what string
+    /// encoding the import or export is using.
+    ///
+    /// The keys of this map are created by `EncodingMap::key` and are
+    /// specifically chosen to be able to be looked up during both insertion and
+    /// fetching. Note that in particular this map does not use `*Id` types such
+    /// as `InterfaceId` from `wit_parser`. This is due to the fact that during
+    /// world merging new interfaces are created for named imports (e.g. `import
+    /// x: interface { ... }`) as inline interfaces are copied from one world to
+    /// another. Additionally during world merging different interfaces at the
+    /// same version may be deduplicated.
+    ///
+    /// For these reasons a string-based key is chosen to avoid juggling IDs
+    /// through the world merging process. Additionally versions are chopped off
+    /// for now to help with a problem such as:
+    ///
+    /// * The main module imports a:b/c@0.1.0
+    /// * An adapter imports a:b/c@0.1.1
+    /// * The final world uses a:b/c@0.1.1, but the main module has no
+    ///   encoding listed for that exact item.
+    ///
+    /// By chopping off versions this is able to get everything registered
+    /// correctly even in the fact of merging interfaces and worlds.
+    encodings: IndexMap<String, StringEncoding>,
+}
+
+impl EncodingMap {
+    fn insert_all(
+        &mut self,
+        resolve: &Resolve,
+        set: &IndexMap<WorldKey, WorldItem>,
+        encoding: StringEncoding,
+    ) {
+        for (name, item) in set {
+            match item {
+                WorldItem::Function(func) => {
+                    let key = self.key(resolve, name, &func.name);
+                    self.encodings.insert(key, encoding);
+                }
+                WorldItem::Interface { id, .. } => {
+                    for (func, _) in resolve.interfaces[*id].functions.iter() {
+                        let key = self.key(resolve, name, func);
+                        self.encodings.insert(key, encoding);
+                    }
+                }
+                WorldItem::Type(_) => {}
+            }
+        }
+    }
+
+    /// Looks up the encoding of the function `func` which is scoped under `key`
+    /// in the world in question.
+    pub fn get(&self, resolve: &Resolve, key: &WorldKey, func: &str) -> Option<StringEncoding> {
+        let key = self.key(resolve, key, func);
+        self.encodings.get(&key).copied()
+    }
+
+    fn key(&self, resolve: &Resolve, key: &WorldKey, func: &str) -> String {
+        format!(
+            "{}/{func}",
+            match key {
+                WorldKey::Name(name) => name.to_string(),
+                WorldKey::Interface(id) => {
+                    let iface = &resolve.interfaces[*id];
+                    let pkg = &resolve.packages[iface.package.unwrap()];
+                    format!(
+                        "{}:{}/{}",
+                        pkg.name.namespace,
+                        pkg.name.name,
+                        iface.name.as_ref().unwrap()
+                    )
+                }
+            }
+        )
+    }
+
+    fn merge(&mut self, other: EncodingMap) -> Result<()> {
+        for (key, encoding) in other.encodings {
+            if let Some(prev) = self.encodings.insert(key.clone(), encoding) {
+                if prev != encoding {
+                    bail!("conflicting string encodings specified for `{key}`");
+                }
+            }
+        }
+        Ok(())
+    }
 }
 
 /// This function will parse the core `wasm` binary given as input and return a
@@ -313,38 +406,18 @@ impl Bindgen {
             producers,
         } = other;
 
-        let world = self
+        let remap = self
             .resolve
             .merge(resolve)
-            .context("failed to merge WIT package sets together")?
-            .map_world(world, None)?;
+            .context("failed to merge WIT package sets together")?;
+        let world = remap.map_world(world, None)?;
         let exports = self.resolve.worlds[world].exports.keys().cloned().collect();
         self.resolve
             .merge_worlds(world, self.world)
             .context("failed to merge worlds from two documents")?;
 
-        for (name, encoding) in export_encodings {
-            let prev = self
-                .metadata
-                .export_encodings
-                .insert(name.clone(), encoding);
-            if let Some(prev) = prev {
-                if prev != encoding {
-                    bail!("conflicting string encodings specified for export `{name}`");
-                }
-            }
-        }
-        for ((module, name), encoding) in import_encodings {
-            let prev = self
-                .metadata
-                .import_encodings
-                .insert((module.clone(), name.clone()), encoding);
-            if let Some(prev) = prev {
-                if prev != encoding {
-                    bail!("conflicting string encodings specified for import `{module}::{name}`");
-                }
-            }
-        }
+        self.metadata.import_encodings.merge(import_encodings)?;
+        self.metadata.export_encodings.merge(export_encodings)?;
         if let Some(producers) = producers {
             if let Some(mine) = &mut self.producers {
                 mine.merge(&producers);
@@ -364,45 +437,10 @@ impl ModuleMetadata {
         let mut ret = ModuleMetadata::default();
 
         let world = &resolve.worlds[world];
-        for (name, item) in world.imports.iter() {
-            let name = resolve.name_world_key(name);
-            match item {
-                WorldItem::Function(_) => {
-                    let prev = ret
-                        .import_encodings
-                        .insert((BARE_FUNC_MODULE_NAME.to_string(), name.clone()), encoding);
-                    assert!(prev.is_none());
-                }
-                WorldItem::Interface { id, .. } => {
-                    for (func, _) in resolve.interfaces[*id].functions.iter() {
-                        let prev = ret
-                            .import_encodings
-                            .insert((name.clone(), func.clone()), encoding);
-                        assert!(prev.is_none());
-                    }
-                }
-                WorldItem::Type(_) => {}
-            }
-        }
-
-        for (name, item) in world.exports.iter() {
-            let name = resolve.name_world_key(name);
-            match item {
-                WorldItem::Function(func) => {
-                    let name = func.core_export_name(None).into_owned();
-                    let prev = ret.export_encodings.insert(name.clone(), encoding);
-                    assert!(prev.is_none());
-                }
-                WorldItem::Interface { id, .. } => {
-                    for (_, func) in resolve.interfaces[*id].functions.iter() {
-                        let name = func.core_export_name(Some(&name)).into_owned();
-                        let prev = ret.export_encodings.insert(name, encoding);
-                        assert!(prev.is_none());
-                    }
-                }
-                WorldItem::Type(_) => {}
-            }
-        }
+        ret.export_encodings
+            .insert_all(resolve, &world.exports, encoding);
+        ret.import_encodings
+            .insert_all(resolve, &world.imports, encoding);
 
         ret
     }
diff --git a/crates/wit-component/src/semver_check.rs b/crates/wit-component/src/semver_check.rs
index d6f4c6c1..1c4a9f4f 100644
--- a/crates/wit-component/src/semver_check.rs
+++ b/crates/wit-component/src/semver_check.rs
@@ -5,7 +5,7 @@ use crate::{
 use anyhow::{bail, Context, Result};
 use wasm_encoder::{ComponentBuilder, ComponentExportKind, ComponentTypeRef};
 use wasmparser::Validator;
-use wit_parser::{Resolve, WorldId};
+use wit_parser::{Mangling, Resolve, WorldId};
 
 /// Tests whether `new` is a semver-compatible upgrade from the world `prev`.
 ///
@@ -63,7 +63,7 @@ pub fn semver_check(mut resolve: Resolve, prev: WorldId, new: WorldId) -> Result
     let mut root_component = ComponentBuilder::default();
 
     // (1) above - create a dummy component which has the shape of `prev`.
-    let mut prev_as_module = dummy_module(&resolve, prev);
+    let mut prev_as_module = dummy_module(&resolve, prev, Mangling::Standard32);
     embed_component_metadata(&mut prev_as_module, &resolve, prev, StringEncoding::UTF8)
         .context("failed to embed component metadata")?;
     let prev_as_component = ComponentEncoder::default()
diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs
index 3bb7dfdd..9e170b99 100644
--- a/crates/wit-component/src/validation.rs
+++ b/crates/wit-component/src/validation.rs
@@ -1,5 +1,5 @@
 use crate::encoding::{Instance, Item, LibraryInfo, MainOrAdapter};
-use crate::metadata::Bindgen;
+use crate::ComponentEncoder;
 use anyhow::{bail, Context, Result};
 use indexmap::{map::Entry, IndexMap, IndexSet};
 use std::mem;
@@ -33,21 +33,6 @@ fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType {
     )
 }
 
-pub const MAIN_MODULE_IMPORT_NAME: &str = "__main_module__";
-
-/// The module name used when a top-level function in a world is imported into a
-/// core wasm module. Note that this is not a valid WIT identifier to avoid
-/// clashes with valid WIT interfaces. This is also not empty because LLVM
-/// interprets an empty module import string as "not specified" which means it
-/// turns into `env`.
-pub const BARE_FUNC_MODULE_NAME: &str = "$root";
-
-pub const RESOURCE_DROP: &str = "[resource-drop]";
-pub const RESOURCE_REP: &str = "[resource-rep]";
-pub const RESOURCE_NEW: &str = "[resource-new]";
-
-pub const POST_RETURN_PREFIX: &str = "cabi_post_";
-
 /// Metadata about a validated module and what was found internally.
 ///
 /// This structure houses information about `imports` and `exports` to the
@@ -65,11 +50,9 @@ pub struct ValidatedModule {
 
 impl ValidatedModule {
     fn new(
+        encoder: &ComponentEncoder,
         bytes: &[u8],
-        resolve: &Resolve,
-        world: WorldId,
         exports: &IndexSet<WorldKey>,
-        adapters: &IndexSet<&str>,
         info: Option<&LibraryInfo>,
     ) -> Result<ValidatedModule> {
         let mut validator = Validator::new();
@@ -90,21 +73,20 @@ impl ValidatedModule {
                 Payload::ImportSection(s) => {
                     for import in s {
                         let import = import?;
-                        ret.imports
-                            .add(import, resolve, world, adapters, info, types)?;
+                        ret.imports.add(import, encoder, info, types)?;
                     }
                 }
                 Payload::ExportSection(s) => {
                     for export in s {
                         let export = export?;
-                        ret.exports.add(export, resolve, world, &exports, types)?;
+                        ret.exports.add(export, encoder, &exports, types)?;
                     }
                 }
                 _ => continue,
             }
         }
 
-        ret.exports.validate(resolve, world, exports)?;
+        ret.exports.validate(encoder, exports)?;
 
         Ok(ret)
     }
@@ -140,7 +122,7 @@ pub enum ImportInstance {
 pub enum Import {
     /// A top-level world function, with the name provided here, is imported
     /// into the module.
-    WorldFunc(String),
+    WorldFunc(WorldKey, String),
 
     /// An interface's function is imported into the module.
     ///
@@ -154,7 +136,7 @@ pub enum Import {
     /// The key provided indicates whether it's for the top-level types of the
     /// world (`None`) or an interface (`Some` with the name of the interface).
     /// The `TypeId` is what resource is being dropped.
-    ImportedResourceDrop(Option<WorldKey>, TypeId),
+    ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
 
     /// A `canon resource.drop` intrinsic for an exported item is being
     /// imported.
@@ -203,14 +185,10 @@ pub enum Import {
 impl ImportMap {
     /// Returns whether the top-level world function `func` is imported.
     pub fn uses_toplevel_func(&self, func: &str) -> bool {
-        let item = self
-            .names
-            .get(BARE_FUNC_MODULE_NAME)
-            .and_then(|map| match map {
-                ImportInstance::Names(names) => names.get(func),
-                _ => None,
-            });
-        matches!(item, Some(Import::WorldFunc(_)))
+        self.imports().any(|(_, _, item)| match item {
+            Import::WorldFunc(_, name) => func == name,
+            _ => false,
+        })
     }
 
     /// Returns whether the interface function specified is imported.
@@ -224,7 +202,7 @@ impl ImportMap {
     /// Returns whether the specified resource's drop method is needed to import.
     pub fn uses_imported_resource_drop(&self, resource: TypeId) -> bool {
         self.imports().any(|(_, _, import)| match import {
-            Import::ImportedResourceDrop(_, id) => resource == *id,
+            Import::ImportedResourceDrop(_, _, id) => resource == *id,
             _ => false,
         })
     }
@@ -274,36 +252,28 @@ impl ImportMap {
     fn add(
         &mut self,
         import: wasmparser::Import<'_>,
-        resolve: &Resolve,
-        world: WorldId,
-        adapters: &IndexSet<&str>,
+        encoder: &ComponentEncoder,
         library_info: Option<&LibraryInfo>,
         types: TypesRef<'_>,
     ) -> Result<()> {
         if self.classify_import_with_library(import, library_info)? {
             return Ok(());
         }
-        let item = self
-            .classify(import, resolve, world, adapters, types)
-            .with_context(|| {
-                format!(
-                    "failed to resolve import `{}::{}`",
-                    import.module, import.name,
-                )
-            })?;
+        let item = self.classify(import, encoder, types).with_context(|| {
+            format!(
+                "failed to resolve import `{}::{}`",
+                import.module, import.name,
+            )
+        })?;
         self.insert_import(import, item)
     }
 
     fn classify(
         &self,
         import: wasmparser::Import<'_>,
-        resolve: &Resolve,
-        world_id: WorldId,
-        adapters: &IndexSet<&str>,
+        encoder: &ComponentEncoder,
         types: TypesRef<'_>,
     ) -> Result<Import> {
-        let world = &resolve.worlds[world_id];
-
         // Special-case the main module's memory imported into adapters which
         // currently with `wasm-ld` is not easily configurable.
         if import.module == "env" && import.name == "memory" {
@@ -311,7 +281,7 @@ impl ImportMap {
         }
 
         // Special-case imports from the main module into adapters.
-        if import.module == MAIN_MODULE_IMPORT_NAME {
+        if import.module == "__main_module__" {
             return Ok(Import::MainModuleExport {
                 name: import.name.to_string(),
                 kind: match import.ty {
@@ -330,19 +300,48 @@ impl ImportMap {
         };
         let ty = types[types.core_type_at(ty_index).unwrap_sub()].unwrap_func();
 
-        // Handle top-level function imports if they're going through the "bare
-        // name" representing the world root.
-        if import.module == BARE_FUNC_MODULE_NAME {
-            let name = import.name;
+        // Handle main module imports that match known adapters and set it up as
+        // an import of an adapter export.
+        if encoder.adapters.contains_key(import.module) {
+            return Ok(Import::AdapterExport(ty.clone()));
+        }
+
+        let (module, names) = match import.module.strip_prefix("cm32p2") {
+            Some(suffix) => (suffix, STANDARD),
+            None if encoder.reject_legacy_names => (import.module, STANDARD),
+            None => (import.module, LEGACY),
+        };
+        self.classify_component_model_import(module, import.name, encoder, ty, names)
+    }
+
+    /// Attempts to classify the import `{module}::{name}` with the rules
+    /// specified in WebAssembly/component-model#378
+    fn classify_component_model_import(
+        &self,
+        module: &str,
+        name: &str,
+        encoder: &ComponentEncoder,
+        ty: &FuncType,
+        names: &dyn NameMangling,
+    ) -> Result<Import> {
+        let resolve = &encoder.metadata.resolve;
+        let world_id = encoder.metadata.world;
+        let world = &resolve.worlds[world_id];
+
+        if module == names.import_root() {
             let key = WorldKey::Name(name.to_string());
             if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
                 validate_func(resolve, ty, func, AbiVariant::GuestImport)?;
-                return Ok(Import::WorldFunc(func.name.clone()));
+                return Ok(Import::WorldFunc(key, func.name.clone()));
             }
 
             let get_resource = resource_test_for_world(resolve, world_id);
-            if let Some(id) = valid_resource_drop(name, ty, get_resource)? {
-                return Ok(Import::ImportedResourceDrop(None, id));
+            if let Some(resource) = names.resource_drop_name(name) {
+                if let Some(id) = get_resource(resource) {
+                    let expected = FuncType::new([ValType::I32], []);
+                    validate_func_sig(name, &expected, ty)?;
+                    return Ok(Import::ImportedResourceDrop(key, None, id));
+                }
             }
 
             match world.imports.get(&key) {
@@ -351,143 +350,59 @@ impl ImportMap {
             }
         }
 
-        // Handle main module imports that match known adapters and set it up as
-        // an import of an adapter export.
-        if adapters.contains(import.module) {
-            return Ok(Import::AdapterExport(ty.clone()));
-        }
+        let interface = match module.strip_prefix(names.import_non_root_prefix()) {
+            Some(name) => name,
+            None => bail!("unknown or invalid component model import syntax"),
+        };
 
-        // Handle imports which are used to manipulate state for exported
-        // resources.
-        if let Some(suffix) = import.module.strip_prefix("[export]") {
-            let (key, id) = self.module_to_interface(suffix, resolve, &world.exports)?;
-            let get_resource = resource_test_for_interface(resolve, id);
+        if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
+            let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
 
-            return if let Some(ty) = valid_resource_drop(import.name, ty, &get_resource)? {
-                Ok(Import::ExportedResourceDrop(key, ty))
-            } else if let Some(id) = import
-                .name
-                .strip_prefix(RESOURCE_NEW)
-                .and_then(&get_resource)
-            {
-                let expected = FuncType::new([ValType::I32], [ValType::I32]);
-                validate_func_sig(import.name, &expected, ty)?;
-                Ok(Import::ExportedResourceNew(key, id))
-            } else if let Some(id) = import
-                .name
-                .strip_prefix(RESOURCE_REP)
-                .and_then(&get_resource)
-            {
-                let expected = FuncType::new([ValType::I32], [ValType::I32]);
-                validate_func_sig(import.name, &expected, ty)?;
-                Ok(Import::ExportedResourceRep(key, id))
-            } else {
-                bail!("unknown function `{}`", import.name)
-            };
+            let get_resource = resource_test_for_interface(resolve, id);
+            if let Some(name) = names.resource_drop_name(name) {
+                if let Some(id) = get_resource(name) {
+                    let expected = FuncType::new([ValType::I32], []);
+                    validate_func_sig(name, &expected, ty)?;
+                    return Ok(Import::ExportedResourceDrop(key, id));
+                }
+            }
+            if let Some(name) = names.resource_new_name(name) {
+                if let Some(id) = get_resource(name) {
+                    let expected = FuncType::new([ValType::I32], [ValType::I32]);
+                    validate_func_sig(name, &expected, ty)?;
+                    return Ok(Import::ExportedResourceNew(key, id));
+                }
+            }
+            if let Some(name) = names.resource_rep_name(name) {
+                if let Some(id) = get_resource(name) {
+                    let expected = FuncType::new([ValType::I32], [ValType::I32]);
+                    validate_func_sig(name, &expected, ty)?;
+                    return Ok(Import::ExportedResourceRep(key, id));
+                }
+            }
+            bail!("unknown function `{name}`")
         }
 
-        // And finally handle imports of functions from interfaces here.
-        let (key, id) = self.module_to_interface(import.module, resolve, &world.imports)?;
+        let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
         let interface = &resolve.interfaces[id];
         let get_resource = resource_test_for_interface(resolve, id);
-        if let Some(f) = interface.functions.get(import.name) {
+        if let Some(f) = interface.functions.get(name) {
             validate_func(resolve, ty, f, AbiVariant::GuestImport).with_context(|| {
                 let name = resolve.name_world_key(&key);
                 format!("failed to validate import interface `{name}`")
             })?;
-            Ok(Import::InterfaceFunc(key, id, f.name.clone()))
-        } else if let Some(ty) = valid_resource_drop(import.name, ty, get_resource)? {
-            Ok(Import::ImportedResourceDrop(Some(key), ty))
-        } else {
-            bail!(
-                "import interface `{}` is missing function \
-                 `{}` that is required by the module",
-                import.module,
-                import.name,
-            )
-        }
-    }
-
-    fn module_to_interface(
-        &self,
-        module: &str,
-        resolve: &Resolve,
-        items: &IndexMap<WorldKey, WorldItem>,
-    ) -> Result<(WorldKey, InterfaceId)> {
-        // First see if this is a bare name
-        let bare_name = WorldKey::Name(module.to_string());
-        if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
-            return Ok((bare_name, *id));
-        }
-
-        // ... and if this isn't a bare name then it's time to do some parsing
-        // related to interfaces, versions, and such. First up the `module` name
-        // is parsed as a normal component name from `wasmparser` to see if it's
-        // of the "interface kind". If it's not then that means the above match
-        // should have been a hit but it wasn't, so an error is returned.
-        let kebab_name = ComponentName::new(module, 0);
-        let name = match kebab_name.as_ref().map(|k| k.kind()) {
-            Ok(ComponentNameKind::Interface(name)) => name,
-            _ => bail!("module requires an import interface named `{module}`"),
-        };
-
-        // Prioritize an exact match based on versions, so try that first.
-        let pkgname = PackageName {
-            namespace: name.namespace().to_string(),
-            name: name.package().to_string(),
-            version: name.version(),
-        };
-        if let Some(pkg) = resolve.package_names.get(&pkgname) {
-            if let Some(id) = resolve.packages[*pkg]
-                .interfaces
-                .get(name.interface().as_str())
-            {
-                let key = WorldKey::Interface(*id);
-                if items.contains_key(&key) {
-                    return Ok((key, *id));
-                }
+            return Ok(Import::InterfaceFunc(key, id, f.name.clone()));
+        } else if let Some(resource) = names.resource_drop_name(name) {
+            if let Some(resource) = get_resource(resource) {
+                let expected = FuncType::new([ValType::I32], []);
+                validate_func_sig(name, &expected, ty)?;
+                return Ok(Import::ImportedResourceDrop(key, Some(id), resource));
             }
         }
-
-        // If an exact match wasn't found then instead search for the first
-        // match based on versions. This means that a core wasm import for
-        // "1.2.3" might end up matching an interface at "1.2.4", for example.
-        // (or "1.2.2", depending on what's available).
-        for (key, _) in items {
-            let id = match key {
-                WorldKey::Interface(id) => *id,
-                WorldKey::Name(_) => continue,
-            };
-            // Make sure the interface names match
-            let interface = &resolve.interfaces[id];
-            if interface.name.as_ref().unwrap() != name.interface().as_str() {
-                continue;
-            }
-
-            // Make sure the package name (without version) matches
-            let pkg = &resolve.packages[interface.package.unwrap()];
-            if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
-                continue;
-            }
-
-            let module_version = match name.version() {
-                Some(version) => version,
-                None => continue,
-            };
-            let pkg_version = match &pkg.name.version {
-                Some(version) => version,
-                None => continue,
-            };
-
-            // Test if the two semver versions are compatible
-            let module_compat = PackageName::version_compat_track(&module_version);
-            let pkg_compat = PackageName::version_compat_track(pkg_version);
-            if module_compat == pkg_compat {
-                return Ok((key.clone(), id));
-            }
-        }
-
-        bail!("module requires an import interface named `{module}`")
+        bail!(
+            "import interface `{module}` is missing function \
+             `{name}` that is required by the module",
+        )
     }
 
     fn classify_import_with_library(
@@ -570,19 +485,20 @@ pub struct ExportMap {
 
 /// All possible (known) exports from a core wasm module that are recognized and
 /// handled during the componentization process.
+#[derive(Debug)]
 pub enum Export {
     /// An export of a top-level function of a world, where the world function
     /// is named here.
     WorldFunc(String),
 
     /// A post-return for a top-level function of a world.
-    WorldFuncPostReturn(String),
+    WorldFuncPostReturn(WorldKey),
 
     /// An export of a function in an interface.
     InterfaceFunc(InterfaceId, String),
 
     /// A post-return for the above function.
-    InterfaceFuncPostReturn(InterfaceId, String),
+    InterfaceFuncPostReturn(WorldKey, String),
 
     /// A destructor for an exported resource.
     ResourceDtor(TypeId),
@@ -610,12 +526,12 @@ impl ExportMap {
     fn add(
         &mut self,
         export: wasmparser::Export<'_>,
-        resolve: &Resolve,
-        world: WorldId,
+        encoder: &ComponentEncoder,
         exports: &IndexSet<WorldKey>,
         types: TypesRef<'_>,
     ) -> Result<()> {
-        if let Some(item) = self.classify(export, resolve, world, exports, types)? {
+        if let Some(item) = self.classify(export, encoder, exports, types)? {
+            log::debug!("classifying export `{}` as {item:?}", export.name);
             let prev = self.names.insert(export.name.to_string(), item);
             assert!(prev.is_none());
         }
@@ -625,22 +541,20 @@ impl ExportMap {
     fn classify(
         &mut self,
         export: wasmparser::Export<'_>,
-        resolve: &Resolve,
-        world: WorldId,
+        encoder: &ComponentEncoder,
         exports: &IndexSet<WorldKey>,
         types: TypesRef<'_>,
     ) -> Result<Option<Export>> {
         match export.kind {
-            ExternalKind::Func => {}
-            ExternalKind::Memory => return Ok(Some(Export::Memory)),
-            _ => return Ok(None),
+            ExternalKind::Func => {
+                let ty = types[types.core_function_at(export.index)].unwrap_func();
+                self.raw_exports.insert(export.name.to_string(), ty.clone());
+            }
+            _ => {}
         }
 
-        let ty = types[types.core_function_at(export.index)].unwrap_func();
-        self.raw_exports.insert(export.name.to_string(), ty.clone());
-
         // Handle a few special-cased names first.
-        if export.name == "cabi_realloc" || export.name == "canonical_abi_realloc" {
+        if export.name == "canonical_abi_realloc" {
             return Ok(Some(Export::GeneralPurposeRealloc));
         } else if export.name == "cabi_import_realloc" {
             return Ok(Some(Export::GeneralPurposeImportRealloc));
@@ -648,12 +562,59 @@ impl ExportMap {
             return Ok(Some(Export::GeneralPurposeExportRealloc));
         } else if export.name == "cabi_realloc_adapter" {
             return Ok(Some(Export::ReallocForAdapter));
-        } else if export.name == "_initialize" {
+        }
+
+        let (name, names) = match export.name.strip_prefix("cm32p2") {
+            Some(name) => (name, STANDARD),
+            None if encoder.reject_legacy_names => return Ok(None),
+            None => (export.name, LEGACY),
+        };
+        if let Some(export) = self
+            .classify_component_export(names, name, &export, encoder, exports, types)
+            .with_context(|| format!("failed to classify export `{}`", export.name))?
+        {
+            return Ok(Some(export));
+        }
+        log::debug!("unknown export `{}`", export.name);
+        Ok(None)
+    }
+
+    fn classify_component_export(
+        &mut self,
+        names: &dyn NameMangling,
+        name: &str,
+        export: &wasmparser::Export<'_>,
+        encoder: &ComponentEncoder,
+        exports: &IndexSet<WorldKey>,
+        types: TypesRef<'_>,
+    ) -> Result<Option<Export>> {
+        let resolve = &encoder.metadata.resolve;
+        let world = encoder.metadata.world;
+        match export.kind {
+            ExternalKind::Func => {}
+            ExternalKind::Memory => {
+                if name == names.export_memory() {
+                    return Ok(Some(Export::Memory));
+                }
+                return Ok(None);
+            }
+            _ => return Ok(None),
+        }
+        let ty = types[types.core_function_at(export.index)].unwrap_func();
+
+        // Handle a few special-cased names first.
+        if name == names.export_realloc() {
+            let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
+            validate_func_sig(name, &expected, ty)?;
+            return Ok(Some(Export::GeneralPurposeRealloc));
+        } else if name == names.export_initialize() {
+            let expected = FuncType::new([], []);
+            validate_func_sig(name, &expected, ty)?;
             return Ok(Some(Export::Initialize));
         }
 
         // Try to match this to a known WIT export that `exports` allows.
-        if let Some((key, id, f)) = self.match_wit_export(export.name, resolve, world, exports) {
+        if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
             validate_func(resolve, ty, f, AbiVariant::GuestExport).with_context(|| {
                 let key = resolve.name_world_key(key);
                 format!("failed to validate export for `{key}`")
@@ -669,121 +630,53 @@ impl ExportMap {
         }
 
         // See if this is a post-return for any known WIT export.
-        if let Some(suffix) = export.name.strip_prefix(POST_RETURN_PREFIX) {
-            if let Some((key, id, f)) = self.match_wit_export(suffix, resolve, world, exports) {
+        if let Some(remaining) = names.strip_post_return(name) {
+            if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
                 validate_post_return(resolve, ty, f).with_context(|| {
                     let key = resolve.name_world_key(key);
                     format!("failed to validate export for `{key}`")
                 })?;
                 match id {
-                    Some(id) => {
-                        return Ok(Some(Export::InterfaceFuncPostReturn(id, f.name.clone())));
+                    Some(_id) => {
+                        return Ok(Some(Export::InterfaceFuncPostReturn(
+                            key.clone(),
+                            f.name.clone(),
+                        )));
                     }
                     None => {
-                        return Ok(Some(Export::WorldFuncPostReturn(f.name.clone())));
+                        return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
                     }
                 }
             }
         }
 
         // And, finally, see if it matches a known destructor.
-        if let Some(dtor) = self.match_wit_resource_dtor(export.name, resolve, world, exports) {
+        if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
             let expected = FuncType::new([ValType::I32], []);
             validate_func_sig(export.name, &expected, ty)?;
             return Ok(Some(Export::ResourceDtor(dtor)));
         }
 
-        log::debug!("unknown export `{}`", export.name);
         Ok(None)
     }
 
-    fn match_wit_export<'a>(
-        &self,
-        export_name: &str,
-        resolve: &'a Resolve,
-        world: WorldId,
-        exports: &'a IndexSet<WorldKey>,
-    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
-        let world = &resolve.worlds[world];
-        for name in exports {
-            match &world.exports[name] {
-                WorldItem::Function(f) => {
-                    if f.core_export_name(None) == export_name {
-                        return Some((name, None, f));
-                    }
-                }
-                WorldItem::Interface { id, .. } => {
-                    let string = resolve.name_world_key(name);
-                    for (_, func) in resolve.interfaces[*id].functions.iter() {
-                        if func.core_export_name(Some(&string)) == export_name {
-                            return Some((name, Some(*id), func));
-                        }
-                    }
-                }
-
-                WorldItem::Type(_) => unreachable!(),
-            }
-        }
-
-        None
-    }
-
-    fn match_wit_resource_dtor<'a>(
-        &self,
-        export_name: &str,
-        resolve: &'a Resolve,
-        world: WorldId,
-        exports: &'a IndexSet<WorldKey>,
-    ) -> Option<TypeId> {
-        let world = &resolve.worlds[world];
-        for name in exports {
-            let id = match &world.exports[name] {
-                WorldItem::Interface { id, .. } => *id,
-                WorldItem::Function(_) => continue,
-                WorldItem::Type(_) => unreachable!(),
-            };
-            let name = resolve.name_world_key(name);
-            let resource = match export_name
-                .strip_prefix(&name)
-                .and_then(|s| s.strip_prefix("#[dtor]"))
-                .and_then(|r| resolve.interfaces[id].types.get(r))
-            {
-                Some(id) => *id,
-                None => continue,
-            };
-
-            match resolve.types[resource].kind {
-                TypeDefKind::Resource => {}
-                _ => continue,
-            }
-
-            return Some(resource);
-        }
-
-        None
-    }
-
     /// Returns the name of the post-return export, if any, for the `interface`
     /// and `func` combo.
-    pub fn post_return(&self, interface: Option<InterfaceId>, func: &Function) -> Option<&str> {
-        self.find(|m| match (m, interface) {
-            (Export::WorldFuncPostReturn(f), None) => func.name == *f,
-            (Export::InterfaceFuncPostReturn(i, f), Some(id)) => *i == id && func.name == *f,
+    pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
+        self.find(|m| match m {
+            Export::WorldFuncPostReturn(k) => k == key,
+            Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
             _ => false,
         })
     }
 
     /// Returns the realloc that the exported function `interface` and `func`
     /// are using.
-    pub fn export_realloc_for(
-        &self,
-        interface: Option<InterfaceId>,
-        func: &Function,
-    ) -> Option<&str> {
+    pub fn export_realloc_for(&self, key: &WorldKey, func: &Function) -> Option<&str> {
         // TODO: This realloc detection should probably be improved with
         // some sort of scheme to have per-function reallocs like
         // `cabi_realloc_{name}` or something like that.
-        let _ = (interface, func);
+        let _ = (key, func);
 
         if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
             return Some(name);
@@ -847,12 +740,9 @@ impl ExportMap {
         self.names.iter().map(|(n, e)| (n.as_str(), e))
     }
 
-    fn validate(
-        &self,
-        resolve: &Resolve,
-        world: WorldId,
-        exports: &IndexSet<WorldKey>,
-    ) -> Result<()> {
+    fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
+        let resolve = &encoder.metadata.resolve;
+        let world = encoder.metadata.world;
         // Multi-memory isn't supported because otherwise we don't know what
         // memory to put things in.
         if self
@@ -907,6 +797,380 @@ impl ExportMap {
     }
 }
 
+/// Trait dispatch and definition for parsing and interpreting "mangled names"
+/// which show up in imports and exports of the component model.
+///
+/// This trait is used to implement classification of imports and exports in the
+/// component model. The methods on `ImportMap` and `ExportMap` will use this to
+/// determine what an import is and how it's lifted/lowered in the world being
+/// bound.
+///
+/// This trait has a bit of history behind it as well. Before
+/// WebAssembly/component-model#378 there was no standard naming scheme for core
+/// wasm imports or exports when componenitizing. This meant that
+/// `wit-component` implemented a particular scheme which mostly worked but was
+/// mostly along the lines of "this at least works" rather than "someone sat
+/// down and designed this". Since then, however, an standard naming scheme has
+/// now been specified which was indeed designed.
+///
+/// This trait serves as the bridge between these two. The historical naming
+/// scheme is still supported for now through the `Legacy` implementation below
+/// and will be for some time. The transition plan at this time is to support
+/// the new scheme, eventually get it supported in bindings generators, and once
+/// that's all propagated remove support for the legacy scheme.
+trait NameMangling {
+    fn import_root(&self) -> &str;
+    fn import_non_root_prefix(&self) -> &str;
+    fn import_exported_intrinsic_prefix(&self) -> &str;
+    fn export_memory(&self) -> &str;
+    fn export_initialize(&self) -> &str;
+    fn export_realloc(&self) -> &str;
+    fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str>;
+    fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str>;
+    fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str>;
+    fn module_to_interface(
+        &self,
+        module: &str,
+        resolve: &Resolve,
+        items: &IndexMap<WorldKey, WorldItem>,
+    ) -> Result<(WorldKey, InterfaceId)>;
+    fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str>;
+    fn match_wit_export<'a>(
+        &self,
+        export_name: &str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
+    fn match_wit_resource_dtor<'a>(
+        &self,
+        export_name: &str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<TypeId>;
+}
+
+/// Definition of the "standard" naming scheme which currently starts with
+/// "cm32p2". Note that wasm64 is not supported at this time.
+struct Standard;
+
+const STANDARD: &'static dyn NameMangling = &Standard;
+
+impl NameMangling for Standard {
+    fn import_root(&self) -> &str {
+        ""
+    }
+    fn import_non_root_prefix(&self) -> &str {
+        "|"
+    }
+    fn import_exported_intrinsic_prefix(&self) -> &str {
+        "_ex_"
+    }
+    fn export_memory(&self) -> &str {
+        "_memory"
+    }
+    fn export_initialize(&self) -> &str {
+        "_initialize"
+    }
+    fn export_realloc(&self) -> &str {
+        "_realloc"
+    }
+    fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_suffix("_drop")
+    }
+    fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_suffix("_new")
+    }
+    fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_suffix("_rep")
+    }
+    fn module_to_interface(
+        &self,
+        interface: &str,
+        resolve: &Resolve,
+        items: &IndexMap<WorldKey, WorldItem>,
+    ) -> Result<(WorldKey, InterfaceId)> {
+        for (key, item) in items.iter() {
+            let id = match key {
+                // Bare keys are matched exactly against `interface`
+                WorldKey::Name(name) => match item {
+                    WorldItem::Interface { id, .. } if name == interface => *id,
+                    _ => continue,
+                },
+                // ID-identified keys are matched with their "canonical name"
+                WorldKey::Interface(id) => {
+                    if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
+                        continue;
+                    }
+                    *id
+                }
+            };
+            return Ok((key.clone(), id));
+        }
+        bail!("failed to find world item corresponding to interface `{interface}`")
+    }
+    fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_suffix("_post")
+    }
+    fn match_wit_export<'a>(
+        &self,
+        export_name: &str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
+        if let Some(world_export_name) = export_name.strip_prefix("||") {
+            let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
+            match &resolve.worlds[world].exports[key] {
+                WorldItem::Function(f) => return Some((key, None, f)),
+                _ => return None,
+            }
+        }
+
+        let (key, id, func_name) =
+            self.match_wit_interface(export_name, resolve, world, exports)?;
+        let func = resolve.interfaces[id].functions.get(func_name)?;
+        Some((key, Some(id), func))
+    }
+
+    fn match_wit_resource_dtor<'a>(
+        &self,
+        export_name: &str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<TypeId> {
+        let (_key, id, name) =
+            self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
+        let ty = *resolve.interfaces[id].types.get(name)?;
+        match resolve.types[ty].kind {
+            TypeDefKind::Resource => Some(ty),
+            _ => None,
+        }
+    }
+}
+
+impl Standard {
+    fn match_wit_interface<'a, 'b>(
+        &self,
+        export_name: &'b str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
+        let world = &resolve.worlds[world];
+        let export_name = export_name.strip_prefix("|")?;
+
+        for export in exports {
+            let id = match &world.exports[export] {
+                WorldItem::Interface { id, .. } => *id,
+                WorldItem::Function(_) => continue,
+                WorldItem::Type(_) => unreachable!(),
+            };
+            let remaining = match export {
+                WorldKey::Name(name) => export_name.strip_prefix(name),
+                WorldKey::Interface(_) => {
+                    let prefix = resolve.canonicalized_id_of(id).unwrap();
+                    export_name.strip_prefix(&prefix)
+                }
+            };
+            let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
+                Some(name) => name,
+                None => continue,
+            };
+            return Some((export, id, item_name));
+        }
+
+        None
+    }
+}
+
+/// Definition of wit-component's "legacy" naming scheme which predates
+/// WebAssembly/component-model#378.
+struct Legacy;
+
+const LEGACY: &'static dyn NameMangling = &Legacy;
+
+impl NameMangling for Legacy {
+    fn import_root(&self) -> &str {
+        "$root"
+    }
+    fn import_non_root_prefix(&self) -> &str {
+        ""
+    }
+    fn import_exported_intrinsic_prefix(&self) -> &str {
+        "[export]"
+    }
+    fn export_memory(&self) -> &str {
+        "memory"
+    }
+    fn export_initialize(&self) -> &str {
+        "_initialize"
+    }
+    fn export_realloc(&self) -> &str {
+        "cabi_realloc"
+    }
+    fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_prefix("[resource-drop]")
+    }
+    fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_prefix("[resource-new]")
+    }
+    fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_prefix("[resource-rep]")
+    }
+    fn module_to_interface(
+        &self,
+        module: &str,
+        resolve: &Resolve,
+        items: &IndexMap<WorldKey, WorldItem>,
+    ) -> Result<(WorldKey, InterfaceId)> {
+        // First see if this is a bare name
+        let bare_name = WorldKey::Name(module.to_string());
+        if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
+            return Ok((bare_name, *id));
+        }
+
+        // ... and if this isn't a bare name then it's time to do some parsing
+        // related to interfaces, versions, and such. First up the `module` name
+        // is parsed as a normal component name from `wasmparser` to see if it's
+        // of the "interface kind". If it's not then that means the above match
+        // should have been a hit but it wasn't, so an error is returned.
+        let kebab_name = ComponentName::new(module, 0);
+        let name = match kebab_name.as_ref().map(|k| k.kind()) {
+            Ok(ComponentNameKind::Interface(name)) => name,
+            _ => bail!("module requires an import interface named `{module}`"),
+        };
+
+        // Prioritize an exact match based on versions, so try that first.
+        let pkgname = PackageName {
+            namespace: name.namespace().to_string(),
+            name: name.package().to_string(),
+            version: name.version(),
+        };
+        if let Some(pkg) = resolve.package_names.get(&pkgname) {
+            if let Some(id) = resolve.packages[*pkg]
+                .interfaces
+                .get(name.interface().as_str())
+            {
+                let key = WorldKey::Interface(*id);
+                if items.contains_key(&key) {
+                    return Ok((key, *id));
+                }
+            }
+        }
+
+        // If an exact match wasn't found then instead search for the first
+        // match based on versions. This means that a core wasm import for
+        // "1.2.3" might end up matching an interface at "1.2.4", for example.
+        // (or "1.2.2", depending on what's available).
+        for (key, _) in items {
+            let id = match key {
+                WorldKey::Interface(id) => *id,
+                WorldKey::Name(_) => continue,
+            };
+            // Make sure the interface names match
+            let interface = &resolve.interfaces[id];
+            if interface.name.as_ref().unwrap() != name.interface().as_str() {
+                continue;
+            }
+
+            // Make sure the package name (without version) matches
+            let pkg = &resolve.packages[interface.package.unwrap()];
+            if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
+                continue;
+            }
+
+            let module_version = match name.version() {
+                Some(version) => version,
+                None => continue,
+            };
+            let pkg_version = match &pkg.name.version {
+                Some(version) => version,
+                None => continue,
+            };
+
+            // Test if the two semver versions are compatible
+            let module_compat = PackageName::version_compat_track(&module_version);
+            let pkg_compat = PackageName::version_compat_track(pkg_version);
+            if module_compat == pkg_compat {
+                return Ok((key.clone(), id));
+            }
+        }
+
+        bail!("module requires an import interface named `{module}`")
+    }
+    fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str> {
+        s.strip_prefix("cabi_post_")
+    }
+    fn match_wit_export<'a>(
+        &self,
+        export_name: &str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
+        let world = &resolve.worlds[world];
+        for name in exports {
+            match &world.exports[name] {
+                WorldItem::Function(f) => {
+                    if f.legacy_core_export_name(None) == export_name {
+                        return Some((name, None, f));
+                    }
+                }
+                WorldItem::Interface { id, .. } => {
+                    let string = resolve.name_world_key(name);
+                    for (_, func) in resolve.interfaces[*id].functions.iter() {
+                        if func.legacy_core_export_name(Some(&string)) == export_name {
+                            return Some((name, Some(*id), func));
+                        }
+                    }
+                }
+
+                WorldItem::Type(_) => unreachable!(),
+            }
+        }
+
+        None
+    }
+
+    fn match_wit_resource_dtor<'a>(
+        &self,
+        export_name: &str,
+        resolve: &'a Resolve,
+        world: WorldId,
+        exports: &'a IndexSet<WorldKey>,
+    ) -> Option<TypeId> {
+        let world = &resolve.worlds[world];
+        for name in exports {
+            let id = match &world.exports[name] {
+                WorldItem::Interface { id, .. } => *id,
+                WorldItem::Function(_) => continue,
+                WorldItem::Type(_) => unreachable!(),
+            };
+            let name = resolve.name_world_key(name);
+            let resource = match export_name
+                .strip_prefix(&name)
+                .and_then(|s| s.strip_prefix("#[dtor]"))
+                .and_then(|r| resolve.interfaces[id].types.get(r))
+            {
+                Some(id) => *id,
+                None => continue,
+            };
+
+            match resolve.types[resource].kind {
+                TypeDefKind::Resource => {}
+                _ => continue,
+            }
+
+            return Some(resource);
+        }
+
+        None
+    }
+}
+
 /// This function validates the following:
 ///
 /// * The `bytes` represent a valid core WebAssembly module.
@@ -918,20 +1182,8 @@ impl ExportMap {
 /// The `ValidatedModule` return value contains the metadata which describes the
 /// input module on success. This is then further used to generate a component
 /// for this module.
-pub fn validate_module(
-    bytes: &[u8],
-    metadata: &Bindgen,
-    exports: &IndexSet<WorldKey>,
-    adapters: &IndexSet<&str>,
-) -> Result<ValidatedModule> {
-    ValidatedModule::new(
-        bytes,
-        &metadata.resolve,
-        metadata.world,
-        exports,
-        adapters,
-        None,
-    )
+pub fn validate_module(encoder: &ComponentEncoder, bytes: &[u8]) -> Result<ValidatedModule> {
+    ValidatedModule::new(encoder, bytes, &encoder.main_module_exports, None)
 }
 
 /// This function will validate the `bytes` provided as a wasm adapter module.
@@ -952,15 +1204,13 @@ pub fn validate_module(
 /// allowing the module to import tables and globals, as well as import
 /// functions at the world level, not just at the interface level.
 pub fn validate_adapter_module(
+    encoder: &ComponentEncoder,
     bytes: &[u8],
-    resolve: &Resolve,
-    world: WorldId,
     required_by_import: &IndexMap<String, FuncType>,
     exports: &IndexSet<WorldKey>,
     library_info: Option<&LibraryInfo>,
-    adapters: &IndexSet<&str>,
 ) -> Result<ValidatedModule> {
-    let ret = ValidatedModule::new(bytes, resolve, world, exports, adapters, library_info)?;
+    let ret = ValidatedModule::new(encoder, bytes, exports, library_info)?;
 
     for (name, required_ty) in required_by_import {
         let actual = match ret.exports.raw_exports.get(name) {
@@ -973,21 +1223,6 @@ pub fn validate_adapter_module(
     Ok(ret)
 }
 
-fn valid_resource_drop(
-    func_name: &str,
-    ty: &FuncType,
-    get_resource: impl Fn(&str) -> Option<TypeId>,
-) -> Result<Option<TypeId>> {
-    if let Some(resource_name) = func_name.strip_prefix(RESOURCE_DROP) {
-        if let Some(id) = get_resource(resource_name) {
-            let expected = FuncType::new([ValType::I32], []);
-            validate_func_sig(func_name, &expected, ty)?;
-            return Ok(Some(id));
-        }
-    }
-    Ok(None)
-}
-
 fn resource_test_for_interface<'a>(
     resolve: &'a Resolve,
     id: InterfaceId,
diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs
index 36524e52..cb0e2cec 100644
--- a/crates/wit-parser/src/decoding.rs
+++ b/crates/wit-parser/src/decoding.rs
@@ -157,7 +157,7 @@ impl ComponentInfo {
             };
             match export.kind {
                 ComponentExternalKind::Type => matches!(
-                    self.types.component_any_type_at(export.index),
+                    self.types.as_ref().component_any_type_at(export.index),
                     types::ComponentAnyTypeId::Component(_)
                 ),
                 _ => false,
@@ -188,7 +188,7 @@ impl ComponentInfo {
                 Extern::Export(e) => e,
                 _ => unreachable!(),
             };
-            let id = self.types.component_type_at(export.index);
+            let id = self.types.as_ref().component_type_at(export.index);
             let ty = &self.types[id];
             if pkg.is_some() {
                 bail!("more than one top-level exported component type found");
@@ -228,7 +228,7 @@ impl ComponentInfo {
             };
 
             let index = export.index;
-            let id = self.types.component_type_at(index);
+            let id = self.types.as_ref().component_type_at(index);
             let component = &self.types[id];
 
             // The single export of this component will determine if it's a world or an interface:
@@ -454,7 +454,7 @@ pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> {
         bail!("expected an un-ascribed exported type");
     }
     let types = types.as_ref().unwrap();
-    let world = match types.component_any_type_at(exports[0].index) {
+    let world = match types.as_ref().component_any_type_at(exports[0].index) {
         ComponentAnyTypeId::Component(c) => c,
         _ => bail!("expected an exported component type"),
     };
@@ -639,7 +639,11 @@ impl WitPackageDecoder<'_> {
         package: &mut PackageFields<'a>,
     ) -> Result<()> {
         log::debug!("decoding component import `{name}`");
-        let ty = self.types.component_entity_type_of_import(name).unwrap();
+        let ty = self
+            .types
+            .as_ref()
+            .component_entity_type_of_import(name)
+            .unwrap();
         let owner = TypeOwner::World(world);
         let (name, item) = match ty {
             types::ComponentEntityType::Instance(i) => {
@@ -690,7 +694,7 @@ impl WitPackageDecoder<'_> {
     ) -> Result<()> {
         let name = &export.name;
         log::debug!("decoding component export `{name}`");
-        let types = &self.types;
+        let types = self.types.as_ref();
         let ty = types.component_entity_type_of_export(name).unwrap();
         let (name, item) = match ty {
             types::ComponentEntityType::Func(i) => {
@@ -859,7 +863,7 @@ impl WitPackageDecoder<'_> {
         let mut cur = id;
         while prev.is_none() {
             prev = self.type_map.get(&cur).copied();
-            cur = match self.types.peel_alias(cur) {
+            cur = match self.types.as_ref().peel_alias(cur) {
                 Some(next) => next,
                 None => break,
             };
diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs
index e85cb210..906f6a7a 100644
--- a/crates/wit-parser/src/lib.rs
+++ b/crates/wit-parser/src/lib.rs
@@ -1,4 +1,4 @@
-use anyhow::{Context, Result};
+use anyhow::{bail, Context, Result};
 use id_arena::{Arena, Id};
 use indexmap::IndexMap;
 use semver::Version;
@@ -21,7 +21,7 @@ pub use ast::{parse_use_path, ParsedUsePath};
 mod sizealign;
 pub use sizealign::*;
 mod resolve;
-pub use resolve::{InvalidTransitiveDependency, Package, PackageId, Remap, Resolve};
+pub use resolve::*;
 mod live;
 pub use live::{LiveTypes, TypeIdVisitor};
 
@@ -219,6 +219,23 @@ impl PackageName {
         }
         version
     }
+
+    /// Returns the string corresponding to
+    /// [`PackageName::version_compat_track`]. This is done to match the
+    /// component model's expected naming scheme of imports and exports.
+    pub fn version_compat_track_string(version: &Version) -> String {
+        let version = Self::version_compat_track(version);
+        if !version.pre.is_empty() {
+            return version.to_string();
+        }
+        if version.major != 0 {
+            return format!("{}", version.major);
+        }
+        if version.minor != 0 {
+            return format!("{}.{}", version.major, version.minor);
+        }
+        version.to_string()
+    }
 }
 
 impl fmt::Display for PackageName {
@@ -850,6 +867,37 @@ impl FunctionKind {
     }
 }
 
+/// Possible forms of name mangling that are supported by this crate.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum Mangling {
+    /// The "standard" component model mangling format for 32-bit linear
+    /// memories. This is specified in WebAssembly/component-model#378
+    Standard32,
+
+    /// The "legacy" name mangling supported in versions 218-and-prior for this
+    /// crate. This is the original support for how components were created from
+    /// core wasm modules and this does not correspond to any standard. This is
+    /// preserved for now while tools transition to the new scheme.
+    Legacy,
+}
+
+impl std::str::FromStr for Mangling {
+    type Err = anyhow::Error;
+
+    fn from_str(s: &str) -> Result<Mangling> {
+        match s {
+            "legacy" => Ok(Mangling::Legacy),
+            "standard32" => Ok(Mangling::Standard32),
+            _ => {
+                bail!(
+                    "unknown name mangling `{s}`, \
+                     supported values are `legacy` or `standard32`"
+                )
+            }
+        }
+    }
+}
+
 impl Function {
     pub fn item_name(&self) -> &str {
         match &self.kind {
@@ -873,10 +921,28 @@ impl Function {
     }
 
     /// Gets the core export name for this function.
-    pub fn core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
+    pub fn standard32_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
+        self.core_export_name(interface, Mangling::Standard32)
+    }
+
+    pub fn legacy_core_export_name<'a>(&'a self, interface: Option<&str>) -> Cow<'a, str> {
+        self.core_export_name(interface, Mangling::Legacy)
+    }
+    /// Gets the core export name for this function.
+    pub fn core_export_name<'a>(
+        &'a self,
+        interface: Option<&str>,
+        mangling: Mangling,
+    ) -> Cow<'a, str> {
         match interface {
-            Some(interface) => Cow::Owned(format!("{interface}#{}", self.name)),
-            None => Cow::Borrowed(&self.name),
+            Some(interface) => match mangling {
+                Mangling::Standard32 => Cow::Owned(format!("cm32p2|{interface}|{}", self.name)),
+                Mangling::Legacy => Cow::Owned(format!("{interface}#{}", self.name)),
+            },
+            None => match mangling {
+                Mangling::Standard32 => Cow::Owned(format!("cm32p2||{}", self.name)),
+                Mangling::Legacy => Cow::Borrowed(&self.name),
+            },
         }
     }
 }
diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs
index 5122d854..02efb938 100644
--- a/crates/wit-parser/src/resolve.rs
+++ b/crates/wit-parser/src/resolve.rs
@@ -18,9 +18,9 @@ use crate::ast::{parse_use_path, ParsedUsePath};
 use crate::serde_::{serialize_arena, serialize_id_map};
 use crate::{
     AstItem, Docs, Error, Function, FunctionKind, Handle, IncludeName, Interface, InterfaceId,
-    InterfaceSpan, PackageName, Results, SourceMap, Stability, Type, TypeDef, TypeDefKind, TypeId,
-    TypeIdVisitor, TypeOwner, UnresolvedPackage, UnresolvedPackageGroup, World, WorldId, WorldItem,
-    WorldKey, WorldSpan,
+    InterfaceSpan, Mangling, PackageName, Results, SourceMap, Stability, Type, TypeDef,
+    TypeDefKind, TypeId, TypeIdVisitor, TypeOwner, UnresolvedPackage, UnresolvedPackageGroup,
+    World, WorldId, WorldItem, WorldKey, WorldSpan,
 };
 
 mod clone;
@@ -1012,6 +1012,15 @@ package {name} is defined in two different locations:\n\
         Some(self.id_of_name(interface.package.unwrap(), interface.name.as_ref()?))
     }
 
+    /// Returns the "canonicalized interface name" of `interface`.
+    ///
+    /// Returns `None` for unnamed interfaces. See `BuildTargets.md` in the
+    /// upstream component model repository for more information about this.
+    pub fn canonicalized_id_of(&self, interface: InterfaceId) -> Option<String> {
+        let interface = &self.interfaces[interface];
+        Some(self.canonicalized_id_of_name(interface.package.unwrap(), interface.name.as_ref()?))
+    }
+
     /// Convert a world to an "importized" version where the world is updated
     /// in-place to reflect what it would look like to be imported.
     ///
@@ -1090,6 +1099,27 @@ package {name} is defined in two different locations:\n\
         base
     }
 
+    /// Returns the "canonicalized interface name" of the specified `name`
+    /// within the `pkg`.
+    ///
+    /// See `BuildTargets.md` in the upstream component model repository for
+    /// more information about this.
+    pub fn canonicalized_id_of_name(&self, pkg: PackageId, name: &str) -> String {
+        let package = &self.packages[pkg];
+        let mut base = String::new();
+        base.push_str(&package.name.namespace);
+        base.push_str(":");
+        base.push_str(&package.name.name);
+        base.push_str("/");
+        base.push_str(name);
+        if let Some(version) = &package.name.version {
+            base.push_str("@");
+            let string = PackageName::version_compat_track_string(version);
+            base.push_str(&string);
+        }
+        base
+    }
+
     /// Attempts to locate a world given the "default" set of `packages` and the
     /// optional string specifier `world`.
     ///
@@ -1278,6 +1308,17 @@ package {name} is defined in two different locations:\n\
         }
     }
 
+    /// Same as [`Resolve::name_world_key`] except that `WorldKey::Interfaces`
+    /// uses [`Resolve::canonicalized_id_of`].
+    pub fn name_canonicalized_world_key(&self, key: &WorldKey) -> String {
+        match key {
+            WorldKey::Name(s) => s.to_string(),
+            WorldKey::Interface(i) => self
+                .canonicalized_id_of(*i)
+                .expect("unexpected anonymous interface"),
+        }
+    }
+
     /// Returns the interface that `id` uses a type from, if it uses a type from
     /// a different interface than `id` is defined within.
     ///
@@ -2173,6 +2214,226 @@ package {name} is defined in two different locations:\n\
         let replacement_id = self.interfaces[*replace_with].types[name];
         self.types[ty].kind = TypeDefKind::Type(Type::Id(replacement_id));
     }
+
+    /// Returns the core wasm module/field names for the specified `import`.
+    ///
+    /// This function will return the core wasm module/field that can be used to
+    /// use `import` with the name `mangling` scheme specified as well. This can
+    /// be useful for bindings generators, for example, and these names are
+    /// recognized by `wit-component` and `wasm-tools component new`.
+    pub fn wasm_import_name(&self, mangling: Mangling, import: WasmImport<'_>) -> (String, String) {
+        match mangling {
+            Mangling::Standard32 => match import {
+                WasmImport::Func { interface, func } => {
+                    let module = match interface {
+                        Some(key) => format!("cm32p2|{}", self.name_canonicalized_world_key(key)),
+                        None => format!("cm32p2"),
+                    };
+                    (module, func.name.clone())
+                }
+                WasmImport::ResourceIntrinsic {
+                    interface,
+                    resource,
+                    intrinsic,
+                } => {
+                    let name = self.types[resource].name.as_ref().unwrap();
+                    let (prefix, name) = match intrinsic {
+                        ResourceIntrinsic::ImportedDrop => ("", format!("{name}_drop")),
+                        ResourceIntrinsic::ExportedDrop => ("_ex_", format!("{name}_drop")),
+                        ResourceIntrinsic::ExportedNew => ("_ex_", format!("{name}_new")),
+                        ResourceIntrinsic::ExportedRep => ("_ex_", format!("{name}_rep")),
+                    };
+                    let module = match interface {
+                        Some(key) => {
+                            format!("cm32p2|{prefix}{}", self.name_canonicalized_world_key(key))
+                        }
+                        None => {
+                            assert_eq!(prefix, "");
+                            format!("cm32p2")
+                        }
+                    };
+                    (module, name)
+                }
+            },
+            Mangling::Legacy => match import {
+                WasmImport::Func { interface, func } => {
+                    let module = match interface {
+                        Some(key) => self.name_world_key(key),
+                        None => format!("$root"),
+                    };
+                    (module, func.name.clone())
+                }
+                WasmImport::ResourceIntrinsic {
+                    interface,
+                    resource,
+                    intrinsic,
+                } => {
+                    let name = self.types[resource].name.as_ref().unwrap();
+                    let (prefix, name) = match intrinsic {
+                        ResourceIntrinsic::ImportedDrop => ("", format!("[resource-drop]{name}")),
+                        ResourceIntrinsic::ExportedDrop => {
+                            ("[export]", format!("[resource-drop]{name}"))
+                        }
+                        ResourceIntrinsic::ExportedNew => {
+                            ("[export]", format!("[resource-new]{name}"))
+                        }
+                        ResourceIntrinsic::ExportedRep => {
+                            ("[export]", format!("[resource-rep]{name}"))
+                        }
+                    };
+                    let module = match interface {
+                        Some(key) => format!("{prefix}{}", self.name_world_key(key)),
+                        None => {
+                            assert_eq!(prefix, "");
+                            format!("$root")
+                        }
+                    };
+                    (module, name)
+                }
+            },
+        }
+    }
+
+    /// Returns the core wasm export name for the specified `import`.
+    ///
+    /// This is the same as [`Resovle::wasm_import_name`], except for exports.
+    pub fn wasm_export_name(&self, mangling: Mangling, import: WasmExport<'_>) -> String {
+        match mangling {
+            Mangling::Standard32 => match import {
+                WasmExport::Func {
+                    interface,
+                    func,
+                    post_return,
+                } => {
+                    let mut name = String::from("cm32p2|");
+                    if let Some(interface) = interface {
+                        let s = self.name_canonicalized_world_key(interface);
+                        name.push_str(&s);
+                    }
+                    name.push_str("|");
+                    name.push_str(&func.name);
+                    if post_return {
+                        name.push_str("_post");
+                    }
+                    name
+                }
+                WasmExport::ResourceDtor {
+                    interface,
+                    resource,
+                } => {
+                    let name = self.types[resource].name.as_ref().unwrap();
+                    let interface = self.name_canonicalized_world_key(interface);
+                    format!("cm32p2|{interface}|{name}_dtor")
+                }
+                WasmExport::Memory => "cm32p2_memory".to_string(),
+                WasmExport::Initialize => "cm32p2_initialize".to_string(),
+                WasmExport::Realloc => "cm32p2_realloc".to_string(),
+            },
+            Mangling::Legacy => match import {
+                WasmExport::Func {
+                    interface,
+                    func,
+                    post_return,
+                } => {
+                    let mut name = String::new();
+                    if post_return {
+                        name.push_str("cabi_post_");
+                    }
+                    if let Some(interface) = interface {
+                        let s = self.name_world_key(interface);
+                        name.push_str(&s);
+                        name.push_str("#");
+                    }
+                    name.push_str(&func.name);
+                    name
+                }
+                WasmExport::ResourceDtor {
+                    interface,
+                    resource,
+                } => {
+                    let name = self.types[resource].name.as_ref().unwrap();
+                    let interface = self.name_world_key(interface);
+                    format!("{interface}#[dtor]{name}")
+                }
+                WasmExport::Memory => "memory".to_string(),
+                WasmExport::Initialize => "_initialize".to_string(),
+                WasmExport::Realloc => "cabi_realloc".to_string(),
+            },
+        }
+    }
+}
+
+/// Possible imports that can be passed to [`Resolve::wasm_import_name`].
+#[derive(Debug)]
+pub enum WasmImport<'a> {
+    /// A WIT function is being imported. Optionally from an interface.
+    Func {
+        /// The name of the interface that the function is being imported from.
+        ///
+        /// If the function is imported directly from the world then this is
+        /// `Noen`.
+        interface: Option<&'a WorldKey>,
+
+        /// The function being imported.
+        func: &'a Function,
+    },
+
+    /// A resource-related intrinsic is being imported.
+    ResourceIntrinsic {
+        /// The optional interface to import from, same as `WasmImport::Func`.
+        interface: Option<&'a WorldKey>,
+
+        /// The resource that's being operated on.
+        resource: TypeId,
+
+        /// The intrinsic that's being imported.
+        intrinsic: ResourceIntrinsic,
+    },
+}
+
+/// Intrinsic definitions to go with [`WasmImport::ResourceIntrinsic`] which
+/// also goes with [`Resolve::wasm_import_name`].
+#[derive(Debug)]
+pub enum ResourceIntrinsic {
+    ImportedDrop,
+    ExportedDrop,
+    ExportedNew,
+    ExportedRep,
+}
+
+/// Different kinds of exports that can be passed to
+/// [`Resolve::wasm_export_name`] to export from core wasm modules.
+#[derive(Debug)]
+pub enum WasmExport<'a> {
+    /// A WIT function is being exported, optionally from an interface.
+    Func {
+        /// An optional interface which owns `func`. Use `None` for top-level
+        /// world function.
+        interface: Option<&'a WorldKey>,
+
+        /// The function being exported.
+        func: &'a Function,
+
+        /// Whether or not this is a post-return function or not.
+        post_return: bool,
+    },
+
+    /// A destructor for a resource exported from this module.
+    ResourceDtor {
+        /// The interface that owns the resource.
+        interface: &'a WorldKey,
+        /// The resource itself that the destructor is for.
+        resource: TypeId,
+    },
+
+    /// Linear memory, the one that the canonical ABI uses.
+    Memory,
+
+    /// An initialization function (not the core wasm `start`).
+    Initialize,
+
+    /// The general-purpose realloc hook.
+    Realloc,
 }
 
 /// Structure returned by [`Resolve::merge`] which contains mappings from
diff --git a/fuzz/src/print.rs b/fuzz/src/print.rs
index d9b88742..1e549f32 100644
--- a/fuzz/src/print.rs
+++ b/fuzz/src/print.rs
@@ -1,7 +1,15 @@
 use arbitrary::{Result, Unstructured};
 
 pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
+    let mut cfg = wasmprinter::Config::new();
+    cfg.fold_instructions(u.arbitrary()?);
+    cfg.print_skeleton(u.arbitrary()?);
+    cfg.print_offsets(u.arbitrary()?);
+    cfg.name_unnamed(u.arbitrary()?);
+
     let data = u.bytes(u.len())?;
-    drop(wasmprinter::print_bytes(data));
+    crate::log_wasm(&data, &cfg);
+    let mut dst = String::new();
+    let _ = cfg.print(&data, &mut wasmprinter::PrintFmtWrite(&mut dst));
     Ok(())
 }
diff --git a/fuzz/src/roundtrip_wit.rs b/fuzz/src/roundtrip_wit.rs
index ed696160..f94d52dd 100644
--- a/fuzz/src/roundtrip_wit.rs
+++ b/fuzz/src/roundtrip_wit.rs
@@ -1,7 +1,7 @@
 use arbitrary::{Result, Unstructured};
 use std::path::Path;
 use wit_component::*;
-use wit_parser::{PackageId, Resolve};
+use wit_parser::{Mangling, PackageId, Resolve};
 
 pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     let wasm = u.arbitrary().and_then(|config| {
@@ -36,7 +36,12 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     let mut decoded_bindgens = Vec::new();
     for (id, world) in resolve.worlds.iter().take(20) {
         log::debug!("embedding world {} as in a dummy module", world.name);
-        let mut dummy = wit_component::dummy_module(&resolve, id);
+        let mangling = match u.int_in_range(0..=1)? {
+            0 => Mangling::Legacy,
+            1 => Mangling::Standard32,
+            _ => unreachable!(),
+        };
+        let mut dummy = wit_component::dummy_module(&resolve, id, mangling);
         wit_component::embed_component_metadata(&mut dummy, &resolve, id, StringEncoding::UTF8)
             .unwrap();
         write_file("dummy.wasm", &dummy);
diff --git a/fuzz/src/validate.rs b/fuzz/src/validate.rs
index 12eae6af..2e849a05 100644
--- a/fuzz/src/validate.rs
+++ b/fuzz/src/validate.rs
@@ -21,8 +21,7 @@ pub fn validate_maybe_invalid_module(u: &mut Unstructured<'_>) -> Result<()> {
         config.allow_invalid_funcs = true;
         Ok(())
     })?;
-    validate_all(crate::validator_for_config(&config), &wasm);
-    Ok(())
+    validate_all(u, crate::validator_for_config(&config), &wasm)
 }
 
 pub fn validate_raw_bytes(u: &mut Unstructured<'_>) -> Result<()> {
@@ -30,19 +29,33 @@ pub fn validate_raw_bytes(u: &mut Unstructured<'_>) -> Result<()> {
     let validator = Validator::new_with_features(WasmFeatures::from_bits_truncate(u.arbitrary()?));
     let wasm = u.bytes(u.len())?;
     crate::log_wasm(wasm, "");
-    validate_all(validator, wasm);
-    Ok(())
+    validate_all(u, validator, wasm)
 }
 
-fn validate_all(mut validator: Validator, wasm: &[u8]) {
+fn validate_all(u: &mut Unstructured<'_>, mut validator: Validator, wasm: &[u8]) -> Result<()> {
+    // First try printing this module. Generate a random configuration for
+    // printing and then see what happens. Mostly making sure nothing panics
+    // here.
+    let mut cfg = wasmprinter::Config::new();
+    cfg.fold_instructions(u.arbitrary()?);
+    cfg.print_skeleton(u.arbitrary()?);
+    cfg.print_offsets(u.arbitrary()?);
+    cfg.name_unnamed(u.arbitrary()?);
+    log::debug!("print config {cfg:?}");
+    let mut wat = String::new();
+    let _ = cfg.print(wasm, &mut wasmprinter::PrintFmtWrite(&mut wat));
+
+    // After printing then try to parse and validate the module. See how far we
+    // get as invalid modules are explicitly allowed here. Generally looking for
+    // panics and excessive resource usage here.
     for payload in Parser::new(0).parse_all(wasm) {
         let payload = match payload {
             Ok(p) => p,
-            Err(_) => return,
+            Err(_) => return Ok(()),
         };
 
         if validator.payload(&payload).is_err() {
-            return;
+            return Ok(());
         }
 
         // Check that the payload's range is in bounds, since the payload is
@@ -91,4 +104,6 @@ fn validate_all(mut validator: Validator, wasm: &[u8]) {
             End(_) => {}
         }
     }
+
+    Ok(())
 }
diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs
index 9c95f14d..701b9a73 100644
--- a/src/bin/wasm-tools/component.rs
+++ b/src/bin/wasm-tools/component.rs
@@ -15,7 +15,7 @@ use wat::Detect;
 use wit_component::{
     embed_component_metadata, ComponentEncoder, DecodedWasm, Linker, StringEncoding, WitPrinter,
 };
-use wit_parser::{PackageId, Resolve};
+use wit_parser::{Mangling, PackageId, Resolve};
 
 /// WebAssembly wit-based component tooling.
 #[derive(Parser)]
@@ -148,6 +148,17 @@ pub struct NewOpts {
     /// This is enabled by default.
     #[clap(long, value_name = "MERGE")]
     merge_imports_based_on_semver: Option<bool>,
+
+    /// Reject usage of the "legacy" naming scheme of `wit-component` and
+    /// require the new naming scheme to be used.
+    ///
+    /// This flag can be used to ignore core module imports/exports that don't
+    /// conform to WebAssembly/component-model#378. This turns off
+    /// compatibility `wit-component`'s historical naming scheme. This is
+    /// intended to be used to test if a tool is compatible with a hypothetical
+    /// removal of the old scheme in the future.
+    #[clap(long)]
+    reject_legacy_names: bool,
 }
 
 impl NewOpts {
@@ -158,7 +169,9 @@ impl NewOpts {
     /// Executes the application.
     fn run(self) -> Result<()> {
         let wasm = self.io.parse_input_wasm()?;
-        let mut encoder = ComponentEncoder::default().validate(!self.skip_validation);
+        let mut encoder = ComponentEncoder::default()
+            .validate(!self.skip_validation)
+            .reject_legacy_names(self.reject_legacy_names);
 
         if let Some(merge) = self.merge_imports_based_on_semver {
             encoder = encoder.merge_imports_based_on_semver(merge);
@@ -278,9 +291,20 @@ pub struct EmbedOpts {
     /// imports/exports and the right signatures for the component model. This
     /// can be useful to, perhaps, inspect a template module and what it looks
     /// like to work with an interface in the component model.
-    #[clap(long)]
+    ///
+    /// This option is equivalent to `--dummy-names standard32`
+    #[clap(long, conflicts_with = "dummy_names")]
     dummy: bool,
 
+    /// Same as `--dummy`, but the style of core wasm names is specified.
+    ///
+    /// This flag is the same as `--dummy` where if specified a core wasm module
+    /// is not read but is instead generated. The value of the option here is
+    /// the name mangling scheme to use for core wasm names generated. Current
+    /// options are `legacy|standard32`.
+    #[clap(long, conflicts_with = "dummy")]
+    dummy_names: Option<Mangling>,
+
     /// Print the output in the WebAssembly text format instead of binary.
     #[clap(long, short = 't')]
     wat: bool,
@@ -293,14 +317,15 @@ impl EmbedOpts {
 
     /// Executes the application.
     fn run(self) -> Result<()> {
-        let wasm = if self.dummy {
-            None
-        } else {
-            Some(self.io.parse_input_wasm()?)
-        };
         let (resolve, pkg_id) = self.resolve.load()?;
         let world = resolve.select_world(pkg_id, self.world.as_deref())?;
-        let mut wasm = wasm.unwrap_or_else(|| wit_component::dummy_module(&resolve, world));
+        let mut wasm = if self.dummy {
+            wit_component::dummy_module(&resolve, world, Mangling::Standard32)
+        } else if let Some(mangling) = self.dummy_names {
+            wit_component::dummy_module(&resolve, world, mangling)
+        } else {
+            self.io.parse_input_wasm()?
+        };
 
         embed_component_metadata(
             &mut wasm,
@@ -998,6 +1023,7 @@ impl UnbundleOpts {
             // create an import corresponding to that module in the import
             // section.
             let mut module_ty = ModuleTypeCreator::new(&mut core_types, &types);
+            let types = types.as_ref();
 
             for (module, name, ty) in types.core_imports().unwrap() {
                 let ty = module_ty.convert_entity_type(ty)?;


Test patch:
diff --git a/crates/wasm-smith/tests/exports.rs b/crates/wasm-smith/tests/exports.rs
index 7c48cd3d..46a1a785 100644
--- a/crates/wasm-smith/tests/exports.rs
+++ b/crates/wasm-smith/tests/exports.rs
@@ -95,6 +95,7 @@ fn smoke_test_with_mutable_global_exports() {
 fn get_func_and_global_exports(features: WasmFeatures, module: &[u8]) -> Vec<(String, ExportType)> {
     let mut validator = Validator::new_with_features(features);
     let types = validate(&mut validator, module);
+    let types = types.as_ref();
     let mut exports = vec![];
 
     for payload in Parser::new(0).parse_all(module) {
diff --git a/crates/wit-component/tests/components/cm32-names/component.wat b/crates/wit-component/tests/components/cm32-names/component.wat
new file mode 100644
index 00000000..7b513ab5
--- /dev/null
+++ b/crates/wit-component/tests/components/cm32-names/component.wat
@@ -0,0 +1,366 @@
+(component
+  (type (;0;)
+    (instance
+      (export (;0;) "r" (type (sub resource)))
+      (type (;1;) (own 0))
+      (type (;2;) (func (param "s" string) (result 1)))
+      (export (;0;) "[constructor]r" (func (type 2)))
+      (type (;3;) (borrow 0))
+      (type (;4;) (func (param "self" 3) (result string)))
+      (export (;1;) "[method]r.m" (func (type 4)))
+      (type (;5;) (func (param "in" 1) (result 1)))
+      (export (;2;) "frob" (func (type 5)))
+    )
+  )
+  (import "ns:pkg/i@0.2.1" (instance (;0;) (type 0)))
+  (type (;1;)
+    (instance
+      (export (;0;) "r" (type (sub resource)))
+      (type (;1;) (own 0))
+      (type (;2;) (func (param "s" string) (result 1)))
+      (export (;0;) "[constructor]r" (func (type 2)))
+      (type (;3;) (borrow 0))
+      (type (;4;) (func (param "self" 3) (result string)))
+      (export (;1;) "[method]r.m" (func (type 4)))
+      (type (;5;) (func (param "in" 1) (result 1)))
+      (export (;2;) "frob" (func (type 5)))
+    )
+  )
+  (import "j" (instance (;1;) (type 1)))
+  (type (;2;) (func (result string)))
+  (import "f" (func (;0;) (type 2)))
+  (core module (;0;)
+    (type (;0;) (func (param i32)))
+    (type (;1;) (func (param i32 i32) (result i32)))
+    (type (;2;) (func (param i32 i32)))
+    (type (;3;) (func (param i32) (result i32)))
+    (type (;4;) (func (result i32)))
+    (type (;5;) (func (param i32 i32 i32 i32) (result i32)))
+    (type (;6;) (func))
+    (import "cm32p2" "f" (func (;0;) (type 0)))
+    (import "cm32p2|ns:pkg/i@0.2" "[constructor]r" (func (;1;) (type 1)))
+    (import "cm32p2|ns:pkg/i@0.2" "[method]r.m" (func (;2;) (type 2)))
+    (import "cm32p2|ns:pkg/i@0.2" "frob" (func (;3;) (type 3)))
+    (import "cm32p2|ns:pkg/i@0.2" "r_drop" (func (;4;) (type 0)))
+    (import "cm32p2|j" "[constructor]r" (func (;5;) (type 1)))
+    (import "cm32p2|j" "[method]r.m" (func (;6;) (type 2)))
+    (import "cm32p2|j" "frob" (func (;7;) (type 3)))
+    (import "cm32p2|j" "r_drop" (func (;8;) (type 0)))
+    (import "cm32p2|_ex_ns:pkg/i@0.2" "r_drop" (func (;9;) (type 0)))
+    (import "cm32p2|_ex_ns:pkg/i@0.2" "r_new" (func (;10;) (type 3)))
+    (import "cm32p2|_ex_ns:pkg/i@0.2" "r_rep" (func (;11;) (type 3)))
+    (import "cm32p2|_ex_j" "r_drop" (func (;12;) (type 0)))
+    (import "cm32p2|_ex_j" "r_new" (func (;13;) (type 3)))
+    (import "cm32p2|_ex_j" "r_rep" (func (;14;) (type 3)))
+    (memory (;0;) 0)
+    (export "cm32p2_memory" (memory 0))
+    (export "cm32p2||g" (func 15))
+    (export "cm32p2||g_post" (func 16))
+    (export "cm32p2|ns:pkg/i@0.2|[constructor]r" (func 17))
+    (export "cm32p2|ns:pkg/i@0.2|[method]r.m" (func 18))
+    (export "cm32p2|ns:pkg/i@0.2|frob" (func 19))
+    (export "cm32p2|ns:pkg/i@0.2|r_dtor" (func 20))
+    (export "cm32p2|j|[constructor]r" (func 21))
+    (export "cm32p2|j|[method]r.m" (func 22))
+    (export "cm32p2|j|frob" (func 23))
+    (export "cm32p2|j|r_dtor" (func 24))
+    (export "cm32p2_realloc" (func 25))
+    (export "cm32p2_initialize" (func 26))
+    (func (;15;) (type 4) (result i32)
+      unreachable
+    )
+    (func (;16;) (type 0) (param i32)
+      unreachable
+    )
+    (func (;17;) (type 1) (param i32 i32) (result i32)
+      unreachable
+    )
+    (func (;18;) (type 3) (param i32) (result i32)
+      unreachable
+    )
+    (func (;19;) (type 3) (param i32) (result i32)
+      unreachable
+    )
+    (func (;20;) (type 0) (param i32)
+      unreachable
+    )
+    (func (;21;) (type 1) (param i32 i32) (result i32)
+      unreachable
+    )
+    (func (;22;) (type 3) (param i32) (result i32)
+      unreachable
+    )
+    (func (;23;) (type 3) (param i32) (result i32)
+      unreachable
+    )
+    (func (;24;) (type 0) (param i32)
+      unreachable
+    )
+    (func (;25;) (type 5) (param i32 i32 i32 i32) (result i32)
+      unreachable
+    )
+    (func (;26;) (type 6))
+    (@producers
+      (processed-by "wit-component" "$CARGO_PKG_VERSION")
+      (processed-by "my-fake-bindgen" "123.45")
+    )
+  )
+  (core module (;1;)
+    (type (;0;) (func (param i32)))
+    (type (;1;) (func (param i32 i32) (result i32)))
+    (type (;2;) (func (param i32 i32)))
+    (type (;3;) (func (param i32)))
+    (table (;0;) 7 7 funcref)
+    (export "0" (func $indirect-cm32p2-f))
+    (export "1" (func $"indirect-cm32p2|ns:pkg/i@0.2-[constructor]r"))
+    (export "2" (func $"indirect-cm32p2|ns:pkg/i@0.2-[method]r.m"))
+    (export "3" (func $"indirect-cm32p2|j-[constructor]r"))
+    (export "4" (func $"indirect-cm32p2|j-[method]r.m"))
+    (export "5" (func $dtor-r))
+    (export "6" (func $"#func6 dtor-r"))
+    (export "$imports" (table 0))
+    (func $indirect-cm32p2-f (;0;) (type 0) (param i32)
+      local.get 0
+      i32.const 0
+      call_indirect (type 0)
+    )
+    (func $"indirect-cm32p2|ns:pkg/i@0.2-[constructor]r" (;1;) (type 1) (param i32 i32) (result i32)
+      local.get 0
+      local.get 1
+      i32.const 1
+      call_indirect (type 1)
+    )
+    (func $"indirect-cm32p2|ns:pkg/i@0.2-[method]r.m" (;2;) (type 2) (param i32 i32)
+      local.get 0
+      local.get 1
+      i32.const 2
+      call_indirect (type 2)
+    )
+    (func $"indirect-cm32p2|j-[constructor]r" (;3;) (type 1) (param i32 i32) (result i32)
+      local.get 0
+      local.get 1
+      i32.const 3
+      call_indirect (type 1)
+    )
+    (func $"indirect-cm32p2|j-[method]r.m" (;4;) (type 2) (param i32 i32)
+      local.get 0
+      local.get 1
+      i32.const 4
+      call_indirect (type 2)
+    )
+    (func $dtor-r (;5;) (type 3) (param i32)
+      local.get 0
+      i32.const 5
+      call_indirect (type 3)
+    )
+    (func $"#func6 dtor-r" (@name "dtor-r") (;6;) (type 3) (param i32)
+      local.get 0
+      i32.const 6
+      call_indirect (type 3)
+    )
+    (@producers
+      (processed-by "wit-component" "$CARGO_PKG_VERSION")
+    )
+  )
+  (core module (;2;)
+    (type (;0;) (func (param i32)))
+    (type (;1;) (func (param i32 i32) (result i32)))
+    (type (;2;) (func (param i32 i32)))
+    (type (;3;) (func (param i32)))
+    (import "" "0" (func (;0;) (type 0)))
+    (import "" "1" (func (;1;) (type 1)))
+    (import "" "2" (func (;2;) (type 2)))
+    (import "" "3" (func (;3;) (type 1)))
+    (import "" "4" (func (;4;) (type 2)))
+    (import "" "5" (func (;5;) (type 3)))
+    (import "" "6" (func (;6;) (type 3)))
+    (import "" "$imports" (table (;0;) 7 7 funcref))
+    (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6)
+    (@producers
+      (processed-by "wit-component" "$CARGO_PKG_VERSION")
+    )
+  )
+  (core instance (;0;) (instantiate 1))
+  (alias core export 0 "5" (core func (;0;)))
+  (type (;3;) (resource (rep i32) (dtor (func 0))))
+  (alias core export 0 "6" (core func (;1;)))
+  (type (;4;) (resource (rep i32) (dtor (func 1))))
+  (alias core export 0 "0" (core func (;2;)))
+  (core instance (;1;)
+    (export "f" (func 2))
+  )
+  (alias core export 0 "1" (core func (;3;)))
+  (alias core export 0 "2" (core func (;4;)))
+  (alias export 0 "frob" (func (;1;)))
+  (core func (;5;) (canon lower (func 1)))
+  (alias export 0 "r" (type (;5;)))
+  (core func (;6;) (canon resource.drop 5))
+  (core instance (;2;)
+    (export "[constructor]r" (func 3))
+    (export "[method]r.m" (func 4))
+    (export "frob" (func 5))
+    (export "r_drop" (func 6))
+  )
+  (alias core export 0 "3" (core func (;7;)))
+  (alias core export 0 "4" (core func (;8;)))
+  (alias export 1 "frob" (func (;2;)))
+  (core func (;9;) (canon lower (func 2)))
+  (alias export 1 "r" (type (;6;)))
+  (core func (;10;) (canon resource.drop 6))
+  (core instance (;3;)
+    (export "[constructor]r" (func 7))
+    (export "[method]r.m" (func 8))
+    (export "frob" (func 9))
+    (export "r_drop" (func 10))
+  )
+  (core func (;11;) (canon resource.drop 3))
+  (core func (;12;) (canon resource.new 3))
+  (core func (;13;) (canon resource.rep 3))
+  (core instance (;4;)
+    (export "r_drop" (func 11))
+    (export "r_new" (func 12))
+    (export "r_rep" (func 13))
+  )
+  (core func (;14;) (canon resource.drop 4))
+  (core func (;15;) (canon resource.new 4))
+  (core func (;16;) (canon resource.rep 4))
+  (core instance (;5;)
+    (export "r_drop" (func 14))
+    (export "r_new" (func 15))
+    (export "r_rep" (func 16))
+  )
+  (core instance (;6;) (instantiate 0
+      (with "cm32p2" (instance 1))
+      (with "cm32p2|ns:pkg/i@0.2" (instance 2))
+      (with "cm32p2|j" (instance 3))
+      (with "cm32p2|_ex_ns:pkg/i@0.2" (instance 4))
+      (with "cm32p2|_ex_j" (instance 5))
+    )
+  )
+  (alias core export 6 "cm32p2_memory" (core memory (;0;)))
+  (alias core export 0 "$imports" (core table (;0;)))
+  (alias core export 6 "cm32p2_realloc" (core func (;17;)))
+  (core func (;18;) (canon lower (func 0) (memory 0) (realloc 17) string-encoding=utf8))
+  (alias export 0 "[constructor]r" (func (;3;)))
+  (core func (;19;) (canon lower (func 3) (memory 0) string-encoding=utf8))
+  (alias export 0 "[method]r.m" (func (;4;)))
+  (core func (;20;) (canon lower (func 4) (memory 0) (realloc 17) string-encoding=utf8))
+  (alias export 1 "[constructor]r" (func (;5;)))
+  (core func (;21;) (canon lower (func 5) (memory 0) string-encoding=utf8))
+  (alias export 1 "[method]r.m" (func (;6;)))
+  (core func (;22;) (canon lower (func 6) (memory 0) (realloc 17) string-encoding=utf8))
+  (alias core export 6 "cm32p2|ns:pkg/i@0.2|r_dtor" (core func (;23;)))
+  (alias core export 6 "cm32p2|j|r_dtor" (core func (;24;)))
+  (core instance (;7;)
+    (export "$imports" (table 0))
+    (export "0" (func 18))
+    (export "1" (func 19))
+    (export "2" (func 20))
+    (export "3" (func 21))
+    (export "4" (func 22))
+    (export "5" (func 23))
+    (export "6" (func 24))
+  )
+  (core instance (;8;) (instantiate 2
+      (with "" (instance 7))
+    )
+  )
+  (alias core export 6 "cm32p2_initialize" (core func (;25;)))
+  (core module (;3;)
+    (type (;0;) (func))
+    (import "" "" (func (;0;) (type 0)))
+    (start 0)
+  )
+  (core instance (;9;)
+    (export "" (func 25))
+  )
+  (core instance (;10;) (instantiate 3
+      (with "" (instance 9))
+    )
+  )
+  (alias core export 6 "cm32p2||g" (core func (;26;)))
+  (alias core export 6 "cm32p2||g_post" (core func (;27;)))
+  (func (;7;) (type 2) (canon lift (core func 26) (memory 0) string-encoding=utf8 (post-return 27)))
+  (export (;8;) "g" (func 7))
+  (type (;7;) (own 3))
+  (type (;8;) (func (param "s" string) (result 7)))
+  (alias core export 6 "cm32p2|ns:pkg/i@0.2|[constructor]r" (core func (;28;)))
+  (func (;9;) (type 8) (canon lift (core func 28) (memory 0) (realloc 17) string-encoding=utf8))
+  (type (;9;) (borrow 3))
+  (type (;10;) (func (param "self" 9) (result string)))
+  (alias core export 6 "cm32p2|ns:pkg/i@0.2|[method]r.m" (core func (;29;)))
+  (func (;10;) (type 10) (canon lift (core func 29) (memory 0) string-encoding=utf8))
+  (type (;11;) (func (param "in" 7) (result 7)))
+  (alias core export 6 "cm32p2|ns:pkg/i@0.2|frob" (core func (;30;)))
+  (func (;11;) (type 11) (canon lift (core func 30)))
+  (component (;0;)
+    (import "import-type-r" (type (;0;) (sub resource)))
+    (type (;1;) (own 0))
+    (type (;2;) (func (param "s" string) (result 1)))
+    (import "import-constructor-r" (func (;0;) (type 2)))
+    (type (;3;) (borrow 0))
+    (type (;4;) (func (param "self" 3) (result string)))
+    (import "import-method-r-m" (func (;1;) (type 4)))
+    (type (;5;) (func (param "in" 1) (result 1)))
+    (import "import-func-frob" (func (;2;) (type 5)))
+    (export (;6;) "r" (type 0))
+    (type (;7;) (own 6))
+    (type (;8;) (func (param "s" string) (result 7)))
+    (export (;3;) "[constructor]r" (func 0) (func (type 8)))
+    (type (;9;) (borrow 6))
+    (type (;10;) (func (param "self" 9) (result string)))
+    (export (;4;) "[method]r.m" (func 1) (func (type 10)))
+    (type (;11;) (func (param "in" 7) (result 7)))
+    (export (;5;) "frob" (func 2) (func (type 11)))
+  )
+  (instance (;2;) (instantiate 0
+      (with "import-constructor-r" (func 9))
+      (with "import-method-r-m" (func 10))
+      (with "import-func-frob" (func 11))
+      (with "import-type-r" (type 3))
+    )
+  )
+  (export (;3;) "ns:pkg/i@0.2.1" (instance 2))
+  (type (;12;) (own 4))
+  (type (;13;) (func (param "s" string) (result 12)))
+  (alias core export 6 "cm32p2|j|[constructor]r" (core func (;31;)))
+  (func (;12;) (type 13) (canon lift (core func 31) (memory 0) (realloc 17) string-encoding=utf8))
+  (type (;14;) (borrow 4))
+  (type (;15;) (func (param "self" 14) (result string)))
+  (alias core export 6 "cm32p2|j|[method]r.m" (core func (;32;)))
+  (func (;13;) (type 15) (canon lift (core func 32) (memory 0) string-encoding=utf8))
+  (type (;16;) (func (param "in" 12) (result 12)))
+  (alias core export 6 "cm32p2|j|frob" (core func (;33;)))
+  (func (;14;) (type 16) (canon lift (core func 33)))
+  (component (;1;)
+    (import "import-type-r" (type (;0;) (sub resource)))
+    (type (;1;) (own 0))
+    (type (;2;) (func (param "s" string) (result 1)))
+    (import "import-constructor-r" (func (;0;) (type 2)))
+    (type (;3;) (borrow 0))
+    (type (;4;) (func (param "self" 3) (result string)))
+    (import "import-method-r-m" (func (;1;) (type 4)))
+    (type (;5;) (func (param "in" 1) (result 1)))
+    (import "import-func-frob" (func (;2;) (type 5)))
+    (export (;6;) "r" (type 0))
+    (type (;7;) (own 6))
+    (type (;8;) (func (param "s" string) (result 7)))
+    (export (;3;) "[constructor]r" (func 0) (func (type 8)))
+    (type (;9;) (borrow 6))
+    (type (;10;) (func (param "self" 9) (result string)))
+    (export (;4;) "[method]r.m" (func 1) (func (type 10)))
+    (type (;11;) (func (param "in" 7) (result 7)))
+    (export (;5;) "frob" (func 2) (func (type 11)))
+  )
+  (instance (;4;) (instantiate 1
+      (with "import-constructor-r" (func 12))
+      (with "import-method-r-m" (func 13))
+      (with "import-func-frob" (func 14))
+      (with "import-type-r" (type 4))
+    )
+  )
+  (export (;5;) "j" (instance 4))
+  (@producers
+    (processed-by "wit-component" "$CARGO_PKG_VERSION")
+  )
+)
diff --git a/crates/wit-component/tests/components/cm32-names/component.wit.print b/crates/wit-component/tests/components/cm32-names/component.wit.print
new file mode 100644
index 00000000..a01bff8d
--- /dev/null
+++ b/crates/wit-component/tests/components/cm32-names/component.wit.print
@@ -0,0 +1,25 @@
+package root:component;
+
+world root {
+  import ns:pkg/i@0.2.1;
+  import j: interface {
+    resource r {
+      constructor(s: string);
+      m: func() -> string;
+    }
+
+    frob: func(in: r) -> r;
+  }
+  import f: func() -> string;
+
+  export g: func() -> string;
+  export ns:pkg/i@0.2.1;
+  export j: interface {
+    resource r {
+      constructor(s: string);
+      m: func() -> string;
+    }
+
+    frob: func(in: r) -> r;
+  }
+}
diff --git a/crates/wit-component/tests/components/cm32-names/module.wat b/crates/wit-component/tests/components/cm32-names/module.wat
new file mode 100644
index 00000000..6b1b47b5
--- /dev/null
+++ b/crates/wit-component/tests/components/cm32-names/module.wat
@@ -0,0 +1,32 @@
+(module
+  (import "cm32p2" "f" (func (param i32)))
+  (import "cm32p2|ns:pkg/i@0.2" "[constructor]r" (func (param i32 i32) (result i32)))
+  (import "cm32p2|ns:pkg/i@0.2" "[method]r.m" (func (param i32 i32)))
+  (import "cm32p2|ns:pkg/i@0.2" "frob" (func (param i32) (result i32)))
+  (import "cm32p2|ns:pkg/i@0.2" "r_drop" (func (param i32)))
+  (import "cm32p2|j" "[constructor]r" (func (param i32 i32) (result i32)))
+  (import "cm32p2|j" "[method]r.m" (func (param i32 i32)))
+  (import "cm32p2|j" "frob" (func (param i32) (result i32)))
+  (import "cm32p2|j" "r_drop" (func (param i32)))
+  (import "cm32p2|_ex_ns:pkg/i@0.2" "r_drop" (func (param i32)))
+  (import "cm32p2|_ex_ns:pkg/i@0.2" "r_new" (func (param i32) (result i32)))
+  (import "cm32p2|_ex_ns:pkg/i@0.2" "r_rep" (func (param i32) (result i32)))
+  (import "cm32p2|_ex_j" "r_drop" (func (param i32)))
+  (import "cm32p2|_ex_j" "r_new" (func (param i32) (result i32)))
+  (import "cm32p2|_ex_j" "r_rep" (func (param i32) (result i32)))
+
+  (memory (export "cm32p2_memory") 0)
+
+  (func (export "cm32p2||g") (result i32) unreachable)
+  (func (export "cm32p2||g_post") (param i32) unreachable)
+  (func (export "cm32p2|ns:pkg/i@0.2|[constructor]r") (param i32 i32) (result i32) unreachable)
+  (func (export "cm32p2|ns:pkg/i@0.2|[method]r.m") (param i32) (result i32) unreachable)
+  (func (export "cm32p2|ns:pkg/i@0.2|frob") (param i32) (result i32) unreachable)
+  (func (export "cm32p2|ns:pkg/i@0.2|r_dtor") (param i32) unreachable)
+  (func (export "cm32p2|j|[constructor]r") (param i32 i32) (result i32) unreachable)
+  (func (export "cm32p2|j|[method]r.m") (param i32) (result i32) unreachable)
+  (func (export "cm32p2|j|frob") (param i32) (result i32) unreachable)
+  (func (export "cm32p2|j|r_dtor") (param i32) unreachable)
+  (func (export "cm32p2_realloc") (param i32 i32 i32 i32) (result i32) unreachable)
+  (func (export "cm32p2_initialize"))
+)
diff --git a/crates/wit-component/tests/components/cm32-names/module.wit b/crates/wit-component/tests/components/cm32-names/module.wit
new file mode 100644
index 00000000..32d8820e
--- /dev/null
+++ b/crates/wit-component/tests/components/cm32-names/module.wit
@@ -0,0 +1,30 @@
+package ns:pkg@0.2.1;
+
+interface i {
+  resource r {
+    constructor(s: string);
+    m: func() -> string;
+  }
+  frob: func(in: r) -> r;
+}
+
+world module {
+  import f: func() -> string;
+  import i;
+  import j: interface {
+    resource r {
+      constructor(s: string);
+      m: func() -> string;
+    }
+    frob: func(in: r) -> r;
+  }
+  export g: func() -> string;
+  export i;
+  export j: interface {
+    resource r {
+      constructor(s: string);
+      m: func() -> string;
+    }
+    frob: func(in: r) -> r;
+  }
+}
diff --git a/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt
index e223246a..d8e5eafd 100644
--- a/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt
+++ b/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt
@@ -1,1 +1,1 @@
-failed to decode world from module: module was not valid: failed to validate export for `a`: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []`
\ No newline at end of file
+failed to decode world from module: module was not valid: failed to classify export `a`: failed to validate export for `a`: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []`
\ No newline at end of file
diff --git a/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt
index 548e42b2..da7e08ea 100644
--- a/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt
+++ b/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt
@@ -1,1 +1,1 @@
-failed to decode world from module: module was not valid: failed to validate export for `foo`: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []`
\ No newline at end of file
+failed to decode world from module: module was not valid: failed to classify export `foo#a`: failed to validate export for `foo`: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []`
\ No newline at end of file
diff --git a/tests/cli/embed-dummy.wit b/tests/cli/embed-dummy.wit
new file mode 100644
index 00000000..ff256eff
--- /dev/null
+++ b/tests/cli/embed-dummy.wit
@@ -0,0 +1,13 @@
+// RUN[legacy]: component embed -t --dummy-names legacy % | strip -t
+// RUN[standard32]: component embed -t --dummy-names standard32 % | strip -t
+
+package a:b;
+
+interface x {
+  y: func() -> string;
+}
+
+world w {
+  import x;
+  export x;
+}
diff --git a/tests/cli/embed-dummy.wit.legacy.stdout b/tests/cli/embed-dummy.wit.legacy.stdout
new file mode 100644
index 00000000..43af3e09
--- /dev/null
+++ b/tests/cli/embed-dummy.wit.legacy.stdout
@@ -0,0 +1,21 @@
+(module
+  (type (;0;) (func (param i32)))
+  (type (;1;) (func (result i32)))
+  (type (;2;) (func (param i32 i32 i32 i32) (result i32)))
+  (type (;3;) (func))
+  (import "a:b/x" "y" (func (;0;) (type 0)))
+  (memory (;0;) 0)
+  (export "a:b/x#y" (func 1))
+  (export "cabi_post_a:b/x#y" (func 2))
+  (export "memory" (memory 0))
+  (export "cabi_realloc" (func 3))
+  (export "_initialize" (func 4))
+  (func (;1;) (type 1) (result i32)
+    unreachable
+  )
+  (func (;2;) (type 0) (param i32))
+  (func (;3;) (type 2) (param i32 i32 i32 i32) (result i32)
+    unreachable
+  )
+  (func (;4;) (type 3))
+)
diff --git a/tests/cli/embed-dummy.wit.standard32.stdout b/tests/cli/embed-dummy.wit.standard32.stdout
new file mode 100644
index 00000000..7b874d82
--- /dev/null
+++ b/tests/cli/embed-dummy.wit.standard32.stdout
@@ -0,0 +1,21 @@
+(module
+  (type (;0;) (func (param i32)))
+  (type (;1;) (func (result i32)))
+  (type (;2;) (func (param i32 i32 i32 i32) (result i32)))
+  (type (;3;) (func))
+  (import "cm32p2|a:b/x" "y" (func (;0;) (type 0)))
+  (memory (;0;) 0)
+  (export "cm32p2|a:b/x|y" (func 1))
+  (export "cm32p2|a:b/x|y_post" (func 2))
+  (export "cm32p2_memory" (memory 0))
+  (export "cm32p2_realloc" (func 3))
+  (export "cm32p2_initialize" (func 4))
+  (func (;1;) (type 1) (result i32)
+    unreachable
+  )
+  (func (;2;) (type 0) (param i32))
+  (func (;3;) (type 2) (param i32 i32 i32 i32) (result i32)
+    unreachable
+  )
+  (func (;4;) (type 3))
+)
diff --git a/tests/cli/reject-legacy-names.wit b/tests/cli/reject-legacy-names.wit
new file mode 100644
index 00000000..2cc55e51
--- /dev/null
+++ b/tests/cli/reject-legacy-names.wit
@@ -0,0 +1,8 @@
+// FAIL: component embed % --dummy-names legacy | component new --reject-legacy-names
+
+package a:b;
+
+world foo {
+  export f: func();
+  import y: func();
+}
diff --git a/tests/cli/reject-legacy-names.wit.stderr b/tests/cli/reject-legacy-names.wit.stderr
new file mode 100644
index 00000000..f4b37ce1
--- /dev/null
+++ b/tests/cli/reject-legacy-names.wit.stderr
@@ -0,0 +1,7 @@
+error: failed to encode a component from module
+
+Caused by:
+    0: failed to decode world from module
+    1: module was not valid
+    2: failed to resolve import `$root::y`
+    3: unknown or invalid component model import syntax
diff --git a/tests/cli/semver-check-add-export.wit.stderr b/tests/cli/semver-check-add-export.wit.stderr
index e7391d96..76f4a07f 100644
--- a/tests/cli/semver-check-add-export.wit.stderr
+++ b/tests/cli/semver-check-add-export.wit.stderr
@@ -2,4 +2,4 @@ error: new world is not semver-compatible with the previous world
 
 Caused by:
     0: type mismatch for import `new`
-       missing export named `a` (at offset 0xf0)
+       missing export named `a` (at offset 0x15a)
diff --git a/tests/cli/semver-check-remove-import.wit.stderr b/tests/cli/semver-check-remove-import.wit.stderr
index 339e7552..8e588913 100644
--- a/tests/cli/semver-check-remove-import.wit.stderr
+++ b/tests/cli/semver-check-remove-import.wit.stderr
@@ -2,4 +2,4 @@ error: new world is not semver-compatible with the previous world
 
 Caused by:
     0: type mismatch for import `new`
-       missing import named `a` (at offset 0x119)
+       missing import named `a` (at offset 0x182)
diff --git a/tests/local/folding/fold-unfoldable-if.wat b/tests/local/folding/fold-unfoldable-if.wat
new file mode 100644
index 00000000..dfc752a6
--- /dev/null
+++ b/tests/local/folding/fold-unfoldable-if.wat
@@ -0,0 +1,9 @@
+(module
+  (func
+    i32.const 0
+    try_table (param i32)
+      if
+      end
+    end
+  )
+)
diff --git a/tests/snapshots/local/folding/fold-unfoldable-if.wat.print b/tests/snapshots/local/folding/fold-unfoldable-if.wat.print
new file mode 100644
index 00000000..1a2e5650
--- /dev/null
+++ b/tests/snapshots/local/folding/fold-unfoldable-if.wat.print
@@ -0,0 +1,11 @@
+(module
+  (type (;0;) (func))
+  (type (;1;) (func (param i32)))
+  (func (;0;) (type 0)
+    i32.const 0
+    try_table (type 1) (param i32) ;; label = @1
+      if ;; label = @2
+      end
+    end
+  )
+)
diff --git a/tests/snapshots/local/folding/fold-unfoldable-if.wat.print-folded b/tests/snapshots/local/folding/fold-unfoldable-if.wat.print-folded
new file mode 100644
index 00000000..7c220e5c
--- /dev/null
+++ b/tests/snapshots/local/folding/fold-unfoldable-if.wat.print-folded
@@ -0,0 +1,10 @@
+(module
+  (type (;0;) (func))
+  (type (;1;) (func (param i32)))
+  (func (;0;) (type 0)
+    (i32.const 0)
+    (try_table (type 1) (param i32) ;; label = @1
+      (if ;; label = @2
+        (then)))
+  )
+)