Bug 1488205 - Repurpose the --wasm-gc switch for GC. r=jseward
authorLars T Hansen <lhansen@mozilla.com>
Fri, 01 Mar 2019 09:55:31 +0100
changeset 462893 8085449bd4261f957dff79032f75d95b94fab787
parent 462892 80c1ab6a0f32412c406d1eb581ea667d023f8742
child 462894 1d4dcfddc3f8483e60105dd19f03481f28518664
push id35662
push useraiakab@mozilla.com
push dateThu, 07 Mar 2019 21:58:58 +0000
treeherdermozilla-central@af29567ecdba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjseward
bugs1488205
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1488205 - Repurpose the --wasm-gc switch for GC. r=jseward Differential Revision: https://phabricator.services.mozilla.com/D21692
js/public/ContextOptions.h
js/src/builtin/TestingFunctions.cpp
js/src/jit-test/lib/wasm-binary.js
js/src/jit-test/tests/wasm/binary.js
js/src/jit-test/tests/wasm/gc/directives.txt
js/src/jit-test/tests/wasm/gc/disabled-ref.js
js/src/jit-test/tests/wasm/gc/ion-and-baseline.js
js/src/jit/CompileWrappers.cpp
js/src/jit/CompileWrappers.h
js/src/shell/js.cpp
js/src/wasm/WasmAST.h
js/src/wasm/WasmBaselineCompile.cpp
js/src/wasm/WasmCompile.cpp
js/src/wasm/WasmIonCompile.cpp
js/src/wasm/WasmJS.cpp
js/src/wasm/WasmJS.h
js/src/wasm/WasmOpIter.h
js/src/wasm/WasmTable.h
js/src/wasm/WasmTextToBinary.cpp
js/src/wasm/WasmTypes.h
js/src/wasm/WasmValidate.cpp
js/src/wasm/WasmValidate.h
js/xpconnect/src/XPCJSContext.cpp
--- a/js/public/ContextOptions.h
+++ b/js/public/ContextOptions.h
@@ -29,17 +29,17 @@ class JS_PUBLIC_API ContextOptions {
         wasm_(true),
 #endif
         wasmVerbose_(false),
         wasmBaseline_(true),
         wasmIon_(true),
 #ifdef ENABLE_WASM_CRANELIFT
         wasmCranelift_(false),
 #endif
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
         wasmGc_(false),
 #endif
         testWasmAwaitTier2_(false),
         throwOnAsmJSValidationFailure_(false),
         nativeRegExp_(true),
         asyncStack_(true),
         throwOnDebuggeeWouldRun_(true),
         dumpStackOnDebuggeeWouldRun_(false),
@@ -120,17 +120,17 @@ class JS_PUBLIC_API ContextOptions {
 #endif
 
   bool testWasmAwaitTier2() const { return testWasmAwaitTier2_; }
   ContextOptions& setTestWasmAwaitTier2(bool flag) {
     testWasmAwaitTier2_ = flag;
     return *this;
   }
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   bool wasmGc() const { return wasmGc_; }
   ContextOptions& setWasmGc(bool flag) {
     wasmGc_ = flag;
     return *this;
   }
 #endif
 
   bool throwOnAsmJSValidationFailure() const {
@@ -211,34 +211,34 @@ class JS_PUBLIC_API ContextOptions {
 
   void disableOptionsForSafeMode() {
     setBaseline(false);
     setIon(false);
     setAsmJS(false);
     setWasm(false);
     setWasmBaseline(false);
     setWasmIon(false);
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
     setWasmGc(false);
 #endif
     setNativeRegExp(false);
   }
 
  private:
   bool baseline_ : 1;
   bool ion_ : 1;
   bool asmJS_ : 1;
   bool wasm_ : 1;
   bool wasmVerbose_ : 1;
   bool wasmBaseline_ : 1;
   bool wasmIon_ : 1;
 #ifdef ENABLE_WASM_CRANELIFT
   bool wasmCranelift_ : 1;
 #endif
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   bool wasmGc_ : 1;
 #endif
   bool testWasmAwaitTier2_ : 1;
   bool throwOnAsmJSValidationFailure_ : 1;
   bool nativeRegExp_ : 1;
   bool asyncStack_ : 1;
   bool throwOnDebuggeeWouldRun_ : 1;
   bool dumpStackOnDebuggeeWouldRun_ : 1;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -696,21 +696,17 @@ static bool WasmBulkMemSupported(JSConte
 static bool WasmReftypesEnabled(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setBoolean(wasm::HasReftypesSupport(cx));
   return true;
 }
 
 static bool WasmGcEnabled(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
-#ifdef ENABLE_WASM_GC
-  args.rval().setBoolean(wasm::HasReftypesSupport(cx));
-#else
-  args.rval().setBoolean(false);
-#endif
+  args.rval().setBoolean(wasm::HasGcSupport(cx));
   return true;
 }
 
 static bool WasmDebugSupport(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setBoolean(cx->options().wasmBaseline() &&
                          wasm::BaselineCanCompile());
   return true;
@@ -6027,25 +6023,25 @@ gc::ZealModeHelpText),
 "  until background compilation is complete."),
 
     JS_FN_HELP("wasmHasTier2CompilationCompleted", WasmHasTier2CompilationCompleted, 1, 0,
 "wasmHasTier2CompilationCompleted(module)",
 "  Returns a boolean indicating whether a given module has finished compiled code for tier2. \n"
 "This will return true early if compilation isn't two-tiered. "),
 
     JS_FN_HELP("wasmReftypesEnabled", WasmReftypesEnabled, 1, 0,
-"wasmReftypesEnabled(bool)",
+"wasmReftypesEnabled()",
 "  Returns a boolean indicating whether the WebAssembly reftypes proposal is enabled."),
 
     JS_FN_HELP("wasmGcEnabled", WasmGcEnabled, 1, 0,
-"wasmGcEnabled(bool)",
+"wasmGcEnabled()",
 "  Returns a boolean indicating whether the WebAssembly GC types proposal is enabled."),
 
     JS_FN_HELP("wasmDebugSupport", WasmDebugSupport, 1, 0,
-"wasmDebugSupport(bool)",
+"wasmDebugSupport()",
 "  Returns a boolean indicating whether the WebAssembly compilers support debugging."),
 
     JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
 "isLazyFunction(fun)",
 "  True if fun is a lazy JSFunction."),
 
     JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0,
 "isRelazifiableFunction(fun)",
--- a/js/src/jit-test/lib/wasm-binary.js
+++ b/js/src/jit-test/lib/wasm-binary.js
@@ -104,16 +104,64 @@ const RefFuncCode      = 0xd2;
 
 const FirstInvalidOpcode = 0xc5;
 const LastInvalidOpcode = 0xfb;
 const MiscPrefix = 0xfc;
 const SimdPrefix = 0xfd;
 const ThreadPrefix = 0xfe;
 const MozPrefix = 0xff;
 
+// See WasmConstants.h for documentation.
+// Limit this to a group of 8 per line.
+
+const definedOpcodes =
+    [0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+     0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+     0x10, 0x11,
+     0x1a, 0x1b,
+     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+     0xc0, 0xc1, 0xc2, 0xc3, 0xc4,
+     0xd0, 0xd1, 0xd2,
+     0xf0,
+     0xfc, 0xfe, 0xff ];
+
+const undefinedOpcodes = (function () {
+    let a = [];
+    let j = 0;
+    let i = 0;
+    while (i < 256) {
+        while (definedOpcodes[j] > i)
+            a.push(i++);
+        assertEq(definedOpcodes[j], i);
+        i++;
+        j++;
+    }
+    assertEq(definedOpcodes.length + a.length, 256);
+    return a;
+})();
+
 // Secondary opcode bytes for misc prefix
 const MemoryInitCode = 0x08;    // Pending
 const DataDropCode = 0x09;      // Pending
 const MemoryCopyCode = 0x0a;    // Pending
 const MemoryFillCode = 0x0b;    // Pending
 const TableInitCode = 0x0c;     // Pending
 const ElemDropCode = 0x0d;      // Pending
 const TableCopyCode = 0x0e;     // Pending
--- a/js/src/jit-test/tests/wasm/binary.js
+++ b/js/src/jit-test/tests/wasm/binary.js
@@ -230,18 +230,18 @@ assertErrorMessage(() => wasmEval(module
     nameSection([moduleNameSubsection('hi')])])
 ).f(), RuntimeError, /unreachable/);
 
 // Diagnose nonstandard block signature types.
 for (var bad of [0xff, 0, 1, 0x3f])
     assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[BlockCode, bad, EndCode]})])])), CompileError, /invalid inline block type/);
 
 // Ensure all invalid opcodes rejected
-for (let i = FirstInvalidOpcode; i <= LastInvalidOpcode; i++) {
-    let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[i]})])]);
+for (let op of undefinedOpcodes) {
+    let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[op]})])]);
     assertErrorMessage(() => wasmEval(binary), CompileError, /unrecognized opcode/);
     assertEq(WebAssembly.validate(binary), false);
 }
 
 // Prefixed opcodes
 
 function checkIllegalPrefixed(prefix, opcode) {
     let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[prefix, opcode]})])]);
--- a/js/src/jit-test/tests/wasm/gc/directives.txt
+++ b/js/src/jit-test/tests/wasm/gc/directives.txt
@@ -1,1 +1,1 @@
-|jit-test| test-also=--wasm-gc; test-also=--wasm-gc --wasm-compiler=ion; test-also=--wasm-gc --wasm-compiler=baseline; include:wasm.js
+|jit-test| test-also=--wasm-gc; test-also=--wasm-compiler=ion; test-also=--wasm-compiler=baseline; test-also=--wasm-gc --wasm-compiler=baseline; include:wasm.js
--- a/js/src/jit-test/tests/wasm/gc/disabled-ref.js
+++ b/js/src/jit-test/tests/wasm/gc/disabled-ref.js
@@ -1,5 +1,5 @@
 // |jit-test| skip-if: wasmGcEnabled()
 
 wasmCompilationShouldFail(
     wasmTextToBinary(`(module (func (param (ref 0)) (unreachable)))`),
-    /reference types not enabled/);
+    /\(ref T\) types not enabled/);
--- a/js/src/jit-test/tests/wasm/gc/ion-and-baseline.js
+++ b/js/src/jit-test/tests/wasm/gc/ion-and-baseline.js
@@ -1,33 +1,31 @@
-// |jit-test| skip-if: !wasmReftypesEnabled()
+// |jit-test| skip-if: !wasmGcEnabled()
 
 // Attempt to test intercalls from ion to baseline and back.
 //
 // We get into this situation when the modules are compiled with different
 // tiering policies, or one tiers up before the other, or (for now) one opts
 // into gc and is baseline-compiled and the other does not and is ion-compiled.
 // There are lots of variables here.  Generally, a small module will be
 // ion-compiled unless there's reason to baseline-compile it, so we're likely
 // actually testing something here.
 //
 // Some logging with printf confirms that refmod is baseline-compiled and
 // nonrefmod is ion-compiled at present, with --wasm-gc enabled.
 
-// Ion can't talk about references yet *but* we can call indirect from Ion to a
-// baseline module that has exported a function that accepts or returns anyref,
-// without the caller knowing this or having to declare it.  All such calls
-// should fail in an orderly manner with a type mismatch, at the point of the
-// call.
-
 var refmod = new WebAssembly.Module(wasmTextToBinary(
     `(module
+      (gc_feature_opt_in 3)
       (import $tbl "" "tbl" (table 4 funcref))
       (import $print "" "print" (func (param i32)))
 
+      ;; Just a dummy
+      (type $s (struct (field i32)))
+
       (type $htype (func (param anyref)))
       (type $itype (func (result anyref)))
 
       (elem (i32.const 0) $f $g)
 
       (func $f (param anyref)
        (call $print (i32.const 1)))
 
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -213,25 +213,18 @@ bool CompileRealm::hasAllocationMetadata
 void CompileRealm::setSingletonsAsValues() {
   realm()->behaviors().setSingletonsAsValues();
 }
 
 JitCompileOptions::JitCompileOptions()
     : cloneSingletons_(false),
       profilerSlowAssertionsEnabled_(false),
       offThreadCompilationAvailable_(false)
-#ifdef ENABLE_WASM_REFTYPES
-      ,
-      wasmGcEnabled_(false)
-#endif
 {
 }
 
 JitCompileOptions::JitCompileOptions(JSContext* cx) {
   cloneSingletons_ = cx->realm()->creationOptions().cloneSingletons();
   profilerSlowAssertionsEnabled_ =
       cx->runtime()->geckoProfiler().enabled() &&
       cx->runtime()->geckoProfiler().slowAssertionsEnabled();
   offThreadCompilationAvailable_ = OffThreadCompilationAvailable(cx);
-#ifdef ENABLE_WASM_REFTYPES
-  wasmGcEnabled_ = wasm::HasReftypesSupport(cx);
-#endif
 }
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -126,25 +126,18 @@ class JitCompileOptions {
   bool profilerSlowAssertionsEnabled() const {
     return profilerSlowAssertionsEnabled_;
   }
 
   bool offThreadCompilationAvailable() const {
     return offThreadCompilationAvailable_;
   }
 
-#ifdef ENABLE_WASM_REFTYPES
-  bool wasmGcEnabled() const { return wasmGcEnabled_; }
-#endif
-
  private:
   bool cloneSingletons_;
   bool profilerSlowAssertionsEnabled_;
   bool offThreadCompilationAvailable_;
-#ifdef ENABLE_WASM_REFTYPES
-  bool wasmGcEnabled_;
-#endif
 };
 
 }  // namespace jit
 }  // namespace js
 
 #endif  // jit_CompileWrappers_h
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -489,17 +489,17 @@ static bool enableBaseline = false;
 static bool enableIon = false;
 static bool enableAsmJS = false;
 static bool enableWasm = false;
 static bool enableNativeRegExp = false;
 static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
 static bool enableWasmBaseline = false;
 static bool enableWasmIon = false;
 static bool enableWasmCranelift = false;
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
 static bool enableWasmGc = false;
 #endif
 static bool enableWasmVerbose = false;
 static bool enableTestWasmAwaitTier2 = false;
 static bool enableAsyncStacks = false;
 static bool enableStreams = false;
 static bool enableBigInt = false;
 #ifdef JS_GC_ZEAL
@@ -9878,17 +9878,17 @@ static bool SetContextOptions(JSContext*
       // Baseline is enabled by default.
       enableWasmIon = false;
       enableWasmCranelift = true;
     } else {
       return OptionFailure("wasm-compiler", str);
     }
   }
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   enableWasmGc = op.getBoolOption("wasm-gc");
 #endif
   enableWasmVerbose = op.getBoolOption("wasm-verbose");
   enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
   enableAsyncStacks = !op.getBoolOption("no-async-stacks");
   enableStreams = !op.getBoolOption("no-streams");
   enableBigInt = !op.getBoolOption("no-bigint");
 
@@ -9897,17 +9897,17 @@ static bool SetContextOptions(JSContext*
       .setIon(enableIon)
       .setAsmJS(enableAsmJS)
       .setWasm(enableWasm)
       .setWasmBaseline(enableWasmBaseline)
       .setWasmIon(enableWasmIon)
 #ifdef ENABLE_WASM_CRANELIFT
       .setWasmCranelift(enableWasmCranelift)
 #endif
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
       .setWasmGc(enableWasmGc)
 #endif
       .setWasmVerbose(enableWasmVerbose)
       .setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
       .setNativeRegExp(enableNativeRegExp)
       .setAsyncStack(enableAsyncStacks);
 
   if (op.getBoolOption("no-unboxed-objects")) {
@@ -10200,17 +10200,17 @@ static void SetWorkerContextOptions(JSCo
       .setIon(enableIon)
       .setAsmJS(enableAsmJS)
       .setWasm(enableWasm)
       .setWasmBaseline(enableWasmBaseline)
       .setWasmIon(enableWasmIon)
 #ifdef ENABLE_WASM_CRANELIFT
       .setWasmCranelift(enableWasmCranelift)
 #endif
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
       .setWasmGc(enableWasmGc)
 #endif
       .setWasmVerbose(enableWasmVerbose)
       .setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
       .setNativeRegExp(enableNativeRegExp);
 
   cx->runtime()->setOffthreadIonCompilationEnabled(offthreadCompilation);
   cx->runtime()->profilingScripts =
@@ -10585,18 +10585,18 @@ int main(int argc, char** argv, char** e
           '\0', "wasm-compiler", "[option]",
           "Choose to enable a subset of the wasm compilers (valid options are "
           "none/baseline/ion/cranelift/baseline+ion/baseline+cranelift)") ||
       !op.addBoolOption('\0', "wasm-verbose",
                         "Enable WebAssembly verbose logging") ||
       !op.addBoolOption('\0', "test-wasm-await-tier2",
                         "Forcibly activate tiering and block "
                         "instantiation on completion of tier2")
-#ifdef ENABLE_WASM_REFTYPES
-      || !op.addBoolOption('\0', "wasm-gc", "Enable wasm GC features")
+#ifdef ENABLE_WASM_GC
+      || !op.addBoolOption('\0', "wasm-gc", "Enable experimental wasm GC features")
 #else
       || !op.addBoolOption('\0', "wasm-gc", "No-op")
 #endif
       || !op.addBoolOption('\0', "no-native-regexp",
                            "Disable native regexp compilation") ||
       !op.addBoolOption('\0', "no-unboxed-objects",
                         "Disable creating unboxed plain objects") ||
       !op.addBoolOption('\0', "enable-streams",
--- a/js/src/wasm/WasmAST.h
+++ b/js/src/wasm/WasmAST.h
@@ -1312,17 +1312,17 @@ class AstModule : public AstNode {
 
   LifoAlloc& lifo_;
   TypeDefVector types_;
   FuncTypeMap funcTypeMap_;
   ImportVector imports_;
   NameVector funcImportNames_;
   AstTableVector tables_;
   AstMemoryVector memories_;
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   uint32_t gcFeatureOptIn_;
 #endif
   Maybe<uint32_t> dataCount_;
   ExportVector exports_;
   Maybe<AstStartFunc> startFunc_;
   FuncVector funcs_;
   AstDataSegmentVector dataSegments_;
   AstElemSegmentVector elemSegments_;
@@ -1334,32 +1334,32 @@ class AstModule : public AstNode {
   explicit AstModule(LifoAlloc& lifo)
       : lifo_(lifo),
         types_(lifo),
         funcTypeMap_(lifo),
         imports_(lifo),
         funcImportNames_(lifo),
         tables_(lifo),
         memories_(lifo),
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
         gcFeatureOptIn_(0),
 #endif
         exports_(lifo),
         funcs_(lifo),
         dataSegments_(lifo),
         elemSegments_(lifo),
         globals_(lifo),
         numGlobalImports_(0) {
   }
   bool addMemory(AstName name, const Limits& memory) {
     return memories_.append(AstMemory(memory, false, name));
   }
   bool hasMemory() const { return !!memories_.length(); }
   const AstMemoryVector& memories() const { return memories_; }
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   bool addGcFeatureOptIn(uint32_t version) {
     gcFeatureOptIn_ = version;
     return true;
   }
   uint32_t gcFeatureOptIn() const { return gcFeatureOptIn_; }
 #endif
   bool initDataCount(uint32_t dataCount) {
     MOZ_ASSERT(dataCount_.isNothing());
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -11420,25 +11420,19 @@ bool BaseCompiler::emitBody() {
         if (!env_.gcTypesEnabled()) {
           return iter_.unrecognizedOpcode(&op);
         }
         CHECK_NEXT(
             emitComparison(emitCompareRef, ValType::AnyRef, Assembler::Equal));
 #endif
 #ifdef ENABLE_WASM_REFTYPES
       case uint16_t(Op::RefNull):
-        if (!env_.gcTypesEnabled()) {
-          return iter_.unrecognizedOpcode(&op);
-        }
         CHECK_NEXT(emitRefNull());
         break;
       case uint16_t(Op::RefIsNull):
-        if (!env_.gcTypesEnabled()) {
-          return iter_.unrecognizedOpcode(&op);
-        }
         CHECK_NEXT(
             emitConversion(emitRefIsNull, ValType::AnyRef, ValType::I32));
         break;
 #endif
 
       // "Miscellaneous" operations
       case uint16_t(Op::MiscPrefix): {
         switch (op.b1) {
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -78,17 +78,17 @@ SharedCompileArgs CompileArgs::build(JSC
   bool baseline = BaselineCanCompile() && cx->options().wasmBaseline();
   bool ion = IonCanCompile() && cx->options().wasmIon();
 #ifdef ENABLE_WASM_CRANELIFT
   bool cranelift = CraneliftCanCompile() && cx->options().wasmCranelift();
 #else
   bool cranelift = false;
 #endif
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   bool gc = cx->options().wasmGc();
 #else
   bool gc = false;
 #endif
 
   // Debug information such as source view or debug traps will require
   // additional memory and permanently stay in baseline code, so we try to
   // only enable it when a developer actually cares: when the debugger tab
@@ -594,18 +594,16 @@ void wasm::CompileTier2(const CompileArg
 
   ModuleEnvironment env(
       gcTypesConfigured, &compilerEnv,
       args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
   if (!DecodeModuleEnvironment(d, &env)) {
     return;
   }
 
-  MOZ_ASSERT(!env.gcTypesEnabled(), "can't ion-compile with gc types yet");
-
   ModuleGenerator mg(args, &env, cancelled, &error);
   if (!mg.init()) {
     return;
   }
 
   if (!DecodeCodeSection(env, d, mg)) {
     return;
   }
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -3116,17 +3116,17 @@ static bool EmitMemOrTableInit(FunctionC
     return false;
   }
 
   return true;
 }
 #endif  // ENABLE_WASM_BULKMEM_OPS
 
 #ifdef ENABLE_WASM_REFTYPES
-// Note, table.{get,grow,set} on table(anyfunc) are currently rejected by the
+// Note, table.{get,grow,set} on table(funcref) are currently rejected by the
 // verifier.
 
 static bool EmitTableGet(FunctionCompiler& f) {
   uint32_t tableIndex;
   MDefinition* index;
   if (!f.iter().readTableGet(&tableIndex, &index)) {
     return false;
   }
@@ -3793,24 +3793,18 @@ static bool EmitBodyExprs(FunctionCompil
         if (!f.env().gcTypesEnabled()) {
           return f.iter().unrecognizedOpcode(&op);
         }
         CHECK(EmitComparison(f, ValType::AnyRef, JSOP_EQ,
                              MCompare::Compare_RefOrNull));
 #endif
 #ifdef ENABLE_WASM_REFTYPES
       case uint16_t(Op::RefNull):
-        if (!f.env().gcTypesEnabled()) {
-          return f.iter().unrecognizedOpcode(&op);
-        }
         CHECK(EmitRefNull(f));
       case uint16_t(Op::RefIsNull):
-        if (!f.env().gcTypesEnabled()) {
-          return f.iter().unrecognizedOpcode(&op);
-        }
         CHECK(EmitRefIsNull(f));
 #endif
 
       // Sign extensions
       case uint16_t(Op::I32Extend8S):
         CHECK(EmitSignExtend(f, 1, 4));
       case uint16_t(Op::I32Extend16S):
         CHECK(EmitSignExtend(f, 2, 4));
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -60,16 +60,29 @@ extern mozilla::Atomic<bool> fuzzingSafe
 
 bool wasm::HasReftypesSupport(JSContext* cx) {
 #ifdef ENABLE_WASM_CRANELIFT
   if (cx->options().wasmCranelift()) {
     return false;
   }
 #endif
 #ifdef ENABLE_WASM_REFTYPES
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool wasm::HasGcSupport(JSContext* cx) {
+#ifdef ENABLE_WASM_CRANELIFT
+  if (cx->options().wasmCranelift()) {
+    return false;
+  }
+#endif
+#ifdef ENABLE_WASM_GC
   return cx->options().wasmGc() && cx->options().wasmBaseline();
 #else
   return false;
 #endif
 }
 
 bool wasm::HasCompilerSupport(JSContext* cx) {
 #if !MOZ_LITTLE_ENDIAN || defined(JS_CODEGEN_NONE)
@@ -2351,17 +2364,17 @@ bool WasmTableObject::growImpl(JSContext
           MOZ_ASSERT(table->table().getAnyFunc(index).code == nullptr);
         }
 #endif
       } else if (IsExportedFunction(fillValue, &value)) {
         TableFunctionFill(cx, &table->table(), value, oldLength,
                           oldLength + delta);
       } else {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
-                                 JSMSG_WASM_BAD_TBL_GROW_INIT, "anyfunc");
+                                 JSMSG_WASM_BAD_TBL_GROW_INIT, "funcref");
         return false;
       }
       break;
     }
     case TableKind::AnyRef: {
       RootedAnyRef tmp(cx, AnyRef::null());
       if (!BoxAnyRef(cx, fillValue, &tmp)) {
         return false;
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -57,16 +57,21 @@ bool HasStreamingSupport(JSContext* cx);
 
 bool HasCachingSupport(JSContext* cx);
 
 // Returns true if WebAssembly as configured by compile-time flags and run-time
 // options can support reference types and stack walking.
 
 bool HasReftypesSupport(JSContext* cx);
 
+// Returns true if WebAssembly as configured by compile-time flags and run-time
+// options can support (ref T) types and structure types, etc (evolving).
+
+bool HasGcSupport(JSContext* cx);
+
 // Compiles the given binary wasm module given the ArrayBufferObject
 // and links the module's imports with the given import object.
 
 MOZ_MUST_USE bool Eval(JSContext* cx, Handle<TypedArrayObject*> code,
                        HandleObject importObj,
                        MutableHandleWasmInstanceObject instanceObj);
 
 // For testing cross-process (de)serialization, this pair of functions are
--- a/js/src/wasm/WasmOpIter.h
+++ b/js/src/wasm/WasmOpIter.h
@@ -757,23 +757,25 @@ inline bool OpIter<Policy>::readBlockTyp
   switch (uncheckedCode) {
     case uint8_t(ExprType::Void):
     case uint8_t(ExprType::I32):
     case uint8_t(ExprType::I64):
     case uint8_t(ExprType::F32):
     case uint8_t(ExprType::F64):
       known = true;
       break;
+    case uint8_t(ExprType::AnyRef):
+#ifdef ENABLE_WASM_REFTYPES
+      known = true;
+#endif
+      break;
     case uint8_t(ExprType::Ref):
       known = env_.gcTypesEnabled() && uncheckedRefTypeIndex < MaxTypes &&
               uncheckedRefTypeIndex < env_.types.length();
       break;
-    case uint8_t(ExprType::AnyRef):
-      known = env_.gcTypesEnabled();
-      break;
     case uint8_t(ExprType::Limit):
       break;
   }
 
   if (!known) {
     return fail("invalid inline block type");
   }
 
@@ -1953,17 +1955,17 @@ inline bool OpIter<Policy>::readMemOrTab
       return fail("memory.init segment index out of range");
     }
   } else {
     if (memOrTableIndex >= env_.tables.length()) {
       return fail("table index out of range for table.init");
     }
     *dstTableIndex = memOrTableIndex;
 
-    // Element segments must carry functions exclusively and anyfunc is not
+    // Element segments must carry functions exclusively and funcref is not
     // yet a subtype of anyref.
     if (env_.tables[*dstTableIndex].kind != TableKind::AnyFunction) {
       return fail("only tables of 'funcref' may have element segments");
     }
     if (*segIndex >= env_.elemSegments.length()) {
       return fail("table.init segment index out of range");
     }
   }
@@ -1986,20 +1988,16 @@ inline bool OpIter<Policy>::readTableGet
   if (*tableIndex >= env_.tables.length()) {
     return fail("table index out of range for table.get");
   }
 
   if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
     return fail("table.get only on tables of anyref");
   }
 
-  if (!env_.gcTypesEnabled()) {
-    return fail("anyref support not enabled");
-  }
-
   infalliblePush(ValType::AnyRef);
   return true;
 }
 
 template <typename Policy>
 inline bool OpIter<Policy>::readTableGrow(uint32_t* tableIndex, Value* delta,
                                           Value* initValue) {
   MOZ_ASSERT(Classify(op_) == OpKind::TableGrow);
@@ -2016,20 +2014,16 @@ inline bool OpIter<Policy>::readTableGro
   }
   if (*tableIndex >= env_.tables.length()) {
     return fail("table index out of range for table.grow");
   }
   if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
     return fail("table.grow only on tables of anyref");
   }
 
-  if (!env_.gcTypesEnabled()) {
-    return fail("anyref support not enabled");
-  }
-
   infalliblePush(ValType::I32);
   return true;
 }
 
 template <typename Policy>
 inline bool OpIter<Policy>::readTableSet(uint32_t* tableIndex, Value* index,
                                          Value* value) {
   MOZ_ASSERT(Classify(op_) == OpKind::TableSet);
@@ -2046,20 +2040,16 @@ inline bool OpIter<Policy>::readTableSet
   }
   if (*tableIndex >= env_.tables.length()) {
     return fail("table index out of range for table.set");
   }
   if (env_.tables[*tableIndex].kind != TableKind::AnyRef) {
     return fail("table.set only on tables of anyref");
   }
 
-  if (!env_.gcTypesEnabled()) {
-    return fail("anyref support not enabled");
-  }
-
   return true;
 }
 
 template <typename Policy>
 inline bool OpIter<Policy>::readTableSize(uint32_t* tableIndex) {
   MOZ_ASSERT(Classify(op_) == OpKind::TableSize);
 
   *tableIndex = 0;
--- a/js/src/wasm/WasmTable.h
+++ b/js/src/wasm/WasmTable.h
@@ -75,17 +75,17 @@ class Table : public ShareableBase<Table
     return kind_ == TableKind::AnyFunction || kind_ == TableKind::TypedFunction;
   }
   uint32_t length() const { return length_; }
   Maybe<uint32_t> maximum() const { return maximum_; }
 
   // Only for function values.  Raw pointer to the table.
   uint8_t* functionBase() const;
 
-  // get/setAnyFunc is allowed only on table-of-anyfunc.
+  // get/setAnyFunc is allowed only on table-of-funcref.
   // get/setAnyRef is allowed only on table-of-anyref.
   // setNull is allowed on either.
   const FunctionTableElem& getAnyFunc(uint32_t index) const;
   void setAnyFunc(uint32_t index, void* code, const Instance* instance);
 
   AnyRef getAnyRef(uint32_t index) const;
   const void* getAnyRefLocForCompiledCode(uint32_t index) const;
   void setAnyRef(uint32_t index, AnyRef);
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -86,17 +86,17 @@ class WasmToken {
     Equal,
     Error,
     Export,
     ExtraConversionOpcode,
     Field,
     Float,
     Func,
     FuncRef,
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
     GcFeatureOptIn,
 #endif
     GetGlobal,
     GetLocal,
     Global,
     If,
     Import,
     Index,
@@ -370,17 +370,17 @@ class WasmToken {
       case Equal:
       case End:
       case Error:
       case Export:
       case Field:
       case Float:
       case Func:
       case FuncRef:
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
       case GcFeatureOptIn:
 #endif
       case Global:
       case Mutable:
       case Import:
       case Index:
       case Memory:
       case NegativeZero:
@@ -1330,17 +1330,17 @@ WasmToken WasmTokenStream::next() {
             }
             break;
         }
         break;
       }
       break;
 
     case 'g':
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
       if (consume(u"gc_feature_opt_in")) {
         return WasmToken(WasmToken::GcFeatureOptIn, begin, cur_);
       }
 #endif
       if (consume(u"get_global")) {
         return WasmToken(WasmToken::GetGlobal, begin, cur_);
       }
       if (consume(u"get_local")) {
@@ -4583,17 +4583,17 @@ static bool ParseMemory(WasmParseContext
   Limits memory;
   if (!ParseLimits(c, &memory, Shareable::True)) {
     return false;
   }
 
   return module->addMemory(name, memory);
 }
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
 // Custom section for experimental work.  The size of this section should always
 // be 1 byte, and that byte is a nonzero varint7 carrying the version number
 // being opted into.
 static bool ParseGcFeatureOptIn(WasmParseContext& c, AstModule* module) {
   WasmToken token;
   if (!c.ts.getIf(WasmToken::Index, &token)) {
     c.ts.generateError(token, "GC feature version number required", c.error);
     return false;
@@ -4657,19 +4657,19 @@ static bool ParseElemType(WasmParseConte
     return true;
   }
 #ifdef ENABLE_WASM_REFTYPES
   if (c.ts.getIf(WasmToken::ValueType, &token) &&
       token.valueType() == ValType::AnyRef) {
     *tableKind = TableKind::AnyRef;
     return true;
   }
-  c.ts.generateError(token, "'anyfunc' or 'anyref' required", c.error);
+  c.ts.generateError(token, "'funcref' or 'anyref' required", c.error);
 #else
-  c.ts.generateError(token, "'anyfunc' required", c.error);
+  c.ts.generateError(token, "'funcref' required", c.error);
 #endif
   return false;
 }
 
 static bool ParseTableSig(WasmParseContext& c, Limits* table,
                           TableKind* tableKind) {
   return ParseLimits(c, table, Shareable::False) && ParseElemType(c, tableKind);
 }
@@ -4901,27 +4901,27 @@ static bool ParseTable(WasmParseContext&
     if (!ParseInlineExport(c, DefinitionKind::Table, module, ref)) {
       return false;
     }
     if (!c.ts.match(WasmToken::CloseParen, c.error)) {
       return false;
     }
   }
 
-  // Either: min max? anyfunc
+  // Either: min max? funcref
   if (c.ts.peek().kind() == WasmToken::Index) {
     TableKind tableKind;
     Limits table;
     if (!ParseTableSig(c, &table, &tableKind)) {
       return false;
     }
     return module->addTable(name, table, tableKind);
   }
 
-  // Or: anyfunc (elem 1 2 ...)
+  // Or: funcref (elem 1 2 ...)
   TableKind tableKind;
   if (!ParseElemType(c, &tableKind)) {
     return false;
   }
 
   if (!c.ts.match(WasmToken::OpenParen, c.error)) {
     return false;
   }
@@ -5137,17 +5137,17 @@ static AstModule* ParseModule(const char
         break;
       }
       case WasmToken::Memory: {
         if (!ParseMemory(c, module)) {
           return nullptr;
         }
         break;
       }
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
       case WasmToken::GcFeatureOptIn: {
         if (!ParseGcFeatureOptIn(c, module)) {
           return nullptr;
         }
         break;
       }
 #endif
       case WasmToken::Global: {
@@ -6626,17 +6626,17 @@ static bool EncodeExpr(Encoder& e, AstEx
 #endif
   }
   MOZ_CRASH("Bad expr kind");
 }
 
 /*****************************************************************************/
 // wasm AST binary serialization
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
 static bool EncodeGcFeatureOptInSection(Encoder& e, AstModule& module) {
   uint32_t optInVersion = module.gcFeatureOptIn();
   if (!optInVersion) {
     return true;
   }
 
   size_t offset;
   if (!e.startSection(SectionId::GcFeatureOptIn, &offset)) {
@@ -7269,17 +7269,17 @@ static bool EncodeModule(AstModule& modu
   if (!e.writeFixedU32(MagicNumber)) {
     return false;
   }
 
   if (!e.writeFixedU32(EncodingVersion)) {
     return false;
   }
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   if (!EncodeGcFeatureOptInSection(e, module)) {
     return false;
   }
 #endif
 
   if (!EncodeTypeSection(e, module)) {
     return false;
   }
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1164,17 +1164,17 @@ struct ElemSegment : AtomicRefCounted<El
 
   InitExpr offset() const { return *offsetIfActive; }
 
   size_t length() const { return elemFuncIndices.length(); }
 
   WASM_DECLARE_SERIALIZABLE(ElemSegment)
 };
 
-// NullFuncIndex represents the case when an element segment (of type anyfunc)
+// NullFuncIndex represents the case when an element segment (of type funcref)
 // contains a null element.
 constexpr uint32_t NullFuncIndex = UINT32_MAX;
 static_assert(NullFuncIndex > MaxFuncs, "Invariant");
 
 typedef RefPtr<ElemSegment> MutableElemSegment;
 typedef SerializableRefPtr<const ElemSegment> SharedElemSegment;
 typedef Vector<SharedElemSegment, 0, SystemAllocPolicy> ElemSegmentVector;
 
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -922,26 +922,20 @@ static bool DecodeFunctionBodyExprs(cons
           return iter.unrecognizedOpcode(&op);
         }
         CHECK(iter.readComparison(ValType::AnyRef, &nothing, &nothing));
         break;
       }
 #endif
 #ifdef ENABLE_WASM_REFTYPES
       case uint16_t(Op::RefNull): {
-        if (!env.gcTypesEnabled()) {
-          return iter.unrecognizedOpcode(&op);
-        }
         CHECK(iter.readRefNull());
         break;
       }
       case uint16_t(Op::RefIsNull): {
-        if (!env.gcTypesEnabled()) {
-          return iter.unrecognizedOpcode(&op);
-        }
         CHECK(iter.readConversion(ValType::AnyRef, ValType::I32, &nothing));
         break;
       }
 #endif
       case uint16_t(Op::ThreadPrefix): {
         switch (op.b1) {
           case uint16_t(ThreadOp::Wake): {
             LinearMemoryAddress<Nothing> addr;
@@ -1350,17 +1344,17 @@ static bool DecodeStructType(Decoder& d,
   env->types[typeIndex] =
       TypeDef(StructType(std::move(fields), env->numStructTypes, isInline));
   (*typeState)[typeIndex] = TypeState::Struct;
   env->numStructTypes++;
 
   return true;
 }
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
 static bool DecodeGCFeatureOptInSection(Decoder& d, ModuleEnvironment* env) {
   MaybeSectionRange range;
   if (!d.startSection(SectionId::GcFeatureOptIn, env, &range,
                       "gcfeatureoptin")) {
     return false;
   }
   if (!range) {
     return true;
@@ -1559,19 +1553,16 @@ static bool DecodeTableTypeAndLimits(Dec
     return d.fail("expected table element type");
   }
 
   TableKind tableKind;
   if (elementType == uint8_t(TypeCode::AnyFunc)) {
     tableKind = TableKind::AnyFunction;
 #ifdef ENABLE_WASM_REFTYPES
   } else if (elementType == uint8_t(TypeCode::AnyRef)) {
-    if (!gcTypesEnabled) {
-      return d.fail("reference types not enabled");
-    }
     tableKind = TableKind::AnyRef;
 #endif
   } else {
 #ifdef ENABLE_WASM_REFTYPES
     return d.fail("expected 'funcref' or 'anyref' element type");
 #else
     return d.fail("expected 'funcref' element type");
 #endif
@@ -1930,26 +1921,26 @@ static bool DecodeInitializerExpression(
       double f64;
       if (!d.readFixedF64(&f64)) {
         return d.fail("failed to read initializer f64 expression");
       }
       *init = InitExpr(LitVal(f64));
       break;
     }
     case uint16_t(Op::RefNull): {
-      if (!env->gcTypesEnabled()) {
-        return d.fail("unexpected initializer expression");
-      }
       if (!expected.isReference()) {
         return d.fail(
             "type mismatch: initializer type and expected type don't match");
       }
       if (expected == ValType::AnyRef) {
         *init = InitExpr(LitVal(AnyRef::null()));
       } else {
+        if (!env->gcTypesEnabled()) {
+          return d.fail("unexpected initializer expression");
+        }
         *init = InitExpr(LitVal(expected, nullptr));
       }
       break;
     }
     case uint16_t(Op::GetGlobal): {
       uint32_t i;
       const GlobalDescVector& globals = env->globals;
       if (!d.readVarU32(&i)) {
@@ -1959,18 +1950,25 @@ static bool DecodeInitializerExpression(
       if (i >= globals.length()) {
         return d.fail("global index out of range in initializer expression");
       }
       if (!globals[i].isImport() || globals[i].isMutable()) {
         return d.fail(
             "initializer expression must reference a global immutable import");
       }
       if (expected.isReference()) {
-        if (!(env->gcTypesEnabled() && globals[i].type().isReference() &&
-              env->isRefSubtypeOf(globals[i].type(), expected))) {
+        bool fail = false;
+        if ((expected.isRef() || globals[i].type().isRef())
+            && !env->gcTypesEnabled()) {
+          fail = true;
+        } else if (!(globals[i].type().isReference() &&
+                     env->isRefSubtypeOf(globals[i].type(), expected))) {
+          fail = true;
+        }
+        if (fail) {
           return d.fail(
               "type mismatch: initializer type and expected type don't match");
         }
         *init = InitExpr(i, expected);
       } else {
         *init = InitExpr(i, globals[i].type());
       }
       break;
@@ -2418,17 +2416,17 @@ bool wasm::StartsCodeSection(const uint8
   return false;
 }
 
 bool wasm::DecodeModuleEnvironment(Decoder& d, ModuleEnvironment* env) {
   if (!DecodePreamble(d)) {
     return false;
   }
 
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   if (!DecodeGCFeatureOptInSection(d, env)) {
     return false;
   }
   bool gcFeatureOptIn = env->gcFeatureOptIn;
 #else
   bool gcFeatureOptIn = false;
 #endif
 
@@ -2773,18 +2771,18 @@ bool wasm::DecodeModuleTail(Decoder& d, 
 }
 
 // Validate algorithm.
 
 bool wasm::Validate(JSContext* cx, const ShareableBytes& bytecode,
                     UniqueChars* error) {
   Decoder d(bytecode.bytes, 0, error);
 
-#ifdef ENABLE_WASM_REFTYPES
-  bool gcTypesConfigured = HasReftypesSupport(cx);
+#ifdef ENABLE_WASM_GC
+  bool gcTypesConfigured = HasGcSupport(cx);
 #else
   bool gcTypesConfigured = false;
 #endif
 
   CompilerEnvironment compilerEnv(CompileMode::Once, Tier::Optimized,
                                   OptimizedBackend::Ion, DebugEnabled::False,
                                   gcTypesConfigured);
   ModuleEnvironment env(
--- a/js/src/wasm/WasmValidate.h
+++ b/js/src/wasm/WasmValidate.h
@@ -128,24 +128,23 @@ struct CompilerEnvironment {
 struct ModuleEnvironment {
   // Constant parameters for the entire compilation:
   const ModuleKind kind;
   const Shareable sharedMemoryEnabled;
   CompilerEnvironment* const compilerEnv;
 
   // Module fields decoded from the module environment (or initialized while
   // validating an asm.js module) and immutable during compilation:
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   // `gcFeatureOptIn` reflects the presence in a module of a GcFeatureOptIn
   // section.  This variable will be removed eventually, allowing it to be
   // replaced everywhere by the value true.
   //
   // The flag is used in the value of gcTypesEnabled(), which controls whether
-  // ref types and struct types and associated instructions are accepted
-  // during validation.
+  // struct types and associated instructions are accepted during validation.
   bool gcFeatureOptIn;
 #endif
   Maybe<uint32_t> dataCount;
   MemoryUsage memoryUsage;
   uint32_t minMemoryLength;
   Maybe<uint32_t> maxMemoryLength;
   uint32_t numStructTypes;
   TypeDefVector types;
@@ -169,17 +168,17 @@ struct ModuleEnvironment {
 
   explicit ModuleEnvironment(bool gcTypesConfigured,
                              CompilerEnvironment* compilerEnv,
                              Shareable sharedMemoryEnabled,
                              ModuleKind kind = ModuleKind::Wasm)
       : kind(kind),
         sharedMemoryEnabled(sharedMemoryEnabled),
         compilerEnv(compilerEnv),
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
         gcFeatureOptIn(false),
 #endif
         memoryUsage(MemoryUsage::None),
         minMemoryLength(0),
         numStructTypes(0) {
   }
 
   Tier tier() const { return compilerEnv->tier(); }
@@ -203,19 +202,19 @@ struct ModuleEnvironment {
     return compilerEnv->debug() == DebugEnabled::True;
   }
   bool funcIsImport(uint32_t funcIndex) const {
     return funcIndex < funcImportGlobalDataOffsets.length();
   }
   bool isRefSubtypeOf(ValType one, ValType two) const {
     MOZ_ASSERT(one.isReference());
     MOZ_ASSERT(two.isReference());
-    MOZ_ASSERT(gcTypesEnabled());
     return one == two || two == ValType::AnyRef || one == ValType::NullRef ||
-           (one.isRef() && two.isRef() && isStructPrefixOf(two, one));
+           (one.isRef() && two.isRef() && gcTypesEnabled() &&
+            isStructPrefixOf(two, one));
   }
 
  private:
   bool isStructPrefixOf(ValType a, ValType b) const {
     const StructType& other = types[a.refTypeIndex()].structType();
     return types[b.refTypeIndex()].structType().hasPrefix(other);
   }
 };
@@ -602,24 +601,21 @@ class Decoder {
     switch (code) {
       case uint8_t(ValType::I32):
       case uint8_t(ValType::F32):
       case uint8_t(ValType::F64):
       case uint8_t(ValType::I64):
         *type = ValType::Code(code);
         return true;
       case uint8_t(ValType::AnyRef):
-        if (!gcTypesEnabled) {
-          return fail("reference types not enabled");
-        }
         *type = ValType::Code(code);
         return true;
       case uint8_t(ValType::Ref): {
         if (!gcTypesEnabled) {
-          return fail("reference types not enabled");
+          return fail("(ref T) types not enabled");
         }
         uint32_t typeIndex;
         if (!readVarU32(&typeIndex)) {
           return false;
         }
         if (typeIndex >= numTypes) {
           return fail("ref index out of range");
         }
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -777,17 +777,17 @@ static void ReloadPrefsCallback(const ch
   bool useWasm = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm");
   bool useWasmIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_ionjit");
   bool useWasmBaseline =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_baselinejit");
 #ifdef ENABLE_WASM_CRANELIFT
   bool useWasmCranelift =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_cranelift");
 #endif
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
   bool useWasmGc = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_gc");
 #endif
   bool useWasmVerbose = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_verbose");
   bool throwOnAsmJSValidationFailure = Preferences::GetBool(
       JS_OPTIONS_DOT_STR "throw_on_asmjs_validation_failure");
   bool useNativeRegExp =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "native_regexp");
 
@@ -871,17 +871,17 @@ static void ReloadPrefsCallback(const ch
       .setIon(useIon)
       .setAsmJS(useAsmJS)
       .setWasm(useWasm)
       .setWasmIon(useWasmIon)
       .setWasmBaseline(useWasmBaseline)
 #ifdef ENABLE_WASM_CRANELIFT
       .setWasmCranelift(useWasmCranelift)
 #endif
-#ifdef ENABLE_WASM_REFTYPES
+#ifdef ENABLE_WASM_GC
       .setWasmGc(useWasmGc)
 #endif
       .setWasmVerbose(useWasmVerbose)
       .setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure)
       .setNativeRegExp(useNativeRegExp)
       .setAsyncStack(useAsyncStack)
       .setThrowOnDebuggeeWouldRun(throwOnDebuggeeWouldRun)
       .setDumpStackOnDebuggeeWouldRun(dumpStackOnDebuggeeWouldRun)