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>
 # User Andre Bargull <andre.bargull@gmail.com>
 # Date 1534435998 25200
 # Date 1534435998 25200
 # Node ID 62d58886e8d759f52c871a82dbe4d9c2a266c0c7
 # Node ID 62d58886e8d759f52c871a82dbe4d9c2a266c0c7
-# Parent  8e364fec49cc363a5810d1fa37c89f6c1e5265f0
+# Parent  e2ba39d047c4805799d435e3847f50de93aa0d98
 Bug 1346211 - Part 2: Split JS::ResetTimeZone into an external and internal implementation. r=Waldo
 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
 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
 diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
 --- a/js/src/jsdate.cpp
 --- a/js/src/jsdate.cpp
 +++ b/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.
          // Steps 3q-t.
          return NewDateObject(cx, args, TimeClip(UTC(finalDate)));
          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/GC-inl.h"
  #include "gc/Marking-inl.h"
  #include "gc/Marking-inl.h"
  #include "vm/JSAtom-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.
       * 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
       * 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>
 # User Andre Bargull <andre.bargull@gmail.com>
 # Date 1534500279 25200
 # Date 1534500279 25200
 # Node ID 7b1a3a49547dc9564aaa6ecf90b919b66b7ada8d
 # Node ID 7b1a3a49547dc9564aaa6ecf90b919b66b7ada8d
-# Parent  3007514b6576d01dadf0061fdd30be70fb8acf68
+# Parent  19aa3626d2f290e729d47cdff9750fadc7daec4c
 Bug 1346211 - Part 6: Use ICU for all time zone computations when available. r=Waldo
 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
 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)
  #if defined(XP_UNIX) && !defined(XP_DARWIN)
  #include <time.h>
  #include <time.h>
  #else
  #else
-@@ -4983,16 +4985,95 @@ SetTimeZone(JSContext* cx, unsigned argc
+@@ -4980,16 +4982,95 @@ SetTimeZone(JSContext* cx, unsigned argc
  #endif /* _WIN32 */
  #endif /* _WIN32 */
  
  
      JS::ResetTimeZone();
      JS::ResetTimeZone();
@@ -191,7 +191,7 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
  
  
      uint32_t max_cnt;
      uint32_t max_cnt;
      if (!ToUint32(cx, args.get(0), &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,
      JS_FN_HELP("isLegacyIterator", IsLegacyIterator, 1, 0,
  "isLegacyIterator(value)",
  "isLegacyIterator(value)",
  "  Returns whether the value is considered is a legacy iterator.\n"),
  "  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"
  "  running the jitcode rather than staying in the interpreter:\n"
  "    baselineCompile();  for (var i=0; i<1; i++) {} ...\n"
  "    baselineCompile();  for (var i=0; i<1; i++) {} ...\n"
  "  The interpreter will enter the new jitcode at the loop header.\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."),
  "  Returns an array of error notes."),
  
  
      JS_FN_HELP("setTimeZone", SetTimeZone, 1, 0,
      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();
      double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
      if (IsFinite(result))
      if (IsFinite(result))
          result = msFromTime(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;
          return false;
      }
      }
  
  
@@ -469,7 +469,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
  
  
      PRMJTime prtm;
      PRMJTime prtm;
      prtm.tm_usec = int32_t(msFromTime(localTime)) * 1000;
      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;
              usetz = false;
  
  
          if (usetz)
          if (usetz)
@@ -487,7 +487,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
  };
  };
  
  
  static bool
  static bool
-@@ -2720,30 +2807,36 @@ FormatDate(JSContext* cx, double utcTime
+@@ -2719,30 +2806,36 @@ FormatDate(JSContext* cx, double utcTime
  
  
      double localTime = LocalTime(utcTime);
      double localTime = LocalTime(utcTime);
  
  
@@ -527,7 +527,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
      char buf[100];
      char buf[100];
      switch (format) {
      switch (format) {
        case FormatSpec::DateTime:
        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("getDate",             date_getDate,            0,0),
      JS_FN("getUTCDate",          date_getUTCDate,         0,0),
      JS_FN("getUTCDate",          date_getUTCDate,         0,0),
      JS_FN("getDay",              date_getDay,             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>
 # User Ashley Hauck <khyperia@mozilla.com>
 # Date 1534260297 25200
 # Date 1534260297 25200
 # Node ID 8464c338715daf9134f9c640d5da3519c9729447
 # Node ID 8464c338715daf9134f9c640d5da3519c9729447
-# Parent  d3e1970a043cba942de33e1dcdcbad883a8e9222
+# Parent  cfa3894a5365229e911e2ee80e7ec0eae3ef23b1
 Bug 1471371 - OOM handling in RegExp construction. r=jorendorff
 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
 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
 diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
 --- a/js/src/vm/RegExpObject.cpp
 --- a/js/src/vm/RegExpObject.cpp
 +++ b/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);
          ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &invalidFlag);
      } else {
      } else {
          AutoCheckCannotGC nogc;
          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());
 +        UniqueChars utf8(JS::CharsToNewUTF8CharsZ(cx, range).c_str());
          if (!utf8)
          if (!utf8)
              return false;
              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 false;
      }
      }
  
  
      return true;
      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
 # Date 1530202064 25200
 #      Thu Jun 28 09:07:44 2018 -0700
 #      Thu Jun 28 09:07:44 2018 -0700
 # Node ID bd01847472fbc512fbf56b8e4748cf5fad6ee897
 # 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
 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
 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();
          auto iter = data->Start();
          data->ReadBytes(iter, buffer.get(), size);
          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
 diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp
 --- a/js/src/jit/BaselineBailouts.cpp
 --- a/js/src/jit/BaselineBailouts.cpp
 +++ b/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
 # Date 1530203446 25200
 #      Thu Jun 28 09:30:46 2018 -0700
 #      Thu Jun 28 09:30:46 2018 -0700
 # Node ID 4e320fc1cbb8c73e868b4bbbe6dee924eed384bc
 # Node ID 4e320fc1cbb8c73e868b4bbbe6dee924eed384bc
-# Parent  70f2e5844cb9ab3a48b5759c6d460d098ea6c380
+# Parent  a5cbcd678bdd2cf4d2c18465c05ac9ee598301d3
 Bug 1471931 - Part 4: Add NewString and NewStringDontDeflate functions which accept UniquePtr. r=sfink
 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
 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
 diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
 --- a/js/src/builtin/TestingFunctions.cpp
 --- a/js/src/builtin/TestingFunctions.cpp
 +++ b/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);
              frameKind = NewStringCopyZ<CanGC>(cx, inlineFrame.kind);
              if (!frameKind)
              if (!frameKind)
@@ -93,13 +93,14 @@ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctio
                  return false;
                  return false;
  
  
 -            size_t length = strlen(inlineFrame.label.get());
 -            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);
 -            frameLabel = NewString<CanGC>(cx, label, length);
--            if (!frameLabel)
+-            if (!frameLabel) {
+-                js_free(label);
 +            frameLabel = NewLatin1StringZ(cx, std::move(inlineFrame.label));
 +            frameLabel = NewLatin1StringZ(cx, std::move(inlineFrame.label));
-+            if (!frameLabel) {
++            if (!frameLabel)
                  return false;
                  return false;
-+            }
+-            }
  
  
              if (!JS_DefineProperty(cx, inlineFrameInfo, "label", frameLabel, propAttrs))
              if (!JS_DefineProperty(cx, inlineFrameInfo, "label", frameLabel, propAttrs))
                  return false;
                  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))
              if (!JS_DefinePropertyById(cx, inlineStack, idx, inlineFrameInfo, 0))
                  return false;
                  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))
          if (!cx->compartment()->wrap(cx, &wrapped))
              return false;
              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
 diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp
 --- a/js/src/vm/JSCompartment.cpp
 --- a/js/src/vm/JSCompartment.cpp
 +++ b/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);
                 : 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>
 # User Chris Peterson <cpeterson@mozilla.com>
 # Date 1532243386 25200
 # Date 1532243386 25200
 # Node ID eb8f3d8844616dbe6789b10a0fa248a7f9da5693
 # Node ID eb8f3d8844616dbe6789b10a0fa248a7f9da5693
-# Parent  457703dd9351442c192791a3249b9250d079b481
+# Parent  d5aa057ba995254ed0c8e7c8088fe3ffea9bd228
 Bug 1481097 - js: Build Array.cpp and JSAtom.cpp in unified mode. r=djvj
 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).
 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
 diff --git a/js/src/moz.build b/js/src/moz.build
 --- a/js/src/moz.build
 --- a/js/src/moz.build
 +++ b/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/Utility.h',
      '../public/Value.h',
      '../public/Value.h',
      '../public/Vector.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/CommonFunctions.cpp',
      'builtin/intl/DateTimeFormat.cpp',
      'builtin/intl/DateTimeFormat.cpp',
      'builtin/intl/IntlObject.cpp',
      'builtin/intl/IntlObject.cpp',
-@@ -354,16 +355,17 @@ UNIFIED_SOURCES += [
+@@ -370,16 +371,17 @@ UNIFIED_SOURCES += [
      'vm/ForOfIterator.cpp',
      'vm/ForOfIterator.cpp',
      'vm/GeckoProfiler.cpp',
      'vm/GeckoProfiler.cpp',
      'vm/GeneratorObject.cpp',
      'vm/GeneratorObject.cpp',
@@ -46,11 +46,11 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'vm/JSONPrinter.cpp',
      'vm/JSONPrinter.cpp',
      'vm/JSScript.cpp',
      'vm/JSScript.cpp',
      'vm/MemoryMetrics.cpp',
      'vm/MemoryMetrics.cpp',
-@@ -419,18 +421,16 @@ UNIFIED_SOURCES += [
+@@ -432,18 +434,16 @@ UNIFIED_SOURCES += [
+     'wasm/WasmSignalHandlers.cpp',
      'wasm/WasmStubs.cpp',
      'wasm/WasmStubs.cpp',
      'wasm/WasmTable.cpp',
      'wasm/WasmTable.cpp',
      'wasm/WasmTextToBinary.cpp',
      'wasm/WasmTextToBinary.cpp',
-     'wasm/WasmTextUtils.cpp',
      'wasm/WasmTypes.cpp',
      'wasm/WasmTypes.cpp',
      'wasm/WasmValidate.cpp'
      'wasm/WasmValidate.cpp'
  ]
  ]
@@ -65,7 +65,7 @@ diff --git a/js/src/moz.build b/js/src/moz.build
  # template instantiations.
  # template instantiations.
  #   template instantiations.
  #   template instantiations.
  # jsmath.cpp cannot be built in unified mode because it needs to re-#define the
  # 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
  # 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
  #   suppress warnings due to usage of the system allocator, and this allows it
  #   to have a deterministic object name.
  #   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
 # Date 1536371493 14400
 #      Fri Sep 07 21:51:33 2018 -0400
 #      Fri Sep 07 21:51:33 2018 -0400
 # Node ID 520d47760632c300e540b63b70e5655d60e9a8f4
 # Node ID 520d47760632c300e540b63b70e5655d60e9a8f4
-# Parent  6323eca91b342bc2a4fb5556be09084449a49e5c
+# Parent  553667bb270f98108d1bb3ca7262e072dab2a6cb
 Bug 1489698 - Add moz.build for js/src/wasm. r=luke,froydnj
 Bug 1489698 - Add moz.build for js/src/wasm. r=luke,froydnj
 
 
 diff --git a/js/src/moz.build b/js/src/moz.build
 diff --git a/js/src/moz.build b/js/src/moz.build
 --- a/js/src/moz.build
 --- a/js/src/moz.build
 +++ b/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/TypedArrayObject.cpp',
      'vm/TypeInference.cpp',
      'vm/TypeInference.cpp',
      'vm/UbiNode.cpp',
      'vm/UbiNode.cpp',
@@ -20,8 +20,6 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'vm/Xdr.cpp',
      'vm/Xdr.cpp',
 -    'wasm/AsmJS.cpp',
 -    'wasm/AsmJS.cpp',
 -    'wasm/WasmBaselineCompile.cpp',
 -    'wasm/WasmBaselineCompile.cpp',
--    'wasm/WasmBinaryToAST.cpp',
--    'wasm/WasmBinaryToText.cpp',
 -    'wasm/WasmBuiltins.cpp',
 -    'wasm/WasmBuiltins.cpp',
 -    'wasm/WasmCode.cpp',
 -    'wasm/WasmCode.cpp',
 -    'wasm/WasmCompile.cpp',
 -    'wasm/WasmCompile.cpp',
@@ -39,7 +37,6 @@ diff --git a/js/src/moz.build b/js/src/moz.build
 -    'wasm/WasmStubs.cpp',
 -    'wasm/WasmStubs.cpp',
 -    'wasm/WasmTable.cpp',
 -    'wasm/WasmTable.cpp',
 -    'wasm/WasmTextToBinary.cpp',
 -    'wasm/WasmTextToBinary.cpp',
--    'wasm/WasmTextUtils.cpp',
 -    'wasm/WasmTypes.cpp',
 -    'wasm/WasmTypes.cpp',
 -    'wasm/WasmValidate.cpp'
 -    'wasm/WasmValidate.cpp'
  ]
  ]
@@ -50,7 +47,7 @@ diff --git a/js/src/moz.build b/js/src/moz.build
  #   win32 test slowdowns
  #   win32 test slowdowns
  # frontend/Parser.cpp cannot be built in unified mode because of explicit
  # frontend/Parser.cpp cannot be built in unified mode because of explicit
  # template instantiations.
  # template instantiations.
-@@ -411,16 +387,17 @@ else:
+@@ -411,16 +390,17 @@ else:
          'perf/pm_stub.cpp'
          '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
 new file mode 100644
 --- /dev/null
 --- /dev/null
 +++ b/js/src/wasm/moz.build
 +++ b/js/src/wasm/moz.build
-@@ -0,0 +1,45 @@
+@@ -0,0 +1,42 @@
 +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 +# vim: set filetype=python:
 +# vim: set filetype=python:
 +# This Source Code Form is subject to the terms of the Mozilla Public
 +# This Source Code Form is subject to the terms of the Mozilla Public
@@ -95,8 +92,6 @@ new file mode 100644
 +UNIFIED_SOURCES += [
 +UNIFIED_SOURCES += [
 +    'AsmJS.cpp',
 +    'AsmJS.cpp',
 +    'WasmBaselineCompile.cpp',
 +    'WasmBaselineCompile.cpp',
-+    'WasmBinaryToAST.cpp',
-+    'WasmBinaryToText.cpp',
 +    'WasmBuiltins.cpp',
 +    'WasmBuiltins.cpp',
 +    'WasmCode.cpp',
 +    'WasmCode.cpp',
 +    'WasmCompile.cpp',
 +    'WasmCompile.cpp',
@@ -114,7 +109,6 @@ new file mode 100644
 +    'WasmStubs.cpp',
 +    'WasmStubs.cpp',
 +    'WasmTable.cpp',
 +    'WasmTable.cpp',
 +    'WasmTextToBinary.cpp',
 +    'WasmTextToBinary.cpp',
-+    'WasmTextUtils.cpp',
 +    'WasmTypes.cpp',
 +    'WasmTypes.cpp',
 +    'WasmValidate.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
 1469593-62a1.patch
 1469444-62a1.patch
 1469444-62a1.patch
 1469469-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
 taken-out-stuff-comes-here.patch
 1319228-3only-62a1.patch
 1319228-3only-62a1.patch
 1319228-6only-62a1.patch
 1319228-6only-62a1.patch
@@ -4980,9 +4987,9 @@ taken-out-stuff-comes-here.patch
 1467438-2-62a1.patch
 1467438-2-62a1.patch
 1467438-3-62a1.patch
 1467438-3-62a1.patch
 1467438-5-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-1-63a1.patch
 1466211-2-63a1.patch
 1466211-2-63a1.patch
 1466211-3-63a1.patch
 1466211-3-63a1.patch
@@ -5013,12 +5020,18 @@ taken-out-stuff-comes-here.patch
 1464782-1-63a1.patch
 1464782-1-63a1.patch
 1464782-2no34-63a1.patch
 1464782-2no34-63a1.patch
 1470522-63a1.patch
 1470522-63a1.patch
+1447591-1-63a1.patch
+1447591-2-63a1.patch
+1471272-63a1.patch
+1471841-63a1.patch
 1472734-63a1.patch
 1472734-63a1.patch
+1412200-63a1.patch
 1471931-1-63a1.patch
 1471931-1-63a1.patch
 1471931-2-63a1.patch
 1471931-2-63a1.patch
 1471931-3-63a1.patch
 1471931-3-63a1.patch
 1471931-4-63a1.patch
 1471931-4-63a1.patch
 1471931-5-63a1.patch
 1471931-5-63a1.patch
+NOBUG-20180629-testingfunctions-63a1.patch
 1471463-63a1.patch
 1471463-63a1.patch
 1471464-63a1.patch
 1471464-63a1.patch
 1471465-63a1.patch
 1471465-63a1.patch
@@ -5102,6 +5115,7 @@ taken-out-stuff-comes-here.patch
 1473371-63a1.patch
 1473371-63a1.patch
 1471556-63a1.patch
 1471556-63a1.patch
 1473297-63a1.patch
 1473297-63a1.patch
+1473256-63a1.patch
 1426909-1-63a1.patch
 1426909-1-63a1.patch
 1472066-3-63a1.patch
 1472066-3-63a1.patch
 1472066-4-63a1.patch
 1472066-4-63a1.patch
@@ -5811,6 +5825,8 @@ NOBUG-20180824-buildsetting-63a1.patch
 1488217-64a1.patch
 1488217-64a1.patch
 1489454-libmar-64a1.patch
 1489454-libmar-64a1.patch
 1458129-64a1.patch
 1458129-64a1.patch
+1502886-1-65a1.patch
+1502886-2-65a1.patch
 #1501154-65a1.patch
 #1501154-65a1.patch
 #1501157-65a1.patch
 #1501157-65a1.patch
 #1502481-1-65a1.patch
 #1502481-1-65a1.patch
@@ -7968,6 +7984,7 @@ TOP-NOBUG-REGEXP-47-fixes-25319.patch
 1878211-11508.patch
 1878211-11508.patch
 1881093-11509.patch
 1881093-11509.patch
 TOP-1880562-NSS3902-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-1514581-needs1434553-66a1.patch
-L-1412200-63a1.patch
 mozilla-esr78-push_445252.patch
 mozilla-esr78-push_445252.patch
 
 
 
 
@@ -10749,10 +10765,9 @@ mozilla-central-push_421533.patch
 L-1478942-63a1.patch
 L-1478942-63a1.patch
 
 
 the-taken-out-stuff-start.patch
 the-taken-out-stuff-start.patch
+
 I-am-here.patch
 I-am-here.patch
 aaaaaaaaaaaaaaaaaaaaaaa
 aaaaaaaaaaaaaaaaaaaaaaa
-mozilla-central-push_421593.patch
-mozilla-central-push_421681.patch
 mozilla-central-push_421779.patch
 mozilla-central-push_421779.patch
 mozilla-central-push_421780.patch
 mozilla-central-push_421780.patch
 mozilla-central-push_421781.patch
 mozilla-central-push_421781.patch
@@ -10789,21 +10804,12 @@ mozilla-central-push_422557.patch
 mozilla-central-push_422558.patch
 mozilla-central-push_422558.patch
 mozilla-central-push_422644.patch
 mozilla-central-push_422644.patch
 mozilla-central-push_422645.patch
 mozilla-central-push_422645.patch
-mozilla-central-push_422771.patch
-mozilla-central-push_422772.patch
 mozilla-central-push_422799.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_422819.patch
 mozilla-central-push_422885.patch
 mozilla-central-push_422885.patch
 mozilla-central-push_422903.patch
 mozilla-central-push_422903.patch
 mozilla-central-push_422904.patch
 mozilla-central-push_422904.patch
 mozilla-central-push_422905.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_422969.patch
 mozilla-central-push_422970.patch
 mozilla-central-push_422970.patch
 mozilla-central-push_422976.patch
 mozilla-central-push_422976.patch
@@ -10841,5 +10847,4 @@ cccccccccccccccccccccccccccc
 
 
 
 
 
 
-
 the-taken-out-stuff-end.patch
 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
 1469593-62a1.patch
 1469444-62a1.patch
 1469444-62a1.patch
 1469469-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-3only-62a1.patch
 1319228-6only-62a1.patch
 1319228-6only-62a1.patch
 1468830-62a1.patch
 1468830-62a1.patch
@@ -4979,9 +4987,9 @@ NOBUG-20231031-formattingfixes-253.patch
 1467438-2-62a1.patch
 1467438-2-62a1.patch
 1467438-3-62a1.patch
 1467438-3-62a1.patch
 1467438-5-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-1-63a1.patch
 1466211-2-63a1.patch
 1466211-2-63a1.patch
 1466211-3-63a1.patch
 1466211-3-63a1.patch
@@ -5012,12 +5020,18 @@ NOBUG-20231031-formattingfixes-253.patch
 1464782-1-63a1.patch
 1464782-1-63a1.patch
 1464782-2no34-63a1.patch
 1464782-2no34-63a1.patch
 1470522-63a1.patch
 1470522-63a1.patch
+1447591-1-63a1.patch
+1447591-2-63a1.patch
+1471272-63a1.patch
+1471841-63a1.patch
 1472734-63a1.patch
 1472734-63a1.patch
+1412200-63a1.patch
 1471931-1-63a1.patch
 1471931-1-63a1.patch
 1471931-2-63a1.patch
 1471931-2-63a1.patch
 1471931-3-63a1.patch
 1471931-3-63a1.patch
 1471931-4-63a1.patch
 1471931-4-63a1.patch
 1471931-5-63a1.patch
 1471931-5-63a1.patch
+NOBUG-20180629-testingfunctions-63a1.patch
 1471463-63a1.patch
 1471463-63a1.patch
 1471464-63a1.patch
 1471464-63a1.patch
 1471465-63a1.patch
 1471465-63a1.patch
@@ -5101,6 +5115,7 @@ NOBUG-20231031-formattingfixes-253.patch
 1473371-63a1.patch
 1473371-63a1.patch
 1471556-63a1.patch
 1471556-63a1.patch
 1473297-63a1.patch
 1473297-63a1.patch
+1473256-63a1.patch
 1426909-1-63a1.patch
 1426909-1-63a1.patch
 1472066-3-63a1.patch
 1472066-3-63a1.patch
 1472066-4-63a1.patch
 1472066-4-63a1.patch
@@ -7912,3 +7927,4 @@ TOP-NOBUG-REGEXP-47-fixes-25319.patch
 1878211-11508.patch
 1878211-11508.patch
 1881093-11509.patch
 1881093-11509.patch
 TOP-1880562-NSS3902-11509.patch
 TOP-1880562-NSS3902-11509.patch
+NOBUG-JSFIXUPS-25319.patch