test
diff --git a/test/lit/passes/cfp_local.wast b/test/lit/passes/cfp_local.wast
index 46e8e0b..7229ae3 100644
--- a/test/lit/passes/cfp_local.wast
+++ b/test/lit/passes/cfp_local.wast
@@ -1730,6 +1730,242 @@
   )
 )
 
+;; As before, but the vtables are in *mutable* globals, which prevents
+;; optimization.
+(module
+  ;; A function type that receives |this| and returns an i32.
+  ;; CHECK:      (type $parent (struct (field (ref $parent.vtable))))
+
+  ;; CHECK:      (type $func (func (param anyref) (result i32)))
+  (type $func (func (param anyref) (result i32)))
+
+  ;; A parent struct type, with a vtable.
+  (type $parent (struct (field (ref $parent.vtable))))
+
+  ;; CHECK:      (type $parent.vtable (struct (field (ref $func))))
+  (type $parent.vtable (struct (field (ref $func))))
+
+  ;; A child struct type that extends the parent. It adds a field to both the
+  ;; struct and its vtable.
+  ;; CHECK:      (type $child.vtable (struct (field (ref $func)) (field (ref $func))) (extends $parent.vtable))
+  (type $child.vtable (struct (field (ref $func)) (field (ref $func)))  (extends $parent.vtable))
+
+  ;; CHECK:      (type $none_=>_anyref (func (result anyref)))
+
+  ;; CHECK:      (type $child (struct (field (ref $child.vtable)) (field i32)) (extends $parent))
+  (type $child (struct (field (ref $child.vtable)) (field i32)) (extends $parent))
+
+  ;; CHECK:      (type $none_=>_i32 (func (result i32)))
+
+  ;; CHECK:      (global $parent.vtable (mut (ref $parent.vtable)) (struct.new_with_rtt $parent.vtable
+  ;; CHECK-NEXT:  (ref.func $parent.func)
+  ;; CHECK-NEXT:  (rtt.canon $parent.vtable)
+  ;; CHECK-NEXT: ))
+  (global $parent.vtable (mut (ref $parent.vtable))
+    (struct.new_with_rtt $parent.vtable
+      (ref.func $parent.func)
+      (rtt.canon $parent.vtable)
+    )
+  )
+  ;; CHECK:      (global $child.vtable (mut (ref $child.vtable)) (struct.new_with_rtt $child.vtable
+  ;; CHECK-NEXT:  (ref.func $child.func)
+  ;; CHECK-NEXT:  (ref.func $child.func)
+  ;; CHECK-NEXT:  (rtt.canon $child.vtable)
+  ;; CHECK-NEXT: ))
+  (global $child.vtable (mut (ref $child.vtable))
+    (struct.new_with_rtt $child.vtable
+      (ref.func $child.func)
+      (ref.func $child.func)
+      (rtt.canon $child.vtable)
+    )
+  )
+
+  ;; CHECK:      (elem declare func $child.func $parent.func)
+
+  ;; CHECK:      (func $keepalive-parent (result anyref)
+  ;; CHECK-NEXT:  (struct.new_with_rtt $parent
+  ;; CHECK-NEXT:   (struct.new_with_rtt $parent.vtable
+  ;; CHECK-NEXT:    (ref.func $parent.func)
+  ;; CHECK-NEXT:    (rtt.canon $parent.vtable)
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:   (rtt.canon $parent)
+  ;; CHECK-NEXT:  )
+  ;; CHECK-NEXT: )
+  (func $keepalive-parent (result anyref)
+    (struct.new_with_rtt $parent
+      (struct.new_with_rtt $parent.vtable
+        (ref.func $parent.func)
+        (rtt.canon $parent.vtable)
+      )
+      (rtt.canon $parent)
+    )
+  )
+
+  ;; CHECK:      (func $keepalive-child (result anyref)
+  ;; CHECK-NEXT:  (struct.new_with_rtt $child
+  ;; CHECK-NEXT:   (struct.new_with_rtt $child.vtable
+  ;; CHECK-NEXT:    (ref.func $child.func)
+  ;; CHECK-NEXT:    (ref.func $child.func)
+  ;; CHECK-NEXT:    (rtt.canon $child.vtable)
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:   (i32.const 9999)
+  ;; CHECK-NEXT:   (rtt.canon $child)
+  ;; CHECK-NEXT:  )
+  ;; CHECK-NEXT: )
+  (func $keepalive-child (result anyref)
+    (struct.new_with_rtt $child
+      (struct.new_with_rtt $child.vtable
+        (ref.func $child.func)
+        (ref.func $child.func)
+        (rtt.canon $child.vtable)
+      )
+      (i32.const 9999)
+      (rtt.canon $child)
+    )
+  )
+
+  ;; CHECK:      (func $parent.func (param $this anyref) (result i32)
+  ;; CHECK-NEXT:  (i32.const 128)
+  ;; CHECK-NEXT: )
+  (func $parent.func (param $this anyref) (result i32)
+    (i32.const 128)
+  )
+
+  ;; CHECK:      (func $child.func (param $this anyref) (result i32)
+  ;; CHECK-NEXT:  (i32.const 4096)
+  ;; CHECK-NEXT: )
+  (func $child.func (param $this anyref) (result i32)
+    (i32.const 4096)
+  )
+
+  ;; CHECK:      (func $create-parent-call-parent (result i32)
+  ;; CHECK-NEXT:  (local $x (ref null $parent))
+  ;; CHECK-NEXT:  (local.set $x
+  ;; CHECK-NEXT:   (struct.new_with_rtt $parent
+  ;; CHECK-NEXT:    (global.get $parent.vtable)
+  ;; CHECK-NEXT:    (rtt.canon $parent)
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:  )
+  ;; CHECK-NEXT:  (i32.add
+  ;; CHECK-NEXT:   (call_ref
+  ;; CHECK-NEXT:    (local.get $x)
+  ;; CHECK-NEXT:    (struct.get $parent.vtable 0
+  ;; CHECK-NEXT:     (struct.get $parent 0
+  ;; CHECK-NEXT:      (local.get $x)
+  ;; CHECK-NEXT:     )
+  ;; CHECK-NEXT:    )
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:   (call_ref
+  ;; CHECK-NEXT:    (local.get $x)
+  ;; CHECK-NEXT:    (struct.get $parent.vtable 0
+  ;; CHECK-NEXT:     (struct.get $parent 0
+  ;; CHECK-NEXT:      (local.get $x)
+  ;; CHECK-NEXT:     )
+  ;; CHECK-NEXT:    )
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:  )
+  ;; CHECK-NEXT: )
+  (func $create-parent-call-parent (result i32)
+    (local $x (ref null $parent))
+    (local.set $x
+      (struct.new_with_rtt $parent
+        ;; To be able to infer the precise type of the parent's vtable, we need
+        ;; to know what is in this global. As the globals are mutable, we
+        ;; fail to optimize here.
+        (global.get $parent.vtable)
+        (rtt.canon $parent)
+      )
+    )
+    (i32.add
+      (call_ref
+        (local.get $x)
+        (struct.get $parent.vtable 0
+          (struct.get $parent 0
+            (local.get $x)
+          )
+        )
+      )
+      (call_ref
+        (local.get $x)
+        (struct.get $parent.vtable 0
+          (struct.get $parent 0
+            (local.get $x)
+          )
+        )
+      )
+    )
+  )
+
+  ;; CHECK:      (func $create-child-call-parent (result i32)
+  ;; CHECK-NEXT:  (local $x (ref null $parent))
+  ;; CHECK-NEXT:  (local.set $x
+  ;; CHECK-NEXT:   (struct.new_with_rtt $child
+  ;; CHECK-NEXT:    (global.get $child.vtable)
+  ;; CHECK-NEXT:    (i32.const 42)
+  ;; CHECK-NEXT:    (rtt.canon $child)
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:  )
+  ;; CHECK-NEXT:  (i32.add
+  ;; CHECK-NEXT:   (call_ref
+  ;; CHECK-NEXT:    (local.get $x)
+  ;; CHECK-NEXT:    (block (result (ref $func))
+  ;; CHECK-NEXT:     (drop
+  ;; CHECK-NEXT:      (ref.as_non_null
+  ;; CHECK-NEXT:       (struct.get $parent 0
+  ;; CHECK-NEXT:        (local.get $x)
+  ;; CHECK-NEXT:       )
+  ;; CHECK-NEXT:      )
+  ;; CHECK-NEXT:     )
+  ;; CHECK-NEXT:     (ref.func $child.func)
+  ;; CHECK-NEXT:    )
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:   (call_ref
+  ;; CHECK-NEXT:    (local.get $x)
+  ;; CHECK-NEXT:    (block (result (ref $func))
+  ;; CHECK-NEXT:     (drop
+  ;; CHECK-NEXT:      (ref.as_non_null
+  ;; CHECK-NEXT:       (struct.get $parent 0
+  ;; CHECK-NEXT:        (local.get $x)
+  ;; CHECK-NEXT:       )
+  ;; CHECK-NEXT:      )
+  ;; CHECK-NEXT:     )
+  ;; CHECK-NEXT:     (ref.func $child.func)
+  ;; CHECK-NEXT:    )
+  ;; CHECK-NEXT:   )
+  ;; CHECK-NEXT:  )
+  ;; CHECK-NEXT: )
+  (func $create-child-call-parent (result i32)
+    (local $x (ref null $parent))
+    (local.set $x
+      (struct.new_with_rtt $child
+        (global.get $child.vtable)
+        (i32.const 42)
+        (rtt.canon $child)
+      )
+    )
+    ;; As above, we don't need global info for the child, so we do optimize
+    ;; here.
+    (i32.add
+      (call_ref
+        (local.get $x)
+        (struct.get $parent.vtable 0
+          (struct.get $parent 0
+            (local.get $x)
+          )
+        )
+      )
+      (call_ref
+        (local.get $x)
+        (struct.get $parent.vtable 0
+          (struct.get $parent 0
+            (local.get $x)
+          )
+        )
+      )
+    )
+  )
+)
+
 (module
   ;; CHECK:      (type $E (struct (field i64) (field i64) (field i64) (field (mut i64))) (extends $D))
   (type $E (struct i64 i64 i64 (mut i64)) (extends $D))