Browse Source

More backports

Frank-Rainer Grahl 7 months ago
parent
commit
b9f0c64e4b
32 changed files with 8391 additions and 2138 deletions
  1. 5 5
      frg/work-js/mozilla-release/patches/1346211-2-63a1.patch
  2. 9 9
      frg/work-js/mozilla-release/patches/1346211-6-63a1.patch
  3. 0 0
      frg/work-js/mozilla-release/patches/1363214-62a1.patch
  4. 84 0
      frg/work-js/mozilla-release/patches/1398839-63a1.patch
  5. 0 0
      frg/work-js/mozilla-release/patches/1412200-63a1.patch
  6. 1951 0
      frg/work-js/mozilla-release/patches/1447591-1-63a1.patch
  7. 5521 0
      frg/work-js/mozilla-release/patches/1447591-2-63a1.patch
  8. 0 0
      frg/work-js/mozilla-release/patches/1450085-1-62a1.patch
  9. 0 0
      frg/work-js/mozilla-release/patches/1450085-2-62a1.patch
  10. 0 0
      frg/work-js/mozilla-release/patches/1450085-3-62a1.patch
  11. 0 0
      frg/work-js/mozilla-release/patches/1466626-2no1-63a1.patch
  12. 0 0
      frg/work-js/mozilla-release/patches/1466626-3-63a1.patch
  13. 0 0
      frg/work-js/mozilla-release/patches/1467142-62a1.patch
  14. 0 0
      frg/work-js/mozilla-release/patches/1467751-62a1.patch
  15. 0 0
      frg/work-js/mozilla-release/patches/1467752-62a1.patch
  16. 4 4
      frg/work-js/mozilla-release/patches/1471371-63a1.patch
  17. 204 0
      frg/work-js/mozilla-release/patches/1471841-63a1.patch
  18. 3 3
      frg/work-js/mozilla-release/patches/1471931-1-63a1.patch
  19. 9 8
      frg/work-js/mozilla-release/patches/1471931-4-63a1.patch
  20. 58 0
      frg/work-js/mozilla-release/patches/1473256-63a1.patch
  21. 6 6
      frg/work-js/mozilla-release/patches/1481097-5-64a1.patch
  22. 4 10
      frg/work-js/mozilla-release/patches/1489698-8-65a1.patch
  23. 333 0
      frg/work-js/mozilla-release/patches/1502886-1-65a1.patch
  24. 48 0
      frg/work-js/mozilla-release/patches/1502886-2-65a1.patch
  25. 30 0
      frg/work-js/mozilla-release/patches/NOBUG-20180629-testingfunctions-63a1.patch
  26. 82 0
      frg/work-js/mozilla-release/patches/NOBUG-JSFIXUPS-25319.patch
  27. 0 318
      frg/work-js/mozilla-release/patches/mozilla-central-push_422771.patch
  28. 0 1634
      frg/work-js/mozilla-release/patches/mozilla-central-push_422772.patch
  29. 0 46
      frg/work-js/mozilla-release/patches/mozilla-central-push_422918.patch
  30. 0 76
      frg/work-js/mozilla-release/patches/mozilla-central-push_422919.patch
  31. 21 16
      frg/work-js/mozilla-release/patches/series
  32. 19 3
      frg/work-js/mozilla-release/patches/series-test

+ 5 - 5
frg/work-js/mozilla-release/patches/1346211-2-63a1.patch

@@ -2,7 +2,7 @@
 # User Andre Bargull <andre.bargull@gmail.com>
 # Date 1534435998 25200
 # Node ID 62d58886e8d759f52c871a82dbe4d9c2a266c0c7
-# Parent  8e364fec49cc363a5810d1fa37c89f6c1e5265f0
+# Parent  e2ba39d047c4805799d435e3847f50de93aa0d98
 Bug 1346211 - Part 2: Split JS::ResetTimeZone into an external and internal implementation. r=Waldo
 
 diff --git a/js/public/Date.h b/js/public/Date.h
@@ -61,7 +61,7 @@ diff --git a/js/src/builtin/intl/DateTimeFormat.cpp b/js/src/builtin/intl/DateTi
 diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
 --- a/js/src/jsdate.cpp
 +++ b/js/src/jsdate.cpp
-@@ -3228,18 +3228,18 @@ DateMultipleArguments(JSContext* cx, con
+@@ -3227,18 +3227,18 @@ DateMultipleArguments(JSContext* cx, con
  
          // Steps 3q-t.
          return NewDateObject(cx, args, TimeClip(UTC(finalDate)));
@@ -399,9 +399,9 @@ diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp
  #include "gc/GC-inl.h"
  #include "gc/Marking-inl.h"
  #include "vm/JSAtom-inl.h"
-@@ -126,17 +127,17 @@ Realm::init(JSContext* cx)
-         return false;
- 
+@@ -123,17 +124,17 @@ bool
+ Realm::init(JSContext* cx)
+ {
      /*
       * As a hack, we clear our timezone cache every time we create a new realm.
       * This ensures that the cache is always relatively fresh, but shouldn't

+ 9 - 9
frg/work-js/mozilla-release/patches/1346211-6-63a1.patch

@@ -2,7 +2,7 @@
 # User Andre Bargull <andre.bargull@gmail.com>
 # Date 1534500279 25200
 # Node ID 7b1a3a49547dc9564aaa6ecf90b919b66b7ada8d
-# Parent  3007514b6576d01dadf0061fdd30be70fb8acf68
+# Parent  19aa3626d2f290e729d47cdff9750fadc7daec4c
 Bug 1346211 - Part 6: Use ICU for all time zone computations when available. r=Waldo
 
 diff --git a/browser/components/resistfingerprinting/test/browser/browser_timezone.js b/browser/components/resistfingerprinting/test/browser/browser_timezone.js
@@ -95,7 +95,7 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
  #if defined(XP_UNIX) && !defined(XP_DARWIN)
  #include <time.h>
  #else
-@@ -4983,16 +4985,95 @@ SetTimeZone(JSContext* cx, unsigned argc
+@@ -4980,16 +4982,95 @@ SetTimeZone(JSContext* cx, unsigned argc
  #endif /* _WIN32 */
  
      JS::ResetTimeZone();
@@ -191,7 +191,7 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
  
      uint32_t max_cnt;
      if (!ToUint32(cx, args.get(0), &max_cnt))
-@@ -5897,16 +5978,20 @@ gc::ZealModeHelpText),
+@@ -5894,16 +5975,20 @@ gc::ZealModeHelpText),
      JS_FN_HELP("isLegacyIterator", IsLegacyIterator, 1, 0,
  "isLegacyIterator(value)",
  "  Returns whether the value is considered is a legacy iterator.\n"),
@@ -212,7 +212,7 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
  "  running the jitcode rather than staying in the interpreter:\n"
  "    baselineCompile();  for (var i=0; i<1; i++) {} ...\n"
  "  The interpreter will enter the new jitcode at the loop header.\n"),
-@@ -5930,16 +6015,22 @@ static const JSFunctionSpecWithHelp Fuzz
+@@ -5927,16 +6012,22 @@ static const JSFunctionSpecWithHelp Fuzz
  "  Returns an array of error notes."),
  
      JS_FN_HELP("setTimeZone", SetTimeZone, 1, 0,
@@ -417,8 +417,8 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
      double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
      if (IsFinite(result))
          result = msFromTime(result);
-@@ -2628,16 +2679,51 @@ date_toJSON(JSContext* cx, unsigned argc
-                                           JSMSG_BAD_TOISOSTRING_PROP);
+@@ -2627,16 +2678,51 @@ date_toJSON(JSContext* cx, unsigned argc
+         JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr, JSMSG_BAD_TOISOSTRING_PROP);
          return false;
      }
  
@@ -469,7 +469,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
  
      PRMJTime prtm;
      prtm.tm_usec = int32_t(msFromTime(localTime)) * 1000;
-@@ -2696,16 +2782,17 @@ TimeZoneComment(JSContext* cx, double ut
+@@ -2695,16 +2781,17 @@ TimeZoneComment(JSContext* cx, double ut
              usetz = false;
  
          if (usetz)
@@ -487,7 +487,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
  };
  
  static bool
-@@ -2720,30 +2807,36 @@ FormatDate(JSContext* cx, double utcTime
+@@ -2719,30 +2806,36 @@ FormatDate(JSContext* cx, double utcTime
  
      double localTime = LocalTime(utcTime);
  
@@ -527,7 +527,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
      char buf[100];
      switch (format) {
        case FormatSpec::DateTime:
-@@ -3035,17 +3128,17 @@ static const JSFunctionSpec date_methods
+@@ -3034,17 +3127,17 @@ static const JSFunctionSpec date_methods
      JS_FN("getDate",             date_getDate,            0,0),
      JS_FN("getUTCDate",          date_getUTCDate,         0,0),
      JS_FN("getDay",              date_getDay,             0,0),

+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_421593.patch → frg/work-js/mozilla-release/patches/1363214-62a1.patch


+ 84 - 0
frg/work-js/mozilla-release/patches/1398839-63a1.patch

@@ -0,0 +1,84 @@
+# HG changeset patch
+# User Tom Schuster <evilpies@gmail.com>
+# Date 1529788847 -7200
+# Node ID 7c907970edec7e9891f3d82f121a3427e39c194e
+# Parent  a4262c0a50cadb84fb6140632383f82e5b77ec02
+Bug 1398839 - DataView getters should throw when the buffer is detached in release/beta. r=anba
+
+diff --git a/js/src/builtin/DataViewObject.cpp b/js/src/builtin/DataViewObject.cpp
+--- a/js/src/builtin/DataViewObject.cpp
++++ b/js/src/builtin/DataViewObject.cpp
+@@ -848,23 +848,21 @@ DataViewObject::bufferGetter(JSContext* 
+     return CallNonGenericMethod<is, bufferGetterImpl>(cx, args);
+ }
+ 
+ bool
+ DataViewObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
+ {
+     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+ 
+-#ifdef NIGHTLY_BUILD
+-    // Step 6,
++    // Step 6.
+     if (thisView->arrayBufferEither().isDetached()) {
+         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+         return false;
+     }
+-#endif
+ 
+     // Step 7.
+     args.rval().set(DataViewObject::byteLengthValue(thisView));
+     return true;
+ }
+ 
+ bool
+ DataViewObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+@@ -873,23 +871,21 @@ DataViewObject::byteLengthGetter(JSConte
+     return CallNonGenericMethod<is, byteLengthGetterImpl>(cx, args);
+ }
+ 
+ bool
+ DataViewObject::byteOffsetGetterImpl(JSContext* cx, const CallArgs& args)
+ {
+     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+ 
+-#ifdef NIGHTLY_BUILD
+-    // Step 6,
++    // Step 6.
+     if (thisView->arrayBufferEither().isDetached()) {
+         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+         return false;
+     }
+-#endif
+ 
+     // Step 7.
+     args.rval().set(DataViewObject::byteOffsetValue(thisView));
+     return true;
+ }
+ 
+ bool
+ DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp)
+diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list
+--- a/js/src/tests/jstests.list
++++ b/js/src/tests/jstests.list
+@@ -271,20 +271,16 @@ skip script test262/built-ins/TypedArray
+ skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/proto-from-ctor-realm.js
+ skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js
+ skip script test262/built-ins/WeakMap/proto-from-ctor-realm.js
+ skip script test262/built-ins/WeakSet/proto-from-ctor-realm.js
+ 
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
+ skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js
+ 
+-# https://bugzilla.mozilla.org/show_bug.cgi?id=1317394
+-skip-if(release_or_beta) script test262/built-ins/DataView/prototype/byteOffset/detached-buffer.js
+-skip-if(release_or_beta) script test262/built-ins/DataView/prototype/byteLength/detached-buffer.js
+-
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1317378
+ skip script test262/language/statements/do-while/cptn-abrupt-empty.js
+ skip script test262/language/statements/do-while/cptn-normal.js
+ skip script test262/language/statements/for-in/cptn-decl-abrupt-empty.js
+ skip script test262/language/statements/for-in/cptn-decl-itr.js
+ skip script test262/language/statements/for-in/cptn-decl-skip-itr.js
+ skip script test262/language/statements/for-in/cptn-decl-zero-itr.js
+ skip script test262/language/statements/for-in/cptn-expr-abrupt-empty.js

+ 0 - 0
frg/work-js/mozilla-release/patches/L-1412200-63a1.patch → frg/work-js/mozilla-release/patches/1412200-63a1.patch


+ 1951 - 0
frg/work-js/mozilla-release/patches/1447591-1-63a1.patch

@@ -0,0 +1,1951 @@
+# HG changeset patch
+# User Benjamin Bouvier <benj@benj.me>
+# Date 1529510179 -7200
+#      Wed Jun 20 17:56:19 2018 +0200
+# Node ID 38d2f921a918b7fd0269e269f48030798044438d
+# Parent  63b21854d8006576e83847cff297cc975ecb8b71
+Bug 1447591: Stub out a few Debugger APIs for wasm; r=yury
+
+diff --git a/devtools/server/actors/source.js b/devtools/server/actors/source.js
+--- a/devtools/server/actors/source.js
++++ b/devtools/server/actors/source.js
+@@ -787,18 +787,20 @@ const SourceActor = ActorClassWithSpec(s
+    * @returns A Promise that resolves to the given BreakpointActor.
+    */
+   _setBreakpoint: function(actor, noSliding) {
+     const { originalLocation } = actor;
+     const { originalLine, originalSourceActor } = originalLocation;
+ 
+     if (!this.isSourceMapped) {
+       const generatedLocation = GeneratedLocation.fromOriginalLocation(originalLocation);
++      const isWasm = this.source && this.source.introductionType === "wasm";
+       if (!this._setBreakpointAtGeneratedLocation(actor, generatedLocation) &&
+-          !noSliding) {
++          !noSliding &&
++          !isWasm) {
+         const query = { line: originalLine };
+         // For most cases, we have a real source to query for. The
+         // only time we don't is for HTML pages. In that case we want
+         // to query for scripts in an HTML page based on its URL, as
+         // there could be several sources within an HTML page.
+         if (this.source) {
+           query.source = this.source;
+         } else {
+diff --git a/devtools/server/tests/unit/test_frameactor_wasm-01.js b/devtools/server/tests/unit/test_frameactor_wasm-01.js
+--- a/devtools/server/tests/unit/test_frameactor_wasm-01.js
++++ b/devtools/server/tests/unit/test_frameactor_wasm-01.js
+@@ -21,17 +21,20 @@ function run_test() {
+   initTestDebuggerServer();
+   gDebuggee = addTestGlobal("test-stack");
+   gClient = new DebuggerClient(DebuggerServer.connectPipe());
+   gClient.connect().then(function() {
+     attachTestTabAndResume(
+       gClient, "test-stack",
+       function(response, tabClient, threadClient) {
+         gThreadClient = threadClient;
+-        gThreadClient.reconfigure({ observeAsmJS: true }, function(response) {
++        gThreadClient.reconfigure({
++          observeAsmJS: true,
++          wasmBinarySource: true
++        }, function(response) {
+           Assert.equal(!!response.error, false);
+           test_pause_frame();
+         });
+       });
+   });
+   do_test_pending();
+ }
+ 
+diff --git a/dom/base/test/test_postMessages.html b/dom/base/test/test_postMessages.html
+--- a/dom/base/test/test_postMessages.html
++++ b/dom/base/test/test_postMessages.html
+@@ -150,17 +150,17 @@ function create_wasmModule() {
+ 
+   ok(WebAssembly, "WebAssembly object should exist");
+   ok(WebAssembly.compile, "WebAssembly.compile function should exist");
+ 
+   const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary);
+   const fooModuleCode = wasmTextToBinary(`(module
+     (func $foo (result i32) (i32.const 42))
+     (export "foo" $foo)
+-  )`, 'new-format');
++  )`);
+ 
+   WebAssembly.compile(fooModuleCode).then((m) => {
+     ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled.");
+     clonableObjects.push({ target: 'sameProcess', data: m });
+     next();
+   }, () => {
+     ok(false, "The compilation of the wasmModule failed.");
+   });
+diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
+--- a/js/src/builtin/TestingFunctions.cpp
++++ b/js/src/builtin/TestingFunctions.cpp
+@@ -654,38 +654,66 @@ WasmTextToBinary(JSContext* cx, unsigned
+         ReportUsageErrorASCII(cx, callee, "First argument must be a String");
+         return false;
+     }
+ 
+     AutoStableStringChars twoByteChars(cx);
+     if (!twoByteChars.initTwoByte(cx, args[0].toString()))
+         return false;
+ 
++    bool withOffsets = false;
+     if (args.hasDefined(1)) {
+-        if (!args[1].isString()) {
+-            ReportUsageErrorASCII(cx, callee, "Second argument, if present, must be a String");
++        if (!args[1].isBoolean()) {
++            ReportUsageErrorASCII(cx, callee, "Second argument, if present, must be a boolean");
+             return false;
+         }
++        withOffsets = ToBoolean(args[1]);
+     }
+ 
+     uintptr_t stackLimit = GetNativeStackLimit(cx);
+ 
+     wasm::Bytes bytes;
+     UniqueChars error;
+-    if (!wasm::TextToBinary(twoByteChars.twoByteChars(), stackLimit, &bytes, &error)) {
++    wasm::Uint32Vector offsets;
++    if (!wasm::TextToBinary(twoByteChars.twoByteChars(), stackLimit, &bytes, &offsets, &error)) {
+         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
+                                   error.get() ? error.get() : "out of memory");
+         return false;
+     }
+ 
+-    RootedObject obj(cx, JS_NewUint8Array(cx, bytes.length()));
++    RootedObject binary(cx, JS_NewUint8Array(cx, bytes.length()));
++    if (!binary)
++        return false;
++
++    memcpy(binary->as<TypedArrayObject>().viewDataUnshared(), bytes.begin(), bytes.length());
++
++    if (!withOffsets) {
++        args.rval().setObject(*binary);
++        return true;
++    }
++
++    RootedObject obj(cx, JS_NewPlainObject(cx));
+     if (!obj)
+         return false;
+ 
+-    memcpy(obj->as<TypedArrayObject>().viewDataUnshared(), bytes.begin(), bytes.length());
++    constexpr unsigned propAttrs = JSPROP_ENUMERATE;
++    if (!JS_DefineProperty(cx, obj, "binary", binary, propAttrs))
++        return false;
++
++    RootedObject jsOffsets(cx, JS_NewArrayObject(cx, offsets.length()));
++    if (!jsOffsets)
++        return false;
++    for (size_t i = 0; i < offsets.length(); i++) {
++        uint32_t offset = offsets[i];
++        RootedValue offsetVal(cx, NumberValue(offset));
++        if (!JS_SetElement(cx, jsOffsets, i, offsetVal))
++            return false;
++    }
++    if (!JS_DefineProperty(cx, obj, "offsets", jsOffsets, propAttrs))
++        return false;
+ 
+     args.rval().setObject(*obj);
+     return true;
+ }
+ 
+ static bool
+ WasmBinaryToText(JSContext* cx, unsigned argc, Value* vp)
+ {
+diff --git a/js/src/jit-test/lib/wasm.js b/js/src/jit-test/lib/wasm.js
+--- a/js/src/jit-test/lib/wasm.js
++++ b/js/src/jit-test/lib/wasm.js
+@@ -111,43 +111,35 @@ function wasmAssert(src, assertions, may
+ function wasmFullPass(text, expected, maybeImports, ...args) {
+     let binary = wasmTextToBinary(text);
+     assertEq(WebAssembly.validate(binary), true, "Must validate.");
+ 
+     let module = new WebAssembly.Module(binary);
+     let instance = new WebAssembly.Instance(module, maybeImports);
+     assertEq(typeof instance.exports.run, 'function', "A 'run' function must be exported.");
+     assertEq(instance.exports.run(...args), expected, "Initial module must return the expected result.");
+-
+-    let retext = wasmBinaryToText(binary);
+-    let rebinary = wasmTextToBinary(retext);
+-
+-    assertEq(WebAssembly.validate(rebinary), true, "Recreated binary must validate.");
+-    let remodule = new WebAssembly.Module(rebinary);
+-    let reinstance = new WebAssembly.Instance(remodule, maybeImports);
+-    assertEq(reinstance.exports.run(...args), expected, "Reformed module must return the expected result");
+ }
+ 
+ // Ditto, but expects a function named '$run' instead of exported with this name.
+ function wasmFullPassI64(text, expected, maybeImports, ...args) {
+     let binary = wasmTextToBinary(text);
+     assertEq(WebAssembly.validate(binary), true, "Must validate.");
+ 
+     let augmentedSrc = _augmentSrc(text, [ { type: 'i64', func: '$run', args, expected } ]);
+     let augmentedBinary = wasmTextToBinary(augmentedSrc);
+     new WebAssembly.Instance(new WebAssembly.Module(augmentedBinary), maybeImports).exports.assert_0();
+-
+-    let retext = wasmBinaryToText(augmentedBinary);
+-    new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(retext)), maybeImports).exports.assert_0();
+ }
+ 
+ function wasmRunWithDebugger(wast, lib, init, done) {
+     let g = newGlobal('');
+     let dbg = new Debugger(g);
+ 
++    // Enable binary source mode.
++    dbg.allowWasmBinarySource = true;
++
+     g.eval(`
+ var wasm = wasmTextToBinary('${wast}');
+ var lib = ${lib || 'undefined'};
+ var m = new WebAssembly.Instance(new WebAssembly.Module(wasm), lib);`);
+ 
+     var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
+ 
+     init({dbg, wasmScript, g,});
+@@ -155,29 +147,16 @@ var m = new WebAssembly.Instance(new Web
+     try {
+         result = g.eval("m.exports.test()");
+     } catch (ex) {
+         error = ex;
+     }
+     done({dbg, result, error, wasmScript, g,});
+ }
+ 
+-function wasmGetScriptBreakpoints(wasmScript) {
+-    var result = [];
+-    var sourceText = wasmScript.source.text;
+-    sourceText.split('\n').forEach(function (line, i) {
+-        var lineOffsets = wasmScript.getLineOffsets(i + 1);
+-        if (lineOffsets.length === 0)
+-            return;
+-        assertEq(lineOffsets.length, 1);
+-        result.push({str: line.trim(), line: i + 1, offset: lineOffsets[0]});
+-    });
+-    return result;
+-}
+-
+ const WasmHelpers = {};
+ 
+ (function() {
+     let enabled = false;
+     try {
+         enableSingleStepProfiling();
+         disableSingleStepProfiling();
+         enabled = true;
+diff --git a/js/src/jit-test/tests/debug/wasm-05.js b/js/src/jit-test/tests/debug/wasm-05.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/wasm-05.js
++++ /dev/null
+@@ -1,115 +0,0 @@
+-// |jit-test| test-also-no-wasm-baseline
+-// Tests that wasm module scripts have text line to bytecode offset information
+-// when source text is generated.
+-
+-load(libdir + "asserts.js");
+-
+-if (!wasmDebuggingIsSupported())
+-     quit();
+-
+-// Checking if experimental format generates internal source map to binary file
+-// by querying debugger scripts getLineOffsets.
+-// (Notice that the source map will not be produced by wasmBinaryToText)
+-function getAllOffsets(wast) {
+-  var sandbox = newGlobal('');
+-  var dbg = new Debugger();
+-  dbg.addDebuggee(sandbox);
+-  sandbox.eval(`
+-    var wasm = wasmTextToBinary('${wast}');
+-    var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
+-  `);
+-  var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
+-  var lines = wasmScript.source.text.split('\n');
+-  return lines.map((l, n) => { return { str: l, offsets: wasmScript.getLineOffsets(n + 1) }; });
+-}
+-
+-var result1 = getAllOffsets('(module \
+-  (func (nop)) \
+-  (func (drop (f32.sqrt (f32.add (f32.const 1.0) (f32.const 2.0))))) \
+-)');
+-
+-var nopLine = result1.filter(i => i.str.indexOf('nop') >= 0);
+-assertEq(nopLine.length, 1);
+-// The nopLine shall have single offset.
+-assertEq(nopLine[0].offsets.length, 1);
+-assertEq(nopLine[0].offsets[0] > 0, true);
+-
+-var singleOffsetLines = result1.filter(i => i.offsets.length === 1);
+-// There shall be total 8 lines with single offset.
+-assertEq(singleOffsetLines.length, 8);
+-
+-// Checking if all reported offsets can be resolved back to the corresponding
+-// line number.
+-function checkOffsetLineNumberMapping(wast, offsetsExpected) {
+-    var sandbox = newGlobal('');
+-    var dbg = new Debugger();
+-    dbg.addDebuggee(sandbox);
+-    sandbox.eval(`
+-var wasm = wasmTextToBinary('${wast}');
+-var module = new WebAssembly.Module(wasm);
+-imports = {}
+-for (let descriptor of WebAssembly.Module.imports(module)) {
+-    imports[descriptor.module] = {}
+-    switch(descriptor.kind) {
+-        case "function": imports[descriptor.module][descriptor.name] = new Function(''); break;
+-    }
+-}
+-var instance = new WebAssembly.Instance(module, imports);
+-`);
+-    var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
+-    assertEq(wasmScript.startLine, 1);
+-    assertEq(wasmScript.lineCount >= 0, true);
+-    var lines = wasmScript.source.text.split('\n');
+-    var offsetsFound = 0;
+-    lines.forEach(function (l, n) {
+-        var offsets = wasmScript.getLineOffsets(n + 1);
+-        if (offsets.length < 1) return;
+-        assertEq(offsets.length, 1);
+-        assertEq(offsets[0] > 0, true);
+-        offsetsFound++;
+-        var loc = wasmScript.getOffsetLocation(offsets[0]);
+-        assertEq(loc instanceof Object, true);
+-        assertEq(loc.isEntryPoint, true);
+-        assertEq(loc.lineNumber, n + 1);
+-        assertEq(loc.columnNumber > 0, true);
+-    });
+-    assertEq(offsetsFound, offsetsExpected);
+-}
+-
+-checkOffsetLineNumberMapping('(module (func))', 1);
+-checkOffsetLineNumberMapping('(module (func (nop)))', 2);
+-checkOffsetLineNumberMapping('(module (import "a" "b"))', 0);
+-checkOffsetLineNumberMapping('(module \
+-  (func (nop)) \
+-  (func (drop (f32.sqrt (f32.add (f32.const 1.0) (f32.const 2.0))))) \
+-)', 8);
+-checkOffsetLineNumberMapping('(module \
+-  (func (local i32) i32.const 0 i32.const 1 set_local 0 get_local 0 call 0 i32.add nop drop) \
+-)', 9);
+-
+-// Checking that there are no offsets are present in a wasm instance script for
+-// which debug mode was not enabled.
+-function getWasmScriptAfterDebuggerAttached(wast) {
+-    var sandbox = newGlobal('');
+-    var dbg = new Debugger();
+-    sandbox.eval(`
+-        var wasm = wasmTextToBinary('${wast}');
+-        var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
+-    `);
+-    // Attaching after wasm instance is created.
+-    dbg.addDebuggee(sandbox);
+-    var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
+-    return wasmScript;
+-}
+-
+-var wasmScript1 = getWasmScriptAfterDebuggerAttached('(module (func (nop)))');
+-var wasmLines1 = wasmScript1.source.text.split('\n');
+-assertEq(wasmScript1.startLine, 1);
+-assertEq(wasmScript1.lineCount, 0);
+-assertEq(wasmLines1.every((l, n) => wasmScript1.getLineOffsets(n + 1).length == 0), true);
+-
+-// Checking that we must not resolve any location for any offset in a wasm
+-// instance which debug mode was not enabled.
+-var wasmScript2 = getWasmScriptAfterDebuggerAttached('(module (func (nop)))');
+-for (var i = wasmTextToBinary('(module (func (nop)))').length - 1; i >= 0; i--)
+-    assertThrowsInstanceOf(() => wasmScript2.getOffsetLocation(i), Error);
+diff --git a/js/src/jit-test/tests/debug/wasm-07.js b/js/src/jit-test/tests/debug/wasm-07.js
+--- a/js/src/jit-test/tests/debug/wasm-07.js
++++ b/js/src/jit-test/tests/debug/wasm-07.js
+@@ -10,30 +10,32 @@ if (!wasmDebuggingIsSupported())
+ 
+ var offsets;
+ wasmRunWithDebugger(
+     '(module (func (nop) (nop)) (export "test" 0))',
+     undefined,
+     function ({dbg}) {
+         offsets = [];
+         dbg.onEnterFrame = function (frame) {
+-            if (frame.type != 'wasmcall') return;
++            if (frame.type != 'wasmcall') {
++                return;
++            }
+             offsets.push(frame.offset);
+             frame.onStep = function () {
+                 offsets.push(frame.offset);
+             };
+             frame.onPop = function () {
+                 offsets.push(frame.offset);
+             };
+         };
+-  },
+-  function ({wasmScript, error}) {
+-      assertEq(error, undefined);
+-      assertEq(offsets.length, 5);
+-      offsets.forEach(offset => {
+-          var loc = wasmScript.getOffsetLocation(offset);
+-          assertEq(loc.isEntryPoint, true);
+-          assertEq(loc.lineNumber > 0, true);
+-          assertEq(loc.columnNumber > 0, true);
+-          assertEq(wasmScript.getLineOffsets(loc.lineNumber).length, 1);
+-      });
+-  }
++    },
++    function ({wasmScript, error}) {
++        assertEq(error, undefined);
++        assertEq(offsets.length, 5);
++        offsets.forEach(offset => {
++            var loc = wasmScript.getOffsetLocation(offset);
++            assertEq(loc.isEntryPoint, true);
++            assertEq(loc.lineNumber > 0, true);
++            assertEq(loc.columnNumber > 0, true);
++            assertEq(wasmScript.getLineOffsets(loc.lineNumber).length, 1);
++        });
++    }
+ );
+diff --git a/js/src/jit-test/tests/debug/wasm-binary-sources.js b/js/src/jit-test/tests/debug/wasm-binary-sources.js
+--- a/js/src/jit-test/tests/debug/wasm-binary-sources.js
++++ b/js/src/jit-test/tests/debug/wasm-binary-sources.js
+@@ -14,24 +14,24 @@ dbg.onNewScript = (script) => {
+   s = script;
+ }
+ 
+ g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);
+ assertEq(s.format, "wasm");
+ 
+ var source = s.source;
+ 
+-// The text is generated if wasm binary sources are disabled.
+-assertEq(source.text.includes('module'), true);
++// The text is never generated with the native Debugger API.
++assertEq(source.text.includes('module'), false);
+ assertThrowsInstanceOf(() => source.binary, Error);
+ 
+ // Enable binary sources.
+ dbg.allowWasmBinarySource = true;
+ 
+ g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);
+ assertEq(s.format, "wasm");
+ 
+ var source2 = s.source;
+ 
+-// The text is '[wasm]' if wasm binary sources are enabled.
++// The text is predefined if wasm binary sources are enabled.
+ assertEq(source2.text, '[wasm]');
+ // The binary contains Uint8Array which is equal to wasm bytecode;
+ arraysEqual(source2.binary, wasmTextToBinary('(module (func) (export "" 0))'));
+diff --git a/js/src/jit-test/tests/debug/wasm-breakpoint.js b/js/src/jit-test/tests/debug/wasm-breakpoint.js
+--- a/js/src/jit-test/tests/debug/wasm-breakpoint.js
++++ b/js/src/jit-test/tests/debug/wasm-breakpoint.js
+@@ -1,110 +1,135 @@
+ // |jit-test| test-also-no-wasm-baseline
+ // Tests that wasm module scripts handles basic breakpoint operations.
+ 
+ load(libdir + "wasm.js");
+ 
+ if (!wasmDebuggingIsSupported())
+     quit();
+ 
+-// Checking if we can stop at specified breakpoint.
++function runTest(wast, initFunc, doneFunc) {
++    let g = newGlobal('');
++    let dbg = new Debugger(g);
++
++    g.eval(`
++var { binary, offsets } = wasmTextToBinary('${wast}', /* offsets */ true);
++var m = new WebAssembly.Instance(new WebAssembly.Module(binary));`);
++
++    var { offsets } = g;
++
++    var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
++
++    initFunc({
++        dbg,
++        wasmScript,
++        g,
++        breakpoints: offsets
++    });
++
++    let result, error;
++    try {
++        result = g.eval("m.exports.test()");
++    } catch (ex) {
++        error = ex;
++    }
++
++    doneFunc({
++        dbg,
++        result,
++        error,
++        wasmScript,
++        g
++    });
++}
++
++
+ var onBreakpointCalled;
+-wasmRunWithDebugger(
++
++// Checking if we can stop at specified breakpoint.
++runTest(
+     '(module (func (nop) (nop)) (export "test" 0))',
+-    undefined,
+-    function ({wasmScript}) {
+-        var breakpoints = wasmGetScriptBreakpoints(wasmScript);
++    function ({wasmScript, breakpoints}) {
+         assertEq(breakpoints.length, 3);
+-        assertEq(breakpoints[0].offset > 0, true);
++        assertEq(breakpoints[0] > 0, true);
+         // Checking if breakpoints offsets are in ascending order.
+-        assertEq(breakpoints[0].offset < breakpoints[1].offset, true);
+-        assertEq(breakpoints[1].offset < breakpoints[2].offset, true);
++        assertEq(breakpoints[0] < breakpoints[1], true);
++        assertEq(breakpoints[1] < breakpoints[2], true);
+         onBreakpointCalled = 0;
+-        breakpoints.forEach(function (bp) {
+-            var offset = bp.offset;
++        breakpoints.forEach(function (offset) {
+             wasmScript.setBreakpoint(offset, {
+                 hit: (frame) => {
+                     assertEq(frame.offset, offset);
+                     onBreakpointCalled++;
+                 }
+             });
+         });
+     },
+     function ({dbg, error}) {
+         assertEq(error, undefined);
+         assertEq(onBreakpointCalled, 3);
+     }
+ );
+ 
+ // Checking if we can remove breakpoint one by one.
+-wasmRunWithDebugger(
++runTest(
+     '(module (func (nop) (nop)) (export "test" 0))',
+-    undefined,
+-    function ({wasmScript}) {
+-        var breakpoints = wasmGetScriptBreakpoints(wasmScript);
++    function ({wasmScript, breakpoints}) {
+         onBreakpointCalled = 0;
+         var handlers = [];
+-        breakpoints.forEach(function (bp, i) {
+-            var offset = bp.offset;
++        breakpoints.forEach(function (offset, i) {
+             wasmScript.setBreakpoint(offset, handlers[i] = {
+                 hit: (frame) => {
+-                    assertEq(frame.offset, breakpoints[0].offset);
++                    assertEq(frame.offset, breakpoints[0]);
+                     onBreakpointCalled++;
+                     // Removing all handlers.
+                     handlers.forEach(h => wasmScript.clearBreakpoint(h));
+                 }
+             });
+         });
+     },
+     function ({error}) {
+         assertEq(error, undefined);
+         assertEq(onBreakpointCalled, 1);
+     }
+ );
+ 
+ // Checking if we can remove breakpoint one by one from a breakpoint handler.
+-wasmRunWithDebugger(
++runTest(
+     '(module (func (nop) (nop)) (export "test" 0))',
+-    undefined,
+-    function ({wasmScript}) {
+-        var breakpoints = wasmGetScriptBreakpoints(wasmScript);
++    function ({wasmScript, breakpoints}) {
+         onBreakpointCalled = 0;
+         var handlers = [];
+-        breakpoints.forEach(function (bp, i) {
+-            var offset = bp.offset;
++        breakpoints.forEach(function (offset, i) {
+             wasmScript.setBreakpoint(offset, handlers[i] = {
+                 hit: (frame) => {
+-                    assertEq(frame.offset, breakpoints[0].offset);
++                    assertEq(frame.offset, breakpoints[0]);
+                     onBreakpointCalled++;
+                     // Removing all handlers.
+                     handlers.forEach(h => wasmScript.clearBreakpoint(h));
+                 }
+             });
+         });
+     },
+     function ({error}) {
+         assertEq(error, undefined);
+         assertEq(onBreakpointCalled, 1);
+     }
+ );
+ 
+ // Checking if we can remove breakpoint one by one from onEnterFrame,
+ // but onStep will still work.
+ var onStepCalled;
+-wasmRunWithDebugger(
++runTest(
+     '(module (func (nop) (nop)) (export "test" 0))',
+-    undefined,
+-    function ({dbg, wasmScript}) {
+-        var breakpoints = wasmGetScriptBreakpoints(wasmScript);
++    function ({dbg, wasmScript, breakpoints}) {
+         onBreakpointCalled = 0;
+         onStepCalled = [];
+         var handlers = [];
+-        breakpoints.forEach(function (bp, i) {
+-            var offset = bp.offset;
++        breakpoints.forEach(function (offset, i) {
+             wasmScript.setBreakpoint(offset, handlers[i] = {
+                 hit: (frame) => {
+                     assertEq(false, true);
+                     onBreakpointCalled++;
+                 }
+             });
+         });
+         dbg.onEnterFrame = function (frame) {
+@@ -120,49 +145,43 @@ wasmRunWithDebugger(
+     function ({error}) {
+         assertEq(error, undefined);
+         assertEq(onBreakpointCalled, 0);
+         assertEq(onStepCalled.length, 3);
+     }
+ );
+ 
+ // Checking if we can remove all breakpoints.
+-wasmRunWithDebugger(
++runTest(
+     '(module (func (nop) (nop)) (export "test" 0))',
+-    undefined,
+-    function ({wasmScript}) {
+-        var breakpoints = wasmGetScriptBreakpoints(wasmScript);
++    function ({wasmScript, breakpoints}) {
+         onBreakpointCalled = 0;
+-        breakpoints.forEach(function (bp, i) {
+-            var offset = bp.offset;
++        breakpoints.forEach(function (offset, i) {
+             wasmScript.setBreakpoint(offset, {
+                 hit: (frame) => {
+-                    assertEq(frame.offset, breakpoints[0].offset);
++                    assertEq(frame.offset, breakpoints[0]);
+                     onBreakpointCalled++;
+                     // Removing all handlers.
+                     wasmScript.clearAllBreakpoints();
+                 }
+             });
+         });
+     },
+     function ({error}) {
+         assertEq(error, undefined);
+         assertEq(onBreakpointCalled, 1);
+     }
+ );
+ 
+ // Checking if breakpoints are removed after debugger has been detached.
+-wasmRunWithDebugger(
++runTest(
+     '(module (func (nop) (nop)) (export "test" 0))',
+-    undefined,
+-    function ({dbg, wasmScript, g}) {
+-        var breakpoints = wasmGetScriptBreakpoints(wasmScript);
++    function ({dbg, wasmScript, g, breakpoints}) {
+         onBreakpointCalled = 0;
+-        breakpoints.forEach(function (bp, i) {
+-            var offset = bp.offset;
++        breakpoints.forEach(function (offset, i) {
+             wasmScript.setBreakpoint(offset, {
+                 hit: (frame) => {
+                     onBreakpointCalled++;
+                 }
+             });
+         });
+         dbg.onEnterFrame = function (frame) {
+             dbg.removeDebuggee(g);
+diff --git a/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js b/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
+--- a/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
++++ b/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
+@@ -1,40 +1,43 @@
+ // |jit-test| test-also-no-wasm-baseline
+ // Tests that wasm module scripts have column and line to bytecode offset
+ // information when source text is generated.
+ 
+ load(libdir + "asserts.js");
+ 
+ if (!wasmDebuggingIsSupported())
+-     quit();
++    quit();
+ 
+ // Checking if experimental format generates internal source map to binary file
+ // by querying debugger scripts getAllColumnOffsets.
+ // (Notice that the source map will not be produced by wasmBinaryToText)
+ function getAllOffsets(wast) {
+   var sandbox = newGlobal('');
+   var dbg = new Debugger();
+   dbg.addDebuggee(sandbox);
++  dbg.allowWasmBinarySource = true;
+   sandbox.eval(`
+     var wasm = wasmTextToBinary('${wast}');
+     var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
+   `);
+   var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
+   return wasmScript.getAllColumnOffsets();
+ }
+ 
+ var offsets1 = getAllOffsets('(module \
+   (func (nop)) \
+   (func (drop (f32.sqrt (f32.add (f32.const 1.0) (f32.const 2.0))))) \
+ )');
+ 
+ // There shall be total 8 lines with single and unique offset per line.
+-var usedOffsets = Object.create(null), usedLines = Object.create(null);
++var usedOffsets = Object.create(null),
++    usedLines = Object.create(null);
+ assertEq(offsets1.length, 8);
++
+ offsets1.forEach(({offset, lineNumber, columnNumber}) => {
+   assertEq(offset > 0, true);
+   assertEq(lineNumber > 0, true);
+   assertEq(columnNumber > 0, true);
+   usedOffsets[offset] = true;
+   usedLines[lineNumber] = true;
+ });
+ assertEq(Object.keys(usedOffsets).length, 8);
+diff --git a/js/src/wasm/WasmBinaryToText.cpp b/js/src/wasm/WasmBinaryToText.cpp
+--- a/js/src/wasm/WasmBinaryToText.cpp
++++ b/js/src/wasm/WasmBinaryToText.cpp
+@@ -35,26 +35,23 @@ using mozilla::IsInfinite;
+ using mozilla::IsNaN;
+ using mozilla::IsNegativeZero;
+ 
+ struct WasmRenderContext
+ {
+     JSContext* cx;
+     AstModule* module;
+     WasmPrintBuffer& buffer;
+-    GeneratedSourceMap* maybeSourceMap;
+     uint32_t indent;
+     uint32_t currentFuncIndex;
+ 
+-    WasmRenderContext(JSContext* cx, AstModule* module, WasmPrintBuffer& buffer,
+-                      GeneratedSourceMap* sourceMap)
++    WasmRenderContext(JSContext* cx, AstModule* module, WasmPrintBuffer& buffer)
+       : cx(cx),
+         module(module),
+         buffer(buffer),
+-        maybeSourceMap(sourceMap),
+         indent(0),
+         currentFuncIndex(0)
+     {}
+ 
+     StringBuffer& sb() { return buffer.stringBuffer(); }
+ };
+ 
+ /*****************************************************************************/
+@@ -245,54 +242,43 @@ RenderBlockNameAndSignature(WasmRenderCo
+     }
+ 
+     return true;
+ }
+ 
+ static bool
+ RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine = true);
+ 
+-#define MAP_AST_EXPR(c, expr)                                                         \
+-    if (c.maybeSourceMap) {                                                           \
+-        uint32_t lineno = c.buffer.lineno();                                          \
+-        uint32_t column = c.buffer.column();                                          \
+-        if (!c.maybeSourceMap->exprlocs().emplaceBack(lineno, column, expr.offset())) \
+-            return false;                                                             \
+-    }
+-
+ /*****************************************************************************/
+ // binary format parsing and rendering
+ 
+ static bool
+ RenderNop(WasmRenderContext& c, AstNop& nop)
+ {
+     if (!RenderIndent(c))
+         return false;
+-    MAP_AST_EXPR(c, nop);
+     return c.buffer.append("nop");
+ }
+ 
+ static bool
+ RenderDrop(WasmRenderContext& c, AstDrop& drop)
+ {
+     if (!RenderExpr(c, drop.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+-    MAP_AST_EXPR(c, drop);
+     return c.buffer.append("drop");
+ }
+ 
+ static bool
+ RenderUnreachable(WasmRenderContext& c, AstUnreachable& unreachable)
+ {
+     if (!RenderIndent(c))
+         return false;
+-    MAP_AST_EXPR(c, unreachable);
+     return c.buffer.append("unreachable");
+ }
+ 
+ static bool
+ RenderCallArgs(WasmRenderContext& c, const AstExprVector& args)
+ {
+     for (uint32_t i = 0; i < args.length(); i++) {
+         if (!RenderExpr(c, *args[i]))
+@@ -306,17 +292,16 @@ static bool
+ RenderCall(WasmRenderContext& c, AstCall& call)
+ {
+     if (!RenderCallArgs(c, call.args()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, call);
+     if (call.op() == Op::Call) {
+         if (!c.buffer.append("call "))
+             return false;
+     } else {
+         return Fail(c, "unexpected operator");
+     }
+ 
+     return RenderRef(c, call.func());
+@@ -329,29 +314,27 @@ RenderCallIndirect(WasmRenderContext& c,
+         return false;
+ 
+     if (!RenderExpr(c, *call.index()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, call);
+     if (!c.buffer.append("call_indirect "))
+         return false;
+     return RenderRef(c, call.funcType());
+ }
+ 
+ static bool
+ RenderConst(WasmRenderContext& c, AstConst& cst)
+ {
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, cst);
+     if (!RenderValType(c, cst.val().type()))
+         return false;
+     if (!c.buffer.append(".const "))
+         return false;
+ 
+     switch (ToExprType(cst.val().type())) {
+       case ExprType::I32:
+         return RenderInt32(c, (int32_t)cst.val().i32());
+@@ -369,74 +352,69 @@ RenderConst(WasmRenderContext& c, AstCon
+ }
+ 
+ static bool
+ RenderGetLocal(WasmRenderContext& c, AstGetLocal& gl)
+ {
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, gl);
+     if (!c.buffer.append("get_local "))
+         return false;
+     return RenderRef(c, gl.local());
+ }
+ 
+ static bool
+ RenderSetLocal(WasmRenderContext& c, AstSetLocal& sl)
+ {
+     if (!RenderExpr(c, sl.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, sl);
+     if (!c.buffer.append("set_local "))
+         return false;
+     return RenderRef(c, sl.local());
+ }
+ 
+ static bool
+ RenderTeeLocal(WasmRenderContext& c, AstTeeLocal& tl)
+ {
+     if (!RenderExpr(c, tl.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, tl);
+     if (!c.buffer.append("tee_local "))
+         return false;
+     return RenderRef(c, tl.local());
+ }
+ 
+ static bool
+ RenderGetGlobal(WasmRenderContext& c, AstGetGlobal& gg)
+ {
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, gg);
+     if (!c.buffer.append("get_global "))
+         return false;
+     return RenderRef(c, gg.global());
+ }
+ 
+ static bool
+ RenderSetGlobal(WasmRenderContext& c, AstSetGlobal& sg)
+ {
+     if (!RenderExpr(c, sg.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, sg);
+     if (!c.buffer.append("set_global "))
+         return false;
+     return RenderRef(c, sg.global());
+ }
+ 
+ static bool
+ RenderExprList(WasmRenderContext& c, const AstExprVector& exprs, uint32_t startAt = 0)
+ {
+@@ -448,17 +426,16 @@ RenderExprList(WasmRenderContext& c, con
+ }
+ 
+ static bool
+ RenderBlock(WasmRenderContext& c, AstBlock& block, bool isInline = false)
+ {
+     if (!isInline && !RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, block);
+     if (block.op() == Op::Block) {
+         if (!c.buffer.append("block"))
+             return false;
+     } else if (block.op() == Op::Loop) {
+         if (!c.buffer.append("loop"))
+             return false;
+     } else {
+         return Fail(c, "unexpected block kind");
+@@ -518,30 +495,28 @@ static bool
+ RenderGrowMemory(WasmRenderContext& c, AstGrowMemory& gm)
+ {
+     if (!RenderExpr(c, *gm.operand()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, gm);
+     return c.buffer.append("grow_memory\n");
+ }
+ 
+ static bool
+ RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& unary)
+ {
+     if (!RenderExpr(c, *unary.operand()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, unary);
+     const char* opStr;
+     switch (unary.op()) {
+       case Op::I32Eqz:     opStr = "i32.eqz"; break;
+       case Op::I32Clz:     opStr = "i32.clz"; break;
+       case Op::I32Ctz:     opStr = "i32.ctz"; break;
+       case Op::I32Popcnt:  opStr = "i32.popcnt"; break;
+       case Op::I64Clz:     opStr = "i64.clz"; break;
+       case Op::I64Ctz:     opStr = "i64.ctz"; break;
+@@ -572,17 +547,16 @@ RenderBinaryOperator(WasmRenderContext& 
+     if (!RenderExpr(c, *binary.lhs()))
+         return false;
+     if (!RenderExpr(c, *binary.rhs()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, binary);
+     const char* opStr;
+     switch (binary.op()) {
+       case Op::I32Add:      opStr = "i32.add"; break;
+       case Op::I32Sub:      opStr = "i32.sub"; break;
+       case Op::I32Mul:      opStr = "i32.mul"; break;
+       case Op::I32DivS:     opStr = "i32.div_s"; break;
+       case Op::I32DivU:     opStr = "i32.div_u"; break;
+       case Op::I32RemS:     opStr = "i32.rem_s"; break;
+@@ -638,17 +612,16 @@ RenderTernaryOperator(WasmRenderContext&
+     if (!RenderExpr(c, *ternary.op1()))
+         return false;
+     if (!RenderExpr(c, *ternary.op2()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, ternary);
+     const char* opStr;
+     switch (ternary.op()) {
+       case Op::Select: opStr = "select"; break;
+       default:           return Fail(c, "unexpected ternary operator");
+     }
+ 
+     return c.buffer.append(opStr, strlen(opStr));
+ }
+@@ -659,17 +632,16 @@ RenderComparisonOperator(WasmRenderConte
+     if (!RenderExpr(c, *comp.lhs()))
+         return false;
+     if (!RenderExpr(c, *comp.rhs()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, comp);
+     const char* opStr;
+     switch (comp.op()) {
+       case Op::I32Eq:  opStr = "i32.eq"; break;
+       case Op::I32Ne:  opStr = "i32.ne"; break;
+       case Op::I32LtS: opStr = "i32.lt_s"; break;
+       case Op::I32LtU: opStr = "i32.lt_u"; break;
+       case Op::I32LeS: opStr = "i32.le_s"; break;
+       case Op::I32LeU: opStr = "i32.le_u"; break;
+@@ -709,17 +681,16 @@ static bool
+ RenderConversionOperator(WasmRenderContext& c, AstConversionOperator& conv)
+ {
+     if (!RenderExpr(c, *conv.operand()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, conv);
+     const char* opStr;
+     switch (conv.op()) {
+       case Op::I32WrapI64:        opStr = "i32.wrap/i64"; break;
+       case Op::I32TruncSF32:      opStr = "i32.trunc_s/f32"; break;
+       case Op::I32TruncUF32:      opStr = "i32.trunc_u/f32"; break;
+       case Op::I32ReinterpretF32: opStr = "i32.reinterpret/f32"; break;
+       case Op::I32TruncSF64:      opStr = "i32.trunc_s/f64"; break;
+       case Op::I32TruncUF64:      opStr = "i32.trunc_u/f64"; break;
+@@ -759,17 +730,16 @@ static bool
+ RenderExtraConversionOperator(WasmRenderContext& c, AstExtraConversionOperator& conv)
+ {
+     if (!RenderExpr(c, *conv.operand()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, conv);
+     const char* opStr;
+     switch (conv.op()) {
+       case MiscOp::I32TruncSSatF32:   opStr = "i32.trunc_s:sat/f32"; break;
+       case MiscOp::I32TruncUSatF32:   opStr = "i32.trunc_u:sat/f32"; break;
+       case MiscOp::I32TruncSSatF64:   opStr = "i32.trunc_s:sat/f64"; break;
+       case MiscOp::I32TruncUSatF64:   opStr = "i32.trunc_u:sat/f64"; break;
+       case MiscOp::I64TruncSSatF32:   opStr = "i64.trunc_s:sat/f32"; break;
+       case MiscOp::I64TruncUSatF32:   opStr = "i64.trunc_u:sat/f32"; break;
+@@ -785,17 +755,16 @@ static bool
+ RenderIf(WasmRenderContext& c, AstIf& if_)
+ {
+     if (!RenderExpr(c, if_.cond()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, if_);
+     if (!c.buffer.append("if"))
+         return false;
+     if (!RenderBlockNameAndSignature(c, if_.name(), if_.type()))
+         return false;
+     if (!c.buffer.append('\n'))
+         return false;
+ 
+     c.indent++;
+@@ -853,17 +822,16 @@ static bool
+ RenderLoad(WasmRenderContext& c, AstLoad& load)
+ {
+     if (!RenderLoadStoreBase(c, load.address()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, load);
+     uint32_t defaultAlignLog2;
+     switch (load.op()) {
+       case Op::I32Load8S:
+         if (!c.buffer.append("i32.load8_s"))
+             return false;
+         defaultAlignLog2 = 0;
+         break;
+       case Op::I64Load8S:
+@@ -945,17 +913,16 @@ RenderStore(WasmRenderContext& c, AstSto
+         return false;
+ 
+     if (!RenderExpr(c, store.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, store);
+     uint32_t defaultAlignLog2;
+     switch (store.op()) {
+       case Op::I32Store8:
+         if (!c.buffer.append("i32.store8"))
+             return false;
+         defaultAlignLog2 = 0;
+         break;
+       case Op::I64Store8:
+@@ -1019,17 +986,16 @@ RenderBranch(WasmRenderContext& c, AstBr
+     if (branch.maybeValue()) {
+         if (!RenderExpr(c, *(branch.maybeValue())))
+             return false;
+     }
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, branch);
+     if (op == Op::BrIf ? !c.buffer.append("br_if ") : !c.buffer.append("br "))
+         return false;
+ 
+     return RenderRef(c, branch.target());
+ }
+ 
+ static bool
+ RenderBrTable(WasmRenderContext& c, AstBranchTable& table)
+@@ -1041,17 +1007,16 @@ RenderBrTable(WasmRenderContext& c, AstB
+ 
+     // Index
+     if (!RenderExpr(c, table.index()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, table);
+     if (!c.buffer.append("br_table "))
+         return false;
+ 
+     uint32_t tableLength = table.table().length();
+     for (uint32_t i = 0; i < tableLength; i++) {
+         if (!RenderRef(c, table.table()[i]))
+             return false;
+ 
+@@ -1068,17 +1033,16 @@ RenderReturn(WasmRenderContext& c, AstRe
+     if (ret.maybeExpr()) {
+         if (!RenderExpr(c, *(ret.maybeExpr())))
+             return false;
+     }
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, ret);
+     return c.buffer.append("return");
+ }
+ 
+ static bool
+ RenderAtomicCmpXchg(WasmRenderContext& c, AstAtomicCmpXchg& cmpxchg)
+ {
+     if (!RenderLoadStoreBase(c, cmpxchg.address()))
+         return false;
+@@ -1086,17 +1050,16 @@ RenderAtomicCmpXchg(WasmRenderContext& c
+     if (!RenderExpr(c, cmpxchg.expected()))
+         return false;
+     if (!RenderExpr(c, cmpxchg.replacement()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, cmpxchg);
+     const char* opname;
+     switch (cmpxchg.op()) {
+       case ThreadOp::I32AtomicCmpXchg8U:  opname = "i32.atomic.rmw8_u.cmpxchg"; break;
+       case ThreadOp::I64AtomicCmpXchg8U:  opname = "i64.atomic.rmw8_u.cmpxchg"; break;
+       case ThreadOp::I32AtomicCmpXchg16U: opname = "i32.atomic.rmw16_u.cmpxchg"; break;
+       case ThreadOp::I64AtomicCmpXchg16U: opname = "i64.atomic.rmw16_u.cmpxchg"; break;
+       case ThreadOp::I64AtomicCmpXchg32U: opname = "i64.atomic.rmw32_u.cmpxchg"; break;
+       case ThreadOp::I32AtomicCmpXchg:    opname = "i32.atomic.rmw.cmpxchg"; break;
+@@ -1114,17 +1077,16 @@ static bool
+ RenderAtomicLoad(WasmRenderContext& c, AstAtomicLoad& load)
+ {
+     if (!RenderLoadStoreBase(c, load.address()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, load);
+     const char* opname;
+     switch (load.op()) {
+       case ThreadOp::I32AtomicLoad8U:  opname = "i32.atomic.load8_u"; break;
+       case ThreadOp::I64AtomicLoad8U:  opname = "i64.atomic.load8_u"; break;
+       case ThreadOp::I32AtomicLoad16U: opname = "i32.atomic.load16_u"; break;
+       case ThreadOp::I64AtomicLoad16U: opname = "i64.atomic.load16_u"; break;
+       case ThreadOp::I64AtomicLoad32U: opname = "i64.atomic.load32_u"; break;
+       case ThreadOp::I32AtomicLoad:    opname = "i32.atomic.load"; break;
+@@ -1145,17 +1107,16 @@ RenderAtomicRMW(WasmRenderContext& c, As
+         return false;
+ 
+     if (!RenderExpr(c, rmw.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, rmw);
+     const char* opname;
+     switch (rmw.op()) {
+       case ThreadOp::I32AtomicAdd:     opname = "i32.atomic.rmw.add"; break;
+       case ThreadOp::I64AtomicAdd:     opname = "i64.atomic.rmw.add"; break;
+       case ThreadOp::I32AtomicAdd8U:   opname = "i32.atomic.rmw8_u.add"; break;
+       case ThreadOp::I32AtomicAdd16U:  opname = "i32.atomic.rmw16_u.add"; break;
+       case ThreadOp::I64AtomicAdd8U:   opname = "i64.atomic.rmw8_u.add"; break;
+       case ThreadOp::I64AtomicAdd16U:  opname = "i64.atomic.rmw16_u.add"; break;
+@@ -1211,17 +1172,16 @@ RenderAtomicStore(WasmRenderContext& c, 
+         return false;
+ 
+     if (!RenderExpr(c, store.value()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, store);
+     const char* opname;
+     switch (store.op()) {
+       case ThreadOp::I32AtomicStore8U:  opname = "i32.atomic.store8_u"; break;
+       case ThreadOp::I64AtomicStore8U:  opname = "i64.atomic.store8_u"; break;
+       case ThreadOp::I32AtomicStore16U: opname = "i32.atomic.store16_u"; break;
+       case ThreadOp::I64AtomicStore16U: opname = "i64.atomic.store16_u"; break;
+       case ThreadOp::I64AtomicStore32U: opname = "i64.atomic.store32_u"; break;
+       case ThreadOp::I32AtomicStore:    opname = "i32.atomic.store"; break;
+@@ -1245,17 +1205,16 @@ RenderWait(WasmRenderContext& c, AstWait
+         return false;
+ 
+     if (!RenderExpr(c, wait.timeout()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, wait);
+     const char* opname;
+     switch (wait.op()) {
+       case ThreadOp::I32Wait:  opname = "i32.atomic.wait"; break;
+       case ThreadOp::I64Wait:  opname = "i64.atomic.wait"; break;
+       default:           return Fail(c, "unexpected wait operator");
+     }
+ 
+     if (!c.buffer.append(opname, strlen(opname)))
+@@ -1291,17 +1250,16 @@ RenderMemCopy(WasmRenderContext& c, AstM
+     if (!RenderExpr(c, mc.src()))
+         return false;
+     if (!RenderExpr(c, mc.len()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, mc);
+     const char* opStr = "memory.copy";
+ 
+     return c.buffer.append(opStr, strlen(opStr));
+ }
+ 
+ static bool
+ RenderMemFill(WasmRenderContext& c, AstMemFill& mf)
+ {
+@@ -1310,17 +1268,16 @@ RenderMemFill(WasmRenderContext& c, AstM
+     if (!RenderExpr(c, mf.val()))
+         return false;
+     if (!RenderExpr(c, mf.len()))
+         return false;
+ 
+     if (!RenderIndent(c))
+         return false;
+ 
+-    MAP_AST_EXPR(c, mf);
+     const char* opStr = "memory.fill";
+ 
+     return c.buffer.append(opStr, strlen(opStr));
+ }
+ #endif
+ 
+ static bool
+ RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine /* = true */)
+@@ -1935,21 +1892,16 @@ RenderFunctionBody(WasmRenderContext& c,
+ 
+ 
+     uint32_t exprsNum = func.body().length();
+     for (uint32_t i = 0; i < exprsNum; i++) {
+         if (!RenderExpr(c, *func.body()[i]))
+             return false;
+     }
+ 
+-    if (c.maybeSourceMap) {
+-        if (!c.maybeSourceMap->exprlocs().emplaceBack(c.buffer.lineno(), c.buffer.column(), func.endOffset()))
+-            return false;
+-    }
+-
+     return true;
+ }
+ 
+ static bool
+ RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
+                   const AstModule::TypeDefVector& types)
+ {
+     uint32_t numFuncBodies = funcs.length();
+@@ -2105,33 +2057,30 @@ RenderModule(WasmRenderContext& c, AstMo
+     c.indent--;
+ 
+     if (!c.buffer.append(")"))
+         return false;
+ 
+     return true;
+ }
+ 
+-#undef MAP_AST_EXPR
+-
+ /*****************************************************************************/
+ // Top-level functions
+ 
+ bool
+-wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer,
+-                   GeneratedSourceMap* sourceMap /* = nullptr */)
++wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer)
+ {
+     LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
+ 
+     AstModule* module;
+     if (!BinaryToAst(cx, bytes, length, lifo, &module))
+         return false;
+ 
+     WasmPrintBuffer buf(buffer);
+-    WasmRenderContext c(cx, module, buf, sourceMap);
++    WasmRenderContext c(cx, module, buf);
+ 
+     if (!RenderModule(c, *module)) {
+         if (!cx->isExceptionPending())
+             ReportOutOfMemory(cx);
+         return false;
+     }
+ 
+     return true;
+diff --git a/js/src/wasm/WasmBinaryToText.h b/js/src/wasm/WasmBinaryToText.h
+--- a/js/src/wasm/WasmBinaryToText.h
++++ b/js/src/wasm/WasmBinaryToText.h
+@@ -30,16 +30,15 @@ namespace js {
+ class StringBuffer;
+ 
+ namespace wasm {
+ 
+ // Translate the given binary representation of a wasm module into the module's textual
+ // representation.
+ 
+ MOZ_MUST_USE bool
+-BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer,
+-             GeneratedSourceMap* sourceMap = nullptr);
++BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer);
+ 
+ }  // namespace wasm
+ 
+ }  // namespace js
+ 
+ #endif // namespace wasm_binary_to_text_h
+diff --git a/js/src/wasm/WasmDebug.cpp b/js/src/wasm/WasmDebug.cpp
+--- a/js/src/wasm/WasmDebug.cpp
++++ b/js/src/wasm/WasmDebug.cpp
+@@ -32,89 +32,36 @@
+ #include "wasm/WasmValidate.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ using namespace js::wasm;
+ 
+ using mozilla::BinarySearchIf;
+ 
+-bool
+-GeneratedSourceMap::searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex)
+-{
+-    MOZ_ASSERT(!exprlocs_.empty());
+-    size_t exprlocsLength = exprlocs_.length();
+-
+-    // Lazily build sorted array for fast log(n) lookup.
+-    if (!sortedByOffsetExprLocIndices_) {
+-        ExprLocIndexVector scratch;
+-        auto indices = MakeUnique<ExprLocIndexVector>();
+-        if (!indices || !indices->resize(exprlocsLength) || !scratch.resize(exprlocsLength)) {
+-            ReportOutOfMemory(cx);
+-            return false;
+-        }
+-        sortedByOffsetExprLocIndices_ = std::move(indices);
+-
+-        for (size_t i = 0; i < exprlocsLength; i++)
+-            (*sortedByOffsetExprLocIndices_)[i] = i;
+-
+-        auto compareExprLocViaIndex = [&](uint32_t i, uint32_t j, bool* lessOrEqualp) -> bool {
+-            *lessOrEqualp = exprlocs_[i].offset <= exprlocs_[j].offset;
+-            return true;
+-        };
+-        MOZ_ALWAYS_TRUE(MergeSort(sortedByOffsetExprLocIndices_->begin(), exprlocsLength,
+-                                  scratch.begin(), compareExprLocViaIndex));
+-    }
+-
+-    // Allowing non-exact search and if BinarySearchIf returns out-of-bound
+-    // index, moving the index to the last index.
+-    auto lookupFn = [&](uint32_t i) -> int {
+-        const ExprLoc& loc = exprlocs_[i];
+-        return offset == loc.offset ? 0 : offset < loc.offset ? -1 : 1;
+-    };
+-    size_t match;
+-    Unused << BinarySearchIf(sortedByOffsetExprLocIndices_->begin(), 0, exprlocsLength, lookupFn, &match);
+-    if (match >= exprlocsLength)
+-        match = exprlocsLength - 1;
+-    *exprlocIndex = (*sortedByOffsetExprLocIndices_)[match];
+-    return true;
+-}
+-
+-size_t
+-GeneratedSourceMap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+-{
+-    size_t size = exprlocs_.sizeOfExcludingThis(mallocSizeOf);
+-    if (sortedByOffsetExprLocIndices_)
+-        size += sortedByOffsetExprLocIndices_->sizeOfIncludingThis(mallocSizeOf);
+-    return size;
+-}
+-
+ DebugState::DebugState(SharedCode code,
+                        const ShareableBytes* maybeBytecode,
+                        bool binarySource)
+   : code_(std::move(code)),
+     maybeBytecode_(maybeBytecode),
+     binarySource_(binarySource),
+     enterAndLeaveFrameTrapsCounter_(0)
+ {
+     MOZ_ASSERT_IF(debugEnabled(), maybeBytecode);
+ }
+ 
+ const char enabledMessage[] =
+-    "Restart with developer tools open to view WebAssembly source";
++    "Restart with developer tools open to view WebAssembly source.";
+ 
+-const char tooBigMessage[] =
+-    "Unfortunately, this WebAssembly module is too big to view as text.\n"
+-    "We are working hard to remove this limitation.";
++const char noBinarySource[] =
++    "Configure the debugger to display WebAssembly bytecode.";
+ 
+ const char notGeneratedMessage[] =
+     "WebAssembly text generation was disabled.";
+ 
+-static const unsigned TooBig = 1000000;
+-
+ static const uint32_t DefaultBinarySourceColumnNumber = 1;
+ 
+ static const CallSite*
+ SlowCallSiteSearchByOffset(const MetadataTier& metadata, uint32_t offset)
+ {
+     for (const CallSite& callSite : metadata.callSites) {
+         if (callSite.lineOrBytecode() == offset && callSite.kind() == CallSiteDesc::Breakpoint)
+             return &callSite;
+@@ -124,188 +71,82 @@ SlowCallSiteSearchByOffset(const Metadat
+ 
+ JSString*
+ DebugState::createText(JSContext* cx)
+ {
+     StringBuffer buffer(cx);
+     if (!maybeBytecode_) {
+         if (!buffer.append(enabledMessage))
+             return nullptr;
+-
+-        MOZ_ASSERT(!maybeSourceMap_);
+     } else if (binarySource_) {
+         if (!buffer.append(notGeneratedMessage))
+             return nullptr;
+-        return buffer.finishString();
+-    } else if (maybeBytecode_->bytes.length() > TooBig) {
+-        if (!buffer.append(tooBigMessage))
+-            return nullptr;
+-
+-        MOZ_ASSERT(!maybeSourceMap_);
+     } else {
+-        const Bytes& bytes = maybeBytecode_->bytes;
+-        auto sourceMap = MakeUnique<GeneratedSourceMap>();
+-        if (!sourceMap) {
+-            ReportOutOfMemory(cx);
++        if (!buffer.append(noBinarySource))
+             return nullptr;
+-        }
+-        maybeSourceMap_ = std::move(sourceMap);
+-
+-        if (!BinaryToText(cx, bytes.begin(), bytes.length(), buffer, maybeSourceMap_.get()))
+-            return nullptr;
+-
+-#if DEBUG
+-        // Check that expression locations are sorted by line number.
+-        uint32_t lastLineno = 0;
+-        for (const ExprLoc& loc : maybeSourceMap_->exprlocs()) {
+-            MOZ_ASSERT(lastLineno <= loc.lineno);
+-            lastLineno = loc.lineno;
+-        }
+-#endif
+     }
+-
+     return buffer.finishString();
+ }
+ 
+ bool
+-DebugState::ensureSourceMap(JSContext* cx)
+-{
+-    if (maybeSourceMap_ || !maybeBytecode_)
+-        return true;
+-
+-    // We just need to cache maybeSourceMap_, ignoring the text result.
+-    return createText(cx);
+-}
+-
+-struct LineComparator
+-{
+-    const uint32_t lineno;
+-    explicit LineComparator(uint32_t lineno) : lineno(lineno) {}
+-
+-    int operator()(const ExprLoc& loc) const {
+-        return lineno == loc.lineno ? 0 : lineno < loc.lineno ? -1 : 1;
+-    }
+-};
+-
+-bool
+ DebugState::getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets)
+ {
+     if (!debugEnabled())
+         return true;
+-
+-    if (binarySource_) {
+-        const CallSite* callsite = SlowCallSiteSearchByOffset(metadata(Tier::Debug), lineno);
+-        if (callsite && !offsets->append(lineno))
+-            return false;
++    if (!binarySource_)
+         return true;
+-    }
+-
+-    if (!ensureSourceMap(cx))
++    const CallSite* callsite = SlowCallSiteSearchByOffset(metadata(Tier::Debug), lineno);
++    if (callsite && !offsets->append(lineno))
+         return false;
+-
+-    if (!maybeSourceMap_)
+-        return true; // no source text available, keep offsets empty.
+-
+-    ExprLocVector& exprlocs = maybeSourceMap_->exprlocs();
+-
+-    // Binary search for the expression with the specified line number and
+-    // rewind to the first expression, if more than one expression on the same line.
+-    size_t match;
+-    if (!BinarySearchIf(exprlocs, 0, exprlocs.length(), LineComparator(lineno), &match))
+-        return true;
+-
+-    while (match > 0 && exprlocs[match - 1].lineno == lineno)
+-        match--;
+-
+-    // Return all expression offsets that were printed on the specified line.
+-    for (size_t i = match; i < exprlocs.length() && exprlocs[i].lineno == lineno; i++) {
+-        if (!offsets->append(exprlocs[i].offset))
+-            return false;
+-    }
+-
+     return true;
+ }
+ 
+ bool
+ DebugState::getAllColumnOffsets(JSContext* cx, Vector<ExprLoc>* offsets)
+ {
+     if (!metadata().debugEnabled)
+         return true;
+-
+-    if (binarySource_) {
+-        for (const CallSite& callSite : metadata(Tier::Debug).callSites) {
+-            if (callSite.kind() != CallSite::Breakpoint)
+-                continue;
+-            uint32_t offset = callSite.lineOrBytecode();
+-            if (!offsets->emplaceBack(offset, DefaultBinarySourceColumnNumber, offset))
+-                return false;
+-        }
++    if (!binarySource_)
+         return true;
++    for (const CallSite& callSite : metadata(Tier::Debug).callSites) {
++        if (callSite.kind() != CallSite::Breakpoint)
++            continue;
++        uint32_t offset = callSite.lineOrBytecode();
++        if (!offsets->emplaceBack(offset, DefaultBinarySourceColumnNumber, offset))
++            return false;
+     }
+-
+-    if (!ensureSourceMap(cx))
+-        return false;
+-
+-    if (!maybeSourceMap_)
+-        return true; // no source text available, keep offsets empty.
+-
+-    return offsets->appendAll(maybeSourceMap_->exprlocs());
++    return true;
+ }
+ 
+ bool
+ DebugState::getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column)
+ {
+     *found = false;
+     if (!debugEnabled())
+         return true;
+-
+-    if (binarySource_) {
+-        if (!SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset))
+-            return true; // offset was not found
+-        *found = true;
+-        *lineno = offset;
+-        *column = DefaultBinarySourceColumnNumber;
++    if (!binarySource_)
+         return true;
+-    }
+-
+-    if (!ensureSourceMap(cx))
+-        return false;
+-
+-    if (!maybeSourceMap_ || maybeSourceMap_->exprlocs().empty())
+-        return true; // no source text available
+-
+-    size_t foundAt;
+-    if (!maybeSourceMap_->searchLineByOffset(cx, offset, &foundAt))
+-        return false;
+-
+-    const ExprLoc& loc = maybeSourceMap_->exprlocs()[foundAt];
++    if (!SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset))
++        return true; // offset was not found
+     *found = true;
+-    *lineno = loc.lineno;
+-    *column = loc.column;
++    *lineno = offset;
++    *column = DefaultBinarySourceColumnNumber;
+     return true;
+ }
+ 
+ bool
+ DebugState::totalSourceLines(JSContext* cx, uint32_t* count)
+ {
+     *count = 0;
+     if (!debugEnabled())
+         return true;
+-
+-    if (binarySource_) {
+-        if (maybeBytecode_)
+-            *count = maybeBytecode_->length();
++    if (!binarySource_)
+         return true;
+-    }
+-
+-    if (!ensureSourceMap(cx))
+-        return false;
+-
+-    if (maybeSourceMap_)
+-        *count = maybeSourceMap_->totalLines();
++    if (maybeBytecode_)
++        *count = maybeBytecode_->length();
+     return true;
+ }
+ 
+ bool
+ DebugState::stepModeEnabled(uint32_t funcIndex) const
+ {
+     return stepModeCounters_.initialized() && stepModeCounters_.lookup(funcIndex);
+ }
+@@ -703,13 +544,11 @@ void
+ DebugState::addSizeOfMisc(MallocSizeOf mallocSizeOf,
+                           Metadata::SeenSet* seenMetadata,
+                           ShareableBytes::SeenSet* seenBytes,
+                           Code::SeenSet* seenCode,
+                           size_t* code,
+                           size_t* data) const
+ {
+     code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
+-    if (maybeSourceMap_)
+-        *data += maybeSourceMap_->sizeOfExcludingThis(mallocSizeOf);
+     if (maybeBytecode_)
+         *data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
+ }
+diff --git a/js/src/wasm/WasmDebug.h b/js/src/wasm/WasmDebug.h
+--- a/js/src/wasm/WasmDebug.h
++++ b/js/src/wasm/WasmDebug.h
+@@ -29,88 +29,58 @@ class Debugger;
+ class WasmBreakpoint;
+ class WasmBreakpointSite;
+ class WasmInstanceObject;
+ 
+ namespace wasm {
+ 
+ struct MetadataTier;
+ 
+-// The generated source location for the AST node/expression. The offset field refers
+-// an offset in an binary format file.
++// The generated source location for the AST node/expression. The offset field
++// refers an offset in an binary format file.
+ 
+ struct ExprLoc
+ {
+     uint32_t lineno;
+     uint32_t column;
+     uint32_t offset;
+     ExprLoc() : lineno(0), column(0), offset(0) {}
+     ExprLoc(uint32_t lineno_, uint32_t column_, uint32_t offset_)
+       : lineno(lineno_), column(column_), offset(offset_)
+     {}
+ };
+ 
+-typedef Vector<ExprLoc, 0, SystemAllocPolicy> ExprLocVector;
+-typedef Vector<uint32_t, 0, SystemAllocPolicy> ExprLocIndexVector;
+-
+-// The generated source map for WebAssembly binary file. This map is generated during
+-// building the text buffer (see BinaryToExperimentalText).
+-
+-class GeneratedSourceMap
+-{
+-    ExprLocVector exprlocs_;
+-    UniquePtr<ExprLocIndexVector> sortedByOffsetExprLocIndices_;
+-    uint32_t totalLines_;
+-
+-  public:
+-    explicit GeneratedSourceMap() : totalLines_(0) {}
+-    ExprLocVector& exprlocs() { return exprlocs_; }
+-
+-    uint32_t totalLines() { return totalLines_; }
+-    void setTotalLines(uint32_t val) { totalLines_ = val; }
+-
+-    bool searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex);
+-
+-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+-};
+-
+-typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap;
+ typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> StepModeCounters;
+-typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, SystemAllocPolicy> WasmBreakpointSiteMap;
++typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, SystemAllocPolicy>
++    WasmBreakpointSiteMap;
+ 
+ class DebugState
+ {
+     const SharedCode         code_;
+     const SharedBytes        maybeBytecode_;
+-    UniqueGeneratedSourceMap maybeSourceMap_;
+     bool                     binarySource_;
+ 
+     // State maintained when debugging is enabled. In this case, the Code is
+     // not actually shared, but is referenced uniquely by the instance that is
+     // being debugged.
+ 
+     uint32_t                 enterAndLeaveFrameTrapsCounter_;
+     WasmBreakpointSiteMap    breakpointSites_;
+     StepModeCounters         stepModeCounters_;
+ 
+     void toggleDebugTrap(uint32_t offset, bool enabled);
+-    bool ensureSourceMap(JSContext* cx);
+ 
+   public:
+     DebugState(SharedCode code,
+                const ShareableBytes* maybeBytecode,
+                bool binarySource);
+ 
+     const Bytes* maybeBytecode() const { return maybeBytecode_ ? &maybeBytecode_->bytes : nullptr; }
+     bool binarySource() const { return binarySource_; }
+ 
+-    // If the source bytecode was saved when this Code was constructed, this
+-    // method will render the binary as text. Otherwise, a diagnostic string
+-    // will be returned.
+-
+     JSString* createText(JSContext* cx);
+     bool getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets);
+     bool getAllColumnOffsets(JSContext* cx, Vector<ExprLoc>* offsets);
+     bool getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column);
+     bool totalSourceLines(JSContext* cx, uint32_t* count);
+ 
+     // The Code can track enter/leave frame events. Any such event triggers
+     // debug trap. The enter/leave frame events enabled or disabled across
+diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp
+--- a/js/src/wasm/WasmTextToBinary.cpp
++++ b/js/src/wasm/WasmTextToBinary.cpp
+@@ -5539,35 +5539,39 @@ EncodeTableSection(Encoder& e, AstModule
+             return false;
+     }
+ 
+     e.finishSection(offset);
+     return true;
+ }
+ 
+ static bool
+-EncodeFunctionBody(Encoder& e, AstFunc& func)
++EncodeFunctionBody(Encoder& e, Uint32Vector* offsets, AstFunc& func)
+ {
+     size_t bodySizeAt;
+     if (!e.writePatchableVarU32(&bodySizeAt))
+         return false;
+ 
+     size_t beforeBody = e.currentOffset();
+ 
+     ValTypeVector varTypes;
+     if (!varTypes.appendAll(func.vars()))
+         return false;
+     if (!EncodeLocalEntries(e, varTypes))
+         return false;
+ 
+     for (AstExpr* expr : func.body()) {
++        if (!offsets->append(e.currentOffset()))
++            return false;
+         if (!EncodeExpr(e, *expr))
+             return false;
+     }
+ 
++    if (!offsets->append(e.currentOffset()))
++        return false;
+     if (!e.writeOp(Op::End))
+         return false;
+ 
+     e.patchVarU32(bodySizeAt, e.currentOffset() - beforeBody);
+     return true;
+ }
+ 
+ static bool
+@@ -5583,30 +5587,30 @@ EncodeStartSection(Encoder& e, AstModule
+     if (!e.writeVarU32(module.startFunc().func().index()))
+         return false;
+ 
+     e.finishSection(offset);
+     return true;
+ }
+ 
+ static bool
+-EncodeCodeSection(Encoder& e, AstModule& module)
++EncodeCodeSection(Encoder& e, Uint32Vector* offsets, AstModule& module)
+ {
+     if (module.funcs().empty())
+         return true;
+ 
+     size_t offset;
+     if (!e.startSection(SectionId::Code, &offset))
+         return false;
+ 
+     if (!e.writeVarU32(module.funcs().length()))
+         return false;
+ 
+     for (AstFunc* func : module.funcs()) {
+-        if (!EncodeFunctionBody(e, *func))
++        if (!EncodeFunctionBody(e, offsets, *func))
+             return false;
+     }
+ 
+     e.finishSection(offset);
+     return true;
+ }
+ 
+ static bool
+@@ -5703,17 +5707,17 @@ EncodeElemSection(Encoder& e, AstModule&
+             return false;
+     }
+ 
+     e.finishSection(offset);
+     return true;
+ }
+ 
+ static bool
+-EncodeModule(AstModule& module, Bytes* bytes)
++EncodeModule(AstModule& module, Uint32Vector* offsets, Bytes* bytes)
+ {
+     Encoder e(*bytes);
+ 
+     if (!e.writeFixedU32(MagicNumber))
+         return false;
+ 
+     if (!e.writeFixedU32(EncodingVersion))
+         return false;
+@@ -5740,17 +5744,17 @@ EncodeModule(AstModule& module, Bytes* b
+         return false;
+ 
+     if (!EncodeStartSection(e, module))
+         return false;
+ 
+     if (!EncodeElemSection(e, module))
+         return false;
+ 
+-    if (!EncodeCodeSection(e, module))
++    if (!EncodeCodeSection(e, offsets, module))
+         return false;
+ 
+     if (!EncodeDataSection(e, module))
+         return false;
+ 
+     return true;
+ }
+ 
+@@ -5774,25 +5778,26 @@ EncodeBinaryModule(const AstModule& modu
+     }
+ 
+     return true;
+ }
+ 
+ /*****************************************************************************/
+ 
+ bool
+-wasm::TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, UniqueChars* error)
++wasm::TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, Uint32Vector* offsets,
++                   UniqueChars* error)
+ {
+     LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
+ 
+     bool binary = false;
+     AstModule* module = ParseModule(text, stackLimit, lifo, error, &binary);
+     if (!module)
+         return false;
+ 
+     if (binary)
+         return EncodeBinaryModule(*module, bytes);
+ 
+     if (!ResolveModule(lifo, module, error))
+         return false;
+ 
+-    return EncodeModule(*module, bytes);
+-}
++    return EncodeModule(*module, offsets, bytes);
++}
+diff --git a/js/src/wasm/WasmTextToBinary.h b/js/src/wasm/WasmTextToBinary.h
+--- a/js/src/wasm/WasmTextToBinary.h
++++ b/js/src/wasm/WasmTextToBinary.h
+@@ -24,14 +24,15 @@
+ namespace js {
+ namespace wasm {
+ 
+ // Translate the textual representation of a wasm module (given by a
+ // null-terminated char16_t array) into serialized bytes. If there is an error
+ // other than out-of-memory an error message string will be stored in 'error'.
+ 
+ extern MOZ_MUST_USE bool
+-TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, UniqueChars* error);
++TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, Uint32Vector* offsets,
++             UniqueChars* error);
+ 
+ } // namespace wasm
+ } // namespace js
+ 
+ #endif // wasm_text_to_binary_h

+ 5521 - 0
frg/work-js/mozilla-release/patches/1447591-2-63a1.patch

@@ -0,0 +1,5521 @@
+# HG changeset patch
+# User Benjamin Bouvier <benj@benj.me>
+# Date 1529574587 -7200
+#      Thu Jun 21 11:49:47 2018 +0200
+# Node ID e7a694ff10044ca9d52f3ed05f61b93cae1a4620
+# Parent  31d0d765dee3100991dbce7653615474b5a31411
+Bug 1447591: Remove wasm::BinaryToText; r=luke
+
+diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
+--- a/js/src/builtin/TestingFunctions.cpp
++++ b/js/src/builtin/TestingFunctions.cpp
+@@ -58,17 +58,16 @@
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/ProxyObject.h"
+ #include "vm/SavedStacks.h"
+ #include "vm/Stack.h"
+ #include "vm/StringType.h"
+ #include "vm/TraceLogging.h"
+ #include "wasm/AsmJS.h"
+-#include "wasm/WasmBinaryToText.h"
+ #include "wasm/WasmJS.h"
+ #include "wasm/WasmModule.h"
+ #include "wasm/WasmSignalHandlers.h"
+ #include "wasm/WasmTextToBinary.h"
+ #include "wasm/WasmTypes.h"
+ 
+ #include "vm/Debugger-inl.h"
+ #include "vm/EnvironmentObject-inl.h"
+@@ -710,73 +709,16 @@ WasmTextToBinary(JSContext* cx, unsigned
+     if (!JS_DefineProperty(cx, obj, "offsets", jsOffsets, propAttrs))
+         return false;
+ 
+     args.rval().setObject(*obj);
+     return true;
+ }
+ 
+ static bool
+-WasmBinaryToText(JSContext* cx, unsigned argc, Value* vp)
+-{
+-    if (!cx->options().wasm()) {
+-        JS_ReportErrorASCII(cx, "wasm support unavailable");
+-        return false;
+-    }
+-
+-    CallArgs args = CallArgsFromVp(argc, vp);
+-
+-    if (!args.get(0).isObject() || !args.get(0).toObject().is<TypedArrayObject>()) {
+-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
+-        return false;
+-    }
+-
+-    Rooted<TypedArrayObject*> code(cx, &args[0].toObject().as<TypedArrayObject>());
+-
+-    if (!TypedArrayObject::ensureHasBuffer(cx, code))
+-        return false;
+-
+-    if (code->isSharedMemory()) {
+-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
+-        return false;
+-    }
+-
+-    const uint8_t* bufferStart = code->bufferUnshared()->dataPointer();
+-    const uint8_t* bytes = bufferStart + code->byteOffset();
+-    uint32_t length = code->byteLength();
+-
+-    Vector<uint8_t> copy(cx);
+-    if (code->bufferUnshared()->hasInlineData()) {
+-        if (!copy.append(bytes, length))
+-            return false;
+-        bytes = copy.begin();
+-    }
+-
+-    if (args.length() > 1) {
+-        JS_ReportErrorASCII(cx, "wasm text format selection is not supported");
+-        return false;
+-    }
+-
+-    StringBuffer buffer(cx);
+-    bool ok = wasm::BinaryToText(cx, bytes, length, buffer);
+-    if (!ok) {
+-        if (!cx->isExceptionPending())
+-            JS_ReportErrorASCII(cx, "wasm binary to text print error");
+-        return false;
+-    }
+-
+-    JSString* result = buffer.finishString();
+-    if (!result)
+-        return false;
+-
+-    args.rval().setString(result);
+-    return true;
+-}
+-
+-static bool
+ WasmExtractCode(JSContext* cx, unsigned argc, Value* vp)
+ {
+     if (!cx->options().wasm()) {
+         JS_ReportErrorASCII(cx, "wasm support unavailable");
+         return false;
+     }
+ 
+     CallArgs args = CallArgsFromVp(argc, vp);
+@@ -5622,20 +5564,16 @@ gc::ZealModeHelpText),
+ "wasmCompileMode()",
+ "  Returns a string indicating the available compile policy: 'baseline', 'ion',\n"
+ "  'baseline-or-ion', or 'disabled' (if wasm is not available at all)."),
+ 
+     JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
+ "wasmTextToBinary(str)",
+ "  Translates the given text wasm module into its binary encoding."),
+ 
+-    JS_FN_HELP("wasmBinaryToText", WasmBinaryToText, 1, 0,
+-"wasmBinaryToText(bin)",
+-"  Translates binary encoding to text format"),
+-
+     JS_FN_HELP("wasmExtractCode", WasmExtractCode, 1, 0,
+ "wasmExtractCode(module[, tier])",
+ "  Extracts generated machine code from WebAssembly.Module.  The tier is a string,\n"
+ "  'stable', 'best', 'baseline', or 'ion'; the default is 'stable'.  If the request\n"
+ "  cannot be satisfied then null is returned.  If the request is 'ion' then block\n"
+ "  until background compilation is complete."),
+ 
+     JS_FN_HELP("wasmHasTier2CompilationCompleted", WasmHasTier2CompilationCompleted, 1, 0,
+diff --git a/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js b/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
+--- a/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
++++ b/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
+@@ -4,17 +4,16 @@
+ 
+ load(libdir + "asserts.js");
+ 
+ if (!wasmDebuggingIsSupported())
+     quit();
+ 
+ // Checking if experimental format generates internal source map to binary file
+ // by querying debugger scripts getAllColumnOffsets.
+-// (Notice that the source map will not be produced by wasmBinaryToText)
+ function getAllOffsets(wast) {
+   var sandbox = newGlobal('');
+   var dbg = new Debugger();
+   dbg.addDebuggee(sandbox);
+   dbg.allowWasmBinarySource = true;
+   sandbox.eval(`
+     var wasm = wasmTextToBinary('${wast}');
+     var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
+diff --git a/js/src/jit-test/tests/wasm/atomic.js b/js/src/jit-test/tests/wasm/atomic.js
+--- a/js/src/jit-test/tests/wasm/atomic.js
++++ b/js/src/jit-test/tests/wasm/atomic.js
+@@ -79,89 +79,20 @@ for (let [type,align,good] of [['i32',1,
+ 
+ for (let align of [1, 2, 4, 8]) {
+     let text = `(module (memory 1 1 shared)
+ 		 (func (result i32) (atomic.wake align=${align} (i32.const 0) (i32.const 1)))
+ 		 (export "" 0))`;
+     assertEq(valText(text), align == 4);
+ }
+ 
+-// Check that the text output is sane.
+-
+-for (let [type,view] of [['i32','8_u'],['i32','16_u'],['i32',''],['i64','8_u'],['i64','16_u'],['i64','32_u'],['i64','']]) {
+-    let addr = "i32.const 48";
+-    let value = `${type}.const 1`;
+-    let value2 = `${type}.const 2`;
+-    for (let op of ["add", "and", "or", "xor", "xchg"]) {
+-	let operator = `${type}.atomic.rmw${view}.${op}`;
+-	let text = `(module (memory 1 1 shared)
+-		     (func (result ${type}) (${operator} (${addr}) (${value})))
+-		     (export "" 0))`;
+-	checkRoundTrip(text, [addr, value, operator]);
+-    }
+-    {
+-	let operator = `${type}.atomic.rmw${view}.cmpxchg`;
+-	let text = `(module (memory 1 1 shared)
+-		     (func (result ${type}) (${operator} (${addr}) (${value}) (${value2})))
+-		     (export "" 0))`;
+-	checkRoundTrip(text, [addr, value, value2, operator]);
+-    }
+-    {
+-	let operator = `${type}.atomic.load${view}`;
+-	let text = `(module (memory 1 1 shared)
+-		     (func (result ${type}) (${operator} (${addr})))
+-		     (export "" 0))`;
+-	checkRoundTrip(text, [addr, operator]);
+-    }
+-    {
+-	let operator = `${type}.atomic.store${view}`;
+-	let text = `(module (memory 1 1 shared)
+-		     (func (${operator} (${addr}) (${value})))
+-		     (export "" 0))`;
+-	checkRoundTrip(text, [addr, value, operator]);
+-    }
+-}
+-
+-for (let type of ['i32', 'i64']) {
+-    let addr = "i32.const 48";
+-    let operator = `${type}.atomic.wait`
+-    let value = `${type}.const 1`;
+-    let timeout = "i64.const 314159";
+-    let text = `(module (memory 1 1 shared)
+-		 (func (result i32) (${operator} (${addr}) (${value}) (${timeout})))
+-		 (export "" 0))`;
+-    checkRoundTrip(text, [addr, value, timeout, operator]);
+-}
+-
+-{
+-    let addr = "i32.const 48";
+-    let operator = "atomic.wake"
+-    let count = "i32.const 1";
+-    let text = `(module (memory 1 1 shared)
+-		 (func (result i32) (${operator} (${addr}) (${count})))
+-		 (export "" 0))`;
+-    checkRoundTrip(text, [addr, count, operator]);
+-}
+-
+ function valText(text) {
+     return WebAssembly.validate(wasmTextToBinary(text));
+ }
+ 
+-function checkRoundTrip(text, ss) {
+-    let input = wasmTextToBinary(text);
+-    let output = wasmBinaryToText(input).split("\n").map(String.trim);
+-    for (let s of output) {
+-	if (ss.length == 0)
+-	    break;
+-	if (s.match(ss[0]))
+-	    ss.shift();
+-    }
+-    assertEq(ss.length, 0);
+-}
+-
+ // Test that atomic operations work.
+ 
+ function I64(hi, lo) {
+     this.high = hi;
+     this.low = lo;
+ }
+ I64.prototype.toString = function () {
+     return "(" + this.high.toString(16) + " " + this.low.toString(16) + ")";
+diff --git a/js/src/jit-test/tests/wasm/gc/structs.js b/js/src/jit-test/tests/wasm/gc/structs.js
+--- a/js/src/jit-test/tests/wasm/gc/structs.js
++++ b/js/src/jit-test/tests/wasm/gc/structs.js
+@@ -64,25 +64,16 @@ var mod = new WebAssembly.Module(bin);
+ var ins = new WebAssembly.Instance(mod, {m:{x1(x){ return x*3 }, x2(x){ return Math.PI }}}).exports;
+ 
+ assertEq(ins.hello(4.0, 0), 2.0)
+ assertEq(ins.hello(4.0, 1), 16.0)
+ 
+ assertEq(ins.x1(12), 36)
+ assertEq(ins.x2(8), Math.PI)
+ 
+-// Crude but at least checks that we have *something*.
+-
+-var txt = wasmBinaryToText(bin);
+-var re = /\(type\s+\$[a-z0-9]+\s+\(struct/gm;
+-assertEq(Array.isArray(re.exec(txt)), true);
+-assertEq(Array.isArray(re.exec(txt)), true);
+-assertEq(Array.isArray(re.exec(txt)), true);
+-assertEq(Array.isArray(re.exec(txt)), false);
+-
+ // The field name is optional, so this should work.
+ 
+ wasmEvalText(`
+ (module
+  (type $s (struct (field i32))))
+ `)
+ 
+ // Empty structs are OK.
+diff --git a/js/src/jit-test/tests/wasm/to-text.js b/js/src/jit-test/tests/wasm/to-text.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/wasm/to-text.js
++++ /dev/null
+@@ -1,293 +0,0 @@
+-var caught = false;
+-try {
+-    wasmBinaryToText(new Int8Array(1));
+-} catch (e) {
+-    caught = true;
+-}
+-assertEq(caught, true);
+-
+-assertErrorMessage(() => wasmBinaryToText(wasmTextToBinary(`(module (func (result i32) (f32.const 13.37)))`)), WebAssembly.CompileError, /type mismatch/);
+-
+-function runTest(code) {
+-    var expected = wasmTextToBinary(code);
+-    var s = wasmBinaryToText(expected);
+-    print("TEXT: " + s);
+-    var roundtrip = wasmTextToBinary(s);
+-    assertDeepEq(expected, roundtrip);
+-}
+-
+-// Smoke test
+-runTest(`
+-(module
+-  (func (param i32) (result f64)
+-     (local $l f32)
+-     (block
+-        (set_local $l (f32.const 0.0))
+-        (loop $exit $cont
+-           (br_if $exit (get_local 0))
+-           (br 2)
+-        )
+-        (drop (if f64 (i32.const 1)
+-           (f64.min (f64.neg (f64.const 1)) (f64.const 0))
+-           (f64.add (f64.const 0.5) (f64.load offset=0 (i32.const 0)) )
+-        ))
+-     )
+-     (i32.store16 (i32.const 8) (i32.const 128))
+-
+-     (return (f64.const 0))
+-  )
+-  (export "test" 0)
+-  (memory 1 10)
+-)`);
+-
+-// Constants, stores and loads
+-runTest(`
+-(module (func
+-  (local i32) (local f32) (local f64)
+-  (drop (i32.const 0))
+-  (drop (i32.const 100002))
+-  (drop (f32.const 0.0))
+-  (drop (f32.const 1.5))
+-  (drop (f64.const 0.0))
+-  (drop (f64.const -10.25))
+-  (i32.store (i32.const 0) (i32.load (i32.const 0)))
+-  (i32.store8 (i32.const 1) (i32.load8_s (i32.const 2)))
+-  (i32.store8 (i32.const 3) (i32.load8_u (i32.const 4)))
+-  (i32.store16 (i32.const 2) (i32.load16_s (i32.const 0)))
+-  (i32.store16 (i32.const 1) (i32.load16_u (i32.const 0)))
+-  (f32.store (i32.const 5) (f32.load (i32.const 6)))
+-  (f64.store (i32.const 5) (f64.load (i32.const 6)))
+-  (set_local 0 (get_local 0))
+-  (set_local 2 (get_local 2))
+-)(memory 100))`);
+-
+-// Branching
+-runTest(`
+-(module
+-(func
+-  (block (block (block (nop))))
+-  (block (loop ))
+-  (if (i32.const 0) (block $label (nop)))
+-  (if (i32.const 1) (nop) (loop $exit $cont (block )))
+-  (block $l (br $l))
+-  (block $m (block (block (br $m))))
+-  (block $k (br_if 0 (i32.const 0)) (return))
+-  (block $n (block (block (br_if 2 (i32.const 1)) (nop))))
+-  (block $1 (block $2 (block $3 (br_table $2 $3 $1 (i32.const 1)) )) (nop))
+-  (loop $exit $cont (br_if $cont (i32.const 0)) (nop))
+-  (return)
+-)
+-(func (result f32) (return (f32.const -0.5)))
+-(memory 0)
+-)`);
+-
+-// i32, f32 and f64 operations
+-runTest(`
+-(module
+-  (func $iadd (param $x i32) (param $y i32) (result i32) (i32.add (get_local $x) (get_local $y)))
+-  (func $isub (param $x i32) (param $y i32) (result i32) (i32.sub (get_local $x) (get_local $y)))
+-  (func $imul (param $x i32) (param $y i32) (result i32) (i32.mul (get_local $x) (get_local $y)))
+-  (func $idiv_s (param $x i32) (param $y i32) (result i32) (i32.div_s (get_local $x) (get_local $y)))
+-  (func $idiv_u (param $x i32) (param $y i32) (result i32) (i32.div_u (get_local $x) (get_local $y)))
+-  (func $irem_s (param $x i32) (param $y i32) (result i32) (i32.rem_s (get_local $x) (get_local $y)))
+-  (func $irem_u (param $x i32) (param $y i32) (result i32) (i32.rem_u (get_local $x) (get_local $y)))
+-  (func $iand (param $x i32) (param $y i32) (result i32) (i32.and (get_local $x) (get_local $y)))
+-  (func $ior (param $x i32) (param $y i32) (result i32) (i32.or (get_local $x) (get_local $y)))
+-  (func $ixor (param $x i32) (param $y i32) (result i32) (i32.xor (get_local $x) (get_local $y)))
+-  (func $ishl (param $x i32) (param $y i32) (result i32) (i32.shl (get_local $x) (get_local $y)))
+-  (func $ishr_s (param $x i32) (param $y i32) (result i32) (i32.shr_s (get_local $x) (get_local $y)))
+-  (func $ishr_u (param $x i32) (param $y i32) (result i32) (i32.shr_u (get_local $x) (get_local $y)))
+-  (func $iclz (param $x i32) (result i32) (i32.clz (get_local $x)))
+-  (func $ictz (param $x i32) (result i32) (i32.ctz (get_local $x)))
+-  (func $ipopcnt (param $x i32) (result i32) (i32.popcnt (get_local $x)))
+-  (func $ieq (param $x i32) (param $y i32) (result i32) (i32.eq (get_local $x) (get_local $y)))
+-  (func $ine (param $x i32) (param $y i32) (result i32) (i32.ne (get_local $x) (get_local $y)))
+-  (func $ilt_s (param $x i32) (param $y i32) (result i32) (i32.lt_s (get_local $x) (get_local $y)))
+-  (func $ilt_u (param $x i32) (param $y i32) (result i32) (i32.lt_u (get_local $x) (get_local $y)))
+-  (func $ile_s (param $x i32) (param $y i32) (result i32) (i32.le_s (get_local $x) (get_local $y)))
+-  (func $ile_u (param $x i32) (param $y i32) (result i32) (i32.le_u (get_local $x) (get_local $y)))
+-  (func $igt_s (param $x i32) (param $y i32) (result i32) (i32.gt_s (get_local $x) (get_local $y)))
+-  (func $igt_u (param $x i32) (param $y i32) (result i32) (i32.gt_u (get_local $x) (get_local $y)))
+-  (func $ige_s (param $x i32) (param $y i32) (result i32) (i32.ge_s (get_local $x) (get_local $y)))
+-  (func $ige_u (param $x i32) (param $y i32) (result i32) (i32.ge_u (get_local $x) (get_local $y)))
+-
+-  (func $fadd (param $x f32) (param $y f32) (result f32) (f32.add (get_local $x) (get_local $y)))
+-  (func $fsub (param $x f32) (param $y f32) (result f32) (f32.sub (get_local $x) (get_local $y)))
+-  (func $fmul (param $x f32) (param $y f32) (result f32) (f32.mul (get_local $x) (get_local $y)))
+-  (func $fdiv (param $x f32) (param $y f32) (result f32) (f32.div (get_local $x) (get_local $y)))
+-  (func $fsqrt (param $x f32) (result f32) (f32.sqrt (get_local $x)))
+-  (func $fmin (param $x f32) (param $y f32) (result f32) (f32.min (get_local $x) (get_local $y)))
+-  (func $fmax (param $x f32) (param $y f32) (result f32) (f32.max (get_local $x) (get_local $y)))
+-  (func $fceil (param $x f32) (result f32) (f32.ceil (get_local $x)))
+-  (func $ffloor (param $x f32) (result f32) (f32.floor (get_local $x)))
+-  (func $fabs (param $x f32) (result f32) (f32.abs (get_local $x)))
+-  (func $fneg (param $x f32) (result f32) (f32.neg (get_local $x)))
+-
+-  (func $dadd (param $x f64) (param $y f64) (result f64) (f64.add (get_local $x) (get_local $y)))
+-  (func $dsub (param $x f64) (param $y f64) (result f64) (f64.sub (get_local $x) (get_local $y)))
+-  (func $dmul (param $x f64) (param $y f64) (result f64) (f64.mul (get_local $x) (get_local $y)))
+-  (func $ddiv (param $x f64) (param $y f64) (result f64) (f64.div (get_local $x) (get_local $y)))
+-  (func $dceil (param $x f64) (result f64) (f64.ceil (get_local $x)))
+-  (func $dfloor (param $x f64) (result f64) (f64.floor (get_local $x)))
+-  (func $dabs (param $x f64) (result f64) (f64.abs (get_local $x)))
+-  (func $dneg (param $x f64) (result f64) (f64.neg (get_local $x)))
+-(memory 0))`);
+-
+-// conversions
+-runTest(`
+-(module
+-  (func $itrunc_s_f32 (param $x f32) (result i32) (i32.trunc_s/f32 (get_local $x)))
+-  (func $itrunc_u_f32 (param $x f32) (result i32) (i32.trunc_u/f32 (get_local $x)))
+-  (func $itrunc_s_f64 (param $x f64) (result i32) (i32.trunc_s/f64 (get_local $x)))
+-  (func $itrunc_u_f64 (param $x f64) (result i32) (i32.trunc_u/f64 (get_local $x)))
+-  (func $fconvert_s_i32 (param $x i32) (result f32) (f32.convert_s/i32 (get_local $x)))
+-  (func $dconvert_s_i32 (param $x i32) (result f64) (f64.convert_s/i32 (get_local $x)))
+-  (func $fconvert_u_i32 (param $x i32) (result f32) (f32.convert_u/i32 (get_local $x)))
+-  (func $dconvert_u_i32 (param $x i32) (result f64) (f64.convert_u/i32 (get_local $x)))
+-  (func $dpromote_f32 (param $x f32) (result f64) (f64.promote/f32 (get_local $x)))
+-  (func $fdemote_f64 (param $x f64) (result f32) (f32.demote/f64 (get_local $x)))
+-(memory 0))`);
+-
+-// function calls
+-runTest(`
+-(module
+-  (type $type1 (func (param i32) (result i32)))
+-  (import $import1 "mod" "test" (param f32) (result f32))
+-  (table anyfunc (elem $func1 $func2))
+-  (func $func1 (param i32) (param f32) (nop))
+-  (func $func2 (param i32) (result i32) (get_local 0))
+-  (func $test
+-    (call $func1
+-      (call_indirect $type1 (i32.const 2) (i32.const 1))
+-      (call $import1 (f32.const 1.0))
+-    )
+-  )
+-  (export "test" $test)
+-  (memory 1)
+-)`);
+-
+-// default memory export from binaryen
+-runTest(`(module (func (nop)) (memory 0 65535))`);
+-
+-// stack-machine code that isn't directly representable as an AST
+-runTest(`
+-(module
+-   (func (result i32)
+-     (local $x i32)
+-     i32.const 100
+-     set_local $x
+-     i32.const 200
+-     set_local $x
+-     i32.const 400
+-     set_local $x
+-     i32.const 2
+-     i32.const 16
+-     nop
+-     set_local $x
+-     i32.const 3
+-     i32.const 17
+-     set_local $x
+-     i32.const 18
+-     set_local $x
+-     i32.lt_s
+-     if i32
+-       i32.const 101
+-       set_local $x
+-       i32.const 8
+-       i32.const 102
+-       set_local $x
+-     else
+-       i32.const 103
+-       set_local $x
+-       i32.const 900
+-       i32.const 104
+-       set_local $x
+-       i32.const 105
+-       set_local $x
+-     end
+-     i32.const 107
+-     set_local $x
+-     get_local $x
+-     i32.add
+-     i32.const 106
+-     set_local $x
+-   )
+-   (export "" 0)
+-)`);
+-
+-// more stack-machine code that isn't directly representable as an AST
+-runTest(`
+-(module
+-   (func $return_void)
+-
+-   (func (result i32)
+-     (local $x i32)
+-     i32.const 0
+-     block
+-       i32.const 1
+-       set_local $x
+-     end
+-     i32.const 2
+-     set_local $x
+-     i32.const 3
+-     loop
+-       i32.const 4
+-       set_local $x
+-     end
+-     i32.const 5
+-     set_local $x
+-     i32.add
+-     call $return_void
+-   )
+-   (export "" 0)
+-)`);
+-
+-runTest(`
+-  (module
+-   (func $func
+-    block $block
+-     i32.const 0
+-     if
+-      i32.const 0
+-      if
+-      end
+-     else
+-     end
+-    end
+-   )
+-  (export "" 0)
+-)`);
+-
+-// Branch table.
+-runTest(`(module
+-    (func (export "run") (param $p i32) (local $n i32)
+-        i32.const 0
+-        set_local $n
+-        loop $outer
+-            block $c block $b block $a
+-                loop $inner
+-                    get_local $p
+-                    br_table $b $a $c $inner $outer
+-                end $inner
+-            end $a
+-                get_local $n
+-                i32.const 1
+-                i32.add
+-                set_local $n
+-            end $b
+-                block
+-                    get_local $n
+-                    i32.const 2
+-                    i32.add
+-                    set_local $n
+-                end
+-            end $c
+-        end $outer
+-    )
+-)`);
+-
+-// Import as a start function.
+-runTest(`(module
+-    (import "env" "test" (func))
+-    (start 0)
+-)`);
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -395,18 +395,16 @@ UNIFIED_SOURCES += [
+     'vm/UbiNode.cpp',
+     'vm/UbiNodeCensus.cpp',
+     'vm/UbiNodeShortestPaths.cpp',
+     'vm/UnboxedObject.cpp',
+     'vm/Value.cpp',
+     'vm/Xdr.cpp',
+     'wasm/AsmJS.cpp',
+     'wasm/WasmBaselineCompile.cpp',
+-    'wasm/WasmBinaryToAST.cpp',
+-    'wasm/WasmBinaryToText.cpp',
+     'wasm/WasmBuiltins.cpp',
+     'wasm/WasmCode.cpp',
+     'wasm/WasmCompile.cpp',
+     'wasm/WasmDebug.cpp',
+     'wasm/WasmFrameIter.cpp',
+     'wasm/WasmGenerator.cpp',
+     'wasm/WasmInstance.cpp',
+     'wasm/WasmIonCompile.cpp',
+@@ -414,17 +412,16 @@ UNIFIED_SOURCES += [
+     'wasm/WasmModule.cpp',
+     'wasm/WasmOpIter.cpp',
+     'wasm/WasmProcess.cpp',
+     'wasm/WasmRealm.cpp',
+     'wasm/WasmSignalHandlers.cpp',
+     'wasm/WasmStubs.cpp',
+     'wasm/WasmTable.cpp',
+     'wasm/WasmTextToBinary.cpp',
+-    'wasm/WasmTextUtils.cpp',
+     'wasm/WasmTypes.cpp',
+     'wasm/WasmValidate.cpp'
+ ]
+ 
+ # builtin/Array.cpp and vm/JSAtom.cpp cannot be built in unified mode because
+ #   xpcshell is broken during packaging when compiled with gcc-4.8.2
+ # builtin/RegExp.cpp cannot be built in unified mode because it is built
+ #   without PGO
+diff --git a/js/src/wasm/WasmAST.h b/js/src/wasm/WasmAST.h
+--- a/js/src/wasm/WasmAST.h
++++ b/js/src/wasm/WasmAST.h
+@@ -121,20 +121,27 @@ typedef AstVector<AstRef> AstRefVector;
+ 
+ struct AstBase
+ {
+     void* operator new(size_t numBytes, LifoAlloc& astLifo) throw() {
+         return astLifo.alloc(numBytes);
+     }
+ };
+ 
++struct AstNode
++{
++    void* operator new(size_t numBytes, LifoAlloc& astLifo) throw() {
++        return astLifo.alloc(numBytes);
++    }
++};
++
+ class AstFuncType;
+ class AstStructType;
+ 
+-class AstTypeDef : public AstBase
++class AstTypeDef : public AstNode
+ {
+   protected:
+     enum class Which { IsFuncType, IsStructType };
+ 
+   private:
+     Which which_;
+ 
+   public:
+@@ -253,29 +260,16 @@ AstTypeDef::asFuncType() const
+ 
+ inline const AstStructType&
+ AstTypeDef::asStructType() const
+ {
+     MOZ_ASSERT(isStructType());
+     return *static_cast<const AstStructType*>(this);
+ }
+ 
+-const uint32_t AstNodeUnknownOffset = 0;
+-
+-class AstNode : public AstBase
+-{
+-    uint32_t offset_; // if applicable, offset in the binary format file
+-
+-  public:
+-    AstNode() : offset_(AstNodeUnknownOffset) {}
+-
+-    uint32_t offset() const { return offset_; }
+-    void setOffset(uint32_t offset) { offset_ = offset; }
+-};
+-
+ enum class AstExprKind
+ {
+     AtomicCmpXchg,
+     AtomicLoad,
+     AtomicRMW,
+     AtomicStore,
+     BinaryOperator,
+     Block,
+@@ -857,35 +851,31 @@ class AstBranchTable : public AstExpr
+ 
+ class AstFunc : public AstNode
+ {
+     AstName name_;
+     AstRef funcType_;
+     AstValTypeVector vars_;
+     AstNameVector localNames_;
+     AstExprVector body_;
+-    uint32_t endOffset_; // if applicable, offset in the binary format file
+ 
+   public:
+     AstFunc(AstName name, AstRef ft, AstValTypeVector&& vars,
+             AstNameVector&& locals, AstExprVector&& body)
+       : name_(name),
+         funcType_(ft),
+         vars_(std::move(vars)),
+         localNames_(std::move(locals)),
+-        body_(std::move(body)),
+-        endOffset_(AstNodeUnknownOffset)
++        body_(std::move(body))
+     {}
+     AstRef& funcType() { return funcType_; }
+     const AstValTypeVector& vars() const { return vars_; }
+     const AstNameVector& locals() const { return localNames_; }
+     const AstExprVector& body() const { return body_; }
+     AstName name() const { return name_; }
+-    uint32_t endOffset() const { return endOffset_; }
+-    void setEndOffset(uint32_t offset) { endOffset_ = offset; }
+ };
+ 
+ class AstGlobal : public AstNode
+ {
+     AstName name_;
+     bool isMutable_;
+     ValType type_;
+     Maybe<AstExpr*> init_;
+diff --git a/js/src/wasm/WasmBinaryToAST.cpp b/js/src/wasm/WasmBinaryToAST.cpp
+deleted file mode 100644
+--- a/js/src/wasm/WasmBinaryToAST.cpp
++++ /dev/null
+@@ -1,2390 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+- * vim: set ts=8 sts=4 et sw=4 tw=99:
+- *
+- * Copyright 2016 Mozilla Foundation
+- *
+- * Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- *
+- *     http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-#include "wasm/WasmBinaryToAST.h"
+-
+-#include "mozilla/MathAlgorithms.h"
+-#include "mozilla/Sprintf.h"
+-
+-#include "vm/JSCompartment.h"
+-#include "vm/JSContext.h"
+-#include "wasm/WasmOpIter.h"
+-#include "wasm/WasmValidate.h"
+-
+-using namespace js;
+-using namespace js::wasm;
+-
+-using mozilla::FloorLog2;
+-
+-enum AstDecodeTerminationKind
+-{
+-    Unknown,
+-    End,
+-    Else
+-};
+-
+-struct AstDecodeStackItem
+-{
+-    AstExpr* expr;
+-    AstDecodeTerminationKind terminationKind;
+-    ExprType type;
+-
+-    explicit AstDecodeStackItem()
+-      : expr(nullptr),
+-        terminationKind(AstDecodeTerminationKind::Unknown),
+-        type(ExprType::Limit)
+-    {}
+-    explicit AstDecodeStackItem(AstDecodeTerminationKind terminationKind, ExprType type)
+-      : expr(nullptr),
+-        terminationKind(terminationKind),
+-        type(type)
+-    {}
+-    explicit AstDecodeStackItem(AstExpr* expr)
+-     : expr(expr),
+-       terminationKind(AstDecodeTerminationKind::Unknown),
+-       type(ExprType::Limit)
+-    {}
+-};
+-
+-// We don't define a Value type because OpIter doesn't push void values, which
+-// we actually need here because we're building an AST, so we maintain our own
+-// stack.
+-struct AstDecodePolicy
+-{
+-    typedef Nothing Value;
+-    typedef Nothing ControlItem;
+-};
+-
+-typedef OpIter<AstDecodePolicy> AstDecodeOpIter;
+-
+-class AstDecodeContext
+-{
+-  public:
+-    typedef AstVector<AstDecodeStackItem> AstDecodeStack;
+-    typedef AstVector<uint32_t> DepthStack;
+-
+-    JSContext* cx;
+-    LifoAlloc& lifo;
+-    Decoder& d;
+-    bool generateNames;
+-
+-  private:
+-    ModuleEnvironment env_;
+-
+-    AstModule& module_;
+-    AstDecodeOpIter *iter_;
+-    AstDecodeStack exprs_;
+-    DepthStack depths_;
+-    const ValTypeVector* locals_;
+-    AstNameVector blockLabels_;
+-    uint32_t currentLabelIndex_;
+-    ExprType retType_;
+-
+-  public:
+-    AstDecodeContext(JSContext* cx, LifoAlloc& lifo, Decoder& d, AstModule& module,
+-                     bool generateNames, HasGcTypes hasGcTypes)
+-     : cx(cx),
+-       lifo(lifo),
+-       d(d),
+-       generateNames(generateNames),
+-       env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, hasGcTypes,
+-            cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()
+-            ? Shareable::True
+-            : Shareable::False),
+-       module_(module),
+-       iter_(nullptr),
+-       exprs_(lifo),
+-       depths_(lifo),
+-       locals_(nullptr),
+-       blockLabels_(lifo),
+-       currentLabelIndex_(0),
+-       retType_(ExprType::Limit)
+-    {}
+-
+-    ModuleEnvironment& env() { return env_; }
+-
+-    AstModule& module() { return module_; }
+-    AstDecodeOpIter& iter() { return *iter_; }
+-    AstDecodeStack& exprs() { return exprs_; }
+-    DepthStack& depths() { return depths_; }
+-
+-    AstNameVector& blockLabels() { return blockLabels_; }
+-
+-    ExprType retType() const { return retType_; }
+-    const ValTypeVector& locals() const { return *locals_; }
+-
+-    void popBack() { return exprs().popBack(); }
+-    AstDecodeStackItem popCopy() { return exprs().popCopy(); }
+-    AstDecodeStackItem& top() { return exprs().back(); }
+-    MOZ_MUST_USE bool push(AstDecodeStackItem item) { return exprs().append(item); }
+-
+-    bool needFirst() {
+-        for (size_t i = depths().back(); i < exprs().length(); ++i) {
+-            if (!exprs()[i].expr->isVoid())
+-                return true;
+-        }
+-        return false;
+-    }
+-
+-    AstExpr* handleVoidExpr(AstExpr* voidNode)
+-    {
+-        MOZ_ASSERT(voidNode->isVoid());
+-
+-        // To attach a node that "returns void" to the middle of an AST, wrap it
+-        // in a first node next to the node it should accompany.
+-        if (needFirst()) {
+-            AstExpr *prev = popCopy().expr;
+-
+-            // If the previous/A node is already a First, reuse it.
+-            if (prev->kind() == AstExprKind::First) {
+-                if (!prev->as<AstFirst>().exprs().append(voidNode))
+-                    return nullptr;
+-                return prev;
+-            }
+-
+-            AstExprVector exprs(lifo);
+-            if (!exprs.append(prev))
+-                return nullptr;
+-            if (!exprs.append(voidNode))
+-                return nullptr;
+-
+-            return new(lifo) AstFirst(std::move(exprs));
+-        }
+-
+-        return voidNode;
+-    }
+-
+-    void startFunction(AstDecodeOpIter* iter, const ValTypeVector* locals, ExprType retType)
+-    {
+-        iter_ = iter;
+-        locals_ = locals;
+-        currentLabelIndex_ = 0;
+-        retType_ = retType;
+-    }
+-    void endFunction()
+-    {
+-        iter_ = nullptr;
+-        locals_ = nullptr;
+-        retType_ = ExprType::Limit;
+-        MOZ_ASSERT(blockLabels_.length() == 0);
+-    }
+-    uint32_t nextLabelIndex()
+-    {
+-        return currentLabelIndex_++;
+-    }
+-};
+-
+-static bool
+-GenerateName(AstDecodeContext& c, const AstName& prefix, uint32_t index, AstName* name)
+-{
+-    if (!c.generateNames) {
+-        *name = AstName();
+-        return true;
+-    }
+-
+-    AstVector<char16_t> result(c.lifo);
+-    if (!result.append(u'$'))
+-        return false;
+-    if (!result.append(prefix.begin(), prefix.length()))
+-        return false;
+-
+-    uint32_t tmp = index;
+-    do {
+-        if (!result.append(u'0'))
+-            return false;
+-        tmp /= 10;
+-    } while (tmp);
+-
+-    if (index) {
+-        char16_t* p = result.end();
+-        for (tmp = index; tmp; tmp /= 10)
+-            *(--p) = u'0' + (tmp % 10);
+-    }
+-
+-    size_t length = result.length();
+-    char16_t* begin = result.extractOrCopyRawBuffer();
+-    if (!begin)
+-        return false;
+-
+-    *name = AstName(begin, length);
+-    return true;
+-}
+-
+-static bool
+-GenerateRef(AstDecodeContext& c, const AstName& prefix, uint32_t index, AstRef* ref)
+-{
+-    MOZ_ASSERT(index != AstNoIndex);
+-
+-    if (!c.generateNames) {
+-        *ref = AstRef(index);
+-        return true;
+-    }
+-
+-    AstName name;
+-    if (!GenerateName(c, prefix, index, &name))
+-        return false;
+-    MOZ_ASSERT(!name.empty());
+-
+-    *ref = AstRef(name);
+-    ref->setIndex(index);
+-    return true;
+-}
+-
+-static bool
+-GenerateFuncRef(AstDecodeContext& c, uint32_t funcIndex, AstRef* ref)
+-{
+-    if (funcIndex < c.module().numFuncImports()) {
+-        *ref = AstRef(c.module().funcImportNames()[funcIndex]);
+-    } else {
+-        if (!GenerateRef(c, AstName(u"func"), funcIndex, ref))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-AstDecodeCallArgs(AstDecodeContext& c, const FuncTypeWithId& funcType, AstExprVector* funcArgs)
+-{
+-    MOZ_ASSERT(!c.iter().currentBlockHasPolymorphicBase());
+-
+-    uint32_t numArgs = funcType.args().length();
+-    if (!funcArgs->resize(numArgs))
+-        return false;
+-
+-    for (size_t i = 0; i < numArgs; ++i)
+-        (*funcArgs)[i] = c.exprs()[c.exprs().length() - numArgs + i].expr;
+-
+-    c.exprs().shrinkBy(numArgs);
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeExpr(AstDecodeContext& c);
+-
+-static bool
+-AstDecodeDrop(AstDecodeContext& c)
+-{
+-    if (!c.iter().readDrop())
+-        return false;
+-
+-    AstDecodeStackItem value = c.popCopy();
+-
+-    AstExpr* tmp = new(c.lifo) AstDrop(*value.expr);
+-    if (!tmp)
+-        return false;
+-
+-    tmp = c.handleVoidExpr(tmp);
+-    if (!tmp)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(tmp)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeCall(AstDecodeContext& c)
+-{
+-    uint32_t funcIndex;
+-    AstDecodeOpIter::ValueVector unusedArgs;
+-    if (!c.iter().readCall(&funcIndex, &unusedArgs))
+-        return false;
+-
+-    if (c.iter().currentBlockHasPolymorphicBase())
+-        return true;
+-
+-    AstRef funcRef;
+-    if (!GenerateFuncRef(c, funcIndex, &funcRef))
+-        return false;
+-
+-    const FuncTypeWithId* funcType = c.env().funcTypes[funcIndex];
+-
+-    AstExprVector args(c.lifo);
+-    if (!AstDecodeCallArgs(c, *funcType, &args))
+-        return false;
+-
+-    AstCall* call = new(c.lifo) AstCall(Op::Call, funcType->ret(), funcRef, std::move(args));
+-    if (!call)
+-        return false;
+-
+-    AstExpr* result = call;
+-    if (IsVoid(funcType->ret()))
+-        result = c.handleVoidExpr(call);
+-
+-    if (!c.push(AstDecodeStackItem(result)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeCallIndirect(AstDecodeContext& c)
+-{
+-    uint32_t funcTypeIndex;
+-    AstDecodeOpIter::ValueVector unusedArgs;
+-    if (!c.iter().readCallIndirect(&funcTypeIndex, nullptr, &unusedArgs))
+-        return false;
+-
+-    if (c.iter().currentBlockHasPolymorphicBase())
+-        return true;
+-
+-    AstDecodeStackItem index = c.popCopy();
+-
+-    AstRef funcTypeRef;
+-    if (!GenerateRef(c, AstName(u"type"), funcTypeIndex, &funcTypeRef))
+-        return false;
+-
+-    const FuncTypeWithId& funcType = c.env().types[funcTypeIndex].funcType();
+-    AstExprVector args(c.lifo);
+-    if (!AstDecodeCallArgs(c, funcType, &args))
+-        return false;
+-
+-    AstCallIndirect* call =
+-        new(c.lifo) AstCallIndirect(funcTypeRef, funcType.ret(), std::move(args), index.expr);
+-    if (!call)
+-        return false;
+-
+-    AstExpr* result = call;
+-    if (IsVoid(funcType.ret()))
+-        result = c.handleVoidExpr(call);
+-
+-    if (!c.push(AstDecodeStackItem(result)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeGetBlockRef(AstDecodeContext& c, uint32_t depth, AstRef* ref)
+-{
+-    if (!c.generateNames || depth >= c.blockLabels().length()) {
+-        // Also ignoring if it's a function body label.
+-        *ref = AstRef(depth);
+-        return true;
+-    }
+-
+-    uint32_t index = c.blockLabels().length() - depth - 1;
+-    if (c.blockLabels()[index].empty()) {
+-        if (!GenerateName(c, AstName(u"label"), c.nextLabelIndex(), &c.blockLabels()[index]))
+-            return false;
+-    }
+-    *ref = AstRef(c.blockLabels()[index]);
+-    ref->setIndex(depth);
+-    return true;
+-}
+-
+-static bool
+-AstDecodeBrTable(AstDecodeContext& c)
+-{
+-    bool unreachable = c.iter().currentBlockHasPolymorphicBase();
+-
+-    Uint32Vector depths;
+-    uint32_t defaultDepth;
+-    ExprType type;
+-    if (!c.iter().readBrTable(&depths, &defaultDepth, &type, nullptr, nullptr))
+-        return false;
+-
+-    if (unreachable)
+-        return true;
+-
+-    AstRefVector table(c.lifo);
+-    if (!table.resize(depths.length()))
+-        return false;
+-
+-    for (size_t i = 0; i < depths.length(); ++i) {
+-        if (!AstDecodeGetBlockRef(c, depths[i], &table[i]))
+-            return false;
+-    }
+-
+-    AstDecodeStackItem index = c.popCopy();
+-    AstDecodeStackItem value;
+-    if (!IsVoid(type))
+-        value = c.popCopy();
+-
+-    AstRef def;
+-    if (!AstDecodeGetBlockRef(c, defaultDepth, &def))
+-        return false;
+-
+-    auto branchTable = new(c.lifo) AstBranchTable(*index.expr, def, std::move(table), value.expr);
+-    if (!branchTable)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(branchTable)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeBlock(AstDecodeContext& c, Op op)
+-{
+-    MOZ_ASSERT(op == Op::Block || op == Op::Loop);
+-
+-    if (!c.blockLabels().append(AstName()))
+-        return false;
+-
+-    if (op == Op::Loop) {
+-      if (!c.iter().readLoop())
+-          return false;
+-    } else {
+-      if (!c.iter().readBlock())
+-          return false;
+-    }
+-
+-    if (!c.depths().append(c.exprs().length()))
+-        return false;
+-
+-    ExprType type;
+-    while (true) {
+-        if (!AstDecodeExpr(c))
+-            return false;
+-
+-        const AstDecodeStackItem& item = c.top();
+-        if (!item.expr) { // Op::End was found
+-            type = item.type;
+-            c.popBack();
+-            break;
+-        }
+-    }
+-
+-    AstExprVector exprs(c.lifo);
+-    for (auto i = c.exprs().begin() + c.depths().back(), e = c.exprs().end();
+-         i != e; ++i) {
+-        if (!exprs.append(i->expr))
+-            return false;
+-    }
+-    c.exprs().shrinkTo(c.depths().popCopy());
+-
+-    AstName name = c.blockLabels().popCopy();
+-    AstBlock* block = new(c.lifo) AstBlock(op, type, name, std::move(exprs));
+-    if (!block)
+-        return false;
+-
+-    AstExpr* result = block;
+-    if (IsVoid(type))
+-        result = c.handleVoidExpr(block);
+-
+-    if (!c.push(AstDecodeStackItem(result)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeIf(AstDecodeContext& c)
+-{
+-    if (!c.iter().readIf(nullptr))
+-        return false;
+-
+-    AstDecodeStackItem cond = c.popCopy();
+-
+-    bool hasElse = false;
+-
+-    if (!c.depths().append(c.exprs().length()))
+-        return false;
+-
+-    if (!c.blockLabels().append(AstName()))
+-        return false;
+-
+-    ExprType type;
+-    while (true) {
+-        if (!AstDecodeExpr(c))
+-            return false;
+-
+-        const AstDecodeStackItem& item = c.top();
+-        if (!item.expr) { // Op::End was found
+-            hasElse = item.terminationKind == AstDecodeTerminationKind::Else;
+-            type = item.type;
+-            c.popBack();
+-            break;
+-        }
+-    }
+-
+-    AstExprVector thenExprs(c.lifo);
+-    for (auto i = c.exprs().begin() + c.depths().back(), e = c.exprs().end();
+-         i != e; ++i) {
+-        if (!thenExprs.append(i->expr))
+-            return false;
+-    }
+-    c.exprs().shrinkTo(c.depths().back());
+-
+-    AstExprVector elseExprs(c.lifo);
+-    if (hasElse) {
+-        while (true) {
+-            if (!AstDecodeExpr(c))
+-                return false;
+-
+-            const AstDecodeStackItem& item = c.top();
+-            if (!item.expr) { // Op::End was found
+-                c.popBack();
+-                break;
+-            }
+-        }
+-
+-        for (auto i = c.exprs().begin() + c.depths().back(), e = c.exprs().end();
+-             i != e; ++i) {
+-            if (!elseExprs.append(i->expr))
+-                return false;
+-        }
+-        c.exprs().shrinkTo(c.depths().back());
+-    }
+-
+-    c.depths().popBack();
+-
+-    AstName name = c.blockLabels().popCopy();
+-
+-    AstIf* if_ = new(c.lifo) AstIf(type, cond.expr, name, std::move(thenExprs), std::move(elseExprs));
+-    if (!if_)
+-        return false;
+-
+-    AstExpr* result = if_;
+-    if (IsVoid(type))
+-        result = c.handleVoidExpr(if_);
+-
+-    if (!c.push(AstDecodeStackItem(result)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeEnd(AstDecodeContext& c)
+-{
+-    LabelKind kind;
+-    ExprType type;
+-    if (!c.iter().readEnd(&kind, &type, nullptr))
+-        return false;
+-
+-    c.iter().popEnd();
+-
+-    if (!c.push(AstDecodeStackItem(AstDecodeTerminationKind::End, type)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeElse(AstDecodeContext& c)
+-{
+-    ExprType type;
+-
+-    if (!c.iter().readElse(&type, nullptr))
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(AstDecodeTerminationKind::Else, type)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeNop(AstDecodeContext& c)
+-{
+-    if (!c.iter().readNop())
+-        return false;
+-
+-    AstExpr* tmp = new(c.lifo) AstNop();
+-    if (!tmp)
+-        return false;
+-
+-    tmp = c.handleVoidExpr(tmp);
+-    if (!tmp)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(tmp)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeUnary(AstDecodeContext& c, ValType type, Op op)
+-{
+-    if (!c.iter().readUnary(type, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem operand = c.popCopy();
+-
+-    AstUnaryOperator* unary = new(c.lifo) AstUnaryOperator(op, operand.expr);
+-    if (!unary)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(unary)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeBinary(AstDecodeContext& c, ValType type, Op op)
+-{
+-    if (!c.iter().readBinary(type, nullptr, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem rhs = c.popCopy();
+-    AstDecodeStackItem lhs = c.popCopy();
+-
+-    AstBinaryOperator* binary = new(c.lifo) AstBinaryOperator(op, lhs.expr, rhs.expr);
+-    if (!binary)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(binary)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeSelect(AstDecodeContext& c)
+-{
+-    StackType type;
+-    if (!c.iter().readSelect(&type, nullptr, nullptr, nullptr))
+-        return false;
+-
+-    if (c.iter().currentBlockHasPolymorphicBase())
+-        return true;
+-
+-    AstDecodeStackItem selectFalse = c.popCopy();
+-    AstDecodeStackItem selectTrue = c.popCopy();
+-    AstDecodeStackItem cond = c.popCopy();
+-
+-    auto* select = new(c.lifo) AstTernaryOperator(Op::Select, cond.expr, selectTrue.expr,
+-                                                  selectFalse.expr);
+-    if (!select)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(select)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeComparison(AstDecodeContext& c, ValType type, Op op)
+-{
+-    if (!c.iter().readComparison(type, nullptr, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem rhs = c.popCopy();
+-    AstDecodeStackItem lhs = c.popCopy();
+-
+-    AstComparisonOperator* comparison = new(c.lifo) AstComparisonOperator(op, lhs.expr, rhs.expr);
+-    if (!comparison)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(comparison)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeConversion(AstDecodeContext& c, ValType fromType, ValType toType, Op op)
+-{
+-    if (!c.iter().readConversion(fromType, toType, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem operand = c.popCopy();
+-
+-    AstConversionOperator* conversion = new(c.lifo) AstConversionOperator(op, operand.expr);
+-    if (!conversion)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(conversion)))
+-        return false;
+-
+-    return true;
+-}
+-
+-#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
+-static bool
+-AstDecodeExtraConversion(AstDecodeContext& c, ValType fromType, ValType toType, MiscOp op)
+-{
+-    if (!c.iter().readConversion(fromType, toType, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem operand = c.popCopy();
+-
+-    AstExtraConversionOperator* conversion =
+-        new(c.lifo) AstExtraConversionOperator(op, operand.expr);
+-    if (!conversion)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(conversion)))
+-        return false;
+-
+-    return true;
+-}
+-#endif
+-
+-static AstLoadStoreAddress
+-AstDecodeLoadStoreAddress(const LinearMemoryAddress<Nothing>& addr, const AstDecodeStackItem& item)
+-{
+-    uint32_t flags = FloorLog2(addr.align);
+-    return AstLoadStoreAddress(item.expr, flags, addr.offset);
+-}
+-
+-static bool
+-AstDecodeLoad(AstDecodeContext& c, ValType type, uint32_t byteSize, Op op)
+-{
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readLoad(type, byteSize, &addr))
+-        return false;
+-
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstLoad* load = new(c.lifo) AstLoad(op, AstDecodeLoadStoreAddress(addr, item));
+-    if (!load)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(load)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeStore(AstDecodeContext& c, ValType type, uint32_t byteSize, Op op)
+-{
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readStore(type, byteSize, &addr, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem value = c.popCopy();
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstStore* store = new(c.lifo) AstStore(op, AstDecodeLoadStoreAddress(addr, item), value.expr);
+-    if (!store)
+-        return false;
+-
+-    AstExpr* wrapped = c.handleVoidExpr(store);
+-    if (!wrapped)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(wrapped)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeCurrentMemory(AstDecodeContext& c)
+-{
+-    if (!c.iter().readCurrentMemory())
+-        return false;
+-
+-    AstCurrentMemory* gm = new(c.lifo) AstCurrentMemory();
+-    if (!gm)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(gm)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeGrowMemory(AstDecodeContext& c)
+-{
+-    if (!c.iter().readGrowMemory(nullptr))
+-        return false;
+-
+-    AstDecodeStackItem operand = c.popCopy();
+-
+-    AstGrowMemory* gm = new(c.lifo) AstGrowMemory(operand.expr);
+-    if (!gm)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(gm)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeBranch(AstDecodeContext& c, Op op)
+-{
+-    MOZ_ASSERT(op == Op::Br || op == Op::BrIf);
+-
+-    uint32_t depth;
+-    ExprType type;
+-    AstDecodeStackItem value;
+-    AstDecodeStackItem cond;
+-    if (op == Op::Br) {
+-        if (!c.iter().readBr(&depth, &type, nullptr))
+-            return false;
+-        if (!IsVoid(type))
+-            value = c.popCopy();
+-    } else {
+-        if (!c.iter().readBrIf(&depth, &type, nullptr, nullptr))
+-            return false;
+-        if (!IsVoid(type))
+-            value = c.popCopy();
+-        cond = c.popCopy();
+-    }
+-
+-    AstRef depthRef;
+-    if (!AstDecodeGetBlockRef(c, depth, &depthRef))
+-        return false;
+-
+-    if (op == Op::Br || !value.expr)
+-        type = ExprType::Void;
+-    AstBranch* branch = new(c.lifo) AstBranch(op, type, cond.expr, depthRef, value.expr);
+-    if (!branch)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(branch)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeGetLocal(AstDecodeContext& c)
+-{
+-    uint32_t getLocalId;
+-    if (!c.iter().readGetLocal(c.locals(), &getLocalId))
+-        return false;
+-
+-    AstRef localRef;
+-    if (!GenerateRef(c, AstName(u"var"), getLocalId, &localRef))
+-        return false;
+-
+-    AstGetLocal* getLocal = new(c.lifo) AstGetLocal(localRef);
+-    if (!getLocal)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(getLocal)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeSetLocal(AstDecodeContext& c)
+-{
+-    uint32_t setLocalId;
+-    if (!c.iter().readSetLocal(c.locals(), &setLocalId, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem setLocalValue = c.popCopy();
+-
+-    AstRef localRef;
+-    if (!GenerateRef(c, AstName(u"var"), setLocalId, &localRef))
+-        return false;
+-
+-    AstSetLocal* setLocal = new(c.lifo) AstSetLocal(localRef, *setLocalValue.expr);
+-    if (!setLocal)
+-        return false;
+-
+-    AstExpr* expr = c.handleVoidExpr(setLocal);
+-    if (!expr)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(expr)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeTeeLocal(AstDecodeContext& c)
+-{
+-    uint32_t teeLocalId;
+-    if (!c.iter().readTeeLocal(c.locals(), &teeLocalId, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem teeLocalValue = c.popCopy();
+-
+-    AstRef localRef;
+-    if (!GenerateRef(c, AstName(u"var"), teeLocalId, &localRef))
+-        return false;
+-
+-    AstTeeLocal* teeLocal = new(c.lifo) AstTeeLocal(localRef, *teeLocalValue.expr);
+-    if (!teeLocal)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(teeLocal)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeGetGlobal(AstDecodeContext& c)
+-{
+-    uint32_t globalId;
+-    if (!c.iter().readGetGlobal(&globalId))
+-        return false;
+-
+-    AstRef globalRef;
+-    if (!GenerateRef(c, AstName(u"global"), globalId, &globalRef))
+-        return false;
+-
+-    auto* getGlobal = new(c.lifo) AstGetGlobal(globalRef);
+-    if (!getGlobal)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(getGlobal)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeSetGlobal(AstDecodeContext& c)
+-{
+-    uint32_t globalId;
+-    if (!c.iter().readSetGlobal(&globalId, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem value = c.popCopy();
+-
+-    AstRef globalRef;
+-    if (!GenerateRef(c, AstName(u"global"), globalId, &globalRef))
+-        return false;
+-
+-    auto* setGlobal = new(c.lifo) AstSetGlobal(globalRef, *value.expr);
+-    if (!setGlobal)
+-        return false;
+-
+-    AstExpr* expr = c.handleVoidExpr(setGlobal);
+-    if (!expr)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(expr)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeReturn(AstDecodeContext& c)
+-{
+-    if (!c.iter().readReturn(nullptr))
+-        return false;
+-
+-    AstDecodeStackItem result;
+-    if (!IsVoid(c.retType()))
+-       result = c.popCopy();
+-
+-    AstReturn* ret = new(c.lifo) AstReturn(result.expr);
+-    if (!ret)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(ret)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeAtomicLoad(AstDecodeContext& c, ThreadOp op)
+-{
+-    ValType type;
+-    uint32_t byteSize;
+-    switch (op) {
+-      case ThreadOp::I32AtomicLoad:    type = ValType::I32; byteSize = 4; break;
+-      case ThreadOp::I64AtomicLoad:    type = ValType::I64; byteSize = 8; break;
+-      case ThreadOp::I32AtomicLoad8U:  type = ValType::I32; byteSize = 1; break;
+-      case ThreadOp::I32AtomicLoad16U: type = ValType::I32; byteSize = 2; break;
+-      case ThreadOp::I64AtomicLoad8U:  type = ValType::I64; byteSize = 1; break;
+-      case ThreadOp::I64AtomicLoad16U: type = ValType::I64; byteSize = 2; break;
+-      case ThreadOp::I64AtomicLoad32U: type = ValType::I64; byteSize = 4; break;
+-      default:
+-        MOZ_CRASH("Should not happen");
+-    }
+-
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readAtomicLoad(&addr, type, byteSize))
+-        return false;
+-
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstAtomicLoad* load = new(c.lifo) AstAtomicLoad(op, AstDecodeLoadStoreAddress(addr, item));
+-    if (!load)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(load)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeAtomicStore(AstDecodeContext& c, ThreadOp op)
+-{
+-    ValType type;
+-    uint32_t byteSize;
+-    switch (op) {
+-      case ThreadOp::I32AtomicStore:    type = ValType::I32; byteSize = 4; break;
+-      case ThreadOp::I64AtomicStore:    type = ValType::I64; byteSize = 8; break;
+-      case ThreadOp::I32AtomicStore8U:  type = ValType::I32; byteSize = 1; break;
+-      case ThreadOp::I32AtomicStore16U: type = ValType::I32; byteSize = 2; break;
+-      case ThreadOp::I64AtomicStore8U:  type = ValType::I64; byteSize = 1; break;
+-      case ThreadOp::I64AtomicStore16U: type = ValType::I64; byteSize = 2; break;
+-      case ThreadOp::I64AtomicStore32U: type = ValType::I64; byteSize = 4; break;
+-      default:
+-        MOZ_CRASH("Should not happen");
+-    }
+-
+-    Nothing nothing;
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readAtomicStore(&addr, type, byteSize, &nothing))
+-        return false;
+-
+-    AstDecodeStackItem value = c.popCopy();
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstAtomicStore* store = new(c.lifo) AstAtomicStore(op, AstDecodeLoadStoreAddress(addr, item), value.expr);
+-    if (!store)
+-        return false;
+-
+-    AstExpr* wrapped = c.handleVoidExpr(store);
+-    if (!wrapped)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(wrapped)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeAtomicRMW(AstDecodeContext& c, ThreadOp op)
+-{
+-    ValType type;
+-    uint32_t byteSize;
+-    switch (op) {
+-      case ThreadOp::I32AtomicAdd:
+-      case ThreadOp::I32AtomicSub:
+-      case ThreadOp::I32AtomicAnd:
+-      case ThreadOp::I32AtomicOr:
+-      case ThreadOp::I32AtomicXor:
+-      case ThreadOp::I32AtomicXchg:
+-        type = ValType::I32;
+-        byteSize = 4;
+-        break;
+-      case ThreadOp::I64AtomicAdd:
+-      case ThreadOp::I64AtomicSub:
+-      case ThreadOp::I64AtomicAnd:
+-      case ThreadOp::I64AtomicOr:
+-      case ThreadOp::I64AtomicXor:
+-      case ThreadOp::I64AtomicXchg:
+-        type = ValType::I64;
+-        byteSize = 8;
+-        break;
+-      case ThreadOp::I32AtomicAdd8U:
+-      case ThreadOp::I32AtomicSub8U:
+-      case ThreadOp::I32AtomicOr8U:
+-      case ThreadOp::I32AtomicXor8U:
+-      case ThreadOp::I32AtomicXchg8U:
+-      case ThreadOp::I32AtomicAnd8U:
+-        type = ValType::I32;
+-        byteSize = 1;
+-        break;
+-      case ThreadOp::I32AtomicAdd16U:
+-      case ThreadOp::I32AtomicSub16U:
+-      case ThreadOp::I32AtomicAnd16U:
+-      case ThreadOp::I32AtomicOr16U:
+-      case ThreadOp::I32AtomicXor16U:
+-      case ThreadOp::I32AtomicXchg16U:
+-        type = ValType::I32;
+-        byteSize = 2;
+-        break;
+-      case ThreadOp::I64AtomicAdd8U:
+-      case ThreadOp::I64AtomicSub8U:
+-      case ThreadOp::I64AtomicAnd8U:
+-      case ThreadOp::I64AtomicOr8U:
+-      case ThreadOp::I64AtomicXor8U:
+-      case ThreadOp::I64AtomicXchg8U:
+-        type = ValType::I64;
+-        byteSize = 1;
+-        break;
+-      case ThreadOp::I64AtomicAdd16U:
+-      case ThreadOp::I64AtomicSub16U:
+-      case ThreadOp::I64AtomicAnd16U:
+-      case ThreadOp::I64AtomicOr16U:
+-      case ThreadOp::I64AtomicXor16U:
+-      case ThreadOp::I64AtomicXchg16U:
+-        type = ValType::I64;
+-        byteSize = 2;
+-        break;
+-      case ThreadOp::I64AtomicAdd32U:
+-      case ThreadOp::I64AtomicSub32U:
+-      case ThreadOp::I64AtomicAnd32U:
+-      case ThreadOp::I64AtomicOr32U:
+-      case ThreadOp::I64AtomicXor32U:
+-      case ThreadOp::I64AtomicXchg32U:
+-        type = ValType::I64;
+-        byteSize = 4;
+-        break;
+-      default:
+-        MOZ_CRASH("Should not happen");
+-    }
+-
+-    Nothing nothing;
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readAtomicRMW(&addr, type, byteSize, &nothing))
+-        return false;
+-
+-    AstDecodeStackItem value = c.popCopy();
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstAtomicRMW* rmw = new(c.lifo) AstAtomicRMW(op, AstDecodeLoadStoreAddress(addr, item),
+-                                                 value.expr);
+-    if (!rmw)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(rmw)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeAtomicCmpXchg(AstDecodeContext& c, ThreadOp op)
+-{
+-    ValType type;
+-    uint32_t byteSize;
+-    switch (op) {
+-      case ThreadOp::I32AtomicCmpXchg:    type = ValType::I32; byteSize = 4; break;
+-      case ThreadOp::I64AtomicCmpXchg:    type = ValType::I64; byteSize = 8; break;
+-      case ThreadOp::I32AtomicCmpXchg8U:  type = ValType::I32; byteSize = 1; break;
+-      case ThreadOp::I32AtomicCmpXchg16U: type = ValType::I32; byteSize = 2; break;
+-      case ThreadOp::I64AtomicCmpXchg8U:  type = ValType::I64; byteSize = 1; break;
+-      case ThreadOp::I64AtomicCmpXchg16U: type = ValType::I64; byteSize = 2; break;
+-      case ThreadOp::I64AtomicCmpXchg32U: type = ValType::I64; byteSize = 4; break;
+-      default:
+-        MOZ_CRASH("Should not happen");
+-    }
+-
+-    Nothing nothing;
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readAtomicCmpXchg(&addr, type, byteSize, &nothing, &nothing))
+-        return false;
+-
+-    AstDecodeStackItem replacement = c.popCopy();
+-    AstDecodeStackItem expected = c.popCopy();
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstAtomicCmpXchg* cmpxchg =
+-        new(c.lifo) AstAtomicCmpXchg(op, AstDecodeLoadStoreAddress(addr, item), expected.expr,
+-                                     replacement.expr);
+-    if (!cmpxchg)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(cmpxchg)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeWait(AstDecodeContext& c, ThreadOp op)
+-{
+-    ValType type;
+-    uint32_t byteSize;
+-    switch (op) {
+-      case ThreadOp::I32Wait: type = ValType::I32; byteSize = 4; break;
+-      case ThreadOp::I64Wait: type = ValType::I64; byteSize = 8; break;
+-      default:
+-        MOZ_CRASH("Should not happen");
+-    }
+-
+-    Nothing nothing;
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readWait(&addr, type, byteSize, &nothing, &nothing))
+-        return false;
+-
+-    AstDecodeStackItem timeout = c.popCopy();
+-    AstDecodeStackItem value = c.popCopy();
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstWait* wait = new(c.lifo) AstWait(op, AstDecodeLoadStoreAddress(addr, item), value.expr,
+-                                        timeout.expr);
+-    if (!wait)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(wait)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeWake(AstDecodeContext& c)
+-{
+-    Nothing nothing;
+-    LinearMemoryAddress<Nothing> addr;
+-    if (!c.iter().readWake(&addr, &nothing))
+-        return false;
+-
+-    AstDecodeStackItem count = c.popCopy();
+-    AstDecodeStackItem item = c.popCopy();
+-
+-    AstWake* wake = new(c.lifo) AstWake(AstDecodeLoadStoreAddress(addr, item), count.expr);
+-    if (!wake)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(wake)))
+-        return false;
+-
+-    return true;
+-}
+-
+-#ifdef ENABLE_WASM_BULKMEM_OPS
+-static bool
+-AstDecodeMemCopy(AstDecodeContext& c)
+-{
+-    if (!c.iter().readMemCopy(nullptr, nullptr, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem dest = c.popCopy();
+-    AstDecodeStackItem src  = c.popCopy();
+-    AstDecodeStackItem len  = c.popCopy();
+-
+-    AstMemCopy* mc = new(c.lifo) AstMemCopy(dest.expr, src.expr, len.expr);
+-
+-    if (!mc)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(mc)))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeMemFill(AstDecodeContext& c)
+-{
+-    if (!c.iter().readMemFill(nullptr, nullptr, nullptr))
+-        return false;
+-
+-    AstDecodeStackItem len   = c.popCopy();
+-    AstDecodeStackItem val   = c.popCopy();
+-    AstDecodeStackItem start = c.popCopy();
+-
+-    AstMemFill* mf = new(c.lifo) AstMemFill(start.expr, val.expr, len.expr);
+-
+-    if (!mf)
+-        return false;
+-
+-    if (!c.push(AstDecodeStackItem(mf)))
+-        return false;
+-
+-    return true;
+-}
+-#endif
+-
+-static bool
+-AstDecodeExpr(AstDecodeContext& c)
+-{
+-    uint32_t exprOffset = c.iter().currentOffset();
+-    OpBytes op;
+-    if (!c.iter().readOp(&op))
+-        return false;
+-
+-    AstExpr* tmp;
+-    switch (op.b0) {
+-      case uint16_t(Op::Nop):
+-        if (!AstDecodeNop(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Drop):
+-        if (!AstDecodeDrop(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Call):
+-        if (!AstDecodeCall(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::CallIndirect):
+-        if (!AstDecodeCallIndirect(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Const):
+-        int32_t i32;
+-        if (!c.iter().readI32Const(&i32))
+-            return false;
+-        tmp = new(c.lifo) AstConst(Val((uint32_t)i32));
+-        if (!tmp || !c.push(AstDecodeStackItem(tmp)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Const):
+-        int64_t i64;
+-        if (!c.iter().readI64Const(&i64))
+-            return false;
+-        tmp = new(c.lifo) AstConst(Val((uint64_t)i64));
+-        if (!tmp || !c.push(AstDecodeStackItem(tmp)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32Const): {
+-        float f32;
+-        if (!c.iter().readF32Const(&f32))
+-            return false;
+-        tmp = new(c.lifo) AstConst(Val(f32));
+-        if (!tmp || !c.push(AstDecodeStackItem(tmp)))
+-            return false;
+-        break;
+-      }
+-      case uint16_t(Op::F64Const): {
+-        double f64;
+-        if (!c.iter().readF64Const(&f64))
+-            return false;
+-        tmp = new(c.lifo) AstConst(Val(f64));
+-        if (!tmp || !c.push(AstDecodeStackItem(tmp)))
+-            return false;
+-        break;
+-      }
+-      case uint16_t(Op::GetLocal):
+-        if (!AstDecodeGetLocal(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::SetLocal):
+-        if (!AstDecodeSetLocal(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::TeeLocal):
+-        if (!AstDecodeTeeLocal(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Select):
+-        if (!AstDecodeSelect(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Block):
+-      case uint16_t(Op::Loop):
+-        if (!AstDecodeBlock(c, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::If):
+-        if (!AstDecodeIf(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Else):
+-        if (!AstDecodeElse(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::End):
+-        if (!AstDecodeEnd(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Clz):
+-      case uint16_t(Op::I32Ctz):
+-      case uint16_t(Op::I32Popcnt):
+-        if (!AstDecodeUnary(c, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Clz):
+-      case uint16_t(Op::I64Ctz):
+-      case uint16_t(Op::I64Popcnt):
+-        if (!AstDecodeUnary(c, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32Abs):
+-      case uint16_t(Op::F32Neg):
+-      case uint16_t(Op::F32Ceil):
+-      case uint16_t(Op::F32Floor):
+-      case uint16_t(Op::F32Sqrt):
+-      case uint16_t(Op::F32Trunc):
+-      case uint16_t(Op::F32Nearest):
+-        if (!AstDecodeUnary(c, ValType::F32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64Abs):
+-      case uint16_t(Op::F64Neg):
+-      case uint16_t(Op::F64Ceil):
+-      case uint16_t(Op::F64Floor):
+-      case uint16_t(Op::F64Sqrt):
+-      case uint16_t(Op::F64Trunc):
+-      case uint16_t(Op::F64Nearest):
+-        if (!AstDecodeUnary(c, ValType::F64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Add):
+-      case uint16_t(Op::I32Sub):
+-      case uint16_t(Op::I32Mul):
+-      case uint16_t(Op::I32DivS):
+-      case uint16_t(Op::I32DivU):
+-      case uint16_t(Op::I32RemS):
+-      case uint16_t(Op::I32RemU):
+-      case uint16_t(Op::I32And):
+-      case uint16_t(Op::I32Or):
+-      case uint16_t(Op::I32Xor):
+-      case uint16_t(Op::I32Shl):
+-      case uint16_t(Op::I32ShrS):
+-      case uint16_t(Op::I32ShrU):
+-      case uint16_t(Op::I32Rotl):
+-      case uint16_t(Op::I32Rotr):
+-        if (!AstDecodeBinary(c, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Add):
+-      case uint16_t(Op::I64Sub):
+-      case uint16_t(Op::I64Mul):
+-      case uint16_t(Op::I64DivS):
+-      case uint16_t(Op::I64DivU):
+-      case uint16_t(Op::I64RemS):
+-      case uint16_t(Op::I64RemU):
+-      case uint16_t(Op::I64And):
+-      case uint16_t(Op::I64Or):
+-      case uint16_t(Op::I64Xor):
+-      case uint16_t(Op::I64Shl):
+-      case uint16_t(Op::I64ShrS):
+-      case uint16_t(Op::I64ShrU):
+-      case uint16_t(Op::I64Rotl):
+-      case uint16_t(Op::I64Rotr):
+-        if (!AstDecodeBinary(c, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32Add):
+-      case uint16_t(Op::F32Sub):
+-      case uint16_t(Op::F32Mul):
+-      case uint16_t(Op::F32Div):
+-      case uint16_t(Op::F32Min):
+-      case uint16_t(Op::F32Max):
+-      case uint16_t(Op::F32CopySign):
+-        if (!AstDecodeBinary(c, ValType::F32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64Add):
+-      case uint16_t(Op::F64Sub):
+-      case uint16_t(Op::F64Mul):
+-      case uint16_t(Op::F64Div):
+-      case uint16_t(Op::F64Min):
+-      case uint16_t(Op::F64Max):
+-      case uint16_t(Op::F64CopySign):
+-        if (!AstDecodeBinary(c, ValType::F64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Eq):
+-      case uint16_t(Op::I32Ne):
+-      case uint16_t(Op::I32LtS):
+-      case uint16_t(Op::I32LtU):
+-      case uint16_t(Op::I32LeS):
+-      case uint16_t(Op::I32LeU):
+-      case uint16_t(Op::I32GtS):
+-      case uint16_t(Op::I32GtU):
+-      case uint16_t(Op::I32GeS):
+-      case uint16_t(Op::I32GeU):
+-        if (!AstDecodeComparison(c, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Eq):
+-      case uint16_t(Op::I64Ne):
+-      case uint16_t(Op::I64LtS):
+-      case uint16_t(Op::I64LtU):
+-      case uint16_t(Op::I64LeS):
+-      case uint16_t(Op::I64LeU):
+-      case uint16_t(Op::I64GtS):
+-      case uint16_t(Op::I64GtU):
+-      case uint16_t(Op::I64GeS):
+-      case uint16_t(Op::I64GeU):
+-        if (!AstDecodeComparison(c, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32Eq):
+-      case uint16_t(Op::F32Ne):
+-      case uint16_t(Op::F32Lt):
+-      case uint16_t(Op::F32Le):
+-      case uint16_t(Op::F32Gt):
+-      case uint16_t(Op::F32Ge):
+-        if (!AstDecodeComparison(c, ValType::F32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64Eq):
+-      case uint16_t(Op::F64Ne):
+-      case uint16_t(Op::F64Lt):
+-      case uint16_t(Op::F64Le):
+-      case uint16_t(Op::F64Gt):
+-      case uint16_t(Op::F64Ge):
+-        if (!AstDecodeComparison(c, ValType::F64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Eqz):
+-        if (!AstDecodeConversion(c, ValType::I32, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Eqz):
+-      case uint16_t(Op::I32WrapI64):
+-        if (!AstDecodeConversion(c, ValType::I64, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32TruncSF32):
+-      case uint16_t(Op::I32TruncUF32):
+-      case uint16_t(Op::I32ReinterpretF32):
+-        if (!AstDecodeConversion(c, ValType::F32, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32TruncSF64):
+-      case uint16_t(Op::I32TruncUF64):
+-        if (!AstDecodeConversion(c, ValType::F64, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64ExtendSI32):
+-      case uint16_t(Op::I64ExtendUI32):
+-        if (!AstDecodeConversion(c, ValType::I32, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64TruncSF32):
+-      case uint16_t(Op::I64TruncUF32):
+-        if (!AstDecodeConversion(c, ValType::F32, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64TruncSF64):
+-      case uint16_t(Op::I64TruncUF64):
+-      case uint16_t(Op::I64ReinterpretF64):
+-        if (!AstDecodeConversion(c, ValType::F64, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32ConvertSI32):
+-      case uint16_t(Op::F32ConvertUI32):
+-      case uint16_t(Op::F32ReinterpretI32):
+-        if (!AstDecodeConversion(c, ValType::I32, ValType::F32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32ConvertSI64):
+-      case uint16_t(Op::F32ConvertUI64):
+-        if (!AstDecodeConversion(c, ValType::I64, ValType::F32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32DemoteF64):
+-        if (!AstDecodeConversion(c, ValType::F64, ValType::F32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64ConvertSI32):
+-      case uint16_t(Op::F64ConvertUI32):
+-        if (!AstDecodeConversion(c, ValType::I32, ValType::F64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64ConvertSI64):
+-      case uint16_t(Op::F64ConvertUI64):
+-      case uint16_t(Op::F64ReinterpretI64):
+-        if (!AstDecodeConversion(c, ValType::I64, ValType::F64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64PromoteF32):
+-        if (!AstDecodeConversion(c, ValType::F32, ValType::F64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Extend8S):
+-      case uint16_t(Op::I32Extend16S):
+-        if (!AstDecodeConversion(c, ValType::I32, ValType::I32, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Extend8S):
+-      case uint16_t(Op::I64Extend16S):
+-      case uint16_t(Op::I64Extend32S):
+-        if (!AstDecodeConversion(c, ValType::I64, ValType::I64, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Load8S):
+-      case uint16_t(Op::I32Load8U):
+-        if (!AstDecodeLoad(c, ValType::I32, 1, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Load16S):
+-      case uint16_t(Op::I32Load16U):
+-        if (!AstDecodeLoad(c, ValType::I32, 2, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Load):
+-        if (!AstDecodeLoad(c, ValType::I32, 4, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Load8S):
+-      case uint16_t(Op::I64Load8U):
+-        if (!AstDecodeLoad(c, ValType::I64, 1, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Load16S):
+-      case uint16_t(Op::I64Load16U):
+-        if (!AstDecodeLoad(c, ValType::I64, 2, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Load32S):
+-      case uint16_t(Op::I64Load32U):
+-        if (!AstDecodeLoad(c, ValType::I64, 4, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Load):
+-        if (!AstDecodeLoad(c, ValType::I64, 8, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32Load):
+-        if (!AstDecodeLoad(c, ValType::F32, 4, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64Load):
+-        if (!AstDecodeLoad(c, ValType::F64, 8, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Store8):
+-        if (!AstDecodeStore(c, ValType::I32, 1, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Store16):
+-        if (!AstDecodeStore(c, ValType::I32, 2, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I32Store):
+-        if (!AstDecodeStore(c, ValType::I32, 4, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Store8):
+-        if (!AstDecodeStore(c, ValType::I64, 1, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Store16):
+-        if (!AstDecodeStore(c, ValType::I64, 2, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Store32):
+-        if (!AstDecodeStore(c, ValType::I64, 4, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::I64Store):
+-        if (!AstDecodeStore(c, ValType::I64, 8, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F32Store):
+-        if (!AstDecodeStore(c, ValType::F32, 4, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::F64Store):
+-        if (!AstDecodeStore(c, ValType::F64, 8, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::CurrentMemory):
+-        if (!AstDecodeCurrentMemory(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::GrowMemory):
+-        if (!AstDecodeGrowMemory(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::SetGlobal):
+-        if (!AstDecodeSetGlobal(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::GetGlobal):
+-        if (!AstDecodeGetGlobal(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Br):
+-      case uint16_t(Op::BrIf):
+-        if (!AstDecodeBranch(c, Op(op.b0)))
+-            return false;
+-        break;
+-      case uint16_t(Op::BrTable):
+-        if (!AstDecodeBrTable(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Return):
+-        if (!AstDecodeReturn(c))
+-            return false;
+-        break;
+-      case uint16_t(Op::Unreachable):
+-        if (!c.iter().readUnreachable())
+-            return false;
+-        tmp = new(c.lifo) AstUnreachable();
+-        if (!tmp)
+-            return false;
+-        if (!c.push(AstDecodeStackItem(tmp)))
+-            return false;
+-        break;
+-      case uint16_t(Op::MiscPrefix):
+-        switch (op.b1) {
+-#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
+-          case uint16_t(MiscOp::I32TruncSSatF32):
+-          case uint16_t(MiscOp::I32TruncUSatF32):
+-            if (!AstDecodeExtraConversion(c, ValType::F32, ValType::I32, MiscOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(MiscOp::I32TruncSSatF64):
+-          case uint16_t(MiscOp::I32TruncUSatF64):
+-            if (!AstDecodeExtraConversion(c, ValType::F64, ValType::I32, MiscOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(MiscOp::I64TruncSSatF32):
+-          case uint16_t(MiscOp::I64TruncUSatF32):
+-            if (!AstDecodeExtraConversion(c, ValType::F32, ValType::I64, MiscOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(MiscOp::I64TruncSSatF64):
+-          case uint16_t(MiscOp::I64TruncUSatF64):
+-            if (!AstDecodeExtraConversion(c, ValType::F64, ValType::I64, MiscOp(op.b1)))
+-                return false;
+-            break;
+-#endif
+-#ifdef ENABLE_WASM_BULKMEM_OPS
+-          case uint16_t(MiscOp::MemCopy):
+-            if (!AstDecodeMemCopy(c))
+-                return false;
+-            break;
+-          case uint16_t(MiscOp::MemFill):
+-            if (!AstDecodeMemFill(c))
+-                return false;
+-            break;
+-#endif
+-          default:
+-            return c.iter().unrecognizedOpcode(&op);
+-        }
+-        break;
+-      case uint16_t(Op::ThreadPrefix):
+-        switch (op.b1) {
+-          case uint16_t(ThreadOp::Wake):
+-            if (!AstDecodeWake(c))
+-                return false;
+-            break;
+-          case uint16_t(ThreadOp::I32Wait):
+-          case uint16_t(ThreadOp::I64Wait):
+-            if (!AstDecodeWait(c, ThreadOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(ThreadOp::I32AtomicLoad):
+-          case uint16_t(ThreadOp::I64AtomicLoad):
+-          case uint16_t(ThreadOp::I32AtomicLoad8U):
+-          case uint16_t(ThreadOp::I32AtomicLoad16U):
+-          case uint16_t(ThreadOp::I64AtomicLoad8U):
+-          case uint16_t(ThreadOp::I64AtomicLoad16U):
+-          case uint16_t(ThreadOp::I64AtomicLoad32U):
+-            if (!AstDecodeAtomicLoad(c, ThreadOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(ThreadOp::I32AtomicStore):
+-          case uint16_t(ThreadOp::I64AtomicStore):
+-          case uint16_t(ThreadOp::I32AtomicStore8U):
+-          case uint16_t(ThreadOp::I32AtomicStore16U):
+-          case uint16_t(ThreadOp::I64AtomicStore8U):
+-          case uint16_t(ThreadOp::I64AtomicStore16U):
+-          case uint16_t(ThreadOp::I64AtomicStore32U):
+-            if (!AstDecodeAtomicStore(c, ThreadOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(ThreadOp::I32AtomicAdd):
+-          case uint16_t(ThreadOp::I64AtomicAdd):
+-          case uint16_t(ThreadOp::I32AtomicAdd8U):
+-          case uint16_t(ThreadOp::I32AtomicAdd16U):
+-          case uint16_t(ThreadOp::I64AtomicAdd8U):
+-          case uint16_t(ThreadOp::I64AtomicAdd16U):
+-          case uint16_t(ThreadOp::I64AtomicAdd32U):
+-          case uint16_t(ThreadOp::I32AtomicSub):
+-          case uint16_t(ThreadOp::I64AtomicSub):
+-          case uint16_t(ThreadOp::I32AtomicSub8U):
+-          case uint16_t(ThreadOp::I32AtomicSub16U):
+-          case uint16_t(ThreadOp::I64AtomicSub8U):
+-          case uint16_t(ThreadOp::I64AtomicSub16U):
+-          case uint16_t(ThreadOp::I64AtomicSub32U):
+-          case uint16_t(ThreadOp::I32AtomicAnd):
+-          case uint16_t(ThreadOp::I64AtomicAnd):
+-          case uint16_t(ThreadOp::I32AtomicAnd8U):
+-          case uint16_t(ThreadOp::I32AtomicAnd16U):
+-          case uint16_t(ThreadOp::I64AtomicAnd8U):
+-          case uint16_t(ThreadOp::I64AtomicAnd16U):
+-          case uint16_t(ThreadOp::I64AtomicAnd32U):
+-          case uint16_t(ThreadOp::I32AtomicOr):
+-          case uint16_t(ThreadOp::I64AtomicOr):
+-          case uint16_t(ThreadOp::I32AtomicOr8U):
+-          case uint16_t(ThreadOp::I32AtomicOr16U):
+-          case uint16_t(ThreadOp::I64AtomicOr8U):
+-          case uint16_t(ThreadOp::I64AtomicOr16U):
+-          case uint16_t(ThreadOp::I64AtomicOr32U):
+-          case uint16_t(ThreadOp::I32AtomicXor):
+-          case uint16_t(ThreadOp::I64AtomicXor):
+-          case uint16_t(ThreadOp::I32AtomicXor8U):
+-          case uint16_t(ThreadOp::I32AtomicXor16U):
+-          case uint16_t(ThreadOp::I64AtomicXor8U):
+-          case uint16_t(ThreadOp::I64AtomicXor16U):
+-          case uint16_t(ThreadOp::I64AtomicXor32U):
+-          case uint16_t(ThreadOp::I32AtomicXchg):
+-          case uint16_t(ThreadOp::I64AtomicXchg):
+-          case uint16_t(ThreadOp::I32AtomicXchg8U):
+-          case uint16_t(ThreadOp::I32AtomicXchg16U):
+-          case uint16_t(ThreadOp::I64AtomicXchg8U):
+-          case uint16_t(ThreadOp::I64AtomicXchg16U):
+-          case uint16_t(ThreadOp::I64AtomicXchg32U):
+-            if (!AstDecodeAtomicRMW(c, ThreadOp(op.b1)))
+-                return false;
+-            break;
+-          case uint16_t(ThreadOp::I32AtomicCmpXchg):
+-          case uint16_t(ThreadOp::I64AtomicCmpXchg):
+-          case uint16_t(ThreadOp::I32AtomicCmpXchg8U):
+-          case uint16_t(ThreadOp::I32AtomicCmpXchg16U):
+-          case uint16_t(ThreadOp::I64AtomicCmpXchg8U):
+-          case uint16_t(ThreadOp::I64AtomicCmpXchg16U):
+-          case uint16_t(ThreadOp::I64AtomicCmpXchg32U):
+-            if (!AstDecodeAtomicCmpXchg(c, ThreadOp(op.b1)))
+-                return false;
+-            break;
+-          default:
+-            return c.iter().unrecognizedOpcode(&op);
+-        }
+-        break;
+-      case uint16_t(Op::MozPrefix):
+-        return c.iter().unrecognizedOpcode(&op);
+-      default:
+-        return c.iter().unrecognizedOpcode(&op);
+-    }
+-
+-    AstExpr* lastExpr = c.top().expr;
+-    if (lastExpr) {
+-        // If last node is a 'first' node, the offset must assigned to it
+-        // last child.
+-        if (lastExpr->kind() == AstExprKind::First)
+-            lastExpr->as<AstFirst>().exprs().back()->setOffset(exprOffset);
+-        else
+-            lastExpr->setOffset(exprOffset);
+-    }
+-    return true;
+-}
+-
+-static bool
+-AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
+-{
+-    uint32_t offset = c.d.currentOffset();
+-    uint32_t bodySize;
+-    if (!c.d.readVarU32(&bodySize))
+-        return c.d.fail("expected number of function body bytes");
+-
+-    if (c.d.bytesRemain() < bodySize)
+-        return c.d.fail("function body length too big");
+-
+-    const uint8_t* bodyBegin = c.d.currentPosition();
+-    const uint8_t* bodyEnd = bodyBegin + bodySize;
+-
+-    const FuncTypeWithId* funcType = c.env().funcTypes[funcIndex];
+-
+-    ValTypeVector locals;
+-    if (!locals.appendAll(funcType->args()))
+-        return false;
+-
+-    if (!DecodeLocalEntries(c.d, ModuleKind::Wasm, c.env().gcTypesEnabled, &locals))
+-        return false;
+-
+-    AstDecodeOpIter iter(c.env(), c.d);
+-    c.startFunction(&iter, &locals, funcType->ret());
+-
+-    AstName funcName;
+-    if (!GenerateName(c, AstName(u"func"), funcIndex, &funcName))
+-        return false;
+-
+-    uint32_t numParams = funcType->args().length();
+-    uint32_t numLocals = locals.length();
+-
+-    AstValTypeVector vars(c.lifo);
+-    for (uint32_t i = numParams; i < numLocals; i++) {
+-        if (!vars.append(locals[i]))
+-            return false;
+-    }
+-
+-    AstNameVector localsNames(c.lifo);
+-    for (uint32_t i = 0; i < numLocals; i++) {
+-        AstName varName;
+-        if (!GenerateName(c, AstName(u"var"), i, &varName))
+-            return false;
+-        if (!localsNames.append(varName))
+-            return false;
+-    }
+-
+-    if (!c.iter().readFunctionStart(funcType->ret()))
+-        return false;
+-
+-    if (!c.depths().append(c.exprs().length()))
+-        return false;
+-
+-    uint32_t endOffset = offset;
+-    while (c.d.currentPosition() < bodyEnd) {
+-        if (!AstDecodeExpr(c))
+-            return false;
+-
+-        const AstDecodeStackItem& item = c.top();
+-        if (!item.expr) { // Op::End was found
+-            c.popBack();
+-            break;
+-        }
+-
+-        endOffset = c.d.currentOffset();
+-    }
+-
+-    AstExprVector body(c.lifo);
+-    for (auto i = c.exprs().begin() + c.depths().back(), e = c.exprs().end(); i != e; ++i) {
+-        if (!body.append(i->expr))
+-            return false;
+-    }
+-    c.exprs().shrinkTo(c.depths().popCopy());
+-
+-    if (!c.iter().readFunctionEnd(bodyEnd))
+-        return false;
+-
+-    c.endFunction();
+-
+-    if (c.d.currentPosition() != bodyEnd)
+-        return c.d.fail("function body length mismatch");
+-
+-    size_t funcTypeIndex = c.env().funcIndexToFuncTypeIndex(funcIndex);
+-
+-    AstRef funcTypeRef;
+-    if (!GenerateRef(c, AstName(u"type"), funcTypeIndex, &funcTypeRef))
+-        return false;
+-
+-    *func = new(c.lifo) AstFunc(funcName, funcTypeRef, std::move(vars), std::move(localsNames),
+-                                std::move(body));
+-    if (!*func)
+-        return false;
+-    (*func)->setOffset(offset);
+-    (*func)->setEndOffset(endOffset);
+-
+-    return true;
+-}
+-
+-/*****************************************************************************/
+-// wasm decoding and generation
+-
+-static bool
+-AstCreateTypes(AstDecodeContext& c)
+-{
+-    uint32_t typeIndexForNames = 0;
+-    for (const TypeDef& td : c.env().types) {
+-        if (td.isFuncType()) {
+-            const FuncType& funcType = td.funcType();
+-
+-            AstValTypeVector args(c.lifo);
+-            if (!args.appendAll(funcType.args()))
+-                return false;
+-
+-            AstFuncType ftNoName(std::move(args), funcType.ret());
+-
+-            AstName ftName;
+-            if (!GenerateName(c, AstName(u"type"), typeIndexForNames, &ftName))
+-                return false;
+-
+-            AstFuncType* astFuncType = new(c.lifo) AstFuncType(ftName, std::move(ftNoName));
+-            if (!astFuncType || !c.module().append(astFuncType))
+-                return false;
+-        } else if (td.isStructType()) {
+-            const StructType& st = td.structType();
+-
+-            AstValTypeVector fieldTypes(c.lifo);
+-            if (!fieldTypes.appendAll(st.fields_))
+-                return false;
+-
+-            AstNameVector fieldNames(c.lifo);
+-            if (!fieldNames.resize(fieldTypes.length()))
+-                return false;
+-
+-            // The multiplication ensures that generated field names are unique
+-            // within the module, though the resulting namespace is very sparse.
+-
+-            for (size_t fieldIndex = 0; fieldIndex < fieldTypes.length(); fieldIndex++) {
+-                size_t idx = (typeIndexForNames * MaxStructFields) + fieldIndex;
+-                if (!GenerateName(c, AstName(u"f"), idx, &fieldNames[fieldIndex]))
+-                    return false;
+-            }
+-
+-            AstStructType stNoName(std::move(fieldNames), std::move(fieldTypes));
+-
+-            AstName stName;
+-            if (!GenerateName(c, AstName(u"type"), typeIndexForNames, &stName))
+-                return false;
+-
+-            AstStructType* astStruct = new(c.lifo) AstStructType(stName, std::move(stNoName));
+-            if (!astStruct || !c.module().append(astStruct))
+-                return false;
+-        } else {
+-            MOZ_CRASH();
+-        }
+-        typeIndexForNames++;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-ToAstName(AstDecodeContext& c, const char* name, AstName* out)
+-{
+-    size_t len = strlen(name);
+-    char16_t* buffer = static_cast<char16_t *>(c.lifo.alloc(len * sizeof(char16_t)));
+-    if (!buffer)
+-        return false;
+-
+-    for (size_t i = 0; i < len; i++)
+-        buffer[i] = name[i];
+-
+-    *out = AstName(buffer, len);
+-    return true;
+-}
+-
+-static bool
+-AstCreateImports(AstDecodeContext& c)
+-{
+-    size_t lastFunc = 0;
+-    size_t lastGlobal = 0;
+-    size_t lastTable = 0;
+-    size_t lastMemory = 0;
+-
+-    Maybe<Limits> memory;
+-    if (c.env().usesMemory()) {
+-        memory = Some(Limits(c.env().minMemoryLength,
+-                             c.env().maxMemoryLength,
+-                             c.env().memoryUsage == MemoryUsage::Shared
+-                               ? Shareable::True
+-                               : Shareable::False));
+-    }
+-
+-    for (size_t importIndex = 0; importIndex < c.env().imports.length(); importIndex++) {
+-        const Import& import = c.env().imports[importIndex];
+-
+-        AstName moduleName;
+-        if (!ToAstName(c, import.module.get(), &moduleName))
+-            return false;
+-
+-        AstName fieldName;
+-        if (!ToAstName(c, import.field.get(), &fieldName))
+-            return false;
+-
+-        AstImport* ast = nullptr;
+-        switch (import.kind) {
+-          case DefinitionKind::Function: {
+-            AstName importName;
+-            if (!GenerateName(c, AstName(u"import"), lastFunc, &importName))
+-                return false;
+-
+-            size_t funcTypeIndex = c.env().funcIndexToFuncTypeIndex(lastFunc);
+-
+-            AstRef funcTypeRef;
+-            if (!GenerateRef(c, AstName(u"type"), funcTypeIndex, &funcTypeRef))
+-                return false;
+-
+-            ast = new(c.lifo) AstImport(importName, moduleName, fieldName, funcTypeRef);
+-            lastFunc++;
+-            break;
+-          }
+-          case DefinitionKind::Global: {
+-            AstName importName;
+-            if (!GenerateName(c, AstName(u"global"), lastGlobal, &importName))
+-                return false;
+-
+-            const GlobalDesc& global = c.env().globals[lastGlobal];
+-            ValType type = global.type();
+-            bool isMutable = global.isMutable();
+-
+-            ast = new(c.lifo) AstImport(importName, moduleName, fieldName,
+-                                        AstGlobal(importName, type, isMutable));
+-            lastGlobal++;
+-            break;
+-          }
+-          case DefinitionKind::Table: {
+-            AstName importName;
+-            if (!GenerateName(c, AstName(u"table"), lastTable, &importName))
+-                return false;
+-
+-            ast = new(c.lifo) AstImport(importName, moduleName, fieldName, DefinitionKind::Table,
+-                                        c.env().tables[lastTable].limits);
+-            lastTable++;
+-            break;
+-          }
+-          case DefinitionKind::Memory: {
+-            AstName importName;
+-            if (!GenerateName(c, AstName(u"memory"), lastMemory, &importName))
+-                return false;
+-
+-            ast = new(c.lifo) AstImport(importName, moduleName, fieldName, DefinitionKind::Memory,
+-                                        *memory);
+-            lastMemory++;
+-            break;
+-          }
+-        }
+-
+-        if (!ast || !c.module().append(ast))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-AstCreateTables(AstDecodeContext& c)
+-{
+-    size_t numImported = c.module().tables().length();
+-
+-    for (size_t i = numImported; i < c.env().tables.length(); i++) {
+-        AstName name;
+-        if (!GenerateName(c, AstName(u"table"), i, &name))
+-            return false;
+-        if (!c.module().addTable(name, c.env().tables[i].limits))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-AstCreateMemory(AstDecodeContext& c)
+-{
+-    bool importedMemory = !!c.module().memories().length();
+-    if (!c.env().usesMemory() || importedMemory)
+-        return true;
+-
+-    AstName name;
+-    if (!GenerateName(c, AstName(u"memory"), c.module().memories().length(), &name))
+-        return false;
+-
+-    return c.module().addMemory(name, Limits(c.env().minMemoryLength,
+-                                             c.env().maxMemoryLength,
+-                                             c.env().memoryUsage == MemoryUsage::Shared
+-                                               ? Shareable::True
+-                                               : Shareable::False));
+-}
+-
+-static AstExpr*
+-ToAstExpr(AstDecodeContext& c, const InitExpr& initExpr)
+-{
+-    switch (initExpr.kind()) {
+-      case InitExpr::Kind::Constant: {
+-        return new(c.lifo) AstConst(Val(initExpr.val()));
+-      }
+-      case InitExpr::Kind::GetGlobal: {
+-        AstRef globalRef;
+-        if (!GenerateRef(c, AstName(u"global"), initExpr.globalIndex(), &globalRef))
+-            return nullptr;
+-        return new(c.lifo) AstGetGlobal(globalRef);
+-      }
+-    }
+-    return nullptr;
+-}
+-
+-static bool
+-AstCreateGlobals(AstDecodeContext& c)
+-{
+-    for (uint32_t i = 0; i < c.env().globals.length(); i++) {
+-        const GlobalDesc& global = c.env().globals[i];
+-        if (global.isImport())
+-            continue;
+-
+-        AstName name;
+-        if (!GenerateName(c, AstName(u"global"), i, &name))
+-            return false;
+-
+-        AstExpr* init = global.isConstant()
+-                        ? new(c.lifo) AstConst(global.constantValue())
+-                        : ToAstExpr(c, global.initExpr());
+-        if (!init)
+-            return false;
+-
+-        auto* g = new(c.lifo) AstGlobal(name, global.type(), global.isMutable(), Some(init));
+-        if (!g || !c.module().append(g))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-AstCreateExports(AstDecodeContext& c)
+-{
+-    for (const Export& exp : c.env().exports) {
+-        size_t index;
+-        switch (exp.kind()) {
+-          case DefinitionKind::Function: index = exp.funcIndex(); break;
+-          case DefinitionKind::Global: index = exp.globalIndex(); break;
+-          case DefinitionKind::Memory: index = 0; break;
+-          case DefinitionKind::Table: index = 0; break;
+-        }
+-
+-        AstName name;
+-        if (!ToAstName(c, exp.fieldName(), &name))
+-            return false;
+-
+-        AstExport* e = new(c.lifo) AstExport(name, exp.kind(), AstRef(index));
+-        if (!e || !c.module().append(e))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-AstCreateStartFunc(AstDecodeContext &c)
+-{
+-    if (!c.env().startFuncIndex)
+-        return true;
+-
+-    AstRef funcRef;
+-    if (!GenerateFuncRef(c, *c.env().startFuncIndex, &funcRef))
+-        return false;
+-
+-    c.module().setStartFunc(AstStartFunc(funcRef));
+-    return true;
+-}
+-
+-static bool
+-AstCreateElems(AstDecodeContext &c)
+-{
+-    for (const ElemSegment& seg : c.env().elemSegments) {
+-        AstRefVector elems(c.lifo);
+-        if (!elems.reserve(seg.elemFuncIndices.length()))
+-            return false;
+-
+-        for (uint32_t i : seg.elemFuncIndices)
+-            elems.infallibleAppend(AstRef(i));
+-
+-        AstExpr* offset = ToAstExpr(c, seg.offset);
+-        if (!offset)
+-            return false;
+-
+-        AstElemSegment* segment = new(c.lifo) AstElemSegment(offset, std::move(elems));
+-        if (!segment || !c.module().append(segment))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeEnvironment(AstDecodeContext& c)
+-{
+-    if (!DecodeModuleEnvironment(c.d, &c.env()))
+-        return false;
+-
+-    if (!AstCreateTypes(c))
+-        return false;
+-
+-    if (!AstCreateImports(c))
+-        return false;
+-
+-    if (!AstCreateTables(c))
+-        return false;
+-
+-    if (!AstCreateMemory(c))
+-        return false;
+-
+-    if (!AstCreateGlobals(c))
+-        return false;
+-
+-    if (!AstCreateExports(c))
+-        return false;
+-
+-    if (!AstCreateStartFunc(c))
+-        return false;
+-
+-    if (!AstCreateElems(c))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-AstDecodeCodeSection(AstDecodeContext& c)
+-{
+-    if (!c.env().codeSection) {
+-        if (c.env().numFuncDefs() != 0)
+-            return c.d.fail("expected function bodies");
+-        return true;
+-    }
+-
+-    uint32_t numFuncBodies;
+-    if (!c.d.readVarU32(&numFuncBodies))
+-        return c.d.fail("expected function body count");
+-
+-    if (numFuncBodies != c.env().numFuncDefs())
+-        return c.d.fail("function body count does not match function signature count");
+-
+-    for (uint32_t funcDefIndex = 0; funcDefIndex < numFuncBodies; funcDefIndex++) {
+-        AstFunc* func;
+-        if (!AstDecodeFunctionBody(c, c.module().numFuncImports() + funcDefIndex, &func))
+-            return false;
+-        if (!c.module().append(func))
+-            return false;
+-    }
+-
+-    return c.d.finishSection(*c.env().codeSection, "code");
+-}
+-
+-// Number of bytes to display in a single fragment of a data section (per line).
+-static const size_t WRAP_DATA_BYTES = 30;
+-
+-static bool
+-AstDecodeModuleTail(AstDecodeContext& c)
+-{
+-    MOZ_ASSERT(c.module().memories().length() <= 1, "at most one memory in MVP");
+-
+-    if (!DecodeModuleTail(c.d, &c.env()))
+-        return false;
+-
+-    for (DataSegment& s : c.env().dataSegments) {
+-        char16_t* buffer = static_cast<char16_t*>(c.lifo.alloc(s.length * sizeof(char16_t)));
+-        if (!buffer)
+-            return false;
+-
+-        const uint8_t* src = c.d.begin() + s.bytecodeOffset;
+-        for (size_t i = 0; i < s.length; i++)
+-            buffer[i] = src[i];
+-
+-        AstExpr* offset = ToAstExpr(c, s.offset);
+-        if (!offset)
+-            return false;
+-
+-        AstNameVector fragments(c.lifo);
+-        for (size_t start = 0; start < s.length; start += WRAP_DATA_BYTES) {
+-            AstName name(buffer + start, Min(WRAP_DATA_BYTES, s.length - start));
+-            if (!fragments.append(name))
+-                return false;
+-        }
+-
+-        AstDataSegment* segment = new(c.lifo) AstDataSegment(offset, std::move(fragments));
+-        if (!segment || !c.module().append(segment))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-bool
+-wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAlloc& lifo,
+-                  AstModule** module)
+-{
+-    AstModule* result = new(lifo) AstModule(lifo);
+-    if (!result || !result->init())
+-        return false;
+-
+-    UniqueChars error;
+-    Decoder d(bytes, bytes + length, 0, &error, nullptr, /* resilient */ true);
+-    AstDecodeContext c(cx, lifo, d, *result, /* generateNames */ true, HasGcTypes::True);
+-
+-    if (!AstDecodeEnvironment(c) ||
+-        !AstDecodeCodeSection(c) ||
+-        !AstDecodeModuleTail(c))
+-    {
+-        if (error) {
+-            JS_ReportErrorNumberUTF8(c.cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
+-                                     error.get());
+-            return false;
+-        }
+-        ReportOutOfMemory(c.cx);
+-        return false;
+-    }
+-
+-    MOZ_ASSERT(!error, "unreported error in decoding");
+-
+-    *module = result;
+-    return true;
+-}
+diff --git a/js/src/wasm/WasmBinaryToAST.h b/js/src/wasm/WasmBinaryToAST.h
+deleted file mode 100644
+--- a/js/src/wasm/WasmBinaryToAST.h
++++ /dev/null
+@@ -1,37 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+- * vim: set ts=8 sts=4 et sw=4 tw=99:
+- *
+- * Copyright 2015 Mozilla Foundation
+- *
+- * Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- *
+- *     http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-#ifndef wasmbinarytoast_h
+-#define wasmbinarytoast_h
+-
+-#include "ds/LifoAlloc.h"
+-
+-#include "wasm/WasmAST.h"
+-#include "wasm/WasmTypes.h"
+-
+-namespace js {
+-namespace wasm {
+-
+-bool
+-BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAlloc& lifo,
+-            AstModule** module);
+-
+-} // end wasm namespace
+-} // end js namespace
+-
+-#endif // namespace wasmbinarytoast_h
+diff --git a/js/src/wasm/WasmBinaryToText.cpp b/js/src/wasm/WasmBinaryToText.cpp
+deleted file mode 100644
+--- a/js/src/wasm/WasmBinaryToText.cpp
++++ /dev/null
+@@ -1,2087 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+- * vim: set ts=8 sts=4 et sw=4 tw=99:
+- *
+- * Copyright 2015 Mozilla Foundation
+- *
+- * Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- *
+- *     http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-#include "wasm/WasmBinaryToText.h"
+-
+-#include "jsnum.h"
+-
+-#include "util/StringBuffer.h"
+-#include "vm/ArrayBufferObject.h"
+-#include "wasm/WasmAST.h"
+-#include "wasm/WasmBinaryToAST.h"
+-#include "wasm/WasmDebug.h"
+-#include "wasm/WasmTextUtils.h"
+-#include "wasm/WasmTypes.h"
+-
+-using namespace js;
+-using namespace js::wasm;
+-
+-using mozilla::IsInfinite;
+-using mozilla::IsNaN;
+-using mozilla::IsNegativeZero;
+-
+-struct WasmRenderContext
+-{
+-    JSContext* cx;
+-    AstModule* module;
+-    WasmPrintBuffer& buffer;
+-    uint32_t indent;
+-    uint32_t currentFuncIndex;
+-
+-    WasmRenderContext(JSContext* cx, AstModule* module, WasmPrintBuffer& buffer)
+-      : cx(cx),
+-        module(module),
+-        buffer(buffer),
+-        indent(0),
+-        currentFuncIndex(0)
+-    {}
+-
+-    StringBuffer& sb() { return buffer.stringBuffer(); }
+-};
+-
+-/*****************************************************************************/
+-// utilities
+-
+-// Return true on purpose, so that we have a useful error message to provide to
+-// the user.
+-static bool
+-Fail(WasmRenderContext& c, const char* msg)
+-{
+-    c.buffer.stringBuffer().clear();
+-
+-    return c.buffer.append("There was a problem when rendering the wasm text format: ") &&
+-           c.buffer.append(msg, strlen(msg)) &&
+-           c.buffer.append("\nYou should consider file a bug on Bugzilla in the "
+-                           "Core:::JavaScript Engine::JIT component at "
+-                           "https://bugzilla.mozilla.org/enter_bug.cgi.");
+-}
+-
+-static bool
+-RenderIndent(WasmRenderContext& c)
+-{
+-    for (uint32_t i = 0; i < c.indent; i++) {
+-        if (!c.buffer.append("  "))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderInt32(WasmRenderContext& c, int32_t num)
+-{
+-    return NumberValueToStringBuffer(c.cx, Int32Value(num), c.sb());
+-}
+-
+-static bool
+-RenderInt64(WasmRenderContext& c, int64_t num)
+-{
+-    if (num < 0 && !c.buffer.append("-"))
+-        return false;
+-    if (!num)
+-        return c.buffer.append("0");
+-    return RenderInBase<10>(c.sb(), mozilla::Abs(num));
+-}
+-
+-static bool
+-RenderDouble(WasmRenderContext& c, double d)
+-{
+-    if (IsNaN(d))
+-        return RenderNaN(c.sb(), d);
+-    if (IsNegativeZero(d))
+-        return c.buffer.append("-0");
+-    if (IsInfinite(d)) {
+-        if (d > 0)
+-            return c.buffer.append("infinity");
+-        return c.buffer.append("-infinity");
+-    }
+-    return NumberValueToStringBuffer(c.cx, DoubleValue(d), c.sb());
+-}
+-
+-static bool
+-RenderFloat32(WasmRenderContext& c, float f)
+-{
+-    if (IsNaN(f))
+-        return RenderNaN(c.sb(), f);
+-    return RenderDouble(c, double(f));
+-}
+-
+-static bool
+-RenderEscapedString(WasmRenderContext& c, const AstName& s)
+-{
+-    size_t length = s.length();
+-    const char16_t* p = s.begin();
+-    for (size_t i = 0; i < length; i++) {
+-        char16_t byte = p[i];
+-        switch (byte) {
+-          case '\n':
+-            if (!c.buffer.append("\\n"))
+-                return false;
+-            break;
+-          case '\r':
+-            if (!c.buffer.append("\\0d"))
+-                return false;
+-            break;
+-          case '\t':
+-            if (!c.buffer.append("\\t"))
+-                return false;
+-            break;
+-          case '\f':
+-            if (!c.buffer.append("\\0c"))
+-                return false;
+-            break;
+-          case '\b':
+-            if (!c.buffer.append("\\08"))
+-                return false;
+-            break;
+-          case '\\':
+-            if (!c.buffer.append("\\\\"))
+-                return false;
+-            break;
+-          case '"' :
+-            if (!c.buffer.append("\\\""))
+-                return false;
+-            break;
+-          case '\'':
+-            if (!c.buffer.append("\\'"))
+-                return false;
+-            break;
+-          default:
+-            if (byte >= 32 && byte < 127) {
+-                if (!c.buffer.append((char)byte))
+-                    return false;
+-            } else {
+-                char digit1 = byte / 16, digit2 = byte % 16;
+-                if (!c.buffer.append("\\"))
+-                    return false;
+-                if (!c.buffer.append((char)(digit1 < 10 ? digit1 + '0' : digit1 + 'a' - 10)))
+-                    return false;
+-                if (!c.buffer.append((char)(digit2 < 10 ? digit2 + '0' : digit2 + 'a' - 10)))
+-                    return false;
+-            }
+-            break;
+-        }
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderExprType(WasmRenderContext& c, ExprType type)
+-{
+-    switch (type) {
+-      case ExprType::Void: return true; // ignoring void
+-      case ExprType::I32: return c.buffer.append("i32");
+-      case ExprType::I64: return c.buffer.append("i64");
+-      case ExprType::F32: return c.buffer.append("f32");
+-      case ExprType::F64: return c.buffer.append("f64");
+-      case ExprType::AnyRef: return c.buffer.append("anyref");
+-      default:;
+-    }
+-
+-    MOZ_CRASH("bad type");
+-}
+-
+-static bool
+-RenderValType(WasmRenderContext& c, ValType type)
+-{
+-    return RenderExprType(c, ToExprType(type));
+-}
+-
+-static bool
+-RenderName(WasmRenderContext& c, const AstName& name)
+-{
+-    return c.buffer.append(name.begin(), name.end());
+-}
+-
+-static bool
+-RenderNonemptyName(WasmRenderContext& c, const AstName& name)
+-{
+-    return name.empty() || (RenderName(c, name) && c.buffer.append(' '));
+-}
+-
+-static bool
+-RenderRef(WasmRenderContext& c, const AstRef& ref)
+-{
+-    if (ref.name().empty())
+-        return RenderInt32(c, ref.index());
+-
+-    return RenderName(c, ref.name());
+-}
+-
+-static bool
+-RenderBlockNameAndSignature(WasmRenderContext& c, const AstName& name, ExprType type)
+-{
+-    if (!name.empty()) {
+-        if (!c.buffer.append(' '))
+-            return false;
+-
+-        if (!RenderName(c, name))
+-            return false;
+-    }
+-
+-    if (!IsVoid(type)) {
+-        if (!c.buffer.append(' '))
+-            return false;
+-
+-        if (!RenderExprType(c, type))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine = true);
+-
+-/*****************************************************************************/
+-// binary format parsing and rendering
+-
+-static bool
+-RenderNop(WasmRenderContext& c, AstNop& nop)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-    return c.buffer.append("nop");
+-}
+-
+-static bool
+-RenderDrop(WasmRenderContext& c, AstDrop& drop)
+-{
+-    if (!RenderExpr(c, drop.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-    return c.buffer.append("drop");
+-}
+-
+-static bool
+-RenderUnreachable(WasmRenderContext& c, AstUnreachable& unreachable)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-    return c.buffer.append("unreachable");
+-}
+-
+-static bool
+-RenderCallArgs(WasmRenderContext& c, const AstExprVector& args)
+-{
+-    for (uint32_t i = 0; i < args.length(); i++) {
+-        if (!RenderExpr(c, *args[i]))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderCall(WasmRenderContext& c, AstCall& call)
+-{
+-    if (!RenderCallArgs(c, call.args()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (call.op() == Op::Call) {
+-        if (!c.buffer.append("call "))
+-            return false;
+-    } else {
+-        return Fail(c, "unexpected operator");
+-    }
+-
+-    return RenderRef(c, call.func());
+-}
+-
+-static bool
+-RenderCallIndirect(WasmRenderContext& c, AstCallIndirect& call)
+-{
+-    if (!RenderCallArgs(c, call.args()))
+-        return false;
+-
+-    if (!RenderExpr(c, *call.index()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("call_indirect "))
+-        return false;
+-    return RenderRef(c, call.funcType());
+-}
+-
+-static bool
+-RenderConst(WasmRenderContext& c, AstConst& cst)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!RenderValType(c, cst.val().type()))
+-        return false;
+-    if (!c.buffer.append(".const "))
+-        return false;
+-
+-    switch (ToExprType(cst.val().type())) {
+-      case ExprType::I32:
+-        return RenderInt32(c, (int32_t)cst.val().i32());
+-      case ExprType::I64:
+-        return RenderInt64(c, (int64_t)cst.val().i64());
+-      case ExprType::F32:
+-        return RenderFloat32(c, cst.val().f32());
+-      case ExprType::F64:
+-        return RenderDouble(c, cst.val().f64());
+-      default:
+-        break;
+-    }
+-
+-    return false;
+-}
+-
+-static bool
+-RenderGetLocal(WasmRenderContext& c, AstGetLocal& gl)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("get_local "))
+-        return false;
+-    return RenderRef(c, gl.local());
+-}
+-
+-static bool
+-RenderSetLocal(WasmRenderContext& c, AstSetLocal& sl)
+-{
+-    if (!RenderExpr(c, sl.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("set_local "))
+-        return false;
+-    return RenderRef(c, sl.local());
+-}
+-
+-static bool
+-RenderTeeLocal(WasmRenderContext& c, AstTeeLocal& tl)
+-{
+-    if (!RenderExpr(c, tl.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("tee_local "))
+-        return false;
+-    return RenderRef(c, tl.local());
+-}
+-
+-static bool
+-RenderGetGlobal(WasmRenderContext& c, AstGetGlobal& gg)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("get_global "))
+-        return false;
+-    return RenderRef(c, gg.global());
+-}
+-
+-static bool
+-RenderSetGlobal(WasmRenderContext& c, AstSetGlobal& sg)
+-{
+-    if (!RenderExpr(c, sg.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("set_global "))
+-        return false;
+-    return RenderRef(c, sg.global());
+-}
+-
+-static bool
+-RenderExprList(WasmRenderContext& c, const AstExprVector& exprs, uint32_t startAt = 0)
+-{
+-    for (uint32_t i = startAt; i < exprs.length(); i++) {
+-        if (!RenderExpr(c, *exprs[i]))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderBlock(WasmRenderContext& c, AstBlock& block, bool isInline = false)
+-{
+-    if (!isInline && !RenderIndent(c))
+-        return false;
+-
+-    if (block.op() == Op::Block) {
+-        if (!c.buffer.append("block"))
+-            return false;
+-    } else if (block.op() == Op::Loop) {
+-        if (!c.buffer.append("loop"))
+-            return false;
+-    } else {
+-        return Fail(c, "unexpected block kind");
+-    }
+-
+-    if (!RenderBlockNameAndSignature(c, block.name(), block.type()))
+-        return false;
+-
+-    uint32_t startAtSubExpr = 0;
+-
+-    // If there is a stack of blocks, print them all inline.
+-    if (block.op() == Op::Block &&
+-        block.exprs().length() &&
+-        block.exprs()[0]->kind() == AstExprKind::Block &&
+-        block.exprs()[0]->as<AstBlock>().op() == Op::Block)
+-    {
+-        if (!c.buffer.append(' '))
+-            return false;
+-
+-        // Render the first inner expr (block) at the same indent level, but
+-        // next instructions one level further.
+-        if (!RenderBlock(c, block.exprs()[0]->as<AstBlock>(), /* isInline */ true))
+-            return false;
+-
+-        startAtSubExpr = 1;
+-    }
+-
+-    if (!c.buffer.append('\n'))
+-        return false;
+-
+-    c.indent++;
+-    if (!RenderExprList(c, block.exprs(), startAtSubExpr))
+-        return false;
+-    c.indent--;
+-
+-    return RenderIndent(c) &&
+-           c.buffer.append("end ") &&
+-           RenderName(c, block.name());
+-}
+-
+-static bool
+-RenderFirst(WasmRenderContext& c, AstFirst& first)
+-{
+-    return RenderExprList(c, first.exprs());
+-}
+-
+-static bool
+-RenderCurrentMemory(WasmRenderContext& c, AstCurrentMemory& cm)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    return c.buffer.append("current_memory\n");
+-}
+-
+-static bool
+-RenderGrowMemory(WasmRenderContext& c, AstGrowMemory& gm)
+-{
+-    if (!RenderExpr(c, *gm.operand()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    return c.buffer.append("grow_memory\n");
+-}
+-
+-static bool
+-RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& unary)
+-{
+-    if (!RenderExpr(c, *unary.operand()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr;
+-    switch (unary.op()) {
+-      case Op::I32Eqz:     opStr = "i32.eqz"; break;
+-      case Op::I32Clz:     opStr = "i32.clz"; break;
+-      case Op::I32Ctz:     opStr = "i32.ctz"; break;
+-      case Op::I32Popcnt:  opStr = "i32.popcnt"; break;
+-      case Op::I64Clz:     opStr = "i64.clz"; break;
+-      case Op::I64Ctz:     opStr = "i64.ctz"; break;
+-      case Op::I64Popcnt:  opStr = "i64.popcnt"; break;
+-      case Op::F32Abs:     opStr = "f32.abs"; break;
+-      case Op::F32Neg:     opStr = "f32.neg"; break;
+-      case Op::F32Ceil:    opStr = "f32.ceil"; break;
+-      case Op::F32Floor:   opStr = "f32.floor"; break;
+-      case Op::F32Sqrt:    opStr = "f32.sqrt"; break;
+-      case Op::F32Trunc:   opStr = "f32.trunc"; break;
+-      case Op::F32Nearest: opStr = "f32.nearest"; break;
+-      case Op::F64Abs:     opStr = "f64.abs"; break;
+-      case Op::F64Neg:     opStr = "f64.neg"; break;
+-      case Op::F64Ceil:    opStr = "f64.ceil"; break;
+-      case Op::F64Floor:   opStr = "f64.floor"; break;
+-      case Op::F64Nearest: opStr = "f64.nearest"; break;
+-      case Op::F64Sqrt:    opStr = "f64.sqrt"; break;
+-      case Op::F64Trunc:   opStr = "f64.trunc"; break;
+-      default:               return Fail(c, "unexpected unary operator");
+-    }
+-
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-
+-static bool
+-RenderBinaryOperator(WasmRenderContext& c, AstBinaryOperator& binary)
+-{
+-    if (!RenderExpr(c, *binary.lhs()))
+-        return false;
+-    if (!RenderExpr(c, *binary.rhs()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr;
+-    switch (binary.op()) {
+-      case Op::I32Add:      opStr = "i32.add"; break;
+-      case Op::I32Sub:      opStr = "i32.sub"; break;
+-      case Op::I32Mul:      opStr = "i32.mul"; break;
+-      case Op::I32DivS:     opStr = "i32.div_s"; break;
+-      case Op::I32DivU:     opStr = "i32.div_u"; break;
+-      case Op::I32RemS:     opStr = "i32.rem_s"; break;
+-      case Op::I32RemU:     opStr = "i32.rem_u"; break;
+-      case Op::I32And:      opStr = "i32.and"; break;
+-      case Op::I32Or:       opStr = "i32.or"; break;
+-      case Op::I32Xor:      opStr = "i32.xor"; break;
+-      case Op::I32Shl:      opStr = "i32.shl"; break;
+-      case Op::I32ShrS:     opStr = "i32.shr_s"; break;
+-      case Op::I32ShrU:     opStr = "i32.shr_u"; break;
+-      case Op::I32Rotl:     opStr = "i32.rotl"; break;
+-      case Op::I32Rotr:     opStr = "i32.rotr"; break;
+-      case Op::I64Add:      opStr = "i64.add"; break;
+-      case Op::I64Sub:      opStr = "i64.sub"; break;
+-      case Op::I64Mul:      opStr = "i64.mul"; break;
+-      case Op::I64DivS:     opStr = "i64.div_s"; break;
+-      case Op::I64DivU:     opStr = "i64.div_u"; break;
+-      case Op::I64RemS:     opStr = "i64.rem_s"; break;
+-      case Op::I64RemU:     opStr = "i64.rem_u"; break;
+-      case Op::I64And:      opStr = "i64.and"; break;
+-      case Op::I64Or:       opStr = "i64.or"; break;
+-      case Op::I64Xor:      opStr = "i64.xor"; break;
+-      case Op::I64Shl:      opStr = "i64.shl"; break;
+-      case Op::I64ShrS:     opStr = "i64.shr_s"; break;
+-      case Op::I64ShrU:     opStr = "i64.shr_u"; break;
+-      case Op::I64Rotl:     opStr = "i64.rotl"; break;
+-      case Op::I64Rotr:     opStr = "i64.rotr"; break;
+-      case Op::F32Add:      opStr = "f32.add"; break;
+-      case Op::F32Sub:      opStr = "f32.sub"; break;
+-      case Op::F32Mul:      opStr = "f32.mul"; break;
+-      case Op::F32Div:      opStr = "f32.div"; break;
+-      case Op::F32Min:      opStr = "f32.min"; break;
+-      case Op::F32Max:      opStr = "f32.max"; break;
+-      case Op::F32CopySign: opStr = "f32.copysign"; break;
+-      case Op::F64Add:      opStr = "f64.add"; break;
+-      case Op::F64Sub:      opStr = "f64.sub"; break;
+-      case Op::F64Mul:      opStr = "f64.mul"; break;
+-      case Op::F64Div:      opStr = "f64.div"; break;
+-      case Op::F64Min:      opStr = "f64.min"; break;
+-      case Op::F64Max:      opStr = "f64.max"; break;
+-      case Op::F64CopySign: opStr = "f64.copysign"; break;
+-      default:                return Fail(c, "unexpected binary operator");
+-    }
+-
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-
+-static bool
+-RenderTernaryOperator(WasmRenderContext& c, AstTernaryOperator& ternary)
+-{
+-    if (!RenderExpr(c, *ternary.op0()))
+-        return false;
+-    if (!RenderExpr(c, *ternary.op1()))
+-        return false;
+-    if (!RenderExpr(c, *ternary.op2()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr;
+-    switch (ternary.op()) {
+-      case Op::Select: opStr = "select"; break;
+-      default:           return Fail(c, "unexpected ternary operator");
+-    }
+-
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-
+-static bool
+-RenderComparisonOperator(WasmRenderContext& c, AstComparisonOperator& comp)
+-{
+-    if (!RenderExpr(c, *comp.lhs()))
+-        return false;
+-    if (!RenderExpr(c, *comp.rhs()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr;
+-    switch (comp.op()) {
+-      case Op::I32Eq:  opStr = "i32.eq"; break;
+-      case Op::I32Ne:  opStr = "i32.ne"; break;
+-      case Op::I32LtS: opStr = "i32.lt_s"; break;
+-      case Op::I32LtU: opStr = "i32.lt_u"; break;
+-      case Op::I32LeS: opStr = "i32.le_s"; break;
+-      case Op::I32LeU: opStr = "i32.le_u"; break;
+-      case Op::I32GtS: opStr = "i32.gt_s"; break;
+-      case Op::I32GtU: opStr = "i32.gt_u"; break;
+-      case Op::I32GeS: opStr = "i32.ge_s"; break;
+-      case Op::I32GeU: opStr = "i32.ge_u"; break;
+-      case Op::I64Eq:  opStr = "i64.eq"; break;
+-      case Op::I64Ne:  opStr = "i64.ne"; break;
+-      case Op::I64LtS: opStr = "i64.lt_s"; break;
+-      case Op::I64LtU: opStr = "i64.lt_u"; break;
+-      case Op::I64LeS: opStr = "i64.le_s"; break;
+-      case Op::I64LeU: opStr = "i64.le_u"; break;
+-      case Op::I64GtS: opStr = "i64.gt_s"; break;
+-      case Op::I64GtU: opStr = "i64.gt_u"; break;
+-      case Op::I64GeS: opStr = "i64.ge_s"; break;
+-      case Op::I64GeU: opStr = "i64.ge_u"; break;
+-      case Op::F32Eq:  opStr = "f32.eq"; break;
+-      case Op::F32Ne:  opStr = "f32.ne"; break;
+-      case Op::F32Lt:  opStr = "f32.lt"; break;
+-      case Op::F32Le:  opStr = "f32.le"; break;
+-      case Op::F32Gt:  opStr = "f32.gt"; break;
+-      case Op::F32Ge:  opStr = "f32.ge"; break;
+-      case Op::F64Eq:  opStr = "f64.eq"; break;
+-      case Op::F64Ne:  opStr = "f64.ne"; break;
+-      case Op::F64Lt:  opStr = "f64.lt"; break;
+-      case Op::F64Le:  opStr = "f64.le"; break;
+-      case Op::F64Gt:  opStr = "f64.gt"; break;
+-      case Op::F64Ge:  opStr = "f64.ge"; break;
+-      default:           return Fail(c, "unexpected comparison operator");
+-    }
+-
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-
+-static bool
+-RenderConversionOperator(WasmRenderContext& c, AstConversionOperator& conv)
+-{
+-    if (!RenderExpr(c, *conv.operand()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr;
+-    switch (conv.op()) {
+-      case Op::I32WrapI64:        opStr = "i32.wrap/i64"; break;
+-      case Op::I32TruncSF32:      opStr = "i32.trunc_s/f32"; break;
+-      case Op::I32TruncUF32:      opStr = "i32.trunc_u/f32"; break;
+-      case Op::I32ReinterpretF32: opStr = "i32.reinterpret/f32"; break;
+-      case Op::I32TruncSF64:      opStr = "i32.trunc_s/f64"; break;
+-      case Op::I32TruncUF64:      opStr = "i32.trunc_u/f64"; break;
+-      case Op::I64ExtendSI32:     opStr = "i64.extend_s/i32"; break;
+-      case Op::I64ExtendUI32:     opStr = "i64.extend_u/i32"; break;
+-      case Op::I64TruncSF32:      opStr = "i64.trunc_s/f32"; break;
+-      case Op::I64TruncUF32:      opStr = "i64.trunc_u/f32"; break;
+-      case Op::I64TruncSF64:      opStr = "i64.trunc_s/f64"; break;
+-      case Op::I64TruncUF64:      opStr = "i64.trunc_u/f64"; break;
+-      case Op::I64ReinterpretF64: opStr = "i64.reinterpret/f64"; break;
+-      case Op::F32ConvertSI32:    opStr = "f32.convert_s/i32"; break;
+-      case Op::F32ConvertUI32:    opStr = "f32.convert_u/i32"; break;
+-      case Op::F32ReinterpretI32: opStr = "f32.reinterpret/i32"; break;
+-      case Op::F32ConvertSI64:    opStr = "f32.convert_s/i64"; break;
+-      case Op::F32ConvertUI64:    opStr = "f32.convert_u/i64"; break;
+-      case Op::F32DemoteF64:      opStr = "f32.demote/f64"; break;
+-      case Op::F64ConvertSI32:    opStr = "f64.convert_s/i32"; break;
+-      case Op::F64ConvertUI32:    opStr = "f64.convert_u/i32"; break;
+-      case Op::F64ConvertSI64:    opStr = "f64.convert_s/i64"; break;
+-      case Op::F64ConvertUI64:    opStr = "f64.convert_u/i64"; break;
+-      case Op::F64ReinterpretI64: opStr = "f64.reinterpret/i64"; break;
+-      case Op::F64PromoteF32:     opStr = "f64.promote/f32"; break;
+-      case Op::I32Extend8S:       opStr = "i32.extend8_s"; break;
+-      case Op::I32Extend16S:      opStr = "i32.extend16_s"; break;
+-      case Op::I64Extend8S:       opStr = "i64.extend8_s"; break;
+-      case Op::I64Extend16S:      opStr = "i64.extend16_s"; break;
+-      case Op::I64Extend32S:      opStr = "i64.extend32_s"; break;
+-      case Op::I32Eqz:            opStr = "i32.eqz"; break;
+-      case Op::I64Eqz:            opStr = "i64.eqz"; break;
+-      default:                      return Fail(c, "unexpected conversion operator");
+-    }
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-
+-#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
+-static bool
+-RenderExtraConversionOperator(WasmRenderContext& c, AstExtraConversionOperator& conv)
+-{
+-    if (!RenderExpr(c, *conv.operand()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr;
+-    switch (conv.op()) {
+-      case MiscOp::I32TruncSSatF32:   opStr = "i32.trunc_s:sat/f32"; break;
+-      case MiscOp::I32TruncUSatF32:   opStr = "i32.trunc_u:sat/f32"; break;
+-      case MiscOp::I32TruncSSatF64:   opStr = "i32.trunc_s:sat/f64"; break;
+-      case MiscOp::I32TruncUSatF64:   opStr = "i32.trunc_u:sat/f64"; break;
+-      case MiscOp::I64TruncSSatF32:   opStr = "i64.trunc_s:sat/f32"; break;
+-      case MiscOp::I64TruncUSatF32:   opStr = "i64.trunc_u:sat/f32"; break;
+-      case MiscOp::I64TruncSSatF64:   opStr = "i64.trunc_s:sat/f64"; break;
+-      case MiscOp::I64TruncUSatF64:   opStr = "i64.trunc_u:sat/f64"; break;
+-      default:                      return Fail(c, "unexpected extra conversion operator");
+-    }
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-#endif
+-
+-static bool
+-RenderIf(WasmRenderContext& c, AstIf& if_)
+-{
+-    if (!RenderExpr(c, if_.cond()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("if"))
+-        return false;
+-    if (!RenderBlockNameAndSignature(c, if_.name(), if_.type()))
+-        return false;
+-    if (!c.buffer.append('\n'))
+-        return false;
+-
+-    c.indent++;
+-    if (!RenderExprList(c, if_.thenExprs()))
+-        return false;
+-    c.indent--;
+-
+-    if (if_.hasElse()) {
+-        if (!RenderIndent(c))
+-            return false;
+-
+-        if (!c.buffer.append("else\n"))
+-            return false;
+-
+-        c.indent++;
+-        if (!RenderExprList(c, if_.elseExprs()))
+-            return false;
+-        c.indent--;
+-    }
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    return c.buffer.append("end");
+-}
+-
+-static bool
+-RenderLoadStoreBase(WasmRenderContext& c, const AstLoadStoreAddress& lsa)
+-{
+-    return RenderExpr(c, lsa.base());
+-}
+-
+-static bool
+-RenderLoadStoreAddress(WasmRenderContext& c, const AstLoadStoreAddress& lsa, uint32_t defaultAlignLog2)
+-{
+-    if (lsa.offset() != 0) {
+-        if (!c.buffer.append(" offset="))
+-            return false;
+-        if (!RenderInt32(c, lsa.offset()))
+-            return false;
+-    }
+-
+-    uint32_t alignLog2 = lsa.flags();
+-    if (defaultAlignLog2 != alignLog2) {
+-        if (!c.buffer.append(" align="))
+-            return false;
+-        if (!RenderInt32(c, 1 << alignLog2))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderLoad(WasmRenderContext& c, AstLoad& load)
+-{
+-    if (!RenderLoadStoreBase(c, load.address()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    uint32_t defaultAlignLog2;
+-    switch (load.op()) {
+-      case Op::I32Load8S:
+-        if (!c.buffer.append("i32.load8_s"))
+-            return false;
+-        defaultAlignLog2 = 0;
+-        break;
+-      case Op::I64Load8S:
+-        if (!c.buffer.append("i64.load8_s"))
+-            return false;
+-        defaultAlignLog2 = 0;
+-        break;
+-      case Op::I32Load8U:
+-        if (!c.buffer.append("i32.load8_u"))
+-            return false;
+-        defaultAlignLog2 = 0;
+-        break;
+-      case Op::I64Load8U:
+-        if (!c.buffer.append("i64.load8_u"))
+-            return false;
+-        defaultAlignLog2 = 0;
+-        break;
+-      case Op::I32Load16S:
+-        if (!c.buffer.append("i32.load16_s"))
+-            return false;
+-        defaultAlignLog2 = 1;
+-        break;
+-      case Op::I64Load16S:
+-        if (!c.buffer.append("i64.load16_s"))
+-            return false;
+-        defaultAlignLog2 = 1;
+-        break;
+-      case Op::I32Load16U:
+-        if (!c.buffer.append("i32.load16_u"))
+-            return false;
+-        defaultAlignLog2 = 1;
+-        break;
+-      case Op::I64Load16U:
+-        if (!c.buffer.append("i64.load16_u"))
+-            return false;
+-        defaultAlignLog2 = 1;
+-        break;
+-      case Op::I64Load32S:
+-        if (!c.buffer.append("i64.load32_s"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::I64Load32U:
+-        if (!c.buffer.append("i64.load32_u"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::I32Load:
+-        if (!c.buffer.append("i32.load"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::I64Load:
+-        if (!c.buffer.append("i64.load"))
+-            return false;
+-        defaultAlignLog2 = 3;
+-        break;
+-      case Op::F32Load:
+-        if (!c.buffer.append("f32.load"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::F64Load:
+-        if (!c.buffer.append("f64.load"))
+-            return false;
+-        defaultAlignLog2 = 3;
+-        break;
+-      default:
+-        return Fail(c, "unexpected load operator");
+-    }
+-
+-    return RenderLoadStoreAddress(c, load.address(), defaultAlignLog2);
+-}
+-
+-static bool
+-RenderStore(WasmRenderContext& c, AstStore& store)
+-{
+-    if (!RenderLoadStoreBase(c, store.address()))
+-        return false;
+-
+-    if (!RenderExpr(c, store.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    uint32_t defaultAlignLog2;
+-    switch (store.op()) {
+-      case Op::I32Store8:
+-        if (!c.buffer.append("i32.store8"))
+-            return false;
+-        defaultAlignLog2 = 0;
+-        break;
+-      case Op::I64Store8:
+-        if (!c.buffer.append("i64.store8"))
+-            return false;
+-        defaultAlignLog2 = 0;
+-        break;
+-      case Op::I32Store16:
+-        if (!c.buffer.append("i32.store16"))
+-            return false;
+-        defaultAlignLog2 = 1;
+-        break;
+-      case Op::I64Store16:
+-        if (!c.buffer.append("i64.store16"))
+-            return false;
+-        defaultAlignLog2 = 1;
+-        break;
+-      case Op::I64Store32:
+-        if (!c.buffer.append("i64.store32"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::I32Store:
+-        if (!c.buffer.append("i32.store"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::I64Store:
+-        if (!c.buffer.append("i64.store"))
+-            return false;
+-        defaultAlignLog2 = 3;
+-        break;
+-      case Op::F32Store:
+-        if (!c.buffer.append("f32.store"))
+-            return false;
+-        defaultAlignLog2 = 2;
+-        break;
+-      case Op::F64Store:
+-        if (!c.buffer.append("f64.store"))
+-            return false;
+-        defaultAlignLog2 = 3;
+-        break;
+-      default:
+-        return Fail(c, "unexpected store operator");
+-    }
+-
+-    return RenderLoadStoreAddress(c, store.address(), defaultAlignLog2);
+-}
+-
+-static bool
+-RenderBranch(WasmRenderContext& c, AstBranch& branch)
+-{
+-    Op op = branch.op();
+-    MOZ_ASSERT(op == Op::BrIf || op == Op::Br);
+-
+-    if (op == Op::BrIf) {
+-        if (!RenderExpr(c, branch.cond()))
+-            return false;
+-    }
+-
+-    if (branch.maybeValue()) {
+-        if (!RenderExpr(c, *(branch.maybeValue())))
+-            return false;
+-    }
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (op == Op::BrIf ? !c.buffer.append("br_if ") : !c.buffer.append("br "))
+-        return false;
+-
+-    return RenderRef(c, branch.target());
+-}
+-
+-static bool
+-RenderBrTable(WasmRenderContext& c, AstBranchTable& table)
+-{
+-    if (table.maybeValue()) {
+-        if (!RenderExpr(c, *(table.maybeValue())))
+-            return false;
+-    }
+-
+-    // Index
+-    if (!RenderExpr(c, table.index()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("br_table "))
+-        return false;
+-
+-    uint32_t tableLength = table.table().length();
+-    for (uint32_t i = 0; i < tableLength; i++) {
+-        if (!RenderRef(c, table.table()[i]))
+-            return false;
+-
+-        if (!c.buffer.append(" "))
+-            return false;
+-    }
+-
+-    return RenderRef(c, table.def());
+-}
+-
+-static bool
+-RenderReturn(WasmRenderContext& c, AstReturn& ret)
+-{
+-    if (ret.maybeExpr()) {
+-        if (!RenderExpr(c, *(ret.maybeExpr())))
+-            return false;
+-    }
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    return c.buffer.append("return");
+-}
+-
+-static bool
+-RenderAtomicCmpXchg(WasmRenderContext& c, AstAtomicCmpXchg& cmpxchg)
+-{
+-    if (!RenderLoadStoreBase(c, cmpxchg.address()))
+-        return false;
+-
+-    if (!RenderExpr(c, cmpxchg.expected()))
+-        return false;
+-    if (!RenderExpr(c, cmpxchg.replacement()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opname;
+-    switch (cmpxchg.op()) {
+-      case ThreadOp::I32AtomicCmpXchg8U:  opname = "i32.atomic.rmw8_u.cmpxchg"; break;
+-      case ThreadOp::I64AtomicCmpXchg8U:  opname = "i64.atomic.rmw8_u.cmpxchg"; break;
+-      case ThreadOp::I32AtomicCmpXchg16U: opname = "i32.atomic.rmw16_u.cmpxchg"; break;
+-      case ThreadOp::I64AtomicCmpXchg16U: opname = "i64.atomic.rmw16_u.cmpxchg"; break;
+-      case ThreadOp::I64AtomicCmpXchg32U: opname = "i64.atomic.rmw32_u.cmpxchg"; break;
+-      case ThreadOp::I32AtomicCmpXchg:    opname = "i32.atomic.rmw.cmpxchg"; break;
+-      case ThreadOp::I64AtomicCmpXchg:    opname = "i64.atomic.rmw.cmpxchg"; break;
+-      default:                            return Fail(c, "unexpected cmpxchg operator");
+-    }
+-
+-    if (!c.buffer.append(opname, strlen(opname)))
+-        return false;
+-
+-    return RenderLoadStoreAddress(c, cmpxchg.address(), 0);
+-}
+-
+-static bool
+-RenderAtomicLoad(WasmRenderContext& c, AstAtomicLoad& load)
+-{
+-    if (!RenderLoadStoreBase(c, load.address()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opname;
+-    switch (load.op()) {
+-      case ThreadOp::I32AtomicLoad8U:  opname = "i32.atomic.load8_u"; break;
+-      case ThreadOp::I64AtomicLoad8U:  opname = "i64.atomic.load8_u"; break;
+-      case ThreadOp::I32AtomicLoad16U: opname = "i32.atomic.load16_u"; break;
+-      case ThreadOp::I64AtomicLoad16U: opname = "i64.atomic.load16_u"; break;
+-      case ThreadOp::I64AtomicLoad32U: opname = "i64.atomic.load32_u"; break;
+-      case ThreadOp::I32AtomicLoad:    opname = "i32.atomic.load"; break;
+-      case ThreadOp::I64AtomicLoad:    opname = "i64.atomic.load"; break;
+-      default:                         return Fail(c, "unexpected load operator");
+-    }
+-
+-    if (!c.buffer.append(opname, strlen(opname)))
+-        return false;
+-
+-    return RenderLoadStoreAddress(c, load.address(), 0);
+-}
+-
+-static bool
+-RenderAtomicRMW(WasmRenderContext& c, AstAtomicRMW& rmw)
+-{
+-    if (!RenderLoadStoreBase(c, rmw.address()))
+-        return false;
+-
+-    if (!RenderExpr(c, rmw.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opname;
+-    switch (rmw.op()) {
+-      case ThreadOp::I32AtomicAdd:     opname = "i32.atomic.rmw.add"; break;
+-      case ThreadOp::I64AtomicAdd:     opname = "i64.atomic.rmw.add"; break;
+-      case ThreadOp::I32AtomicAdd8U:   opname = "i32.atomic.rmw8_u.add"; break;
+-      case ThreadOp::I32AtomicAdd16U:  opname = "i32.atomic.rmw16_u.add"; break;
+-      case ThreadOp::I64AtomicAdd8U:   opname = "i64.atomic.rmw8_u.add"; break;
+-      case ThreadOp::I64AtomicAdd16U:  opname = "i64.atomic.rmw16_u.add"; break;
+-      case ThreadOp::I64AtomicAdd32U:  opname = "i64.atomic.rmw32_u.add"; break;
+-      case ThreadOp::I32AtomicSub:     opname = "i32.atomic.rmw.sub"; break;
+-      case ThreadOp::I64AtomicSub:     opname = "i64.atomic.rmw.sub"; break;
+-      case ThreadOp::I32AtomicSub8U:   opname = "i32.atomic.rmw8_u.sub"; break;
+-      case ThreadOp::I32AtomicSub16U:  opname = "i32.atomic.rmw16_u.sub"; break;
+-      case ThreadOp::I64AtomicSub8U:   opname = "i64.atomic.rmw8_u.sub"; break;
+-      case ThreadOp::I64AtomicSub16U:  opname = "i64.atomic.rmw16_u.sub"; break;
+-      case ThreadOp::I64AtomicSub32U:  opname = "i64.atomic.rmw32_u.sub"; break;
+-      case ThreadOp::I32AtomicAnd:     opname = "i32.atomic.rmw.and"; break;
+-      case ThreadOp::I64AtomicAnd:     opname = "i64.atomic.rmw.and"; break;
+-      case ThreadOp::I32AtomicAnd8U:   opname = "i32.atomic.rmw8_u.and"; break;
+-      case ThreadOp::I32AtomicAnd16U:  opname = "i32.atomic.rmw16_u.and"; break;
+-      case ThreadOp::I64AtomicAnd8U:   opname = "i64.atomic.rmw8_u.and"; break;
+-      case ThreadOp::I64AtomicAnd16U:  opname = "i64.atomic.rmw16_u.and"; break;
+-      case ThreadOp::I64AtomicAnd32U:  opname = "i64.atomic.rmw32_u.and"; break;
+-      case ThreadOp::I32AtomicOr:      opname = "i32.atomic.rmw.or"; break;
+-      case ThreadOp::I64AtomicOr:      opname = "i64.atomic.rmw.or"; break;
+-      case ThreadOp::I32AtomicOr8U:    opname = "i32.atomic.rmw8_u.or"; break;
+-      case ThreadOp::I32AtomicOr16U:   opname = "i32.atomic.rmw16_u.or"; break;
+-      case ThreadOp::I64AtomicOr8U:    opname = "i64.atomic.rmw8_u.or"; break;
+-      case ThreadOp::I64AtomicOr16U:   opname = "i64.atomic.rmw16_u.or"; break;
+-      case ThreadOp::I64AtomicOr32U:   opname = "i64.atomic.rmw32_u.or"; break;
+-      case ThreadOp::I32AtomicXor:     opname = "i32.atomic.rmw.xor"; break;
+-      case ThreadOp::I64AtomicXor:     opname = "i64.atomic.rmw.xor"; break;
+-      case ThreadOp::I32AtomicXor8U:   opname = "i32.atomic.rmw8_u.xor"; break;
+-      case ThreadOp::I32AtomicXor16U:  opname = "i32.atomic.rmw16_u.xor"; break;
+-      case ThreadOp::I64AtomicXor8U:   opname = "i64.atomic.rmw8_u.xor"; break;
+-      case ThreadOp::I64AtomicXor16U:  opname = "i64.atomic.rmw16_u.xor"; break;
+-      case ThreadOp::I64AtomicXor32U:  opname = "i64.atomic.rmw32_u.xor"; break;
+-      case ThreadOp::I32AtomicXchg:    opname = "i32.atomic.rmw.xchg"; break;
+-      case ThreadOp::I64AtomicXchg:    opname = "i64.atomic.rmw.xchg"; break;
+-      case ThreadOp::I32AtomicXchg8U:  opname = "i32.atomic.rmw8_u.xchg"; break;
+-      case ThreadOp::I32AtomicXchg16U: opname = "i32.atomic.rmw16_u.xchg"; break;
+-      case ThreadOp::I64AtomicXchg8U:  opname = "i64.atomic.rmw8_u.xchg"; break;
+-      case ThreadOp::I64AtomicXchg16U: opname = "i64.atomic.rmw16_u.xchg"; break;
+-      case ThreadOp::I64AtomicXchg32U: opname = "i64.atomic.rmw32_u.xchg"; break;
+-      default:                         return Fail(c, "unexpected rmw operator");
+-    }
+-
+-    if (!c.buffer.append(opname, strlen(opname)))
+-        return false;
+-
+-    return RenderLoadStoreAddress(c, rmw.address(), 0);
+-}
+-
+-static bool
+-RenderAtomicStore(WasmRenderContext& c, AstAtomicStore& store)
+-{
+-    if (!RenderLoadStoreBase(c, store.address()))
+-        return false;
+-
+-    if (!RenderExpr(c, store.value()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opname;
+-    switch (store.op()) {
+-      case ThreadOp::I32AtomicStore8U:  opname = "i32.atomic.store8_u"; break;
+-      case ThreadOp::I64AtomicStore8U:  opname = "i64.atomic.store8_u"; break;
+-      case ThreadOp::I32AtomicStore16U: opname = "i32.atomic.store16_u"; break;
+-      case ThreadOp::I64AtomicStore16U: opname = "i64.atomic.store16_u"; break;
+-      case ThreadOp::I64AtomicStore32U: opname = "i64.atomic.store32_u"; break;
+-      case ThreadOp::I32AtomicStore:    opname = "i32.atomic.store"; break;
+-      case ThreadOp::I64AtomicStore:    opname = "i64.atomic.store"; break;
+-      default:                          return Fail(c, "unexpected store operator");
+-    }
+-
+-    if (!c.buffer.append(opname, strlen(opname)))
+-        return false;
+-
+-    return RenderLoadStoreAddress(c, store.address(), 0);
+-}
+-
+-static bool
+-RenderWait(WasmRenderContext& c, AstWait& wait)
+-{
+-    if (!RenderLoadStoreBase(c, wait.address()))
+-        return false;
+-
+-    if (!RenderExpr(c, wait.expected()))
+-        return false;
+-
+-    if (!RenderExpr(c, wait.timeout()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opname;
+-    switch (wait.op()) {
+-      case ThreadOp::I32Wait:  opname = "i32.atomic.wait"; break;
+-      case ThreadOp::I64Wait:  opname = "i64.atomic.wait"; break;
+-      default:           return Fail(c, "unexpected wait operator");
+-    }
+-
+-    if (!c.buffer.append(opname, strlen(opname)))
+-        return false;
+-
+-    return RenderLoadStoreAddress(c, wait.address(), 0);
+-}
+-
+-static bool
+-RenderWake(WasmRenderContext& c, AstWake& wake)
+-{
+-    if (!RenderLoadStoreBase(c, wake.address()))
+-        return false;
+-
+-    if (!RenderExpr(c, wake.count()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    if (!c.buffer.append("atomic.wake", strlen("atomic.wake")))
+-        return false;
+-
+-    return RenderLoadStoreAddress(c, wake.address(), 0);
+-}
+-
+-#ifdef ENABLE_WASM_BULKMEM_OPS
+-static bool
+-RenderMemCopy(WasmRenderContext& c, AstMemCopy& mc)
+-{
+-    if (!RenderExpr(c, mc.dest()))
+-        return false;
+-    if (!RenderExpr(c, mc.src()))
+-        return false;
+-    if (!RenderExpr(c, mc.len()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr = "memory.copy";
+-
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-
+-static bool
+-RenderMemFill(WasmRenderContext& c, AstMemFill& mf)
+-{
+-    if (!RenderExpr(c, mf.start()))
+-        return false;
+-    if (!RenderExpr(c, mf.val()))
+-        return false;
+-    if (!RenderExpr(c, mf.len()))
+-        return false;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-
+-    const char* opStr = "memory.fill";
+-
+-    return c.buffer.append(opStr, strlen(opStr));
+-}
+-#endif
+-
+-static bool
+-RenderExpr(WasmRenderContext& c, AstExpr& expr, bool newLine /* = true */)
+-{
+-    switch (expr.kind()) {
+-      case AstExprKind::Drop:
+-        if (!RenderDrop(c, expr.as<AstDrop>()))
+-            return false;
+-        break;
+-      case AstExprKind::Nop:
+-        if (!RenderNop(c, expr.as<AstNop>()))
+-            return false;
+-        break;
+-      case AstExprKind::Unreachable:
+-        if (!RenderUnreachable(c, expr.as<AstUnreachable>()))
+-            return false;
+-        break;
+-      case AstExprKind::Call:
+-        if (!RenderCall(c, expr.as<AstCall>()))
+-            return false;
+-        break;
+-      case AstExprKind::CallIndirect:
+-        if (!RenderCallIndirect(c, expr.as<AstCallIndirect>()))
+-            return false;
+-        break;
+-      case AstExprKind::Const:
+-        if (!RenderConst(c, expr.as<AstConst>()))
+-            return false;
+-        break;
+-      case AstExprKind::GetLocal:
+-        if (!RenderGetLocal(c, expr.as<AstGetLocal>()))
+-            return false;
+-        break;
+-      case AstExprKind::SetLocal:
+-        if (!RenderSetLocal(c, expr.as<AstSetLocal>()))
+-            return false;
+-        break;
+-      case AstExprKind::GetGlobal:
+-        if (!RenderGetGlobal(c, expr.as<AstGetGlobal>()))
+-            return false;
+-        break;
+-      case AstExprKind::SetGlobal:
+-        if (!RenderSetGlobal(c, expr.as<AstSetGlobal>()))
+-            return false;
+-        break;
+-      case AstExprKind::TeeLocal:
+-        if (!RenderTeeLocal(c, expr.as<AstTeeLocal>()))
+-            return false;
+-        break;
+-      case AstExprKind::Block:
+-        if (!RenderBlock(c, expr.as<AstBlock>()))
+-            return false;
+-        break;
+-      case AstExprKind::If:
+-        if (!RenderIf(c, expr.as<AstIf>()))
+-            return false;
+-        break;
+-      case AstExprKind::UnaryOperator:
+-        if (!RenderUnaryOperator(c, expr.as<AstUnaryOperator>()))
+-            return false;
+-        break;
+-      case AstExprKind::BinaryOperator:
+-        if (!RenderBinaryOperator(c, expr.as<AstBinaryOperator>()))
+-            return false;
+-        break;
+-      case AstExprKind::TernaryOperator:
+-        if (!RenderTernaryOperator(c, expr.as<AstTernaryOperator>()))
+-            return false;
+-        break;
+-      case AstExprKind::ComparisonOperator:
+-        if (!RenderComparisonOperator(c, expr.as<AstComparisonOperator>()))
+-            return false;
+-        break;
+-      case AstExprKind::ConversionOperator:
+-        if (!RenderConversionOperator(c, expr.as<AstConversionOperator>()))
+-            return false;
+-        break;
+-#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
+-      case AstExprKind::ExtraConversionOperator:
+-        if (!RenderExtraConversionOperator(c, expr.as<AstExtraConversionOperator>()))
+-            return false;
+-        break;
+-#endif
+-      case AstExprKind::Load:
+-        if (!RenderLoad(c, expr.as<AstLoad>()))
+-            return false;
+-        break;
+-      case AstExprKind::Store:
+-        if (!RenderStore(c, expr.as<AstStore>()))
+-            return false;
+-        break;
+-      case AstExprKind::Branch:
+-        if (!RenderBranch(c, expr.as<AstBranch>()))
+-            return false;
+-        break;
+-      case AstExprKind::BranchTable:
+-        if (!RenderBrTable(c, expr.as<AstBranchTable>()))
+-            return false;
+-        break;
+-      case AstExprKind::Return:
+-        if (!RenderReturn(c, expr.as<AstReturn>()))
+-            return false;
+-        break;
+-      case AstExprKind::First:
+-        newLine = false;
+-        if (!RenderFirst(c, expr.as<AstFirst>()))
+-            return false;
+-        break;
+-      case AstExprKind::CurrentMemory:
+-        if (!RenderCurrentMemory(c, expr.as<AstCurrentMemory>()))
+-            return false;
+-        break;
+-      case AstExprKind::GrowMemory:
+-        if (!RenderGrowMemory(c, expr.as<AstGrowMemory>()))
+-            return false;
+-        break;
+-      case AstExprKind::AtomicCmpXchg:
+-        if (!RenderAtomicCmpXchg(c, expr.as<AstAtomicCmpXchg>()))
+-            return false;
+-        break;
+-      case AstExprKind::AtomicLoad:
+-        if (!RenderAtomicLoad(c, expr.as<AstAtomicLoad>()))
+-            return false;
+-        break;
+-      case AstExprKind::AtomicRMW:
+-        if (!RenderAtomicRMW(c, expr.as<AstAtomicRMW>()))
+-            return false;
+-        break;
+-      case AstExprKind::AtomicStore:
+-        if (!RenderAtomicStore(c, expr.as<AstAtomicStore>()))
+-            return false;
+-        break;
+-      case AstExprKind::Wait:
+-        if (!RenderWait(c, expr.as<AstWait>()))
+-            return false;
+-        break;
+-      case AstExprKind::Wake:
+-        if (!RenderWake(c, expr.as<AstWake>()))
+-            return false;
+-        break;
+-#ifdef ENABLE_WASM_BULKMEM_OPS
+-      case AstExprKind::MemCopy:
+-        if (!RenderMemCopy(c, expr.as<AstMemCopy>()))
+-            return false;
+-        break;
+-      case AstExprKind::MemFill:
+-        if (!RenderMemFill(c, expr.as<AstMemFill>()))
+-            return false;
+-        break;
+-#endif
+-      default:
+-        MOZ_CRASH("Bad AstExprKind");
+-    }
+-
+-    return !newLine || c.buffer.append("\n");
+-}
+-
+-static bool
+-RenderSignature(WasmRenderContext& c, const AstFuncType& funcType,
+-                const AstNameVector* maybeLocals = nullptr)
+-{
+-    uint32_t paramsNum = funcType.args().length();
+-
+-    if (maybeLocals) {
+-        for (uint32_t i = 0; i < paramsNum; i++) {
+-            if (!c.buffer.append(" (param "))
+-                return false;
+-            const AstName& name = (*maybeLocals)[i];
+-            if (!RenderNonemptyName(c, name))
+-                return false;
+-            ValType arg = funcType.args()[i];
+-            if (!RenderValType(c, arg))
+-                return false;
+-            if (!c.buffer.append(")"))
+-                return false;
+-        }
+-    } else if (paramsNum > 0) {
+-        if (!c.buffer.append(" (param"))
+-            return false;
+-        for (uint32_t i = 0; i < paramsNum; i++) {
+-            if (!c.buffer.append(" "))
+-                return false;
+-            ValType arg = funcType.args()[i];
+-            if (!RenderValType(c, arg))
+-                return false;
+-        }
+-        if (!c.buffer.append(")"))
+-            return false;
+-    }
+-    if (funcType.ret() != ExprType::Void) {
+-        if (!c.buffer.append(" (result "))
+-            return false;
+-        if (!RenderExprType(c, funcType.ret()))
+-            return false;
+-        if (!c.buffer.append(")"))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderFields(WasmRenderContext& c, const AstStructType& st)
+-{
+-    const AstNameVector& fieldNames = st.fieldNames();
+-    const AstValTypeVector& fieldTypes = st.fieldTypes();
+-
+-    for (uint32_t fieldIndex = 0; fieldIndex < fieldTypes.length(); fieldIndex++) {
+-        if (!c.buffer.append("\n"))
+-            return false;
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!c.buffer.append("(field "))
+-            return false;
+-        if (!RenderNonemptyName(c, fieldNames[fieldIndex]))
+-            return false;
+-        if (!RenderValType(c, fieldTypes[fieldIndex]))
+-            return false;
+-        if (!c.buffer.append(')'))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-template<size_t ArrayLength>
+-static bool
+-RenderTypeStart(WasmRenderContext& c, const AstName& name, const char (&keyword)[ArrayLength])
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-    if (!c.buffer.append("(type "))
+-        return false;
+-    if (!RenderNonemptyName(c, name))
+-        return false;
+-    if (!c.buffer.append("("))
+-        return false;
+-    return c.buffer.append(keyword);
+-}
+-
+-static bool
+-RenderTypeEnd(WasmRenderContext& c)
+-{
+-    return c.buffer.append("))\n");
+-}
+-
+-static bool
+-RenderTypeSection(WasmRenderContext& c, const AstModule::TypeDefVector& types)
+-{
+-    for (uint32_t typeIndex = 0; typeIndex < types.length(); typeIndex++) {
+-        const AstTypeDef* type = types[typeIndex];
+-        if (type->isFuncType()) {
+-            const AstFuncType* funcType = &type->asFuncType();
+-            if (!RenderTypeStart(c, funcType->name(), "func"))
+-                return false;
+-            if (!RenderSignature(c, *funcType))
+-                return false;
+-        } else {
+-            const AstStructType* st = &type->asStructType();
+-            if (!RenderTypeStart(c, st->name(), "struct"))
+-                return false;
+-            c.indent++;
+-            if (!RenderFields(c, *st))
+-                return false;
+-            c.indent--;
+-        }
+-        if (!RenderTypeEnd(c))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderLimits(WasmRenderContext& c, const Limits& limits)
+-{
+-    if (!RenderInt32(c, limits.initial))
+-        return false;
+-    if (limits.maximum) {
+-        if (!c.buffer.append(" "))
+-            return false;
+-        if (!RenderInt32(c, *limits.maximum))
+-            return false;
+-    }
+-    if (limits.shared == Shareable::True) {
+-        if (!c.buffer.append(" shared"))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderResizableTable(WasmRenderContext& c, const Limits& table)
+-{
+-    if (!c.buffer.append("(table "))
+-        return false;
+-    if (!RenderLimits(c, table))
+-        return false;
+-    MOZ_ASSERT(table.shared == Shareable::False);
+-    return c.buffer.append(" anyfunc)");
+-}
+-
+-static bool
+-RenderTableSection(WasmRenderContext& c, const AstModule& module)
+-{
+-    if (!module.hasTable())
+-        return true;
+-    for (const AstResizable& table : module.tables()) {
+-        if (table.imported)
+-            continue;
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!RenderResizableTable(c, table.limits))
+-            return false;
+-        if (!c.buffer.append("\n"))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderInlineExpr(WasmRenderContext& c, AstExpr& expr)
+-{
+-    if (!c.buffer.append("("))
+-        return false;
+-
+-    uint32_t prevIndent = c.indent;
+-    c.indent = 0;
+-    if (!RenderExpr(c, expr, /* newLine */ false))
+-        return false;
+-    c.indent = prevIndent;
+-
+-    return c.buffer.append(")");
+-}
+-
+-static bool
+-RenderElemSection(WasmRenderContext& c, const AstModule& module)
+-{
+-    for (const AstElemSegment* segment : module.elemSegments()) {
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!c.buffer.append("(elem "))
+-            return false;
+-        if (!RenderInlineExpr(c, *segment->offset()))
+-            return false;
+-
+-        for (const AstRef& elem : segment->elems()) {
+-            if (!c.buffer.append(" "))
+-                return false;
+-
+-            uint32_t index = elem.index();
+-            AstName name = index < module.funcImportNames().length()
+-                           ? module.funcImportNames()[index]
+-                           : module.funcs()[index - module.funcImportNames().length()]->name();
+-
+-            if (name.empty()) {
+-                if (!RenderInt32(c, index))
+-                    return false;
+-            } else {
+-                if (!RenderName(c, name))
+-                    return false;
+-            }
+-        }
+-
+-        if (!c.buffer.append(")\n"))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderGlobal(WasmRenderContext& c, const AstGlobal& glob, bool inImport = false)
+-{
+-    if (!c.buffer.append("(global "))
+-        return false;
+-
+-    if (!inImport) {
+-        if (!RenderName(c, glob.name()))
+-            return false;
+-        if (!c.buffer.append(" "))
+-            return false;
+-    }
+-
+-    if (glob.isMutable()) {
+-        if (!c.buffer.append("(mut "))
+-            return false;
+-        if (!RenderValType(c, glob.type()))
+-            return false;
+-        if (!c.buffer.append(")"))
+-            return false;
+-    } else {
+-        if (!RenderValType(c, glob.type()))
+-            return false;
+-    }
+-
+-    if (glob.hasInit()) {
+-        if (!c.buffer.append(" "))
+-            return false;
+-        if (!RenderInlineExpr(c, glob.init()))
+-            return false;
+-    }
+-
+-    if (!c.buffer.append(")"))
+-        return false;
+-
+-    return inImport || c.buffer.append("\n");
+-}
+-
+-static bool
+-RenderGlobalSection(WasmRenderContext& c, const AstModule& module)
+-{
+-    if (module.globals().empty())
+-        return true;
+-
+-    for (const AstGlobal* global : module.globals()) {
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!RenderGlobal(c, *global))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderResizableMemory(WasmRenderContext& c, const Limits& memory)
+-{
+-    if (!c.buffer.append("(memory "))
+-        return false;
+-
+-    Limits resizedMemory = memory;
+-
+-    MOZ_ASSERT(resizedMemory.initial % PageSize == 0);
+-    resizedMemory.initial /= PageSize;
+-
+-    if (resizedMemory.maximum) {
+-        if (*resizedMemory.maximum == UINT32_MAX) {
+-            // See special casing in DecodeMemoryLimits.
+-            *resizedMemory.maximum = MaxMemoryMaximumPages;
+-        } else {
+-            MOZ_ASSERT(*resizedMemory.maximum % PageSize == 0);
+-            *resizedMemory.maximum /= PageSize;
+-        }
+-    }
+-
+-    if (!RenderLimits(c, resizedMemory))
+-        return false;
+-
+-    return c.buffer.append(")");
+-}
+-
+-static bool
+-RenderImport(WasmRenderContext& c, AstImport& import, const AstModule& module)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-    if (!c.buffer.append("(import "))
+-        return false;
+-    if (!RenderName(c, import.name()))
+-        return false;
+-    if (!c.buffer.append(" \""))
+-        return false;
+-
+-    const AstName& moduleName = import.module();
+-    if (!RenderEscapedString(c, moduleName))
+-        return false;
+-
+-    if (!c.buffer.append("\" \""))
+-        return false;
+-
+-    const AstName& fieldName = import.field();
+-    if (!RenderEscapedString(c, fieldName))
+-        return false;
+-
+-    if (!c.buffer.append("\" "))
+-        return false;
+-
+-    switch (import.kind()) {
+-      case DefinitionKind::Function: {
+-        if (!c.buffer.append("(func"))
+-            return false;
+-        const AstFuncType* funcType = &module.types()[import.funcType().index()]->asFuncType();
+-        if (!RenderSignature(c, *funcType))
+-            return false;
+-        if (!c.buffer.append(")"))
+-            return false;
+-        break;
+-      }
+-      case DefinitionKind::Table: {
+-        if (!RenderResizableTable(c, import.limits()))
+-            return false;
+-        break;
+-      }
+-      case DefinitionKind::Memory: {
+-        if (!RenderResizableMemory(c, import.limits()))
+-            return false;
+-        break;
+-      }
+-      case DefinitionKind::Global: {
+-        const AstGlobal& glob = import.global();
+-        if (!RenderGlobal(c, glob, /* inImport */ true))
+-            return false;
+-        break;
+-      }
+-    }
+-
+-    return c.buffer.append(")\n");
+-}
+-
+-static bool
+-RenderImportSection(WasmRenderContext& c, const AstModule& module)
+-{
+-    for (AstImport* import : module.imports()) {
+-        if (!RenderImport(c, *import, module))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderExport(WasmRenderContext& c, AstExport& export_,
+-             const AstModule::NameVector& funcImportNames,
+-             const AstModule::FuncVector& funcs)
+-{
+-    if (!RenderIndent(c))
+-        return false;
+-    if (!c.buffer.append("(export \""))
+-        return false;
+-    if (!RenderEscapedString(c, export_.name()))
+-        return false;
+-    if (!c.buffer.append("\" "))
+-        return false;
+-
+-    switch (export_.kind()) {
+-      case DefinitionKind::Function: {
+-        uint32_t index = export_.ref().index();
+-        AstName name = index < funcImportNames.length()
+-                       ? funcImportNames[index]
+-                       : funcs[index - funcImportNames.length()]->name();
+-        if (name.empty()) {
+-            if (!RenderInt32(c, index))
+-                return false;
+-        } else {
+-            if (!RenderName(c, name))
+-                return false;
+-        }
+-        break;
+-      }
+-      case DefinitionKind::Table: {
+-        if (!c.buffer.append("table"))
+-            return false;
+-        break;
+-      }
+-      case DefinitionKind::Memory: {
+-        if (!c.buffer.append("memory"))
+-            return false;
+-        break;
+-      }
+-      case DefinitionKind::Global: {
+-        if (!c.buffer.append("global "))
+-            return false;
+-        if (!RenderRef(c, export_.ref()))
+-            return false;
+-        break;
+-      }
+-    }
+-
+-    return c.buffer.append(")\n");
+-}
+-
+-static bool
+-RenderExportSection(WasmRenderContext& c, const AstModule::ExportVector& exports,
+-                    const AstModule::NameVector& funcImportNames,
+-                    const AstModule::FuncVector& funcs)
+-{
+-    uint32_t numExports = exports.length();
+-    for (uint32_t i = 0; i < numExports; i++) {
+-        if (!RenderExport(c, *exports[i], funcImportNames, funcs))
+-            return false;
+-    }
+-    return true;
+-}
+-
+-static bool
+-RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::TypeDefVector& types)
+-{
+-    const AstFuncType* funcType = &types[func.funcType().index()]->asFuncType();
+-
+-    uint32_t argsNum = funcType->args().length();
+-    uint32_t localsNum = func.vars().length();
+-    if (localsNum > 0) {
+-        if (!RenderIndent(c))
+-            return false;
+-        for (uint32_t i = 0; i < localsNum; i++) {
+-            if (!c.buffer.append("(local "))
+-                return false;
+-            const AstName& name = func.locals()[argsNum + i];
+-            if (!name.empty()) {
+-                if (!RenderName(c, name))
+-                    return false;
+-                if (!c.buffer.append(" "))
+-                    return false;
+-            }
+-            ValType local = func.vars()[i];
+-            if (!RenderValType(c, local))
+-                return false;
+-            if (!c.buffer.append(") "))
+-                return false;
+-        }
+-        if (!c.buffer.append("\n"))
+-            return false;
+-    }
+-
+-
+-    uint32_t exprsNum = func.body().length();
+-    for (uint32_t i = 0; i < exprsNum; i++) {
+-        if (!RenderExpr(c, *func.body()[i]))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
+-                  const AstModule::TypeDefVector& types)
+-{
+-    uint32_t numFuncBodies = funcs.length();
+-    for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
+-        AstFunc* func = funcs[funcIndex];
+-        uint32_t funcTypeIndex = func->funcType().index();
+-        AstFuncType* funcType = &types[funcTypeIndex]->asFuncType();
+-
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!c.buffer.append("(func "))
+-            return false;
+-        if (!func->name().empty()) {
+-            if (!RenderName(c, func->name()))
+-                return false;
+-        }
+-
+-        if (!RenderSignature(c, *funcType, &(func->locals())))
+-            return false;
+-        if (!c.buffer.append("\n"))
+-            return false;
+-
+-        c.currentFuncIndex = funcIndex;
+-
+-        c.indent++;
+-        if (!RenderFunctionBody(c, *func, types))
+-            return false;
+-        c.indent--;
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!c.buffer.append(")\n"))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderMemorySection(WasmRenderContext& c, const AstModule& module)
+-{
+-    if (!module.hasMemory())
+-        return true;
+-
+-    for (const AstResizable& memory : module.memories()) {
+-        if (memory.imported)
+-            continue;
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!RenderResizableMemory(c, memory.limits))
+-            return false;
+-        if (!c.buffer.append("\n"))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderDataSection(WasmRenderContext& c, const AstModule& module)
+-{
+-    uint32_t numSegments = module.dataSegments().length();
+-    if (!numSegments)
+-        return true;
+-
+-    for (const AstDataSegment* seg : module.dataSegments()) {
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!c.buffer.append("(data "))
+-            return false;
+-        if (!RenderInlineExpr(c, *seg->offset()))
+-            return false;
+-        if (!c.buffer.append("\n"))
+-            return false;
+-
+-        c.indent++;
+-        for (const AstName& fragment : seg->fragments()) {
+-            if (!RenderIndent(c))
+-                return false;
+-            if (!c.buffer.append("\""))
+-                return false;
+-            if (!RenderEscapedString(c, fragment))
+-                return false;
+-            if (!c.buffer.append("\"\n"))
+-                return false;
+-        }
+-        c.indent--;
+-
+-        if (!RenderIndent(c))
+-            return false;
+-        if (!c.buffer.append(")\n"))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-static bool
+-RenderStartSection(WasmRenderContext& c, AstModule& module)
+-{
+-    if (!module.hasStartFunc())
+-        return true;
+-
+-    if (!RenderIndent(c))
+-        return false;
+-    if (!c.buffer.append("(start "))
+-        return false;
+-    if (!RenderRef(c, module.startFunc().func()))
+-        return false;
+-    if (!c.buffer.append(")\n"))
+-        return false;
+-
+-    return true;
+-}
+-
+-static bool
+-RenderModule(WasmRenderContext& c, AstModule& module)
+-{
+-    if (!c.buffer.append("(module\n"))
+-        return false;
+-
+-    c.indent++;
+-
+-    if (!RenderTypeSection(c, module.types()))
+-        return false;
+-
+-    if (!RenderImportSection(c, module))
+-        return false;
+-
+-    if (!RenderTableSection(c, module))
+-        return false;
+-
+-    if (!RenderMemorySection(c, module))
+-        return false;
+-
+-    if (!RenderGlobalSection(c, module))
+-        return false;
+-
+-    if (!RenderExportSection(c, module.exports(), module.funcImportNames(), module.funcs()))
+-        return false;
+-
+-    if (!RenderStartSection(c, module))
+-        return false;
+-
+-    if (!RenderElemSection(c, module))
+-        return false;
+-
+-    if (!RenderCodeSection(c, module.funcs(), module.types()))
+-        return false;
+-
+-    if (!RenderDataSection(c, module))
+-        return false;
+-
+-    c.indent--;
+-
+-    if (!c.buffer.append(")"))
+-        return false;
+-
+-    return true;
+-}
+-
+-/*****************************************************************************/
+-// Top-level functions
+-
+-bool
+-wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer)
+-{
+-    LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
+-
+-    AstModule* module;
+-    if (!BinaryToAst(cx, bytes, length, lifo, &module))
+-        return false;
+-
+-    WasmPrintBuffer buf(buffer);
+-    WasmRenderContext c(cx, module, buf);
+-
+-    if (!RenderModule(c, *module)) {
+-        if (!cx->isExceptionPending())
+-            ReportOutOfMemory(cx);
+-        return false;
+-    }
+-
+-    return true;
+-}
+diff --git a/js/src/wasm/WasmBinaryToText.h b/js/src/wasm/WasmBinaryToText.h
+deleted file mode 100644
+--- a/js/src/wasm/WasmBinaryToText.h
++++ /dev/null
+@@ -1,44 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+- * vim: set ts=8 sts=4 et sw=4 tw=99:
+- *
+- * Copyright 2015 Mozilla Foundation
+- *
+- * Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- *
+- *     http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-#ifndef wasm_binary_to_text_h
+-#define wasm_binary_to_text_h
+-
+-#include "NamespaceImports.h"
+-
+-#include "gc/Rooting.h"
+-#include "js/Class.h"
+-#include "wasm/WasmCode.h"
+-
+-namespace js {
+-
+-class StringBuffer;
+-
+-namespace wasm {
+-
+-// Translate the given binary representation of a wasm module into the module's textual
+-// representation.
+-
+-MOZ_MUST_USE bool
+-BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer);
+-
+-}  // namespace wasm
+-
+-}  // namespace js
+-
+-#endif // namespace wasm_binary_to_text_h
+diff --git a/js/src/wasm/WasmDebug.cpp b/js/src/wasm/WasmDebug.cpp
+--- a/js/src/wasm/WasmDebug.cpp
++++ b/js/src/wasm/WasmDebug.cpp
+@@ -22,17 +22,16 @@
+ 
+ #include "ds/Sort.h"
+ #include "gc/FreeOp.h"
+ #include "jit/ExecutableAllocator.h"
+ #include "jit/MacroAssembler.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "vm/Debugger.h"
+-#include "wasm/WasmBinaryToText.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmValidate.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ using namespace js::wasm;
+ 
+ using mozilla::BinarySearchIf;
+diff --git a/js/src/wasm/WasmTextUtils.cpp b/js/src/wasm/WasmTextUtils.cpp
+deleted file mode 100644
+--- a/js/src/wasm/WasmTextUtils.cpp
++++ /dev/null
+@@ -1,80 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+- * vim: set ts=8 sts=4 et sw=4 tw=99:
+- *
+- * Copyright 2016 Mozilla Foundation
+- *
+- * Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- *
+- *     http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-#include "wasm/WasmTextUtils.h"
+-
+-#include "util/StringBuffer.h"
+-#include "wasm/WasmTypes.h"
+-
+-using namespace js;
+-using namespace jit;
+-using namespace wasm;
+-
+-using mozilla::IsNaN;
+-
+-template<size_t base>
+-bool
+-wasm::RenderInBase(StringBuffer& sb, uint64_t num)
+-{
+-    uint64_t n = num;
+-    uint64_t pow = 1;
+-    while (n) {
+-        pow *= base;
+-        n /= base;
+-    }
+-    pow /= base;
+-
+-    n = num;
+-    while (pow) {
+-        if (!sb.append("0123456789abcdef"[n / pow]))
+-            return false;
+-        n -= (n / pow) * pow;
+-        pow /= base;
+-    }
+-
+-    return true;
+-}
+-
+-template bool wasm::RenderInBase<10>(StringBuffer& sb, uint64_t num);
+-
+-template<class T>
+-bool
+-wasm::RenderNaN(StringBuffer& sb, T num)
+-{
+-    typedef typename mozilla::SelectTrait<T> Traits;
+-    typedef typename Traits::Bits Bits;
+-
+-    MOZ_ASSERT(IsNaN(num));
+-
+-    Bits bits = mozilla::BitwiseCast<Bits>(num);
+-    if ((bits & Traits::kSignBit) && !sb.append("-"))
+-        return false;
+-    if (!sb.append("nan"))
+-        return false;
+-
+-    Bits payload = bits & Traits::kSignificandBits;
+-    // Only render the payload if it's not the spec's default NaN.
+-    if (payload == ((Traits::kSignificandBits + 1) >> 1))
+-        return true;
+-
+-    return sb.append(":0x") &&
+-           RenderInBase<16>(sb, payload);
+-}
+-
+-template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, float num);
+-template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, double num);
+diff --git a/js/src/wasm/WasmTextUtils.h b/js/src/wasm/WasmTextUtils.h
+deleted file mode 100644
+--- a/js/src/wasm/WasmTextUtils.h
++++ /dev/null
+@@ -1,105 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+- * vim: set ts=8 sts=4 et sw=4 tw=99:
+- *
+- * Copyright 2016 Mozilla Foundation
+- *
+- * Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- *
+- *     http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-#ifndef wasm_text_utils
+-#define wasm_text_utils
+-
+-#include "NamespaceImports.h"
+-
+-#include "util/StringBuffer.h"
+-
+-namespace js {
+-namespace wasm {
+-
+-template<size_t base>
+-MOZ_MUST_USE bool
+-RenderInBase(StringBuffer& sb, uint64_t num);
+-
+-template<class T>
+-MOZ_MUST_USE bool
+-RenderNaN(StringBuffer& sb, T num);
+-
+-// Helper class, StringBuffer wrapper, to track the position (line and column)
+-// within the generated source.
+-
+-class WasmPrintBuffer
+-{
+-    StringBuffer& stringBuffer_;
+-    uint32_t lineno_;
+-    uint32_t column_;
+-
+-  public:
+-    explicit WasmPrintBuffer(StringBuffer& stringBuffer)
+-      : stringBuffer_(stringBuffer),
+-        lineno_(1),
+-        column_(1)
+-    {}
+-    inline char processChar(char ch) {
+-        if (ch == '\n') {
+-            lineno_++; column_ = 1;
+-        } else
+-            column_++;
+-        return ch;
+-    }
+-    inline char16_t processChar(char16_t ch) {
+-        if (ch == '\n') {
+-            lineno_++; column_ = 1;
+-        } else
+-            column_++;
+-        return ch;
+-    }
+-    bool append(const char ch) {
+-        return stringBuffer_.append(processChar(ch));
+-    }
+-    bool append(const char16_t ch) {
+-        return stringBuffer_.append(processChar(ch));
+-    }
+-    bool append(const char* str, size_t length) {
+-        for (size_t i = 0; i < length; i++)
+-            processChar(str[i]);
+-        return stringBuffer_.append(str, length);
+-    }
+-    bool append(const char16_t* begin, const char16_t* end) {
+-        for (const char16_t* p = begin; p != end; p++)
+-            processChar(*p);
+-        return stringBuffer_.append(begin, end);
+-    }
+-    bool append(const char16_t* str, size_t length) {
+-        return append(str, str + length);
+-    }
+-    template <size_t ArrayLength>
+-    bool append(const char (&array)[ArrayLength]) {
+-        static_assert(ArrayLength > 0, "null-terminated");
+-        MOZ_ASSERT(array[ArrayLength - 1] == '\0');
+-        return append(array, ArrayLength - 1);
+-    }
+-    char16_t getChar(size_t index) {
+-        return stringBuffer_.getChar(index);
+-    }
+-    size_t length() {
+-        return stringBuffer_.length();
+-    }
+-    StringBuffer& stringBuffer() { return stringBuffer_; }
+-    uint32_t lineno() { return lineno_; }
+-    uint32_t column() { return column_; }
+-};
+-
+-}  // namespace wasm
+-}  // namespace js
+-
+-#endif // namespace wasm_text_utils
+diff --git a/js/src/wasm/WasmValidate.h b/js/src/wasm/WasmValidate.h
+--- a/js/src/wasm/WasmValidate.h
++++ b/js/src/wasm/WasmValidate.h
+@@ -127,19 +127,16 @@ struct ModuleEnvironment
+         return kind == ModuleKind::AsmJS;
+     }
+     bool debugEnabled() const {
+         return debug == DebugEnabled::True;
+     }
+     bool funcIsImport(uint32_t funcIndex) const {
+         return funcIndex < funcImportGlobalDataOffsets.length();
+     }
+-    uint32_t funcIndexToFuncTypeIndex(uint32_t funcIndex) const {
+-        return TypeDef::fromFuncTypeWithIdPtr(funcTypes[funcIndex]) - types.begin();
+-    }
+ };
+ 
+ // The Encoder class appends bytes to the Bytes object it is given during
+ // construction. The client is responsible for the Bytes's lifetime and must
+ // keep the Bytes alive as long as the Encoder is used.
+ 
+ class Encoder
+ {

+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_422801.patch → frg/work-js/mozilla-release/patches/1450085-1-62a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_422802.patch → frg/work-js/mozilla-release/patches/1450085-2-62a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_422803.patch → frg/work-js/mozilla-release/patches/1450085-3-62a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/1466626-2no1-62a1.patch → frg/work-js/mozilla-release/patches/1466626-2no1-63a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/1466626-3-62a1.patch → frg/work-js/mozilla-release/patches/1466626-3-63a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_421681.patch → frg/work-js/mozilla-release/patches/1467142-62a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_422915.patch → frg/work-js/mozilla-release/patches/1467751-62a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central-push_422914.patch → frg/work-js/mozilla-release/patches/1467752-62a1.patch


+ 4 - 4
frg/work-js/mozilla-release/patches/1471371-63a1.patch

@@ -2,7 +2,7 @@
 # User Ashley Hauck <khyperia@mozilla.com>
 # Date 1534260297 25200
 # Node ID 8464c338715daf9134f9c640d5da3519c9729447
-# Parent  d3e1970a043cba942de33e1dcdcbad883a8e9222
+# Parent  cfa3894a5365229e911e2ee80e7ec0eae3ef23b1
 Bug 1471371 - OOM handling in RegExp construction. r=jorendorff
 
 diff --git a/js/src/tests/non262/RegExp/oom-in-construction.js b/js/src/tests/non262/RegExp/oom-in-construction.js
@@ -30,7 +30,7 @@ new file mode 100644
 diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
 --- a/js/src/vm/RegExpObject.cpp
 +++ b/js/src/vm/RegExpObject.cpp
-@@ -1439,17 +1439,17 @@ js::ParseRegExpFlags(JSContext* cx, JSSt
+@@ -1417,17 +1417,17 @@ js::ParseRegExpFlags(JSContext* cx, JSSt
          ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &invalidFlag);
      } else {
          AutoCheckCannotGC nogc;
@@ -43,9 +43,9 @@ diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
 +        UniqueChars utf8(JS::CharsToNewUTF8CharsZ(cx, range).c_str());
          if (!utf8)
              return false;
-         JS_ReportErrorFlagsAndNumberUTF8(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
-                                          JSMSG_BAD_REGEXP_FLAG, utf8.get());
+         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_BAD_REGEXP_FLAG, utf8.get());
          return false;
      }
  
      return true;
+ }

+ 204 - 0
frg/work-js/mozilla-release/patches/1471841-63a1.patch

@@ -0,0 +1,204 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530218662 25200
+# Node ID ffa64e3aff88f81d0931fa815a60d0d0a57a7e11
+# Parent  3b0f73ff448258a7e2562d6af5cfbab35c33227c
+Bug 1471841: Move WouldDefinePastNonwritableLength into NativeObject.cpp. r=jandem
+
+diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp
+--- a/js/src/builtin/Array.cpp
++++ b/js/src/builtin/Array.cpp
+@@ -934,26 +934,16 @@ js::ArraySetLength(JSContext* cx, Handle
+         arr->setNonWritableLength(cx);
+ 
+     if (!succeeded)
+         return result.fail(JSMSG_CANT_TRUNCATE_ARRAY);
+ 
+     return result.succeed();
+ }
+ 
+-bool
+-js::WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index)
+-{
+-    if (!obj->is<ArrayObject>())
+-        return false;
+-
+-    ArrayObject* arr = &obj->as<ArrayObject>();
+-    return !arr->lengthIsWritable() && index >= arr->length();
+-}
+-
+ static bool
+ array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
+ {
+     ArrayObject* arr = &obj->as<ArrayObject>();
+ 
+     uint32_t index;
+     if (!IdIsIndex(id, &index))
+         return true;
+diff --git a/js/src/builtin/Array.h b/js/src/builtin/Array.h
+--- a/js/src/builtin/Array.h
++++ b/js/src/builtin/Array.h
+@@ -108,24 +108,16 @@ NewCopiedArrayTryUseGroup(JSContext* cx,
+                           const Value* vp, size_t length,
+                           NewObjectKind newKind = GenericObject,
+                           ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
+ 
+ extern ArrayObject*
+ NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
+                                        HandleObject proto = nullptr);
+ 
+-/*
+- * Determines whether a write to the given element on |obj| should fail because
+- * |obj| is an Array with a non-writable length, and writing that element would
+- * increase the length of the array.
+- */
+-extern bool
+-WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index);
+-
+ extern bool
+ GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp);
+ 
+ extern bool
+ SetLengthProperty(JSContext* cx, HandleObject obj, uint32_t length);
+ 
+ /*
+  * Copy 'length' elements from aobj to vp.
+diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
+--- a/js/src/vm/NativeObject.cpp
++++ b/js/src/vm/NativeObject.cpp
+@@ -1189,16 +1189,27 @@ CallAddPropertyHookDense(JSContext* cx, 
+         if (!CallJSAddPropertyOp(cx, addProperty, obj, id, value)) {
+             obj->setDenseElementHole(cx, index);
+             return false;
+         }
+     }
+     return true;
+ }
+ 
++/**
++ * Determines whether a write to the given element on |arr| should fail
++ * because |arr| has a non-writable length, and writing that element would
++ * increase the length of the array.
++ */
++static bool
++WouldDefinePastNonwritableLength(ArrayObject* arr, uint32_t index)
++{
++    return !arr->lengthIsWritable() && index >= arr->length();
++}
++
+ static MOZ_ALWAYS_INLINE void
+ UpdateShapeTypeAndValue(JSContext* cx, NativeObject* obj, Shape* shape, jsid id,
+                         const Value& value)
+ {
+     MOZ_ASSERT(id == shape->propid());
+ 
+     if (shape->isDataProperty()) {
+         obj->setSlotWithType(cx, shape, value, /* overwriting = */ false);
+@@ -1616,17 +1627,17 @@ js::NativeDefineProperty(JSContext* cx, 
+ 
+             MOZ_ASSERT(!cx->helperThread());
+             return ArraySetLength(cx, arr, id, desc_.attributes(), desc_.value(), result);
+         }
+ 
+         // 9.4.2.1 step 3. Don't extend a fixed-length array.
+         uint32_t index;
+         if (IdIsIndex(id, &index)) {
+-            if (WouldDefinePastNonwritableLength(obj, index))
++            if (WouldDefinePastNonwritableLength(arr, index))
+                 return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
+         }
+     } else if (obj->is<TypedArrayObject>()) {
+         // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
+         uint64_t index;
+         if (IsTypedArrayIndex(id, &index)) {
+             MOZ_ASSERT(!cx->helperThread());
+             return DefineTypedArrayElement(cx, obj, index, desc_, result);
+@@ -1918,17 +1929,17 @@ DefineNonexistentProperty(JSContext* cx,
+     if (obj->is<ArrayObject>()) {
+         // Array's length property is non-configurable, so we shouldn't
+         // encounter it in this function.
+         MOZ_ASSERT(id != NameToId(cx->names().length));
+ 
+         // 9.4.2.1 step 3. Don't extend a fixed-length array.
+         uint32_t index;
+         if (IdIsIndex(id, &index)) {
+-            if (WouldDefinePastNonwritableLength(obj, index))
++            if (WouldDefinePastNonwritableLength(&obj->as<ArrayObject>(), index))
+                 return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
+         }
+     } else if (obj->is<TypedArrayObject>()) {
+         // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
+         uint64_t index;
+         if (IsTypedArrayIndex(id, &index)) {
+             // This method is only called for non-existent properties, which
+             // means any absent indexed property must be out of range.
+@@ -2642,21 +2653,24 @@ SetDenseOrTypedArrayElement(JSContext* c
+         // current behavior.  (ES6 currently says to throw for this in
+         // strict mode code, so we may eventually need to change.)
+         uint32_t len = obj->as<TypedArrayObject>().length();
+         if (index < len) {
+             TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
+             return result.succeed();
+         }
+ 
+-        return result.failSoft(JSMSG_BAD_INDEX);
++        // A previously existing typed array element can only be out-of-bounds
++        // if the above ToNumber call detached the typed array's buffer.
++        MOZ_ASSERT(obj->as<TypedArrayObject>().hasDetachedBuffer());
++
++        return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
+     }
+ 
+-    if (WouldDefinePastNonwritableLength(obj, index))
+-        return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
++    MOZ_ASSERT(obj->containsDenseElement(index));
+ 
+     if (!obj->maybeCopyElementsForWrite(cx))
+         return false;
+ 
+     obj->setDenseElementWithType(cx, index, v);
+     return result.succeed();
+ }
+ 
+@@ -2664,19 +2678,18 @@ SetDenseOrTypedArrayElement(JSContext* c
+  * Finish the assignment `receiver[id] = v` when an existing property (shape)
+  * has been found on a native object (pobj). This implements ES6 draft rev 32
+  * (2015 Feb 2) 9.1.9 steps 5 and 6.
+  *
+  * It is necessary to pass both id and shape because shape could be an implicit
+  * dense or typed array element (i.e. not actually a pointer to a Shape).
+  */
+ static bool
+-SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
+-                    HandleValue receiver, HandleNativeObject pobj, Handle<PropertyResult> prop,
+-                    ObjectOpResult& result)
++SetExistingProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
++                    HandleNativeObject pobj, Handle<PropertyResult> prop, ObjectOpResult& result)
+ {
+     // Step 5 for dense elements.
+     if (prop.isDenseOrTypedArrayElement()) {
+         // Step 5.a.
+         if (pobj->denseElementsAreFrozen())
+             return result.fail(JSMSG_READ_ONLY);
+ 
+         // Pure optimization for the common case:
+@@ -2739,17 +2752,17 @@ js::NativeSetProperty(JSContext* cx, Han
+     for (;;) {
+         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
+         bool done;
+         if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
+             return false;
+ 
+         if (prop) {
+             // Steps 5-6.
+-            return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result);
++            return SetExistingProperty(cx, id, v, receiver, pobj, prop, result);
+         }
+ 
+         // Steps 4.a-b. The check for 'done' on this next line is tricky.
+         // done can be true in exactly these unlikely-sounding cases:
+         // - We're looking up an element, and pobj is a TypedArray that
+         //   doesn't have that many elements.
+         // - We're being called from a resolve hook to assign to the property
+         //   being resolved.
+

+ 3 - 3
frg/work-js/mozilla-release/patches/1471931-1-63a1.patch

@@ -3,7 +3,7 @@
 # Date 1530202064 25200
 #      Thu Jun 28 09:07:44 2018 -0700
 # Node ID bd01847472fbc512fbf56b8e4748cf5fad6ee897
-# Parent  4a79f1f833ecbb7d5ca2ea6cde313b0dfdfcfaec
+# Parent  77b4a266b95c06dccf43efe00b3eb74c3153bb22
 Bug 1471931 - Part 1: Replace some js_malloc/js_calloc/js_realloc with their js_pod_malloc/js_pod_calloc/js_pod_realloc counterparts. r=sfink
 
 diff --git a/js/src/builtin/Profilers.cpp b/js/src/builtin/Profilers.cpp
@@ -88,8 +88,8 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
          }
          auto iter = data->Start();
          data->ReadBytes(iter, buffer.get(), size);
-         JSObject* arrayBuffer = JS_NewArrayBufferWithContents(cx, size, buffer.release());
-         if (!arrayBuffer)
+ 
+         auto* rawBuffer = buffer.release();
 diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp
 --- a/js/src/jit/BaselineBailouts.cpp
 +++ b/js/src/jit/BaselineBailouts.cpp

+ 9 - 8
frg/work-js/mozilla-release/patches/1471931-4-63a1.patch

@@ -3,7 +3,7 @@
 # Date 1530203446 25200
 #      Thu Jun 28 09:30:46 2018 -0700
 # Node ID 4e320fc1cbb8c73e868b4bbbe6dee924eed384bc
-# Parent  70f2e5844cb9ab3a48b5759c6d460d098ea6c380
+# Parent  a5cbcd678bdd2cf4d2c18465c05ac9ee598301d3
 Bug 1471931 - Part 4: Add NewString and NewStringDontDeflate functions which accept UniquePtr. r=sfink
 
 diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
@@ -83,7 +83,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
 diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
 --- a/js/src/builtin/TestingFunctions.cpp
 +++ b/js/src/builtin/TestingFunctions.cpp
-@@ -2462,21 +2462,20 @@ ReadGeckoProfilingStack(JSContext* cx, u
+@@ -2460,23 +2460,19 @@ ReadGeckoProfilingStack(JSContext* cx, u
  
              frameKind = NewStringCopyZ<CanGC>(cx, inlineFrame.kind);
              if (!frameKind)
@@ -93,13 +93,14 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
                  return false;
  
 -            size_t length = strlen(inlineFrame.label.get());
--            auto label = reinterpret_cast<Latin1Char*>(inlineFrame.label.release());
+-            auto* label = reinterpret_cast<Latin1Char*>(inlineFrame.label.release());
 -            frameLabel = NewString<CanGC>(cx, label, length);
--            if (!frameLabel)
+-            if (!frameLabel) {
+-                js_free(label);
 +            frameLabel = NewLatin1StringZ(cx, std::move(inlineFrame.label));
-+            if (!frameLabel) {
++            if (!frameLabel)
                  return false;
-+            }
+-            }
  
              if (!JS_DefineProperty(cx, inlineFrameInfo, "label", frameLabel, propAttrs))
                  return false;
@@ -108,7 +109,7 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
              if (!JS_DefinePropertyById(cx, inlineStack, idx, inlineFrameInfo, 0))
                  return false;
  
-@@ -3667,20 +3666,20 @@ FindPath(JSContext* cx, unsigned argc, V
+@@ -3670,20 +3666,20 @@ FindPath(JSContext* cx, unsigned argc, V
          if (!cx->compartment()->wrap(cx, &wrapped))
              return false;
  
@@ -206,7 +207,7 @@ diff --git a/js/src/util/StringBuffer.cpp b/js/src/util/StringBuffer.cpp
 diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp
 --- a/js/src/vm/JSCompartment.cpp
 +++ b/js/src/vm/JSCompartment.cpp
-@@ -281,32 +281,24 @@ CopyStringPure(JSContext* cx, JSString* 
+@@ -278,32 +278,24 @@ CopyStringPure(JSContext* cx, JSString* 
                 : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
      }
  

+ 58 - 0
frg/work-js/mozilla-release/patches/1473256-63a1.patch

@@ -0,0 +1,58 @@
+# HG changeset patch
+# User Jan de Mooij <jdemooij@mozilla.com>
+# Date 1531225971 -7200
+# Node ID 238948fa4dd6f8b94e3d44c00d922830fbfbb0f7
+# Parent  49addf2ffc711112af5c6a937ad66216b89caa05
+Bug 1473256 - Don't add a length property in AddLengthProperty if it's already present. r=anba
+
+diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp
+--- a/js/src/builtin/Array.cpp
++++ b/js/src/builtin/Array.cpp
+@@ -1000,26 +1000,29 @@ ObjectMayHaveExtraIndexedProperties(JSOb
+         if (obj->as<NativeObject>().getDenseInitializedLength() != 0)
+             return true;
+     } while (true);
+ }
+ 
+ static bool
+ AddLengthProperty(JSContext* cx, HandleArrayObject obj)
+ {
+-    /*
+-     * Add the 'length' property for a newly created array,
+-     * and update the elements to be an empty array owned by the object.
+-     * The shared emptyObjectElements singleton cannot be used for slow arrays,
+-     * as accesses to 'length' will use the elements header.
+-     */
++    // Add the 'length' property for a newly created array. Shapes are shared
++    // across realms within a zone and because we update the initial shape with
++    // a Shape that contains the length-property (in NewArray), it's possible
++    // the length property has already been defined.
++
++    Shape* shape = obj->lastProperty();
++    if (!shape->isEmptyShape()) {
++        MOZ_ASSERT(JSID_IS_ATOM(shape->propidRaw(), cx->names().length));
++        MOZ_ASSERT(shape->previous()->isEmptyShape());
++        return true;
++    }
+ 
+     RootedId lengthId(cx, NameToId(cx->names().length));
+-    MOZ_ASSERT(!obj->lookup(cx, lengthId));
+-
+     return NativeObject::addAccessorProperty(cx, obj, lengthId,
+                                              array_length_getter, array_length_setter,
+                                              JSPROP_PERMANENT | JSPROP_SHADOWABLE);
+ }
+ 
+ static bool
+ IsArrayConstructor(const JSObject* obj)
+ {
+diff --git a/js/src/jit-test/tests/basic/bug1473256.js b/js/src/jit-test/tests/basic/bug1473256.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/basic/bug1473256.js
+@@ -0,0 +1,5 @@
++var a1 = Reflect.construct(Array, [], Object);
++var g = newGlobal({sameZoneAs: this});
++var a2 = new g.Array(1, 2, 3);
++assertEq(a1.length, 0);
++assertEq(a2.length, 3);

+ 6 - 6
frg/work-js/mozilla-release/patches/1481097-5-64a1.patch

@@ -2,7 +2,7 @@
 # User Chris Peterson <cpeterson@mozilla.com>
 # Date 1532243386 25200
 # Node ID eb8f3d8844616dbe6789b10a0fa248a7f9da5693
-# Parent  457703dd9351442c192791a3249b9250d079b481
+# Parent  d5aa057ba995254ed0c8e7c8088fe3ffea9bd228
 Bug 1481097 - js: Build Array.cpp and JSAtom.cpp in unified mode. r=djvj
 
 This gcc 4.8.2 workaround (from bug 942421) is no longer needed because Firefox currently requires gcc 6.1 or later (as of bug 1444274).
@@ -10,7 +10,7 @@ This gcc 4.8.2 workaround (from bug 942421) is no longer needed because Firefox
 diff --git a/js/src/moz.build b/js/src/moz.build
 --- a/js/src/moz.build
 +++ b/js/src/moz.build
-@@ -170,16 +170,17 @@ EXPORTS.js += [
+@@ -173,16 +173,17 @@ EXPORTS.js += [
      '../public/Utility.h',
      '../public/Value.h',
      '../public/Vector.h',
@@ -28,7 +28,7 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'builtin/intl/CommonFunctions.cpp',
      'builtin/intl/DateTimeFormat.cpp',
      'builtin/intl/IntlObject.cpp',
-@@ -354,16 +355,17 @@ UNIFIED_SOURCES += [
+@@ -370,16 +371,17 @@ UNIFIED_SOURCES += [
      'vm/ForOfIterator.cpp',
      'vm/GeckoProfiler.cpp',
      'vm/GeneratorObject.cpp',
@@ -46,11 +46,11 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'vm/JSONPrinter.cpp',
      'vm/JSScript.cpp',
      'vm/MemoryMetrics.cpp',
-@@ -419,18 +421,16 @@ UNIFIED_SOURCES += [
+@@ -432,18 +434,16 @@ UNIFIED_SOURCES += [
+     'wasm/WasmSignalHandlers.cpp',
      'wasm/WasmStubs.cpp',
      'wasm/WasmTable.cpp',
      'wasm/WasmTextToBinary.cpp',
-     'wasm/WasmTextUtils.cpp',
      'wasm/WasmTypes.cpp',
      'wasm/WasmValidate.cpp'
  ]
@@ -65,7 +65,7 @@ diff --git a/js/src/moz.build b/js/src/moz.build
  # template instantiations.
  #   template instantiations.
  # jsmath.cpp cannot be built in unified mode because it needs to re-#define the
-@@ -443,25 +443,23 @@ UNIFIED_SOURCES += [
+@@ -456,25 +456,23 @@ UNIFIED_SOURCES += [
  # perf/ProfilingStack.cpp cannot be built in unified mode because we want to
  #   suppress warnings due to usage of the system allocator, and this allows it
  #   to have a deterministic object name.

+ 4 - 10
frg/work-js/mozilla-release/patches/1489698-8-65a1.patch

@@ -3,13 +3,13 @@
 # Date 1536371493 14400
 #      Fri Sep 07 21:51:33 2018 -0400
 # Node ID 520d47760632c300e540b63b70e5655d60e9a8f4
-# Parent  6323eca91b342bc2a4fb5556be09084449a49e5c
+# Parent  553667bb270f98108d1bb3ca7262e072dab2a6cb
 Bug 1489698 - Add moz.build for js/src/wasm. r=luke,froydnj
 
 diff --git a/js/src/moz.build b/js/src/moz.build
 --- a/js/src/moz.build
 +++ b/js/src/moz.build
-@@ -287,40 +287,16 @@ UNIFIED_SOURCES += [
+@@ -290,37 +290,16 @@ UNIFIED_SOURCES += [
      'vm/TypedArrayObject.cpp',
      'vm/TypeInference.cpp',
      'vm/UbiNode.cpp',
@@ -20,8 +20,6 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'vm/Xdr.cpp',
 -    'wasm/AsmJS.cpp',
 -    'wasm/WasmBaselineCompile.cpp',
--    'wasm/WasmBinaryToAST.cpp',
--    'wasm/WasmBinaryToText.cpp',
 -    'wasm/WasmBuiltins.cpp',
 -    'wasm/WasmCode.cpp',
 -    'wasm/WasmCompile.cpp',
@@ -39,7 +37,6 @@ diff --git a/js/src/moz.build b/js/src/moz.build
 -    'wasm/WasmStubs.cpp',
 -    'wasm/WasmTable.cpp',
 -    'wasm/WasmTextToBinary.cpp',
--    'wasm/WasmTextUtils.cpp',
 -    'wasm/WasmTypes.cpp',
 -    'wasm/WasmValidate.cpp'
  ]
@@ -50,7 +47,7 @@ diff --git a/js/src/moz.build b/js/src/moz.build
  #   win32 test slowdowns
  # frontend/Parser.cpp cannot be built in unified mode because of explicit
  # template instantiations.
-@@ -411,16 +387,17 @@ else:
+@@ -411,16 +390,17 @@ else:
          'perf/pm_stub.cpp'
      ]
  
@@ -72,7 +69,7 @@ diff --git a/js/src/wasm/moz.build b/js/src/wasm/moz.build
 new file mode 100644
 --- /dev/null
 +++ b/js/src/wasm/moz.build
-@@ -0,0 +1,45 @@
+@@ -0,0 +1,42 @@
 +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 +# vim: set filetype=python:
 +# This Source Code Form is subject to the terms of the Mozilla Public
@@ -95,8 +92,6 @@ new file mode 100644
 +UNIFIED_SOURCES += [
 +    'AsmJS.cpp',
 +    'WasmBaselineCompile.cpp',
-+    'WasmBinaryToAST.cpp',
-+    'WasmBinaryToText.cpp',
 +    'WasmBuiltins.cpp',
 +    'WasmCode.cpp',
 +    'WasmCompile.cpp',
@@ -114,7 +109,6 @@ new file mode 100644
 +    'WasmStubs.cpp',
 +    'WasmTable.cpp',
 +    'WasmTextToBinary.cpp',
-+    'WasmTextUtils.cpp',
 +    'WasmTypes.cpp',
 +    'WasmValidate.cpp'
 +]

+ 333 - 0
frg/work-js/mozilla-release/patches/1502886-1-65a1.patch

@@ -0,0 +1,333 @@
+# HG changeset patch
+# User Benjamin Bouvier <benj@benj.me>
+# Date 1540835717 -3600
+# Node ID ab04d8c725fd0cbd61e6c32e4096ee4caa53d55c
+# Parent  3b346840a52a7d1cbc890047a9c507f11a7d8cfe
+Bug 1502886: Delete wasm breakpoints when the wasm instance's Zone is swept; r=jonco
+
+diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp
+--- a/js/src/gc/Zone.cpp
++++ b/js/src/gc/Zone.cpp
+@@ -9,16 +9,17 @@
+ #include "gc/FreeOp.h"
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/Ion.h"
+ #include "jit/JitRealm.h"
+ #include "vm/Debugger.h"
+ #include "vm/Runtime.h"
++#include "wasm/WasmInstance.h"
+ 
+ #include "gc/GC-inl.h"
+ #include "gc/Marking-inl.h"
+ #include "vm/JSCompartment-inl.h"
+ 
+ using namespace js;
+ using namespace js::gc;
+ 
+@@ -179,16 +180,28 @@ Zone::sweepBreakpoints(FreeOp* fop)
+ 
+                 bool dying = scriptGone || IsAboutToBeFinalized(&dbgobj);
+                 MOZ_ASSERT_IF(!dying, !IsAboutToBeFinalized(&bp->getHandlerRef()));
+                 if (dying)
+                     bp->destroy(fop);
+             }
+         }
+     }
++
++    for (RealmsInZoneIter realms(this); !realms.done(); realms.next()) {
++        for (wasm::Instance* instance : realms->wasm.instances()) {
++            if (!instance->debugEnabled()) {
++                continue;
++            }
++            if (!IsAboutToBeFinalized(&instance->object_)) {
++                continue;
++            }
++            instance->debug().clearAllBreakpoints(fop, instance->objectUnbarriered());
++        }
++    }
+ }
+ 
+ void
+ Zone::sweepWeakMaps()
+ {
+     /* Finalize unreachable (key,value) pairs in all weak maps. */
+     WeakMapBase::sweepZone(this);
+ }
+diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
+--- a/js/src/vm/Debugger.cpp
++++ b/js/src/vm/Debugger.cpp
+@@ -588,23 +588,25 @@ Breakpoint::Breakpoint(Debugger* debugge
+   : debugger(debugger), site(site), handler(handler)
+ {
+     MOZ_ASSERT(handler->compartment() == debugger->object->compartment());
+     debugger->breakpoints.pushBack(this);
+     site->breakpoints.pushBack(this);
+ }
+ 
+ void
+-Breakpoint::destroy(FreeOp* fop)
++Breakpoint::destroy(FreeOp* fop, MayDestroySite mayDestroySite /* true */)
+ {
+     if (debugger->enabled)
+         site->dec(fop);
+     debugger->breakpoints.remove(this);
+     site->breakpoints.remove(this);
+-    site->destroyIfEmpty(fop);
++    if (mayDestroySite == MayDestroySite::True) {
++        site->destroyIfEmpty(fop);
++    }
+     fop->delete_(this);
+ }
+ 
+ Breakpoint*
+ Breakpoint::nextInDebugger()
+ {
+     return debuggerLink.mNext;
+ }
+@@ -4147,18 +4149,18 @@ Debugger::removeDebuggeeGlobal(FreeOp* f
+         DebuggerFrame* frameobj = e.front().value();
+         if (frame.global() == global) {
+             frameobj->freeFrameIterData(fop);
+             DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, frame, frameobj);
+             e.removeFront();
+         }
+     }
+ 
+-    auto *globalDebuggersVector = global->getDebuggers();
+-    auto *zoneDebuggersVector = global->zone()->getDebuggers();
++    auto* globalDebuggersVector = global->getDebuggers();
++    auto* zoneDebuggersVector = global->zone()->getDebuggers();
+ 
+     /*
+      * The relation must be removed from up to three places:
+      * globalDebuggersVector and debuggees for sure, and possibly the
+      * compartment's debuggee set.
+      *
+      * The debuggee zone set is recomputed on demand. This avoids refcounting
+      * and in practice we have relatively few debuggees that tend to all be in
+@@ -4186,16 +4188,18 @@ Debugger::removeDebuggeeGlobal(FreeOp* f
+           case BreakpointSite::Type::JS:
+             if (bp->site->asJS()->script->realm() == global->realm())
+                 bp->destroy(fop);
+             break;
+           case BreakpointSite::Type::Wasm:
+             if (bp->asWasm()->wasmInstance->realm() == global->realm())
+                 bp->destroy(fop);
+             break;
++          default:
++            MOZ_CRASH("unknown breakpoint type");
+         }
+     }
+     MOZ_ASSERT_IF(debuggees.empty(), !firstBreakpoint());
+ 
+     /*
+      * If we are tracking allocation sites, we need to remove the object
+      * metadata callback from this global's realm.
+      */
+@@ -6543,26 +6547,32 @@ DebuggerScript_getBreakpoints(JSContext*
+ 
+ class DebuggerScriptClearBreakpointMatcher
+ {
+     JSContext* cx_;
+     Debugger* dbg_;
+     JSObject* handler_;
+ 
+   public:
+-    explicit DebuggerScriptClearBreakpointMatcher(JSContext* cx, Debugger* dbg, JSObject* handler) : cx_(cx), dbg_(dbg), handler_(handler) { }
++    DebuggerScriptClearBreakpointMatcher(JSContext* cx, Debugger* dbg, JSObject* handler)
++      : cx_(cx),
++        dbg_(dbg),
++        handler_(handler)
++    { }
+     using ReturnType = bool;
+ 
+     ReturnType match(HandleScript script) {
+         script->clearBreakpointsIn(cx_->runtime()->defaultFreeOp(), dbg_, handler_);
+         return true;
+     }
+ 
+     ReturnType match(Handle<WasmInstanceObject*> instance) {
+-        return instance->instance().debug().clearBreakpointsIn(cx_, instance, dbg_, handler_);
++        instance->instance().debug().clearBreakpointsIn(cx_->runtime()->defaultFreeOp(), instance, dbg_,
++                                                        handler_);
++        return true;
+     }
+ };
+ 
+ 
+ static bool
+ DebuggerScript_clearBreakpoint(JSContext* cx, unsigned argc, Value* vp)
+ {
+     THIS_DEBUGSCRIPT_REFERENT(cx, argc, vp, "clearBreakpoint", args, obj, referent);
+diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
+--- a/js/src/vm/Debugger.h
++++ b/js/src/vm/Debugger.h
+@@ -1613,28 +1613,28 @@ class BreakpointSite {
+     using BreakpointList =
+         mozilla::DoublyLinkedList<js::Breakpoint,
+                                   SiteLinkAccess<js::Breakpoint>>;
+     BreakpointList breakpoints;
+     size_t enabledCount;  /* number of breakpoints in the list that are enabled */
+ 
+   protected:
+     virtual void recompile(FreeOp* fop) = 0;
+-    bool isEmpty() const;
+     inline bool isEnabled() const { return enabledCount > 0; }
+ 
+   public:
+     BreakpointSite(Type type);
+     Breakpoint* firstBreakpoint() const;
+     virtual ~BreakpointSite() {}
+     bool hasBreakpoint(Breakpoint* bp);
+     inline Type type() const { return type_; }
+ 
+     void inc(FreeOp* fop);
+     void dec(FreeOp* fop);
++    bool isEmpty() const;
+     virtual void destroyIfEmpty(FreeOp* fop) = 0;
+ 
+     inline JSBreakpointSite* asJS();
+     inline WasmBreakpointSite* asWasm();
+ };
+ 
+ /*
+  * Each Breakpoint is a member of two linked lists: its debugger's list and its
+@@ -1669,17 +1669,23 @@ class Breakpoint {
+     /**
+      * Link elements for each list this breakpoint can be in.
+      */
+     mozilla::DoublyLinkedListElement<Breakpoint> debuggerLink;
+     mozilla::DoublyLinkedListElement<Breakpoint> siteLink;
+ 
+   public:
+     Breakpoint(Debugger* debugger, BreakpointSite* site, JSObject* handler);
+-    void destroy(FreeOp* fop);
++
++    enum MayDestroySite {
++        False,
++        True
++    };
++    void destroy(FreeOp* fop, MayDestroySite mayDestroySite = MayDestroySite::True);
++
+     Breakpoint* nextInDebugger();
+     Breakpoint* nextInSite();
+     const PreBarrieredObject& getHandler() const { return handler; }
+     PreBarrieredObject& getHandlerRef() { return handler; }
+ 
+     inline WasmBreakpoint* asWasm();
+ };
+ 
+diff --git a/js/src/wasm/WasmDebug.cpp b/js/src/wasm/WasmDebug.cpp
+--- a/js/src/wasm/WasmDebug.cpp
++++ b/js/src/wasm/WasmDebug.cpp
+@@ -282,45 +282,47 @@ DebugState::destroyBreakpointSite(FreeOp
+ {
+     MOZ_ASSERT(breakpointSites_.initialized());
+     WasmBreakpointSiteMap::Ptr p = breakpointSites_.lookup(offset);
+     MOZ_ASSERT(p);
+     fop->delete_(p->value());
+     breakpointSites_.remove(p);
+ }
+ 
+-bool
+-DebugState::clearBreakpointsIn(JSContext* cx, WasmInstanceObject* instance, js::Debugger* dbg, JSObject* handler)
++void
++DebugState::clearBreakpointsIn(FreeOp* fop, WasmInstanceObject* instance, js::Debugger* dbg,
++                               JSObject* handler)
+ {
+     MOZ_ASSERT(instance);
+     if (!breakpointSites_.initialized())
+-        return true;
++        return;
+ 
+-    // Make copy of all sites list, so breakpointSites_ can be modified by
+-    // destroyBreakpointSite calls.
+-    Vector<WasmBreakpointSite*> sites(cx);
+-    if (!sites.resize(breakpointSites_.count()))
+-        return false;
+-    size_t i = 0;
+-    for (WasmBreakpointSiteMap::Range r = breakpointSites_.all(); !r.empty(); r.popFront())
+-        sites[i++] = r.front().value();
+-
+-    for (WasmBreakpointSite* site : sites) {
++    for (WasmBreakpointSiteMap::Enum e(breakpointSites_); !e.empty(); e.popFront()) {
++        WasmBreakpointSite* site = e.front().value();
+         Breakpoint* nextbp;
+         for (Breakpoint* bp = site->firstBreakpoint(); bp; bp = nextbp) {
+             nextbp = bp->nextInSite();
+             if (bp->asWasm()->wasmInstance == instance &&
+                 (!dbg || bp->debugger == dbg) &&
+                 (!handler || bp->getHandler() == handler))
+             {
+-                bp->destroy(cx->runtime()->defaultFreeOp());
++                bp->destroy(fop, Breakpoint::MayDestroySite::False);
+             }
+         }
++        if (site->isEmpty()) {
++            fop->delete_(site);
++            e.removeFront();
++        }
+     }
+-    return true;
++}
++
++void
++DebugState::clearAllBreakpoints(FreeOp* fop, WasmInstanceObject* instance)
++{
++    clearBreakpointsIn(fop, instance, nullptr, nullptr);
+ }
+ 
+ void
+ DebugState::toggleDebugTrap(uint32_t offset, bool enabled)
+ {
+     MOZ_ASSERT(offset);
+     uint8_t* trap = code_->segment(Tier::Debug).base() + offset;
+     const Uint32Vector& farJumpOffsets = metadata(Tier::Debug).debugTrapFarJumpOffsets;
+diff --git a/js/src/wasm/WasmDebug.h b/js/src/wasm/WasmDebug.h
+--- a/js/src/wasm/WasmDebug.h
++++ b/js/src/wasm/WasmDebug.h
+@@ -91,17 +91,19 @@ class DebugState
+     // When the Code is debugEnabled, individual breakpoints can be enabled or
+     // disabled at instruction offsets.
+ 
+     bool hasBreakpointTrapAtOffset(uint32_t offset);
+     void toggleBreakpointTrap(JSRuntime* rt, uint32_t offset, bool enabled);
+     WasmBreakpointSite* getOrCreateBreakpointSite(JSContext* cx, uint32_t offset);
+     bool hasBreakpointSite(uint32_t offset);
+     void destroyBreakpointSite(FreeOp* fop, uint32_t offset);
+-    bool clearBreakpointsIn(JSContext* cx, WasmInstanceObject* instance, js::Debugger* dbg, JSObject* handler);
++    void clearBreakpointsIn(FreeOp* fp, WasmInstanceObject* instance, js::Debugger* dbg,
++                            JSObject* handler);
++    void clearAllBreakpoints(FreeOp* fp, WasmInstanceObject* instance);
+ 
+     // When the Code is debug-enabled, single-stepping mode can be toggled on
+     // the granularity of individual functions.
+ 
+     bool stepModeEnabled(uint32_t funcIndex) const;
+     bool incrementStepModeCount(JSContext* cx, uint32_t funcIndex);
+     bool decrementStepModeCount(FreeOp* fop, uint32_t funcIndex);
+ 
+diff --git a/js/src/wasm/WasmInstance.h b/js/src/wasm/WasmInstance.h
+--- a/js/src/wasm/WasmInstance.h
++++ b/js/src/wasm/WasmInstance.h
+@@ -49,16 +49,18 @@ class Instance
+     jit::TrampolinePtr              jsJitExceptionHandler_;
+     const SharedCode                code_;
+     const UniqueDebugState          debug_;
+     const UniqueTlsData             tlsData_;
+     GCPtrWasmMemoryObject           memory_;
+     SharedTableVector               tables_;
+     bool                            enterFrameTrapsEnabled_;
+ 
++    friend void Zone::sweepBreakpoints(js::FreeOp*);
++
+     // Internal helpers:
+     const void** addressOfFuncTypeId(const FuncTypeIdDesc& funcTypeId) const;
+     FuncImportTls& funcImportTls(const FuncImport& fi);
+     TableTls& tableTls(const TableDesc& td) const;
+ 
+     // Only WasmInstanceObject can call the private trace function.
+     friend class js::WasmInstanceObject;
+     void tracePrivate(JSTracer* trc);

+ 48 - 0
frg/work-js/mozilla-release/patches/1502886-2-65a1.patch

@@ -0,0 +1,48 @@
+# HG changeset patch
+# User Benjamin Bouvier <benj@benj.me>
+# Date 1540904845 -3600
+# Node ID aa663ad84e3695d8be66f8b30cdcf663d19228e4
+# Parent  ab04d8c725fd0cbd61e6c32e4096ee4caa53d55c
+Bug 1502886: Test; r=jonco
+
+diff --git a/js/src/jit-test/tests/wasm/regress/bug1502886.js b/js/src/jit-test/tests/wasm/regress/bug1502886.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/wasm/regress/bug1502886.js
+@@ -0,0 +1,35 @@
++newGlobal();
++g = newGlobal();
++var dbg = Debugger(g);
++gczeal(2, 100);
++function f(x, initFunc) {
++    newGlobal();
++    g.eval(`
++        var {
++            binary,
++            offsets
++        } = wasmTextToBinary('${x}', true);
++        new WebAssembly.Instance(new WebAssembly.Module(binary));
++    `);
++    var {
++        offsets
++    } = g;
++    var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
++    initFunc({
++        wasmScript,
++        breakpoints: offsets
++    })
++};
++try {
++    f('(module (funcnopnop)(export "" 0))',
++        function({
++            wasmScript,
++            breakpoints
++        }) {
++            breakpoints.forEach(function(offset) {
++                wasmScript.setBreakpoint(offset, s = {});
++            });
++        }
++    );
++    f();
++} catch (e) {}
+

+ 30 - 0
frg/work-js/mozilla-release/patches/NOBUG-20180629-testingfunctions-63a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530320467 25200
+#      Fri Jun 29 18:01:07 2018 -0700
+# Node ID 44508edc10b4f31d257594aaa612acfffbb589a5
+# Parent  7f70f23c962119d2b11ecef5f35696b32a11b8e3
+Remove a |false &&| inadvertently left in a patch as part of testing a fallback code path.  Followup to bug 1457560, r=me, thanks to IRC for pointing it out recently
+
+diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
+--- a/js/src/builtin/TestingFunctions.cpp
++++ b/js/src/builtin/TestingFunctions.cpp
+@@ -4978,17 +4978,17 @@ MonotonicNow(JSContext* cx, unsigned arg
+ // The std::chrono symbols are too new to be present in STL on all platforms we
+ // care about, so use raw POSIX clock APIs when it might be necessary.
+ #if defined(XP_UNIX) && !defined(XP_DARWIN)
+     auto ComputeNow = [](const timespec& ts) {
+         return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+     };
+ 
+     timespec ts;
+-    if (false && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
++    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+         // Use a monotonic clock if available.
+         now = ComputeNow(ts);
+     } else {
+         // Use a realtime clock as fallback.
+         if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
+             // Fail if no clock is available.
+             JS_ReportErrorASCII(cx, "can't retrieve system clock");
+             return false;

+ 82 - 0
frg/work-js/mozilla-release/patches/NOBUG-JSFIXUPS-25319.patch

@@ -0,0 +1,82 @@
+# HG changeset patch
+# User Frank-Rainer Grahl <frgrahl@gmx.net>
+# Date 1709405564 -3600
+# Parent  06ebdb7502d0ea4a097b66e007fe1d4f75b392bd
+No Bug - Fix js compartment to realm stuff for legacy behavior. r=me a=me
+
+ - Undo removing obj from SetExistingProperty in Bug 1471841.
+ - GetRealmForCompartment was removed in Bug 1363214.
+   Add something which works for now but needs to be checked for multiple
+   realms in a compartment later. Might be best to remove the add-on
+   compartment after all.
+
+diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
+--- a/js/src/vm/NativeObject.cpp
++++ b/js/src/vm/NativeObject.cpp
+@@ -2693,18 +2693,19 @@ SetDenseOrTypedArrayElement(JSContext* c
+  * Finish the assignment `receiver[id] = v` when an existing property (shape)
+  * has been found on a native object (pobj). This implements ES6 draft rev 32
+  * (2015 Feb 2) 9.1.9 steps 5 and 6.
+  *
+  * It is necessary to pass both id and shape because shape could be an implicit
+  * dense or typed array element (i.e. not actually a pointer to a Shape).
+  */
+ static bool
+-SetExistingProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
+-                    HandleNativeObject pobj, Handle<PropertyResult> prop, ObjectOpResult& result)
++SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
++                    HandleValue receiver, HandleNativeObject pobj, Handle<PropertyResult> prop,
++                    ObjectOpResult& result)
+ {
+     // Step 5 for dense elements.
+     if (prop.isDenseOrTypedArrayElement()) {
+         // Step 5.a.
+         if (pobj->denseElementsAreFrozen())
+             return result.fail(JSMSG_READ_ONLY);
+ 
+         // Pure optimization for the common case:
+@@ -2783,17 +2784,17 @@ js::NativeSetProperty(JSContext* cx, Han
+     for (;;) {
+         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
+         bool done;
+         if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
+             return false;
+ 
+         if (prop) {
+             // Steps 5-6.
+-            return SetExistingProperty(cx, id, v, receiver, pobj, prop, result);
++            return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result);
+         }
+ 
+         // Steps 4.a-b. The check for 'done' on this next line is tricky.
+         // done can be true in exactly these unlikely-sounding cases:
+         // - We're looking up an element, and pobj is a TypedArray that
+         //   doesn't have that many elements.
+         // - We're being called from a resolve hook to assign to the property
+         //   being resolved.
+diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp
+--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
++++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
+@@ -371,18 +371,20 @@ XPCWrappedNativeScope::AllowContentXBLSc
+ 
+ namespace xpc {
+ JSObject*
+ GetXBLScope(JSContext* cx, JSObject* contentScopeArg)
+ {
+     MOZ_ASSERT(!IsInAddonScope(contentScopeArg));
+ 
+     JS::RootedObject contentScope(cx, contentScopeArg);
+-    JSCompartment* addonComp = js::GetObjectCompartment(contentScope);
+-    JS::Rooted<JS::Realm*> addonRealm(cx, JS::GetRealmForCompartment(addonComp));
++    Realm* targetRealm = GetObjectRealmOrNull(contentScope);
++    MOZ_RELEASE_ASSERT(targetRealm);
++
++    JS::Rooted<JS::Realm*> addonRealm(cx, targetRealm);
+     JSAutoRealm ar(cx, contentScope);
+     JSObject* scope = RealmPrivate::Get(addonRealm)->scope->EnsureContentXBLScope(cx);
+     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
+     scope = js::UncheckedUnwrap(scope);
+     JS::ExposeObjectToActiveJS(scope);
+     return scope;
+ }
+ 

+ 0 - 318
frg/work-js/mozilla-release/patches/mozilla-central-push_422771.patch

@@ -1,318 +0,0 @@
-# HG changeset patch
-# User Jon Coppeard <jcoppeard@mozilla.com>
-# Date 1529100306 25200
-#      Fri Jun 15 15:05:06 2018 -0700
-# Node ID 461ae20806865d625e7c842e75d6453bde89445d
-# Parent  2cf978a6ae5206b15647ec515f78004de5c1021d
-Bug 1468867 - Move heap state to JSRuntime r=sfink
-
-diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
---- a/js/src/gc/GC.cpp
-+++ b/js/src/gc/GC.cpp
-@@ -3389,24 +3389,24 @@ GCRuntime::triggerGC(JS::gcreason::Reaso
-     JS::PrepareForFullGC(rt->mainContextFromOwnThread());
-     requestMajorGC(reason);
-     return true;
- }
- 
- void
- GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
--
-     if (!CurrentThreadCanAccessRuntime(rt)) {
-         // Zones in use by a helper thread can't be collected.
-         MOZ_ASSERT(zone->usedByHelperThread() || zone->isAtomsZone());
-         return;
-     }
- 
-+    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+
-     size_t usedBytes = zone->usage.gcBytes();
-     size_t thresholdBytes = zone->threshold.gcTriggerBytes();
- 
-     if (usedBytes >= thresholdBytes) {
-         // The threshold has been surpassed, immediately trigger a GC, which
-         // will be done non-incrementally.
-         triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
-         return;
-@@ -6899,40 +6899,41 @@ HeapStateToLabel(JS::HeapState heapState
-     }
-     MOZ_ASSERT_UNREACHABLE("Should have exhausted every JS::HeapState variant!");
-     return nullptr;
- }
- 
- /* Start a new heap session. */
- AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
-   : runtime(rt),
--    prevState(rt->mainContextFromOwnThread()->heapState),
-+    prevState(rt->heapState_),
-     profilingStackFrame(rt->mainContextFromOwnThread(), HeapStateToLabel(heapState),
-                         ProfilingStackFrame::Category::GC)
- {
-+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
-     MOZ_ASSERT(prevState == JS::HeapState::Idle);
-     MOZ_ASSERT(heapState != JS::HeapState::Idle);
-     MOZ_ASSERT_IF(heapState == JS::HeapState::MajorCollecting, rt->gc.nursery().isEmpty());
- 
-     // Session always begins with lock held, see comment in class definition.
-     maybeLock.emplace(rt);
- 
--    rt->mainContextFromOwnThread()->heapState = heapState;
-+    rt->heapState_ = heapState;
- }
- 
- AutoTraceSession::~AutoTraceSession()
- {
-     MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
--    runtime->mainContextFromOwnThread()->heapState = prevState;
-+    runtime->heapState_ = prevState;
- }
- 
- JS_PUBLIC_API(JS::HeapState)
- JS::CurrentThreadHeapState()
- {
--    return TlsContext.get()->heapState;
-+    return TlsContext.get()->runtime()->heapState();
- }
- 
- GCRuntime::IncrementalResult
- GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoTraceSession& session)
- {
-     MOZ_ASSERT(reason != gc::AbortReason::None);
- 
-     switch (incrementalState) {
-@@ -8534,25 +8535,27 @@ AutoAssertNoNurseryAlloc::AutoAssertNoNu
- }
- 
- AutoAssertNoNurseryAlloc::~AutoAssertNoNurseryAlloc()
- {
-     TlsContext.get()->allowNurseryAlloc();
- }
- 
- JS::AutoEnterCycleCollection::AutoEnterCycleCollection(JSRuntime* rt)
--{
-+  : runtime_(rt)
-+{
-+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
-     MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
--    TlsContext.get()->heapState = HeapState::CycleCollecting;
-+    runtime_->heapState_ = HeapState::CycleCollecting;
- }
- 
- JS::AutoEnterCycleCollection::~AutoEnterCycleCollection()
- {
-     MOZ_ASSERT(JS::CurrentThreadIsHeapCycleCollecting());
--    TlsContext.get()->heapState = HeapState::Idle;
-+    runtime_->heapState_ = HeapState::Idle;
- }
- 
- JS::AutoAssertGCCallback::AutoAssertGCCallback()
-   : AutoSuppressGCAnalysis()
- {
-     MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
- }
- 
-@@ -9233,23 +9236,23 @@ JS_PUBLIC_API(bool)
- js::gc::detail::CellIsNotGray(const Cell* cell)
- {
-     // Check that a cell is not marked gray.
-     //
-     // Since this is a debug-only check, take account of the eventual mark state
-     // of cells that will be marked black by the next GC slice in an incremental
-     // GC. For performance reasons we don't do this in CellIsMarkedGrayIfKnown.
- 
-+    if (!CanCheckGrayBits(cell))
-+        return true;
-+
-     // TODO: I'd like to AssertHeapIsIdle() here, but this ends up getting
-     // called during GC and while iterating the heap for memory reporting.
-     MOZ_ASSERT(!JS::CurrentThreadIsHeapCycleCollecting());
- 
--    if (!CanCheckGrayBits(cell))
--        return true;
--
-     auto tc = &cell->asTenured();
-     if (!detail::CellIsMarkedGray(tc))
-         return true;
- 
-     // The cell is gray, but may eventually be marked black if we are in an
-     // incremental GC and the cell is reachable by something on the mark stack.
- 
-     auto rt = tc->runtimeFromAnyThread();
-diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h
---- a/js/src/jspubtd.h
-+++ b/js/src/jspubtd.h
-@@ -157,16 +157,18 @@ CurrentThreadIsHeapCycleCollecting()
-     return CurrentThreadHeapState() == HeapState::CycleCollecting;
- }
- 
- // Decorates the Unlinking phase of CycleCollection so that accidental use
- // of barriered accessors results in assertions instead of leaks.
- class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection)
- {
- #ifdef DEBUG
-+    JSRuntime* runtime_;
-+
-   public:
-     explicit AutoEnterCycleCollection(JSRuntime* rt);
-     ~AutoEnterCycleCollection();
- #else
-   public:
-     explicit AutoEnterCycleCollection(JSRuntime* rt) {}
-     ~AutoEnterCycleCollection() {}
- #endif
-diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp
---- a/js/src/vm/HelperThreads.cpp
-+++ b/js/src/vm/HelperThreads.cpp
-@@ -1533,19 +1533,17 @@ js::GCParallelTask::runFromHelperThread(
-     MOZ_ASSERT(isDispatched(lock));
- 
-     AutoSetContextRuntime ascr(runtime());
-     gc::AutoSetThreadIsPerformingGC performingGC;
- 
-     {
-         AutoUnlockHelperThreadState parallelSection(lock);
-         TimeStamp timeStart = TimeStamp::Now();
--        TlsContext.get()->heapState = JS::HeapState::MajorCollecting;
-         runTask();
--        TlsContext.get()->heapState = JS::HeapState::Idle;
-         duration_ = TimeSince(timeStart);
-     }
- 
-     setFinished(lock);
-     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, lock);
- }
- 
- bool
-diff --git a/js/src/vm/JSContext-inl.h b/js/src/vm/JSContext-inl.h
---- a/js/src/vm/JSContext-inl.h
-+++ b/js/src/vm/JSContext-inl.h
-@@ -176,17 +176,17 @@ class CompartmentChecker
-     }
- };
- 
- /*
-  * Don't perform these checks when called from a finalizer. The checking
-  * depends on other objects not having been swept yet.
-  */
- #define START_ASSERT_SAME_COMPARTMENT()                                 \
--    if (cx->heapState != JS::HeapState::Idle)                           \
-+    if (JS::CurrentThreadIsHeapCollecting())                            \
-         return;                                                         \
-     CompartmentChecker c(cx)
- 
- template <class T1> inline void
- releaseAssertSameCompartment(JSContext* cx, const T1& t1)
- {
-     START_ASSERT_SAME_COMPARTMENT();
-     c.check(t1);
-diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp
---- a/js/src/vm/JSContext.cpp
-+++ b/js/src/vm/JSContext.cpp
-@@ -1239,17 +1239,16 @@ JSContext::JSContext(JSRuntime* runtime,
- #ifdef JS_SIMULATOR
-     simulator_(nullptr),
- #endif
- #ifdef JS_TRACE_LOGGING
-     traceLogger(nullptr),
- #endif
-     autoFlushICache_(nullptr),
-     dtoaState(nullptr),
--    heapState(JS::HeapState::Idle),
-     suppressGC(0),
- #ifdef DEBUG
-     ionCompiling(false),
-     ionCompilingSafeForMinorGC(false),
-     performingGC(false),
-     gcSweeping(false),
-     gcHelperStateThread(false),
-     isTouchingGrayThings(false),
-diff --git a/js/src/vm/JSContext.h b/js/src/vm/JSContext.h
---- a/js/src/vm/JSContext.h
-+++ b/js/src/vm/JSContext.h
-@@ -454,19 +454,16 @@ struct JSContext : public JS::RootingCon
-   public:
- 
-     js::jit::AutoFlushICache* autoFlushICache() const;
-     void setAutoFlushICache(js::jit::AutoFlushICache* afc);
- 
-     // State used by util/DoubleToString.cpp.
-     js::ThreadData<DtoaState*> dtoaState;
- 
--    // Any GC activity occurring on this thread.
--    js::ThreadData<JS::HeapState> heapState;
--
-     /*
-      * When this flag is non-zero, any attempt to GC will be skipped. It is used
-      * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
-      * debugging facilities that cannot tolerate a GC and would rather OOM
-      * immediately, such as utilities exposed to GDB. Setting this flag is
-      * extremely dangerous and should only be used when in an OOM situation or
-      * in non-exposed debugging facilities.
-      */
-diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
---- a/js/src/vm/Runtime.cpp
-+++ b/js/src/vm/Runtime.cpp
-@@ -127,16 +127,17 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
- #ifdef DEBUG
-     activeThreadHasExclusiveAccess(false),
- #endif
-     scriptDataLock(mutexid::RuntimeScriptData),
- #ifdef DEBUG
-     activeThreadHasScriptDataAccess(false),
- #endif
-     numActiveHelperThreadZones(0),
-+    heapState_(JS::HeapState::Idle),
-     numRealms(0),
-     localeCallbacks(nullptr),
-     defaultLocale(nullptr),
-     profilingScripts(false),
-     scriptAndCountsVector(nullptr),
-     lcovOutput_(),
-     jitRuntime_(nullptr),
-     selfHostingGlobal_(nullptr),
-diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
---- a/js/src/vm/Runtime.h
-+++ b/js/src/vm/Runtime.h
-@@ -475,16 +475,19 @@ struct JSRuntime : public js::MallocProv
-     js::Mutex scriptDataLock;
- #ifdef DEBUG
-     bool activeThreadHasScriptDataAccess;
- #endif
- 
-     // Number of zones which may be operated on by helper threads.
-     mozilla::Atomic<size_t> numActiveHelperThreadZones;
- 
-+    // Any GC activity affecting the heap.
-+    mozilla::Atomic<JS::HeapState> heapState_;
-+
-     friend class js::AutoLockForExclusiveAccess;
-     friend class js::AutoLockScriptData;
- 
-   public:
-     void setUsedByHelperThread(JS::Zone* zone);
-     void clearUsedByHelperThread(JS::Zone* zone);
- 
-     bool hasHelperThreadZones() const {
-@@ -502,16 +505,20 @@ struct JSRuntime : public js::MallocProv
-     bool currentThreadHasScriptDataAccess() const {
-         if (!hasHelperThreadZones())
-             return CurrentThreadCanAccessRuntime(this) && activeThreadHasScriptDataAccess;
- 
-         return scriptDataLock.ownedByCurrentThread();
-     }
- #endif
- 
-+    JS::HeapState heapState() const {
-+        return heapState_;
-+    }
-+
-     // How many realms there are across all zones. This number includes
-     // off-thread context realms, so it isn't necessarily equal to the
-     // number of realms visited by RealmsIter.
-     js::MainThreadData<size_t> numRealms;
- 
-     /* Locale-specific callbacks for string conversion. */
-     js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
- 

+ 0 - 1634
frg/work-js/mozilla-release/patches/mozilla-central-push_422772.patch

@@ -1,1634 +0,0 @@
-# HG changeset patch
-# User Jon Coppeard <jcoppeard@mozilla.com>
-# Date 1529100306 25200
-#      Fri Jun 15 15:05:06 2018 -0700
-# Node ID bbdcb2e0eb3e4e6184015a95083aab52bfe0d57e
-# Parent  461ae20806865d625e7c842e75d6453bde89445d
-Bug 1468867 - Rename heap state checking functions r=sfink
-
-diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h
---- a/js/public/HeapAPI.h
-+++ b/js/public/HeapAPI.h
-@@ -586,20 +586,20 @@ namespace js {
- namespace gc {
- 
- static MOZ_ALWAYS_INLINE bool
- IsIncrementalBarrierNeededOnTenuredGCThing(const JS::GCCellPtr thing)
- {
-     MOZ_ASSERT(thing);
-     MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
- 
--    // TODO: I'd like to assert !CurrentThreadIsHeapBusy() here but this gets
-+    // TODO: I'd like to assert !RuntimeHeapIsBusy() here but this gets
-     // called while we are tracing the heap, e.g. during memory reporting
-     // (see bug 1313318).
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
- 
-     JS::Zone* zone = JS::GetTenuredGCThingZone(thing);
-     return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
- }
- 
- static MOZ_ALWAYS_INLINE void
- ExposeGCThingToActiveJS(JS::GCCellPtr thing)
- {
-@@ -627,17 +627,17 @@ extern JS_PUBLIC_API(bool)
- EdgeNeedsSweepUnbarrieredSlow(T* thingp);
- 
- static MOZ_ALWAYS_INLINE bool
- EdgeNeedsSweepUnbarriered(JSObject** objp)
- {
-     // This function does not handle updating nursery pointers. Raw JSObject
-     // pointers should be updated separately or replaced with
-     // JS::Heap<JSObject*> which handles this automatically.
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
-     if (IsInsideNursery(reinterpret_cast<Cell*>(*objp)))
-         return false;
- 
-     auto zone = JS::shadow::Zone::asShadowZone(detail::GetGCThingZone(uintptr_t(*objp)));
-     if (!zone->isGCSweepingOrCompacting())
-         return false;
- 
-     return EdgeNeedsSweepUnbarrieredSlow(objp);
-diff --git a/js/src/builtin/intl/SharedIntlData.cpp b/js/src/builtin/intl/SharedIntlData.cpp
---- a/js/src/builtin/intl/SharedIntlData.cpp
-+++ b/js/src/builtin/intl/SharedIntlData.cpp
-@@ -398,17 +398,17 @@ js::intl::SharedIntlData::destroyInstanc
-     ianaLinksCanonicalizedDifferentlyByICU.finish();
-     upperCaseFirstLocales.finish();
- }
- 
- void
- js::intl::SharedIntlData::trace(JSTracer* trc)
- {
-     // Atoms are always tenured.
--    if (!JS::CurrentThreadIsHeapMinorCollecting()) {
-+    if (!JS::RuntimeHeapIsMinorCollecting()) {
-         availableTimeZones.trace(trc);
-         ianaZonesTreatedAsLinksByICU.trace(trc);
-         ianaLinksCanonicalizedDifferentlyByICU.trace(trc);
-         upperCaseFirstLocales.trace(trc);
-     }
- }
- 
- size_t
-diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp
---- a/js/src/gc/Allocator.cpp
-+++ b/js/src/gc/Allocator.cpp
-@@ -279,17 +279,17 @@ GCRuntime::checkAllocatorState(JSContext
-                   kind == AllocKind::ATOM ||
-                   kind == AllocKind::FAT_INLINE_ATOM ||
-                   kind == AllocKind::SYMBOL ||
-                   kind == AllocKind::JITCODE ||
-                   kind == AllocKind::SCOPE);
-     MOZ_ASSERT_IF(!cx->zone()->isAtomsZone(),
-                   kind != AllocKind::ATOM &&
-                   kind != AllocKind::FAT_INLINE_ATOM);
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-     MOZ_ASSERT(cx->isAllocAllowed());
- #endif
- 
-     // Crash if we perform a GC action when it is not safe.
-     if (allowGC && !cx->suppressGC)
-         cx->verifyIsSafeToGC();
- 
-     // For testing out of memory conditions
-@@ -375,17 +375,17 @@ GCRuntime::refillFreeListFromAnyThread(J
- }
- 
- /* static */ TenuredCell*
- GCRuntime::refillFreeListFromMainThread(JSContext* cx, AllocKind thingKind)
- {
-     // It should not be possible to allocate on the main thread while we are
-     // inside a GC.
-     Zone *zone = cx->zone();
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy(), "allocating while under GC");
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy(), "allocating while under GC");
- 
-     return cx->arenas()->allocateFromArena(zone, thingKind, ShouldCheckThresholds::CheckThresholds);
- }
- 
- /* static */ TenuredCell*
- GCRuntime::refillFreeListFromHelperThread(JSContext* cx, AllocKind thingKind)
- {
-     // A GC may be happening on the main thread, but zones used by off thread
-@@ -400,18 +400,18 @@ GCRuntime::refillFreeListFromHelperThrea
- GCRuntime::refillFreeListInGC(Zone* zone, AllocKind thingKind)
- {
-     /*
-      * Called by compacting GC to refill a free list while we are in a GC.
-      */
- 
-     zone->arenas.checkEmptyFreeList(thingKind);
-     mozilla::DebugOnly<JSRuntime*> rt = zone->runtimeFromMainThread();
--    MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
--    MOZ_ASSERT_IF(!JS::CurrentThreadIsHeapMinorCollecting(), !rt->gc.isBackgroundSweeping());
-+    MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
-+    MOZ_ASSERT_IF(!JS::RuntimeHeapIsMinorCollecting(), !rt->gc.isBackgroundSweeping());
- 
-     return zone->arenas.allocateFromArena(zone, thingKind, ShouldCheckThresholds::DontCheckThresholds);
- }
- 
- TenuredCell*
- ArenaLists::allocateFromArena(JS::Zone* zone, AllocKind thingKind,
-                               ShouldCheckThresholds checkThresholds)
- {
-diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp
---- a/js/src/gc/Barrier.cpp
-+++ b/js/src/gc/Barrier.cpp
-@@ -19,17 +19,17 @@
- #include "wasm/WasmJS.h"
- 
- namespace js {
- 
- bool
- RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone)
- {
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(shadowZone->runtimeFromMainThread()));
--    return JS::CurrentThreadIsHeapMajorCollecting();
-+    return JS::RuntimeHeapIsMajorCollecting();
- }
- 
- #ifdef DEBUG
- 
- bool
- IsMarkedBlack(JSObject* obj)
- {
-     return obj->isMarkedBlack();
-diff --git a/js/src/gc/Cell.h b/js/src/gc/Cell.h
---- a/js/src/gc/Cell.h
-+++ b/js/src/gc/Cell.h
-@@ -388,17 +388,17 @@ TenuredCell::readBarrier(TenuredCell* th
-         Cell* tmp = thing;
-         TraceManuallyBarrieredGenericPointerEdge(shadowZone->barrierTracer(), &tmp, "read barrier");
-         MOZ_ASSERT(tmp == thing);
-     }
- 
-     if (thing->isMarkedGray()) {
-         // There shouldn't be anything marked grey unless we're on the main thread.
-         MOZ_ASSERT(CurrentThreadCanAccessRuntime(thing->runtimeFromAnyThread()));
--        if (!JS::CurrentThreadIsHeapCollecting())
-+        if (!JS::RuntimeHeapIsCollecting())
-             JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr(thing, thing->getTraceKind()));
-     }
- }
- 
- void
- AssertSafeToSkipBarrier(TenuredCell* thing);
- 
- /* static */ MOZ_ALWAYS_INLINE void
-diff --git a/js/src/gc/DeletePolicy.h b/js/src/gc/DeletePolicy.h
---- a/js/src/gc/DeletePolicy.h
-+++ b/js/src/gc/DeletePolicy.h
-@@ -69,17 +69,17 @@ IsClearEdgesTracer(JSTracer *trc)
-  * into the object and make it safe to delete.
-  */
- template <typename T>
- struct GCManagedDeletePolicy
- {
-     void operator()(const T* constPtr) {
-         if (constPtr) {
-             auto ptr = const_cast<T*>(constPtr);
--            if (JS::CurrentThreadIsHeapCollecting()) {
-+            if (JS::RuntimeHeapIsCollecting()) {
-                 MOZ_ASSERT(js::CurrentThreadIsGCSweeping());
-                 // Do not attempt to clear out storebuffer edges.
-             } else {
-                 gc::ClearEdgesTracer trc;
-                 ptr->trace(&trc);
-             }
-             js_delete(ptr);
-         }
-diff --git a/js/src/gc/GC-inl.h b/js/src/gc/GC-inl.h
---- a/js/src/gc/GC-inl.h
-+++ b/js/src/gc/GC-inl.h
-@@ -125,17 +125,17 @@ class ArenaCellIterImpl
-     void init(Arena* arena, CellIterNeedsBarrier mayNeedBarrier) {
-         MOZ_ASSERT(!initialized);
-         MOZ_ASSERT(arena);
-         initialized = true;
-         AllocKind kind = arena->getAllocKind();
-         firstThingOffset = Arena::firstThingOffset(kind);
-         thingSize = Arena::thingSize(kind);
-         traceKind = MapAllocToTraceKind(kind);
--        needsBarrier = mayNeedBarrier && !JS::CurrentThreadIsHeapCollecting();
-+        needsBarrier = mayNeedBarrier && !JS::RuntimeHeapIsCollecting();
-         reset(arena);
-     }
- 
-     // Use this to move from an Arena of a particular kind to another Arena of
-     // the same kind.
-     void reset(Arena* arena) {
-         MOZ_ASSERT(initialized);
-         MOZ_ASSERT(arena);
-@@ -183,17 +183,17 @@ JSObject*
- ArenaCellIterImpl::get<JSObject>() const;
- 
- class ArenaCellIter : public ArenaCellIterImpl
- {
-   public:
-     explicit ArenaCellIter(Arena* arena)
-       : ArenaCellIterImpl(arena, CellIterMayNeedBarrier)
-     {
--        MOZ_ASSERT(JS::CurrentThreadIsHeapTracing());
-+        MOZ_ASSERT(JS::RuntimeHeapIsTracing());
-     }
- };
- 
- template <typename T>
- class ZoneCellIter;
- 
- template <>
- class ZoneCellIter<TenuredCell> {
-@@ -212,17 +212,17 @@ class ZoneCellIter<TenuredCell> {
-         initForTenuredIteration(zone, kind);
-     }
- 
-     void initForTenuredIteration(JS::Zone* zone, AllocKind kind) {
-         JSRuntime* rt = zone->runtimeFromAnyThread();
- 
-         // If called from outside a GC, ensure that the heap is in a state
-         // that allows us to iterate.
--        if (!JS::CurrentThreadIsHeapBusy()) {
-+        if (!JS::RuntimeHeapIsBusy()) {
-             // Assert that no GCs can occur while a ZoneCellIter is live.
-             nogc.emplace();
-         }
- 
-         // We have a single-threaded runtime, so there's no need to protect
-         // against other threads iterating or allocating. However, we do have
-         // background finalization; we may have to wait for this to finish if
-         // it's currently active.
-diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
---- a/js/src/gc/GC.cpp
-+++ b/js/src/gc/GC.cpp
-@@ -1729,17 +1729,17 @@ GCRuntime::getParameter(JSGCParamKey key
-         MOZ_ASSERT(key == JSGC_NUMBER);
-         return uint32_t(number);
-     }
- }
- 
- void
- GCRuntime::setMarkStackLimit(size_t limit, AutoLockGC& lock)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-     AutoUnlockGC unlock(lock);
-     AutoStopVerifyingBarriers pauseVerification(rt, false);
-     marker.setMaxCapacity(limit);
- }
- 
- bool
- GCRuntime::addBlackRootsTracer(JSTraceDataOp traceOp, void* data)
- {
-@@ -3325,34 +3325,34 @@ GCRuntime::triggerGC(JS::gcreason::Reaso
-     /*
-      * Don't trigger GCs if this is being called off the main thread from
-      * onTooMuchMalloc().
-      */
-     if (!CurrentThreadCanAccessRuntime(rt))
-         return false;
- 
-     /* GC is already running. */
--    if (JS::CurrentThreadIsHeapCollecting())
-+    if (JS::RuntimeHeapIsCollecting())
-         return false;
- 
-     JS::PrepareForFullGC(rt->mainContextFromOwnThread());
-     requestMajorGC(reason);
-     return true;
- }
- 
- void
- GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock)
- {
-     if (!CurrentThreadCanAccessRuntime(rt)) {
-         // Zones in use by a helper thread can't be collected.
-         MOZ_ASSERT(zone->usedByHelperThread() || zone->isAtomsZone());
-         return;
-     }
- 
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
- 
-     size_t usedBytes = zone->usage.gcBytes();
-     size_t thresholdBytes = zone->threshold.gcTriggerBytes();
- 
-     if (usedBytes >= thresholdBytes) {
-         // The threshold has been surpassed, immediately trigger a GC, which
-         // will be done non-incrementally.
-         triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
-@@ -3389,17 +3389,17 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone*
- }
- 
- bool
- GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason, size_t used, size_t threshold)
- {
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
- 
-     /* GC is already running. */
--    if (JS::CurrentThreadIsHeapBusy())
-+    if (JS::RuntimeHeapIsBusy())
-         return false;
- 
- #ifdef JS_GC_ZEAL
-     if (hasZealMode(ZealMode::Alloc)) {
-         MOZ_RELEASE_ASSERT(triggerGC(reason));
-         return true;
-     }
- #endif
-@@ -3449,17 +3449,17 @@ GCRuntime::maybeGC(Zone* zone)
-     }
- }
- 
- void
- GCRuntime::triggerFullGCForAtoms(JSContext* cx)
- {
-     MOZ_ASSERT(fullGCForAtomsRequested_);
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
-     MOZ_ASSERT(cx->canCollectAtoms());
-     fullGCForAtomsRequested_ = false;
-     MOZ_RELEASE_ASSERT(triggerGC(JS::gcreason::DELAYED_ATOMS_GC));
- }
- 
- // Do all possible decommit immediately from the current thread without
- // releasing the GC lock or allocating any memory.
- void
-@@ -3700,25 +3700,25 @@ GCRuntime::queueZonesForBackgroundSweep(
-     AutoLockGC lock(rt);
-     backgroundSweepZones.ref().transferFrom(zones);
-     helperState.maybeStartBackgroundSweep(lock, helperLock);
- }
- 
- void
- GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo)
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-     AutoLockGC lock(rt);
-     blocksToFreeAfterSweeping.ref().transferUnusedFrom(lifo);
- }
- 
- void
- GCRuntime::freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo)
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-     AutoLockGC lock(rt);
-     blocksToFreeAfterSweeping.ref().transferFrom(lifo);
- }
- 
- void
- GCRuntime::freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo)
- {
-     blocksToFreeAfterMinorGC.ref().transferFrom(lifo);
-@@ -5888,17 +5888,17 @@ GCRuntime::endSweepingSweepGroup(FreeOp*
- }
- 
- void
- GCRuntime::beginSweepPhase(JS::gcreason::Reason reason, AutoTraceSession& session)
- {
-     /*
-      * Sweep phase.
-      *
--     * Finalize as we sweep, outside of lock but with CurrentThreadIsHeapBusy()
-+     * Finalize as we sweep, outside of lock but with RuntimeHeapIsBusy()
-      * true so that any attempt to allocate a GC-thing from a finalizer will
-      * fail, rather than nest badly and leave the unmarked newborn to be swept.
-      */
- 
-     MOZ_ASSERT(!abortSweepAfterCurrentGroup);
- 
-     AutoSetThreadIsSweeping threadIsSweeping;
- 
-@@ -6888,22 +6888,22 @@ AutoTraceSession::AutoTraceSession(JSRun
-     // Session always begins with lock held, see comment in class definition.
-     maybeLock.emplace(rt);
- 
-     rt->heapState_ = heapState;
- }
- 
- AutoTraceSession::~AutoTraceSession()
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-     runtime->heapState_ = prevState;
- }
- 
- JS_PUBLIC_API(JS::HeapState)
--JS::CurrentThreadHeapState()
-+JS::RuntimeHeapState()
- {
-     return TlsContext.get()->runtime()->heapState();
- }
- 
- GCRuntime::IncrementalResult
- GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoTraceSession& session)
- {
-     MOZ_ASSERT(reason != gc::AbortReason::None);
-@@ -7633,17 +7633,17 @@ GCRuntime::maybeDoCycleCollection()
- }
- 
- void
- GCRuntime::checkCanCallAPI()
- {
-     MOZ_RELEASE_ASSERT(CurrentThreadCanAccessRuntime(rt));
- 
-     /* If we attempt to invoke the GC while we are running in the GC, assert. */
--    MOZ_RELEASE_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_RELEASE_ASSERT(!JS::RuntimeHeapIsBusy());
- 
-     MOZ_ASSERT(rt->mainContextFromOwnThread()->isAllocAllowed());
- }
- 
- bool
- GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason)
- {
-     if (rt->mainContextFromOwnThread()->suppressGC)
-@@ -7890,17 +7890,17 @@ GCRuntime::onOutOfMallocMemory(const Aut
-     // might let the OS scrape together enough pages to satisfy the failing
-     // malloc request.
-     decommitAllWithoutUnlocking(lock);
- }
- 
- void
- GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
- 
-     MOZ_ASSERT_IF(reason == JS::gcreason::EVICT_NURSERY,
-                   !rt->mainContextFromOwnThread()->suppressGC);
-     if (rt->mainContextFromOwnThread()->suppressGC)
-         return;
- 
-     gcstats::AutoPhase ap(rt->gc.stats(), phase);
- 
-@@ -8289,17 +8289,17 @@ GCRuntime::runDebugGC()
-     }
- 
- #endif
- }
- 
- void
- GCRuntime::setFullCompartmentChecks(bool enabled)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
-     fullCompartmentChecks = enabled;
- }
- 
- void
- GCRuntime::notifyRootsRemoved()
- {
-     rootsRemoved = true;
- 
-@@ -8309,30 +8309,30 @@ GCRuntime::notifyRootsRemoved()
-         nextScheduled = 1;
- #endif
- }
- 
- #ifdef JS_GC_ZEAL
- bool
- GCRuntime::selectForMarking(JSObject* object)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
-     return selectedForMarking.ref().append(object);
- }
- 
- void
- GCRuntime::clearSelectedForMarking()
- {
-     selectedForMarking.ref().clearAndFree();
- }
- 
- void
- GCRuntime::setDeterministic(bool enabled)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
-     deterministicOnly = enabled;
- }
- #endif
- 
- #ifdef ENABLE_WASM_GC
- /* static */ bool
- GCRuntime::temporaryAbortIfWasmGc(JSContext* cx) {
-     return cx->options().wasmGc() && cx->suppressGC;
-@@ -8497,30 +8497,30 @@ AutoAssertNoNurseryAlloc::~AutoAssertNoN
- {
-     TlsContext.get()->allowNurseryAlloc();
- }
- 
- JS::AutoEnterCycleCollection::AutoEnterCycleCollection(JSRuntime* rt)
-   : runtime_(rt)
- {
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-     runtime_->heapState_ = HeapState::CycleCollecting;
- }
- 
- JS::AutoEnterCycleCollection::~AutoEnterCycleCollection()
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapCycleCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsCycleCollecting());
-     runtime_->heapState_ = HeapState::Idle;
- }
- 
- JS::AutoAssertGCCallback::AutoAssertGCCallback()
-   : AutoSuppressGCAnalysis()
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
- }
- 
- #endif // DEBUG
- 
- JS_FRIEND_API(const char*)
- JS::GCTraceKindToAscii(JS::TraceKind kind)
- {
-     switch(kind) {
-@@ -8805,44 +8805,44 @@ JS_PUBLIC_API(bool)
- JS::IsIncrementalGCInProgress(JSRuntime* rt)
- {
-     return rt->gc.isIncrementalGCInProgress() && !rt->gc.isVerifyPreBarriersEnabled();
- }
- 
- JS_PUBLIC_API(bool)
- JS::IsIncrementalBarrierNeeded(JSContext* cx)
- {
--    if (JS::CurrentThreadIsHeapBusy())
-+    if (JS::RuntimeHeapIsBusy())
-         return false;
- 
-     auto state = cx->runtime()->gc.state();
-     return state != gc::State::NotActive && state <= gc::State::Sweep;
- }
- 
- JS_PUBLIC_API(void)
- JS::IncrementalPreWriteBarrier(JSObject* obj)
- {
-     if (!obj)
-         return;
- 
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
-     JSObject::writeBarrierPre(obj);
- }
- 
- struct IncrementalReadBarrierFunctor {
-     template <typename T> void operator()(T* t) { T::readBarrier(t); }
- };
- 
- JS_PUBLIC_API(void)
- JS::IncrementalReadBarrier(GCCellPtr thing)
- {
-     if (!thing)
-         return;
- 
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMajorCollecting());
-     DispatchTyped(IncrementalReadBarrierFunctor(), thing);
- }
- 
- JS_PUBLIC_API(bool)
- JS::WasIncrementalGC(JSRuntime* rt)
- {
-     return rt->gc.isIncrementalGc();
- }
-@@ -9200,17 +9200,17 @@ js::gc::detail::CellIsNotGray(const Cell
-     // of cells that will be marked black by the next GC slice in an incremental
-     // GC. For performance reasons we don't do this in CellIsMarkedGrayIfKnown.
- 
-     if (!CanCheckGrayBits(cell))
-         return true;
- 
-     // TODO: I'd like to AssertHeapIsIdle() here, but this ends up getting
-     // called during GC and while iterating the heap for memory reporting.
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCycleCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCycleCollecting());
- 
-     auto tc = &cell->asTenured();
-     if (!detail::CellIsMarkedGray(tc))
-         return true;
- 
-     // The cell is gray, but may eventually be marked black if we are in an
-     // incremental GC and the cell is reachable by something on the mark stack.
- 
-diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
---- a/js/src/gc/Marking.cpp
-+++ b/js/src/gc/Marking.cpp
-@@ -263,17 +263,17 @@ js::CheckTracedThing(JSTracer* trc, T* t
-      * if it has not then we assume it is allocated, but if it has then it is
-      * either free or uninitialized in which case we check the free list.
-      *
-      * Further complications are that background sweeping may be running and
-      * concurrently modifiying the free list and that tracing is done off
-      * thread during compacting GC and reading the contents of the thing by
-      * IsThingPoisoned would be racy in this case.
-      */
--    MOZ_ASSERT_IF(JS::CurrentThreadIsHeapBusy() &&
-+    MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy() &&
-                   !zone->isGCCompacting() &&
-                   !rt->gc.isBackgroundSweeping(),
-                   !IsThingPoisoned(thing) || !InFreeList(thing->asTenured().arena(), thing));
- #endif
- }
- 
- template <typename S>
- struct CheckTracedFunctor : public VoidDefaultAdaptor<S> {
-@@ -2570,17 +2570,17 @@ GCMarker::sizeOfExcludingThis(mozilla::M
-         size += zone->gcGrayRoots().sizeOfExcludingThis(mallocSizeOf);
-     return size;
- }
- 
- #ifdef DEBUG
- Zone*
- GCMarker::stackContainsCrossZonePointerTo(const Cell* target) const
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
- 
-     Zone* targetZone = target->asTenured().zone();
- 
-     for (MarkStackIter iter(stack); !iter.done(); iter.next()) {
-         if (iter.peekTag() != MarkStack::ObjectTag)
-             continue;
- 
-         auto source = iter.peekPtr().as<JSObject>();
-@@ -3209,17 +3209,17 @@ CheckIsMarkedThing(T* thingp)
- 
- #ifdef DEBUG
-     MOZ_ASSERT(thingp);
-     MOZ_ASSERT(*thingp);
-     JSRuntime* rt = (*thingp)->runtimeFromAnyThread();
-     MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
-                   CurrentThreadCanAccessRuntime(rt) ||
-                   CurrentThreadCanAccessZone((*thingp)->zoneFromAnyThread()) ||
--                  (JS::CurrentThreadIsHeapCollecting() && rt->gc.state() == State::Sweep));
-+                  (JS::RuntimeHeapIsCollecting() && rt->gc.state() == State::Sweep));
- #endif
- }
- 
- template <typename T>
- static bool
- IsMarkedInternalCommon(T* thingp)
- {
-     CheckIsMarkedThing(thingp);
-@@ -3294,17 +3294,17 @@ js::gc::IsAboutToBeFinalizedInternal(T**
-     T* thing = *thingp;
-     JSRuntime* rt = thing->runtimeFromAnyThread();
- 
-     /* Permanent atoms are never finalized by non-owning runtimes. */
-     if (ThingIsPermanentAtomOrWellKnownSymbol(thing) && TlsContext.get()->runtime() != rt)
-         return false;
- 
-     if (IsInsideNursery(thing)) {
--        return JS::CurrentThreadIsHeapMinorCollecting() &&
-+        return JS::RuntimeHeapIsMinorCollecting() &&
-                !Nursery::getForwardedPointer(reinterpret_cast<Cell**>(thingp));
-     }
- 
-     Zone* zone = thing->asTenured().zoneFromAnyThread();
-     if (zone->isGCSweeping()) {
-         return IsAboutToBeFinalizedDuringSweep(thing->asTenured());
-     } else if (zone->isGCCompacting() && IsForwarded(thing)) {
-         *thingp = Forwarded(thing);
-@@ -3509,18 +3509,18 @@ UnmarkGrayGCThing(JSRuntime* rt, JS::GCC
-     gcstats::AutoPhase innerPhase(rt->gc.stats(), gcstats::PhaseKind::UNMARK_GRAY);
-     unmarker.unmark(thing);
-     return unmarker.unmarkedAny;
- }
- 
- JS_FRIEND_API(bool)
- JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr thing)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCycleCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCycleCollecting());
- 
-     JSRuntime* rt = thing.asCell()->runtimeFromMainThread();
-     gcstats::AutoPhase outerPhase(rt->gc.stats(), gcstats::PhaseKind::BARRIER);
-     return UnmarkGrayGCThing(rt, thing);
- }
- 
- bool
- js::UnmarkGrayShapeRecursively(Shape* shape)
-diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
---- a/js/src/gc/Nursery.cpp
-+++ b/js/src/gc/Nursery.cpp
-@@ -349,17 +349,17 @@ js::Nursery::allocateString(Zone* zone, 
-     gcTracer.traceNurseryAlloc(cell, kind);
-     return cell;
- }
- 
- void*
- js::Nursery::allocate(size_t size)
- {
-     MOZ_ASSERT(isEnabled());
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
-     MOZ_ASSERT_IF(currentChunk_ == currentStartChunk_, position() >= currentStartPosition_);
-     MOZ_ASSERT(position() % CellAlignBytes == 0);
-     MOZ_ASSERT(size % CellAlignBytes == 0);
- 
- #ifdef JS_GC_ZEAL
-     static const size_t CanarySize = (sizeof(Nursery::Canary) + CellAlignBytes - 1) & ~CellAlignMask;
-     if (runtime()->gc.hasZealMode(ZealMode::CheckNursery))
-diff --git a/js/src/gc/PrivateIterators-inl.h b/js/src/gc/PrivateIterators-inl.h
---- a/js/src/gc/PrivateIterators-inl.h
-+++ b/js/src/gc/PrivateIterators-inl.h
-@@ -58,17 +58,17 @@ class GrayObjectIter : public ZoneCellIt
- };
- 
- class GCZonesIter
- {
-     ZonesIter zone;
- 
-   public:
-     explicit GCZonesIter(JSRuntime* rt, ZoneSelector selector = WithAtoms) : zone(rt, selector) {
--        MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
-+        MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-         MOZ_ASSERT_IF(rt->gc.atomsZone->isCollectingFromAnyThread(),
-                       !rt->hasHelperThreadZones());
- 
-         if (!done() && !zone->isCollectingFromAnyThread())
-             next();
-     }
- 
-     bool done() const { return zone.done(); }
-diff --git a/js/src/gc/PublicIterators.cpp b/js/src/gc/PublicIterators.cpp
---- a/js/src/gc/PublicIterators.cpp
-+++ b/js/src/gc/PublicIterators.cpp
-@@ -115,26 +115,26 @@ IterateGrayObjects(Zone* zone, GCThingCa
-                 cellCallback(data, JS::GCCellPtr(obj.get()));
-         }
-     }
- }
- 
- void
- js::IterateGrayObjects(Zone* zone, GCThingCallback cellCallback, void* data)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-     AutoPrepareForTracing prep(TlsContext.get());
-     ::IterateGrayObjects(zone, cellCallback, data);
- }
- 
- void
- js::IterateGrayObjectsUnderCC(Zone* zone, GCThingCallback cellCallback, void* data)
- {
-     mozilla::DebugOnly<JSRuntime*> rt = zone->runtimeFromMainThread();
--    MOZ_ASSERT(JS::CurrentThreadIsHeapCycleCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsCycleCollecting());
-     MOZ_ASSERT(!rt->gc.isIncrementalGCInProgress());
-     ::IterateGrayObjects(zone, cellCallback, data);
- }
- 
- JS_PUBLIC_API(void)
- JS_IterateCompartments(JSContext* cx, void* data,
-                        JSIterateCompartmentCallback compartmentCallback)
- {
-diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp
---- a/js/src/gc/RootMarking.cpp
-+++ b/js/src/gc/RootMarking.cpp
-@@ -384,17 +384,17 @@ js::gc::GCRuntime::traceRuntimeCommon(JS
-     // parent pointer if traceRoots actually traces anything.
-     for (RealmsIter r(rt); !r.done(); r.next())
-         r->traceRoots(trc, traceOrMark);
- 
-     // Trace helper thread roots.
-     HelperThreadState().trace(trc, session);
- 
-     // Trace the embedding's black and gray roots.
--    if (!JS::CurrentThreadIsHeapMinorCollecting()) {
-+    if (!JS::RuntimeHeapIsMinorCollecting()) {
-         gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_EMBEDDING);
- 
-         /*
-          * The embedding can register additional roots here.
-          *
-          * We don't need to trace these in a minor GC because all pointers into
-          * the nursery should be in the store buffer, and we want to avoid the
-          * time taken to trace all these roots.
-@@ -523,17 +523,17 @@ js::gc::GCRuntime::bufferGrayRoots()
-       grayBufferState = GrayBufferState::Okay;
-     }
- }
- 
- template <typename T>
- inline void
- BufferGrayRootsTracer::bufferRoot(T* thing)
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-     MOZ_ASSERT(thing);
-     // Check if |thing| is corrupt by calling a method that touches the heap.
-     MOZ_ASSERT(thing->getTraceKind() <= JS::TraceKind::Null);
- 
-     TenuredCell* tenured = &thing->asTenured();
- 
-     // This is run from a helper thread while the mutator is paused so we have
-     // to use *FromAnyThread methods here.
-diff --git a/js/src/gc/StoreBuffer.h b/js/src/gc/StoreBuffer.h
---- a/js/src/gc/StoreBuffer.h
-+++ b/js/src/gc/StoreBuffer.h
-@@ -401,27 +401,27 @@ class StoreBuffer
-             static bool match(const SlotsEdge& k, const Lookup& l) { return k == l; }
-         } Hasher;
- 
-         static const auto FullBufferReason = JS::gcreason::FULL_SLOT_BUFFER;
-     };
- 
-     template <typename Buffer, typename Edge>
-     void unput(Buffer& buffer, const Edge& edge) {
--        MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+        MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-         MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
-         if (!isEnabled())
-             return;
-         mozilla::ReentrancyGuard g(*this);
-         buffer.unput(this, edge);
-     }
- 
-     template <typename Buffer, typename Edge>
-     void put(Buffer& buffer, const Edge& edge) {
--        MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+        MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-         MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
-         if (!isEnabled())
-             return;
-         mozilla::ReentrancyGuard g(*this);
-         if (edge.maybeInRememberedSet(nursery_))
-             buffer.put(this, edge);
-     }
- 
-diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp
---- a/js/src/gc/Verifier.cpp
-+++ b/js/src/gc/Verifier.cpp
-@@ -713,17 +713,17 @@ CheckGrayMarkingTracer::check(AutoTraceS
-         return true; // Ignore failure.
- 
-     return failures == 0;
- }
- 
- JS_FRIEND_API(bool)
- js::CheckGrayMarkingState(JSRuntime* rt)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
-     MOZ_ASSERT(!rt->gc.isIncrementalGCInProgress());
-     if (!rt->gc.areGrayBitsValid())
-         return true;
- 
-     gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
-     AutoTraceSession session(rt, JS::HeapState::Tracing);
-     CheckGrayMarkingTracer tracer(rt);
-     if (!tracer.init())
-diff --git a/js/src/gc/WeakMap.h b/js/src/gc/WeakMap.h
---- a/js/src/gc/WeakMap.h
-+++ b/js/src/gc/WeakMap.h
-@@ -195,17 +195,17 @@ class WeakMap : public HashMap<Key, Valu
-             TraceEdge(marker, &p->value(), "WeakMap ephemeron value");
-             TraceEdge(marker, &key, "proxy-preserved WeakMap ephemeron key");
-             MOZ_ASSERT(key == p->key()); // No moving
-         }
-         key.unsafeSet(nullptr); // Prevent destructor from running barriers.
-     }
- 
-     void trace(JSTracer* trc) override {
--        MOZ_ASSERT_IF(JS::CurrentThreadIsHeapBusy(), isInList());
-+        MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), isInList());
- 
-         TraceNullableEdge(trc, &memberOf, "WeakMap owner");
- 
-         if (!Base::initialized())
-             return;
- 
-         if (trc->isMarkingTracer()) {
-             MOZ_ASSERT(trc->weakMapAction() == ExpandWeakMaps);
-diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h
---- a/js/src/gc/Zone.h
-+++ b/js/src/gc/Zone.h
-@@ -221,51 +221,51 @@ class Zone : public JS::shadow::Zone,
-         return runtimeFromMainThread()->onOutOfMemory(allocFunc, nbytes, reallocPtr);
-     }
-     void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
- 
-     void beginSweepTypes(bool releaseTypes);
- 
-     bool hasMarkedRealms();
- 
--    void scheduleGC() { MOZ_ASSERT(!CurrentThreadIsHeapBusy()); gcScheduled_ = true; }
-+    void scheduleGC() { MOZ_ASSERT(!RuntimeHeapIsBusy()); gcScheduled_ = true; }
-     void unscheduleGC() { gcScheduled_ = false; }
-     bool isGCScheduled() { return gcScheduled_; }
- 
-     void setPreservingCode(bool preserving) { gcPreserveCode_ = preserving; }
-     bool isPreservingCode() const { return gcPreserveCode_; }
- 
-     // Whether this zone can currently be collected. This doesn't take account
-     // of AutoKeepAtoms for the atoms zone.
-     bool canCollect();
- 
-     void changeGCState(GCState prev, GCState next) {
--        MOZ_ASSERT(CurrentThreadIsHeapBusy());
-+        MOZ_ASSERT(RuntimeHeapIsBusy());
-         MOZ_ASSERT(gcState() == prev);
-         MOZ_ASSERT_IF(next != NoGC, canCollect());
-         gcState_ = next;
-     }
- 
-     bool isCollecting() const {
-         MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromMainThread()));
-         return isCollectingFromAnyThread();
-     }
- 
-     bool isCollectingFromAnyThread() const {
--        if (CurrentThreadIsHeapCollecting())
-+        if (RuntimeHeapIsCollecting())
-             return gcState_ != NoGC;
-         else
-             return needsIncrementalBarrier();
-     }
- 
-     // If this returns true, all object tracing must be done with a GC marking
-     // tracer.
-     bool requireGCTracer() const {
-         JSRuntime* rt = runtimeFromAnyThread();
--        return CurrentThreadIsHeapMajorCollecting() && !rt->gc.isHeapCompacting() && gcState_ != NoGC;
-+        return RuntimeHeapIsMajorCollecting() && !rt->gc.isHeapCompacting() && gcState_ != NoGC;
-     }
- 
-     bool shouldMarkInZone() const {
-         return needsIncrementalBarrier() || isGCMarking();
-     }
- 
-     // Get a number that is incremented whenever this zone is collected, and
-     // possibly at other times too.
-diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
---- a/js/src/jit/Ion.cpp
-+++ b/js/src/jit/Ion.cpp
-@@ -579,17 +579,17 @@ jit::LazyLinkTopActivation(JSContext* cx
-     MOZ_ASSERT(calleeScript->jitCodeRaw());
- 
-     return calleeScript->jitCodeRaw();
- }
- 
- /* static */ void
- JitRuntime::Trace(JSTracer* trc, AutoLockForExclusiveAccess& lock)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
- 
-     // Shared stubs are allocated in the atoms zone, so do not iterate
-     // them after the atoms heap after it has been "finished."
-     if (trc->runtime()->atomsAreFinished())
-         return;
- 
-     Zone* zone = trc->runtime()->atomsZone(lock);
-     for (auto i = zone->cellIter<JitCode>(); !i.done(); i.next()) {
-@@ -773,17 +773,17 @@ JitCode::traceChildren(JSTracer* trc)
- 
-     if (jumpRelocTableBytes_) {
-         uint8_t* start = code_ + jumpRelocTableOffset();
-         CompactBufferReader reader(start, start + jumpRelocTableBytes_);
-         MacroAssembler::TraceJumpRelocations(trc, this, reader);
-     }
-     if (dataRelocTableBytes_) {
-         // If we're moving objects, we need writable JIT code.
--        bool movingObjects = JS::CurrentThreadIsHeapMinorCollecting() || zone()->isGCCompacting();
-+        bool movingObjects = JS::RuntimeHeapIsMinorCollecting() || zone()->isGCCompacting();
-         MaybeAutoWritableJitCode awjc(this, movingObjects ? Reprotect : DontReprotect);
- 
-         uint8_t* start = code_ + dataRelocTableOffset();
-         CompactBufferReader reader(start, start + dataRelocTableBytes_);
-         MacroAssembler::TraceDataRelocations(trc, this, reader);
-     }
- }
- 
-diff --git a/js/src/jit/JSJitFrameIter.cpp b/js/src/jit/JSJitFrameIter.cpp
---- a/js/src/jit/JSJitFrameIter.cpp
-+++ b/js/src/jit/JSJitFrameIter.cpp
-@@ -404,17 +404,17 @@ JSJitFrameIter::verifyReturnAddressUsing
-     // Don't verify while off thread.
-     if (!CurrentThreadCanAccessRuntime(rt))
-         return true;
- 
-     // Don't verify if sampling is being suppressed.
-     if (!TlsContext.get()->isProfilerSamplingEnabled())
-         return true;
- 
--    if (JS::CurrentThreadIsHeapMinorCollecting())
-+    if (JS::RuntimeHeapIsMinorCollecting())
-         return true;
- 
-     JitRuntime* jitrt = rt->jitRuntime();
- 
-     // Look up and print bytecode info for the native address.
-     const JitcodeGlobalEntry* entry = jitrt->getJitcodeGlobalTable()->lookup(returnAddressToFp_);
-     if (!entry)
-         return true;
-diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
---- a/js/src/jit/JitFrames.cpp
-+++ b/js/src/jit/JitFrames.cpp
-@@ -1335,17 +1335,17 @@ TraceJitActivations(JSContext* cx, JSTra
- {
-     for (JitActivationIterator activations(cx); !activations.done(); ++activations)
-         TraceJitActivation(trc, activations->asJit());
- }
- 
- void
- UpdateJitActivationsForMinorGC(JSRuntime* rt)
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
-     JSContext* cx = rt->mainContextFromOwnThread();
-     for (JitActivationIterator activations(cx); !activations.done(); ++activations) {
-         for (OnlyJSJitFrameIter iter(activations); !iter.done(); ++iter) {
-             if (iter.frame().type() == JitFrame_IonJS)
-                 UpdateIonJSFrameForMinorGC(rt, iter.frame());
-         }
-     }
- }
-diff --git a/js/src/jit/JitcodeMap.cpp b/js/src/jit/JitcodeMap.cpp
---- a/js/src/jit/JitcodeMap.cpp
-+++ b/js/src/jit/JitcodeMap.cpp
-@@ -735,17 +735,17 @@ struct Unconditionally
- };
- 
- void
- JitcodeGlobalTable::traceForMinorGC(JSTracer* trc)
- {
-     // Trace only entries that can directly contain nursery pointers.
- 
-     MOZ_ASSERT(trc->runtime()->geckoProfiler().enabled());
--    MOZ_ASSERT(JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
- 
-     JSContext* cx = trc->runtime()->mainContextFromOwnThread();
-     AutoSuppressProfilerSampling suppressSampling(cx);
-     JitcodeGlobalEntry::IonEntry* entry = nurseryEntries_;
-     while (entry) {
-         entry->trace<Unconditionally>(trc);
-         JitcodeGlobalEntry::IonEntry* prev = entry;
-         entry = entry->nextNursery_;
-@@ -785,17 +785,17 @@ JitcodeGlobalTable::markIteratively(GCMa
-     // the frame was on-stack at the beginning of the sweep phase, or 2) the
-     // frame was pushed between incremental sweep slices. Frames of case 1)
-     // are already marked. Frames of case 2) must have been reachable to have
-     // been newly pushed, and thus are already marked.
-     //
-     // The approach above obviates the need for read barriers. The assumption
-     // above is checked in JitcodeGlobalTable::lookupForSampler.
- 
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
- 
-     AutoSuppressProfilerSampling suppressSampling(TlsContext.get());
- 
-     // If the profiler is off, rangeStart will be Nothing() and all entries are
-     // considered to be expired.
-     Maybe<uint64_t> rangeStart = marker->runtime()->profilerSampleBufferRangeStart();
- 
-     bool markedAny = false;
-diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
---- a/js/src/jsapi.cpp
-+++ b/js/src/jsapi.cpp
-@@ -318,35 +318,35 @@ JS_GetEmptyString(JSContext* cx)
-     return cx->emptyString();
- }
- 
- namespace js {
- 
- void
- AssertHeapIsIdle()
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
- }
- 
- } // namespace js
- 
- static void
- AssertHeapIsIdleOrIterating()
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
- }
- 
- static void
- AssertHeapIsIdleOrStringIsFlat(JSString* str)
- {
-     /*
-      * We allow some functions to be called during a GC as long as the argument
-      * is a flat string, since that will not cause allocation.
-      */
--    MOZ_ASSERT_IF(JS::CurrentThreadIsHeapBusy(), str->isFlat());
-+    MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), str->isFlat());
- }
- 
- JS_PUBLIC_API(bool)
- JS_ValueToObject(JSContext* cx, HandleValue value, MutableHandleObject objp)
- {
-     AssertHeapIsIdle();
-     CHECK_REQUEST(cx);
-     assertSameCompartment(cx, value);
-diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h
---- a/js/src/jspubtd.h
-+++ b/js/src/jspubtd.h
-@@ -113,53 +113,53 @@ enum class HeapState {
-     Idle,             // doing nothing with the GC heap
-     Tracing,          // tracing the GC heap without collecting, e.g. IterateCompartments()
-     MajorCollecting,  // doing a GC of the major heap
-     MinorCollecting,  // doing a GC of the minor heap (nursery)
-     CycleCollecting   // in the "Unlink" phase of cycle collection
- };
- 
- JS_PUBLIC_API(HeapState)
--CurrentThreadHeapState();
-+RuntimeHeapState();
- 
- static inline bool
--CurrentThreadIsHeapBusy()
-+RuntimeHeapIsBusy()
- {
--    return CurrentThreadHeapState() != HeapState::Idle;
-+    return RuntimeHeapState() != HeapState::Idle;
- }
- 
- static inline bool
--CurrentThreadIsHeapTracing()
-+RuntimeHeapIsTracing()
- {
--    return CurrentThreadHeapState() == HeapState::Tracing;
-+    return RuntimeHeapState() == HeapState::Tracing;
- }
- 
- static inline bool
--CurrentThreadIsHeapMajorCollecting()
-+RuntimeHeapIsMajorCollecting()
- {
--    return CurrentThreadHeapState() == HeapState::MajorCollecting;
-+    return RuntimeHeapState() == HeapState::MajorCollecting;
- }
- 
- static inline bool
--CurrentThreadIsHeapMinorCollecting()
-+RuntimeHeapIsMinorCollecting()
- {
--    return CurrentThreadHeapState() == HeapState::MinorCollecting;
-+    return RuntimeHeapState() == HeapState::MinorCollecting;
- }
- 
- static inline bool
--CurrentThreadIsHeapCollecting()
-+RuntimeHeapIsCollecting()
- {
--    HeapState state = CurrentThreadHeapState();
-+    HeapState state = RuntimeHeapState();
-     return state == HeapState::MajorCollecting || state == HeapState::MinorCollecting;
- }
- 
- static inline bool
--CurrentThreadIsHeapCycleCollecting()
-+RuntimeHeapIsCycleCollecting()
- {
--    return CurrentThreadHeapState() == HeapState::CycleCollecting;
-+    return RuntimeHeapState() == HeapState::CycleCollecting;
- }
- 
- // Decorates the Unlinking phase of CycleCollection so that accidental use
- // of barriered accessors results in assertions instead of leaks.
- class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection)
- {
- #ifdef DEBUG
-     JSRuntime* runtime_;
-diff --git a/js/src/proxy/Wrapper.cpp b/js/src/proxy/Wrapper.cpp
---- a/js/src/proxy/Wrapper.cpp
-+++ b/js/src/proxy/Wrapper.cpp
-@@ -370,17 +370,17 @@ js::UncheckedUnwrapWithoutExpose(JSObjec
-             wrapped = MaybeForwarded(wrapped);
-     }
-     return wrapped;
- }
- 
- JS_FRIEND_API(JSObject*)
- js::UncheckedUnwrap(JSObject* wrapped, bool stopAtWindowProxy, unsigned* flagsp)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(wrapped->runtimeFromAnyThread()));
- 
-     unsigned flags = 0;
-     while (true) {
-         if (!wrapped->is<WrapperObject>() ||
-             MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(wrapped)))
-         {
-             break;
-@@ -402,17 +402,17 @@ js::CheckedUnwrap(JSObject* obj, bool st
-         if (!obj || obj == wrapper)
-             return obj;
-     }
- }
- 
- JS_FRIEND_API(JSObject*)
- js::UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy)
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
-     MOZ_ASSERT(CurrentThreadCanAccessRuntime(obj->runtimeFromAnyThread()));
- 
-     if (!obj->is<WrapperObject>() ||
-         MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(obj)))
-     {
-         return obj;
-     }
- 
-diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
---- a/js/src/shell/js.cpp
-+++ b/js/src/shell/js.cpp
-@@ -1658,17 +1658,17 @@ ParseCompileOptions(JSContext* cx, Compi
- 
- static void
- my_LargeAllocFailCallback()
- {
-     JSContext* cx = TlsContext.get();
-     if (!cx || cx->helperThread())
-         return;
- 
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
- 
-     JS::PrepareForFullGC(cx);
-     cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::SHARED_MEMORY_LIMIT);
- }
- 
- static const uint32_t CacheEntry_SOURCE = 0;
- static const uint32_t CacheEntry_BYTECODE = 1;
- 
-diff --git a/js/src/vm/BytecodeUtil.cpp b/js/src/vm/BytecodeUtil.cpp
---- a/js/src/vm/BytecodeUtil.cpp
-+++ b/js/src/vm/BytecodeUtil.cpp
-@@ -1144,17 +1144,17 @@ ToDisassemblySource(JSContext* cx, Handl
-         if (!copy) {
-             ReportOutOfMemory(cx);
-             return false;
-         }
-         bytes->initBytes(std::move(copy));
-         return true;
-     }
- 
--    if (JS::CurrentThreadIsHeapBusy() || !cx->isAllocAllowed()) {
-+    if (JS::RuntimeHeapIsBusy() || !cx->isAllocAllowed()) {
-         UniqueChars source = JS_smprintf("<value>");
-         if (!source) {
-             ReportOutOfMemory(cx);
-             return false;
-         }
-         bytes->initBytes(std::move(source));
-         return true;
-     }
-diff --git a/js/src/vm/Compartment.cpp b/js/src/vm/Compartment.cpp
---- a/js/src/vm/Compartment.cpp
-+++ b/js/src/vm/Compartment.cpp
-@@ -380,17 +380,17 @@ Compartment::wrap(JSContext* cx, Mutable
-             return false;
-     }
-     return true;
- }
- 
- void
- Compartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc)
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsMajorCollecting());
-     MOZ_ASSERT(!zone()->isCollectingFromAnyThread() || trc->runtime()->gc.isHeapCompacting());
- 
-     for (NonStringWrapperEnum e(this); !e.empty(); e.popFront()) {
-         if (e.front().key().is<JSObject*>()) {
-             Value v = e.front().value().unbarrieredGet();
-             ProxyObject* wrapper = &v.toObject().as<ProxyObject>();
- 
-             /*
-@@ -401,17 +401,17 @@ Compartment::traceOutgoingCrossCompartme
-         }
-     }
- }
- 
- /* static */ void
- Compartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc)
- {
-     gcstats::AutoPhase ap(trc->runtime()->gc.stats(), gcstats::PhaseKind::MARK_CCWS);
--    MOZ_ASSERT(JS::CurrentThreadIsHeapMajorCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsMajorCollecting());
-     for (CompartmentsIter c(trc->runtime()); !c.done(); c.next()) {
-         if (!c->zone()->isCollecting())
-             c->traceOutgoingCrossCompartmentWrappers(trc);
-     }
-     Debugger::traceIncomingCrossCompartmentEdges(trc);
- }
- 
- void
-diff --git a/js/src/vm/JSContext-inl.h b/js/src/vm/JSContext-inl.h
---- a/js/src/vm/JSContext-inl.h
-+++ b/js/src/vm/JSContext-inl.h
-@@ -176,17 +176,17 @@ class CompartmentChecker
-     }
- };
- 
- /*
-  * Don't perform these checks when called from a finalizer. The checking
-  * depends on other objects not having been swept yet.
-  */
- #define START_ASSERT_SAME_COMPARTMENT()                                 \
--    if (JS::CurrentThreadIsHeapCollecting())                            \
-+    if (JS::RuntimeHeapIsCollecting())                            \
-         return;                                                         \
-     CompartmentChecker c(cx)
- 
- template <class T1> inline void
- releaseAssertSameCompartment(JSContext* cx, const T1& t1)
- {
-     START_ASSERT_SAME_COMPARTMENT();
-     c.check(t1);
-diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp
---- a/js/src/vm/JSContext.cpp
-+++ b/js/src/vm/JSContext.cpp
-@@ -1544,17 +1544,17 @@ JSContext::updateMallocCounter(size_t nb
- }
- 
- #ifdef DEBUG
- 
- JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext* cxArg)
-   : cx(cxArg->helperThread() ? nullptr : cxArg)
- {
-     if (cx) {
--        MOZ_ASSERT(cx->requestDepth || JS::CurrentThreadIsHeapBusy());
-+        MOZ_ASSERT(cx->requestDepth || JS::RuntimeHeapIsBusy());
-         MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
-         cx->checkRequestDepth++;
-     }
- }
- 
- JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
- {
-     if (cx) {
-diff --git a/js/src/vm/Realm.cpp b/js/src/vm/Realm.cpp
---- a/js/src/vm/Realm.cpp
-+++ b/js/src/vm/Realm.cpp
-@@ -277,17 +277,17 @@ void
- Realm::traceGlobal(JSTracer* trc)
- {
-     // Trace things reachable from the realm's global. Note that these edges
-     // must be swept too in case the realm is live but the global is not.
- 
-     savedStacks_.trace(trc);
- 
-     // Atoms are always tenured.
--    if (!JS::CurrentThreadIsHeapMinorCollecting())
-+    if (!JS::RuntimeHeapIsMinorCollecting())
-         varNames_.trace(trc);
- }
- 
- void
- ObjectRealm::trace(JSTracer* trc)
- {
-     if (lazyArrayBuffers)
-         lazyArrayBuffers->trace(trc);
-@@ -303,17 +303,17 @@ void
- Realm::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark)
- {
-     if (objectMetadataState_.is<PendingMetadata>()) {
-         TraceRoot(trc,
-                   &objectMetadataState_.as<PendingMetadata>(),
-                   "on-stack object pending metadata");
-     }
- 
--    if (!JS::CurrentThreadIsHeapMinorCollecting()) {
-+    if (!JS::RuntimeHeapIsMinorCollecting()) {
-         // The global is never nursery allocated, so we don't need to
-         // trace it when doing a minor collection.
-         //
-         // If a compartment is on-stack, we mark its global so that
-         // JSContext::global() remains valid.
-         if (shouldTraceGlobal() && global_.unbarrieredGet())
-             TraceRoot(trc, global_.unsafeUnbarrieredForTracing(), "on-stack compartment global");
-     }
-@@ -338,17 +338,17 @@ Realm::traceRoots(JSTracer* trc, js::gc:
-     // keys of the HashMap to avoid adding a strong reference to the JSScript
-     // pointers.
-     //
-     // If the code coverage is either enabled with the --dump-bytecode command
-     // line option, or with the PCCount JSFriend API functions, then we mark the
-     // keys of the map to hold the JSScript alive.
-     if (scriptCountsMap &&
-         trc->runtime()->profilingScripts &&
--        !JS::CurrentThreadIsHeapMinorCollecting())
-+        !JS::RuntimeHeapIsMinorCollecting())
-     {
-         MOZ_ASSERT_IF(!trc->runtime()->isBeingDestroyed(), collectCoverage());
-         for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
-             JSScript* script = const_cast<JSScript*>(r.front().key());
-             MOZ_ASSERT(script->hasScriptCounts());
-             TraceRoot(trc, &script, "profilingScripts");
-             MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
-         }
-diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
---- a/js/src/vm/RegExpObject.cpp
-+++ b/js/src/vm/RegExpObject.cpp
-@@ -139,22 +139,22 @@ RegExpObject::trace(JSTracer* trc, JSObj
- }
- 
- static inline bool
- IsMarkingTrace(JSTracer* trc)
- {
-     // Determine whether tracing is happening during normal marking.  We need to
-     // test all the following conditions, since:
-     //
--    //   1. During TraceRuntime, CurrentThreadIsHeapBusy() is true, but the
-+    //   1. During TraceRuntime, RuntimeHeapIsBusy() is true, but the
-     //      tracer might not be a marking tracer.
-     //   2. When a write barrier executes, IsMarkingTracer is true, but
--    //      CurrentThreadIsHeapBusy() will be false.
-+    //      RuntimeHeapIsBusy() will be false.
- 
--    return JS::CurrentThreadIsHeapCollecting() && trc->isMarkingTracer();
-+    return JS::RuntimeHeapIsCollecting() && trc->isMarkingTracer();
- }
- 
- void
- RegExpObject::trace(JSTracer* trc)
- {
-     TraceNullableEdge(trc, &sharedRef(), "RegExpObject shared");
- }
- 
-diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
---- a/js/src/vm/Runtime.cpp
-+++ b/js/src/vm/Runtime.cpp
-@@ -251,17 +251,17 @@ JSRuntime::init(JSContext* cx, uint32_t 
-         return false;
- 
-     return true;
- }
- 
- void
- JSRuntime::destroyRuntime()
- {
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
-     MOZ_ASSERT(childRuntimeCount == 0);
-     MOZ_ASSERT(initialized_);
- 
-     sharedIntlData.ref().destroyInstance();
- 
-     if (gcInitialized) {
-         /*
-          * Finish any in-progress GCs first. This ensures the parseWaitingOnGC
-@@ -722,17 +722,17 @@ JSRuntime::updateMallocCounter(size_t nb
-     gc.updateMallocCounter(nbytes);
- }
- 
- JS_FRIEND_API(void*)
- JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr, JSContext* maybecx)
- {
-     MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
- 
--    if (JS::CurrentThreadIsHeapBusy())
-+    if (JS::RuntimeHeapIsBusy())
-         return nullptr;
- 
-     if (!oom::IsSimulatedOOMAllocation()) {
-         /*
-          * Retry when we are done with the background sweeping and have stopped
-          * all the allocations and released the empty GC chunks.
-          */
-         gc.onOutOfMallocMemory();
-@@ -773,17 +773,17 @@ JSRuntime::activeGCInAtomsZone()
-     Zone* zone = unsafeAtomsZone();
-     return (zone->needsIncrementalBarrier() && !gc.isVerifyPreBarriersEnabled()) ||
-            zone->wasGCStarted();
- }
- 
- bool
- JSRuntime::createAtomsAddedWhileSweepingTable()
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
-     MOZ_ASSERT(!atomsAddedWhileSweeping_);
- 
-     atomsAddedWhileSweeping_ = js_new<AtomSet>();
-     if (!atomsAddedWhileSweeping_)
-         return false;
- 
-     if (!atomsAddedWhileSweeping_->init()) {
-         destroyAtomsAddedWhileSweepingTable();
-@@ -791,17 +791,17 @@ JSRuntime::createAtomsAddedWhileSweeping
-     }
- 
-     return true;
- }
- 
- void
- JSRuntime::destroyAtomsAddedWhileSweepingTable()
- {
--    MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
-     MOZ_ASSERT(atomsAddedWhileSweeping_);
- 
-     js_delete(atomsAddedWhileSweeping_.ref());
-     atomsAddedWhileSweeping_ = nullptr;
- }
- 
- void
- JSRuntime::setUsedByHelperThread(Zone* zone)
-diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
---- a/js/src/vm/Runtime.h
-+++ b/js/src/vm/Runtime.h
-@@ -714,17 +714,17 @@ struct JSRuntime : public js::MallocProv
-     js::ExclusiveAccessLockOrGCTaskData<js::SymbolRegistry> symbolRegistry_;
- 
-   public:
-     bool initializeAtoms(JSContext* cx);
-     void finishAtoms();
-     bool atomsAreFinished() const { return !atoms_; }
- 
-     js::AtomSet* atomsForSweeping() {
--        MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
-+        MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
-         return atoms_;
-     }
- 
-     js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
-         MOZ_ASSERT(atoms_);
-         return *atoms_;
-     }
-     js::AtomSet& unsafeAtoms() {
-diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
---- a/js/src/vm/TypeInference.cpp
-+++ b/js/src/vm/TypeInference.cpp
-@@ -4140,17 +4140,17 @@ TypeNewScript::trace(JSTracer* trc)
-     TraceNullableEdge(trc, &templateObject_, "TypeNewScript_templateObject");
-     TraceNullableEdge(trc, &initializedShape_, "TypeNewScript_initializedShape");
-     TraceNullableEdge(trc, &initializedGroup_, "TypeNewScript_initializedGroup");
- }
- 
- /* static */ void
- TypeNewScript::writeBarrierPre(TypeNewScript* newScript)
- {
--    if (JS::CurrentThreadIsHeapCollecting())
-+    if (JS::RuntimeHeapIsCollecting())
-         return;
- 
-     JS::Zone* zone = newScript->function()->zoneFromAnyThread();
-     if (zone->needsIncrementalBarrier())
-         newScript->trace(zone->barrierTracer());
- }
- 
- void
-@@ -4180,17 +4180,17 @@ TraceObjectKey(JSTracer* trc, TypeSet::O
- }
- 
- void
- ConstraintTypeSet::trace(Zone* zone, JSTracer* trc)
- {
-     checkMagic();
- 
-     // ConstraintTypeSets only hold strong references during minor collections.
--    MOZ_ASSERT(JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
- 
-     unsigned objectCount = baseObjectCount();
-     if (objectCount >= 2) {
-         unsigned oldCapacity = TypeHashSet::Capacity(objectCount);
-         ObjectKey** oldArray = objectSet;
- 
-         MOZ_RELEASE_ASSERT(uintptr_t(oldArray[-1]) == oldCapacity);
- 
-@@ -4258,17 +4258,17 @@ ConstraintTypeSet::trace(Zone* zone, JST
- 
- static inline void
- AssertGCStateForSweep(Zone* zone)
- {
-     MOZ_ASSERT(zone->isGCSweepingOrCompacting());
- 
-     // IsAboutToBeFinalized doesn't work right on tenured objects when called
-     // during a minor collection.
--    MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting());
-+    MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
- }
- 
- void
- ConstraintTypeSet::sweep(const AutoSweepBase& sweep, Zone* zone,
-                          AutoClearTypeInferenceStateOnOOM& oom)
- {
-     AssertGCStateForSweep(zone);
- 

+ 0 - 46
frg/work-js/mozilla-release/patches/mozilla-central-push_422918.patch

@@ -1,46 +0,0 @@
-# HG changeset patch
-# User Jeff Walden <jwalden@mit.edu>
-# Date 1529348084 25200
-#      Mon Jun 18 11:54:44 2018 -0700
-# Node ID 9fcf87cdfb395004c885f581b59dcd1999316c9a
-# Parent  7a56278c7b7849359567d9dca06abc4ddef42c63
-Bug 1467753 - Don't leak freshly-allocated, copied string chars in CopyStringPure when OOM happens allocating the JSString* that will adopt them.  r=anba
-
-diff --git a/js/src/vm/Compartment.cpp b/js/src/vm/Compartment.cpp
---- a/js/src/vm/Compartment.cpp
-+++ b/js/src/vm/Compartment.cpp
-@@ -126,24 +126,32 @@ CopyStringPure(JSContext* cx, JSString* 
-                : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
-     }
- 
-     if (str->hasLatin1Chars()) {
-         ScopedJSFreePtr<Latin1Char> copiedChars;
-         if (!str->asRope().copyLatin1CharsZ(cx, copiedChars))
-             return nullptr;
- 
--        return NewString<CanGC>(cx, copiedChars.forget(), len);
-+        auto* rawCopiedChars = copiedChars.forget();
-+        auto* result = NewString<CanGC>(cx, rawCopiedChars, len);
-+        if (!result)
-+            js_free(rawCopiedChars);
-+        return result;
-     }
- 
-     ScopedJSFreePtr<char16_t> copiedChars;
-     if (!str->asRope().copyTwoByteCharsZ(cx, copiedChars))
-         return nullptr;
- 
--    return NewStringDontDeflate<CanGC>(cx, copiedChars.forget(), len);
-+    auto* rawCopiedChars = copiedChars.forget();
-+    auto* result = NewStringDontDeflate<CanGC>(cx, rawCopiedChars, len);
-+    if (!result)
-+        js_free(rawCopiedChars);
-+    return result;
- }
- 
- bool
- Compartment::wrap(JSContext* cx, MutableHandleString strp)
- {
-     MOZ_ASSERT(cx->compartment() == this);
- 
-     /* If the string is already in this compartment, we are done. */

+ 0 - 76
frg/work-js/mozilla-release/patches/mozilla-central-push_422919.patch

@@ -1,76 +0,0 @@
-# HG changeset patch
-# User Jeff Walden <jwalden@mit.edu>
-# Date 1529348107 25200
-#      Mon Jun 18 11:55:07 2018 -0700
-# Node ID d8eb78d6b65d8583281f22d84b5bc82a7c05ef98
-# Parent  9fcf87cdfb395004c885f581b59dcd1999316c9a
-Bug 1468860 - Rename a few error-message constants to fix s/REGEP/REGEXP/ typos.  r=sfink
-
-diff --git a/js/src/irregexp/RegExpParser.cpp b/js/src/irregexp/RegExpParser.cpp
---- a/js/src/irregexp/RegExpParser.cpp
-+++ b/js/src/irregexp/RegExpParser.cpp
-@@ -1816,17 +1816,17 @@ RegExpParser<CharT>::ParseDisjunction()
-                     return ReportError(JSMSG_INVALID_IDENTITY_ESCAPE);
-                 builder->AddCharacter(Next());
-                 Advance(2);
-                 break;
-             }
-             break;
-           case '{': {
-             if (unicode_)
--                return ReportError(JSMSG_RAW_BRACE_IN_REGEP);
-+                return ReportError(JSMSG_RAW_BRACE_IN_REGEXP);
-             int dummy;
-             if (ParseIntervalQuantifier(&dummy, &dummy))
-                 return ReportError(JSMSG_NOTHING_TO_REPEAT);
-             MOZ_FALLTHROUGH;
-           }
-           default:
-             if (unicode_) {
-                 char16_t lead, trail;
-@@ -1834,19 +1834,19 @@ RegExpParser<CharT>::ParseDisjunction()
-                     builder->AddAtom(SurrogatePairAtom(alloc, lead, trail, ignore_case_));
-                 } else {
-                     widechar c = current();
-                     if (unicode::IsLeadSurrogate(c))
-                         builder->AddAtom(LeadSurrogateAtom(alloc, c));
-                     else if (unicode::IsTrailSurrogate(c))
-                         builder->AddAtom(TrailSurrogateAtom(alloc, c));
-                     else if (c == ']')
--                        return ReportError(JSMSG_RAW_BRACKET_IN_REGEP);
-+                        return ReportError(JSMSG_RAW_BRACKET_IN_REGEXP);
-                     else if (c == '}')
--                        return ReportError(JSMSG_RAW_BRACE_IN_REGEP);
-+                        return ReportError(JSMSG_RAW_BRACE_IN_REGEXP);
-                     else
-                         builder->AddCharacter(c);
-                     Advance();
-                 }
-                 break;
-             }
-             builder->AddCharacter(current());
-             Advance();
-diff --git a/js/src/js.msg b/js/src/js.msg
---- a/js/src/js.msg
-+++ b/js/src/js.msg
-@@ -513,18 +513,18 @@ MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0,
- MSG_DEF(JSMSG_INVALID_GROUP,           0, JSEXN_SYNTAXERR, "invalid regexp group")
- MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression")
- MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE,  0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression")
- MSG_DEF(JSMSG_MISSING_PAREN,           0, JSEXN_SYNTAXERR, "unterminated parenthetical")
- MSG_DEF(JSMSG_NEWREGEXP_FLAGGED,       0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
- MSG_DEF(JSMSG_NOTHING_TO_REPEAT,       0, JSEXN_SYNTAXERR, "nothing to repeat")
- MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER,    0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
- MSG_DEF(JSMSG_RANGE_WITH_CLASS_ESCAPE, 0, JSEXN_SYNTAXERR, "character class escape cannot be used in class range in regular expression")
--MSG_DEF(JSMSG_RAW_BRACE_IN_REGEP,      0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag")
--MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEP,    0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag")
-+MSG_DEF(JSMSG_RAW_BRACE_IN_REGEXP,     0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag")
-+MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEXP,   0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag")
- MSG_DEF(JSMSG_TOO_MANY_PARENS,         0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
- MSG_DEF(JSMSG_UNICODE_OVERFLOW,        1, JSEXN_SYNTAXERR, "Unicode codepoint must not be greater than 0x10FFFF in {0}")
- MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
- MSG_DEF(JSMSG_UNTERM_CLASS,            0, JSEXN_SYNTAXERR, "unterminated character class")
- 
- // Self-hosting
- MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR,    0, JSEXN_ERR, "internal error getting the default locale")
- MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}")

+ 21 - 16
frg/work-js/mozilla-release/patches/series

@@ -4918,6 +4918,13 @@ NOBUG-20231031-formattingfixes-253.patch
 1469593-62a1.patch
 1469444-62a1.patch
 1469469-62a1.patch
+1450085-1-62a1.patch
+1450085-2-62a1.patch
+1450085-3-62a1.patch
+1363214-62a1.patch
+1467142-62a1.patch
+1467752-62a1.patch
+1467751-62a1.patch
 taken-out-stuff-comes-here.patch
 1319228-3only-62a1.patch
 1319228-6only-62a1.patch
@@ -4980,9 +4987,9 @@ taken-out-stuff-comes-here.patch
 1467438-2-62a1.patch
 1467438-3-62a1.patch
 1467438-5-62a1.patch
-1466626-2no1-62a1.patch
-1466626-3-62a1.patch
-1471272-63a1.patch
+1466626-2no1-63a1.patch
+1466626-3-63a1.patch
+1398839-63a1.patch
 1466211-1-63a1.patch
 1466211-2-63a1.patch
 1466211-3-63a1.patch
@@ -5013,12 +5020,18 @@ taken-out-stuff-comes-here.patch
 1464782-1-63a1.patch
 1464782-2no34-63a1.patch
 1470522-63a1.patch
+1447591-1-63a1.patch
+1447591-2-63a1.patch
+1471272-63a1.patch
+1471841-63a1.patch
 1472734-63a1.patch
+1412200-63a1.patch
 1471931-1-63a1.patch
 1471931-2-63a1.patch
 1471931-3-63a1.patch
 1471931-4-63a1.patch
 1471931-5-63a1.patch
+NOBUG-20180629-testingfunctions-63a1.patch
 1471463-63a1.patch
 1471464-63a1.patch
 1471465-63a1.patch
@@ -5102,6 +5115,7 @@ taken-out-stuff-comes-here.patch
 1473371-63a1.patch
 1471556-63a1.patch
 1473297-63a1.patch
+1473256-63a1.patch
 1426909-1-63a1.patch
 1472066-3-63a1.patch
 1472066-4-63a1.patch
@@ -5811,6 +5825,8 @@ NOBUG-20180824-buildsetting-63a1.patch
 1488217-64a1.patch
 1489454-libmar-64a1.patch
 1458129-64a1.patch
+1502886-1-65a1.patch
+1502886-2-65a1.patch
 #1501154-65a1.patch
 #1501157-65a1.patch
 #1502481-1-65a1.patch
@@ -7968,6 +7984,7 @@ TOP-NOBUG-REGEXP-47-fixes-25319.patch
 1878211-11508.patch
 1881093-11509.patch
 TOP-1880562-NSS3902-11509.patch
+NOBUG-JSFIXUPS-25319.patch
 
 
 
@@ -8334,7 +8351,6 @@ mozilla-esr78-push_475032.patch
 
 
 L-1514581-needs1434553-66a1.patch
-L-1412200-63a1.patch
 mozilla-esr78-push_445252.patch
 
 
@@ -10749,10 +10765,9 @@ mozilla-central-push_421533.patch
 L-1478942-63a1.patch
 
 the-taken-out-stuff-start.patch
+
 I-am-here.patch
 aaaaaaaaaaaaaaaaaaaaaaa
-mozilla-central-push_421593.patch
-mozilla-central-push_421681.patch
 mozilla-central-push_421779.patch
 mozilla-central-push_421780.patch
 mozilla-central-push_421781.patch
@@ -10789,21 +10804,12 @@ mozilla-central-push_422557.patch
 mozilla-central-push_422558.patch
 mozilla-central-push_422644.patch
 mozilla-central-push_422645.patch
-mozilla-central-push_422771.patch
-mozilla-central-push_422772.patch
 mozilla-central-push_422799.patch
-mozilla-central-push_422801.patch
-mozilla-central-push_422802.patch
-mozilla-central-push_422803.patch
 mozilla-central-push_422819.patch
 mozilla-central-push_422885.patch
 mozilla-central-push_422903.patch
 mozilla-central-push_422904.patch
 mozilla-central-push_422905.patch
-mozilla-central-push_422914.patch
-mozilla-central-push_422915.patch
-mozilla-central-push_422918.patch
-mozilla-central-push_422919.patch
 mozilla-central-push_422969.patch
 mozilla-central-push_422970.patch
 mozilla-central-push_422976.patch
@@ -10841,5 +10847,4 @@ cccccccccccccccccccccccccccc
 
 
 
-
 the-taken-out-stuff-end.patch

+ 19 - 3
frg/work-js/mozilla-release/patches/series-test

@@ -4918,6 +4918,14 @@ NOBUG-20231031-formattingfixes-253.patch
 1469593-62a1.patch
 1469444-62a1.patch
 1469469-62a1.patch
+1450085-1-62a1.patch
+1450085-2-62a1.patch
+1450085-3-62a1.patch
+1363214-62a1.patch
+1467142-62a1.patch
+1467752-62a1.patch
+1467751-62a1.patch
+taken-out-stuff-comes-here.patch
 1319228-3only-62a1.patch
 1319228-6only-62a1.patch
 1468830-62a1.patch
@@ -4979,9 +4987,9 @@ NOBUG-20231031-formattingfixes-253.patch
 1467438-2-62a1.patch
 1467438-3-62a1.patch
 1467438-5-62a1.patch
-1466626-2no1-62a1.patch
-1466626-3-62a1.patch
-1471272-63a1.patch
+1466626-2no1-63a1.patch
+1466626-3-63a1.patch
+1398839-63a1.patch
 1466211-1-63a1.patch
 1466211-2-63a1.patch
 1466211-3-63a1.patch
@@ -5012,12 +5020,18 @@ NOBUG-20231031-formattingfixes-253.patch
 1464782-1-63a1.patch
 1464782-2no34-63a1.patch
 1470522-63a1.patch
+1447591-1-63a1.patch
+1447591-2-63a1.patch
+1471272-63a1.patch
+1471841-63a1.patch
 1472734-63a1.patch
+1412200-63a1.patch
 1471931-1-63a1.patch
 1471931-2-63a1.patch
 1471931-3-63a1.patch
 1471931-4-63a1.patch
 1471931-5-63a1.patch
+NOBUG-20180629-testingfunctions-63a1.patch
 1471463-63a1.patch
 1471464-63a1.patch
 1471465-63a1.patch
@@ -5101,6 +5115,7 @@ NOBUG-20231031-formattingfixes-253.patch
 1473371-63a1.patch
 1471556-63a1.patch
 1473297-63a1.patch
+1473256-63a1.patch
 1426909-1-63a1.patch
 1472066-3-63a1.patch
 1472066-4-63a1.patch
@@ -7912,3 +7927,4 @@ TOP-NOBUG-REGEXP-47-fixes-25319.patch
 1878211-11508.patch
 1881093-11509.patch
 TOP-1880562-NSS3902-11509.patch
+NOBUG-JSFIXUPS-25319.patch