Repository: bytecodealliance/wasm-tools
Pull request #1566 (2024-05-19 07:25:07)

Add `#[inline]` to forwarding methods of `wasmparser::collections` types
I applied `#[inline]` to all trivial methods of types in the `wasmparser::collections` submodule [as stated here](https://github.com/bytecodealliance/wasm-tools/pull/1521#issuecomment-2106164632).

I ran benchmarks on `main` and the PR and built `main` and PR after a `cargo clean` to observe the performance impact of the changes on both compilation and execution. The tl;dr is that compile times are the same, and I only see minor improvements on execution.

Build times:

- `main`: 16.08s user 0.46s system 343% cpu 4.822 total
- PR: 16.04s user 0.46s system 348% cpu 4.736 total

Benchmarks: (PR run after `main` run)

## Default Features

![image](https://github.com/bytecodealliance/wasm-tools/assets/8193155/a61af3cc-da31-4d0a-a1df-d2dbad6567ee)

## Features: `no-hash-maps`

![image](https://github.com/bytecodealliance/wasm-tools/assets/8193155/4dedec89-4577-4a0c-818f-c41de8944fe2)



Patch:
diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs
index 4834b206..de176686 100644
--- a/crates/wasm-encoder/src/core/code.rs
+++ b/crates/wasm-encoder/src/core/code.rs
@@ -1020,6 +1020,34 @@ pub enum Instruction<'a> {
         ordering: Ordering,
         global_index: u32,
     },
+    GlobalAtomicRmwAdd {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwSub {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwAnd {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwOr {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwXor {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwXchg {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwCmpxchg {
+        ordering: Ordering,
+        global_index: u32,
+    },
 }
 
 impl Encode for Instruction<'_> {
@@ -3183,6 +3211,69 @@ impl Encode for Instruction<'_> {
                 ordering.encode(sink);
                 global_index.encode(sink);
             }
+            Instruction::GlobalAtomicRmwAdd {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x51);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwSub {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x52);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwAnd {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x53);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwOr {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x54);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwXor {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x55);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwXchg {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x56);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwCmpxchg {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x57);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
         }
     }
 }
diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs
index cf286946..fe059792 100644
--- a/crates/wasmparser/src/binary_reader.rs
+++ b/crates/wasmparser/src/binary_reader.rs
@@ -1684,6 +1684,25 @@ impl<'a> BinaryReader<'a> {
             // Decode shared-everything-threads proposal.
             0x4f => visitor.visit_global_atomic_get(self.read_ordering()?, self.read_var_u32()?),
             0x50 => visitor.visit_global_atomic_set(self.read_ordering()?, self.read_var_u32()?),
+            0x51 => {
+                visitor.visit_global_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x52 => {
+                visitor.visit_global_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x53 => {
+                visitor.visit_global_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x54 => visitor.visit_global_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),
+            0x55 => {
+                visitor.visit_global_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x56 => {
+                visitor.visit_global_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x57 => {
+                visitor.visit_global_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
+            }
 
             _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"),
         })
diff --git a/crates/wasmparser/src/collections/index_map.rs b/crates/wasmparser/src/collections/index_map.rs
index 8a25f6ba..f9fd676b 100644
--- a/crates/wasmparser/src/collections/index_map.rs
+++ b/crates/wasmparser/src/collections/index_map.rs
@@ -22,6 +22,7 @@ pub struct IndexMap<K, V> {
 }
 
 impl<K, V> Default for IndexMap<K, V> {
+    #[inline]
     fn default() -> Self {
         Self {
             inner: detail::IndexMapImpl::default(),
@@ -31,21 +32,25 @@ impl<K, V> Default for IndexMap<K, V> {
 
 impl<K, V> IndexMap<K, V> {
     /// Clears the [`IndexMap`], removing all elements.
+    #[inline]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
 
     /// Returns the number of elements in the [`IndexMap`].
+    #[inline]
     pub fn len(&self) -> usize {
         self.inner.len()
     }
 
     /// Returns `true` if the [`IndexMap`] contains no elements.
+    #[inline]
     pub fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
 
     /// Returns an iterator that yields the items in the [`IndexMap`].
+    #[inline]
     pub fn iter(&self) -> Iter<'_, K, V> {
         Iter {
             inner: self.inner.iter(),
@@ -53,6 +58,7 @@ impl<K, V> IndexMap<K, V> {
     }
 
     /// Returns an iterator that yields the mutable items in the [`IndexMap`].
+    #[inline]
     pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
         IterMut {
             inner: self.inner.iter_mut(),
@@ -60,6 +66,7 @@ impl<K, V> IndexMap<K, V> {
     }
 
     /// Returns an iterator that yields the keys in the [`IndexMap`].
+    #[inline]
     pub fn keys(&self) -> Keys<'_, K, V> {
         Keys {
             inner: self.inner.keys(),
@@ -67,6 +74,7 @@ impl<K, V> IndexMap<K, V> {
     }
 
     /// Returns an iterator that yields the values in the [`IndexMap`].
+    #[inline]
     pub fn values(&self) -> Values<'_, K, V> {
         Values {
             inner: self.inner.values(),
@@ -74,6 +82,7 @@ impl<K, V> IndexMap<K, V> {
     }
 
     /// Returns a mutable iterator that yields the values in the [`IndexMap`].
+    #[inline]
     pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
         ValuesMut {
             inner: self.inner.values_mut(),
@@ -81,11 +90,13 @@ impl<K, V> IndexMap<K, V> {
     }
 
     /// Returns the key-value entry at the given `index` if any.
+    #[inline]
     pub fn get_index(&self, index: usize) -> Option<(&K, &V)> {
         self.inner.get_index(index)
     }
 
     /// Returns the mutable key-value entry at the given `index` if any.
+    #[inline]
     pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> {
         self.inner.get_index_mut(index)
     }
@@ -96,6 +107,7 @@ where
     K: Hash + Eq + Ord + Clone,
 {
     /// Reserves capacity for at least `additional` more elements to be inserted in the [`IndexMap`].
+    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         #[cfg(not(feature = "no-hash-maps"))]
         self.inner.reserve(additional);
@@ -104,6 +116,7 @@ where
     }
 
     /// Returns true if `key` is contains in the [`IndexMap`].
+    #[inline]
     pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
     where
         K: Borrow<Q>,
@@ -113,6 +126,7 @@ where
     }
 
     /// Returns a reference to the value corresponding to the `key`.
+    #[inline]
     pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
     where
         K: Borrow<Q>,
@@ -123,6 +137,7 @@ where
 
     /// Return references to the key-value pair stored for `key`,
     /// if it is present, else `None`.
+    #[inline]
     pub fn get_key_value<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
     where
         K: Borrow<Q>,
@@ -137,6 +152,7 @@ where
     /// The supplied key may be any borrowed form of the map's key type,
     /// but the ordering on the borrowed form *must* match the ordering
     /// on the key type.
+    #[inline]
     pub fn get_full<Q: ?Sized>(&self, key: &Q) -> Option<(usize, &K, &V)>
     where
         K: Borrow<Q> + Ord,
@@ -146,6 +162,7 @@ where
     }
 
     /// Returns a mutable reference to the value corresponding to the key.
+    #[inline]
     pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
     where
         K: Borrow<Q>,
@@ -161,6 +178,7 @@ where
     /// If the map did have this key present, the value is updated, and the old
     /// value is returned. The key is not updated, though; this matters for
     /// types that can be `==` without being identical.
+    #[inline]
     pub fn insert(&mut self, key: K, value: V) -> Option<V> {
         self.inner.insert(key, value)
     }
@@ -174,6 +192,7 @@ where
     /// Return `None` if `key` is not in map.
     ///
     /// [`Vec::swap_remove`]: alloc::vec::Vec::swap_remove
+    #[inline]
     pub fn swap_remove<Q>(&mut self, key: &Q) -> Option<V>
     where
         K: Borrow<Q>,
@@ -191,6 +210,7 @@ where
     /// Return `None` if `key` is not in map.
     ///
     /// [`Vec::swap_remove`]: alloc::vec::Vec::swap_remove
+    #[inline]
     pub fn swap_remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
     where
         K: Borrow<Q>,
@@ -200,6 +220,7 @@ where
     }
 
     /// Gets the given key's corresponding entry in the [`IndexMap`] for in-place manipulation.
+    #[inline]
     pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
         match self.inner.entry(key) {
             detail::EntryImpl::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }),
@@ -215,6 +236,7 @@ where
 {
     type Output = V;
 
+    #[inline]
     fn index(&self, key: &Q) -> &V {
         &self.inner[key]
     }
@@ -226,6 +248,7 @@ where
 {
     type Output = V;
 
+    #[inline]
     fn index(&self, key: usize) -> &V {
         &self.inner[key]
     }
@@ -235,6 +258,7 @@ impl<K, V> Extend<(K, V)> for IndexMap<K, V>
 where
     K: Eq + Hash + Ord + Clone,
 {
+    #[inline]
     fn extend<Iter: IntoIterator<Item = (K, V)>>(&mut self, iter: Iter) {
         self.inner.extend(iter)
     }
@@ -256,6 +280,7 @@ where
     K: Hash + Eq + Ord + Clone,
 {
     /// Returns a reference to this entry's key.
+    #[inline]
     pub fn key(&self) -> &K {
         match *self {
             Self::Occupied(ref entry) => entry.key(),
@@ -271,6 +296,7 @@ where
 {
     /// Ensures a value is in the entry by inserting the default value if empty,
     /// and returns a mutable reference to the value in the entry.
+    #[inline]
     pub fn or_default(self) -> &'a mut V {
         match self {
             Self::Occupied(entry) => entry.into_mut(),
@@ -292,27 +318,32 @@ where
     K: Ord + Clone,
 {
     /// Gets a reference to the key in the entry.
+    #[inline]
     pub fn key(&self) -> &K {
         self.inner.key()
     }
 
     /// Gets a reference to the value in the entry.
+    #[inline]
     pub fn get(&self) -> &V {
         self.inner.get()
     }
 
     /// Gets a mutable reference to the value in the entry.
+    #[inline]
     pub fn get_mut(&mut self) -> &mut V {
         self.inner.get_mut()
     }
 
     /// Sets the value of the entry with the [`OccupiedEntry`]'s key, and returns the entry's old value.
+    #[inline]
     pub fn insert(&mut self, value: V) -> V {
         self.inner.insert(value)
     }
 
     /// Converts the [`OccupiedEntry`] into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
+    #[inline]
     pub fn into_mut(self) -> &'a mut V {
         self.inner.into_mut()
     }
@@ -331,16 +362,19 @@ where
     K: Ord + Clone,
 {
     /// Gets a reference to the key in the entry.
+    #[inline]
     pub fn key(&self) -> &K {
         self.inner.key()
     }
 
     /// Take ownership of the key.
+    #[inline]
     pub fn into_key(self) -> K {
         self.inner.into_key()
     }
 
     /// Sets the value of the entry with the [`VacantEntry`]'s key, and returns a mutable reference to it.
+    #[inline]
     pub fn insert(self, value: V) -> &'a mut V
     where
         K: Hash,
@@ -353,6 +387,7 @@ impl<K, V> FromIterator<(K, V)> for IndexMap<K, V>
 where
     K: Hash + Ord + Eq + Clone,
 {
+    #[inline]
     fn from_iter<I>(iter: I) -> Self
     where
         I: IntoIterator<Item = (K, V)>,
@@ -367,6 +402,7 @@ impl<'a, K, V> IntoIterator for &'a IndexMap<K, V> {
     type Item = (&'a K, &'a V);
     type IntoIter = Iter<'a, K, V>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
     }
@@ -381,16 +417,19 @@ pub struct Iter<'a, K, V> {
 impl<'a, K, V> Iterator for Iter<'a, K, V> {
     type Item = (&'a K, &'a V);
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -402,6 +441,7 @@ impl<'a, K, V> IntoIterator for &'a mut IndexMap<K, V> {
     type Item = (&'a K, &'a mut V);
     type IntoIter = IterMut<'a, K, V>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         self.iter_mut()
     }
@@ -416,16 +456,19 @@ pub struct IterMut<'a, K, V> {
 impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     type Item = (&'a K, &'a mut V);
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -437,6 +480,7 @@ impl<K, V> IntoIterator for IndexMap<K, V> {
     type Item = (K, V);
     type IntoIter = IntoIter<K, V>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         IntoIter {
             inner: self.inner.into_iter(),
@@ -453,16 +497,19 @@ pub struct IntoIter<K, V> {
 impl<'a, K, V> Iterator for IntoIter<K, V> {
     type Item = (K, V);
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V> ExactSizeIterator for IntoIter<K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -479,16 +526,19 @@ pub struct Keys<'a, K, V> {
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
     type Item = &'a K;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -505,16 +555,19 @@ pub struct Values<'a, K, V> {
 impl<'a, K, V> Iterator for Values<'a, K, V> {
     type Item = &'a V;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -531,16 +584,19 @@ pub struct ValuesMut<'a, K, V> {
 impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
     type Item = &'a mut V;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
diff --git a/crates/wasmparser/src/collections/index_set.rs b/crates/wasmparser/src/collections/index_set.rs
index 230e33d5..23367850 100644
--- a/crates/wasmparser/src/collections/index_set.rs
+++ b/crates/wasmparser/src/collections/index_set.rs
@@ -15,6 +15,7 @@ pub struct IndexSet<T> {
 }
 
 impl<T> Default for IndexSet<T> {
+    #[inline]
     fn default() -> Self {
         Self {
             inner: IndexMap::default(),
@@ -24,21 +25,25 @@ impl<T> Default for IndexSet<T> {
 
 impl<T> IndexSet<T> {
     /// Clears the [`IndexSet`], removing all elements.
+    #[inline]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
 
     /// Returns the number of elements in the [`IndexSet`].
+    #[inline]
     pub fn len(&self) -> usize {
         self.inner.len()
     }
 
     /// Returns `true` if the [`IndexSet`] contains no elements.
+    #[inline]
     pub fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
 
     /// Returns an iterator that yields the items in the [`IndexSet`].
+    #[inline]
     pub fn iter(&self) -> Iter<'_, T> {
         Iter {
             inner: self.inner.iter(),
@@ -51,11 +56,13 @@ where
     T: Eq + Hash + Ord + Clone,
 {
     /// Reserves capacity for at least `additional` more elements to be inserted in the [`IndexSet`].
+    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional);
     }
 
     /// Returns true if the [`IndexSet`] contains an element equal to the `value`.
+    #[inline]
     pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
     where
         T: Borrow<Q>,
@@ -65,6 +72,7 @@ where
     }
 
     /// Returns a reference to the element in the [`IndexSet`], if any, that is equal to the `value`.
+    #[inline]
     pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
     where
         T: Borrow<Q>,
@@ -79,6 +87,7 @@ where
     ///
     /// - Returns `true` if the set did not previously contain an equal value.
     /// - Returns `false` otherwise and the entry is not updated.
+    #[inline]
     pub fn insert(&mut self, value: T) -> bool {
         self.inner.insert(value, ()).is_none()
     }
@@ -94,6 +103,7 @@ where
     /// Computes in **O(1)** time (average).
     ///
     /// [`Vec::swap_remove`]: alloc::vec::Vec::swap_remove
+    #[inline]
     pub fn swap_remove<Q: ?Sized>(&mut self, value: &Q) -> bool
     where
         T: Borrow<Q>,
@@ -128,6 +138,7 @@ where
 
     /// Returns `true` if the [`IndexSet`] is a superset of another,
     /// i.e., `self` contains at least all the values in `other`.
+    #[inline]
     pub fn is_superset(&self, other: &Self) -> bool {
         other.is_subset(self)
     }
@@ -139,6 +150,7 @@ where
 {
     type Output = T;
 
+    #[inline]
     fn index(&self, index: usize) -> &T {
         let Some((value, _)) = self.inner.get_index(index) else {
             panic!("out of bounds index: {index}");
@@ -165,6 +177,7 @@ impl<'a, T> IntoIterator for &'a IndexSet<T> {
     type Item = &'a T;
     type IntoIter = Iter<'a, T>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
     }
@@ -188,16 +201,19 @@ pub struct Iter<'a, T> {
 impl<'a, T> Iterator for Iter<'a, T> {
     type Item = &'a T;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next().map(|(key, _value)| key)
     }
 }
 
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -209,6 +225,7 @@ impl<T> IntoIterator for IndexSet<T> {
     type Item = T;
     type IntoIter = IntoIter<T>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         IntoIter {
             inner: self.inner.into_iter(),
@@ -225,16 +242,19 @@ pub struct IntoIter<T> {
 impl<T> Iterator for IntoIter<T> {
     type Item = T;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next().map(|(key, _value)| key)
     }
 }
 
 impl<T> ExactSizeIterator for IntoIter<T> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
diff --git a/crates/wasmparser/src/collections/map.rs b/crates/wasmparser/src/collections/map.rs
index 14980c24..ac1bf8d6 100644
--- a/crates/wasmparser/src/collections/map.rs
+++ b/crates/wasmparser/src/collections/map.rs
@@ -52,6 +52,7 @@ pub struct Map<K, V> {
 }
 
 impl<K, V> Default for Map<K, V> {
+    #[inline]
     fn default() -> Self {
         Self {
             inner: detail::MapImpl::default(),
@@ -61,26 +62,31 @@ impl<K, V> Default for Map<K, V> {
 
 impl<K, V> Map<K, V> {
     /// Creates a new empty [`Map`].
+    #[inline]
     pub fn new() -> Self {
         Self::default()
     }
 
     /// Clears the [`Map`], removing all elements.
+    #[inline]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
 
     /// Returns the number of elements in the [`Map`].
+    #[inline]
     pub fn len(&self) -> usize {
         self.inner.len()
     }
 
     /// Returns `true` if the [`Map`] contains no elements.
+    #[inline]
     pub fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
 
     /// Returns an iterator that yields the items in the [`Map`].
+    #[inline]
     pub fn iter(&self) -> Iter<'_, K, V> {
         Iter {
             inner: self.inner.iter(),
@@ -88,6 +94,7 @@ impl<K, V> Map<K, V> {
     }
 
     /// Returns a mutable iterator that yields the items in the [`Map`].
+    #[inline]
     pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
         IterMut {
             inner: self.inner.iter_mut(),
@@ -95,6 +102,7 @@ impl<K, V> Map<K, V> {
     }
 
     /// Returns an iterator that yields the keys in the [`Map`].
+    #[inline]
     pub fn keys(&self) -> Keys<'_, K, V> {
         Keys {
             inner: self.inner.keys(),
@@ -105,6 +113,7 @@ impl<K, V> Map<K, V> {
     ///
     /// The [`Map`] cannot be used after calling this.
     /// The iterator element type is `K`.
+    #[inline]
     pub fn into_keys(self) -> IntoKeys<K, V> {
         IntoKeys {
             inner: self.inner.into_keys(),
@@ -112,6 +121,7 @@ impl<K, V> Map<K, V> {
     }
 
     /// Returns an iterator that yields the values in the [`Map`].
+    #[inline]
     pub fn values(&self) -> Values<'_, K, V> {
         Values {
             inner: self.inner.values(),
@@ -122,6 +132,7 @@ impl<K, V> Map<K, V> {
     ///
     /// The [`Map`] cannot be used after calling this.
     /// The iterator element type is `V`.
+    #[inline]
     pub fn into_values(self) -> IntoValues<K, V> {
         IntoValues {
             inner: self.inner.into_values(),
@@ -129,6 +140,7 @@ impl<K, V> Map<K, V> {
     }
 
     /// Returns a mutable iterator that yields the values in the [`Map`].
+    #[inline]
     pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
         ValuesMut {
             inner: self.inner.values_mut(),
@@ -141,6 +153,7 @@ where
     K: Hash + Eq + Ord,
 {
     /// Reserves capacity for at least `additional` more elements to be inserted in the [`Map`].
+    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         #[cfg(not(feature = "no-hash-maps"))]
         self.inner.reserve(additional);
@@ -149,6 +162,7 @@ where
     }
 
     /// Returns true if `key` is contains in the [`Map`].
+    #[inline]
     pub fn contains_key<Q>(&self, key: &Q) -> bool
     where
         K: Borrow<Q>,
@@ -158,6 +172,7 @@ where
     }
 
     /// Returns a reference to the value corresponding to the `key`.
+    #[inline]
     pub fn get<Q>(&self, key: &Q) -> Option<&V>
     where
         K: Borrow<Q>,
@@ -170,6 +185,7 @@ where
     ///
     /// The supplied key may be any borrowed form of the map's key type, but the ordering
     /// on the borrowed form *must* match the ordering on the key type.
+    #[inline]
     pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
     where
         K: Borrow<Q>,
@@ -179,6 +195,7 @@ where
     }
 
     /// Returns a mutable reference to the value corresponding to the key.
+    #[inline]
     pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
     where
         K: Borrow<Q>,
@@ -194,11 +211,13 @@ where
     /// If the map did have this key present, the value is updated, and the old
     /// value is returned. The key is not updated, though; this matters for
     /// types that can be `==` without being identical.
+    #[inline]
     pub fn insert(&mut self, key: K, value: V) -> Option<V> {
         self.inner.insert(key, value)
     }
 
     /// Removes a key from the [`Map`], returning the value at the key if the key was previously in the map.
+    #[inline]
     pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
     where
         K: Borrow<Q>,
@@ -212,6 +231,7 @@ where
     ///
     /// The key may be any borrowed form of the map's key type, but the ordering
     /// on the borrowed form *must* match the ordering on the key type.
+    #[inline]
     pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
     where
         K: Borrow<Q>,
@@ -221,6 +241,7 @@ where
     }
 
     /// Gets the given key's corresponding entry in the [`Map`] for in-place manipulation.
+    #[inline]
     pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
         match self.inner.entry(key) {
             detail::EntryImpl::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }),
@@ -232,6 +253,7 @@ where
     ///
     /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
     /// The elements are visited in ascending key order.
+    #[inline]
     pub fn retain<F>(&mut self, f: F)
     where
         F: FnMut(&K, &mut V) -> bool,
@@ -245,6 +267,7 @@ where
     K: Eq + Hash,
     V: Eq,
 {
+    #[inline]
     fn eq(&self, other: &Self) -> bool {
         self.inner == other.inner
     }
@@ -264,6 +287,7 @@ where
 {
     type Output = V;
 
+    #[inline]
     fn index(&self, key: &Q) -> &V {
         &self.inner[key]
     }
@@ -274,6 +298,7 @@ where
     K: Eq + Hash + Ord + Copy,
     V: Copy,
 {
+    #[inline]
     fn extend<Iter: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: Iter) {
         self.inner.extend(iter)
     }
@@ -283,6 +308,7 @@ impl<K, V> Extend<(K, V)> for Map<K, V>
 where
     K: Eq + Hash + Ord,
 {
+    #[inline]
     fn extend<Iter: IntoIterator<Item = (K, V)>>(&mut self, iter: Iter) {
         self.inner.extend(iter)
     }
@@ -305,6 +331,7 @@ where
 {
     /// Ensures a value is in the entry by inserting the default if empty, and returns
     /// a mutable reference to the value in the entry.
+    #[inline]
     pub fn or_insert(self, default: V) -> &'a mut V {
         match self {
             Self::Occupied(entry) => entry.into_mut(),
@@ -314,6 +341,7 @@ where
 
     /// Ensures a value is in the [`Entry`] by inserting the result of the default function if empty,
     /// and returns a mutable reference to the value in the entry.
+    #[inline]
     pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
         match self {
             Self::Occupied(entry) => entry.into_mut(),
@@ -327,6 +355,7 @@ where
     ///
     /// The reference to the moved key is provided so that cloning or copying the key is
     /// unnecessary, unlike with `.or_insert_with(|| ... )`.
+    #[inline]
     pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
         match self {
             Self::Occupied(entry) => entry.into_mut(),
@@ -338,6 +367,7 @@ where
     }
 
     /// Returns a reference to this [`Entry`]'s key.
+    #[inline]
     pub fn key(&self) -> &K {
         match *self {
             Self::Occupied(ref entry) => entry.key(),
@@ -347,6 +377,7 @@ where
 
     /// Provides in-place mutable access to an occupied [`Entry`] before any
     /// potential inserts into the map.
+    #[inline]
     pub fn and_modify<F>(self, f: F) -> Self
     where
         F: FnOnce(&mut V),
@@ -368,6 +399,7 @@ where
 {
     /// Ensures a value is in the [`Entry`] by inserting the default value if empty,
     /// and returns a mutable reference to the value in the entry.
+    #[inline]
     pub fn or_default(self) -> &'a mut V {
         match self {
             Self::Occupied(entry) => entry.into_mut(),
@@ -399,37 +431,44 @@ where
     V: 'a,
 {
     /// Gets a reference to the key in the entry.
+    #[inline]
     pub fn key(&self) -> &K {
         self.inner.key()
     }
 
     /// Gets a reference to the value in the entry.
+    #[inline]
     pub fn get(&self) -> &V {
         self.inner.get()
     }
 
     /// Gets a mutable reference to the value in the entry.
+    #[inline]
     pub fn get_mut(&mut self) -> &mut V {
         self.inner.get_mut()
     }
 
     /// Sets the value of the entry with the [`OccupiedEntry`]'s key, and returns the entry's old value.
+    #[inline]
     pub fn insert(&mut self, value: V) -> V {
         self.inner.insert(value)
     }
 
     /// Converts the [`OccupiedEntry`] into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
+    #[inline]
     pub fn into_mut(self) -> &'a mut V {
         self.inner.into_mut()
     }
 
     /// Take ownership of the key and value from the [`Map`].
+    #[inline]
     pub fn remove_entry(self) -> (K, V) {
         self.inner.remove_entry()
     }
 
     /// Takes the value of the entry out of the [`Map`], and returns it.
+    #[inline]
     pub fn remove(self) -> V {
         self.inner.remove()
     }
@@ -458,16 +497,19 @@ where
     V: 'a,
 {
     /// Gets a reference to the key in the entry.
+    #[inline]
     pub fn key(&self) -> &K {
         self.inner.key()
     }
 
     /// Take ownership of the key.
+    #[inline]
     pub fn into_key(self) -> K {
         self.inner.into_key()
     }
 
     /// Sets the value of the entry with the [`VacantEntry`]'s key, and returns a mutable reference to it.
+    #[inline]
     pub fn insert(self, value: V) -> &'a mut V
     where
         K: Hash,
@@ -480,6 +522,7 @@ impl<K, V> FromIterator<(K, V)> for Map<K, V>
 where
     K: Hash + Eq + Ord,
 {
+    #[inline]
     fn from_iter<I>(iter: I) -> Self
     where
         I: IntoIterator<Item = (K, V)>,
@@ -494,6 +537,7 @@ impl<'a, K, V> IntoIterator for &'a Map<K, V> {
     type Item = (&'a K, &'a V);
     type IntoIter = Iter<'a, K, V>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
     }
@@ -508,16 +552,19 @@ pub struct Iter<'a, K, V> {
 impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
     type Item = (&'a K, &'a V);
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -532,6 +579,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut Map<K, V> {
     type Item = (&'a K, &'a mut V);
     type IntoIter = IterMut<'a, K, V>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         self.iter_mut()
     }
@@ -546,16 +594,19 @@ pub struct IterMut<'a, K, V> {
 impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
     type Item = (&'a K, &'a mut V);
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -570,6 +621,7 @@ impl<K, V> IntoIterator for Map<K, V> {
     type Item = (K, V);
     type IntoIter = IntoIter<K, V>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         IntoIter {
             inner: self.inner.into_iter(),
@@ -586,16 +638,19 @@ pub struct IntoIter<K, V> {
 impl<K, V> Iterator for IntoIter<K, V> {
     type Item = (K, V);
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -612,16 +667,19 @@ pub struct Keys<'a, K, V> {
 impl<'a, K: 'a, V> Iterator for Keys<'a, K, V> {
     type Item = &'a K;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K: 'a, V> ExactSizeIterator for Keys<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -638,16 +696,19 @@ pub struct Values<'a, K, V> {
 impl<'a, K, V: 'a> Iterator for Values<'a, K, V> {
     type Item = &'a V;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V: 'a> ExactSizeIterator for Values<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -667,16 +728,19 @@ pub struct ValuesMut<'a, K, V> {
 impl<'a, K, V: 'a> Iterator for ValuesMut<'a, K, V> {
     type Item = &'a mut V;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, K, V: 'a> ExactSizeIterator for ValuesMut<'a, K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -696,16 +760,19 @@ pub struct IntoKeys<K, V> {
 impl<K, V> Iterator for IntoKeys<K, V> {
     type Item = K;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -722,16 +789,19 @@ pub struct IntoValues<K, V> {
 impl<K, V> Iterator for IntoValues<K, V> {
     type Item = V;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<K, V> ExactSizeIterator for IntoValues<K, V> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
diff --git a/crates/wasmparser/src/collections/set.rs b/crates/wasmparser/src/collections/set.rs
index 0314fc30..d7a62e87 100644
--- a/crates/wasmparser/src/collections/set.rs
+++ b/crates/wasmparser/src/collections/set.rs
@@ -49,6 +49,7 @@ pub struct Set<T> {
 }
 
 impl<T> Default for Set<T> {
+    #[inline]
     fn default() -> Self {
         Self {
             inner: detail::SetImpl::default(),
@@ -58,6 +59,7 @@ impl<T> Default for Set<T> {
 
 impl<T> Set<T> {
     /// Clears the [`Set`], removing all elements.
+    #[inline]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
@@ -66,6 +68,7 @@ impl<T> Set<T> {
     ///
     /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
     /// The elements are visited in unsorted (and unspecified) order.
+    #[inline]
     pub fn retain<F>(&mut self, f: F)
     where
         T: Ord,
@@ -75,16 +78,19 @@ impl<T> Set<T> {
     }
 
     /// Returns the number of elements in the [`Set`].
+    #[inline]
     pub fn len(&self) -> usize {
         self.inner.len()
     }
 
     /// Returns `true` if the [`Set`] contains no elements.
+    #[inline]
     pub fn is_empty(&self) -> bool {
         self.inner.is_empty()
     }
 
     /// Returns an iterator that yields the items in the [`Set`].
+    #[inline]
     pub fn iter(&self) -> Iter<'_, T> {
         Iter {
             inner: self.inner.iter(),
@@ -97,6 +103,7 @@ where
     T: Eq + Hash + Ord,
 {
     /// Reserves capacity for at least `additional` more elements to be inserted in the [`Set`].
+    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         #[cfg(not(feature = "no-hash-maps"))]
         self.inner.reserve(additional);
@@ -105,6 +112,7 @@ where
     }
 
     /// Returns true if the [`Set`] contains an element equal to the `value`.
+    #[inline]
     pub fn contains<Q>(&self, value: &Q) -> bool
     where
         T: Borrow<Q>,
@@ -114,6 +122,7 @@ where
     }
 
     /// Returns a reference to the element in the [`Set`], if any, that is equal to the `value`.
+    #[inline]
     pub fn get<Q>(&self, value: &Q) -> Option<&T>
     where
         T: Borrow<Q>,
@@ -128,6 +137,7 @@ where
     ///
     /// - Returns `true` if the set did not previously contain an equal value.
     /// - Returns `false` otherwise and the entry is not updated.
+    #[inline]
     pub fn insert(&mut self, value: T) -> bool {
         self.inner.insert(value)
     }
@@ -135,6 +145,7 @@ where
     /// If the set contains an element equal to the value, removes it from the [`Set`] and drops it.
     ///
     /// Returns `true` if such an element was present, otherwise `false`.
+    #[inline]
     pub fn remove<Q>(&mut self, value: &Q) -> bool
     where
         T: Borrow<Q>,
@@ -149,6 +160,7 @@ where
     /// The value may be any borrowed form of the set's element type,
     /// but the ordering on the borrowed form *must* match the
     /// ordering on the element type.
+    #[inline]
     pub fn take<Q>(&mut self, value: &Q) -> Option<T>
     where
         T: Borrow<Q>,
@@ -159,30 +171,35 @@ where
 
     /// Adds a value to the [`Set`], replacing the existing value, if any, that is equal to the given
     /// one. Returns the replaced value.
+    #[inline]
     pub fn replace(&mut self, value: T) -> Option<T> {
         self.inner.replace(value)
     }
 
     /// Returns `true` if `self` has no elements in common with `other`.
     /// This is equivalent to checking for an empty intersection.
+    #[inline]
     pub fn is_disjoint(&self, other: &Self) -> bool {
         self.inner.is_disjoint(&other.inner)
     }
 
     /// Returns `true` if the [`Set`] is a subset of another,
     /// i.e., `other` contains at least all the values in `self`.
+    #[inline]
     pub fn is_subset(&self, other: &Self) -> bool {
         self.inner.is_subset(&other.inner)
     }
 
     /// Returns `true` if the [`Set`] is a superset of another,
     /// i.e., `self` contains at least all the values in `other`.
+    #[inline]
     pub fn is_superset(&self, other: &Self) -> bool {
         self.inner.is_superset(&other.inner)
     }
 
     /// Visits the values representing the difference,
     /// i.e., the values that are in `self` but not in `other`.
+    #[inline]
     pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T> {
         Difference {
             inner: self.inner.difference(&other.inner),
@@ -191,6 +208,7 @@ where
 
     /// Visits the values representing the symmetric difference,
     /// i.e., the values that are in `self` or in `other` but not in both.
+    #[inline]
     pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T> {
         SymmetricDifference {
             inner: self.inner.symmetric_difference(&other.inner),
@@ -205,6 +223,7 @@ where
     /// one or the other. This can be relevant if `T` contains fields which
     /// are not compared by its `Eq` implementation, and may hold different
     /// value between the two equal copies of `T` in the two sets.
+    #[inline]
     pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T> {
         Intersection {
             inner: self.inner.intersection(&other.inner),
@@ -213,6 +232,7 @@ where
 
     /// Visits the values representing the union,
     /// i.e., all the values in `self` or `other`, without duplicates.
+    #[inline]
     pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T> {
         Union {
             inner: self.inner.union(&other.inner),
@@ -224,6 +244,7 @@ impl<T> PartialEq for Set<T>
 where
     T: Eq + Hash,
 {
+    #[inline]
     fn eq(&self, other: &Self) -> bool {
         self.inner == other.inner
     }
@@ -235,6 +256,7 @@ impl<T> FromIterator<T> for Set<T>
 where
     T: Hash + Eq + Ord,
 {
+    #[inline]
     fn from_iter<I>(iter: I) -> Self
     where
         I: IntoIterator<Item = T>,
@@ -249,6 +271,7 @@ impl<'a, T> IntoIterator for &'a Set<T> {
     type Item = &'a T;
     type IntoIter = Iter<'a, T>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
     }
@@ -258,6 +281,7 @@ impl<'a, T> Extend<&'a T> for Set<T>
 where
     T: Hash + Eq + Ord + Copy + 'a,
 {
+    #[inline]
     fn extend<Iter: IntoIterator<Item = &'a T>>(&mut self, iter: Iter) {
         self.inner.extend(iter)
     }
@@ -267,6 +291,7 @@ impl<T> Extend<T> for Set<T>
 where
     T: Hash + Eq + Ord,
 {
+    #[inline]
     fn extend<Iter: IntoIterator<Item = T>>(&mut self, iter: Iter) {
         self.inner.extend(iter)
     }
@@ -278,6 +303,7 @@ where
 {
     type Output = Set<T>;
 
+    #[inline]
     fn bitand(self, rhs: Self) -> Set<T> {
         Set {
             inner: BitAnd::bitand(&self.inner, &rhs.inner),
@@ -291,6 +317,7 @@ where
 {
     type Output = Set<T>;
 
+    #[inline]
     fn bitor(self, rhs: Self) -> Set<T> {
         Set {
             inner: BitOr::bitor(&self.inner, &rhs.inner),
@@ -304,6 +331,7 @@ where
 {
     type Output = Set<T>;
 
+    #[inline]
     fn bitxor(self, rhs: Self) -> Set<T> {
         Set {
             inner: BitXor::bitxor(&self.inner, &rhs.inner),
@@ -317,6 +345,7 @@ where
 {
     type Output = Set<T>;
 
+    #[inline]
     fn sub(self, rhs: Self) -> Set<T> {
         Set {
             inner: Sub::sub(&self.inner, &rhs.inner),
@@ -333,16 +362,19 @@ pub struct Iter<'a, T> {
 impl<'a, T: 'a> Iterator for Iter<'a, T> {
     type Item = &'a T;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<'a, T: 'a> ExactSizeIterator for Iter<'a, T> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -354,6 +386,7 @@ impl<T> IntoIterator for Set<T> {
     type Item = T;
     type IntoIter = IntoIter<T>;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         IntoIter {
             inner: self.inner.into_iter(),
@@ -370,16 +403,19 @@ pub struct IntoIter<T> {
 impl<T> Iterator for IntoIter<T> {
     type Item = T;
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 }
 
 impl<T> ExactSizeIterator for IntoIter<T> {
+    #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
@@ -407,6 +443,7 @@ where
 }
 
 impl<T> Clone for Difference<'_, T> {
+    #[inline]
     fn clone(&self) -> Self {
         Self {
             inner: self.inner.clone(),
@@ -420,10 +457,12 @@ where
 {
     type Item = &'a T;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
@@ -456,6 +495,7 @@ where
 }
 
 impl<T> Clone for Intersection<'_, T> {
+    #[inline]
     fn clone(&self) -> Self {
         Self {
             inner: self.inner.clone(),
@@ -469,10 +509,12 @@ where
 {
     type Item = &'a T;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
@@ -505,6 +547,7 @@ where
 }
 
 impl<T> Clone for SymmetricDifference<'_, T> {
+    #[inline]
     fn clone(&self) -> Self {
         Self {
             inner: self.inner.clone(),
@@ -518,10 +561,12 @@ where
 {
     type Item = &'a T;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
@@ -554,6 +599,7 @@ where
 }
 
 impl<T> Clone for Union<'_, T> {
+    #[inline]
     fn clone(&self) -> Self {
         Self {
             inner: self.inner.clone(),
@@ -567,10 +613,12 @@ where
 {
     type Item = &'a T;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs
index 28cc15bb..909dbea7 100644
--- a/crates/wasmparser/src/lib.rs
+++ b/crates/wasmparser/src/lib.rs
@@ -498,6 +498,13 @@ macro_rules! for_each_operator {
             // https://github.com/WebAssembly/shared-everything-threads
             @shared_everything_threads GlobalAtomicGet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_get
             @shared_everything_threads GlobalAtomicSet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_set
+            @shared_everything_threads GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add
+            @shared_everything_threads GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub
+            @shared_everything_threads GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and
+            @shared_everything_threads GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or
+            @shared_everything_threads GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor
+            @shared_everything_threads GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg
+            @shared_everything_threads GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg
 
             // 0xFD operators
             // 128-bit SIMD
diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs
index 8e99b399..a3d1c313 100644
--- a/crates/wasmparser/src/validator/operators.rs
+++ b/crates/wasmparser/src/validator/operators.rs
@@ -22,13 +22,13 @@
 // confusing it's recommended to read over that section to see how it maps to
 // the various methods here.
 
-use crate::prelude::*;
 use crate::{
     limits::MAX_WASM_FUNCTION_LOCALS, ArrayType, BinaryReaderError, BlockType, BrTable, Catch,
     CompositeType, FieldType, FuncType, HeapType, Ieee32, Ieee64, MemArg, RefType, Result,
     StorageType, StructType, SubType, TableType, TryTable, UnpackedIndex, ValType, VisitOperator,
     WasmFeatures, WasmModuleResources, V128,
 };
+use crate::{prelude::*, GlobalType};
 use core::ops::{Deref, DerefMut};
 
 pub(crate) struct OperatorValidator {
@@ -938,8 +938,8 @@ where
         Ok(())
     }
 
-    /// Checks the validity of a common atomic binary operator.
-    fn check_atomic_binary_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
+    /// Checks the validity of atomic binary operator on memory.
+    fn check_atomic_binary_memory_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
         let ty = self.check_shared_memarg(memarg)?;
         self.pop_operand(Some(op_ty))?;
         self.pop_operand(Some(ty))?;
@@ -947,8 +947,8 @@ where
         Ok(())
     }
 
-    /// Checks the validity of an atomic compare exchange operator.
-    fn check_atomic_binary_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
+    /// Checks the validity of an atomic compare exchange operator on memories.
+    fn check_atomic_binary_memory_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
         let ty = self.check_shared_memarg(memarg)?;
         self.pop_operand(Some(op_ty))?;
         self.pop_operand(Some(op_ty))?;
@@ -1073,22 +1073,17 @@ where
         self.push_operand(sub_ty)
     }
 
-    /// Common helper for checking the types of global types accessed
-    /// atomically.
-    fn check_atomic_global_ty(&self, global_index: u32) -> Result<()> {
-        let ty = self
-            .resources
-            .global_at(global_index)
-            .expect("existence should be checked prior to this point");
-        let ty = ty.content_type;
-        let supertype = RefType::ANYREF.into();
-        if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
+    /// Common helper for checking the types of globals accessed with atomic RMW
+    /// instructions, which only allow `i32` and `i64`.
+    fn check_atomic_global_rmw_ty(&self, global_index: u32) -> Result<ValType> {
+        let ty = self.global_type_at(global_index)?.content_type;
+        if !(ty == ValType::I32 || ty == ValType::I64) {
             bail!(
-                    self.offset,
-                    "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`"
-                );
+                self.offset,
+                "invalid type: `global.atomic.rmw.*` only allows `i32` and `i64`"
+            );
         }
-        Ok(())
+        Ok(ty)
     }
 
     fn element_type_at(&self, elem_index: u32) -> Result<RefType> {
@@ -1163,6 +1158,14 @@ where
             .ok_or_else(|| format_err!(self.offset, "unknown tag {}: tag index out of bounds", at))
     }
 
+    fn global_type_at(&self, at: u32) -> Result<GlobalType> {
+        if let Some(ty) = self.resources.global_at(at) {
+            Ok(ty)
+        } else {
+            bail!(self.offset, "unknown global: global index out of bounds");
+        }
+    }
+
     fn params(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
         Ok(match ty {
             BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()),
@@ -1631,13 +1634,9 @@ where
         Ok(())
     }
     fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
-        if let Some(ty) = self.resources.global_at(global_index) {
-            let ty = ty.content_type;
-            debug_assert_type_indices_are_ids(ty);
-            self.push_operand(ty)?;
-        } else {
-            bail!(self.offset, "unknown global: global index out of bounds");
-        };
+        let ty = self.global_type_at(global_index)?.content_type;
+        debug_assert_type_indices_are_ids(ty);
+        self.push_operand(ty)?;
         Ok(())
     }
     fn visit_global_atomic_get(
@@ -1647,22 +1646,24 @@ where
     ) -> Self::Output {
         self.visit_global_get(global_index)?;
         // No validation of `ordering` is needed because `global.atomic.get` can
-        // be used on both shared and unshared globals.
-        self.check_atomic_global_ty(global_index)?;
+        // be used on both shared and unshared globals. But we do need to limit
+        // which types can be used with this instruction.
+        let ty = self.global_type_at(global_index)?.content_type;
+        let supertype = RefType::ANYREF.into();
+        if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
+            bail!(self.offset, "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`");
+        }
         Ok(())
     }
     fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
-        if let Some(ty) = self.resources.global_at(global_index) {
-            if !ty.mutable {
-                bail!(
-                    self.offset,
-                    "global is immutable: cannot modify it with `global.set`"
-                );
-            }
-            self.pop_operand(Some(ty.content_type))?;
-        } else {
-            bail!(self.offset, "unknown global: global index out of bounds");
-        };
+        let ty = self.global_type_at(global_index)?;
+        if !ty.mutable {
+            bail!(
+                self.offset,
+                "global is immutable: cannot modify it with `global.set`"
+            );
+        }
+        self.pop_operand(Some(ty.content_type))?;
         Ok(())
     }
     fn visit_global_atomic_set(
@@ -1673,9 +1674,82 @@ where
         self.visit_global_set(global_index)?;
         // No validation of `ordering` is needed because `global.atomic.get` can
         // be used on both shared and unshared globals.
-        self.check_atomic_global_ty(global_index)?;
+        let ty = self.global_type_at(global_index)?.content_type;
+        let supertype = RefType::ANYREF.into();
+        if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
+            bail!(self.offset, "invalid type: `global.atomic.set` only allows `i32`, `i64` and subtypes of `anyref`");
+        }
         Ok(())
     }
+    fn visit_global_atomic_rmw_add(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_sub(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_and(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_or(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_xor(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_xchg(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.global_type_at(global_index)?.content_type;
+        if !(ty == ValType::I32
+            || ty == ValType::I64
+            || self.resources.is_subtype(ty, RefType::ANYREF.into()))
+        {
+            bail!(self.offset, "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`");
+        }
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_cmpxchg(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.global_type_at(global_index)?.content_type;
+        if !(ty == ValType::I32
+            || ty == ValType::I64
+            || self.resources.is_subtype(ty, RefType::EQREF.into()))
+        {
+            bail!(self.offset, "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`");
+        }
+        self.check_binary_op(ty)
+    }
+
     fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
         let ty = self.check_memarg(memarg)?;
         self.pop_operand(Some(ty))?;
@@ -2293,154 +2367,154 @@ where
         self.check_atomic_store(memarg, ValType::I64)
     }
     fn visit_i32_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i64_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
     }
     fn visit_i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_memory_atomic_notify(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_memory_atomic_wait32(&mut self, memarg: MemArg) -> Self::Output {
         let ty = self.check_shared_memarg(memarg)?;
diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs
index fcb3acc5..6b6f6211 100644
--- a/crates/wasmprinter/src/operator.rs
+++ b/crates/wasmprinter/src/operator.rs
@@ -1155,6 +1155,13 @@ macro_rules! define_visit {
     (name Delegate) => ("delegate");
     (name GlobalAtomicGet) => ("global.atomic.get");
     (name GlobalAtomicSet) => ("global.atomic.set");
+    (name GlobalAtomicRmwAdd) => ("global.atomic.rmw.add");
+    (name GlobalAtomicRmwSub) => ("global.atomic.rmw.sub");
+    (name GlobalAtomicRmwAnd) => ("global.atomic.rmw.and");
+    (name GlobalAtomicRmwOr) => ("global.atomic.rmw.or");
+    (name GlobalAtomicRmwXor) => ("global.atomic.rmw.xor");
+    (name GlobalAtomicRmwXchg) => ("global.atomic.rmw.xchg");
+    (name GlobalAtomicRmwCmpxchg) => ("global.atomic.rmw.cmpxchg");
 }
 
 impl<'a> VisitOperator<'a> for PrintOperator<'_, '_> {
diff --git a/crates/wast/src/core/expr.rs b/crates/wast/src/core/expr.rs
index df0abb7c..df585c22 100644
--- a/crates/wast/src/core/expr.rs
+++ b/crates/wast/src/core/expr.rs
@@ -803,6 +803,13 @@ instructions! {
         // proposal: shared-everything-threads
         GlobalAtomicGet(OrderedAccess<'a>) : [0xfe, 0x4f] : "global.atomic.get",
         GlobalAtomicSet(OrderedAccess<'a>) : [0xfe, 0x50] : "global.atomic.set",
+        GlobalAtomicRmwAdd(OrderedAccess<'a>) : [0xfe, 0x51] : "global.atomic.rmw.add",
+        GlobalAtomicRmwSub(OrderedAccess<'a>) : [0xfe, 0x52] : "global.atomic.rmw.sub",
+        GlobalAtomicRmwAnd(OrderedAccess<'a>) : [0xfe, 0x53] : "global.atomic.rmw.and",
+        GlobalAtomicRmwOr(OrderedAccess<'a>) : [0xfe, 0x54] : "global.atomic.rmw.or",
+        GlobalAtomicRmwXor(OrderedAccess<'a>) : [0xfe, 0x55] : "global.atomic.rmw.xor",
+        GlobalAtomicRmwXchg(OrderedAccess<'a>) : [0xfe, 0x56] : "global.atomic.rmw.xchg",
+        GlobalAtomicRmwCmpxchg(OrderedAccess<'a>) : [0xfe, 0x57] : "global.atomic.rmw.cmpxchg",
 
         // proposal: simd
         //
diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs
index f17590bb..b73195cb 100644
--- a/crates/wast/src/core/resolve/names.rs
+++ b/crates/wast/src/core/resolve/names.rs
@@ -457,7 +457,15 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
                 self.resolver.resolve(i, Ns::Global)?;
             }
 
-            GlobalAtomicSet(i) | GlobalAtomicGet(i) => {
+            GlobalAtomicSet(i)
+            | GlobalAtomicGet(i)
+            | GlobalAtomicRmwAdd(i)
+            | GlobalAtomicRmwSub(i)
+            | GlobalAtomicRmwAnd(i)
+            | GlobalAtomicRmwOr(i)
+            | GlobalAtomicRmwXor(i)
+            | GlobalAtomicRmwXchg(i)
+            | GlobalAtomicRmwCmpxchg(i) => {
                 self.resolver.resolve(&mut i.index, Ns::Global)?;
             }
 


Test patch:
diff --git a/tests/local/shared-everything-threads/global.wast b/tests/local/shared-everything-threads/global.wast
index 2281017c..ad33bf2b 100644
--- a/tests/local/shared-everything-threads/global.wast
+++ b/tests/local/shared-everything-threads/global.wast
@@ -1,4 +1,40 @@
-;; Styled after ../../testsuite/global.wast
+;; Check shared attribute.
+
+(module
+  ;; Imported.
+  (global (import "spectest" "global_i32") (shared i32))
+  (global (import "spectest" "global_i32_mut") (shared mut i32))
+  (global (import "spectest" "global_i64") (shared i64))
+  (global (import "spectest" "global_i64_mut") (shared mut i64))
+  (global (import "spectest" "global_f32") (shared i32))
+  (global (import "spectest" "global_f32_mut") (shared mut f32))
+  (global (import "spectest" "global_f64") (shared f64))
+  (global (import "spectest" "global_f64_mut") (shared mut f64))
+  (global (import "spectest" "global_v128") (shared v128))
+  (global (import "spectest" "global_v128_mut") (shared mut v128))
+
+  ;; Initialized.
+  (global (shared i32) (i32.const 0))
+  (global (shared mut i32) (i32.const 0))
+  (global (shared i64) (i64.const 0))
+  (global (shared mut i64) (i64.const 0))
+  (global (shared f32) (f32.const 0))
+  (global (shared mut f32) (f32.const 0))
+  (global (shared f64) (f64.const 0))
+  (global (shared mut f64) (f64.const 0))
+  (global (shared v128) (v128.const i64x2 0 0))
+  (global (shared mut v128) (v128.const i64x2 0 0))
+)
+
+(assert_malformed
+  (module quote "(global (mut shared i64) (i64.const -1))")
+  "unexpected token")
+
+(assert_invalid
+  (module (global $a (import "spectest" "global_ref") (shared funcref)))
+  "shared value type")
+
+;; Check global.atomic.get, global.atomic.set.
 
 (module
   (global $a (import "spectest" "global_i32") (shared i32))
@@ -12,10 +48,6 @@
   (func (export "set-e-acqrel") (global.atomic.set acq_rel $e (i64.const 2)))
 )
 
-(assert_malformed
-  (module quote "(global (mut shared i64) (i64.const -1))")
-  "unexpected token")
-
 (assert_invalid
   (module
     (global $a (shared i32) (i32.const 0))
@@ -23,15 +55,316 @@
   )
   "global is immutable")
 
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (result f32) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (global.atomic.set seq_cst $a (f32.const 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (result f32) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (global.atomic.set acq_rel $a (f32.const 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f32) (f32.const 0))
+    (func (result f32) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f32) (f32.const 0))
+    (func (result f32) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
 (assert_invalid
   (module
     (global $a (shared mut f64) (f64.const 0))
-    (func (export "set-shared") (global.atomic.set acq_rel $a (f64.const 1.0)))
+    (func (result f64) (global.atomic.get seq_cst $a))
   )
   "invalid type")
 
 (assert_invalid
   (module
-    (global $a (import "spectest" "global_ref") (shared funcref))
+    (global $a (shared mut f64) (f64.const 0))
+    (func (global.atomic.set seq_cst $a (f64.const 0)))
   )
-  "shared value type")
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f64) (f64.const 0))
+    (func (result f64) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f64) (f64.const 0))
+    (func (global.atomic.set acq_rel $a (f64.const 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f64) (f64.const 0))
+    (func (result f64) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f64) (f64.const 0))
+    (func (result f64) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (global.atomic.set seq_cst $a (v128.const i64x2 0 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (global.atomic.set acq_rel $a (v128.const i64x2 0 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+;; Check global.atomic.rmw.*.
+(module (;i32;)
+  (global $a (import "spectest" "global_i32") (shared mut i32))
+  (global $b (shared mut i32) (i32.const 0))
+  (func (export "rmw-add-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a)
+  (func (export "rmw-add-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b)
+  (func (export "rmw-add-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a)
+  (func (export "rmw-add-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b)
+  (func (export "rmw-sub-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a)
+  (func (export "rmw-sub-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b)
+  (func (export "rmw-sub-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a)
+  (func (export "rmw-sub-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b)
+  (func (export "rmw-and-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a)
+  (func (export "rmw-and-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b)
+  (func (export "rmw-and-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a)
+  (func (export "rmw-and-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b)
+  (func (export "rmw-or-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a)
+  (func (export "rmw-or-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b)
+  (func (export "rmw-or-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a)
+  (func (export "rmw-or-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b)
+  (func (export "rmw-xor-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a)
+  (func (export "rmw-xor-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b)
+  (func (export "rmw-xor-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a)
+  (func (export "rmw-xor-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b)
+  (func (export "rmw-xchg-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a)
+  (func (export "rmw-xchg-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b)
+  (func (export "rmw-xchg-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a)
+  (func (export "rmw-xchg-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b)
+  (func (export "rmw-cmpxchg-i32-seq_cst-$a") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a)
+  (func (export "rmw-cmpxchg-i32-seq_cst-$b") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b)
+  (func (export "rmw-cmpxchg-i32-acq_rel-$a") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a)
+  (func (export "rmw-cmpxchg-i32-acq_rel-$b") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b)
+)
+
+(module (;i64;)
+  (global $a (import "spectest" "global_i64") (shared mut i64))
+  (global $b (shared mut i64) (i64.const 0))
+  (func (export "rmw-add-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a)
+  (func (export "rmw-add-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b)
+  (func (export "rmw-add-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a)
+  (func (export "rmw-add-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b)
+  (func (export "rmw-sub-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a)
+  (func (export "rmw-sub-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b)
+  (func (export "rmw-sub-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a)
+  (func (export "rmw-sub-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b)
+  (func (export "rmw-and-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a)
+  (func (export "rmw-and-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b)
+  (func (export "rmw-and-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a)
+  (func (export "rmw-and-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b)
+  (func (export "rmw-or-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a)
+  (func (export "rmw-or-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b)
+  (func (export "rmw-or-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a)
+  (func (export "rmw-or-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b)
+  (func (export "rmw-xor-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a)
+  (func (export "rmw-xor-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b)
+  (func (export "rmw-xor-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a)
+  (func (export "rmw-xor-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b)
+  (func (export "rmw-xchg-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a)
+  (func (export "rmw-xchg-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b)
+  (func (export "rmw-xchg-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a)
+  (func (export "rmw-xchg-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b)
+  (func (export "rmw-cmpxchg-i64-seq_cst-$a") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a)
+  (func (export "rmw-cmpxchg-i64-seq_cst-$b") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b)
+  (func (export "rmw-cmpxchg-i64-acq_rel-$a") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a)
+  (func (export "rmw-cmpxchg-i64-acq_rel-$b") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b)
+)
+
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast.json b/tests/snapshots/local/shared-everything-threads/global.wast.json
index 1ff22c67..250e98b1 100644
--- a/tests/snapshots/local/shared-everything-threads/global.wast.json
+++ b/tests/snapshots/local/shared-everything-threads/global.wast.json
@@ -8,31 +8,165 @@
     },
     {
       "type": "assert_malformed",
-      "line": 16,
+      "line": 30,
       "filename": "global.1.wat",
       "text": "unexpected token",
       "module_type": "text"
     },
     {
       "type": "assert_invalid",
-      "line": 20,
+      "line": 34,
       "filename": "global.2.wasm",
+      "text": "shared value type",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 39,
+      "filename": "global.3.wasm"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 52,
+      "filename": "global.4.wasm",
       "text": "global is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 27,
-      "filename": "global.3.wasm",
+      "line": 59,
+      "filename": "global.5.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 34,
-      "filename": "global.4.wasm",
-      "text": "shared value type",
+      "line": 66,
+      "filename": "global.6.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 73,
+      "filename": "global.7.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 80,
+      "filename": "global.8.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 87,
+      "filename": "global.9.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 94,
+      "filename": "global.10.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 101,
+      "filename": "global.11.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 108,
+      "filename": "global.12.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 115,
+      "filename": "global.13.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 122,
+      "filename": "global.14.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 129,
+      "filename": "global.15.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 136,
+      "filename": "global.16.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 143,
+      "filename": "global.17.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 150,
+      "filename": "global.18.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 157,
+      "filename": "global.19.wasm",
+      "text": "invalid type",
       "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 164,
+      "filename": "global.20.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 171,
+      "filename": "global.21.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 178,
+      "filename": "global.22.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 185,
+      "filename": "global.23.wasm"
+    },
+    {
+      "type": "module",
+      "line": 278,
+      "filename": "global.24.wasm"
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/0.print b/tests/snapshots/local/shared-everything-threads/global.wast/0.print
index 9fddda89..b79452f3 100644
--- a/tests/snapshots/local/shared-everything-threads/global.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/0.print
@@ -1,26 +1,22 @@
 (module
-  (type (;0;) (func (result i32)))
-  (type (;1;) (func))
-  (import "spectest" "global_i32" (global $a (;0;) (shared i32)))
-  (import "spectest" "global_i64" (global $b (;1;) (shared mut i64)))
-  (func (;0;) (type 0) (result i32)
-    global.atomic.get seq_cst $a
-  )
-  (func (;1;) (type 1)
-    i64.const 1
-    global.atomic.set seq_cst $b
-  )
-  (func (;2;) (type 0) (result i32)
-    global.atomic.get acq_rel $d
-  )
-  (func (;3;) (type 1)
-    i64.const 2
-    global.atomic.set acq_rel $e
-  )
-  (global $d (;2;) (shared i32) i32.const 0)
-  (global $e (;3;) (shared mut i64) i64.const 1)
-  (export "get-a-seqcst" (func 0))
-  (export "set-b-seqcst" (func 1))
-  (export "get-d-acqrel" (func 2))
-  (export "set-e-acqrel" (func 3))
+  (import "spectest" "global_i32" (global (;0;) (shared i32)))
+  (import "spectest" "global_i32_mut" (global (;1;) (shared mut i32)))
+  (import "spectest" "global_i64" (global (;2;) (shared i64)))
+  (import "spectest" "global_i64_mut" (global (;3;) (shared mut i64)))
+  (import "spectest" "global_f32" (global (;4;) (shared i32)))
+  (import "spectest" "global_f32_mut" (global (;5;) (shared mut f32)))
+  (import "spectest" "global_f64" (global (;6;) (shared f64)))
+  (import "spectest" "global_f64_mut" (global (;7;) (shared mut f64)))
+  (import "spectest" "global_v128" (global (;8;) (shared v128)))
+  (import "spectest" "global_v128_mut" (global (;9;) (shared mut v128)))
+  (global (;10;) (shared i32) i32.const 0)
+  (global (;11;) (shared mut i32) i32.const 0)
+  (global (;12;) (shared i64) i64.const 0)
+  (global (;13;) (shared mut i64) i64.const 0)
+  (global (;14;) (shared f32) f32.const 0x0p+0 (;=0;))
+  (global (;15;) (shared mut f32) f32.const 0x0p+0 (;=0;))
+  (global (;16;) (shared f64) f64.const 0x0p+0 (;=0;))
+  (global (;17;) (shared mut f64) f64.const 0x0p+0 (;=0;))
+  (global (;18;) (shared v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
+  (global (;19;) (shared mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
 )
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/23.print b/tests/snapshots/local/shared-everything-threads/global.wast/23.print
new file mode 100644
index 00000000..0e052f4e
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/23.print
@@ -0,0 +1,150 @@
+(module
+  (type (;0;) (func (param i32) (result i32)))
+  (type (;1;) (func (param i32 i32) (result i32)))
+  (import "spectest" "global_i32" (global $a (;0;) (shared mut i32)))
+  (func (;0;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a
+  )
+  (func (;1;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b
+  )
+  (func (;2;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a
+  )
+  (func (;3;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b
+  )
+  (func (;4;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a
+  )
+  (func (;5;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b
+  )
+  (func (;6;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a
+  )
+  (func (;7;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b
+  )
+  (func (;8;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a
+  )
+  (func (;9;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b
+  )
+  (func (;10;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a
+  )
+  (func (;11;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b
+  )
+  (func (;12;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a
+  )
+  (func (;13;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b
+  )
+  (func (;14;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a
+  )
+  (func (;15;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b
+  )
+  (func (;16;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a
+  )
+  (func (;17;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b
+  )
+  (func (;18;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a
+  )
+  (func (;19;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b
+  )
+  (func (;20;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a
+  )
+  (func (;21;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b
+  )
+  (func (;22;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a
+  )
+  (func (;23;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b
+  )
+  (func (;24;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a
+  )
+  (func (;25;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b
+  )
+  (func (;26;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a
+  )
+  (func (;27;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b
+  )
+  (global $b (;1;) (shared mut i32) i32.const 0)
+  (export "rmw-add-i32-seq_cst-$a" (func 0))
+  (export "rmw-add-i32-seq_cst-$b" (func 1))
+  (export "rmw-add-i32-acq_rel-$a" (func 2))
+  (export "rmw-add-i32-acq_rel-$b" (func 3))
+  (export "rmw-sub-i32-seq_cst-$a" (func 4))
+  (export "rmw-sub-i32-seq_cst-$b" (func 5))
+  (export "rmw-sub-i32-acq_rel-$a" (func 6))
+  (export "rmw-sub-i32-acq_rel-$b" (func 7))
+  (export "rmw-and-i32-seq_cst-$a" (func 8))
+  (export "rmw-and-i32-seq_cst-$b" (func 9))
+  (export "rmw-and-i32-acq_rel-$a" (func 10))
+  (export "rmw-and-i32-acq_rel-$b" (func 11))
+  (export "rmw-or-i32-seq_cst-$a" (func 12))
+  (export "rmw-or-i32-seq_cst-$b" (func 13))
+  (export "rmw-or-i32-acq_rel-$a" (func 14))
+  (export "rmw-or-i32-acq_rel-$b" (func 15))
+  (export "rmw-xor-i32-seq_cst-$a" (func 16))
+  (export "rmw-xor-i32-seq_cst-$b" (func 17))
+  (export "rmw-xor-i32-acq_rel-$a" (func 18))
+  (export "rmw-xor-i32-acq_rel-$b" (func 19))
+  (export "rmw-xchg-i32-seq_cst-$a" (func 20))
+  (export "rmw-xchg-i32-seq_cst-$b" (func 21))
+  (export "rmw-xchg-i32-acq_rel-$a" (func 22))
+  (export "rmw-xchg-i32-acq_rel-$b" (func 23))
+  (export "rmw-cmpxchg-i32-seq_cst-$a" (func 24))
+  (export "rmw-cmpxchg-i32-seq_cst-$b" (func 25))
+  (export "rmw-cmpxchg-i32-acq_rel-$a" (func 26))
+  (export "rmw-cmpxchg-i32-acq_rel-$b" (func 27))
+)
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/24.print b/tests/snapshots/local/shared-everything-threads/global.wast/24.print
new file mode 100644
index 00000000..1aac4333
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/24.print
@@ -0,0 +1,150 @@
+(module
+  (type (;0;) (func (param i64) (result i64)))
+  (type (;1;) (func (param i64 i64) (result i64)))
+  (import "spectest" "global_i64" (global $a (;0;) (shared mut i64)))
+  (func (;0;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a
+  )
+  (func (;1;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b
+  )
+  (func (;2;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a
+  )
+  (func (;3;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b
+  )
+  (func (;4;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a
+  )
+  (func (;5;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b
+  )
+  (func (;6;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a
+  )
+  (func (;7;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b
+  )
+  (func (;8;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a
+  )
+  (func (;9;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b
+  )
+  (func (;10;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a
+  )
+  (func (;11;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b
+  )
+  (func (;12;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a
+  )
+  (func (;13;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b
+  )
+  (func (;14;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a
+  )
+  (func (;15;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b
+  )
+  (func (;16;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a
+  )
+  (func (;17;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b
+  )
+  (func (;18;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a
+  )
+  (func (;19;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b
+  )
+  (func (;20;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a
+  )
+  (func (;21;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b
+  )
+  (func (;22;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a
+  )
+  (func (;23;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b
+  )
+  (func (;24;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a
+  )
+  (func (;25;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b
+  )
+  (func (;26;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a
+  )
+  (func (;27;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b
+  )
+  (global $b (;1;) (shared mut i64) i64.const 0)
+  (export "rmw-add-i64-seq_cst-$a" (func 0))
+  (export "rmw-add-i64-seq_cst-$b" (func 1))
+  (export "rmw-add-i64-acq_rel-$a" (func 2))
+  (export "rmw-add-i64-acq_rel-$b" (func 3))
+  (export "rmw-sub-i64-seq_cst-$a" (func 4))
+  (export "rmw-sub-i64-seq_cst-$b" (func 5))
+  (export "rmw-sub-i64-acq_rel-$a" (func 6))
+  (export "rmw-sub-i64-acq_rel-$b" (func 7))
+  (export "rmw-and-i64-seq_cst-$a" (func 8))
+  (export "rmw-and-i64-seq_cst-$b" (func 9))
+  (export "rmw-and-i64-acq_rel-$a" (func 10))
+  (export "rmw-and-i64-acq_rel-$b" (func 11))
+  (export "rmw-or-i64-seq_cst-$a" (func 12))
+  (export "rmw-or-i64-seq_cst-$b" (func 13))
+  (export "rmw-or-i64-acq_rel-$a" (func 14))
+  (export "rmw-or-i64-acq_rel-$b" (func 15))
+  (export "rmw-xor-i64-seq_cst-$a" (func 16))
+  (export "rmw-xor-i64-seq_cst-$b" (func 17))
+  (export "rmw-xor-i64-acq_rel-$a" (func 18))
+  (export "rmw-xor-i64-acq_rel-$b" (func 19))
+  (export "rmw-xchg-i64-seq_cst-$a" (func 20))
+  (export "rmw-xchg-i64-seq_cst-$b" (func 21))
+  (export "rmw-xchg-i64-acq_rel-$a" (func 22))
+  (export "rmw-xchg-i64-acq_rel-$b" (func 23))
+  (export "rmw-cmpxchg-i64-seq_cst-$a" (func 24))
+  (export "rmw-cmpxchg-i64-seq_cst-$b" (func 25))
+  (export "rmw-cmpxchg-i64-acq_rel-$a" (func 26))
+  (export "rmw-cmpxchg-i64-acq_rel-$b" (func 27))
+)
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/3.print b/tests/snapshots/local/shared-everything-threads/global.wast/3.print
new file mode 100644
index 00000000..9fddda89
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/3.print
@@ -0,0 +1,26 @@
+(module
+  (type (;0;) (func (result i32)))
+  (type (;1;) (func))
+  (import "spectest" "global_i32" (global $a (;0;) (shared i32)))
+  (import "spectest" "global_i64" (global $b (;1;) (shared mut i64)))
+  (func (;0;) (type 0) (result i32)
+    global.atomic.get seq_cst $a
+  )
+  (func (;1;) (type 1)
+    i64.const 1
+    global.atomic.set seq_cst $b
+  )
+  (func (;2;) (type 0) (result i32)
+    global.atomic.get acq_rel $d
+  )
+  (func (;3;) (type 1)
+    i64.const 2
+    global.atomic.set acq_rel $e
+  )
+  (global $d (;2;) (shared i32) i32.const 0)
+  (global $e (;3;) (shared mut i64) i64.const 1)
+  (export "get-a-seqcst" (func 0))
+  (export "set-b-seqcst" (func 1))
+  (export "get-d-acqrel" (func 2))
+  (export "set-e-acqrel" (func 3))
+)