Merge inbound to mozilla-central. a=merge
authorBrindusan Cristian <cbrindusan@mozilla.com>
Fri, 21 Sep 2018 20:29:29 +0300
changeset 437712 ce4e883f7642c2c8652e7c065f5bfb122a71cb95
parent 437711 3ffe4318af3ad3033e22c80f1d4c8d1e8222a5f7 (current diff)
parent 437664 1330a9eb3da56d783aefabe063764eb55e9adadc (diff)
child 437713 1879856ca1ab0def40038be7482a9bc2e140cfee
child 437744 7d5961e2ffe35c5618814354daf8c93c9204e69d
child 437750 bb920e4191661b821481bfc9cba14a5ab84dc241
push id108133
push usercbrindusan@mozilla.com
push dateFri, 21 Sep 2018 17:33:11 +0000
treeherdermozilla-inbound@1879856ca1ab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.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
Merge inbound to mozilla-central. a=merge
js/src/jit-test/tests/wasm/regress/proxy-has-trap-table.js
testing/geckodriver/.gitignore
testing/web-platform/meta/wasm/jsapi/global/constructor.any.js.ini
testing/web-platform/meta/wasm/jsapi/global/value-set.any.js.ini
testing/web-platform/meta/wasm/jsapi/interface.any.js.ini
testing/web-platform/meta/wasm/jsapi/memory/constructor.any.js.ini
testing/web-platform/meta/wasm/jsapi/memory/grow.any.js.ini
testing/web-platform/meta/wasm/jsapi/module/customSections.any.js.ini
testing/web-platform/meta/wasm/jsapi/table/constructor.any.js.ini
testing/web-platform/meta/wasm/jsapi/table/get-set.any.js.ini
testing/web-platform/meta/wasm/jsapi/table/grow.any.js.ini
testing/web-platform/tests/wasm/jsapi/global/value-set.any.js
testing/webdriver/.gitignore
testing/webdriver/.hgignore
testing/webdriver/.travis.yml
toolkit/themes/shared/icons/check-partial.svg
toolkit/themes/shared/icons/check.svg
--- a/accessible/generic/ImageAccessible.cpp
+++ b/accessible/generic/ImageAccessible.cpp
@@ -56,17 +56,17 @@ ImageAccessible::NativeState() const
     content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                         getter_AddRefs(imageRequest));
 
   nsCOMPtr<imgIContainer> imgContainer;
   if (imageRequest)
     imageRequest->GetImage(getter_AddRefs(imgContainer));
 
   if (imgContainer) {
-    bool animated;
+    bool animated = false;
     imgContainer->GetAnimated(&animated);
     if (animated)
       state |= states::ANIMATED;
   }
 
   return state;
 }
 
--- a/browser/config/mozconfigs/win64/nightly-asan-reporter
+++ b/browser/config/mozconfigs/win64/nightly-asan-reporter
@@ -30,13 +30,9 @@ export MOZILLA_OFFICIAL=1
 ac_add_options --disable-sandbox
 
 # Enable Telemetry
 # The channel reported by Telemetry here will be "nightly-asan" as specified
 # in the respective override pref (toolkit.telemetry.overrideUpdateChannel),
 # while the build otherwise identifies as "nightly" to receive its updates.
 export MOZ_TELEMETRY_REPORTING=1
 
-# Disable stack instrumentation until we can tackle bug 1477490
-export CFLAGS="-mllvm -asan-stack=0"
-export CXXFLAGS="-mllvm -asan-stack=0"
-
 . "$topsrcdir/build/mozconfig.common.override"
--- a/build/build-clang/clang-win64.json
+++ b/build/build-clang/clang-win64.json
@@ -10,11 +10,13 @@
     "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_700/final",
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_700/final",
     "python_path": "c:/mozilla-build/python/python.exe",
     "cc": "cl.exe",
     "cxx": "cl.exe",
     "ml": "ml64.exe",
     "patches": [
       "workaround-issue38586.patch",
+      "r342649-hotpatch-8-byte-nops.patch",
+      "r342652-unpoison-thread-stacks.patch",
       "loosen-msvc-detection.patch"
     ]
 }
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r342649-hotpatch-8-byte-nops.patch
@@ -0,0 +1,30 @@
+[winasan] Reduce hotpatch prefix check to 8 bytes
+
+Same idea as r310419: The 8 byte nop is a suffix of the 9 byte nop, and we need at most 6 bytes.
+
+Differential Revision: https://reviews.llvm.org/D51788
+
+--- a/compiler-rt/lib/interception/interception_win.cc	(revision 342648)
++++ b/compiler-rt/lib/interception/interception_win.cc	(revision 342649)
+@@ -223,8 +223,8 @@
+   return true;
+ }
+ 
+-static const u8 kHintNop9Bytes[] = {
+-  0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
++static const u8 kHintNop8Bytes[] = {
++  0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ 
+ template<class T>
+@@ -239,8 +239,8 @@
+ static bool FunctionHasPadding(uptr address, uptr size) {
+   if (IsMemoryPadding(address - size, size))
+     return true;
+-  if (size <= sizeof(kHintNop9Bytes) &&
+-      FunctionHasPrefix(address, kHintNop9Bytes))
++  if (size <= sizeof(kHintNop8Bytes) &&
++      FunctionHasPrefix(address, kHintNop8Bytes))
+     return true;
+   return false;
+ }
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r342652-unpoison-thread-stacks.patch
@@ -0,0 +1,34 @@
+[winasan] Unpoison the stack in NtTerminateThread
+
+In long-running builds we've seen some ASan complaints during thread creation that we suspect are due to leftover poisoning from previous threads whose stacks occupied that memory. This patch adds a hook that unpoisons the stack just before the NtTerminateThread syscall.
+
+Differential Revision: https://reviews.llvm.org/D52091
+
+--- a/compiler-rt/lib/asan/asan_win.cc	(revision 342651)
++++ b/compiler-rt/lib/asan/asan_win.cc	(revision 342652)
+@@ -154,6 +154,14 @@
+                             asan_thread_start, t, thr_flags, tid);
+ }
+ 
++INTERCEPTOR_WINAPI(void, NtTerminateThread, void *rcx) {
++  // Unpoison the terminating thread's stack because the memory may be re-used.
++  NT_TIB *tib = (NT_TIB *)NtCurrentTeb();
++  uptr stackSize = (uptr)tib->StackBase - (uptr)tib->StackLimit;
++  __asan_unpoison_memory_region(tib->StackLimit, stackSize);
++  return REAL(NtTerminateThread(rcx));
++}
++
+ // }}}
+ 
+ namespace __asan {
+@@ -161,7 +169,9 @@
+ void InitializePlatformInterceptors() {
+   ASAN_INTERCEPT_FUNC(CreateThread);
+   ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
+-
++  CHECK(::__interception::OverrideFunction("NtTerminateThread",
++                                           (uptr)WRAP(NtTerminateThread),
++                                           (uptr *)&REAL(NtTerminateThread)));
+ #ifdef _WIN64
+   ASAN_INTERCEPT_FUNC(__C_specific_handler);
+ #else
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -185,61 +185,42 @@ def bootstrap(topsrcdir, mozilla_dir=Non
             # more robust.
             return mozversioncontrol.get_repository_object(path=mozilla_dir)
         except (mozversioncontrol.InvalidRepoPath,
                 mozversioncontrol.MissingVCSTool):
             return None
 
     def telemetry_handler(context, data):
         # We have not opted-in to telemetry
-        if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
+        if not context.settings.build.telemetry:
             return
 
         telemetry_dir = os.path.join(get_state_dir()[0], 'telemetry')
         try:
             os.mkdir(telemetry_dir)
         except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
         outgoing_dir = os.path.join(telemetry_dir, 'outgoing')
         try:
             os.mkdir(outgoing_dir)
         except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
 
-        # Add common metadata to help submit sorted data later on.
-        data['argv'] = sys.argv
-        data.setdefault('system', {}).update(dict(
-            architecture=list(platform.architecture()),
-            machine=platform.machine(),
-            python_version=platform.python_version(),
-            release=platform.release(),
-            system=platform.system(),
-            version=platform.version(),
-        ))
-
-        if platform.system() == 'Linux':
-            dist = list(platform.linux_distribution())
-            data['system']['linux_distribution'] = dist
-        elif platform.system() == 'Windows':
-            win32_ver = list((platform.win32_ver())),
-            data['system']['win32_ver'] = win32_ver
-        elif platform.system() == 'Darwin':
-            # mac version is a special Cupertino snowflake
-            r, v, m = platform.mac_ver()
-            data['system']['mac_ver'] = [r, list(v), m]
-
         with open(os.path.join(outgoing_dir, str(uuid.uuid4()) + '.json'),
                   'w') as f:
             json.dump(data, f, sort_keys=True)
 
     def should_skip_dispatch(context, handler):
         # The user is performing a maintenance command.
-        if handler.name in ('bootstrap', 'doctor', 'mach-commands', 'vcs-setup'):
+        if handler.name in ('bootstrap', 'doctor', 'mach-commands', 'vcs-setup',
+                            # We call mach environment in client.mk which would cause the
+                            # data submission to block the forward progress of make.
+                            'environment'):
             return True
 
         # We are running in automation.
         if 'MOZ_AUTOMATION' in os.environ or 'TASK_ID' in os.environ:
             return True
 
         # The environment is likely a machine invocation.
         if sys.stdin.closed or not sys.stdin.isatty():
@@ -252,23 +233,18 @@ def bootstrap(topsrcdir, mozilla_dir=Non
 
 
         For now,  we will use this to handle build system telemetry.
         """
         # Don't do anything when...
         if should_skip_dispatch(context, handler):
             return
 
-        # We call mach environment in client.mk which would cause the
-        # data submission below to block the forward progress of make.
-        if handler.name in ('environment'):
-            return
-
         # We have not opted-in to telemetry
-        if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
+        if not context.settings.build.telemetry:
             return
 
         # Every n-th operation
         if random.randint(1, TELEMETRY_SUBMISSION_FREQUENCY) != 1:
             return
 
         with open(os.devnull, 'wb') as devnull:
             subprocess.Popen([sys.executable,
--- a/dom/svg/SVGTextPathElement.cpp
+++ b/dom/svg/SVGTextPathElement.cpp
@@ -85,16 +85,28 @@ nsSVGElement::StringInfo SVGTextPathElem
 //----------------------------------------------------------------------
 // Implementation
 
 SVGTextPathElement::SVGTextPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : SVGTextPathElementBase(aNodeInfo)
 {
 }
 
+void
+SVGTextPathElement::HrefAsString(nsAString& aHref)
+{
+  if (mStringAttributes[SVGTextPathElement::HREF].IsExplicitlySet()) {
+    mStringAttributes[SVGTextPathElement::HREF]
+      .GetAnimValue(aHref, this);
+  } else {
+    mStringAttributes[SVGTextPathElement::XLINK_HREF]
+      .GetAnimValue(aHref, this);
+  }
+}
+
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGTextPathElement)
 
 already_AddRefed<SVGAnimatedString>
 SVGTextPathElement::Href()
 {
--- a/dom/svg/SVGTextPathElement.h
+++ b/dom/svg/SVGTextPathElement.h
@@ -54,16 +54,18 @@ public:
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> StartOffset();
   already_AddRefed<SVGAnimatedEnumeration> Method();
   already_AddRefed<SVGAnimatedEnumeration> Spacing();
   already_AddRefed<SVGAnimatedEnumeration> Side();
   already_AddRefed<SVGAnimatedString> Href();
 
+  void HrefAsString(nsAString& aHref);
+
  protected:
 
   virtual LengthAttributesInfo GetLengthInfo() override;
   virtual EnumAttributesInfo GetEnumInfo() override;
   virtual StringAttributesInfo GetStringInfo() override;
 
   enum { /* TEXTLENGTH, */ STARTOFFSET = 1 };
   nsSVGLength2 mLengthAttributes[2];
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -190,17 +190,16 @@ ContentClient::BeginPaint(PaintedLayer* 
       }
 
       // Try to rotate the buffer or unrotate it if we cannot be rotated
       if (needsUnrotate) {
         if (canUnrotate && mBuffer->UnrotateBufferTo(newParameters)) {
           newParameters.SetUnrotated();
           mBuffer->SetParameters(newParameters);
         } else {
-          MOZ_ASSERT(!result.mAsyncPaint);
           MOZ_ASSERT(GetFrontBuffer());
           mBuffer->Unlock();
           dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
           dest.mCanReuseBuffer = false;
         }
       } else {
         mBuffer->SetParameters(newParameters);
       }
new file mode 100644
--- /dev/null
+++ b/gfx/tests/crashtests/1470440.html
@@ -0,0 +1,7 @@
+<style>
+:last-child{
+  border-width: 9596.6vmin thin;
+  border-style: dotted;
+}
+</style>
+<rect id='id3'/>
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -162,9 +162,10 @@ load 1308394.html
 load 1317403-1.html # bug 1331533
 load 1325159-1.html
 load 1331683.html
 skip-if(Android) pref(dom.disable_open_during_load,false) load 1343666.html
 load 1408078-1.html
 load 1464243.html
 load 1467847-1.html
 load 1468020.html
+load 1470440.html
 load 1478035.html
--- a/js/src/devtools/automation/autospider.py
+++ b/js/src/devtools/automation/autospider.py
@@ -418,17 +418,17 @@ if not args.nobuild:
         if not os.path.isdir(hostdir):
             os.makedirs(hostdir)
         shutil.copy(os.path.join(DIR.tooltool, "breakpad-tools", "dump_syms"),
                     os.path.join(hostdir, 'dump_syms'))
         run_command([
             'make',
             'recurse_syms',
             'MOZ_SOURCE_REPO=file://' + DIR.source,
-            'RUST_TARGET=0', 'RUSTC_COMMIT=0',
+            'RUSTC_COMMIT=0',
             'MOZ_CRASHREPORTER=1',
             'MOZ_AUTOMATION_BUILD_SYMBOLS=1',
         ], check=True)
 
 COMMAND_PREFIX = []
 # On Linux, disable ASLR to make shell builds a bit more reproducible.
 if subprocess.call("type setarch >/dev/null 2>&1", shell=True) == 0:
     COMMAND_PREFIX.extend(['setarch', platform.machine(), '-R'])
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -4278,16 +4278,21 @@ GCRuntime::purgeRuntime()
     rt->caches().purge();
 
     if (auto cache = rt->maybeThisRuntimeSharedImmutableStrings()) {
         cache->purge();
     }
 
     MOZ_ASSERT(unmarkGrayStack.empty());
     unmarkGrayStack.clearAndFree();
+
+    // If we're the main runtime, tell helper threads to free their unused
+    // memory when they are next idle.
+    if (!rt->parentRuntime)
+        HelperThreadState().triggerFreeUnusedMemory();
 }
 
 bool
 GCRuntime::shouldPreserveJITCode(Realm* realm, const TimeStamp &currentTime,
                                  JS::gcreason::Reason reason, bool canAllocateMoreCode)
 {
     static const auto oneSecond = TimeDuration::FromSeconds(1);
 
--- a/js/src/jit-test/tests/wasm/gc/anyref-global-object.js
+++ b/js/src/jit-test/tests/wasm/gc/anyref-global-object.js
@@ -42,19 +42,18 @@ assertEq(new WebAssembly.Global({value: 
     g = new WebAssembly.Global({value: "anyref"}, true);
     assertEq(g.value instanceof Boolean, true);
     assertEq(!!g.value, true);
 
     g = new WebAssembly.Global({value: "anyref"}, Symbol("status"));
     assertEq(g.value instanceof Symbol, true);
     assertEq(g.value.toString(), "Symbol(status)");
 
-    assertErrorMessage(() => new WebAssembly.Global({value: "anyref"}, undefined),
-                       TypeError,
-                       "can't convert undefined to object");
+    g = new WebAssembly.Global({value: "anyref"}, undefined);
+    assertEq(g.value, null);
 })();
 
 (function() {
     // Test mutable property and assignment.
     let g = new WebAssembly.Global({value: "anyref", mutable: true}, null);
     assertEq(g.value, null);
 
     let obj = { x: 42 };
--- a/js/src/jit-test/tests/wasm/gc/anyref.js
+++ b/js/src/jit-test/tests/wasm/gc/anyref.js
@@ -88,21 +88,35 @@ let { exports } = wasmEvalText(`(module
         ref.null anyref
         set_local 0
         i32.const 58
         call $sum
         drop
         get_local 0
         ref.is_null
     )
-)`);
+
+    (func (export "ref_eq") (param $a anyref) (param $b anyref) (result i32)
+	  (ref.eq (get_local $a) (get_local $b)))
+
+    (func (export "ref_eq_for_control") (param $a anyref) (param $b anyref) (result f64)
+	  (if f64 (ref.eq (get_local $a) (get_local $b))
+	      (f64.const 5.0)
+	      (f64.const 3.0)))
+    )`);
 
 assertEq(exports.is_null(), 1);
 assertEq(exports.is_null_spill(), 1);
 assertEq(exports.is_null_local(), 1);
+assertEq(exports.ref_eq(null, null), 1);
+assertEq(exports.ref_eq(null, {}), 0);
+assertEq(exports.ref_eq(this, this), 1);
+assertEq(exports.ref_eq_for_control(null, null), 5);
+assertEq(exports.ref_eq_for_control(null, {}), 3);
+assertEq(exports.ref_eq_for_control(this, this), 5);
 
 // Anyref param and result in wasm functions.
 
 exports = wasmEvalText(`(module
     (gc_feature_opt_in 1)
     (func (export "is_null") (result i32) (param $ref anyref)
         get_local $ref
         ref.is_null
--- a/js/src/jit-test/tests/wasm/gc/gc-feature-opt-in.js
+++ b/js/src/jit-test/tests/wasm/gc/gc-feature-opt-in.js
@@ -113,8 +113,14 @@ assertErrorMessage(() => new WebAssembly
                    WebAssembly.CompileError,
                    /unrecognized opcode/);
 
 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
     `(module
       (func ref.is_null))`)),
                    WebAssembly.CompileError,
                    /unrecognized opcode/);
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(
+    `(module
+      (func ref.eq))`)),
+                   WebAssembly.CompileError,
+                   /unrecognized opcode/);
--- a/js/src/jit-test/tests/wasm/gc/ref.js
+++ b/js/src/jit-test/tests/wasm/gc/ref.js
@@ -53,16 +53,21 @@ var bin = wasmTextToBinary(
        (ref.null (ref $even)))
 
       (func (param (ref $cons))
        (call $cdr (get_local 0))
        drop
        (call $imp (get_local 0))
        drop)
 
+      (func (param (ref $cons))
+       (drop (ref.eq (get_local 0) (ref.null (ref $cons))))
+       (drop (ref.eq (ref.null (ref $cons)) (get_local 0)))
+       (drop (ref.eq (get_local 0) (ref.null anyref)))
+       (drop (ref.eq (ref.null anyref) (get_local 0))))
      )`);
 
 // Validation
 
 assertEq(WebAssembly.validate(bin), true);
 
 // ref.is_null should work on any reference type
 
--- a/js/src/jit-test/tests/wasm/globals.js
+++ b/js/src/jit-test/tests/wasm/globals.js
@@ -338,22 +338,22 @@ wasmAssert(`(module
     let mod = wasmEvalText(`(module
                              (import "" "g" (global i64))
                              (func (export "f") (result i32)
                               (i64.eqz (get_global 0))))`,
                            {"":{g: new Global({value: "i64"})}});
     assertEq(mod.exports.f(), 1);
 
     {
-        // "value" is enumerable
+        // "value" is enumerable and is the first enumerated value
         let x = new Global({value: "i32"});
         let s = "";
         for ( let i in x )
             s = s + i + ",";
-        assertEq(s, "value,");
+        assertEq(s.substring(0,6), "value,");
     }
 
     // "value" is defined on the prototype, not on the object
     assertEq("value" in Global.prototype, true);
 
     // Can't set the value of an immutable global
     assertErrorMessage(() => (new Global({value: "i32"})).value = 10,
                        TypeError,
rename from js/src/jit-test/tests/wasm/regress/proxy-has-trap-table.js
rename to js/src/jit-test/tests/wasm/regress/proxy-get-trap-table.js
--- a/js/src/jit-test/tests/wasm/regress/proxy-has-trap-table.js
+++ b/js/src/jit-test/tests/wasm/regress/proxy-get-trap-table.js
@@ -1,11 +1,14 @@
+// The 'get' handler should be invoked directly when reading fields of the
+// descriptor.
+
 assertErrorMessage(() => {
     var desc = {
         element: "anyfunc",
         initial: 1
     };
     var proxy = new Proxy({}, {
-        has: true
+        get: true
     });
     Object.setPrototypeOf(desc, proxy);
     let table = new WebAssembly.Table(desc);
-}, TypeError, /proxy handler's has trap/);
+}, TypeError, /proxy handler's get trap/);
--- a/js/src/jit-test/tests/wasm/spec/jsapi.js
+++ b/js/src/jit-test/tests/wasm/spec/jsapi.js
@@ -251,17 +251,17 @@ test(() => {
     assert_equals(String(emptyModule), "[object WebAssembly.Module]");
     assert_equals(Object.getPrototypeOf(emptyModule), moduleProto);
 }, "'WebAssembly.Module' instance objects");
 
 test(() => {
     const moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports');
     assert_equals(typeof moduleImportsDesc.value, "function");
     assert_equals(moduleImportsDesc.writable, true);
-    assert_equals(moduleImportsDesc.enumerable, false);
+    assert_equals(moduleImportsDesc.enumerable, true);
     assert_equals(moduleImportsDesc.configurable, true);
 }, "'WebAssembly.Module.imports' data property");
 
 test(() => {
     const moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports');
     const moduleImports = moduleImportsDesc.value;
     assert_equals(moduleImports.length, 1);
     assertThrows(() => moduleImports(), TypeError);
@@ -286,17 +286,17 @@ test(() => {
     assert_equals(arr[3].module, "g");
     assert_equals(arr[3].name, "⚡");
 }, "'WebAssembly.Module.imports' method");
 
 test(() => {
     const moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports');
     assert_equals(typeof moduleExportsDesc.value, "function");
     assert_equals(moduleExportsDesc.writable, true);
-    assert_equals(moduleExportsDesc.enumerable, false);
+    assert_equals(moduleExportsDesc.enumerable, true);
     assert_equals(moduleExportsDesc.configurable, true);
 }, "'WebAssembly.Module.exports' data property");
 
 test(() => {
     const moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports');
     const moduleExports = moduleExportsDesc.value;
     assert_equals(moduleExports.length, 1);
     assertThrows(() => moduleExports(), TypeError);
@@ -317,28 +317,28 @@ test(() => {
     assert_equals(arr[3].kind, "global");
     assert_equals(arr[3].name, "⚡");
 }, "'WebAssembly.Module.exports' method");
 
 test(() => {
     const customSectionsDesc = Object.getOwnPropertyDescriptor(Module, 'customSections');
     assert_equals(typeof customSectionsDesc.value, "function");
     assert_equals(customSectionsDesc.writable, true);
-    assert_equals(customSectionsDesc.enumerable, false);
+    assert_equals(customSectionsDesc.enumerable, true);
     assert_equals(customSectionsDesc.configurable, true);
 }, "'WebAssembly.Module.customSections' data property");
 
 test(() => {
     const customSectionsDesc = Object.getOwnPropertyDescriptor(Module, 'customSections');
     const moduleCustomSections = customSectionsDesc.value;
     assert_equals(moduleCustomSections.length, 2);
     assertThrows(() => moduleCustomSections(), TypeError);
     assertThrows(() => moduleCustomSections(undefined), TypeError);
     assertThrows(() => moduleCustomSections({}), TypeError);
-    var arr = moduleCustomSections(emptyModule);
+    var arr = moduleCustomSections(emptyModule, "abracadabra");
     assert_equals(arr instanceof Array, true);
     assert_equals(arr.length, 0);
 }, "'WebAssembly.Module.customSections' method");
 
 test(() => {
     const instanceDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Instance');
     assert_equals(typeof instanceDesc.value, "function");
     assert_equals(instanceDesc.writable, true);
@@ -388,17 +388,17 @@ test(() => {
     assert_equals(String(exportingInstance), "[object WebAssembly.Instance]");
     assert_equals(Object.getPrototypeOf(exportingInstance), instanceProto);
 }, "'WebAssembly.Instance' instance objects");
 
 test(() => {
     const exportsDesc = Object.getOwnPropertyDescriptor(instanceProto, 'exports');
     assert_equals(typeof exportsDesc.get, "function");
     assert_equals(exportsDesc.set, undefined);
-    assert_equals(exportsDesc.enumerable, false);
+    assert_equals(exportsDesc.enumerable, true);
     assert_equals(exportsDesc.configurable, true);
     const exportsGetter = exportsDesc.get;
     assertThrows(() => exportsGetter.call(), TypeError);
     assertThrows(() => exportsGetter.call({}), TypeError);
     assert_equals(typeof exportsGetter.call(exportingInstance), "object");
 }, "'WebAssembly.Instance.prototype.exports' accessor property");
 
 test(() => {
@@ -437,21 +437,21 @@ test(() => {
 test(() => {
     const memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory');
     assert_equals(Memory, memoryDesc.value);
     assert_equals(Memory.length, 1);
     assert_equals(Memory.name, "Memory");
     assertThrows(() => Memory(), TypeError);
     assertThrows(() => new Memory(1), TypeError);
     assertThrows(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error);
-    assertThrows(() => new Memory({initial:-1}), RangeError);
-    assertThrows(() => new Memory({initial:Math.pow(2,32)}), RangeError);
+    assertThrows(() => new Memory({initial:-1}), TypeError);
+    assertThrows(() => new Memory({initial:Math.pow(2,32)}), TypeError);
     assertThrows(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), RangeError);
     assertThrows(() => new Memory({initial:2, maximum:1 }), RangeError);
-    assertThrows(() => new Memory({maximum: -1 }), RangeError);
+    assertThrows(() => new Memory({maximum: -1 }), TypeError);
     assert_equals(new Memory({initial:1}) instanceof Memory, true);
     assert_equals(new Memory({initial:1.5}).buffer.byteLength, WasmPage);
 }, "'WebAssembly.Memory' constructor function");
 
 test(() => {
     const memoryProtoDesc = Object.getOwnPropertyDescriptor(Memory, 'prototype');
     assert_equals(typeof memoryProtoDesc.value, "object");
     assert_equals(memoryProtoDesc.writable, false);
@@ -473,44 +473,44 @@ test(() => {
     assert_equals(String(mem1), "[object WebAssembly.Memory]");
     assert_equals(Object.getPrototypeOf(mem1), memoryProto);
 }, "'WebAssembly.Memory' instance objects");
 
 test(() => {
     const bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer');
     assert_equals(typeof bufferDesc.get, "function");
     assert_equals(bufferDesc.set, undefined);
-    assert_equals(bufferDesc.enumerable, false);
+    assert_equals(bufferDesc.enumerable, true);
     assert_equals(bufferDesc.configurable, true);
 }, "'WebAssembly.Memory.prototype.buffer' accessor property");
 
 test(() => {
     const bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer');
     const bufferGetter = bufferDesc.get;
     assertThrows(() => bufferGetter.call(), TypeError);
     assertThrows(() => bufferGetter.call({}), TypeError);
     assert_equals(bufferGetter.call(mem1) instanceof ArrayBuffer, true);
     assert_equals(bufferGetter.call(mem1).byteLength, WasmPage);
 }, "'WebAssembly.Memory.prototype.buffer' getter");
 
 test(() => {
     const memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
     assert_equals(typeof memGrowDesc.value, "function");
-    assert_equals(memGrowDesc.enumerable, false);
+    assert_equals(memGrowDesc.enumerable, true);
     assert_equals(memGrowDesc.configurable, true);
 }, "'WebAssembly.Memory.prototype.grow' data property");
 
 test(() => {
     const memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
     const memGrow = memGrowDesc.value;
     assert_equals(memGrow.length, 1);
     assertThrows(() => memGrow.call(), TypeError);
     assertThrows(() => memGrow.call({}), TypeError);
-    assertThrows(() => memGrow.call(mem1, -1), RangeError);
-    assertThrows(() => memGrow.call(mem1, Math.pow(2,32)), RangeError);
+    assertThrows(() => memGrow.call(mem1, -1), TypeError);
+    assertThrows(() => memGrow.call(mem1, Math.pow(2,32)), TypeError);
     var mem = new Memory({initial:1, maximum:2});
     var buf = mem.buffer;
     assert_equals(buf.byteLength, WasmPage);
     assert_equals(mem.grow(0), 1);
     assert_not_equals(buf, mem.buffer)
     assert_equals(buf.byteLength, 0);
     buf = mem.buffer;
     assert_equals(buf.byteLength, WasmPage);
@@ -545,20 +545,20 @@ test(() => {
     assert_equals(Table.length, 1);
     assert_equals(Table.name, "Table");
     assertThrows(() => Table(), TypeError);
     assertThrows(() => new Table(1), TypeError);
     assertThrows(() => new Table({initial:1, element:1}), TypeError);
     assertThrows(() => new Table({initial:1, element:"any"}), TypeError);
     assertThrows(() => new Table({initial:1, element:{valueOf() { return "anyfunc" }}}), TypeError);
     assertThrows(() => new Table({initial:{valueOf() { throw new Error("here")}}, element:"anyfunc"}), Error);
-    assertThrows(() => new Table({initial:-1, element:"anyfunc"}), RangeError);
-    assertThrows(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), RangeError);
+    assertThrows(() => new Table({initial:-1, element:"anyfunc"}), TypeError);
+    assertThrows(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), TypeError);
     assertThrows(() => new Table({initial:2, maximum:1, element:"anyfunc"}), RangeError);
-    assertThrows(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), RangeError);
+    assertThrows(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), TypeError);
     assert_equals(new Table({initial:1, element:"anyfunc"}) instanceof Table, true);
     assert_equals(new Table({initial:1.5, element:"anyfunc"}) instanceof Table, true);
     assert_equals(new Table({initial:1, maximum:1.5, element:"anyfunc"}) instanceof Table, true);
     assertThrows(() => new Table({initial:1, maximum:Math.pow(2,32)-1, element:"anyfunc"}), RangeError);
 }, "'WebAssembly.Table' constructor function");
 
 test(() => {
     const tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
@@ -582,94 +582,94 @@ test(() => {
     assert_equals(String(tbl1), "[object WebAssembly.Table]");
     assert_equals(Object.getPrototypeOf(tbl1), tableProto);
 }, "'WebAssembly.Table' instance objects");
 
 test(() => {
     const lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
     assert_equals(typeof lengthDesc.get, "function");
     assert_equals(lengthDesc.set, undefined);
-    assert_equals(lengthDesc.enumerable, false);
+    assert_equals(lengthDesc.enumerable, true);
     assert_equals(lengthDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.length' accessor data property");
 
 test(() => {
     const lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
     const lengthGetter = lengthDesc.get;
     assert_equals(lengthGetter.length, 0);
     assertThrows(() => lengthGetter.call(), TypeError);
     assertThrows(() => lengthGetter.call({}), TypeError);
     assert_equals(typeof lengthGetter.call(tbl1), "number");
     assert_equals(lengthGetter.call(tbl1), 2);
 }, "'WebAssembly.Table.prototype.length' getter");
 
 test(() => {
     const getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get');
     assert_equals(typeof getDesc.value, "function");
-    assert_equals(getDesc.enumerable, false);
+    assert_equals(getDesc.enumerable, true);
     assert_equals(getDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.get' data property");
 
 test(() => {
     const getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get');
     const get = getDesc.value;
     assert_equals(get.length, 1);
     assertThrows(() => get.call(), TypeError);
     assertThrows(() => get.call({}), TypeError);
     assert_equals(get.call(tbl1, 0), null);
     assert_equals(get.call(tbl1, 1), null);
     assert_equals(get.call(tbl1, 1.5), null);
     assertThrows(() => get.call(tbl1, 2), RangeError);
     assertThrows(() => get.call(tbl1, 2.5), RangeError);
-    assertThrows(() => get.call(tbl1, -1), RangeError);
-    assertThrows(() => get.call(tbl1, Math.pow(2,33)), RangeError);
+    assertThrows(() => get.call(tbl1, -1), TypeError);
+    assertThrows(() => get.call(tbl1, Math.pow(2,33)), TypeError);
     assertThrows(() => get.call(tbl1, {valueOf() { throw new Error("hi") }}), Error);
 }, "'WebAssembly.Table.prototype.get' method");
 
 test(() => {
     const setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set');
     assert_equals(typeof setDesc.value, "function");
-    assert_equals(setDesc.enumerable, false);
+    assert_equals(setDesc.enumerable, true);
     assert_equals(setDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.set' data property");
 
 test(() => {
     const setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set');
     const set = setDesc.value;
     assert_equals(set.length, 2);
     assertThrows(() => set.call(), TypeError);
     assertThrows(() => set.call({}), TypeError);
     assertThrows(() => set.call(tbl1, 0), TypeError);
     assertThrows(() => set.call(tbl1, 2, null), RangeError);
-    assertThrows(() => set.call(tbl1, -1, null), RangeError);
-    assertThrows(() => set.call(tbl1, Math.pow(2,33), null), RangeError);
+    assertThrows(() => set.call(tbl1, -1, null), TypeError);
+    assertThrows(() => set.call(tbl1, Math.pow(2,33), null), TypeError);
     assertThrows(() => set.call(tbl1, 0, undefined), TypeError);
     assertThrows(() => set.call(tbl1, 0, {}), TypeError);
     assertThrows(() => set.call(tbl1, 0, function() {}), TypeError);
     assertThrows(() => set.call(tbl1, 0, Math.sin), TypeError);
     assertThrows(() => set.call(tbl1, {valueOf() { throw Error("hai") }}, null), Error);
     assert_equals(set.call(tbl1, 0, null), undefined);
     assert_equals(set.call(tbl1, 1, null), undefined);
 }, "'WebAssembly.Table.prototype.set' method");
 
 test(() => {
     const tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
     assert_equals(typeof tblGrowDesc.value, "function");
-    assert_equals(tblGrowDesc.enumerable, false);
+    assert_equals(tblGrowDesc.enumerable, true);
     assert_equals(tblGrowDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.grow' data property");
 
 test(() => {
     const tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
     const tblGrow = tblGrowDesc.value;
     assert_equals(tblGrow.length, 1);
     assertThrows(() => tblGrow.call(), TypeError);
     assertThrows(() => tblGrow.call({}), TypeError);
-    assertThrows(() => tblGrow.call(tbl1, -1), RangeError);
-    assertThrows(() => tblGrow.call(tbl1, Math.pow(2,32)), RangeError);
+    assertThrows(() => tblGrow.call(tbl1, -1), TypeError);
+    assertThrows(() => tblGrow.call(tbl1, Math.pow(2,32)), TypeError);
     var tbl = new Table({element:"anyfunc", initial:1, maximum:2});
     assert_equals(tbl.length, 1);
     assert_equals(tbl.grow(0), 1);
     assert_equals(tbl.length, 1);
     assert_equals(tbl.grow(1), 1);
     assert_equals(tbl.length, 2);
     assertThrows(() => tbl.grow(1), Error);
 }, "'WebAssembly.Table.prototype.grow' method");
@@ -832,17 +832,17 @@ test(() => {
     assert_equals(globalI32Mut.value, 1234);
     assert_equals(globalF32Mut.value, 5678);
     assert_equals(globalF64Mut.value, 9012);
 }, "'WebAssembly.Global.prototype.value' setter");
 
 test(() => {
     const valueOfDesc = Object.getOwnPropertyDescriptor(globalProto, 'valueOf');
     assert_equals(typeof valueOfDesc.value, "function");
-    assert_equals(valueOfDesc.enumerable, false);
+    assert_equals(valueOfDesc.enumerable, true);
     assert_equals(valueOfDesc.configurable, true);
 }, "'WebAssembly.Global.prototype.valueOf' data property");
 
 test(() => {
     const valueOfDesc = Object.getOwnPropertyDescriptor(globalProto, 'valueOf');
     const valueOf = valueOfDesc.value;
     assert_equals(valueOf.length, 0);
     assertThrows(() => valueOf.call(), TypeError);
@@ -954,17 +954,17 @@ test(() => {
     assert_false(WebAssembly.validate(moduleBinaryImporting2Memories));
     assert_false(WebAssembly.validate(moduleBinaryWithMemSectionAndMemImport));
 }, "'WebAssembly.validate' method");
 
 test(() => {
     const compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
     assert_equals(typeof compileDesc.value, "function");
     assert_equals(compileDesc.writable, true);
-    assert_equals(compileDesc.enumerable, false);
+    assert_equals(compileDesc.enumerable, true);
     assert_equals(compileDesc.configurable, true);
 }, "'WebAssembly.compile' data property");
 
 test(() => {
     const compile = WebAssembly.compile;
     const compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
 
     assert_equals(compile, compileDesc.value);
@@ -1006,17 +1006,17 @@ function assertCompileSuccess(bytes) {
 
 assertCompileSuccess(emptyModuleBinary);
 assertCompileSuccess(new Uint8Array(emptyModuleBinary));
 
 test(() => {
     const instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
     assert_equals(typeof instantiateDesc.value, "function");
     assert_equals(instantiateDesc.writable, true);
-    assert_equals(instantiateDesc.enumerable, false);
+    assert_equals(instantiateDesc.enumerable, true);
     assert_equals(instantiateDesc.configurable, true);
 }, "'WebAssembly.instantiate' data property");
 
 test(() => {
     const instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
     const instantiate = WebAssembly.instantiate;
     assert_equals(instantiate, instantiateDesc.value);
     assert_equals(instantiate.length, 1);
--- a/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
+++ b/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
@@ -27,17 +27,17 @@
 #endif
 
 #if defined(JS_SIMULATOR_MIPS32) && !defined(__i386__)
 # error "The MIPS32 simulator atomics assume x86"
 #endif
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 struct AddressLock
 {
   public:
     void acquire();
     void release();
   private:
     uint32_t spinlock;
@@ -96,17 +96,17 @@ js::jit::AtomicOperations::loadSeqCst(T*
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     T v;
     __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
     return v;
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::loadSeqCst(int64_t* addr)
 {
     AddressGuard guard(addr);
     return *addr;
 }
@@ -128,17 +128,17 @@ inline void
 js::jit::AtomicOperations::storeSeqCst(T* addr, T val)
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline void
 js::jit::AtomicOperations::storeSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     *addr = val;
 }
@@ -161,17 +161,17 @@ js::jit::AtomicOperations::compareExchan
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
     return oldval;
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::compareExchangeSeqCst(int64_t* addr, int64_t oldval, int64_t newval)
 {
     AddressGuard guard(addr);
     int64_t val = *addr;
     if (val == oldval) {
@@ -201,17 +201,17 @@ inline T
 js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val)
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::fetchAddSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     int64_t old = *addr;
     *addr = old + val;
@@ -237,17 +237,17 @@ inline T
 js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val)
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::fetchSubSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     int64_t old = *addr;
     *addr = old - val;
@@ -274,17 +274,17 @@ js::jit::AtomicOperations::fetchAndSeqCs
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
 }
 
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::fetchAndSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     int64_t old = *addr;
     *addr = old & val;
@@ -310,17 +310,17 @@ inline T
 js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val)
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::fetchOrSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     int64_t old = *addr;
     *addr = old | val;
@@ -347,17 +347,17 @@ js::jit::AtomicOperations::fetchXorSeqCs
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
 
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::fetchXorSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     int64_t old = *addr;
     *addr = old ^ val;
@@ -385,17 +385,17 @@ js::jit::AtomicOperations::loadSafeWhenR
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     T v;
     __atomic_load(addr, &v, __ATOMIC_RELAXED);
     return v;
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::loadSafeWhenRacy(int64_t* addr)
 {
     return *addr;
 }
 
@@ -438,17 +438,17 @@ inline void
 js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val)
 {
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     __atomic_store(addr, &val, __ATOMIC_RELAXED);
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline void
 js::jit::AtomicOperations::storeSafeWhenRacy(int64_t* addr, int64_t val)
 {
     *addr = val;
 }
 
@@ -505,17 +505,17 @@ js::jit::AtomicOperations::exchangeSeqCs
     static_assert(sizeof(T) <= sizeof(void*), "atomics supported up to pointer size only");
     T v;
     __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
     return v;
 }
 
 namespace js { namespace jit {
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 template<>
 inline int64_t
 js::jit::AtomicOperations::exchangeSeqCst(int64_t* addr, int64_t val)
 {
     AddressGuard guard(addr);
     int64_t old = *addr;
     *addr = val;
@@ -531,17 +531,17 @@ js::jit::AtomicOperations::exchangeSeqCs
     *addr = val;
     return old;
 }
 
 #endif
 
 } }
 
-#if defined(JS_CODEGEN_MIPS32)
+#if !defined(JS_64BIT)
 
 inline void
 js::jit::AddressLock::acquire()
 {
     uint32_t zero = 0;
     uint32_t one = 1;
     while (!__atomic_compare_exchange(&spinlock, &zero, &one, true, __ATOMIC_SEQ_CST,
           __ATOMIC_SEQ_CST))
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -388,18 +388,19 @@ MSG_DEF(JSMSG_WASM_UNREACHABLE,        0
 MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW,   0, JSEXN_WASMRUNTIMEERROR, "integer overflow")
 MSG_DEF(JSMSG_WASM_INVALID_CONVERSION, 0, JSEXN_WASMRUNTIMEERROR, "invalid conversion to integer")
 MSG_DEF(JSMSG_WASM_INT_DIVIDE_BY_ZERO, 0, JSEXN_WASMRUNTIMEERROR, "integer divide by zero")
 MSG_DEF(JSMSG_WASM_OUT_OF_BOUNDS,      0, JSEXN_WASMRUNTIMEERROR, "index out of bounds")
 MSG_DEF(JSMSG_WASM_UNALIGNED_ACCESS,   0, JSEXN_WASMRUNTIMEERROR, "unaligned memory access")
 MSG_DEF(JSMSG_WASM_WAKE_OVERFLOW,      0, JSEXN_WASMRUNTIMEERROR, "too many woken agents")
 MSG_DEF(JSMSG_WASM_INVALID_PASSIVE_DATA_SEG, 0, JSEXN_WASMRUNTIMEERROR, "use of invalid passive data segment")
 MSG_DEF(JSMSG_WASM_INVALID_PASSIVE_ELEM_SEG, 0, JSEXN_WASMRUNTIMEERROR, "use of invalid passive element segment")
-MSG_DEF(JSMSG_WASM_BAD_UINT32,         2, JSEXN_RANGEERR,    "bad {0} {1}")
+MSG_DEF(JSMSG_WASM_BAD_RANGE ,         2, JSEXN_RANGEERR,    "bad {0} {1}")
 MSG_DEF(JSMSG_WASM_BAD_GROW,           1, JSEXN_RANGEERR,    "failed to grow {0}")
+MSG_DEF(JSMSG_WASM_BAD_UINT32,         2, JSEXN_TYPEERR,     "bad {0} {1}")
 MSG_DEF(JSMSG_WASM_BAD_BUF_ARG,        0, JSEXN_TYPEERR,     "first argument must be an ArrayBuffer or typed array object")
 MSG_DEF(JSMSG_WASM_BAD_MOD_ARG,        0, JSEXN_TYPEERR,     "first argument must be a WebAssembly.Module")
 MSG_DEF(JSMSG_WASM_BAD_BUF_MOD_ARG,    0, JSEXN_TYPEERR,     "first argument must be a WebAssembly.Module, ArrayBuffer or typed array object")
 MSG_DEF(JSMSG_WASM_BAD_DESC_ARG,       1, JSEXN_TYPEERR,     "first argument must be a {0} descriptor")
 MSG_DEF(JSMSG_WASM_BAD_ELEMENT,        0, JSEXN_TYPEERR,     "\"element\" property of table descriptor must be \"anyfunc\"")
 MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG,     0, JSEXN_TYPEERR,     "second argument must be an object")
 MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD,   1, JSEXN_TYPEERR,     "import object field '{0}' is not an Object")
 MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE,    0, JSEXN_TYPEERR,     "can only assign WebAssembly exported functions to Table")
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -1232,16 +1232,28 @@ GlobalHelperThreadState::checkTaskThread
     // run.
     if (isMaster && idle == 1) {
         return false;
     }
 
     return true;
 }
 
+void
+GlobalHelperThreadState::triggerFreeUnusedMemory()
+{
+    if (!CanUseExtraThreads())
+        return;
+
+    AutoLockHelperThreadState lock;
+    for (auto& thread : *threads)
+        thread.shouldFreeUnusedMemory = true;
+    notifyAll(PRODUCER, lock);
+}
+
 struct MOZ_RAII AutoSetContextRuntime
 {
     explicit AutoSetContextRuntime(JSRuntime* rt) {
         TlsContext.get()->setRuntime(rt);
     }
     ~AutoSetContextRuntime() {
         TlsContext.get()->setRuntime(nullptr);
     }
@@ -2561,16 +2573,18 @@ HelperThread::threadLoop()
             }
             // Now that we are holding the helper thread state lock again,
             // notify the record/replay system that we might block soon.
             // The helper thread state lock may not be released until the
             // block occurs.
             mozilla::recordreplay::NotifyUnrecordedWait(WakeupAll);
         }
 
+        maybeFreeUnusedMemory(&cx);
+
         // The selectors may depend on the HelperThreadState not changing
         // between task selection and task execution, in particular, on new
         // tasks not being added (because of the lifo structure of the work
         // lists). Unlocking the HelperThreadState between task selection and
         // execution is not well-defined.
 
         const TaskSpec* task = findHighestPriorityTask(lock);
         if (!task) {
@@ -2595,8 +2609,21 @@ HelperThread::findHighestPriorityTask(co
     for (const auto& task : taskSpecs) {
         if ((HelperThreadState().*(task.canStart))(locked)) {
             return &task;
         }
     }
 
     return nullptr;
 }
+
+void
+HelperThread::maybeFreeUnusedMemory(JSContext* cx)
+{
+    MOZ_ASSERT(idle());
+
+    cx->tempLifoAlloc().releaseAll();
+
+    if (shouldFreeUnusedMemory) {
+        cx->tempLifoAlloc().freeAll();
+        shouldFreeUnusedMemory = false;
+    }
+}
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -310,16 +310,18 @@ class GlobalHelperThreadState
 
     bool hasActiveThreads(const AutoLockHelperThreadState&);
     void waitForAllThreads();
     void waitForAllThreadsLocked(AutoLockHelperThreadState&);
 
     template <typename T>
     bool checkTaskThreadLimit(size_t maxThreads, bool isMaster = false) const;
 
+    void triggerFreeUnusedMemory();
+
   private:
     /*
      * Lock protecting all mutable shared state accessed by helper threads, and
      * used by all condition variables.
      */
     js::Mutex helperLock;
 
     /* Condvars for threads waiting/notifying each other. */
@@ -358,16 +360,22 @@ struct HelperThread
     mozilla::Maybe<Thread> thread;
 
     /*
      * Indicate to a thread that it should terminate itself. This is only read
      * or written with the helper thread state lock held.
      */
     bool terminate;
 
+    /*
+     * Indicates that this thread should free its unused memory when it is next
+     * idle.
+     */
+    bool shouldFreeUnusedMemory;
+
     /* The current task being executed by this thread, if any. */
     mozilla::Maybe<HelperTaskUnion> currentTask;
 
     bool idle() const {
         return currentTask.isNothing();
     }
 
     /* Any builder currently being compiled by Ion on this thread. */
@@ -447,16 +455,18 @@ struct HelperThread
     T maybeCurrentTaskAs() {
         if (currentTask.isSome() && currentTask->is<T>()) {
             return currentTask->as<T>();
         }
 
         return nullptr;
     }
 
+    void maybeFreeUnusedMemory(JSContext* cx);
+
     void handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::CompileMode mode);
 
     void handleWasmTier1Workload(AutoLockHelperThreadState& locked);
     void handleWasmTier2Workload(AutoLockHelperThreadState& locked);
     void handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked);
     void handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked);
     void handleIonWorkload(AutoLockHelperThreadState& locked);
     void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -6018,16 +6018,17 @@ class BaseCompiler final : public BaseCo
 
     void doReturn(ExprType returnType, bool popStack);
     void pushReturnedIfNonVoid(const FunctionCall& call, ExprType type);
 
     void emitCompareI32(Assembler::Condition compareOp, ValType compareType);
     void emitCompareI64(Assembler::Condition compareOp, ValType compareType);
     void emitCompareF32(Assembler::DoubleCondition compareOp, ValType compareType);
     void emitCompareF64(Assembler::DoubleCondition compareOp, ValType compareType);
+    void emitCompareRef(Assembler::Condition compareOp, ValType compareType);
 
     void emitAddI32();
     void emitAddI64();
     void emitAddF64();
     void emitAddF32();
     void emitSubtractI32();
     void emitSubtractI64();
     void emitSubtractF32();
@@ -7379,16 +7380,21 @@ BaseCompiler::sniffConditionalControlCmp
     // On x86, latent i64 binary comparisons use too many registers: the
     // reserved join register and the lhs and rhs operands require six, but we
     // only have five.
     if (operandType == ValType::I64) {
         return false;
     }
 #endif
 
+    // No optimization for pointer compares yet.
+    if (operandType.isRefOrAnyRef()) {
+        return false;
+    }
+
     OpBytes op;
     iter_.peekOp(&op);
     switch (op.b0) {
       case uint16_t(Op::BrIf):
       case uint16_t(Op::If):
       case uint16_t(Op::Select):
         setLatentCompare(compareOp, operandType);
         return true;
@@ -9165,16 +9171,30 @@ BaseCompiler::emitCompareF64(Assembler::
     moveImm32(0, rd);
     masm.bind(&across);
     freeF64(rs0);
     freeF64(rs1);
     pushI32(rd);
 }
 
 void
+BaseCompiler::emitCompareRef(Assembler::Condition compareOp, ValType compareType)
+{
+    MOZ_ASSERT(!sniffConditionalControlCmp(compareOp, compareType));
+
+    RegPtr rs1, rs2;
+    pop2xRef(&rs1, &rs2);
+    RegI32 rd = needI32();
+    masm.cmpPtrSet(compareOp, rs1, rs2, rd);
+    freeRef(rs1);
+    freeRef(rs2);
+    pushI32(rd);
+}
+
+void
 BaseCompiler::emitInstanceCall(uint32_t lineOrBytecode, const MIRTypeVector& sig,
                                ExprType retType, SymbolicAddress builtin)
 {
     MOZ_ASSERT(sig[0] == MIRType::Pointer);
 
     sync();
 
     uint32_t numArgs = sig.length() - 1 /* instance */;
@@ -9634,21 +9654,23 @@ BaseCompiler::emitMemOrTableCopy(bool is
 }
 
 bool
 BaseCompiler::emitMemOrTableDrop(bool isMem)
 {
     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
 
     uint32_t segIndex = 0;
-    if (!iter_.readMemOrTableDrop(isMem, &segIndex))
+    if (!iter_.readMemOrTableDrop(isMem, &segIndex)) {
         return false;
-
-    if (deadCode_)
+    }
+
+    if (deadCode_) {
         return true;
+    }
 
     // Despite the cast to int32_t, the callee regards the value as unsigned.
     pushI32(int32_t(segIndex));
     SymbolicAddress callee = isMem ? SymbolicAddress::MemDrop
                                    : SymbolicAddress::TableDrop;
     emitInstanceCall(lineOrBytecode, SigPI_, ExprType::Void, callee);
 
     Label ok;
@@ -9685,21 +9707,23 @@ BaseCompiler::emitMemFill()
 
 bool
 BaseCompiler::emitMemOrTableInit(bool isMem)
 {
     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
 
     uint32_t segIndex = 0;
     Nothing nothing;
-    if (!iter_.readMemOrTableInit(isMem, &segIndex, &nothing, &nothing, &nothing))
+    if (!iter_.readMemOrTableInit(isMem, &segIndex, &nothing, &nothing, &nothing)) {
         return false;
-
-    if (deadCode_)
+    }
+
+    if (deadCode_) {
         return true;
+    }
 
     pushI32(int32_t(segIndex));
     SymbolicAddress callee = isMem ? SymbolicAddress::MemInit
                                    : SymbolicAddress::TableInit;
     emitInstanceCall(lineOrBytecode, SigPIIII_, ExprType::Void, callee);
 
     Label ok;
     masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &ok);
@@ -10270,16 +10294,21 @@ BaseCompiler::emitBody()
 
           // Memory Related
           case uint16_t(Op::GrowMemory):
             CHECK_NEXT(emitGrowMemory());
           case uint16_t(Op::CurrentMemory):
             CHECK_NEXT(emitCurrentMemory());
 
 #ifdef ENABLE_WASM_GC
+          case uint16_t(Op::RefEq):
+            if (env_.gcTypesEnabled() == HasGcTypes::False) {
+                return iter_.unrecognizedOpcode(&op);
+            }
+            CHECK_NEXT(emitComparison(emitCompareRef, ValType::AnyRef, Assembler::Equal));
           case uint16_t(Op::RefNull):
             if (env_.gcTypesEnabled() == HasGcTypes::False) {
                 return iter_.unrecognizedOpcode(&op);
             }
             CHECK_NEXT(emitRefNull());
             break;
           case uint16_t(Op::RefIsNull):
             if (env_.gcTypesEnabled() == HasGcTypes::False) {
--- a/js/src/wasm/WasmConstants.h
+++ b/js/src/wasm/WasmConstants.h
@@ -355,16 +355,17 @@ enum class Op
     I32Extend16S                         = 0xc1,
     I64Extend8S                          = 0xc2,
     I64Extend16S                         = 0xc3,
     I64Extend32S                         = 0xc4,
 
     // GC ops
     RefNull                              = 0xd0,
     RefIsNull                            = 0xd1,
+    RefEq                                = 0xd2, // Unofficial
 
     FirstPrefix                          = 0xfc,
     MiscPrefix                           = 0xfc,
     ThreadPrefix                         = 0xfe,
     MozPrefix                            = 0xff,
 
     Limit                                = 0x100
 };
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -3554,16 +3554,17 @@ EmitBodyExprs(FunctionCompiler& f)
           case uint16_t(Op::I64ReinterpretF64):
             CHECK(EmitReinterpret(f, ValType::I64, ValType::F64, MIRType::Int64));
           case uint16_t(Op::F32ReinterpretI32):
             CHECK(EmitReinterpret(f, ValType::F32, ValType::I32, MIRType::Float32));
           case uint16_t(Op::F64ReinterpretI64):
             CHECK(EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double));
 
           // GC types are NYI in Ion.
+          case uint16_t(Op::RefEq):
           case uint16_t(Op::RefNull):
           case uint16_t(Op::RefIsNull):
             return f.iter().unrecognizedOpcode(&op);
 
           // Sign extensions
           case uint16_t(Op::I32Extend8S):
             CHECK(EmitSignExtend(f, 1, 4));
           case uint16_t(Op::I32Extend16S):
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -443,18 +443,17 @@ wasm::Eval(JSContext* cx, Handle<TypedAr
 
 // ============================================================================
 // Common functions
 
 // '[EnforceRange] unsigned long' types are coerced with
 //    ConvertToInt(v, 32, 'unsigned')
 // defined in Web IDL Section 3.2.4.9.
 static bool
-EnforceRangeU32(JSContext* cx, HandleValue v, uint32_t max, const char* kind, const char* noun,
-                uint32_t* u32)
+EnforceRangeU32(JSContext* cx, HandleValue v, const char* kind, const char* noun, uint32_t* u32)
 {
     // Step 4.
     double x;
     if (!ToNumber(cx, v, &x)) {
         return false;
     }
 
     // Step 5.
@@ -466,18 +465,18 @@ EnforceRangeU32(JSContext* cx, HandleVal
     if (!mozilla::IsFinite(x)) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, kind, noun);
         return false;
     }
 
     // Step 6.2.
     x = JS::ToInteger(x);
 
-    // Step 6.3, allowing caller to supply a more restrictive uint32_t max.
-    if (x < 0 || x > double(max)) {
+    // Step 6.3.
+    if (x < 0 || x > double(UINT32_MAX)) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, kind, noun);
         return false;
     }
 
     *u32 = uint32_t(x);
     MOZ_ASSERT(double(*u32) == x);
     return true;
 }
@@ -492,74 +491,72 @@ GetLimits(JSContext* cx, HandleObject ob
     }
     RootedId initialId(cx, AtomToId(initialAtom));
 
     RootedValue initialVal(cx);
     if (!GetProperty(cx, obj, obj, initialId, &initialVal)) {
         return false;
     }
 
-    if (!EnforceRangeU32(cx, initialVal, maxInitial, kind, "initial size", &limits->initial)) {
+    if (!EnforceRangeU32(cx, initialVal, kind, "initial size", &limits->initial)) {
+        return false;
+    }
+
+    if (limits->initial > maxInitial) {
+        JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_RANGE,
+                                 kind, "initial size");
         return false;
     }
 
     JSAtom* maximumAtom = Atomize(cx, "maximum", strlen("maximum"));
     if (!maximumAtom) {
         return false;
     }
     RootedId maximumId(cx, AtomToId(maximumAtom));
 
-    bool foundMaximum;
-    if (!HasProperty(cx, obj, maximumId, &foundMaximum)) {
+    RootedValue maxVal(cx);
+    if (!GetProperty(cx, obj, obj, maximumId, &maxVal)) {
         return false;
     }
 
-    if (foundMaximum) {
-        RootedValue maxVal(cx);
-        if (!GetProperty(cx, obj, obj, maximumId, &maxVal)) {
+    // maxVal does not have a default value.
+    if (!maxVal.isUndefined()) {
+        limits->maximum.emplace();
+        if (!EnforceRangeU32(cx, maxVal, kind, "maximum size", limits->maximum.ptr())) {
             return false;
         }
 
-        limits->maximum.emplace();
-        if (!EnforceRangeU32(cx, maxVal, maxMaximum, kind, "maximum size", limits->maximum.ptr())) {
-            return false;
-        }
-
-        if (limits->initial > *limits->maximum) {
-            JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32,
+        if (*limits->maximum > maxMaximum || limits->initial > *limits->maximum) {
+            JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_RANGE,
                                      kind, "maximum size");
             return false;
         }
     }
 
     limits->shared = Shareable::False;
 
 #ifdef ENABLE_WASM_THREAD_OPS
     if (allowShared == Shareable::True) {
         JSAtom* sharedAtom = Atomize(cx, "shared", strlen("shared"));
         if (!sharedAtom) {
             return false;
         }
         RootedId sharedId(cx, AtomToId(sharedAtom));
 
-        bool foundShared;
-        if (!HasProperty(cx, obj, sharedId, &foundShared)) {
+        RootedValue sharedVal(cx);
+        if (!GetProperty(cx, obj, obj, sharedId, &sharedVal)) {
             return false;
         }
 
-        if (foundShared) {
-            RootedValue sharedVal(cx);
-            if (!GetProperty(cx, obj, obj, sharedId, &sharedVal)) {
-                return false;
-            }
-
+        // shared's default value is false, which is already the value set above.
+        if (!sharedVal.isUndefined()) {
             limits->shared = ToBoolean(sharedVal) ? Shareable::True : Shareable::False;
 
             if (limits->shared == Shareable::True) {
-                if (!foundMaximum) {
+                if (maxVal.isUndefined()) {
                     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_MISSING_MAXIMUM,
                                               kind);
                     return false;
                 }
 
                 if (!cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
                     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                               JSMSG_WASM_NO_SHMEM_LINK);
@@ -599,19 +596,19 @@ const Class WasmModuleObject::class_ =
 const JSPropertySpec WasmModuleObject::properties[] =
 { JS_PS_END };
 
 const JSFunctionSpec WasmModuleObject::methods[] =
 { JS_FS_END };
 
 const JSFunctionSpec WasmModuleObject::static_methods[] =
 {
-    JS_FN("imports", WasmModuleObject::imports, 1, 0),
-    JS_FN("exports", WasmModuleObject::exports, 1, 0),
-    JS_FN("customSections", WasmModuleObject::customSections, 2, 0),
+    JS_FN("imports", WasmModuleObject::imports, 1, JSPROP_ENUMERATE),
+    JS_FN("exports", WasmModuleObject::exports, 1, JSPROP_ENUMERATE),
+    JS_FN("customSections", WasmModuleObject::customSections, 2, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
 /* static */ void
 WasmModuleObject::finalize(FreeOp* fop, JSObject* obj)
 {
     obj->as<WasmModuleObject>().module().Release();
 }
@@ -624,19 +621,19 @@ IsModuleObject(JSObject* obj, const Modu
         return false;
     }
 
     *module = &unwrapped->as<WasmModuleObject>().module();
     return true;
 }
 
 static bool
-GetModuleArg(JSContext* cx, CallArgs args, const char* name, const Module** module)
+GetModuleArg(JSContext* cx, CallArgs args, uint32_t numRequired, const char* name, const Module** module)
 {
-    if (!args.requireAtLeast(cx, name, 1)) {
+    if (!args.requireAtLeast(cx, name, numRequired)) {
         return false;
     }
 
     if (!args[0].isObject() || !IsModuleObject(&args[0].toObject(), module)) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_MOD_ARG);
         return false;
     }
 
@@ -747,17 +744,17 @@ UTF8CharsToString(JSContext* cx, const c
 }
 
 /* static */ bool
 WasmModuleObject::imports(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     const Module* module;
-    if (!GetModuleArg(cx, args, "WebAssembly.Module.imports", &module)) {
+    if (!GetModuleArg(cx, args, 1, "WebAssembly.Module.imports", &module)) {
         return false;
     }
 
     KindNames names(cx);
     if (!InitKindNames(cx, &names)) {
         return false;
     }
 
@@ -821,17 +818,17 @@ WasmModuleObject::imports(JSContext* cx,
 }
 
 /* static */ bool
 WasmModuleObject::exports(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     const Module* module;
-    if (!GetModuleArg(cx, args, "WebAssembly.Module.exports", &module)) {
+    if (!GetModuleArg(cx, args, 1, "WebAssembly.Module.exports", &module)) {
         return false;
     }
 
     KindNames names(cx);
     if (!InitKindNames(cx, &names)) {
         return false;
     }
 
@@ -889,17 +886,17 @@ WasmModuleObject::exports(JSContext* cx,
 }
 
 /* static */ bool
 WasmModuleObject::customSections(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     const Module* module;
-    if (!GetModuleArg(cx, args, "WebAssembly.Module.customSections", &module)) {
+    if (!GetModuleArg(cx, args, 2, "WebAssembly.Module.customSections", &module)) {
         return false;
     }
 
     Vector<char, 8> name(cx);
     {
         RootedString str(cx, ToString(cx, args.get(1)));
         if (!str) {
             return false;
@@ -1127,17 +1124,17 @@ WasmInstanceObject::exportsGetterImpl(JS
 WasmInstanceObject::exportsGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsInstance, exportsGetterImpl>(cx, args);
 }
 
 const JSPropertySpec WasmInstanceObject::properties[] =
 {
-    JS_PSG("exports", WasmInstanceObject::exportsGetter, 0),
+    JS_PSG("exports", WasmInstanceObject::exportsGetter, JSPROP_ENUMERATE),
     JS_PS_END
 };
 
 const JSFunctionSpec WasmInstanceObject::methods[] =
 { JS_FS_END };
 
 const JSFunctionSpec WasmInstanceObject::static_methods[] =
 { JS_FS_END };
@@ -1737,27 +1734,31 @@ WasmMemoryObject::bufferGetterImpl(JSCon
 WasmMemoryObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsMemory, bufferGetterImpl>(cx, args);
 }
 
 const JSPropertySpec WasmMemoryObject::properties[] =
 {
-    JS_PSG("buffer", WasmMemoryObject::bufferGetter, 0),
+    JS_PSG("buffer", WasmMemoryObject::bufferGetter, JSPROP_ENUMERATE),
     JS_PS_END
 };
 
 /* static */ bool
 WasmMemoryObject::growImpl(JSContext* cx, const CallArgs& args)
 {
     RootedWasmMemoryObject memory(cx, &args.thisv().toObject().as<WasmMemoryObject>());
 
+    if (!args.requireAtLeast(cx, "WebAssembly.Memory.grow", 1)) {
+        return false;
+    }
+
     uint32_t delta;
-    if (!EnforceRangeU32(cx, args.get(0), UINT32_MAX, "Memory", "grow delta", &delta)) {
+    if (!EnforceRangeU32(cx, args.get(0), "Memory", "grow delta", &delta)) {
         return false;
     }
 
     uint32_t ret = grow(memory, delta, cx);
 
     if (ret == uint32_t(-1)) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "memory");
         return false;
@@ -1771,17 +1772,17 @@ WasmMemoryObject::growImpl(JSContext* cx
 WasmMemoryObject::grow(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsMemory, growImpl>(cx, args);
 }
 
 const JSFunctionSpec WasmMemoryObject::methods[] =
 {
-    JS_FN("grow", WasmMemoryObject::grow, 1, 0),
+    JS_FN("grow", WasmMemoryObject::grow, 1, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
 const JSFunctionSpec WasmMemoryObject::static_methods[] =
 { JS_FS_END };
 
 ArrayBufferObjectMaybeShared&
 WasmMemoryObject::buffer() const
@@ -2072,27 +2073,27 @@ WasmTableObject::construct(JSContext* cx
     }
     RootedId elementId(cx, AtomToId(elementAtom));
 
     RootedValue elementVal(cx);
     if (!GetProperty(cx, obj, obj, elementId, &elementVal)) {
         return false;
     }
 
-    if (!elementVal.isString()) {
-        JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
-        return false;
-    }
-
-    JSLinearString* elementStr = elementVal.toString()->ensureLinear(cx);
+    RootedString elementStr(cx, ToString(cx, elementVal));
     if (!elementStr) {
         return false;
     }
 
-    if (!StringEqualsAscii(elementStr, "anyfunc")) {
+    RootedLinearString elementLinearStr(cx, elementStr->ensureLinear(cx));
+    if (!elementLinearStr) {
+        return false;
+    }
+
+    if (!StringEqualsAscii(elementLinearStr, "anyfunc")) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
         return false;
     }
 
     Limits limits;
     if (!GetLimits(cx, obj, MaxTableInitialLength, MaxTableMaximumLength, "Table", &limits,
                    Shareable::False))
     {
@@ -2125,41 +2126,45 @@ WasmTableObject::lengthGetterImpl(JSCont
 WasmTableObject::lengthGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsTable, lengthGetterImpl>(cx, args);
 }
 
 const JSPropertySpec WasmTableObject::properties[] =
 {
-    JS_PSG("length", WasmTableObject::lengthGetter, 0),
+    JS_PSG("length", WasmTableObject::lengthGetter, JSPROP_ENUMERATE),
     JS_PS_END
 };
 
 static bool
 ToTableIndex(JSContext* cx, HandleValue v, const Table& table, const char* noun, uint32_t* index)
 {
-    if (!EnforceRangeU32(cx, v, UINT32_MAX, "Table", noun, index)) {
+    if (!EnforceRangeU32(cx, v, "Table", noun, index)) {
         return false;
     }
 
     if (*index >= table.length()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, "Table", noun);
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_RANGE, "Table", noun);
         return false;
     }
 
     return true;
 }
 
 /* static */ bool
 WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
 {
     RootedWasmTableObject tableObj(cx, &args.thisv().toObject().as<WasmTableObject>());
     const Table& table = tableObj->table();
 
+    if (!args.requireAtLeast(cx, "WebAssembly.Table.get", 1)) {
+        return false;
+    }
+
     uint32_t index;
     if (!ToTableIndex(cx, args.get(0), table, "get index", &index)) {
         return false;
     }
 
     ExternalTableElem& elem = table.externalArray()[index];
     if (!elem.code) {
         args.rval().setNull();
@@ -2187,17 +2192,17 @@ WasmTableObject::get(JSContext* cx, unsi
 }
 
 /* static */ bool
 WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
 {
     RootedWasmTableObject tableObj(cx, &args.thisv().toObject().as<WasmTableObject>());
     Table& table = tableObj->table();
 
-    if (!args.requireAtLeast(cx, "set", 2)) {
+    if (!args.requireAtLeast(cx, "WebAssembly.Table.set", 2)) {
         return false;
     }
 
     uint32_t index;
     if (!ToTableIndex(cx, args.get(0), table, "set index", &index)) {
         return false;
     }
 
@@ -2238,18 +2243,22 @@ WasmTableObject::set(JSContext* cx, unsi
     return CallNonGenericMethod<IsTable, setImpl>(cx, args);
 }
 
 /* static */ bool
 WasmTableObject::growImpl(JSContext* cx, const CallArgs& args)
 {
     RootedWasmTableObject table(cx, &args.thisv().toObject().as<WasmTableObject>());
 
+    if (!args.requireAtLeast(cx, "WebAssembly.Table.grow", 1)) {
+        return false;
+    }
+
     uint32_t delta;
-    if (!EnforceRangeU32(cx, args.get(0), UINT32_MAX, "Table", "grow delta", &delta)) {
+    if (!EnforceRangeU32(cx, args.get(0), "Table", "grow delta", &delta)) {
         return false;
     }
 
     uint32_t ret = table->table().grow(delta, cx);
 
     if (ret == uint32_t(-1)) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "table");
         return false;
@@ -2263,19 +2272,19 @@ WasmTableObject::growImpl(JSContext* cx,
 WasmTableObject::grow(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsTable, growImpl>(cx, args);
 }
 
 const JSFunctionSpec WasmTableObject::methods[] =
 {
-    JS_FN("get", WasmTableObject::get, 1, 0),
-    JS_FN("set", WasmTableObject::set, 2, 0),
-    JS_FN("grow", WasmTableObject::grow, 1, 0),
+    JS_FN("get", WasmTableObject::get, 1, JSPROP_ENUMERATE),
+    JS_FN("set", WasmTableObject::set, 2, JSPROP_ENUMERATE),
+    JS_FN("grow", WasmTableObject::grow, 1, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
 const JSFunctionSpec WasmTableObject::static_methods[] =
 { JS_FS_END };
 
 Table&
 WasmTableObject::table() const
@@ -2416,16 +2425,23 @@ WasmGlobalObject::construct(JSContext* c
 
     if (!args.get(0).isObject()) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_DESC_ARG, "global");
         return false;
     }
 
     RootedObject obj(cx, &args[0].toObject());
 
+    // Extract properties in lexicographic order per spec.
+
+    RootedValue mutableVal(cx);
+    if (!JS_GetProperty(cx, obj, "mutable", &mutableVal)) {
+        return false;
+    }
+
     RootedValue typeVal(cx);
     if (!JS_GetProperty(cx, obj, "value", &typeVal)) {
         return false;
     }
 
     RootedString typeStr(cx, ToString(cx, typeVal));
     if (!typeStr) {
         return false;
@@ -2451,39 +2467,37 @@ WasmGlobalObject::construct(JSContext* c
     } else if (cx->options().wasmGc() && StringEqualsAscii(typeLinearStr, "anyref")) {
         globalType = ValType::AnyRef;
 #endif
     } else {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GLOBAL_TYPE);
         return false;
     }
 
-    RootedValue mutableVal(cx);
-    if (!JS_GetProperty(cx, obj, "mutable", &mutableVal)) {
-        return false;
-    }
-
     bool isMutable = ToBoolean(mutableVal);
 
     // Extract the initial value, or provide a suitable default.
     RootedVal globalVal(cx);
-    if (args.length() >= 2) {
-        RootedValue valueVal(cx, args.get(1));
+
+    // Initialize with default value.
+    switch (globalType.code()) {
+      case ValType::I32:    globalVal = Val(uint32_t(0)); break;
+      case ValType::I64:    globalVal = Val(uint64_t(0)); break;
+      case ValType::F32:    globalVal = Val(float(0.0));  break;
+      case ValType::F64:    globalVal = Val(double(0.0)); break;
+      case ValType::AnyRef: globalVal = Val(nullptr);     break;
+      case ValType::Ref:    MOZ_CRASH("Ref NYI");
+    }
+
+    // Override with non-undefined value, if provided.
+    RootedValue valueVal(cx, args.get(1));
+    if (!valueVal.isUndefined()) {
         if (!ToWebAssemblyValue(cx, globalType, valueVal, &globalVal)) {
             return false;
         }
-    } else {
-        switch (globalType.code()) {
-          case ValType::I32:    globalVal = Val(uint32_t(0)); break;
-          case ValType::I64:    globalVal = Val(uint64_t(0)); break;
-          case ValType::F32:    globalVal = Val(float(0.0));  break;
-          case ValType::F64:    globalVal = Val(double(0.0)); break;
-          case ValType::AnyRef: globalVal = Val(nullptr);     break;
-          case ValType::Ref:    MOZ_CRASH("Ref NYI");
-        }
     }
 
     WasmGlobalObject* global = WasmGlobalObject::create(cx, globalVal, isMutable);
     if (!global) {
         return false;
     }
 
     args.rval().setObject(*global);
@@ -2520,16 +2534,20 @@ WasmGlobalObject::valueGetter(JSContext*
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsGlobal, valueGetterImpl>(cx, args);
 }
 
 /* static */ bool
 WasmGlobalObject::valueSetterImpl(JSContext* cx, const CallArgs& args)
 {
+    if (!args.requireAtLeast(cx, "WebAssembly.Global setter", 1)) {
+        return false;
+    }
+
     RootedWasmGlobalObject global(cx, &args.thisv().toObject().as<WasmGlobalObject>());
     if (!global->isMutable()) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_GLOBAL_IMMUTABLE);
         return false;
     }
 
     if (global->type() == ValType::I64) {
         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64_TYPE);
@@ -2582,17 +2600,17 @@ const JSPropertySpec WasmGlobalObject::p
 {
     JS_PSGS("value", WasmGlobalObject::valueGetter, WasmGlobalObject::valueSetter,
             JSPROP_ENUMERATE),
     JS_PS_END
 };
 
 const JSFunctionSpec WasmGlobalObject::methods[] =
 {
-    JS_FN(js_valueOf_str, WasmGlobalObject::valueGetter, 0, 0),
+    JS_FN(js_valueOf_str, WasmGlobalObject::valueGetter, 0, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
 const JSFunctionSpec WasmGlobalObject::static_methods[] =
 { JS_FS_END };
 
 ValType
 WasmGlobalObject::type() const
@@ -3469,21 +3487,21 @@ WebAssembly_instantiateStreaming(JSConte
 
     callArgs.rval().setObject(*promise);
     return true;
 }
 
 static const JSFunctionSpec WebAssembly_static_methods[] =
 {
     JS_FN(js_toSource_str, WebAssembly_toSource, 0, 0),
-    JS_FN("compile", WebAssembly_compile, 1, 0),
-    JS_FN("instantiate", WebAssembly_instantiate, 1, 0),
-    JS_FN("validate", WebAssembly_validate, 1, 0),
-    JS_FN("compileStreaming", WebAssembly_compileStreaming, 1, 0),
-    JS_FN("instantiateStreaming", WebAssembly_instantiateStreaming, 1, 0),
+    JS_FN("compile", WebAssembly_compile, 1, JSPROP_ENUMERATE),
+    JS_FN("instantiate", WebAssembly_instantiate, 1, JSPROP_ENUMERATE),
+    JS_FN("validate", WebAssembly_validate, 1, JSPROP_ENUMERATE),
+    JS_FN("compileStreaming", WebAssembly_compileStreaming, 1, JSPROP_ENUMERATE),
+    JS_FN("instantiateStreaming", WebAssembly_instantiateStreaming, 1, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
 const Class js::WebAssemblyClass =
 {
     js_WebAssembly_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_WebAssembly)
 };
--- a/js/src/wasm/WasmOpIter.cpp
+++ b/js/src/wasm/WasmOpIter.cpp
@@ -144,16 +144,17 @@ wasm::Classify(OpBytes op)
       case Op::F32Gt:
       case Op::F32Ge:
       case Op::F64Eq:
       case Op::F64Ne:
       case Op::F64Lt:
       case Op::F64Le:
       case Op::F64Gt:
       case Op::F64Ge:
+      case Op::RefEq:
         return OpKind::Comparison;
       case Op::I32Eqz:
       case Op::I32WrapI64:
       case Op::I32TruncSF32:
       case Op::I32TruncUF32:
       case Op::I32ReinterpretF32:
       case Op::I32TruncSF64:
       case Op::I32TruncUF64:
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -2049,16 +2049,19 @@ WasmTokenStream::next()
       case 'r':
         if (consume(u"result")) {
             return WasmToken(WasmToken::Result, begin, cur_);
         }
         if (consume(u"return")) {
             return WasmToken(WasmToken::Return, begin, cur_);
         }
         if (consume(u"ref")) {
+            if (consume(u".eq")) {
+                return WasmToken(WasmToken::ComparisonOpcode, Op::RefEq, begin, cur_);
+            }
             if (consume(u".null")) {
                 return WasmToken(WasmToken::RefNull, begin, cur_);
             }
             if (consume(u".is_null")) {
                 return WasmToken(WasmToken::UnaryOpcode, Op::RefIsNull, begin, cur_);
             }
             return WasmToken(WasmToken::Ref, begin, cur_);
         }
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -932,16 +932,23 @@ DecodeFunctionBodyExprs(const ModuleEnvi
               }
 #endif
               default:
                 return iter.unrecognizedOpcode(&op);
             }
             break;
           }
 #ifdef ENABLE_WASM_GC
+          case uint16_t(Op::RefEq): {
+            if (env.gcTypesEnabled() == HasGcTypes::False) {
+                return iter.unrecognizedOpcode(&op);
+            }
+            CHECK(iter.readComparison(ValType::AnyRef, &nothing, &nothing));
+            break;
+          }
           case uint16_t(Op::RefNull): {
             if (env.gcTypesEnabled() == HasGcTypes::False) {
                 return iter.unrecognizedOpcode(&op);
             }
             ValType unusedType;
             CHECK(iter.readRefNull(&unusedType));
             break;
           }
--- a/layout/svg/SVGContextPaint.cpp
+++ b/layout/svg/SVGContextPaint.cpp
@@ -85,33 +85,30 @@ SVGContextPaint::IsAllowedForImageFromUR
 
 /**
  * Stores in |aTargetPaint| information on how to reconstruct the current
  * fill or stroke pattern. Will also set the paint opacity to transparent if
  * the paint is set to "none".
  * @param aOuterContextPaint pattern information from the outer text context
  * @param aTargetPaint where to store the current pattern information
  * @param aFillOrStroke member pointer to the paint we are setting up
- * @param aProperty the frame property descriptor of the fill or stroke paint
- *   server frame
  */
 static void
 SetupInheritablePaint(const DrawTarget* aDrawTarget,
                       const gfxMatrix& aContextMatrix,
                       nsIFrame* aFrame,
                       float& aOpacity,
                       SVGContextPaint* aOuterContextPaint,
                       SVGContextPaintImpl::Paint& aTargetPaint,
                       nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
-                      SVGObserverUtils::PaintingPropertyDescriptor aProperty,
                       imgDrawingParams& aImgParams)
 {
   const nsStyleSVG *style = aFrame->StyleSVG();
   nsSVGPaintServerFrame *ps =
-    SVGObserverUtils::GetPaintServer(aFrame, aFillOrStroke, aProperty);
+    SVGObserverUtils::GetPaintServer(aFrame, aFillOrStroke);
 
   if (ps) {
     RefPtr<gfxPattern> pattern =
       ps->GetPaintServerPattern(aFrame, aDrawTarget, aContextMatrix,
                                 aFillOrStroke, aOpacity, aImgParams);
 
     if (pattern) {
       aTargetPaint.SetPaintServer(aFrame, aContextMatrix, ps);
@@ -162,36 +159,34 @@ SVGContextPaintImpl::Init(const DrawTarg
     SetFillOpacity(0.0f);
   } else {
     float opacity = nsSVGUtils::GetOpacity(style->FillOpacitySource(),
                                            style->mFillOpacity,
                                            aOuterContextPaint);
 
     SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame, opacity,
                           aOuterContextPaint, mFillPaint, &nsStyleSVG::mFill,
-                          SVGObserverUtils::FillProperty(), aImgParams);
+                          aImgParams);
 
     SetFillOpacity(opacity);
 
     toDraw |= DrawMode::GLYPH_FILL;
   }
 
   // stroke:
   if (style->mStroke.Type() == eStyleSVGPaintType_None) {
     SetStrokeOpacity(0.0f);
   } else {
     float opacity = nsSVGUtils::GetOpacity(style->StrokeOpacitySource(),
                                            style->mStrokeOpacity,
                                            aOuterContextPaint);
 
     SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame, opacity,
                           aOuterContextPaint, mStrokePaint,
-                          &nsStyleSVG::mStroke,
-                          SVGObserverUtils::StrokeProperty(),
-                          aImgParams);
+                          &nsStyleSVG::mStroke, aImgParams);
 
     SetStrokeOpacity(opacity);
 
     toDraw |= DrawMode::GLYPH_STROKE;
   }
 
   return toDraw;
 }
--- a/layout/svg/SVGGeometryFrame.cpp
+++ b/layout/svg/SVGGeometryFrame.cpp
@@ -636,44 +636,33 @@ SVGGeometryFrame::GetBBoxContribution(co
       MOZ_ASSERT(ToRect(strokeBBoxExtents).IsFinite(), "bbox is about to go bad");
       bbox.UnionEdges(strokeBBoxExtents);
 #endif
     }
   }
 
   // Account for markers:
   if ((aFlags & nsSVGUtils::eBBoxIncludeMarkers) != 0 &&
-      static_cast<SVGGeometryElement*>(GetContent())->IsMarkable()) {
-
-    float strokeWidth = nsSVGUtils::GetStrokeWidth(this);
-    MarkerProperties properties = GetMarkerProperties(this);
-
-    if (properties.MarkersExist()) {
+      element->IsMarkable()) {
+    nsSVGMarkerFrame* markerFrames[nsSVGMark::eTypeCount];
+    if (SVGObserverUtils::GetMarkerFrames(this, &markerFrames)) {
       nsTArray<nsSVGMark> marks;
-      static_cast<SVGGeometryElement*>(GetContent())->GetMarkPoints(&marks);
-      uint32_t num = marks.Length();
-
-      // These are in the same order as the nsSVGMark::Type constants.
-      nsSVGMarkerFrame* markerFrames[] = {
-        properties.GetMarkerStartFrame(),
-        properties.GetMarkerMidFrame(),
-        properties.GetMarkerEndFrame(),
-      };
-      static_assert(MOZ_ARRAY_LENGTH(markerFrames) == nsSVGMark::eTypeCount,
-                    "Number of Marker frames should be equal to eTypeCount");
-
-      for (uint32_t i = 0; i < num; i++) {
-        const nsSVGMark& mark = marks[i];
-        nsSVGMarkerFrame* frame = markerFrames[mark.type];
-        if (frame) {
-          SVGBBox mbbox =
-            frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this,
-                                           mark, strokeWidth);
-          MOZ_ASSERT(mbbox.IsFinite(), "bbox is about to go bad");
-          bbox.UnionEdges(mbbox);
+      element->GetMarkPoints(&marks);
+      if (uint32_t num = marks.Length()) {
+        float strokeWidth = nsSVGUtils::GetStrokeWidth(this);
+        for (uint32_t i = 0; i < num; i++) {
+          const nsSVGMark& mark = marks[i];
+          nsSVGMarkerFrame* frame = markerFrames[mark.type];
+          if (frame) {
+            SVGBBox mbbox =
+              frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this,
+                                             mark, strokeWidth);
+            MOZ_ASSERT(mbbox.IsFinite(), "bbox is about to go bad");
+            bbox.UnionEdges(mbbox);
+          }
         }
       }
     }
   }
 
   return bbox;
 }
 
@@ -686,67 +675,16 @@ SVGGeometryFrame::GetCanvasTM()
   NS_ASSERTION(GetParent(), "null parent");
 
   nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
   SVGGraphicsElement *content = static_cast<SVGGraphicsElement*>(GetContent());
 
   return content->PrependLocalTransformsTo(parent->GetCanvasTM());
 }
 
-SVGGeometryFrame::MarkerProperties
-SVGGeometryFrame::GetMarkerProperties(SVGGeometryFrame *aFrame)
-{
-  NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
-
-  MarkerProperties result;
-  RefPtr<URLAndReferrerInfo> markerURL =
-    SVGObserverUtils::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
-  result.mMarkerStart =
-    SVGObserverUtils::GetMarkerProperty(markerURL, aFrame,
-                                        SVGObserverUtils::MarkerBeginProperty());
-
-  markerURL = SVGObserverUtils::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
-  result.mMarkerMid =
-    SVGObserverUtils::GetMarkerProperty(markerURL, aFrame,
-                                        SVGObserverUtils::MarkerMiddleProperty());
-
-  markerURL = SVGObserverUtils::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
-  result.mMarkerEnd =
-    SVGObserverUtils::GetMarkerProperty(markerURL, aFrame,
-                                        SVGObserverUtils::MarkerEndProperty());
-  return result;
-}
-
-nsSVGMarkerFrame *
-SVGGeometryFrame::MarkerProperties::GetMarkerStartFrame()
-{
-  if (!mMarkerStart)
-    return nullptr;
-  return static_cast<nsSVGMarkerFrame*>(
-    mMarkerStart->GetReferencedFrame(LayoutFrameType::SVGMarker, nullptr));
-}
-
-nsSVGMarkerFrame *
-SVGGeometryFrame::MarkerProperties::GetMarkerMidFrame()
-{
-  if (!mMarkerMid)
-    return nullptr;
-  return static_cast<nsSVGMarkerFrame*>(
-    mMarkerMid->GetReferencedFrame(LayoutFrameType::SVGMarker, nullptr));
-}
-
-nsSVGMarkerFrame *
-SVGGeometryFrame::MarkerProperties::GetMarkerEndFrame()
-{
-  if (!mMarkerEnd)
-    return nullptr;
-  return static_cast<nsSVGMarkerFrame*>(
-    mMarkerEnd->GetReferencedFrame(LayoutFrameType::SVGMarker, nullptr));
-}
-
 void
 SVGGeometryFrame::Render(gfxContext* aContext,
                          uint32_t aRenderComponents,
                          const gfxMatrix& aNewTransform,
                          imgDrawingParams& aImgParams)
 {
   MOZ_ASSERT(!aNewTransform.IsSingular());
 
@@ -861,38 +799,27 @@ SVGGeometryFrame::Render(gfxContext* aCo
   }
 }
 
 void
 SVGGeometryFrame::PaintMarkers(gfxContext& aContext,
                                const gfxMatrix& aTransform,
                                imgDrawingParams& aImgParams)
 {
-  SVGContextPaint* contextPaint = SVGContextPaint::GetContextPaint(GetContent());
-  if (static_cast<SVGGeometryElement*>(GetContent())->IsMarkable()) {
-    MarkerProperties properties = GetMarkerProperties(this);
-
-    if (properties.MarkersExist()) {
-      float strokeWidth = nsSVGUtils::GetStrokeWidth(this, contextPaint);
-
-      nsTArray<nsSVGMark> marks;
-      static_cast<SVGGeometryElement*>
-                 (GetContent())->GetMarkPoints(&marks);
+  auto element = static_cast<SVGGeometryElement*>(GetContent());
 
-      uint32_t num = marks.Length();
-      if (num) {
-        // These are in the same order as the nsSVGMark::Type constants.
-        nsSVGMarkerFrame* markerFrames[] = {
-          properties.GetMarkerStartFrame(),
-          properties.GetMarkerMidFrame(),
-          properties.GetMarkerEndFrame(),
-        };
-        static_assert(MOZ_ARRAY_LENGTH(markerFrames) == nsSVGMark::eTypeCount,
-                      "Number of Marker frames should be equal to eTypeCount");
-
+  if (element->IsMarkable()) {
+    nsSVGMarkerFrame* markerFrames[nsSVGMark::eTypeCount];
+    if (SVGObserverUtils::GetMarkerFrames(this, &markerFrames)) {
+      nsTArray<nsSVGMark> marks;
+      element->GetMarkPoints(&marks);
+      if (uint32_t num = marks.Length()) {
+        SVGContextPaint* contextPaint =
+          SVGContextPaint::GetContextPaint(GetContent());
+        float strokeWidth = nsSVGUtils::GetStrokeWidth(this, contextPaint);
         for (uint32_t i = 0; i < num; i++) {
           const nsSVGMark& mark = marks[i];
           nsSVGMarkerFrame* frame = markerFrames[mark.type];
           if (frame) {
             frame->PaintMark(aContext, aTransform, this, mark, strokeWidth,
                              aImgParams);
           }
         }
--- a/layout/svg/SVGGeometryFrame.h
+++ b/layout/svg/SVGGeometryFrame.h
@@ -124,31 +124,12 @@ private:
               const gfxMatrix& aTransform, imgDrawingParams& aImgParams);
 
   /**
    * @param aMatrix The transform that must be multiplied onto aContext to
    *   establish this frame's SVG user space.
    */
   void PaintMarkers(gfxContext& aContext, const gfxMatrix& aMatrix,
                     imgDrawingParams& aImgParams);
-
-  struct MarkerProperties {
-    SVGMarkerObserver* mMarkerStart;
-    SVGMarkerObserver* mMarkerMid;
-    SVGMarkerObserver* mMarkerEnd;
-
-    bool MarkersExist() const {
-      return mMarkerStart || mMarkerMid || mMarkerEnd;
-    }
-
-    nsSVGMarkerFrame *GetMarkerStartFrame();
-    nsSVGMarkerFrame *GetMarkerMidFrame();
-    nsSVGMarkerFrame *GetMarkerEndFrame();
-  };
-
-  /**
-   * @param aFrame should be the first continuation
-   */
-  static MarkerProperties GetMarkerProperties(SVGGeometryFrame *aFrame);
 };
 } // namespace mozilla
 
 #endif // __SVGGEOMETRYFRAME_H__
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -13,16 +13,17 @@
 #include "nsISupportsImpl.h"
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGPaintServerFrame.h"
 #include "nsSVGFilterFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "nsIReflowCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "SVGGeometryElement.h"
+#include "SVGTextPathElement.h"
 #include "SVGUseElement.h"
 #include "ImageLoader.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
@@ -218,28 +219,51 @@ nsSVGFrameReferenceFromProperty::Get()
 {
   if (mFramePresShell && mFramePresShell->IsDestroying()) {
     // mFrame is no longer valid.
     Detach();
   }
   return mFrame;
 }
 
+
+NS_IMPL_ISUPPORTS(SVGTemplateElementObserver, nsIMutationObserver)
+
+void
+SVGTemplateElementObserver::OnRenderingChange()
+{
+  SVGIDRenderingObserver::OnRenderingChange();
+
+  if (nsIFrame* frame = mFrameReference.Get()) {
+    // We know that we don't need to walk the parent chain notifying rendering
+    // observers since changes to a gradient etc. do not affect ancestor
+    // elements.  So we only invalidate *direct* rendering observers here.
+    // Since we don't need to walk the parent chain, we don't need to worry
+    // about coalescing multiple invalidations by using a change hint as we do
+    // in nsSVGRenderingObserverProperty::OnRenderingChange.
+    SVGObserverUtils::InvalidateDirectRenderingObservers(frame);
+  }
+}
+
+
 NS_IMPL_ISUPPORTS(nsSVGRenderingObserverProperty, nsIMutationObserver)
 
 void
 nsSVGRenderingObserverProperty::OnRenderingChange()
 {
   SVGIDRenderingObserver::OnRenderingChange();
 
   nsIFrame* frame = mFrameReference.Get();
 
   if (frame && frame->HasAllStateBits(NS_FRAME_SVG_LAYOUT)) {
-    // Changes should propagate out to things that might be observing
-    // the referencing frame or its ancestors.
+    // We need to notify anything that is observing the referencing frame or
+    // any of its ancestors that the referencing frame has been invalidated.
+    // Since walking the parent chain checking for observers is expensive we
+    // do that using a change hint (multiple change hints of the same type are
+    // coalesced).
     nsLayoutUtils::PostRestyleEvent(
       frame->GetContent()->AsElement(), nsRestyleHint(0),
       nsChangeHint_InvalidateRenderingObservers);
   }
 }
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserver)
@@ -566,29 +590,97 @@ GetEffectProperty(URLAndReferrerInfo* aU
   if (prop)
     return prop;
   prop = new T(aURI, aFrame, false);
   NS_ADDREF(prop);
   aFrame->SetProperty(aProperty, prop);
   return prop;
 }
 
-SVGMarkerObserver*
-SVGObserverUtils::GetMarkerProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
-  const mozilla::FramePropertyDescriptor<SVGMarkerObserver>* aProperty)
+bool
+SVGObserverUtils::GetMarkerFrames(nsIFrame* aMarkedFrame,
+                                  nsSVGMarkerFrame*(*aFrames)[3])
 {
-  MOZ_ASSERT(aFrame->IsSVGGeometryFrame() &&
-             static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable(),
+  MOZ_ASSERT(!aMarkedFrame->GetPrevContinuation() &&
+             aMarkedFrame->IsSVGGeometryFrame() &&
+             static_cast<SVGGeometryElement*>(aMarkedFrame->GetContent())->IsMarkable(),
              "Bad frame");
-  return GetEffectProperty(aURI, aFrame, aProperty);
+
+  bool foundMarker = false;
+  RefPtr<URLAndReferrerInfo> markerURL;
+  SVGMarkerObserver* observer;
+  nsIFrame* marker;
+
+#define GET_MARKER(type)                                                      \
+  markerURL = GetMarkerURI(aMarkedFrame, &nsStyleSVG::mMarker##type);         \
+  observer = GetEffectProperty(markerURL, aMarkedFrame,                       \
+                               SVGObserverUtils::Marker##type##Property());   \
+  marker = observer ?                                                         \
+           observer->GetReferencedFrame(LayoutFrameType::SVGMarker, nullptr) :\
+           nullptr;                                                           \
+  foundMarker = foundMarker || bool(marker);                                  \
+  (*aFrames)[nsSVGMark::e##type] = static_cast<nsSVGMarkerFrame*>(marker);
+
+  GET_MARKER(Start)
+  GET_MARKER(Mid)
+  GET_MARKER(End)
+
+#undef GET_MARKER
+
+  return foundMarker;
 }
 
-SVGTextPathObserver*
-SVGObserverUtils::GetTextPathProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
-  const mozilla::FramePropertyDescriptor<SVGTextPathObserver>* aProperty)
+SVGGeometryElement*
+SVGObserverUtils::GetTextPathsReferencedPath(nsIFrame* aTextPathFrame)
+{
+  SVGTextPathObserver* property =
+    aTextPathFrame->GetProperty(SVGObserverUtils::HrefAsTextPathProperty());
+
+  if (!property) {
+    nsIContent* content = aTextPathFrame->GetContent();
+    nsAutoString href;
+    static_cast<SVGTextPathElement*>(content)->HrefAsString(href);
+    if (href.IsEmpty()) {
+      return nullptr; // no URL
+    }
+
+    nsCOMPtr<nsIURI> targetURI;
+    nsCOMPtr<nsIURI> base = content->GetBaseURI();
+    nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
+                                              content->GetUncomposedDoc(), base);
+
+    // There's no clear refererer policy spec about non-CSS SVG resource references
+    // Bug 1415044 to investigate which referrer we should use
+    RefPtr<URLAndReferrerInfo> target =
+      new URLAndReferrerInfo(targetURI,
+                             content->OwnerDoc()->GetDocumentURI(),
+                             content->OwnerDoc()->GetReferrerPolicy());
+
+    property = GetEffectProperty(target, aTextPathFrame,
+                                 HrefAsTextPathProperty());
+    if (!property) {
+      return nullptr;
+    }
+  }
+
+  Element* element = property->GetReferencedElement();
+  return (element && element->IsNodeOfType(nsINode::eSHAPE)) ?
+    static_cast<SVGGeometryElement*>(element) : nullptr;
+}
+
+void
+SVGObserverUtils::RemoveTextPathObserver(nsIFrame* aTextPathFrame)
+{
+  aTextPathFrame->DeleteProperty(HrefAsTextPathProperty());
+}
+
+SVGTemplateElementObserver*
+SVGObserverUtils::GetTemplateElementObserver(URLAndReferrerInfo* aURI,
+  nsIFrame* aFrame,
+  const mozilla::FramePropertyDescriptor<SVGTemplateElementObserver>* aProperty)
 {
   return GetEffectProperty(aURI, aFrame, aProperty);
 }
 
 nsSVGPaintingProperty*
 SVGObserverUtils::GetPaintingProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
   const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty)
 {
@@ -641,18 +733,17 @@ SVGObserverUtils::GetEffectProperties(ns
   result.mMaskObservers = style->HasMask()
                           ? GetOrCreateMaskProperty(aFrame) : nullptr;
 
   return result;
 }
 
 nsSVGPaintServerFrame *
 SVGObserverUtils::GetPaintServer(nsIFrame* aTargetFrame,
-                                 nsStyleSVGPaint nsStyleSVG::* aPaint,
-                                 PaintingPropertyDescriptor aType)
+                                 nsStyleSVGPaint nsStyleSVG::* aPaint)
 {
   // If we're looking at a frame within SVG text, then we need to look up
   // to find the right frame to get the painting property off.  We should at
   // least look up past a text frame, and if the text frame's parent is the
   // anonymous block frame, then we look up to its parent (the SVGTextFrame).
   nsIFrame* frame = aTargetFrame;
   if (frame->GetContent()->IsText()) {
     frame = frame->GetParent();
@@ -663,18 +754,22 @@ SVGObserverUtils::GetPaintServer(nsIFram
   }
 
   const nsStyleSVG* svgStyle = frame->StyleSVG();
   if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
     return nullptr;
 
   RefPtr<URLAndReferrerInfo> paintServerURL =
     SVGObserverUtils::GetPaintURI(frame, aPaint);
+  MOZ_ASSERT(aPaint == &nsStyleSVG::mFill || aPaint == &nsStyleSVG::mStroke);
+  PaintingPropertyDescriptor propDesc = (aPaint == &nsStyleSVG::mFill) ?
+                                        SVGObserverUtils::FillProperty() :
+                                        SVGObserverUtils::StrokeProperty();
   nsSVGPaintingProperty *property =
-    SVGObserverUtils::GetPaintingProperty(paintServerURL, frame, aType);
+    SVGObserverUtils::GetPaintingProperty(paintServerURL, frame, propDesc);
   if (!property)
     return nullptr;
   nsIFrame* result = property->GetReferencedFrame();
   if (!result)
     return nullptr;
 
   LayoutFrameType type = result->Type();
   if (type != LayoutFrameType::SVGLinearGradient &&
@@ -770,38 +865,38 @@ void
 SVGObserverUtils::UpdateEffects(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame->GetContent()->IsElement(),
                "aFrame's content should be an element");
 
   aFrame->DeleteProperty(FilterProperty());
   aFrame->DeleteProperty(MaskProperty());
   aFrame->DeleteProperty(ClipPathProperty());
-  aFrame->DeleteProperty(MarkerBeginProperty());
-  aFrame->DeleteProperty(MarkerMiddleProperty());
+  aFrame->DeleteProperty(MarkerStartProperty());
+  aFrame->DeleteProperty(MarkerMidProperty());
   aFrame->DeleteProperty(MarkerEndProperty());
   aFrame->DeleteProperty(FillProperty());
   aFrame->DeleteProperty(StrokeProperty());
   aFrame->DeleteProperty(BackgroundImageProperty());
 
   // Ensure that the filter is repainted correctly
   // We can't do that in OnRenderingChange as the referenced frame may
   // not be valid
   GetOrCreateFilterObserverListForCSS(aFrame);
 
   if (aFrame->IsSVGGeometryFrame() &&
       static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
     // Set marker properties here to avoid reference loops
     RefPtr<URLAndReferrerInfo> markerURL =
       GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
-    GetMarkerProperty(markerURL, aFrame, MarkerBeginProperty());
+    GetEffectProperty(markerURL, aFrame, MarkerStartProperty());
     markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
-    GetMarkerProperty(markerURL, aFrame, MarkerMiddleProperty());
+    GetEffectProperty(markerURL, aFrame, MarkerMidProperty());
     markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
-    GetMarkerProperty(markerURL, aFrame, MarkerEndProperty());
+    GetEffectProperty(markerURL, aFrame, MarkerEndProperty());
   }
 }
 
 SVGFilterObserverListForCSSProp*
 SVGObserverUtils::GetFilterObserverList(nsIFrame* aFrame)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
--- a/layout/svg/SVGObserverUtils.h
+++ b/layout/svg/SVGObserverUtils.h
@@ -23,21 +23,25 @@
 #include "nsTHashtable.h"
 #include "nsURIHashKey.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsAtom;
 class nsIPresShell;
 class nsIURI;
 class nsSVGClipPathFrame;
+class nsSVGMarkerFrame;
 class nsSVGPaintServerFrame;
 class nsSVGFilterFrame;
 class nsSVGMaskFrame;
 namespace mozilla {
 class SVGFilterObserverList;
+namespace dom {
+class SVGGeometryElement;
+}
 }
 
 namespace mozilla {
 
 /*
  * This class contains URL and referrer information (referrer and referrer
  * policy).
  * We use it to pass to svg system instead of nsIURI. The object brings referrer
@@ -230,16 +234,49 @@ private:
   // the presshell for the frames we care about and, before we use the frame,
   // we test the presshell to see if it's destroying itself. If it is,
   // then the frame pointer is not valid and we know the frame has gone away.
   // mFramePresShell may be null, but when mFrame is non-null, mFramePresShell
   // is guaranteed to be non-null, too.
   nsIPresShell *mFramePresShell;
 };
 
+/**
+ * Used for gradient-to-gradient, pattern-to-pattern and filter-to-filter
+ * references to "template" elements (specified via the 'href' attributes).
+ *
+ * This is a special class for the case where we know we only want to call
+ * InvalidateDirectRenderingObservers (as opposed to
+ * InvalidateRenderingObservers).
+ *
+ * TODO(jwatt): If we added a new NS_FRAME_RENDERING_OBSERVER_CONTAINER state
+ * bit to clipPath, filter, gradients, marker, mask, pattern and symbol, and
+ * could have InvalidateRenderingObservers stop on reaching such an element,
+ * then we would no longer need this class (not to mention improving perf by
+ * significantly cutting down on ancestor traversal).
+ */
+class SVGTemplateElementObserver : public SVGIDRenderingObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  SVGTemplateElementObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
+                             bool aReferenceImage)
+    : SVGIDRenderingObserver(aURI, aFrame->GetContent(), aReferenceImage)
+    , mFrameReference(aFrame)
+  {}
+
+protected:
+  virtual ~SVGTemplateElementObserver() = default; // non-public
+
+  virtual void OnRenderingChange() override;
+
+  nsSVGFrameReferenceFromProperty mFrameReference;
+};
+
 class nsSVGRenderingObserverProperty : public SVGIDRenderingObserver
 {
 public:
   NS_DECL_ISUPPORTS
 
   nsSVGRenderingObserverProperty(URLAndReferrerInfo* aURI, nsIFrame *aFrame,
                                  bool aReferenceImage)
     : SVGIDRenderingObserver(aURI, aFrame->GetContent(), aReferenceImage)
@@ -494,16 +531,17 @@ public:
 private:
   nsTHashtable<nsPtrHashKey<SVGRenderingObserver>> mObservers;
 };
 
 class SVGObserverUtils
 {
 public:
   typedef mozilla::dom::Element Element;
+  typedef dom::SVGGeometryElement SVGGeometryElement;
   typedef nsInterfaceHashtable<nsRefPtrHashKey<URLAndReferrerInfo>,
     nsIMutationObserver> URIObserverHashtable;
 
   using PaintingPropertyDescriptor =
     const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>*;
   using URIObserverHashtablePropertyDescriptor =
     const mozilla::FramePropertyDescriptor<URIObserverHashtable>*;
 
@@ -512,40 +550,33 @@ public:
     // SVGFilterObserverListForCSSProp is cycle-collected, so dropping the last
     // reference doesn't necessarily destroy it. We need to tell it that the
     // frame has now become invalid.
     aProp->DetachFromFrame();
 
     aProp->Release();
   }
 
+  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefToTemplateProperty,
+                                       SVGTemplateElementObserver)
   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(FilterProperty,
                                       SVGFilterObserverListForCSSProp,
                                       DestroyFilterProperty)
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MaskProperty, SVGMaskObserverList)
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(ClipPathProperty, nsSVGPaintingProperty)
-  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerBeginProperty, SVGMarkerObserver)
-  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerMiddleProperty, SVGMarkerObserver)
+  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerStartProperty, SVGMarkerObserver)
+  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerMidProperty, SVGMarkerObserver)
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerEndProperty, SVGMarkerObserver)
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(FillProperty, nsSVGPaintingProperty)
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(StrokeProperty, nsSVGPaintingProperty)
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefAsTextPathProperty,
                                        SVGTextPathObserver)
-  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefAsPaintingProperty,
-                                       nsSVGPaintingProperty)
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(BackgroundImageProperty,
                                       URIObserverHashtable)
 
-  /**
-   * Get the paint server for a aTargetFrame.
-   */
-  static nsSVGPaintServerFrame *GetPaintServer(nsIFrame* aTargetFrame,
-                                               nsStyleSVGPaint nsStyleSVG::* aPaint,
-                                               PaintingPropertyDescriptor aProperty);
-
   struct EffectProperties {
     SVGFilterObserverListForCSSProp* mFilterObservers;
     SVGMaskObserverList* mMaskObservers;
     nsSVGPaintingProperty* mClipPath;
 
     /**
      * @return the clip-path frame, or null if there is no clip-path frame
      */
@@ -680,27 +711,47 @@ public:
   /**
    * This can be called on any element or frame. Only direct observers of this
    * (frame's) element, if any, are invalidated.
    */
   static void InvalidateDirectRenderingObservers(Element* aElement, uint32_t aFlags = 0);
   static void InvalidateDirectRenderingObservers(nsIFrame* aFrame, uint32_t aFlags = 0);
 
   /**
-   * Get an SVGMarkerObserver for the frame, creating a fresh one if necessary
+   * Get the paint server for a aTargetFrame.
    */
-  static SVGMarkerObserver *
-  GetMarkerProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
-    const mozilla::FramePropertyDescriptor<SVGMarkerObserver>* aProperty);
+  static nsSVGPaintServerFrame *GetPaintServer(nsIFrame* aTargetFrame,
+                                               nsStyleSVGPaint nsStyleSVG::* aPaint);
+
+  /**
+   * Get the start/mid/end-markers for the given frame, and add the frame as
+   * an observer to those markers.  Returns true if at least one marker type is
+   * found, false otherwise.
+   */
+  static bool
+  GetMarkerFrames(nsIFrame* aMarkedFrame, nsSVGMarkerFrame*(*aFrames)[3]);
+
   /**
-   * Get an SVGTextPathObserver for the frame, creating a fresh one if necessary
+   * Get the SVGGeometryElement that is referenced by aTextPathFrame, and make
+   * aTextPathFrame start observing rendering changes to that element.
    */
-  static SVGTextPathObserver *
-  GetTextPathProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
-    const mozilla::FramePropertyDescriptor<SVGTextPathObserver>* aProperty);
+  static SVGGeometryElement*
+  GetTextPathsReferencedPath(nsIFrame* aTextPathFrame);
+
+  /**
+   * Make aTextPathFrame stop observing rendering changes to the
+   * SVGGeometryElement that it references, if any.
+   */
+  static void
+  RemoveTextPathObserver(nsIFrame* aTextPathFrame);
+
+  static SVGTemplateElementObserver*
+  GetTemplateElementObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
+      const mozilla::FramePropertyDescriptor<SVGTemplateElementObserver>* aProperty);
+
   /**
    * Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
    */
   static nsSVGPaintingProperty*
   GetPaintingProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
       const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty);
   /**
    * Get an nsSVGPaintingProperty for the frame for that URI, creating a fresh
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -3392,18 +3392,17 @@ SVGTextFrame::HandleAttributeChangeInDes
          aAttribute == nsGkAtoms::side_)) {
       NotifyGlyphMetricsChange();
     } else if ((aNameSpaceID == kNameSpaceID_XLink ||
                 aNameSpaceID == kNameSpaceID_None) &&
                aAttribute == nsGkAtoms::href) {
       // Blow away our reference, if any
       nsIFrame* childElementFrame = aElement->GetPrimaryFrame();
       if (childElementFrame) {
-        childElementFrame->DeleteProperty(
-          SVGObserverUtils::HrefAsTextPathProperty());
+        SVGObserverUtils::RemoveTextPathObserver(childElementFrame);
         NotifyGlyphMetricsChange();
       }
     }
   } else {
     if (aNameSpaceID == kNameSpaceID_None &&
         IsGlyphPositioningAttribute(aAttribute)) {
       NotifyGlyphMetricsChange();
     }
@@ -4978,75 +4977,29 @@ SVGTextFrame::AdjustPositionsForClusters
         mPositions[charIndex + 1].mStartOfChunk = true;
       }
     }
 
     it.Next();
   }
 }
 
-SVGGeometryElement*
-SVGTextFrame::GetTextPathGeometryElement(nsIFrame* aTextPathFrame)
-{
-  SVGTextPathObserver *property =
-    aTextPathFrame->GetProperty(SVGObserverUtils::HrefAsTextPathProperty());
-
-  if (!property) {
-    nsIContent* content = aTextPathFrame->GetContent();
-    SVGTextPathElement* tp = static_cast<SVGTextPathElement*>(content);
-    nsAutoString href;
-    if (tp->mStringAttributes[SVGTextPathElement::HREF].IsExplicitlySet()) {
-      tp->mStringAttributes[SVGTextPathElement::HREF]
-        .GetAnimValue(href, tp);
-    } else {
-      tp->mStringAttributes[SVGTextPathElement::XLINK_HREF]
-        .GetAnimValue(href, tp);
-    }
-
-    if (href.IsEmpty()) {
-      return nullptr; // no URL
-    }
-
-    nsCOMPtr<nsIURI> targetURI;
-    nsCOMPtr<nsIURI> base = content->GetBaseURI();
-    nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
-                                              content->GetUncomposedDoc(), base);
-
-    // There's no clear refererer policy spec about non-CSS SVG resource references
-    // Bug 1415044 to investigate which referrer we should use
-    RefPtr<URLAndReferrerInfo> target =
-      new URLAndReferrerInfo(targetURI,
-                             mContent->OwnerDoc()->GetDocumentURI(),
-                             mContent->OwnerDoc()->GetReferrerPolicy());
-
-    property = SVGObserverUtils::GetTextPathProperty(
-      target,
-      aTextPathFrame,
-      SVGObserverUtils::HrefAsTextPathProperty());
-    if (!property)
-      return nullptr;
-  }
-
-  Element* element = property->GetReferencedElement();
-  return (element && element->IsNodeOfType(nsINode::eSHAPE)) ?
-    static_cast<SVGGeometryElement*>(element) : nullptr;
-}
-
 already_AddRefed<Path>
 SVGTextFrame::GetTextPath(nsIFrame* aTextPathFrame)
 {
   nsIContent* content = aTextPathFrame->GetContent();
   SVGTextPathElement* tp = static_cast<SVGTextPathElement*>(content);
   if (tp->mPath.IsRendered()) {
     // This is just an attribute so there's no transform that can apply
     // so we can just return the path directly.
     return tp->mPath.GetAnimValue().BuildPathForMeasuring();
   }
 
-  SVGGeometryElement* geomElement = GetTextPathGeometryElement(aTextPathFrame);
+  SVGGeometryElement* geomElement =
+    SVGObserverUtils::GetTextPathsReferencedPath(aTextPathFrame);
   if (!geomElement) {
     return nullptr;
   }
 
   RefPtr<Path> path = geomElement->GetOrBuildPathForMeasuring();
   if (!path) {
     return nullptr;
   }
@@ -5068,17 +5021,18 @@ SVGTextFrame::GetOffsetScale(nsIFrame* a
   nsIContent* content = aTextPathFrame->GetContent();
   SVGTextPathElement* tp = static_cast<SVGTextPathElement*>(content);
   if (tp->mPath.IsRendered()) {
     // A path attribute has no pathLength or transform
     // so we return a unit scale.
     return 1.0;
   }
 
-  SVGGeometryElement* geomElement = GetTextPathGeometryElement(aTextPathFrame);
+  SVGGeometryElement* geomElement =
+    SVGObserverUtils::GetTextPathsReferencedPath(aTextPathFrame);
   if (!geomElement)
     return 1.0;
 
   return geomElement->GetPathLengthScale(SVGGeometryElement::eForTextPath);
 }
 
 gfxFloat
 SVGTextFrame::GetStartOffset(nsIFrame* aTextPathFrame)
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -533,18 +533,16 @@ private:
    * the text frames.
    *
    * @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text
    *   should be painted.
    */
   bool ShouldRenderAsPath(nsTextFrame* aFrame, bool& aShouldPaintSVGGlyphs);
 
   // Methods to get information for a <textPath> frame.
-  mozilla::dom::SVGGeometryElement*
-  GetTextPathGeometryElement(nsIFrame* aTextPathFrame);
   already_AddRefed<Path> GetTextPath(nsIFrame* aTextPathFrame);
   gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
   gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);
 
   /**
    * The MutationObserver we have registered for the <text> element subtree.
    */
   RefPtr<MutationObserver> mMutationObserver;
--- a/layout/svg/nsSVGFilterFrame.cpp
+++ b/layout/svg/nsSVGFilterFrame.cpp
@@ -112,20 +112,20 @@ nsSVGFilterFrame::GetFilterContent(nsICo
 }
 
 nsSVGFilterFrame *
 nsSVGFilterFrame::GetReferencedFilter()
 {
   if (mNoHRefURI)
     return nullptr;
 
-  nsSVGPaintingProperty *property =
-    GetProperty(SVGObserverUtils::HrefAsPaintingProperty());
+  SVGTemplateElementObserver* observer =
+    GetProperty(SVGObserverUtils::HrefToTemplateProperty());
 
-  if (!property) {
+  if (!observer) {
     // Fetch our Filter element's href or xlink:href attribute
     SVGFilterElement *filter = static_cast<SVGFilterElement *>(GetContent());
     nsAutoString href;
     if (filter->mStringAttributes[SVGFilterElement::HREF].IsExplicitlySet()) {
       filter->mStringAttributes[SVGFilterElement::HREF]
         .GetAnimValue(href, filter);
     } else {
       filter->mStringAttributes[SVGFilterElement::XLINK_HREF]
@@ -144,23 +144,24 @@ nsSVGFilterFrame::GetReferencedFilter()
                                               mContent->GetUncomposedDoc(), base);
 
     // There's no clear refererer policy spec about non-CSS SVG resource references
     // Bug 1415044 to investigate which referrer we should use
     RefPtr<URLAndReferrerInfo> target =
       new URLAndReferrerInfo(targetURI,
                              mContent->OwnerDoc()->GetDocumentURI(),
                              mContent->OwnerDoc()->GetReferrerPolicy());
-    property = SVGObserverUtils::GetPaintingProperty(target, this,
-      SVGObserverUtils::HrefAsPaintingProperty());
-    if (!property)
+    observer = SVGObserverUtils::GetTemplateElementObserver(target, this,
+                 SVGObserverUtils::HrefToTemplateProperty());
+    if (!observer) {
       return nullptr;
+    }
   }
 
-  nsIFrame *result = property->GetReferencedFrame();
+  nsIFrame* result = observer->GetReferencedFrame();
   if (!result)
     return nullptr;
 
   LayoutFrameType frameType = result->Type();
   if (frameType != LayoutFrameType::SVGFilter)
     return nullptr;
 
   return static_cast<nsSVGFilterFrame*>(result);
@@ -178,17 +179,17 @@ nsSVGFilterFrame::AttributeChanged(int32
        aAttribute == nsGkAtoms::height ||
        aAttribute == nsGkAtoms::filterUnits ||
        aAttribute == nsGkAtoms::primitiveUnits)) {
     SVGObserverUtils::InvalidateDirectRenderingObservers(this);
   } else if ((aNameSpaceID == kNameSpaceID_XLink ||
               aNameSpaceID == kNameSpaceID_None) &&
              aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
-    DeleteProperty(SVGObserverUtils::HrefAsPaintingProperty());
+    DeleteProperty(SVGObserverUtils::HrefToTemplateProperty());
     mNoHRefURI = false;
     // And update whoever references us
     SVGObserverUtils::InvalidateDirectRenderingObservers(this);
   }
   return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
                                                aAttribute, aModType);
 }
 
--- a/layout/svg/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -51,17 +51,17 @@ nsSVGGradientFrame::AttributeChanged(int
       (aAttribute == nsGkAtoms::gradientUnits ||
        aAttribute == nsGkAtoms::gradientTransform ||
        aAttribute == nsGkAtoms::spreadMethod)) {
     SVGObserverUtils::InvalidateDirectRenderingObservers(this);
   } else if ((aNameSpaceID == kNameSpaceID_XLink ||
               aNameSpaceID == kNameSpaceID_None) &&
              aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
-    DeleteProperty(SVGObserverUtils::HrefAsPaintingProperty());
+    DeleteProperty(SVGObserverUtils::HrefToTemplateProperty());
     mNoHRefURI = false;
     // And update whoever references us
     SVGObserverUtils::InvalidateDirectRenderingObservers(this);
   }
 
   return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
                                                  aAttribute, aModType);
 }
@@ -337,20 +337,20 @@ nsSVGGradientFrame::GetPaintServerPatter
 // Private (helper) methods
 
 nsSVGGradientFrame *
 nsSVGGradientFrame::GetReferencedGradient()
 {
   if (mNoHRefURI)
     return nullptr;
 
-  nsSVGPaintingProperty *property =
-    GetProperty(SVGObserverUtils::HrefAsPaintingProperty());
+  SVGTemplateElementObserver* observer =
+    GetProperty(SVGObserverUtils::HrefToTemplateProperty());
 
-  if (!property) {
+  if (!observer) {
     // Fetch our gradient element's href or xlink:href attribute
     dom::SVGGradientElement* grad =
       static_cast<dom::SVGGradientElement*>(GetContent());
     nsAutoString href;
     if (grad->mStringAttributes[dom::SVGGradientElement::HREF]
           .IsExplicitlySet()) {
       grad->mStringAttributes[dom::SVGGradientElement::HREF]
         .GetAnimValue(href, grad);
@@ -372,23 +372,24 @@ nsSVGGradientFrame::GetReferencedGradien
 
     // There's no clear refererer policy spec about non-CSS SVG resource references
     // Bug 1415044 to investigate which referrer we should use
     RefPtr<URLAndReferrerInfo> target =
       new URLAndReferrerInfo(targetURI,
                              mContent->OwnerDoc()->GetDocumentURI(),
                              mContent->OwnerDoc()->GetReferrerPolicy());
 
-    property = SVGObserverUtils::GetPaintingProperty(target, this,
-      SVGObserverUtils::HrefAsPaintingProperty());
-    if (!property)
+    observer = SVGObserverUtils::GetTemplateElementObserver(target, this,
+                 SVGObserverUtils::HrefToTemplateProperty());
+    if (!observer) {
       return nullptr;
+    }
   }
 
-  nsIFrame *result = property->GetReferencedFrame();
+  nsIFrame* result = observer->GetReferencedFrame();
   if (!result)
     return nullptr;
 
   LayoutFrameType frameType = result->Type();
   if (frameType != LayoutFrameType::SVGLinearGradient &&
       frameType != LayoutFrameType::SVGRadialGradient)
     return nullptr;
 
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -65,17 +65,17 @@ nsSVGPatternFrame::AttributeChanged(int3
        aAttribute == nsGkAtoms::viewBox)) {
     SVGObserverUtils::InvalidateDirectRenderingObservers(this);
   }
 
   if ((aNameSpaceID == kNameSpaceID_XLink ||
        aNameSpaceID == kNameSpaceID_None) &&
       aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
-    DeleteProperty(SVGObserverUtils::HrefAsPaintingProperty());
+    DeleteProperty(SVGObserverUtils::HrefToTemplateProperty());
     mNoHRefURI = false;
     // And update whoever references us
     SVGObserverUtils::InvalidateDirectRenderingObservers(this);
   }
 
   return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
                                                  aAttribute, aModType);
 }
@@ -573,20 +573,20 @@ nsSVGPatternFrame::GetLengthValue(uint32
 
 // Private (helper) methods
 nsSVGPatternFrame *
 nsSVGPatternFrame::GetReferencedPattern()
 {
   if (mNoHRefURI)
     return nullptr;
 
-  nsSVGPaintingProperty *property =
-    GetProperty(SVGObserverUtils::HrefAsPaintingProperty());
+  SVGTemplateElementObserver* observer =
+    GetProperty(SVGObserverUtils::HrefToTemplateProperty());
 
-  if (!property) {
+  if (!observer) {
     // Fetch our pattern element's href or xlink:href attribute
     SVGPatternElement *pattern = static_cast<SVGPatternElement *>(GetContent());
     nsAutoString href;
     if (pattern->mStringAttributes[SVGPatternElement::HREF].IsExplicitlySet()) {
       pattern->mStringAttributes[SVGPatternElement::HREF]
         .GetAnimValue(href, pattern);
     } else {
       pattern->mStringAttributes[SVGPatternElement::XLINK_HREF]
@@ -606,23 +606,24 @@ nsSVGPatternFrame::GetReferencedPattern(
 
     // There's no clear refererer policy spec about non-CSS SVG resource references
     // Bug 1415044 to investigate which referrer we should use
     RefPtr<URLAndReferrerInfo> target =
       new URLAndReferrerInfo(targetURI,
                              mContent->OwnerDoc()->GetDocumentURI(),
                              mContent->OwnerDoc()->GetReferrerPolicy());
 
-    property = SVGObserverUtils::GetPaintingProperty(target, this,
-      SVGObserverUtils::HrefAsPaintingProperty());
-    if (!property)
+    observer = SVGObserverUtils::GetTemplateElementObserver(target, this,
+                 SVGObserverUtils::HrefToTemplateProperty());
+    if (!observer) {
       return nullptr;
+    }
   }
 
-  nsIFrame *result = property->GetReferencedFrame();
+  nsIFrame* result = observer->GetReferencedFrame();
   if (!result)
     return nullptr;
 
   LayoutFrameType frameType = result->Type();
   if (frameType != LayoutFrameType::SVGPattern)
     return nullptr;
 
   return static_cast<nsSVGPatternFrame*>(result);
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1495,18 +1495,17 @@ nsSVGUtils::MakeFillPatternFor(nsIFrame*
     // Combine the group opacity into the fill opacity (we will have skipped
     // creating an offscreen surface to apply the group opacity).
     fillOpacity *= opacity;
   }
 
   const DrawTarget* dt = aContext->GetDrawTarget();
 
   nsSVGPaintServerFrame *ps =
-    SVGObserverUtils::GetPaintServer(aFrame, &nsStyleSVG::mFill,
-                                     SVGObserverUtils::FillProperty());
+    SVGObserverUtils::GetPaintServer(aFrame, &nsStyleSVG::mFill);
 
   if (ps) {
     RefPtr<gfxPattern> pattern =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrixDouble(),
                                 &nsStyleSVG::mFill, fillOpacity, aImgParams);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
@@ -1571,18 +1570,17 @@ nsSVGUtils::MakeStrokePatternFor(nsIFram
     // Combine the group opacity into the stroke opacity (we will have skipped
     // creating an offscreen surface to apply the group opacity).
     strokeOpacity *= opacity;
   }
 
   const DrawTarget* dt = aContext->GetDrawTarget();
 
   nsSVGPaintServerFrame *ps =
-    SVGObserverUtils::GetPaintServer(aFrame, &nsStyleSVG::mStroke,
-                                     SVGObserverUtils::StrokeProperty());
+    SVGObserverUtils::GetPaintServer(aFrame, &nsStyleSVG::mStroke);
 
   if (ps) {
     RefPtr<gfxPattern> pattern =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrixDouble(),
                                 &nsStyleSVG::mStroke, strokeOpacity, aImgParams);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
--- a/layout/tools/reftest/api.js
+++ b/layout/tools/reftest/api.js
@@ -61,16 +61,21 @@ this.reftest = class extends ExtensionAP
 
     // Starting tests is handled quite differently on android and desktop.
     // On Android, OnRefTestLoad() takes over the main browser window so
     // we just need to call it as soon as the browser window is available.
     // On desktop, a separate window (dummy) is created and explicitly given
     // focus (see bug 859339 for details), then tests are launched in a new
     // top-level window.
     let win = Services.wm.getMostRecentWindow("navigator:browser");
+    if (!win) {
+      // There is no navigator:browser in the geckoview TestRunnerActivity;
+      // try navigator.geckoview instead.
+      win = Services.wm.getMostRecentWindow("navigator:geckoview");
+    }
 
     if (Services.appinfo.OS == "Android") {
       ChromeUtils.import("resource://reftest/reftest.jsm");
       if (win) {
         startAndroid(win);
       } else {
         Services.wm.addListener(WindowListener);
       }
--- a/python/mach/mach/registrar.py
+++ b/python/mach/mach/registrar.py
@@ -87,17 +87,17 @@ class MachRegistrar(object):
             import pdb
             result = pdb.runcall(fn, **kwargs)
         else:
             result = fn(**kwargs)
 
         result = result or 0
         assert isinstance(result, (int, long))
 
-        if context:
+        if context and not debug_command:
             postrun = getattr(context, 'post_dispatch_handler', None)
             if postrun:
                 postrun(context, handler, args=kwargs)
 
         return result
 
     def dispatch(self, name, context=None, argv=None, subcommand=None, **kwargs):
         """Dispatch/run a command.
--- a/python/mozbuild/mozbuild/controller/building.py
+++ b/python/mozbuild/mozbuild/controller/building.py
@@ -36,32 +36,34 @@ from mozsystemmonitor.resourcemonitor im
 from mozterm.widgets import Footer
 
 import mozpack.path as mozpath
 
 from .clobber import (
     Clobberer,
 )
 from ..base import (
-    BuildEnvironmentNotFoundException,
     MozbuildObject,
 )
 from ..backend import (
     get_backend_class,
 )
 from ..testing import (
     install_test_files,
 )
 from ..compilation.warnings import (
     WarningsCollector,
     WarningsDatabase,
 )
 from ..shellutil import (
     quote as shell_quote,
 )
+from ..telemetry import (
+    gather_telemetry,
+)
 from ..util import (
     FileAvoidWrite,
     mkdir,
     resolve_target_to_make,
 )
 
 
 FINDER_SLOW_MESSAGE = '''
@@ -1280,62 +1282,37 @@ class BuildDriver(MozbuildObject):
         except ValueError:
             # Just stick with the default
             pass
 
         if monitor.elapsed > notify_minimum_time:
             # Display a notification when the build completes.
             self.notify('Build complete' if not status else 'Build failed')
 
+        gather_telemetry(command='build', success=(status == 0), monitor=monitor,
+                         mach_context=mach_context, substs=self.substs,
+                         paths=[self.topsrcdir, self.topobjdir])
+
         if status:
             return status
 
-        long_build = monitor.elapsed > 600
-
-        if long_build:
-            output.on_line('We know it took a while, but your build finally finished successfully!')
-        else:
-            output.on_line('Your build was successful!')
-
         if monitor.have_resource_usage:
             excessive, swap_in, swap_out = monitor.have_excessive_swapping()
             # if excessive:
             #    print(EXCESSIVE_SWAP_MESSAGE)
 
             print('To view resource usage of the build, run |mach '
-                'resource-usage|.')
+                  'resource-usage|.')
 
-            telemetry_handler = getattr(mach_context,
-                                        'telemetry_handler', None)
-            telemetry_data = monitor.get_resource_usage()
+        long_build = monitor.elapsed > 600
 
-            # Record build configuration data. For now, we cherry pick
-            # items we need rather than grabbing everything, in order
-            # to avoid accidentally disclosing PII.
-            telemetry_data['substs'] = {}
-            try:
-                for key in ['MOZ_ARTIFACT_BUILDS', 'MOZ_USING_CCACHE', 'MOZ_USING_SCCACHE']:
-                    value = self.substs.get(key, False)
-                    telemetry_data['substs'][key] = value
-            except BuildEnvironmentNotFoundException:
-                pass
-
-            # Grab ccache stats if available. We need to be careful not
-            # to capture information that can potentially identify the
-            # user (such as the cache location)
-            if ccache_diff:
-                telemetry_data['ccache'] = {}
-                for key in [key[0] for key in ccache_diff.STATS_KEYS]:
-                    try:
-                        telemetry_data['ccache'][key] = ccache_diff._values[key]
-                    except KeyError:
-                        pass
-
-            if telemetry_handler:
-                telemetry_handler(mach_context, telemetry_data)
+        if long_build:
+            output.on_line('We know it took a while, but your build finally finished successfully!')
+        else:
+            output.on_line('Your build was successful!')
 
         # Only for full builds because incremental builders likely don't
         # need to be burdened with this.
         if not what:
             try:
                 # Fennec doesn't have useful output from just building. We should
                 # arguably make the build action useful for Fennec. Another day...
                 if self.substs['MOZ_BUILD_APP'] != 'mobile/android':
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -2837,8 +2837,17 @@ class Analyze(MachCommandBase):
             # path to cost_dict.gz was specified
             if os.path.isfile(path):
                 r = Report(days, path)
                 r.generate_output(format, limit, self.topobjdir)
             else:
                 res = 'Please specify the location of cost_dict.gz with --path.'
                 print ('Could not find cost_dict.gz at %s' % path, res, sep='\n')
                 return 1
+
+
+@SettingsProvider
+class TelemetrySettings():
+    config_settings = [
+        ('build.telemetry', 'boolean', """
+Enable submission of build system telemetry.
+        """.strip(), False),
+    ]
--- a/python/mozbuild/mozbuild/telemetry.py
+++ b/python/mozbuild/mozbuild/telemetry.py
@@ -1,27 +1,41 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 '''
-This file contains a voluptuous schema definition for build system telemetry.
+This file contains a voluptuous schema definition for build system telemetry, and functions
+to fill an instance of that schema for a single mach invocation.
 '''
 
-from mozbuild.configure.constants import CompilerType
+from datetime import datetime
+import json
+import os
+import math
+import platform
+import pprint
+import sys
 from voluptuous import (
     Any,
     Optional,
+    MultipleInvalid,
     Required,
     Schema,
 )
 from voluptuous.validators import Datetime
 
+import mozpack.path as mozpath
+from .base import (
+    BuildEnvironmentNotFoundException,
+)
+from .configure.constants import CompilerType
+
 schema = Schema({
     Required('client_id', description='A UUID to uniquely identify a client'): basestring,
     Required('time', description='Time at which this event happened'): Datetime(),
     Required('command', description='The mach command that was invoked'): basestring,
     Required('argv', description=(
         'Full mach commandline. ' +
         'If the commandline contains absolute paths they will be sanitized.')): [basestring],
     Required('success', description='true if the command succeeded'): bool,
@@ -55,8 +69,206 @@ schema = Schema({
         Optional('physical_cores', description='Number of physical CPU cores present'): int,
         Optional('memory_gb', description='System memory in GB'): int,
         Optional('drive_is_ssd',
                  description='true if the source directory is on a solid-state disk'): bool,
         Optional('virtual_machine',
                  description='true if the OS appears to be running in a virtual machine'): bool,
     },
 })
+
+
+def get_client_id(state_dir):
+    '''
+    Get a client id, which is a UUID, from a file in the state directory. If the file doesn't
+    exist, generate a UUID and save it to a file.
+    '''
+    path = os.path.join(state_dir, 'telemetry_client_id.json')
+    if os.path.exists(path):
+        with open(path, 'rb') as f:
+            return json.load(f)['client_id']
+    import uuid
+    # uuid4 is random, other uuid types may include identifiers from the local system.
+    client_id = str(uuid.uuid4())
+    with open(path, 'wb') as f:
+        json.dump({'client_id': client_id}, f)
+    return client_id
+
+
+def cpu_brand_linux():
+    '''
+    Read the CPU brand string out of /proc/cpuinfo on Linux.
+    '''
+    with open('/proc/cpuinfo', 'rb') as f:
+        for line in f:
+            if line.startswith('model name'):
+                _, brand = line.split(': ', 1)
+                return brand.rstrip().decode('ascii')
+    # not found?
+    return None
+
+
+def cpu_brand_windows():
+    '''
+    Read the CPU brand string from the registry on Windows.
+    '''
+    try:
+        import _winreg
+    except ImportError:
+        import winreg as _winreg
+
+    try:
+        h = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
+                            r'HARDWARE\DESCRIPTION\System\CentralProcessor\0')
+        (brand, ty) = _winreg.QueryValueEx(h, 'ProcessorNameString')
+        if ty == _winreg.REG_SZ:
+            return brand
+    except WindowsError:
+        pass
+    return None
+
+
+def cpu_brand_mac():
+    '''
+    Get the CPU brand string via sysctl on macos.
+    '''
+    import ctypes
+    import ctypes.util
+
+    libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c"))
+    # First, find the required buffer size.
+    bufsize = ctypes.c_size_t(0)
+    result = libc.sysctlbyname(b'machdep.cpu.brand_string', None, ctypes.byref(bufsize),
+                               None, 0)
+    if result != 0:
+        return None
+    bufsize.value += 1
+    buf = ctypes.create_string_buffer(bufsize.value)
+    # Now actually get the value.
+    result = libc.sysctlbyname(b'machdep.cpu.brand_string', buf, ctypes.byref(bufsize), None, 0)
+    if result != 0:
+        return None
+
+    return buf.value.decode()
+
+
+def get_cpu_brand():
+    '''
+    Get the CPU brand string as returned by CPUID.
+    '''
+    return {
+        'Linux': cpu_brand_linux,
+        'Windows': cpu_brand_windows,
+        'Darwin': cpu_brand_mac,
+    }.get(platform.system(), lambda: None)()
+
+
+def get_system_info():
+    '''
+    Gather info to fill the `system` keys in the schema.
+    '''
+    # Normalize OS names a bit, and bucket non-tier-1 platforms into "other".
+    info = {
+        'os': {
+            'Linux': 'linux',
+            'Windows': 'windows',
+            'Darwin': 'macos',
+        }.get(platform.system(), 'other')
+    }
+    try:
+        import psutil
+
+        info['logical_cores'] = psutil.cpu_count()
+        info['physical_cores'] = psutil.cpu_count(logical=False)
+        # `total` on Linux is gathered from /proc/meminfo's `MemTotal`, which is the total
+        # amount of physical memory minus some kernel usage, so round up to the nearest GB
+        # to get a sensible answer.
+        info['memory_gb'] = int(
+            math.ceil(float(psutil.virtual_memory().total) / (1024 * 1024 * 1024)))
+    except ImportError:
+        # TODO: sort out psutil availability on Windows, or write a fallback impl for Windows.
+        # https://bugzilla.mozilla.org/show_bug.cgi?id=1481612
+        pass
+    cpu_brand = get_cpu_brand()
+    if cpu_brand is not None:
+        info['cpu_brand'] = cpu_brand
+    # TODO: drive_is_ssd, virtual_machine: https://bugzilla.mozilla.org/show_bug.cgi?id=1481613
+    return info
+
+
+def get_build_opts(substs):
+    '''
+    Translate selected items from `substs` into `build_opts` keys in the schema.
+    '''
+    try:
+        return {
+            k: ty(substs.get(s, None)) for (k, s, ty) in (
+                # Selected substitutions.
+                ('compiler', 'CC_TYPE', str),
+                ('artifact', 'MOZ_ARTIFACT_BUILDS', bool),
+                ('debug', 'MOZ_DEBUG', bool),
+                ('opt', 'MOZ_OPTIMIZE', bool),
+                ('ccache', 'CCACHE', bool),
+                ('sccache', 'MOZ_USING_SCCACHE', bool),
+                # TODO: detect icecream: https://bugzilla.mozilla.org/show_bug.cgi?id=1481614
+            )
+        }
+    except BuildEnvironmentNotFoundException:
+        return {}
+
+
+def filter_args(command, argv, paths):
+    '''
+    Given the full list of command-line arguments, remove anything up to and including `command`,
+    and attempt to filter absolute pathnames out of any arguments after that.
+    '''
+    args = list(argv)
+    while args:
+        a = args.pop(0)
+        if a == command:
+            break
+
+    def filter_path(p):
+        p = mozpath.abspath(p)
+        base = mozpath.basedir(p, paths)
+        if base:
+            return mozpath.relpath(p, base)
+        # Best-effort.
+        return '<path omitted>'
+    return [filter_path(arg) for arg in args]
+
+
+def gather_telemetry(command='', success=False, monitor=None, mach_context=None, substs={},
+                     paths=[]):
+    '''
+    Gather telemetry about the build and the user's system and pass it to the telemetry
+    handler to be stored for later submission.
+
+    Any absolute paths on the command line will be made relative to `paths` or replaced
+    with a placeholder to avoid including paths from developer's machines.
+    '''
+    data = {
+        'client_id': get_client_id(mach_context.state_dir),
+        # Simplest way to get an rfc3339 datetime string, AFAICT.
+        'time': datetime.utcfromtimestamp(monitor.start_time).isoformat(b'T') + 'Z',
+        'command': command,
+        'argv': filter_args(command, sys.argv, paths),
+        'success': success,
+        # TODO: use a monotonic clock: https://bugzilla.mozilla.org/show_bug.cgi?id=1481624
+        'duration_ms': int(monitor.elapsed * 1000),
+        'build_opts': get_build_opts(substs),
+        'system': get_system_info(),
+        # TODO: exception: https://bugzilla.mozilla.org/show_bug.cgi?id=1481617
+        # TODO: file_types_changed: https://bugzilla.mozilla.org/show_bug.cgi?id=1481774
+    }
+    try:
+        # Validate against the schema.
+        schema(data)
+    except MultipleInvalid as exc:
+        msg = ['Build telemetry is invalid:']
+        for error in exc.errors:
+            msg.append(str(error))
+        print('\n'.join(msg) + '\n' + pprint.pformat(data))
+
+    telemetry_handler = getattr(mach_context,
+                                'telemetry_handler', None)
+    if telemetry_handler:
+        telemetry_handler(mach_context, data)
--- a/taskcluster/scripts/builder/hazard-analysis.sh
+++ b/taskcluster/scripts/builder/hazard-analysis.sh
@@ -9,16 +9,17 @@ JS_SRCDIR=$GECKO_DIR/js/src
 ANALYSIS_SRCDIR=$JS_SRCDIR/devtools/rootAnalysis
 
 export CC="$TOOLTOOL_DIR/gcc/bin/gcc"
 export CXX="$TOOLTOOL_DIR/gcc/bin/g++"
 export PATH="$TOOLTOOL_DIR/gcc/bin:$PATH"
 export LD_LIBRARY_PATH="$TOOLTOOL_DIR/gcc/lib64"
 export RUSTC="$TOOLTOOL_DIR/rustc/bin/rustc"
 export CARGO="$TOOLTOOL_DIR/rustc/bin/cargo"
+export LLVM_CONFIG="$TOOLTOOL_DIR/clang/bin/llvm-config"
 
 PYTHON=python2.7
 if ! which $PYTHON; then
     PYTHON=python
 fi
 
 
 function check_commit_msg () {
deleted file mode 100644
--- a/testing/geckodriver/.gitignore
+++ /dev/null
@@ -1,1 +0,0 @@
-/target
--- a/testing/geckodriver/build.rs
+++ b/testing/geckodriver/build.rs
@@ -106,16 +106,20 @@ impl Git {
         self.exec(&["cinnabar", "git2hg", &git_sha])
     }
 }
 
 impl BuildInfo for Git {
     fn hash(&self) -> Option<String> {
         self.exec(&["rev-parse", "HEAD"])
             .and_then(|sha| self.to_hg_sha(sha))
+            .map(|mut s| {
+              s.truncate(12);
+              s
+            })
     }
 
     fn date(&self) -> Option<String> {
         self.exec(&["log", "-1", "--date=short", "--pretty=format:%cd"])
     }
 }
 
 struct Noop;
--- a/testing/geckodriver/src/main.rs
+++ b/testing/geckodriver/src/main.rs
@@ -175,17 +175,17 @@ fn run() -> ProgramResult {
     } else {
         match matches.occurrences_of("verbosity") {
             0 => Some(logging::Level::Info),
             1 => Some(logging::Level::Debug),
             _ => Some(logging::Level::Trace),
         }
     };
     if let Some(ref level) = log_level {
-        logging::init_with_level(level.clone()).unwrap();
+        logging::init_with_level(*level).unwrap();
     } else {
         logging::init().unwrap();
     }
 
     let settings = MarionetteSettings {
         port: marionette_port,
         binary,
         connect_existing: matches.is_present("connect_existing"),
--- a/testing/mozharness/mozharness/mozilla/testing/android.py
+++ b/testing/mozharness/mozharness/mozilla/testing/android.py
@@ -1,35 +1,32 @@
 #!/usr/bin/env python
 # ***** BEGIN LICENSE BLOCK *****
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 # ***** END LICENSE BLOCK *****
 
-import datetime
 import glob
 import os
 import subprocess
 import tempfile
-import time
 from mozharness.mozilla.automation import TBPL_RETRY, EXIT_STATUS_DICT
 
 
 class AndroidMixin(object):
     """
        Mixin class used by Android test scripts.
     """
 
     def __init__(self, **kwargs):
         self.logcat_proc = None
         self.logcat_file = None
 
         self._adb_path = None
-        self.sdk_level = None
         self.device_name = os.environ.get('DEVICE_NAME', None)
         self.device_serial = os.environ.get('DEVICE_SERIAL', None)
         self.device_ip = os.environ.get('DEVICE_IP', None)
         super(AndroidMixin, self).__init__(**kwargs)
 
     @property
     def adb_path(self):
         '''Get the path to the adb executable.
@@ -45,95 +42,16 @@ class AndroidMixin(object):
                 # Ignore attribute errors since BaseScript will
                 # attempt to access properties before the other Mixins
                 # have completed initialization. We recover afterwards
                 # when additional attemps occur after initialization
                 # is completed.
                 pass
         return self._adb_path
 
-    def _retry(self, max_attempts, interval, func, description, max_time=0):
-        '''
-        Execute func until it returns True, up to max_attempts times, waiting for
-        interval seconds between each attempt. description is logged on each attempt.
-        If max_time is specified, no further attempts will be made once max_time
-        seconds have elapsed; this provides some protection for the case where
-        the run-time for func is long or highly variable.
-        '''
-        status = False
-        attempts = 0
-        if max_time > 0:
-            end_time = datetime.datetime.now() + datetime.timedelta(seconds=max_time)
-        else:
-            end_time = None
-        while attempts < max_attempts and not status:
-            if (end_time is not None) and (datetime.datetime.now() > end_time):
-                self.info("Maximum retry run-time of %d seconds exceeded; "
-                          "remaining attempts abandoned" % max_time)
-                break
-            if attempts != 0:
-                self.info("Sleeping %d seconds" % interval)
-                time.sleep(interval)
-            attempts += 1
-            self.info(">> %s: Attempt #%d of %d" % (description, attempts, max_attempts))
-            status = func()
-        return status
-
-    def _run_proc(self, cmd, quiet=False):
-        self.info('Running %s' % subprocess.list2cmdline(cmd))
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
-        out, err = p.communicate()
-        if out and not quiet:
-            self.info('%s' % str(out.strip()))
-        if err and not quiet:
-            self.info('stderr: %s' % str(err.strip()))
-        return out, err
-
-    def _run_with_timeout(self, timeout, cmd, quiet=False):
-        timeout_cmd = ['timeout', '%s' % timeout] + cmd
-        return self._run_proc(timeout_cmd, quiet=quiet)
-
-    def _run_adb_with_timeout(self, timeout, cmd, quiet=False):
-        cmd = [self.adb_path, '-s', self.device_serial] + cmd
-        return self._run_with_timeout(timeout, cmd, quiet)
-
-    def _verify_adb(self):
-        self.info('Verifying adb connectivity')
-        self._run_with_timeout(180, [self.adb_path,
-                                     '-s',
-                                     self.device_serial,
-                                     'wait-for-device'])
-        return True
-
-    def _verify_adb_device(self):
-        out, _ = self._run_with_timeout(30, [self.adb_path, 'devices'])
-        if (self.device_serial in out) and ("device" in out):
-            return True
-        return False
-
-    def _is_boot_completed(self):
-        boot_cmd = ['shell', 'getprop', 'sys.boot_completed']
-        out, _ = self._run_adb_with_timeout(30, boot_cmd)
-        if out.strip() == '1':
-            return True
-        return False
-
-    def _install_apk(self):
-        install_ok = False
-        if int(self.sdk_level) >= 23:
-            cmd = ['install', '-r', '-g', self.installer_path]
-        else:
-            cmd = ['install', '-r', self.installer_path]
-            self.warning("Installing apk with default run-time permissions (sdk %s)" %
-                         str(self.sdk_level))
-        out, err = self._run_adb_with_timeout(300, cmd, True)
-        if 'Success' in out or 'Success' in err:
-            install_ok = True
-        return install_ok
-
     def _get_repo_url(self, path):
         """
            Return a url for a file (typically a tooltool manifest) in this hg repo
            and using this revision (or mozilla-central/default if repo/rev cannot
            be determined).
 
            :param path specifies the directory path to the file of interest.
         """
@@ -196,26 +114,24 @@ class AndroidMixin(object):
             self.info("Killing logcat pid %d." % self.logcat_proc.pid)
             self.logcat_proc.kill()
             self.logcat_file.close()
 
     def install_apk(self, apk):
         """
            Install the specified apk.
         """
-        cmd = [self.adb_path, '-s', self.device_serial, 'shell',
-               'getprop', 'ro.build.version.sdk']
-        self.sdk_level, _ = self._run_with_timeout(30, cmd)
-
-        install_ok = self._retry(3, 30, self._install_apk, "Install app APK")
-        if not install_ok:
+        import mozdevice
+        try:
+            device = mozdevice.ADBAndroid(adb=self.adb_path, device=self.device_serial)
+            device.install_app(apk)
+        except mozdevice.ADBError:
             self.fatal('INFRA-ERROR: Failed to install %s on %s' %
                        (self.installer_path, self.device_name),
                        EXIT_STATUS_DICT[TBPL_RETRY])
-        return install_ok
 
     def screenshot(self, prefix):
         """
            Save a screenshot of the entire screen to the blob upload directory.
         """
         dirs = self.query_abs_dirs()
         utility = os.path.join(self.xre_path, "screentopng")
         if not os.path.exists(utility):
--- a/testing/mozharness/mozharness/mozilla/testing/raptor.py
+++ b/testing/mozharness/mozharness/mozilla/testing/raptor.py
@@ -361,17 +361,17 @@ class Raptor(TestingMixin, MercurialScri
         # listed in raptor requirements.txt file.
         self.install_module(
             requirements=[os.path.join(self.raptor_path,
                                        'requirements.txt')]
         )
 
     def install(self):
         if self.app == "geckoview":
-            self.install_apk(os.path.basename(self.installer_url))
+            self.install_apk(self.installer_path)
         else:
             super(Raptor, self).install()
 
     def _validate_treeherder_data(self, parser):
         # late import is required, because install is done in create_virtualenv
         import jsonschema
 
         if len(parser.found_perf_data) != 1:
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -313741,16 +313741,21 @@
      {}
     ]
    ],
    "wasm/jsapi/bad-imports.js": [
     [
      {}
     ]
    ],
+   "wasm/jsapi/instanceTestFactory.js": [
+    [
+     {}
+    ]
+   ],
    "wasm/jsapi/table/assertions.js": [
     [
      {}
     ]
    ],
    "wasm/jsapi/wasm-constants.js": [
     [
      {}
@@ -401345,29 +401350,29 @@
       "jsshell": true
      }
     ],
     [
      "/wasm/jsapi/global/toString.any.worker.html",
      {}
     ]
    ],
-   "wasm/jsapi/global/value-set.any.js": [
-    [
-     "/wasm/jsapi/global/value-set.any.html",
-     {}
-    ],
-    [
-     "/wasm/jsapi/global/value-set.any.js",
+   "wasm/jsapi/global/value-get-set.any.js": [
+    [
+     "/wasm/jsapi/global/value-get-set.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/global/value-get-set.any.js",
      {
       "jsshell": true
      }
     ],
     [
-     "/wasm/jsapi/global/value-set.any.worker.html",
+     "/wasm/jsapi/global/value-get-set.any.worker.html",
      {}
     ]
    ],
    "wasm/jsapi/global/valueOf.any.js": [
     [
      "/wasm/jsapi/global/valueOf.any.html",
      {}
     ],
@@ -579661,25 +579666,25 @@
    "bfa3211ae26bfaa992b541d3b0c92f3df0503499",
    "reftest"
   ],
   "css/filter-effects/svg-feoffset-001.html": [
    "3d8118b387d938b588e8e88ad5ec87a5343e4f72",
    "reftest"
   ],
   "css/filter-effects/svg-unknown-input-001.html": [
-   "7789f2a9af4f1492fa6db36b53a72ada151f61d5",
+   "4ed1335caab262c39193ff752b4023718f1acca2",
    "reftest"
   ],
   "css/filter-effects/svg-unknown-input-002.html": [
-   "f45d3e344ad193c59826543239c33fffc61d6527",
+   "915a3df0245ce56db9929236a6ee70b19d413250",
    "reftest"
   ],
   "css/filter-effects/svg-unknown-input-ref.html": [
-   "1fff2a6175cfe1956ff2c451aece45ec73345d81",
+   "fd8af11300031fb9051df2ef288c96e3f1dcb6cd",
    "support"
   ],
   "css/geometry/DOMMatrix-001.html": [
    "a8a357bff606925aaa95dce6c4642b81bd8c88ea",
    "testharness"
   ],
   "css/geometry/DOMMatrix-002.html": [
    "d5f1137a413ce747f40792b06504255d151bd97b",
@@ -646389,17 +646394,17 @@
    "2490f05b3e80aa67a0c70a9cb12be282fa0e15b2",
    "testharness"
   ],
   "shadow-dom/input-element-list.html": [
    "b571534eb0d6f3f57cfbec3e706648b19848b6d6",
    "testharness"
   ],
   "shadow-dom/input-type-radio.html": [
-   "bd5d8e43b0fd9d0c9f1e078ed97a1bbd18b7b0be",
+   "9c90fcf0603222785aa81990fb2b09511ff6ba86",
    "testharness"
   ],
   "shadow-dom/layout-slot-no-longer-assigned.html": [
    "dfcac99da023ec2bbd94835f71efaef952a62341",
    "reftest"
   ],
   "shadow-dom/layout-slot-no-longer-fallback.html": [
    "7507f11ac18e6590367a147acbc78834b0d19afd",
@@ -656985,17 +656990,17 @@
    "bd6553fadcb16db177e522a0e60c82e8c55bca03",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorinternetexplorer.py": [
    "898ff144593877c3be33a33be567816e869dcf3e",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executormarionette.py": [
-   "ad71a8fa31c7cf4626c11214a520a2121db897c4",
+   "9ec8f6e5832619905118db632e32dc50fe74c131",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executoropera.py": [
    "55f1f0d59590807452a9ffc201ad8d0f8f972fcd",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorsafari.py": [
    "ed01f4d8341b5497473b6f535ac4a2c04158cd9e",
@@ -657021,17 +657026,17 @@
    "c728ae18e03b09f6c690be82efc78bd0c2ff7347",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/process.py": [
    "fb8c17a96ba04ce601ad3cb9ad4c7588f947e949",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/protocol.py": [
-   "71fc3c9a8f651913e53266f181ef2161ac91c97e",
+   "f8292ff5ec118b8f3d80da96bcd07586bedba45a",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/pytestrunner/__init__.py": [
    "1baaf9573aa804df8b9a853fef7382715fc4bf59",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/pytestrunner/runner.py": [
    "9555f5f51dcc84a19186ff0c8bde7e87e0153891",
@@ -657121,17 +657126,17 @@
    "62ddaffb443c94505383083923dc13fcb1cf5660",
    "support"
   ],
   "tools/wptrunner/wptrunner/testloader.py": [
    "2313a80c745bfac9946119926411234c506c6654",
    "support"
   ],
   "tools/wptrunner/wptrunner/testrunner.py": [
-   "90f7e4615e078840f9804f791422f9f2f3464a72",
+   "7e386b881d4c83a93d2543b7e5b9afd01623a5bc",
    "support"
   ],
   "tools/wptrunner/wptrunner/tests/__init__.py": [
    "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
    "support"
   ],
   "tools/wptrunner/wptrunner/tests/base.py": [
    "84dc4f2e7f82ee2e3a2aa6f4d8bdda76b1581da1",
@@ -657205,17 +657210,17 @@
    "1de951938cf57692edca2e019bdfdc6260b8fe62",
    "support"
   ],
   "tools/wptrunner/wptrunner/webdriver_server.py": [
    "4ec415ce78bb89a82d5f098b1c4e8560e7ec39e4",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptcommandline.py": [
-   "0075ad9096201a04c5342ad92aab59ab8dcf434e",
+   "d25e561ad195ef3de91a42871820ad372269f016",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptlogging.py": [
    "ac311816c18b7f898e4421410f97d9357d2edd2d",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptmanifest/__init__.py": [
    "8985b5ae35067a24fbc87fdd2e61d72794123892",
@@ -659773,121 +659778,125 @@
    "bda3ae7bc3c8dc5020a50c645b8dba2aaeb44591",
    "support"
   ],
   "wasm/jsapi/bad-imports.js": [
    "f076baacca8b3e6addf49f6841874d11bfcfe5a2",
    "support"
   ],
   "wasm/jsapi/constructor/compile.any.js": [
-   "0139a18fda3f928dc0eed0bef86098dcbabf5979",
+   "bd23a8666e76f30d212524bc30ffd00c0a546e70",
    "testharness"
   ],
   "wasm/jsapi/constructor/instantiate-bad-imports.any.js": [
    "86700298dfae66de6f4d026baa29e6e3584320f7",
    "testharness"
   ],
   "wasm/jsapi/constructor/instantiate.any.js": [
-   "e90f21e28ebf478c7af7d40c8744fba9e5f48720",
+   "5da6bd58dfc3463bdead679143566cfaeb8bf281",
    "testharness"
   ],
   "wasm/jsapi/constructor/validate.any.js": [
-   "70bd9f7022ad616c2d5e0be636f6935923e19173",
+   "c8613cbd9b3a467a919d87d3244c4f508dce6317",
    "testharness"
   ],
   "wasm/jsapi/global/constructor.any.js": [
-   "7a45cc4191c55684cde187fc73fb9741d6f5c2c5",
+   "237f99c8b298183a557c10778c70e1d359b9d6b6",
    "testharness"
   ],
   "wasm/jsapi/global/toString.any.js": [
    "ca025576c2b49604f053c83002f3a9cc8ef41a7b",
    "testharness"
   ],
-  "wasm/jsapi/global/value-set.any.js": [
-   "b4e6770f10ed9e3ad55b9ae18ee96deda3ff171e",
+  "wasm/jsapi/global/value-get-set.any.js": [
+   "6de62d5f58362bab593ae7eb453fa14c1424cf2c",
    "testharness"
   ],
   "wasm/jsapi/global/valueOf.any.js": [
-   "176c5a784698399351eedeaac0ec305aa8ab7b81",
+   "d4a84b254f76ea50284619967ab6dc98c99bfea2",
    "testharness"
   ],
   "wasm/jsapi/instance/constructor-bad-imports.any.js": [
    "24c51c10dc5df9d52c06bfb0715e435b17f24f7a",
    "testharness"
   ],
   "wasm/jsapi/instance/constructor.any.js": [
-   "f9bd06ac8e95e0f4dc2ce96560529fad9bf2095b",
+   "e6a0450202e94baa82eb4797fed6a7c248ed00a7",
    "testharness"
   ],
   "wasm/jsapi/instance/exports.any.js": [
-   "31423918720543da2ba25e392267bf541b756242",
+   "cad468660e099b33f0a03b83a09df0498d67a7e0",
    "testharness"
   ],
   "wasm/jsapi/instance/toString.any.js": [
    "08dcb14a50d04f6db196626ddb93f2b50da8f055",
    "testharness"
   ],
+  "wasm/jsapi/instanceTestFactory.js": [
+   "24f849e6f943d9008343909a00b2f2b0d1ea0c3d",
+   "support"
+  ],
   "wasm/jsapi/interface.any.js": [
-   "5d76ac56ec5fafde8dde3924df863a2694bd6691",
+   "98c4a1d781b7d77709a7f1df5adb3c756648fbd3",
    "testharness"
   ],
   "wasm/jsapi/memory/buffer.any.js": [
-   "b04460b6c5e56cf1fe990e3107aa9efcb4964ed5",
+   "4788ffcf84ff8d88adbafbe416dd7d5b80ec89d1",
    "testharness"
   ],
   "wasm/jsapi/memory/constructor.any.js": [
-   "f9907ca6104d8ec76861e43b6b981042d86fb865",
+   "a584a23ecf0a582b21b913a780accee38e277927",
    "testharness"
   ],
   "wasm/jsapi/memory/grow.any.js": [
-   "95300399f192b7eab70dd8f07c43f4db37eebe01",
+   "1ccfb946756fef71b89672dfc86830c620a9e981",
    "testharness"
   ],
   "wasm/jsapi/memory/toString.any.js": [
    "4e15d75ea20f1ebfeba5dc7c8a9a52c253dd01bf",
    "testharness"
   ],
   "wasm/jsapi/module/constructor.any.js": [
-   "32f183fac8738d30cc8a432768da315949320257",
+   "a467c1a17bb62ac52d323e1976cd067d92a9410d",
    "testharness"
   ],
   "wasm/jsapi/module/customSections.any.js": [
-   "58ac63b61c93a015bfa9d5daab39f8d5b48548da",
+   "04c5abed52435714a18467c419dce17dfcf4073d",
    "testharness"
   ],
   "wasm/jsapi/module/exports.any.js": [
-   "e63a885a4c34add0f6787d3642de83d9766568d1",
+   "9d95b652233b3d7687d4fe14371144519719e97b",
    "testharness"
   ],
   "wasm/jsapi/module/imports.any.js": [
-   "640da591d21d8924d261fdc58b8e7cc762187a11",
+   "b3bb8598b080c376f4de1294780e6072eac2b354",
    "testharness"
   ],
   "wasm/jsapi/module/toString.any.js": [
    "d9231a132ca8bf965f69c3cc81070a2ffe179efa",
    "testharness"
   ],
   "wasm/jsapi/table/assertions.js": [
-   "dde2fd770904207a1f9f287fa48d82954a418f2e",
+   "c88972b4ebdcd760b2a441835c2c9eb31dabfea8",
    "support"
   ],
   "wasm/jsapi/table/constructor.any.js": [
-   "e924bdb2ba42c67bcc6d4a949c2eeb50eac63e31",
+   "99eee19fecd49e432c7f6774c0968218e6d931a3",
    "testharness"
   ],
   "wasm/jsapi/table/get-set.any.js": [
-   "2bb43a9308d732b5b6fa689c181ac411880c3733",
+   "f8a0194364fde1b25eeb998d1837349c3a8bafc2",
    "testharness"
   ],
   "wasm/jsapi/table/grow.any.js": [
-   "d3efb511e4b1db1efa089322c0a3079705dfbdbd",
+   "4978e3ca23d0261aaccf4aad97dd348da22a54d0",
    "testharness"
   ],
   "wasm/jsapi/table/length.any.js": [
-   "a6a9661dbaddc800cb99b7b8e2b804cb0c8e3c62",
+   "b1bfa6cfd1f44fbdbf18769b3f3e8129310c7e0e",
    "testharness"
   ],
   "wasm/jsapi/table/toString.any.js": [
    "e576477910ad3198b446b4addf89ba9a571d020b",
    "testharness"
   ],
   "wasm/jsapi/wasm-constants.js": [
    "f056f9cbfcfbac52d0506edddd01c8fad8636ebb",
--- a/testing/web-platform/meta/wasm/idlharness.any.js.ini
+++ b/testing/web-platform/meta/wasm/idlharness.any.js.ini
@@ -204,28 +204,16 @@
     expected: FAIL
 
   [RuntimeError interface: existence and properties of interface prototype object's "constructor" property]
     expected: FAIL
 
   [RuntimeError interface: existence and properties of interface prototype object's @@unscopables property]
     expected: FAIL
 
-  [WebAssembly namespace: operation compile(BufferSource)]
-    expected: FAIL
-
-  [WebAssembly namespace: operation instantiate(Module, object)]
-    expected: FAIL
-
-  [WebAssembly namespace: operation instantiate(BufferSource, object)]
-    expected: FAIL
-
-  [WebAssembly namespace: operation validate(BufferSource)]
-    expected: FAIL
-
 
 [idlharness.any.worker.html]
   [Module interface: existence and properties of interface object]
     expected: FAIL
 
   [Module interface object length]
     expected: FAIL
 
@@ -373,21 +361,8 @@
   [Global interface: existence and properties of interface prototype object's @@unscopables property]
     expected: FAIL
 
   [Global interface: operation valueOf()]
     expected: FAIL
 
   [Global interface: attribute value]
     expected: FAIL
-
-  [WebAssembly namespace: operation instantiate(BufferSource, object)]
-    expected: FAIL
-
-  [WebAssembly namespace: operation validate(BufferSource)]
-    expected: FAIL
-
-  [WebAssembly namespace: operation instantiate(Module, object)]
-    expected: FAIL
-
-  [WebAssembly namespace: operation compile(BufferSource)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/global/constructor.any.js.ini
+++ /dev/null
@@ -1,39 +0,0 @@
-[constructor.any.html]
-  [Order of evaluation]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490232
-    expected: FAIL
-
-  [Explicit value undefined for type f32]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490286
-    expected: FAIL
-
-  [Explicit value undefined for type f64]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490286
-    expected: FAIL
-
-[constructor.any.worker.html]
-  [Order of evaluation]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490232
-    expected: FAIL
-
-  [Explicit value undefined for type f32]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490286
-    expected: FAIL
-
-  [Explicit value undefined for type f64]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490286
-    expected: FAIL
-
-[constructor.any.js]
-  [Order of evaluation]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490232
-    expected: FAIL
-
-  [Explicit value undefined for type f32]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490286
-    expected: FAIL
-
-  [Explicit value undefined for type f64]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490286
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/global/value-set.any.js.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[value-set.any.html]
-  [Calling setter without argument]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-[value-set.any.worker.html]
-  [Calling setter without argument]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-[value-set.any.js]
-  [Calling setter without argument]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/interface.any.js.ini
+++ /dev/null
@@ -1,170 +0,0 @@
-[interface.any.html]
-  [WebAssembly.validate]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.compile]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.instantiate]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.exports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.imports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.customSections]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Instance.exports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Memory.grow]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Memory.buffer]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.grow]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.get]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.set]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.length]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Global.valueOf]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-[interface.any.worker.html]
-  [WebAssembly.validate]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.compile]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.instantiate]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.exports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.imports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.customSections]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Instance.exports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Memory.grow]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Memory.buffer]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.grow]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.get]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.set]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.length]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Global.valueOf]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-[interface.any.js]
-  [WebAssembly.validate]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.compile]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.instantiate]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.exports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.imports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Module.customSections]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Instance.exports]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Memory.grow]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Memory.buffer]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.grow]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.get]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.set]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Table.length]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
-
-  [WebAssembly.Global.valueOf]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490229
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/memory/constructor.any.js.ini
+++ /dev/null
@@ -1,182 +0,0 @@
-[constructor.any.html]
-  [Invalid descriptor argument]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Undefined initial value in descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Proxy descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-[constructor.any.worker.html]
-  [Invalid descriptor argument]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Undefined initial value in descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Proxy descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-[constructor.any.js]
-  [Invalid descriptor argument]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Undefined initial value in descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Proxy descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/memory/grow.any.js.ini
+++ /dev/null
@@ -1,123 +0,0 @@
-[grow.any.html]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-[grow.any.worker.html]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-[grow.any.js]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/module/customSections.any.js.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[customSections.any.html]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-[customSections.any.worker.html]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-[customSections.any.js]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/table/constructor.any.js.ini
+++ /dev/null
@@ -1,195 +0,0 @@
-[constructor.any.html]
-  [Undefined initial value in descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Proxy descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Type conversion for descriptor.element]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490275
-    expected: FAIL
-
-  [Order of evaluation for descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490275
-    expected: FAIL
-
-[constructor.any.worker.html]
-  [Undefined initial value in descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Proxy descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Type conversion for descriptor.element]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490275
-    expected: FAIL
-
-  [Order of evaluation for descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490275
-    expected: FAIL
-
-[constructor.any.js]
-  [Undefined initial value in descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range initial value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range maximum value in descriptor: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Proxy descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490277
-    expected: FAIL
-
-  [Type conversion for descriptor.element]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490275
-    expected: FAIL
-
-  [Order of evaluation for descriptor]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490275
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/table/get-set.any.js.ini
+++ /dev/null
@@ -1,231 +0,0 @@
-[get-set.any.html]
-  [Missing arguments: get]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Getting out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-[get-set.any.worker.html]
-  [Missing arguments: get]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Getting out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-[get-set.any.js]
-  [Missing arguments: get]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Getting out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Getting out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Setting out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/wasm/jsapi/table/grow.any.js.ini
+++ /dev/null
@@ -1,123 +0,0 @@
-[grow.any.html]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-[grow.any.worker.html]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-[grow.any.js]
-  [Missing arguments]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1490274
-    expected: FAIL
-
-  [Out-of-range argument: undefined]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: NaN]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -Infinity]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: -1]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 4294967296]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: 68719476736]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: "0x100000000"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
-  [Out-of-range argument: object "[object Object\]"]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1488473
-    expected: FAIL
-
--- a/testing/web-platform/mozilla/meta/MANIFEST.json
+++ b/testing/web-platform/mozilla/meta/MANIFEST.json
@@ -1560,17 +1560,17 @@
    "c7b1a5cd565107a9d2ed860c88bbbda7f20c111f",
    "support"
   ],
   "wasm/js/int_literals.wast.js": [
    "60ae9db6154aa04e03604c80a769061b042ad490",
    "support"
   ],
   "wasm/js/jsapi.js": [
-   "c0b9c4a200b6ec7132d81d48259ec97e2a047ae8",
+   "b7f30d280b9d5cb37c3c007e31e1717ca4290601",
    "support"
   ],
   "wasm/js/labels.wast.js": [
    "75e5c04f8317e5c3363981a5488ddb808293cae1",
    "support"
   ],
   "wasm/js/left-to-right.wast.js": [
    "6a3522dc0303bf525b7d52b7ac7d0330979a15b9",
--- a/testing/web-platform/mozilla/tests/wasm/js/jsapi.js
+++ b/testing/web-platform/mozilla/tests/wasm/js/jsapi.js
@@ -228,17 +228,17 @@ test(() => {
     assert_equals(String(emptyModule), "[object WebAssembly.Module]");
     assert_equals(Object.getPrototypeOf(emptyModule), moduleProto);
 }, "'WebAssembly.Module' instance objects");
 
 test(() => {
     const moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports');
     assert_equals(typeof moduleImportsDesc.value, "function");
     assert_equals(moduleImportsDesc.writable, true);
-    assert_equals(moduleImportsDesc.enumerable, false);
+    assert_equals(moduleImportsDesc.enumerable, true);
     assert_equals(moduleImportsDesc.configurable, true);
 }, "'WebAssembly.Module.imports' data property");
 
 test(() => {
     const moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports');
     const moduleImports = moduleImportsDesc.value;
     assert_equals(moduleImports.length, 1);
     assertThrows(() => moduleImports(), TypeError);
@@ -263,17 +263,17 @@ test(() => {
     assert_equals(arr[3].module, "g");
     assert_equals(arr[3].name, "⚡");
 }, "'WebAssembly.Module.imports' method");
 
 test(() => {
     const moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports');
     assert_equals(typeof moduleExportsDesc.value, "function");
     assert_equals(moduleExportsDesc.writable, true);
-    assert_equals(moduleExportsDesc.enumerable, false);
+    assert_equals(moduleExportsDesc.enumerable, true);
     assert_equals(moduleExportsDesc.configurable, true);
 }, "'WebAssembly.Module.exports' data property");
 
 test(() => {
     const moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports');
     const moduleExports = moduleExportsDesc.value;
     assert_equals(moduleExports.length, 1);
     assertThrows(() => moduleExports(), TypeError);
@@ -294,28 +294,28 @@ test(() => {
     assert_equals(arr[3].kind, "global");
     assert_equals(arr[3].name, "⚡");
 }, "'WebAssembly.Module.exports' method");
 
 test(() => {
     const customSectionsDesc = Object.getOwnPropertyDescriptor(Module, 'customSections');
     assert_equals(typeof customSectionsDesc.value, "function");
     assert_equals(customSectionsDesc.writable, true);
-    assert_equals(customSectionsDesc.enumerable, false);
+    assert_equals(customSectionsDesc.enumerable, true);
     assert_equals(customSectionsDesc.configurable, true);
 }, "'WebAssembly.Module.customSections' data property");
 
 test(() => {
     const customSectionsDesc = Object.getOwnPropertyDescriptor(Module, 'customSections');
     const moduleCustomSections = customSectionsDesc.value;
     assert_equals(moduleCustomSections.length, 2);
     assertThrows(() => moduleCustomSections(), TypeError);
     assertThrows(() => moduleCustomSections(undefined), TypeError);
     assertThrows(() => moduleCustomSections({}), TypeError);
-    var arr = moduleCustomSections(emptyModule);
+    var arr = moduleCustomSections(emptyModule, "");
     assert_equals(arr instanceof Array, true);
     assert_equals(arr.length, 0);
 }, "'WebAssembly.Module.customSections' method");
 
 test(() => {
     const instanceDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Instance');
     assert_equals(typeof instanceDesc.value, "function");
     assert_equals(instanceDesc.writable, true);
@@ -365,17 +365,17 @@ test(() => {
     assert_equals(String(exportingInstance), "[object WebAssembly.Instance]");
     assert_equals(Object.getPrototypeOf(exportingInstance), instanceProto);
 }, "'WebAssembly.Instance' instance objects");
 
 test(() => {
     const exportsDesc = Object.getOwnPropertyDescriptor(instanceProto, 'exports');
     assert_equals(typeof exportsDesc.get, "function");
     assert_equals(exportsDesc.set, undefined);
-    assert_equals(exportsDesc.enumerable, false);
+    assert_equals(exportsDesc.enumerable, true);
     assert_equals(exportsDesc.configurable, true);
     const exportsGetter = exportsDesc.get;
     assertThrows(() => exportsGetter.call(), TypeError);
     assertThrows(() => exportsGetter.call({}), TypeError);
     assert_equals(typeof exportsGetter.call(exportingInstance), "object");
 }, "'WebAssembly.Instance.prototype.exports' accessor property");
 
 test(() => {
@@ -413,21 +413,21 @@ test(() => {
 test(() => {
     const memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory');
     assert_equals(Memory, memoryDesc.value);
     assert_equals(Memory.length, 1);
     assert_equals(Memory.name, "Memory");
     assertThrows(() => Memory(), TypeError);
     assertThrows(() => new Memory(1), TypeError);
     assertThrows(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error);
-    assertThrows(() => new Memory({initial:-1}), RangeError);
-    assertThrows(() => new Memory({initial:Math.pow(2,32)}), RangeError);
+    assertThrows(() => new Memory({initial:-1}), TypeError);
+    assertThrows(() => new Memory({initial:Math.pow(2,32)}), TypeError);
     assertThrows(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), RangeError);
     assertThrows(() => new Memory({initial:2, maximum:1 }), RangeError);
-    assertThrows(() => new Memory({maximum: -1 }), RangeError);
+    assertThrows(() => new Memory({maximum: -1 }), TypeError);
     assert_equals(new Memory({initial:1}) instanceof Memory, true);
     assert_equals(new Memory({initial:1.5}).buffer.byteLength, WasmPage);
 }, "'WebAssembly.Memory' constructor function");
 
 test(() => {
     const memoryProtoDesc = Object.getOwnPropertyDescriptor(Memory, 'prototype');
     assert_equals(typeof memoryProtoDesc.value, "object");
     assert_equals(memoryProtoDesc.writable, false);
@@ -449,44 +449,44 @@ test(() => {
     assert_equals(String(mem1), "[object WebAssembly.Memory]");
     assert_equals(Object.getPrototypeOf(mem1), memoryProto);
 }, "'WebAssembly.Memory' instance objects");
 
 test(() => {
     const bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer');
     assert_equals(typeof bufferDesc.get, "function");
     assert_equals(bufferDesc.set, undefined);
-    assert_equals(bufferDesc.enumerable, false);
+    assert_equals(bufferDesc.enumerable, true);
     assert_equals(bufferDesc.configurable, true);
 }, "'WebAssembly.Memory.prototype.buffer' accessor property");
 
 test(() => {
     const bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer');
     const bufferGetter = bufferDesc.get;
     assertThrows(() => bufferGetter.call(), TypeError);
     assertThrows(() => bufferGetter.call({}), TypeError);
     assert_equals(bufferGetter.call(mem1) instanceof ArrayBuffer, true);
     assert_equals(bufferGetter.call(mem1).byteLength, WasmPage);
 }, "'WebAssembly.Memory.prototype.buffer' getter");
 
 test(() => {
     const memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
     assert_equals(typeof memGrowDesc.value, "function");
-    assert_equals(memGrowDesc.enumerable, false);
+    assert_equals(memGrowDesc.enumerable, true);
     assert_equals(memGrowDesc.configurable, true);
 }, "'WebAssembly.Memory.prototype.grow' data property");
 
 test(() => {
     const memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
     const memGrow = memGrowDesc.value;
     assert_equals(memGrow.length, 1);
     assertThrows(() => memGrow.call(), TypeError);
     assertThrows(() => memGrow.call({}), TypeError);
-    assertThrows(() => memGrow.call(mem1, -1), RangeError);
-    assertThrows(() => memGrow.call(mem1, Math.pow(2,32)), RangeError);
+    assertThrows(() => memGrow.call(mem1, -1), TypeError);
+    assertThrows(() => memGrow.call(mem1, Math.pow(2,32)), TypeError);
     var mem = new Memory({initial:1, maximum:2});
     var buf = mem.buffer;
     assert_equals(buf.byteLength, WasmPage);
     assert_equals(mem.grow(0), 1);
     assert_equals(buf !== mem.buffer, true);
     assert_equals(buf.byteLength, 0);
     buf = mem.buffer;
     assert_equals(buf.byteLength, WasmPage);
@@ -514,20 +514,20 @@ test(() => {
     assert_equals(Table.length, 1);
     assert_equals(Table.name, "Table");
     assertThrows(() => Table(), TypeError);
     assertThrows(() => new Table(1), TypeError);
     assertThrows(() => new Table({initial:1, element:1}), TypeError);
     assertThrows(() => new Table({initial:1, element:"any"}), TypeError);
     assertThrows(() => new Table({initial:1, element:{valueOf() { return "anyfunc" }}}), TypeError);
     assertThrows(() => new Table({initial:{valueOf() { throw new Error("here")}}, element:"anyfunc"}), Error);
-    assertThrows(() => new Table({initial:-1, element:"anyfunc"}), RangeError);
-    assertThrows(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), RangeError);
+    assertThrows(() => new Table({initial:-1, element:"anyfunc"}), TypeError);
+    assertThrows(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), TypeError);
     assertThrows(() => new Table({initial:2, maximum:1, element:"anyfunc"}), RangeError);
-    assertThrows(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), RangeError);
+    assertThrows(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), TypeError);
     assert_equals(new Table({initial:1, element:"anyfunc"}) instanceof Table, true);
     assert_equals(new Table({initial:1.5, element:"anyfunc"}) instanceof Table, true);
     assert_equals(new Table({initial:1, maximum:1.5, element:"anyfunc"}) instanceof Table, true);
     assertThrows(() => new Table({initial:1, maximum:Math.pow(2,32)-1, element:"anyfunc"}), RangeError);
 }, "'WebAssembly.Table' constructor function");
 
 test(() => {
     const tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
@@ -551,94 +551,94 @@ test(() => {
     assert_equals(String(tbl1), "[object WebAssembly.Table]");
     assert_equals(Object.getPrototypeOf(tbl1), tableProto);
 }, "'WebAssembly.Table' instance objects");
 
 test(() => {
     const lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
     assert_equals(typeof lengthDesc.get, "function");
     assert_equals(lengthDesc.set, undefined);
-    assert_equals(lengthDesc.enumerable, false);
+    assert_equals(lengthDesc.enumerable, true);
     assert_equals(lengthDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.length' accessor data property");
 
 test(() => {
     const lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
     const lengthGetter = lengthDesc.get;
     assert_equals(lengthGetter.length, 0);
     assertThrows(() => lengthGetter.call(), TypeError);
     assertThrows(() => lengthGetter.call({}), TypeError);
     assert_equals(typeof lengthGetter.call(tbl1), "number");
     assert_equals(lengthGetter.call(tbl1), 2);
 }, "'WebAssembly.Table.prototype.length' getter");
 
 test(() => {
     const getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get');
     assert_equals(typeof getDesc.value, "function");
-    assert_equals(getDesc.enumerable, false);
+    assert_equals(getDesc.enumerable, true);
     assert_equals(getDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.get' data property");
 
 test(() => {
     const getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get');
     const get = getDesc.value;
     assert_equals(get.length, 1);
     assertThrows(() => get.call(), TypeError);
     assertThrows(() => get.call({}), TypeError);
     assert_equals(get.call(tbl1, 0), null);
     assert_equals(get.call(tbl1, 1), null);
     assert_equals(get.call(tbl1, 1.5), null);
     assertThrows(() => get.call(tbl1, 2), RangeError);
     assertThrows(() => get.call(tbl1, 2.5), RangeError);
-    assertThrows(() => get.call(tbl1, -1), RangeError);
-    assertThrows(() => get.call(tbl1, Math.pow(2,33)), RangeError);
+    assertThrows(() => get.call(tbl1, -1), TypeError);
+    assertThrows(() => get.call(tbl1, Math.pow(2,33)), TypeError);
     assertThrows(() => get.call(tbl1, {valueOf() { throw new Error("hi") }}), Error);
 }, "'WebAssembly.Table.prototype.get' method");
 
 test(() => {
     const setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set');
     assert_equals(typeof setDesc.value, "function");
-    assert_equals(setDesc.enumerable, false);
+    assert_equals(setDesc.enumerable, true);
     assert_equals(setDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.set' data property");
 
 test(() => {
     const setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set');
     const set = setDesc.value;
     assert_equals(set.length, 2);
     assertThrows(() => set.call(), TypeError);
     assertThrows(() => set.call({}), TypeError);
     assertThrows(() => set.call(tbl1, 0), TypeError);
     assertThrows(() => set.call(tbl1, 2, null), RangeError);
-    assertThrows(() => set.call(tbl1, -1, null), RangeError);
-    assertThrows(() => set.call(tbl1, Math.pow(2,33), null), RangeError);
+    assertThrows(() => set.call(tbl1, -1, null), TypeError);
+    assertThrows(() => set.call(tbl1, Math.pow(2,33), null), TypeError);
     assertThrows(() => set.call(tbl1, 0, undefined), TypeError);
     assertThrows(() => set.call(tbl1, 0, {}), TypeError);
     assertThrows(() => set.call(tbl1, 0, function() {}), TypeError);
     assertThrows(() => set.call(tbl1, 0, Math.sin), TypeError);
     assertThrows(() => set.call(tbl1, {valueOf() { throw Error("hai") }}, null), Error);
     assert_equals(set.call(tbl1, 0, null), undefined);
     assert_equals(set.call(tbl1, 1, null), undefined);
 }, "'WebAssembly.Table.prototype.set' method");
 
 test(() => {
     const tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
     assert_equals(typeof tblGrowDesc.value, "function");
-    assert_equals(tblGrowDesc.enumerable, false);
+    assert_equals(tblGrowDesc.enumerable, true);
     assert_equals(tblGrowDesc.configurable, true);
 }, "'WebAssembly.Table.prototype.grow' data property");
 
 test(() => {
     const tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
     const tblGrow = tblGrowDesc.value;
     assert_equals(tblGrow.length, 1);
     assertThrows(() => tblGrow.call(), TypeError);
     assertThrows(() => tblGrow.call({}), TypeError);
-    assertThrows(() => tblGrow.call(tbl1, -1), RangeError);
-    assertThrows(() => tblGrow.call(tbl1, Math.pow(2,32)), RangeError);
+    assertThrows(() => tblGrow.call(tbl1, -1), TypeError);
+    assertThrows(() => tblGrow.call(tbl1, Math.pow(2,32)), TypeError);
     var tbl = new Table({element:"anyfunc", initial:1, maximum:2});
     assert_equals(tbl.length, 1);
     assert_equals(tbl.grow(0), 1);
     assert_equals(tbl.length, 1);
     assert_equals(tbl.grow(1), 1);
     assert_equals(tbl.length, 2);
     assertThrows(() => tbl.grow(1), Error);
 }, "'WebAssembly.Table.prototype.grow' method");
@@ -651,17 +651,17 @@ test(() => {
     assert_false(WebAssembly.validate(moduleBinaryImporting2Memories));
     assert_false(WebAssembly.validate(moduleBinaryWithMemSectionAndMemImport));
 }, "'WebAssembly.validate' method"),
 
 test(() => {
     const compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
     assert_equals(typeof compileDesc.value, "function");
     assert_equals(compileDesc.writable, true);
-    assert_equals(compileDesc.enumerable, false);
+    assert_equals(compileDesc.enumerable, true);
     assert_equals(compileDesc.configurable, true);
 }, "'WebAssembly.compile' data property");
 
 test(() => {
     const compile = WebAssembly.compile;
     const compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
 
     assert_equals(compile, compileDesc.value);
@@ -704,17 +704,17 @@ function assertCompileSuccess(bytes) {
 
 assertCompileSuccess(emptyModuleBinary);
 assertCompileSuccess(emptyModuleBinary.buffer);
 
 test(() => {
     const instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
     assert_equals(typeof instantiateDesc.value, "function");
     assert_equals(instantiateDesc.writable, true);
-    assert_equals(instantiateDesc.enumerable, false);
+    assert_equals(instantiateDesc.enumerable, true);
     assert_equals(instantiateDesc.configurable, true);
 }, "'WebAssembly.instantiate' data property");
 
 test(() => {
     const instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
     const instantiate = WebAssembly.instantiate;
     assert_equals(instantiate, instantiateDesc.value);
     assert_equals(instantiate.length, 1);
--- a/testing/web-platform/tests/css/filter-effects/svg-unknown-input-001.html
+++ b/testing/web-platform/tests/css/filter-effects/svg-unknown-input-001.html
@@ -1,19 +1,20 @@
 <!DOCTYPE html>
 <title>Filter Effects: The in attribute</title>
 <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
 <link rel="help" href="https://www.w3.org/TR/filter-effects-1/#CommonAttributes">
 <link rel="match" href="svg-unknown-input-ref.html">
 <meta name="flags" content="svg">
 <meta name="assert" content="References to non-existent results on a first primitive must be treated like SourceGraphic.">
 <p>The test passes if you see a green square and no red.</p>
-<svg width="100" height="100">
+<svg width="200" height="200">
   <defs>
-    <filter id="f" x="0" y="0" width="100" height="100" filterUnits="userSpaceOnUse">
+    <filter id="f" x="10" y="10" width="100" height="100" filterUnits="userSpaceOnUse">
       <feComposite in="unknown" in2="SourceGraphic" result="a"/>
       <feFlood flood-color="green" result="b"/>
       <feComposite in="b" in2="a"/>
     </filter>
   </defs>
-  <rect width="100" height="100" fill="red"/>
-  <rect x="25" y="25" width="50" height="50" fill="green" filter="url(#f)"/>
+  <rect x="10" y="10" width="100" height="100" fill="red"/>
+  <rect x="35" y="35" width="50" height="50" fill="green" filter="url(#f)"/>
+  <rect x="10" y="10" width="100" height="100" fill="none" stroke="green" stroke-width="4"/>
 </svg>
--- a/testing/web-platform/tests/css/filter-effects/svg-unknown-input-002.html
+++ b/testing/web-platform/tests/css/filter-effects/svg-unknown-input-002.html
@@ -1,18 +1,19 @@
 <!DOCTYPE html>
 <title>Filter Effects: The in attribute</title>
 <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
 <link rel="help" href="https://www.w3.org/TR/filter-effects-1/#CommonAttributes">
 <link rel="match" href="svg-unknown-input-ref.html">
 <meta name="flags" content="svg">
 <meta name="assert" content="References to non-existent results on a subsequent primitive must be treated like the previous primitive result.">
 <p>The test passes if you see a green square and no red.</p>
-<svg width="100" height="100">
+<svg width="200" height="200">
   <defs>
-    <filter id="f" x="0" y="0" width="100" height="100" filterUnits="userSpaceOnUse">
+    <filter id="f" x="10" y="10" width="100" height="100" filterUnits="userSpaceOnUse">
       <feFlood flood-color="green"/>
       <feComposite in="unknown" in2="SourceGraphic"/>
     </filter>
   </defs>
-  <rect width="100" height="100" fill="red"/>
-  <rect x="25" y="25" width="50" height="50" fill="blue" filter="url(#f)"/>
+  <rect x="10" y="10" width="100" height="100" fill="red"/>
+  <rect x="35" y="35" width="50" height="50" fill="blue" filter="url(#f)"/>
+  <rect x="10" y="10" width="100" height="100" fill="none" stroke="green" stroke-width="4"/>
 </svg>
--- a/testing/web-platform/tests/css/filter-effects/svg-unknown-input-ref.html
+++ b/testing/web-platform/tests/css/filter-effects/svg-unknown-input-ref.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <title>Filter Effects: Reference</title>
 <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
 <meta name="flags" content="svg">
 <p>The test passes if you see a green square and no red.</p>
-<svg width="100" height="100">
-  <rect width="100" height="100" fill="green"/>
+<svg width="200" height="200">
+  <rect x="10" y="10" width="100" height="100" fill="green" stroke="green" stroke-width="4"/>
 </svg>
--- a/testing/web-platform/tests/wasm/jsapi/constructor/compile.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/constructor/compile.any.js
@@ -64,14 +64,18 @@ promise_test(t => {
   return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.compile(buffer));
 }, "Invalid code");
 
 promise_test(() => {
   return WebAssembly.compile(emptyModuleBinary).then(assert_Module);
 }, "Result type");
 
 promise_test(() => {
+  return WebAssembly.compile(emptyModuleBinary, {}).then(assert_Module);
+}, "Stray argument");
+
+promise_test(() => {
   const buffer = new WasmModuleBuilder().toBuffer();
   assert_equals(buffer[0], 0);
   const promise = WebAssembly.compile(buffer);
   buffer[0] = 1;
   return promise.then(assert_Module);
 }, "Changing the buffer");
--- a/testing/web-platform/tests/wasm/jsapi/constructor/instantiate.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/constructor/instantiate.any.js
@@ -1,12 +1,13 @@
 // META: global=jsshell
 // META: script=/wasm/jsapi/wasm-constants.js
 // META: script=/wasm/jsapi/wasm-module-builder.js
 // META: script=/wasm/jsapi/assertions.js
+// META: script=/wasm/jsapi/instanceTestFactory.js
 
 function assert_WebAssemblyInstantiatedSource(actual, expected_exports={}) {
   assert_equals(Object.getPrototypeOf(actual), Object.prototype,
                 "Prototype");
   assert_true(Object.isExtensible(actual), "Extensibility");
 
   const module = Object.getOwnPropertyDescriptor(actual, "module");
   assert_equals(typeof module, "object", "module: type of descriptor");
@@ -72,120 +73,34 @@ promise_test(t => {
 }, "Invalid arguments");
 
 test(() => {
   const promise = WebAssembly.instantiate(emptyModuleBinary);
   assert_equals(Object.getPrototypeOf(promise), Promise.prototype, "prototype");
   assert_true(Object.isExtensible(promise), "extensibility");
 }, "Promise type");
 
-const createModule = () => {
-  const builder = new WasmModuleBuilder();
-
-  builder
-    .addFunction("fn", kSig_v_d)
-    .addBody([
-        kExprEnd
-    ])
-    .exportFunc();
-  builder
-    .addFunction("fn2", kSig_v_v)
-    .addBody([
-        kExprEnd
-    ])
-    .exportFunc();
-
-  builder.setFunctionTableLength(1);
-  builder.addExportOfKind("table", kExternalTable, 0);
-
-  builder.addGlobal(kWasmI32, true)
-    .exportAs("global")
-    .init = 7;
-  builder.addGlobal(kWasmF64, true)
-    .exportAs("global2")
-    .init = 1.2;
-
-  builder.addMemory(4, 8, true);
-
-  const buffer = builder.toBuffer();
-
-  const exports = {
-    "fn": { "kind": "function", "name": "0", "length": 1 },
-    "fn2": { "kind": "function", "name": "1", "length": 0 },
-    "table": { "kind": "table", "length": 1 },
-    "global": { "kind": "global", "value": 7 },
-    "global2": { "kind": "global", "value": 1.2 },
-    "memory": { "kind": "memory", "size": 4 },
-  };
-
-  return [buffer, exports];
-}
-
-promise_test(() => {
-  const [buffer, expected] = createModule();
-  return WebAssembly.instantiate(buffer).then(result => assert_WebAssemblyInstantiatedSource(result, expected));
-}, "BufferSource argument");
+for (const [name, fn] of instanceTestFactory) {
+  promise_test(() => {
+    const { buffer, args, exports, verify } = fn();
+    return WebAssembly.instantiate(buffer, ...args).then(result => {
+      assert_WebAssemblyInstantiatedSource(result, exports);
+      verify(result.instance);
+    });
+  }, `${name}: BufferSource argument`);
 
-promise_test(() => {
-  const [buffer, expected] = createModule();
-  const module = new WebAssembly.Module(buffer);
-  return WebAssembly.instantiate(module).then(instance => assert_Instance(instance, expected));
-}, "Module argument");
-
-const createModuleWithImports = () => {
-  const builder = new WasmModuleBuilder();
-
-  const index = builder.addImportedGlobal("module", "global", kWasmI32);
-  builder
-    .addFunction("fn", kSig_i_v)
-    .addBody([
-        kExprGetGlobal,
-        index,
-        kExprReturn,
-        kExprEnd,
-    ])
-    .exportFunc();
-
-  const buffer = builder.toBuffer();
-
-  const expected = {
-    "fn": { "kind": "function", "name": "0", "length": 0 },
-  };
-
-  return [buffer, expected];
-};
-
-promise_test(() => {
-  const [buffer, expected] = createModuleWithImports();
-
-  const value = 102;
-  return WebAssembly.instantiate(buffer, {
-    "module": {
-      "global": value,
-    },
-  }).then(result => {
-    assert_WebAssemblyInstantiatedSource(result, expected)
-    assert_equals(result.instance.exports.fn(), value);
-  });
-}, "exports and imports: buffer argument");
-
-promise_test(() => {
-  const [buffer, expected] = createModuleWithImports();
-  const module = new WebAssembly.Module(buffer);
-
-  const value = 102;
-  return WebAssembly.instantiate(module, {
-    "module": {
-      "global": value,
-    },
-  }).then(instance => {
-    assert_Instance(instance, expected)
-    assert_equals(instance.exports.fn(), value);
-  });
-}, "exports and imports: Module argument");
+  promise_test(() => {
+    const { buffer, args, exports, verify } = fn();
+    const module = new WebAssembly.Module(buffer);
+    return WebAssembly.instantiate(module, ...args).then(instance => {
+      assert_Instance(instance, exports);
+      verify(instance);
+    });
+  }, `${name}: Module argument`);
+}
 
 promise_test(t => {
   const buffer = new Uint8Array();
   return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.instantiate(buffer));
 }, "Invalid code");
 
 promise_test(() => {
   const buffer = new WasmModuleBuilder().toBuffer();
--- a/testing/web-platform/tests/wasm/jsapi/constructor/validate.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/constructor/validate.any.js
@@ -89,8 +89,12 @@ for (const [module, expected] of modules
       test(() => {
         const bytes = new Uint8Array(module);
         const moduleBuffer = new bufferType(bytes.buffer);
         assert_equals(WebAssembly.validate(moduleBuffer), expected);
       }, `Validating module [${name}] in ${bufferType.name}`);
     }
   }
 }
+
+test(() => {
+  assert_true(WebAssembly.validate(emptyModuleBinary, {}));
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/global/constructor.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/global/constructor.any.js
@@ -114,8 +114,14 @@ for (const type of ["i32", "f32", "f64"]
   for (const [value, expected, name = format_value(value)] of valueArguments) {
     test(() => {
       const argument = { "value": type };
       const global = new WebAssembly.Global(argument, value);
       assert_Global(global, expected);
     }, `Explicit value ${name} for type ${type}`);
   }
 }
+
+test(() => {
+  const argument = { "value": "i32" };
+  const global = new WebAssembly.Global(argument, 0, {});
+  assert_Global(global, 0);
+}, "Stray argument");
rename from testing/web-platform/tests/wasm/jsapi/global/value-set.any.js
rename to testing/web-platform/tests/wasm/jsapi/global/value-get-set.any.js
--- a/testing/web-platform/tests/wasm/jsapi/global/value-set.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/global/value-get-set.any.js
@@ -87,8 +87,25 @@ test(() => {
   const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value");
   assert_equals(typeof desc, "object");
 
   const setter = desc.set;
   assert_equals(typeof setter, "function");
 
   assert_throws(new TypeError(), () => setter.call(global));
 }, "Calling setter without argument");
+
+test(() => {
+  const argument = { "value": "i32", "mutable": true };
+  const global = new WebAssembly.Global(argument);
+  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value");
+  assert_equals(typeof desc, "object");
+
+  const getter = desc.get;
+  assert_equals(typeof getter, "function");
+
+  const setter = desc.set;
+  assert_equals(typeof setter, "function");
+
+  assert_equals(getter.call(global, {}), 0);
+  assert_equals(setter.call(global, 1, {}), undefined);
+  assert_equals(global.value, 1);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/global/valueOf.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/global/valueOf.any.js
@@ -15,8 +15,14 @@ test(() => {
   ];
 
   const fn = WebAssembly.Global.prototype.valueOf;
 
   for (const thisValue of thisValues) {
     assert_throws(new TypeError(), () => fn.call(thisValue), `this=${format_value(thisValue)}`);
   }
 }, "Branding");
+
+test(() => {
+  const argument = { "value": "i32" };
+  const global = new WebAssembly.Global(argument, 0);
+  assert_equals(global.valueOf({}), 0);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/instance/constructor.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/instance/constructor.any.js
@@ -1,12 +1,13 @@
 // META: global=jsshell
 // META: script=/wasm/jsapi/wasm-constants.js
 // META: script=/wasm/jsapi/wasm-module-builder.js
 // META: script=/wasm/jsapi/assertions.js
+// META: script=/wasm/jsapi/instanceTestFactory.js
 
 let emptyModuleBinary;
 setup(() => {
   emptyModuleBinary = new WasmModuleBuilder().toBuffer();
 });
 
 test(() => {
   assert_function_name(WebAssembly.Instance, "Instance", "WebAssembly.Instance");
@@ -35,187 +36,20 @@ test(() => {
   for (const argument of invalidArguments) {
     assert_throws(new TypeError(), () => new WebAssembly.Instance(argument),
                   `new Instance(${format_value(argument)})`);
   }
 }, "Non-Module arguments");
 
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
-  const invalidArguments = [
-    null,
-    true,
-    "",
-    Symbol(),
-    1,
-  ];
-  for (const argument of invalidArguments) {
-    assert_throws(new TypeError(), () => new WebAssembly.Instance(module, argument),
-                  `new Instance(module, ${format_value(argument)})`);
-  }
-}, "Non-object imports");
-
-test(() => {
-  const module = new WebAssembly.Module(emptyModuleBinary);
   assert_throws(new TypeError(), () => WebAssembly.Instance(module));
 }, "Calling");
 
-test(() => {
-  const module = new WebAssembly.Module(emptyModuleBinary);
-  const arguments = [
-    [],
-    [undefined],
-    [{}],
-  ];
-  for (const value of arguments) {
-    const instance = new WebAssembly.Instance(module, ...arguments);
-    assert_Instance(instance, {});
-  }
-}, "Empty module");
-
-test(() => {
-  const builder = new WasmModuleBuilder();
-  builder.addImportedGlobal("module", "global1", kWasmI32);
-  builder.addImportedGlobal("module2", "global3", kWasmI32);
-  builder.addImportedMemory("module", "memory", 0, 128);
-  builder.addImportedGlobal("module", "global2", kWasmI32);
-  const buffer = builder.toBuffer();
-  const module = new WebAssembly.Module(buffer);
-  const order = [];
-  const imports = {
-    get module() {
-      order.push("module getter");
-      return {
-        get global1() {
-          order.push("global1 getter");
-          return 0;
-        },
-        get global2() {
-          order.push("global2 getter");
-          return 0;
-        },
-        get memory() {
-          order.push("memory getter");
-          return new WebAssembly.Memory({ "initial": 64, maximum: 128 });
-        },
-      }
-    },
-    get module2() {
-      order.push("module2 getter");
-      return {
-        get global3() {
-          order.push("global3 getter");
-          return 0;
-        },
-      }
-    },
-  };
-  new WebAssembly.Instance(module, imports);
-  const expected = [
-    "module getter",
-    "global1 getter",
-    "module2 getter",
-    "global3 getter",
-    "module getter",
-    "memory getter",
-    "module getter",
-    "global2 getter",
-  ];
-  assert_array_equals(order, expected);
-}, "getter order for imports object");
-
-test(() => {
-  const builder = new WasmModuleBuilder();
-
-  builder.addImport("module", "fn", kSig_v_v);
-  builder.addImportedGlobal("module", "global", kWasmI32);
-  builder.addImportedMemory("module", "memory", 0, 128);
-  builder.addImportedTable("module", "table", 0, 128);
-
-  const buffer = builder.toBuffer();
-  const module = new WebAssembly.Module(buffer);
-  const instance = new WebAssembly.Instance(module, {
-    "module": {
-      "fn": function() {},
-      "global": 0,
-      "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }),
-      "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }),
-    },
-    get "module2"() {
-      assert_unreached("Should not get modules that are not imported");
-    },
-  });
-  assert_Instance(instance, {});
-}, "imports");
-
-test(() => {
-  const builder = new WasmModuleBuilder();
-
-  builder
-    .addFunction("fn", kSig_v_d)
-    .addBody([
-        kExprEnd
-    ])
-    .exportFunc();
-  builder
-    .addFunction("fn2", kSig_v_v)
-    .addBody([
-        kExprEnd
-    ])
-    .exportFunc();
-
-  builder.setFunctionTableLength(1);
-  builder.addExportOfKind("table", kExternalTable, 0);
-
-  builder.addGlobal(kWasmI32, true)
-    .exportAs("global")
-    .init = 7;
-  builder.addGlobal(kWasmF64, true)
-    .exportAs("global2")
-    .init = 1.2;
-
-  builder.addMemory(4, 8, true);
-
-  const buffer = builder.toBuffer()
-  const module = new WebAssembly.Module(buffer);
-
-  const instance = new WebAssembly.Instance(module, {});
-  const expected = {
-    "fn": { "kind": "function", "name": "0", "length": 1 },
-    "fn2": { "kind": "function", "name": "1", "length": 0 },
-    "table": { "kind": "table", "length": 1 },
-    "global": { "kind": "global", "value": 7 },
-    "global2": { "kind": "global", "value": 1.2 },
-    "memory": { "kind": "memory", "size": 4 },
-  };
-  assert_Instance(instance, expected);
-}, "exports");
-
-test(() => {
-  const value = 102;
-
-  const builder = new WasmModuleBuilder();
-
-  builder.addImportedGlobal("module", "global", kWasmI32);
-  builder
-    .addFunction("fn", kSig_i_v)
-    .addBody([
-        kExprGetGlobal,
-        0,
-        kExprReturn,
-        kExprEnd,
-    ])
-    .exportFunc();
-
-  const buffer = builder.toBuffer();
-  const module = new WebAssembly.Module(buffer);
-  const instance = new WebAssembly.Instance(module, {
-    "module": {
-      "global": value,
-    },
-  });
-  const expected = {
-    "fn": { "kind": "function", "name": "0", "length": 0 },
-  };
-  assert_Instance(instance, expected);
-
-  assert_equals(instance.exports.fn(), value);
-}, "exports and imports");
+for (const [name, fn] of instanceTestFactory) {
+  test(() => {
+    const { buffer, args, exports, verify } = fn();
+    const module = new WebAssembly.Module(buffer);
+    const instance = new WebAssembly.Instance(module, ...args);
+    assert_Instance(instance, exports);
+    verify(instance);
+  }, name);
+}
--- a/testing/web-platform/tests/wasm/jsapi/instance/exports.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/instance/exports.any.js
@@ -32,16 +32,30 @@ test(() => {
     assert_throws(new TypeError(), () => getter.call(thisValue), `this=${format_value(thisValue)}`);
   }
 }, "Branding");
 
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   const instance = new WebAssembly.Instance(module);
   const exports = instance.exports;
+
+  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Instance.prototype, "exports");
+  assert_equals(typeof desc, "object");
+
+  const getter = desc.get;
+  assert_equals(typeof getter, "function");
+
+  assert_equals(getter.call(instance, {}), exports);
+}, "Stray argument");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const instance = new WebAssembly.Instance(module);
+  const exports = instance.exports;
   instance.exports = {};
   assert_equals(instance.exports, exports, "Should not change the exports");
 }, "Setting (sloppy mode)");
 
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   const instance = new WebAssembly.Instance(module);
   const exports = instance.exports;
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/wasm/jsapi/instanceTestFactory.js
@@ -0,0 +1,229 @@
+const instanceTestFactory = [
+  [
+    "Empty module without imports argument",
+    function() {
+      return {
+        buffer: emptyModuleBinary,
+        args: [],
+        exports: {},
+        verify: () => {},
+      };
+    }
+  ],
+
+  [
+    "Empty module with undefined imports argument",
+    function() {
+      return {
+        buffer: emptyModuleBinary,
+        args: [undefined],
+        exports: {},
+        verify: () => {},
+      };
+    }
+  ],
+
+  [
+    "Empty module with empty imports argument",
+    function() {
+      return {
+        buffer: emptyModuleBinary,
+        args: [{}],
+        exports: {},
+        verify: () => {},
+      };
+    }
+  ],
+
+  [
+    "getter order for imports object",
+    function() {
+      const builder = new WasmModuleBuilder();
+      builder.addImportedGlobal("module", "global1", kWasmI32);
+      builder.addImportedGlobal("module2", "global3", kWasmI32);
+      builder.addImportedMemory("module", "memory", 0, 128);
+      builder.addImportedGlobal("module", "global2", kWasmI32);
+      const buffer = builder.toBuffer();
+      const order = [];
+
+      const imports = {
+        get module() {
+          order.push("module getter");
+          return {
+            get global1() {
+              order.push("global1 getter");
+              return 0;
+            },
+            get global2() {
+              order.push("global2 getter");
+              return 0;
+            },
+            get memory() {
+              order.push("memory getter");
+              return new WebAssembly.Memory({ "initial": 64, maximum: 128 });
+            },
+          }
+        },
+        get module2() {
+          order.push("module2 getter");
+          return {
+            get global3() {
+              order.push("global3 getter");
+              return 0;
+            },
+          }
+        },
+      };
+
+      const expected = [
+        "module getter",
+        "global1 getter",
+        "module2 getter",
+        "global3 getter",
+        "module getter",
+        "memory getter",
+        "module getter",
+        "global2 getter",
+      ];
+      return {
+        buffer,
+        args: [imports],
+        exports: {},
+        verify: () => assert_array_equals(order, expected),
+      };
+    }
+  ],
+
+  [
+    "imports",
+    function() {
+      const builder = new WasmModuleBuilder();
+
+      builder.addImport("module", "fn", kSig_v_v);
+      builder.addImportedGlobal("module", "global", kWasmI32);
+      builder.addImportedMemory("module", "memory", 0, 128);
+      builder.addImportedTable("module", "table", 0, 128);
+
+      const buffer = builder.toBuffer();
+      const imports = {
+        "module": {
+          "fn": function() {},
+          "global": 0,
+          "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }),
+          "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }),
+        },
+        get "module2"() {
+          assert_unreached("Should not get modules that are not imported");
+        },
+      };
+
+      return {
+        buffer,
+        args: [imports],
+        exports: {},
+        verify: () => {},
+      };
+    }
+  ],
+
+  [
+    "No imports",
+    function() {
+      const builder = new WasmModuleBuilder();
+
+      builder
+        .addFunction("fn", kSig_v_d)
+        .addBody([
+            kExprEnd
+        ])
+        .exportFunc();
+      builder
+        .addFunction("fn2", kSig_v_v)
+        .addBody([
+            kExprEnd
+        ])
+        .exportFunc();
+
+      builder.setFunctionTableLength(1);
+      builder.addExportOfKind("table", kExternalTable, 0);
+
+      builder.addGlobal(kWasmI32, true)
+        .exportAs("global")
+        .init = 7;
+      builder.addGlobal(kWasmF64, true)
+        .exportAs("global2")
+        .init = 1.2;
+
+      builder.addMemory(4, 8, true);
+
+      const buffer = builder.toBuffer();
+
+      const exports = {
+        "fn": { "kind": "function", "name": "0", "length": 1 },
+        "fn2": { "kind": "function", "name": "1", "length": 0 },
+        "table": { "kind": "table", "length": 1 },
+        "global": { "kind": "global", "value": 7 },
+        "global2": { "kind": "global", "value": 1.2 },
+        "memory": { "kind": "memory", "size": 4 },
+      };
+
+      return {
+        buffer,
+        args: [],
+        exports,
+        verify: () => {},
+      };
+    }
+  ],
+
+  [
+    "exports and imports",
+    function() {
+      const value = 102;
+
+      const builder = new WasmModuleBuilder();
+
+      const index = builder.addImportedGlobal("module", "global", kWasmI32);
+      builder
+        .addFunction("fn", kSig_i_v)
+        .addBody([
+            kExprGetGlobal,
+            index,
+            kExprReturn,
+            kExprEnd,
+        ])
+        .exportFunc();
+
+      const buffer = builder.toBuffer();
+
+      const imports = {
+        "module": {
+          "global": value,
+        },
+      };
+
+      const exports = {
+        "fn": { "kind": "function", "name": "0", "length": 0 },
+      };
+
+      return {
+        buffer,
+        args: [imports],
+        exports,
+        verify: instance => assert_equals(instance.exports.fn(), value)
+      };
+    }
+  ],
+
+  [
+    "stray argument",
+    function() {
+      return {
+        buffer: emptyModuleBinary,
+        args: [{}, {}],
+        exports: {},
+        verify: () => {}
+      };
+    }
+  ],
+];
--- a/testing/web-platform/tests/wasm/jsapi/interface.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/interface.any.js
@@ -4,17 +4,17 @@
 function test_operations(object, object_name, operations) {
   for (const [name, length] of operations) {
     test(() => {
       const propdesc = Object.getOwnPropertyDescriptor(object, name);
       assert_equals(typeof propdesc, "object");
       assert_true(propdesc.writable, "writable");
       assert_true(propdesc.enumerable, "enumerable");
       assert_true(propdesc.configurable, "configurable");
-      assert_equals(propdesc.value, WebAssembly[name]);
+      assert_equals(propdesc.value, object[name]);
     }, `${object_name}.${name}`);
 
     test(() => {
       assert_function_name(object[name], name, `${object_name}.${name}`);
     }, `${object_name}.${name}: name`);
 
     test(() => {
       assert_function_length(object[name], length, `${object_name}.${name}`);
--- a/testing/web-platform/tests/wasm/jsapi/memory/buffer.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/memory/buffer.any.js
@@ -24,16 +24,30 @@ test(() => {
   for (const thisValue of thisValues) {
     assert_throws(new TypeError(), () => getter.call(thisValue), `this=${format_value(thisValue)}`);
   }
 }, "Branding");
 
 test(() => {
   const argument = { "initial": 0 };
   const memory = new WebAssembly.Memory(argument);
+  const buffer = memory.buffer;
+
+  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Memory.prototype, "buffer");
+  assert_equals(typeof desc, "object");
+
+  const getter = desc.get;
+  assert_equals(typeof getter, "function");
+
+  assert_equals(getter.call(memory, {}), buffer);
+}, "Stray argument");
+
+test(() => {
+  const argument = { "initial": 0 };
+  const memory = new WebAssembly.Memory(argument);
   const memory2 = new WebAssembly.Memory(argument);
   const buffer = memory.buffer;
   assert_not_equals(buffer, memory2.buffer, "Need two distinct buffers");
   memory.buffer = memory2.buffer;
   assert_equals(memory.buffer, buffer, "Should not change the buffer");
 }, "Setting (sloppy mode)");
 
 test(() => {
--- a/testing/web-platform/tests/wasm/jsapi/memory/constructor.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/memory/constructor.any.js
@@ -75,16 +75,20 @@ for (const value of outOfRangeValues) {
   }, `Out-of-range initial value in descriptor: ${format_value(value)}`);
 
   test(() => {
     assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": 0, "maximum": value }));
   }, `Out-of-range maximum value in descriptor: ${format_value(value)}`);
 }
 
 test(() => {
+  assert_throws(new RangeError(), () => new WebAssembly.Memory({ "element": "anyfunc", "initial": 10, "maximum": 9 }));
+}, "Initial value exceeds maximum");
+
+test(() => {
   const proxy = new Proxy({}, {
     has(o, x) {
       assert_unreached(`Should not call [[HasProperty]] with ${x}`);
     },
     get(o, x) {
       return 0;
     },
   });
@@ -130,8 +134,14 @@ test(() => {
   assert_Memory(memory, { "size": 0 });
 }, "Zero initial");
 
 test(() => {
   const argument = { "initial": 4 };
   const memory = new WebAssembly.Memory(argument);
   assert_Memory(memory, { "size": 4 });
 }, "Non-zero initial");
+
+test(() => {
+  const argument = { "initial": 0 };
+  const memory = new WebAssembly.Memory(argument, {});
+  assert_Memory(memory, { "size": 0 });
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/memory/grow.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/memory/grow.any.js
@@ -163,8 +163,23 @@ const outOfRangeValues = [
 
 for (const value of outOfRangeValues) {
   test(() => {
     const argument = { "initial": 0 };
     const memory = new WebAssembly.Memory(argument);
     assert_throws(new TypeError(), () => memory.grow(value));
   }, `Out-of-range argument: ${format_value(value)}`);
 }
+
+test(() => {
+  const argument = { "initial": 0 };
+  const memory = new WebAssembly.Memory(argument);
+  const oldMemory = memory.buffer;
+  assert_ArrayBuffer(oldMemory, { "size": 0 }, "Buffer before growing");
+
+  const result = memory.grow(2, {});
+  assert_equals(result, 0);
+
+  const newMemory = memory.buffer;
+  assert_not_equals(oldMemory, newMemory);
+  assert_ArrayBuffer(oldMemory, { "detached": true }, "Old buffer after growing");
+  assert_ArrayBuffer(newMemory, { "size": 2 }, "New buffer after growing");
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/module/constructor.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/module/constructor.any.js
@@ -53,8 +53,13 @@ test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype);
 }, "Prototype");
 
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   assert_true(Object.isExtensible(module));
 }, "Extensibility");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary, {});
+  assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/module/customSections.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/module/customSections.any.js
@@ -155,8 +155,13 @@ test(() => {
   assert_sections(WebAssembly.Module.customSections(module, "name"), []);
   assert_sections(WebAssembly.Module.customSections(module, "na\uFFFDme"), [
     bytes,
   ]);
   assert_sections(WebAssembly.Module.customSections(module, "na\uDC01me"), [
     bytes,
   ]);
 }, "Custom sections with U+FFFD");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_sections(WebAssembly.Module.customSections(module, "", {}), []);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/module/exports.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/module/exports.any.js
@@ -123,8 +123,14 @@ test(() => {
     { "kind": "function", "name": "fn2" },
     { "kind": "table", "name": "table" },
     { "kind": "global", "name": "global" },
     { "kind": "global", "name": "global2" },
     { "kind": "memory", "name": "memory" },
   ];
   assert_exports(exports, expected);
 }, "exports");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const exports = WebAssembly.Module.exports(module, {});
+  assert_exports(exports, []);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/module/imports.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/module/imports.any.js
@@ -113,8 +113,14 @@ test(() => {
   const expected = [
     { "module": "module", "kind": "function", "name": "fn" },
     { "module": "module", "kind": "global", "name": "global" },
     { "module": "module", "kind": "memory", "name": "memory" },
     { "module": "module", "kind": "table", "name": "table" },
   ];
   assert_imports(imports, expected);
 }, "imports");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const imports = WebAssembly.Module.imports(module, {});
+  assert_imports(imports, []);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/table/assertions.js
+++ b/testing/web-platform/tests/wasm/jsapi/table/assertions.js
@@ -1,11 +1,13 @@
 function assert_equal_to_array(table, expected, message) {
   assert_equals(table.length, expected.length, `${message}: length`);
-  assert_throws(new RangeError(), () => table.get(-1), `${message}: table.get(-1)`);
+  // The argument check in get() happens before the range check, and negative numbers
+  // are illegal, hence will throw TypeError per spec.
+  assert_throws(new TypeError(), () => table.get(-1), `${message}: table.get(-1)`);
   for (let i = 0; i < expected.length; ++i) {
     assert_equals(table.get(i), expected[i], `${message}: table.get(${i} of ${expected.length})`);
   }
   assert_throws(new RangeError(), () => table.get(expected.length),
                 `${message}: table.get(${expected.length} of ${expected.length})`);
   assert_throws(new RangeError(), () => table.get(expected.length + 1),
                 `${message}: table.get(${expected.length + 1} of ${expected.length})`);
 }
--- a/testing/web-platform/tests/wasm/jsapi/table/constructor.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/table/constructor.any.js
@@ -92,16 +92,22 @@ test(() => {
 
 test(() => {
   const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_Table(table, { "length": 5 });
 }, "Basic (non-zero)");
 
 test(() => {
+  const argument = { "element": "anyfunc", "initial": 0 };
+  const table = new WebAssembly.Table(argument, {});
+  assert_Table(table, { "length": 0 });
+}, "Stray argument");
+
+test(() => {
   const proxy = new Proxy({}, {
     has(o, x) {
       assert_unreached(`Should not call [[HasProperty]] with ${x}`);
     },
     get(o, x) {
       switch (x) {
       case "element":
         return "anyfunc";
--- a/testing/web-platform/tests/wasm/jsapi/table/get-set.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/table/get-set.any.js
@@ -126,17 +126,19 @@ test(() => {
 
 test(() => {
   const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null, null, null, null, null]);
 
   const {fn} = functions;
 
-  assert_throws(new RangeError(), () => table.set(-1, fn));
+  // -1 is the wrong type hence the type check on entry gets this
+  // before the range check does.
+  assert_throws(new TypeError(), () => table.set(-1, fn));
   assert_throws(new RangeError(), () => table.set(5, fn));
   assert_equal_to_array(table, [null, null, null, null, null]);
 }, "Setting out-of-bounds");
 
 test(() => {
   const argument = { "element": "anyfunc", "initial": 1 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null]);
@@ -213,8 +215,16 @@ test(() => {
       called++;
       return 0;
     },
   };
   assert_throws(new TypeError(), () => table.set(value, {}));
   assert_equals(called, 1);
 }, "Order of argument conversion");
 
+test(() => {
+  const {fn} = functions;
+  const argument = { "element": "anyfunc", "initial": 1 };
+  const table = new WebAssembly.Table(argument);
+
+  assert_equals(table.get(0, {}), null);
+  assert_equals(table.set(0, fn, {}), undefined);
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/table/grow.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/table/grow.any.js
@@ -79,8 +79,18 @@ const outOfRangeValues = [
 
 for (const value of outOfRangeValues) {
   test(() => {
     const argument = { "element": "anyfunc", "initial": 1 };
     const table = new WebAssembly.Table(argument);
     assert_throws(new TypeError(), () => table.grow(value));
   }, `Out-of-range argument: ${format_value(value)}`);
 }
+
+test(() => {
+  const argument = { "element": "anyfunc", "initial": 5 };
+  const table = new WebAssembly.Table(argument);
+  assert_equal_to_array(table, nulls(5), "before");
+
+  const result = table.grow(3, {});
+  assert_equals(result, 5);
+  assert_equal_to_array(table, nulls(8), "after");
+}, "Stray argument");
--- a/testing/web-platform/tests/wasm/jsapi/table/length.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/table/length.any.js
@@ -25,16 +25,30 @@ test(() => {
     assert_throws(new TypeError(), () => getter.call(thisValue), `this=${format_value(thisValue)}`);
   }
 }, "Branding");
 
 test(() => {
   const argument = { "element": "anyfunc", "initial": 2 };
   const table = new WebAssembly.Table(argument);
   assert_equals(table.length, 2, "Initial length");
+
+  const desc = Object.getOwnPropertyDescriptor(WebAssembly.Table.prototype, "length");
+  assert_equals(typeof desc, "object");
+
+  const getter = desc.get;
+  assert_equals(typeof getter, "function");
+
+  assert_equals(getter.call(table, {}), 2);
+}, "Stray argument");
+
+test(() => {
+  const argument = { "element": "anyfunc", "initial": 2 };
+  const table = new WebAssembly.Table(argument);
+  assert_equals(table.length, 2, "Initial length");
   table.length = 4;
   assert_equals(table.length, 2, "Should not change the length");
 }, "Setting (sloppy mode)");
 
 test(() => {
   const argument = { "element": "anyfunc", "initial": 2 };
   const table = new WebAssembly.Table(argument);
   assert_equals(table.length, 2, "Initial length");
deleted file mode 100644
--- a/testing/webdriver/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-/target
-/Cargo.lock
-*~
-*.swp
-*.swo
deleted file mode 100644
--- a/testing/webdriver/.hgignore
+++ /dev/null
@@ -1,2 +0,0 @@
-target/
-Cargo.lock
deleted file mode 100644
--- a/testing/webdriver/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: rust
-
-rust:
-    - nightly
-    - stable
-
-script:
-    - cargo build --verbose
-    - cargo test --verbose
\ No newline at end of file
--- a/toolkit/components/telemetry/app/TelemetryReportingPolicy.jsm
+++ b/toolkit/components/telemetry/app/TelemetryReportingPolicy.jsm
@@ -426,21 +426,18 @@ var TelemetryReportingPolicyImpl = {
     }
 
     let firstRunPolicyURL = Services.prefs.getStringPref(TelemetryUtils.Preferences.FirstRunURL, "");
     if (!firstRunPolicyURL) {
       return false;
     }
     firstRunPolicyURL = Services.urlFormatter.formatURL(firstRunPolicyURL);
 
-    let win;
-    try {
-      const { BrowserWindowTracker } = ChromeUtils.import("resource:///modules/BrowserWindowTracker.jsm", {});
-      win = BrowserWindowTracker.getTopWindow();
-    } catch (e) {}
+    const { BrowserWindowTracker } = ChromeUtils.import("resource:///modules/BrowserWindowTracker.jsm", {});
+    let win = BrowserWindowTracker.getTopWindow();
 
     if (!win) {
       this._log.info("Couldn't find browser window to open first-run page. Falling back to infobar.");
       return false;
     }
 
     // We'll consider the user notified once the privacy policy has been loaded
     // in a background tab even if that tab hasn't been selected.