Repository: wasmerio/wasmer (language: rust)

Issue:
Expose the size of an Artifact
We need to analyze the size that an Artifact will take in Memory. We could consider using loupe again.

Here's the PR removing loupe as it may be useful for this task: 

[Remove loupe dep for wasmer 3.0 by epilys · Pull Request #2868 · wasmerio/wasmer](https://github.com/wasmerio/wasmer/pull/2868)

We'll need to return how much memory the `AllocatedArtifact` + `CompileModuleInfo` take


Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 275ca45fd7a..65725cf9991 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2856,6 +2856,27 @@ dependencies = [
  "logos-codegen",
 ]
 
+[[package]]
+name = "loupe"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d"
+dependencies = [
+ "indexmap 1.9.3",
+ "loupe-derive",
+ "rustversion",
+]
+
+[[package]]
+name = "loupe-derive"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "lz4_flex"
 version = "0.11.3"
@@ -6396,6 +6417,7 @@ dependencies = [
  "hashbrown 0.11.2",
  "indexmap 1.9.3",
  "js-sys",
+ "loupe",
  "macro-wasmer-universal-test",
  "more-asserts",
  "rustc-demangle",
@@ -6667,6 +6689,7 @@ dependencies = [
  "lazy_static",
  "leb128",
  "libc",
+ "loupe",
  "memmap2 0.6.2",
  "more-asserts",
  "region",
@@ -7026,6 +7049,7 @@ dependencies = [
  "getrandom",
  "hex",
  "indexmap 1.9.3",
+ "loupe",
  "memoffset 0.9.1",
  "more-asserts",
  "rkyv",
@@ -7053,6 +7077,7 @@ dependencies = [
  "indexmap 1.9.3",
  "lazy_static",
  "libc",
+ "loupe",
  "mach2",
  "memoffset 0.9.1",
  "more-asserts",
diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml
index 5eeb1685e66..a0b2b515180 100644
--- a/lib/api/Cargo.toml
+++ b/lib/api/Cargo.toml
@@ -35,6 +35,10 @@ tracing = { version = "0.1" }
 wat = { version = "=1.0.71", optional = true }
 rustc-demangle = "0.1"
 shared-buffer = { workspace = true }
+loupe = { version = "0.1.3", optional = true, features = [
+	"indexmap",
+	"enable-indexmap",
+] }
 
 # Dependencies and Development Dependencies for `sys`.
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -67,7 +71,9 @@ macro-wasmer-universal-test = { version = "4.3.7", path = "./macro-wasmer-univer
 # Dependencies and Develoment Dependencies for `js`.
 [target.'cfg(target_arch = "wasm32")'.dependencies]
 # - Mandatory dependencies for `js`.
-wasmer-types = { path = "../types", version = "=4.3.7", default-features = false, features = ["std"] }
+wasmer-types = { path = "../types", version = "=4.3.7", default-features = false, features = [
+	"std",
+] }
 wasm-bindgen = "0.2.74"
 js-sys = "0.3.51"
 wasmer-derive = { path = "../derive", version = "=4.3.7" }
@@ -99,6 +105,11 @@ default = ["sys-default"]
 # default = ["js-default"]
 std = []
 core = ["hashbrown"]
+artifact-size = [
+	"dep:loupe",
+	"wasmer-vm/artifact-size",
+	"wasmer-compiler/artifact-size",
+]
 
 # Features for `sys`.
 sys = ["wasmer-compiler/translator", "wasmer-compiler/compiler", "std"]
@@ -125,9 +136,9 @@ js-serializable-module = []
 
 # Optional
 enable-serde = [
-  "wasmer-vm/enable-serde",
-  "wasmer-compiler/enable-serde",
-  "wasmer-types/enable-serde",
+	"wasmer-vm/enable-serde",
+	"wasmer-compiler/enable-serde",
+	"wasmer-types/enable-serde",
 ]
 
 wasmer-artifact-load = ["wasmer-compiler/wasmer-artifact-load"]
@@ -137,17 +148,17 @@ static-artifact-create = ["wasmer-compiler/static-artifact-create"]
 
 [package.metadata.docs.rs]
 features = [
-  "compiler",
-  "core",
-  "cranelift",
-  "engine",
-  "jit",
-  "singlepass",
-  "static-artifact-create",
-  "static-artifact-load",
-  "sys",
-  "sys-default",
-  "wasmer-artifact-create",
-  "wasmer-artifact-load",
+	"compiler",
+	"core",
+	"cranelift",
+	"engine",
+	"jit",
+	"singlepass",
+	"static-artifact-create",
+	"static-artifact-load",
+	"sys",
+	"sys-default",
+	"wasmer-artifact-create",
+	"wasmer-artifact-load",
 ]
 rustc-args = ["--cfg", "docsrs"]
diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs
index d2f821145f2..b242ff81336 100644
--- a/lib/api/src/exports.rs
+++ b/lib/api/src/exports.rs
@@ -58,6 +58,7 @@ pub enum ExportError {
 ///
 /// TODO: add examples of using exports
 #[derive(Clone, Default, PartialEq, Eq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Exports {
     map: IndexMap<String, Extern>,
 }
diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs
index 70d18c3ca48..b351b3f545d 100644
--- a/lib/api/src/externals/function.rs
+++ b/lib/api/src/externals/function.rs
@@ -84,6 +84,7 @@ mod private {
 ///   result in a panic.
 ///   [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
 #[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Function(pub(crate) function_impl::Function);
 
 impl Function {
diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs
index 3420562ff46..5021fbf09e0 100644
--- a/lib/api/src/externals/global.rs
+++ b/lib/api/src/externals/global.rs
@@ -22,6 +22,7 @@ use crate::sys::externals::global as global_impl;
 ///
 /// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
 #[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Global(pub(crate) global_impl::Global);
 
 impl Global {
diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs
index 3e2b07efa22..5c53b81d54c 100644
--- a/lib/api/src/externals/memory.rs
+++ b/lib/api/src/externals/memory.rs
@@ -30,6 +30,7 @@ use wasmer_types::{MemoryError, Pages};
 ///
 /// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
 #[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Memory(pub(crate) memory_impl::Memory);
 
 impl Memory {
diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs
index c5b46e8972c..462c928c5d3 100644
--- a/lib/api/src/externals/mod.rs
+++ b/lib/api/src/externals/mod.rs
@@ -28,6 +28,7 @@ use crate::store::{AsStoreMut, AsStoreRef};
 ///
 /// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#external-values>
 #[derive(Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub enum Extern {
     /// A external [`Function`].
     Function(Function),
diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs
index 49eb38924f8..4253ce0857b 100644
--- a/lib/api/src/externals/table.rs
+++ b/lib/api/src/externals/table.rs
@@ -23,6 +23,7 @@ use crate::Value;
 ///
 /// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
 #[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Table(pub(crate) table_impl::Table);
 
 impl Table {
diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs
old mode 100755
new mode 100644
diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs
index 52bf98ae30b..60b5e347af8 100644
--- a/lib/api/src/module.rs
+++ b/lib/api/src/module.rs
@@ -42,6 +42,7 @@ pub enum IoCompileError {
 /// Cloning a module is cheap: it does a shallow copy of the compiled
 /// contents rather than a deep copy.
 #[derive(Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Module(pub(crate) module_imp::Module);
 
 impl Module {
diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs
index 41c292f90cb..a6adcceb9a8 100644
--- a/lib/api/src/sys/externals/function.rs
+++ b/lib/api/src/sys/externals/function.rs
@@ -13,6 +13,7 @@ use wasmer_vm::{
     VMFunction, VMFunctionContext, VMFunctionKind, VMTrampoline,
 };
 
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Function {
     pub(crate) handle: StoreHandle<VMFunction>,
diff --git a/lib/api/src/sys/externals/global.rs b/lib/api/src/sys/externals/global.rs
index 7b5accdbe24..8e159c7c36d 100644
--- a/lib/api/src/sys/externals/global.rs
+++ b/lib/api/src/sys/externals/global.rs
@@ -7,6 +7,7 @@ use crate::Mutability;
 use wasmer_vm::{StoreHandle, VMExtern, VMGlobal};
 
 #[derive(Debug, Clone)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Global {
     handle: StoreHandle<VMGlobal>,
 }
diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs
index b61adc4ff68..a3b4f38953f 100644
--- a/lib/api/src/sys/externals/memory.rs
+++ b/lib/api/src/sys/externals/memory.rs
@@ -19,6 +19,7 @@ use crate::{
 };
 
 #[derive(Debug, Clone)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Memory {
     pub(crate) handle: StoreHandle<VMMemory>,
 }
diff --git a/lib/api/src/sys/externals/table.rs b/lib/api/src/sys/externals/table.rs
index aba68442415..285135dfd2a 100644
--- a/lib/api/src/sys/externals/table.rs
+++ b/lib/api/src/sys/externals/table.rs
@@ -6,6 +6,7 @@ use crate::{vm::VMExternTable, ExternRef, Function, RuntimeError};
 use wasmer_vm::{StoreHandle, TableElement, Trap, VMExtern, VMTable};
 
 #[derive(Debug, Clone)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Table {
     handle: StoreHandle<VMTable>,
 }
diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs
index 3aae35d02ed..c4030c950c2 100644
--- a/lib/api/src/sys/module.rs
+++ b/lib/api/src/sys/module.rs
@@ -14,6 +14,7 @@ use crate::{
 };
 
 #[derive(Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Module {
     // The field ordering here is actually significant because of the drop
     // order: we want to drop the artifact before dropping the engine.
diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml
index 29cee1f45c3..fbd94b3414f 100644
--- a/lib/compiler/Cargo.toml
+++ b/lib/compiler/Cargo.toml
@@ -23,6 +23,11 @@ thiserror = "1.0"
 serde_bytes = { version = "0.11", optional = true }
 smallvec = "1.6"
 xxhash-rust = { version = "0.8.10", features = ["xxh64"] }
+loupe = { version = "0.1.3", optional = true, features = [
+	"indexmap",
+	"enable-indexmap",
+] }
+
 
 backtrace = "0.3"
 memmap2 = "0.6"
@@ -44,7 +49,9 @@ wasmer-vm = { path = "../vm", version = "=4.3.7" }
 region = { version = "3.0" }
 
 [target.'cfg(target_os = "windows")'.dependencies]
-windows-sys = { version = "0.59", features = ["Win32_System_Diagnostics_Debug"] }
+windows-sys = { version = "0.59", features = [
+	"Win32_System_Diagnostics_Debug",
+] }
 
 [features]
 default = ["std"]
@@ -60,15 +67,16 @@ static-artifact-create = ["wasmer-object"]
 std = ["wasmer-types/std"]
 core = ["hashbrown", "wasmer-types/core"]
 enable-serde = ["serde", "serde_bytes", "wasmer-types/enable-serde"]
+artifact-size = ["dep:loupe"]
 
 [badges]
 maintenance = { status = "experimental" }
 
 [package.metadata.docs.rs]
 features = [
-    "static-artifact-create",
-    "static-artifact-load",
-    "wasmer-artifact-create",
-    "wasmer-artifact-load",
+	"static-artifact-create",
+	"static-artifact-load",
+	"wasmer-artifact-create",
+	"wasmer-artifact-load",
 ]
 rustc-args = ["--cfg", "docsrs"]
diff --git a/lib/compiler/src/artifact_builders/artifact_builder.rs b/lib/compiler/src/artifact_builders/artifact_builder.rs
index 03ecc47b7c8..13fe0659239 100644
--- a/lib/compiler/src/artifact_builders/artifact_builder.rs
+++ b/lib/compiler/src/artifact_builders/artifact_builder.rs
@@ -34,6 +34,7 @@ use wasmer_types::{
 use wasmer_types::{MetadataHeader, SerializeError};
 
 /// A compiled wasm module, ready to be instantiated.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct ArtifactBuild {
     serializable: SerializableModule,
 }
@@ -287,8 +288,16 @@ self_cell!(
     impl {Debug}
 );
 
+#[cfg(feature = "artifact-size")]
+impl loupe::MemoryUsage for ArtifactBuildFromArchiveCell {
+    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        std::mem::size_of_val(self.borrow_owner()) + std::mem::size_of_val(self.borrow_dependent())
+    }
+}
+
 /// A compiled wasm module that was loaded from a serialized archive.
 #[derive(Clone, Debug)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct ArtifactBuildFromArchive {
     cell: Arc<ArtifactBuildFromArchiveCell>,
 
diff --git a/lib/compiler/src/engine/artifact.rs b/lib/compiler/src/engine/artifact.rs
index 0864abf46c9..1c2d5393c2d 100644
--- a/lib/compiler/src/engine/artifact.rs
+++ b/lib/compiler/src/engine/artifact.rs
@@ -44,6 +44,7 @@ use wasmer_types::{SerializableModule, SerializeError};
 use wasmer_vm::{FunctionBodyPtr, MemoryStyle, TableStyle, VMSharedSignatureIndex, VMTrampoline};
 use wasmer_vm::{InstanceAllocator, StoreObjects, TrapHandlerFn, VMConfig, VMExtern, VMInstance};
 
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct AllocatedArtifact {
     // This shows if the frame info has been regestered already or not.
     // Because the 'GlobalFrameInfoRegistration' ownership can be transfered to EngineInner
@@ -55,6 +56,8 @@ pub struct AllocatedArtifact {
     // so the GloabelFrameInfo and MMap stays in sync and get dropped at the same time
     frame_info_registration: Option<GlobalFrameInfoRegistration>,
     finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
+
+    #[cfg_attr(feature = "artifact-size", loupe(skip))]
     finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
     finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
     signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
@@ -62,6 +65,7 @@ pub struct AllocatedArtifact {
 }
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[repr(transparent)]
 /// A unique identifier for an Artifact.
 pub struct ArtifactId {
@@ -91,6 +95,7 @@ impl Default for ArtifactId {
 }
 
 /// A compiled wasm module, ready to be instantiated.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct Artifact {
     id: ArtifactId,
     artifact: ArtifactBuildVariant,
@@ -102,6 +107,7 @@ pub struct Artifact {
 /// Artifacts may be created as the result of the compilation of a wasm
 /// module, corresponding to `ArtifactBuildVariant::Plain`, or loaded
 /// from an archive, corresponding to `ArtifactBuildVariant::Archived`.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub enum ArtifactBuildVariant {
     Plain(ArtifactBuild),
     Archived(ArtifactBuildFromArchive),
diff --git a/lib/compiler/src/engine/trap/frame_info.rs b/lib/compiler/src/engine/trap/frame_info.rs
index f09dae724a9..58635a91627 100644
--- a/lib/compiler/src/engine/trap/frame_info.rs
+++ b/lib/compiler/src/engine/trap/frame_info.rs
@@ -54,6 +54,7 @@ pub struct GlobalFrameInfo {
 
 /// An RAII structure used to unregister a module's frame information when the
 /// module is destroyed.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct GlobalFrameInfoRegistration {
     /// The key that will be removed from the global `ranges` map when this is
     /// dropped.
diff --git a/lib/types/Cargo.toml b/lib/types/Cargo.toml
index d36bb7fafd0..ccc41f73b39 100644
--- a/lib/types/Cargo.toml
+++ b/lib/types/Cargo.toml
@@ -13,7 +13,10 @@ rust-version.workspace = true
 version.workspace = true
 
 [dependencies]
-serde = { version = "1.0", features = ["derive", "rc"], optional = true, default-features = false }
+serde = { version = "1.0", features = [
+	"derive",
+	"rc",
+], optional = true, default-features = false }
 serde_bytes = { version = "0.11", optional = true }
 thiserror = "1.0"
 more-asserts = "0.2"
@@ -26,6 +29,8 @@ bytecheck = "0.6.8"
 xxhash-rust = { version = "0.8.8", features = ["xxh64"] }
 sha2 = { version = "0.10" }
 hex = { version = "^0.4" }
+loupe = { version = "0.1.3", optional = true }
+
 
 # `rand` uses `getrandom` transitively, and to be able to
 # compile the project for `js`, we need to enable this feature
@@ -41,6 +46,7 @@ default = ["std"]
 std = []
 core = []
 enable-serde = ["serde", "serde/std", "serde_bytes", "indexmap/serde-1"]
+artifact-size = ["dep:loupe"]
 
 [package.metadata.docs.rs]
 rustc-args = ["--cfg", "docsrs"]
diff --git a/lib/types/src/compilation/address_map.rs b/lib/types/src/compilation/address_map.rs
index 0fee3ccd217..0081d60bc6e 100644
--- a/lib/types/src/compilation/address_map.rs
+++ b/lib/types/src/compilation/address_map.rs
@@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
 
 /// Single source location to generated address mapping.
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, Copy, PartialEq, Eq)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub struct InstructionAddressMap {
@@ -23,6 +24,7 @@ pub struct InstructionAddressMap {
 }
 
 /// Function and its instructions addresses mappings.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq, Default)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
diff --git a/lib/types/src/compilation/function.rs b/lib/types/src/compilation/function.rs
index aabf1195674..a916f4fbb3b 100644
--- a/lib/types/src/compilation/function.rs
+++ b/lib/types/src/compilation/function.rs
@@ -22,6 +22,7 @@ use super::unwind::CompiledFunctionUnwindInfoLike;
 ///
 /// This structure is only used for reconstructing
 /// the frame information after a `Trap`.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq, Default)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
@@ -37,6 +38,7 @@ pub struct CompiledFunctionFrameInfo {
 
 /// The function body.
 #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub struct FunctionBody {
@@ -116,6 +118,7 @@ pub type CustomSections = PrimaryMap<SectionIndex, CustomSection>;
 /// In the future this structure may also hold other information useful
 /// for debugging.
 #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(
     RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Debug, PartialEq, Eq, Clone,
 )]
diff --git a/lib/types/src/compilation/module.rs b/lib/types/src/compilation/module.rs
index 43be092d271..cda598943ee 100644
--- a/lib/types/src/compilation/module.rs
+++ b/lib/types/src/compilation/module.rs
@@ -12,6 +12,7 @@ use std::sync::Arc;
 /// possible after translation (such as the features used for compiling,
 /// or the `MemoryStyle` and `TableStyle`).
 #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(Debug, Clone, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub struct CompileModuleInfo {
diff --git a/lib/types/src/compilation/relocation.rs b/lib/types/src/compilation/relocation.rs
index 0b1b1331a10..15294c79aad 100644
--- a/lib/types/src/compilation/relocation.rs
+++ b/lib/types/src/compilation/relocation.rs
@@ -20,6 +20,7 @@ use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
 use serde::{Deserialize, Serialize};
 
 /// Relocation kinds for every ISA.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 #[derive(
     RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Copy, Clone, Debug, PartialEq, Eq,
@@ -92,6 +93,7 @@ impl fmt::Display for RelocationKind {
 
 /// A record of a relocation to perform.
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub struct Relocation {
@@ -211,6 +213,7 @@ impl RelocationLike for ArchivedRelocation {
 
 /// Destination function. Can be either user function or some special one, like `memory.grow`.
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(
     RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Debug, Copy, Clone, PartialEq, Eq,
 )]
diff --git a/lib/types/src/compilation/section.rs b/lib/types/src/compilation/section.rs
index 14d97f34600..1f0f7b70dea 100644
--- a/lib/types/src/compilation/section.rs
+++ b/lib/types/src/compilation/section.rs
@@ -29,6 +29,7 @@ use serde::{Deserialize, Serialize};
     Default,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct SectionIndex(u32);
 
@@ -37,6 +38,7 @@ entity_impl!(SectionIndex);
 /// Custom section Protection.
 ///
 /// Determines how a custom section may be used.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 #[derive(
     RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Debug, Clone, PartialEq, Eq,
@@ -56,6 +58,7 @@ pub enum CustomSectionProtection {
 /// This is used so compilers can store arbitrary information
 /// in the emitted module.
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub struct CustomSection {
@@ -118,6 +121,7 @@ impl<'a> CustomSectionLike<'a> for ArchivedCustomSection {
 
 /// The bytes in the section.
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq, Default)]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub struct SectionBody(#[cfg_attr(feature = "enable-serde", serde(with = "serde_bytes"))] Vec<u8>);
diff --git a/lib/types/src/compilation/unwind.rs b/lib/types/src/compilation/unwind.rs
index 0dae88d9cb6..0747eef9bfb 100644
--- a/lib/types/src/compilation/unwind.rs
+++ b/lib/types/src/compilation/unwind.rs
@@ -19,6 +19,7 @@ use serde::{Deserialize, Serialize};
 /// [unwind info]: https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=vs-2019
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive_attr(derive(rkyv::CheckBytes, Debug))]
 pub enum CompiledFunctionUnwindInfo {
     /// Windows UNWIND_INFO.
diff --git a/lib/types/src/entity/boxed_slice.rs b/lib/types/src/entity/boxed_slice.rs
index eca12d89185..704457eb495 100644
--- a/lib/types/src/entity/boxed_slice.rs
+++ b/lib/types/src/entity/boxed_slice.rs
@@ -24,6 +24,22 @@ where
     unused: PhantomData<K>,
 }
 
+#[cfg(feature = "artifact-size")]
+impl<K, V> loupe::MemoryUsage for BoxedSlice<K, V>
+where
+    K: EntityRef,
+    V: loupe::MemoryUsage,
+{
+    fn size_of_val(&self, tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        std::mem::size_of_val(self)
+            + self
+                .elems
+                .iter()
+                .map(|value| value.size_of_val(tracker) - std::mem::size_of_val(value))
+                .sum::<usize>()
+    }
+}
+
 impl<K, V> BoxedSlice<K, V>
 where
     K: EntityRef,
diff --git a/lib/types/src/entity/primary_map.rs b/lib/types/src/entity/primary_map.rs
index a810791331e..f1d79ada8a3 100644
--- a/lib/types/src/entity/primary_map.rs
+++ b/lib/types/src/entity/primary_map.rs
@@ -43,6 +43,22 @@ where
     pub(crate) unused: PhantomData<K>,
 }
 
+#[cfg(feature = "artifact-size")]
+impl<K, V> loupe::MemoryUsage for PrimaryMap<K, V>
+where
+    K: EntityRef,
+    V: loupe::MemoryUsage,
+{
+    fn size_of_val(&self, tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        std::mem::size_of_val(self)
+            + self
+                .elems
+                .iter()
+                .map(|value| value.size_of_val(tracker) - std::mem::size_of_val(value))
+                .sum::<usize>()
+    }
+}
+
 impl<K, V> PrimaryMap<K, V>
 where
     K: EntityRef,
diff --git a/lib/types/src/entity/secondary_map.rs b/lib/types/src/entity/secondary_map.rs
index 554bc4278ae..03d8367e041 100644
--- a/lib/types/src/entity/secondary_map.rs
+++ b/lib/types/src/entity/secondary_map.rs
@@ -39,6 +39,22 @@ where
     pub(crate) unused: PhantomData<K>,
 }
 
+#[cfg(feature = "artifact-size")]
+impl<K, V> loupe::MemoryUsage for SecondaryMap<K, V>
+where
+    K: EntityRef,
+    V: Clone + loupe::MemoryUsage,
+{
+    fn size_of_val(&self, tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        std::mem::size_of_val(self)
+            + self
+                .elems
+                .iter()
+                .map(|value| value.size_of_val(tracker) - std::mem::size_of_val(value))
+                .sum::<usize>()
+    }
+}
+
 /// Shared `SecondaryMap` implementation for all value types.
 impl<K, V> SecondaryMap<K, V>
 where
diff --git a/lib/types/src/features.rs b/lib/types/src/features.rs
index 54197762db5..4d7591a753c 100644
--- a/lib/types/src/features.rs
+++ b/lib/types/src/features.rs
@@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
 /// [WebAssembly proposal]: https://github.com/WebAssembly/proposals
 #[derive(Clone, Debug, Eq, PartialEq, rkyv::CheckBytes)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive(as = "Self")]
 pub struct Features {
diff --git a/lib/types/src/indexes.rs b/lib/types/src/indexes.rs
index 3bf3883f3f1..e4cd6116e61 100644
--- a/lib/types/src/indexes.rs
+++ b/lib/types/src/indexes.rs
@@ -21,18 +21,21 @@ use serde::{Deserialize, Serialize};
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct LocalFunctionIndex(u32);
 entity_impl!(LocalFunctionIndex);
 
 /// Index type of a table defined locally inside the WebAssembly module.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 pub struct LocalTableIndex(u32);
 entity_impl!(LocalTableIndex);
 
 /// Index type of a memory defined locally inside the WebAssembly module.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 pub struct LocalMemoryIndex(u32);
 entity_impl!(LocalMemoryIndex);
@@ -53,6 +56,7 @@ entity_impl!(LocalMemoryIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct LocalGlobalIndex(u32);
 entity_impl!(LocalGlobalIndex);
@@ -73,6 +77,7 @@ entity_impl!(LocalGlobalIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct FunctionIndex(u32);
 entity_impl!(FunctionIndex);
@@ -93,6 +98,7 @@ entity_impl!(FunctionIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct TableIndex(u32);
 entity_impl!(TableIndex);
@@ -113,6 +119,7 @@ entity_impl!(TableIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct GlobalIndex(u32);
 entity_impl!(GlobalIndex);
@@ -133,6 +140,7 @@ entity_impl!(GlobalIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct MemoryIndex(u32);
 entity_impl!(MemoryIndex);
@@ -153,6 +161,7 @@ entity_impl!(MemoryIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct SignatureIndex(u32);
 entity_impl!(SignatureIndex);
@@ -173,6 +182,7 @@ entity_impl!(SignatureIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct DataIndex(u32);
 entity_impl!(DataIndex);
@@ -193,6 +203,7 @@ entity_impl!(DataIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct ElemIndex(u32);
 entity_impl!(ElemIndex);
@@ -213,6 +224,7 @@ entity_impl!(ElemIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct CustomSectionIndex(u32);
 entity_impl!(CustomSectionIndex);
@@ -233,6 +245,7 @@ entity_impl!(CustomSectionIndex);
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 #[repr(u8)]
 pub enum ExportIndex {
@@ -261,6 +274,7 @@ pub enum ExportIndex {
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 #[repr(u8)]
 pub enum ImportIndex {
diff --git a/lib/types/src/initializers.rs b/lib/types/src/initializers.rs
index 4c8f177d94b..f29934a415b 100644
--- a/lib/types/src/initializers.rs
+++ b/lib/types/src/initializers.rs
@@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
 /// A WebAssembly table initializer.
 #[derive(Clone, Debug, Hash, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct TableInitializer {
     /// The index of a table to initialize.
@@ -24,6 +25,7 @@ pub struct TableInitializer {
 /// A memory index and offset within that memory where a data initialization
 /// should be performed.
 #[derive(Clone, Debug, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct DataInitializerLocation {
@@ -91,6 +93,7 @@ pub struct DataInitializer<'data> {
 /// holding a reference to it
 #[derive(Debug, Clone, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct OwnedDataInitializer {
     /// The location where the initialization is to be performed.
diff --git a/lib/types/src/libcalls.rs b/lib/types/src/libcalls.rs
index 21222c588d6..67c999b9307 100644
--- a/lib/types/src/libcalls.rs
+++ b/lib/types/src/libcalls.rs
@@ -21,6 +21,7 @@ use std::fmt;
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 #[repr(u16)]
 pub enum LibCall {
diff --git a/lib/types/src/memory.rs b/lib/types/src/memory.rs
index 5999f0c11c3..4896477a22e 100644
--- a/lib/types/src/memory.rs
+++ b/lib/types/src/memory.rs
@@ -21,6 +21,7 @@ use std::ops::{Add, AddAssign};
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 #[repr(u8)]
 pub enum MemoryStyle {
diff --git a/lib/types/src/module.rs b/lib/types/src/module.rs
index 5ddea198a5a..ea77fe8d5f4 100644
--- a/lib/types/src/module.rs
+++ b/lib/types/src/module.rs
@@ -27,6 +27,7 @@ use std::iter::ExactSizeIterator;
 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 
 #[derive(Debug, Clone, RkyvSerialize, RkyvDeserialize, Archive)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct ModuleId {
     id: usize,
@@ -106,6 +107,7 @@ mod serde_imports {
 /// to make sure we don't break compatibility between versions.
 #[derive(Debug, Clone, Default)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct ModuleInfo {
     /// A unique identifier (within this process) for this module.
     ///
diff --git a/lib/types/src/module_hash.rs b/lib/types/src/module_hash.rs
index 7c4e967f599..38966dba8e6 100644
--- a/lib/types/src/module_hash.rs
+++ b/lib/types/src/module_hash.rs
@@ -38,6 +38,16 @@ pub enum ModuleHash {
     Sha256([u8; 32]),
 }
 
+#[cfg(feature = "artifact-size")]
+impl loupe::MemoryUsage for ModuleHash {
+    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        match self {
+            ModuleHash::XXHash(_) => 8 * 8,
+            ModuleHash::Sha256(_) => 8 * 32,
+        }
+    }
+}
+
 impl ModuleHash {
     /// Create a new [`ModuleHash`] from the raw xxhash hash.
     pub fn xxhash_from_bytes(key: [u8; 8]) -> Self {
diff --git a/lib/types/src/serialize.rs b/lib/types/src/serialize.rs
index d98af1dac76..a65b6132ad6 100644
--- a/lib/types/src/serialize.rs
+++ b/lib/types/src/serialize.rs
@@ -17,6 +17,7 @@ use std::mem;
 
 /// The compilation related data for a serialized modules
 #[derive(Archive, Default, RkyvDeserialize, RkyvSerialize)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[allow(missing_docs)]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct SerializableCompilation {
@@ -52,6 +53,7 @@ impl SerializableCompilation {
 
 /// Serializable struct that is able to serialize from and to a `ArtifactInfo`.
 #[derive(Archive, RkyvDeserialize, RkyvSerialize)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[allow(missing_docs)]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct SerializableModule {
diff --git a/lib/types/src/stack/sourceloc.rs b/lib/types/src/stack/sourceloc.rs
index e91586f4073..66af03a4318 100644
--- a/lib/types/src/stack/sourceloc.rs
+++ b/lib/types/src/stack/sourceloc.rs
@@ -21,6 +21,7 @@ use serde::{Deserialize, Serialize};
     derive(Serialize, Deserialize),
     serde(transparent)
 )]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[repr(transparent)]
 #[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::CheckBytes)]
diff --git a/lib/types/src/stack/trap.rs b/lib/types/src/stack/trap.rs
index b13c14b7df6..cf6ae88f70e 100644
--- a/lib/types/src/stack/trap.rs
+++ b/lib/types/src/stack/trap.rs
@@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
 
 /// Information about trap.
 #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(
     RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Clone, Copy, Debug, PartialEq, Eq,
 )]
diff --git a/lib/types/src/store_id.rs b/lib/types/src/store_id.rs
index 414a4af1d0f..7b6e380160b 100644
--- a/lib/types/src/store_id.rs
+++ b/lib/types/src/store_id.rs
@@ -12,6 +12,13 @@ use std::{
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub struct StoreId(NonZeroUsize);
 
+#[cfg(feature = "artifact-size")]
+impl loupe::MemoryUsage for StoreId {
+    fn size_of_val(&self, _visited: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        std::mem::size_of_val(self)
+    }
+}
+
 impl Default for StoreId {
     // Allocates a unique ID for a new context.
     fn default() -> Self {
diff --git a/lib/types/src/table.rs b/lib/types/src/table.rs
index 0b155d1f881..0837af841a6 100644
--- a/lib/types/src/table.rs
+++ b/lib/types/src/table.rs
@@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
     Debug, Clone, Hash, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive, CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 #[repr(u8)]
 pub enum TableStyle {
diff --git a/lib/types/src/trapcode.rs b/lib/types/src/trapcode.rs
index ae8066d89c4..52249a444fa 100644
--- a/lib/types/src/trapcode.rs
+++ b/lib/types/src/trapcode.rs
@@ -27,6 +27,7 @@ use thiserror::Error;
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[repr(u32)]
 #[archive(as = "Self")]
 pub enum TrapCode {
diff --git a/lib/types/src/types.rs b/lib/types/src/types.rs
index 3b9e4af215f..65ba989de79 100644
--- a/lib/types/src/types.rs
+++ b/lib/types/src/types.rs
@@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize};
 /// A list of all possible value types in WebAssembly.
 #[derive(Copy, Debug, Clone, Eq, PartialEq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes)]
 #[archive(as = "Self")]
 #[repr(u8)]
@@ -67,6 +68,13 @@ impl fmt::Display for Type {
 #[archive(as = "Self")]
 pub struct V128(pub(crate) [u8; 16]);
 
+#[cfg(feature = "artifact-size")]
+impl loupe::MemoryUsage for V128 {
+    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        16 * 8
+    }
+}
+
 impl V128 {
     /// Get the bytes corresponding to the V128 value
     pub fn bytes(&self) -> &[u8; 16] {
@@ -241,6 +249,7 @@ impl ExternType {
 /// WebAssembly functions can have 0 or more parameters and results.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct FunctionType {
@@ -327,6 +336,7 @@ impl From<&Self> for FunctionType {
 
 /// Indicator of whether a global is mutable or not
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, CheckBytes)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive(as = "Self")]
@@ -367,6 +377,7 @@ impl From<Mutability> for bool {
 /// WebAssembly global.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, CheckBytes)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive(as = "Self")]
 pub struct GlobalType {
@@ -412,6 +423,7 @@ impl fmt::Display for GlobalType {
 /// Globals are initialized via the `const` operators or by referring to another import.
 #[derive(Debug, Clone, Copy, PartialEq)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes)]
 #[archive(as = "Self")]
 #[repr(u8)]
@@ -446,6 +458,7 @@ pub enum GlobalInit {
 /// which `call_indirect` can invoke other functions.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct TableType {
@@ -487,6 +500,7 @@ impl fmt::Display for TableType {
 /// chunks of addressable memory.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(RkyvSerialize, RkyvDeserialize, Archive)]
 #[archive_attr(derive(CheckBytes, Debug))]
 pub struct MemoryType {
diff --git a/lib/types/src/units.rs b/lib/types/src/units.rs
index 60e488b4a31..fc6671f5344 100644
--- a/lib/types/src/units.rs
+++ b/lib/types/src/units.rs
@@ -34,6 +34,7 @@ pub const WASM_MIN_PAGES: u32 = 0x100;
     rkyv::CheckBytes,
 )]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[archive(as = "Self")]
 pub struct Pages(pub u32);
 
diff --git a/lib/vm/Cargo.toml b/lib/vm/Cargo.toml
index 0fcf37541f3..04c65486b26 100644
--- a/lib/vm/Cargo.toml
+++ b/lib/vm/Cargo.toml
@@ -33,12 +33,18 @@ fnv = "1.0.3"
 # - Optional shared dependencies.
 tracing = { version = "0.1", optional = true }
 crossbeam-queue = "0.3.8"
+loupe = { version = "0.1.3", optional = true }
 
 [target.'cfg(target_vendor = "apple")'.dependencies]
 mach2 = "0.4.2"
 
 [target.'cfg(target_os = "windows")'.dependencies]
-windows-sys = { version = "0.59", features = ["Win32_System_Diagnostics_Debug", "Win32_System_Threading", "Win32_System_Kernel", "Win32_System_Memory"] }
+windows-sys = { version = "0.59", features = [
+	"Win32_System_Diagnostics_Debug",
+	"Win32_System_Threading",
+	"Win32_System_Kernel",
+	"Win32_System_Memory",
+] }
 
 [build-dependencies]
 cc = "1.0"
@@ -48,7 +54,8 @@ maintenance = { status = "actively-developed" }
 
 [features]
 default = []
-enable-serde = ["serde", "indexmap/serde-1", "wasmer-types/enable-serde" ]
+enable-serde = ["serde", "indexmap/serde-1", "wasmer-types/enable-serde"]
+artifact-size = ["dep:loupe", "wasmer-types/artifact-size"]
 
 [package.metadata.docs.rs]
 rustc-args = ["--cfg", "docsrs"]
diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs
index 3a670b14b14..462725ccb6d 100644
--- a/lib/vm/src/export.rs
+++ b/lib/vm/src/export.rs
@@ -12,6 +12,7 @@ use std::any::Any;
 use wasmer_types::FunctionType;
 
 /// The value of an export passed from one instance to another.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub enum VMExtern {
     /// A function export value.
     Function(InternalStoreHandle<VMFunction>),
diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs
index 726e304b8b5..a49f115250b 100644
--- a/lib/vm/src/lib.rs
+++ b/lib/vm/src/lib.rs
@@ -90,6 +90,7 @@ pub struct VMFunctionBody(u8);
 
 /// A safe wrapper around `VMFunctionBody`.
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[repr(transparent)]
 pub struct FunctionBodyPtr(pub *const VMFunctionBody);
 
diff --git a/lib/vm/src/store.rs b/lib/vm/src/store.rs
index 8813ee26c15..09f25e6bb44 100644
--- a/lib/vm/src/store.rs
+++ b/lib/vm/src/store.rs
@@ -105,6 +105,7 @@ impl StoreObjects {
 ///
 /// Internally this is just an integer index into a context. A reference to the
 /// context must be passed in separately to access the actual object.
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 pub struct StoreHandle<T> {
     id: StoreId,
     internal: InternalStoreHandle<T>,
@@ -199,6 +200,13 @@ pub struct InternalStoreHandle<T> {
     marker: PhantomData<fn() -> T>,
 }
 
+#[cfg(feature = "artifact-size")]
+impl<T> loupe::MemoryUsage for InternalStoreHandle<T> {
+    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
+        std::mem::size_of_val(&self)
+    }
+}
+
 impl<T> Clone for InternalStoreHandle<T> {
     fn clone(&self) -> Self {
         *self
diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs
index c75d6b5f69e..bea67b71190 100644
--- a/lib/vm/src/vmcontext.rs
+++ b/lib/vm/src/vmcontext.rs
@@ -538,6 +538,7 @@ impl VMGlobalDefinition {
 /// An index into the shared signature registry, usable for checking signatures
 /// at indirect calls.
 #[repr(C)]
+#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
 #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
 pub struct VMSharedSignatureIndex(u32);
 


Test patch: