Browse Source

js frontend up to end of 63

Frank-Rainer Grahl 8 months ago
parent
commit
2e73e4cfa5
100 changed files with 25028 additions and 134 deletions
  1. 1387 0
      frg/work-js/mozilla-release/patches/1033916-1-63a1.patch
  2. 29 0
      frg/work-js/mozilla-release/patches/1033916-2-63a1.patch
  3. 1431 0
      frg/work-js/mozilla-release/patches/1040316-63a1.patch
  4. 617 0
      frg/work-js/mozilla-release/patches/1426909-1-63a1.patch
  5. 1124 0
      frg/work-js/mozilla-release/patches/1426909-2-63a1.patch
  6. 77 77
      frg/work-js/mozilla-release/patches/1432135-63a1.patch
  7. 313 0
      frg/work-js/mozilla-release/patches/1441333-1-60a1.patch
  8. 128 0
      frg/work-js/mozilla-release/patches/1454285-3-63a1.patch
  9. 15 15
      frg/work-js/mozilla-release/patches/1461938-20-62a1.patch
  10. 411 0
      frg/work-js/mozilla-release/patches/1463979-0-63a1.patch
  11. 949 0
      frg/work-js/mozilla-release/patches/1463979-1-63a1.patch
  12. 0 0
      frg/work-js/mozilla-release/patches/1467336-24-63a1.patch
  13. 0 0
      frg/work-js/mozilla-release/patches/1467336-25-63a1.patch
  14. 975 0
      frg/work-js/mozilla-release/patches/1471463-63a1.patch
  15. 203 0
      frg/work-js/mozilla-release/patches/1471464-63a1.patch
  16. 156 0
      frg/work-js/mozilla-release/patches/1471465-65a1.patch
  17. 141 0
      frg/work-js/mozilla-release/patches/1472031-1-63a1.patch
  18. 91 0
      frg/work-js/mozilla-release/patches/1472031-2-63a1.patch
  19. 58 0
      frg/work-js/mozilla-release/patches/1472031-3-63a1.patch
  20. 71 0
      frg/work-js/mozilla-release/patches/1472031-4-63a1.patch
  21. 119 0
      frg/work-js/mozilla-release/patches/1472031-5-63a1.patch
  22. 155 0
      frg/work-js/mozilla-release/patches/1472031-6-63a1.patch
  23. 92 0
      frg/work-js/mozilla-release/patches/1472066-1-63a1.patch
  24. 174 0
      frg/work-js/mozilla-release/patches/1472066-2-63a1.patch
  25. 77 0
      frg/work-js/mozilla-release/patches/1472066-3-63a1.patch
  26. 65 0
      frg/work-js/mozilla-release/patches/1472066-4-63a1.patch
  27. 1268 0
      frg/work-js/mozilla-release/patches/1472569-63a1.patch
  28. 70 0
      frg/work-js/mozilla-release/patches/1475559-1-63a1.patch
  29. 104 0
      frg/work-js/mozilla-release/patches/1476012-1-63a1.patch
  30. 177 0
      frg/work-js/mozilla-release/patches/1476012-2-63a1.patch
  31. 2086 0
      frg/work-js/mozilla-release/patches/1476012-3-63a1.patch
  32. 401 0
      frg/work-js/mozilla-release/patches/1476012-4-63a1.patch
  33. 107 0
      frg/work-js/mozilla-release/patches/1476012-5-63a1.patch
  34. 92 0
      frg/work-js/mozilla-release/patches/1476012-6-63a1.patch
  35. 180 0
      frg/work-js/mozilla-release/patches/1476012-7-63a1.patch
  36. 34 0
      frg/work-js/mozilla-release/patches/1476012-8-63a1.patch
  37. 27 0
      frg/work-js/mozilla-release/patches/1476012-9-63a1.patch
  38. 893 0
      frg/work-js/mozilla-release/patches/1476203-63a1.patch
  39. 124 0
      frg/work-js/mozilla-release/patches/1476409-63a1.patch
  40. 163 0
      frg/work-js/mozilla-release/patches/1476657-63a1.patch
  41. 44 0
      frg/work-js/mozilla-release/patches/1476866-01-63a1.patch
  42. 153 0
      frg/work-js/mozilla-release/patches/1476866-02-63a1.patch
  43. 393 0
      frg/work-js/mozilla-release/patches/1476866-03-63a1.patch
  44. 163 0
      frg/work-js/mozilla-release/patches/1476866-04-63a1.patch
  45. 166 0
      frg/work-js/mozilla-release/patches/1476866-05-63a1.patch
  46. 109 0
      frg/work-js/mozilla-release/patches/1476866-06-63a1.patch
  47. 349 0
      frg/work-js/mozilla-release/patches/1476866-07-63a1.patch
  48. 223 0
      frg/work-js/mozilla-release/patches/1476866-08-63a1.patch
  49. 62 0
      frg/work-js/mozilla-release/patches/1476866-09-63a1.patch
  50. 143 0
      frg/work-js/mozilla-release/patches/1476866-10-63a1.patch
  51. 305 0
      frg/work-js/mozilla-release/patches/1476866-11-63a1.patch
  52. 343 0
      frg/work-js/mozilla-release/patches/1476866-12-63a1.patch
  53. 274 0
      frg/work-js/mozilla-release/patches/1476866-13-63a1.patch
  54. 200 0
      frg/work-js/mozilla-release/patches/1476866-14-63a1.patch
  55. 174 0
      frg/work-js/mozilla-release/patches/1476866-15-63a1.patch
  56. 334 0
      frg/work-js/mozilla-release/patches/1477157-63a1.patch
  57. 327 0
      frg/work-js/mozilla-release/patches/1477896-63a1.patch
  58. 357 0
      frg/work-js/mozilla-release/patches/1478045-1-63a1.patch
  59. 39 0
      frg/work-js/mozilla-release/patches/1478045-2-63a1.patch
  60. 49 0
      frg/work-js/mozilla-release/patches/1478045-3-63a1.patch
  61. 66 0
      frg/work-js/mozilla-release/patches/1478045-4-63a1.patch
  62. 62 0
      frg/work-js/mozilla-release/patches/1478045-5-63a1.patch
  63. 114 0
      frg/work-js/mozilla-release/patches/1478045-6-63a1.patch
  64. 80 0
      frg/work-js/mozilla-release/patches/1478170-01-63a1.patch
  65. 235 0
      frg/work-js/mozilla-release/patches/1478170-02-63a1.patch
  66. 94 0
      frg/work-js/mozilla-release/patches/1478170-03-63a1.patch
  67. 113 0
      frg/work-js/mozilla-release/patches/1478170-04-63a1.patch
  68. 545 0
      frg/work-js/mozilla-release/patches/1478170-05-63a1.patch
  69. 58 0
      frg/work-js/mozilla-release/patches/1478170-06-63a1.patch
  70. 84 0
      frg/work-js/mozilla-release/patches/1478170-07-63a1.patch
  71. 77 0
      frg/work-js/mozilla-release/patches/1478170-08-63a1.patch
  72. 173 0
      frg/work-js/mozilla-release/patches/1478170-09-63a1.patch
  73. 47 0
      frg/work-js/mozilla-release/patches/1478170-10-63a1.patch
  74. 158 0
      frg/work-js/mozilla-release/patches/1478170-11-63a1.patch
  75. 172 0
      frg/work-js/mozilla-release/patches/1478170-12-63a1.patch
  76. 176 0
      frg/work-js/mozilla-release/patches/1478170-13-63a1.patch
  77. 32 0
      frg/work-js/mozilla-release/patches/1478170-14-63a1.patch
  78. 70 0
      frg/work-js/mozilla-release/patches/1478587-01-63a1.patch
  79. 56 0
      frg/work-js/mozilla-release/patches/1478587-02-63a1.patch
  80. 30 0
      frg/work-js/mozilla-release/patches/1478587-03-63a1.patch
  81. 157 0
      frg/work-js/mozilla-release/patches/1478587-04-63a1.patch
  82. 92 0
      frg/work-js/mozilla-release/patches/1478587-05-63a1.patch
  83. 30 0
      frg/work-js/mozilla-release/patches/1478587-06-63a1.patch
  84. 62 0
      frg/work-js/mozilla-release/patches/1478587-07-63a1.patch
  85. 45 0
      frg/work-js/mozilla-release/patches/1478587-08-63a1.patch
  86. 364 0
      frg/work-js/mozilla-release/patches/1478587-09-63a1.patch
  87. 32 0
      frg/work-js/mozilla-release/patches/1478587-10-63a1.patch
  88. 142 0
      frg/work-js/mozilla-release/patches/1478892-1-63a1.patch
  89. 30 0
      frg/work-js/mozilla-release/patches/1478892-2-63a1.patch
  90. 28 0
      frg/work-js/mozilla-release/patches/1478892-3-63a1.patch
  91. 371 0
      frg/work-js/mozilla-release/patches/1478910-63a1.patch
  92. 7 7
      frg/work-js/mozilla-release/patches/1479900-2-63a1.patch
  93. 33 0
      frg/work-js/mozilla-release/patches/1480306-63a1.patch
  94. 352 0
      frg/work-js/mozilla-release/patches/1480493-63a1.patch
  95. 216 0
      frg/work-js/mozilla-release/patches/1481248-63a1.patch
  96. 486 0
      frg/work-js/mozilla-release/patches/1483275-1-63a1.patch
  97. 449 0
      frg/work-js/mozilla-release/patches/1484389-63a1.patch
  98. 7 7
      frg/work-js/mozilla-release/patches/1485347-1-63a1.patch
  99. 865 0
      frg/work-js/mozilla-release/patches/1486730-63a1.patch
  100. 27 28
      frg/work-js/mozilla-release/patches/1494752-604.patch

+ 1387 - 0
frg/work-js/mozilla-release/patches/1033916-1-63a1.patch

@@ -0,0 +1,1387 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1534776368 25200
+# Node ID 67d5039dcbc2522e187bcf3dbec1c6e92bd32167
+# Parent  c0a1fdc3845951de8f5e66901b3f498608a32e2f
+Bug 1033916 - Move JSAutoByteString out of jsapi.h into js/public/AutoByteString.h, incidentally breaking the jsfriendapi.h -> jsapi.h dependency.  r=jandem
+
+diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp
+--- a/dom/base/ChromeUtils.cpp
++++ b/dom/base/ChromeUtils.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "ChromeUtils.h"
+ 
++#include "js/AutoByteString.h"
+ #include "js/SavedFrameAPI.h"
+ #include "jsfriendapi.h"
+ #include "WrapperFactory.h"
+ 
+ #include "mozilla/Base64.h"
+ #include "mozilla/BasePrincipal.h"
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/dom/IdleDeadline.h"
+diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
+--- a/dom/base/nsJSUtils.h
++++ b/dom/base/nsJSUtils.h
+@@ -14,16 +14,17 @@
+  * the generated code itself.
+  */
+ 
+ #include "mozilla/Assertions.h"
+ 
+ #include "GeckoProfiler.h"
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
++#include "js/AutoByteString.h"
+ #include "js/Conversions.h"
+ #include "js/StableStringChars.h"
+ #include "nsString.h"
+ 
+ class nsIScriptContext;
+ class nsIScriptElement;
+ class nsIScriptGlobalObject;
+ class nsXBLPrototypeBinding;
+diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
+--- a/dom/bindings/BindingUtils.h
++++ b/dom/bindings/BindingUtils.h
+@@ -3,16 +3,17 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+  * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef mozilla_dom_BindingUtils_h__
+ #define mozilla_dom_BindingUtils_h__
+ 
+ #include "jsfriendapi.h"
++#include "js/AutoByteString.h"
+ #include "js/Wrapper.h"
+ #include "js/Conversions.h"
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Alignment.h"
+ #include "mozilla/Array.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/CycleCollectedJSContext.h"
+ #include "mozilla/DeferredFinalize.h"
+diff --git a/dom/bindings/DOMJSClass.h b/dom/bindings/DOMJSClass.h
+--- a/dom/bindings/DOMJSClass.h
++++ b/dom/bindings/DOMJSClass.h
+@@ -2,16 +2,17 @@
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+  * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef mozilla_dom_DOMJSClass_h
+ #define mozilla_dom_DOMJSClass_h
+ 
++#include "jsapi.h"
+ #include "jsfriendapi.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Likely.h"
+ 
+ #include "mozilla/dom/PrototypeList.h" // auto-generated
+ 
+ #include "mozilla/dom/JSSlots.h"
+diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp
+--- a/ipc/testshell/XPCShellEnvironment.cpp
++++ b/ipc/testshell/XPCShellEnvironment.cpp
+@@ -11,16 +11,17 @@
+ #endif
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>     /* for isatty() */
+ #endif
+ 
+ #include "base/basictypes.h"
+ 
+ #include "jsapi.h"
++#include "js/AutoByteString.h"
+ 
+ #include "xpcpublic.h"
+ 
+ #include "XPCShellEnvironment.h"
+ 
+ #include "mozilla/XPCOM.h"
+ 
+ #include "nsIChannel.h"
+diff --git a/js/public/AutoByteString.h b/js/public/AutoByteString.h
+new file mode 100644
+--- /dev/null
++++ b/js/public/AutoByteString.h
+@@ -0,0 +1,140 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++/*
++ * DEPRECATED functions and classes for heap-allocating copies of a JSString's
++ * data.
++ */
++
++#ifndef js_AutoByteString_h
++#define js_AutoByteString_h
++
++#include "mozilla/Assertions.h" // MOZ_ASSERT
++#include "mozilla/Attributes.h" // MOZ_RAII, MOZ_GUARD*
++
++#include <string.h> // strlen
++
++#include "jstypes.h" // JS_PUBLIC_API
++
++#include "js/MemoryFunctions.h" // JS_free
++#include "js/RootingAPI.h" // JS::Handle
++#include "js/TypeDecls.h" // JSContext, JSString
++#include "js/Utility.h" // js_free, JS::UniqueChars
++
++/**
++ * DEPRECATED
++ *
++ * Allocate memory sufficient to contain the characters of |str| truncated to
++ * Latin-1 and a trailing null terminator, fill the memory with the characters
++ * interpreted in that manner plus the null terminator, and return a pointer to
++ * the memory.  The memory must be freed using JS_free to avoid leaking.
++ *
++ * This function *loses information* when it copies the characters of |str| if
++ * |str| contains code units greater than 0xFF.  Additionally, users that
++ * depend on null-termination will misinterpret the copied characters if |str|
++ * contains any nulls.  Avoid using this function if possible, because it will
++ * eventually be removed.
++ */
++extern JS_PUBLIC_API(char*)
++JS_EncodeString(JSContext* cx, JSString* str);
++
++/**
++ * DEPRECATED
++ *
++ * Same behavior as JS_EncodeString(), but encode into a UTF-8 string.
++ *
++ * This function *loses information* when it copies the characters of |str| if
++ * |str| contains invalid UTF-16: U+FFFD REPLACEMENT CHARACTER will be copied
++ * instead.
++ *
++ * The returned string is also subject to misinterpretation if |str| contains
++ * any nulls (which are faithfully transcribed into the returned string, but
++ * which will implicitly truncate the string if it's passed to functions that
++ * expect null-terminated strings).
++ *
++ * Avoid using this function if possible, because we'll remove it once we can
++ * devise a better API for the task.
++ */
++extern JS_PUBLIC_API(char*)
++JS_EncodeStringToUTF8(JSContext* cx, JS::Handle<JSString*> str);
++
++/**
++ * DEPRECATED
++ *
++ * A lightweight RAII helper class around the various JS_Encode* functions
++ * above, subject to the same pitfalls noted above.  Avoid using this class if
++ * possible, because as with the functions above, it too needs to be replaced
++ * with a better, safer API.
++ */
++class MOZ_RAII JSAutoByteString final
++{
++  private:
++    char* mBytes;
++    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
++
++  private:
++    JSAutoByteString(const JSAutoByteString& another) = delete;
++    void operator=(const JSAutoByteString& another) = delete;
++
++  public:
++    JSAutoByteString(JSContext* cx, JSString* str
++                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
++      : mBytes(JS_EncodeString(cx, str))
++    {
++        MOZ_ASSERT(cx);
++        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
++    }
++
++    explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
++      : mBytes(nullptr)
++    {
++        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
++    }
++
++    ~JSAutoByteString() {
++        JS_free(nullptr, mBytes);
++    }
++
++    /* Take ownership of the given byte array. */
++    void initBytes(JS::UniqueChars&& bytes) {
++        MOZ_ASSERT(!mBytes);
++        mBytes = bytes.release();
++    }
++
++    char* encodeLatin1(JSContext* cx, JSString* str) {
++        MOZ_ASSERT(!mBytes);
++        MOZ_ASSERT(cx);
++        mBytes = JS_EncodeString(cx, str);
++        return mBytes;
++    }
++
++    char* encodeUtf8(JSContext* cx, JS::Handle<JSString*> str) {
++        MOZ_ASSERT(!mBytes);
++        MOZ_ASSERT(cx);
++        mBytes = JS_EncodeStringToUTF8(cx, str);
++        return mBytes;
++    }
++
++    void clear() {
++        js_free(mBytes);
++        mBytes = nullptr;
++    }
++
++    char* ptr() const {
++        return mBytes;
++    }
++
++    bool operator!() const {
++        return !mBytes;
++    }
++
++    size_t length() const {
++        if (!mBytes)
++            return 0;
++        return strlen(mBytes);
++    }
++};
++
++#endif /* js_AutoByteString_h */
+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
+@@ -36,16 +36,17 @@
+ #include "irregexp/RegExpAST.h"
+ #include "irregexp/RegExpEngine.h"
+ #include "irregexp/RegExpParser.h"
+ #endif
+ #include "gc/Heap.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/JitRealm.h"
++#include "js/AutoByteString.h"
+ #include "js/Debug.h"
+ #include "js/HashTable.h"
+ #include "js/StableStringChars.h"
+ #include "js/StructuredClone.h"
+ #include "js/UbiNode.h"
+ #include "js/UbiNodeBreadthFirst.h"
+ #include "js/UbiNodeShortestPaths.h"
+ #include "js/UniquePtr.h"
+diff --git a/js/src/builtin/intl/Collator.cpp b/js/src/builtin/intl/Collator.cpp
+--- a/js/src/builtin/intl/Collator.cpp
++++ b/js/src/builtin/intl/Collator.cpp
+@@ -12,16 +12,17 @@
+ 
+ #include "jsapi.h"
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "builtin/intl/SharedIntlData.h"
+ #include "gc/FreeOp.h"
++#include "js/AutoByteString.h"
+ #include "js/StableStringChars.h"
+ #include "js/TypeDecls.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/Runtime.h"
+ #include "vm/StringType.h"
+ 
+ #include "vm/JSObject-inl.h"
+diff --git a/js/src/builtin/intl/DateTimeFormat.cpp b/js/src/builtin/intl/DateTimeFormat.cpp
+--- a/js/src/builtin/intl/DateTimeFormat.cpp
++++ b/js/src/builtin/intl/DateTimeFormat.cpp
+@@ -14,16 +14,17 @@
+ #include "jsfriendapi.h"
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "builtin/intl/SharedIntlData.h"
+ #include "builtin/intl/TimeZoneDataGenerated.h"
+ #include "gc/FreeOp.h"
++#include "js/AutoByteString.h"
+ #include "js/StableStringChars.h"
+ #include "vm/DateTime.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/Runtime.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+diff --git a/js/src/builtin/intl/IntlObject.cpp b/js/src/builtin/intl/IntlObject.cpp
+--- a/js/src/builtin/intl/IntlObject.cpp
++++ b/js/src/builtin/intl/IntlObject.cpp
+@@ -16,16 +16,17 @@
+ 
+ #include "builtin/intl/Collator.h"
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/DateTimeFormat.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/NumberFormat.h"
+ #include "builtin/intl/PluralRules.h"
+ #include "builtin/intl/ScopedICUObject.h"
++#include "js/AutoByteString.h"
+ #include "js/Class.h"
+ #include "js/StableStringChars.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/StringType.h"
+ 
+ #include "vm/JSObject-inl.h"
+diff --git a/js/src/builtin/intl/PluralRules.cpp b/js/src/builtin/intl/PluralRules.cpp
+--- a/js/src/builtin/intl/PluralRules.cpp
++++ b/js/src/builtin/intl/PluralRules.cpp
+@@ -10,16 +10,17 @@
+ 
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Casting.h"
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "gc/FreeOp.h"
++#include "js/AutoByteString.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/StringType.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ 
+ using namespace js;
+diff --git a/js/src/builtin/intl/RelativeTimeFormat.cpp b/js/src/builtin/intl/RelativeTimeFormat.cpp
+--- a/js/src/builtin/intl/RelativeTimeFormat.cpp
++++ b/js/src/builtin/intl/RelativeTimeFormat.cpp
+@@ -10,16 +10,17 @@
+ 
+ #include "mozilla/Assertions.h"
+ #include "mozilla/FloatingPoint.h"
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "gc/FreeOp.h"
++#include "js/AutoByteString.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ 
+ #include "vm/NativeObject-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::IsNegativeZero;
+diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp
+--- a/js/src/ctypes/CTypes.cpp
++++ b/js/src/ctypes/CTypes.cpp
+@@ -35,16 +35,17 @@
+ #include "jsnum.h"
+ 
+ #include "builtin/TypedObject.h"
+ #include "ctypes/Library.h"
+ #include "gc/FreeOp.h"
+ #include "gc/Policy.h"
+ #include "gc/Zone.h"
+ #include "jit/AtomicOperations.h"
++#include "js/AutoByteString.h"
+ #include "js/StableStringChars.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
+ #include "util/Windows.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ 
+ #include "vm/JSObject-inl.h"
+diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp
+--- a/js/src/ctypes/Library.cpp
++++ b/js/src/ctypes/Library.cpp
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "ctypes/Library.h"
+ 
+ #include "prerror.h"
+ #include "prlink.h"
+ 
+ #include "ctypes/CTypes.h"
++#include "js/AutoByteString.h"
+ #include "js/StableStringChars.h"
+ 
+ using JS::AutoStableStringChars;
+ 
+ namespace js {
+ namespace ctypes {
+ 
+ /*******************************************************************************
+diff --git a/js/src/frontend/EmitterScope.cpp b/js/src/frontend/EmitterScope.cpp
+--- a/js/src/frontend/EmitterScope.cpp
++++ b/js/src/frontend/EmitterScope.cpp
+@@ -3,16 +3,17 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "frontend/EmitterScope.h"
+ 
+ #include "frontend/BytecodeEmitter.h"
+ #include "frontend/TDZCheckCache.h"
++#include "js/AutoByteString.h"
+ 
+ using namespace js;
+ using namespace js::frontend;
+ 
+ using mozilla::DebugOnly;
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::Some;
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -30,16 +30,17 @@
+ #include "jstypes.h"
+ 
+ #include "builtin/ModuleObject.h"
+ #include "builtin/SelfHostingDefines.h"
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/FoldConstants.h"
+ #include "frontend/TokenStream.h"
+ #include "irregexp/RegExpParser.h"
++#include "js/AutoByteString.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ #include "vm/JSScript.h"
+ #include "vm/RegExpObject.h"
+ #include "vm/StringType.h"
+ #include "wasm/AsmJS.h"
+diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h
+--- a/js/src/jsapi-tests/tests.h
++++ b/js/src/jsapi-tests/tests.h
+@@ -12,16 +12,17 @@
+ 
+ #include <errno.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ #include "gc/GC.h"
+ #include "js/AllocPolicy.h"
++#include "js/AutoByteString.h"
+ #include "js/Vector.h"
+ #include "vm/JSContext.h"
+ 
+ /* Note: Aborts on OOM. */
+ class JSAPITestString {
+     js::Vector<char, 0, js::SystemAllocPolicy> chars;
+ 
+   public:
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -53,16 +53,17 @@
+ #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
+ #include "gc/FreeOp.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "gc/WeakMap.h"
+ #include "jit/JitCommon.h"
+ #include "jit/JitSpewer.h"
++#include "js/AutoByteString.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Conversions.h"
+ #include "js/Date.h"
+ #include "js/Initialization.h"
+ #include "js/Proxy.h"
+ #include "js/SliceBudget.h"
+ #include "js/StableStringChars.h"
+ #include "js/StructuredClone.h"
+diff --git a/js/src/jsapi.h b/js/src/jsapi.h
+--- a/js/src/jsapi.h
++++ b/js/src/jsapi.h
+@@ -4597,29 +4597,16 @@ JS_ConcatStrings(JSContext* cx, JS::Hand
+  * NB: This function does not store an additional zero byte or char16_t after the
+  * transcoded string.
+  */
+ JS_PUBLIC_API(bool)
+ JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, char16_t* dst,
+                size_t* dstlenp);
+ 
+ /**
+- * A variation on JS_EncodeCharacters where a null terminated string is
+- * returned that you are expected to call JS_free on when done.
+- */
+-JS_PUBLIC_API(char*)
+-JS_EncodeString(JSContext* cx, JSString* str);
+-
+-/**
+- * Same behavior as JS_EncodeString(), but encode into UTF-8 string
+- */
+-JS_PUBLIC_API(char*)
+-JS_EncodeStringToUTF8(JSContext* cx, JS::HandleString str);
+-
+-/**
+  * Get number of bytes in the string encoding (without accounting for a
+  * terminating zero bytes. The function returns (size_t) -1 if the string
+  * can not be encoded into bytes and reports an error using cx accordingly.
+  */
+ JS_PUBLIC_API(size_t)
+ JS_GetStringEncodingLength(JSContext* cx, JSString* str);
+ 
+ /**
+@@ -4628,85 +4615,16 @@ JS_GetStringEncodingLength(JSContext* cx
+  * encoded into bytes with no error reported. Otherwise it returns the number
+  * of bytes that are necessary to encode the string. If that exceeds the
+  * length parameter, the string will be cut and only length bytes will be
+  * written into the buffer.
+  */
+ JS_PUBLIC_API(size_t)
+ JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t length);
+ 
+-class MOZ_RAII JSAutoByteString
+-{
+-  public:
+-    JSAutoByteString(JSContext* cx, JSString* str
+-                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+-      : mBytes(JS_EncodeString(cx, str))
+-    {
+-        MOZ_ASSERT(cx);
+-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+-    }
+-
+-    explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+-      : mBytes(nullptr)
+-    {
+-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+-    }
+-
+-    ~JSAutoByteString() {
+-        JS_free(nullptr, mBytes);
+-    }
+-
+-    /* Take ownership of the given byte array. */
+-    void initBytes(JS::UniqueChars&& bytes) {
+-        MOZ_ASSERT(!mBytes);
+-        mBytes = bytes.release();
+-    }
+-
+-    char* encodeLatin1(JSContext* cx, JSString* str) {
+-        MOZ_ASSERT(!mBytes);
+-        MOZ_ASSERT(cx);
+-        mBytes = JS_EncodeString(cx, str);
+-        return mBytes;
+-    }
+-
+-    char* encodeUtf8(JSContext* cx, JS::HandleString str) {
+-        MOZ_ASSERT(!mBytes);
+-        MOZ_ASSERT(cx);
+-        mBytes = JS_EncodeStringToUTF8(cx, str);
+-        return mBytes;
+-    }
+-
+-    void clear() {
+-        js_free(mBytes);
+-        mBytes = nullptr;
+-    }
+-
+-    char* ptr() const {
+-        return mBytes;
+-    }
+-
+-    bool operator!() const {
+-        return !mBytes;
+-    }
+-
+-    size_t length() const {
+-        if (!mBytes)
+-            return 0;
+-        return strlen(mBytes);
+-    }
+-
+-  private:
+-    char* mBytes;
+-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+-
+-    /* Copy and assignment are not supported. */
+-    JSAutoByteString(const JSAutoByteString& another);
+-    JSAutoByteString& operator=(const JSAutoByteString& another);
+-};
+-
+ namespace JS {
+ 
+ extern JS_PUBLIC_API(JSAddonId*)
+ NewAddonId(JSContext* cx, JS::HandleString str);
+ 
+ extern JS_PUBLIC_API(JSString*)
+ StringOfAddonId(JSAddonId* id);
+ 
+diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
+--- a/js/src/jsexn.cpp
++++ b/js/src/jsexn.cpp
+@@ -18,16 +18,17 @@
+ 
+ #include "jsapi.h"
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "gc/FreeOp.h"
+ #include "gc/Marking.h"
++#include "js/AutoByteString.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/UniquePtr.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "vm/ErrorObject.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+diff --git a/js/src/jsexn.h b/js/src/jsexn.h
+--- a/js/src/jsexn.h
++++ b/js/src/jsexn.h
+@@ -12,16 +12,18 @@
+ #define jsexn_h
+ 
+ #include "jsapi.h"
+ #include "NamespaceImports.h"
+ 
+ #include "js/UniquePtr.h"
+ #include "vm/JSContext.h"
+ 
++class JSAutoByteString;
++
+ namespace js {
+ class ErrorObject;
+ 
+ UniquePtr<JSErrorNotes::Note>
+ CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note);
+ 
+ UniquePtr<JSErrorReport>
+ CopyErrorReport(JSContext* cx, JSErrorReport* report);
+diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp
+--- a/js/src/jsfriendapi.cpp
++++ b/js/src/jsfriendapi.cpp
+@@ -14,16 +14,17 @@
+ #ifdef ENABLE_BIGINT
+ #include "builtin/BigInt.h"
+ #endif
+ #include "builtin/Promise.h"
+ #include "builtin/TestingFunctions.h"
+ #include "gc/GCInternals.h"
+ #include "gc/PublicIterators.h"
+ #include "gc/WeakMap.h"
++#include "js/AutoByteString.h"
+ #include "js/Printf.h"
+ #include "js/Proxy.h"
+ #include "js/Wrapper.h"
+ #include "proxy/DeadObjectProxy.h"
+ #include "vm/ArgumentsObject.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -8,19 +8,19 @@
+ #define jsfriendapi_h
+ 
+ #include "mozilla/Atomics.h"
+ #include "mozilla/Casting.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/UniquePtr.h"
+ 
+-#include "jsapi.h" // For JSAutoByteString.  See bug 1033916.
+ #include "jspubtd.h"
+ 
++#include "js/AutoByteString.h"
+ #include "js/CallArgs.h"
+ #include "js/CallNonGenericMethod.h"
+ #include "js/Class.h"
+ #include "js/HeapAPI.h"
+ #include "js/StableStringChars.h"
+ #include "js/TypeDecls.h"
+ #include "js/Utility.h"
+ 
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -118,16 +118,17 @@ EXPORTS += [
+     'jsfriendapi.h',
+     'jspubtd.h',
+     'jstypes.h',
+     'perf/jsperf.h',
+ ]
+ 
+ EXPORTS.js += [
+     '../public/AllocPolicy.h',
++    '../public/AutoByteString.h',
+     '../public/CallArgs.h',
+     '../public/CallNonGenericMethod.h',
+     '../public/CharacterEncoding.h',
+     '../public/Class.h',
+     '../public/Conversions.h',
+     '../public/Date.h',
+     '../public/Debug.h',
+     '../public/GCAnnotations.h',
+diff --git a/js/src/proxy/ScriptedProxyHandler.cpp b/js/src/proxy/ScriptedProxyHandler.cpp
+--- a/js/src/proxy/ScriptedProxyHandler.cpp
++++ b/js/src/proxy/ScriptedProxyHandler.cpp
+@@ -3,16 +3,17 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "proxy/ScriptedProxyHandler.h"
+ 
+ #include "jsapi.h"
+ 
++#include "js/AutoByteString.h"
+ #include "vm/Interpreter.h" // For InstanceOfOperator
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ 
+ using namespace js;
+ 
+ using JS::IsArrayAnswer;
+diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp
+--- a/js/src/shell/OSObject.cpp
++++ b/js/src/shell/OSObject.cpp
+@@ -20,16 +20,17 @@
+ #endif
+ 
+ #include "jsapi.h"
+ // For JSFunctionSpecWithHelp
+ #include "jsfriendapi.h"
+ 
+ #include "builtin/String.h"
+ #include "gc/FreeOp.h"
++#include "js/AutoByteString.h"
+ #include "js/Conversions.h"
+ #include "js/Wrapper.h"
+ #include "shell/jsshell.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "util/Windows.h"
+ #include "vm/JSObject.h"
+ #include "vm/TypedArrayObject.h"
+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
+@@ -69,16 +69,17 @@
+ #include "frontend/Parser.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/arm/Simulator-arm.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/Ion.h"
+ #include "jit/JitcodeMap.h"
+ #include "jit/JitRealm.h"
+ #include "jit/shared/CodeGenerator-shared.h"
++#include "js/AutoByteString.h"
+ #include "js/Debug.h"
+ #include "js/GCVector.h"
+ #include "js/Initialization.h"
+ #include "js/Printf.h"
+ #include "js/StableStringChars.h"
+ #include "js/StructuredClone.h"
+ #include "js/SweepingAPI.h"
+ #include "js/Wrapper.h"
+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
+@@ -28,16 +28,17 @@
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "builtin/String.h"
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/SourceNotes.h"
+ #include "gc/FreeOp.h"
+ #include "gc/GCInternals.h"
++#include "js/AutoByteString.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Printf.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "vm/CodeCoverage.h"
+ #include "vm/EnvironmentObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSCompartment.h"
+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
+@@ -20,16 +20,17 @@
+ #include "frontend/Parser.h"
+ #include "gc/FreeOp.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/BaselineDebugModeOSR.h"
+ #include "jit/BaselineJIT.h"
++#include "js/AutoByteString.h"
+ #include "js/Date.h"
+ #include "js/StableStringChars.h"
+ #include "js/UbiNodeBreadthFirst.h"
+ #include "js/Vector.h"
+ #include "js/Wrapper.h"
+ #include "proxy/ScriptedProxyHandler.h"
+ #include "util/Text.h"
+ #include "vm/ArgumentsObject.h"
+diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp
+--- a/js/src/vm/EnvironmentObject.cpp
++++ b/js/src/vm/EnvironmentObject.cpp
+@@ -3,16 +3,17 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "vm/EnvironmentObject-inl.h"
+ 
+ #include "builtin/ModuleObject.h"
+ #include "gc/Policy.h"
++#include "js/AutoByteString.h"
+ #include "vm/ArgumentsObject.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/Iteration.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/ProxyObject.h"
+ #include "vm/Shape.h"
+ #include "vm/Xdr.h"
+diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp
+--- a/js/src/vm/ErrorObject.cpp
++++ b/js/src/vm/ErrorObject.cpp
+@@ -8,16 +8,17 @@
+ #include "vm/ErrorObject-inl.h"
+ 
+ #include "mozilla/Range.h"
+ 
+ #include <utility>
+ 
+ #include "jsexn.h"
+ 
++#include "js/AutoByteString.h"
+ #include "js/CallArgs.h"
+ #include "js/CharacterEncoding.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/SelfHosting.h"
+ #include "vm/StringType.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
+--- a/js/src/vm/Interpreter.cpp
++++ b/js/src/vm/Interpreter.cpp
+@@ -24,16 +24,17 @@
+ #include "builtin/Eval.h"
+ #include "builtin/ModuleObject.h"
+ #include "builtin/String.h"
+ #include "jit/AtomicOperations.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/Ion.h"
+ #include "jit/IonAnalysis.h"
+ #include "jit/Jit.h"
++#include "js/AutoByteString.h"
+ #include "util/StringBuffer.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/AsyncIteration.h"
+ #ifdef ENABLE_BIGINT
+ #include "vm/BigIntType.h"
+ #endif
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+diff --git a/js/src/vm/JSAtom.cpp b/js/src/vm/JSAtom.cpp
+--- a/js/src/vm/JSAtom.cpp
++++ b/js/src/vm/JSAtom.cpp
+@@ -16,16 +16,17 @@
+ #include "mozilla/Unused.h"
+ 
+ #include <string.h>
+ 
+ #include "jstypes.h"
+ 
+ #include "builtin/String.h"
+ #include "gc/Marking.h"
++#include "js/AutoByteString.h"
+ #include "util/Text.h"
+ #include "vm/JSContext.h"
+ #include "vm/SymbolType.h"
+ #include "vm/Xdr.h"
+ 
+ #include "gc/AtomMarking-inl.h"
+ #include "vm/JSCompartment-inl.h"
+ #include "vm/JSContext-inl.h"
+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
+@@ -32,16 +32,17 @@
+ #include "jspubtd.h"
+ #include "jstypes.h"
+ 
+ #include "builtin/String.h"
+ #include "gc/FreeOp.h"
+ #include "gc/Marking.h"
+ #include "jit/Ion.h"
+ #include "jit/PcScriptCache.h"
++#include "js/AutoByteString.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Printf.h"
+ #include "util/DoubleToString.h"
+ #include "util/NativeStack.h"
+ #include "util/Windows.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/ErrorReporting.h"
+ #include "vm/HelperThreads.h"
+diff --git a/js/src/vm/JSFunction-inl.h b/js/src/vm/JSFunction-inl.h
+--- a/js/src/vm/JSFunction-inl.h
++++ b/js/src/vm/JSFunction-inl.h
+@@ -10,16 +10,18 @@
+ #include "vm/JSFunction.h"
+ 
+ #include "gc/Allocator.h"
+ #include "gc/GCTrace.h"
+ #include "vm/EnvironmentObject.h"
+ 
+ #include "vm/JSObject-inl.h"
+ 
++class JSAutoByteString;
++
+ namespace js {
+ 
+ inline const char*
+ GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
+ {
+     if (JSAtom* name = fun->explicitName())
+         return bytes->encodeLatin1(cx, name);
+     return js_anonymous_str;
+diff --git a/js/src/vm/JSFunction.cpp b/js/src/vm/JSFunction.cpp
+--- a/js/src/vm/JSFunction.cpp
++++ b/js/src/vm/JSFunction.cpp
+@@ -26,16 +26,17 @@
+ #include "builtin/SelfHostingDefines.h"
+ #include "builtin/String.h"
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/TokenStream.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/Ion.h"
++#include "js/AutoByteString.h"
+ #include "js/CallNonGenericMethod.h"
+ #include "js/Proxy.h"
+ #include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/AsyncIteration.h"
+ #include "vm/Debugger.h"
+diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp
+--- a/js/src/vm/JSObject.cpp
++++ b/js/src/vm/JSObject.cpp
+@@ -30,16 +30,17 @@
+ #endif
+ #include "builtin/Eval.h"
+ #include "builtin/Object.h"
+ #include "builtin/String.h"
+ #include "builtin/Symbol.h"
+ #include "frontend/BytecodeCompiler.h"
+ #include "gc/Policy.h"
+ #include "jit/BaselineJIT.h"
++#include "js/AutoByteString.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/Proxy.h"
+ #include "js/UbiNode.h"
+ #include "js/UniquePtr.h"
+ #include "js/Wrapper.h"
+ #include "util/Text.h"
+ #include "util/Windows.h"
+ #include "vm/ArgumentsObject.h"
+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
+@@ -7,16 +7,17 @@
+ #include "vm/NativeObject-inl.h"
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Casting.h"
+ #include "mozilla/CheckedInt.h"
+ #include "mozilla/DebugOnly.h"
+ 
+ #include "gc/Marking.h"
++#include "js/AutoByteString.h"
+ #include "js/Value.h"
+ #include "vm/Debugger.h"
+ #include "vm/TypedArrayObject.h"
+ #include "vm/UnboxedObject.h"
+ 
+ #include "gc/Nursery-inl.h"
+ #include "vm/ArrayObject-inl.h"
+ #include "vm/EnvironmentObject-inl.h"
+diff --git a/js/src/vm/Probes.cpp b/js/src/vm/Probes.cpp
+--- a/js/src/vm/Probes.cpp
++++ b/js/src/vm/Probes.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  * vim: set ts=8 sts=4 et sw=4 tw=99:
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "vm/Probes-inl.h"
+ 
++#include "js/AutoByteString.h"
+ #include "vm/JSContext.h"
+ 
+ #ifdef INCLUDE_MOZILLA_DTRACE
+ #include "vm/JSScript-inl.h"
+ #endif
+ 
+ #define TYPEOF(cx,v)    (v.isNull() ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
+ 
+diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
+--- a/js/src/vm/Scope.cpp
++++ b/js/src/vm/Scope.cpp
+@@ -9,16 +9,17 @@
+ #include "mozilla/ScopeExit.h"
+ 
+ #include <memory>
+ #include <new>
+ 
+ #include "builtin/ModuleObject.h"
+ #include "gc/Allocator.h"
+ #include "gc/FreeOp.h"
++#include "js/AutoByteString.h"
+ #include "util/StringBuffer.h"
+ #include "vm/EnvironmentObject.h"
+ #include "vm/JSScript.h"
+ #include "wasm/WasmInstance.h"
+ 
+ #include "gc/ObjectKind-inl.h"
+ #include "vm/Shape-inl.h"
+ 
+diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
+--- a/js/src/vm/SelfHosting.cpp
++++ b/js/src/vm/SelfHosting.cpp
+@@ -34,16 +34,17 @@
+ #include "builtin/String.h"
+ #include "builtin/TypedObject.h"
+ #include "builtin/WeakMapObject.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "jit/AtomicOperations.h"
+ #include "jit/InlinableNatives.h"
++#include "js/AutoByteString.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Date.h"
+ #include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "vm/ArgumentsObject.h"
+ #include "vm/Compression.h"
+ #include "vm/GeneratorObject.h"
+diff --git a/js/src/vm/StringType.cpp b/js/src/vm/StringType.cpp
+--- a/js/src/vm/StringType.cpp
++++ b/js/src/vm/StringType.cpp
+@@ -14,16 +14,17 @@
+ #include "mozilla/RangedPtr.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ 
+ #include "gc/GCInternals.h"
+ #include "gc/Marking.h"
+ #include "gc/Nursery.h"
++#include "js/AutoByteString.h"
+ #include "js/StableStringChars.h"
+ #include "js/UbiNode.h"
+ #include "util/StringBuffer.h"
+ #include "vm/GeckoProfiler.h"
+ 
+ #include "vm/GeckoProfiler-inl.h"
+ #include "vm/JSCompartment-inl.h"
+ #include "vm/JSContext-inl.h"
+diff --git a/js/src/vm/StringType.h b/js/src/vm/StringType.h
+--- a/js/src/vm/StringType.h
++++ b/js/src/vm/StringType.h
+@@ -21,16 +21,17 @@
+ #include "gc/Nursery.h"
+ #include "gc/Rooting.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/RootingAPI.h"
+ #include "js/UniquePtr.h"
+ #include "util/Text.h"
+ #include "vm/Printer.h"
+ 
++class JSAutoByteString;
+ class JSDependentString;
+ class JSExtensibleString;
+ class JSExternalString;
+ class JSInlineString;
+ class JSRope;
+ 
+ namespace JS {
+ 
+diff --git a/js/src/vm/UbiNodeCensus.cpp b/js/src/vm/UbiNodeCensus.cpp
+--- a/js/src/vm/UbiNodeCensus.cpp
++++ b/js/src/vm/UbiNodeCensus.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  * vim: set ts=8 sts=4 et sw=4 tw=99:
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "js/UbiNodeCensus.h"
+ 
++#include "js/AutoByteString.h"
+ #include "js/StableStringChars.h"
+ #include "util/Text.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ 
+diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h
+--- a/js/src/vm/Xdr.h
++++ b/js/src/vm/Xdr.h
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef vm_Xdr_h
+ #define vm_Xdr_h
+ 
+ #include "mozilla/EndianUtils.h"
+ #include "mozilla/TypeTraits.h"
+ 
++#include "jsapi.h"
+ #include "jsfriendapi.h"
+ #include "NamespaceImports.h"
+ 
+ #include "js/TypeDecls.h"
+ #include "vm/JSAtom.h"
+ 
+ namespace js {
+ 
+diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
+--- a/js/src/wasm/AsmJS.cpp
++++ b/js/src/wasm/AsmJS.cpp
+@@ -28,16 +28,17 @@
+ #include "jsmath.h"
+ #include "jsutil.h"
+ 
+ #include "builtin/SIMD.h"
+ #include "builtin/String.h"
+ #include "frontend/Parser.h"
+ #include "gc/Policy.h"
+ #include "jit/AtomicOperations.h"
++#include "js/AutoByteString.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/Printf.h"
+ #include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "vm/ErrorReporting.h"
+ #include "vm/SelfHosting.h"
+diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp
+--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
++++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
+@@ -12,16 +12,17 @@
+ #ifdef ANDROID
+ #include <android/log.h>
+ #endif
+ #ifdef XP_WIN
+ #include <windows.h>
+ #endif
+ 
+ #include "jsapi.h"
++#include "js/AutoByteString.h"
+ #include "js/Printf.h"
+ #include "nsCOMPtr.h"
+ #include "nsAutoPtr.h"
+ #include "nsExceptionHandler.h"
+ #include "nsIComponentManager.h"
+ #include "mozilla/Module.h"
+ #include "nsIFile.h"
+ #include "mozJSComponentLoader.h"
+diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp
+--- a/js/xpconnect/src/Sandbox.cpp
++++ b/js/xpconnect/src/Sandbox.cpp
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ /*
+  * The Components.Sandbox object.
+  */
+ 
+ #include "AccessCheck.h"
+ #include "jsfriendapi.h"
++#include "js/AutoByteString.h"
+ #include "js/Proxy.h"
+ #include "js/StructuredClone.h"
+ #include "nsContentUtils.h"
+ #include "nsGlobalWindow.h"
+ #include "nsIException.h" // for nsIStackFrame
+ #include "nsIScriptContext.h"
+ #include "nsIScriptObjectPrincipal.h"
+ #include "nsIURI.h"
+diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
+--- a/js/xpconnect/src/XPCComponents.cpp
++++ b/js/xpconnect/src/XPCComponents.cpp
+@@ -10,16 +10,17 @@
+ #include "xpc_make_class.h"
+ #include "XPCJSWeakReference.h"
+ #include "WrapperFactory.h"
+ #include "nsJSUtils.h"
+ #include "mozJSComponentLoader.h"
+ #include "nsContentUtils.h"
+ #include "nsCycleCollector.h"
+ #include "jsfriendapi.h"
++#include "js/AutoByteString.h"
+ #include "js/SavedFrameAPI.h"
+ #include "js/StructuredClone.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
+ #include "mozilla/Preferences.h"
+ #include "nsJSEnvironment.h"
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/ResultExtensions.h"
+diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp
+--- a/js/xpconnect/src/XPCConvert.cpp
++++ b/js/xpconnect/src/XPCConvert.cpp
+@@ -17,16 +17,17 @@
+ #include "nsQueryObject.h"
+ #include "nsScriptError.h"
+ #include "WrapperFactory.h"
+ 
+ #include "nsWrapperCacheInlines.h"
+ 
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
++#include "js/AutoByteString.h"
+ #include "js/CharacterEncoding.h"
+ 
+ #include "mozilla/dom/BindingUtils.h"
+ #include "mozilla/dom/DOMException.h"
+ #include "mozilla/dom/PrimitiveConversions.h"
+ #include "mozilla/dom/Promise.h"
+ #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
+ 
+diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp
+--- a/js/xpconnect/src/XPCShellImpl.cpp
++++ b/js/xpconnect/src/XPCShellImpl.cpp
+@@ -2,16 +2,17 @@
+ /* vim: set ts=8 sts=4 et sw=4 tw=99: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "nsXULAppAPI.h"
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
++#include "js/AutoByteString.h"
+ #include "js/Printf.h"
+ #include "mozilla/ChaosMode.h"
+ #include "mozilla/dom/ScriptSettings.h"
+ #include "mozilla/Preferences.h"
+ #include "nsServiceManagerUtils.h"
+ #include "nsComponentManagerUtils.h"
+ #include "nsExceptionHandler.h"
+ #include "nsIServiceManager.h"
+diff --git a/js/xpconnect/src/XPCThrower.cpp b/js/xpconnect/src/XPCThrower.cpp
+--- a/js/xpconnect/src/XPCThrower.cpp
++++ b/js/xpconnect/src/XPCThrower.cpp
+@@ -3,16 +3,17 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ /* Code for throwing errors into JavaScript. */
+ 
+ #include "xpcprivate.h"
+ #include "XPCWrapper.h"
++#include "js/AutoByteString.h"
+ #include "js/Printf.h"
+ #include "mozilla/dom/BindingUtils.h"
+ #include "mozilla/dom/DOMException.h"
+ #include "mozilla/dom/Exceptions.h"
+ #include "nsString.h"
+ 
+ using namespace mozilla;
+ using namespace mozilla::dom;
+diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
++++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+@@ -7,16 +7,17 @@
+ /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
+ 
+ #include "xpcprivate.h"
+ #include "xpc_make_class.h"
+ #include "mozilla/dom/BindingUtils.h"
+ #include "mozilla/Preferences.h"
+ #include "nsIAddonInterposition.h"
+ #include "AddonWrapper.h"
++#include "js/AutoByteString.h"
+ #include "js/Class.h"
+ #include "js/Printf.h"
+ 
+ using namespace mozilla;
+ using namespace JS;
+ 
+ /***************************************************************************/
+ 
+diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h
+--- a/js/xpconnect/wrappers/XrayWrapper.h
++++ b/js/xpconnect/wrappers/XrayWrapper.h
+@@ -6,16 +6,17 @@
+ 
+ #ifndef XrayWrapper_h
+ #define XrayWrapper_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+ #include "WrapperFactory.h"
+ 
++#include "jsapi.h"
+ #include "js/Proxy.h"
+ #include "js/Wrapper.h"
+ 
+ // Slot where Xray functions for Web IDL methods store a pointer to
+ // the Xray wrapper they're associated with.
+ #define XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT 0
+ // Slot where in debug builds Xray functions for Web IDL methods store
+ // a pointer to their themselves, just so we can assert that they're the
+diff --git a/toolkit/components/mozintl/MozIntlHelper.cpp b/toolkit/components/mozintl/MozIntlHelper.cpp
+--- a/toolkit/components/mozintl/MozIntlHelper.cpp
++++ b/toolkit/components/mozintl/MozIntlHelper.cpp
+@@ -1,14 +1,15 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "MozIntlHelper.h"
++#include "jsapi.h"
+ #include "js/Wrapper.h"
+ #include "mozilla/ModuleUtils.h"
+ 
+ #define MOZ_MOZINTLHELPER_CID \
+   { 0xb43c96be, 0x2b3a, 0x4dc4, { 0x90, 0xe9, 0xb0, 0x6d, 0x34, 0x21, 0x9b, 0x68 } }
+ 
+ using namespace mozilla;
+ 

+ 29 - 0
frg/work-js/mozilla-release/patches/1033916-2-63a1.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Jan de Mooij <jdemooij@mozilla.com>
+# Date 1534838003 -7200
+# Node ID b56e88c1b06df751b5c9d8ce9589373aa2bb01ce
+# Parent  6c3db80981da2613b3e58c4904dec3504b7476d8
+Bug 1033916 followup - Fix SpiderMonkey Rust bindings by including jsapi.h in wrapper.hpp instead of relying on jsfriendapi.h doing it. r=me
+
+diff --git a/js/rust/etc/wrapper.hpp b/js/rust/etc/wrapper.hpp
+--- a/js/rust/etc/wrapper.hpp
++++ b/js/rust/etc/wrapper.hpp
+@@ -6,16 +6,17 @@
+ 
+ #include <stdint.h>
+ #ifndef _MSC_VER
+ #include <unistd.h>
+ #endif
+ 
+ typedef uint32_t HashNumber;
+ 
++#include "jsapi.h"
+ #include "jsfriendapi.h"
+ #include "js/Conversions.h"
+ #include "js/Initialization.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/StructuredClone.h"
+ 
+ // Replacements for types that are too difficult for rust-bindgen.
+ 
+

+ 1431 - 0
frg/work-js/mozilla-release/patches/1040316-63a1.patch

@@ -0,0 +1,1431 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1534776284 25200
+# Node ID 6d10eda7f12de64044246e544d581537f30f8998
+# Parent  e158e3d76ab16f5d234397ba088038cc21b1e95a
+Bug 1040316 - Move AutoStableStringChars out of friendapi into public API.  r=jandem
+
+diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
+--- a/dom/base/nsJSUtils.h
++++ b/dom/base/nsJSUtils.h
+@@ -15,16 +15,17 @@
+  */
+ 
+ #include "mozilla/Assertions.h"
+ 
+ #include "GeckoProfiler.h"
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
+ #include "js/Conversions.h"
++#include "js/StableStringChars.h"
+ #include "nsString.h"
+ 
+ class nsIScriptContext;
+ class nsIScriptElement;
+ class nsIScriptGlobalObject;
+ class nsXBLPrototypeBinding;
+ 
+ namespace mozilla {
+@@ -216,17 +217,17 @@ public:
+ 
+   static void ResetTimeZone();
+ };
+ 
+ template<typename T>
+ inline bool
+ AssignJSString(JSContext *cx, T &dest, JSString *s)
+ {
+-  size_t len = js::GetStringLength(s);
++  size_t len = JS::GetStringLength(s);
+   static_assert(js::MaxStringLength < (1 << 28),
+                 "Shouldn't overflow here or in SetCapacity");
+   if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
+     JS_ReportOutOfMemory(cx);
+     return false;
+   }
+   return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
+ }
+diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
+--- a/dom/bindings/BindingUtils.cpp
++++ b/dom/bindings/BindingUtils.cpp
+@@ -12,16 +12,17 @@
+ #include "mozilla/Assertions.h"
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Preferences.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/UseCounter.h"
+ 
+ #include "AccessCheck.h"
++#include "js/StableStringChars.h"
+ #include "jsfriendapi.h"
+ #include "nsContentCreatorFunctions.h"
+ #include "nsContentUtils.h"
+ #include "nsGlobalWindow.h"
+ #include "nsHTMLTags.h"
+ #include "nsIDocShell.h"
+ #include "nsIDOMGlobalPropertyInitializer.h"
+ #include "nsIPermissionManager.h"
+@@ -2759,17 +2760,17 @@ ConvertJSValueToByteString(JSContext* cx
+       // terminator.
+       char badCharArray[6];
+       static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
+       SprintfLiteral(badCharArray, "%d", badChar);
+       ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
+       return false;
+     }
+   } else {
+-    length = js::GetStringLength(s);
++    length = JS::GetStringLength(s);
+   }
+ 
+   static_assert(js::MaxStringLength < UINT32_MAX,
+                 "length+1 shouldn't overflow");
+ 
+   if (!result.SetLength(length, fallible)) {
+     return false;
+   }
+diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp
+--- a/dom/script/ScriptSettings.cpp
++++ b/dom/script/ScriptSettings.cpp
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "mozilla/dom/ScriptSettings.h"
+ #include "mozilla/ThreadLocal.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/CycleCollectedJSContext.h"
+ 
+ #include "jsapi.h"
++#include "js/StableStringChars.h"
+ #include "xpcpublic.h"
+ #include "nsIGlobalObject.h"
+ #include "nsIDocShell.h"
+ #include "nsIScriptGlobalObject.h"
+ #include "nsIScriptContext.h"
+ #include "nsContentUtils.h"
+ #include "nsGlobalWindow.h"
+ #include "nsPIDOMWindow.h"
+@@ -717,17 +718,17 @@ AutoEntryScript::DocshellEntryMonitor::E
+       !window->GetDocShell()->GetRecordProfileTimelineMarkers()) {
+     return;
+   }
+ 
+   nsCOMPtr<nsIDocShell> docShellForJSRunToCompletion = window->GetDocShell();
+   nsString filename;
+   uint32_t lineNumber = 0;
+ 
+-  js::AutoStableStringChars functionName(aCx);
++  JS::AutoStableStringChars functionName(aCx);
+   if (rootedFunction) {
+     JS::Rooted<JSString*> displayId(aCx, JS_GetFunctionDisplayId(rootedFunction));
+     if (displayId) {
+       if (!functionName.initTwoByte(aCx, displayId)) {
+         JS_ClearPendingException(aCx);
+         return;
+       }
+     }
+diff --git a/js/public/StableStringChars.h b/js/public/StableStringChars.h
+new file mode 100644
+--- /dev/null
++++ b/js/public/StableStringChars.h
+@@ -0,0 +1,123 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++/*
++ * Safely access the contents of a string even as GC can cause the string's
++ * contents to move around in memory.
++ */
++
++#ifndef js_StableStringChars_h
++#define js_StableStringChars_h
++
++#include "mozilla/Assertions.h" // MOZ_ASSERT
++#include "mozilla/Attributes.h" // MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS, MOZ_MUST_USE
++#include "mozilla/Maybe.h" // mozilla::Maybe
++#include "mozilla/Range.h" // mozilla::Range
++
++#include <stddef.h> // size_t
++#include <stdint.h> // uint8_t
++
++#include "jstypes.h" // JS_FRIEND_API
++
++#include "js/HeapAPI.h" // JS::shadow::String
++#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
++#include "js/TypeDecls.h" // JSContext, JS::Latin1Char, JSString
++#include "js/Vector.h" // js::Vector
++
++class JSLinearString;
++
++namespace JS {
++
++MOZ_ALWAYS_INLINE size_t
++GetStringLength(JSString* s)
++{
++    return reinterpret_cast<shadow::String*>(s)->length();
++}
++
++/**
++ * This class provides safe access to a string's chars across a GC. Once
++ * we allocate strings and chars in the nursery (bug 903519), this class
++ * will have to make a copy of the string's chars if they are allocated
++ * in the nursery, so it's best to avoid using this class unless you really
++ * need it. It's usually more efficient to use the latin1Chars/twoByteChars
++ * JSString methods and often the code can be rewritten so that only indexes
++ * instead of char pointers are used in parts of the code that can GC.
++ */
++class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) final
++{
++    /*
++     * When copying string char, use this many bytes of inline storage.  This is
++     * chosen to allow the inline string types to be copied without allocating.
++     * This is asserted in AutoStableStringChars::allocOwnChars.
++     */
++    static const size_t InlineCapacity = 24;
++
++    /* Ensure the string is kept alive while we're using its chars. */
++    Rooted<JSString*> s_;
++    MOZ_INIT_OUTSIDE_CTOR union {
++        const char16_t* twoByteChars_;
++        const Latin1Char* latin1Chars_;
++    };
++    mozilla::Maybe<js::Vector<uint8_t, InlineCapacity>> ownChars_;
++    enum State { Uninitialized, Latin1, TwoByte };
++    State state_;
++
++  public:
++    explicit AutoStableStringChars(JSContext* cx)
++      : s_(cx), state_(Uninitialized)
++    {}
++
++    MOZ_MUST_USE bool init(JSContext* cx, JSString* s);
++
++    /* Like init(), but Latin1 chars are inflated to TwoByte. */
++    MOZ_MUST_USE bool initTwoByte(JSContext* cx, JSString* s);
++
++    bool isLatin1() const { return state_ == Latin1; }
++    bool isTwoByte() const { return state_ == TwoByte; }
++
++    const Latin1Char* latin1Chars() const {
++        MOZ_ASSERT(state_ == Latin1);
++        return latin1Chars_;
++    }
++    const char16_t* twoByteChars() const {
++        MOZ_ASSERT(state_ == TwoByte);
++        return twoByteChars_;
++    }
++
++    mozilla::Range<const Latin1Char> latin1Range() const {
++        MOZ_ASSERT(state_ == Latin1);
++        return mozilla::Range<const Latin1Char>(latin1Chars_, GetStringLength(s_));
++    }
++
++    mozilla::Range<const char16_t> twoByteRange() const {
++        MOZ_ASSERT(state_ == TwoByte);
++        return mozilla::Range<const char16_t>(twoByteChars_,
++                                              GetStringLength(s_));
++    }
++
++    /* If we own the chars, transfer ownership to the caller. */
++    bool maybeGiveOwnershipToCaller() {
++        MOZ_ASSERT(state_ != Uninitialized);
++        if (!ownChars_.isSome() || !ownChars_->extractRawBuffer())
++            return false;
++        state_ = Uninitialized;
++        ownChars_.reset();
++        return true;
++    }
++
++  private:
++    AutoStableStringChars(const AutoStableStringChars& other) = delete;
++    void operator=(const AutoStableStringChars& other) = delete;
++
++    bool baseIsInline(Handle<JSLinearString*> linearString);
++    template <typename T> T* allocOwnChars(JSContext* cx, size_t count);
++    bool copyLatin1Chars(JSContext* cx, Handle<JSLinearString*> linearString);
++    bool copyTwoByteChars(JSContext* cx, Handle<JSLinearString*> linearString);
++    bool copyAndInflateLatin1Chars(JSContext*, Handle<JSLinearString*> linearString);
++};
++
++} // namespace JS
++
++#endif /* js_StableStringChars_h */
+diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp
+--- a/js/src/builtin/Eval.cpp
++++ b/js/src/builtin/Eval.cpp
+@@ -6,30 +6,32 @@
+ 
+ #include "builtin/Eval.h"
+ 
+ #include "mozilla/HashFunctions.h"
+ #include "mozilla/Range.h"
+ 
+ #include "frontend/BytecodeCompiler.h"
+ #include "gc/HashUtil.h"
++#include "js/StableStringChars.h"
+ #include "vm/Debugger.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSONParser.h"
+ 
+ #include "vm/Interpreter-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::AddToHash;
+ using mozilla::HashString;
+ using mozilla::RangedPtr;
+ 
+ using JS::AutoCheckCannotGC;
++using JS::AutoStableStringChars;
+ 
+ // We should be able to assert this for *any* fp->environmentChain().
+ static void
+ AssertInnerizedEnvironmentChain(JSContext* cx, JSObject& env)
+ {
+ #ifdef DEBUG
+     RootedObject obj(cx);
+     for (obj = &env; obj; obj = obj->enclosingEnvironment())
+diff --git a/js/src/builtin/JSON.cpp b/js/src/builtin/JSON.cpp
+--- a/js/src/builtin/JSON.cpp
++++ b/js/src/builtin/JSON.cpp
+@@ -14,16 +14,17 @@
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "builtin/Array.h"
+ #ifdef ENABLE_BIGINT
+ #include "builtin/BigInt.h"
+ #endif
+ #include "builtin/String.h"
++#include "js/StableStringChars.h"
+ #include "util/StringBuffer.h"
+ #include "vm/Interpreter.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/JSONParser.h"
+ 
+ #include "builtin/Array-inl.h"
+@@ -33,16 +34,18 @@
+ 
+ using namespace js;
+ using namespace js::gc;
+ 
+ using mozilla::IsFinite;
+ using mozilla::Maybe;
+ using mozilla::RangedPtr;
+ 
++using JS::AutoStableStringChars;
++
+ const Class js::JSONClass = {
+     js_JSON_str,
+     JSCLASS_HAS_CACHED_PROTO(JSProto_JSON)
+ };
+ 
+ /* ES5 15.12.3 Quote.
+  * Requires that the destination has enough space allocated for src after escaping
+  * (that is, `2 + 6 * (srcEnd - srcBegin)` characters).
+diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
+--- a/js/src/builtin/ReflectParse.cpp
++++ b/js/src/builtin/ReflectParse.cpp
+@@ -14,26 +14,28 @@
+ 
+ #include "jspubtd.h"
+ 
+ #include "builtin/Array.h"
+ #include "builtin/Reflect.h"
+ #include "frontend/Parser.h"
+ #include "frontend/TokenStream.h"
+ #include "js/CharacterEncoding.h"
++#include "js/StableStringChars.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSObject.h"
+ #include "vm/RegExpObject.h"
+ 
+ #include "frontend/ParseNode-inl.h"
+ #include "vm/JSObject-inl.h"
+ 
+ using namespace js;
+ using namespace js::frontend;
+ 
++using JS::AutoStableStringChars;
+ using JS::AutoValueArray;
+ using mozilla::DebugOnly;
+ 
+ enum ASTType {
+     AST_ERROR = -1,
+ #define ASTDEF(ast, str, method) ast,
+ #include "jsast.tbl"
+ #undef ASTDEF
+diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
+--- a/js/src/builtin/String.cpp
++++ b/js/src/builtin/String.cpp
+@@ -27,16 +27,17 @@
+ 
+ #include "builtin/Array.h"
+ #include "builtin/Boolean.h"
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/RegExp.h"
+ #include "jit/InlinableNatives.h"
+ #include "js/Conversions.h"
++#include "js/StableStringChars.h"
+ #include "js/UniquePtr.h"
+ #if ENABLE_INTL_API
+ # include "unicode/uchar.h"
+ # include "unicode/unorm2.h"
+ #endif
+ #include "util/StringBuffer.h"
+ #include "util/Unicode.h"
+ #include "vm/BytecodeUtil.h"
+@@ -64,16 +65,17 @@ using JS::SymbolCode;
+ 
+ using mozilla::CheckedInt;
+ using mozilla::IsNaN;
+ using mozilla::IsSame;
+ using mozilla::PodCopy;
+ using mozilla::RangedPtr;
+ 
+ using JS::AutoCheckCannotGC;
++using JS::AutoStableStringChars;
+ 
+ static JSLinearString*
+ ArgToLinearString(JSContext* cx, const CallArgs& args, unsigned argno)
+ {
+     if (argno >= args.length())
+         return cx->names().undefined;
+ 
+     JSString* str = ToString<CanGC>(cx, args[argno]);
+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
+@@ -38,16 +38,17 @@
+ #include "irregexp/RegExpParser.h"
+ #endif
+ #include "gc/Heap.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/JitRealm.h"
+ #include "js/Debug.h"
+ #include "js/HashTable.h"
++#include "js/StableStringChars.h"
+ #include "js/StructuredClone.h"
+ #include "js/UbiNode.h"
+ #include "js/UbiNodeBreadthFirst.h"
+ #include "js/UbiNodeShortestPaths.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+@@ -80,16 +81,18 @@
+ #include "vm/NativeObject-inl.h"
+ #include "vm/StringType-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::ArrayLength;
+ using mozilla::Maybe;
+ 
++using JS::AutoStableStringChars;
++
+ // If fuzzingSafe is set, remove functionality that could cause problems with
+ // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
+ mozilla::Atomic<bool> fuzzingSafe(false);
+ 
+ // If disableOOMFunctions is set, disable functionality that causes artificial
+ // OOM conditions.
+ static mozilla::Atomic<bool> disableOOMFunctions(false);
+ 
+diff --git a/js/src/builtin/intl/Collator.cpp b/js/src/builtin/intl/Collator.cpp
+--- a/js/src/builtin/intl/Collator.cpp
++++ b/js/src/builtin/intl/Collator.cpp
+@@ -12,26 +12,29 @@
+ 
+ #include "jsapi.h"
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "builtin/intl/SharedIntlData.h"
+ #include "gc/FreeOp.h"
++#include "js/StableStringChars.h"
+ #include "js/TypeDecls.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/Runtime.h"
+ #include "vm/StringType.h"
+ 
+ #include "vm/JSObject-inl.h"
+ 
+ using namespace js;
+ 
++using JS::AutoStableStringChars;
++
+ using js::intl::GetAvailableLocales;
+ using js::intl::IcuLocale;
+ using js::intl::ReportInternalError;
+ using js::intl::SharedIntlData;
+ using js::intl::StringsAreEqual;
+ 
+ const ClassOps CollatorObject::classOps_ = {
+     nullptr, /* addProperty */
+diff --git a/js/src/builtin/intl/DateTimeFormat.cpp b/js/src/builtin/intl/DateTimeFormat.cpp
+--- a/js/src/builtin/intl/DateTimeFormat.cpp
++++ b/js/src/builtin/intl/DateTimeFormat.cpp
+@@ -14,26 +14,28 @@
+ #include "jsfriendapi.h"
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "builtin/intl/SharedIntlData.h"
+ #include "builtin/intl/TimeZoneDataGenerated.h"
+ #include "gc/FreeOp.h"
++#include "js/StableStringChars.h"
+ #include "vm/DateTime.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/Runtime.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ 
+ using namespace js;
+ 
++using JS::AutoStableStringChars;
+ using JS::ClippedTime;
+ using JS::TimeClip;
+ 
+ using js::intl::CallICU;
+ using js::intl::DateTimeFormatOptions;
+ using js::intl::GetAvailableLocales;
+ using js::intl::IcuLocale;
+ using js::intl::INITIAL_CHAR_BUFFER_SIZE;
+diff --git a/js/src/builtin/intl/IntlObject.cpp b/js/src/builtin/intl/IntlObject.cpp
+--- a/js/src/builtin/intl/IntlObject.cpp
++++ b/js/src/builtin/intl/IntlObject.cpp
+@@ -17,28 +17,31 @@
+ #include "builtin/intl/Collator.h"
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/DateTimeFormat.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/NumberFormat.h"
+ #include "builtin/intl/PluralRules.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "js/Class.h"
++#include "js/StableStringChars.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/StringType.h"
+ 
+ #include "vm/JSObject-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::Range;
+ using mozilla::RangedPtr;
+ 
++using JS::AutoStableStringChars;
++
+ using js::intl::CallICU;
+ using js::intl::DateTimeFormatOptions;
+ using js::intl::IcuLocale;
+ 
+ /******************** Intl ********************/
+ 
+ bool
+ js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
+diff --git a/js/src/builtin/intl/NumberFormat.cpp b/js/src/builtin/intl/NumberFormat.cpp
+--- a/js/src/builtin/intl/NumberFormat.cpp
++++ b/js/src/builtin/intl/NumberFormat.cpp
+@@ -16,16 +16,17 @@
+ #include <stdint.h>
+ 
+ #include "builtin/intl/CommonFunctions.h"
+ #include "builtin/intl/ICUStubs.h"
+ #include "builtin/intl/ScopedICUObject.h"
+ #include "ds/Sort.h"
+ #include "gc/FreeOp.h"
+ #include "js/RootingAPI.h"
++#include "js/StableStringChars.h"
+ #include "js/TypeDecls.h"
+ #include "vm/JSContext.h"
+ #include "vm/SelfHosting.h"
+ #include "vm/Stack.h"
+ 
+ #include "vm/JSObject-inl.h"
+ 
+ using namespace js;
+@@ -35,16 +36,18 @@ using mozilla::IsFinite;
+ using mozilla::IsNaN;
+ using mozilla::IsNegativeZero;
+ 
+ using js::intl::CallICU;
+ using js::intl::DateTimeFormatOptions;
+ using js::intl::GetAvailableLocales;
+ using js::intl::IcuLocale;
+ 
++using JS::AutoStableStringChars;
++
+ const ClassOps NumberFormatObject::classOps_ = {
+     nullptr, /* addProperty */
+     nullptr, /* delProperty */
+     nullptr, /* enumerate */
+     nullptr, /* newEnumerate */
+     nullptr, /* resolve */
+     nullptr, /* mayResolve */
+     NumberFormatObject::finalize
+diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp
+--- a/js/src/ctypes/CTypes.cpp
++++ b/js/src/ctypes/CTypes.cpp
+@@ -35,30 +35,32 @@
+ #include "jsnum.h"
+ 
+ #include "builtin/TypedObject.h"
+ #include "ctypes/Library.h"
+ #include "gc/FreeOp.h"
+ #include "gc/Policy.h"
+ #include "gc/Zone.h"
+ #include "jit/AtomicOperations.h"
++#include "js/StableStringChars.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
+ #include "util/Windows.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ 
+ #include "vm/JSObject-inl.h"
+ 
+ using namespace std;
+ 
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
+ 
+ using JS::AutoCheckCannotGC;
++using JS::AutoStableStringChars;
+ 
+ namespace js {
+ namespace ctypes {
+ 
+ template <typename CharT>
+ size_t
+ GetDeflatedUTF8StringLength(JSContext* maybecx, const CharT* chars,
+                             size_t nchars)
+diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp
+--- a/js/src/ctypes/Library.cpp
++++ b/js/src/ctypes/Library.cpp
+@@ -5,16 +5,19 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "ctypes/Library.h"
+ 
+ #include "prerror.h"
+ #include "prlink.h"
+ 
+ #include "ctypes/CTypes.h"
++#include "js/StableStringChars.h"
++
++using JS::AutoStableStringChars;
+ 
+ namespace js {
+ namespace ctypes {
+ 
+ /*******************************************************************************
+ ** JSAPI function prototypes
+ *******************************************************************************/
+ 
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -59,16 +59,17 @@
+ #include "jit/JitCommon.h"
+ #include "jit/JitSpewer.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Conversions.h"
+ #include "js/Date.h"
+ #include "js/Initialization.h"
+ #include "js/Proxy.h"
+ #include "js/SliceBudget.h"
++#include "js/StableStringChars.h"
+ #include "js/StructuredClone.h"
+ #include "js/Utility.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/AsyncIteration.h"
+ #include "vm/DateObject.h"
+@@ -105,16 +106,18 @@
+ 
+ using namespace js;
+ using namespace js::gc;
+ 
+ using mozilla::Maybe;
+ using mozilla::PodCopy;
+ using mozilla::Some;
+ 
++using JS::AutoStableStringChars;
++
+ #ifdef HAVE_VA_LIST_AS_ARRAY
+ #define JS_ADDRESSOF_VA_LIST(ap) ((va_list*)(ap))
+ #else
+ #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
+ #endif
+ 
+ JS_PUBLIC_API(bool)
+ JS::CallArgs::requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -15,16 +15,17 @@
+ 
+ #include "jsapi.h" // For JSAutoByteString.  See bug 1033916.
+ #include "jspubtd.h"
+ 
+ #include "js/CallArgs.h"
+ #include "js/CallNonGenericMethod.h"
+ #include "js/Class.h"
+ #include "js/HeapAPI.h"
++#include "js/StableStringChars.h"
+ #include "js/TypeDecls.h"
+ #include "js/Utility.h"
+ 
+ #ifndef JS_STACK_GROWTH_DIRECTION
+ # ifdef __hppa
+ #  define JS_STACK_GROWTH_DIRECTION (1)
+ # else
+ #  define JS_STACK_GROWTH_DIRECTION (-1)
+@@ -33,17 +34,16 @@
+ 
+ #if JS_STACK_GROWTH_DIRECTION > 0
+ # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit)))
+ #else
+ # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit)))
+ #endif
+ 
+ struct JSErrorFormatString;
+-class JSLinearString;
+ struct JSJitInfo;
+ class JSErrorReport;
+ 
+ namespace JS {
+ template <class T>
+ class Heap;
+ } /* namespace JS */
+ 
+@@ -801,22 +801,16 @@ MOZ_ALWAYS_INLINE size_t
+ GetAtomLength(JSAtom* atom)
+ {
+     return reinterpret_cast<JS::shadow::String*>(atom)->length();
+ }
+ 
+ static const uint32_t MaxStringLength = (1 << 28) - 1;
+ 
+ MOZ_ALWAYS_INLINE size_t
+-GetStringLength(JSString* s)
+-{
+-    return reinterpret_cast<JS::shadow::String*>(s)->length();
+-}
+-
+-MOZ_ALWAYS_INLINE size_t
+ GetFlatStringLength(JSFlatString* s)
+ {
+     return reinterpret_cast<JS::shadow::String*>(s)->length();
+ }
+ 
+ MOZ_ALWAYS_INLINE size_t
+ GetLinearStringLength(JSLinearString* s)
+ {
+@@ -1403,104 +1397,16 @@ typedef enum JSErrNum {
+ 
+ namespace js {
+ 
+ /* Implemented in vm/JSContext.cpp. */
+ 
+ extern JS_FRIEND_API(const JSErrorFormatString*)
+ GetErrorMessage(void* userRef, const unsigned errorNumber);
+ 
+-// AutoStableStringChars is here so we can use it in ErrorReport.  It
+-// should get moved out of here if we can manage it.  See bug 1040316.
+-
+-/**
+- * This class provides safe access to a string's chars across a GC. Once
+- * we allocate strings and chars in the nursery (bug 903519), this class
+- * will have to make a copy of the string's chars if they are allocated
+- * in the nursery, so it's best to avoid using this class unless you really
+- * need it. It's usually more efficient to use the latin1Chars/twoByteChars
+- * JSString methods and often the code can be rewritten so that only indexes
+- * instead of char pointers are used in parts of the code that can GC.
+- */
+-class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars)
+-{
+-    /*
+-     * When copying string char, use this many bytes of inline storage.  This is
+-     * chosen to allow the inline string types to be copied without allocating.
+-     * This is asserted in AutoStableStringChars::allocOwnChars.
+-     */
+-    static const size_t InlineCapacity = 24;
+-
+-    /* Ensure the string is kept alive while we're using its chars. */
+-    JS::RootedString s_;
+-    MOZ_INIT_OUTSIDE_CTOR union {
+-        const char16_t* twoByteChars_;
+-        const JS::Latin1Char* latin1Chars_;
+-    };
+-    mozilla::Maybe<Vector<uint8_t, InlineCapacity>> ownChars_;
+-    enum State { Uninitialized, Latin1, TwoByte };
+-    State state_;
+-
+-  public:
+-    explicit AutoStableStringChars(JSContext* cx)
+-      : s_(cx), state_(Uninitialized)
+-    {}
+-
+-    MOZ_MUST_USE
+-    bool init(JSContext* cx, JSString* s);
+-
+-    /* Like init(), but Latin1 chars are inflated to TwoByte. */
+-    MOZ_MUST_USE
+-    bool initTwoByte(JSContext* cx, JSString* s);
+-
+-    bool isLatin1() const { return state_ == Latin1; }
+-    bool isTwoByte() const { return state_ == TwoByte; }
+-
+-    const JS::Latin1Char* latin1Chars() const {
+-        MOZ_ASSERT(state_ == Latin1);
+-        return latin1Chars_;
+-    }
+-    const char16_t* twoByteChars() const {
+-        MOZ_ASSERT(state_ == TwoByte);
+-        return twoByteChars_;
+-    }
+-
+-    mozilla::Range<const JS::Latin1Char> latin1Range() const {
+-        MOZ_ASSERT(state_ == Latin1);
+-        return mozilla::Range<const JS::Latin1Char>(latin1Chars_,
+-                                                    GetStringLength(s_));
+-    }
+-
+-    mozilla::Range<const char16_t> twoByteRange() const {
+-        MOZ_ASSERT(state_ == TwoByte);
+-        return mozilla::Range<const char16_t>(twoByteChars_,
+-                                              GetStringLength(s_));
+-    }
+-
+-    /* If we own the chars, transfer ownership to the caller. */
+-    bool maybeGiveOwnershipToCaller() {
+-        MOZ_ASSERT(state_ != Uninitialized);
+-        if (!ownChars_.isSome() || !ownChars_->extractRawBuffer())
+-            return false;
+-        state_ = Uninitialized;
+-        ownChars_.reset();
+-        return true;
+-    }
+-
+-  private:
+-    AutoStableStringChars(const AutoStableStringChars& other) = delete;
+-    void operator=(const AutoStableStringChars& other) = delete;
+-
+-    bool baseIsInline(JS::Handle<JSLinearString*> linearString);
+-    template <typename T> T* allocOwnChars(JSContext* cx, size_t count);
+-    bool copyLatin1Chars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
+-    bool copyTwoByteChars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
+-    bool copyAndInflateLatin1Chars(JSContext*, JS::Handle<JSLinearString*> linearString);
+-};
+-
+ struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport)
+ {
+     explicit ErrorReport(JSContext* cx);
+     ~ErrorReport();
+ 
+     enum SniffingBehavior {
+         WithSideEffects,
+         NoSideEffects
+@@ -1566,17 +1472,17 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(Err
+     // Or we may need to synthesize a JSErrorReport one of our own.
+     JSErrorReport ownedReport;
+ 
+     // And we have a string to maybe keep alive that has pointers into
+     // it from ownedReport.
+     JS::RootedString str;
+ 
+     // And keep its chars alive too.
+-    AutoStableStringChars strChars;
++    JS::AutoStableStringChars strChars;
+ 
+     // And we need to root our exception value.
+     JS::RootedObject exnObject;
+ 
+     // And for our filename.
+     JSAutoByteString filename;
+ 
+     // We may have a result of error.toString().
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -148,16 +148,17 @@ EXPORTS.js += [
+     '../public/ProtoKey.h',
+     '../public/Proxy.h',
+     '../public/Realm.h',
+     '../public/RefCounted.h',
+     '../public/RequiredDefines.h',
+     '../public/Result.h',
+     '../public/RootingAPI.h',
+     '../public/SliceBudget.h',
++    '../public/StableStringChars.h',
+     '../public/Stream.h',
+     '../public/StructuredClone.h',
+     '../public/SweepingAPI.h',
+     '../public/TraceKind.h',
+     '../public/TracingAPI.h',
+     '../public/TrackedOptimizationInfo.h',
+     '../public/TypeDecls.h',
+     '../public/UbiNode.h',
+diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp
+--- a/js/src/proxy/Proxy.cpp
++++ b/js/src/proxy/Proxy.cpp
+@@ -7,31 +7,34 @@
+ #include "js/Proxy.h"
+ 
+ #include "mozilla/Attributes.h"
+ 
+ #include <string.h>
+ 
+ #include "jsapi.h"
+ 
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "proxy/DeadObjectProxy.h"
+ #include "proxy/ScriptedProxyHandler.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ #include "vm/WrapperObject.h"
+ 
+ #include "gc/Marking-inl.h"
+ #include "vm/JSAtom-inl.h"
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ 
+ using namespace js;
+ using namespace js::gc;
+ 
++using JS::AutoStableStringChars;
++
+ void
+ js::AutoEnterPolicy::reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id)
+ {
+     if (JS_IsExceptionPending(cx))
+         return;
+ 
+     if (JSID_IS_VOID(id)) {
+         ReportAccessDenied(cx);
+diff --git a/js/src/proxy/SecurityWrapper.cpp b/js/src/proxy/SecurityWrapper.cpp
+--- a/js/src/proxy/SecurityWrapper.cpp
++++ b/js/src/proxy/SecurityWrapper.cpp
+@@ -3,21 +3,24 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
+ #include "NamespaceImports.h"
+ 
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "vm/StringType.h"
+ 
+ using namespace js;
+ 
++using JS::AutoStableStringChars;
++
+ template <class Base>
+ bool
+ SecurityWrapper<Base>::enter(JSContext* cx, HandleObject wrapper, HandleId id,
+                              Wrapper::Action act, bool mayThrow, bool* bp) const
+ {
+     ReportAccessDenied(cx);
+     *bp = false;
+     return false;
+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
+@@ -73,16 +73,17 @@
+ #include "jit/Ion.h"
+ #include "jit/JitcodeMap.h"
+ #include "jit/JitRealm.h"
+ #include "jit/shared/CodeGenerator-shared.h"
+ #include "js/Debug.h"
+ #include "js/GCVector.h"
+ #include "js/Initialization.h"
+ #include "js/Printf.h"
++#include "js/StableStringChars.h"
+ #include "js/StructuredClone.h"
+ #include "js/SweepingAPI.h"
+ #include "js/Wrapper.h"
+ #include "perf/jsperf.h"
+ #include "shell/jsoptparse.h"
+ #include "shell/jsshell.h"
+ #include "shell/OSObject.h"
+ #include "threading/ConditionVariable.h"
+@@ -116,16 +117,18 @@
+ #include "vm/JSCompartment-inl.h"
+ #include "vm/JSObject-inl.h"
+ #include "vm/Stack-inl.h"
+ 
+ using namespace js;
+ using namespace js::cli;
+ using namespace js::shell;
+ 
++using JS::AutoStableStringChars;
++
+ using js::shell::RCFile;
+ 
+ using mozilla::ArrayLength;
+ using mozilla::Atomic;
+ using mozilla::MakeScopeExit;
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::NumberEqualsInt32;
+diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp
+--- a/js/src/vm/ArgumentsObject.cpp
++++ b/js/src/vm/ArgumentsObject.cpp
+@@ -5,28 +5,31 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "vm/ArgumentsObject-inl.h"
+ 
+ #include "mozilla/PodOperations.h"
+ 
+ #include "gc/FreeOp.h"
+ #include "jit/JitFrames.h"
++#include "js/StableStringChars.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/Stack.h"
+ 
+ #include "gc/Nursery-inl.h"
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ #include "vm/Stack-inl.h"
+ 
+ using namespace js;
+ using namespace js::gc;
+ 
++using JS::AutoStableStringChars;
++
+ /* static */ size_t
+ RareArgumentsData::bytesRequired(size_t numActuals)
+ {
+     size_t extraBytes = NumWordsForBitArrayOfLength(numActuals) * sizeof(size_t);
+     return offsetof(RareArgumentsData, deletedBits_) + extraBytes;
+ }
+ 
+ /* static */ RareArgumentsData*
+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
+@@ -21,16 +21,17 @@
+ #include "gc/FreeOp.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/BaselineDebugModeOSR.h"
+ #include "jit/BaselineJIT.h"
+ #include "js/Date.h"
++#include "js/StableStringChars.h"
+ #include "js/UbiNodeBreadthFirst.h"
+ #include "js/Vector.h"
+ #include "js/Wrapper.h"
+ #include "proxy/ScriptedProxyHandler.h"
+ #include "util/Text.h"
+ #include "vm/ArgumentsObject.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/AsyncIteration.h"
+@@ -49,16 +50,17 @@
+ #include "vm/GeckoProfiler-inl.h"
+ #include "vm/JSObject-inl.h"
+ #include "vm/JSScript-inl.h"
+ #include "vm/NativeObject-inl.h"
+ #include "vm/Stack-inl.h"
+ 
+ using namespace js;
+ 
++using JS::AutoStableStringChars;
+ using JS::dbg::AutoEntryMonitor;
+ using JS::dbg::Builder;
+ using js::frontend::IsIdentifier;
+ using mozilla::DebugOnly;
+ using mozilla::MakeScopeExit;
+ using mozilla::Maybe;
+ using mozilla::Some;
+ using mozilla::Nothing;
+@@ -5067,17 +5069,17 @@ Debugger::isCompilableUnit(JSContext* cx
+     if (!args[0].isString()) {
+         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+                                   "Debugger.isCompilableUnit", "string",
+                                   InformalValueTypeName(args[0]));
+         return false;
+     }
+ 
+     JSString* str = args[0].toString();
+-    size_t length = GetStringLength(str);
++    size_t length = str->length();
+ 
+     AutoStableStringChars chars(cx);
+     if (!chars.initTwoByte(cx, str))
+         return false;
+ 
+     bool result = true;
+ 
+     CompileOptions options(cx);
+diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp
+--- a/js/src/vm/JSCompartment.cpp
++++ b/js/src/vm/JSCompartment.cpp
+@@ -14,16 +14,17 @@
+ 
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/JitOptions.h"
+ #include "jit/JitRealm.h"
+ #include "js/Date.h"
+ #include "js/Proxy.h"
+ #include "js/RootingAPI.h"
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "proxy/DeadObjectProxy.h"
+ #include "vm/DateTime.h"
+ #include "vm/Debugger.h"
+ #include "vm/Iteration.h"
+ #include "vm/JSContext.h"
+ #include "vm/WrapperObject.h"
+ 
+@@ -35,16 +36,18 @@
+ #include "vm/JSScript-inl.h"
+ #include "vm/NativeObject-inl.h"
+ #include "vm/UnboxedObject-inl.h"
+ 
+ using namespace js;
+ using namespace js::gc;
+ using namespace js::jit;
+ 
++using JS::AutoStableStringChars;
++
+ using mozilla::PodArrayZero;
+ 
+ JSCompartment::JSCompartment(Zone* zone)
+   : zone_(zone),
+     runtime_(zone->runtimeFromAnyThread())
+ {}
+ 
+ ObjectRealm::ObjectRealm(JS::Zone* zone)
+diff --git a/js/src/vm/JSFunction.cpp b/js/src/vm/JSFunction.cpp
+--- a/js/src/vm/JSFunction.cpp
++++ b/js/src/vm/JSFunction.cpp
+@@ -28,16 +28,17 @@
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/TokenStream.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/Ion.h"
+ #include "js/CallNonGenericMethod.h"
+ #include "js/Proxy.h"
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "vm/AsyncFunction.h"
+ #include "vm/AsyncIteration.h"
+ #include "vm/Debugger.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/Interpreter.h"
+ #include "vm/JSAtom.h"
+@@ -59,16 +60,18 @@ using namespace js;
+ using namespace js::gc;
+ using namespace js::frontend;
+ 
+ using mozilla::ArrayLength;
+ using mozilla::CheckedInt;
+ using mozilla::Maybe;
+ using mozilla::Some;
+ 
++using JS::AutoStableStringChars;
++
+ static bool
+ fun_enumerate(JSContext* cx, HandleObject obj)
+ {
+     MOZ_ASSERT(obj->is<JSFunction>());
+ 
+     RootedId id(cx);
+     bool found;
+ 
+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
+@@ -17,16 +17,17 @@
+ #include "builtin/RegExp.h"
+ #include "frontend/TokenStream.h"
+ #include "gc/HashUtil.h"
+ #ifdef DEBUG
+ #include "irregexp/RegExpBytecode.h"
+ #endif
+ #include "irregexp/RegExpParser.h"
+ #include "jit/VMFunctions.h"
++#include "js/StableStringChars.h"
+ #include "util/StringBuffer.h"
+ #include "vm/MatchPairs.h"
+ #include "vm/RegExpStatics.h"
+ #include "vm/StringType.h"
+ #include "vm/TraceLogging.h"
+ #ifdef DEBUG
+ #include "util/Unicode.h"
+ #endif
+@@ -36,16 +37,17 @@
+ #include "vm/NativeObject-inl.h"
+ #include "vm/Shape-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::ArrayLength;
+ using mozilla::DebugOnly;
+ using mozilla::PodCopy;
++using JS::AutoStableStringChars;
+ using js::frontend::TokenStream;
+ 
+ using JS::AutoCheckCannotGC;
+ 
+ JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
+ JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
+ JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
+ JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
+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
+@@ -33,16 +33,17 @@
+ #include "jit/arm64/vixl/Simulator-vixl.h"
+ #include "jit/IonBuilder.h"
+ #include "jit/JitRealm.h"
+ #include "jit/mips32/Simulator-mips32.h"
+ #include "jit/mips64/Simulator-mips64.h"
+ #include "js/Date.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/SliceBudget.h"
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/Windows.h"
+ #include "vm/DateTime.h"
+ #include "vm/Debugger.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSObject.h"
+ #include "vm/JSScript.h"
+ #include "vm/TraceLogging.h"
+@@ -54,16 +55,17 @@
+ using namespace js;
+ using namespace js::gc;
+ 
+ using mozilla::Atomic;
+ using mozilla::DebugOnly;
+ using mozilla::NegativeInfinity;
+ using mozilla::PodZero;
+ using mozilla::PositiveInfinity;
++using JS::AutoStableStringChars;
+ using JS::DoubleNaNValue;
+ 
+ /* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
+ /* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
+ Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
+ 
+ namespace js {
+     bool gCanUseExtraThreads = true;
+diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
+--- a/js/src/vm/SelfHosting.cpp
++++ b/js/src/vm/SelfHosting.cpp
+@@ -36,16 +36,17 @@
+ #include "builtin/WeakMapObject.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "jit/AtomicOperations.h"
+ #include "jit/InlinableNatives.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Date.h"
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "vm/ArgumentsObject.h"
+ #include "vm/Compression.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/Interpreter.h"
+ #include "vm/Iteration.h"
+ #include "vm/JSCompartment.h"
+@@ -66,16 +67,17 @@
+ #include "vm/NativeObject-inl.h"
+ #include "vm/NumberObject-inl.h"
+ #include "vm/StringObject-inl.h"
+ 
+ using namespace js;
+ using namespace js::selfhosted;
+ 
+ using JS::AutoCheckCannotGC;
++using JS::AutoStableStringChars;
+ using mozilla::IsInRange;
+ using mozilla::Maybe;
+ 
+ static void
+ selfHosting_WarningReporter(JSContext* cx, JSErrorReport* report)
+ {
+     MOZ_ASSERT(report);
+     MOZ_ASSERT(JSREPORT_IS_WARNING(report->flags));
+diff --git a/js/src/vm/StringType.cpp b/js/src/vm/StringType.cpp
+--- a/js/src/vm/StringType.cpp
++++ b/js/src/vm/StringType.cpp
+@@ -14,16 +14,17 @@
+ #include "mozilla/RangedPtr.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ 
+ #include "gc/GCInternals.h"
+ #include "gc/Marking.h"
+ #include "gc/Nursery.h"
++#include "js/StableStringChars.h"
+ #include "js/UbiNode.h"
+ #include "util/StringBuffer.h"
+ #include "vm/GeckoProfiler.h"
+ 
+ #include "vm/GeckoProfiler-inl.h"
+ #include "vm/JSCompartment-inl.h"
+ #include "vm/JSContext-inl.h"
+ #include "vm/JSObject-inl.h"
+@@ -35,16 +36,17 @@ using mozilla::IsNegativeZero;
+ using mozilla::IsSame;
+ using mozilla::PodCopy;
+ using mozilla::PodEqual;
+ using mozilla::RangedPtr;
+ using mozilla::RoundUpPow2;
+ using mozilla::Unused;
+ 
+ using JS::AutoCheckCannotGC;
++using JS::AutoStableStringChars;
+ 
+ using UniqueLatin1Chars = UniquePtr<Latin1Char[], JS::FreePolicy>;
+ 
+ size_t
+ JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+ {
+     // JSRope: do nothing, we'll count all children chars when we hit the leaf strings.
+     if (isRope())
+diff --git a/js/src/vm/StringType.h b/js/src/vm/StringType.h
+--- a/js/src/vm/StringType.h
++++ b/js/src/vm/StringType.h
+@@ -27,19 +27,24 @@
+ #include "vm/Printer.h"
+ 
+ class JSDependentString;
+ class JSExtensibleString;
+ class JSExternalString;
+ class JSInlineString;
+ class JSRope;
+ 
++namespace JS {
++
++class AutoStableStringChars;
++
++} // namespace JS
++
+ namespace js {
+ 
+-class AutoStableStringChars;
+ class StaticStrings;
+ class PropertyName;
+ 
+ /* The buffer length required to contain any unsigned 32-bit integer. */
+ static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
+ 
+ } /* namespace js */
+ 
+@@ -805,17 +810,17 @@ class JSRope : public JSString
+ };
+ 
+ static_assert(sizeof(JSRope) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+ class JSLinearString : public JSString
+ {
+     friend class JSString;
+-    friend class js::AutoStableStringChars;
++    friend class JS::AutoStableStringChars;
+     friend class js::TenuringTracer;
+ 
+     /* Vacuous and therefore unimplemented. */
+     JSLinearString* ensureLinear(JSContext* cx) = delete;
+     bool isLinear() const = delete;
+     JSLinearString& asLinear() const = delete;
+ 
+   protected:
+diff --git a/js/src/vm/UbiNodeCensus.cpp b/js/src/vm/UbiNodeCensus.cpp
+--- a/js/src/vm/UbiNodeCensus.cpp
++++ b/js/src/vm/UbiNodeCensus.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  * vim: set ts=8 sts=4 et sw=4 tw=99:
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "js/UbiNodeCensus.h"
+ 
++#include "js/StableStringChars.h"
+ #include "util/Text.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/NativeObject-inl.h"
+ 
+ using namespace js;
+diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
+--- a/js/src/wasm/AsmJS.cpp
++++ b/js/src/wasm/AsmJS.cpp
+@@ -30,16 +30,17 @@
+ 
+ #include "builtin/SIMD.h"
+ #include "builtin/String.h"
+ #include "frontend/Parser.h"
+ #include "gc/Policy.h"
+ #include "jit/AtomicOperations.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/Printf.h"
++#include "js/StableStringChars.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "vm/ErrorReporting.h"
+ #include "vm/SelfHosting.h"
+ #include "vm/Time.h"
+ #include "vm/TypedArrayObject.h"
+ #include "wasm/WasmCompile.h"
+@@ -66,16 +67,17 @@ using mozilla::IsNaN;
+ using mozilla::IsNegativeZero;
+ using mozilla::IsPositiveZero;
+ using mozilla::IsPowerOfTwo;
+ using mozilla::PodEqual;
+ using mozilla::PodZero;
+ using mozilla::PositiveInfinity;
+ using mozilla::Unused;
+ using JS::AsmJSOption;
++using JS::AutoStableStringChars;
+ using JS::GenericNaN;
+ 
+ /*****************************************************************************/
+ 
+ // The asm.js valid heap lengths are precisely the WASM valid heap lengths for ARM
+ // greater or equal to MinHeapLength
+ static const size_t MinHeapLength = PageSize;
+ 

+ 617 - 0
frg/work-js/mozilla-release/patches/1426909-1-63a1.patch

@@ -0,0 +1,617 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1515695393 25200
+#      Thu Jan 11 11:29:53 2018 -0700
+# Node ID d7fcfaa2c82d744eb07a138d8fb4870bd039127f
+# Parent  f7b8c6ced658a64481bc11e04eec32c655f39916
+Bug 1426909 - Introduce a new mfbt/Utf8.h header for UTF-8-related functionality, including a UTF-8 code unit type that is compatible with, but doesn't directly interconvert with, |char|.  r=froydnj
+
+diff --git a/js/public/CharacterEncoding.h b/js/public/CharacterEncoding.h
+--- a/js/public/CharacterEncoding.h
++++ b/js/public/CharacterEncoding.h
+@@ -321,21 +321,14 @@ LossyUTF8CharsToNewLatin1CharsZ(JSContex
+ 
+ /*
+  * Returns true if all characters in the given null-terminated string are
+  * ASCII, i.e. < 0x80, false otherwise.
+  */
+ extern JS_PUBLIC_API(bool)
+ StringIsASCII(const char* s);
+ 
+-/*
+- * Returns true if the given length-delimited string is a valid UTF-8 string,
+- * false otherwise.
+- */
+-extern JS_PUBLIC_API(bool)
+-StringIsUTF8(const uint8_t* s, uint32_t length);
+-
+ } // namespace JS
+ 
+ inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); }
+ inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); }
+ 
+ #endif /* js_CharacterEncoding_h */
+diff --git a/js/src/vm/CharacterEncoding.cpp b/js/src/vm/CharacterEncoding.cpp
+--- a/js/src/vm/CharacterEncoding.cpp
++++ b/js/src/vm/CharacterEncoding.cpp
+@@ -490,48 +490,8 @@ JS::StringIsASCII(const char* s)
+ {
+     while (*s) {
+         if (*s & 0x80)
+             return false;
+         s++;
+     }
+     return true;
+ }
+-
+-bool
+-JS::StringIsUTF8(const uint8_t* s, uint32_t length)
+-{
+-    const uint8_t* limit = s + length;
+-    while (s < limit) {
+-        uint32_t len;
+-        uint32_t min;
+-        uint32_t n = *s;
+-        if ((n & 0x80) == 0) {
+-            len = 1;
+-            min = 0;
+-        } else if ((n & 0xE0) == 0xC0) {
+-            len = 2;
+-            min = 0x80;
+-            n &= 0x1F;
+-        } else if ((n & 0xF0) == 0xE0) {
+-            len = 3;
+-            min = 0x800;
+-            n &= 0x0F;
+-        } else if ((n & 0xF8) == 0xF0) {
+-            len = 4;
+-            min = 0x10000;
+-            n &= 0x07;
+-        } else {
+-            return false;
+-        }
+-        if (s + len > limit)
+-            return false;
+-        for (uint32_t i = 1; i < len; i++) {
+-            if ((s[i] & 0xC0) != 0x80)
+-                return false;
+-            n = (n << 6) | (s[i] & 0x3F);
+-        }
+-        if (n < min || (0xD800 <= n && n < 0xE000) || n >= 0x110000)
+-            return false;
+-        s += len;
+-    }
+-    return true;
+-}
+diff --git a/js/src/wasm/WasmValidate.cpp b/js/src/wasm/WasmValidate.cpp
+--- a/js/src/wasm/WasmValidate.cpp
++++ b/js/src/wasm/WasmValidate.cpp
+@@ -15,28 +15,30 @@
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ #include "wasm/WasmValidate.h"
+ 
+ #include "mozilla/CheckedInt.h"
+ #include "mozilla/Unused.h"
++#include "mozilla/Utf8.h"
+ 
+ #include "jit/JitOptions.h"
+ #include "js/Printf.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ #include "wasm/WasmOpIter.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ using namespace js::wasm;
+ 
+ using mozilla::CheckedInt;
++using mozilla::IsValidUtf8;
+ using mozilla::Unused;
+ 
+ // Decoder implementation.
+ 
+ bool
+ Decoder::failf(const char* msg, ...)
+ {
+     va_list ap;
+@@ -1185,17 +1187,17 @@ DecodeName(Decoder& d)
+ 
+     if (numBytes > MaxStringBytes)
+         return nullptr;
+ 
+     const uint8_t* bytes;
+     if (!d.readBytes(numBytes, &bytes))
+         return nullptr;
+ 
+-    if (!JS::StringIsUTF8(bytes, numBytes))
++    if (!IsValidUtf8(bytes, numBytes))
+         return nullptr;
+ 
+     UniqueChars name(js_pod_malloc<char>(numBytes + 1));
+     if (!name)
+         return nullptr;
+ 
+     memcpy(name.get(), bytes, numBytes);
+     name[numBytes] = '\0';
+diff --git a/mfbt/Utf8.cpp b/mfbt/Utf8.cpp
+new file mode 100644
+--- /dev/null
++++ b/mfbt/Utf8.cpp
+@@ -0,0 +1,79 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "mozilla/Types.h"
++#include "mozilla/Utf8.h"
++
++#include <stddef.h>
++#include <stdint.h>
++
++MFBT_API bool
++mozilla::IsValidUtf8(const void* aCodeUnits, size_t aCount)
++{
++  const auto* s = static_cast<const unsigned char*>(aCodeUnits);
++  const auto* limit = s + aCount;
++
++  while (s < limit) {
++    uint32_t n = *s++;
++
++    // If the first byte is ASCII, it's the only one in the code point.  Have a
++    // fast path that avoids all the rest of the work and looping in that case.
++    if ((n & 0x80) == 0) {
++      continue;
++    }
++
++    // The leading code unit determines the length of the next code point and
++    // the number of bits of the leading code unit that contribute to the code
++    // point's value.
++    uint_fast8_t remaining;
++    uint32_t min;
++    if ((n & 0xE0) == 0xC0) {
++      remaining = 1;
++      min = 0x80;
++      n &= 0x1F;
++    } else if ((n & 0xF0) == 0xE0) {
++      remaining = 2;
++      min = 0x800;
++      n &= 0x0F;
++    } else if ((n & 0xF8) == 0xF0) {
++      remaining = 3;
++      min = 0x10000;
++      n &= 0x07;
++    } else {
++      // UTF-8 used to have a hyper-long encoding form, but it's been removed
++      // for years now.  So in this case, the string is not valid UTF-8.
++      return false;
++    }
++
++    // If the code point would require more code units than remain, the encoding
++    // is invalid.
++    if (s + remaining > limit) {
++      return false;
++    }
++
++    for (uint_fast8_t i = 0; i < remaining; i++) {
++      // Every non-leading code unit in properly encoded UTF-8 has its high bit
++      // set and the next-highest bit unset.
++      if ((s[i] & 0xC0) != 0x80) {
++        return false;
++      }
++
++      // The code point being encoded is the concatenation of all the
++      // unconstrained bits.
++      n = (n << 6) | (s[i] & 0x3F);
++    }
++
++    // Don't consider code points that are overlong, UTF-16 surrogates, or
++    // exceed the maximum code point to be valid.
++    if (n < min || (0xD800 <= n && n < 0xE000) || n >= 0x110000) {
++      return false;
++    }
++
++    s += remaining;
++  }
++
++  return true;
++}
+diff --git a/mfbt/Utf8.h b/mfbt/Utf8.h
+new file mode 100644
+--- /dev/null
++++ b/mfbt/Utf8.h
+@@ -0,0 +1,210 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++/*
++ * UTF-8-related functionality, including a type-safe structure representing a
++ * UTF-8 code unit.
++ */
++
++#ifndef mozilla_Utf8_h
++#define mozilla_Utf8_h
++
++#include "mozilla/Types.h" // for MFBT_API
++
++#include <limits.h> // for CHAR_BIT
++#include <stddef.h> // for size_t
++#include <stdint.h> // for uint8_t
++
++namespace mozilla {
++
++union Utf8Unit;
++
++static_assert(CHAR_BIT == 8,
++              "Utf8Unit won't work so well with non-octet chars");
++
++/**
++ * A code unit within a UTF-8 encoded string.  (A code unit is the smallest
++ * unit within the Unicode encoding of a string.  For UTF-8 this is an 8-bit
++ * number; for UTF-16 it would be a 16-bit number.)
++ *
++ * This is *not* the same as a single code point: in UTF-8, non-ASCII code
++ * points are constituted by multiple code units.
++ */
++union Utf8Unit
++{
++private:
++  // Utf8Unit is a union wrapping a raw |char|.  The C++ object model and C++
++  // requirements as to how objects may be accessed with respect to their actual
++  // types (almost?) uniquely compel this choice.
++  //
++  // Our requirements for a UTF-8 code unit representation are:
++  //
++  //   1. It must be "compatible" with C++ character/string literals that use
++  //      the UTF-8 encoding.  Given a properly encoded C++ literal, you should
++  //      be able to use |Utf8Unit| and friends to access it; given |Utf8Unit|
++  //      and friends (particularly UnicodeData), you should be able to access
++  //      C++ character types for their contents.
++  //   2. |Utf8Unit| and friends must convert to/from |char| and |char*| only by
++  //      explicit operation.
++  //   3. |Utf8Unit| must participate in overload resolution and template type
++  //      equivalence (that is, given |template<class> class X|, when |X<T>| and
++  //      |X<U>| are the same type) distinctly from the C++ character types.
++  //
++  // And a few nice-to-haves (at least for the moment):
++  //
++  //   4. The representation should use unsigned numbers, to avoid undefined
++  //      behavior that can arise with signed types, and because Unicode code
++  //      points and code units are unsigned.
++  //   5. |Utf8Unit| and friends should be convertible to/from |unsigned char|
++  //      and |unsigned char*|, for APIs that (because of #4 above) use those
++  //      types as the "natural" choice for UTF-8 data.
++  //
++  // #1 requires that |Utf8Unit| "incorporate" a C++ character type: one of
++  // |{,{un,}signed} char|.[0]  |uint8_t| won't work because it might not be a
++  // C++ character type.
++  //
++  // #2 and #3 mean that |Utf8Unit| can't *be* such a type (or a typedef to one:
++  // typedefs don't generate *new* types, just type aliases).  This requires a
++  // compound type.
++  //
++  // The ultimate representation (and character type in it) is constrained by
++  // C++14 [basic.lval]p10 that defines how objects may be accessed, with
++  // respect to the dynamic type in memory and the actual type used to access
++  // them.  It reads:
++  //
++  //     If a program attempts to access the stored value of an object
++  //     through a glvalue of other than one of the following types the
++  //     behavior is undefined:
++  //
++  //       1. the dynamic type of the object,
++  //       2. a cv-qualified version of the dynamic type of the object,
++  //       ...other types irrelevant here...
++  //       3. an aggregate or union type that includes one of the
++  //          aforementioned types among its elements or non-static data
++  //          members (including, recursively, an element or non-static
++  //          data member of a subaggregate or contained union),
++  //       ...more irrelevant types...
++  //       4. a char or unsigned char type.
++  //
++  // Accessing (wrapped) UTF-8 data as |char|/|unsigned char| is allowed no
++  // matter the representation by #4.  (Briefly set aside what values are seen.)
++  // (And #2 allows |const| on either the dynamic type or the accessing type.)
++  // (|signed char| is really only useful for small signed numbers, not
++  // characters, so we ignore it.)
++  //
++  // If we interpret contents as |char|/|unsigned char| contrary to the actual
++  // type stored there, what happens?  C++14 [basic.fundamental]p1 requires
++  // character types be identically aligned/sized; C++14 [basic.fundamental]p3
++  // requires |signed char| and |unsigned char| have the same value
++  // representation.  C++ doesn't require identical bitwise representation, tho.
++  // Practically we could assume it, but this verges on C++ spec bits best not
++  // *relied* on for correctness, if possible.
++  //
++  // So we don't expose |Utf8Unit|'s contents as |unsigned char*|: only |char|
++  // and |char*|.  Instead we safely expose |unsigned char| by fully-defined
++  // *integral conversion* (C++14 [conv.integral]p2).  Integral conversion from
++  // |unsigned char| → |char| has only implementation-defined behavior.  It'd be
++  // better not to depend on that, but given twos-complement won, it should be
++  // okay.  (Also |unsigned char*| is awkward enough to work with for strings
++  // that it probably doesn't appear in string manipulation much anyway, only in
++  // places that should really use |Utf8Unit| directly.)
++  //
++  // The opposite direction -- interpreting |char| or |char*| data through
++  // |Utf8Unit| -- isn't tricky as long as |Utf8Unit| contains a |char| as
++  // decided above, using #3.  An "aggregate or union" will work that contains a
++  // |char|.  Oddly, an aggregate won't work: C++14 [dcl.init.aggr]p1 says
++  // aggregates must have "no private or protected non-static data members", and
++  // we want to keep the inner |char| hidden.  So a |struct| is out, and only
++  // |union| remains.
++  //
++  // (Enums are not "an aggregate or union type", so [maybe surprisingly] we
++  // can't make |Utf8Unit| an enum class with |char| underlying type, because we
++  // are given no license to treat |char| memory as such an |enum|'s memory.)
++  //
++  // Therefore |Utf8Unit| is a union type with a |char| non-static data member.
++  // This satisfies all our requirements.  It also supports the nice-to-haves of
++  // creating a |Utf8Unit| from an |unsigned char|, and being convertible to
++  // |unsigned char|.  It doesn't satisfy the nice-to-haves of using an
++  // |unsigned char| internally, nor of letting us wrap an existing
++  // |unsigned char| or pointer to one.  We probably *could* do these, if we
++  // were willing to rely harder on implementation-defined behaviors, but for
++  // now we privilege C++'s main character type over some conceptual purity.
++  //
++  // 0. There's a proposal for a UTF-8 character type distinct from the existing
++  //    C++ narrow character types:
++  //
++  //      http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0482r0.html
++  //
++  //    but it hasn't been standardized (and might never be), and none of the
++  //    compilers we really care about have implemented it.  Maybe someday we
++  //    can change our implementation to it without too much trouble, if we're
++  //    lucky...
++  char mValue;
++
++public:
++  explicit constexpr Utf8Unit(char aUnit)
++    : mValue(aUnit)
++  {}
++
++  explicit constexpr Utf8Unit(unsigned char aUnit)
++    : mValue(static_cast<char>(aUnit))
++  {
++    // Per the above comment, the prior cast is integral conversion with
++    // implementation-defined semantics, and we regretfully but unavoidably
++    // assume the conversion does what we want it to.
++  }
++
++  constexpr bool operator==(const Utf8Unit& aOther) const
++  {
++    return mValue == aOther.mValue;
++  }
++
++  constexpr bool operator!=(const Utf8Unit& aOther) const
++  {
++    return !(*this == aOther);
++  }
++
++  /** Convert a UTF-8 code unit to a raw char. */
++  constexpr char toChar() const
++  {
++    // Only a |char| is ever permitted to be written into this location, so this
++    // is both permissible and returns the desired value.
++    return mValue;
++  }
++
++  /** Convert a UTF-8 code unit to a raw unsigned char. */
++  constexpr unsigned char toUnsignedChar() const
++  {
++    // Per the above comment, this is well-defined integral conversion.
++    return static_cast<unsigned char>(mValue);
++  }
++
++  /** Convert a UTF-8 code unit to a uint8_t. */
++  constexpr uint8_t toUint8() const
++  {
++    // Per the above comment, this is well-defined integral conversion.
++    return static_cast<uint8_t>(mValue);
++  }
++
++  // We currently don't expose |&mValue|.  |UnicodeData| sort of does, but
++  // that's a somewhat separate concern, justified in different comments in
++  // that other code.
++};
++
++/**
++ * Returns true if the given length-delimited memory consists of a valid UTF-8
++ * string, false otherwise.
++ *
++ * A valid UTF-8 string contains no overlong-encoded code points (as one would
++ * expect) and contains no code unit sequence encoding a UTF-16 surrogate.  The
++ * string *may* contain U+0000 NULL code points.
++ */
++extern MFBT_API bool
++IsValidUtf8(const void* aCodeUnits, size_t aCount);
++
++} // namespace mozilla
++
++#endif /* mozilla_Utf8_h */
+diff --git a/mfbt/moz.build b/mfbt/moz.build
+--- a/mfbt/moz.build
++++ b/mfbt/moz.build
+@@ -95,16 +95,17 @@ EXPORTS.mozilla = [
+     'ToString.h',
+     'Tuple.h',
+     'TypedEnumBits.h',
+     'Types.h',
+     'TypeTraits.h',
+     'UniquePtr.h',
+     'UniquePtrExtensions.h',
+     'Unused.h',
++    'Utf8.h',
+     'Variant.h',
+     'Vector.h',
+     'WeakPtr.h',
+     'WrappingOperations.h',
+     'XorShift128PlusRNG.h',
+ ]
+ 
+ EXPORTS["double-conversion"] = [
+@@ -138,16 +139,17 @@ UNIFIED_SOURCES += [
+     'double-conversion/double-conversion/strtod.cc',
+     'FloatingPoint.cpp',
+     'HashFunctions.cpp',
+     'JSONWriter.cpp',
+     'Poison.cpp',
+     'SHA1.cpp',
+     'TaggedAnonymousMemory.cpp',
+     'Unused.cpp',
++    'Utf8.cpp',
+ ]
+ 
+ DEFINES['IMPL_MFBT'] = True
+ 
+ SOURCES += [
+     'Compression.cpp',
+     'decimal/Decimal.cpp',
+     'lz4.c',
+diff --git a/mfbt/tests/TestUtf8.cpp b/mfbt/tests/TestUtf8.cpp
+new file mode 100644
+--- /dev/null
++++ b/mfbt/tests/TestUtf8.cpp
+@@ -0,0 +1,115 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "mozilla/Utf8.h"
++
++#include "mozilla/ArrayUtils.h"
++#include "mozilla/Assertions.h"
++
++using mozilla::ArrayLength;
++using mozilla::IsValidUtf8;
++using mozilla::Utf8Unit;
++
++static void
++TestUtf8Unit()
++{
++  Utf8Unit c('A');
++  MOZ_RELEASE_ASSERT(c.toChar() == 'A');
++  MOZ_RELEASE_ASSERT(c == Utf8Unit('A'));
++  MOZ_RELEASE_ASSERT(c != Utf8Unit('B'));
++  MOZ_RELEASE_ASSERT(c.toUint8() == 0x41);
++
++  unsigned char asUnsigned = 'A';
++  MOZ_RELEASE_ASSERT(c.toUnsignedChar() == asUnsigned);
++  MOZ_RELEASE_ASSERT(Utf8Unit('B').toUnsignedChar() != asUnsigned);
++
++  Utf8Unit first('@');
++  Utf8Unit second('#');
++
++  MOZ_RELEASE_ASSERT(first != second);
++
++  first = second;
++  MOZ_RELEASE_ASSERT(first == second);
++}
++
++static void
++TestIsValidUtf8()
++{
++  // Note we include the U+0000 NULL in this one -- and that's fine.
++  static const char asciiBytes[] = u8"How about a nice game of chess?";
++  MOZ_RELEASE_ASSERT(IsValidUtf8(asciiBytes, ArrayLength(asciiBytes)));
++
++  static const char endNonAsciiBytes[] = u8"Life is like a 🌯";
++  MOZ_RELEASE_ASSERT(IsValidUtf8(endNonAsciiBytes, ArrayLength(endNonAsciiBytes) - 1));
++
++  static const unsigned char badLeading[] = { 0x80 };
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(badLeading, ArrayLength(badLeading)));
++
++  // Byte-counts
++
++  // 1
++  static const char oneBytes[] = u8"A"; // U+0041 LATIN CAPITAL LETTER A
++  constexpr size_t oneBytesLen = ArrayLength(oneBytes);
++  static_assert(oneBytesLen == 2, "U+0041 plus nul");
++  MOZ_RELEASE_ASSERT(IsValidUtf8(oneBytes, oneBytesLen));
++
++  // 2
++  static const char twoBytes[] = u8"؆"; // U+0606 ARABIC-INDIC CUBE ROOT
++  constexpr size_t twoBytesLen = ArrayLength(twoBytes);
++  static_assert(twoBytesLen == 3, "U+0606 in two bytes plus nul");
++  MOZ_RELEASE_ASSERT(IsValidUtf8(twoBytes, twoBytesLen));
++
++  // 3
++  static const char threeBytes[] = u8"᨞"; // U+1A1E BUGINESE PALLAWA
++  constexpr size_t threeBytesLen = ArrayLength(threeBytes);
++  static_assert(threeBytesLen == 4, "U+1A1E in three bytes plus nul");
++  MOZ_RELEASE_ASSERT(IsValidUtf8(threeBytes, threeBytesLen));
++
++  // 4
++  static const char fourBytes[] = u8"🁡"; // U+1F061 DOMINO TILE HORIZONTAL-06-06
++  constexpr size_t fourBytesLen = ArrayLength(fourBytes);
++  static_assert(fourBytesLen == 5, "U+1F061 in four bytes plus nul");
++  MOZ_RELEASE_ASSERT(IsValidUtf8(fourBytes, fourBytesLen));
++
++  // Max code point
++  static const char maxCodePoint[] = u8"􏿿"; // U+10FFFF
++  constexpr size_t maxCodePointLen = ArrayLength(maxCodePoint);
++  static_assert(maxCodePointLen == 5, "U+10FFFF in four bytes plus nul");
++  MOZ_RELEASE_ASSERT(IsValidUtf8(maxCodePoint, maxCodePointLen));
++
++  // One past max code point
++  static unsigned const char onePastMaxCodePoint[] = { 0xF4, 0x90, 0x80, 0x80 };
++  constexpr size_t onePastMaxCodePointLen = ArrayLength(onePastMaxCodePoint);
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(onePastMaxCodePoint, onePastMaxCodePointLen));
++
++  // Surrogate-related testing
++
++  static const unsigned char justBeforeSurrogates[] = { 0xED, 0x9F, 0xBF };
++  MOZ_RELEASE_ASSERT(IsValidUtf8(justBeforeSurrogates, ArrayLength(justBeforeSurrogates)));
++
++  static const unsigned char leastSurrogate[] = { 0xED, 0xA0, 0x80 };
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(leastSurrogate, ArrayLength(leastSurrogate)));
++
++  static const unsigned char arbitraryHighSurrogate[] = { 0xED, 0xA2, 0x87 };
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(arbitraryHighSurrogate, ArrayLength(arbitraryHighSurrogate)));
++
++  static const unsigned char arbitraryLowSurrogate[] = { 0xED, 0xB7, 0xAF };
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(arbitraryLowSurrogate, ArrayLength(arbitraryLowSurrogate)));
++
++  static const unsigned char greatestSurrogate[] = { 0xED, 0xBF, 0xBF };
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(greatestSurrogate, ArrayLength(greatestSurrogate)));
++
++  static const unsigned char justAfterSurrogates[] = { 0xEE, 0x80, 0x80 };
++  MOZ_RELEASE_ASSERT(IsValidUtf8(justAfterSurrogates, ArrayLength(justAfterSurrogates)));
++}
++
++int
++main()
++{
++  TestUtf8Unit();
++  TestIsValidUtf8();
++  return 0;
++}
+diff --git a/mfbt/tests/moz.build b/mfbt/tests/moz.build
+--- a/mfbt/tests/moz.build
++++ b/mfbt/tests/moz.build
+@@ -52,16 +52,17 @@ CppUnitTests([
+     'TestSplayTree',
+     'TestTemplateLib',
+     'TestTextUtils',
+     'TestThreadSafeWeakPtr',
+     'TestTuple',
+     'TestTypedEnum',
+     'TestTypeTraits',
+     'TestUniquePtr',
++    'TestUtf8',
+     'TestVariant',
+     'TestVector',
+     'TestWeakPtr',
+     'TestWrappingOperations',
+     'TestXorShift128PlusRNG',
+ ])
+ 
+ if not CONFIG['MOZ_ASAN']:

+ 1124 - 0
frg/work-js/mozilla-release/patches/1426909-2-63a1.patch

@@ -0,0 +1,1124 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531442491 25200
+#      Thu Jul 12 17:41:31 2018 -0700
+# Node ID 8258ce540165d59bd100a953e89ea316fe5962ac
+# Parent  7d07cfa666bf8bb2ec9aef3c7f88654f66e9a433
+Bug 1426909 - Abstract out mozilla::DecodeOneUtf8CodePoint for decoding a UTF-8 code point after having consumed a non-ASCII lead unit, with configurable error notification through optional user-provided functors.  r=froydnj
+
+diff --git a/mfbt/Utf8.cpp b/mfbt/Utf8.cpp
+--- a/mfbt/Utf8.cpp
++++ b/mfbt/Utf8.cpp
+@@ -1,79 +1,39 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
++#include "mozilla/Maybe.h"
++#include "mozilla/TextUtils.h"
+ #include "mozilla/Types.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <stddef.h>
+ #include <stdint.h>
+ 
+ MFBT_API bool
+ mozilla::IsValidUtf8(const void* aCodeUnits, size_t aCount)
+ {
+   const auto* s = static_cast<const unsigned char*>(aCodeUnits);
+-  const auto* limit = s + aCount;
++  const auto* const limit = s + aCount;
+ 
+   while (s < limit) {
+-    uint32_t n = *s++;
++    unsigned char c = *s++;
+ 
+     // If the first byte is ASCII, it's the only one in the code point.  Have a
+     // fast path that avoids all the rest of the work and looping in that case.
+-    if ((n & 0x80) == 0) {
++    if (IsAscii(c)) {
+       continue;
+     }
+ 
+-    // The leading code unit determines the length of the next code point and
+-    // the number of bits of the leading code unit that contribute to the code
+-    // point's value.
+-    uint_fast8_t remaining;
+-    uint32_t min;
+-    if ((n & 0xE0) == 0xC0) {
+-      remaining = 1;
+-      min = 0x80;
+-      n &= 0x1F;
+-    } else if ((n & 0xF0) == 0xE0) {
+-      remaining = 2;
+-      min = 0x800;
+-      n &= 0x0F;
+-    } else if ((n & 0xF8) == 0xF0) {
+-      remaining = 3;
+-      min = 0x10000;
+-      n &= 0x07;
+-    } else {
+-      // UTF-8 used to have a hyper-long encoding form, but it's been removed
+-      // for years now.  So in this case, the string is not valid UTF-8.
++    Maybe<char32_t> maybeCodePoint =
++      DecodeOneUtf8CodePoint(Utf8Unit(c), &s, limit);
++    if (maybeCodePoint.isNothing()) {
+       return false;
+     }
+-
+-    // If the code point would require more code units than remain, the encoding
+-    // is invalid.
+-    if (s + remaining > limit) {
+-      return false;
+-    }
+-
+-    for (uint_fast8_t i = 0; i < remaining; i++) {
+-      // Every non-leading code unit in properly encoded UTF-8 has its high bit
+-      // set and the next-highest bit unset.
+-      if ((s[i] & 0xC0) != 0x80) {
+-        return false;
+-      }
+-
+-      // The code point being encoded is the concatenation of all the
+-      // unconstrained bits.
+-      n = (n << 6) | (s[i] & 0x3F);
+-    }
+-
+-    // Don't consider code points that are overlong, UTF-16 surrogates, or
+-    // exceed the maximum code point to be valid.
+-    if (n < min || (0xD800 <= n && n < 0xE000) || n >= 0x110000) {
+-      return false;
+-    }
+-
+-    s += remaining;
+   }
+ 
++  MOZ_ASSERT(s == limit);
+   return true;
+ }
+diff --git a/mfbt/Utf8.h b/mfbt/Utf8.h
+--- a/mfbt/Utf8.h
++++ b/mfbt/Utf8.h
+@@ -7,16 +7,20 @@
+ /*
+  * UTF-8-related functionality, including a type-safe structure representing a
+  * UTF-8 code unit.
+  */
+ 
+ #ifndef mozilla_Utf8_h
+ #define mozilla_Utf8_h
+ 
++#include "mozilla/Casting.h" // for mozilla::AssertedCast
++#include "mozilla/Likely.h" // for MOZ_UNLIKELY
++#include "mozilla/Maybe.h" // for mozilla::Maybe
++#include "mozilla/TextUtils.h" // for mozilla::IsAscii
+ #include "mozilla/Types.h" // for MFBT_API
+ 
+ #include <limits.h> // for CHAR_BIT
+ #include <stddef.h> // for size_t
+ #include <stdint.h> // for uint8_t
+ 
+ namespace mozilla {
+ 
+@@ -200,11 +204,222 @@ public:
+  *
+  * A valid UTF-8 string contains no overlong-encoded code points (as one would
+  * expect) and contains no code unit sequence encoding a UTF-16 surrogate.  The
+  * string *may* contain U+0000 NULL code points.
+  */
+ extern MFBT_API bool
+ IsValidUtf8(const void* aCodeUnits, size_t aCount);
+ 
++/**
++ * Given |aLeadUnit| that is a non-ASCII code unit, a pointer to an |Iter aIter|
++ * that (initially) itself points one unit past |aLeadUnit|, and
++ * |const EndIter aEnd| that denotes the end of the UTF-8 data when compared
++ * against |*aIter| using |aEnd - *aIter|:
++ *
++ * If |aLeadUnit| and subsequent code units computed using |*aIter| (up to
++ * |aEnd|) encode a valid code point -- not exceeding Unicode's range, not a
++ * surrogate, in shortest form -- then return Some(that code point) and advance
++ * |*aIter| past those code units.
++ *
++ * Otherwise decrement |*aIter| (so that it points at |aLeadUnit|) and return
++ * Nothing().
++ *
++ * |Iter| and |EndIter| are generalized concepts most easily understood as if
++ * they were |const char*|, |const unsigned char*|, or |const Utf8Unit*|:
++ * iterators that when dereferenced can be used to construct a |Utf8Unit| and
++ * that can be compared and modified in certain limited ways.  (Carefully note
++ * that this function mutates |*aIter|.)  |Iter| and |EndIter| are template
++ * parameters to support more-complicated adaptor iterators.
++ *
++ * The template parameters after |Iter| allow users to implement custom handling
++ * for various forms of invalid UTF-8.  A version of this function that defaults
++ * all such handling to no-ops is defined below this function.  To learn how to
++ * define your own custom handling, consult the implementation of that function,
++ * which documents exactly how custom handler functors are invoked.
++ *
++ * This function is MOZ_ALWAYS_INLINE: if you don't need that, use the version
++ * of this function without the "Inline" suffix on the name.
++ */
++template<typename Iter,
++         typename EndIter,
++         class OnBadLeadUnit,
++         class OnNotEnoughUnits,
++         class OnBadTrailingUnit,
++         class OnBadCodePoint,
++         class OnNotShortestForm>
++MOZ_ALWAYS_INLINE Maybe<char32_t>
++DecodeOneUtf8CodePointInline(const Utf8Unit aLeadUnit,
++                             Iter* aIter, const EndIter aEnd,
++                             OnBadLeadUnit aOnBadLeadUnit,
++                             OnNotEnoughUnits aOnNotEnoughUnits,
++                             OnBadTrailingUnit aOnBadTrailingUnit,
++                             OnBadCodePoint aOnBadCodePoint,
++                             OnNotShortestForm aOnNotShortestForm)
++{
++  MOZ_ASSERT(Utf8Unit((*aIter)[-1]) == aLeadUnit);
++
++  char32_t n = aLeadUnit.toUint8();
++  MOZ_ASSERT(!IsAscii(n));
++
++  // |aLeadUnit| determines the number of trailing code units in the code point
++  // and the bits of |aLeadUnit| that contribute to the code point's value.
++  uint8_t remaining;
++  uint32_t min;
++  if ((n & 0b1110'0000) == 0b1100'0000) {
++    remaining = 1;
++    min = 0x80;
++    n &= 0b0001'1111;
++  } else if ((n & 0b1111'0000) == 0b1110'0000) {
++    remaining = 2;
++    min = 0x800;
++    n &= 0b0000'1111;
++  } else if ((n & 0b1111'1000) == 0b1111'0000) {
++    remaining = 3;
++    min = 0x10000;
++    n &= 0b0000'0111;
++  } else {
++    *aIter -= 1;
++    aOnBadLeadUnit();
++    return Nothing();
++  }
++
++  // If the code point would require more code units than remain, the encoding
++  // is invalid.
++  auto actual = aEnd - *aIter;
++  if (MOZ_UNLIKELY(actual < remaining)) {
++    *aIter -= 1;
++    aOnNotEnoughUnits(AssertedCast<uint8_t>(actual + 1), remaining + 1);
++    return Nothing();
++  }
++
++  for (uint8_t i = 0; i < remaining; i++) {
++    uint8_t unit = Utf8Unit(*(*aIter)++).toUint8();
++
++    // Every non-leading code unit in properly encoded UTF-8 has its high
++    // bit set and the next-highest bit unset.
++    if (MOZ_UNLIKELY((unit & 0b1100'0000) != 0b1000'0000)) {
++      uint8_t unitsObserved = i + 1 + 1;
++      *aIter -= unitsObserved;
++      aOnBadTrailingUnit(unitsObserved);
++      return Nothing();
++    }
++
++    // The code point being encoded is the concatenation of all the
++    // unconstrained bits.
++    n = (n << 6) | (unit & 0b0011'1111);
++  }
++
++  // UTF-16 surrogates and values outside the Unicode range are invalid.
++  if (MOZ_UNLIKELY(n > 0x10FFFF || (0xD800 <= n && n <= 0xDFFF))) {
++    uint8_t unitsObserved = remaining + 1;
++    *aIter -= unitsObserved;
++    aOnBadCodePoint(n, unitsObserved);
++    return Nothing();
++  }
++
++  // Overlong code points are also invalid.
++  if (MOZ_UNLIKELY(n < min)) {
++    uint8_t unitsObserved = remaining + 1;
++    *aIter -= unitsObserved;
++    aOnNotShortestForm(n, unitsObserved);
++    return Nothing();
++  }
++
++  return Some(n);
++}
++
++/**
++ * Identical to the above function, but not forced to be instantiated inline --
++ * the compiler is permitted to common up separate invocations if it chooses.
++ */
++template<typename Iter,
++         typename EndIter,
++         class OnBadLeadUnit,
++         class OnNotEnoughUnits,
++         class OnBadTrailingUnit,
++         class OnBadCodePoint,
++         class OnNotShortestForm>
++inline Maybe<char32_t>
++DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit,
++                       Iter* aIter, const EndIter aEnd,
++                       OnBadLeadUnit aOnBadLeadUnit,
++                       OnNotEnoughUnits aOnNotEnoughUnits,
++                       OnBadTrailingUnit aOnBadTrailingUnit,
++                       OnBadCodePoint aOnBadCodePoint,
++                       OnNotShortestForm aOnNotShortestForm)
++{
++  return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd,
++                                      aOnBadLeadUnit, aOnNotEnoughUnits,
++                                      aOnBadTrailingUnit, aOnBadCodePoint,
++                                      aOnNotShortestForm);
++}
++
++/**
++ * Like the always-inlined function above, but with no-op behavior from all
++ * trailing if-invalid notifier functors.
++ *
++ * This function is MOZ_ALWAYS_INLINE: if you don't need that, use the version
++ * of this function without the "Inline" suffix on the name.
++ */
++template<typename Iter, typename EndIter>
++MOZ_ALWAYS_INLINE Maybe<char32_t>
++DecodeOneUtf8CodePointInline(const Utf8Unit aLeadUnit,
++                             Iter* aIter, const EndIter aEnd)
++{
++  // aOnBadLeadUnit is called when |aLeadUnit| itself is an invalid lead unit in
++  // a multi-unit code point.  It is passed no arguments: the caller already has
++  // |aLeadUnit| on hand, so no need to provide it again.
++  auto onBadLeadUnit = []() {};
++
++  // aOnNotEnoughUnits is called when |aLeadUnit| properly indicates a code
++  // point length, but there aren't enough units from |*aIter| to |aEnd| to
++  // satisfy that length.  It is passed the number of code units actually
++  // available (according to |aEnd - *aIter|) and the number of code units that
++  // |aLeadUnit| indicates are needed.  Both numbers include the contribution
++  // of |aLeadUnit| itself: so |aUnitsAvailable <= 3|, |aUnitsNeeded <= 4|, and
++  // |aUnitsAvailable < aUnitsNeeded|.  As above, it also is not passed the lead
++  // code unit.
++  auto onNotEnoughUnits = [](uint8_t aUnitsAvailable, uint8_t aUnitsNeeded) {};
++
++  // aOnBadTrailingUnit is called when one of the trailing code units implied by
++  // |aLeadUnit| doesn't match the 0b10xx'xxxx bit pattern that all UTF-8
++  // trailing code units must satisfy.  It is passed the total count of units
++  // observed (including |aLeadUnit|).  The bad trailing code unit will
++  // conceptually be at |(*aIter)[aUnitsObserved - 1]| if this functor is
++  // called, and so |aUnitsObserved <= 4|.
++  auto onBadTrailingUnit = [](uint8_t aUnitsObserved) {};
++
++  // aOnBadCodePoint is called when a structurally-correct code point encoding
++  // is found, but the *value* that is encoded is not a valid code point: either
++  // because it exceeded the U+10FFFF Unicode maximum code point, or because it
++  // was a UTF-16 surrogate.  It is passed the non-code point value and the
++  // number of code units used to encode it.
++  auto onBadCodePoint = [](char32_t aBadCodePoint, uint8_t aUnitsObserved) {};
++
++  // aOnNotShortestForm is called when structurally-correct encoding is found,
++  // but the encoded value should have been encoded in fewer code units (e.g.
++  // mis-encoding U+0000 as 0b1100'0000 0b1000'0000 in two code units instead of
++  // as 0b0000'0000).  It is passed the mis-encoded code point (which will be
++  // valid and not a surrogate) and the count of code units that mis-encoded it.
++  auto onNotShortestForm = [](char32_t aBadCodePoint, uint8_t aUnitsObserved) {};
++
++  return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd,
++                                      onBadLeadUnit, onNotEnoughUnits,
++                                      onBadTrailingUnit, onBadCodePoint,
++                                      onNotShortestForm);
++}
++
++/**
++ * Identical to the above function, but not forced to be instantiated inline --
++ * the compiler/linker are allowed to common up separate invocations.
++ */
++template<typename Iter, typename EndIter>
++inline Maybe<char32_t>
++DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit,
++                       Iter* aIter, const EndIter aEnd)
++{
++  return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd);
++}
++
+ } // namespace mozilla
+ 
+ #endif /* mozilla_Utf8_h */
+diff --git a/mfbt/tests/TestUtf8.cpp b/mfbt/tests/TestUtf8.cpp
+--- a/mfbt/tests/TestUtf8.cpp
++++ b/mfbt/tests/TestUtf8.cpp
+@@ -3,18 +3,25 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "mozilla/Utf8.h"
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Assertions.h"
++#include "mozilla/EnumSet.h"
++#include "mozilla/IntegerRange.h"
++#include "mozilla/TextUtils.h"
+ 
+ using mozilla::ArrayLength;
++using mozilla::DecodeOneUtf8CodePoint;
++using mozilla::EnumSet;
++using mozilla::IntegerRange;
++using mozilla::IsAscii;
+ using mozilla::IsValidUtf8;
+ using mozilla::Utf8Unit;
+ 
+ static void
+ TestUtf8Unit()
+ {
+   Utf8Unit c('A');
+   MOZ_RELEASE_ASSERT(c.toChar() == 'A');
+@@ -30,16 +37,252 @@ TestUtf8Unit()
+   Utf8Unit second('#');
+ 
+   MOZ_RELEASE_ASSERT(first != second);
+ 
+   first = second;
+   MOZ_RELEASE_ASSERT(first == second);
+ }
+ 
++template<typename Char>
++struct ToUtf8Units
++{
++public:
++  explicit ToUtf8Units(const Char* aStart, const Char* aEnd)
++    : lead(Utf8Unit(aStart[0]))
++    , iter(aStart + 1)
++    , end(aEnd)
++  {
++    MOZ_RELEASE_ASSERT(!IsAscii(aStart[0]));
++  }
++
++  const Utf8Unit lead;
++  const Char* iter;
++  const Char* const end;
++};
++
++class AssertIfCalled
++{
++public:
++  template<typename... Args>
++  void operator()(Args&&... aArgs) {
++    MOZ_RELEASE_ASSERT(false, "AssertIfCalled instance was called");
++  }
++};
++
++// NOTE: For simplicity in treating |aCharN| identically regardless whether it's
++//       a string literal or a more-generalized array, we require |aCharN| be
++//       null-terminated.
++
++template<typename Char, size_t N>
++static void
++ExpectValidCodePoint(const Char (&aCharN)[N],
++                     char32_t aExpectedCodePoint)
++{
++  MOZ_RELEASE_ASSERT(aCharN[N - 1] == 0,
++                     "array must be null-terminated for |aCharN + N - 1| to "
++                     "compute the value of |aIter| as altered by "
++                     "DecodeOneUtf8CodePoint");
++
++  ToUtf8Units<Char> simpleUnit(aCharN, aCharN + N - 1);
++  auto simple =
++    DecodeOneUtf8CodePoint(simpleUnit.lead, &simpleUnit.iter, simpleUnit.end);
++  MOZ_RELEASE_ASSERT(simple.isSome());
++  MOZ_RELEASE_ASSERT(*simple == aExpectedCodePoint);
++  MOZ_RELEASE_ASSERT(simpleUnit.iter == simpleUnit.end);
++
++  ToUtf8Units<Char> complexUnit(aCharN, aCharN + N - 1);
++  auto complex =
++    DecodeOneUtf8CodePoint(complexUnit.lead, &complexUnit.iter, complexUnit.end,
++                           AssertIfCalled(),
++                           AssertIfCalled(),
++                           AssertIfCalled(),
++                           AssertIfCalled(),
++                           AssertIfCalled());
++  MOZ_RELEASE_ASSERT(complex.isSome());
++  MOZ_RELEASE_ASSERT(*complex == aExpectedCodePoint);
++  MOZ_RELEASE_ASSERT(complexUnit.iter == complexUnit.end);
++}
++
++enum class InvalidUtf8Reason
++{
++  BadLeadUnit,
++  NotEnoughUnits,
++  BadTrailingUnit,
++  BadCodePoint,
++  NotShortestForm,
++};
++
++template<typename Char, size_t N>
++static void
++ExpectInvalidCodePointHelper(const Char (&aCharN)[N],
++                             InvalidUtf8Reason aExpectedReason,
++                             uint8_t aExpectedUnitsAvailable,
++                             uint8_t aExpectedUnitsNeeded,
++                             char32_t aExpectedBadCodePoint,
++                             uint8_t aExpectedUnitsObserved)
++{
++  MOZ_RELEASE_ASSERT(aCharN[N - 1] == 0,
++                     "array must be null-terminated for |aCharN + N - 1| to "
++                     "compute the value of |aIter| as altered by "
++                     "DecodeOneUtf8CodePoint");
++
++  ToUtf8Units<Char> simpleUnit(aCharN, aCharN + N - 1);
++  auto simple =
++    DecodeOneUtf8CodePoint(simpleUnit.lead, &simpleUnit.iter, simpleUnit.end);
++  MOZ_RELEASE_ASSERT(simple.isNothing());
++  MOZ_RELEASE_ASSERT(static_cast<const void*>(simpleUnit.iter) == aCharN);
++
++  EnumSet<InvalidUtf8Reason> reasons;
++  uint8_t unitsAvailable;
++  uint8_t unitsNeeded;
++  char32_t badCodePoint;
++  uint8_t unitsObserved;
++
++  struct OnNotShortestForm
++  {
++    EnumSet<InvalidUtf8Reason>& reasons;
++    char32_t& badCodePoint;
++    uint8_t& unitsObserved;
++
++    void operator()(char32_t aBadCodePoint, uint8_t aUnitsObserved) {
++      reasons += InvalidUtf8Reason::NotShortestForm;
++      badCodePoint = aBadCodePoint;
++      unitsObserved = aUnitsObserved;
++    }
++  };
++
++  ToUtf8Units<Char> complexUnit(aCharN, aCharN + N - 1);
++  auto complex =
++    DecodeOneUtf8CodePoint(complexUnit.lead, &complexUnit.iter, complexUnit.end,
++                           [&reasons]() {
++                             reasons += InvalidUtf8Reason::BadLeadUnit;
++                           },
++                           [&reasons, &unitsAvailable, &unitsNeeded](uint8_t aUnitsAvailable,
++                                                                     uint8_t aUnitsNeeded)
++                           {
++                             reasons += InvalidUtf8Reason::NotEnoughUnits;
++                             unitsAvailable = aUnitsAvailable;
++                             unitsNeeded = aUnitsNeeded;
++                           },
++                           [&reasons, &unitsObserved](uint8_t aUnitsObserved)
++                           {
++                             reasons += InvalidUtf8Reason::BadTrailingUnit;
++                             unitsObserved = aUnitsObserved;
++                           },
++                           [&reasons, &badCodePoint, &unitsObserved](char32_t aBadCodePoint,
++                                                                     uint8_t aUnitsObserved)
++                           {
++                             reasons += InvalidUtf8Reason::BadCodePoint;
++                             badCodePoint = aBadCodePoint;
++                             unitsObserved = aUnitsObserved;
++                           },
++                           [&reasons, &badCodePoint, &unitsObserved](char32_t aBadCodePoint,
++                                                                     uint8_t aUnitsObserved)
++                           {
++                             reasons += InvalidUtf8Reason::NotShortestForm;
++                             badCodePoint = aBadCodePoint;
++                             unitsObserved = aUnitsObserved;
++                           });
++  MOZ_RELEASE_ASSERT(complex.isNothing());
++  MOZ_RELEASE_ASSERT(static_cast<const void*>(complexUnit.iter) == aCharN);
++
++  bool alreadyIterated = false;
++  for (InvalidUtf8Reason reason : reasons) {
++    MOZ_RELEASE_ASSERT(!alreadyIterated);
++    alreadyIterated = true;
++
++    switch (reason) {
++    case InvalidUtf8Reason::BadLeadUnit:
++      break;
++
++    case InvalidUtf8Reason::NotEnoughUnits:
++      MOZ_RELEASE_ASSERT(unitsAvailable == aExpectedUnitsAvailable);
++      MOZ_RELEASE_ASSERT(unitsNeeded == aExpectedUnitsNeeded);
++      break;
++
++    case InvalidUtf8Reason::BadTrailingUnit:
++      MOZ_RELEASE_ASSERT(unitsObserved == aExpectedUnitsObserved);
++      break;
++
++    case InvalidUtf8Reason::BadCodePoint:
++      MOZ_RELEASE_ASSERT(badCodePoint == aExpectedBadCodePoint);
++      MOZ_RELEASE_ASSERT(unitsObserved == aExpectedUnitsObserved);
++      break;
++
++    case InvalidUtf8Reason::NotShortestForm:
++      MOZ_RELEASE_ASSERT(badCodePoint == aExpectedBadCodePoint);
++      MOZ_RELEASE_ASSERT(unitsObserved == aExpectedUnitsObserved);
++      break;
++    }
++  }
++}
++
++// NOTE: For simplicity in treating |aCharN| identically regardless whether it's
++//       a string literal or a more-generalized array, we require |aCharN| be
++//       null-terminated in all these functions.
++
++template<typename Char, size_t N>
++static void
++ExpectBadLeadUnit(const Char (&aCharN)[N])
++{
++  ExpectInvalidCodePointHelper(aCharN,
++                               InvalidUtf8Reason::BadLeadUnit,
++                               0xFF, 0xFF, 0xFFFFFFFF, 0xFF);
++}
++
++template<typename Char, size_t N>
++static void
++ExpectNotEnoughUnits(const Char (&aCharN)[N],
++                     uint8_t aExpectedUnitsAvailable,
++                     uint8_t aExpectedUnitsNeeded)
++{
++  ExpectInvalidCodePointHelper(aCharN,
++                               InvalidUtf8Reason::NotEnoughUnits,
++                               aExpectedUnitsAvailable, aExpectedUnitsNeeded,
++                               0xFFFFFFFF, 0xFF);
++}
++
++template<typename Char, size_t N>
++static void
++ExpectBadTrailingUnit(const Char (&aCharN)[N],
++                      uint8_t aExpectedUnitsObserved)
++{
++  ExpectInvalidCodePointHelper(aCharN,
++                               InvalidUtf8Reason::BadTrailingUnit,
++                               0xFF, 0xFF, 0xFFFFFFFF,
++                               aExpectedUnitsObserved);
++}
++
++template<typename Char, size_t N>
++static void
++ExpectNotShortestForm(const Char (&aCharN)[N],
++                      char32_t aExpectedBadCodePoint,
++                      uint8_t aExpectedUnitsObserved)
++{
++  ExpectInvalidCodePointHelper(aCharN,
++                               InvalidUtf8Reason::NotShortestForm,
++                               0xFF, 0xFF,
++                               aExpectedBadCodePoint,
++                               aExpectedUnitsObserved);
++}
++
++template<typename Char, size_t N>
++static void
++ExpectBadCodePoint(const Char (&aCharN)[N],
++                   char32_t aExpectedBadCodePoint,
++                   uint8_t aExpectedUnitsObserved)
++{
++  ExpectInvalidCodePointHelper(aCharN,
++                               InvalidUtf8Reason::BadCodePoint,
++                               0xFF, 0xFF,
++                               aExpectedBadCodePoint,
++                               aExpectedUnitsObserved);
++}
++
+ static void
+ TestIsValidUtf8()
+ {
+   // Note we include the U+0000 NULL in this one -- and that's fine.
+   static const char asciiBytes[] = u8"How about a nice game of chess?";
+   MOZ_RELEASE_ASSERT(IsValidUtf8(asciiBytes, ArrayLength(asciiBytes)));
+ 
+   static const char endNonAsciiBytes[] = u8"Life is like a 🌯";
+@@ -57,59 +300,481 @@ TestIsValidUtf8()
+   MOZ_RELEASE_ASSERT(IsValidUtf8(oneBytes, oneBytesLen));
+ 
+   // 2
+   static const char twoBytes[] = u8"؆"; // U+0606 ARABIC-INDIC CUBE ROOT
+   constexpr size_t twoBytesLen = ArrayLength(twoBytes);
+   static_assert(twoBytesLen == 3, "U+0606 in two bytes plus nul");
+   MOZ_RELEASE_ASSERT(IsValidUtf8(twoBytes, twoBytesLen));
+ 
++  ExpectValidCodePoint(twoBytes, 0x0606);
++
+   // 3
+   static const char threeBytes[] = u8"᨞"; // U+1A1E BUGINESE PALLAWA
+   constexpr size_t threeBytesLen = ArrayLength(threeBytes);
+   static_assert(threeBytesLen == 4, "U+1A1E in three bytes plus nul");
+   MOZ_RELEASE_ASSERT(IsValidUtf8(threeBytes, threeBytesLen));
+ 
++  ExpectValidCodePoint(threeBytes, 0x1A1E);
++
+   // 4
+   static const char fourBytes[] = u8"🁡"; // U+1F061 DOMINO TILE HORIZONTAL-06-06
+   constexpr size_t fourBytesLen = ArrayLength(fourBytes);
+   static_assert(fourBytesLen == 5, "U+1F061 in four bytes plus nul");
+   MOZ_RELEASE_ASSERT(IsValidUtf8(fourBytes, fourBytesLen));
+ 
++  ExpectValidCodePoint(fourBytes, 0x1F061);
++
+   // Max code point
+   static const char maxCodePoint[] = u8"􏿿"; // U+10FFFF
+   constexpr size_t maxCodePointLen = ArrayLength(maxCodePoint);
+   static_assert(maxCodePointLen == 5, "U+10FFFF in four bytes plus nul");
+   MOZ_RELEASE_ASSERT(IsValidUtf8(maxCodePoint, maxCodePointLen));
+ 
++  ExpectValidCodePoint(maxCodePoint, 0x10FFFF);
++
+   // One past max code point
+-  static unsigned const char onePastMaxCodePoint[] = { 0xF4, 0x90, 0x80, 0x80 };
++  static const unsigned char onePastMaxCodePoint[] = { 0xF4, 0x90, 0x80, 0x80, 0x0 };
+   constexpr size_t onePastMaxCodePointLen = ArrayLength(onePastMaxCodePoint);
+   MOZ_RELEASE_ASSERT(!IsValidUtf8(onePastMaxCodePoint, onePastMaxCodePointLen));
+ 
++  ExpectBadCodePoint(onePastMaxCodePoint, 0x110000, 4);
++
+   // Surrogate-related testing
+ 
+-  static const unsigned char justBeforeSurrogates[] = { 0xED, 0x9F, 0xBF };
+-  MOZ_RELEASE_ASSERT(IsValidUtf8(justBeforeSurrogates, ArrayLength(justBeforeSurrogates)));
++  // (Note that the various code unit sequences here are null-terminated to
++  // simplify life for ExpectValidCodePoint, which presumes null termination.)
++
++  static const unsigned char justBeforeSurrogates[] = { 0xED, 0x9F, 0xBF, 0x0 };
++  constexpr size_t justBeforeSurrogatesLen = ArrayLength(justBeforeSurrogates) - 1;
++  MOZ_RELEASE_ASSERT(IsValidUtf8(justBeforeSurrogates, justBeforeSurrogatesLen));
++
++  ExpectValidCodePoint(justBeforeSurrogates, 0xD7FF);
++
++  static const unsigned char leastSurrogate[] = { 0xED, 0xA0, 0x80, 0x0 };
++  constexpr size_t leastSurrogateLen = ArrayLength(leastSurrogate) - 1;
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(leastSurrogate, leastSurrogateLen));
++
++  ExpectBadCodePoint(leastSurrogate, 0xD800, 3);
++
++  static const unsigned char arbitraryHighSurrogate[] = { 0xED, 0xA2, 0x87, 0x0 };
++  constexpr size_t arbitraryHighSurrogateLen = ArrayLength(arbitraryHighSurrogate) - 1;
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(arbitraryHighSurrogate, arbitraryHighSurrogateLen));
++
++  ExpectBadCodePoint(arbitraryHighSurrogate, 0xD887, 3);
++
++  static const unsigned char arbitraryLowSurrogate[] = { 0xED, 0xB7, 0xAF, 0x0 };
++  constexpr size_t arbitraryLowSurrogateLen = ArrayLength(arbitraryLowSurrogate) - 1;
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(arbitraryLowSurrogate, arbitraryLowSurrogateLen));
++
++  ExpectBadCodePoint(arbitraryLowSurrogate, 0xDDEF, 3);
++
++  static const unsigned char greatestSurrogate[] = { 0xED, 0xBF, 0xBF, 0x0 };
++  constexpr size_t greatestSurrogateLen = ArrayLength(greatestSurrogate) - 1;
++  MOZ_RELEASE_ASSERT(!IsValidUtf8(greatestSurrogate, greatestSurrogateLen));
++
++  ExpectBadCodePoint(greatestSurrogate, 0xDFFF, 3);
++
++  static const unsigned char justAfterSurrogates[] = { 0xEE, 0x80, 0x80, 0x0 };
++  constexpr size_t justAfterSurrogatesLen = ArrayLength(justAfterSurrogates) - 1;
++  MOZ_RELEASE_ASSERT(IsValidUtf8(justAfterSurrogates, justAfterSurrogatesLen));
++
++  ExpectValidCodePoint(justAfterSurrogates, 0xE000);
++}
++
++static void
++TestDecodeOneValidUtf8CodePoint()
++{
++  // NOTE: DecodeOneUtf8CodePoint decodes only *non*-ASCII code points that
++  //       consist of multiple code units, so there are no ASCII tests below.
++
++  // Length two.
++
++  ExpectValidCodePoint(u8"€", 0x80); // <control>
++  ExpectValidCodePoint(u8"©", 0xA9); // COPYRIGHT SIGN
++  ExpectValidCodePoint(u8"¶", 0xB6); // PILCROW SIGN
++  ExpectValidCodePoint(u8"¾", 0xBE); // VULGAR FRACTION THREE QUARTERS
++  ExpectValidCodePoint(u8"÷", 0xF7); // DIVISION SIGN
++  ExpectValidCodePoint(u8"ÿ", 0xFF); // LATIN SMALL LETTER Y WITH DIAERESIS
++  ExpectValidCodePoint(u8"Ā", 0x100); // LATIN CAPITAL LETTER A WITH MACRON
++  ExpectValidCodePoint(u8"IJ", 0x132); // LATIN CAPITAL LETTER LIGATURE IJ
++  ExpectValidCodePoint(u8"ͼ", 0x37C); // GREEK SMALL DOTTED LUNATE SIGMA SYMBOL
++  ExpectValidCodePoint(u8"Ӝ", 0x4DC); // CYRILLIC CAPITAL LETTER ZHE WITTH DIAERESIS
++  ExpectValidCodePoint(u8"۩", 0x6E9); // ARABIC PLACE OF SAJDAH
++  ExpectValidCodePoint(u8"߿", 0x7FF); // <not assigned>
++
++  // Length three.
++
++  ExpectValidCodePoint(u8"ࠀ", 0x800); // SAMARITAN LETTER ALAF
++  ExpectValidCodePoint(u8"ࡁ", 0x841); // MANDAIC LETTER AB
++  ExpectValidCodePoint(u8"ࣿ", 0x8FF); // ARABIC MARK SIDEWAYS NOON GHUNNA
++  ExpectValidCodePoint(u8"ஆ", 0xB86); // TAMIL LETTER AA
++  ExpectValidCodePoint(u8"༃", 0xF03); // TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
++  ExpectValidCodePoint(u8"࿉", 0xFC9); // TIBETAN SYMBOL NOR BU (but on my system it really looks like SOFT-SERVE ICE CREAM FROM ABOVE THE PLANE if you ask me)
++  ExpectValidCodePoint(u8"ဪ", 0x102A); // MYANMAR LETTER AU
++  ExpectValidCodePoint(u8"ᚏ", 0x168F); // OGHAM LETTER RUIS
++  ExpectValidCodePoint("\xE2\x80\xA8", 0x2028); // (the hated) LINE SEPARATOR
++  ExpectValidCodePoint("\xE2\x80\xA9", 0x2029); // (the hated) PARAGRAPH SEPARATOR
++  ExpectValidCodePoint(u8"☬", 0x262C); // ADI SHAKTI
++  ExpectValidCodePoint(u8"㊮", 0x32AE); // CIRCLED IDEOGRAPH RESOURCE
++  ExpectValidCodePoint(u8"㏖", 0x33D6); // SQUARE MOL
++  ExpectValidCodePoint(u8"ꔄ", 0xA504); // VAI SYLLABLE WEEN
++  ExpectValidCodePoint(u8"ퟕ", 0xD7D5); // HANGUL JONGSEONG RIEUL-SSANGKIYEOK
++  ExpectValidCodePoint(u8"퟿", 0xD7FF); // <not assigned>
++  ExpectValidCodePoint(u8"", 0xE000); // <Private Use>
++  ExpectValidCodePoint(u8"鱗", 0xF9F2); // CJK COMPATIBILITY IDEOGRAPH-F9F
++  ExpectValidCodePoint(u8"﷽", 0xFDFD); // ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHHHEEEEM
++  ExpectValidCodePoint(u8"￿", 0xFFFF); // <not assigned>
++
++  // Length four.
++  ExpectValidCodePoint(u8"𐀀", 0x10000); // LINEAR B SYLLABLE B008 A
++  ExpectValidCodePoint(u8"𔑀", 0x14440); // ANATOLIAN HIEROGLYPH A058
++  ExpectValidCodePoint(u8"𝛗", 0x1D6D7); // MATHEMATICAL BOLD SMALL PHI
++  ExpectValidCodePoint(u8"💩", 0x1F4A9); // PILE OF POO
++  ExpectValidCodePoint(u8"🔫", 0x1F52B); // PISTOL
++  ExpectValidCodePoint(u8"🥌", 0x1F94C); // CURLING STONE
++  ExpectValidCodePoint(u8"🥏", 0x1F94F); // FLYING DISC
++  ExpectValidCodePoint(u8"𠍆", 0x20346); // CJK UNIFIED IDEOGRAPH-20346
++  ExpectValidCodePoint(u8"𡠺", 0x2183A); // CJK UNIFIED IDEOGRAPH-2183A
++  ExpectValidCodePoint(u8"񁟶", 0x417F6); // <not assigned>
++  ExpectValidCodePoint(u8"񾠶", 0x7E836); // <not assigned>
++  ExpectValidCodePoint(u8"󾽧", 0xFEF67); // <Plane 15 Private Use>
++  ExpectValidCodePoint(u8"􏿿", 0x10FFFF); //
++}
++
++static void
++TestDecodeBadLeadUnit()
++{
++  // These tests are actually exhaustive.
+ 
+-  static const unsigned char leastSurrogate[] = { 0xED, 0xA0, 0x80 };
+-  MOZ_RELEASE_ASSERT(!IsValidUtf8(leastSurrogate, ArrayLength(leastSurrogate)));
++  unsigned char badLead[] = { '\0', '\0' };
++
++  for (uint8_t lead : IntegerRange(0b1000'0000, 0b1100'0000)) {
++    badLead[0] = lead;
++    ExpectBadLeadUnit(badLead);
++  }
++
++  {
++    uint8_t lead = 0b1111'1000;
++    do {
++      badLead[0] = lead;
++      ExpectBadLeadUnit(badLead);
++      if (lead == 0b1111'1111) {
++        break;
++      }
++
++      lead++;
++    } while (true);
++  }
++}
++
++static void
++TestTooFewOrBadTrailingUnits()
++{
++  // Lead unit indicates a two-byte code point.
++
++  char truncatedTwo[] = { '\0', '\0' };
++  char badTrailTwo[] = { '\0', '\0', '\0' };
++
++  for (uint8_t lead : IntegerRange(0b1100'0000, 0b1110'0000)) {
++    truncatedTwo[0] = lead;
++    ExpectNotEnoughUnits(truncatedTwo, 1, 2);
++
++    badTrailTwo[0] = lead;
++    for (uint8_t trail : IntegerRange(0b0000'0000, 0b1000'0000)) {
++      badTrailTwo[1] = trail;
++      ExpectBadTrailingUnit(badTrailTwo, 2);
++    }
++
++    for (uint8_t trail : IntegerRange(0b1100'0000, 0b1111'1111)) {
++      badTrailTwo[1] = trail;
++      ExpectBadTrailingUnit(badTrailTwo, 2);
++    }
++  }
++
++  // Lead unit indicates a three-byte code point.
++
++  char truncatedThreeOne[] = { '\0', '\0' };
++  char truncatedThreeTwo[] = { '\0', '\0', '\0' };
++  unsigned char badTrailThree[] = { '\0', '\0', '\0', '\0' };
+ 
+-  static const unsigned char arbitraryHighSurrogate[] = { 0xED, 0xA2, 0x87 };
+-  MOZ_RELEASE_ASSERT(!IsValidUtf8(arbitraryHighSurrogate, ArrayLength(arbitraryHighSurrogate)));
++  for (uint8_t lead : IntegerRange(0b1110'0000, 0b1111'0000)) {
++    truncatedThreeOne[0] = lead;
++    ExpectNotEnoughUnits(truncatedThreeOne, 1, 3);
++
++    truncatedThreeTwo[0] = lead;
++    ExpectNotEnoughUnits(truncatedThreeTwo, 2, 3);
++
++    badTrailThree[0] = lead;
++    badTrailThree[2] = 0b1011'1111; // make valid to test overreads
++    for (uint8_t mid : IntegerRange(0b0000'0000, 0b1000'0000)) {
++      badTrailThree[1] = mid;
++      ExpectBadTrailingUnit(badTrailThree, 2);
++    }
++    {
++      uint8_t mid = 0b1100'0000;
++      do {
++        badTrailThree[1] = mid;
++        ExpectBadTrailingUnit(badTrailThree, 2);
++        if (mid == 0b1111'1111) {
++          break;
++        }
++
++        mid++;
++      } while (true);
++    }
++
++    badTrailThree[1] = 0b1011'1111;
++    for (uint8_t last : IntegerRange(0b0000'0000, 0b1000'0000)) {
++      badTrailThree[2] = last;
++      ExpectBadTrailingUnit(badTrailThree, 3);
++    }
++    {
++      uint8_t last = 0b1100'0000;
++      do {
++        badTrailThree[2] = last;
++        ExpectBadTrailingUnit(badTrailThree, 3);
++        if (last == 0b1111'1111) {
++          break;
++        }
++
++        last++;
++      } while (true);
++    }
++  }
++
++  // Lead unit indicates a four-byte code point.
++
++  char truncatedFourOne[] = { '\0', '\0' };
++  char truncatedFourTwo[] = { '\0', '\0', '\0' };
++  char truncatedFourThree[] = { '\0', '\0', '\0', '\0' };
++
++  unsigned char badTrailFour[] = { '\0', '\0', '\0', '\0', '\0' };
++
++  for (uint8_t lead : IntegerRange(0b1111'0000, 0b1111'1000)) {
++    truncatedFourOne[0] = lead;
++    ExpectNotEnoughUnits(truncatedFourOne, 1, 4);
+ 
+-  static const unsigned char arbitraryLowSurrogate[] = { 0xED, 0xB7, 0xAF };
+-  MOZ_RELEASE_ASSERT(!IsValidUtf8(arbitraryLowSurrogate, ArrayLength(arbitraryLowSurrogate)));
++    truncatedFourTwo[0] = lead;
++    ExpectNotEnoughUnits(truncatedFourTwo, 2, 4);
++
++    truncatedFourThree[0] = lead;
++    ExpectNotEnoughUnits(truncatedFourThree, 3, 4);
++
++    badTrailFour[0] = lead;
++    badTrailFour[2] = badTrailFour[3] = 0b1011'1111; // test for overreads
++    for (uint8_t second : IntegerRange(0b0000'0000, 0b1000'0000)) {
++      badTrailFour[1] = second;
++      ExpectBadTrailingUnit(badTrailFour, 2);
++    }
++    {
++      uint8_t second = 0b1100'0000;
++      do {
++        badTrailFour[1] = second;
++        ExpectBadTrailingUnit(badTrailFour, 2);
++        if (second == 0b1111'1111) {
++          break;
++        }
++
++        second++;
++      } while (true);
++    }
++
++    badTrailFour[1] = badTrailFour[3] = 0b1011'1111; // test for overreads
++    for (uint8_t third : IntegerRange(0b0000'0000, 0b1000'0000)) {
++      badTrailFour[2] = third;
++      ExpectBadTrailingUnit(badTrailFour, 3);
++    }
++    {
++      uint8_t third = 0b1100'0000;
++      do {
++        badTrailFour[2] = third;
++        ExpectBadTrailingUnit(badTrailFour, 3);
++        if (third == 0b1111'1111) {
++          break;
++        }
++
++        third++;
++      } while (true);
++    }
++
++    badTrailFour[2] = 0b1011'1111;
++    for (uint8_t fourth : IntegerRange(0b0000'0000, 0b1000'0000)) {
++      badTrailFour[3] = fourth;
++      ExpectBadTrailingUnit(badTrailFour, 4);
++    }
++    {
++      uint8_t fourth = 0b1100'0000;
++      do {
++        badTrailFour[3] = fourth;
++        ExpectBadTrailingUnit(badTrailFour, 4);
++        if (fourth == 0b1111'1111) {
++          break;
++        }
++
++        fourth++;
++      } while (true);
++    }
++  }
++}
++
++static void
++TestBadSurrogate()
++{
++  // These tests are actually exhaustive.
++
++  ExpectValidCodePoint("\xED\x9F\xBF", 0xD7FF); // last before surrogates
++  ExpectValidCodePoint("\xEE\x80\x80", 0xE000); // first after surrogates
++
++  // First invalid surrogate encoding is { 0xED, 0xA0, 0x80 }.  Last invalid
++  // surrogate encoding is { 0xED, 0xBF, 0xBF }.
++
++  char badSurrogate[] = { '\xED', '\0', '\0', '\0' };
++
++  for (char32_t c = 0xD800; c < 0xE000; c++) {
++    badSurrogate[1] = 0b1000'0000 ^ ((c & 0b1111'1100'0000) >> 6);
++    badSurrogate[2] = 0b1000'0000 ^ ((c & 0b0000'0011'1111));
++
++    ExpectBadCodePoint(badSurrogate, c, 3);
++  }
++}
++
++static void
++TestBadTooBig()
++{
++  // These tests are actually exhaustive.
++
++  ExpectValidCodePoint("\xF4\x8F\xBF\xBF", 0x10'FFFF); // last code point
++
++  // Four-byte code points are
++  //
++  //   0b1111'0xxx 0b10xx'xxxx 0b10xx'xxxx 0b10xx'xxxx
++  //
++  // with 3 + 6 + 6 + 6 == 21 unconstrained bytes, so the structurally
++  // representable limit (exclusive) is 2**21 - 1 == 2097152.
++
++  char tooLargeCodePoint[] = { '\0', '\0', '\0', '\0', '\0' };
++
++  for (char32_t c = 0x11'0000; c < (1 << 21); c++) {
++    tooLargeCodePoint[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18);
++    tooLargeCodePoint[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12);
++    tooLargeCodePoint[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6);
++    tooLargeCodePoint[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111));
+ 
+-  static const unsigned char greatestSurrogate[] = { 0xED, 0xBF, 0xBF };
+-  MOZ_RELEASE_ASSERT(!IsValidUtf8(greatestSurrogate, ArrayLength(greatestSurrogate)));
++    ExpectBadCodePoint(tooLargeCodePoint, c, 4);
++  }
++}
++
++static void
++TestBadCodePoint()
++{
++  TestBadSurrogate();
++  TestBadTooBig();
++}
++
++static void
++TestNotShortestForm()
++{
++  {
++    // One-byte in two-byte.
++
++    char oneInTwo[] = { '\0', '\0', '\0' };
++
++    for (char32_t c = '\0'; c < 0x80; c++) {
++      oneInTwo[0] = 0b1100'0000 ^ ((c & 0b0111'1100'0000) >> 6);
++      oneInTwo[1] = 0b1000'0000 ^ ((c & 0b0000'0011'1111));
++
++      ExpectNotShortestForm(oneInTwo, c, 2);
++    }
++
++    // One-byte in three-byte.
++
++    char oneInThree[] = { '\0', '\0', '\0', '\0' };
++
++    for (char32_t c = '\0'; c < 0x80; c++) {
++      oneInThree[0] = 0b1110'0000 ^ ((c & 0b1111'0000'0000'0000) >> 12);
++      oneInThree[1] = 0b1000'0000 ^ ((c & 0b0000'1111'1100'0000) >> 6);
++      oneInThree[2] = 0b1000'0000 ^ ((c & 0b0000'0000'0011'1111));
++
++      ExpectNotShortestForm(oneInThree, c, 3);
++    }
++
++    // One-byte in four-byte.
++
++    char oneInFour[] = { '\0', '\0', '\0', '\0', '\0' };
++
++    for (char32_t c = '\0'; c < 0x80; c++) {
++      oneInFour[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18);
++      oneInFour[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12);
++      oneInFour[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6);
++      oneInFour[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111));
++
++      ExpectNotShortestForm(oneInFour, c, 4);
++    }
++  }
++
++  {
++    // Two-byte in three-byte.
+ 
+-  static const unsigned char justAfterSurrogates[] = { 0xEE, 0x80, 0x80 };
+-  MOZ_RELEASE_ASSERT(IsValidUtf8(justAfterSurrogates, ArrayLength(justAfterSurrogates)));
++    char twoInThree[] = { '\0', '\0', '\0', '\0' };
++
++    for (char32_t c = 0x80; c < 0x800; c++) {
++      twoInThree[0] = 0b1110'0000 ^ ((c & 0b1111'0000'0000'0000) >> 12);
++      twoInThree[1] = 0b1000'0000 ^ ((c & 0b0000'1111'1100'0000) >> 6);
++      twoInThree[2] = 0b1000'0000 ^ ((c & 0b0000'0000'0011'1111));
++
++      ExpectNotShortestForm(twoInThree, c, 3);
++    }
++
++    // Two-byte in four-byte.
++
++    char twoInFour[] = { '\0', '\0', '\0', '\0', '\0' };
++
++    for (char32_t c = 0x80; c < 0x800; c++) {
++      twoInFour[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18);
++      twoInFour[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12);
++      twoInFour[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6);
++      twoInFour[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111));
++
++      ExpectNotShortestForm(twoInFour, c, 4);
++    }
++  }
++
++  {
++    // Three-byte in four-byte.
++
++    char threeInFour[] = { '\0', '\0', '\0', '\0', '\0' };
++
++    for (char32_t c = 0x800; c < 0x1'0000; c++) {
++      threeInFour[0] = 0b1111'0000 ^ ((c & 0b1'1100'0000'0000'0000'0000) >> 18);
++      threeInFour[1] = 0b1000'0000 ^ ((c & 0b0'0011'1111'0000'0000'0000) >> 12);
++      threeInFour[2] = 0b1000'0000 ^ ((c & 0b0'0000'0000'1111'1100'0000) >> 6);
++      threeInFour[3] = 0b1000'0000 ^ ((c & 0b0'0000'0000'0000'0011'1111));
++
++      ExpectNotShortestForm(threeInFour, c, 4);
++    }
++  }
++}
++
++static void
++TestDecodeOneInvalidUtf8CodePoint()
++{
++  TestDecodeBadLeadUnit();
++  TestTooFewOrBadTrailingUnits();
++  TestBadCodePoint();
++  TestNotShortestForm();
++}
++
++static void
++TestDecodeOneUtf8CodePoint()
++{
++  TestDecodeOneValidUtf8CodePoint();
++  TestDecodeOneInvalidUtf8CodePoint();
+ }
+ 
+ int
+ main()
+ {
+   TestUtf8Unit();
+   TestIsValidUtf8();
++  TestDecodeOneUtf8CodePoint();
+   return 0;
+ }

+ 77 - 77
frg/work-js/mozilla-release/patches/1432135-63a1.patch

@@ -2,7 +2,7 @@
 # User Thi Huynh <so61pi.re@gmail.com>
 # User Thi Huynh <so61pi.re@gmail.com>
 # Date 1534842295 0
 # Date 1534842295 0
 # Node ID 2102f887e46bf3cb2b6a7fb00ed33640c9cb330e
 # Node ID 2102f887e46bf3cb2b6a7fb00ed33640c9cb330e
-# Parent  73fdb585bc3e4a24ec3a4187e4b7575cfbb4f661
+# Parent  48a8bc83f17aadcc3c5125d41bacde9577d1fc08
 Bug 1432135 - Rename TokenKind::{Lb,Rb,Lc,Rc,Lp,Rp} to their long names. r=jandem
 Bug 1432135 - Rename TokenKind::{Lb,Rb,Lc,Rc,Lp,Rp} to their long names. r=jandem
 
 
 Differential Revision: https://phabricator.services.mozilla.com/D3803
 Differential Revision: https://phabricator.services.mozilla.com/D3803
@@ -10,7 +10,7 @@ Differential Revision: https://phabricator.services.mozilla.com/D3803
 diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 --- a/js/src/frontend/Parser.cpp
 --- a/js/src/frontend/Parser.cpp
 +++ b/js/src/frontend/Parser.cpp
 +++ b/js/src/frontend/Parser.cpp
-@@ -1741,18 +1741,18 @@ PerHandlerParser<ParseHandler>::propagat
+@@ -1794,18 +1794,18 @@ PerHandlerParser<ParseHandler>::propagat
  
  
  template <typename CharT>
  template <typename CharT>
  bool
  bool
@@ -31,7 +31,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          return false;
          return false;
      }
      }
      return true;
      return true;
-@@ -2922,17 +2922,18 @@ bool
+@@ -2975,17 +2975,18 @@ bool
  GeneralParser<ParseHandler, CharT>::matchOrInsertSemicolon()
  GeneralParser<ParseHandler, CharT>::matchOrInsertSemicolon()
  {
  {
      TokenKind tt = TokenKind::Eof;
      TokenKind tt = TokenKind::Eof;
@@ -51,7 +51,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
           *        ^
           *        ^
           *        |
           *        |
           *        tried to insert semicolon here
           *        tried to insert semicolon here
-@@ -3055,17 +3056,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3108,17 +3109,17 @@ GeneralParser<ParseHandler, CharT>::func
          }
          }
      }
      }
  
  
@@ -70,7 +70,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
          firstTokenPos = pos();
          firstTokenPos = pos();
  
  
-@@ -3084,17 +3085,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3137,17 +3138,17 @@ GeneralParser<ParseHandler, CharT>::func
          return false;
          return false;
      handler.setFunctionFormalParametersAndBody(funcpn, argsbody);
      handler.setFunctionFormalParametersAndBody(funcpn, argsbody);
  
  
@@ -89,7 +89,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          bool hasRest = false;
          bool hasRest = false;
          bool hasDefault = false;
          bool hasDefault = false;
          bool duplicatedParam = false;
          bool duplicatedParam = false;
-@@ -3135,27 +3136,27 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3188,27 +3189,27 @@ GeneralParser<ParseHandler, CharT>::func
  
  
                  hasRest = true;
                  hasRest = true;
                  funbox->setHasRest();
                  funbox->setHasRest();
@@ -121,7 +121,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  }
                  }
  
  
                  funbox->hasDestructuringArgs = true;
                  funbox->hasDestructuringArgs = true;
-@@ -3254,26 +3255,26 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3307,26 +3308,26 @@ GeneralParser<ParseHandler, CharT>::func
              if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
              if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
                  return false;
                  return false;
              if (!matched)
              if (!matched)
@@ -150,7 +150,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  error(JSMSG_PAREN_AFTER_FORMAL);
                  error(JSMSG_PAREN_AFTER_FORMAL);
                  return false;
                  return false;
              }
              }
-@@ -3354,17 +3355,17 @@ GeneralParser<ParseHandler, CharT>::addE
+@@ -3407,17 +3408,17 @@ GeneralParser<ParseHandler, CharT>::addE
      Node pn = expr(InAllowed, yieldHandling, TripledotProhibited);
      Node pn = expr(InAllowed, yieldHandling, TripledotProhibited);
      if (!pn)
      if (!pn)
          return false;
          return false;
@@ -169,7 +169,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  }
  }
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
-@@ -3825,17 +3826,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3879,17 +3880,17 @@ GeneralParser<ParseHandler, CharT>::func
      }
      }
  
  
      // Parse the function body.
      // Parse the function body.
@@ -188,7 +188,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          anyChars.ungetToken();
          anyChars.ungetToken();
          bodyType = ExpressionBody;
          bodyType = ExpressionBody;
          funbox->setHasExprBody();
          funbox->setHasExprBody();
-@@ -3885,17 +3886,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3940,17 +3941,17 @@ GeneralParser<ParseHandler, CharT>::func
          // we don't need call AutoAwaitIsKeyword here.
          // we don't need call AutoAwaitIsKeyword here.
  
  
          uint32_t nameOffset = handler.getFunctionNameOffset(*pn, anyChars);
          uint32_t nameOffset = handler.getFunctionNameOffset(*pn, anyChars);
@@ -207,7 +207,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
          if (anyChars.hadError())
          if (anyChars.hadError())
              return false;
              return false;
-@@ -4235,17 +4236,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -4300,17 +4301,17 @@ GeneralParser<ParseHandler, CharT>::stat
      uint32_t statementBegin = 0;
      uint32_t statementBegin = 0;
      for (;;) {
      for (;;) {
          TokenKind tt = TokenKind::Eof;
          TokenKind tt = TokenKind::Eof;
@@ -226,7 +226,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              break;
              break;
          }
          }
          if (afterReturn) {
          if (afterReturn) {
-@@ -4281,23 +4282,23 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -4346,23 +4347,23 @@ GeneralParser<ParseHandler, CharT>::stat
  
  
      return pn;
      return pn;
  }
  }
@@ -252,7 +252,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      }
      }
      return pn;
      return pn;
  }
  }
-@@ -4519,52 +4520,52 @@ GeneralParser<ParseHandler, CharT>::bind
+@@ -4584,52 +4585,52 @@ GeneralParser<ParseHandler, CharT>::bind
  }
  }
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
@@ -309,7 +309,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              tokenStream.consumeKnownToken(TokenKind::TripleDot);
              tokenStream.consumeKnownToken(TokenKind::TripleDot);
              uint32_t begin = pos().begin;
              uint32_t begin = pos().begin;
  
  
-@@ -4653,30 +4654,30 @@ GeneralParser<ParseHandler, CharT>::obje
+@@ -4718,30 +4719,30 @@ GeneralParser<ParseHandler, CharT>::obje
          if (!matched)
          if (!matched)
              break;
              break;
          if (tt == TokenKind::TripleDot) {
          if (tt == TokenKind::TripleDot) {
@@ -342,7 +342,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      Node literal = handler.newArrayLiteral(begin);
      Node literal = handler.newArrayLiteral(begin);
      if (!literal)
      if (!literal)
          return null();
          return null();
-@@ -4687,17 +4688,17 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -4752,17 +4753,17 @@ GeneralParser<ParseHandler, CharT>::arra
               error(JSMSG_ARRAY_INIT_TOO_BIG);
               error(JSMSG_ARRAY_INIT_TOO_BIG);
               return null();
               return null();
           }
           }
@@ -361,7 +361,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
           if (tt == TokenKind::Comma) {
           if (tt == TokenKind::Comma) {
               if (!handler.addElision(literal, pos()))
               if (!handler.addElision(literal, pos()))
                   return null();
                   return null();
-@@ -4742,34 +4743,34 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -4807,34 +4808,34 @@ GeneralParser<ParseHandler, CharT>::arra
  
  
               if (tt == TokenKind::TripleDot) {
               if (tt == TokenKind::TripleDot) {
                   error(JSMSG_REST_WITH_COMMA);
                   error(JSMSG_REST_WITH_COMMA);
@@ -400,7 +400,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  typename ParseHandler::Node
  typename ParseHandler::Node
  GeneralParser<ParseHandler, CharT>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
  GeneralParser<ParseHandler, CharT>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
                                                                                  YieldHandling yieldHandling,
                                                                                  YieldHandling yieldHandling,
-@@ -4791,29 +4792,29 @@ GeneralParser<ParseHandler, CharT>::dest
+@@ -4856,29 +4857,29 @@ GeneralParser<ParseHandler, CharT>::dest
      return res;
      return res;
  }
  }
  
  
@@ -432,7 +432,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
  typename ParseHandler::Node
  typename ParseHandler::Node
-@@ -4830,18 +4831,18 @@ GeneralParser<ParseHandler, CharT>::expr
+@@ -4895,18 +4896,18 @@ GeneralParser<ParseHandler, CharT>::expr
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
  typename ParseHandler::Node
  typename ParseHandler::Node
  GeneralParser<ParseHandler, CharT>::declarationPattern(DeclarationKind declKind, TokenKind tt,
  GeneralParser<ParseHandler, CharT>::declarationPattern(DeclarationKind declKind, TokenKind tt,
@@ -453,7 +453,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      if (initialDeclaration && forHeadKind) {
      if (initialDeclaration && forHeadKind) {
          bool isForIn, isForOf;
          bool isForIn, isForOf;
          if (!matchInOrOf(&isForIn, &isForOf))
          if (!matchInOrOf(&isForIn, &isForOf))
-@@ -5054,17 +5055,17 @@ GeneralParser<ParseHandler, CharT>::decl
+@@ -5119,17 +5120,17 @@ GeneralParser<ParseHandler, CharT>::decl
      do {
      do {
          MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
          MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
                        *forHeadKind == ParseNodeKind::ForHead);
                        *forHeadKind == ParseNodeKind::ForHead);
@@ -472,7 +472,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              return null();
              return null();
  
  
          handler.addList(decl, binding);
          handler.addList(decl, binding);
-@@ -5110,25 +5111,25 @@ GeneralParser<ParseHandler, CharT>::lexi
+@@ -5175,25 +5176,25 @@ GeneralParser<ParseHandler, CharT>::lexi
  
  
      return decl;
      return decl;
  }
  }
@@ -500,7 +500,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              }
              }
  
  
              Rooted<PropertyName*> importName(context, anyChars.currentName());
              Rooted<PropertyName*> importName(context, anyChars.currentName());
-@@ -5177,17 +5178,17 @@ Parser<FullParseHandler, CharT>::namedIm
+@@ -5242,17 +5243,17 @@ Parser<FullParseHandler, CharT>::namedIm
                  return false;
                  return false;
  
  
              handler.addList(importSpecSet, importSpec);
              handler.addList(importSpecSet, importSpec);
@@ -519,7 +519,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              }
              }
          }
          }
      } else {
      } else {
-@@ -5248,17 +5249,17 @@ Parser<FullParseHandler, CharT>::importD
+@@ -5313,17 +5314,17 @@ Parser<FullParseHandler, CharT>::importD
      if (!importSpecSet)
      if (!importSpecSet)
          return null();
          return null();
  
  
@@ -538,7 +538,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              // 'a' as the binding name. This is equivalent to
              // 'a' as the binding name. This is equivalent to
              // |import { default as a } from 'b'|.
              // |import { default as a } from 'b'|.
              Node importName = newName(context->names().default_);
              Node importName = newName(context->names().default_);
-@@ -5285,17 +5286,17 @@ Parser<FullParseHandler, CharT>::importD
+@@ -5350,17 +5351,17 @@ Parser<FullParseHandler, CharT>::importD
              if (!tokenStream.peekToken(&tt))
              if (!tokenStream.peekToken(&tt))
                  return null();
                  return null();
  
  
@@ -557,7 +557,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      return null();
                      return null();
              }
              }
          } else {
          } else {
-@@ -5729,30 +5730,30 @@ GeneralParser<ParseHandler, CharT>::chec
+@@ -5794,30 +5795,30 @@ GeneralParser<ParseHandler, CharT>::chec
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
  typename ParseHandler::Node
  typename ParseHandler::Node
@@ -590,7 +590,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
          }
  
  
          Node bindingName = newName(anyChars.currentName());
          Node bindingName = newName(anyChars.currentName());
-@@ -5777,17 +5778,17 @@ GeneralParser<ParseHandler, CharT>::expo
+@@ -5842,17 +5843,17 @@ GeneralParser<ParseHandler, CharT>::expo
              return null();
              return null();
  
  
          handler.addList(kid, exportSpec);
          handler.addList(kid, exportSpec);
@@ -609,7 +609,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
          }
      }
      }
  
  
-@@ -6077,17 +6078,17 @@ GeneralParser<ParseHandler, CharT>::expo
+@@ -6142,17 +6143,17 @@ GeneralParser<ParseHandler, CharT>::expo
  
  
      TokenKind tt;
      TokenKind tt;
      if (!tokenStream.getToken(&tt))
      if (!tokenStream.getToken(&tt))
@@ -628,7 +628,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
        case TokenKind::Function:
        case TokenKind::Function:
          return exportFunctionDeclaration(begin, pos().begin);
          return exportFunctionDeclaration(begin, pos().begin);
  
  
-@@ -6313,17 +6314,17 @@ GeneralParser<ParseHandler, CharT>::matc
+@@ -6378,17 +6379,17 @@ GeneralParser<ParseHandler, CharT>::matc
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
  bool
  bool
@@ -647,7 +647,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      // Super-duper easy case: |for (;| is a C-style for-loop with no init
      // Super-duper easy case: |for (;| is a C-style for-loop with no init
      // component.
      // component.
      if (tt == TokenKind::Semi) {
      if (tt == TokenKind::Semi) {
-@@ -6485,17 +6486,17 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6550,17 +6551,17 @@ GeneralParser<ParseHandler, CharT>::forS
              return null();
              return null();
  
  
          if (matched) {
          if (matched) {
@@ -666,7 +666,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      // ParseNodeKind::ForOf depending on the loop type.
      // ParseNodeKind::ForOf depending on the loop type.
      ParseNodeKind headKind;
      ParseNodeKind headKind;
  
  
-@@ -6565,25 +6566,25 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6630,25 +6631,25 @@ GeneralParser<ParseHandler, CharT>::forS
          }
          }
  
  
          MUST_MATCH_TOKEN_MOD(TokenKind::Semi, TokenStream::Operand, JSMSG_SEMI_AFTER_FOR_COND);
          MUST_MATCH_TOKEN_MOD(TokenKind::Semi, TokenStream::Operand, JSMSG_SEMI_AFTER_FOR_COND);
@@ -694,7 +694,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      } else {
      } else {
          MOZ_ASSERT(headKind == ParseNodeKind::ForIn || headKind == ParseNodeKind::ForOf);
          MOZ_ASSERT(headKind == ParseNodeKind::ForIn || headKind == ParseNodeKind::ForOf);
  
  
-@@ -6597,17 +6598,17 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6662,17 +6663,17 @@ GeneralParser<ParseHandler, CharT>::forS
              stmt.refineForKind(StatementKind::ForInLoop);
              stmt.refineForKind(StatementKind::ForInLoop);
          } else {
          } else {
              stmt.refineForKind(StatementKind::ForOfLoop);
              stmt.refineForKind(StatementKind::ForOfLoop);
@@ -713,7 +713,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      }
      }
  
  
      Node body = statement(yieldHandling);
      Node body = statement(yieldHandling);
-@@ -6626,40 +6627,40 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6691,40 +6692,40 @@ GeneralParser<ParseHandler, CharT>::forS
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
  typename ParseHandler::Node
  typename ParseHandler::Node
@@ -758,7 +758,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
            case TokenKind::Default:
            case TokenKind::Default:
              if (seenDefault) {
              if (seenDefault) {
                  error(JSMSG_TOO_MANY_DEFAULTS);
                  error(JSMSG_TOO_MANY_DEFAULTS);
-@@ -6687,17 +6688,17 @@ GeneralParser<ParseHandler, CharT>::swit
+@@ -6752,17 +6753,17 @@ GeneralParser<ParseHandler, CharT>::swit
              return null();
              return null();
  
  
          bool afterReturn = false;
          bool afterReturn = false;
@@ -777,7 +777,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              Node stmt = statementListItem(yieldHandling);
              Node stmt = statementListItem(yieldHandling);
              if (!stmt)
              if (!stmt)
                  return null();
                  return null();
-@@ -6817,17 +6818,17 @@ GeneralParser<ParseHandler, CharT>::retu
+@@ -6882,17 +6883,17 @@ GeneralParser<ParseHandler, CharT>::retu
      Node exprNode;
      Node exprNode;
      TokenKind tt = TokenKind::Eof;
      TokenKind tt = TokenKind::Eof;
      if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
      if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
@@ -796,7 +796,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              return null();
              return null();
        }
        }
      }
      }
-@@ -6860,19 +6861,19 @@ GeneralParser<ParseHandler, CharT>::yiel
+@@ -6925,19 +6926,19 @@ GeneralParser<ParseHandler, CharT>::yiel
        // quirk in the grammar.
        // quirk in the grammar.
        case TokenKind::Eol:
        case TokenKind::Eol:
        // The rest of these make up the complete set of tokens that can
        // The rest of these make up the complete set of tokens that can
@@ -819,7 +819,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          anyChars.addModifierException(TokenStream::NoneIsOperand);
          anyChars.addModifierException(TokenStream::NoneIsOperand);
          break;
          break;
        case TokenKind::Mul:
        case TokenKind::Mul:
-@@ -6901,23 +6902,23 @@ GeneralParser<ParseHandler, CharT>::with
+@@ -6966,23 +6967,23 @@ GeneralParser<ParseHandler, CharT>::with
      // use strictModeError directly.  But while 'with' is forbidden in strict
      // use strictModeError directly.  But while 'with' is forbidden in strict
      // mode code, it doesn't even merit a warning in non-strict code.  See
      // mode code, it doesn't even merit a warning in non-strict code.  See
      // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
      // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
@@ -845,7 +845,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          if (!innerBlock)
          if (!innerBlock)
              return null();
              return null();
      }
      }
-@@ -6998,17 +6999,17 @@ GeneralParser<ParseHandler, CharT>::thro
+@@ -7063,17 +7064,17 @@ GeneralParser<ParseHandler, CharT>::thro
  {
  {
      MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Throw));
      MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Throw));
      uint32_t begin = pos().begin;
      uint32_t begin = pos().begin;
@@ -864,7 +864,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          return null();
          return null();
      }
      }
  
  
-@@ -7036,41 +7037,41 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7101,41 +7102,41 @@ GeneralParser<ParseHandler, CharT>::tryS
       * kid3 is the finally statement
       * kid3 is the finally statement
       *
       *
       * catch nodes are binary.
       * catch nodes are binary.
@@ -910,7 +910,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      TokenKind tt;
      TokenKind tt;
      if (!tokenStream.getToken(&tt))
      if (!tokenStream.getToken(&tt))
          return null();
          return null();
-@@ -7086,30 +7087,30 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7151,30 +7152,30 @@ GeneralParser<ParseHandler, CharT>::tryS
  
  
          /*
          /*
           * Legal catch forms are:
           * Legal catch forms are:
@@ -945,7 +945,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
                default: {
                default: {
                  if (!TokenKindIsPossibleIdentifierName(tt)) {
                  if (!TokenKindIsPossibleIdentifierName(tt)) {
-@@ -7120,19 +7121,19 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7185,19 +7186,19 @@ GeneralParser<ParseHandler, CharT>::tryS
                  catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
                  catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
                                                yieldHandling);
                                                yieldHandling);
                  if (!catchName)
                  if (!catchName)
@@ -968,7 +968,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
          catchScope = finishLexicalScope(scope, catchBody);
          catchScope = finishLexicalScope(scope, catchBody);
          if (!catchScope)
          if (!catchScope)
-@@ -7144,34 +7145,34 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7209,34 +7210,34 @@ GeneralParser<ParseHandler, CharT>::tryS
  
  
          if (!tokenStream.getToken(&tt, TokenStream::Operand))
          if (!tokenStream.getToken(&tt, TokenStream::Operand))
              return null();
              return null();
@@ -1005,7 +1005,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      if (!catchScope && !finallyBlock) {
      if (!catchScope && !finallyBlock) {
          error(JSMSG_CATCH_OR_FINALLY);
          error(JSMSG_CATCH_OR_FINALLY);
          return null();
          return null();
-@@ -7201,17 +7202,17 @@ GeneralParser<ParseHandler, CharT>::catc
+@@ -7266,17 +7267,17 @@ GeneralParser<ParseHandler, CharT>::catc
      // block, so declare the name in the inner scope.
      // block, so declare the name in the inner scope.
      if (!scope.addCatchParameters(pc, catchParamScope))
      if (!scope.addCatchParameters(pc, catchParamScope))
          return null();
          return null();
@@ -1024,7 +1024,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      scope.removeCatchParameters(pc, catchParamScope);
      scope.removeCatchParameters(pc, catchParamScope);
      return finishLexicalScope(scope, list);
      return finishLexicalScope(scope, list);
  }
  }
-@@ -7316,44 +7317,44 @@ GeneralParser<ParseHandler, CharT>::clas
+@@ -7381,44 +7382,44 @@ GeneralParser<ParseHandler, CharT>::clas
      if (hasHeritage) {
      if (hasHeritage) {
          if (!tokenStream.getToken(&tt))
          if (!tokenStream.getToken(&tt))
              return null();
              return null();
@@ -1073,7 +1073,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
          }
  
  
          uint32_t nameOffset;
          uint32_t nameOffset;
-@@ -7389,28 +7390,28 @@ GeneralParser<ParseHandler, CharT>::clas
+@@ -7454,28 +7455,28 @@ GeneralParser<ParseHandler, CharT>::clas
              errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
              errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
              return null();
              return null();
          }
          }
@@ -1104,7 +1104,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          // parsing and will be amended when class parsing finishes below.
          // parsing and will be amended when class parsing finishes below.
          Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
          Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
                                     propType, funName);
                                     propType, funName);
-@@ -7478,17 +7479,17 @@ bool
+@@ -7543,17 +7544,17 @@ bool
  ParserBase::nextTokenContinuesLetDeclaration(TokenKind next)
  ParserBase::nextTokenContinuesLetDeclaration(TokenKind next)
  {
  {
      MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Let));
      MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Let));
@@ -1123,7 +1123,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      //   let;
      //   let;
      //
      //
      // Static semantics in §13.3.1.1 turn a LexicalDeclaration that binds
      // Static semantics in §13.3.1.1 turn a LexicalDeclaration that binds
-@@ -7523,17 +7524,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7588,17 +7589,17 @@ GeneralParser<ParseHandler, CharT>::stat
          return null();
          return null();
  
  
      TokenKind tt;
      TokenKind tt;
@@ -1142,7 +1142,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
        // EmptyStatement
        // EmptyStatement
        case TokenKind::Semi:
        case TokenKind::Semi:
-@@ -7572,32 +7573,32 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7637,32 +7638,32 @@ GeneralParser<ParseHandler, CharT>::stat
          if (!tokenStream.peekToken(&next))
          if (!tokenStream.peekToken(&next))
              return null();
              return null();
  
  
@@ -1178,7 +1178,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              if (forbiddenLetDeclaration) {
              if (forbiddenLetDeclaration) {
                  error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
                  error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
                  return null();
                  return null();
-@@ -7741,17 +7742,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7806,17 +7807,17 @@ GeneralParser<ParseHandler, CharT>::stat
          return null();
          return null();
  
  
      TokenKind tt;
      TokenKind tt;
@@ -1197,7 +1197,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
        // EmptyStatement
        // EmptyStatement
        case TokenKind::Semi:
        case TokenKind::Semi:
-@@ -7950,23 +7951,23 @@ GeneralParser<ParseHandler, CharT>::expr
+@@ -8015,23 +8016,23 @@ GeneralParser<ParseHandler, CharT>::expr
          // directly under CoverParenthesizedExpressionAndArrowParameterList,
          // directly under CoverParenthesizedExpressionAndArrowParameterList,
          // and the next two tokens are closing parenthesis and arrow. If all
          // and the next two tokens are closing parenthesis and arrow. If all
          // are present allow the trailing comma.
          // are present allow the trailing comma.
@@ -1224,7 +1224,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              }
              }
          }
          }
  
  
-@@ -8292,17 +8293,17 @@ GeneralParser<ParseHandler, CharT>::assi
+@@ -8357,17 +8358,17 @@ GeneralParser<ParseHandler, CharT>::assi
  
  
              TokenKind nextSameLine = TokenKind::Eof;
              TokenKind nextSameLine = TokenKind::Eof;
              if (!tokenStream.peekTokenSameLine(&nextSameLine))
              if (!tokenStream.peekTokenSameLine(&nextSameLine))
@@ -1243,7 +1243,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          Node pn = handler.newArrowFunction(pos());
          Node pn = handler.newArrowFunction(pos());
          if (!pn)
          if (!pn)
              return null();
              return null();
-@@ -8608,17 +8609,17 @@ typename ParseHandler::Node
+@@ -8677,17 +8678,17 @@ typename ParseHandler::Node
  GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bool* isSpread,
  GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bool* isSpread,
                                                   PossibleError* possibleError /* = nullptr */)
                                                   PossibleError* possibleError /* = nullptr */)
  {
  {
@@ -1262,7 +1262,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
      while (true) {
      while (true) {
          bool spread = false;
          bool spread = false;
-@@ -8646,21 +8647,21 @@ GeneralParser<ParseHandler, CharT>::argu
+@@ -8715,21 +8716,21 @@ GeneralParser<ParseHandler, CharT>::argu
          if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
          if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
              return null();
              return null();
          if (!matched)
          if (!matched)
@@ -1286,7 +1286,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  bool
  bool
  ParserBase::checkAndMarkSuperScope()
  ParserBase::checkAndMarkSuperScope()
  {
  {
-@@ -8700,17 +8701,17 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8769,17 +8770,17 @@ GeneralParser<ParseHandler, CharT>::memb
              tt = anyChars.currentToken().type;
              tt = anyChars.currentToken().type;
              Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
              Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
                                         /* allowCallSyntax = */ false,
                                         /* allowCallSyntax = */ false,
@@ -1305,7 +1305,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  args = argumentList(yieldHandling, &isSpread);
                  args = argumentList(yieldHandling, &isSpread);
              } else {
              } else {
                  args = handler.newArguments(pos());
                  args = handler.newArguments(pos());
-@@ -8768,41 +8769,41 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8837,41 +8838,41 @@ GeneralParser<ParseHandler, CharT>::memb
  
  
                  nextMember = handler.newPropertyAccess(lhs, name);
                  nextMember = handler.newPropertyAccess(lhs, name);
                  if (!nextMember)
                  if (!nextMember)
@@ -1351,7 +1351,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  // generator, we still inherit the yieldHandling of the
                  // generator, we still inherit the yieldHandling of the
                  // memberExpression, per spec. Curious.
                  // memberExpression, per spec. Curious.
                  bool isSpread = false;
                  bool isSpread = false;
-@@ -8837,17 +8838,17 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8906,17 +8907,17 @@ GeneralParser<ParseHandler, CharT>::memb
                      // right syntax.
                      // right syntax.
                      if (prop == context->names().apply) {
                      if (prop == context->names().apply) {
                          op = JSOP_FUNAPPLY;
                          op = JSOP_FUNAPPLY;
@@ -1370,7 +1370,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                          // part of the CoverCallExpressionAndAsyncArrowHead
                          // part of the CoverCallExpressionAndAsyncArrowHead
                          // syntax when the initial name is "async".
                          // syntax when the initial name is "async".
                          maybeAsyncArrow = true;
                          maybeAsyncArrow = true;
-@@ -8866,17 +8867,17 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8935,17 +8936,17 @@ GeneralParser<ParseHandler, CharT>::memb
                          // If we're in a method, mark the method as requiring
                          // If we're in a method, mark the method as requiring
                          // support for 'super', since direct eval code can use
                          // support for 'super', since direct eval code can use
                          // it. (If we're not in a method, that's fine, so
                          // it. (If we're not in a method, that's fine, so
@@ -1389,7 +1389,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      if (isSpread) {
                      if (isSpread) {
                          if (op == JSOP_EVAL)
                          if (op == JSOP_EVAL)
                              op = JSOP_SPREADEVAL;
                              op = JSOP_SPREADEVAL;
-@@ -9274,28 +9275,28 @@ GeneralParser<ParseHandler, CharT>::chec
+@@ -9336,28 +9337,28 @@ GeneralParser<ParseHandler, CharT>::chec
      return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError, possibleError);
      return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError, possibleError);
  }
  }
  
  
@@ -1420,7 +1420,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      } else {
      } else {
          anyChars.ungetToken();
          anyChars.ungetToken();
  
  
-@@ -9303,17 +9304,17 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -9365,17 +9366,17 @@ GeneralParser<ParseHandler, CharT>::arra
              if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
              if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
                  error(JSMSG_ARRAY_INIT_TOO_BIG);
                  error(JSMSG_ARRAY_INIT_TOO_BIG);
                  return null();
                  return null();
@@ -1439,7 +1439,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      return null();
                      return null();
                  continue;
                  continue;
              }
              }
-@@ -9364,17 +9365,17 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -9426,17 +9427,17 @@ GeneralParser<ParseHandler, CharT>::arra
                  return null();
                  return null();
              if (!matched)
              if (!matched)
                  break;
                  break;
@@ -1458,7 +1458,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      return literal;
      return literal;
  }
  }
  
  
-@@ -9385,17 +9386,17 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9447,17 +9448,17 @@ GeneralParser<ParseHandler, CharT>::prop
                                                   Node propList,
                                                   Node propList,
                                                   PropertyType* propType,
                                                   PropertyType* propType,
                                                   MutableHandleAtom propAtom)
                                                   MutableHandleAtom propAtom)
@@ -1477,7 +1477,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          // AsyncMethod[Yield, Await]:
          // AsyncMethod[Yield, Await]:
          //   async [no LineTerminator here] PropertyName[?Yield, ?Await] ...
          //   async [no LineTerminator here] PropertyName[?Yield, ?Await] ...
          //
          //
-@@ -9411,17 +9412,17 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9473,17 +9474,17 @@ GeneralParser<ParseHandler, CharT>::prop
          //   StringLiteral
          //   StringLiteral
          //   NumericLiteral
          //   NumericLiteral
          //
          //
@@ -1496,7 +1496,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
          }
      }
      }
  
  
-@@ -9453,17 +9454,17 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9515,17 +9516,17 @@ GeneralParser<ParseHandler, CharT>::prop
              break;
              break;
          }
          }
          propName = stringLiteral();
          propName = stringLiteral();
@@ -1515,7 +1515,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
        default: {
        default: {
          if (!TokenKindIsPossibleIdentifierName(ltok)) {
          if (!TokenKindIsPossibleIdentifierName(ltok)) {
              error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
              error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
-@@ -9509,18 +9510,18 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9571,18 +9572,18 @@ GeneralParser<ParseHandler, CharT>::prop
          if (tt == TokenKind::Number) {
          if (tt == TokenKind::Number) {
              tokenStream.consumeKnownToken(TokenKind::Number);
              tokenStream.consumeKnownToken(TokenKind::Number);
  
  
@@ -1536,7 +1536,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos());
          propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos());
          if (!propName)
          if (!propName)
              return null();
              return null();
-@@ -9537,32 +9538,32 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9599,32 +9600,32 @@ GeneralParser<ParseHandler, CharT>::prop
              error(JSMSG_BAD_PROP_ID);
              error(JSMSG_BAD_PROP_ID);
              return null();
              return null();
          }
          }
@@ -1571,7 +1571,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              *propType = PropertyType::GeneratorMethod;
              *propType = PropertyType::GeneratorMethod;
          else if (isAsync)
          else if (isAsync)
              *propType = PropertyType::AsyncMethod;
              *propType = PropertyType::AsyncMethod;
-@@ -9576,57 +9577,57 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9638,57 +9639,57 @@ GeneralParser<ParseHandler, CharT>::prop
  }
  }
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
@@ -1633,7 +1633,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              tokenStream.consumeKnownToken(TokenKind::TripleDot);
              tokenStream.consumeKnownToken(TokenKind::TripleDot);
              uint32_t begin = pos().begin;
              uint32_t begin = pos().begin;
  
  
-@@ -9777,17 +9778,17 @@ GeneralParser<ParseHandler, CharT>::obje
+@@ -9839,17 +9840,17 @@ GeneralParser<ParseHandler, CharT>::obje
                  Node propExpr = handler.newAssignment(ParseNodeKind::Assign, lhs, rhs);
                  Node propExpr = handler.newAssignment(ParseNodeKind::Assign, lhs, rhs);
                  if (!propExpr)
                  if (!propExpr)
                      return null();
                      return null();
@@ -1652,7 +1652,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                              return null();
                              return null();
                      }
                      }
                  }
                  }
-@@ -9811,17 +9812,17 @@ GeneralParser<ParseHandler, CharT>::obje
+@@ -9873,17 +9874,17 @@ GeneralParser<ParseHandler, CharT>::obje
          if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
          if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
              return null();
              return null();
          if (!matched)
          if (!matched)
@@ -1671,7 +1671,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  }
  }
  
  
  template <class ParseHandler, typename CharT>
  template <class ParseHandler, typename CharT>
-@@ -9974,50 +9975,50 @@ GeneralParser<ParseHandler, CharT>::prim
+@@ -10036,50 +10037,50 @@ GeneralParser<ParseHandler, CharT>::prim
  
  
      switch (tt) {
      switch (tt) {
        case TokenKind::Function:
        case TokenKind::Function:
@@ -1729,7 +1729,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
        case TokenKind::NoSubsTemplate:
        case TokenKind::NoSubsTemplate:
          return noSubstitutionUntaggedTemplate();
          return noSubstitutionUntaggedTemplate();
-@@ -10085,17 +10086,17 @@ GeneralParser<ParseHandler, CharT>::prim
+@@ -10147,17 +10148,17 @@ GeneralParser<ParseHandler, CharT>::prim
              error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
              error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
              return null();
              return null();
          }
          }
@@ -1748,7 +1748,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  return null();
                  return null();
              }
              }
          } else {
          } else {
-@@ -10106,46 +10107,46 @@ GeneralParser<ParseHandler, CharT>::prim
+@@ -10168,46 +10169,46 @@ GeneralParser<ParseHandler, CharT>::prim
              if (!TokenKindIsPossibleIdentifier(next)) {
              if (!TokenKindIsPossibleIdentifier(next)) {
                  error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next));
                  error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next));
                  return null();
                  return null();
@@ -1795,9 +1795,9 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
  
  template class PerHandlerParser<FullParseHandler>;
  template class PerHandlerParser<FullParseHandler>;
  template class PerHandlerParser<SyntaxParseHandler>;
  template class PerHandlerParser<SyntaxParseHandler>;
+ template class GeneralParser<FullParseHandler, Utf8Unit>;
+ template class GeneralParser<SyntaxParseHandler, Utf8Unit>;
  template class GeneralParser<FullParseHandler, char16_t>;
  template class GeneralParser<FullParseHandler, char16_t>;
- template class GeneralParser<SyntaxParseHandler, char16_t>;
- template class Parser<FullParseHandler, char16_t>;
 diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h
 diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h
 --- a/js/src/frontend/TokenKind.h
 --- a/js/src/frontend/TokenKind.h
 +++ b/js/src/frontend/TokenKind.h
 +++ b/js/src/frontend/TokenKind.h
@@ -1833,7 +1833,7 @@ diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h
 diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
 diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
 --- a/js/src/frontend/TokenStream.cpp
 --- a/js/src/frontend/TokenStream.cpp
 +++ b/js/src/frontend/TokenStream.cpp
 +++ b/js/src/frontend/TokenStream.cpp
-@@ -422,19 +422,19 @@ TokenStreamAnyChars::TokenStreamAnyChars
+@@ -438,19 +438,19 @@ TokenStreamAnyChars::TokenStreamAnyChars
      cx(cx),
      cx(cx),
      mutedErrors(options.mutedErrors()),
      mutedErrors(options.mutedErrors()),
      strictModeGetter(smg)
      strictModeGetter(smg)
@@ -1853,10 +1853,10 @@ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
  template<typename CharT>
  template<typename CharT>
  TokenStreamCharsBase<CharT>::TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length,
  TokenStreamCharsBase<CharT>::TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length,
                                                    size_t startOffset)
                                                    size_t startOffset)
-   : sourceUnits(chars, length, startOffset),
-     tokenbuf(cx)
+   : TokenStreamCharsShared(cx),
+     sourceUnits(chars, length, startOffset)
  {}
  {}
-@@ -1527,24 +1527,24 @@ enum FirstCharKind {
+@@ -1969,24 +1969,24 @@ enum FirstCharKind {
  // Plus:    43: '+'
  // Plus:    43: '+'
  // ZeroDigit:  48: '0'
  // ZeroDigit:  48: '0'
  // Space:   9, 11, 12, 32: '\t', '\v', '\f', ' '
  // Space:   9, 11, 12, 32: '\t', '\v', '\f', ' '
@@ -1890,7 +1890,7 @@ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
 diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
 diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
 --- a/js/src/wasm/AsmJS.cpp
 --- a/js/src/wasm/AsmJS.cpp
 +++ b/js/src/wasm/AsmJS.cpp
 +++ b/js/src/wasm/AsmJS.cpp
-@@ -7470,17 +7470,17 @@ CheckModuleExportObject(ModuleValidator&
+@@ -7477,17 +7477,17 @@ CheckModuleExportObject(ModuleValidator&
  static bool
  static bool
  CheckModuleReturn(ModuleValidator& m)
  CheckModuleReturn(ModuleValidator& m)
  {
  {
@@ -1909,7 +1909,7 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
      ParseNode* returnStmt = m.parser().statementListItem(YieldIsName);
      ParseNode* returnStmt = m.parser().statementListItem(YieldIsName);
      if (!returnStmt)
      if (!returnStmt)
          return false;
          return false;
-@@ -7502,17 +7502,17 @@ CheckModuleReturn(ModuleValidator& m)
+@@ -7509,17 +7509,17 @@ CheckModuleReturn(ModuleValidator& m)
  
  
  static bool
  static bool
  CheckModuleEnd(ModuleValidator &m)
  CheckModuleEnd(ModuleValidator &m)

+ 313 - 0
frg/work-js/mozilla-release/patches/1441333-1-60a1.patch

@@ -0,0 +1,313 @@
+# HG changeset patch
+# User Kris Maglione <maglione.k@gmail.com>
+# Date 1510450756 28800
+# Node ID f9eb113f179f94145a575f602e359186d71b2b34
+# Parent  b4e357795847c5cb2c79ecf660e581658af04f25
+Bug 1441333: Part 1 - Add helper to retrieve closest stack frame with a given principal. r=bz
+
+Most WebExtension APIs are async, and have fairly complicated error reporting
+semantics. As a result, when we report an error, the current JS stack has very
+little to do with the JS caller that triggered the error, which makes it
+difficult to diagnose.
+
+In order to improve the situation, we need to store the location of the caller
+at the start of an async operation, so we can tie the error to some marginally
+useful location. We don't have a reasonable way to do that now other than
+proactively creating an error object when the API is called, or creating a
+promise with a full async stack, both of which are too expensive.
+
+This helper instead returns a single SavedStack frame with a given principal,
+which should be considerably cheaper, and likely good enough to give a
+starting point for debugging cryptic errors.
+
+MozReview-Commit-ID: BTxhpZK9Fdz
+
+diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp
+--- a/dom/base/ChromeUtils.cpp
++++ b/dom/base/ChromeUtils.cpp
+@@ -616,10 +616,36 @@ ChromeUtils::IsOriginAttributesEqual(con
+                                      const dom::OriginAttributesDictionary& aB)
+ {
+   return aA.mAppId == aB.mAppId &&
+          aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
+          aA.mUserContextId == aB.mUserContextId &&
+          aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
+ }
+ 
++constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
++
++/* static */ void
++ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal, nsIPrincipal* aPrincipal,
++                               JS::MutableHandle<JSObject*> aRetval)
++{
++  JSContext* cx = aGlobal.Context();
++
++  auto* principals = nsJSPrincipals::get(aPrincipal);
++
++  JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
++
++  JS::RootedObject frame(cx);
++  if (!JS::CaptureCurrentStack(cx, &frame, mozilla::Move(captureMode))) {
++    JS_ClearPendingException(cx);
++    aRetval.set(nullptr);
++    return;
++  }
++
++  // FirstSubsumedFrame gets us a stack which stops at the first principal which
++  // is subsumed by the given principal. That means that we may have a lot of
++  // privileged frames that we don't care about at the top of the stack, though.
++  // We need to filter those out to get the frame we actually want.
++  aRetval.set(js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
++}
++
+ } // namespace dom
+ } // namespace mozilla
+diff --git a/dom/base/ChromeUtils.h b/dom/base/ChromeUtils.h
+--- a/dom/base/ChromeUtils.h
++++ b/dom/base/ChromeUtils.h
+@@ -155,14 +155,18 @@ public:
+                      JS::MutableHandle<JSObject*> aRetval,
+                      ErrorResult& aRv);
+ 
+   static void DefineModuleGetter(const GlobalObject& global,
+                                  JS::Handle<JSObject*> target,
+                                  const nsAString& id,
+                                  const nsAString& resourceURI,
+                                  ErrorResult& aRv);
++
++  static void
++  GetCallerLocation(const GlobalObject& global, nsIPrincipal* principal,
++                    JS::MutableHandle<JSObject*> aRetval);
+ };
+ 
+ } // namespace dom
+ } // namespace mozilla
+ 
+ #endif // mozilla_dom_ChromeUtils__
+diff --git a/dom/webidl/ChromeUtils.webidl b/dom/webidl/ChromeUtils.webidl
+--- a/dom/webidl/ChromeUtils.webidl
++++ b/dom/webidl/ChromeUtils.webidl
+@@ -253,16 +253,23 @@ partial namespace ChromeUtils {
+    * @param target The target object on which to define the property.
+    * @param id The name of the property to define, and of the symbol to
+    *           import.
+    * @param resourceURI The resource URI of the module, as passed to
+    *                    ChromeUtils.import.
+    */
+   [Throws]
+   void defineModuleGetter(object target, DOMString id, DOMString resourceURI);
++
++  /**
++   * Returns the scripted location of the first ancestor stack frame with a
++   * principal which is subsumed by the given principal. If no such frame
++   * exists on the call stack, returns null.
++   */
++  object? getCallerLocation(Principal principal);
+ };
+ 
+ /**
+  * Used by principals and the script security manager to represent origin
+  * attributes. The first dictionary is designed to contain the full set of
+  * OriginAttributes, the second is used for pattern-matching (i.e. does this
+  * OriginAttributesDictionary match the non-empty attributes in this pattern).
+  *
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -2985,16 +2985,25 @@ SetJitExceptionHandler(JitExceptionHandl
+  *
+  * Do NOT pass a non-SavedFrame object here.
+  *
+  * The savedFrame and cx do not need to be in the same compartment.
+  */
+ extern JS_FRIEND_API(JSObject*)
+ GetFirstSubsumedSavedFrame(JSContext* cx, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted);
+ 
++/**
++ * Get the first SavedFrame object in this SavedFrame stack whose principals are
++ * subsumed by the given |principals|. If there is no such frame, return nullptr.
++ *
++ * Do NOT pass a non-SavedFrame object here.
++ */
++extern JS_FRIEND_API(JSObject*)
++GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted);
++
+ extern JS_FRIEND_API(bool)
+ ReportIsNotFunction(JSContext* cx, JS::HandleValue v);
+ 
+ extern JS_FRIEND_API(JSObject*)
+ ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args);
+ 
+ /**
+  * Window and WindowProxy
+diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
+--- a/js/src/vm/SavedStacks.cpp
++++ b/js/src/vm/SavedStacks.cpp
+@@ -567,55 +567,89 @@ SavedFrameSubsumedByCaller(JSContext* cx
+         return cx->runningWithTrustedPrincipals();
+     if (framePrincipals == &ReconstructedSavedFramePrincipals::IsNotSystem)
+         return true;
+ 
+     return subsumes(currentCompartmentPrincipals, framePrincipals);
+ }
+ 
+ // Return the first SavedFrame in the chain that starts with |frame| whose
+-// principals are subsumed by |principals|, according to |subsumes|. If there is
+-// no such frame, return nullptr. |skippedAsync| is set to true if any of the
+-// skipped frames had the |asyncCause| property set, otherwise it is explicitly
+-// set to false.
++// for which the given match function returns true. If there is no such frame,
++// return nullptr. |skippedAsync| is set to true if any of the skipped frames
++// had the |asyncCause| property set, otherwise it is explicitly set to false.
++template<typename Matcher>
+ static SavedFrame*
+-GetFirstSubsumedFrame(JSContext* cx, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
+-                      bool& skippedAsync)
++GetFirstMatchedFrame(JSContext* cx, Matcher& matches,
++                     HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
++                     bool& skippedAsync)
+ {
+     skippedAsync = false;
+ 
+     RootedSavedFrame rootedFrame(cx, frame);
+     while (rootedFrame) {
+         if ((selfHosted == JS::SavedFrameSelfHosted::Include ||
+              !rootedFrame->isSelfHosted(cx)) &&
+-            SavedFrameSubsumedByCaller(cx, rootedFrame))
++            matches(cx, rootedFrame))
+         {
+             return rootedFrame;
+         }
+ 
+         if (rootedFrame->getAsyncCause())
+             skippedAsync = true;
+ 
+         rootedFrame = rootedFrame->getParent();
+     }
+ 
+     return nullptr;
+ }
+ 
++// Return the first SavedFrame in the chain that starts with |frame| whose
++// principals are subsumed by the principals of the context's current
++// compartment, according to |subsumes|. If there is no such frame, return
++// nullptr. |skippedAsync| is set to true if any of the skipped frames had the
++// |asyncCause| property set, otherwise it is explicitly set to false.
++static SavedFrame*
++GetFirstSubsumedFrame(JSContext* cx, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
++                      bool& skippedAsync)
++{
++    return GetFirstMatchedFrame(cx, SavedFrameSubsumedByCaller, frame, selfHosted, skippedAsync);
++}
++
+ JS_FRIEND_API(JSObject*)
+ GetFirstSubsumedSavedFrame(JSContext* cx, HandleObject savedFrame,
+                            JS::SavedFrameSelfHosted selfHosted)
+ {
+     if (!savedFrame)
+         return nullptr;
+     bool skippedAsync;
+     RootedSavedFrame frame(cx, &savedFrame->as<SavedFrame>());
+     return GetFirstSubsumedFrame(cx, frame, selfHosted, skippedAsync);
+ }
+ 
++JS_FRIEND_API(JSObject*)
++GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals,
++                           HandleObject savedFrame,
++                           JS::SavedFrameSelfHosted selfHosted)
++{
++    if (!savedFrame)
++        return nullptr;
++
++    auto subsumes = cx->runtime()->securityCallbacks->subsumes;
++    if (!subsumes)
++        return nullptr;
++
++    auto matcher = [&](JSContext* cx, HandleSavedFrame frame) -> bool {
++        return subsumes(principals, frame->getPrincipals());
++    };
++
++    bool skippedAsync;
++    RootedSavedFrame frame(cx, &savedFrame->as<SavedFrame>());
++    return GetFirstMatchedFrame(cx, matcher, frame, selfHosted, skippedAsync);
++}
++
+ static MOZ_MUST_USE bool
+ SavedFrame_checkThis(JSContext* cx, CallArgs& args, const char* fnName,
+                      MutableHandleObject frame)
+ {
+     const Value& thisValue = args.thisv();
+ 
+     if (!thisValue.isObject()) {
+         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
+diff --git a/js/xpconnect/tests/unit/test_getCallerLocation.js b/js/xpconnect/tests/unit/test_getCallerLocation.js
+new file mode 100644
+--- /dev/null
++++ b/js/xpconnect/tests/unit/test_getCallerLocation.js
+@@ -0,0 +1,45 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++"use strict";
++
++Cu.importGlobalProperties(["ChromeUtils"]);
++
++add_task(async function() {
++  const sandbox = Cu.Sandbox("http://example.com/");
++
++  function foo() {
++    return bar();
++  }
++
++  function bar() {
++    return baz();
++  }
++
++  function baz() {
++    return ChromeUtils.getCallerLocation(Cu.getObjectPrincipal(sandbox));
++  }
++
++  Cu.evalInSandbox(`
++    function it() {
++      // Use map() to throw a self-hosted frame on the stack, which we
++      // should filter out.
++      return [0].map(foo)[0];
++    }
++    function thing() {
++      return it();
++    }
++  `, sandbox, undefined, "thing.js");
++
++  Cu.exportFunction(foo, sandbox, {defineAs: "foo"});
++
++  let frame = sandbox.thing();
++
++  equal(frame.source, "thing.js", "Frame source");
++  equal(frame.line, 5, "Frame line");
++  equal(frame.column, 14, "Frame column");
++  equal(frame.functionDisplayName, "it", "Frame function name");
++  equal(frame.parent, null, "Frame parent");
++
++  equal(String(frame), "it@thing.js:5:14\n", "Stringified frame");
++});
+diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini
+--- a/js/xpconnect/tests/unit/xpcshell.ini
++++ b/js/xpconnect/tests/unit/xpcshell.ini
+@@ -67,16 +67,17 @@ support-files =
+ [test_classesByID_instanceof.js]
+ [test_compileScript.js]
+ [test_deepFreezeClone.js]
+ [test_defineModuleGetter.js]
+ [test_file.js]
+ [test_blob.js]
+ [test_blob2.js]
+ [test_file2.js]
++[test_getCallerLocation.js]
+ [test_import.js]
+ [test_import_fail.js]
+ [test_interposition.js]
+ [test_isModuleLoaded.js]
+ [test_js_weak_references.js]
+ [test_onGarbageCollection-01.js]
+ head = head_ongc.js
+ [test_onGarbageCollection-02.js]

+ 128 - 0
frg/work-js/mozilla-release/patches/1454285-3-63a1.patch

@@ -0,0 +1,128 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1535006893 -32400
+# Node ID ac3e5dee7c57d25faebadbea06c57c2b4b216878
+# Parent  d17c68d95b1630adf72fe81ff214b0acdf4cd590
+Bug 1454285 - Part 3: Add test. r=jwalden
+
+diff --git a/js/src/frontend/ForOfLoopControl.cpp b/js/src/frontend/ForOfLoopControl.cpp
+--- a/js/src/frontend/ForOfLoopControl.cpp
++++ b/js/src/frontend/ForOfLoopControl.cpp
+@@ -119,16 +119,25 @@ ForOfLoopControl::emitIteratorCloseInSco
+                                        allowSelfHosted_))
+     {
+         return false;
+     }
+     ptrdiff_t end = bce->offset();
+     return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
+ }
+ 
++// Since we're in the middle of emitting code that will leave
++// |bce->innermostEmitterScope()|, passing the innermost emitter scope to
++// emitIteratorCloseInScope and looking up .generator there would be very,
++// very wrong.  We'd find .generator in the function environment, and we'd
++// compute a NameLocation with the correct slot, but we'd compute a
++// hop-count to the function environment that was too big.  At runtime we'd
++// either crash, or we'd find a user-controllable value in that slot, and
++// Very Bad Things would ensue as we reinterpreted that value as an
++// iterator.
+ bool
+ ForOfLoopControl::emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
+                                                       EmitterScope& currentScope,
+                                                       bool isTarget)
+ {
+     // Pop unnecessary value from the stack.  Effectively this means
+     // leaving try-catch block.  However, the performing IteratorClose can
+     // reach the depth for try-catch, and effectively re-enter the
+diff --git a/js/src/jit-test/tests/auto-regress/bug1454285.js b/js/src/jit-test/tests/auto-regress/bug1454285.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/auto-regress/bug1454285.js
+@@ -0,0 +1,86 @@
++// IteratorClose in for-await-of with block-scoped function.
++
++// Non-local-jump without target.
++
++(async function() {
++    for await (let c of []) {
++        function f() {};
++        return;
++    }
++})();
++(async function() {
++    for await (let c of []) {
++        function f() {};
++        break;
++    }
++})();
++(async function() {
++    for await (let c of []) {
++        function f() {};
++        continue;
++    }
++})();
++
++// Non-local-jump with target.
++
++(async function() {
++    for (let x of []) {
++        x: for (let y of []) {
++            for await (let c of []) {
++                function f() {};
++                return;
++            }
++        }
++    }
++})();
++(async function() {
++    for (let x of []) {
++        x: for (let y of []) {
++            for await (let c of []) {
++                function f() {};
++                break x;
++            }
++        }
++    }
++})();
++(async function() {
++    for (let x of []) {
++        x: for (let y of []) {
++            for await (let c of []) {
++                function f() {};
++                continue x;
++            }
++        }
++    }
++})();
++
++(async function() {
++    for await (let x of []) {
++        x: for await (let y of []) {
++            for await (let c of []) {
++                function f() {};
++                return;
++            }
++        }
++    }
++})();
++(async function() {
++    for await (let x of []) {
++        x: for await (let y of []) {
++            for await (let c of []) {
++                function f() {};
++                break x;
++            }
++        }
++    }
++})();
++(async function() {
++    for await (let x of []) {
++        x: for await (let y of []) {
++            for await (let c of []) {
++                function f() {};
++                continue x;
++            }
++        }
++    }
++})();
+

+ 15 - 15
frg/work-js/mozilla-release/patches/1461938-20-62a1.patch

@@ -3,7 +3,7 @@
 # Date 1527066267 -7200
 # Date 1527066267 -7200
 #      Wed May 23 11:04:27 2018 +0200
 #      Wed May 23 11:04:27 2018 +0200
 # Node ID 716d49972dba8f3754814c280dd3782a9964dada
 # Node ID 716d49972dba8f3754814c280dd3782a9964dada
-# Parent  ee885447fceb0ec6a060c6daac3f369550c5b36f
+# Parent  b837eaad3216cef4ba8a128c5c9d26a4248b998f
 Bug 1461938 part 20 - Move principals and isSystem from JSCompartment to JS::Realm. r=luke
 Bug 1461938 part 20 - Move principals and isSystem from JSCompartment to JS::Realm. r=luke
 
 
 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
@@ -620,12 +620,12 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
  }
  }
  
  
  // Return the first SavedFrame in the chain that starts with |frame| whose
  // Return the first SavedFrame in the chain that starts with |frame| whose
- // principals are subsumed by |principals|, according to |subsumes|. If there is
- // no such frame, return nullptr. |skippedAsync| is set to true if any of the
- // skipped frames had the |asyncCause| property set, otherwise it is explicitly
- // set to false.
+ // for which the given match function returns true. If there is no such frame,
+ // return nullptr. |skippedAsync| is set to true if any of the skipped frames
+ // had the |asyncCause| property set, otherwise it is explicitly set to false.
+ template<typename Matcher>
  static SavedFrame*
  static SavedFrame*
-@@ -732,39 +732,39 @@ namespace {
+@@ -766,39 +766,39 @@ namespace {
  // stack) but we're working with an SavedFrame object that was captured in
  // stack) but we're working with an SavedFrame object that was captured in
  // unprivileged code.  If so, drop privileges down to its level.  The idea is
  // unprivileged code.  If so, drop privileges down to its level.  The idea is
  // that this way devtools code that's asking an exception object for a stack to
  // that this way devtools code that's asking an exception object for a stack to
@@ -675,7 +675,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
  
  
   private:
   private:
      Maybe<JSAutoRealm> ar_;
      Maybe<JSAutoRealm> ar_;
-@@ -793,17 +793,17 @@ JS_PUBLIC_API(SavedFrameResult)
+@@ -827,17 +827,17 @@ JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
  GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
                      SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
                      SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
  {
  {
@@ -694,7 +694,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
          }
          }
          sourcep.set(frame->getSource());
          sourcep.set(frame->getSource());
      }
      }
-@@ -816,17 +816,17 @@ JS_PUBLIC_API(SavedFrameResult)
+@@ -850,17 +850,17 @@ JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
  GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
                    SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
                    SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
  {
  {
@@ -713,7 +713,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
      }
      }
      *linep = frame->getLine();
      *linep = frame->getLine();
      return SavedFrameResult::Ok;
      return SavedFrameResult::Ok;
-@@ -836,17 +836,17 @@ JS_PUBLIC_API(SavedFrameResult)
+@@ -870,17 +870,17 @@ JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
  GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
                      SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
                      SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
  {
  {
@@ -732,7 +732,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
      }
      }
      *columnp = frame->getColumn();
      *columnp = frame->getColumn();
      return SavedFrameResult::Ok;
      return SavedFrameResult::Ok;
-@@ -856,17 +856,17 @@ JS_PUBLIC_API(SavedFrameResult)
+@@ -890,17 +890,17 @@ JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
  GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
                                   SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
                                   SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
  {
  {
@@ -751,7 +751,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
          }
          }
          namep.set(frame->getFunctionDisplayName());
          namep.set(frame->getFunctionDisplayName());
      }
      }
-@@ -879,17 +879,17 @@ JS_PUBLIC_API(SavedFrameResult)
+@@ -913,17 +913,17 @@ JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
  GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
                          SavedFrameSelfHosted unused_ /* = SavedFrameSelfHosted::Include */)
                          SavedFrameSelfHosted unused_ /* = SavedFrameSelfHosted::Include */)
  {
  {
@@ -770,7 +770,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
          // parameter and always include self-hosted frames.
          // parameter and always include self-hosted frames.
          js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, SavedFrameSelfHosted::Include,
          js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, SavedFrameSelfHosted::Include,
                                                          skippedAsync));
                                                          skippedAsync));
-@@ -909,17 +909,17 @@ GetSavedFrameAsyncCause(JSContext* cx, H
+@@ -943,17 +943,17 @@ GetSavedFrameAsyncCause(JSContext* cx, H
  JS_PUBLIC_API(SavedFrameResult)
  JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
  GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
                           SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
                           SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
@@ -789,7 +789,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
      }
      }
      js::RootedSavedFrame parent(cx, frame->getParent());
      js::RootedSavedFrame parent(cx, frame->getParent());
  
  
-@@ -942,17 +942,17 @@ GetSavedFrameAsyncParent(JSContext* cx, 
+@@ -976,17 +976,17 @@ GetSavedFrameAsyncParent(JSContext* cx, 
  JS_PUBLIC_API(SavedFrameResult)
  JS_PUBLIC_API(SavedFrameResult)
  GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
  GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
                      SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
                      SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
@@ -808,7 +808,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
      }
      }
      js::RootedSavedFrame parent(cx, frame->getParent());
      js::RootedSavedFrame parent(cx, frame->getParent());
  
  
-@@ -1055,21 +1055,21 @@ BuildStackString(JSContext* cx, HandleOb
+@@ -1089,21 +1089,21 @@ BuildStackString(JSContext* cx, HandleOb
  
  
      js::StringBuffer sb(cx);
      js::StringBuffer sb(cx);
  
  
@@ -834,7 +834,7 @@ diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
              return true;
              return true;
          }
          }
  
  
-@@ -1442,17 +1442,17 @@ SavedStacks::insertFrames(JSContext* cx,
+@@ -1476,17 +1476,17 @@ SavedStacks::insertFrames(JSContext* cx,
          {
          {
              AutoRealmUnchecked ar(cx, iter.compartment());
              AutoRealmUnchecked ar(cx, iter.compartment());
              if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))
              if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))

+ 411 - 0
frg/work-js/mozilla-release/patches/1463979-0-63a1.patch

@@ -0,0 +1,411 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531916132 -32400
+# Node ID eb4fac6db424a39e865b646c26397ca427753b70
+# Parent  6b88d6a0f82d76883cb7c6d342f9c9fcdb7e69e5
+Bug 1463979 - Part 0: Prohibit failing compilation after linking function and non-lazy script while delazification. r=jorendorff
+
+diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
+--- a/js/src/frontend/BytecodeCompiler.cpp
++++ b/js/src/frontend/BytecodeCompiler.cpp
+@@ -8,17 +8,16 @@
+ 
+ #include "mozilla/IntegerPrintfMacros.h"
+ #include "mozilla/Maybe.h"
+ 
+ #include "builtin/ModuleObject.h"
+ #include "frontend/BytecodeEmitter.h"
+ #include "frontend/ErrorReporter.h"
+ #include "frontend/FoldConstants.h"
+-#include "frontend/NameFunctions.h"
+ #include "frontend/Parser.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSScript.h"
+ #include "vm/TraceLogging.h"
+ #include "wasm/AsmJS.h"
+ 
+ #include "vm/EnvironmentObject-inl.h"
+@@ -339,19 +338,16 @@ BytecodeCompiler::compileScript(HandleOb
+                 // of arguments objects for the caller script and any other scripts it is
+                 // transitively nested inside. The debugger can access any variable on the
+                 // scope chain.
+                 if (!deoptimizeArgumentsInEnclosingScripts(cx, environment))
+                     return nullptr;
+             }
+             if (!emitter->emitScript(pn))
+                 return nullptr;
+-            if (!NameFunctions(cx, pn))
+-                return nullptr;
+-
+             break;
+         }
+ 
+         // Maybe we aborted a syntax parse. See if we can try again.
+         if (!handleParseFailure(directives, startPosition))
+             return nullptr;
+ 
+         // Reset UsedNameTracker state before trying again.
+@@ -411,19 +407,16 @@ BytecodeCompiler::compileModule()
+         return nullptr;
+ 
+     Maybe<BytecodeEmitter> emitter;
+     if (!emplaceEmitter(emitter, &modulesc))
+         return nullptr;
+     if (!emitter->emitScript(pn->pn_body))
+         return nullptr;
+ 
+-    if (!NameFunctions(cx, pn))
+-        return nullptr;
+-
+     if (!builder.initModule())
+         return nullptr;
+ 
+     RootedModuleEnvironmentObject env(cx, ModuleEnvironmentObject::create(cx, module));
+     if (!env)
+         return nullptr;
+ 
+     module->setInitialEnvironment(env);
+@@ -471,26 +464,23 @@ BytecodeCompiler::compileStandaloneFunct
+         MOZ_ASSERT(fun == fn->pn_funbox->function());
+ 
+         if (!createScript(fn->pn_funbox->toStringStart, fn->pn_funbox->toStringEnd))
+             return false;
+ 
+         Maybe<BytecodeEmitter> emitter;
+         if (!emplaceEmitter(emitter, fn->pn_funbox))
+             return false;
+-        if (!emitter->emitFunctionScript(fn->pn_body))
++        if (!emitter->emitFunctionScript(fn, BytecodeEmitter::TopLevelFunction::Yes))
+             return false;
+     } else {
+         fun.set(fn->pn_funbox->function());
+         MOZ_ASSERT(IsAsmJSModule(fun));
+     }
+ 
+-    if (!NameFunctions(cx, fn))
+-        return false;
+-
+     // Enqueue an off-thread source compression task after finishing parsing.
+     if (!scriptSource->tryCompressOffThread(cx))
+         return false;
+ 
+     return true;
+ }
+ 
+ ScriptSourceObject*
+@@ -679,24 +669,68 @@ frontend::CompileModule(JSContext* cx, c
+     // module is compiled off thread.
+     if (!ModuleObject::Freeze(cx, module))
+         return nullptr;
+ 
+     assertException.reset();
+     return module;
+ }
+ 
++// When leaving this scope, the given function should either:
++//   * be linked to a fully compiled script
++//   * remain linking to a lazy script
++class MOZ_STACK_CLASS AutoAssertFunctionDelazificationCompletion
++{
++#ifdef DEBUG
++    RootedFunction fun_;
++#endif
++
++  public:
++    AutoAssertFunctionDelazificationCompletion(JSContext* cx, HandleFunction fun)
++#ifdef DEBUG
++      : fun_(cx, fun)
++#endif
++    {
++        MOZ_ASSERT(fun_->isInterpretedLazy());
++        MOZ_ASSERT(!fun_->lazyScript()->hasScript());
++    }
++
++    ~AutoAssertFunctionDelazificationCompletion() {
++#ifdef DEBUG
++        if (!fun_)
++            return;
++#endif
++
++        // If fun_ is not nullptr, it means delazification doesn't complete.
++        // Assert that the function keeps linking to lazy script
++        MOZ_ASSERT(fun_->isInterpretedLazy());
++        MOZ_ASSERT(!fun_->lazyScript()->hasScript());
++    }
++
++    void complete() {
++        // Assert the completion of delazification and forget the function.
++        MOZ_ASSERT(fun_->hasScript());
++        MOZ_ASSERT(!fun_->hasUncompletedScript());
++
++#ifdef DEBUG
++        fun_ = nullptr;
++#endif
++    }
++};
++
+ bool
+ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length)
+ {
+     MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
+     // We can't be running this script unless we've run its parent.
+     MOZ_ASSERT(!lazy->isEnclosingScriptLazy());
+ 
+     AutoAssertReportedException assertException(cx);
++    Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
++    AutoAssertFunctionDelazificationCompletion delazificationCompletion(cx, fun);
+ 
+     CompileOptions options(cx);
+     options.setMutedErrors(lazy->mutedErrors())
+            .setFileAndLine(lazy->filename(), lazy->lineno())
+            .setColumn(lazy->column())
+            .setScriptSourceOffset(lazy->sourceStart())
+            .setNoScriptRval(false)
+            .setSelfHostingMode(false);
+@@ -725,17 +759,16 @@ frontend::CompileLazyFunction(JSContext*
+ 
+     RootedScriptSourceObject sourceObject(cx, &lazy->sourceObject());
+     Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options, chars, length,
+                                               /* foldConstants = */ true, usedNames, nullptr,
+                                               lazy, sourceObject, lazy->parseGoal());
+     if (!parser.checkOptions())
+         return false;
+ 
+-    Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
+     ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->toStringStart(),
+                                                   lazy->strict(), lazy->generatorKind(),
+                                                   lazy->asyncKind());
+     if (!pn)
+         return false;
+ 
+     Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
+                                                   lazy->sourceStart(), lazy->sourceEnd(),
+@@ -748,22 +781,20 @@ frontend::CompileLazyFunction(JSContext*
+     if (lazy->hasBeenCloned())
+         script->setHasBeenCloned();
+ 
+     BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
+                         pn->pn_pos, BytecodeEmitter::LazyFunction);
+     if (!bce.init())
+         return false;
+ 
+-    if (!bce.emitFunctionScript(pn->pn_body))
++    if (!bce.emitFunctionScript(pn, BytecodeEmitter::TopLevelFunction::Yes))
+         return false;
+ 
+-    if (!NameFunctions(cx, pn))
+-        return false;
+-
++    delazificationCompletion.complete();
+     assertException.reset();
+     return true;
+ }
+ 
+ bool
+ frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+                                     const ReadOnlyCompileOptions& options,
+                                     JS::SourceBufferHolder& srcBuf,
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -2804,27 +2804,33 @@ BytecodeEmitter::emitScript(ParseNode* b
+         return false;
+ 
+     if (!emit1(JSOP_RETRVAL))
+         return false;
+ 
+     if (!emitterScope.leave(this))
+         return false;
+ 
++    if (!NameFunctions(cx, body))
++        return false;
++
+     if (!JSScript::fullyInitFromEmitter(cx, script, this))
+         return false;
+ 
+     tellDebuggerAboutCompiledScript(cx);
+ 
+     return true;
+ }
+ 
+ bool
+-BytecodeEmitter::emitFunctionScript(ParseNode* body)
+-{
++BytecodeEmitter::emitFunctionScript(ParseNode* fn, TopLevelFunction isTopLevel)
++{
++    MOZ_ASSERT(fn->isKind(ParseNodeKind::Function));
++    ParseNode* body = fn->pn_body;
++    MOZ_ASSERT(body->isKind(ParseNodeKind::ParamsBody));
+     FunctionBox* funbox = sc->asFunctionBox();
+     AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), funbox);
+ 
+     setScriptStartOffsetIfUnset(body->pn_pos);
+ 
+     // The ordering of these EmitterScopes is important. The named lambda
+     // scope needs to enclose the function scope needs to enclose the extra
+     // var scope.
+@@ -2868,16 +2874,21 @@ BytecodeEmitter::emitFunctionScript(Pars
+         return false;
+ 
+     if (namedLambdaEmitterScope) {
+         if (!namedLambdaEmitterScope->leave(this))
+             return false;
+         namedLambdaEmitterScope.reset();
+     }
+ 
++    if (isTopLevel == TopLevelFunction::Yes) {
++        if (!NameFunctions(cx, fn))
++            return false;
++    }
++
+     if (!JSScript::fullyInitFromEmitter(cx, script, this))
+         return false;
+ 
+     tellDebuggerAboutCompiledScript(cx);
+ 
+     return true;
+ }
+ 
+@@ -5657,17 +5668,17 @@ BytecodeEmitter::emitFunction(ParseNode*
+                 return false;
+ 
+             BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
+                                  pn->pn_pos, emitterMode);
+             if (!bce2.init())
+                 return false;
+ 
+             /* We measured the max scope depth when we parsed the function. */
+-            if (!bce2.emitFunctionScript(pn->pn_body))
++            if (!bce2.emitFunctionScript(pn, TopLevelFunction::No))
+                 return false;
+ 
+             if (funbox->isLikelyConstructorWrapper())
+                 script->setLikelyConstructorWrapper();
+         }
+ 
+         if (outersc->isFunctionBox())
+             outersc->asFunctionBox()->setHasInnerFunctions();
+diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
+--- a/js/src/frontend/BytecodeEmitter.h
++++ b/js/src/frontend/BytecodeEmitter.h
+@@ -10,16 +10,17 @@
+ #define frontend_BytecodeEmitter_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+ #include "ds/InlineTable.h"
+ #include "frontend/BCEParserHandle.h"
+ #include "frontend/EitherParser.h"
+ #include "frontend/JumpList.h"
++#include "frontend/NameFunctions.h"
+ #include "frontend/SharedContext.h"
+ #include "frontend/SourceNotes.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Interpreter.h"
+ #include "vm/Iteration.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSScript.h"
+ 
+@@ -471,17 +472,21 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
+                                        ValueUsage valueUsage = ValueUsage::WantValue);
+ 
+     // Emit global, eval, or module code for tree rooted at body. Always
+     // encompasses the entire source.
+     MOZ_MUST_USE bool emitScript(ParseNode* body);
+ 
+     // Emit function code for the tree rooted at body.
+-    MOZ_MUST_USE bool emitFunctionScript(ParseNode* body);
++    enum class TopLevelFunction {
++        No,
++        Yes
++    };
++    MOZ_MUST_USE bool emitFunctionScript(ParseNode* fn, TopLevelFunction isTopLevel);
+ 
+     // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
+     // reserve a type set to store its result.
+     void checkTypeSet(JSOp op);
+ 
+     void updateDepth(ptrdiff_t target);
+     MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset);
+     MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset);
+diff --git a/js/src/vm/JSFunction.cpp b/js/src/vm/JSFunction.cpp
+--- a/js/src/vm/JSFunction.cpp
++++ b/js/src/vm/JSFunction.cpp
+@@ -1617,22 +1617,21 @@ JSFunction::createScriptForLazilyInterpr
+         size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
+         UncompressedSourceCache::AutoHoldEntry holder;
+         ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
+                                         lazy->sourceStart(), lazyLength);
+         if (!chars.get())
+             return false;
+ 
+         if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
+-            // The frontend may have linked the function and the non-lazy
+-            // script together during bytecode compilation. Reset it now on
+-            // error.
+-            fun->initLazyScript(lazy);
+-            if (lazy->hasScript())
+-                lazy->resetScript();
++            // The frontend shouldn't fail after linking the function and the
++            // non-lazy script together.
++            MOZ_ASSERT(fun->isInterpretedLazy());
++            MOZ_ASSERT(fun->lazyScript() == lazy);
++            MOZ_ASSERT(!lazy->hasScript());
+             return false;
+         }
+ 
+         script = fun->nonLazyScript();
+ 
+         // Remember the compiled script on the lazy script itself, in case
+         // there are clones of the function still pointing to the lazy script.
+         if (!lazy->maybeScript())
+diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
+--- a/js/src/vm/JSScript.cpp
++++ b/js/src/vm/JSScript.cpp
+@@ -4219,23 +4219,16 @@ void
+ LazyScript::initScript(JSScript* script)
+ {
+     MOZ_ASSERT(script);
+     MOZ_ASSERT(!script_.unbarrieredGet());
+     script_.set(script);
+ }
+ 
+ void
+-LazyScript::resetScript()
+-{
+-    MOZ_ASSERT(script_.unbarrieredGet());
+-    script_.set(nullptr);
+-}
+-
+-void
+ LazyScript::setEnclosingScope(Scope* enclosingScope)
+ {
+     // This method may be called to update the enclosing scope. See comment
+     // above the callsite in BytecodeEmitter::emitFunction.
+     enclosingScope_ = enclosingScope;
+ }
+ 
+ ScriptSourceObject&
+diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h
+--- a/js/src/vm/JSScript.h
++++ b/js/src/vm/JSScript.h
+@@ -2255,17 +2255,16 @@ class LazyScript : public gc::TenuredCel
+     void initRuntimeFields(uint64_t packedFields);
+ 
+     static inline JSFunction* functionDelazifying(JSContext* cx, Handle<LazyScript*>);
+     JSFunction* functionNonDelazifying() const {
+         return function_;
+     }
+ 
+     void initScript(JSScript* script);
+-    void resetScript();
+ 
+     JSScript* maybeScript() {
+         return script_;
+     }
+     const JSScript* maybeScriptUnbarriered() const {
+         return script_.unbarrieredGet();
+     }
+     bool hasScript() const {

+ 949 - 0
frg/work-js/mozilla-release/patches/1463979-1-63a1.patch

@@ -0,0 +1,949 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531916132 -32400
+# Node ID 6edce1e74d5aeb53247e9c22d4e3b5fce3810d8b
+# Parent  4412082244aa9e9b26e822aeadaf68d2be01371d
+Bug 1463979 - Part 1: Store a pointer to enclosing LazyScript into LazyScript. r=jimb,sfink
+
+diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
+--- a/js/src/frontend/BytecodeCompiler.cpp
++++ b/js/src/frontend/BytecodeCompiler.cpp
+@@ -715,18 +715,20 @@ class MOZ_STACK_CLASS AutoAssertFunction
+ #endif
+     }
+ };
+ 
+ bool
+ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length)
+ {
+     MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
+-    // We can't be running this script unless we've run its parent.
+-    MOZ_ASSERT(!lazy->isEnclosingScriptLazy());
++    // We can only compile functions whose parents have previously been
++    // compiled, because compilation requires full information about the
++    // function's immediately enclosing scope.
++    MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
+ 
+     AutoAssertReportedException assertException(cx);
+     Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
+     AutoAssertFunctionDelazificationCompletion delazificationCompletion(cx, fun);
+ 
+     CompileOptions options(cx);
+     options.setMutedErrors(lazy->mutedErrors())
+            .setFileAndLine(lazy->filename(), lazy->lineno())
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -5634,24 +5634,17 @@ BytecodeEmitter::emitFunction(ParseNode*
+     // make a deep clone of its contents.
+     if (fun->isInterpreted()) {
+         bool singleton = checkRunOnceContext();
+         if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
+             return false;
+ 
+         SharedContext* outersc = sc;
+         if (fun->isInterpretedLazy()) {
+-            // We need to update the static scope chain regardless of whether
+-            // the LazyScript has already been initialized, due to the case
+-            // where we previously successfully compiled an inner function's
+-            // lazy script but failed to compile the outer script after the
+-            // fact. If we attempt to compile the outer script again, the
+-            // static scope chain will be newly allocated and will mismatch
+-            // the previously compiled LazyScript's.
+-            fun->lazyScript()->setEnclosingScope(innermostScope());
++            funbox->setEnclosingScopeForInnerLazyFunction(innermostScope());
+             if (emittingRunOnceLambda)
+                 fun->lazyScript()->setTreatAsRunOnce();
+         } else {
+             MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
+ 
+             // Inherit most things (principals, version, etc) from the
+             // parent.  Use default values for the rest.
+             Rooted<JSScript*> parent(cx, script);
+@@ -9110,16 +9103,18 @@ CGObjectList::finish(ObjectArray* array)
+     MOZ_ASSERT(length == array->length);
+ 
+     js::GCPtrObject* cursor = array->vector + array->length;
+     ObjectBox* objbox = lastbox;
+     do {
+         --cursor;
+         MOZ_ASSERT(!*cursor);
+         MOZ_ASSERT(objbox->object->isTenured());
++        if (objbox->isFunctionBox())
++            objbox->asFunctionBox()->finish();
+         *cursor = objbox->object;
+     } while ((objbox = objbox->emitLink) != nullptr);
+     MOZ_ASSERT(cursor == array->vector);
+ }
+ 
+ void
+ CGScopeList::finish(ScopeArray* array)
+ {
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -507,17 +507,20 @@ FunctionBox::FunctionBox(JSContext* cx, 
+ void
+ FunctionBox::initFromLazyFunction()
+ {
+     JSFunction* fun = function();
+     if (fun->lazyScript()->isDerivedClassConstructor())
+         setDerivedClassConstructor();
+     if (fun->lazyScript()->needsHomeObject())
+         setNeedsHomeObject();
+-    enclosingScope_ = fun->lazyScript()->enclosingScope();
++    if (fun->lazyScript()->hasEnclosingScope())
++        enclosingScope_ = fun->lazyScript()->enclosingScope();
++    else
++        enclosingScope_ = nullptr;
+     initWithEnclosingScope(enclosingScope_);
+ }
+ 
+ void
+ FunctionBox::initStandaloneFunction(Scope* enclosingScope)
+ {
+     // Standalone functions are Function or Generator constructors and are
+     // always scoped to the global.
+@@ -589,16 +592,37 @@ FunctionBox::initWithEnclosingScope(Scop
+     } else {
+         computeAllowSyntax(enclosingScope);
+         computeThisBinding(enclosingScope);
+     }
+ 
+     computeInWith(enclosingScope);
+ }
+ 
++void
++FunctionBox::setEnclosingScopeForInnerLazyFunction(Scope* enclosingScope)
++{
++    MOZ_ASSERT(isLazyFunctionWithoutEnclosingScope());
++
++    // For lazy functions inside a function which is being compiled, we cache
++    // the incomplete scope object while compiling, and store it to the
++    // LazyScript once the enclosing script successfully finishes compilation
++    // in FunctionBox::finish.
++    enclosingScope_ = enclosingScope;
++}
++
++void
++FunctionBox::finish()
++{
++    if (!isLazyFunctionWithoutEnclosingScope())
++        return;
++    MOZ_ASSERT(enclosingScope_);
++    function()->lazyScript()->setEnclosingScope(enclosingScope_);
++}
++
+ template <class ParseHandler, typename CharT>
+ inline typename GeneralParser<ParseHandler, CharT>::FinalParser*
+ GeneralParser<ParseHandler, CharT>::asFinalParser()
+ {
+     static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, CharT>, FinalParser>::value,
+                   "inheritance relationship required by the static_cast<> below");
+ 
+     return static_cast<FinalParser*>(this);
+diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
+--- a/js/src/frontend/SharedContext.h
++++ b/js/src/frontend/SharedContext.h
+@@ -292,16 +292,26 @@ SharedContext::asEvalContext()
+     return static_cast<EvalSharedContext*>(this);
+ }
+ 
+ class FunctionBox : public ObjectBox, public SharedContext
+ {
+     // The parser handles tracing the fields below via the ObjectBox linked
+     // list.
+ 
++    // This field is used for two purposes:
++    //   * If this FunctionBox refers to the function being compiled, this field
++    //     holds its enclosing scope, used for compilation.
++    //   * If this FunctionBox refers to a lazy child of the function being
++    //     compiled, this field holds the child's immediately enclosing scope.
++    //     Once compilation succeeds, we will store it in the child's
++    //     LazyScript.  (Debugger may become confused if LazyScripts refer to
++    //     partially initialized enclosing scopes, so we must avoid storing the
++    //     scope in the LazyScript until compilation has completed
++    //     successfully.)
+     Scope* enclosingScope_;
+ 
+     // Names from the named lambda scope, if a named lambda.
+     LexicalScope::Data* namedLambdaBindings_;
+ 
+     // Names from the function scope.
+     FunctionScope::Data* functionScopeBindings_;
+ 
+@@ -413,24 +423,44 @@ class FunctionBox : public ObjectBox, pu
+         MOZ_ASSERT(context->zone()->hasKeptAtoms());
+         return MutableHandle<VarScope::Data*>::fromMarkedLocation(&extraVarScopeBindings_);
+     }
+ 
+     void initFromLazyFunction();
+     void initStandaloneFunction(Scope* enclosingScope);
+     void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
+ 
++    inline bool isLazyFunctionWithoutEnclosingScope() const {
++        return function()->isInterpretedLazy() &&
++               !function()->lazyScript()->hasEnclosingScope();
++    }
++    void setEnclosingScopeForInnerLazyFunction(Scope* enclosingScope);
++    void finish();
++
+     JSFunction* function() const { return &object->as<JSFunction>(); }
+ 
+     Scope* compilationEnclosingScope() const override {
+         // This method is used to distinguish the outermost SharedContext. If
+         // a FunctionBox is the outermost SharedContext, it must be a lazy
+         // function.
+-        MOZ_ASSERT_IF(function()->isInterpretedLazy(),
++
++        // If the function is lazy and it has enclosing scope, the function is
++        // being delazified.  In that case the enclosingScope_ field is copied
++        // from the lazy function at the beginning of delazification and should
++        // keep pointing the same scope.
++        MOZ_ASSERT_IF(function()->isInterpretedLazy() &&
++                      function()->lazyScript()->hasEnclosingScope(),
+                       enclosingScope_ == function()->lazyScript()->enclosingScope());
++
++        // If this FunctionBox is a lazy child of the function we're actually
++        // compiling, then it is not the outermost SharedContext, so this
++        // method should return nullptr."
++        if (isLazyFunctionWithoutEnclosingScope())
++            return nullptr;
++
+         return enclosingScope_;
+     }
+ 
+     bool needsCallObjectRegardlessOfBindings() const {
+         return hasExtensibleScope() ||
+                needsHomeObject() ||
+                isDerivedClassConstructor() ||
+                isGenerator() ||
+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
+@@ -934,18 +934,20 @@ LazyScript::traceChildren(JSTracer* trc)
+         TraceWeakEdge(trc, &script_, "script");
+ 
+     if (function_)
+         TraceEdge(trc, &function_, "function");
+ 
+     if (sourceObject_)
+         TraceEdge(trc, &sourceObject_, "sourceObject");
+ 
+-    if (enclosingScope_)
+-        TraceEdge(trc, &enclosingScope_, "enclosingScope");
++    if (enclosingLazyScriptOrScope_) {
++        TraceGenericPointerRoot(trc, reinterpret_cast<Cell**>(enclosingLazyScriptOrScope_.unsafeUnbarrieredForTracing()),
++                                "enclosingScope or enclosingLazyScript");
++    }
+ 
+     // We rely on the fact that atoms are always tenured.
+     JSAtom** closedOverBindings = this->closedOverBindings();
+     for (auto i : IntegerRange(numClosedOverBindings())) {
+         if (closedOverBindings[i])
+             TraceManuallyBarrieredEdge(trc, &closedOverBindings[i], "closedOverBinding");
+     }
+ 
+@@ -960,18 +962,20 @@ js::GCMarker::eagerlyMarkChildren(LazySc
+         noteWeakEdge(thing->script_.unsafeUnbarrieredForTracing());
+ 
+     if (thing->function_)
+         traverseEdge(thing, static_cast<JSObject*>(thing->function_));
+ 
+     if (thing->sourceObject_)
+         traverseEdge(thing, static_cast<JSObject*>(thing->sourceObject_));
+ 
+-    if (thing->enclosingScope_)
+-        traverseEdge(thing, static_cast<Scope*>(thing->enclosingScope_));
++    if (thing->enclosingLazyScriptOrScope_) {
++        TraceManuallyBarrieredGenericPointerEdge(this, reinterpret_cast<Cell**>(thing->enclosingLazyScriptOrScope_.unsafeUnbarrieredForTracing()),
++                                                 "enclosingScope or enclosingLazyScript");
++    }
+ 
+     // We rely on the fact that atoms are always tenured.
+     JSAtom** closedOverBindings = thing->closedOverBindings();
+     for (auto i : IntegerRange(thing->numClosedOverBindings())) {
+         if (closedOverBindings[i])
+             traverseEdge(thing, static_cast<JSString*>(closedOverBindings[i]));
+     }
+ 
+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
+@@ -4605,20 +4605,21 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
+     }
+ 
+     /*
+      * If |script| matches this query, append it to |vector| or place it in
+      * |innermostForRealm|, as appropriate. Set |oom| if an out of memory
+      * condition occurred.
+      */
+     void consider(JSScript* script, const JS::AutoRequireNoGC& nogc) {
+-        // We check for presence of script->code() because it is possible that
+-        // the script was created and thus exposed to GC, but *not* fully
+-        // initialized from fullyInit{FromEmitter,Trivial} due to errors.
+-        if (oom || script->selfHosted() || !script->code())
++        // We check for presence of script->isUncompleted() because it is
++        // possible that the script was created and thus exposed to GC, but
++        // *not* fully initialized from fullyInit{FromEmitter,Trivial} due to
++        // errors.
++        if (oom || script->selfHosted() || script->isUncompleted())
+             return;
+         Realm* realm = script->realm();
+         if (!realms.has(realm))
+             return;
+         if (urlCString.ptr()) {
+             bool gotFilename = false;
+             if (script->filename() && strcmp(script->filename(), urlCString.ptr()) == 0)
+                 gotFilename = true;
+diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp
+--- a/js/src/vm/JSCompartment.cpp
++++ b/js/src/vm/JSCompartment.cpp
+@@ -1134,17 +1134,17 @@ AddLazyFunctionsForRealm(JSContext* cx, 
+         if (gc::IsAboutToBeFinalizedUnbarriered(&fun) ||
+             fun->realm() != cx->realm())
+         {
+             continue;
+         }
+ 
+         if (fun->isInterpretedLazy()) {
+             LazyScript* lazy = fun->lazyScriptOrNull();
+-            if (lazy && !lazy->isEnclosingScriptLazy() && !lazy->hasUncompletedEnclosingScript()) {
++            if (lazy && lazy->enclosingScriptHasEverBeenCompiled()) {
+                 if (!lazyFunctions.append(fun))
+                     return false;
+             }
+         }
+     }
+ 
+     return true;
+ }
+diff --git a/js/src/vm/JSFunction.cpp b/js/src/vm/JSFunction.cpp
+--- a/js/src/vm/JSFunction.cpp
++++ b/js/src/vm/JSFunction.cpp
+@@ -1587,35 +1587,43 @@ JSFunction::createScriptForLazilyInterpr
+         // chain of their inner functions, or in the case of eval, possibly
+         // eval'd inner functions. This prohibits re-lazification as
+         // StaticScopeIter queries needsCallObject of those functions, which
+         // requires a non-lazy script.  Note that if this ever changes,
+         // XDRRelazificationInfo will have to be fixed.
+         bool canRelazify = !lazy->numInnerFunctions() && !lazy->hasDirectEval();
+ 
+         if (script) {
++            // This function is non-canonical function, and the canonical
++            // function is already delazified.
+             fun->setUnlazifiedScript(script);
+             // Remember the lazy script on the compiled script, so it can be
+             // stored on the function again in case of re-lazification.
+             if (canRelazify)
+                 script->setLazyScript(lazy);
+             return true;
+         }
+ 
+         if (fun != lazy->functionNonDelazifying()) {
++            // This function is non-canonical function, and the canonical
++            // function is lazy.
++            // Delazify the canonical function, which will result in calling
++            // this function again with the canonical function.
+             if (!LazyScript::functionDelazifying(cx, lazy))
+                 return false;
+             script = lazy->functionNonDelazifying()->nonLazyScript();
+             if (!script)
+                 return false;
+ 
+             fun->setUnlazifiedScript(script);
+             return true;
+         }
+ 
++        // This is lazy canonical-function.
++
+         MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
+ 
+         // Parse and compile the script from source.
+         size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
+         UncompressedSourceCache::AutoHoldEntry holder;
+         ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
+                                         lazy->sourceStart(), lazyLength);
+         if (!chars.get())
+@@ -2119,17 +2127,17 @@ js::CanReuseScriptForClone(JSCompartment
+     // example.
+     if (IsSyntacticEnvironment(newParent))
+         return true;
+ 
+     // We need to clone the script if we're not already marked as having a
+     // non-syntactic scope.
+     return fun->hasScript()
+         ? fun->nonLazyScript()->hasNonSyntacticScope()
+-        : fun->lazyScript()->enclosingScope()->hasOnChain(ScopeKind::NonSyntactic);
++        : fun->lazyScript()->hasNonSyntacticScope();
+ }
+ 
+ static inline JSFunction*
+ NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
+                  gc::AllocKind allocKind, HandleObject proto)
+ {
+     RootedObject cloneProto(cx, proto);
+     if (!proto && (fun->isGenerator() || fun->isAsync())) {
+diff --git a/js/src/vm/JSFunction.h b/js/src/vm/JSFunction.h
+--- a/js/src/vm/JSFunction.h
++++ b/js/src/vm/JSFunction.h
+@@ -559,16 +559,19 @@ class JSFunction : public js::NativeObje
+             initScript(script);
+         }
+         return nonLazyScript();
+     }
+ 
+     // The state of a JSFunction whose script errored out during bytecode
+     // compilation. Such JSFunctions are only reachable via GC iteration and
+     // not from script.
++    // If u.scripted.s.script_ is non-null, the pointed JSScript is guaranteed
++    // to be complete (see the comment above JSScript::initFromFunctionBox
++    // callsite in JSScript::fullyInitFromEmitter).
+     bool hasUncompletedScript() const {
+         MOZ_ASSERT(hasScript());
+         return !u.scripted.s.script_;
+     }
+ 
+     JSScript* nonLazyScript() const {
+         MOZ_ASSERT(!hasUncompletedScript());
+         return u.scripted.s.script_;
+diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
+--- a/js/src/vm/JSScript.cpp
++++ b/js/src/vm/JSScript.cpp
+@@ -266,19 +266,19 @@ XDRRelazificationInfo(XDRState<mode>* xd
+             // JSFunction::createScriptForLazilyInterpretedFunction.
+             MOZ_ASSERT(lazy->numInnerFunctions() == 0);
+         }
+ 
+         MOZ_TRY(xdr->codeUint64(&packedFields));
+ 
+         if (mode == XDR_DECODE) {
+             RootedScriptSourceObject sourceObject(cx, &script->scriptSourceUnwrap());
+-            lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
+-                                        packedFields, sourceStart, sourceEnd, toStringStart,
+-                                        lineno, column));
++            lazy.set(LazyScript::CreateForXDR(cx, fun, script, enclosingScope, sourceObject,
++                                              packedFields, sourceStart, sourceEnd, toStringStart,
++                                              lineno, column));
+             if (!lazy)
+                 return xdr->fail(JS::TranscodeResult_Throw);
+ 
+             lazy->setToStringEnd(toStringEnd);
+ 
+             // As opposed to XDRLazyScript, we need to restore the runtime bits
+             // of the script, as we are trying to match the fact this function
+             // has already been parsed and that it would need to be re-lazified.
+@@ -944,19 +944,19 @@ js::XDRLazyScript(XDRState<mode>* xdr, H
+         MOZ_TRY(xdr->codeUint32(&sourceEnd));
+         MOZ_TRY(xdr->codeUint32(&toStringStart));
+         MOZ_TRY(xdr->codeUint32(&toStringEnd));
+         MOZ_TRY(xdr->codeUint32(&lineno));
+         MOZ_TRY(xdr->codeUint32(&column));
+         MOZ_TRY(xdr->codeUint64(&packedFields));
+ 
+         if (mode == XDR_DECODE) {
+-            lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
+-                                        packedFields, sourceStart, sourceEnd, toStringStart,
+-                                        lineno, column));
++            lazy.set(LazyScript::CreateForXDR(cx, fun, nullptr, enclosingScope, sourceObject,
++                                              packedFields, sourceStart, sourceEnd, toStringStart,
++                                              lineno, column));
+             if (!lazy)
+                 return xdr->fail(JS::TranscodeResult_Throw);
+             lazy->setToStringEnd(toStringEnd);
+             fun->initLazyScript(lazy);
+         }
+     }
+ 
+     // Code closed-over bindings.
+@@ -968,18 +968,21 @@ js::XDRLazyScript(XDRState<mode>* xdr, H
+         GCPtrFunction* innerFunctions = lazy->innerFunctions();
+         size_t numInnerFunctions = lazy->numInnerFunctions();
+         for (size_t i = 0; i < numInnerFunctions; i++) {
+             if (mode == XDR_ENCODE)
+                 func = innerFunctions[i];
+ 
+             MOZ_TRY(XDRInterpretedFunction(xdr, nullptr, sourceObject, &func));
+ 
+-            if (mode == XDR_DECODE)
++            if (mode == XDR_DECODE) {
+                 innerFunctions[i] = func;
++                if (innerFunctions[i]->isInterpretedLazy())
++                    innerFunctions[i]->lazyScript()->setEnclosingLazyScript(lazy);
++            }
+         }
+     }
+ 
+     return Ok();
+ }
+ 
+ template XDRResult
+ js::XDRLazyScript(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSourceObject,
+@@ -2945,16 +2948,22 @@ JSScript::initFromModuleContext(HandleSc
+ 
+ /* static */ bool
+ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, BytecodeEmitter* bce)
+ {
+     /* The counts of indexed things must be checked during code generation. */
+     MOZ_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
+     MOZ_ASSERT(bce->objectList.length <= INDEX_LIMIT);
+ 
++    uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
++    if (nslots > UINT32_MAX) {
++        bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
++        return false;
++    }
++
+     uint32_t mainLength = bce->offset();
+     uint32_t prologueLength = bce->prologueOffset();
+     uint32_t nsrcnotes;
+     if (!bce->finishTakingSrcNotes(&nsrcnotes))
+         return false;
+     uint32_t natoms = bce->atomIndices->count();
+     if (!partiallyInit(cx, script,
+                        bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
+@@ -2967,16 +2976,21 @@ JSScript::fullyInitFromEmitter(JSContext
+     MOZ_ASSERT(script->mainOffset() == 0);
+     script->mainOffset_ = prologueLength;
+ 
+     script->lineno_ = bce->firstLine;
+ 
+     if (!script->createScriptData(cx, prologueLength + mainLength, nsrcnotes, natoms))
+         return false;
+ 
++    // Any fallible operation after JSScript::createScriptData should reset
++    // JSScript.scriptData_, in order to treat this script as uncompleted,
++    // in JSScript::isUncompleted.
++    // JSScript::shareScriptData resets it before returning false.
++
+     jsbytecode* code = script->code();
+     PodCopy<jsbytecode>(code, bce->prologue.code.begin(), prologueLength);
+     PodCopy<jsbytecode>(code + prologueLength, bce->main.code.begin(), mainLength);
+     bce->copySrcNotes((jssrcnote*)(code + script->length()), nsrcnotes);
+     InitAtomMap(*bce->atomIndices, script->atoms());
+ 
+     if (!script->shareScriptData(cx))
+         return false;
+@@ -2991,28 +3005,25 @@ JSScript::fullyInitFromEmitter(JSContext
+         bce->tryNoteList.finish(script->trynotes());
+     if (bce->scopeNoteList.length() != 0)
+         bce->scopeNoteList.finish(script->scopeNotes(), prologueLength);
+     script->bitFields_.strict_ = bce->sc->strict();
+     script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
+     script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
+     script->bitFields_.hasSingletons_ = bce->hasSingletons;
+ 
+-    uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
+-    if (nslots > UINT32_MAX) {
+-        bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
+-        return false;
+-    }
+-
+     script->nfixed_ = bce->maxFixedSlots;
+     script->nslots_ = nslots;
+     script->bodyScopeIndex_ = bce->bodyScopeIndex;
+     script->bitFields_.hasNonSyntacticScope_ =
+         bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
+ 
++    // There shouldn't be any fallible operation after initFromFunctionBox,
++    // JSFunction::hasUncompletedScript relies on the fact that the existence
++    // of the pointer to JSScript means the pointed JSScript is complete.
+     if (bce->sc->isFunctionBox())
+         initFromFunctionBox(script, bce->sc->asFunctionBox());
+     else if (bce->sc->isModuleContext())
+         initFromModuleContext(script);
+ 
+     // Copy yield offsets last, as the generator kind is set in
+     // initFromFunctionBox.
+     if (bce->yieldAndAwaitOffsetList.length() != 0)
+@@ -4192,17 +4203,16 @@ JSScript::formalLivesInArgumentsObject(u
+ }
+ 
+ LazyScript::LazyScript(JSFunction* fun, ScriptSourceObject& sourceObject,
+                        void* table, uint64_t packedFields,
+                        uint32_t sourceStart, uint32_t sourceEnd,
+                        uint32_t toStringStart, uint32_t lineno, uint32_t column)
+   : script_(nullptr),
+     function_(fun),
+-    enclosingScope_(nullptr),
+     sourceObject_(&sourceObject),
+     table_(table),
+     packedFields_(packedFields),
+     sourceStart_(sourceStart),
+     sourceEnd_(sourceEnd),
+     toStringStart_(toStringStart),
+     toStringEnd_(sourceEnd),
+     lineno_(lineno),
+@@ -4219,21 +4229,36 @@ void
+ LazyScript::initScript(JSScript* script)
+ {
+     MOZ_ASSERT(script);
+     MOZ_ASSERT(!script_.unbarrieredGet());
+     script_.set(script);
+ }
+ 
+ void
++LazyScript::setEnclosingLazyScript(LazyScript* enclosingLazyScript)
++{
++    MOZ_ASSERT(enclosingLazyScript);
++
++    // We never change an existing LazyScript.
++    MOZ_ASSERT(!hasEnclosingLazyScript());
++
++    // Enclosing scopes never transition back to enclosing lazy scripts.
++    MOZ_ASSERT(!hasEnclosingScope());
++
++    enclosingLazyScriptOrScope_ = enclosingLazyScript;
++}
++
++void
+ LazyScript::setEnclosingScope(Scope* enclosingScope)
+ {
+-    // This method may be called to update the enclosing scope. See comment
+-    // above the callsite in BytecodeEmitter::emitFunction.
+-    enclosingScope_ = enclosingScope;
++    MOZ_ASSERT(enclosingScope);
++    MOZ_ASSERT(!hasEnclosingScope());
++
++    enclosingLazyScriptOrScope_ = enclosingScope;
+ }
+ 
+ ScriptSourceObject&
+ LazyScript::sourceObject() const
+ {
+     return sourceObject_->as<ScriptSourceObject>();
+ }
+ 
+@@ -4320,28 +4345,31 @@ LazyScript::Create(JSContext* cx, Handle
+     if (!res)
+         return nullptr;
+ 
+     JSAtom** resClosedOverBindings = res->closedOverBindings();
+     for (size_t i = 0; i < res->numClosedOverBindings(); i++)
+         resClosedOverBindings[i] = closedOverBindings[i];
+ 
+     GCPtrFunction* resInnerFunctions = res->innerFunctions();
+-    for (size_t i = 0; i < res->numInnerFunctions(); i++)
++    for (size_t i = 0; i < res->numInnerFunctions(); i++) {
+         resInnerFunctions[i].init(innerFunctions[i]);
++        if (resInnerFunctions[i]->isInterpretedLazy())
++            resInnerFunctions[i]->lazyScript()->setEnclosingLazyScript(res);
++    }
+ 
+     return res;
+ }
+ 
+ /* static */ LazyScript*
+-LazyScript::Create(JSContext* cx, HandleFunction fun,
+-                   HandleScript script, HandleScope enclosingScope,
+-                   HandleScriptSourceObject sourceObject,
+-                   uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
+-                   uint32_t toStringStart, uint32_t lineno, uint32_t column)
++LazyScript::CreateForXDR(JSContext* cx, HandleFunction fun,
++                         HandleScript script, HandleScope enclosingScope,
++                         HandleScriptSourceObject sourceObject,
++                         uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
++                         uint32_t toStringStart, uint32_t lineno, uint32_t column)
+ {
+     // Dummy atom which is not a valid property name.
+     RootedAtom dummyAtom(cx, cx->names().comma);
+ 
+     // Dummy function which is not a valid function as this is the one which is
+     // holding this lazy script.
+     HandleFunction dummyFun = fun;
+ 
+@@ -4358,20 +4386,21 @@ LazyScript::Create(JSContext* cx, Handle
+     for (i = 0, num = res->numClosedOverBindings(); i < num; i++)
+         closedOverBindings[i] = dummyAtom;
+ 
+     GCPtrFunction* functions = res->innerFunctions();
+     for (i = 0, num = res->numInnerFunctions(); i < num; i++)
+         functions[i].init(dummyFun);
+ 
+     // Set the enclosing scope of the lazy function. This value should only be
+-    // non-null if we have a non-lazy enclosing script.
+-    // LazyScript::isEnclosingScriptLazy relies on the enclosing scope being
+-    // null if we're nested inside another lazy function.
+-    MOZ_ASSERT(!res->enclosingScope());
++    // set if we have a non-lazy enclosing script at this point.
++    // LazyScript::enclosingScriptHasEverBeenCompiled relies on the enclosing
++    // scope being non-null if we have ever been nested inside non-lazy
++    // function.
++    MOZ_ASSERT(!res->hasEnclosingScope());
+     if (enclosingScope)
+         res->setEnclosingScope(enclosingScope);
+ 
+     MOZ_ASSERT(!res->hasScript());
+     if (script)
+         res->initScript(script);
+ 
+     return res;
+@@ -4385,34 +4414,16 @@ LazyScript::initRuntimeFields(uint64_t p
+         uint64_t packed;
+     };
+ 
+     packed = packedFields;
+     p_.hasBeenCloned = p.hasBeenCloned;
+     p_.treatAsRunOnce = p.treatAsRunOnce;
+ }
+ 
+-bool
+-LazyScript::hasUncompletedEnclosingScript() const
+-{
+-    // It can happen that we created lazy scripts while compiling an enclosing
+-    // script, but we errored out while compiling that script. When we iterate
+-    // over lazy script in a compartment, we might see lazy scripts that never
+-    // escaped to script and should be ignored.
+-    //
+-    // If the enclosing scope is a function with a null script or has a script
+-    // without code, it was not successfully compiled.
+-
+-    if (!enclosingScope() || !enclosingScope()->is<FunctionScope>())
+-        return false;
+-
+-    JSFunction* fun = enclosingScope()->as<FunctionScope>().canonicalFunction();
+-    return !fun->hasScript() || fun->hasUncompletedScript() || !fun->nonLazyScript()->code();
+-}
+-
+ void
+ JSScript::updateJitCodeRaw(JSRuntime* rt)
+ {
+     MOZ_ASSERT(rt);
+     if (hasBaselineScript() && baseline->hasPendingIonBuilder()) {
+         MOZ_ASSERT(!isIonCompilingOffThread());
+         jitCodeRaw_ = rt->jitRuntime()->lazyLinkStub().value;
+         jitCodeSkipArgCheck_ = jitCodeRaw_;
+diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h
+--- a/js/src/vm/JSScript.h
++++ b/js/src/vm/JSScript.h
+@@ -1260,16 +1260,22 @@ class JSScript : public js::gc::TenuredC
+     }
+ 
+     // Script bytecode is immutable after creation.
+     jsbytecode* code() const {
+         if (!scriptData_)
+             return nullptr;
+         return scriptData_->code();
+     }
++    bool isUncompleted() const {
++        // code() becomes non-null only if this script is complete.
++        // See the comment in JSScript::fullyInitFromEmitter.
++        return !code();
++    }
++
+     size_t length() const {
+         MOZ_ASSERT(scriptData_);
+         return scriptData_->codeLength();
+     }
+ 
+     jsbytecode* codeEnd() const { return code() + length(); }
+ 
+     jsbytecode* lastPC() const {
+@@ -2139,18 +2145,92 @@ class LazyScript : public gc::TenuredCel
+     // If non-nullptr, the script has been compiled and this is a forwarding
+     // pointer to the result. This is a weak pointer: after relazification, we
+     // can collect the script if there are no other pointers to it.
+     WeakRef<JSScript*> script_;
+ 
+     // Original function with which the lazy script is associated.
+     GCPtrFunction function_;
+ 
+-    // Scope in which the script is nested.
+-    GCPtrScope enclosingScope_;
++    // This field holds one of:
++    //   * LazyScript in which the script is nested.  This case happens if the
++    //     enclosing script is lazily parsed and have never been compiled.
++    //
++    //     This is used by the debugger to delazify the enclosing scripts
++    //     recursively.  The all ancestor LazyScripts in this linked-list are
++    //     kept alive as long as this LazyScript is alive, which doesn't result
++    //     in keeping them unnecessarily alive outside of the debugger for the
++    //     following reasons:
++    //
++    //       * Outside of the debugger, a LazyScript is visible to user (which
++    //         means the LazyScript can be pointed from somewhere else than the
++    //         enclosing script) only if the enclosing script is compiled and
++    //         executed.  While compiling the enclosing script, this field is
++    //         changed to point the enclosing scope.  So the enclosing
++    //         LazyScript is no more in the list.
++    //       * Before the enclosing script gets compiled, this LazyScript is
++    //         kept alive only if the outermost LazyScript in the list is kept
++    //         alive.
++    //       * Once this field is changed to point the enclosing scope, this
++    //         field will never point the enclosing LazyScript again, since
++    //         relazification is not performed on non-leaf scripts.
++    //
++    //   * Scope in which the script is nested.  This case happens if the
++    //     enclosing script has ever been compiled.
++    //
++    //   * nullptr for incomplete (initial or failure) state
++    //
++    // This field should be accessed via accessors:
++    //   * enclosingScope
++    //   * setEnclosingScope (cannot be called twice)
++    //   * enclosingLazyScript
++    //   * setEnclosingLazyScript (cannot be called twice)
++    // after checking:
++    //   * hasEnclosingLazyScript
++    //   * hasEnclosingScope
++    //
++    // The transition of fields are following:
++    //
++    //  o                               o
++    //  | when function is lazily       | when decoded from XDR,
++    //  | parsed inside a function      | and enclosing script is lazy
++    //  | which is lazily parsed        | (CreateForXDR without enclosingScope)
++    //  | (Create)                      |
++    //  v                               v
++    // +---------+                     +---------+
++    // | nullptr |                     | nullptr |
++    // +---------+                     +---------+
++    //  |                               |
++    //  | when enclosing function is    | when enclosing script is decoded
++    //  | lazily parsed and this        | and this script's function is put
++    //  | script's function is put      | into innerFunctions()
++    //  | into innerFunctions()         | (setEnclosingLazyScript)
++    //  | (setEnclosingLazyScript)      |
++    //  |                               |
++    //  |                               |     o
++    //  |                               |     | when function is lazily
++    //  |                               |     | parsed inside a function
++    //  |                               |     | which is eagerly parsed
++    //  |                               |     | (Create)
++    //  v                               |     v
++    // +----------------------+         |    +---------+
++    // | enclosing LazyScript |<--------+    | nullptr |
++    // +----------------------+              +---------+
++    //  |                                     |
++    //  v                                     |
++    //  +<------------------------------------+
++    //  |
++    //  | when the enclosing script     o
++    //  | is successfully compiled      | when decoded from XDR,
++    //  | (setEnclosingScope)           | and enclosing script is not lazy
++    //  v                               | (CreateForXDR with enclosingScope)
++    // +-----------------+              |
++    // | enclosing Scope |<-------------+
++    // +-----------------+
++    GCPtr<TenuredCell*> enclosingLazyScriptOrScope_;
+ 
+     // ScriptSourceObject. We leave this set to nullptr until we generate
+     // bytecode for our immediate parent. This is never a CCW; we don't clone
+     // LazyScripts into other compartments.
+     GCPtrObject sourceObject_;
+ 
+     // Heap allocated table with any free variables or inner functions.
+     void* table_;
+@@ -2241,21 +2321,21 @@ class LazyScript : public gc::TenuredCel
+     // innerFunctions with dummy values to be replaced in a later initialization
+     // phase.
+     //
+     // The "script" argument to this function can be null.  If it's non-null,
+     // then this LazyScript should be associated with the given JSScript.
+     //
+     // The sourceObject and enclosingScope arguments may be null if the
+     // enclosing function is also lazy.
+-    static LazyScript* Create(JSContext* cx, HandleFunction fun,
+-                              HandleScript script, HandleScope enclosingScope,
+-                              HandleScriptSourceObject sourceObject,
+-                              uint64_t packedData, uint32_t begin, uint32_t end,
+-                              uint32_t toStringStart, uint32_t lineno, uint32_t column);
++    static LazyScript* CreateForXDR(JSContext* cx, HandleFunction fun,
++                                    HandleScript script, HandleScope enclosingScope,
++                                    HandleScriptSourceObject sourceObject,
++                                    uint64_t packedData, uint32_t begin, uint32_t end,
++                                    uint32_t toStringStart, uint32_t lineno, uint32_t column);
+ 
+     void initRuntimeFields(uint64_t packedFields);
+ 
+     static inline JSFunction* functionDelazifying(JSContext* cx, Handle<LazyScript*>);
+     JSFunction* functionNonDelazifying() const {
+         return function_;
+     }
+ 
+@@ -2266,31 +2346,50 @@ class LazyScript : public gc::TenuredCel
+     }
+     const JSScript* maybeScriptUnbarriered() const {
+         return script_.unbarrieredGet();
+     }
+     bool hasScript() const {
+         return bool(script_);
+     }
+ 
++    bool hasEnclosingScope() const {
++        return enclosingLazyScriptOrScope_ &&
++               enclosingLazyScriptOrScope_->is<Scope>();
++    }
++    bool hasEnclosingLazyScript() const {
++        return enclosingLazyScriptOrScope_ &&
++               enclosingLazyScriptOrScope_->is<LazyScript>();
++    }
++
++    LazyScript* enclosingLazyScript() const {
++        MOZ_ASSERT(hasEnclosingLazyScript());
++        return enclosingLazyScriptOrScope_->as<LazyScript>();
++    }
++    void setEnclosingLazyScript(LazyScript* enclosingLazyScript);
++
+     Scope* enclosingScope() const {
+-        return enclosingScope_;
++        MOZ_ASSERT(hasEnclosingScope());
++        return enclosingLazyScriptOrScope_->as<Scope>();
++    }
++    void setEnclosingScope(Scope* enclosingScope);
++
++    bool hasNonSyntacticScope() const {
++        return enclosingScope()->hasOnChain(ScopeKind::NonSyntactic);
+     }
+ 
+     ScriptSourceObject& sourceObject() const;
+     ScriptSource* scriptSource() const {
+         return sourceObject().source();
+     }
+     ScriptSource* maybeForwardedScriptSource() const;
+     bool mutedErrors() const {
+         return scriptSource()->mutedErrors();
+     }
+ 
+-    void setEnclosingScope(Scope* enclosingScope);
+-
+     uint32_t numClosedOverBindings() const {
+         return p_.numClosedOverBindings;
+     }
+     JSAtom** closedOverBindings() {
+         return (JSAtom**)table_;
+     }
+ 
+     uint32_t numInnerFunctions() const {
+@@ -2435,23 +2534,24 @@ class LazyScript : public gc::TenuredCel
+     }
+ 
+     void setToStringEnd(uint32_t toStringEnd) {
+         MOZ_ASSERT(toStringStart_ <= toStringEnd);
+         MOZ_ASSERT(toStringEnd_ >= sourceEnd_);
+         toStringEnd_ = toStringEnd;
+     }
+ 
+-    // Returns true if the enclosing script failed to compile.
+-    // See the comment in the definition for more details.
+-    bool hasUncompletedEnclosingScript() const;
+-
+-    // Returns true if the enclosing script is also lazy.
+-    bool isEnclosingScriptLazy() const {
+-        return !enclosingScope_;
++    // Returns true if the enclosing script has ever been compiled.
++    // Once the enclosing script is compiled, the scope chain is created.
++    // This LazyScript is delazify-able as long as it has the enclosing scope,
++    // even if the enclosing JSScript is GCed.
++    // The enclosing JSScript can be GCed later if the enclosing scope is not
++    // FunctionScope or ModuleScope.
++    bool enclosingScriptHasEverBeenCompiled() const {
++        return hasEnclosingScope();
+     }
+ 
+     friend class GCMarker;
+     void traceChildren(JSTracer* trc);
+     void finalize(js::FreeOp* fop);
+ 
+     static const JS::TraceKind TraceKind = JS::TraceKind::LazyScript;
+ 

+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central_424539.patch → frg/work-js/mozilla-release/patches/1467336-24-63a1.patch


+ 0 - 0
frg/work-js/mozilla-release/patches/mozilla-central_424540.patch → frg/work-js/mozilla-release/patches/1467336-25-63a1.patch


+ 975 - 0
frg/work-js/mozilla-release/patches/1471463-63a1.patch

@@ -0,0 +1,975 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530131157 25200
+# Node ID e20c1d6852e4fb05f4fce71523d698cb9ebf28fe
+# Parent  4a30badbe7c0acbb30a31b1325196fbe4f9a95ba
+Bug 1471463 - Move TokenStreamCharsBase::tokenbuf and related functions into a new TokenStreamCharsShared base class, make the character type always char16_t, and rename it/them to 'charBuffer' for clarity.  r=arai
+
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -9089,43 +9089,42 @@ ParseNode*
+ Parser<FullParseHandler, CharT>::newRegExp()
+ {
+     MOZ_ASSERT(!options().selfHostingMode);
+ 
+     static_assert(mozilla::IsSame<CharT, char16_t>::value,
+                   "code below will need changing for UTF-8 handling");
+ 
+     // Create the regexp and check its syntax.
+-    const CharT* chars = tokenStream.getTokenbuf().begin();
+-    size_t length = tokenStream.getTokenbuf().length();
++    const auto& chars = tokenStream.getCharBuffer();
+     RegExpFlag flags = anyChars.currentToken().regExpFlags();
+ 
+     Rooted<RegExpObject*> reobj(context);
+-    reobj = RegExpObject::create(context, chars, length, flags, anyChars, alloc, TenuredObject);
++    reobj = RegExpObject::create(context, chars.begin(), chars.length(), flags, anyChars, alloc,
++                                 TenuredObject);
+     if (!reobj)
+         return null();
+ 
+     return handler.newRegExp(reobj, pos(), *this);
+ }
+ 
+ template <typename CharT>
+ SyntaxParseHandler::Node
+ Parser<SyntaxParseHandler, CharT>::newRegExp()
+ {
+     MOZ_ASSERT(!options().selfHostingMode);
+ 
+     static_assert(mozilla::IsSame<CharT, char16_t>::value,
+                   "code below will need changing for UTF-8 handling");
+ 
+     // Only check the regexp's syntax, but don't create a regexp object.
+-    const CharT* chars = tokenStream.getTokenbuf().begin();
+-    size_t length = tokenStream.getTokenbuf().length();
++    const auto& chars = tokenStream.getCharBuffer();
+     RegExpFlag flags = anyChars.currentToken().regExpFlags();
+ 
+-    mozilla::Range<const CharT> source(chars, length);
++    mozilla::Range<const CharT> source(chars.begin(), chars.length());
+     if (!js::irregexp::ParsePatternSyntax(anyChars, alloc, source, flags & UnicodeFlag))
+         return null();
+ 
+     return handler.newRegExp(SyntaxParseHandler::NodeGeneric, pos(), *this);
+ }
+ 
+ template <class ParseHandler, typename CharT>
+ typename ParseHandler::Node
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -8,20 +8,20 @@
+ 
+ #include "frontend/TokenStream.h"
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/IntegerTypeTraits.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/MemoryChecking.h"
+-#include "mozilla/PodOperations.h"
+ #include "mozilla/ScopeExit.h"
+ #include "mozilla/TextUtils.h"
+ 
++#include <algorithm>
+ #include <ctype.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <utility>
+ 
+ #include "jsexn.h"
+ #include "jsnum.h"
+@@ -39,17 +39,16 @@
+ #include "vm/JSContext.h"
+ 
+ using mozilla::ArrayLength;
+ using mozilla::AssertedCast;
+ using mozilla::IsAscii;
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
+ using mozilla::MakeScopeExit;
+-using mozilla::PodCopy;
+ 
+ struct ReservedWordInfo
+ {
+     const char* chars;         // C string with reserved word text
+     js::frontend::TokenKind tokentype;
+ };
+ 
+ static const ReservedWordInfo reservedWords[] = {
+@@ -430,18 +429,18 @@ TokenStreamAnyChars::TokenStreamAnyChars
+     isExprEnding[size_t(TokenKind::Rp)] = true;
+     isExprEnding[size_t(TokenKind::Rb)] = true;
+     isExprEnding[size_t(TokenKind::Rc)] = true;
+ }
+ 
+ template<typename CharT>
+ TokenStreamCharsBase<CharT>::TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length,
+                                                   size_t startOffset)
+-  : sourceUnits(chars, length, startOffset),
+-    tokenbuf(cx)
++  : TokenStreamCharsShared(cx),
++    sourceUnits(chars, length, startOffset)
+ {}
+ 
+ template<typename CharT, class AnyCharsAccess>
+ TokenStreamSpecific<CharT, AnyCharsAccess>::TokenStreamSpecific(JSContext* cx,
+                                                                 const ReadOnlyCompileOptions& options,
+                                                                 const CharT* base, size_t length)
+   : TokenStreamChars<CharT, AnyCharsAccess>(cx, base, length, options.scriptSourceOffset)
+ {}
+@@ -1161,28 +1160,27 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     bool res = getDisplayURL(isMultiline, shouldWarnDeprecated) &&
+                getSourceMappingURL(isMultiline, shouldWarnDeprecated);
+     if (!res)
+         badToken();
+ 
+     return res;
+ }
+ 
+-template<>
+ MOZ_MUST_USE bool
+-TokenStreamCharsBase<char16_t>::copyTokenbufTo(JSContext* cx,
+-                                               UniquePtr<char16_t[], JS::FreePolicy>* destination)
++TokenStreamCharsShared::copyCharBufferTo(JSContext* cx,
++                                         UniquePtr<char16_t[], JS::FreePolicy>* destination)
+ {
+-    size_t length = tokenbuf.length();
++    size_t length = charBuffer.length();
+ 
+     *destination = cx->make_pod_array<char16_t>(length + 1);
+     if (!*destination)
+         return false;
+ 
+-    PodCopy(destination->get(), tokenbuf.begin(), length);
++    std::copy(charBuffer.begin(), charBuffer.end(), destination->get());
+     (*destination)[length] = '\0';
+     return true;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::getDirective(bool isMultiline,
+                                                          bool shouldWarnDeprecated,
+@@ -1204,17 +1202,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         return true;
+ 
+     if (shouldWarnDeprecated) {
+         if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma))
+             return false;
+     }
+ 
+     sourceUnits.skipCodeUnits(directiveLength);
+-    tokenbuf.clear();
++    charBuffer.clear();
+ 
+     do {
+         int32_t unit = peekCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (unicode::IsSpaceOrBOM2(unit))
+@@ -1225,42 +1223,42 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             // Debugging directives can occur in both single- and multi-line
+             // comments. If we're currently inside a multi-line comment, we
+             // also must recognize multi-line comment terminators.
+             if (isMultiline && unit == '*' && peekCodeUnit() == '/') {
+                 ungetCodeUnit('*');
+                 break;
+             }
+ 
+-            if (!tokenbuf.append(unit))
++            if (!charBuffer.append(unit))
+                 return false;
+ 
+             continue;
+         }
+ 
+         int32_t codePoint;
+         if (!getCodePoint(&codePoint))
+             return false;
+ 
+         if (unicode::IsSpaceOrBOM2(codePoint)) {
+             ungetNonAsciiNormalizedCodePoint(codePoint);
+             break;
+         }
+ 
+-        if (!appendCodePointToTokenbuf(codePoint))
++        if (!appendCodePointToCharBuffer(codePoint))
+             return false;
+     } while (true);
+ 
+-    if (tokenbuf.empty()) {
++    if (charBuffer.empty()) {
+         // The directive's URL was missing, but comments can contain anything,
+         // so it isn't an error.
+         return true;
+     }
+ 
+-    return copyTokenbufTo(anyCharsAccess().cx, destination);
++    return copyCharBufferTo(anyCharsAccess().cx, destination);
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::getDisplayURL(bool isMultiline,
+                                                           bool shouldWarnDeprecated)
+ {
+     // Match comments of the form "//# sourceURL=<url>" or
+@@ -1330,58 +1328,57 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+     // erroneous token has been seen, sourceUnits will not be consulted again.
+     // This is true because the parser will deal with the illegal token by
+     // aborting parsing immediately.
+     sourceUnits.poisonInDebug();
+ 
+     return false;
+ };
+ 
+-template<>
+ MOZ_MUST_USE bool
+-TokenStreamCharsBase<char16_t>::appendCodePointToTokenbuf(uint32_t codePoint)
++TokenStreamCharsShared::appendCodePointToCharBuffer(uint32_t codePoint)
+ {
+     char16_t units[2];
+     unsigned numUnits = 0;
+     unicode::UTF16Encode(codePoint, units, &numUnits);
+ 
+     MOZ_ASSERT(numUnits == 1 || numUnits == 2,
+                "UTF-16 code points are only encoded in one or two units");
+ 
+-    if (!tokenbuf.append(units[0]))
++    if (!charBuffer.append(units[0]))
+         return false;
+ 
+     if (numUnits == 1)
+         return true;
+ 
+-    return tokenbuf.append(units[1]);
++    return charBuffer.append(units[1]);
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+-TokenStreamSpecific<CharT, AnyCharsAccess>::putIdentInTokenbuf(const CharT* identStart)
++TokenStreamSpecific<CharT, AnyCharsAccess>::putIdentInCharBuffer(const CharT* identStart)
+ {
+     const CharT* const originalAddress = sourceUnits.addressOfNextCodeUnit();
+     sourceUnits.setAddressOfNextCodeUnit(identStart);
+ 
+     auto restoreNextRawCharAddress =
+         MakeScopeExit([this, originalAddress]() {
+             this->sourceUnits.setAddressOfNextCodeUnit(originalAddress);
+         });
+ 
+-    tokenbuf.clear();
++    charBuffer.clear();
+     do {
+         int32_t unit = getCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         uint32_t codePoint;
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (MOZ_LIKELY(unicode::IsIdentifierPart(char16_t(unit)))) {
+-                if (!tokenbuf.append(unit))
++                if (!charBuffer.append(unit))
+                     return false;
+ 
+                 continue;
+             }
+ 
+             if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint))
+                 break;
+         } else {
+@@ -1400,17 +1397,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 // revert line/column updates.  The ASCII code path never
+                 // updates line/column state, so only Unicode separators gotten
+                 // by |getNonAsciiCodePoint| require this.
+                 anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+             }
+             break;
+         }
+ 
+-        if (!appendCodePointToTokenbuf(codePoint))
++        if (!appendCodePointToCharBuffer(codePoint))
+             return false;
+     } while (true);
+ 
+     return true;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+@@ -1458,21 +1455,21 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         }
+     }
+ 
+     const CharT* chars;
+     size_t length;
+     if (escaping == IdentifierEscapes::SawUnicodeEscape) {
+         // Identifiers containing Unicode escapes have to be converted into
+         // tokenbuf before atomizing.
+-        if (!putIdentInTokenbuf(identStart))
++        if (!putIdentInCharBuffer(identStart))
+             return false;
+ 
+-        chars = tokenbuf.begin();
+-        length = tokenbuf.length();
++        chars = charBuffer.begin();
++        length = charBuffer.length();
+     } else {
+         // Escape-free identifiers can be created directly from sourceUnits.
+         chars = identStart;
+         length = sourceUnits.addressOfNextCodeUnit() - identStart;
+ 
+         // Represent reserved words lacking escapes as reserved word tokens.
+         if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
+             noteBadToken.release();
+@@ -1681,30 +1678,30 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     return true;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
+ {
+     MOZ_ASSERT(sourceUnits.previousCodeUnit() == '/');
+-    tokenbuf.clear();
++    charBuffer.clear();
+ 
+     auto ProcessNonAsciiCodePoint = [this](CharT lead) {
+         int32_t codePoint;
+         if (!this->getNonAsciiCodePoint(lead, &codePoint))
+             return false;
+ 
+         if (codePoint == '\n') {
+             this->ungetLineTerminator();
+             this->reportError(JSMSG_UNTERMINATED_REGEXP);
+             return false;
+         }
+ 
+-        return this->appendCodePointToTokenbuf(codePoint);
++        return this->appendCodePointToCharBuffer(codePoint);
+     };
+ 
+     auto ReportUnterminatedRegExp = [this](CharT unit) {
+         this->ungetCodeUnit(unit);
+         this->error(JSMSG_UNTERMINATED_REGEXP);
+     };
+ 
+     bool inCharClass = false;
+@@ -1712,17 +1709,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         int32_t unit = getCodeUnit();
+         if (unit == EOF) {
+             ReportUnterminatedRegExp(unit);
+             return badToken();
+         }
+ 
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (unit == '\\')  {
+-                if (!tokenbuf.append(unit))
++                if (!charBuffer.append(unit))
+                     return badToken();
+ 
+                 unit = getCodeUnit();
+                 if (unit == EOF) {
+                     ReportUnterminatedRegExp(unit);
+                     return badToken();
+                 }
+ 
+@@ -1743,17 +1740,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 break;
+             }
+ 
+             if (unit == '\r' || unit == '\n') {
+                 ReportUnterminatedRegExp(unit);
+                 return badToken();
+             }
+ 
+-            if (!tokenbuf.append(unit))
++            if (!charBuffer.append(unit))
+                 return badToken();
+         } else {
+             if (!ProcessNonAsciiCodePoint(unit))
+                 return badToken();
+         }
+     } while (true);
+ 
+     int32_t unit;
+@@ -2301,17 +2298,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ {
+     MOZ_ASSERT(untilChar == '\'' || untilChar == '"' || untilChar == '`',
+                "unexpected string/template literal delimiter");
+ 
+     bool parsingTemplate = (untilChar == '`');
+     bool templateHead = false;
+ 
+     TokenStart start(sourceUnits, -1);
+-    tokenbuf.clear();
++    charBuffer.clear();
+ 
+     // Run the bad-token code for every path out of this function except the
+     // one success-case.
+     auto noteBadToken = MakeScopeExit([this]() {
+         this->badToken();
+     });
+ 
+     auto ReportPrematureEndOfLiteral = [this, untilChar](unsigned errnum) {
+@@ -2359,26 +2356,26 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 anyCharsAccess().updateFlagsForEOL();
+ 
+                 codePoint = unit;
+             } else {
+                 if (!getNonAsciiCodePoint(unit, &codePoint))
+                     return false;
+             }
+ 
+-            if (!appendCodePointToTokenbuf(codePoint))
++            if (!appendCodePointToCharBuffer(codePoint))
+                 return false;
+ 
+             continue;
+         }
+ 
+         if (unit == '\\') {
+             // When parsing templates, we don't immediately report errors for
+             // invalid escapes; these are handled by the parser.  We don't
+-            // append to tokenbuf in those cases because it won't be read.
++            // append to charBuffer in those cases because it won't be read.
+             unit = getCodeUnit();
+             if (unit == EOF) {
+                 ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
+                 return false;
+             }
+ 
+             // Non-ASCII |unit| isn't handled by code after this, so dedicate
+             // an unlikely special-case to it and then continue.
+@@ -2387,17 +2384,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 if (!getNonAsciiCodePoint(unit, &codePoint))
+                     return false;
+ 
+                 // If we consumed U+2028 LINE SEPARATOR or U+2029 PARAGRAPH
+                 // SEPARATOR, they'll be normalized to '\n'.  '\' followed by
+                 // LineContinuation represents no code points, so don't append
+                 // in this case.
+                 if (codePoint != '\n') {
+-                    if (!tokenbuf.append(unit))
++                    if (!charBuffer.append(unit))
+                         return false;
+                 }
+ 
+                 continue;
+             }
+ 
+             switch (static_cast<CharT>(unit)) {
+               case 'b': unit = '\b'; break;
+@@ -2496,17 +2493,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ 
+                         first = false;
+                     } while (true);
+ 
+                     if (!valid)
+                         continue;
+ 
+                     MOZ_ASSERT(code <= unicode::NonBMPMax);
+-                    if (!appendCodePointToTokenbuf(code))
++                    if (!appendCodePointToCharBuffer(code))
+                         return false;
+ 
+                     continue;
+                 } // end of delimited Unicode escape handling
+ 
+                 // Otherwise it must be a fixed-length \uXXXX Unicode escape.
+                 // If it isn't, this is usually an error -- but if this is a
+                 // template literal, we must defer error reporting because
+@@ -2603,17 +2600,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     }
+                 }
+ 
+                 unit = char16_t(val);
+                 break;
+               } // default
+             }
+ 
+-            if (!tokenbuf.append(unit))
++            if (!charBuffer.append(unit))
+                 return false;
+ 
+             continue;
+         } // (unit == '\\')
+ 
+         if (unit == '\r' || unit == '\n') {
+             if (!parsingTemplate) {
+                 // String literals don't allow ASCII line breaks.
+@@ -2634,21 +2631,21 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 return false;
+ 
+             anyCharsAccess().updateFlagsForEOL();
+         } else if (parsingTemplate && unit == '$' && matchCodeUnit('{')) {
+             templateHead = true;
+             break;
+         }
+ 
+-        if (!tokenbuf.append(unit))
++        if (!charBuffer.append(unit))
+             return false;
+     }
+ 
+-    JSAtom* atom = atomizeChars(anyCharsAccess().cx, tokenbuf.begin(), tokenbuf.length());
++    JSAtom* atom = atomizeChars(anyCharsAccess().cx, charBuffer.begin(), charBuffer.length());
+     if (!atom)
+         return false;
+ 
+     noteBadToken.release();
+ 
+     MOZ_ASSERT_IF(!parsingTemplate, !templateHead);
+ 
+     TokenKind kind = !parsingTemplate
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -330,33 +330,53 @@ struct Token
+     };
+     friend class TokenStreamShared;
+ 
+   public:
+     // WARNING: TokenStreamPosition assumes that the only GC things a Token
+     //          includes are atoms.  DON'T ADD NON-ATOM GC THING POINTERS HERE
+     //          UNLESS YOU ADD ADDITIONAL ROOTING TO THAT CLASS.
+ 
+-    TokenKind           type;           // char value or above enumerator
+-    TokenPos            pos;            // token position in file
++    /** The type of this token. */
++    TokenKind type;
++
++    /** The token's position in the overall script. */
++    TokenPos pos;
++
+     union {
+       private:
+         friend struct Token;
+-        PropertyName*   name;          // non-numeric atom
+-        JSAtom*         atom;          // potentially-numeric atom
++
++        /** Non-numeric atom. */
++        PropertyName* name;
++
++        /** Potentially-numeric atom. */
++        JSAtom* atom;
++
+         struct {
+-            double      value;          // floating point number
+-            DecimalPoint decimalPoint;  // literal contains '.'
++            /** Numeric literal's value. */
++            double value;
++
++            /** Does the numeric literal contain a '.'? */
++            DecimalPoint decimalPoint;
+         } number;
+-        RegExpFlag      reflags;        // regexp flags; use tokenbuf to access
+-                                        //   regexp chars
++
++        /** Regular expression flags; use charBuffer to access source chars. */
++        RegExpFlag reflags;
+     } u;
++
+ #ifdef DEBUG
+-    Modifier modifier;                  // Modifier used to get this token
+-    ModifierException modifierException; // Exception for this modifier
++    /** The modifier used to get this token. */
++    Modifier modifier;
++
++    /**
++     * Exception for this modifier to permit modifier mismatches in certain
++     * situations.
++     */
++    ModifierException modifierException;
+ #endif
+ 
+     // Mutators
+ 
+     void setName(PropertyName* name) {
+         MOZ_ASSERT(type == TokenKind::Name);
+         u.name = name;
+     }
+@@ -1046,44 +1066,65 @@ class SourceUnits
+ 
+     /** Limit for quick bounds check. */
+     const CharT* limit_;
+ 
+     /** Next char to get. */
+     const CharT* ptr;
+ };
+ 
++class TokenStreamCharsShared
++{
++    // Using char16_t (not CharT) is a simplifying decision that hopefully
++    // eliminates the need for a UTF-8 regular expression parser and makes
++    // |copyCharBufferTo| markedly simpler.
++    using CharBuffer = Vector<char16_t, 32>;
++
++  protected:
++    /**
++     * Character buffer transiently used to store sequences of identifier or
++     * string code points when such can't be directly processed from the
++     * original source text (e.g. because it contains escapes).
++     */
++    CharBuffer charBuffer;
++
++  protected:
++    explicit TokenStreamCharsShared(JSContext* cx)
++      : charBuffer(cx)
++    {}
++
++    MOZ_MUST_USE bool appendCodePointToCharBuffer(uint32_t codePoint);
++
++    MOZ_MUST_USE bool copyCharBufferTo(JSContext* cx,
++                                       UniquePtr<char16_t[], JS::FreePolicy>* destination);
++
++  public:
++    CharBuffer& getCharBuffer() { return charBuffer; }
++};
++
+ template<typename CharT>
+ class TokenStreamCharsBase
++  : public TokenStreamCharsShared
+ {
+   protected:
+     void ungetCodeUnit(int32_t c) {
+         if (c == EOF)
+             return;
+ 
+         sourceUnits.ungetCodeUnit();
+     }
+ 
+   public:
+-    using CharBuffer = Vector<CharT, 32>;
+-
+     TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
+ 
+     static MOZ_ALWAYS_INLINE JSAtom*
+     atomizeChars(JSContext* cx, const CharT* chars, size_t length);
+ 
+-    const CharBuffer& getTokenbuf() const { return tokenbuf; }
+-
+-    MOZ_MUST_USE bool copyTokenbufTo(JSContext* cx,
+-                                     UniquePtr<char16_t[], JS::FreePolicy>* destination);
+-
+     using SourceUnits = frontend::SourceUnits<CharT>;
+ 
+-    MOZ_MUST_USE bool appendCodePointToTokenbuf(uint32_t codePoint);
+-
+     // |expect| cannot be an EOL char.
+     bool matchCodeUnit(int32_t expect) {
+         MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
+         MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
+         return MOZ_LIKELY(!sourceUnits.atEnd()) && sourceUnits.matchCodeUnit(expect);
+     }
+ 
+   protected:
+@@ -1097,30 +1138,30 @@ class TokenStreamCharsBase
+ #ifdef DEBUG
+         CharT next =
+ #endif
+             sourceUnits.getCodeUnit();
+         MOZ_ASSERT(next == unit, "must be consuming the correct unit");
+     }
+ 
+     MOZ_MUST_USE bool
+-    fillWithTemplateStringContents(CharBuffer& charbuf, const CharT* cur, const CharT* end) {
++    fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end) {
+         while (cur < end) {
+             // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
+             // interpreted literally inside template literal contents; only
+             // literal CRLF sequences are normalized to '\n'.  See
+             // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
+             CharT ch = *cur;
+             if (ch == '\r') {
+                 ch = '\n';
+                 if ((cur + 1 < end) && (*(cur + 1) == '\n'))
+                     cur++;
+             }
+ 
+-            if (!charbuf.append(ch))
++            if (!charBuffer.append(ch))
+                 return false;
+ 
+             cur++;
+         }
+ 
+         return true;
+     }
+ 
+@@ -1131,19 +1172,16 @@ class TokenStreamCharsBase
+      */
+     static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(CharT unit) {
+         return mozilla::IsAscii(unit);
+     }
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+-
+-    /** Current token string buffer. */
+-    CharBuffer tokenbuf;
+ };
+ 
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeChars(JSContext* cx, const char16_t* chars, size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+@@ -1168,17 +1206,17 @@ class TokenStart
+ 
+     uint32_t offset() const { return startOffset_; }
+ };
+ 
+ template<typename CharT, class AnyCharsAccess>
+ class GeneralTokenStreamChars
+   : public TokenStreamCharsBase<CharT>
+ {
+-    using CharsSharedBase = TokenStreamCharsBase<CharT>;
++    using CharsBase = TokenStreamCharsBase<CharT>;
+ 
+     Token* newTokenInternal(TokenKind kind, TokenStart start, TokenKind* out);
+ 
+     /**
+      * Allocates a new Token from the given offset to the current offset,
+      * ascribes it the given kind, and sets |*out| to that kind.
+      */
+     Token* newToken(TokenKind kind, TokenStart start, TokenStreamShared::Modifier modifier,
+@@ -1196,22 +1234,22 @@ class GeneralTokenStreamChars
+ 
+         return token;
+     }
+ 
+     uint32_t matchUnicodeEscape(uint32_t* codePoint);
+     uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+ 
+   protected:
+-    using typename CharsSharedBase::SourceUnits;
++    using typename CharsBase::SourceUnits;
+ 
+-    using CharsSharedBase::sourceUnits;
++    using CharsBase::sourceUnits;
+ 
+-  public:
+-    using CharsSharedBase::CharsSharedBase;
++  protected:
++    using CharsBase::CharsBase;
+ 
+     TokenStreamAnyChars& anyCharsAccess() {
+         return AnyCharsAccess::anyChars(this);
+     }
+ 
+     const TokenStreamAnyChars& anyCharsAccess() const {
+         return AnyCharsAccess::anyChars(this);
+     }
+@@ -1280,61 +1318,61 @@ class GeneralTokenStreamChars
+ 
+         anyCharsAccess().flags.isEOF = true;
+         return EOF;
+     }
+ 
+     void ungetCodeUnit(int32_t c) {
+         MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
+ 
+-        CharsSharedBase::ungetCodeUnit(c);
++        CharsBase::ungetCodeUnit(c);
+     }
+ 
+     void ungetChar(int32_t c);
+ 
+     /**
+      * Consume characters til EOL/EOF following the start of a single-line
+      * comment, without consuming the EOL/EOF.
+      */
+     void consumeRestOfSingleLineComment();
+ 
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+         return anyCharsAccess().internalUpdateLineInfoForEOL(sourceUnits.offset());
+     }
+ 
+-  protected:
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ };
+ 
+ template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+ 
+ template<class AnyCharsAccess>
+ class TokenStreamChars<char16_t, AnyCharsAccess>
+   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
+ {
+   private:
+-    using Self = TokenStreamChars<char16_t, AnyCharsAccess>;
++    using CharsBase = TokenStreamCharsBase<char16_t>;
+     using GeneralCharsBase = GeneralTokenStreamChars<char16_t, AnyCharsAccess>;
+-    using CharsSharedBase = TokenStreamCharsBase<char16_t>;
++    using Self = TokenStreamChars<char16_t, AnyCharsAccess>;
+ 
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
+-    using CharsSharedBase::isAsciiCodePoint;
+-    using GeneralCharsBase::sourceUnits;
+-    using CharsSharedBase::ungetCodeUnit;
++    using CharsBase::isAsciiCodePoint;
++    using CharsBase::sourceUnits;
++    using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+ 
++  protected:
+     using GeneralCharsBase::GeneralCharsBase;
+ 
+     // Try to get the next code point, normalizing '\r', '\r\n', '\n', and the
+     // Unicode line/paragraph separators into '\n'.  Also updates internal
+     // line-counter state.  Return true on success and store the character in
+     // |*c|.  Return false and leave |*c| undefined on failure.
+     MOZ_MUST_USE bool getCodePoint(int32_t* cp);
+ 
+@@ -1472,70 +1510,68 @@ class TokenStreamChars<char16_t, AnyChar
+ //
+ template<typename CharT, class AnyCharsAccess>
+ class MOZ_STACK_CLASS TokenStreamSpecific
+   : public TokenStreamChars<CharT, AnyCharsAccess>,
+     public TokenStreamShared,
+     public ErrorReporter
+ {
+   public:
+-    using CharsBase = TokenStreamChars<CharT, AnyCharsAccess>;
++    using CharsBase = TokenStreamCharsBase<CharT>;
+     using GeneralCharsBase = GeneralTokenStreamChars<CharT, AnyCharsAccess>;
+-    using CharsSharedBase = TokenStreamCharsBase<CharT>;
++    using SpecializedCharsBase = TokenStreamChars<CharT, AnyCharsAccess>;
+ 
+     using Position = TokenStreamPosition<CharT>;
+ 
+     // Anything inherited through a base class whose type depends upon this
+     // class's template parameters can only be accessed through a dependent
+     // name: prefixed with |this|, by explicit qualification, and so on.  (This
+     // is so that references to inherited fields are statically distinguishable
+     // from references to names outside of the class.)  This is tedious and
+     // onerous.
+     //
+     // As an alternative, we directly add every one of these functions to this
+     // class, using explicit qualification to address the dependent-name
+     // problem.  |this| or other qualification is no longer necessary -- at
+     // cost of this ever-changing laundry list of |using|s.  So it goes.
+   public:
+     using GeneralCharsBase::anyCharsAccess;
+-    using CharsSharedBase::getTokenbuf;
+ 
+   private:
+-    using typename CharsSharedBase::CharBuffer;
+-    using typename CharsSharedBase::SourceUnits;
++    using typename CharsBase::SourceUnits;
+ 
+   private:
+-    using CharsSharedBase::appendCodePointToTokenbuf;
+-    using CharsSharedBase::atomizeChars;
++    using TokenStreamCharsShared::appendCodePointToCharBuffer;
++    using CharsBase::atomizeChars;
+     using GeneralCharsBase::badToken;
+-    using CharsSharedBase::consumeKnownCodeUnit;
++    using TokenStreamCharsShared::charBuffer;
++    using CharsBase::consumeKnownCodeUnit;
+     using GeneralCharsBase::consumeRestOfSingleLineComment;
+-    using CharsSharedBase::copyTokenbufTo;
+-    using CharsSharedBase::fillWithTemplateStringContents;
+-    using CharsBase::getChar;
+-    using CharsBase::getCodePoint;
++    using TokenStreamCharsShared::copyCharBufferTo;
++    using CharsBase::fillCharBufferWithTemplateStringContents;
++    using SpecializedCharsBase::getChar;
++    using SpecializedCharsBase::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+-    using CharsBase::getFullAsciiCodePoint;
+-    using CharsBase::getNonAsciiCodePoint;
+-    using CharsSharedBase::isAsciiCodePoint;
+-    using CharsSharedBase::matchCodeUnit;
++    using SpecializedCharsBase::getFullAsciiCodePoint;
++    using SpecializedCharsBase::getNonAsciiCodePoint;
++    using CharsBase::isAsciiCodePoint;
++    using CharsBase::matchCodeUnit;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+-    using CharsSharedBase::peekCodeUnit;
+-    using CharsSharedBase::sourceUnits;
+-    using CharsSharedBase::tokenbuf;
++    using CharsBase::peekCodeUnit;
++    using CharsBase::sourceUnits;
+     using GeneralCharsBase::ungetChar;
+-    using CharsBase::ungetCodePointIgnoreEOL;
+-    using CharsSharedBase::ungetCodeUnit;
+-    using CharsBase::ungetNonAsciiNormalizedCodePoint;
++    using SpecializedCharsBase::ungetCodePointIgnoreEOL;
++    using GeneralCharsBase::ungetCodeUnit;
++    using SpecializedCharsBase::ungetNonAsciiNormalizedCodePoint;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     template<typename CharU> friend class TokenStreamPosition;
+ 
+   public:
+     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
+                         const CharT* base, size_t length);
+ 
+@@ -1628,21 +1664,20 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+         if (anyChars.currentToken().type == TokenKind::TemplateHead) {
+             // Of the form    |`...${|   or   |}...${|
+             end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
+         } else {
+             // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
+             end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
+         }
+ 
+-        CharBuffer charbuf(anyChars.cx);
+-        if (!fillWithTemplateStringContents(charbuf, cur, end))
++        if (!fillCharBufferWithTemplateStringContents(cur, end))
+             return nullptr;
+ 
+-        return atomizeChars(anyChars.cx, charbuf.begin(), charbuf.length());
++        return atomizeChars(anyChars.cx, charBuffer.begin(), charBuffer.length());
+     }
+ 
+   private:
+     // This is private because it should only be called by the tokenizer while
+     // tokenizing not by, for example, BytecodeEmitter.
+     bool reportStrictModeError(unsigned errorNumber, ...);
+ 
+     void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) {
+@@ -1660,17 +1695,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+                 errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence");
+                 return;
+             case InvalidEscapeType::Octal:
+                 errorAt(offset, JSMSG_DEPRECATED_OCTAL);
+                 return;
+         }
+     }
+ 
+-    MOZ_MUST_USE bool putIdentInTokenbuf(const CharT* identStart);
++    MOZ_MUST_USE bool putIdentInCharBuffer(const CharT* identStart);
+ 
+     /**
+      * Tokenize a decimal number that begins at |numStart| into the provided
+      * token.
+      *
+      * |unit| must be one of these values:
+      *
+      *   1. The first decimal digit in the integral part of a decimal number

+ 203 - 0
frg/work-js/mozilla-release/patches/1471464-63a1.patch

@@ -0,0 +1,203 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530131173 25200
+# Node ID f3b134e1e8f154a9df09490a459b8cf6fc218c34
+# Parent  e20c1d6852e4fb05f4fce71523d698cb9ebf28fe
+Bug 1471464 - Make getNonAsciiCodePoint, getFullAsciiCodePoint, and isAsciiCodePoint all take |int32_t| and not |CharT|, because they're all passed |int32_t| from |getCodeUnit()| or a code point-getting mechanism.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -532,18 +532,19 @@ TokenStreamChars<char16_t, AnyCharsAcces
+         return false;
+ 
+     *cp = '\n';
+     return true;
+ }
+ 
+ template<class AnyCharsAccess>
+ bool
+-TokenStreamChars<char16_t, AnyCharsAccess>::getNonAsciiCodePoint(char16_t lead, int32_t* codePoint)
++TokenStreamChars<char16_t, AnyCharsAccess>::getNonAsciiCodePoint(int32_t lead, int32_t* codePoint)
+ {
++    MOZ_ASSERT(lead != EOF);
+     MOZ_ASSERT(!isAsciiCodePoint(lead),
+                "ASCII code unit/point must be handled separately");
+     MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
+                "getNonAsciiCodePoint called incorrectly");
+ 
+     // The code point is usually |lead|: overwrite later if needed.
+     *codePoint = lead;
+ 
+@@ -1680,17 +1681,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
+ {
+     MOZ_ASSERT(sourceUnits.previousCodeUnit() == '/');
+     charBuffer.clear();
+ 
+-    auto ProcessNonAsciiCodePoint = [this](CharT lead) {
++    auto ProcessNonAsciiCodePoint = [this](int32_t lead) {
++        MOZ_ASSERT(lead != EOF);
++
+         int32_t codePoint;
+         if (!this->getNonAsciiCodePoint(lead, &codePoint))
+             return false;
+ 
+         if (codePoint == '\n') {
+             this->ungetLineTerminator();
+             this->reportError(JSMSG_UNTERMINATED_REGEXP);
+             return false;
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1091,16 +1091,25 @@ class TokenStreamCharsShared
+       : charBuffer(cx)
+     {}
+ 
+     MOZ_MUST_USE bool appendCodePointToCharBuffer(uint32_t codePoint);
+ 
+     MOZ_MUST_USE bool copyCharBufferTo(JSContext* cx,
+                                        UniquePtr<char16_t[], JS::FreePolicy>* destination);
+ 
++    /**
++     * Determine whether a code unit constitutes a complete ASCII code point.
++     * (The code point's exact value might not be used, however, if subsequent
++     * code observes that |unit| is part of a LineTerminatorSequence.)
++     */
++    static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(int32_t unit) {
++        return mozilla::IsAscii(unit);
++    }
++
+   public:
+     CharBuffer& getCharBuffer() { return charBuffer; }
+ };
+ 
+ template<typename CharT>
+ class TokenStreamCharsBase
+   : public TokenStreamCharsShared
+ {
+@@ -1160,25 +1169,16 @@ class TokenStreamCharsBase
+                 return false;
+ 
+             cur++;
+         }
+ 
+         return true;
+     }
+ 
+-    /**
+-     * Determine whether a code unit constitutes a complete ASCII code point.
+-     * (The code point's exact value might not be used, however, if subsequent
+-     * code observes that |unit| is part of a LineTerminatorSequence.)
+-     */
+-    static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(CharT unit) {
+-        return mozilla::IsAscii(unit);
+-    }
+-
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeChars(JSContext* cx, const char16_t* chars, size_t length)
+@@ -1355,17 +1355,17 @@ class TokenStreamChars<char16_t, AnyChar
+ 
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
+-    using CharsBase::isAsciiCodePoint;
++    using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::sourceUnits;
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+ 
+   protected:
+     using GeneralCharsBase::GeneralCharsBase;
+@@ -1387,17 +1387,17 @@ class TokenStreamChars<char16_t, AnyChar
+      * point or LineTerminatorSequence (normalizing it to '\n') and store it in
+      * |*codePoint|.  Return true on success, otherwise return false and leave
+      * |*codePoint| undefined on failure.
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+      * This may change the current |sourceUnits| offset.
+      */
+-    MOZ_MUST_USE bool getFullAsciiCodePoint(char16_t lead, int32_t* codePoint) {
++    MOZ_MUST_USE bool getFullAsciiCodePoint(int32_t lead, int32_t* codePoint) {
+         MOZ_ASSERT(isAsciiCodePoint(lead),
+                    "non-ASCII code units must be handled separately");
+         MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
+                    "getFullAsciiCodePoint called incorrectly");
+ 
+         if (MOZ_UNLIKELY(lead == '\r')) {
+             if (MOZ_LIKELY(!sourceUnits.atEnd()))
+                 sourceUnits.matchCodeUnit('\n');
+@@ -1422,17 +1422,17 @@ class TokenStreamChars<char16_t, AnyChar
+      * consume a full code point or LineTerminatorSequence (normalizing it to
+      * '\n') and store it in |*codePoint|.  Return true on success, otherwise
+      * return false and leave |*codePoint| undefined on failure.
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+      * This may change the current |sourceUnits| offset.
+      */
+-    MOZ_MUST_USE bool getNonAsciiCodePoint(char16_t lead, int32_t* cp);
++    MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* cp);
+ 
+     /**
+      * Unget a full code point (ASCII or not) without altering line/column
+      * state.  If line/column state must be updated, this must happen manually.
+      * This method ungets a single code point, not a LineTerminatorSequence
+      * that is multiple code points.  (Generally you shouldn't be in a state
+      * where you've just consumed "\r\n" and want to unget that full sequence.)
+      *
+@@ -1441,17 +1441,17 @@ class TokenStreamChars<char16_t, AnyChar
+      */
+     void ungetCodePointIgnoreEOL(uint32_t codePoint);
+ 
+     /**
+      * Unget an originally non-ASCII, normalized code point, including undoing
+      * line/column updates that were performed for it.  Don't use this if the
+      * code point was gotten *without* line/column state being updated!
+      */
+-    void ungetNonAsciiNormalizedCodePoint(uint32_t codePoint) {
++    void ungetNonAsciiNormalizedCodePoint(int32_t codePoint) {
+         MOZ_ASSERT_IF(isAsciiCodePoint(codePoint),
+                       codePoint == '\n');
+         MOZ_ASSERT(codePoint != unicode::LINE_SEPARATOR,
+                    "should not be ungetting un-normalized code points");
+         MOZ_ASSERT(codePoint != unicode::PARA_SEPARATOR,
+                    "should not be ungetting un-normalized code points");
+ 
+         ungetCodePointIgnoreEOL(codePoint);
+@@ -1547,17 +1547,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using GeneralCharsBase::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedCharsBase::getChar;
+     using SpecializedCharsBase::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedCharsBase::getFullAsciiCodePoint;
+     using SpecializedCharsBase::getNonAsciiCodePoint;
+-    using CharsBase::isAsciiCodePoint;
++    using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+

+ 156 - 0
frg/work-js/mozilla-release/patches/1471465-65a1.patch

@@ -0,0 +1,156 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530131174 25200
+# Node ID 26ded9d5d3321a20235036cbc45a118aea6942cf
+# Parent  f3b134e1e8f154a9df09490a459b8cf6fc218c34
+Bug 1471465 - Fix some issues with ungetting LineTerminatorSequence in certain places.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1368,44 +1368,40 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     charBuffer.clear();
+     do {
+         int32_t unit = getCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         uint32_t codePoint;
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+-            if (MOZ_LIKELY(unicode::IsIdentifierPart(char16_t(unit)))) {
++            if (unicode::IsIdentifierPart(char16_t(unit))) {
+                 if (!charBuffer.append(unit))
+                     return false;
+ 
+                 continue;
+             }
+ 
+             if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint))
+                 break;
+         } else {
+             int32_t cp;
+             if (!getNonAsciiCodePoint(unit, &cp))
+                 return false;
+ 
+             codePoint = AssertedCast<uint32_t>(cp);
+-        }
+-
+-        if (!unicode::IsIdentifierPart(codePoint)) {
+-            if (MOZ_UNLIKELY(codePoint == unicode::LINE_SEPARATOR ||
+-                             codePoint == unicode::PARA_SEPARATOR))
+-            {
+-                // |restoreNextRawCharAddress| undoes all gets, but it doesn't
+-                // revert line/column updates.  The ASCII code path never
+-                // updates line/column state, so only Unicode separators gotten
+-                // by |getNonAsciiCodePoint| require this.
+-                anyCharsAccess().undoInternalUpdateLineInfoForEOL();
++
++            if (!unicode::IsIdentifierPart(codePoint)) {
++                if (MOZ_UNLIKELY(codePoint == '\n')) {
++                    // |restoreNextRawCharAddress| will undo all gets, but we
++                    // have to revert a line/column update manually.
++                    anyCharsAccess().undoInternalUpdateLineInfoForEOL();
++                }
++                break;
+             }
+-            break;
+         }
+ 
+         if (!appendCodePointToCharBuffer(codePoint))
+             return false;
+     } while (true);
+ 
+     return true;
+ }
+@@ -1829,22 +1825,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             TokenStart start(sourceUnits, -1);
+             const CharT* identStart = sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+             int32_t codePoint;
+             if (!getNonAsciiCodePoint(unit, &codePoint))
+                 return badToken();
+ 
+             if (unicode::IsSpaceOrBOM2(codePoint)) {
+-                if (codePoint == unicode::LINE_SEPARATOR || codePoint == unicode::PARA_SEPARATOR) {
+-                    if (!updateLineInfoForEOL())
+-                        return badToken();
+-
++                if (codePoint == '\n')
+                     anyCharsAccess().updateFlagsForEOL();
+-                }
+ 
+                 continue;
+             }
+ 
+             static_assert(isAsciiCodePoint('$'),
+                           "IdentifierStart contains '$', but as "
+                           "!IsUnicodeIDStart('$'), ensure that '$' is never "
+                           "handled here");
+@@ -2034,19 +2026,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     error(JSMSG_IDSTART_AFTER_NUMBER);
+                     return badToken();
+                 }
+             } else {
+                 int32_t codePoint;
+                 if (!getNonAsciiCodePoint(unit, &codePoint))
+                     return badToken();
+ 
+-                ungetCodePointIgnoreEOL(codePoint);
+-                if (codePoint == unicode::LINE_SEPARATOR || codePoint == unicode::PARA_SEPARATOR)
+-                    anyCharsAccess().undoInternalUpdateLineInfoForEOL();
++                ungetNonAsciiNormalizedCodePoint(codePoint);
+ 
+                 if (unicode::IsIdentifierStart(uint32_t(codePoint))) {
+                     error(JSMSG_IDSTART_AFTER_NUMBER);
+                     return badToken();
+                 }
+             }
+ 
+             double dval;
+diff --git a/js/src/tests/non262/syntax/line-number-maintenance-for-identifier-containing-escape-terminated-by-unicode-separator.js b/js/src/tests/non262/syntax/line-number-maintenance-for-identifier-containing-escape-terminated-by-unicode-separator.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/tests/non262/syntax/line-number-maintenance-for-identifier-containing-escape-terminated-by-unicode-separator.js
+@@ -0,0 +1,41 @@
++/*
++ * Any copyright is dedicated to the Public Domain.
++ * http://creativecommons.org/licenses/publicdomain/
++ */
++
++//-----------------------------------------------------------------------------
++var BUGNUMBER = 9999999;
++var summary =
++  "Properly maintain the line number when tokenizing identifiers that " +
++  "contain Unicode escapes *and* are terminated by U+2028 LINE SEPARATOR " +
++  "or U+2029 PARAGRAPH SEPARATOR";
++
++print(BUGNUMBER + ": " + summary);
++
++/**************
++ * BEGIN TEST *
++ **************/
++
++var code = "var a\u0062c = [];\n"; // line 1
++
++for (var i = 0; i < 100; i++)
++  code += "a\\u0062c\u2028a\\u0062c\u2029"; // lines 2..2+200-1
++
++code += "@"; // line 2+200
++
++try
++{
++  eval(code);
++  throw new Error("didn't throw");
++}
++catch (e)
++{
++  assertEq(e.lineNumber, 2 + 200);
++}
++
++/******************************************************************************/
++
++if (typeof reportCompare === "function")
++  reportCompare(true, true);
++
++print("Tests complete");
+

+ 141 - 0
frg/work-js/mozilla-release/patches/1472031-1-63a1.patch

@@ -0,0 +1,141 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530225073 25200
+#      Thu Jun 28 15:31:13 2018 -0700
+# Node ID b64aec5cf563ec12e1ec505a769389ed0cf6e936
+# Parent  4396a31f09b5e3b49204cd6e9ca14e1d41ca366d
+Bug 1472031 - Introduce a drainCharBufferIntoAtom function to clear charBuffer and create an atom from the chars that were in it.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1426,40 +1426,38 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ 
+             if (!unicode::IsIdentifierPart(uint32_t(codePoint))) {
+                 ungetNonAsciiNormalizedCodePoint(codePoint);
+                 break;
+             }
+         }
+     }
+ 
+-    const CharT* chars;
+-    size_t length;
+-    if (escaping == IdentifierEscapes::SawUnicodeEscape) {
++    JSAtom* atom;
++    if (MOZ_UNLIKELY(escaping == IdentifierEscapes::SawUnicodeEscape)) {
+         // Identifiers containing Unicode escapes have to be converted into
+         // tokenbuf before atomizing.
+         if (!putIdentInCharBuffer(identStart))
+             return false;
+ 
+-        chars = charBuffer.begin();
+-        length = charBuffer.length();
++        atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
+     } else {
+         // Escape-free identifiers can be created directly from sourceUnits.
+-        chars = identStart;
+-        length = sourceUnits.addressOfNextCodeUnit() - identStart;
++        const CharT* chars = identStart;
++        size_t length = sourceUnits.addressOfNextCodeUnit() - identStart;
+ 
+         // Represent reserved words lacking escapes as reserved word tokens.
+         if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
+             noteBadToken.release();
+             newSimpleToken(rw->tokentype, start, modifier, out);
+             return true;
+         }
++
++        atom = atomizeChars(anyCharsAccess().cx, chars, length);
+     }
+-
+-    JSAtom* atom = atomizeChars(anyCharsAccess().cx, chars, length);
+     if (!atom)
+         return false;
+ 
+     noteBadToken.release();
+     newNameToken(atom->asPropertyName(), start, modifier, out);
+     return true;
+ }
+ 
+@@ -2607,17 +2605,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             templateHead = true;
+             break;
+         }
+ 
+         if (!charBuffer.append(unit))
+             return false;
+     }
+ 
+-    JSAtom* atom = atomizeChars(anyCharsAccess().cx, charBuffer.begin(), charBuffer.length());
++    JSAtom* atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
+     if (!atom)
+         return false;
+ 
+     noteBadToken.release();
+ 
+     MOZ_ASSERT_IF(!parsingTemplate, !templateHead);
+ 
+     TokenKind kind = !parsingTemplate
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1100,16 +1100,22 @@ class TokenStreamCharsShared
+      * Determine whether a code unit constitutes a complete ASCII code point.
+      * (The code point's exact value might not be used, however, if subsequent
+      * code observes that |unit| is part of a LineTerminatorSequence.)
+      */
+     static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(int32_t unit) {
+         return mozilla::IsAscii(unit);
+     }
+ 
++    JSAtom* drainCharBufferIntoAtom(JSContext* cx) {
++        JSAtom* atom = AtomizeChars(cx, charBuffer.begin(), charBuffer.length());
++        charBuffer.clear();
++        return atom;
++    }
++
+   public:
+     CharBuffer& getCharBuffer() { return charBuffer; }
+ };
+ 
+ template<typename CharT>
+ class TokenStreamCharsBase
+   : public TokenStreamCharsShared
+ {
+@@ -1533,16 +1539,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+   private:
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+     using CharsBase::atomizeChars;
+     using GeneralCharsBase::badToken;
+     using TokenStreamCharsShared::charBuffer;
+     using CharsBase::consumeKnownCodeUnit;
+     using GeneralCharsBase::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
++    using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedCharsBase::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedCharsBase::getFullAsciiCodePoint;
+     using SpecializedCharsBase::getNonAsciiCodePoint;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+@@ -1657,17 +1664,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+         } else {
+             // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
+             end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
+         }
+ 
+         if (!fillCharBufferWithTemplateStringContents(cur, end))
+             return nullptr;
+ 
+-        return atomizeChars(anyChars.cx, charBuffer.begin(), charBuffer.length());
++        return drainCharBufferIntoAtom(anyChars.cx);
+     }
+ 
+   private:
+     // This is private because it should only be called by the tokenizer while
+     // tokenizing not by, for example, BytecodeEmitter.
+     bool reportStrictModeError(unsigned errorNumber, ...);
+ 
+     void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) {

+ 91 - 0
frg/work-js/mozilla-release/patches/1472031-2-63a1.patch

@@ -0,0 +1,91 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530225161 25200
+#      Thu Jun 28 15:32:41 2018 -0700
+# Node ID 08cf6e4ccccec3eb39d8d5cb3a2989a547b50cf0
+# Parent  b64aec5cf563ec12e1ec505a769389ed0cf6e936
+Bug 1472031 - Rename atomizeChars to atomizeSourceChars to clarify it's only for atomizing directly from source text.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1446,17 +1446,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ 
+         // Represent reserved words lacking escapes as reserved word tokens.
+         if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
+             noteBadToken.release();
+             newSimpleToken(rw->tokentype, start, modifier, out);
+             return true;
+         }
+ 
+-        atom = atomizeChars(anyCharsAccess().cx, chars, length);
++        atom = atomizeSourceChars(anyCharsAccess().cx, chars, length);
+     }
+     if (!atom)
+         return false;
+ 
+     noteBadToken.release();
+     newNameToken(atom->asPropertyName(), start, modifier, out);
+     return true;
+ }
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1126,17 +1126,17 @@ class TokenStreamCharsBase
+ 
+         sourceUnits.ungetCodeUnit();
+     }
+ 
+   public:
+     TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
+ 
+     static MOZ_ALWAYS_INLINE JSAtom*
+-    atomizeChars(JSContext* cx, const CharT* chars, size_t length);
++    atomizeSourceChars(JSContext* cx, const CharT* chars, size_t length);
+ 
+     using SourceUnits = frontend::SourceUnits<CharT>;
+ 
+     // |expect| cannot be an EOL char.
+     bool matchCodeUnit(int32_t expect) {
+         MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
+         MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
+         return MOZ_LIKELY(!sourceUnits.atEnd()) && sourceUnits.matchCodeUnit(expect);
+@@ -1182,17 +1182,18 @@ class TokenStreamCharsBase
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+-TokenStreamCharsBase<char16_t>::atomizeChars(JSContext* cx, const char16_t* chars, size_t length)
++TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
++                                                   size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
+ /** A small class encapsulating computation of the start-offset of a Token. */
+ class TokenStart
+ {
+     uint32_t startOffset_;
+@@ -1533,17 +1534,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+   public:
+     using GeneralCharsBase::anyCharsAccess;
+ 
+   private:
+     using typename CharsBase::SourceUnits;
+ 
+   private:
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+-    using CharsBase::atomizeChars;
++    using CharsBase::atomizeSourceChars;
+     using GeneralCharsBase::badToken;
+     using TokenStreamCharsShared::charBuffer;
+     using CharsBase::consumeKnownCodeUnit;
+     using GeneralCharsBase::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedCharsBase::getCodePoint;

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

@@ -0,0 +1,58 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530225209 25200
+#      Thu Jun 28 15:33:29 2018 -0700
+# Node ID 481871dcc4888e3e67aa4bf1864a78dc41996744
+# Parent  08cf6e4ccccec3eb39d8d5cb3a2989a547b50cf0
+Bug 1472031 - Define TokenStreamAnyChars::updateFlagsForEOL inline in the header, for simplicity.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -480,22 +480,16 @@ void
+ TokenStreamAnyChars::undoInternalUpdateLineInfoForEOL()
+ {
+     MOZ_ASSERT(prevLinebase != size_t(-1)); // we should never get more than one EOL
+     linebase = prevLinebase;
+     prevLinebase = size_t(-1);
+     lineno--;
+ }
+ 
+-MOZ_ALWAYS_INLINE void
+-TokenStreamAnyChars::updateFlagsForEOL()
+-{
+-    flags.isDirtyLine = false;
+-}
+-
+ // This gets a full code point, starting from an already-consumed leading code
+ // unit, normalizing EOL sequences to '\n', also updating line/column info as
+ // needed.
+ template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
+ {
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -798,17 +798,19 @@ class TokenStreamAnyChars
+ 
+     /**
+      * Fill in |err|, excepting line-of-context-related fields.  If the token
+      * stream has location information, use that and return true.  If it does
+      * not, use the caller's location information and return false.
+      */
+     bool fillExcludingContext(ErrorMetadata* err, uint32_t offset);
+ 
+-    void updateFlagsForEOL();
++    MOZ_ALWAYS_INLINE void updateFlagsForEOL() {
++        flags.isDirtyLine = false;
++    }
+ 
+   private:
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool internalUpdateLineInfoForEOL(uint32_t lineStartOffset);
+ 
+     void undoInternalUpdateLineInfoForEOL();
+ 
+   public:
+     const Token& nextToken() const {

+ 71 - 0
frg/work-js/mozilla-release/patches/1472031-4-63a1.patch

@@ -0,0 +1,71 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530225252 25200
+#      Thu Jun 28 15:34:12 2018 -0700
+# Node ID d857b06f51caedfb9c5844b82f1308effe2a7b4b
+# Parent  481871dcc4888e3e67aa4bf1864a78dc41996744
+Bug 1472031 - Implement a SourceUnits::remaining() function exposing how many code units are left.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -941,16 +941,21 @@ class SourceUnits
+         return ptr == base_;
+     }
+ 
+     bool atEnd() const {
+         MOZ_ASSERT(ptr <= limit_, "shouldn't have overrun");
+         return ptr >= limit_;
+     }
+ 
++    size_t remaining() const {
++        MOZ_ASSERT(ptr, "can't get a count of remaining code units if poisoned");
++        return mozilla::PointerRangeSize(ptr, limit_);
++    }
++
+     size_t startOffset() const {
+         return startOffset_;
+     }
+ 
+     size_t offset() const {
+         return startOffset_ + mozilla::PointerRangeSize(base_, ptr);
+     }
+ 
+@@ -975,34 +980,34 @@ class SourceUnits
+     }
+ 
+     CharT peekCodeUnit() const {
+         return *ptr;        // this will nullptr-crash if poisoned
+     }
+ 
+     bool peekCodeUnits(uint8_t n, CharT* out) const {
+         MOZ_ASSERT(ptr, "shouldn't peek into poisoned SourceUnits");
+-        if (n > mozilla::PointerRangeSize(ptr, limit_))
++        if (n > remaining())
+             return false;
+ 
+         std::copy_n(ptr, n, out);
+         return true;
+     }
+ 
+     void skipCodeUnits(uint32_t n) {
+         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+-        MOZ_ASSERT(n <= mozilla::PointerRangeSize(ptr, limit_),
++        MOZ_ASSERT(n <= remaining(),
+                    "shouldn't skip beyond end of SourceUnits");
+         ptr += n;
+     }
+ 
+     void unskipCodeUnits(uint32_t n) {
+         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+         MOZ_ASSERT(n <= mozilla::PointerRangeSize(base_, ptr),
+-                   "shouldn't skip beyond start of SourceUnits");
++                   "shouldn't unskip beyond start of SourceUnits");
+         ptr -= n;
+     }
+ 
+     bool matchCodeUnit(CharT c) {
+         if (*ptr == c) {    // this will nullptr-crash if poisoned
+             ptr++;
+             return true;
+         }

+ 119 - 0
frg/work-js/mozilla-release/patches/1472031-5-63a1.patch

@@ -0,0 +1,119 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530225554 25200
+#      Thu Jun 28 15:39:14 2018 -0700
+# Node ID dad92f9be9b723945131b9065d30333de2f0cd13
+# Parent  d857b06f51caedfb9c5844b82f1308effe2a7b4b
+Bug 1472031 - Avoid copying potential directives in TokenStreamSpecific::getDirective.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1098,30 +1098,16 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+ 
+         sourceUnits.unskipCodeUnits(length);
+     }
+ 
+     MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
+     return false;
+ }
+ 
+-// Helper function which returns true if the first length(q) characters in p are
+-// the same as the characters in q.
+-template<typename CharT>
+-static bool
+-CharsMatch(const CharT* p, const char* q)
+-{
+-    while (*q) {
+-        if (*p++ != *q++)
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::getDirectives(bool isMultiline,
+                                                           bool shouldWarnDeprecated)
+ {
+     // Match directive comments used in debugging, such as "//# sourceURL" and
+     // "//# sourceMappingURL". Use of "//@" instead of "//#" is deprecated.
+     //
+@@ -1157,35 +1143,27 @@ template<typename CharT, class AnyCharsA
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::getDirective(bool isMultiline,
+                                                          bool shouldWarnDeprecated,
+                                                          const char* directive,
+                                                          uint8_t directiveLength,
+                                                          const char* errorMsgPragma,
+                                                          UniquePtr<char16_t[], JS::FreePolicy>* destination)
+ {
+-    MOZ_ASSERT(directiveLength <= 18);
+-    char16_t peeked[18];
+-
+-    // If there aren't enough code units left, it can't be the desired
+-    // directive.  (Note that |directive| must be ASCII, so there are no
+-    // tricky encoding issues to consider.)
+-    if (!sourceUnits.peekCodeUnits(directiveLength, peeked))
+-        return true;
+-
+-    // It's also not the desired directive if the code units don't match.
+-    if (!CharsMatch(peeked, directive))
++    // Stop if we don't find |directive|.  (Note that |directive| must be
++    // ASCII, so there are no tricky encoding issues to consider in matching
++    // UTF-8/16-agnostically.)
++    if (!sourceUnits.matchCodeUnits(directive, directiveLength))
+         return true;
+ 
+     if (shouldWarnDeprecated) {
+         if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma))
+             return false;
+     }
+ 
+-    sourceUnits.skipCodeUnits(directiveLength);
+     charBuffer.clear();
+ 
+     do {
+         int32_t unit = peekCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -987,16 +987,33 @@ class SourceUnits
+         MOZ_ASSERT(ptr, "shouldn't peek into poisoned SourceUnits");
+         if (n > remaining())
+             return false;
+ 
+         std::copy_n(ptr, n, out);
+         return true;
+     }
+ 
++    bool matchCodeUnits(const char* chars, uint8_t length) {
++        MOZ_ASSERT(ptr, "shouldn't match into poisoned SourceUnits");
++        if (length > remaining())
++            return false;
++
++        const CharT* start = ptr;
++        const CharT* end = ptr + length;
++        while (ptr < end) {
++            if (*ptr++ != CharT(*chars++)) {
++                ptr = start;
++                return false;
++            }
++        }
++
++        return true;
++    }
++
+     void skipCodeUnits(uint32_t n) {
+         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+         MOZ_ASSERT(n <= remaining(),
+                    "shouldn't skip beyond end of SourceUnits");
+         ptr += n;
+     }
+ 
+     void unskipCodeUnits(uint32_t n) {

+ 155 - 0
frg/work-js/mozilla-release/patches/1472031-6-63a1.patch

@@ -0,0 +1,155 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530227333 25200
+#      Thu Jun 28 16:08:53 2018 -0700
+# Node ID ba24991f7f4d976ee709a23d62b91fb39d4641d6
+# Parent  dad92f9be9b723945131b9065d30333de2f0cd13
+Bug 1472031 - Add SourceUnits::matchHexDigits and remove SourceUnits::peekCodeUnits used for the same ends (but that also performed a needless copy).  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1003,27 +1003,20 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+     int32_t unit = getCodeUnit();
+     if (unit != 'u') {
+         // NOTE: |unit| may be EOF here.
+         ungetCodeUnit(unit);
+         MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
+         return 0;
+     }
+ 
+-    CharT cp[3];
++    char16_t v;
+     unit = getCodeUnit();
+-    if (JS7_ISHEX(unit) &&
+-        sourceUnits.peekCodeUnits(3, cp) &&
+-        JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]))
+-    {
+-        *codePoint = (JS7_UNHEX(unit) << 12) |
+-                     (JS7_UNHEX(cp[0]) << 8) |
+-                     (JS7_UNHEX(cp[1]) << 4) |
+-                     JS7_UNHEX(cp[2]);
+-        sourceUnits.skipCodeUnits(3);
++    if (JS7_ISHEX(unit) && sourceUnits.matchHexDigits(3, &v)) {
++        *codePoint = (JS7_UNHEX(unit) << 12) | v;
+         return 5;
+     }
+ 
+     if (unit == '{')
+         return matchExtendedUnicodeEscape(codePoint);
+ 
+     // NOTE: |unit| may be EOF here, so this ungets either one or two units.
+     ungetCodeUnit(unit);
+@@ -2445,26 +2438,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ 
+                     continue;
+                 } // end of delimited Unicode escape handling
+ 
+                 // Otherwise it must be a fixed-length \uXXXX Unicode escape.
+                 // If it isn't, this is usually an error -- but if this is a
+                 // template literal, we must defer error reporting because
+                 // malformed escapes are okay in *tagged* template literals.
+-                CharT cp[3];
+-                if (JS7_ISHEX(c2) &&
+-                    sourceUnits.peekCodeUnits(3, cp) &&
+-                    JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]))
+-                {
+-                    unit = (JS7_UNHEX(c2) << 12) |
+-                           (JS7_UNHEX(cp[0]) << 8) |
+-                           (JS7_UNHEX(cp[1]) << 4) |
+-                           JS7_UNHEX(cp[2]);
+-                    sourceUnits.skipCodeUnits(3);
++                char16_t v;
++                if (JS7_ISHEX(c2) && sourceUnits.matchHexDigits(3, &v)) {
++                    unit = (JS7_UNHEX(c2) << 12) | v;
+                 } else {
+                     // Beware: |c2| may not be an ASCII code point here!
+                     ungetCodeUnit(c2);
+                     uint32_t start = sourceUnits.offset() - 2;
+                     if (parsingTemplate) {
+                         TokenStreamAnyChars& anyChars = anyCharsAccess();
+                         anyChars.setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
+                         continue;
+@@ -2472,22 +2458,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
+                     return false;
+                 }
+                 break;
+               } // case 'u'
+ 
+               // Hexadecimal character specification.
+               case 'x': {
+-                CharT cp[2];
+-                if (sourceUnits.peekCodeUnits(2, cp) &&
+-                    JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]))
+-                {
+-                    unit = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
+-                    sourceUnits.skipCodeUnits(2);
++                char16_t v;
++                if (sourceUnits.matchHexDigits(2, &v)) {
++                    unit = v;
+                 } else {
+                     uint32_t start = sourceUnits.offset() - 2;
+                     if (parsingTemplate) {
+                         TokenStreamAnyChars& anyChars = anyCharsAccess();
+                         anyChars.setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal);
+                         continue;
+                     }
+                     reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal);
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -178,16 +178,17 @@
+ #include <stdio.h>
+ 
+ #include "jspubtd.h"
+ 
+ #include "frontend/ErrorReporter.h"
+ #include "frontend/TokenKind.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
++#include "util/Text.h"
+ #include "util/Unicode.h"
+ #include "vm/ErrorReporting.h"
+ #include "vm/JSContext.h"
+ #include "vm/RegExpShared.h"
+ #include "vm/StringType.h"
+ 
+ struct KeywordInfo;
+ 
+@@ -978,22 +979,33 @@ class SourceUnits
+     CharT getCodeUnit() {
+         return *ptr++;      // this will nullptr-crash if poisoned
+     }
+ 
+     CharT peekCodeUnit() const {
+         return *ptr;        // this will nullptr-crash if poisoned
+     }
+ 
+-    bool peekCodeUnits(uint8_t n, CharT* out) const {
++    /** Match |n| hexadecimal digits and store their value in |*out|. */
++    bool matchHexDigits(uint8_t n, char16_t* out) {
+         MOZ_ASSERT(ptr, "shouldn't peek into poisoned SourceUnits");
++        MOZ_ASSERT(n <= 4, "hexdigit value can't overflow char16_t");
+         if (n > remaining())
+             return false;
+ 
+-        std::copy_n(ptr, n, out);
++        char16_t v = 0;
++        for (uint8_t i = 0; i < n; i++) {
++            if (!JS7_ISHEX(ptr[i]))
++                return false;
++
++            v = (v << 4) | JS7_UNHEX(ptr[i]);
++        }
++
++        *out = v;
++        ptr += n;
+         return true;
+     }
+ 
+     bool matchCodeUnits(const char* chars, uint8_t length) {
+         MOZ_ASSERT(ptr, "shouldn't match into poisoned SourceUnits");
+         if (length > remaining())
+             return false;
+ 

+ 92 - 0
frg/work-js/mozilla-release/patches/1472066-1-63a1.patch

@@ -0,0 +1,92 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530242067 25200
+#      Thu Jun 28 20:14:27 2018 -0700
+# Node ID 234fc6b955c94397b0d17f1b9b273315b91b92bc
+# Parent  ba24991f7f4d976ee709a23d62b91fb39d4641d6
+Bug 1472066 - Specialize TokenStreamCharsBase::fillCharBufferWithTemplateStringContents for char16_t now that its alternative UTF-8 implementation will have to function a bit differently to write data into a char16_t charBuffer.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1188,52 +1188,58 @@ class TokenStreamCharsBase
+         MOZ_ASSERT(!sourceUnits.atEnd(), "must have units to consume");
+ #ifdef DEBUG
+         CharT next =
+ #endif
+             sourceUnits.getCodeUnit();
+         MOZ_ASSERT(next == unit, "must be consuming the correct unit");
+     }
+ 
+-    MOZ_MUST_USE bool
+-    fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end) {
+-        while (cur < end) {
+-            // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
+-            // interpreted literally inside template literal contents; only
+-            // literal CRLF sequences are normalized to '\n'.  See
+-            // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
+-            CharT ch = *cur;
+-            if (ch == '\r') {
+-                ch = '\n';
+-                if ((cur + 1 < end) && (*(cur + 1) == '\n'))
+-                    cur++;
+-            }
+-
+-            if (!charBuffer.append(ch))
+-                return false;
+-
+-            cur++;
+-        }
+-
+-        return true;
+-    }
++    MOZ_MUST_USE inline bool
++    fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+                                                    size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
++template<>
++MOZ_MUST_USE inline bool
++TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
++                                                                         const char16_t* end)
++{
++    MOZ_ASSERT(charBuffer.length() == 0);
++
++    while (cur < end) {
++        // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
++        // interpreted literally inside template literal contents; only
++        // literal CRLF sequences are normalized to '\n'.  See
++        // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
++        char16_t ch = *cur++;
++        if (ch == '\r') {
++            ch = '\n';
++            if (cur < end && *cur == '\n')
++                cur++;
++        }
++
++        if (!charBuffer.append(ch))
++            return false;
++    }
++
++    return true;
++}
++
+ /** A small class encapsulating computation of the start-offset of a Token. */
+ class TokenStart
+ {
+     uint32_t startOffset_;
+ 
+   public:
+     /**
+      * Compute a starting offset that is the current offset of |sourceUnits|,

+ 174 - 0
frg/work-js/mozilla-release/patches/1472066-2-63a1.patch

@@ -0,0 +1,174 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530242237 25200
+#      Thu Jun 28 20:17:17 2018 -0700
+# Node ID 29dc2c52071353c63e34f90f36fe9aefd4b07c0c
+# Parent  234fc6b955c94397b0d17f1b9b273315b91b92bc
+Bug 1472066 - Add some helper functions to enable (once the non-integral Utf8Unit code unit type lands, soon) dealing with Utf8Unit as the type of UTF-8 source code in addition to char16_t for UTF-16 source code.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -160,16 +160,17 @@
+  * TokenStream class, that requires different offset calculations.  So even if
+  * we wanted to hardcode this (it's not clear we would, because forcing the
+  * TokenStreamSpecific declarer to specify this is more explicit), we couldn't.
+  */
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Attributes.h"
++#include "mozilla/Casting.h"
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/PodOperations.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ 
+ #include <algorithm>
+@@ -909,16 +910,22 @@ class TokenStreamAnyChars
+      */
+     bool isExprEnding[size_t(TokenKind::Limit)] = {}; // all-false initially
+ 
+     JSContext* const    cx;
+     bool                mutedErrors;
+     StrictModeGetter*   strictModeGetter;  // used to test for strict mode
+ };
+ 
++constexpr char16_t
++CodeUnitValue(char16_t unit)
++{
++    return unit;
++}
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //
+@@ -988,20 +995,21 @@ class SourceUnits
+     bool matchHexDigits(uint8_t n, char16_t* out) {
+         MOZ_ASSERT(ptr, "shouldn't peek into poisoned SourceUnits");
+         MOZ_ASSERT(n <= 4, "hexdigit value can't overflow char16_t");
+         if (n > remaining())
+             return false;
+ 
+         char16_t v = 0;
+         for (uint8_t i = 0; i < n; i++) {
+-            if (!JS7_ISHEX(ptr[i]))
++            auto unit = CodeUnitValue(ptr[i]);
++            if (!JS7_ISHEX(unit))
+                 return false;
+ 
+-            v = (v << 4) | JS7_UNHEX(ptr[i]);
++            v = (v << 4) | JS7_UNHEX(unit);
+         }
+ 
+         *out = v;
+         ptr += n;
+         return true;
+     }
+ 
+     bool matchCodeUnits(const char* chars, uint8_t length) {
+@@ -1151,69 +1159,89 @@ class TokenStreamCharsShared
+     CharBuffer& getCharBuffer() { return charBuffer; }
+ };
+ 
+ template<typename CharT>
+ class TokenStreamCharsBase
+   : public TokenStreamCharsShared
+ {
+   protected:
++    /**
++     * Convert a non-EOF code unit returned by |getCodeUnit()| or
++     * |peekCodeUnit()| to a CharT code unit.
++     */
++    inline CharT toCharT(int32_t codeUnitValue);
++
+     void ungetCodeUnit(int32_t c) {
+         if (c == EOF)
+             return;
+ 
+         sourceUnits.ungetCodeUnit();
+     }
+ 
+   public:
+     TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
+ 
+     static MOZ_ALWAYS_INLINE JSAtom*
+     atomizeSourceChars(JSContext* cx, const CharT* chars, size_t length);
+ 
+     using SourceUnits = frontend::SourceUnits<CharT>;
+ 
+-    // |expect| cannot be an EOL char.
+-    bool matchCodeUnit(int32_t expect) {
+-        MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
+-        MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
+-        return MOZ_LIKELY(!sourceUnits.atEnd()) && sourceUnits.matchCodeUnit(expect);
+-    }
++    /** Match a non-EOL, non-EOF code unit; return true iff it was matched. */
++    inline bool matchCodeUnit(int32_t expect);
+ 
+   protected:
+     int32_t peekCodeUnit() {
+-        return MOZ_LIKELY(!sourceUnits.atEnd()) ? sourceUnits.peekCodeUnit() : EOF;
++        return MOZ_LIKELY(!sourceUnits.atEnd()) ? CodeUnitValue(sourceUnits.peekCodeUnit()) : EOF;
+     }
+ 
+     void consumeKnownCodeUnit(int32_t unit) {
+         MOZ_ASSERT(unit != EOF, "shouldn't be matching EOF");
+         MOZ_ASSERT(!sourceUnits.atEnd(), "must have units to consume");
+ #ifdef DEBUG
+         CharT next =
+ #endif
+             sourceUnits.getCodeUnit();
+-        MOZ_ASSERT(next == unit, "must be consuming the correct unit");
++        MOZ_ASSERT(CodeUnitValue(next) == unit,
++                   "must be consuming the correct unit");
+     }
+ 
+     MOZ_MUST_USE inline bool
+     fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
++inline char16_t
++TokenStreamCharsBase<char16_t>::toCharT(int32_t codeUnitValue)
++{
++    MOZ_ASSERT(codeUnitValue != EOF, "EOF is not a CharT");
++    return mozilla::AssertedCast<char16_t>(codeUnitValue);
++}
++
++template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+                                                    size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
++template<typename CharT>
++inline bool
++TokenStreamCharsBase<CharT>::matchCodeUnit(int32_t expect)
++{
++    MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
++    MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
++    return MOZ_LIKELY(!sourceUnits.atEnd()) && sourceUnits.matchCodeUnit(toCharT(expect));
++}
++
+ template<>
+ MOZ_MUST_USE inline bool
+ TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
+                                                                          const char16_t* end)
+ {
+     MOZ_ASSERT(charBuffer.length() == 0);
+ 
+     while (cur < end) {

+ 77 - 0
frg/work-js/mozilla-release/patches/1472066-3-63a1.patch

@@ -0,0 +1,77 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530242331 25200
+#      Thu Jun 28 20:18:51 2018 -0700
+# Node ID 1031a09274e0bc148e11f0dae2426e64e107c69a
+# Parent  d7fcfaa2c82d744eb07a138d8fb4870bd039127f
+Bug 1472066 - Define UTF-8-specific versions of certain tokenizing helper functions, complementing the existing UTF-16 versions.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -167,16 +167,17 @@
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Casting.h"
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/PodOperations.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
++#include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+ #include <stdarg.h>
+ #include <stddef.h>
+ #include <stdio.h>
+ 
+ #include "jspubtd.h"
+ 
+@@ -916,16 +917,22 @@ class TokenStreamAnyChars
+ };
+ 
+ constexpr char16_t
+ CodeUnitValue(char16_t unit)
+ {
+     return unit;
+ }
+ 
++constexpr uint8_t
++CodeUnitValue(mozilla::Utf8Unit unit)
++{
++    return unit.toUint8();
++}
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //
+@@ -1216,16 +1223,24 @@ template<>
+ inline char16_t
+ TokenStreamCharsBase<char16_t>::toCharT(int32_t codeUnitValue)
+ {
+     MOZ_ASSERT(codeUnitValue != EOF, "EOF is not a CharT");
+     return mozilla::AssertedCast<char16_t>(codeUnitValue);
+ }
+ 
+ template<>
++inline mozilla::Utf8Unit
++TokenStreamCharsBase<mozilla::Utf8Unit>::toCharT(int32_t value)
++{
++    MOZ_ASSERT(value != EOF, "EOF is not a CharT");
++    return mozilla::Utf8Unit(static_cast<unsigned char>(value));
++}
++
++template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+                                                    size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
+ template<typename CharT>

+ 65 - 0
frg/work-js/mozilla-release/patches/1472066-4-63a1.patch

@@ -0,0 +1,65 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530242364 25200
+#      Thu Jun 28 20:19:24 2018 -0700
+# Node ID fe4e166eea33dfe82a4fb4bffc0282fe4ac0d402
+# Parent  67f38ee63d7c9c4bb1cb0a919102c3a760b5ed7c
+Bug 1472066 - Instantiate TokenStreamCharsBase for UTF-8 source text.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -10,16 +10,17 @@
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/IntegerTypeTraits.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/ScopeExit.h"
+ #include "mozilla/TextUtils.h"
++#include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+ #include <ctype.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <utility>
+ 
+@@ -39,16 +40,17 @@
+ #include "vm/JSContext.h"
+ 
+ using mozilla::ArrayLength;
+ using mozilla::AssertedCast;
+ using mozilla::IsAscii;
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
+ using mozilla::MakeScopeExit;
++using mozilla::Utf8Unit;
+ 
+ struct ReservedWordInfo
+ {
+     const char* chars;         // C string with reserved word text
+     js::frontend::TokenKind tokentype;
+ };
+ 
+ static const ReservedWordInfo reservedWords[] = {
+@@ -2607,16 +2609,17 @@ TokenKindToString(TokenKind tt)
+ #undef EMIT_CASE
+       case TokenKind::Limit: break;
+     }
+ 
+     return "<bad TokenKind>";
+ }
+ #endif
+ 
++template class frontend::TokenStreamCharsBase<Utf8Unit>;
+ template class frontend::TokenStreamCharsBase<char16_t>;
+ 
+ template class frontend::TokenStreamChars<char16_t, frontend::TokenStreamAnyCharsAccess>;
+ template class frontend::TokenStreamSpecific<char16_t, frontend::TokenStreamAnyCharsAccess>;
+ 
+ template class
+ frontend::TokenStreamChars<char16_t, frontend::ParserAnyCharsAccess<frontend::GeneralParser<frontend::FullParseHandler, char16_t>>>;
+ template class

+ 1268 - 0
frg/work-js/mozilla-release/patches/1472569-63a1.patch

@@ -0,0 +1,1268 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530584218 25200
+# Node ID 25d29385236c0062dc73e2b7199de1dc40d702e0
+# Parent  f947d902ed915d6069314d07fa10cc9d5ac2a283
+Bug 1472569 - |this->|-qualify a bunch of function calls on |using Base::foo| members that gcc 8 completely chokes on and grossly misunderstands.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -489,33 +489,33 @@ TokenStreamAnyChars::undoInternalUpdateL
+ // unit, normalizing EOL sequences to '\n', also updating line/column info as
+ // needed.
+ template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
+ {
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+-    if (MOZ_UNLIKELY(sourceUnits.atEnd())) {
++    if (MOZ_UNLIKELY(this->sourceUnits.atEnd())) {
+         anyChars.flags.isEOF = true;
+         *cp = EOF;
+         return true;
+     }
+ 
+-    int32_t c = sourceUnits.getCodeUnit();
++    int32_t c = this->sourceUnits.getCodeUnit();
+ 
+     do {
+         // Normalize the char16_t if it was a newline.
+         if (MOZ_UNLIKELY(c == '\n'))
+             break;
+ 
+         if (MOZ_UNLIKELY(c == '\r')) {
+             // If it's a \r\n sequence: treat as a single EOL, skip over the \n.
+-            if (MOZ_LIKELY(!sourceUnits.atEnd()))
+-                sourceUnits.matchCodeUnit('\n');
++            if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
++                this->sourceUnits.matchCodeUnit('\n');
+ 
+             break;
+         }
+ 
+         if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR))
+             break;
+ 
+         *cp = c;
+@@ -531,17 +531,17 @@ TokenStreamChars<char16_t, AnyCharsAcces
+ 
+ template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getNonAsciiCodePoint(int32_t lead, int32_t* codePoint)
+ {
+     MOZ_ASSERT(lead != EOF);
+     MOZ_ASSERT(!isAsciiCodePoint(lead),
+                "ASCII code unit/point must be handled separately");
+-    MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
++    MOZ_ASSERT(lead == this->sourceUnits.previousCodeUnit(),
+                "getNonAsciiCodePoint called incorrectly");
+ 
+     // The code point is usually |lead|: overwrite later if needed.
+     *codePoint = lead;
+ 
+     // ECMAScript specifically requires that unpaired UTF-16 surrogates be
+     // treated as the corresponding code point and not as an error.  See
+     // <https://tc39.github.io/ecma262/#sec-ecmascript-language-types-string-type>.
+@@ -565,56 +565,56 @@ TokenStreamChars<char16_t, AnyCharsAcces
+         } else {
+             MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
+         }
+ 
+         return true;
+     }
+ 
+     // Also handle a lead surrogate not paired with a trailing surrogate.
+-    if (MOZ_UNLIKELY(sourceUnits.atEnd() ||
+-                     !unicode::IsTrailSurrogate(sourceUnits.peekCodeUnit())))
++    if (MOZ_UNLIKELY(this->sourceUnits.atEnd() ||
++                     !unicode::IsTrailSurrogate(this->sourceUnits.peekCodeUnit())))
+     {
+         MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
+         return true;
+     }
+ 
+     // Otherwise we have a multi-unit code point.
+-    *codePoint = unicode::UTF16Decode(lead, sourceUnits.getCodeUnit());
++    *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
+     MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
+     return true;
+ }
+ 
+ template<class AnyCharsAccess>
+ void
+ TokenStreamChars<char16_t, AnyCharsAccess>::ungetCodePointIgnoreEOL(uint32_t codePoint)
+ {
+-    MOZ_ASSERT(!sourceUnits.atStart());
++    MOZ_ASSERT(!this->sourceUnits.atStart());
+ 
+     unsigned numUnits = 0;
+     char16_t units[2];
+     unicode::UTF16Encode(codePoint, units, &numUnits);
+ 
+     MOZ_ASSERT(numUnits == 1 || numUnits == 2);
+ 
+     while (numUnits-- > 0)
+         ungetCodeUnit(units[numUnits]);
+ }
+ 
+ template<class AnyCharsAccess>
+ void
+ TokenStreamChars<char16_t, AnyCharsAccess>::ungetLineTerminator()
+ {
+-    sourceUnits.ungetCodeUnit();
+-
+-    char16_t last = sourceUnits.peekCodeUnit();
++    this->sourceUnits.ungetCodeUnit();
++
++    char16_t last = this->sourceUnits.peekCodeUnit();
+     MOZ_ASSERT(SourceUnits::isRawEOLChar(last));
+ 
+     if (last == '\n')
+-        sourceUnits.ungetOptionalCRBeforeLF();
++        this->sourceUnits.ungetOptionalCRBeforeLF();
+ 
+     anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+ }
+ 
+ template<typename CharT>
+ size_t
+ SourceUnits<CharT>::findEOLMax(size_t start, size_t max)
+ {
+@@ -636,38 +636,38 @@ SourceUnits<CharT>::findEOLMax(size_t st
+     }
+     return start + n;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::advance(size_t position)
+ {
+-    const CharT* end = sourceUnits.codeUnitPtrAt(position);
+-    while (sourceUnits.addressOfNextCodeUnit() < end) {
++    const CharT* end = this->sourceUnits.codeUnitPtrAt(position);
++    while (this->sourceUnits.addressOfNextCodeUnit() < end) {
+         int32_t c;
+         if (!getCodePoint(&c))
+             return false;
+     }
+ 
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+     Token* cur = const_cast<Token*>(&anyChars.currentToken());
+-    cur->pos.begin = sourceUnits.offset();
++    cur->pos.begin = this->sourceUnits.offset();
+     MOZ_MAKE_MEM_UNDEFINED(&cur->type, sizeof(cur->type));
+     anyChars.lookahead = 0;
+     return true;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ void
+ TokenStreamSpecific<CharT, AnyCharsAccess>::seek(const Position& pos)
+ {
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+-    sourceUnits.setAddressOfNextCodeUnit(pos.buf, /* allowPoisoned = */ true);
++    this->sourceUnits.setAddressOfNextCodeUnit(pos.buf, /* allowPoisoned = */ true);
+     anyChars.flags = pos.flags;
+     anyChars.lineno = pos.lineno;
+     anyChars.linebase = pos.linebase;
+     anyChars.prevLinebase = pos.prevLinebase;
+     anyChars.lookahead = pos.lookahead;
+ 
+     anyChars.tokens[anyChars.cursor()] = pos.currentToken;
+     for (unsigned i = 0; i < anyChars.lookahead; i++)
+@@ -827,22 +827,22 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     // |windowRadius| characters before |offset|.
+     MOZ_ASSERT(offset >= anyChars.linebase);
+     size_t windowStart = (offset - anyChars.linebase > windowRadius) ?
+                          offset - windowRadius :
+                          anyChars.linebase;
+ 
+     // The window must start within the portion of the current line that we
+     // actually have in our buffer.
+-    if (windowStart < sourceUnits.startOffset())
+-        windowStart = sourceUnits.startOffset();
++    if (windowStart < this->sourceUnits.startOffset())
++        windowStart = this->sourceUnits.startOffset();
+ 
+     // The window must end within the current line, no later than
+     // windowRadius after offset.
+-    size_t windowEnd = sourceUnits.findEOLMax(offset, windowRadius);
++    size_t windowEnd = this->sourceUnits.findEOLMax(offset, windowRadius);
+     size_t windowLength = windowEnd - windowStart;
+     MOZ_ASSERT(windowLength <= windowRadius * 2);
+ 
+     // Create the windowed string, not including the potential line
+     // terminator.
+     StringBuffer windowBuf(anyChars.cx);
+     if (!windowBuf.append(codeUnitPtrAt(windowStart), windowLength) ||
+         !windowBuf.append('\0'))
+@@ -951,17 +951,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ template<typename CharT, class AnyCharsAccess>
+ void
+ TokenStreamSpecific<CharT, AnyCharsAccess>::error(unsigned errorNumber, ...)
+ {
+     va_list args;
+     va_start(args, errorNumber);
+ 
+     ErrorMetadata metadata;
+-    if (computeErrorMetadata(&metadata, sourceUnits.offset())) {
++    if (computeErrorMetadata(&metadata, this->sourceUnits.offset())) {
+         TokenStreamAnyChars& anyChars = anyCharsAccess();
+         ReportCompileError(anyChars.cx, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber,
+                            args);
+     }
+ 
+     va_end(args);
+ }
+ 
+@@ -993,48 +993,48 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ // We have encountered a '\': check for a Unicode escape sequence after it.
+ // Return the length of the escape sequence and the encoded code point (by
+ // value) if we found a Unicode escape sequence, and skip all code units
+ // involed.  Otherwise, return 0 and don't advance along the buffer.
+ template<typename CharT, class AnyCharsAccess>
+ uint32_t
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscape(uint32_t* codePoint)
+ {
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
+ 
+     int32_t unit = getCodeUnit();
+     if (unit != 'u') {
+         // NOTE: |unit| may be EOF here.
+         ungetCodeUnit(unit);
+-        MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
++        MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
+         return 0;
+     }
+ 
+     char16_t v;
+     unit = getCodeUnit();
+-    if (JS7_ISHEX(unit) && sourceUnits.matchHexDigits(3, &v)) {
++    if (JS7_ISHEX(unit) && this->sourceUnits.matchHexDigits(3, &v)) {
+         *codePoint = (JS7_UNHEX(unit) << 12) | v;
+         return 5;
+     }
+ 
+     if (unit == '{')
+         return matchExtendedUnicodeEscape(codePoint);
+ 
+     // NOTE: |unit| may be EOF here, so this ungets either one or two units.
+     ungetCodeUnit(unit);
+     ungetCodeUnit('u');
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
+     return 0;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ uint32_t
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchExtendedUnicodeEscape(uint32_t* codePoint)
+ {
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '{');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '{');
+ 
+     int32_t unit = getCodeUnit();
+ 
+     // Skip leading zeroes.
+     uint32_t leadingZeroes = 0;
+     while (unit == '0') {
+         leadingZeroes++;
+         unit = getCodeUnit();
+@@ -1054,50 +1054,50 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+         i + // significant hexdigits
+         (unit != EOF); // subtract a get if it didn't contribute to length
+ 
+     if (unit == '}' && (leadingZeroes > 0 || i > 0) && code <= unicode::NonBMPMax) {
+         *codePoint = code;
+         return gotten;
+     }
+ 
+-    sourceUnits.unskipCodeUnits(gotten);
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
++    this->sourceUnits.unskipCodeUnits(gotten);
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
+     return 0;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ uint32_t
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdStart(uint32_t* codePoint)
+ {
+     uint32_t length = matchUnicodeEscape(codePoint);
+     if (MOZ_LIKELY(length > 0)) {
+         if (MOZ_LIKELY(unicode::IsIdentifierStart(*codePoint)))
+             return length;
+ 
+-        sourceUnits.unskipCodeUnits(length);
++        this->sourceUnits.unskipCodeUnits(length);
+     }
+ 
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
+     return 0;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t* codePoint)
+ {
+     uint32_t length = matchUnicodeEscape(codePoint);
+     if (MOZ_LIKELY(length > 0)) {
+         if (MOZ_LIKELY(unicode::IsIdentifierPart(*codePoint)))
+             return true;
+ 
+-        sourceUnits.unskipCodeUnits(length);
++        this->sourceUnits.unskipCodeUnits(length);
+     }
+ 
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
+     return false;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::getDirectives(bool isMultiline,
+                                                           bool shouldWarnDeprecated)
+ {
+@@ -1139,25 +1139,25 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                                                          const char* directive,
+                                                          uint8_t directiveLength,
+                                                          const char* errorMsgPragma,
+                                                          UniquePtr<char16_t[], JS::FreePolicy>* destination)
+ {
+     // Stop if we don't find |directive|.  (Note that |directive| must be
+     // ASCII, so there are no tricky encoding issues to consider in matching
+     // UTF-8/16-agnostically.)
+-    if (!sourceUnits.matchCodeUnits(directive, directiveLength))
++    if (!this->sourceUnits.matchCodeUnits(directive, directiveLength))
+         return true;
+ 
+     if (shouldWarnDeprecated) {
+         if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma))
+             return false;
+     }
+ 
+-    charBuffer.clear();
++    this->charBuffer.clear();
+ 
+     do {
+         int32_t unit = peekCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (unicode::IsSpaceOrBOM2(unit))
+@@ -1168,17 +1168,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             // Debugging directives can occur in both single- and multi-line
+             // comments. If we're currently inside a multi-line comment, we
+             // also must recognize multi-line comment terminators.
+             if (isMultiline && unit == '*' && peekCodeUnit() == '/') {
+                 ungetCodeUnit('*');
+                 break;
+             }
+ 
+-            if (!charBuffer.append(unit))
++            if (!this->charBuffer.append(unit))
+                 return false;
+ 
+             continue;
+         }
+ 
+         int32_t codePoint;
+         if (!getCodePoint(&codePoint))
+             return false;
+@@ -1187,17 +1187,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             ungetNonAsciiNormalizedCodePoint(codePoint);
+             break;
+         }
+ 
+         if (!appendCodePointToCharBuffer(codePoint))
+             return false;
+     } while (true);
+ 
+-    if (charBuffer.empty()) {
++    if (this->charBuffer.empty()) {
+         // The directive's URL was missing, but comments can contain anything,
+         // so it isn't an error.
+         return true;
+     }
+ 
+     return copyCharBufferTo(anyCharsAccess().cx, destination);
+ }
+ 
+@@ -1268,17 +1268,17 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+ {
+     // We didn't get a token, so don't set |flags.isDirtyLine|.
+     anyCharsAccess().flags.hadError = true;
+ 
+     // Poisoning sourceUnits on error establishes an invariant: once an
+     // erroneous token has been seen, sourceUnits will not be consulted again.
+     // This is true because the parser will deal with the illegal token by
+     // aborting parsing immediately.
+-    sourceUnits.poisonInDebug();
++    this->sourceUnits.poisonInDebug();
+ 
+     return false;
+ };
+ 
+ MOZ_MUST_USE bool
+ TokenStreamCharsShared::appendCodePointToCharBuffer(uint32_t codePoint)
+ {
+     char16_t units[2];
+@@ -1296,34 +1296,34 @@ TokenStreamCharsShared::appendCodePointT
+ 
+     return charBuffer.append(units[1]);
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::putIdentInCharBuffer(const CharT* identStart)
+ {
+-    const CharT* const originalAddress = sourceUnits.addressOfNextCodeUnit();
+-    sourceUnits.setAddressOfNextCodeUnit(identStart);
++    const CharT* const originalAddress = this->sourceUnits.addressOfNextCodeUnit();
++    this->sourceUnits.setAddressOfNextCodeUnit(identStart);
+ 
+     auto restoreNextRawCharAddress =
+         MakeScopeExit([this, originalAddress]() {
+             this->sourceUnits.setAddressOfNextCodeUnit(originalAddress);
+         });
+ 
+-    charBuffer.clear();
++    this->charBuffer.clear();
+     do {
+         int32_t unit = getCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         uint32_t codePoint;
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (unicode::IsIdentifierPart(char16_t(unit))) {
+-                if (!charBuffer.append(unit))
++                if (!this->charBuffer.append(unit))
+                     return false;
+ 
+                 continue;
+             }
+ 
+             if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint))
+                 break;
+         } else {
+@@ -1402,17 +1402,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         // tokenbuf before atomizing.
+         if (!putIdentInCharBuffer(identStart))
+             return false;
+ 
+         atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
+     } else {
+         // Escape-free identifiers can be created directly from sourceUnits.
+         const CharT* chars = identStart;
+-        size_t length = sourceUnits.addressOfNextCodeUnit() - identStart;
++        size_t length = this->sourceUnits.addressOfNextCodeUnit() - identStart;
+ 
+         // Represent reserved words lacking escapes as reserved word tokens.
+         if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
+             noteBadToken.release();
+             newSimpleToken(rw->tokentype, start, modifier, out);
+             return true;
+         }
+ 
+@@ -1541,18 +1541,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     double dval;
+     DecimalPoint decimalPoint = NoDecimal;
+     if (unit != '.' && unit != 'e' && unit != 'E') {
+         // NOTE: |unit| may be EOF here.
+         ungetCodeUnit(unit);
+ 
+         // Most numbers are pure decimal integers without fractional component
+         // or exponential notation.  Handle that with optimized code.
+-        if (!GetDecimalInteger(anyCharsAccess().cx, numStart, sourceUnits.addressOfNextCodeUnit(),
+-                               &dval))
++        if (!GetDecimalInteger(anyCharsAccess().cx, numStart,
++                               this->sourceUnits.addressOfNextCodeUnit(), &dval))
+         {
+             return false;
+         }
+     } else {
+         // Consume any decimal dot and fractional component.
+         if (unit == '.') {
+             decimalPoint = HasDecimal;
+             do {
+@@ -1577,18 +1577,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             do {
+                 unit = getCodeUnit();
+             } while (IsAsciiDigit(unit));
+         }
+ 
+         ungetCodeUnit(unit);
+ 
+         const CharT* dummy;
+-        if (!js_strtod(anyCharsAccess().cx, numStart, sourceUnits.addressOfNextCodeUnit(), &dummy,
+-                       &dval))
++        if (!js_strtod(anyCharsAccess().cx, numStart, this->sourceUnits.addressOfNextCodeUnit(),
++                       &dummy, &dval))
+         {
+            return false;
+         }
+     }
+ 
+     // Number followed by IdentifierStart is an error.  (This is the only place
+     // in ECMAScript where token boundary is inadequate to properly separate
+     // two tokens, necessitating this unaesthetic lookahead.)
+@@ -1616,18 +1616,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     newNumberToken(dval, decimalPoint, start, modifier, out);
+     return true;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
+ {
+-    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '/');
+-    charBuffer.clear();
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '/');
++    this->charBuffer.clear();
+ 
+     auto ProcessNonAsciiCodePoint = [this](int32_t lead) {
+         MOZ_ASSERT(lead != EOF);
+ 
+         int32_t codePoint;
+         if (!this->getNonAsciiCodePoint(lead, &codePoint))
+             return false;
+ 
+@@ -1650,17 +1650,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         int32_t unit = getCodeUnit();
+         if (unit == EOF) {
+             ReportUnterminatedRegExp(unit);
+             return badToken();
+         }
+ 
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (unit == '\\')  {
+-                if (!charBuffer.append(unit))
++                if (!this->charBuffer.append(unit))
+                     return badToken();
+ 
+                 unit = getCodeUnit();
+                 if (unit == EOF) {
+                     ReportUnterminatedRegExp(unit);
+                     return badToken();
+                 }
+ 
+@@ -1681,17 +1681,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 break;
+             }
+ 
+             if (unit == '\r' || unit == '\n') {
+                 ReportUnterminatedRegExp(unit);
+                 return badToken();
+             }
+ 
+-            if (!charBuffer.append(unit))
++            if (!this->charBuffer.append(unit))
+                 return badToken();
+         } else {
+             if (!ProcessNonAsciiCodePoint(unit))
+                 return badToken();
+         }
+     } while (true);
+ 
+     int32_t unit;
+@@ -1745,32 +1745,32 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     if (MOZ_UNLIKELY(modifier == TemplateTail))
+         return getStringOrTemplateToken('`', modifier, ttp);
+ 
+     // This loop runs more than once only when whitespace or comments are
+     // encountered.
+     do {
+         int32_t unit = getCodeUnit();
+         if (MOZ_UNLIKELY(unit == EOF)) {
+-            MOZ_ASSERT(sourceUnits.atEnd());
++            MOZ_ASSERT(this->sourceUnits.atEnd());
+             anyCharsAccess().flags.isEOF = true;
+-            TokenStart start(sourceUnits, 0);
++            TokenStart start(this->sourceUnits, 0);
+             newSimpleToken(TokenKind::Eof, start, modifier, ttp);
+             return true;
+         }
+ 
+         if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+             // Non-ASCII code points can only be identifiers or whitespace.
+             // It would be nice to compute these *after* discarding whitespace,
+             // but IN A WORLD where |unicode::IsSpaceOrBOM2| requires consuming
+             // a variable number of code points, it's easier to assume it's an
+             // identifier and maybe do a little wasted work, than to unget and
+             // compute and reget if whitespace.
+-            TokenStart start(sourceUnits, -1);
+-            const CharT* identStart = sourceUnits.addressOfNextCodeUnit() - 1;
++            TokenStart start(this->sourceUnits, -1);
++            const CharT* identStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+             int32_t codePoint;
+             if (!getNonAsciiCodePoint(unit, &codePoint))
+                 return badToken();
+ 
+             if (unicode::IsSpaceOrBOM2(codePoint)) {
+                 if (codePoint == '\n')
+                     anyCharsAccess().updateFlagsForEOL();
+@@ -1814,120 +1814,120 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         // frequencies used to break close categories (e.g. |Dec| and
+         // |String|).  |Other| is biggish, but no other token kind is common
+         // enough for it to be worth adding extra values to FirstCharKind.
+         FirstCharKind c1kind = FirstCharKind(firstCharKinds[unit]);
+ 
+         // Look for an unambiguous single-char token.
+         //
+         if (c1kind <= OneChar_Max) {
+-            TokenStart start(sourceUnits, -1);
++            TokenStart start(this->sourceUnits, -1);
+             newSimpleToken(TokenKind(c1kind), start, modifier, ttp);
+             return true;
+         }
+ 
+         // Skip over non-EOL whitespace chars.
+         //
+         if (c1kind == Space)
+             continue;
+ 
+         // Look for an identifier.
+         //
+         if (c1kind == Ident) {
+-            TokenStart start(sourceUnits, -1);
+-            return identifierName(start, sourceUnits.addressOfNextCodeUnit() - 1,
++            TokenStart start(this->sourceUnits, -1);
++            return identifierName(start, this->sourceUnits.addressOfNextCodeUnit() - 1,
+                                   IdentifierEscapes::None, modifier, ttp);
+         }
+ 
+         // Look for a decimal number.
+         //
+         if (c1kind == Dec) {
+-            TokenStart start(sourceUnits, -1);
+-            const CharT* numStart = sourceUnits.addressOfNextCodeUnit() - 1;
++            TokenStart start(this->sourceUnits, -1);
++            const CharT* numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+             return decimalNumber(unit, start, numStart, modifier, ttp);
+         }
+ 
+         // Look for a string or a template string.
+         //
+         if (c1kind == String)
+             return getStringOrTemplateToken(static_cast<char>(unit), modifier, ttp);
+ 
+         // Skip over EOL chars, updating line state along the way.
+         //
+         if (c1kind == EOL) {
+             // If it's a \r\n sequence, consume it as a single EOL.
+-            if (unit == '\r' && !sourceUnits.atEnd())
+-                sourceUnits.matchCodeUnit('\n');
++            if (unit == '\r' && !this->sourceUnits.atEnd())
++                this->sourceUnits.matchCodeUnit('\n');
+ 
+             if (!updateLineInfoForEOL())
+                 return badToken();
+ 
+             anyCharsAccess().updateFlagsForEOL();
+             continue;
+         }
+ 
+         // From a '0', look for a hexadecimal, binary, octal, or "noctal" (a
+         // number starting with '0' that contains '8' or '9' and is treated as
+         // decimal) number.
+         //
+         if (c1kind == ZeroDigit) {
+-            TokenStart start(sourceUnits, -1);
++            TokenStart start(this->sourceUnits, -1);
+ 
+             int radix;
+             const CharT* numStart;
+             unit = getCodeUnit();
+             if (unit == 'x' || unit == 'X') {
+                 radix = 16;
+                 unit = getCodeUnit();
+                 if (!JS7_ISHEX(unit)) {
+                     // NOTE: |unit| may be EOF here.
+                     ungetCodeUnit(unit);
+                     error(JSMSG_MISSING_HEXDIGITS);
+                     return badToken();
+                 }
+ 
+                 // one past the '0x'
+-                numStart = sourceUnits.addressOfNextCodeUnit() - 1;
++                numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+                 while (JS7_ISHEX(unit))
+                     unit = getCodeUnit();
+             } else if (unit == 'b' || unit == 'B') {
+                 radix = 2;
+                 unit = getCodeUnit();
+                 if (unit != '0' && unit != '1') {
+                     // NOTE: |unit| may be EOF here.
+                     ungetCodeUnit(unit);
+                     error(JSMSG_MISSING_BINARY_DIGITS);
+                     return badToken();
+                 }
+ 
+                 // one past the '0b'
+-                numStart = sourceUnits.addressOfNextCodeUnit() - 1;
++                numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+                 while (unit == '0' || unit == '1')
+                     unit = getCodeUnit();
+             } else if (unit == 'o' || unit == 'O') {
+                 radix = 8;
+                 unit = getCodeUnit();
+                 if (!JS7_ISOCT(unit)) {
+                     // NOTE: |unit| may be EOF here.
+                     ungetCodeUnit(unit);
+                     error(JSMSG_MISSING_OCTAL_DIGITS);
+                     return badToken();
+                 }
+ 
+                 // one past the '0o'
+-                numStart = sourceUnits.addressOfNextCodeUnit() - 1;
++                numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+                 while (JS7_ISOCT(unit))
+                     unit = getCodeUnit();
+             } else if (IsAsciiDigit(unit)) {
+                 radix = 8;
+                 // one past the '0'
+-                numStart = sourceUnits.addressOfNextCodeUnit() - 1;
++                numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+                 do {
+                     // Octal integer literals are not permitted in strict mode
+                     // code.
+                     if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
+                         return badToken();
+ 
+                     // Outside strict mode, we permit 08 and 09 as decimal
+@@ -1941,17 +1941,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                         // Use the decimal scanner for the rest of the number.
+                         return decimalNumber(unit, start, numStart, modifier, ttp);
+                     }
+ 
+                     unit = getCodeUnit();
+                 } while (IsAsciiDigit(unit));
+             } else {
+                 // '0' not followed by [XxBbOo0-9];  scan as a decimal number.
+-                numStart = sourceUnits.addressOfNextCodeUnit() - 1;
++                numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+                 // NOTE: |unit| may be EOF here.  (This is permitted by case #3
+                 //       in TokenStream.h docs for this function.)
+                 return decimalNumber(unit, start, numStart, modifier, ttp);
+             }
+ 
+             // Check for an identifier-start code point immediately after the
+             // number.  This must be an error, and somewhat surprisingly, if
+@@ -1979,43 +1979,43 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     error(JSMSG_IDSTART_AFTER_NUMBER);
+                     return badToken();
+                 }
+             }
+ 
+             double dval;
+             const char16_t* dummy;
+             if (!GetPrefixInteger(anyCharsAccess().cx, numStart,
+-                                  sourceUnits.addressOfNextCodeUnit(), radix, &dummy, &dval))
++                                  this->sourceUnits.addressOfNextCodeUnit(), radix, &dummy, &dval))
+             {
+                 return badToken();
+             }
+ 
+             newNumberToken(dval, NoDecimal, start, modifier, ttp);
+             return true;
+         }
+ 
+         MOZ_ASSERT(c1kind == Other);
+ 
+         // This handles everything else.  Simple tokens distinguished solely by
+         // TokenKind should set |simpleKind| and break, to share simple-token
+         // creation code for all such tokens.  All other tokens must be handled
+         // by returning (or by continuing from the loop enclosing this).
+         //
+-        TokenStart start(sourceUnits, -1);
++        TokenStart start(this->sourceUnits, -1);
+         TokenKind simpleKind;
+ #ifdef DEBUG
+         simpleKind = TokenKind::Limit; // sentinel value for code after switch
+ #endif
+         switch (static_cast<CharT>(unit)) {
+           case '.':
+             unit = getCodeUnit();
+             if (IsAsciiDigit(unit)) {
+-                return decimalNumber('.', start, sourceUnits.addressOfNextCodeUnit() - 2, modifier,
+-                                     ttp);
++                return decimalNumber('.', start, this->sourceUnits.addressOfNextCodeUnit() - 2,
++                                     modifier, ttp);
+             }
+ 
+             if (unit == '.') {
+                 if (matchCodeUnit('.')) {
+                     simpleKind = TokenKind::TripleDot;
+                     break;
+                 }
+             }
+@@ -2042,17 +2042,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             else
+                 simpleKind = matchCodeUnit('=') ? TokenKind::AddAssign : TokenKind::Add;
+             break;
+ 
+           case '\\': {
+             uint32_t codePoint;
+             if (uint32_t escapeLength = matchUnicodeEscapeIdStart(&codePoint)) {
+                 return identifierName(start,
+-                                      sourceUnits.addressOfNextCodeUnit() - escapeLength - 1,
++                                      this->sourceUnits.addressOfNextCodeUnit() - escapeLength - 1,
+                                       IdentifierEscapes::SawUnicodeEscape, modifier, ttp);
+             }
+ 
+             // We could point "into" a mistyped escape, e.g. for "\u{41H}" we
+             // could point at the 'H'.  But we don't do that now, so the code
+             // unit after the '\' isn't necessarily bad, so just point at the
+             // start of the actually-invalid escape.
+             ungetCodeUnit('\\');
+@@ -2232,18 +2232,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                                                                      TokenKind* out)
+ {
+     MOZ_ASSERT(untilChar == '\'' || untilChar == '"' || untilChar == '`',
+                "unexpected string/template literal delimiter");
+ 
+     bool parsingTemplate = (untilChar == '`');
+     bool templateHead = false;
+ 
+-    TokenStart start(sourceUnits, -1);
+-    charBuffer.clear();
++    TokenStart start(this->sourceUnits, -1);
++    this->charBuffer.clear();
+ 
+     // Run the bad-token code for every path out of this function except the
+     // one success-case.
+     auto noteBadToken = MakeScopeExit([this]() {
+         this->badToken();
+     });
+ 
+     auto ReportPrematureEndOfLiteral = [this, untilChar](unsigned errnum) {
+@@ -2319,33 +2319,33 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 if (!getNonAsciiCodePoint(unit, &codePoint))
+                     return false;
+ 
+                 // If we consumed U+2028 LINE SEPARATOR or U+2029 PARAGRAPH
+                 // SEPARATOR, they'll be normalized to '\n'.  '\' followed by
+                 // LineContinuation represents no code points, so don't append
+                 // in this case.
+                 if (codePoint != '\n') {
+-                    if (!charBuffer.append(unit))
++                    if (!this->charBuffer.append(unit))
+                         return false;
+                 }
+ 
+                 continue;
+             }
+ 
+             switch (static_cast<CharT>(unit)) {
+               case 'b': unit = '\b'; break;
+               case 'f': unit = '\f'; break;
+               case 'n': unit = '\n'; break;
+               case 'r': unit = '\r'; break;
+               case 't': unit = '\t'; break;
+               case 'v': unit = '\v'; break;
+ 
+               case '\r':
+-                sourceUnits.matchCodeUnit('\n');
++                this->sourceUnits.matchCodeUnit('\n');
+                 MOZ_FALLTHROUGH;
+               case '\n': {
+                 // LineContinuation represents no code points.  We're manually
+                 // consuming a LineTerminatorSequence, so we must manually
+                 // update line/column info.
+                 if (!updateLineInfoForEOL())
+                     return false;
+ 
+@@ -2357,17 +2357,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 int32_t c2 = getCodeUnit();
+                 if (c2 == EOF) {
+                     ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
+                     return false;
+                 }
+ 
+                 // First handle a delimited Unicode escape, e.g. \u{1F4A9}.
+                 if (c2 == '{') {
+-                    uint32_t start = sourceUnits.offset() - 3;
++                    uint32_t start = this->sourceUnits.offset() - 3;
+                     uint32_t code = 0;
+                     bool first = true;
+                     bool valid = true;
+                     do {
+                         int32_t u3 = getCodeUnit();
+                         if (u3 == EOF) {
+                             if (parsingTemplate) {
+                                 TokenStreamAnyChars& anyChars = anyCharsAccess();
+@@ -2439,40 +2439,40 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     continue;
+                 } // end of delimited Unicode escape handling
+ 
+                 // Otherwise it must be a fixed-length \uXXXX Unicode escape.
+                 // If it isn't, this is usually an error -- but if this is a
+                 // template literal, we must defer error reporting because
+                 // malformed escapes are okay in *tagged* template literals.
+                 char16_t v;
+-                if (JS7_ISHEX(c2) && sourceUnits.matchHexDigits(3, &v)) {
++                if (JS7_ISHEX(c2) && this->sourceUnits.matchHexDigits(3, &v)) {
+                     unit = (JS7_UNHEX(c2) << 12) | v;
+                 } else {
+                     // Beware: |c2| may not be an ASCII code point here!
+                     ungetCodeUnit(c2);
+-                    uint32_t start = sourceUnits.offset() - 2;
++                    uint32_t start = this->sourceUnits.offset() - 2;
+                     if (parsingTemplate) {
+                         TokenStreamAnyChars& anyChars = anyCharsAccess();
+                         anyChars.setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
+                         continue;
+                     }
+                     reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
+                     return false;
+                 }
+                 break;
+               } // case 'u'
+ 
+               // Hexadecimal character specification.
+               case 'x': {
+                 char16_t v;
+-                if (sourceUnits.matchHexDigits(2, &v)) {
++                if (this->sourceUnits.matchHexDigits(2, &v)) {
+                     unit = v;
+                 } else {
+-                    uint32_t start = sourceUnits.offset() - 2;
++                    uint32_t start = this->sourceUnits.offset() - 2;
+                     if (parsingTemplate) {
+                         TokenStreamAnyChars& anyChars = anyCharsAccess();
+                         anyChars.setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal);
+                         continue;
+                     }
+                     reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal);
+                     return false;
+                 }
+@@ -2491,17 +2491,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
+                     return false;
+                 }
+ 
+                 // Strict mode code allows only \0, then a non-digit.
+                 if (val != 0 || IsAsciiDigit(unit)) {
+                     TokenStreamAnyChars& anyChars = anyCharsAccess();
+                     if (parsingTemplate) {
+-                        anyChars.setInvalidTemplateEscape(sourceUnits.offset() - 2,
++                        anyChars.setInvalidTemplateEscape(this->sourceUnits.offset() - 2,
+                                                           InvalidEscapeType::Octal);
+                         continue;
+                     }
+                     if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
+                         return false;
+                     anyChars.flags.sawOctalEscape = true;
+                 }
+ 
+@@ -2525,17 +2525,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     }
+                 }
+ 
+                 unit = char16_t(val);
+                 break;
+               } // default
+             }
+ 
+-            if (!charBuffer.append(unit))
++            if (!this->charBuffer.append(unit))
+                 return false;
+ 
+             continue;
+         } // (unit == '\\')
+ 
+         if (unit == '\r' || unit == '\n') {
+             if (!parsingTemplate) {
+                 // String literals don't allow ASCII line breaks.
+@@ -2543,30 +2543,30 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 ReportPrematureEndOfLiteral(JSMSG_EOL_BEFORE_END_OF_STRING);
+                 return false;
+             }
+ 
+             if (unit == '\r') {
+                 unit = '\n';
+ 
+                 // If it's a \r\n sequence: treat as a single EOL, skip over the \n.
+-                if (!sourceUnits.atEnd())
+-                    sourceUnits.matchCodeUnit('\n');
++                if (!this->sourceUnits.atEnd())
++                    this->sourceUnits.matchCodeUnit('\n');
+             }
+ 
+             if (!updateLineInfoForEOL())
+                 return false;
+ 
+             anyCharsAccess().updateFlagsForEOL();
+         } else if (parsingTemplate && unit == '$' && matchCodeUnit('{')) {
+             templateHead = true;
+             break;
+         }
+ 
+-        if (!charBuffer.append(unit))
++        if (!this->charBuffer.append(unit))
+             return false;
+     }
+ 
+     JSAtom* atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
+     if (!atom)
+         return false;
+ 
+     noteBadToken.release();
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1229,39 +1229,40 @@ TokenStreamCharsBase<char16_t>::atomizeS
+ }
+ 
+ template<typename CharT>
+ inline bool
+ TokenStreamCharsBase<CharT>::matchCodeUnit(int32_t expect)
+ {
+     MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
+     MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
+-    return MOZ_LIKELY(!sourceUnits.atEnd()) && sourceUnits.matchCodeUnit(toCharT(expect));
++    return MOZ_LIKELY(!this->sourceUnits.atEnd()) &&
++           this->sourceUnits.matchCodeUnit(toCharT(expect));
+ }
+ 
+ template<>
+ MOZ_MUST_USE inline bool
+ TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
+                                                                          const char16_t* end)
+ {
+-    MOZ_ASSERT(charBuffer.length() == 0);
++    MOZ_ASSERT(this->charBuffer.length() == 0);
+ 
+     while (cur < end) {
+         // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
+         // interpreted literally inside template literal contents; only
+         // literal CRLF sequences are normalized to '\n'.  See
+         // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
+         char16_t ch = *cur++;
+         if (ch == '\r') {
+             ch = '\n';
+             if (cur < end && *cur == '\n')
+                 cur++;
+         }
+ 
+-        if (!charBuffer.append(ch))
++        if (!this->charBuffer.append(ch))
+             return false;
+     }
+ 
+     return true;
+ }
+ 
+ /** A small class encapsulating computation of the start-offset of a Token. */
+ class TokenStart
+@@ -1313,18 +1314,16 @@ class GeneralTokenStreamChars
+     }
+ 
+     uint32_t matchUnicodeEscape(uint32_t* codePoint);
+     uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+ 
+   protected:
+     using typename CharsBase::SourceUnits;
+ 
+-    using CharsBase::sourceUnits;
+-
+   protected:
+     using CharsBase::CharsBase;
+ 
+     TokenStreamAnyChars& anyCharsAccess() {
+         return AnyCharsAccess::anyChars(this);
+     }
+ 
+     const TokenStreamAnyChars& anyCharsAccess() const {
+@@ -1385,18 +1384,18 @@ class GeneralTokenStreamChars
+      * counters or consuming LineTerminatorSequences.
+      *
+      * Because of these limitations, only use this if (a) the resulting code
+      * unit is guaranteed to be ungotten (by ungetCodeUnit()) if it's an EOL,
+      * and (b) the line-related state (lineno, linebase) is not used before
+      * it's ungotten.
+      */
+     int32_t getCodeUnit() {
+-        if (MOZ_LIKELY(!sourceUnits.atEnd()))
+-            return sourceUnits.getCodeUnit();
++        if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
++            return this->sourceUnits.getCodeUnit();
+ 
+         anyCharsAccess().flags.isEOF = true;
+         return EOF;
+     }
+ 
+     void ungetCodeUnit(int32_t c) {
+         MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
+ 
+@@ -1405,17 +1404,17 @@ class GeneralTokenStreamChars
+ 
+     /**
+      * Consume code units til EOL/EOF following the start of a single-line
+      * comment, without consuming the EOL/EOF.
+      */
+     void consumeRestOfSingleLineComment();
+ 
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+-        return anyCharsAccess().internalUpdateLineInfoForEOL(sourceUnits.offset());
++        return anyCharsAccess().internalUpdateLineInfoForEOL(this->sourceUnits.offset());
+     }
+ 
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ };
+ 
+ template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+ 
+@@ -1431,17 +1430,17 @@ class TokenStreamChars<char16_t, AnyChar
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+-    using CharsBase::sourceUnits;
++    // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+ 
+   protected:
+     using GeneralCharsBase::GeneralCharsBase;
+ 
+@@ -1459,22 +1458,24 @@ class TokenStreamChars<char16_t, AnyChar
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+      * This may change the current |sourceUnits| offset.
+      */
+     MOZ_MUST_USE bool getFullAsciiCodePoint(int32_t lead, int32_t* codePoint) {
+         MOZ_ASSERT(isAsciiCodePoint(lead),
+                    "non-ASCII code units must be handled separately");
+-        MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
++        // NOTE: |this->|-qualify to avoid a gcc bug: see bug 1472569.
++        MOZ_ASSERT(lead == this->sourceUnits.previousCodeUnit(),
+                    "getFullAsciiCodePoint called incorrectly");
+ 
+         if (MOZ_UNLIKELY(lead == '\r')) {
+-            if (MOZ_LIKELY(!sourceUnits.atEnd()))
+-                sourceUnits.matchCodeUnit('\n');
++            // NOTE: |this->|-qualify to avoid a gcc bug: see bug 1472569.
++            if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
++                this->sourceUnits.matchCodeUnit('\n');
+         } else if (MOZ_LIKELY(lead != '\n')) {
+             *codePoint = lead;
+             return true;
+         }
+ 
+         *codePoint = '\n';
+         bool ok = updateLineInfoForEOL();
+         if (!ok) {
+@@ -1606,17 +1607,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+ 
+   private:
+     using typename CharsBase::SourceUnits;
+ 
+   private:
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+     using CharsBase::atomizeSourceChars;
+     using GeneralCharsBase::badToken;
+-    using TokenStreamCharsShared::charBuffer;
++    // Deliberately don't |using| |charBuffer| because of bug 1472569.  :-(
+     using CharsBase::consumeKnownCodeUnit;
+     using GeneralCharsBase::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedCharsBase::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedCharsBase::getFullAsciiCodePoint;
+@@ -1626,17 +1627,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+     using CharsBase::peekCodeUnit;
+-    using CharsBase::sourceUnits;
++    // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using SpecializedCharsBase::ungetCodePointIgnoreEOL;
+     using GeneralCharsBase::ungetCodeUnit;
+     using SpecializedCharsBase::ungetNonAsciiNormalizedCodePoint;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     template<typename CharU> friend class TokenStreamPosition;
+ 
+   public:
+@@ -1722,24 +1723,24 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
+                                          unsigned errorNumber, va_list* args);
+ 
+     JSAtom* getRawTemplateStringAtom() {
+         TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+         MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
+                    anyChars.currentToken().type == TokenKind::NoSubsTemplate);
+-        const CharT* cur = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
++        const CharT* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
+         const CharT* end;
+         if (anyChars.currentToken().type == TokenKind::TemplateHead) {
+             // Of the form    |`...${|   or   |}...${|
+-            end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
++            end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
+         } else {
+             // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
+-            end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
++            end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
+         }
+ 
+         if (!fillCharBufferWithTemplateStringContents(cur, end))
+             return nullptr;
+ 
+         return drainCharBufferIntoAtom(anyChars.cx);
+     }
+ 
+@@ -1961,21 +1962,21 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     }
+ 
+     MOZ_MUST_USE bool advance(size_t position);
+ 
+     void seek(const Position& pos);
+     MOZ_MUST_USE bool seek(const Position& pos, const TokenStreamAnyChars& other);
+ 
+     const CharT* codeUnitPtrAt(size_t offset) const {
+-        return sourceUnits.codeUnitPtrAt(offset);
++        return this->sourceUnits.codeUnitPtrAt(offset);
+     }
+ 
+     const CharT* rawLimit() const {
+-        return sourceUnits.limit();
++        return this->sourceUnits.limit();
+     }
+ 
+     MOZ_MUST_USE bool identifierName(TokenStart start, const CharT* identStart,
+                                      IdentifierEscapes escaping, Modifier modifier,
+                                      TokenKind* out);
+ 
+     MOZ_MUST_USE bool getTokenInternal(TokenKind* const ttp, const Modifier modifier);
+ 
+

+ 70 - 0
frg/work-js/mozilla-release/patches/1475559-1-63a1.patch

@@ -0,0 +1,70 @@
+# HG changeset patch
+# User Jan de Mooij <jdemooij@mozilla.com>
+# Date 1532176300 -7200
+#      Sat Jul 21 14:31:40 2018 +0200
+# Node ID c9c0fea0993bb64a234ed23389450a38e13ea822
+# Parent  18a20a23b5e7c0f631f915d2a6becd55908bc00c
+Bug 1475559 part 1 - Remove unused GetFirstSubsumedSavedFrame API. r=bz
+
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -2958,27 +2958,16 @@ typedef long
+  * only once per process.
+  */
+ extern JS_FRIEND_API(void)
+ SetJitExceptionHandler(JitExceptionHandler handler);
+ #endif
+ 
+ /**
+  * Get the first SavedFrame object in this SavedFrame stack whose principals are
+- * subsumed by the cx's principals. If there is no such frame, return nullptr.
+- *
+- * Do NOT pass a non-SavedFrame object here.
+- *
+- * The savedFrame and cx do not need to be in the same compartment.
+- */
+-extern JS_FRIEND_API(JSObject*)
+-GetFirstSubsumedSavedFrame(JSContext* cx, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted);
+-
+-/**
+- * Get the first SavedFrame object in this SavedFrame stack whose principals are
+  * subsumed by the given |principals|. If there is no such frame, return nullptr.
+  *
+  * Do NOT pass a non-SavedFrame object here.
+  */
+ extern JS_FRIEND_API(JSObject*)
+ GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted);
+ 
+ extern JS_FRIEND_API(bool)
+diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
+--- a/js/src/vm/SavedStacks.cpp
++++ b/js/src/vm/SavedStacks.cpp
+@@ -666,27 +666,16 @@ GetFirstMatchedFrame(JSContext* cx, Matc
+ static SavedFrame*
+ GetFirstSubsumedFrame(JSContext* cx, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
+                       bool& skippedAsync)
+ {
+     return GetFirstMatchedFrame(cx, SavedFrameSubsumedByCaller, frame, selfHosted, skippedAsync);
+ }
+ 
+ JS_FRIEND_API(JSObject*)
+-GetFirstSubsumedSavedFrame(JSContext* cx, HandleObject savedFrame,
+-                           JS::SavedFrameSelfHosted selfHosted)
+-{
+-    if (!savedFrame)
+-        return nullptr;
+-    bool skippedAsync;
+-    RootedSavedFrame frame(cx, &savedFrame->as<SavedFrame>());
+-    return GetFirstSubsumedFrame(cx, frame, selfHosted, skippedAsync);
+-}
+-
+-JS_FRIEND_API(JSObject*)
+ GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals,
+                            HandleObject savedFrame,
+                            JS::SavedFrameSelfHosted selfHosted)
+ {
+     if (!savedFrame)
+         return nullptr;
+ 
+     auto subsumes = cx->runtime()->securityCallbacks->subsumes;

+ 104 - 0
frg/work-js/mozilla-release/patches/1476012-1-63a1.patch

@@ -0,0 +1,104 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829142 -3600
+#      Tue Jul 17 13:05:42 2018 +0100
+# Node ID 2513d9eaeed829ee70f6fc75de67fb58da241708
+# Parent  14374e92fb0ec4ae5fdbbdbda4889b3de6bf5fc5
+Bug 1476012 - Remove dependency of jit/IonAnalysis.h on jit/MIR.h r=nbp
+
+diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h
+--- a/js/src/jit/IonAnalysis.h
++++ b/js/src/jit/IonAnalysis.h
+@@ -5,23 +5,26 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef jit_IonAnalysis_h
+ #define jit_IonAnalysis_h
+ 
+ // This file declares various analysis passes that operate on MIR.
+ 
+ #include "jit/JitAllocPolicy.h"
+-#include "jit/MIR.h"
+ 
+ namespace js {
+ namespace jit {
+ 
++class MBasicBlock;
++class MCompare;
++class MDefinition;
+ class MIRGenerator;
+ class MIRGraph;
++class MTest;
+ 
+ MOZ_MUST_USE bool
+ PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph);
+ 
+ MOZ_MUST_USE bool
+ FoldTests(MIRGraph& graph);
+ 
+ MOZ_MUST_USE bool
+@@ -94,18 +97,16 @@ void
+ AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer = false, bool force = false);
+ 
+ MOZ_MUST_USE bool
+ EliminateRedundantChecks(MIRGraph& graph);
+ 
+ MOZ_MUST_USE bool
+ AddKeepAliveInstructions(MIRGraph& graph);
+ 
+-class MDefinition;
+-
+ // Simple linear sum of the form 'n' or 'x + n'.
+ struct SimpleLinearSum
+ {
+     MDefinition* term;
+     int32_t constant;
+ 
+     SimpleLinearSum(MDefinition* term, int32_t constant)
+         : term(term), constant(constant)
+diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h
+--- a/js/src/jit/IonTypes.h
++++ b/js/src/jit/IonTypes.h
+@@ -929,12 +929,17 @@ enum class RoundingMode {
+ // limit has a generous buffer before the real end of the native stack.
+ static const uint32_t MAX_UNCHECKED_LEAF_FRAME_SIZE = 64;
+ 
+ // Truncating conversion modifiers.
+ typedef uint32_t TruncFlags;
+ static const TruncFlags TRUNC_UNSIGNED   = TruncFlags(1) << 0;
+ static const TruncFlags TRUNC_SATURATING = TruncFlags(1) << 1;
+ 
++enum BranchDirection {
++    FALSE_BRANCH,
++    TRUE_BRANCH
++};
++
+ } // namespace jit
+ } // namespace js
+ 
+ #endif /* jit_IonTypes_h */
+diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
+--- a/js/src/jit/MIR.h
++++ b/js/src/jit/MIR.h
+@@ -3149,21 +3149,16 @@ class MGoto
+     MBasicBlock* target() {
+         return getSuccessor(0);
+     }
+     AliasSet getAliasSet() const override {
+         return AliasSet::None();
+     }
+ };
+ 
+-enum BranchDirection {
+-    FALSE_BRANCH,
+-    TRUE_BRANCH
+-};
+-
+ static inline BranchDirection
+ NegateBranchDirection(BranchDirection dir)
+ {
+     return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
+ }
+ 
+ // Tests if the input instruction evaluates to true or false, and jumps to the
+ // start of a corresponding basic block.

+ 177 - 0
frg/work-js/mozilla-release/patches/1476012-2-63a1.patch

@@ -0,0 +1,177 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829163 -3600
+#      Tue Jul 17 13:06:03 2018 +0100
+# Node ID 01ab0200841fb028d3579f19996e9f16081657d4
+# Parent  9cf3721112a5598a47fa3b06ed8cf3b7da74b817
+Bug 1476012 - Remove dependency of jit/BaselineJit.h on jit/MacroAssembler.h r=nbp
+
+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
+@@ -33,16 +33,17 @@
+ #include "frontend/TokenStream.h"
+ #include "irregexp/RegExpAST.h"
+ #include "irregexp/RegExpEngine.h"
+ #include "irregexp/RegExpParser.h"
+ #endif
+ #include "gc/Heap.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/InlinableNatives.h"
++#include "jit/JitRealm.h"
+ #include "js/Debug.h"
+ #include "js/HashTable.h"
+ #include "js/StructuredClone.h"
+ #include "js/UbiNode.h"
+ #include "js/UbiNodeBreadthFirst.h"
+ #include "js/UbiNodeShortestPaths.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
+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
+@@ -14,16 +14,17 @@
+ 
+ #include "jsutil.h"
+ 
+ #include "gc/FreeOp.h"
+ #include "gc/GCInternals.h"
+ #include "gc/Memory.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/JitFrames.h"
++#include "jit/JitRealm.h"
+ #include "vm/ArrayObject.h"
+ #include "vm/Debugger.h"
+ #if defined(DEBUG)
+ #include "vm/EnvironmentObject.h"
+ #endif
+ #include "vm/JSCompartment.h"
+ #include "vm/JSONPrinter.h"
+ #include "vm/Time.h"
+diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h
+--- a/js/src/jit/BaselineJIT.h
++++ b/js/src/jit/BaselineJIT.h
+@@ -7,17 +7,17 @@
+ #ifndef jit_BaselineJIT_h
+ #define jit_BaselineJIT_h
+ 
+ #include "mozilla/MemoryReporting.h"
+ 
+ #include "ds/LifoAlloc.h"
+ #include "jit/Bailouts.h"
+ #include "jit/IonCode.h"
+-#include "jit/MacroAssembler.h"
++#include "vm/EnvironmentObject.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ #include "vm/TraceLogging.h"
+ 
+ namespace js {
+ namespace jit {
+ 
+ class StackValue;
+diff --git a/js/src/jit/Jit.cpp b/js/src/jit/Jit.cpp
+--- a/js/src/jit/Jit.cpp
++++ b/js/src/jit/Jit.cpp
+@@ -4,16 +4,17 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "jit/Jit.h"
+ 
+ #include "jit/BaselineJIT.h"
+ #include "jit/Ion.h"
+ #include "jit/JitCommon.h"
++#include "jit/JitRealm.h"
+ #include "vm/Interpreter.h"
+ 
+ #include "vm/Stack-inl.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ 
+ static EnterJitStatus
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -52,16 +52,17 @@
+ #include "frontend/FullParseHandler.h"  // for JS_BufferIsCompileableUnit
+ #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
+ #include "gc/FreeOp.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "gc/WeakMap.h"
+ #include "jit/JitCommon.h"
++#include "jit/JitSpewer.h"
+ #include "js/CharacterEncoding.h"
+ #include "js/Conversions.h"
+ #include "js/Date.h"
+ #include "js/Initialization.h"
+ #include "js/Proxy.h"
+ #include "js/SliceBudget.h"
+ #include "js/StructuredClone.h"
+ #include "js/Utility.h"
+diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
+--- a/js/src/vm/JSScript.cpp
++++ b/js/src/vm/JSScript.cpp
+@@ -30,16 +30,17 @@
+ 
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/BytecodeEmitter.h"
+ #include "frontend/SharedContext.h"
+ #include "gc/FreeOp.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/Ion.h"
+ #include "jit/IonCode.h"
++#include "jit/JitRealm.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/Printf.h"
+ #include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ #include "js/Wrapper.h"
+ #include "util/StringBuffer.h"
+ #include "util/Text.h"
+ #include "vm/ArgumentsObject.h"
+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
+@@ -16,16 +16,17 @@
+ 
+ #include "builtin/RegExp.h"
+ #include "frontend/TokenStream.h"
+ #include "gc/HashUtil.h"
+ #ifdef DEBUG
+ #include "irregexp/RegExpBytecode.h"
+ #endif
+ #include "irregexp/RegExpParser.h"
++#include "jit/VMFunctions.h"
+ #include "util/StringBuffer.h"
+ #include "vm/MatchPairs.h"
+ #include "vm/RegExpStatics.h"
+ #include "vm/StringType.h"
+ #include "vm/TraceLogging.h"
+ #ifdef DEBUG
+ #include "util/Unicode.h"
+ #endif
+diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp
+--- a/js/src/wasm/WasmInstance.cpp
++++ b/js/src/wasm/WasmInstance.cpp
+@@ -17,16 +17,17 @@
+  */
+ 
+ #include "wasm/WasmInstance.h"
+ 
+ #include "jit/AtomicOperations.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/JitCommon.h"
++#include "jit/JitRealm.h"
+ #include "wasm/WasmBuiltins.h"
+ #include "wasm/WasmModule.h"
+ 
+ #include "vm/ArrayBufferObject-inl.h"
+ #include "vm/JSObject-inl.h"
+ 
+ using namespace js;
+ using namespace js::jit;

+ 2086 - 0
frg/work-js/mozilla-release/patches/1476012-3-63a1.patch

@@ -0,0 +1,2086 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829193 -3600
+#      Tue Jul 17 13:06:33 2018 +0100
+# Node ID bedc90c72ee31e496b2aa178b159026941b08613
+# Parent  82d13b582c5653df56c4012e0f514e65015ebc3a
+Bug 1476012 - Split SIMD constant definitions out into builtin/SIMDConstants.h r=bbouvier
+
+diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h
+--- a/js/src/builtin/SIMD.h
++++ b/js/src/builtin/SIMD.h
+@@ -5,953 +5,30 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef builtin_SIMD_h
+ #define builtin_SIMD_h
+ 
+ #include "jsapi.h"
+ #include "NamespaceImports.h"
+ 
+-#include "builtin/TypedObjectConstants.h"
++#include "builtin/SIMDConstants.h"
+ #include "jit/IonTypes.h"
+ #include "js/Conversions.h"
+ 
+ /*
+  * JS SIMD functions.
+  * Spec matching polyfill:
+  * https://github.com/tc39/ecmascript_simd/blob/master/src/ecmascript_simd.js
+  */
+ 
+-// Bool8x16.
+-#define BOOL8X16_UNARY_FUNCTION_LIST(V)                                               \
+-  V(not, (UnaryFunc<Bool8x16, LogicalNot, Bool8x16>), 1)                              \
+-  V(check, (UnaryFunc<Bool8x16, Identity, Bool8x16>), 1)                              \
+-  V(splat, (FuncSplat<Bool8x16>), 1)                                                  \
+-  V(allTrue, (AllTrue<Bool8x16>), 1)                                                  \
+-  V(anyTrue, (AnyTrue<Bool8x16>), 1)
+-
+-#define BOOL8X16_BINARY_FUNCTION_LIST(V)                                              \
+-  V(extractLane, (ExtractLane<Bool8x16>), 2)                                          \
+-  V(and, (BinaryFunc<Bool8x16, And, Bool8x16>), 2)                                    \
+-  V(or, (BinaryFunc<Bool8x16, Or, Bool8x16>), 2)                                      \
+-  V(xor, (BinaryFunc<Bool8x16, Xor, Bool8x16>), 2)                                    \
+-
+-#define BOOL8X16_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Bool8x16>), 3)
+-
+-#define BOOL8X16_FUNCTION_LIST(V)                                                     \
+-  BOOL8X16_UNARY_FUNCTION_LIST(V)                                                     \
+-  BOOL8X16_BINARY_FUNCTION_LIST(V)                                                    \
+-  BOOL8X16_TERNARY_FUNCTION_LIST(V)
+-
+-// Bool 16x8.
+-#define BOOL16X8_UNARY_FUNCTION_LIST(V)                                               \
+-  V(not, (UnaryFunc<Bool16x8, LogicalNot, Bool16x8>), 1)                              \
+-  V(check, (UnaryFunc<Bool16x8, Identity, Bool16x8>), 1)                              \
+-  V(splat, (FuncSplat<Bool16x8>), 1)                                                  \
+-  V(allTrue, (AllTrue<Bool16x8>), 1)                                                  \
+-  V(anyTrue, (AnyTrue<Bool16x8>), 1)
+-
+-#define BOOL16X8_BINARY_FUNCTION_LIST(V)                                              \
+-  V(extractLane, (ExtractLane<Bool16x8>), 2)                                          \
+-  V(and, (BinaryFunc<Bool16x8, And, Bool16x8>), 2)                                    \
+-  V(or, (BinaryFunc<Bool16x8, Or, Bool16x8>), 2)                                      \
+-  V(xor, (BinaryFunc<Bool16x8, Xor, Bool16x8>), 2)                                    \
+-
+-#define BOOL16X8_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Bool16x8>), 3)
+-
+-#define BOOL16X8_FUNCTION_LIST(V)                                                     \
+-  BOOL16X8_UNARY_FUNCTION_LIST(V)                                                     \
+-  BOOL16X8_BINARY_FUNCTION_LIST(V)                                                    \
+-  BOOL16X8_TERNARY_FUNCTION_LIST(V)
+-
+-// Bool32x4.
+-#define BOOL32X4_UNARY_FUNCTION_LIST(V)                                               \
+-  V(not, (UnaryFunc<Bool32x4, LogicalNot, Bool32x4>), 1)                              \
+-  V(check, (UnaryFunc<Bool32x4, Identity, Bool32x4>), 1)                              \
+-  V(splat, (FuncSplat<Bool32x4>), 1)                                                  \
+-  V(allTrue, (AllTrue<Bool32x4>), 1)                                                  \
+-  V(anyTrue, (AnyTrue<Bool32x4>), 1)
+-
+-#define BOOL32X4_BINARY_FUNCTION_LIST(V)                                              \
+-  V(extractLane, (ExtractLane<Bool32x4>), 2)                                          \
+-  V(and, (BinaryFunc<Bool32x4, And, Bool32x4>), 2)                                    \
+-  V(or, (BinaryFunc<Bool32x4, Or, Bool32x4>), 2)                                      \
+-  V(xor, (BinaryFunc<Bool32x4, Xor, Bool32x4>), 2)                                    \
+-
+-#define BOOL32X4_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Bool32x4>), 3)
+-
+-#define BOOL32X4_FUNCTION_LIST(V)                                                     \
+-  BOOL32X4_UNARY_FUNCTION_LIST(V)                                                     \
+-  BOOL32X4_BINARY_FUNCTION_LIST(V)                                                    \
+-  BOOL32X4_TERNARY_FUNCTION_LIST(V)
+-
+-// Bool64x2.
+-#define BOOL64X2_UNARY_FUNCTION_LIST(V)                                               \
+-  V(not, (UnaryFunc<Bool64x2, LogicalNot, Bool64x2>), 1)                              \
+-  V(check, (UnaryFunc<Bool64x2, Identity, Bool64x2>), 1)                              \
+-  V(splat, (FuncSplat<Bool64x2>), 1)                                                  \
+-  V(allTrue, (AllTrue<Bool64x2>), 1)                                                  \
+-  V(anyTrue, (AnyTrue<Bool64x2>), 1)
+-
+-#define BOOL64X2_BINARY_FUNCTION_LIST(V)                                              \
+-  V(extractLane, (ExtractLane<Bool64x2>), 2)                                          \
+-  V(and, (BinaryFunc<Bool64x2, And, Bool64x2>), 2)                                    \
+-  V(or, (BinaryFunc<Bool64x2, Or, Bool64x2>), 2)                                      \
+-  V(xor, (BinaryFunc<Bool64x2, Xor, Bool64x2>), 2)                                    \
+-
+-#define BOOL64X2_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Bool64x2>), 3)
+-
+-#define BOOL64X2_FUNCTION_LIST(V)                                                     \
+-  BOOL64X2_UNARY_FUNCTION_LIST(V)                                                     \
+-  BOOL64X2_BINARY_FUNCTION_LIST(V)                                                    \
+-  BOOL64X2_TERNARY_FUNCTION_LIST(V)
+-
+-// Float32x4.
+-#define FLOAT32X4_UNARY_FUNCTION_LIST(V)                                              \
+-  V(abs, (UnaryFunc<Float32x4, Abs, Float32x4>), 1)                                   \
+-  V(check, (UnaryFunc<Float32x4, Identity, Float32x4>), 1)                            \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1)                    \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Float32x4>), 1)                    \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Float32x4>), 1)                    \
+-  V(fromInt32x4,       (FuncConvert<Int32x4,       Float32x4>), 1)                    \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Float32x4>), 1)                    \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Float32x4>), 1)                    \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Float32x4>), 1)                    \
+-  V(fromUint32x4,      (FuncConvert<Uint32x4,      Float32x4>), 1)                    \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Float32x4>), 1)                    \
+-  V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1)                                   \
+-  V(reciprocalApproximation, (UnaryFunc<Float32x4, RecApprox, Float32x4>), 1)         \
+-  V(reciprocalSqrtApproximation, (UnaryFunc<Float32x4, RecSqrtApprox, Float32x4>), 1) \
+-  V(splat, (FuncSplat<Float32x4>), 1)                                                 \
+-  V(sqrt, (UnaryFunc<Float32x4, Sqrt, Float32x4>), 1)
+-
+-#define FLOAT32X4_BINARY_FUNCTION_LIST(V)                                             \
+-  V(add, (BinaryFunc<Float32x4, Add, Float32x4>), 2)                                  \
+-  V(div, (BinaryFunc<Float32x4, Div, Float32x4>), 2)                                  \
+-  V(equal, (CompareFunc<Float32x4, Equal, Bool32x4>), 2)                              \
+-  V(extractLane, (ExtractLane<Float32x4>), 2)                                         \
+-  V(greaterThan, (CompareFunc<Float32x4, GreaterThan, Bool32x4>), 2)                  \
+-  V(greaterThanOrEqual, (CompareFunc<Float32x4, GreaterThanOrEqual, Bool32x4>), 2)    \
+-  V(lessThan, (CompareFunc<Float32x4, LessThan, Bool32x4>), 2)                        \
+-  V(lessThanOrEqual, (CompareFunc<Float32x4, LessThanOrEqual, Bool32x4>), 2)          \
+-  V(load,  (Load<Float32x4, 4>), 2)                                                   \
+-  V(load3, (Load<Float32x4, 3>), 2)                                                   \
+-  V(load2, (Load<Float32x4, 2>), 2)                                                   \
+-  V(load1, (Load<Float32x4, 1>), 2)                                                   \
+-  V(max, (BinaryFunc<Float32x4, Maximum, Float32x4>), 2)                              \
+-  V(maxNum, (BinaryFunc<Float32x4, MaxNum, Float32x4>), 2)                            \
+-  V(min, (BinaryFunc<Float32x4, Minimum, Float32x4>), 2)                              \
+-  V(minNum, (BinaryFunc<Float32x4, MinNum, Float32x4>), 2)                            \
+-  V(mul, (BinaryFunc<Float32x4, Mul, Float32x4>), 2)                                  \
+-  V(notEqual, (CompareFunc<Float32x4, NotEqual, Bool32x4>), 2)                        \
+-  V(sub, (BinaryFunc<Float32x4, Sub, Float32x4>), 2)
+-
+-#define FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                            \
+-  V(replaceLane, (ReplaceLane<Float32x4>), 3)                                         \
+-  V(select, (Select<Float32x4, Bool32x4>), 3)                                         \
+-  V(store,  (Store<Float32x4, 4>), 3)                                                 \
+-  V(store3, (Store<Float32x4, 3>), 3)                                                 \
+-  V(store2, (Store<Float32x4, 2>), 3)                                                 \
+-  V(store1, (Store<Float32x4, 1>), 3)
+-
+-#define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)                                            \
+-  V(swizzle, Swizzle<Float32x4>, 5)                                                   \
+-  V(shuffle, Shuffle<Float32x4>, 6)
+-
+-#define FLOAT32X4_FUNCTION_LIST(V)                                                    \
+-  FLOAT32X4_UNARY_FUNCTION_LIST(V)                                                    \
+-  FLOAT32X4_BINARY_FUNCTION_LIST(V)                                                   \
+-  FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                                  \
+-  FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Float64x2.
+-#define FLOAT64X2_UNARY_FUNCTION_LIST(V)                                              \
+-  V(abs, (UnaryFunc<Float64x2, Abs, Float64x2>), 1)                                   \
+-  V(check, (UnaryFunc<Float64x2, Identity, Float64x2>), 1)                            \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1)                    \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Float64x2>), 1)                    \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Float64x2>), 1)                    \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Float64x2>), 1)                    \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Float64x2>), 1)                    \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Float64x2>), 1)                    \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Float64x2>), 1)                    \
+-  V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1)                                   \
+-  V(reciprocalApproximation, (UnaryFunc<Float64x2, RecApprox, Float64x2>), 1)         \
+-  V(reciprocalSqrtApproximation, (UnaryFunc<Float64x2, RecSqrtApprox, Float64x2>), 1) \
+-  V(splat, (FuncSplat<Float64x2>), 1)                                                 \
+-  V(sqrt, (UnaryFunc<Float64x2, Sqrt, Float64x2>), 1)
+-
+-#define FLOAT64X2_BINARY_FUNCTION_LIST(V)                                             \
+-  V(add, (BinaryFunc<Float64x2, Add, Float64x2>), 2)                                  \
+-  V(div, (BinaryFunc<Float64x2, Div, Float64x2>), 2)                                  \
+-  V(equal, (CompareFunc<Float64x2, Equal, Bool64x2>), 2)                              \
+-  V(extractLane, (ExtractLane<Float64x2>), 2)                                         \
+-  V(greaterThan, (CompareFunc<Float64x2, GreaterThan, Bool64x2>), 2)                  \
+-  V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual, Bool64x2>), 2)    \
+-  V(lessThan, (CompareFunc<Float64x2, LessThan, Bool64x2>), 2)                        \
+-  V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual, Bool64x2>), 2)          \
+-  V(load,  (Load<Float64x2, 2>), 2)                                                   \
+-  V(load1, (Load<Float64x2, 1>), 2)                                                   \
+-  V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2)                              \
+-  V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2)                            \
+-  V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2)                              \
+-  V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2)                            \
+-  V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2)                                  \
+-  V(notEqual, (CompareFunc<Float64x2, NotEqual, Bool64x2>), 2)                        \
+-  V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2)
+-
+-#define FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                            \
+-  V(replaceLane, (ReplaceLane<Float64x2>), 3)                                         \
+-  V(select, (Select<Float64x2, Bool64x2>), 3)                                         \
+-  V(store,  (Store<Float64x2, 2>), 3)                                                 \
+-  V(store1, (Store<Float64x2, 1>), 3)
+-
+-#define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)                                            \
+-  V(swizzle, Swizzle<Float64x2>, 3)                                                   \
+-  V(shuffle, Shuffle<Float64x2>, 4)
+-
+-#define FLOAT64X2_FUNCTION_LIST(V)                                                    \
+-  FLOAT64X2_UNARY_FUNCTION_LIST(V)                                                    \
+-  FLOAT64X2_BINARY_FUNCTION_LIST(V)                                                   \
+-  FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                                  \
+-  FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Int8x16.
+-#define INT8X16_UNARY_FUNCTION_LIST(V)                                                \
+-  V(check, (UnaryFunc<Int8x16, Identity, Int8x16>), 1)                                \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int8x16>), 1)                      \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int8x16>), 1)                      \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Int8x16>), 1)                      \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Int8x16>), 1)                      \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Int8x16>), 1)                      \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Int8x16>), 1)                      \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Int8x16>), 1)                      \
+-  V(neg, (UnaryFunc<Int8x16, Neg, Int8x16>), 1)                                       \
+-  V(not, (UnaryFunc<Int8x16, Not, Int8x16>), 1)                                       \
+-  V(splat, (FuncSplat<Int8x16>), 1)
+-
+-#define INT8X16_BINARY_FUNCTION_LIST(V)                                               \
+-  V(add, (BinaryFunc<Int8x16, Add, Int8x16>), 2)                                      \
+-  V(addSaturate, (BinaryFunc<Int8x16, AddSaturate, Int8x16>), 2)                      \
+-  V(and, (BinaryFunc<Int8x16, And, Int8x16>), 2)                                      \
+-  V(equal, (CompareFunc<Int8x16, Equal, Bool8x16>), 2)                                \
+-  V(extractLane, (ExtractLane<Int8x16>), 2)                                           \
+-  V(greaterThan, (CompareFunc<Int8x16, GreaterThan, Bool8x16>), 2)                    \
+-  V(greaterThanOrEqual, (CompareFunc<Int8x16, GreaterThanOrEqual, Bool8x16>), 2)      \
+-  V(lessThan, (CompareFunc<Int8x16, LessThan, Bool8x16>), 2)                          \
+-  V(lessThanOrEqual, (CompareFunc<Int8x16, LessThanOrEqual, Bool8x16>), 2)            \
+-  V(load, (Load<Int8x16, 16>), 2)                                                     \
+-  V(mul, (BinaryFunc<Int8x16, Mul, Int8x16>), 2)                                      \
+-  V(notEqual, (CompareFunc<Int8x16, NotEqual, Bool8x16>), 2)                          \
+-  V(or, (BinaryFunc<Int8x16, Or, Int8x16>), 2)                                        \
+-  V(sub, (BinaryFunc<Int8x16, Sub, Int8x16>), 2)                                      \
+-  V(subSaturate, (BinaryFunc<Int8x16, SubSaturate, Int8x16>), 2)                      \
+-  V(shiftLeftByScalar, (BinaryScalar<Int8x16, ShiftLeft>), 2)                         \
+-  V(shiftRightByScalar, (BinaryScalar<Int8x16, ShiftRightArithmetic>), 2)             \
+-  V(xor, (BinaryFunc<Int8x16, Xor, Int8x16>), 2)
+-
+-#define INT8X16_TERNARY_FUNCTION_LIST(V)                                              \
+-  V(replaceLane, (ReplaceLane<Int8x16>), 3)                                           \
+-  V(select, (Select<Int8x16, Bool8x16>), 3)                                           \
+-  V(store, (Store<Int8x16, 16>), 3)
+-
+-#define INT8X16_SHUFFLE_FUNCTION_LIST(V)                                              \
+-  V(swizzle, Swizzle<Int8x16>, 17)                                                    \
+-  V(shuffle, Shuffle<Int8x16>, 18)
+-
+-#define INT8X16_FUNCTION_LIST(V)                                                      \
+-  INT8X16_UNARY_FUNCTION_LIST(V)                                                      \
+-  INT8X16_BINARY_FUNCTION_LIST(V)                                                     \
+-  INT8X16_TERNARY_FUNCTION_LIST(V)                                                    \
+-  INT8X16_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Uint8x16.
+-#define UINT8X16_UNARY_FUNCTION_LIST(V)                                               \
+-  V(check, (UnaryFunc<Uint8x16, Identity, Uint8x16>), 1)                              \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint8x16>), 1)                     \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint8x16>), 1)                     \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Uint8x16>), 1)                     \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Uint8x16>), 1)                     \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Uint8x16>), 1)                     \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Uint8x16>), 1)                     \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Uint8x16>), 1)                     \
+-  V(neg, (UnaryFunc<Uint8x16, Neg, Uint8x16>), 1)                                     \
+-  V(not, (UnaryFunc<Uint8x16, Not, Uint8x16>), 1)                                     \
+-  V(splat, (FuncSplat<Uint8x16>), 1)
+-
+-#define UINT8X16_BINARY_FUNCTION_LIST(V)                                              \
+-  V(add, (BinaryFunc<Uint8x16, Add, Uint8x16>), 2)                                    \
+-  V(addSaturate, (BinaryFunc<Uint8x16, AddSaturate, Uint8x16>), 2)                    \
+-  V(and, (BinaryFunc<Uint8x16, And, Uint8x16>), 2)                                    \
+-  V(equal, (CompareFunc<Uint8x16, Equal, Bool8x16>), 2)                               \
+-  V(extractLane, (ExtractLane<Uint8x16>), 2)                                          \
+-  V(greaterThan, (CompareFunc<Uint8x16, GreaterThan, Bool8x16>), 2)                   \
+-  V(greaterThanOrEqual, (CompareFunc<Uint8x16, GreaterThanOrEqual, Bool8x16>), 2)     \
+-  V(lessThan, (CompareFunc<Uint8x16, LessThan, Bool8x16>), 2)                         \
+-  V(lessThanOrEqual, (CompareFunc<Uint8x16, LessThanOrEqual, Bool8x16>), 2)           \
+-  V(load, (Load<Uint8x16, 16>), 2)                                                    \
+-  V(mul, (BinaryFunc<Uint8x16, Mul, Uint8x16>), 2)                                    \
+-  V(notEqual, (CompareFunc<Uint8x16, NotEqual, Bool8x16>), 2)                         \
+-  V(or, (BinaryFunc<Uint8x16, Or, Uint8x16>), 2)                                      \
+-  V(sub, (BinaryFunc<Uint8x16, Sub, Uint8x16>), 2)                                    \
+-  V(subSaturate, (BinaryFunc<Uint8x16, SubSaturate, Uint8x16>), 2)                    \
+-  V(shiftLeftByScalar, (BinaryScalar<Uint8x16, ShiftLeft>), 2)                        \
+-  V(shiftRightByScalar, (BinaryScalar<Uint8x16, ShiftRightLogical>), 2)               \
+-  V(xor, (BinaryFunc<Uint8x16, Xor, Uint8x16>), 2)
+-
+-#define UINT8X16_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Uint8x16>), 3)                                          \
+-  V(select, (Select<Uint8x16, Bool8x16>), 3)                                          \
+-  V(store, (Store<Uint8x16, 16>), 3)
+-
+-#define UINT8X16_SHUFFLE_FUNCTION_LIST(V)                                             \
+-  V(swizzle, Swizzle<Uint8x16>, 17)                                                   \
+-  V(shuffle, Shuffle<Uint8x16>, 18)
+-
+-#define UINT8X16_FUNCTION_LIST(V)                                                     \
+-  UINT8X16_UNARY_FUNCTION_LIST(V)                                                     \
+-  UINT8X16_BINARY_FUNCTION_LIST(V)                                                    \
+-  UINT8X16_TERNARY_FUNCTION_LIST(V)                                                   \
+-  UINT8X16_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Int16x8.
+-#define INT16X8_UNARY_FUNCTION_LIST(V)                                                \
+-  V(check, (UnaryFunc<Int16x8, Identity, Int16x8>), 1)                                \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int16x8>), 1)                      \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int16x8>), 1)                      \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Int16x8>), 1)                      \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Int16x8>), 1)                      \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Int16x8>), 1)                      \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Int16x8>), 1)                      \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Int16x8>), 1)                      \
+-  V(neg, (UnaryFunc<Int16x8, Neg, Int16x8>), 1)                                       \
+-  V(not, (UnaryFunc<Int16x8, Not, Int16x8>), 1)                                       \
+-  V(splat, (FuncSplat<Int16x8>), 1)
+-
+-#define INT16X8_BINARY_FUNCTION_LIST(V)                                               \
+-  V(add, (BinaryFunc<Int16x8, Add, Int16x8>), 2)                                      \
+-  V(addSaturate, (BinaryFunc<Int16x8, AddSaturate, Int16x8>), 2)                      \
+-  V(and, (BinaryFunc<Int16x8, And, Int16x8>), 2)                                      \
+-  V(equal, (CompareFunc<Int16x8, Equal, Bool16x8>), 2)                                \
+-  V(extractLane, (ExtractLane<Int16x8>), 2)                                           \
+-  V(greaterThan, (CompareFunc<Int16x8, GreaterThan, Bool16x8>), 2)                    \
+-  V(greaterThanOrEqual, (CompareFunc<Int16x8, GreaterThanOrEqual, Bool16x8>), 2)      \
+-  V(lessThan, (CompareFunc<Int16x8, LessThan, Bool16x8>), 2)                          \
+-  V(lessThanOrEqual, (CompareFunc<Int16x8, LessThanOrEqual, Bool16x8>), 2)            \
+-  V(load, (Load<Int16x8, 8>), 2)                                                      \
+-  V(mul, (BinaryFunc<Int16x8, Mul, Int16x8>), 2)                                      \
+-  V(notEqual, (CompareFunc<Int16x8, NotEqual, Bool16x8>), 2)                          \
+-  V(or, (BinaryFunc<Int16x8, Or, Int16x8>), 2)                                        \
+-  V(sub, (BinaryFunc<Int16x8, Sub, Int16x8>), 2)                                      \
+-  V(subSaturate, (BinaryFunc<Int16x8, SubSaturate, Int16x8>), 2)                      \
+-  V(shiftLeftByScalar, (BinaryScalar<Int16x8, ShiftLeft>), 2)                         \
+-  V(shiftRightByScalar, (BinaryScalar<Int16x8, ShiftRightArithmetic>), 2)             \
+-  V(xor, (BinaryFunc<Int16x8, Xor, Int16x8>), 2)
+-
+-#define INT16X8_TERNARY_FUNCTION_LIST(V)                                              \
+-  V(replaceLane, (ReplaceLane<Int16x8>), 3)                                           \
+-  V(select, (Select<Int16x8, Bool16x8>), 3)                                           \
+-  V(store, (Store<Int16x8, 8>), 3)
+-
+-#define INT16X8_SHUFFLE_FUNCTION_LIST(V)                                              \
+-  V(swizzle, Swizzle<Int16x8>, 9)                                                     \
+-  V(shuffle, Shuffle<Int16x8>, 10)
+-
+-#define INT16X8_FUNCTION_LIST(V)                                                      \
+-  INT16X8_UNARY_FUNCTION_LIST(V)                                                      \
+-  INT16X8_BINARY_FUNCTION_LIST(V)                                                     \
+-  INT16X8_TERNARY_FUNCTION_LIST(V)                                                    \
+-  INT16X8_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Uint16x8.
+-#define UINT16X8_UNARY_FUNCTION_LIST(V)                                               \
+-  V(check, (UnaryFunc<Uint16x8, Identity, Uint16x8>), 1)                              \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint16x8>), 1)                     \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint16x8>), 1)                     \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Uint16x8>), 1)                     \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Uint16x8>), 1)                     \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Uint16x8>), 1)                     \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Uint16x8>), 1)                     \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Uint16x8>), 1)                     \
+-  V(neg, (UnaryFunc<Uint16x8, Neg, Uint16x8>), 1)                                     \
+-  V(not, (UnaryFunc<Uint16x8, Not, Uint16x8>), 1)                                     \
+-  V(splat, (FuncSplat<Uint16x8>), 1)
+-
+-#define UINT16X8_BINARY_FUNCTION_LIST(V)                                              \
+-  V(add, (BinaryFunc<Uint16x8, Add, Uint16x8>), 2)                                    \
+-  V(addSaturate, (BinaryFunc<Uint16x8, AddSaturate, Uint16x8>), 2)                    \
+-  V(and, (BinaryFunc<Uint16x8, And, Uint16x8>), 2)                                    \
+-  V(equal, (CompareFunc<Uint16x8, Equal, Bool16x8>), 2)                               \
+-  V(extractLane, (ExtractLane<Uint16x8>), 2)                                          \
+-  V(greaterThan, (CompareFunc<Uint16x8, GreaterThan, Bool16x8>), 2)                   \
+-  V(greaterThanOrEqual, (CompareFunc<Uint16x8, GreaterThanOrEqual, Bool16x8>), 2)     \
+-  V(lessThan, (CompareFunc<Uint16x8, LessThan, Bool16x8>), 2)                         \
+-  V(lessThanOrEqual, (CompareFunc<Uint16x8, LessThanOrEqual, Bool16x8>), 2)           \
+-  V(load, (Load<Uint16x8, 8>), 2)                                                     \
+-  V(mul, (BinaryFunc<Uint16x8, Mul, Uint16x8>), 2)                                    \
+-  V(notEqual, (CompareFunc<Uint16x8, NotEqual, Bool16x8>), 2)                         \
+-  V(or, (BinaryFunc<Uint16x8, Or, Uint16x8>), 2)                                      \
+-  V(sub, (BinaryFunc<Uint16x8, Sub, Uint16x8>), 2)                                    \
+-  V(subSaturate, (BinaryFunc<Uint16x8, SubSaturate, Uint16x8>), 2)                    \
+-  V(shiftLeftByScalar, (BinaryScalar<Uint16x8, ShiftLeft>), 2)                        \
+-  V(shiftRightByScalar, (BinaryScalar<Uint16x8, ShiftRightLogical>), 2)               \
+-  V(xor, (BinaryFunc<Uint16x8, Xor, Uint16x8>), 2)
+-
+-#define UINT16X8_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Uint16x8>), 3)                                          \
+-  V(select, (Select<Uint16x8, Bool16x8>), 3)                                          \
+-  V(store, (Store<Uint16x8, 8>), 3)
+-
+-#define UINT16X8_SHUFFLE_FUNCTION_LIST(V)                                             \
+-  V(swizzle, Swizzle<Uint16x8>, 9)                                                    \
+-  V(shuffle, Shuffle<Uint16x8>, 10)
+-
+-#define UINT16X8_FUNCTION_LIST(V)                                                     \
+-  UINT16X8_UNARY_FUNCTION_LIST(V)                                                     \
+-  UINT16X8_BINARY_FUNCTION_LIST(V)                                                    \
+-  UINT16X8_TERNARY_FUNCTION_LIST(V)                                                   \
+-  UINT16X8_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Int32x4.
+-#define INT32X4_UNARY_FUNCTION_LIST(V)                                                \
+-  V(check, (UnaryFunc<Int32x4, Identity, Int32x4>), 1)                                \
+-  V(fromFloat32x4,     (FuncConvert<Float32x4,     Int32x4>), 1)                      \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1)                      \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1)                      \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Int32x4>), 1)                      \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Int32x4>), 1)                      \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Int32x4>), 1)                      \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Int32x4>), 1)                      \
+-  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Int32x4>), 1)                      \
+-  V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1)                                       \
+-  V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1)                                       \
+-  V(splat, (FuncSplat<Int32x4>), 0)
+-
+-#define INT32X4_BINARY_FUNCTION_LIST(V)                                               \
+-  V(add, (BinaryFunc<Int32x4, Add, Int32x4>), 2)                                      \
+-  V(and, (BinaryFunc<Int32x4, And, Int32x4>), 2)                                      \
+-  V(equal, (CompareFunc<Int32x4, Equal, Bool32x4>), 2)                                \
+-  V(extractLane, (ExtractLane<Int32x4>), 2)                                           \
+-  V(greaterThan, (CompareFunc<Int32x4, GreaterThan, Bool32x4>), 2)                    \
+-  V(greaterThanOrEqual, (CompareFunc<Int32x4, GreaterThanOrEqual, Bool32x4>), 2)      \
+-  V(lessThan, (CompareFunc<Int32x4, LessThan, Bool32x4>), 2)                          \
+-  V(lessThanOrEqual, (CompareFunc<Int32x4, LessThanOrEqual, Bool32x4>), 2)            \
+-  V(load,  (Load<Int32x4, 4>), 2)                                                     \
+-  V(load3, (Load<Int32x4, 3>), 2)                                                     \
+-  V(load2, (Load<Int32x4, 2>), 2)                                                     \
+-  V(load1, (Load<Int32x4, 1>), 2)                                                     \
+-  V(mul, (BinaryFunc<Int32x4, Mul, Int32x4>), 2)                                      \
+-  V(notEqual, (CompareFunc<Int32x4, NotEqual, Bool32x4>), 2)                          \
+-  V(or, (BinaryFunc<Int32x4, Or, Int32x4>), 2)                                        \
+-  V(sub, (BinaryFunc<Int32x4, Sub, Int32x4>), 2)                                      \
+-  V(shiftLeftByScalar, (BinaryScalar<Int32x4, ShiftLeft>), 2)                         \
+-  V(shiftRightByScalar, (BinaryScalar<Int32x4, ShiftRightArithmetic>), 2)             \
+-  V(xor, (BinaryFunc<Int32x4, Xor, Int32x4>), 2)
+-
+-#define INT32X4_TERNARY_FUNCTION_LIST(V)                                              \
+-  V(replaceLane, (ReplaceLane<Int32x4>), 3)                                           \
+-  V(select, (Select<Int32x4, Bool32x4>), 3)                                           \
+-  V(store,  (Store<Int32x4, 4>), 3)                                                   \
+-  V(store3, (Store<Int32x4, 3>), 3)                                                   \
+-  V(store2, (Store<Int32x4, 2>), 3)                                                   \
+-  V(store1, (Store<Int32x4, 1>), 3)
+-
+-#define INT32X4_SHUFFLE_FUNCTION_LIST(V)                                              \
+-  V(swizzle, Swizzle<Int32x4>, 5)                                                     \
+-  V(shuffle, Shuffle<Int32x4>, 6)
+-
+-#define INT32X4_FUNCTION_LIST(V)                                                      \
+-  INT32X4_UNARY_FUNCTION_LIST(V)                                                      \
+-  INT32X4_BINARY_FUNCTION_LIST(V)                                                     \
+-  INT32X4_TERNARY_FUNCTION_LIST(V)                                                    \
+-  INT32X4_SHUFFLE_FUNCTION_LIST(V)
+-
+-// Uint32x4.
+-#define UINT32X4_UNARY_FUNCTION_LIST(V)                                               \
+-  V(check, (UnaryFunc<Uint32x4, Identity, Uint32x4>), 1)                              \
+-  V(fromFloat32x4,     (FuncConvert<Float32x4,     Uint32x4>), 1)                     \
+-  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint32x4>), 1)                     \
+-  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint32x4>), 1)                     \
+-  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Uint32x4>), 1)                     \
+-  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Uint32x4>), 1)                     \
+-  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Uint32x4>), 1)                     \
+-  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Uint32x4>), 1)                     \
+-  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Uint32x4>), 1)                     \
+-  V(neg, (UnaryFunc<Uint32x4, Neg, Uint32x4>), 1)                                     \
+-  V(not, (UnaryFunc<Uint32x4, Not, Uint32x4>), 1)                                     \
+-  V(splat, (FuncSplat<Uint32x4>), 0)
+-
+-#define UINT32X4_BINARY_FUNCTION_LIST(V)                                              \
+-  V(add, (BinaryFunc<Uint32x4, Add, Uint32x4>), 2)                                    \
+-  V(and, (BinaryFunc<Uint32x4, And, Uint32x4>), 2)                                    \
+-  V(equal, (CompareFunc<Uint32x4, Equal, Bool32x4>), 2)                               \
+-  V(extractLane, (ExtractLane<Uint32x4>), 2)                                          \
+-  V(greaterThan, (CompareFunc<Uint32x4, GreaterThan, Bool32x4>), 2)                   \
+-  V(greaterThanOrEqual, (CompareFunc<Uint32x4, GreaterThanOrEqual, Bool32x4>), 2)     \
+-  V(lessThan, (CompareFunc<Uint32x4, LessThan, Bool32x4>), 2)                         \
+-  V(lessThanOrEqual, (CompareFunc<Uint32x4, LessThanOrEqual, Bool32x4>), 2)           \
+-  V(load,  (Load<Uint32x4, 4>), 2)                                                    \
+-  V(load3, (Load<Uint32x4, 3>), 2)                                                    \
+-  V(load2, (Load<Uint32x4, 2>), 2)                                                    \
+-  V(load1, (Load<Uint32x4, 1>), 2)                                                    \
+-  V(mul, (BinaryFunc<Uint32x4, Mul, Uint32x4>), 2)                                    \
+-  V(notEqual, (CompareFunc<Uint32x4, NotEqual, Bool32x4>), 2)                         \
+-  V(or, (BinaryFunc<Uint32x4, Or, Uint32x4>), 2)                                      \
+-  V(sub, (BinaryFunc<Uint32x4, Sub, Uint32x4>), 2)                                    \
+-  V(shiftLeftByScalar, (BinaryScalar<Uint32x4, ShiftLeft>), 2)                        \
+-  V(shiftRightByScalar, (BinaryScalar<Uint32x4, ShiftRightLogical>), 2)               \
+-  V(xor, (BinaryFunc<Uint32x4, Xor, Uint32x4>), 2)
+-
+-#define UINT32X4_TERNARY_FUNCTION_LIST(V)                                             \
+-  V(replaceLane, (ReplaceLane<Uint32x4>), 3)                                          \
+-  V(select, (Select<Uint32x4, Bool32x4>), 3)                                          \
+-  V(store,  (Store<Uint32x4, 4>), 3)                                                  \
+-  V(store3, (Store<Uint32x4, 3>), 3)                                                  \
+-  V(store2, (Store<Uint32x4, 2>), 3)                                                  \
+-  V(store1, (Store<Uint32x4, 1>), 3)
+-
+-#define UINT32X4_SHUFFLE_FUNCTION_LIST(V)                                             \
+-  V(swizzle, Swizzle<Uint32x4>, 5)                                                    \
+-  V(shuffle, Shuffle<Uint32x4>, 6)
+-
+-#define UINT32X4_FUNCTION_LIST(V)                                                     \
+-  UINT32X4_UNARY_FUNCTION_LIST(V)                                                     \
+-  UINT32X4_BINARY_FUNCTION_LIST(V)                                                    \
+-  UINT32X4_TERNARY_FUNCTION_LIST(V)                                                   \
+-  UINT32X4_SHUFFLE_FUNCTION_LIST(V)
+-
+-/*
+- * The FOREACH macros below partition all of the SIMD operations into disjoint
+- * sets.
+- */
+-
+-// Operations available on all SIMD types. Mixed arity.
+-#define FOREACH_COMMON_SIMD_OP(_)     \
+-    _(extractLane)                    \
+-    _(replaceLane)                    \
+-    _(check)                          \
+-    _(splat)
+-
+-// Lanewise operations available on numeric SIMD types.
+-// Include lane-wise select here since it is not arithmetic and defined on
+-// numeric types too.
+-#define FOREACH_LANE_SIMD_OP(_)       \
+-    _(select)                         \
+-    _(swizzle)                        \
+-    _(shuffle)
+-
+-// Memory operations available on numeric SIMD types.
+-#define FOREACH_MEMORY_SIMD_OP(_)     \
+-    _(load)                           \
+-    _(store)
+-
+-// Memory operations available on numeric X4 SIMD types.
+-#define FOREACH_MEMORY_X4_SIMD_OP(_)  \
+-    _(load1)                          \
+-    _(load2)                          \
+-    _(load3)                          \
+-    _(store1)                         \
+-    _(store2)                         \
+-    _(store3)
+-
+-// Unary operations on Bool vectors.
+-#define FOREACH_BOOL_SIMD_UNOP(_)     \
+-    _(allTrue)                        \
+-    _(anyTrue)
+-
+-// Unary bitwise SIMD operators defined on all integer and boolean SIMD types.
+-#define FOREACH_BITWISE_SIMD_UNOP(_)  \
+-    _(not)
+-
+-// Binary bitwise SIMD operators defined on all integer and boolean SIMD types.
+-#define FOREACH_BITWISE_SIMD_BINOP(_) \
+-    _(and)                            \
+-    _(or)                             \
+-    _(xor)
+-
+-// Bitwise shifts defined on integer SIMD types.
+-#define FOREACH_SHIFT_SIMD_OP(_)      \
+-    _(shiftLeftByScalar)              \
+-    _(shiftRightByScalar)
+-
+-// Unary arithmetic operators defined on numeric SIMD types.
+-#define FOREACH_NUMERIC_SIMD_UNOP(_)  \
+-    _(neg)
+-
+-// Binary arithmetic operators defined on numeric SIMD types.
+-#define FOREACH_NUMERIC_SIMD_BINOP(_) \
+-    _(add)                            \
+-    _(sub)                            \
+-    _(mul)
+-
+-// Unary arithmetic operators defined on floating point SIMD types.
+-#define FOREACH_FLOAT_SIMD_UNOP(_)    \
+-    _(abs)                            \
+-    _(sqrt)                           \
+-    _(reciprocalApproximation)        \
+-    _(reciprocalSqrtApproximation)
+-
+-// Binary arithmetic operators defined on floating point SIMD types.
+-#define FOREACH_FLOAT_SIMD_BINOP(_)   \
+-    _(div)                            \
+-    _(max)                            \
+-    _(min)                            \
+-    _(maxNum)                         \
+-    _(minNum)
+-
+-// Binary operations on small integer (< 32 bits) vectors.
+-#define FOREACH_SMINT_SIMD_BINOP(_)   \
+-    _(addSaturate)                    \
+-    _(subSaturate)
+-
+-// Comparison operators defined on numeric SIMD types.
+-#define FOREACH_COMP_SIMD_OP(_)       \
+-    _(lessThan)                       \
+-    _(lessThanOrEqual)                \
+-    _(equal)                          \
+-    _(notEqual)                       \
+-    _(greaterThan)                    \
+-    _(greaterThanOrEqual)
+-
+-/*
+- * All SIMD operations, excluding casts.
+- */
+-#define FORALL_SIMD_NONCAST_OP(_)     \
+-    FOREACH_COMMON_SIMD_OP(_)         \
+-    FOREACH_LANE_SIMD_OP(_)           \
+-    FOREACH_MEMORY_SIMD_OP(_)         \
+-    FOREACH_MEMORY_X4_SIMD_OP(_)      \
+-    FOREACH_BOOL_SIMD_UNOP(_)         \
+-    FOREACH_BITWISE_SIMD_UNOP(_)      \
+-    FOREACH_BITWISE_SIMD_BINOP(_)     \
+-    FOREACH_SHIFT_SIMD_OP(_)          \
+-    FOREACH_NUMERIC_SIMD_UNOP(_)      \
+-    FOREACH_NUMERIC_SIMD_BINOP(_)     \
+-    FOREACH_FLOAT_SIMD_UNOP(_)        \
+-    FOREACH_FLOAT_SIMD_BINOP(_)       \
+-    FOREACH_SMINT_SIMD_BINOP(_)       \
+-    FOREACH_COMP_SIMD_OP(_)
+-
+-/*
+- * All operations on integer SIMD types, excluding casts and
+- * FOREACH_MEMORY_X4_OP.
+- */
+-#define FORALL_INT_SIMD_OP(_)         \
+-    FOREACH_COMMON_SIMD_OP(_)         \
+-    FOREACH_LANE_SIMD_OP(_)           \
+-    FOREACH_MEMORY_SIMD_OP(_)         \
+-    FOREACH_BITWISE_SIMD_UNOP(_)      \
+-    FOREACH_BITWISE_SIMD_BINOP(_)     \
+-    FOREACH_SHIFT_SIMD_OP(_)          \
+-    FOREACH_NUMERIC_SIMD_UNOP(_)      \
+-    FOREACH_NUMERIC_SIMD_BINOP(_)     \
+-    FOREACH_COMP_SIMD_OP(_)
+-
+-/*
+- * All operations on floating point SIMD types, excluding casts and
+- * FOREACH_MEMORY_X4_OP.
+- */
+-#define FORALL_FLOAT_SIMD_OP(_)       \
+-    FOREACH_COMMON_SIMD_OP(_)         \
+-    FOREACH_LANE_SIMD_OP(_)           \
+-    FOREACH_MEMORY_SIMD_OP(_)         \
+-    FOREACH_NUMERIC_SIMD_UNOP(_)      \
+-    FOREACH_NUMERIC_SIMD_BINOP(_)     \
+-    FOREACH_FLOAT_SIMD_UNOP(_)        \
+-    FOREACH_FLOAT_SIMD_BINOP(_)       \
+-    FOREACH_COMP_SIMD_OP(_)
+-
+-/*
+- * All operations on Bool SIMD types.
+- *
+- * These types don't have casts, so no need to specialize.
+- */
+-#define FORALL_BOOL_SIMD_OP(_)        \
+-    FOREACH_COMMON_SIMD_OP(_)         \
+-    FOREACH_BOOL_SIMD_UNOP(_)         \
+-    FOREACH_BITWISE_SIMD_UNOP(_)      \
+-    FOREACH_BITWISE_SIMD_BINOP(_)
+-
+-/*
+- * The sets of cast operations are listed per type below.
+- *
+- * These sets are not disjoint.
+- */
+-
+-#define FOREACH_INT8X16_SIMD_CAST(_)  \
+-    _(fromFloat32x4Bits)              \
+-    _(fromFloat64x2Bits)              \
+-    _(fromInt16x8Bits)                \
+-    _(fromInt32x4Bits)
+-
+-#define FOREACH_INT16X8_SIMD_CAST(_)  \
+-    _(fromFloat32x4Bits)              \
+-    _(fromFloat64x2Bits)              \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt32x4Bits)
+-
+-#define FOREACH_INT32X4_SIMD_CAST(_)  \
+-    _(fromFloat32x4)                  \
+-    _(fromFloat32x4Bits)              \
+-    _(fromFloat64x2Bits)              \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt16x8Bits)
+-
+-#define FOREACH_FLOAT32X4_SIMD_CAST(_)\
+-    _(fromFloat64x2Bits)              \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt16x8Bits)                \
+-    _(fromInt32x4)                    \
+-    _(fromInt32x4Bits)
+-
+-#define FOREACH_FLOAT64X2_SIMD_CAST(_)\
+-    _(fromFloat32x4Bits)              \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt16x8Bits)                \
+-    _(fromInt32x4Bits)
+-
+-// All operations on Int32x4.
+-#define FORALL_INT32X4_SIMD_OP(_)     \
+-    FORALL_INT_SIMD_OP(_)             \
+-    FOREACH_MEMORY_X4_SIMD_OP(_)      \
+-    FOREACH_INT32X4_SIMD_CAST(_)
+-
+-// All operations on Float32X4
+-#define FORALL_FLOAT32X4_SIMD_OP(_)   \
+-    FORALL_FLOAT_SIMD_OP(_)           \
+-    FOREACH_MEMORY_X4_SIMD_OP(_)      \
+-    FOREACH_FLOAT32X4_SIMD_CAST(_)
+-
+-/*
+- * All SIMD operations assuming only 32x4 types exist.
+- * This is used in the current asm.js impl.
+- */
+-#define FORALL_SIMD_ASMJS_OP(_)       \
+-    FORALL_SIMD_NONCAST_OP(_)         \
+-    _(fromFloat32x4)                  \
+-    _(fromFloat32x4Bits)              \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt16x8Bits)                \
+-    _(fromInt32x4)                    \
+-    _(fromInt32x4Bits)                \
+-    _(fromUint8x16Bits)               \
+-    _(fromUint16x8Bits)               \
+-    _(fromUint32x4)                   \
+-    _(fromUint32x4Bits)
+-
+-// All operations on Int8x16 or Uint8x16 in the asm.js world.
+-// Note: this does not include conversions and casts to/from Uint8x16 because
+-// this list is shared between Int8x16 and Uint8x16.
+-#define FORALL_INT8X16_ASMJS_OP(_)    \
+-    FORALL_INT_SIMD_OP(_)             \
+-    FOREACH_SMINT_SIMD_BINOP(_)       \
+-    _(fromInt16x8Bits)                \
+-    _(fromInt32x4Bits)                \
+-    _(fromFloat32x4Bits)
+-
+-// All operations on Int16x8 or Uint16x8 in the asm.js world.
+-// Note: this does not include conversions and casts to/from Uint16x8 because
+-// this list is shared between Int16x8 and Uint16x8.
+-#define FORALL_INT16X8_ASMJS_OP(_)    \
+-    FORALL_INT_SIMD_OP(_)             \
+-    FOREACH_SMINT_SIMD_BINOP(_)       \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt32x4Bits)                \
+-    _(fromFloat32x4Bits)
+-
+-// All operations on Int32x4 or Uint32x4 in the asm.js world.
+-// Note: this does not include conversions and casts to/from Uint32x4 because
+-// this list is shared between Int32x4 and Uint32x4.
+-#define FORALL_INT32X4_ASMJS_OP(_)    \
+-    FORALL_INT_SIMD_OP(_)             \
+-    FOREACH_MEMORY_X4_SIMD_OP(_)      \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt16x8Bits)                \
+-    _(fromFloat32x4)                  \
+-    _(fromFloat32x4Bits)
+-
+-// All operations on Float32X4 in the asm.js world.
+-#define FORALL_FLOAT32X4_ASMJS_OP(_)  \
+-    FORALL_FLOAT_SIMD_OP(_)           \
+-    FOREACH_MEMORY_X4_SIMD_OP(_)      \
+-    _(fromInt8x16Bits)                \
+-    _(fromInt16x8Bits)                \
+-    _(fromInt32x4Bits)                \
+-    _(fromInt32x4)                    \
+-    _(fromUint32x4)
+-
+ namespace js {
+ 
+ class GlobalObject;
+ 
+-// Complete set of SIMD types.
+-// It must be kept in sync with the enumeration of values in
+-// TypedObjectConstants.h; in particular we need to ensure that Count is
+-// appropriately set with respect to the number of actual types.
+-enum class SimdType {
+-    Int8x16   = JS_SIMDTYPEREPR_INT8X16,
+-    Int16x8   = JS_SIMDTYPEREPR_INT16X8,
+-    Int32x4   = JS_SIMDTYPEREPR_INT32X4,
+-    Uint8x16  = JS_SIMDTYPEREPR_UINT8X16,
+-    Uint16x8  = JS_SIMDTYPEREPR_UINT16X8,
+-    Uint32x4  = JS_SIMDTYPEREPR_UINT32X4,
+-    Float32x4 = JS_SIMDTYPEREPR_FLOAT32X4,
+-    Float64x2 = JS_SIMDTYPEREPR_FLOAT64X2,
+-    Bool8x16  = JS_SIMDTYPEREPR_BOOL8X16,
+-    Bool16x8  = JS_SIMDTYPEREPR_BOOL16X8,
+-    Bool32x4  = JS_SIMDTYPEREPR_BOOL32X4,
+-    Bool64x2  = JS_SIMDTYPEREPR_BOOL64X2,
+-    Count
+-};
+-
+-// The integer SIMD types have a lot of operations that do the exact same thing
+-// for signed and unsigned integer types. Sometimes it is simpler to treat
+-// signed and unsigned integer SIMD types as the same type, using a SimdSign to
+-// distinguish the few cases where there is a difference.
+-enum class SimdSign {
+-    // Signedness is not applicable to this type. (i.e., Float or Bool).
+-    NotApplicable,
+-    // Treat as an unsigned integer with a range 0 .. 2^N-1.
+-    Unsigned,
+-    // Treat as a signed integer in two's complement encoding.
+-    Signed,
+-};
+-
+-// Get the signedness of a SIMD type.
+-inline SimdSign
+-GetSimdSign(SimdType t)
+-{
+-    switch(t) {
+-      case SimdType::Int8x16:
+-      case SimdType::Int16x8:
+-      case SimdType::Int32x4:
+-        return SimdSign::Signed;
+-
+-      case SimdType::Uint8x16:
+-      case SimdType::Uint16x8:
+-      case SimdType::Uint32x4:
+-        return SimdSign::Unsigned;
+-
+-      default:
+-        return SimdSign::NotApplicable;
+-    }
+-}
+-
+-inline bool
+-IsSignedIntSimdType(SimdType type)
+-{
+-    return GetSimdSign(type) == SimdSign::Signed;
+-}
+-
+-// Get the boolean SIMD type with the same shape as t.
+-//
+-// This is the result type of a comparison operation, and it can also be used to
+-// identify the geometry of a SIMD type.
+-inline SimdType
+-GetBooleanSimdType(SimdType t)
+-{
+-    switch(t) {
+-      case SimdType::Int8x16:
+-      case SimdType::Uint8x16:
+-      case SimdType::Bool8x16:
+-        return SimdType::Bool8x16;
+-
+-      case SimdType::Int16x8:
+-      case SimdType::Uint16x8:
+-      case SimdType::Bool16x8:
+-        return SimdType::Bool16x8;
+-
+-      case SimdType::Int32x4:
+-      case SimdType::Uint32x4:
+-      case SimdType::Float32x4:
+-      case SimdType::Bool32x4:
+-        return SimdType::Bool32x4;
+-
+-      case SimdType::Float64x2:
+-      case SimdType::Bool64x2:
+-        return SimdType::Bool64x2;
+-
+-      case SimdType::Count:
+-        break;
+-    }
+-    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type");
+-}
+-
+-// Get the number of lanes in a SIMD type.
+-inline unsigned
+-GetSimdLanes(SimdType t)
+-{
+-    switch(t) {
+-      case SimdType::Int8x16:
+-      case SimdType::Uint8x16:
+-      case SimdType::Bool8x16:
+-        return 16;
+-
+-      case SimdType::Int16x8:
+-      case SimdType::Uint16x8:
+-      case SimdType::Bool16x8:
+-        return 8;
+-
+-      case SimdType::Int32x4:
+-      case SimdType::Uint32x4:
+-      case SimdType::Float32x4:
+-      case SimdType::Bool32x4:
+-        return 4;
+-
+-      case SimdType::Float64x2:
+-      case SimdType::Bool64x2:
+-        return 2;
+-
+-      case SimdType::Count:
+-        break;
+-    }
+-    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type");
+-}
+-
+-// Complete set of SIMD operations.
+-//
+-// No SIMD types implement all of these operations.
+-//
+-// C++ defines keywords and/or/xor/not, so prepend Fn_ to all named functions to
+-// avoid clashes.
+-//
+-// Note: because of a gcc < v4.8's compiler bug, uint8_t can't be used as the
+-// storage class here. See bug 1243810. See also
+-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64037 .
+-enum class SimdOperation {
+-    // The constructor call. No Fn_ prefix here.
+-    Constructor,
+-
+-    // All the operations, except for casts.
+-#define DEFOP(x) Fn_##x,
+-    FORALL_SIMD_NONCAST_OP(DEFOP)
+-#undef DEFOP
+-
+-    // Int <-> Float conversions.
+-    Fn_fromInt32x4,
+-    Fn_fromUint32x4,
+-    Fn_fromFloat32x4,
+-
+-    // Bitcasts. One for each type with a memory representation.
+-    Fn_fromInt8x16Bits,
+-    Fn_fromInt16x8Bits,
+-    Fn_fromInt32x4Bits,
+-    Fn_fromUint8x16Bits,
+-    Fn_fromUint16x8Bits,
+-    Fn_fromUint32x4Bits,
+-    Fn_fromFloat32x4Bits,
+-    Fn_fromFloat64x2Bits,
+-
+-    Last = Fn_fromFloat64x2Bits
+-};
+-
+ // These classes implement the concept containing the following constraints:
+ // - requires typename Elem: this is the scalar lane type, stored in each lane
+ // of the SIMD vector.
+ // - requires static const unsigned lanes: this is the number of lanes (length)
+ // of the SIMD vector.
+ // - requires static const SimdType type: this is the SimdType enum value
+ // corresponding to the SIMD type.
+ // - requires static bool Cast(JSContext*, JS::HandleValue, Elem*): casts a
+diff --git a/js/src/builtin/SIMDConstants.h b/js/src/builtin/SIMDConstants.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/builtin/SIMDConstants.h
+@@ -0,0 +1,941 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++ * vim: set ts=8 sts=4 et sw=4 tw=99:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef builtin_SIMDConstants_h
++#define builtin_SIMDConstants_h
++
++#include "mozilla/Assertions.h"
++
++#include "builtin/TypedObjectConstants.h"
++
++// Bool8x16.
++#define BOOL8X16_UNARY_FUNCTION_LIST(V)                                               \
++  V(not, (UnaryFunc<Bool8x16, LogicalNot, Bool8x16>), 1)                              \
++  V(check, (UnaryFunc<Bool8x16, Identity, Bool8x16>), 1)                              \
++  V(splat, (FuncSplat<Bool8x16>), 1)                                                  \
++  V(allTrue, (AllTrue<Bool8x16>), 1)                                                  \
++  V(anyTrue, (AnyTrue<Bool8x16>), 1)
++
++#define BOOL8X16_BINARY_FUNCTION_LIST(V)                                              \
++  V(extractLane, (ExtractLane<Bool8x16>), 2)                                          \
++  V(and, (BinaryFunc<Bool8x16, And, Bool8x16>), 2)                                    \
++  V(or, (BinaryFunc<Bool8x16, Or, Bool8x16>), 2)                                      \
++  V(xor, (BinaryFunc<Bool8x16, Xor, Bool8x16>), 2)                                    \
++
++#define BOOL8X16_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Bool8x16>), 3)
++
++#define BOOL8X16_FUNCTION_LIST(V)                                                     \
++  BOOL8X16_UNARY_FUNCTION_LIST(V)                                                     \
++  BOOL8X16_BINARY_FUNCTION_LIST(V)                                                    \
++  BOOL8X16_TERNARY_FUNCTION_LIST(V)
++
++// Bool 16x8.
++#define BOOL16X8_UNARY_FUNCTION_LIST(V)                                               \
++  V(not, (UnaryFunc<Bool16x8, LogicalNot, Bool16x8>), 1)                              \
++  V(check, (UnaryFunc<Bool16x8, Identity, Bool16x8>), 1)                              \
++  V(splat, (FuncSplat<Bool16x8>), 1)                                                  \
++  V(allTrue, (AllTrue<Bool16x8>), 1)                                                  \
++  V(anyTrue, (AnyTrue<Bool16x8>), 1)
++
++#define BOOL16X8_BINARY_FUNCTION_LIST(V)                                              \
++  V(extractLane, (ExtractLane<Bool16x8>), 2)                                          \
++  V(and, (BinaryFunc<Bool16x8, And, Bool16x8>), 2)                                    \
++  V(or, (BinaryFunc<Bool16x8, Or, Bool16x8>), 2)                                      \
++  V(xor, (BinaryFunc<Bool16x8, Xor, Bool16x8>), 2)                                    \
++
++#define BOOL16X8_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Bool16x8>), 3)
++
++#define BOOL16X8_FUNCTION_LIST(V)                                                     \
++  BOOL16X8_UNARY_FUNCTION_LIST(V)                                                     \
++  BOOL16X8_BINARY_FUNCTION_LIST(V)                                                    \
++  BOOL16X8_TERNARY_FUNCTION_LIST(V)
++
++// Bool32x4.
++#define BOOL32X4_UNARY_FUNCTION_LIST(V)                                               \
++  V(not, (UnaryFunc<Bool32x4, LogicalNot, Bool32x4>), 1)                              \
++  V(check, (UnaryFunc<Bool32x4, Identity, Bool32x4>), 1)                              \
++  V(splat, (FuncSplat<Bool32x4>), 1)                                                  \
++  V(allTrue, (AllTrue<Bool32x4>), 1)                                                  \
++  V(anyTrue, (AnyTrue<Bool32x4>), 1)
++
++#define BOOL32X4_BINARY_FUNCTION_LIST(V)                                              \
++  V(extractLane, (ExtractLane<Bool32x4>), 2)                                          \
++  V(and, (BinaryFunc<Bool32x4, And, Bool32x4>), 2)                                    \
++  V(or, (BinaryFunc<Bool32x4, Or, Bool32x4>), 2)                                      \
++  V(xor, (BinaryFunc<Bool32x4, Xor, Bool32x4>), 2)                                    \
++
++#define BOOL32X4_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Bool32x4>), 3)
++
++#define BOOL32X4_FUNCTION_LIST(V)                                                     \
++  BOOL32X4_UNARY_FUNCTION_LIST(V)                                                     \
++  BOOL32X4_BINARY_FUNCTION_LIST(V)                                                    \
++  BOOL32X4_TERNARY_FUNCTION_LIST(V)
++
++// Bool64x2.
++#define BOOL64X2_UNARY_FUNCTION_LIST(V)                                               \
++  V(not, (UnaryFunc<Bool64x2, LogicalNot, Bool64x2>), 1)                              \
++  V(check, (UnaryFunc<Bool64x2, Identity, Bool64x2>), 1)                              \
++  V(splat, (FuncSplat<Bool64x2>), 1)                                                  \
++  V(allTrue, (AllTrue<Bool64x2>), 1)                                                  \
++  V(anyTrue, (AnyTrue<Bool64x2>), 1)
++
++#define BOOL64X2_BINARY_FUNCTION_LIST(V)                                              \
++  V(extractLane, (ExtractLane<Bool64x2>), 2)                                          \
++  V(and, (BinaryFunc<Bool64x2, And, Bool64x2>), 2)                                    \
++  V(or, (BinaryFunc<Bool64x2, Or, Bool64x2>), 2)                                      \
++  V(xor, (BinaryFunc<Bool64x2, Xor, Bool64x2>), 2)                                    \
++
++#define BOOL64X2_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Bool64x2>), 3)
++
++#define BOOL64X2_FUNCTION_LIST(V)                                                     \
++  BOOL64X2_UNARY_FUNCTION_LIST(V)                                                     \
++  BOOL64X2_BINARY_FUNCTION_LIST(V)                                                    \
++  BOOL64X2_TERNARY_FUNCTION_LIST(V)
++
++// Float32x4.
++#define FLOAT32X4_UNARY_FUNCTION_LIST(V)                                              \
++  V(abs, (UnaryFunc<Float32x4, Abs, Float32x4>), 1)                                   \
++  V(check, (UnaryFunc<Float32x4, Identity, Float32x4>), 1)                            \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1)                    \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Float32x4>), 1)                    \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Float32x4>), 1)                    \
++  V(fromInt32x4,       (FuncConvert<Int32x4,       Float32x4>), 1)                    \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Float32x4>), 1)                    \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Float32x4>), 1)                    \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Float32x4>), 1)                    \
++  V(fromUint32x4,      (FuncConvert<Uint32x4,      Float32x4>), 1)                    \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Float32x4>), 1)                    \
++  V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1)                                   \
++  V(reciprocalApproximation, (UnaryFunc<Float32x4, RecApprox, Float32x4>), 1)         \
++  V(reciprocalSqrtApproximation, (UnaryFunc<Float32x4, RecSqrtApprox, Float32x4>), 1) \
++  V(splat, (FuncSplat<Float32x4>), 1)                                                 \
++  V(sqrt, (UnaryFunc<Float32x4, Sqrt, Float32x4>), 1)
++
++#define FLOAT32X4_BINARY_FUNCTION_LIST(V)                                             \
++  V(add, (BinaryFunc<Float32x4, Add, Float32x4>), 2)                                  \
++  V(div, (BinaryFunc<Float32x4, Div, Float32x4>), 2)                                  \
++  V(equal, (CompareFunc<Float32x4, Equal, Bool32x4>), 2)                              \
++  V(extractLane, (ExtractLane<Float32x4>), 2)                                         \
++  V(greaterThan, (CompareFunc<Float32x4, GreaterThan, Bool32x4>), 2)                  \
++  V(greaterThanOrEqual, (CompareFunc<Float32x4, GreaterThanOrEqual, Bool32x4>), 2)    \
++  V(lessThan, (CompareFunc<Float32x4, LessThan, Bool32x4>), 2)                        \
++  V(lessThanOrEqual, (CompareFunc<Float32x4, LessThanOrEqual, Bool32x4>), 2)          \
++  V(load,  (Load<Float32x4, 4>), 2)                                                   \
++  V(load3, (Load<Float32x4, 3>), 2)                                                   \
++  V(load2, (Load<Float32x4, 2>), 2)                                                   \
++  V(load1, (Load<Float32x4, 1>), 2)                                                   \
++  V(max, (BinaryFunc<Float32x4, Maximum, Float32x4>), 2)                              \
++  V(maxNum, (BinaryFunc<Float32x4, MaxNum, Float32x4>), 2)                            \
++  V(min, (BinaryFunc<Float32x4, Minimum, Float32x4>), 2)                              \
++  V(minNum, (BinaryFunc<Float32x4, MinNum, Float32x4>), 2)                            \
++  V(mul, (BinaryFunc<Float32x4, Mul, Float32x4>), 2)                                  \
++  V(notEqual, (CompareFunc<Float32x4, NotEqual, Bool32x4>), 2)                        \
++  V(sub, (BinaryFunc<Float32x4, Sub, Float32x4>), 2)
++
++#define FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                            \
++  V(replaceLane, (ReplaceLane<Float32x4>), 3)                                         \
++  V(select, (Select<Float32x4, Bool32x4>), 3)                                         \
++  V(store,  (Store<Float32x4, 4>), 3)                                                 \
++  V(store3, (Store<Float32x4, 3>), 3)                                                 \
++  V(store2, (Store<Float32x4, 2>), 3)                                                 \
++  V(store1, (Store<Float32x4, 1>), 3)
++
++#define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)                                            \
++  V(swizzle, Swizzle<Float32x4>, 5)                                                   \
++  V(shuffle, Shuffle<Float32x4>, 6)
++
++#define FLOAT32X4_FUNCTION_LIST(V)                                                    \
++  FLOAT32X4_UNARY_FUNCTION_LIST(V)                                                    \
++  FLOAT32X4_BINARY_FUNCTION_LIST(V)                                                   \
++  FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                                  \
++  FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)
++
++// Float64x2.
++#define FLOAT64X2_UNARY_FUNCTION_LIST(V)                                              \
++  V(abs, (UnaryFunc<Float64x2, Abs, Float64x2>), 1)                                   \
++  V(check, (UnaryFunc<Float64x2, Identity, Float64x2>), 1)                            \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1)                    \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Float64x2>), 1)                    \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Float64x2>), 1)                    \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Float64x2>), 1)                    \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Float64x2>), 1)                    \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Float64x2>), 1)                    \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Float64x2>), 1)                    \
++  V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1)                                   \
++  V(reciprocalApproximation, (UnaryFunc<Float64x2, RecApprox, Float64x2>), 1)         \
++  V(reciprocalSqrtApproximation, (UnaryFunc<Float64x2, RecSqrtApprox, Float64x2>), 1) \
++  V(splat, (FuncSplat<Float64x2>), 1)                                                 \
++  V(sqrt, (UnaryFunc<Float64x2, Sqrt, Float64x2>), 1)
++
++#define FLOAT64X2_BINARY_FUNCTION_LIST(V)                                             \
++  V(add, (BinaryFunc<Float64x2, Add, Float64x2>), 2)                                  \
++  V(div, (BinaryFunc<Float64x2, Div, Float64x2>), 2)                                  \
++  V(equal, (CompareFunc<Float64x2, Equal, Bool64x2>), 2)                              \
++  V(extractLane, (ExtractLane<Float64x2>), 2)                                         \
++  V(greaterThan, (CompareFunc<Float64x2, GreaterThan, Bool64x2>), 2)                  \
++  V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual, Bool64x2>), 2)    \
++  V(lessThan, (CompareFunc<Float64x2, LessThan, Bool64x2>), 2)                        \
++  V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual, Bool64x2>), 2)          \
++  V(load,  (Load<Float64x2, 2>), 2)                                                   \
++  V(load1, (Load<Float64x2, 1>), 2)                                                   \
++  V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2)                              \
++  V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2)                            \
++  V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2)                              \
++  V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2)                            \
++  V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2)                                  \
++  V(notEqual, (CompareFunc<Float64x2, NotEqual, Bool64x2>), 2)                        \
++  V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2)
++
++#define FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                            \
++  V(replaceLane, (ReplaceLane<Float64x2>), 3)                                         \
++  V(select, (Select<Float64x2, Bool64x2>), 3)                                         \
++  V(store,  (Store<Float64x2, 2>), 3)                                                 \
++  V(store1, (Store<Float64x2, 1>), 3)
++
++#define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)                                            \
++  V(swizzle, Swizzle<Float64x2>, 3)                                                   \
++  V(shuffle, Shuffle<Float64x2>, 4)
++
++#define FLOAT64X2_FUNCTION_LIST(V)                                                    \
++  FLOAT64X2_UNARY_FUNCTION_LIST(V)                                                    \
++  FLOAT64X2_BINARY_FUNCTION_LIST(V)                                                   \
++  FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                                  \
++  FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)
++
++// Int8x16.
++#define INT8X16_UNARY_FUNCTION_LIST(V)                                                \
++  V(check, (UnaryFunc<Int8x16, Identity, Int8x16>), 1)                                \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int8x16>), 1)                      \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int8x16>), 1)                      \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Int8x16>), 1)                      \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Int8x16>), 1)                      \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Int8x16>), 1)                      \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Int8x16>), 1)                      \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Int8x16>), 1)                      \
++  V(neg, (UnaryFunc<Int8x16, Neg, Int8x16>), 1)                                       \
++  V(not, (UnaryFunc<Int8x16, Not, Int8x16>), 1)                                       \
++  V(splat, (FuncSplat<Int8x16>), 1)
++
++#define INT8X16_BINARY_FUNCTION_LIST(V)                                               \
++  V(add, (BinaryFunc<Int8x16, Add, Int8x16>), 2)                                      \
++  V(addSaturate, (BinaryFunc<Int8x16, AddSaturate, Int8x16>), 2)                      \
++  V(and, (BinaryFunc<Int8x16, And, Int8x16>), 2)                                      \
++  V(equal, (CompareFunc<Int8x16, Equal, Bool8x16>), 2)                                \
++  V(extractLane, (ExtractLane<Int8x16>), 2)                                           \
++  V(greaterThan, (CompareFunc<Int8x16, GreaterThan, Bool8x16>), 2)                    \
++  V(greaterThanOrEqual, (CompareFunc<Int8x16, GreaterThanOrEqual, Bool8x16>), 2)      \
++  V(lessThan, (CompareFunc<Int8x16, LessThan, Bool8x16>), 2)                          \
++  V(lessThanOrEqual, (CompareFunc<Int8x16, LessThanOrEqual, Bool8x16>), 2)            \
++  V(load, (Load<Int8x16, 16>), 2)                                                     \
++  V(mul, (BinaryFunc<Int8x16, Mul, Int8x16>), 2)                                      \
++  V(notEqual, (CompareFunc<Int8x16, NotEqual, Bool8x16>), 2)                          \
++  V(or, (BinaryFunc<Int8x16, Or, Int8x16>), 2)                                        \
++  V(sub, (BinaryFunc<Int8x16, Sub, Int8x16>), 2)                                      \
++  V(subSaturate, (BinaryFunc<Int8x16, SubSaturate, Int8x16>), 2)                      \
++  V(shiftLeftByScalar, (BinaryScalar<Int8x16, ShiftLeft>), 2)                         \
++  V(shiftRightByScalar, (BinaryScalar<Int8x16, ShiftRightArithmetic>), 2)             \
++  V(xor, (BinaryFunc<Int8x16, Xor, Int8x16>), 2)
++
++#define INT8X16_TERNARY_FUNCTION_LIST(V)                                              \
++  V(replaceLane, (ReplaceLane<Int8x16>), 3)                                           \
++  V(select, (Select<Int8x16, Bool8x16>), 3)                                           \
++  V(store, (Store<Int8x16, 16>), 3)
++
++#define INT8X16_SHUFFLE_FUNCTION_LIST(V)                                              \
++  V(swizzle, Swizzle<Int8x16>, 17)                                                    \
++  V(shuffle, Shuffle<Int8x16>, 18)
++
++#define INT8X16_FUNCTION_LIST(V)                                                      \
++  INT8X16_UNARY_FUNCTION_LIST(V)                                                      \
++  INT8X16_BINARY_FUNCTION_LIST(V)                                                     \
++  INT8X16_TERNARY_FUNCTION_LIST(V)                                                    \
++  INT8X16_SHUFFLE_FUNCTION_LIST(V)
++
++// Uint8x16.
++#define UINT8X16_UNARY_FUNCTION_LIST(V)                                               \
++  V(check, (UnaryFunc<Uint8x16, Identity, Uint8x16>), 1)                              \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint8x16>), 1)                     \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint8x16>), 1)                     \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Uint8x16>), 1)                     \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Uint8x16>), 1)                     \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Uint8x16>), 1)                     \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Uint8x16>), 1)                     \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Uint8x16>), 1)                     \
++  V(neg, (UnaryFunc<Uint8x16, Neg, Uint8x16>), 1)                                     \
++  V(not, (UnaryFunc<Uint8x16, Not, Uint8x16>), 1)                                     \
++  V(splat, (FuncSplat<Uint8x16>), 1)
++
++#define UINT8X16_BINARY_FUNCTION_LIST(V)                                              \
++  V(add, (BinaryFunc<Uint8x16, Add, Uint8x16>), 2)                                    \
++  V(addSaturate, (BinaryFunc<Uint8x16, AddSaturate, Uint8x16>), 2)                    \
++  V(and, (BinaryFunc<Uint8x16, And, Uint8x16>), 2)                                    \
++  V(equal, (CompareFunc<Uint8x16, Equal, Bool8x16>), 2)                               \
++  V(extractLane, (ExtractLane<Uint8x16>), 2)                                          \
++  V(greaterThan, (CompareFunc<Uint8x16, GreaterThan, Bool8x16>), 2)                   \
++  V(greaterThanOrEqual, (CompareFunc<Uint8x16, GreaterThanOrEqual, Bool8x16>), 2)     \
++  V(lessThan, (CompareFunc<Uint8x16, LessThan, Bool8x16>), 2)                         \
++  V(lessThanOrEqual, (CompareFunc<Uint8x16, LessThanOrEqual, Bool8x16>), 2)           \
++  V(load, (Load<Uint8x16, 16>), 2)                                                    \
++  V(mul, (BinaryFunc<Uint8x16, Mul, Uint8x16>), 2)                                    \
++  V(notEqual, (CompareFunc<Uint8x16, NotEqual, Bool8x16>), 2)                         \
++  V(or, (BinaryFunc<Uint8x16, Or, Uint8x16>), 2)                                      \
++  V(sub, (BinaryFunc<Uint8x16, Sub, Uint8x16>), 2)                                    \
++  V(subSaturate, (BinaryFunc<Uint8x16, SubSaturate, Uint8x16>), 2)                    \
++  V(shiftLeftByScalar, (BinaryScalar<Uint8x16, ShiftLeft>), 2)                        \
++  V(shiftRightByScalar, (BinaryScalar<Uint8x16, ShiftRightLogical>), 2)               \
++  V(xor, (BinaryFunc<Uint8x16, Xor, Uint8x16>), 2)
++
++#define UINT8X16_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Uint8x16>), 3)                                          \
++  V(select, (Select<Uint8x16, Bool8x16>), 3)                                          \
++  V(store, (Store<Uint8x16, 16>), 3)
++
++#define UINT8X16_SHUFFLE_FUNCTION_LIST(V)                                             \
++  V(swizzle, Swizzle<Uint8x16>, 17)                                                   \
++  V(shuffle, Shuffle<Uint8x16>, 18)
++
++#define UINT8X16_FUNCTION_LIST(V)                                                     \
++  UINT8X16_UNARY_FUNCTION_LIST(V)                                                     \
++  UINT8X16_BINARY_FUNCTION_LIST(V)                                                    \
++  UINT8X16_TERNARY_FUNCTION_LIST(V)                                                   \
++  UINT8X16_SHUFFLE_FUNCTION_LIST(V)
++
++// Int16x8.
++#define INT16X8_UNARY_FUNCTION_LIST(V)                                                \
++  V(check, (UnaryFunc<Int16x8, Identity, Int16x8>), 1)                                \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int16x8>), 1)                      \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int16x8>), 1)                      \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Int16x8>), 1)                      \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Int16x8>), 1)                      \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Int16x8>), 1)                      \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Int16x8>), 1)                      \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Int16x8>), 1)                      \
++  V(neg, (UnaryFunc<Int16x8, Neg, Int16x8>), 1)                                       \
++  V(not, (UnaryFunc<Int16x8, Not, Int16x8>), 1)                                       \
++  V(splat, (FuncSplat<Int16x8>), 1)
++
++#define INT16X8_BINARY_FUNCTION_LIST(V)                                               \
++  V(add, (BinaryFunc<Int16x8, Add, Int16x8>), 2)                                      \
++  V(addSaturate, (BinaryFunc<Int16x8, AddSaturate, Int16x8>), 2)                      \
++  V(and, (BinaryFunc<Int16x8, And, Int16x8>), 2)                                      \
++  V(equal, (CompareFunc<Int16x8, Equal, Bool16x8>), 2)                                \
++  V(extractLane, (ExtractLane<Int16x8>), 2)                                           \
++  V(greaterThan, (CompareFunc<Int16x8, GreaterThan, Bool16x8>), 2)                    \
++  V(greaterThanOrEqual, (CompareFunc<Int16x8, GreaterThanOrEqual, Bool16x8>), 2)      \
++  V(lessThan, (CompareFunc<Int16x8, LessThan, Bool16x8>), 2)                          \
++  V(lessThanOrEqual, (CompareFunc<Int16x8, LessThanOrEqual, Bool16x8>), 2)            \
++  V(load, (Load<Int16x8, 8>), 2)                                                      \
++  V(mul, (BinaryFunc<Int16x8, Mul, Int16x8>), 2)                                      \
++  V(notEqual, (CompareFunc<Int16x8, NotEqual, Bool16x8>), 2)                          \
++  V(or, (BinaryFunc<Int16x8, Or, Int16x8>), 2)                                        \
++  V(sub, (BinaryFunc<Int16x8, Sub, Int16x8>), 2)                                      \
++  V(subSaturate, (BinaryFunc<Int16x8, SubSaturate, Int16x8>), 2)                      \
++  V(shiftLeftByScalar, (BinaryScalar<Int16x8, ShiftLeft>), 2)                         \
++  V(shiftRightByScalar, (BinaryScalar<Int16x8, ShiftRightArithmetic>), 2)             \
++  V(xor, (BinaryFunc<Int16x8, Xor, Int16x8>), 2)
++
++#define INT16X8_TERNARY_FUNCTION_LIST(V)                                              \
++  V(replaceLane, (ReplaceLane<Int16x8>), 3)                                           \
++  V(select, (Select<Int16x8, Bool16x8>), 3)                                           \
++  V(store, (Store<Int16x8, 8>), 3)
++
++#define INT16X8_SHUFFLE_FUNCTION_LIST(V)                                              \
++  V(swizzle, Swizzle<Int16x8>, 9)                                                     \
++  V(shuffle, Shuffle<Int16x8>, 10)
++
++#define INT16X8_FUNCTION_LIST(V)                                                      \
++  INT16X8_UNARY_FUNCTION_LIST(V)                                                      \
++  INT16X8_BINARY_FUNCTION_LIST(V)                                                     \
++  INT16X8_TERNARY_FUNCTION_LIST(V)                                                    \
++  INT16X8_SHUFFLE_FUNCTION_LIST(V)
++
++// Uint16x8.
++#define UINT16X8_UNARY_FUNCTION_LIST(V)                                               \
++  V(check, (UnaryFunc<Uint16x8, Identity, Uint16x8>), 1)                              \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint16x8>), 1)                     \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint16x8>), 1)                     \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Uint16x8>), 1)                     \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Uint16x8>), 1)                     \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Uint16x8>), 1)                     \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Uint16x8>), 1)                     \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Uint16x8>), 1)                     \
++  V(neg, (UnaryFunc<Uint16x8, Neg, Uint16x8>), 1)                                     \
++  V(not, (UnaryFunc<Uint16x8, Not, Uint16x8>), 1)                                     \
++  V(splat, (FuncSplat<Uint16x8>), 1)
++
++#define UINT16X8_BINARY_FUNCTION_LIST(V)                                              \
++  V(add, (BinaryFunc<Uint16x8, Add, Uint16x8>), 2)                                    \
++  V(addSaturate, (BinaryFunc<Uint16x8, AddSaturate, Uint16x8>), 2)                    \
++  V(and, (BinaryFunc<Uint16x8, And, Uint16x8>), 2)                                    \
++  V(equal, (CompareFunc<Uint16x8, Equal, Bool16x8>), 2)                               \
++  V(extractLane, (ExtractLane<Uint16x8>), 2)                                          \
++  V(greaterThan, (CompareFunc<Uint16x8, GreaterThan, Bool16x8>), 2)                   \
++  V(greaterThanOrEqual, (CompareFunc<Uint16x8, GreaterThanOrEqual, Bool16x8>), 2)     \
++  V(lessThan, (CompareFunc<Uint16x8, LessThan, Bool16x8>), 2)                         \
++  V(lessThanOrEqual, (CompareFunc<Uint16x8, LessThanOrEqual, Bool16x8>), 2)           \
++  V(load, (Load<Uint16x8, 8>), 2)                                                     \
++  V(mul, (BinaryFunc<Uint16x8, Mul, Uint16x8>), 2)                                    \
++  V(notEqual, (CompareFunc<Uint16x8, NotEqual, Bool16x8>), 2)                         \
++  V(or, (BinaryFunc<Uint16x8, Or, Uint16x8>), 2)                                      \
++  V(sub, (BinaryFunc<Uint16x8, Sub, Uint16x8>), 2)                                    \
++  V(subSaturate, (BinaryFunc<Uint16x8, SubSaturate, Uint16x8>), 2)                    \
++  V(shiftLeftByScalar, (BinaryScalar<Uint16x8, ShiftLeft>), 2)                        \
++  V(shiftRightByScalar, (BinaryScalar<Uint16x8, ShiftRightLogical>), 2)               \
++  V(xor, (BinaryFunc<Uint16x8, Xor, Uint16x8>), 2)
++
++#define UINT16X8_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Uint16x8>), 3)                                          \
++  V(select, (Select<Uint16x8, Bool16x8>), 3)                                          \
++  V(store, (Store<Uint16x8, 8>), 3)
++
++#define UINT16X8_SHUFFLE_FUNCTION_LIST(V)                                             \
++  V(swizzle, Swizzle<Uint16x8>, 9)                                                    \
++  V(shuffle, Shuffle<Uint16x8>, 10)
++
++#define UINT16X8_FUNCTION_LIST(V)                                                     \
++  UINT16X8_UNARY_FUNCTION_LIST(V)                                                     \
++  UINT16X8_BINARY_FUNCTION_LIST(V)                                                    \
++  UINT16X8_TERNARY_FUNCTION_LIST(V)                                                   \
++  UINT16X8_SHUFFLE_FUNCTION_LIST(V)
++
++// Int32x4.
++#define INT32X4_UNARY_FUNCTION_LIST(V)                                                \
++  V(check, (UnaryFunc<Int32x4, Identity, Int32x4>), 1)                                \
++  V(fromFloat32x4,     (FuncConvert<Float32x4,     Int32x4>), 1)                      \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1)                      \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1)                      \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Int32x4>), 1)                      \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Int32x4>), 1)                      \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Int32x4>), 1)                      \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Int32x4>), 1)                      \
++  V(fromUint32x4Bits,  (FuncConvertBits<Uint32x4,  Int32x4>), 1)                      \
++  V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1)                                       \
++  V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1)                                       \
++  V(splat, (FuncSplat<Int32x4>), 0)
++
++#define INT32X4_BINARY_FUNCTION_LIST(V)                                               \
++  V(add, (BinaryFunc<Int32x4, Add, Int32x4>), 2)                                      \
++  V(and, (BinaryFunc<Int32x4, And, Int32x4>), 2)                                      \
++  V(equal, (CompareFunc<Int32x4, Equal, Bool32x4>), 2)                                \
++  V(extractLane, (ExtractLane<Int32x4>), 2)                                           \
++  V(greaterThan, (CompareFunc<Int32x4, GreaterThan, Bool32x4>), 2)                    \
++  V(greaterThanOrEqual, (CompareFunc<Int32x4, GreaterThanOrEqual, Bool32x4>), 2)      \
++  V(lessThan, (CompareFunc<Int32x4, LessThan, Bool32x4>), 2)                          \
++  V(lessThanOrEqual, (CompareFunc<Int32x4, LessThanOrEqual, Bool32x4>), 2)            \
++  V(load,  (Load<Int32x4, 4>), 2)                                                     \
++  V(load3, (Load<Int32x4, 3>), 2)                                                     \
++  V(load2, (Load<Int32x4, 2>), 2)                                                     \
++  V(load1, (Load<Int32x4, 1>), 2)                                                     \
++  V(mul, (BinaryFunc<Int32x4, Mul, Int32x4>), 2)                                      \
++  V(notEqual, (CompareFunc<Int32x4, NotEqual, Bool32x4>), 2)                          \
++  V(or, (BinaryFunc<Int32x4, Or, Int32x4>), 2)                                        \
++  V(sub, (BinaryFunc<Int32x4, Sub, Int32x4>), 2)                                      \
++  V(shiftLeftByScalar, (BinaryScalar<Int32x4, ShiftLeft>), 2)                         \
++  V(shiftRightByScalar, (BinaryScalar<Int32x4, ShiftRightArithmetic>), 2)             \
++  V(xor, (BinaryFunc<Int32x4, Xor, Int32x4>), 2)
++
++#define INT32X4_TERNARY_FUNCTION_LIST(V)                                              \
++  V(replaceLane, (ReplaceLane<Int32x4>), 3)                                           \
++  V(select, (Select<Int32x4, Bool32x4>), 3)                                           \
++  V(store,  (Store<Int32x4, 4>), 3)                                                   \
++  V(store3, (Store<Int32x4, 3>), 3)                                                   \
++  V(store2, (Store<Int32x4, 2>), 3)                                                   \
++  V(store1, (Store<Int32x4, 1>), 3)
++
++#define INT32X4_SHUFFLE_FUNCTION_LIST(V)                                              \
++  V(swizzle, Swizzle<Int32x4>, 5)                                                     \
++  V(shuffle, Shuffle<Int32x4>, 6)
++
++#define INT32X4_FUNCTION_LIST(V)                                                      \
++  INT32X4_UNARY_FUNCTION_LIST(V)                                                      \
++  INT32X4_BINARY_FUNCTION_LIST(V)                                                     \
++  INT32X4_TERNARY_FUNCTION_LIST(V)                                                    \
++  INT32X4_SHUFFLE_FUNCTION_LIST(V)
++
++// Uint32x4.
++#define UINT32X4_UNARY_FUNCTION_LIST(V)                                               \
++  V(check, (UnaryFunc<Uint32x4, Identity, Uint32x4>), 1)                              \
++  V(fromFloat32x4,     (FuncConvert<Float32x4,     Uint32x4>), 1)                     \
++  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint32x4>), 1)                     \
++  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint32x4>), 1)                     \
++  V(fromInt8x16Bits,   (FuncConvertBits<Int8x16,   Uint32x4>), 1)                     \
++  V(fromInt16x8Bits,   (FuncConvertBits<Int16x8,   Uint32x4>), 1)                     \
++  V(fromInt32x4Bits,   (FuncConvertBits<Int32x4,   Uint32x4>), 1)                     \
++  V(fromUint8x16Bits,  (FuncConvertBits<Uint8x16,  Uint32x4>), 1)                     \
++  V(fromUint16x8Bits,  (FuncConvertBits<Uint16x8,  Uint32x4>), 1)                     \
++  V(neg, (UnaryFunc<Uint32x4, Neg, Uint32x4>), 1)                                     \
++  V(not, (UnaryFunc<Uint32x4, Not, Uint32x4>), 1)                                     \
++  V(splat, (FuncSplat<Uint32x4>), 0)
++
++#define UINT32X4_BINARY_FUNCTION_LIST(V)                                              \
++  V(add, (BinaryFunc<Uint32x4, Add, Uint32x4>), 2)                                    \
++  V(and, (BinaryFunc<Uint32x4, And, Uint32x4>), 2)                                    \
++  V(equal, (CompareFunc<Uint32x4, Equal, Bool32x4>), 2)                               \
++  V(extractLane, (ExtractLane<Uint32x4>), 2)                                          \
++  V(greaterThan, (CompareFunc<Uint32x4, GreaterThan, Bool32x4>), 2)                   \
++  V(greaterThanOrEqual, (CompareFunc<Uint32x4, GreaterThanOrEqual, Bool32x4>), 2)     \
++  V(lessThan, (CompareFunc<Uint32x4, LessThan, Bool32x4>), 2)                         \
++  V(lessThanOrEqual, (CompareFunc<Uint32x4, LessThanOrEqual, Bool32x4>), 2)           \
++  V(load,  (Load<Uint32x4, 4>), 2)                                                    \
++  V(load3, (Load<Uint32x4, 3>), 2)                                                    \
++  V(load2, (Load<Uint32x4, 2>), 2)                                                    \
++  V(load1, (Load<Uint32x4, 1>), 2)                                                    \
++  V(mul, (BinaryFunc<Uint32x4, Mul, Uint32x4>), 2)                                    \
++  V(notEqual, (CompareFunc<Uint32x4, NotEqual, Bool32x4>), 2)                         \
++  V(or, (BinaryFunc<Uint32x4, Or, Uint32x4>), 2)                                      \
++  V(sub, (BinaryFunc<Uint32x4, Sub, Uint32x4>), 2)                                    \
++  V(shiftLeftByScalar, (BinaryScalar<Uint32x4, ShiftLeft>), 2)                        \
++  V(shiftRightByScalar, (BinaryScalar<Uint32x4, ShiftRightLogical>), 2)               \
++  V(xor, (BinaryFunc<Uint32x4, Xor, Uint32x4>), 2)
++
++#define UINT32X4_TERNARY_FUNCTION_LIST(V)                                             \
++  V(replaceLane, (ReplaceLane<Uint32x4>), 3)                                          \
++  V(select, (Select<Uint32x4, Bool32x4>), 3)                                          \
++  V(store,  (Store<Uint32x4, 4>), 3)                                                  \
++  V(store3, (Store<Uint32x4, 3>), 3)                                                  \
++  V(store2, (Store<Uint32x4, 2>), 3)                                                  \
++  V(store1, (Store<Uint32x4, 1>), 3)
++
++#define UINT32X4_SHUFFLE_FUNCTION_LIST(V)                                             \
++  V(swizzle, Swizzle<Uint32x4>, 5)                                                    \
++  V(shuffle, Shuffle<Uint32x4>, 6)
++
++#define UINT32X4_FUNCTION_LIST(V)                                                     \
++  UINT32X4_UNARY_FUNCTION_LIST(V)                                                     \
++  UINT32X4_BINARY_FUNCTION_LIST(V)                                                    \
++  UINT32X4_TERNARY_FUNCTION_LIST(V)                                                   \
++  UINT32X4_SHUFFLE_FUNCTION_LIST(V)
++
++/*
++ * The FOREACH macros below partition all of the SIMD operations into disjoint
++ * sets.
++ */
++
++// Operations available on all SIMD types. Mixed arity.
++#define FOREACH_COMMON_SIMD_OP(_)     \
++    _(extractLane)                    \
++    _(replaceLane)                    \
++    _(check)                          \
++    _(splat)
++
++// Lanewise operations available on numeric SIMD types.
++// Include lane-wise select here since it is not arithmetic and defined on
++// numeric types too.
++#define FOREACH_LANE_SIMD_OP(_)       \
++    _(select)                         \
++    _(swizzle)                        \
++    _(shuffle)
++
++// Memory operations available on numeric SIMD types.
++#define FOREACH_MEMORY_SIMD_OP(_)     \
++    _(load)                           \
++    _(store)
++
++// Memory operations available on numeric X4 SIMD types.
++#define FOREACH_MEMORY_X4_SIMD_OP(_)  \
++    _(load1)                          \
++    _(load2)                          \
++    _(load3)                          \
++    _(store1)                         \
++    _(store2)                         \
++    _(store3)
++
++// Unary operations on Bool vectors.
++#define FOREACH_BOOL_SIMD_UNOP(_)     \
++    _(allTrue)                        \
++    _(anyTrue)
++
++// Unary bitwise SIMD operators defined on all integer and boolean SIMD types.
++#define FOREACH_BITWISE_SIMD_UNOP(_)  \
++    _(not)
++
++// Binary bitwise SIMD operators defined on all integer and boolean SIMD types.
++#define FOREACH_BITWISE_SIMD_BINOP(_) \
++    _(and)                            \
++    _(or)                             \
++    _(xor)
++
++// Bitwise shifts defined on integer SIMD types.
++#define FOREACH_SHIFT_SIMD_OP(_)      \
++    _(shiftLeftByScalar)              \
++    _(shiftRightByScalar)
++
++// Unary arithmetic operators defined on numeric SIMD types.
++#define FOREACH_NUMERIC_SIMD_UNOP(_)  \
++    _(neg)
++
++// Binary arithmetic operators defined on numeric SIMD types.
++#define FOREACH_NUMERIC_SIMD_BINOP(_) \
++    _(add)                            \
++    _(sub)                            \
++    _(mul)
++
++// Unary arithmetic operators defined on floating point SIMD types.
++#define FOREACH_FLOAT_SIMD_UNOP(_)    \
++    _(abs)                            \
++    _(sqrt)                           \
++    _(reciprocalApproximation)        \
++    _(reciprocalSqrtApproximation)
++
++// Binary arithmetic operators defined on floating point SIMD types.
++#define FOREACH_FLOAT_SIMD_BINOP(_)   \
++    _(div)                            \
++    _(max)                            \
++    _(min)                            \
++    _(maxNum)                         \
++    _(minNum)
++
++// Binary operations on small integer (< 32 bits) vectors.
++#define FOREACH_SMINT_SIMD_BINOP(_)   \
++    _(addSaturate)                    \
++    _(subSaturate)
++
++// Comparison operators defined on numeric SIMD types.
++#define FOREACH_COMP_SIMD_OP(_)       \
++    _(lessThan)                       \
++    _(lessThanOrEqual)                \
++    _(equal)                          \
++    _(notEqual)                       \
++    _(greaterThan)                    \
++    _(greaterThanOrEqual)
++
++/*
++ * All SIMD operations, excluding casts.
++ */
++#define FORALL_SIMD_NONCAST_OP(_)     \
++    FOREACH_COMMON_SIMD_OP(_)         \
++    FOREACH_LANE_SIMD_OP(_)           \
++    FOREACH_MEMORY_SIMD_OP(_)         \
++    FOREACH_MEMORY_X4_SIMD_OP(_)      \
++    FOREACH_BOOL_SIMD_UNOP(_)         \
++    FOREACH_BITWISE_SIMD_UNOP(_)      \
++    FOREACH_BITWISE_SIMD_BINOP(_)     \
++    FOREACH_SHIFT_SIMD_OP(_)          \
++    FOREACH_NUMERIC_SIMD_UNOP(_)      \
++    FOREACH_NUMERIC_SIMD_BINOP(_)     \
++    FOREACH_FLOAT_SIMD_UNOP(_)        \
++    FOREACH_FLOAT_SIMD_BINOP(_)       \
++    FOREACH_SMINT_SIMD_BINOP(_)       \
++    FOREACH_COMP_SIMD_OP(_)
++
++/*
++ * All operations on integer SIMD types, excluding casts and
++ * FOREACH_MEMORY_X4_OP.
++ */
++#define FORALL_INT_SIMD_OP(_)         \
++    FOREACH_COMMON_SIMD_OP(_)         \
++    FOREACH_LANE_SIMD_OP(_)           \
++    FOREACH_MEMORY_SIMD_OP(_)         \
++    FOREACH_BITWISE_SIMD_UNOP(_)      \
++    FOREACH_BITWISE_SIMD_BINOP(_)     \
++    FOREACH_SHIFT_SIMD_OP(_)          \
++    FOREACH_NUMERIC_SIMD_UNOP(_)      \
++    FOREACH_NUMERIC_SIMD_BINOP(_)     \
++    FOREACH_COMP_SIMD_OP(_)
++
++/*
++ * All operations on floating point SIMD types, excluding casts and
++ * FOREACH_MEMORY_X4_OP.
++ */
++#define FORALL_FLOAT_SIMD_OP(_)       \
++    FOREACH_COMMON_SIMD_OP(_)         \
++    FOREACH_LANE_SIMD_OP(_)           \
++    FOREACH_MEMORY_SIMD_OP(_)         \
++    FOREACH_NUMERIC_SIMD_UNOP(_)      \
++    FOREACH_NUMERIC_SIMD_BINOP(_)     \
++    FOREACH_FLOAT_SIMD_UNOP(_)        \
++    FOREACH_FLOAT_SIMD_BINOP(_)       \
++    FOREACH_COMP_SIMD_OP(_)
++
++/*
++ * All operations on Bool SIMD types.
++ *
++ * These types don't have casts, so no need to specialize.
++ */
++#define FORALL_BOOL_SIMD_OP(_)        \
++    FOREACH_COMMON_SIMD_OP(_)         \
++    FOREACH_BOOL_SIMD_UNOP(_)         \
++    FOREACH_BITWISE_SIMD_UNOP(_)      \
++    FOREACH_BITWISE_SIMD_BINOP(_)
++
++/*
++ * The sets of cast operations are listed per type below.
++ *
++ * These sets are not disjoint.
++ */
++
++#define FOREACH_INT8X16_SIMD_CAST(_)  \
++    _(fromFloat32x4Bits)              \
++    _(fromFloat64x2Bits)              \
++    _(fromInt16x8Bits)                \
++    _(fromInt32x4Bits)
++
++#define FOREACH_INT16X8_SIMD_CAST(_)  \
++    _(fromFloat32x4Bits)              \
++    _(fromFloat64x2Bits)              \
++    _(fromInt8x16Bits)                \
++    _(fromInt32x4Bits)
++
++#define FOREACH_INT32X4_SIMD_CAST(_)  \
++    _(fromFloat32x4)                  \
++    _(fromFloat32x4Bits)              \
++    _(fromFloat64x2Bits)              \
++    _(fromInt8x16Bits)                \
++    _(fromInt16x8Bits)
++
++#define FOREACH_FLOAT32X4_SIMD_CAST(_)\
++    _(fromFloat64x2Bits)              \
++    _(fromInt8x16Bits)                \
++    _(fromInt16x8Bits)                \
++    _(fromInt32x4)                    \
++    _(fromInt32x4Bits)
++
++#define FOREACH_FLOAT64X2_SIMD_CAST(_)\
++    _(fromFloat32x4Bits)              \
++    _(fromInt8x16Bits)                \
++    _(fromInt16x8Bits)                \
++    _(fromInt32x4Bits)
++
++// All operations on Int32x4.
++#define FORALL_INT32X4_SIMD_OP(_)     \
++    FORALL_INT_SIMD_OP(_)             \
++    FOREACH_MEMORY_X4_SIMD_OP(_)      \
++    FOREACH_INT32X4_SIMD_CAST(_)
++
++// All operations on Float32X4
++#define FORALL_FLOAT32X4_SIMD_OP(_)   \
++    FORALL_FLOAT_SIMD_OP(_)           \
++    FOREACH_MEMORY_X4_SIMD_OP(_)      \
++    FOREACH_FLOAT32X4_SIMD_CAST(_)
++
++/*
++ * All SIMD operations assuming only 32x4 types exist.
++ * This is used in the current asm.js impl.
++ */
++#define FORALL_SIMD_ASMJS_OP(_)       \
++    FORALL_SIMD_NONCAST_OP(_)         \
++    _(fromFloat32x4)                  \
++    _(fromFloat32x4Bits)              \
++    _(fromInt8x16Bits)                \
++    _(fromInt16x8Bits)                \
++    _(fromInt32x4)                    \
++    _(fromInt32x4Bits)                \
++    _(fromUint8x16Bits)               \
++    _(fromUint16x8Bits)               \
++    _(fromUint32x4)                   \
++    _(fromUint32x4Bits)
++
++// All operations on Int8x16 or Uint8x16 in the asm.js world.
++// Note: this does not include conversions and casts to/from Uint8x16 because
++// this list is shared between Int8x16 and Uint8x16.
++#define FORALL_INT8X16_ASMJS_OP(_)    \
++    FORALL_INT_SIMD_OP(_)             \
++    FOREACH_SMINT_SIMD_BINOP(_)       \
++    _(fromInt16x8Bits)                \
++    _(fromInt32x4Bits)                \
++    _(fromFloat32x4Bits)
++
++// All operations on Int16x8 or Uint16x8 in the asm.js world.
++// Note: this does not include conversions and casts to/from Uint16x8 because
++// this list is shared between Int16x8 and Uint16x8.
++#define FORALL_INT16X8_ASMJS_OP(_)    \
++    FORALL_INT_SIMD_OP(_)             \
++    FOREACH_SMINT_SIMD_BINOP(_)       \
++    _(fromInt8x16Bits)                \
++    _(fromInt32x4Bits)                \
++    _(fromFloat32x4Bits)
++
++// All operations on Int32x4 or Uint32x4 in the asm.js world.
++// Note: this does not include conversions and casts to/from Uint32x4 because
++// this list is shared between Int32x4 and Uint32x4.
++#define FORALL_INT32X4_ASMJS_OP(_)    \
++    FORALL_INT_SIMD_OP(_)             \
++    FOREACH_MEMORY_X4_SIMD_OP(_)      \
++    _(fromInt8x16Bits)                \
++    _(fromInt16x8Bits)                \
++    _(fromFloat32x4)                  \
++    _(fromFloat32x4Bits)
++
++// All operations on Float32X4 in the asm.js world.
++#define FORALL_FLOAT32X4_ASMJS_OP(_)  \
++    FORALL_FLOAT_SIMD_OP(_)           \
++    FOREACH_MEMORY_X4_SIMD_OP(_)      \
++    _(fromInt8x16Bits)                \
++    _(fromInt16x8Bits)                \
++    _(fromInt32x4Bits)                \
++    _(fromInt32x4)                    \
++    _(fromUint32x4)
++
++namespace js {
++
++// Complete set of SIMD types.
++// It must be kept in sync with the enumeration of values in
++// TypedObjectConstants.h; in particular we need to ensure that Count is
++// appropriately set with respect to the number of actual types.
++enum class SimdType {
++    Int8x16   = JS_SIMDTYPEREPR_INT8X16,
++    Int16x8   = JS_SIMDTYPEREPR_INT16X8,
++    Int32x4   = JS_SIMDTYPEREPR_INT32X4,
++    Uint8x16  = JS_SIMDTYPEREPR_UINT8X16,
++    Uint16x8  = JS_SIMDTYPEREPR_UINT16X8,
++    Uint32x4  = JS_SIMDTYPEREPR_UINT32X4,
++    Float32x4 = JS_SIMDTYPEREPR_FLOAT32X4,
++    Float64x2 = JS_SIMDTYPEREPR_FLOAT64X2,
++    Bool8x16  = JS_SIMDTYPEREPR_BOOL8X16,
++    Bool16x8  = JS_SIMDTYPEREPR_BOOL16X8,
++    Bool32x4  = JS_SIMDTYPEREPR_BOOL32X4,
++    Bool64x2  = JS_SIMDTYPEREPR_BOOL64X2,
++    Count
++};
++
++// The integer SIMD types have a lot of operations that do the exact same thing
++// for signed and unsigned integer types. Sometimes it is simpler to treat
++// signed and unsigned integer SIMD types as the same type, using a SimdSign to
++// distinguish the few cases where there is a difference.
++enum class SimdSign {
++    // Signedness is not applicable to this type. (i.e., Float or Bool).
++    NotApplicable,
++    // Treat as an unsigned integer with a range 0 .. 2^N-1.
++    Unsigned,
++    // Treat as a signed integer in two's complement encoding.
++    Signed,
++};
++
++// Get the signedness of a SIMD type.
++inline SimdSign
++GetSimdSign(SimdType t)
++{
++    switch(t) {
++      case SimdType::Int8x16:
++      case SimdType::Int16x8:
++      case SimdType::Int32x4:
++        return SimdSign::Signed;
++
++      case SimdType::Uint8x16:
++      case SimdType::Uint16x8:
++      case SimdType::Uint32x4:
++        return SimdSign::Unsigned;
++
++      default:
++        return SimdSign::NotApplicable;
++    }
++}
++
++inline bool
++IsSignedIntSimdType(SimdType type)
++{
++    return GetSimdSign(type) == SimdSign::Signed;
++}
++
++// Get the boolean SIMD type with the same shape as t.
++//
++// This is the result type of a comparison operation, and it can also be used to
++// identify the geometry of a SIMD type.
++inline SimdType
++GetBooleanSimdType(SimdType t)
++{
++    switch(t) {
++      case SimdType::Int8x16:
++      case SimdType::Uint8x16:
++      case SimdType::Bool8x16:
++        return SimdType::Bool8x16;
++
++      case SimdType::Int16x8:
++      case SimdType::Uint16x8:
++      case SimdType::Bool16x8:
++        return SimdType::Bool16x8;
++
++      case SimdType::Int32x4:
++      case SimdType::Uint32x4:
++      case SimdType::Float32x4:
++      case SimdType::Bool32x4:
++        return SimdType::Bool32x4;
++
++      case SimdType::Float64x2:
++      case SimdType::Bool64x2:
++        return SimdType::Bool64x2;
++
++      case SimdType::Count:
++        break;
++    }
++    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type");
++}
++
++// Get the number of lanes in a SIMD type.
++inline unsigned
++GetSimdLanes(SimdType t)
++{
++    switch(t) {
++      case SimdType::Int8x16:
++      case SimdType::Uint8x16:
++      case SimdType::Bool8x16:
++        return 16;
++
++      case SimdType::Int16x8:
++      case SimdType::Uint16x8:
++      case SimdType::Bool16x8:
++        return 8;
++
++      case SimdType::Int32x4:
++      case SimdType::Uint32x4:
++      case SimdType::Float32x4:
++      case SimdType::Bool32x4:
++        return 4;
++
++      case SimdType::Float64x2:
++      case SimdType::Bool64x2:
++        return 2;
++
++      case SimdType::Count:
++        break;
++    }
++    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type");
++}
++
++// Complete set of SIMD operations.
++//
++// No SIMD types implement all of these operations.
++//
++// C++ defines keywords and/or/xor/not, so prepend Fn_ to all named functions to
++// avoid clashes.
++//
++// Note: because of a gcc < v4.8's compiler bug, uint8_t can't be used as the
++// storage class here. See bug 1243810. See also
++// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64037 .
++enum class SimdOperation {
++    // The constructor call. No Fn_ prefix here.
++    Constructor,
++
++    // All the operations, except for casts.
++#define DEFOP(x) Fn_##x,
++    FORALL_SIMD_NONCAST_OP(DEFOP)
++#undef DEFOP
++
++    // Int <-> Float conversions.
++    Fn_fromInt32x4,
++    Fn_fromUint32x4,
++    Fn_fromFloat32x4,
++
++    // Bitcasts. One for each type with a memory representation.
++    Fn_fromInt8x16Bits,
++    Fn_fromInt16x8Bits,
++    Fn_fromInt32x4Bits,
++    Fn_fromUint8x16Bits,
++    Fn_fromUint16x8Bits,
++    Fn_fromUint32x4Bits,
++    Fn_fromFloat32x4Bits,
++    Fn_fromFloat64x2Bits,
++
++    Last = Fn_fromFloat64x2Bits
++};
++
++} // namespace js
++
++#endif /* builtin_SIMDConstants_h */
+diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
+--- a/js/src/builtin/TypedObject.cpp
++++ b/js/src/builtin/TypedObject.cpp
+@@ -6,17 +6,17 @@
+ 
+ #include "builtin/TypedObject-inl.h"
+ 
+ #include "mozilla/Casting.h"
+ #include "mozilla/CheckedInt.h"
+ 
+ #include "jsutil.h"
+ 
+-#include "builtin/SIMD.h"
++#include "builtin/SIMDConstants.h"
+ #include "gc/Marking.h"
+ #include "js/Vector.h"
+ #include "util/StringBuffer.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSFunction.h"
+ #include "vm/SelfHosting.h"
+ #include "vm/StringType.h"
+diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
+--- a/js/src/jit/BaselineIC.cpp
++++ b/js/src/jit/BaselineIC.cpp
+@@ -9,17 +9,17 @@
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/TemplateLib.h"
+ 
+ #include "jsfriendapi.h"
+ #include "jslibmath.h"
+ #include "jstypes.h"
+ 
+ #include "builtin/Eval.h"
+-#include "builtin/SIMD.h"
++#include "builtin/SIMDConstants.h"
+ #include "gc/Policy.h"
+ #include "jit/BaselineCacheIRCompiler.h"
+ #include "jit/BaselineDebugModeOSR.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/JitSpewer.h"
+ #include "jit/Linker.h"
+ #include "jit/Lowering.h"
+diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp
+--- a/js/src/jit/MCallOptimize.cpp
++++ b/js/src/jit/MCallOptimize.cpp
+@@ -10,17 +10,17 @@
+ 
+ #include "builtin/AtomicsObject.h"
+ #include "builtin/intl/Collator.h"
+ #include "builtin/intl/DateTimeFormat.h"
+ #include "builtin/intl/NumberFormat.h"
+ #include "builtin/intl/PluralRules.h"
+ #include "builtin/intl/RelativeTimeFormat.h"
+ #include "builtin/MapObject.h"
+-#include "builtin/SIMD.h"
++#include "builtin/SIMDConstants.h"
+ #include "builtin/String.h"
+ #include "builtin/TestingFunctions.h"
+ #include "builtin/TypedObject.h"
+ #include "jit/BaselineInspector.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/IonBuilder.h"
+ #include "jit/Lowering.h"
+ #include "jit/MIR.h"
+diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
+--- a/js/src/jit/MIR.cpp
++++ b/js/src/jit/MIR.cpp
+@@ -12,16 +12,17 @@
+ #include "mozilla/IntegerPrintfMacros.h"
+ #include "mozilla/MathAlgorithms.h"
+ 
+ #include <ctype.h>
+ 
+ #include "jslibmath.h"
+ 
+ #include "builtin/RegExp.h"
++#include "builtin/SIMD.h"
+ #include "builtin/String.h"
+ #include "jit/AtomicOperations.h"
+ #include "jit/BaselineInspector.h"
+ #include "jit/IonBuilder.h"
+ #include "jit/JitSpewer.h"
+ #include "jit/MIRGraph.h"
+ #include "jit/RangeAnalysis.h"
+ #include "js/Conversions.h"
+diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
+--- a/js/src/jit/MIR.h
++++ b/js/src/jit/MIR.h
+@@ -12,17 +12,17 @@
+ #ifndef jit_MIR_h
+ #define jit_MIR_h
+ 
+ #include "mozilla/Alignment.h"
+ #include "mozilla/Array.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/MacroForEach.h"
+ 
+-#include "builtin/SIMD.h"
++#include "builtin/SIMDConstants.h"
+ #include "jit/AtomicOp.h"
+ #include "jit/BaselineIC.h"
+ #include "jit/FixedList.h"
+ #include "jit/InlineList.h"
+ #include "jit/JitAllocPolicy.h"
+ #include "jit/MacroAssembler.h"
+ #include "jit/MOpcodes.h"
+ #include "jit/TypedObjectPrediction.h"
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -38,17 +38,17 @@
+ #include "builtin/JSON.h"
+ #include "builtin/MapObject.h"
+ #include "builtin/Promise.h"
+ #include "builtin/RegExp.h"
+ #include "builtin/Stream.h"
+ #include "builtin/String.h"
+ #include "builtin/Symbol.h"
+ #ifdef ENABLE_SIMD
+-# include "builtin/SIMD.h"
++# include "builtin/SIMDConstants.h"
+ #endif
+ #ifdef ENABLE_BINARYDATA
+ # include "builtin/TypedObject.h"
+ #endif
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/FullParseHandler.h"  // for JS_BufferIsCompileableUnit
+ #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
+ #include "gc/FreeOp.h"
+diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h
+--- a/js/src/wasm/WasmBinaryConstants.h
++++ b/js/src/wasm/WasmBinaryConstants.h
+@@ -14,17 +14,17 @@
+  * 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_h
+ #define wasm_binary_h
+ 
+-#include "builtin/SIMD.h"
++#include "builtin/SIMDConstants.h"
+ 
+ namespace js {
+ namespace wasm {
+ 
+ static const uint32_t MagicNumber        = 0x6d736100; // "\0asm"
+ static const uint32_t EncodingVersion    = 0x01;
+ 
+ enum class SectionId
+diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp
+--- a/js/src/wasm/WasmInstance.cpp
++++ b/js/src/wasm/WasmInstance.cpp
+@@ -13,16 +13,17 @@
+  * 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/WasmInstance.h"
+ 
++#include "builtin/SIMD.h"
+ #include "jit/AtomicOperations.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/JitCommon.h"
+ #include "jit/JitRealm.h"
+ #include "wasm/WasmBuiltins.h"
+ #include "wasm/WasmModule.h"
+ 

+ 401 - 0
frg/work-js/mozilla-release/patches/1476012-4-63a1.patch

@@ -0,0 +1,401 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829234 -3600
+#      Tue Jul 17 13:07:14 2018 +0100
+# Node ID dc942361448ddd7af5e31213f3e4b45343b8f9ab
+# Parent  07e89fa1364ea14ace973a4a41559587489a2bc1
+Bug 1476012 - Remove the dependency of JitcodeMap.h on CodeGenerator-shared.h r=nbp
+
+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
+@@ -218,16 +218,17 @@
+ #include "gc/GCInternals.h"
+ #include "gc/GCTrace.h"
+ #include "gc/Memory.h"
+ #include "gc/Policy.h"
+ #include "gc/WeakMap.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/IonCode.h"
+ #include "jit/JitcodeMap.h"
++#include "jit/JitRealm.h"
+ #include "js/SliceBudget.h"
+ #include "proxy/DeadObjectProxy.h"
+ #include "util/Windows.h"
+ #ifdef ENABLE_BIGINT
+ #include "vm/BigIntType.h"
+ #endif
+ #include "vm/Debugger.h"
+ #include "vm/GeckoProfiler.h"
+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
+@@ -8,16 +8,17 @@
+ 
+ #include "mozilla/MathAlgorithms.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/Sprintf.h"
+ 
+ #include "gc/Marking.h"
+ #include "gc/Statistics.h"
+ #include "jit/BaselineJIT.h"
++#include "jit/JitRealm.h"
+ #include "jit/JitSpewer.h"
+ #include "js/Vector.h"
+ #include "vm/GeckoProfiler.h"
+ 
+ #include "vm/GeckoProfiler-inl.h"
+ #include "vm/JSScript-inl.h"
+ #include "vm/TypeInference-inl.h"
+ 
+@@ -1194,18 +1195,18 @@ JitcodeRegionEntry::ReadDelta(CompactBuf
+         pcDeltaU |= ~ENC4_PC_DELTA_MAX;
+     *pcDelta = pcDeltaU;
+ 
+     MOZ_ASSERT(*pcDelta != 0);
+     MOZ_ASSERT_IF(*nativeDelta == 0, *pcDelta <= 0);
+ }
+ 
+ /* static */ uint32_t
+-JitcodeRegionEntry::ExpectedRunLength(const CodeGeneratorShared::NativeToBytecode* entry,
+-                                      const CodeGeneratorShared::NativeToBytecode* end)
++JitcodeRegionEntry::ExpectedRunLength(const NativeToBytecode* entry,
++                                      const NativeToBytecode* end)
+ {
+     MOZ_ASSERT(entry < end);
+ 
+     // We always use the first entry, so runLength starts at 1
+     uint32_t runLength = 1;
+ 
+     uint32_t curNativeOffset = entry->nativeOffset.offset();
+     uint32_t curBytecodeOffset = entry->tree->script()->pcToOffset(entry->pc);
+@@ -1282,17 +1283,17 @@ struct JitcodeMapBufferWriteSpewer
+     void spewAndAdvance(const char* name) {}
+ #endif // JS_JITSPEW
+ };
+ 
+ // Write a run, starting at the given NativeToBytecode entry, into the given buffer writer.
+ /* static */ bool
+ JitcodeRegionEntry::WriteRun(CompactBufferWriter& writer,
+                              JSScript** scriptList, uint32_t scriptListSize,
+-                             uint32_t runLength, const CodeGeneratorShared::NativeToBytecode* entry)
++                             uint32_t runLength, const NativeToBytecode* entry)
+ {
+     MOZ_ASSERT(runLength > 0);
+     MOZ_ASSERT(runLength <= MAX_RUN_LENGTH);
+ 
+     // Calculate script depth.
+     MOZ_ASSERT(entry->tree->depth() <= 0xff);
+     uint8_t scriptDepth = entry->tree->depth();
+     uint32_t regionNativeOffset = entry->nativeOffset.offset();
+@@ -1532,18 +1533,18 @@ JitcodeIonTable::findRegionEntry(uint32_
+         }
+     }
+     return idx;
+ }
+ 
+ /* static */ bool
+ JitcodeIonTable::WriteIonTable(CompactBufferWriter& writer,
+                                JSScript** scriptList, uint32_t scriptListSize,
+-                               const CodeGeneratorShared::NativeToBytecode* start,
+-                               const CodeGeneratorShared::NativeToBytecode* end,
++                               const NativeToBytecode* start,
++                               const NativeToBytecode* end,
+                                uint32_t* tableOffsetOut, uint32_t* numRegionsOut)
+ {
+     MOZ_ASSERT(tableOffsetOut != nullptr);
+     MOZ_ASSERT(numRegionsOut != nullptr);
+     MOZ_ASSERT(writer.length() == 0);
+     MOZ_ASSERT(scriptListSize > 0);
+ 
+     JitSpew(JitSpew_Profiling, "Writing native to bytecode map for %s:%u (%zu entries)",
+@@ -1553,17 +1554,17 @@ JitcodeIonTable::WriteIonTable(CompactBu
+     JitSpew(JitSpew_Profiling, "  ScriptList of size %d", int(scriptListSize));
+     for (uint32_t i = 0; i < scriptListSize; i++) {
+         JitSpew(JitSpew_Profiling, "  Script %d - %s:%u",
+                 int(i), scriptList[i]->filename(), scriptList[i]->lineno());
+     }
+ 
+     // Write out runs first.  Keep a vector tracking the positive offsets from payload
+     // start to the run.
+-    const CodeGeneratorShared::NativeToBytecode* curEntry = start;
++    const NativeToBytecode* curEntry = start;
+     js::Vector<uint32_t, 32, SystemAllocPolicy> runOffsets;
+ 
+     while (curEntry != end) {
+         // Calculate the length of the next run.
+         uint32_t runLength = JitcodeRegionEntry::ExpectedRunLength(curEntry, end);
+         MOZ_ASSERT(runLength > 0);
+         MOZ_ASSERT(runLength <= uintptr_t(end - curEntry));
+         JitSpew(JitSpew_Profiling, "  Run at entry %d, length %d, buffer offset %d",
+diff --git a/js/src/jit/JitcodeMap.h b/js/src/jit/JitcodeMap.h
+--- a/js/src/jit/JitcodeMap.h
++++ b/js/src/jit/JitcodeMap.h
+@@ -6,17 +6,16 @@
+ 
+ #ifndef jit_JitcodeMap_h
+ #define jit_JitcodeMap_h
+ 
+ #include "jit/CompactBuffer.h"
+ #include "jit/CompileInfo.h"
+ #include "jit/ExecutableAllocator.h"
+ #include "jit/OptimizationTracking.h"
+-#include "jit/shared/CodeGenerator-shared.h"
+ 
+ namespace js {
+ namespace jit {
+ 
+ /*
+  * The Ion jitcode map implements tables to allow mapping from addresses in ion jitcode
+  * to the list of (JSScript*, jsbytecode*) pairs that are implicitly active in the frame at
+  * that point in the native code.
+@@ -32,16 +31,22 @@ namespace jit {
+  */
+ 
+ class JitcodeGlobalTable;
+ class JitcodeIonTable;
+ class JitcodeRegionEntry;
+ 
+ class JitcodeGlobalEntry;
+ 
++struct NativeToBytecode {
++    CodeOffset nativeOffset;
++    InlineScriptTree* tree;
++    jsbytecode* pc;
++};
++
+ class JitcodeSkiplistTower
+ {
+   public:
+     static const unsigned MAX_HEIGHT = 32;
+ 
+   private:
+     uint8_t height_;
+     bool isFree_;
+@@ -1257,23 +1262,23 @@ class JitcodeRegionEntry
+     static void ReadScriptPc(CompactBufferReader& reader, uint32_t* scriptIdx, uint32_t* pcOffset);
+ 
+     static void WriteDelta(CompactBufferWriter& writer, uint32_t nativeDelta, int32_t pcDelta);
+     static void ReadDelta(CompactBufferReader& reader, uint32_t* nativeDelta, int32_t* pcDelta);
+ 
+     // Given a pointer into an array of NativeToBytecode (and a pointer to the end of the array),
+     // compute the number of entries that would be consume by outputting a run starting
+     // at this one.
+-    static uint32_t ExpectedRunLength(const CodeGeneratorShared::NativeToBytecode* entry,
+-                                      const CodeGeneratorShared::NativeToBytecode* end);
++    static uint32_t ExpectedRunLength(const NativeToBytecode* entry,
++                                      const NativeToBytecode* end);
+ 
+     // Write a run, starting at the given NativeToBytecode entry, into the given buffer writer.
+     static MOZ_MUST_USE bool WriteRun(CompactBufferWriter& writer, JSScript** scriptList,
+                                       uint32_t scriptListSize, uint32_t runLength,
+-                                      const CodeGeneratorShared::NativeToBytecode* entry);
++                                      const NativeToBytecode* entry);
+ 
+     // Delta Run entry formats are encoded little-endian:
+     //
+     //  byte 0
+     //  NNNN-BBB0
+     //      Single byte format.  nativeDelta in [0, 15], pcDelta in [0, 7]
+     //
+     static const uint32_t ENC1_MASK = 0x1;
+@@ -1519,18 +1524,18 @@ class JitcodeIonTable
+ 
+     const uint8_t* payloadStart() const {
+         // The beginning of the payload the beginning of the first region are the same.
+         return payloadEnd() - regionOffset(0);
+     }
+ 
+     static MOZ_MUST_USE bool WriteIonTable(CompactBufferWriter& writer,
+                                            JSScript** scriptList, uint32_t scriptListSize,
+-                                           const CodeGeneratorShared::NativeToBytecode* start,
+-                                           const CodeGeneratorShared::NativeToBytecode* end,
++                                           const NativeToBytecode* start,
++                                           const NativeToBytecode* end,
+                                            uint32_t* tableOffsetOut, uint32_t* numRegionsOut);
+ };
+ 
+ 
+ } // namespace jit
+ } // namespace js
+ 
+ #endif /* jit_JitcodeMap_h */
+diff --git a/js/src/jit/OptimizationTracking.h b/js/src/jit/OptimizationTracking.h
+--- a/js/src/jit/OptimizationTracking.h
++++ b/js/src/jit/OptimizationTracking.h
+@@ -15,17 +15,23 @@
+ #include "jit/JitSpewer.h"
+ #include "js/TrackedOptimizationInfo.h"
+ #include "vm/TypeInference.h"
+ 
+ namespace js {
+ 
+ namespace jit {
+ 
+-struct NativeToTrackedOptimizations;
++struct NativeToTrackedOptimizations
++{
++    // [startOffset, endOffset]
++    CodeOffset startOffset;
++    CodeOffset endOffset;
++    const TrackedOptimizations* optimizations;
++};
+ 
+ class OptimizationAttempt
+ {
+     JS::TrackedStrategy strategy_;
+     JS::TrackedOutcome outcome_;
+ 
+   public:
+     OptimizationAttempt(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome)
+diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h
+--- a/js/src/jit/shared/CodeGenerator-shared.h
++++ b/js/src/jit/shared/CodeGenerator-shared.h
+@@ -6,16 +6,17 @@
+ 
+ #ifndef jit_shared_CodeGenerator_shared_h
+ #define jit_shared_CodeGenerator_shared_h
+ 
+ #include "mozilla/Alignment.h"
+ #include "mozilla/Move.h"
+ #include "mozilla/TypeTraits.h"
+ 
++#include "jit/JitcodeMap.h"
+ #include "jit/JitFrames.h"
+ #include "jit/LIR.h"
+ #include "jit/MacroAssembler.h"
+ #include "jit/MIRGenerator.h"
+ #include "jit/MIRGraph.h"
+ #include "jit/OptimizationTracking.h"
+ #include "jit/Safepoints.h"
+ #include "jit/Snapshots.h"
+@@ -34,27 +35,16 @@ class OutOfLineCallVM;
+ 
+ class OutOfLineTruncateSlow;
+ 
+ struct ReciprocalMulConstants {
+     int64_t multiplier;
+     int32_t shiftAmount;
+ };
+ 
+-// This should be nested in CodeGeneratorShared, but it is used in
+-// optimization tracking implementation and nested classes cannot be
+-// forward-declared.
+-struct NativeToTrackedOptimizations
+-{
+-    // [startOffset, endOffset]
+-    CodeOffset startOffset;
+-    CodeOffset endOffset;
+-    const TrackedOptimizations* optimizations;
+-};
+-
+ class CodeGeneratorShared : public LElementVisitor
+ {
+     js::Vector<OutOfLineCode*, 0, SystemAllocPolicy> outOfLineCode_;
+ 
+     MacroAssembler& ensureMasm(MacroAssembler* masm);
+     mozilla::Maybe<IonHeapMacroAssembler> maybeMasm_;
+ 
+   public:
+@@ -106,23 +96,16 @@ class CodeGeneratorShared : public LElem
+         PatchableTLEvent(CodeOffset offset, const char* event)
+             : offset(offset), event(event)
+         {}
+     };
+     js::Vector<PatchableTLEvent, 0, SystemAllocPolicy> patchableTLEvents_;
+     js::Vector<CodeOffset, 0, SystemAllocPolicy> patchableTLScripts_;
+ #endif
+ 
+-  public:
+-    struct NativeToBytecode {
+-        CodeOffset nativeOffset;
+-        InlineScriptTree* tree;
+-        jsbytecode* pc;
+-    };
+-
+   protected:
+     js::Vector<NativeToBytecode, 0, SystemAllocPolicy> nativeToBytecodeList_;
+     uint8_t* nativeToBytecodeMap_;
+     uint32_t nativeToBytecodeMapSize_;
+     uint32_t nativeToBytecodeTableOffset_;
+     uint32_t nativeToBytecodeNumRegions_;
+ 
+     JSScript** nativeToBytecodeScriptList_;
+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
+@@ -67,24 +67,24 @@
+ #include "builtin/RegExp.h"
+ #include "builtin/TestingFunctions.h"
+ #include "frontend/Parser.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/arm/Simulator-arm.h"
+ #include "jit/InlinableNatives.h"
+ #include "jit/Ion.h"
+ #include "jit/JitcodeMap.h"
+-#include "jit/OptimizationTracking.h"
++#include "jit/JitRealm.h"
++#include "jit/shared/CodeGenerator-shared.h"
+ #include "js/Debug.h"
+ #include "js/GCVector.h"
+ #include "js/Initialization.h"
+ #include "js/Printf.h"
+ #include "js/StructuredClone.h"
+ #include "js/SweepingAPI.h"
+-#include "js/TrackedOptimizationInfo.h"
+ #include "js/Wrapper.h"
+ #include "perf/jsperf.h"
+ #include "shell/jsoptparse.h"
+ #include "shell/jsshell.h"
+ #include "shell/OSObject.h"
+ #include "threading/ConditionVariable.h"
+ #include "threading/ExclusiveData.h"
+ #include "threading/LockGuard.h"
+diff --git a/js/src/vm/GeckoProfiler.cpp b/js/src/vm/GeckoProfiler.cpp
+--- a/js/src/vm/GeckoProfiler.cpp
++++ b/js/src/vm/GeckoProfiler.cpp
+@@ -5,21 +5,23 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "vm/GeckoProfiler-inl.h"
+ 
+ #include "mozilla/DebugOnly.h"
+ 
+ #include "jsnum.h"
+ 
++#include "gc/GC.h"
+ #include "gc/PublicIterators.h"
+ #include "jit/BaselineFrame.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/JitcodeMap.h"
+ #include "jit/JitFrames.h"
++#include "jit/JitRealm.h"
+ #include "jit/JSJitFrameIter.h"
+ #include "util/StringBuffer.h"
+ #include "vm/JSScript.h"
+ 
+ #include "gc/Marking-inl.h"
+ 
+ using namespace js;
+ 
+diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
+--- a/js/src/vm/Stack.cpp
++++ b/js/src/vm/Stack.cpp
+@@ -7,16 +7,17 @@
+ #include "vm/Stack-inl.h"
+ 
+ #include <utility>
+ 
+ #include "gc/Marking.h"
+ #include "jit/BaselineFrame.h"
+ #include "jit/JitcodeMap.h"
+ #include "jit/JitRealm.h"
++#include "jit/shared/CodeGenerator-shared.h"
+ #include "vm/Debugger.h"
+ #include "vm/JSContext.h"
+ #include "vm/Opcodes.h"
+ 
+ #include "jit/JSJitFrameIter-inl.h"
+ #include "vm/EnvironmentObject-inl.h"
+ #include "vm/Interpreter-inl.h"
+ #include "vm/Probes-inl.h"

+ 107 - 0
frg/work-js/mozilla-release/patches/1476012-5-63a1.patch

@@ -0,0 +1,107 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829267 -3600
+#      Tue Jul 17 13:07:47 2018 +0100
+# Node ID c67b560d92a6920b8254adb5fee6fe25a43e8c4b
+# Parent  1311f7fcf03a42316fcadb140bf2283f30710650
+Bug 1476012 - Remove the dependency of JitFrames.h on Safepoints.h r=nbp
+
+diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h
+--- a/js/src/jit/BaselineJIT.h
++++ b/js/src/jit/BaselineJIT.h
+@@ -7,16 +7,17 @@
+ #ifndef jit_BaselineJIT_h
+ #define jit_BaselineJIT_h
+ 
+ #include "mozilla/MemoryReporting.h"
+ 
+ #include "ds/LifoAlloc.h"
+ #include "jit/Bailouts.h"
+ #include "jit/IonCode.h"
++#include "jit/shared/Assembler-shared.h"
+ #include "vm/EnvironmentObject.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ #include "vm/TraceLogging.h"
+ 
+ namespace js {
+ namespace jit {
+ 
+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
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "jit/JSJitFrameIter-inl.h"
+ 
+ #include "jit/BaselineDebugModeOSR.h"
+ #include "jit/BaselineIC.h"
+ #include "jit/JitcodeMap.h"
+ #include "jit/JitFrames.h"
++#include "jit/Safepoints.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ 
+ JSJitFrameIter::JSJitFrameIter(const JitActivation* activation)
+   : current_(activation->jsExitFP()),
+     type_(JitFrame_Exit),
+     returnAddressToFp_(nullptr),
+diff --git a/js/src/jit/JitFrames.h b/js/src/jit/JitFrames.h
+--- a/js/src/jit/JitFrames.h
++++ b/js/src/jit/JitFrames.h
+@@ -5,30 +5,31 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef jit_JitFrames_h
+ #define jit_JitFrames_h
+ 
+ #include <stdint.h>
+ 
+ #include "jit/JSJitFrameIter.h"
+-#include "jit/Safepoints.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ 
+ namespace js {
+ namespace jit {
+ 
+ enum CalleeTokenTag
+ {
+     CalleeToken_Function = 0x0, // untagged
+     CalleeToken_FunctionConstructing = 0x1,
+     CalleeToken_Script = 0x2
+ };
+ 
++struct SafepointSlotEntry;
++
+ static const uintptr_t CalleeTokenMask = ~uintptr_t(0x3);
+ 
+ static inline CalleeTokenTag
+ GetCalleeTokenTag(CalleeToken token)
+ {
+     CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
+     MOZ_ASSERT(tag <= CalleeToken_Script);
+     return tag;
+diff --git a/js/src/jit/OptimizationTracking.h b/js/src/jit/OptimizationTracking.h
+--- a/js/src/jit/OptimizationTracking.h
++++ b/js/src/jit/OptimizationTracking.h
+@@ -8,16 +8,17 @@
+ #define jit_OptimizationTracking_h
+ 
+ #include "mozilla/Maybe.h"
+ 
+ #include "jit/CompactBuffer.h"
+ #include "jit/CompileInfo.h"
+ #include "jit/JitAllocPolicy.h"
+ #include "jit/JitSpewer.h"
++#include "jit/shared/Assembler-shared.h"
+ #include "js/TrackedOptimizationInfo.h"
+ #include "vm/TypeInference.h"
+ 
+ namespace js {
+ 
+ namespace jit {
+ 
+ struct NativeToTrackedOptimizations

+ 92 - 0
frg/work-js/mozilla-release/patches/1476012-6-63a1.patch

@@ -0,0 +1,92 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829314 -3600
+#      Tue Jul 17 13:08:34 2018 +0100
+# Node ID f47a00d46ef21f4da2760ea9634aa8ef5f44b442
+# Parent  119cc18cf0ae40575f99c6128bac2e7d711cc43e
+Bug 1476012 - Remove dependency of Realm.h on GlobalObject.h r=jandem
+
+diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h
+--- a/js/src/vm/EnvironmentObject.h
++++ b/js/src/vm/EnvironmentObject.h
+@@ -8,16 +8,17 @@
+ #define vm_EnvironmentObject_h
+ 
+ #include "builtin/ModuleObject.h"
+ #include "frontend/NameAnalysisTypes.h"
+ #include "gc/Barrier.h"
+ #include "gc/WeakMap.h"
+ #include "js/GCHashTable.h"
+ #include "vm/ArgumentsObject.h"
++#include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/ProxyObject.h"
+ #include "vm/Scope.h"
+ 
+ namespace js {
+ 
+ class ModuleObject;
+diff --git a/js/src/vm/ErrorReporting.cpp b/js/src/vm/ErrorReporting.cpp
+--- a/js/src/vm/ErrorReporting.cpp
++++ b/js/src/vm/ErrorReporting.cpp
+@@ -8,16 +8,17 @@
+ 
+ #include "mozilla/Move.h"
+ 
+ #include <stdarg.h>
+ 
+ #include "jsexn.h"
+ #include "jsfriendapi.h"
+ 
++#include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ 
+ #include "vm/JSContext-inl.h"
+ 
+ using JS::HandleObject;
+ using JS::HandleValue;
+ using JS::UniqueTwoByteChars;
+ 
+diff --git a/js/src/vm/JSCompartment-inl.h b/js/src/vm/JSCompartment-inl.h
+--- a/js/src/vm/JSCompartment-inl.h
++++ b/js/src/vm/JSCompartment-inl.h
+@@ -6,16 +6,17 @@
+ 
+ #ifndef vm_JSCompartment_inl_h
+ #define vm_JSCompartment_inl_h
+ 
+ #include "vm/JSCompartment.h"
+ 
+ #include "gc/Barrier.h"
+ #include "gc/Marking.h"
++#include "vm/GlobalObject.h"
+ #include "vm/Iteration.h"
+ 
+ #include "vm/JSContext-inl.h"
+ 
+ inline void
+ JS::Realm::initGlobal(js::GlobalObject& global)
+ {
+     MOZ_ASSERT(global.realm() == this);
+diff --git a/js/src/vm/JSCompartment.h b/js/src/vm/JSCompartment.h
+--- a/js/src/vm/JSCompartment.h
++++ b/js/src/vm/JSCompartment.h
+@@ -11,16 +11,17 @@
+ #include "mozilla/Maybe.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/Tuple.h"
+ #include "mozilla/Variant.h"
+ #include "mozilla/XorShift128PlusRNG.h"
+ 
+ #include <stddef.h>
+ 
++#include "builtin/Array.h"
+ #include "gc/Barrier.h"
+ #include "gc/NurseryAwareHashMap.h"
+ #include "gc/Zone.h"
+ #include "js/UniquePtr.h"
+ #include "vm/ArrayBufferObject.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/ReceiverGuard.h"
+ #include "vm/RegExpShared.h"

+ 180 - 0
frg/work-js/mozilla-release/patches/1476012-7-63a1.patch

@@ -0,0 +1,180 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829335 -3600
+#      Tue Jul 17 13:08:55 2018 +0100
+# Node ID 9c19e1788337dc016e76071f10c8a493e38c89a7
+# Parent  f47a00d46ef21f4da2760ea9634aa8ef5f44b442
+Bug 1476012 - Remove dependency of Principals.h on StructuredClone.h r=sfink
+
+diff --git a/js/public/Principals.h b/js/public/Principals.h
+--- a/js/public/Principals.h
++++ b/js/public/Principals.h
+@@ -10,17 +10,18 @@
+ #define js_Principals_h
+ 
+ #include "mozilla/Atomics.h"
+ 
+ #include <stdint.h>
+ 
+ #include "jspubtd.h"
+ 
+-#include "js/StructuredClone.h"
++struct JSStructuredCloneReader;
++struct JSStructuredCloneWriter;
+ 
+ namespace js {
+     struct JS_PUBLIC_API(PerformanceGroup);
+ } // namespace js
+ 
+ struct JSPrincipals {
+     /* Don't call "destroy"; use reference counting macros below. */
+     mozilla::Atomic<int32_t> refcount;
+diff --git a/js/rust/src/jsglue.cpp b/js/rust/src/jsglue.cpp
+--- a/js/rust/src/jsglue.cpp
++++ b/js/rust/src/jsglue.cpp
+@@ -13,16 +13,17 @@
+ #endif
+ 
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
+ #include "js/Proxy.h"
+ #include "js/Class.h"
+ #include "js/MemoryMetrics.h"
+ #include "js/Principals.h"
++#include "js/StructuredClone.h"
+ #include "js/Wrapper.h"
+ #include "assert.h"
+ 
+ struct ProxyTraps {
+     bool (*enter)(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                   js::BaseProxyHandler::Action action, bool *bp);
+ 
+     bool (*getOwnPropertyDescriptor)(JSContext *cx, JS::HandleObject proxy,
+diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h
+--- a/js/src/builtin/AtomicsObject.h
++++ b/js/src/builtin/AtomicsObject.h
+@@ -13,16 +13,17 @@
+ #include "threading/ConditionVariable.h"
+ #include "vm/JSObject.h"
+ #include "vm/MutexIDs.h"
+ #include "vm/NativeObject.h"
+ 
+ namespace js {
+ 
+ class GlobalObject;
++class SharedArrayRawBuffer;
+ 
+ class AtomicsObject : public NativeObject
+ {
+   public:
+     static const Class class_;
+     static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
+     static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
+ };
+diff --git a/js/src/fuzz-tests/testStructuredCloneReader.cpp b/js/src/fuzz-tests/testStructuredCloneReader.cpp
+--- a/js/src/fuzz-tests/testStructuredCloneReader.cpp
++++ b/js/src/fuzz-tests/testStructuredCloneReader.cpp
+@@ -6,16 +6,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ 
+ #include "mozilla/ScopeExit.h"
+ 
+ #include "jsapi.h"
+ 
+ #include "fuzz-tests/tests.h"
++#include "js/StructuredClone.h"
+ #include "vm/Interpreter.h"
+ 
+ #include "vm/JSContext-inl.h"
+ 
+ using namespace js;
+ 
+ // These are defined and pre-initialized by the harness (in tests.cpp).
+ extern JS::PersistentRootedObject gGlobal;
+diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp
+--- a/js/src/jit/CacheIRCompiler.cpp
++++ b/js/src/jit/CacheIRCompiler.cpp
+@@ -1,16 +1,18 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  * vim: set ts=8 sts=4 et sw=4 tw=99:
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "jit/CacheIRCompiler.h"
+ 
++#include "mozilla/ScopeExit.h"
++
+ #include <utility>
+ 
+ #include "jit/IonIC.h"
+ #include "jit/SharedICHelpers.h"
+ 
+ #include "builtin/Boolean-inl.h"
+ 
+ #include "jit/MacroAssembler-inl.h"
+diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
+--- a/js/src/vm/Scope.cpp
++++ b/js/src/vm/Scope.cpp
+@@ -1,16 +1,18 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  * vim: set ts=8 sts=4 et sw=4 tw=99:
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "vm/Scope.h"
+ 
++#include "mozilla/ScopeExit.h"
++
+ #include <memory>
+ #include <new>
+ 
+ #include "builtin/ModuleObject.h"
+ #include "gc/Allocator.h"
+ #include "gc/FreeOp.h"
+ #include "util/StringBuffer.h"
+ #include "vm/EnvironmentObject.h"
+diff --git a/js/src/wasm/WasmJS.h b/js/src/wasm/WasmJS.h
+--- a/js/src/wasm/WasmJS.h
++++ b/js/src/wasm/WasmJS.h
+@@ -24,16 +24,17 @@
+ #include "wasm/WasmTypes.h"
+ 
+ namespace js {
+ 
+ class GlobalObject;
+ class TypedArrayObject;
+ class WasmFunctionScope;
+ class WasmInstanceScope;
++class SharedArrayRawBuffer;
+ 
+ namespace wasm {
+ 
+ // Return whether WebAssembly can be compiled on this platform.
+ // This must be checked and must be true to call any of the top-level wasm
+ // eval/compile methods.
+ 
+ bool
+diff --git a/js/src/wasm/WasmProcess.cpp b/js/src/wasm/WasmProcess.cpp
+--- a/js/src/wasm/WasmProcess.cpp
++++ b/js/src/wasm/WasmProcess.cpp
+@@ -14,16 +14,17 @@
+  * 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/WasmProcess.h"
+ 
+ #include "mozilla/BinarySearch.h"
++#include "mozilla/ScopeExit.h"
+ 
+ #include "vm/MutexIDs.h"
+ #include "wasm/WasmBuiltins.h"
+ #include "wasm/WasmCode.h"
+ #include "wasm/WasmInstance.h"
+ 
+ using namespace js;
+ using namespace wasm;

+ 34 - 0
frg/work-js/mozilla-release/patches/1476012-8-63a1.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531829356 -3600
+#      Tue Jul 17 13:09:16 2018 +0100
+# Node ID 372e6a24e99b2230431f9a53b6851fa13658e035
+# Parent  9c19e1788337dc016e76071f10c8a493e38c89a7
+Bug 1476012 - Remove the dependency of DeletePolicy.h on BigIntType.h r=sfink
+
+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
+@@ -3,18 +3,21 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef gc_DeletePolicy_h
+ #define gc_DeletePolicy_h
+ 
+ #include "js/TracingAPI.h"
++
+ #ifdef ENABLE_BIGINT
+-#include "vm/BigIntType.h"
++namespace JS {
++class BigInt;
++} // namespace JS
+ #endif
+ 
+ namespace js {
+ namespace gc {
+ 
+ struct ClearEdgesTracer : public JS::CallbackTracer
+ {
+     ClearEdgesTracer();

+ 27 - 0
frg/work-js/mozilla-release/patches/1476012-9-63a1.patch

@@ -0,0 +1,27 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531831960 -3600
+#      Tue Jul 17 13:52:40 2018 +0100
+# Node ID 9a7bf0017c6cdc258f3bec3383b86ec6b4795af0
+# Parent  66ee3a9fe9caee878fc3d1163458e9fb6de61f88
+Bug 1476012 - Fix rust bustage r=me
+
+diff --git a/js/rust/etc/wrapper.hpp b/js/rust/etc/wrapper.hpp
+--- a/js/rust/etc/wrapper.hpp
++++ b/js/rust/etc/wrapper.hpp
+@@ -10,14 +10,15 @@
+ #endif
+ 
+ typedef uint32_t HashNumber;
+ 
+ #include "jsfriendapi.h"
+ #include "js/Conversions.h"
+ #include "js/Initialization.h"
+ #include "js/MemoryMetrics.h"
++#include "js/StructuredClone.h"
+ 
+ // Replacements for types that are too difficult for rust-bindgen.
+ 
+ /// <div rustbindgen replaces="JS::detail::MaybeWrapped" />
+ template <typename T>
+ using replaces_MaybeWrapped = T;

+ 893 - 0
frg/work-js/mozilla-release/patches/1476203-63a1.patch

@@ -0,0 +1,893 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1534162787 25200
+# Node ID 125176893a0a113be1865f1d3efc1e38425ee0e6
+# Parent  ec59471499f174cd05086b572f759f67cdfa4476
+Bug 1476203 - Separate IfEmitter and CondEmitter. r=jwalden
+
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -4348,22 +4348,20 @@ BytecodeEmitter::emitTry(ParseNode* pn)
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitIf(ParseNode* pn)
+ {
+     IfEmitter ifThenElse(this);
+ 
++    if (!ifThenElse.emitIf(Some(pn->pn_pos.begin)))
++        return false;
++
+   if_again:
+-    // Make sure this code is attributed to the "if" so that it gets a useful
+-    // column number, instead of the default 0 value.
+-    if (!updateSourceCoordNotes(pn->pn_pos.begin))
+-        return false;
+-
+     /* Emit code for the condition before pushing stmtInfo. */
+     if (!emitTree(pn->pn_kid1))
+         return false;
+ 
+     ParseNode* elseNode = pn->pn_kid3;
+     if (elseNode) {
+         if (!ifThenElse.emitThenElse())
+             return false;
+@@ -4375,17 +4373,17 @@ BytecodeEmitter::emitIf(ParseNode* pn)
+     /* Emit code for the then part. */
+     if (!emitTree(pn->pn_kid2))
+         return false;
+ 
+     if (elseNode) {
+         if (elseNode->isKind(ParseNodeKind::If)) {
+             pn = elseNode;
+ 
+-            if (!ifThenElse.emitElseIf())
++            if (!ifThenElse.emitElseIf(Some(pn->pn_pos.begin)))
+                 return false;
+ 
+             goto if_again;
+         }
+ 
+         if (!ifThenElse.emitElse())
+             return false;
+ 
+@@ -6841,36 +6839,38 @@ BytecodeEmitter::emitLabeledStatement(co
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional,
+                                            ValueUsage valueUsage /* = ValueUsage::WantValue */)
+ {
+-    /* Emit the condition, then branch if false to the else part. */
++    CondEmitter cond(this);
++    if (!cond.emitCond())
++        return false;
++
+     if (!emitTree(&conditional.condition()))
+         return false;
+ 
+-    IfEmitter ifThenElse(this);
+-    if (!ifThenElse.emitCond())
++    if (!cond.emitThenElse())
+         return false;
+ 
+     if (!emitTree(&conditional.thenExpression(), valueUsage))
+         return false;
+ 
+-    if (!ifThenElse.emitElse())
++    if (!cond.emitElse())
+         return false;
+ 
+     if (!emitTree(&conditional.elseExpression(), valueUsage))
+         return false;
+ 
+-    if (!ifThenElse.emitEnd())
+-        return false;
+-    MOZ_ASSERT(ifThenElse.pushed() == 1);
++    if (!cond.emitEnd())
++        return false;
++    MOZ_ASSERT(cond.pushed() == 1);
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type)
+ {
+     for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
+diff --git a/js/src/frontend/IfEmitter.cpp b/js/src/frontend/IfEmitter.cpp
+--- a/js/src/frontend/IfEmitter.cpp
++++ b/js/src/frontend/IfEmitter.cpp
+@@ -8,37 +8,34 @@
+ 
+ #include "frontend/BytecodeEmitter.h"
+ #include "frontend/SourceNotes.h"
+ #include "vm/Opcodes.h"
+ 
+ using namespace js;
+ using namespace js::frontend;
+ 
+-IfEmitter::IfEmitter(BytecodeEmitter* bce, Kind kind)
++using mozilla::Maybe;
++
++BranchEmitterBase::BranchEmitterBase(BytecodeEmitter* bce, Kind kind)
+   : bce_(bce),
+-    thenDepth_(0),
+     kind_(kind)
+-#ifdef DEBUG
+-  , pushed_(0),
+-    calculatedPushed_(false),
+-    state_(State::Start)
+-#endif
++{}
++
++IfEmitter::IfEmitter(BytecodeEmitter* bce, Kind kind)
++  : BranchEmitterBase(bce, kind)
+ {}
+ 
+ IfEmitter::IfEmitter(BytecodeEmitter* bce)
+   : IfEmitter(bce, Kind::MayContainLexicalAccessInBranch)
+ {}
+ 
+ bool
+-IfEmitter::emitIfInternal(SrcNoteType type)
++BranchEmitterBase::emitThenInternal(SrcNoteType type)
+ {
+-    MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome());
+-    MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing());
+-
+     // The end of TDZCheckCache for cond for else-if.
+     if (kind_ == Kind::MayContainLexicalAccessInBranch)
+         tdzCache_.reset();
+ 
+     // Emit an annotated branch-if-false around the then part.
+     if (!bce_->newSrcNote(type))
+         return false;
+     if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_))
+@@ -56,69 +53,30 @@ IfEmitter::emitIfInternal(SrcNoteType ty
+     // Enclose then-branch with TDZCheckCache.
+     if (kind_ == Kind::MayContainLexicalAccessInBranch)
+         tdzCache_.emplace(bce_);
+ 
+     return true;
+ }
+ 
+ void
+-IfEmitter::calculateOrCheckPushed()
++BranchEmitterBase::calculateOrCheckPushed()
+ {
+ #ifdef DEBUG
+     if (!calculatedPushed_) {
+         pushed_ = bce_->stackDepth - thenDepth_;
+         calculatedPushed_ = true;
+     } else {
+         MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
+     }
+ #endif
+ }
+ 
+ bool
+-IfEmitter::emitThen()
+-{
+-    MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
+-    if (!emitIfInternal(SRC_IF))
+-        return false;
+-
+-#ifdef DEBUG
+-    state_ = State::Then;
+-#endif
+-    return true;
+-}
+-
+-bool
+-IfEmitter::emitCond()
+-{
+-    MOZ_ASSERT(state_ == State::Start);
+-    if (!emitIfInternal(SRC_COND))
+-        return false;
+-
+-#ifdef DEBUG
+-    state_ = State::Cond;
+-#endif
+-    return true;
+-}
+-
+-bool
+-IfEmitter::emitThenElse()
+-{
+-    MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
+-    if (!emitIfInternal(SRC_IF_ELSE))
+-        return false;
+-
+-#ifdef DEBUG
+-    state_ = State::ThenElse;
+-#endif
+-    return true;
+-}
+-
+-bool
+-IfEmitter::emitElseInternal()
++BranchEmitterBase::emitElseInternal()
+ {
+     calculateOrCheckPushed();
+ 
+     // The end of TDZCheckCache for then-clause.
+     if (kind_ == Kind::MayContainLexicalAccessInBranch) {
+         MOZ_ASSERT(tdzCache_.isSome());
+         tdzCache_.reset();
+     }
+@@ -133,67 +91,27 @@ IfEmitter::emitElseInternal()
+     if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
+         return false;
+ 
+     // Clear jumpAroundThen_ offset, to tell emitEnd there was an else part.
+     jumpAroundThen_ = JumpList();
+ 
+     // Restore stack depth of the then part.
+     bce_->stackDepth = thenDepth_;
+-#ifdef DEBUG
+-    state_ = State::Else;
+-#endif
+-    return true;
+-}
+-
+-bool
+-IfEmitter::emitElse()
+-{
+-    MOZ_ASSERT(state_ == State::ThenElse || state_ == State::Cond);
+-
+-    if (!emitElseInternal())
+-        return false;
+ 
+     // Enclose else-branch with TDZCheckCache.
+     if (kind_ == Kind::MayContainLexicalAccessInBranch)
+         tdzCache_.emplace(bce_);
+ 
+-#ifdef DEBUG
+-    state_ = State::Else;
+-#endif
+     return true;
+ }
+ 
+ bool
+-IfEmitter::emitElseIf()
++BranchEmitterBase::emitEndInternal()
+ {
+-    MOZ_ASSERT(state_ == State::ThenElse);
+-
+-    if (!emitElseInternal())
+-        return false;
+-
+-    // Enclose cond for else-if with TDZCheckCache.
+-    if (kind_ == Kind::MayContainLexicalAccessInBranch)
+-        tdzCache_.emplace(bce_);
+-
+-#ifdef DEBUG
+-    state_ = State::ElseIf;
+-#endif
+-    return true;
+-}
+-
+-bool
+-IfEmitter::emitEnd()
+-{
+-    MOZ_ASSERT(state_ == State::Then || state_ == State::Else);
+-    // If there was an else part for the last branch, jumpAroundThen_ is
+-    // already fixed up when emitting the else part.
+-    MOZ_ASSERT_IF(state_ == State::Then, jumpAroundThen_.offset != -1);
+-    MOZ_ASSERT_IF(state_ == State::Else, jumpAroundThen_.offset == -1);
+-
+     // The end of TDZCheckCache for then or else-clause.
+     if (kind_ == Kind::MayContainLexicalAccessInBranch) {
+         MOZ_ASSERT(tdzCache_.isSome());
+         tdzCache_.reset();
+     }
+ 
+     calculateOrCheckPushed();
+ 
+@@ -203,17 +121,178 @@ IfEmitter::emitEnd()
+         if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
+             return false;
+     }
+ 
+     // Patch all the jumps around else parts.
+     if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
+         return false;
+ 
++    return true;
++}
++
++bool
++IfEmitter::emitIf(const Maybe<uint32_t>& ifPos)
++{
++    MOZ_ASSERT(state_ == State::Start);
++
++    if (ifPos) {
++        // Make sure this code is attributed to the "if" so that it gets a
++        // useful column number, instead of the default 0 value.
++        if (!bce_->updateSourceCoordNotes(*ifPos))
++            return false;
++    }
++
++#ifdef DEBUG
++    state_ = State::If;
++#endif
++    return true;
++}
++
++bool
++IfEmitter::emitThen()
++{
++    MOZ_ASSERT(state_ == State::If || state_ == State::ElseIf);
++    MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome());
++    MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing());
++
++    if (!emitThenInternal(SRC_IF))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Then;
++#endif
++    return true;
++}
++
++bool
++IfEmitter::emitThenElse()
++{
++    MOZ_ASSERT(state_ == State::If || state_ == State::ElseIf);
++    MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome());
++    MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing());
++
++    if (!emitThenInternal(SRC_IF_ELSE))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::ThenElse;
++#endif
++    return true;
++}
++
++bool
++IfEmitter::emitElseIf(const Maybe<uint32_t>& ifPos)
++{
++    MOZ_ASSERT(state_ == State::ThenElse);
++
++    if (!emitElseInternal())
++        return false;
++
++    if (ifPos) {
++        // Make sure this code is attributed to the "if" so that it gets a
++        // useful column number, instead of the default 0 value.
++        if (!bce_->updateSourceCoordNotes(*ifPos))
++            return false;
++    }
++
++#ifdef DEBUG
++    state_ = State::ElseIf;
++#endif
++    return true;
++}
++
++bool
++IfEmitter::emitElse()
++{
++    MOZ_ASSERT(state_ == State::ThenElse);
++
++    if (!emitElseInternal())
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Else;
++#endif
++    return true;
++}
++
++bool
++IfEmitter::emitEnd()
++{
++    MOZ_ASSERT(state_ == State::Then || state_ == State::Else);
++    // If there was an else part for the last branch, jumpAroundThen_ is
++    // already fixed up when emitting the else part.
++    MOZ_ASSERT_IF(state_ == State::Then, jumpAroundThen_.offset != -1);
++    MOZ_ASSERT_IF(state_ == State::Else, jumpAroundThen_.offset == -1);
++
++    if (!emitEndInternal())
++        return false;
++
+ #ifdef DEBUG
+     state_ = State::End;
+ #endif
+     return true;
+ }
+ 
+ InternalIfEmitter::InternalIfEmitter(BytecodeEmitter* bce)
+   : IfEmitter(bce, Kind::NoLexicalAccessInBranch)
++{
++#ifdef DEBUG
++    // Skip emitIf (see the comment above InternalIfEmitter declaration).
++    state_ = State::If;
++#endif
++}
++
++CondEmitter::CondEmitter(BytecodeEmitter* bce)
++  : BranchEmitterBase(bce, Kind::MayContainLexicalAccessInBranch)
+ {}
++
++bool
++CondEmitter::emitCond()
++{
++    MOZ_ASSERT(state_ == State::Start);
++#ifdef DEBUG
++    state_ = State::Cond;
++#endif
++    return true;
++}
++
++bool
++CondEmitter::emitThenElse()
++{
++    MOZ_ASSERT(state_ == State::Cond);
++    if (!emitThenInternal(SRC_COND))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::ThenElse;
++#endif
++    return true;
++}
++
++bool
++CondEmitter::emitElse()
++{
++    MOZ_ASSERT(state_ == State::ThenElse);
++
++    if (!emitElseInternal())
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Else;
++#endif
++    return true;
++}
++
++bool
++CondEmitter::emitEnd()
++{
++    MOZ_ASSERT(state_ == State::Else);
++    MOZ_ASSERT(jumpAroundThen_.offset == -1);
++
++    if (!emitEndInternal())
++        return false;
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/IfEmitter.h b/js/src/frontend/IfEmitter.h
+--- a/js/src/frontend/IfEmitter.h
++++ b/js/src/frontend/IfEmitter.h
+@@ -16,68 +16,33 @@
+ #include "frontend/SourceNotes.h"
+ #include "frontend/TDZCheckCache.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+ struct BytecodeEmitter;
+ 
+-// Class for emitting bytecode for blocks like if-then-else.
+-//
+-// This class can be used to emit single if-then-else block, or cascading
+-// else-if blocks.
+-//
+-// Usage: (check for the return value is omitted for simplicity)
+-//
+-//   `if (cond) then_block`
+-//     IfEmitter ifThen(this);
+-//     emit(cond);
+-//     ifThen.emitThen();
+-//     emit(then_block);
+-//     ifThen.emitEnd();
+-//
+-//   `if (cond) then_block else else_block`
+-//     IfEmitter ifThenElse(this);
+-//     emit(cond);
+-//     ifThenElse.emitThenElse();
+-//     emit(then_block);
+-//     ifThenElse.emitElse();
+-//     emit(else_block);
+-//     ifThenElse.emitEnd();
+-//
+-//   `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
+-//     IfEmitter ifThenElse(this);
+-//     emit(c1);
+-//     ifThenElse.emitThenElse();
+-//     emit(b1);
+-//     ifThenElse.emitElseIf();
+-//     emit(c2);
+-//     ifThenElse.emitThenElse();
+-//     emit(b2);
+-//     ifThenElse.emitElseIf();
+-//     emit(c3);
+-//     ifThenElse.emitThenElse();
+-//     emit(b3);
+-//     ifThenElse.emitElse();
+-//     emit(b4);
+-//     ifThenElse.emitEnd();
+-//
+-//   `cond ? then_expr : else_expr`
+-//     IfEmitter condElse(this);
+-//     emit(cond);
+-//     condElse.emitCond();
+-//     emit(then_block);
+-//     condElse.emitElse();
+-//     emit(else_block);
+-//     condElse.emitEnd();
+-//
+-class MOZ_STACK_CLASS IfEmitter
++class MOZ_STACK_CLASS BranchEmitterBase
+ {
+-  public:
++  protected:
++    BytecodeEmitter* bce_;
++
++    // Jump around the then clause, to the beginning of the else clause.
++    JumpList jumpAroundThen_;
++
++    // Jump around the else clause, to the end of the entire branch.
++    JumpList jumpsAroundElse_;
++
++    // The stack depth before emitting the then block.
++    // Used for restoring stack depth before emitting the else block.
++    // Also used for assertion to make sure then and else blocks pushed the
++    // same number of values.
++    int32_t thenDepth_ = 0;
++
+     // Whether the then-clause, the else-clause, or else-if condition may
+     // contain declaration or access to lexical variables, which means they
+     // should have their own TDZCheckCache.  Basically TDZCheckCache should be
+     // created for each basic block, which then-clause, else-clause, and
+     // else-if condition are, but for internally used branches which are
+     // known not to touch lexical variables we can skip creating TDZCheckCache
+     // for them.
+     //
+@@ -87,131 +52,253 @@ class MOZ_STACK_CLASS IfEmitter
+         // which basically may contain declaration or accesses to lexical
+         // variables inside then-clause, else-clause, and else-if condition.
+         MayContainLexicalAccessInBranch,
+ 
+         // For internally used branches which don't touch lexical variables
+         // inside then-clause, else-clause, nor else-if condition.
+         NoLexicalAccessInBranch
+     };
+-
+-  private:
+-    BytecodeEmitter* bce_;
+-
+-    // Jump around the then clause, to the beginning of the else clause.
+-    JumpList jumpAroundThen_;
++    Kind kind_;
+ 
+-    // Jump around the else clause, to the end of the entire branch.
+-    JumpList jumpsAroundElse_;
+-
+-    // The stack depth before emitting the then block.
+-    // Used for restoring stack depth before emitting the else block.
+-    // Also used for assertion to make sure then and else blocks pushed the
+-    // same number of values.
+-    int32_t thenDepth_;
+-
+-    Kind kind_;
+     mozilla::Maybe<TDZCheckCache> tdzCache_;
+ 
+ #ifdef DEBUG
+     // The number of values pushed in the then and else blocks.
+-    int32_t pushed_;
+-    bool calculatedPushed_;
+-
+-    // The state of this emitter.
+-    //
+-    // +-------+   emitCond +------+ emitElse +------+        emitEnd +-----+
+-    // | Start |-+--------->| Cond |--------->| Else |------>+------->| End |
+-    // +-------+ |          +------+          +------+       ^        +-----+
+-    //           |                                           |
+-    //           v emitThen +------+                         |
+-    //        +->+--------->| Then |------------------------>+
+-    //        ^  |          +------+                         ^
+-    //        |  |                                           |
+-    //        |  |                                           +---+
+-    //        |  |                                               |
+-    //        |  | emitThenElse +----------+   emitElse +------+ |
+-    //        |  +------------->| ThenElse |-+--------->| Else |-+
+-    //        |                 +----------+ |          +------+
+-    //        |                              |
+-    //        |                              | emitElseIf +--------+
+-    //        |                              +----------->| ElseIf |-+
+-    //        |                                           +--------+ |
+-    //        |                                                      |
+-    //        +------------------------------------------------------+
+-    enum class State {
+-        // The initial state.
+-        Start,
+-
+-        // After calling emitThen.
+-        Then,
+-
+-        // After calling emitCond.
+-        Cond,
+-
+-        // After calling emitThenElse.
+-        ThenElse,
+-
+-        // After calling emitElse.
+-        Else,
+-
+-        // After calling emitElseIf.
+-        ElseIf,
+-
+-        // After calling emitEnd.
+-        End
+-    };
+-    State state_;
++    int32_t pushed_ = 0;
++    bool calculatedPushed_ = false;
+ #endif
+ 
+   protected:
+-    // For InternalIfEmitter.
+-    IfEmitter(BytecodeEmitter* bce, Kind kind);
++    BranchEmitterBase(BytecodeEmitter* bce, Kind kind);
++
++    MOZ_MUST_USE bool emitThenInternal(SrcNoteType type);
++    void calculateOrCheckPushed();
++    MOZ_MUST_USE bool emitElseInternal();
++    MOZ_MUST_USE bool emitEndInternal();
+ 
+   public:
+-    explicit IfEmitter(BytecodeEmitter* bce);
+-
+-    MOZ_MUST_USE bool emitThen();
+-    MOZ_MUST_USE bool emitCond();
+-    MOZ_MUST_USE bool emitThenElse();
+-
+-    MOZ_MUST_USE bool emitElse();
+-    MOZ_MUST_USE bool emitElseIf();
+-
+-    MOZ_MUST_USE bool emitEnd();
+-
+ #ifdef DEBUG
+     // Returns the number of values pushed onto the value stack inside
+     // `then_block` and `else_block`.
+     // Can be used in assertion after emitting if-then-else.
+     int32_t pushed() const {
+         return pushed_;
+     }
+ 
+     // Returns the number of values popped onto the value stack inside
+     // `then_block` and `else_block`.
+     // Can be used in assertion after emitting if-then-else.
+     int32_t popped() const {
+         return -pushed_;
+     }
+ #endif
++};
+ 
+-  private:
+-    MOZ_MUST_USE bool emitIfInternal(SrcNoteType type);
+-    void calculateOrCheckPushed();
+-    MOZ_MUST_USE bool emitElseInternal();
++// Class for emitting bytecode for blocks like if-then-else.
++//
++// This class can be used to emit single if-then-else block, or cascading
++// else-if blocks.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `if (cond) then_block`
++//     IfEmitter ifThen(this);
++//     ifThen.emitIf(Some(offset_of_if));
++//     emit(cond);
++//     ifThen.emitThen();
++//     emit(then_block);
++//     ifThen.emitEnd();
++//
++//   `if (cond) then_block else else_block`
++//     IfEmitter ifThenElse(this);
++//     ifThen.emitIf(Some(offset_of_if));
++//     emit(cond);
++//     ifThenElse.emitThenElse();
++//     emit(then_block);
++//     ifThenElse.emitElse();
++//     emit(else_block);
++//     ifThenElse.emitEnd();
++//
++//   `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
++//     IfEmitter ifThenElse(this);
++//     ifThen.emitIf(Some(offset_of_if));
++//     emit(c1);
++//     ifThenElse.emitThenElse();
++//     emit(b1);
++//     ifThenElse.emitElseIf(Some(offset_of_if));
++//     emit(c2);
++//     ifThenElse.emitThenElse();
++//     emit(b2);
++//     ifThenElse.emitElseIf(Some(offset_of_if));
++//     emit(c3);
++//     ifThenElse.emitThenElse();
++//     emit(b3);
++//     ifThenElse.emitElse();
++//     emit(b4);
++//     ifThenElse.emitEnd();
++//
++class MOZ_STACK_CLASS IfEmitter : public BranchEmitterBase
++{
++  protected:
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitIf +----+
++    // | Start |------->| If |-+
++    // +-------+        +----+ |
++    //                         |
++    //    +--------------------+
++    //    |
++    //    v emitThen +------+                               emitEnd +-----+
++    // +->+--------->| Then |---------------------------->+-------->| End |
++    // ^  |          +------+                             ^         +-----+
++    // |  |                                               |
++    // |  |                                               |
++    // |  |                                               |
++    // |  | emitThenElse +----------+   emitElse +------+ |
++    // |  +------------->| ThenElse |-+--------->| Else |-+
++    // |                 +----------+ |          +------+
++    // |                              |
++    // |                              | emitElseIf +--------+
++    // |                              +----------->| ElseIf |-+
++    // |                                           +--------+ |
++    // |                                                      |
++    // +------------------------------------------------------+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitIf.
++        If,
++
++        // After calling emitThen.
++        Then,
++
++        // After calling emitThenElse.
++        ThenElse,
++
++        // After calling emitElse.
++        Else,
++
++        // After calling emitElseIf.
++        ElseIf,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  protected:
++    // For InternalIfEmitter.
++    IfEmitter(BytecodeEmitter* bce, Kind kind);
++
++  public:
++    explicit IfEmitter(BytecodeEmitter* bce);
++
++    // `ifPos` is the offset in the source code for the character below:
++    //
++    //   if ( cond ) { ... } else if ( cond2 ) { ... }
++    //   ^                        ^
++    //   |                        |
++    //   |                        ifPos for emitElseIf
++    //   |
++    //   ifPos for emitIf
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitIf(const mozilla::Maybe<uint32_t>& ifPos);
++
++    MOZ_MUST_USE bool emitThen();
++    MOZ_MUST_USE bool emitThenElse();
++
++    MOZ_MUST_USE bool emitElseIf(const mozilla::Maybe<uint32_t>& ifPos);
++    MOZ_MUST_USE bool emitElse();
++
++    MOZ_MUST_USE bool emitEnd();
+ };
+ 
+ // Class for emitting bytecode for blocks like if-then-else which doesn't touch
+ // lexical variables.
+ //
+ // See the comments above NoLexicalAccessInBranch for more details when to use
+ // this instead of IfEmitter.
++// Compared to IfEmitter, this class doesn't have emitIf method, given that
++// it doesn't have syntactic `if`, and also the `cond` value can be already
++// on the stack.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `if (cond) then_block else else_block` (effectively)
++//     emit(cond);
++//     InternalIfEmitter ifThenElse(this);
++//     ifThenElse.emitThenElse();
++//     emit(then_block);
++//     ifThenElse.emitElse();
++//     emit(else_block);
++//     ifThenElse.emitEnd();
++//
+ class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter
+ {
+   public:
+     explicit InternalIfEmitter(BytecodeEmitter* bce);
+ };
+ 
++// Class for emitting bytecode for conditional expression.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `cond ? then_expr : else_expr`
++//     CondEmitter condElse(this);
++//     condElse.emitCond();
++//     emit(cond);
++//     condElse.emitThenElse();
++//     emit(then_expr);
++//     condElse.emitElse();
++//     emit(else_expr);
++//     condElse.emitEnd();
++//
++class MOZ_STACK_CLASS CondEmitter : public BranchEmitterBase
++{
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitCond +------+ emitThenElse +----------+
++    // | Start |--------->| Cond |------------->| ThenElse |-+
++    // +-------+          +------+              +----------+ |
++    //                                                       |
++    //                                     +-----------------+
++    //                                     |
++    //                                     | emitElse +------+ emitEnd +-----+
++    //                                     +--------->| Else |-------->| End |
++    //                                                +------+         +-----+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitCond.
++        Cond,
++
++        // After calling emitThenElse.
++        ThenElse,
++
++        // After calling emitElse.
++        Else,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  public:
++    explicit CondEmitter(BytecodeEmitter* bce);
++
++    MOZ_MUST_USE bool emitCond();
++    MOZ_MUST_USE bool emitThenElse();
++    MOZ_MUST_USE bool emitElse();
++    MOZ_MUST_USE bool emitEnd();
++};
++
+ } /* namespace frontend */
+ } /* namespace js */
+ 
+ #endif /* frontend_IfEmitter_h */
+

+ 124 - 0
frg/work-js/mozilla-release/patches/1476409-63a1.patch

@@ -0,0 +1,124 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531886428 25200
+# Node ID 0e23f233f5cfc81731417f562456016a59a3d865
+# Parent  430be372318cdc8623ddb24c669ae042fd42f4fa
+Bug 1476409 - Fix a case where during tokenization we could overread source text by one code unit -- but safely, due to conservatively-written subsequent code.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -2337,17 +2337,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+               case 'b': unit = '\b'; break;
+               case 'f': unit = '\f'; break;
+               case 'n': unit = '\n'; break;
+               case 'r': unit = '\r'; break;
+               case 't': unit = '\t'; break;
+               case 'v': unit = '\v'; break;
+ 
+               case '\r':
+-                this->sourceUnits.matchCodeUnit('\n');
++                if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
++                    this->sourceUnits.matchCodeUnit('\n');
+                 MOZ_FALLTHROUGH;
+               case '\n': {
+                 // LineContinuation represents no code points.  We're manually
+                 // consuming a LineTerminatorSequence, so we must manually
+                 // update line/column info.
+                 if (!updateLineInfoForEOL())
+                     return false;
+ 
+diff --git a/js/src/tests/non262/syntax/linefeed-at-eof-in-unterminated-string-or-template.js b/js/src/tests/non262/syntax/linefeed-at-eof-in-unterminated-string-or-template.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/tests/non262/syntax/linefeed-at-eof-in-unterminated-string-or-template.js
+@@ -0,0 +1,88 @@
++/*
++ * Any copyright is dedicated to the Public Domain.
++ * http://creativecommons.org/licenses/publicdomain/
++ */
++
++//-----------------------------------------------------------------------------
++var BUGNUMBER = 1476409;
++var summary =
++  "Properly handle the case of U+005C REVERSE SOLIDUS U+000D CARRIAGE RETURN " +
++  "at the end of source text being tokenized, in the middle of a string or " +
++  "template literal, where the next code point in memory (outside the bounds " +
++  "of the source text) is U+000A LINE FEED";
++
++print(BUGNUMBER + ": " + summary);
++
++/**************
++ * BEGIN TEST *
++ **************/
++
++function expectSyntaxError(code)
++{
++  try
++  {
++    eval(code);
++    throw new Error("didn't throw");
++  }
++  catch (e)
++  {
++    assertEq(e instanceof SyntaxError, true,
++             "got " + e.name + ", expected SyntaxError");
++  }
++}
++
++// The fundamental requirements of this test:
++//
++// 1. The computed string that is eval'd must be a Script that ends in a string
++//    literal ending with the code points U+005C REVERSE SOLIDUS U+000D CARRIAGE
++//    RETURN.
++// 2. The *memory* that is actually tokenized/parsed by eval must be
++//    immediately followed by U+000A LINE FEED.
++//
++// There's only one way to guarantee a U+000A LINE FEED after the source text:
++// compute the source text as a dependent string,  of a larger (linear) string.
++//  A simple substr will do the trick -- just as long as the substring can't fit
++// in inline storage.  53 in the tests below comfortably exceeds all inline
++// storage limits.
++//
++// One final wrinkle: because we only tokenize/parse two-byte source text right
++// now, ensuring we directly tokenize/parse the dependent string's character
++// data means the dependent string must have two-byte character data, hence the
++// '\u1234' in the strings below.
++
++function singleQuote()
++{
++  var containsBadSingleQuoteLiteral =
++    "\u1234x'01234567890123456789012345678901234567890123456789\\\r\n0123456789";
++  //        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++  expectSyntaxError(containsBadSingleQuoteLiteral.substr(2, 53));
++}
++singleQuote();
++
++function doubleQuote()
++{
++  var containsBadDoubleQuoteLiteral =
++    "\u1234x\"01234567890123456789012345678901234567890123456789\\\r\n0123456789";
++  //        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++  expectSyntaxError(containsBadDoubleQuoteLiteral.substr(2, 53));
++}
++doubleQuote();
++
++function template()
++{
++  var containsBadTemplateLiteral =
++    "\u1234x`01234567890123456789012345678901234567890123456789\\\r\n0123456789";
++  //        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++  expectSyntaxError(containsBadTemplateLiteral.substr(2, 53));
++}
++template();
++
++/******************************************************************************/
++
++if (typeof reportCompare === "function")
++  reportCompare(true, true);
++
++print("Tests complete");
+

+ 163 - 0
frg/work-js/mozilla-release/patches/1476657-63a1.patch

@@ -0,0 +1,163 @@
+# HG changeset patch
+# User Robert Bartlensky <rbartlensky@mozilla.com>
+# Date 1532090675 -3600
+# Node ID 358b59601fb9f672a45394d94c308716e6ce96de
+# Parent  e5ec530fd95e85b8e67b991965e73c38373dbedc
+Bug 1476657: Fix DEAD_STORE issues in js/src/frontend/Parser.cpp. r=arai
+
+MozReview-Commit-ID: HI9p2AfOUiU
+
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -17,16 +17,17 @@
+  * This parser attempts no error recovery.
+  */
+ 
+ #include "frontend/Parser.h"
+ 
+ #include "mozilla/Range.h"
+ #include "mozilla/Sprintf.h"
+ #include "mozilla/TypeTraits.h"
++#include "mozilla/Unused.h"
+ 
+ #include <memory>
+ #include <new>
+ 
+ #include "jsapi.h"
+ #include "jstypes.h"
+ 
+ #include "builtin/ModuleObject.h"
+@@ -53,16 +54,17 @@
+ using namespace js;
+ using namespace js::gc;
+ 
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::PodCopy;
+ using mozilla::PodZero;
+ using mozilla::Some;
++using mozilla::Unused;
+ 
+ using JS::AutoGCRooter;
+ 
+ namespace js {
+ namespace frontend {
+ 
+ using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
+ using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
+@@ -1853,17 +1855,17 @@ NewGlobalScopeData(JSContext* context, P
+         BindingName* cursor = start;
+ 
+         cursor = FreshlyInitializeBindings(cursor, vars);
+ 
+         bindings->letStart = cursor - start;
+         cursor = FreshlyInitializeBindings(cursor, lets);
+ 
+         bindings->constStart = cursor - start;
+-        cursor = FreshlyInitializeBindings(cursor, consts);
++        Unused << FreshlyInitializeBindings(cursor, consts);
+ 
+         bindings->length = numBindings;
+     }
+ 
+     return Some(bindings);
+ }
+ 
+ Maybe<GlobalScope::Data*>
+@@ -1923,17 +1925,17 @@ NewModuleScopeData(JSContext* context, P
+ 
+         bindings->varStart = cursor - start;
+         cursor = FreshlyInitializeBindings(cursor, vars);
+ 
+         bindings->letStart = cursor - start;
+         cursor = FreshlyInitializeBindings(cursor, lets);
+ 
+         bindings->constStart = cursor - start;
+-        cursor = FreshlyInitializeBindings(cursor, consts);
++        Unused << FreshlyInitializeBindings(cursor, consts);
+ 
+         bindings->length = numBindings;
+     }
+ 
+     return Some(bindings);
+ }
+ 
+ Maybe<ModuleScope::Data*>
+@@ -1963,17 +1965,17 @@ NewEvalScopeData(JSContext* context, Par
+     if (numBindings > 0) {
+         bindings = NewEmptyBindingData<EvalScope>(context, alloc, numBindings);
+         if (!bindings)
+             return Nothing();
+ 
+         BindingName* start = bindings->trailingNames.start();
+         BindingName* cursor = start;
+ 
+-        cursor = FreshlyInitializeBindings(cursor, vars);
++        Unused << FreshlyInitializeBindings(cursor, vars);
+ 
+         bindings->length = numBindings;
+     }
+ 
+     return Some(bindings);
+ }
+ 
+ Maybe<EvalScope::Data*>
+@@ -2062,17 +2064,17 @@ NewFunctionScopeData(JSContext* context,
+         BindingName* cursor = start;
+ 
+         cursor = FreshlyInitializeBindings(cursor, positionalFormals);
+ 
+         bindings->nonPositionalFormalStart = cursor - start;
+         cursor = FreshlyInitializeBindings(cursor, formals);
+ 
+         bindings->varStart = cursor - start;
+-        cursor = FreshlyInitializeBindings(cursor, vars);
++        Unused << FreshlyInitializeBindings(cursor, vars);
+ 
+         bindings->length = numBindings;
+     }
+ 
+     return Some(bindings);
+ }
+ 
+ Maybe<FunctionScope::Data*>
+@@ -2103,17 +2105,17 @@ NewVarScopeData(JSContext* context, Pars
+         bindings = NewEmptyBindingData<VarScope>(context, alloc, numBindings);
+         if (!bindings)
+             return Nothing();
+ 
+         // The ordering here is important. See comments in FunctionScope.
+         BindingName* start = bindings->trailingNames.start();
+         BindingName* cursor = start;
+ 
+-        cursor = FreshlyInitializeBindings(cursor, vars);
++        Unused << FreshlyInitializeBindings(cursor, vars);
+ 
+         bindings->length = numBindings;
+     }
+ 
+     return Some(bindings);
+ }
+ 
+ Maybe<VarScope::Data*>
+@@ -2160,17 +2162,17 @@ NewLexicalScopeData(JSContext* context, 
+ 
+         // The ordering here is important. See comments in LexicalScope.
+         BindingName* cursor = bindings->trailingNames.start();
+         BindingName* start = cursor;
+ 
+         cursor = FreshlyInitializeBindings(cursor, lets);
+ 
+         bindings->constStart = cursor - start;
+-        cursor = FreshlyInitializeBindings(cursor, consts);
++        Unused << FreshlyInitializeBindings(cursor, consts);
+ 
+         bindings->length = numBindings;
+     }
+ 
+     return Some(bindings);
+ }
+ 
+ Maybe<LexicalScope::Data*>
+

+ 44 - 0
frg/work-js/mozilla-release/patches/1476866-01-63a1.patch

@@ -0,0 +1,44 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531886455 25200
+#      Tue Jul 17 21:00:55 2018 -0700
+# Node ID 1b604df36960311748f612b3dd01597938977d77
+# Parent  729210e6e8b614b8c51f16acf642f6f508679d98
+Bug 1476866 - Fix the TokenStreamChars::getNonAsciiCodePoint doc comment to be clearer about |lead| being non-ASCII but still potentially (for UTF-16) a full code point.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1498,26 +1498,27 @@ class TokenStreamChars<char16_t, AnyChar
+             *codePoint = EOF; // sentinel value to hopefully cause errors
+ #endif
+             MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
+         }
+         return ok;
+     }
+ 
+     /**
+-     * Given a just-consumed non-ASCII code unit (and maybe point) |lead|,
+-     * consume a full code point or LineTerminatorSequence (normalizing it to
+-     * '\n') and store it in |*codePoint|.  Return true on success, otherwise
+-     * return false and leave |*codePoint| undefined on failure.
++     * Given a just-consumed non-ASCII code unit |lead| (which may also be a
++     * full code point, for UTF-16), consume a full code point or
++     * LineTerminatorSequence (normalizing it to '\n') and store it in
++     * |*codePoint|.  Return true on success, otherwise return false and leave
++     * |*codePoint| undefined on failure.
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+      * This may change the current |sourceUnits| offset.
+      */
+-    MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* cp);
++    MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* codePoint);
+ 
+     /**
+      * Unget a full code point (ASCII or not) without altering line/column
+      * state.  If line/column state must be updated, this must happen manually.
+      * This method ungets a single code point, not a LineTerminatorSequence
+      * that is multiple code points.  (Generally you shouldn't be in a state
+      * where you've just consumed "\r\n" and want to unget that full sequence.)
+      *

+ 153 - 0
frg/work-js/mozilla-release/patches/1476866-02-63a1.patch

@@ -0,0 +1,153 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530922373 25200
+#      Fri Jul 06 17:12:53 2018 -0700
+# Node ID 9ed1d40847424b11e2bc6b5cbc7e497753c81938
+# Parent  1b604df36960311748f612b3dd01597938977d77
+Bug 1476866 - Add a SpecializedTokenStreamCharsBase class to the hierarchy as a clear collection point for functions entirely specific to UTF-8 or UTF-16 tokenizing only.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -55,33 +55,51 @@
+  * potentially the compiler *can't* unify them because offsets into the
+  * hypothetical TokenStream<CharT>s would differ.)  Second, some of this stuff
+  * needs to be accessible in ParserBase, the aspects of JS language parsing
+  * that have meaning independent of the character type of the source text being
+  * parsed.  So we need a separate data structure that ParserBase can hold on to
+  * for it.  (ParserBase isn't the only instance of this, but it's certainly the
+  * biggest case of it.)  Ergo, TokenStreamAnyChars.
+  *
+- * == TokenStreamCharsBase<CharT> → ∅ ==
++ * == TokenStreamCharsShared → ∅ ==
++ *
++ * Some functionality has meaning independent of character type, yet has no use
++ * *unless* you know the character type in actual use.  It *could* live in
++ * TokenStreamAnyChars, but it makes more sense to live in a separate class
++ * that character-aware token information can simply inherit.
+  *
+- * Certain data structures in tokenizing are character-type-specific:
++ * This class currently exists only to contain a char16_t buffer, transiently
++ * used to accumulate strings in tricky cases that can't just be read directly
++ * from source text.  It's not used outside character-aware tokenizing, so it
++ * doesn't make sense in TokenStreamAnyChars.
++ *
++ * == TokenStreamCharsBase<CharT> → TokenStreamCharsShared ==
++ *
++ * Certain data structures in tokenizing are character-type-specific: namely,
+  * the various pointers identifying the source text (including current offset
+- * and end) , and the temporary vector into which characters are read/written
+- * in certain cases (think writing out the actual codepoints identified by an
+- * identifier containing a Unicode escape, to create the atom for the
+- * identifier: |a\u0062c| versus |abc|, for example).
++ * and end).
+  *
+  * Additionally, some functions operating on this data are defined the same way
+- * no matter what character type you have -- the offset being |offset - start|
+- * no matter whether those two variables are single- or double-byte pointers.
++ * no matter what character type you have (e.g. current offset in code units
++ * into the source text) or share a common interface regardless of character
++ * type (e.g. consume the next code unit if it has a given value).
+  *
+  * All such functionality lives in TokenStreamCharsBase<CharT>.
+  *
++ * == SpecializedTokenStreamCharsBase<CharT> → TokenStreamCharsBase<CharT> ==
++ *
++ * Certain tokenizing functionality is specific to a single character type.
++ * For example, JS's UTF-16 encoding recognizes no coding errors, because lone
++ * surrogates are not an error; but a UTF-8 encoding must recognize a variety
++ * of validation errors.  Such functionality is defined only in the appropriate
++ * SpecializedTokenStreamCharsBase specialization.
++ *
+  * == GeneralTokenStreamChars<CharT, AnyCharsAccess> →
+- *    TokenStreamCharsBase<CharT> ==
++ *    SpecializedTokenStreamCharsBase<CharT> ==
+  *
+  * Some functionality operates differently on different character types, just
+  * as for TokenStreamCharsBase, but additionally requires access to character-
+  * type-agnostic information in TokenStreamAnyChars.  For example, getting the
+  * next character performs different steps for different character types and
+  * must access TokenStreamAnyChars to update line break information.
+  *
+  * Such functionality, if it can be defined using the same algorithm for all
+@@ -1274,16 +1292,39 @@ TokenStreamCharsBase<char16_t>::fillChar
+ 
+         if (!this->charBuffer.append(ch))
+             return false;
+     }
+ 
+     return true;
+ }
+ 
++template<typename CharT>
++class SpecializedTokenStreamCharsBase;
++
++template<>
++class SpecializedTokenStreamCharsBase<char16_t>
++  : public TokenStreamCharsBase<char16_t>
++{
++    using CharsBase = TokenStreamCharsBase<char16_t>;
++
++  protected:
++    using CharsBase::CharsBase;
++};
++
++template<>
++class SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>
++  : public TokenStreamCharsBase<mozilla::Utf8Unit>
++{
++    using CharsBase = TokenStreamCharsBase<mozilla::Utf8Unit>;
++
++  protected:
++    using CharsBase::CharsBase;
++};
++
+ /** A small class encapsulating computation of the start-offset of a Token. */
+ class TokenStart
+ {
+     uint32_t startOffset_;
+ 
+   public:
+     /**
+      * Compute a starting offset that is the current offset of |sourceUnits|,
+@@ -1297,19 +1338,20 @@ class TokenStart
+ 
+     TokenStart(const TokenStart&) = default;
+ 
+     uint32_t offset() const { return startOffset_; }
+ };
+ 
+ template<typename CharT, class AnyCharsAccess>
+ class GeneralTokenStreamChars
+-  : public TokenStreamCharsBase<CharT>
++  : public SpecializedTokenStreamCharsBase<CharT>
+ {
+     using CharsBase = TokenStreamCharsBase<CharT>;
++    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
+ 
+     Token* newTokenInternal(TokenKind kind, TokenStart start, TokenKind* out);
+ 
+     /**
+      * Allocates a new Token from the given offset to the current offset,
+      * ascribes it the given kind, and sets |*out| to that kind.
+      */
+     Token* newToken(TokenKind kind, TokenStart start, TokenStreamShared::Modifier modifier,
+@@ -1330,17 +1372,17 @@ class GeneralTokenStreamChars
+ 
+     uint32_t matchUnicodeEscape(uint32_t* codePoint);
+     uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+ 
+   protected:
+     using typename CharsBase::SourceUnits;
+ 
+   protected:
+-    using CharsBase::CharsBase;
++    using SpecializedCharsBase::SpecializedCharsBase;
+ 
+     TokenStreamAnyChars& anyCharsAccess() {
+         return AnyCharsAccess::anyChars(this);
+     }
+ 
+     const TokenStreamAnyChars& anyCharsAccess() const {
+         return AnyCharsAccess::anyChars(this);
+     }

+ 393 - 0
frg/work-js/mozilla-release/patches/1476866-03-63a1.patch

@@ -0,0 +1,393 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530305169 25200
+#      Fri Jun 29 13:46:09 2018 -0700
+# Node ID 44b64b5a44fcfdaf086bd32b7c8038efac5bf652
+# Parent  9ed1d40847424b11e2bc6b5cbc7e497753c81938
+Bug 1476866 - Move consumeRestOfSingleLineComment into TokenStreamChars (and the infallible UTF-16 implementation into SpecializedTokenStreamCharsBase) so that it can be easily specialized for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1506,26 +1506,26 @@ static const uint8_t firstCharKinds[] = 
+ #undef T_RB
+ #undef T_LC
+ #undef T_RC
+ #undef _______
+ 
+ static_assert(LastCharKind < (1 << (sizeof(firstCharKinds[0]) * 8)),
+               "Elements of firstCharKinds[] are too small");
+ 
+-template<typename CharT, class AnyCharsAccess>
+ void
+-GeneralTokenStreamChars<CharT, AnyCharsAccess>::consumeRestOfSingleLineComment()
++SpecializedTokenStreamCharsBase<char16_t>::infallibleConsumeRestOfSingleLineComment()
+ {
+-    int32_t c;
+-    do {
+-        c = getCodeUnit();
+-    } while (c != EOF && !SourceUnits::isRawEOLChar(c));
+-
+-    ungetCodeUnit(c);
++    while (MOZ_LIKELY(!this->sourceUnits.atEnd())) {
++        char16_t unit = this->sourceUnits.peekCodeUnit();
++        if (SourceUnits::isRawEOLChar(unit))
++            return;
++
++        this->sourceUnits.consumeKnownCodeUnit(unit);
++    }
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStart start,
+                                                           const CharT* numStart,
+                                                           Modifier modifier, TokenKind* out)
+ {
+@@ -2092,17 +2092,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             break;
+ 
+           case '<':
+             if (anyCharsAccess().options().allowHTMLComments) {
+                 // Treat HTML begin-comment as comment-till-end-of-line.
+                 if (matchCodeUnit('!')) {
+                     if (matchCodeUnit('-')) {
+                         if (matchCodeUnit('-')) {
+-                            consumeRestOfSingleLineComment();
++                            if (!consumeRestOfSingleLineComment())
++                                return false;
++
+                             continue;
+                         }
+                         ungetCodeUnit('-');
+                     }
+                     ungetCodeUnit('!');
+                 }
+             }
+             if (matchCodeUnit('<'))
+@@ -2137,17 +2139,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     bool shouldWarn = unit == '@';
+                     if (!getDirectives(false, shouldWarn))
+                         return false;
+                 } else {
+                     // NOTE: |unit| may be EOF here.
+                     ungetCodeUnit(unit);
+                 }
+ 
+-                consumeRestOfSingleLineComment();
++                if (!consumeRestOfSingleLineComment())
++                    return false;
++
+                 continue;
+             }
+ 
+             // Look for a multi-line comment.
+             if (matchCodeUnit('*')) {
+                 TokenStreamAnyChars& anyChars = anyCharsAccess();
+                 unsigned linenoBefore = anyChars.lineno;
+ 
+@@ -2194,17 +2198,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             break;
+ 
+           case '-':
+             if (matchCodeUnit('-')) {
+                 if (anyCharsAccess().options().allowHTMLComments &&
+                     !anyCharsAccess().flags.isDirtyLine)
+                 {
+                     if (matchCodeUnit('>')) {
+-                        consumeRestOfSingleLineComment();
++                        if (!consumeRestOfSingleLineComment())
++                            return false;
++
+                         continue;
+                     }
+                 }
+ 
+                 simpleKind = TokenKind::Dec;
+             } else {
+                 simpleKind = matchCodeUnit('=') ? TokenKind::SubAssign : TokenKind::Sub;
+             }
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1071,16 +1071,22 @@ class SourceUnits
+     bool matchCodeUnit(CharT c) {
+         if (*ptr == c) {    // this will nullptr-crash if poisoned
+             ptr++;
+             return true;
+         }
+         return false;
+     }
+ 
++    void consumeKnownCodeUnit(CharT c) {
++        MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
++        MOZ_ASSERT(*ptr == c, "consuming the wrong code unit");
++        ptr++;
++    }
++
+     /**
+      * Unget the '\n' (CR) that precedes a '\n' (LF), when ungetting a line
+      * terminator that's a full "\r\n" sequence.  If the prior code unit isn't
+      * '\r', do nothing.
+      */
+     void ungetOptionalCRBeforeLF() {
+         MOZ_ASSERT(ptr, "shouldn't unget a '\\r' from poisoned SourceUnits");
+         MOZ_ASSERT(*ptr == CharT('\n'),
+@@ -1213,26 +1219,24 @@ class TokenStreamCharsBase
+     /** Match a non-EOL, non-EOF code unit; return true iff it was matched. */
+     inline bool matchCodeUnit(int32_t expect);
+ 
+   protected:
+     int32_t peekCodeUnit() {
+         return MOZ_LIKELY(!sourceUnits.atEnd()) ? CodeUnitValue(sourceUnits.peekCodeUnit()) : EOF;
+     }
+ 
+-    void consumeKnownCodeUnit(int32_t unit) {
+-        MOZ_ASSERT(unit != EOF, "shouldn't be matching EOF");
+-        MOZ_ASSERT(!sourceUnits.atEnd(), "must have units to consume");
+-#ifdef DEBUG
+-        CharT next =
+-#endif
+-            sourceUnits.getCodeUnit();
+-        MOZ_ASSERT(CodeUnitValue(next) == unit,
+-                   "must be consuming the correct unit");
+-    }
++    /** Consume a known, non-EOF code unit. */
++    inline void consumeKnownCodeUnit(int32_t unit);
++
++    // Forbid accidental calls to consumeKnownCodeUnit *not* with the single
++    // unit-or-EOF type.  CharT should use SourceUnits::consumeKnownCodeUnit;
++    // CodeUnitValue() results should go through toCharT(), or better yet just
++    // use the original CharT.
++    template<typename T> inline void consumeKnownCodeUnit(T) = delete;
+ 
+     MOZ_MUST_USE inline bool
+     fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+@@ -1248,16 +1252,23 @@ TokenStreamCharsBase<char16_t>::toCharT(
+ template<>
+ inline mozilla::Utf8Unit
+ TokenStreamCharsBase<mozilla::Utf8Unit>::toCharT(int32_t value)
+ {
+     MOZ_ASSERT(value != EOF, "EOF is not a CharT");
+     return mozilla::Utf8Unit(static_cast<unsigned char>(value));
+ }
+ 
++template<typename CharT>
++inline void
++TokenStreamCharsBase<CharT>::consumeKnownCodeUnit(int32_t unit)
++{
++    sourceUnits.consumeKnownCodeUnit(toCharT(unit));
++}
++
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+                                                    size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
+@@ -1302,26 +1313,53 @@ class SpecializedTokenStreamCharsBase;
+ 
+ template<>
+ class SpecializedTokenStreamCharsBase<char16_t>
+   : public TokenStreamCharsBase<char16_t>
+ {
+     using CharsBase = TokenStreamCharsBase<char16_t>;
+ 
+   protected:
++    // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
++
++    using typename CharsBase::SourceUnits;
++
++  protected:
++    // These APIs are only usable by UTF-16-specific code.
++
++    /**
++     * Consume the rest of a single-line comment (but not the EOL/EOF that
++     * terminates it) -- infallibly because no 16-bit code unit sequence in a
++     * comment is an error.
++     */
++    void infallibleConsumeRestOfSingleLineComment();
++
++  protected:
++    // These APIs are in both SpecializedTokenStreamCharsBase specializations
++    // and so are usable in subclasses no matter what CharT is.
++
+     using CharsBase::CharsBase;
+ };
+ 
+ template<>
+ class SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>
+   : public TokenStreamCharsBase<mozilla::Utf8Unit>
+ {
+     using CharsBase = TokenStreamCharsBase<mozilla::Utf8Unit>;
+ 
+   protected:
++    // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
++
++  protected:
++    // These APIs are only usable by UTF-8-specific code.
++
++  protected:
++    // These APIs are in both SpecializedTokenStreamCharsBase specializations
++    // and so are usable in subclasses no matter what CharT is.
++
+     using CharsBase::CharsBase;
+ };
+ 
+ /** A small class encapsulating computation of the start-offset of a Token. */
+ class TokenStart
+ {
+     uint32_t startOffset_;
+ 
+@@ -1454,48 +1492,44 @@ class GeneralTokenStreamChars
+     }
+ 
+     void ungetCodeUnit(int32_t c) {
+         MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
+ 
+         CharsBase::ungetCodeUnit(c);
+     }
+ 
+-    /**
+-     * Consume code units til EOL/EOF following the start of a single-line
+-     * comment, without consuming the EOL/EOF.
+-     */
+-    void consumeRestOfSingleLineComment();
+-
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+         return anyCharsAccess().internalUpdateLineInfoForEOL(this->sourceUnits.offset());
+     }
+ 
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ };
+ 
+ template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+ 
+ template<class AnyCharsAccess>
+ class TokenStreamChars<char16_t, AnyCharsAccess>
+   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
+ {
+   private:
+     using CharsBase = TokenStreamCharsBase<char16_t>;
++    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<char16_t>;
+     using GeneralCharsBase = GeneralTokenStreamChars<char16_t, AnyCharsAccess>;
+     using Self = TokenStreamChars<char16_t, AnyCharsAccess>;
+ 
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
++    using SpecializedCharsBase::infallibleConsumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+ 
+   protected:
+@@ -1588,16 +1622,27 @@ class TokenStreamChars<char16_t, AnyChar
+     }
+ 
+     /**
+      * Unget a just-gotten LineTerminator sequence: '\r', '\n', '\r\n', or
+      * a Unicode line/paragraph separator, also undoing line/column information
+      * changes reflecting that LineTerminator.
+      */
+     void ungetLineTerminator();
++
++    /**
++     * Consume code points til EOL/EOF following the start of a single-line
++     * comment, without consuming the EOL/EOF.
++     */
++    MOZ_MUST_USE bool consumeRestOfSingleLineComment() {
++        // This operation is infallible for UTF-16 -- and this implementation
++        // approach lets the compiler boil away call-side fallibility handling.
++        infallibleConsumeRestOfSingleLineComment();
++        return true;
++    }
+ };
+ 
+ // TokenStream is the lexical scanner for JavaScript source text.
+ //
+ // It takes a buffer of CharT code units (currently only char16_t encoding
+ // UTF-16, but we're adding either UTF-8 or Latin-1 single-byte text soon) and
+ // linearly scans it into |Token|s.
+ //
+@@ -1639,18 +1684,19 @@ class TokenStreamChars<char16_t, AnyChar
+ template<typename CharT, class AnyCharsAccess>
+ class MOZ_STACK_CLASS TokenStreamSpecific
+   : public TokenStreamChars<CharT, AnyCharsAccess>,
+     public TokenStreamShared,
+     public ErrorReporter
+ {
+   public:
+     using CharsBase = TokenStreamCharsBase<CharT>;
++    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
+     using GeneralCharsBase = GeneralTokenStreamChars<CharT, AnyCharsAccess>;
+-    using SpecializedCharsBase = TokenStreamChars<CharT, AnyCharsAccess>;
++    using SpecializedChars = TokenStreamChars<CharT, AnyCharsAccess>;
+ 
+     using Position = TokenStreamPosition<CharT>;
+ 
+     // Anything inherited through a base class whose type depends upon this
+     // class's template parameters can only be accessed through a dependent
+     // name: prefixed with |this|, by explicit qualification, and so on.  (This
+     // is so that references to inherited fields are statically distinguishable
+     // from references to names outside of the class.)  This is tedious and
+@@ -1667,38 +1713,38 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using typename CharsBase::SourceUnits;
+ 
+   private:
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+     using CharsBase::atomizeSourceChars;
+     using GeneralCharsBase::badToken;
+     // Deliberately don't |using| |charBuffer| because of bug 1472569.  :-(
+     using CharsBase::consumeKnownCodeUnit;
+-    using GeneralCharsBase::consumeRestOfSingleLineComment;
++    using SpecializedChars::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+-    using SpecializedCharsBase::getCodePoint;
++    using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+-    using SpecializedCharsBase::getFullAsciiCodePoint;
+-    using SpecializedCharsBase::getNonAsciiCodePoint;
++    using SpecializedChars::getFullAsciiCodePoint;
++    using SpecializedChars::getNonAsciiCodePoint;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+     using CharsBase::peekCodeUnit;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+-    using SpecializedCharsBase::ungetCodePointIgnoreEOL;
++    using SpecializedChars::ungetCodePointIgnoreEOL;
+     using GeneralCharsBase::ungetCodeUnit;
+-    using SpecializedCharsBase::ungetNonAsciiNormalizedCodePoint;
++    using SpecializedChars::ungetNonAsciiNormalizedCodePoint;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     template<typename CharU> friend class TokenStreamPosition;
+ 
+   public:
+     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
+                         const CharT* base, size_t length);
+ 

+ 163 - 0
frg/work-js/mozilla-release/patches/1476866-04-63a1.patch

@@ -0,0 +1,163 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531172296 25200
+#      Mon Jul 09 14:38:16 2018 -0700
+# Node ID 3a4e6ae59b597084afaed1d84d1674ee556406d5
+# Parent  44b64b5a44fcfdaf086bd32b7c8038efac5bf652
+Bug 1476866 - Add a getNonAsciiCodePointDontNormalize for use in situations that demand such.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1324,30 +1324,25 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     return false;
+ 
+                 continue;
+             }
+ 
+             if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint))
+                 break;
+         } else {
+-            int32_t cp;
+-            if (!getNonAsciiCodePoint(unit, &cp))
++            // |restoreNextRawCharAddress| undoes all gets, and this function
++            // doesn't update line/column info.
++            char32_t cp;
++            if (!getNonAsciiCodePointDontNormalize(unit, &cp))
+                 return false;
+ 
+-            codePoint = AssertedCast<uint32_t>(cp);
+-
+-            if (!unicode::IsIdentifierPart(codePoint)) {
+-                if (MOZ_UNLIKELY(codePoint == '\n')) {
+-                    // |restoreNextRawCharAddress| will undo all gets, but we
+-                    // have to revert a line/column update manually.
+-                    anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+-                }
++            codePoint = cp;
++            if (!unicode::IsIdentifierPart(codePoint))
+                 break;
+-            }
+         }
+ 
+         if (!appendCodePointToCharBuffer(codePoint))
+             return false;
+     } while (true);
+ 
+     return true;
+ }
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1313,30 +1313,53 @@ class SpecializedTokenStreamCharsBase;
+ 
+ template<>
+ class SpecializedTokenStreamCharsBase<char16_t>
+   : public TokenStreamCharsBase<char16_t>
+ {
+     using CharsBase = TokenStreamCharsBase<char16_t>;
+ 
+   protected:
++    using TokenStreamCharsShared::isAsciiCodePoint;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+ 
+     using typename CharsBase::SourceUnits;
+ 
+   protected:
+     // These APIs are only usable by UTF-16-specific code.
+ 
+     /**
+      * Consume the rest of a single-line comment (but not the EOL/EOF that
+      * terminates it) -- infallibly because no 16-bit code unit sequence in a
+      * comment is an error.
+      */
+     void infallibleConsumeRestOfSingleLineComment();
+ 
++    /**
++     * Given |lead| already consumed, consume and return the code point encoded
++     * starting from it.  Infallible because lone surrogates in JS encode a
++     * "code point" of the same value.
++     */
++    char32_t infallibleGetNonAsciiCodePointDontNormalize(char16_t lead) {
++        MOZ_ASSERT(!isAsciiCodePoint(lead));
++        MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == lead);
++
++        // Handle single-unit code points and lone trailing surrogates.
++        if (MOZ_LIKELY(!unicode::IsLeadSurrogate(lead)) ||
++            // Or handle lead surrogates not paired with trailing surrogates.
++            MOZ_UNLIKELY(this->sourceUnits.atEnd() ||
++                         !unicode::IsTrailSurrogate(this->sourceUnits.peekCodeUnit())))
++        {
++            return lead;
++        }
++
++        // Otherwise it's a multi-unit code point.
++        return unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
++    }
++
+   protected:
+     // These APIs are in both SpecializedTokenStreamCharsBase specializations
+     // and so are usable in subclasses no matter what CharT is.
+ 
+     using CharsBase::CharsBase;
+ };
+ 
+ template<>
+@@ -1520,26 +1543,39 @@ class TokenStreamChars<char16_t, AnyChar
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedCharsBase::infallibleConsumeRestOfSingleLineComment;
++    using SpecializedCharsBase::infallibleGetNonAsciiCodePointDontNormalize;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+ 
+   protected:
+     using GeneralCharsBase::GeneralCharsBase;
+ 
++    /**
++     * Given the non-ASCII |lead| code unit just consumed, consume and return a
++     * complete non-ASCII code point.  Line/column updates are not performed,
++     * and line breaks are returned as-is without normalization.
++     */
++    MOZ_MUST_USE bool getNonAsciiCodePointDontNormalize(char16_t lead, char32_t* codePoint) {
++        // There are no encoding errors in 16-bit JS, so implement this so that
++        // the compiler knows it, too.
++        *codePoint = infallibleGetNonAsciiCodePointDontNormalize(lead);
++        return true;
++    }
++
+     // Try to get the next code point, normalizing '\r', '\r\n', '\n', and the
+     // Unicode line/paragraph separators into '\n'.  Also updates internal
+     // line-counter state.  Return true on success and store the code point in
+     // |*c|.  Return false and leave |*c| undefined on failure.
+     MOZ_MUST_USE bool getCodePoint(int32_t* cp);
+ 
+     /**
+      * Given a just-consumed ASCII code unit/point |lead|, consume a full code
+@@ -1721,16 +1757,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using SpecializedChars::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedChars::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
++    using SpecializedChars::getNonAsciiCodePointDontNormalize;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;

+ 166 - 0
frg/work-js/mozilla-release/patches/1476866-05-63a1.patch

@@ -0,0 +1,166 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531178570 25200
+#      Mon Jul 09 16:22:50 2018 -0700
+# Node ID 80b3a14e84c23a7215243376d1a3143a985aee8a
+# Parent  3a4e6ae59b597084afaed1d84d1674ee556406d5
+Bug 1476866 - Remove ungetLineTerminator, used only to unget Unicode separators, and replace it with a SourceUnits::ungetLineOrParagraphSeparator.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -596,31 +596,16 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     unicode::UTF16Encode(codePoint, units, &numUnits);
+ 
+     MOZ_ASSERT(numUnits == 1 || numUnits == 2);
+ 
+     while (numUnits-- > 0)
+         ungetCodeUnit(units[numUnits]);
+ }
+ 
+-template<class AnyCharsAccess>
+-void
+-TokenStreamChars<char16_t, AnyCharsAccess>::ungetLineTerminator()
+-{
+-    this->sourceUnits.ungetCodeUnit();
+-
+-    char16_t last = this->sourceUnits.peekCodeUnit();
+-    MOZ_ASSERT(SourceUnits::isRawEOLChar(last));
+-
+-    if (last == '\n')
+-        this->sourceUnits.ungetOptionalCRBeforeLF();
+-
+-    anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+-}
+-
+ template<typename CharT>
+ size_t
+ SourceUnits<CharT>::findEOLMax(size_t start, size_t max)
+ {
+     const CharT* p = codeUnitPtrAt(start);
+ 
+     size_t n = 0;
+     while (true) {
+@@ -1618,23 +1603,26 @@ template<typename CharT, class AnyCharsA
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
+ {
+     MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '/');
+     this->charBuffer.clear();
+ 
+     auto ProcessNonAsciiCodePoint = [this](int32_t lead) {
+         MOZ_ASSERT(lead != EOF);
+-
+-        int32_t codePoint;
+-        if (!this->getNonAsciiCodePoint(lead, &codePoint))
++        MOZ_ASSERT(!this->isAsciiCodePoint(lead));
++
++        char32_t codePoint;
++        if (!this->getNonAsciiCodePointDontNormalize(lead, &codePoint))
+             return false;
+ 
+-        if (codePoint == '\n') {
+-            this->ungetLineTerminator();
++        if (MOZ_UNLIKELY(codePoint == unicode::LINE_SEPARATOR ||
++                         codePoint == unicode::PARA_SEPARATOR))
++        {
++            this->sourceUnits.ungetLineOrParagraphSeparator();
+             this->reportError(JSMSG_UNTERMINATED_REGEXP);
+             return false;
+         }
+ 
+         return this->appendCodePointToCharBuffer(codePoint);
+     };
+ 
+     auto ReportUnterminatedRegExp = [this](CharT unit) {
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1092,16 +1092,19 @@ class SourceUnits
+         MOZ_ASSERT(*ptr == CharT('\n'),
+                    "function should only be called when a '\\n' was just "
+                    "ungotten, and any '\\r' preceding it must also be "
+                    "ungotten");
+         if (*(ptr - 1) == CharT('\r'))
+             ptr--;
+     }
+ 
++    /** Unget U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR. */
++    inline void ungetLineOrParagraphSeparator();
++
+     void ungetCodeUnit() {
+         MOZ_ASSERT(!atStart(), "can't unget if currently at start");
+         MOZ_ASSERT(ptr);     // make sure it hasn't been poisoned
+         ptr--;
+     }
+ 
+     const CharT* addressOfNextCodeUnit(bool allowPoisoned = false) const {
+         MOZ_ASSERT_IF(!allowPoisoned, ptr);     // make sure it hasn't been poisoned
+@@ -1141,16 +1144,43 @@ class SourceUnits
+ 
+     /** Limit for quick bounds check. */
+     const CharT* limit_;
+ 
+     /** Next char to get. */
+     const CharT* ptr;
+ };
+ 
++template<>
++inline void
++SourceUnits<char16_t>::ungetLineOrParagraphSeparator()
++{
++#ifdef DEBUG
++    char16_t prev = previousCodeUnit();
++#endif
++    MOZ_ASSERT(prev == unicode::LINE_SEPARATOR || prev == unicode::PARA_SEPARATOR);
++
++    ungetCodeUnit();
++}
++
++template<>
++inline void
++SourceUnits<mozilla::Utf8Unit>::ungetLineOrParagraphSeparator()
++{
++    unskipCodeUnits(3);
++
++    MOZ_ASSERT(ptr[0].toUint8() == 0xE2);
++    MOZ_ASSERT(ptr[1].toUint8() == 0x80);
++
++#ifdef DEBUG
++    uint8_t last = ptr[2].toUint8();
++#endif
++    MOZ_ASSERT(last == 0xA8 || last == 0xA9);
++}
++
+ class TokenStreamCharsShared
+ {
+     // Using char16_t (not CharT) is a simplifying decision that hopefully
+     // eliminates the need for a UTF-8 regular expression parser and makes
+     // |copyCharBufferTo| markedly simpler.
+     using CharBuffer = Vector<char16_t, 32>;
+ 
+   protected:
+@@ -1653,23 +1683,16 @@ class TokenStreamChars<char16_t, AnyChar
+                    "should not be ungetting un-normalized code points");
+ 
+         ungetCodePointIgnoreEOL(codePoint);
+         if (codePoint == '\n')
+             anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+     }
+ 
+     /**
+-     * Unget a just-gotten LineTerminator sequence: '\r', '\n', '\r\n', or
+-     * a Unicode line/paragraph separator, also undoing line/column information
+-     * changes reflecting that LineTerminator.
+-     */
+-    void ungetLineTerminator();
+-
+-    /**
+      * Consume code points til EOL/EOF following the start of a single-line
+      * comment, without consuming the EOL/EOF.
+      */
+     MOZ_MUST_USE bool consumeRestOfSingleLineComment() {
+         // This operation is infallible for UTF-16 -- and this implementation
+         // approach lets the compiler boil away call-side fallibility handling.
+         infallibleConsumeRestOfSingleLineComment();
+         return true;

+ 109 - 0
frg/work-js/mozilla-release/patches/1476866-06-63a1.patch

@@ -0,0 +1,109 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531886456 25200
+#      Tue Jul 17 21:00:56 2018 -0700
+# Node ID 0ed3f8f103c013b9c360360c6337956175b59ef5
+# Parent  80b3a14e84c23a7215243376d1a3143a985aee8a
+Bug 1476866 - Reduce code indentation in the loop to accumulate regular expression source text by handling the non-ASCII case in an early block-with-continue.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1633,55 +1633,63 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     bool inCharClass = false;
+     do {
+         int32_t unit = getCodeUnit();
+         if (unit == EOF) {
+             ReportUnterminatedRegExp(unit);
+             return badToken();
+         }
+ 
+-        if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+-            if (unit == '\\')  {
+-                if (!this->charBuffer.append(unit))
+-                    return badToken();
+-
+-                unit = getCodeUnit();
+-                if (unit == EOF) {
+-                    ReportUnterminatedRegExp(unit);
+-                    return badToken();
+-                }
+-
+-                // Fallthrough only handles ASCII code points, so
+-                // deal with non-ASCII and skip everything else.
+-                if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+-                    if (!ProcessNonAsciiCodePoint(unit))
+-                        return badToken();
+-
+-                    continue;
+-                }
+-            } else if (unit == '[') {
+-                inCharClass = true;
+-            } else if (unit == ']') {
+-                inCharClass = false;
+-            } else if (unit == '/' && !inCharClass) {
+-                // For IE compat, allow unescaped / in char classes.
+-                break;
+-            }
+-
+-            if (unit == '\r' || unit == '\n') {
++        if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
++            if (!ProcessNonAsciiCodePoint(unit))
++                return badToken();
++
++            continue;
++        }
++
++        if (unit == '\\')  {
++            if (!this->charBuffer.append(unit))
++                return badToken();
++
++            unit = getCodeUnit();
++            if (unit == EOF) {
+                 ReportUnterminatedRegExp(unit);
+                 return badToken();
+             }
+ 
+-            if (!this->charBuffer.append(unit))
+-                return badToken();
+-        } else {
+-            if (!ProcessNonAsciiCodePoint(unit))
+-                return badToken();
++            // Fallthrough only handles ASCII code points, so
++            // deal with non-ASCII and skip everything else.
++            if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
++                if (!ProcessNonAsciiCodePoint(unit))
++                    return badToken();
++
++                continue;
++            }
++        } else if (unit == '[') {
++            inCharClass = true;
++        } else if (unit == ']') {
++            inCharClass = false;
++        } else if (unit == '/' && !inCharClass) {
++            // For IE compat, allow unescaped / in char classes.
++            break;
+         }
++
++        if (unit == '\r' || unit == '\n') {
++            ReportUnterminatedRegExp(unit);
++            return badToken();
++        }
++
++        // We're accumulating regular expression *source* text here: source
++        // text matching a line break will appear as U+005C REVERSE SOLIDUS
++        // U+006E LATIN SMALL LETTER N, and |unit| here would be the latter
++        // code point.
++        MOZ_ASSERT(!SourceUnits::isRawEOLChar(unit));
++
++        if (!this->charBuffer.append(unit))
++            return badToken();
+     } while (true);
+ 
+     int32_t unit;
+     RegExpFlag reflags = NoFlags;
+     while (true) {
+         RegExpFlag flag;
+         unit = getCodeUnit();
+         if (unit == 'g')

+ 349 - 0
frg/work-js/mozilla-release/patches/1476866-07-63a1.patch

@@ -0,0 +1,349 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531886457 25200
+#      Tue Jul 17 21:00:57 2018 -0700
+# Node ID 4bd4c0e74bc6ce7ef610ef902085a3609b9517f8
+# Parent  0ed3f8f103c013b9c360360c6337956175b59ef5
+Bug 1476866 - Make matchCodeUnit only accept ASCII, and split matchLineTerminator (for '\r' and '\n') out of it.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -482,19 +482,16 @@ void
+ TokenStreamAnyChars::undoInternalUpdateLineInfoForEOL()
+ {
+     MOZ_ASSERT(prevLinebase != size_t(-1)); // we should never get more than one EOL
+     linebase = prevLinebase;
+     prevLinebase = size_t(-1);
+     lineno--;
+ }
+ 
+-// This gets a full code point, starting from an already-consumed leading code
+-// unit, normalizing EOL sequences to '\n', also updating line/column info as
+-// needed.
+ template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
+ {
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+     if (MOZ_UNLIKELY(this->sourceUnits.atEnd())) {
+         anyChars.flags.isEOF = true;
+@@ -505,20 +502,17 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     int32_t c = this->sourceUnits.getCodeUnit();
+ 
+     do {
+         // Normalize the char16_t if it was a newline.
+         if (MOZ_UNLIKELY(c == '\n'))
+             break;
+ 
+         if (MOZ_UNLIKELY(c == '\r')) {
+-            // If it's a \r\n sequence: treat as a single EOL, skip over the \n.
+-            if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
+-                this->sourceUnits.matchCodeUnit('\n');
+-
++            matchLineTerminator('\n');
+             break;
+         }
+ 
+         if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR))
+             break;
+ 
+         *cp = c;
+         return true;
+@@ -1841,19 +1835,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         // Look for a string or a template string.
+         //
+         if (c1kind == String)
+             return getStringOrTemplateToken(static_cast<char>(unit), modifier, ttp);
+ 
+         // Skip over EOL chars, updating line state along the way.
+         //
+         if (c1kind == EOL) {
+-            // If it's a \r\n sequence, consume it as a single EOL.
+-            if (unit == '\r' && !this->sourceUnits.atEnd())
+-                this->sourceUnits.matchCodeUnit('\n');
++            if (unit == '\r')
++                matchLineTerminator('\n');
+ 
+             if (!updateLineInfoForEOL())
+                 return badToken();
+ 
+             anyCharsAccess().updateFlagsForEOL();
+             continue;
+         }
+ 
+@@ -2334,18 +2327,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+               case 'b': unit = '\b'; break;
+               case 'f': unit = '\f'; break;
+               case 'n': unit = '\n'; break;
+               case 'r': unit = '\r'; break;
+               case 't': unit = '\t'; break;
+               case 'v': unit = '\v'; break;
+ 
+               case '\r':
+-                if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
+-                    this->sourceUnits.matchCodeUnit('\n');
++                matchLineTerminator('\n');
+                 MOZ_FALLTHROUGH;
+               case '\n': {
+                 // LineContinuation represents no code points.  We're manually
+                 // consuming a LineTerminatorSequence, so we must manually
+                 // update line/column info.
+                 if (!updateLineInfoForEOL())
+                     return false;
+ 
+@@ -2541,20 +2533,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 // String literals don't allow ASCII line breaks.
+                 ungetCodeUnit(unit);
+                 ReportPrematureEndOfLiteral(JSMSG_EOL_BEFORE_END_OF_STRING);
+                 return false;
+             }
+ 
+             if (unit == '\r') {
+                 unit = '\n';
+-
+-                // If it's a \r\n sequence: treat as a single EOL, skip over the \n.
+-                if (!this->sourceUnits.atEnd())
+-                    this->sourceUnits.matchCodeUnit('\n');
++                matchLineTerminator('\n');
+             }
+ 
+             if (!updateLineInfoForEOL())
+                 return false;
+ 
+             anyCharsAccess().updateFlagsForEOL();
+         } else if (parsingTemplate && unit == '$' && matchCodeUnit('{')) {
+             templateHead = true;
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -941,16 +941,19 @@ CodeUnitValue(char16_t unit)
+ }
+ 
+ constexpr uint8_t
+ CodeUnitValue(mozilla::Utf8Unit unit)
+ {
+     return unit.toUint8();
+ }
+ 
++template<typename CharT>
++class TokenStreamCharsBase;
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //
+@@ -1063,24 +1066,29 @@ class SourceUnits
+ 
+     void unskipCodeUnits(uint32_t n) {
+         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+         MOZ_ASSERT(n <= mozilla::PointerRangeSize(base_, ptr),
+                    "shouldn't unskip beyond start of SourceUnits");
+         ptr -= n;
+     }
+ 
+-    bool matchCodeUnit(CharT c) {
+-        if (*ptr == c) {    // this will nullptr-crash if poisoned
++  private:
++    friend class TokenStreamCharsBase<CharT>;
++
++    bool internalMatchCodeUnit(CharT c) {
++        MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
++        if (MOZ_LIKELY(!atEnd()) && *ptr == c) {
+             ptr++;
+             return true;
+         }
+         return false;
+     }
+ 
++  public:
+     void consumeKnownCodeUnit(CharT c) {
+         MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+         MOZ_ASSERT(*ptr == c, "consuming the wrong code unit");
+         ptr++;
+     }
+ 
+     /**
+      * Unget the '\n' (CR) that precedes a '\n' (LF), when ungetting a line
+@@ -1220,41 +1228,59 @@ class TokenStreamCharsShared
+     CharBuffer& getCharBuffer() { return charBuffer; }
+ };
+ 
+ template<typename CharT>
+ class TokenStreamCharsBase
+   : public TokenStreamCharsShared
+ {
+   protected:
++    TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
++
+     /**
+      * Convert a non-EOF code unit returned by |getCodeUnit()| or
+      * |peekCodeUnit()| to a CharT code unit.
+      */
+     inline CharT toCharT(int32_t codeUnitValue);
+ 
+     void ungetCodeUnit(int32_t c) {
+         if (c == EOF)
+             return;
+ 
+         sourceUnits.ungetCodeUnit();
+     }
+ 
+-  public:
+-    TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
+-
+     static MOZ_ALWAYS_INLINE JSAtom*
+     atomizeSourceChars(JSContext* cx, const CharT* chars, size_t length);
+ 
+     using SourceUnits = frontend::SourceUnits<CharT>;
+ 
+-    /** Match a non-EOL, non-EOF code unit; return true iff it was matched. */
+-    inline bool matchCodeUnit(int32_t expect);
++    /**
++     * Try to match a non-LineTerminator ASCII code point.  Return true iff it
++     * was matched.
++     */
++    bool matchCodeUnit(char expect) {
++        MOZ_ASSERT(mozilla::IsAscii(expect));
++        MOZ_ASSERT(expect != '\r');
++        MOZ_ASSERT(expect != '\n');
++        return this->sourceUnits.internalMatchCodeUnit(CharT(expect));
++    }
+ 
+-  protected:
++    /**
++     * Try to match an ASCII LineTerminator code point.  Return true iff it was
++     * matched.
++     */
++    bool matchLineTerminator(char expect) {
++        MOZ_ASSERT(expect == '\r' || expect == '\n');
++        return this->sourceUnits.internalMatchCodeUnit(CharT(expect));
++    }
++
++    template<typename T> bool matchCodeUnit(T) = delete;
++    template<typename T> bool matchLineTerminator(T) = delete;
++
+     int32_t peekCodeUnit() {
+         return MOZ_LIKELY(!sourceUnits.atEnd()) ? CodeUnitValue(sourceUnits.peekCodeUnit()) : EOF;
+     }
+ 
+     /** Consume a known, non-EOF code unit. */
+     inline void consumeKnownCodeUnit(int32_t unit);
+ 
+     // Forbid accidental calls to consumeKnownCodeUnit *not* with the single
+@@ -1297,26 +1323,16 @@ TokenStreamCharsBase<CharT>::consumeKnow
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+                                                    size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
+-template<typename CharT>
+-inline bool
+-TokenStreamCharsBase<CharT>::matchCodeUnit(int32_t expect)
+-{
+-    MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
+-    MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
+-    return MOZ_LIKELY(!this->sourceUnits.atEnd()) &&
+-           this->sourceUnits.matchCodeUnit(toCharT(expect));
+-}
+-
+ template<>
+ MOZ_MUST_USE inline bool
+ TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
+                                                                          const char16_t* end)
+ {
+     MOZ_ASSERT(this->charBuffer.length() == 0);
+ 
+     while (cur < end) {
+@@ -1575,16 +1591,17 @@ class TokenStreamChars<char16_t, AnyChar
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedCharsBase::infallibleConsumeRestOfSingleLineComment;
+     using SpecializedCharsBase::infallibleGetNonAsciiCodePointDontNormalize;
+     using TokenStreamCharsShared::isAsciiCodePoint;
++    using CharsBase::matchLineTerminator;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+ 
+   protected:
+     using GeneralCharsBase::GeneralCharsBase;
+@@ -1596,20 +1613,22 @@ class TokenStreamChars<char16_t, AnyChar
+      */
+     MOZ_MUST_USE bool getNonAsciiCodePointDontNormalize(char16_t lead, char32_t* codePoint) {
+         // There are no encoding errors in 16-bit JS, so implement this so that
+         // the compiler knows it, too.
+         *codePoint = infallibleGetNonAsciiCodePointDontNormalize(lead);
+         return true;
+     }
+ 
+-    // Try to get the next code point, normalizing '\r', '\r\n', '\n', and the
+-    // Unicode line/paragraph separators into '\n'.  Also updates internal
+-    // line-counter state.  Return true on success and store the code point in
+-    // |*c|.  Return false and leave |*c| undefined on failure.
++    /**
++     * Get the next code point, converting LineTerminatorSequences to '\n' and
++     * updating internal line-counter state if needed.  Return true on success
++     * and store the code point in |*c|.  Return false and leave |*c| undefined
++     * on failure.
++     */
+     MOZ_MUST_USE bool getCodePoint(int32_t* cp);
+ 
+     /**
+      * Given a just-consumed ASCII code unit/point |lead|, consume a full code
+      * point or LineTerminatorSequence (normalizing it to '\n') and store it in
+      * |*codePoint|.  Return true on success, otherwise return false and leave
+      * |*codePoint| undefined on failure.
+      *
+@@ -1620,19 +1639,17 @@ class TokenStreamChars<char16_t, AnyChar
+     MOZ_MUST_USE bool getFullAsciiCodePoint(int32_t lead, int32_t* codePoint) {
+         MOZ_ASSERT(isAsciiCodePoint(lead),
+                    "non-ASCII code units must be handled separately");
+         // NOTE: |this->|-qualify to avoid a gcc bug: see bug 1472569.
+         MOZ_ASSERT(lead == this->sourceUnits.previousCodeUnit(),
+                    "getFullAsciiCodePoint called incorrectly");
+ 
+         if (MOZ_UNLIKELY(lead == '\r')) {
+-            // NOTE: |this->|-qualify to avoid a gcc bug: see bug 1472569.
+-            if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
+-                this->sourceUnits.matchCodeUnit('\n');
++            matchLineTerminator('\n');
+         } else if (MOZ_LIKELY(lead != '\n')) {
+             *codePoint = lead;
+             return true;
+         }
+ 
+         *codePoint = '\n';
+         bool ok = updateLineInfoForEOL();
+         if (!ok) {
+@@ -1783,16 +1800,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedChars::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePointDontNormalize;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
++    using CharsBase::matchLineTerminator;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+     using CharsBase::peekCodeUnit;

+ 223 - 0
frg/work-js/mozilla-release/patches/1476866-08-63a1.patch

@@ -0,0 +1,223 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530305169 25200
+#      Fri Jun 29 13:46:09 2018 -0700
+# Node ID 7d07cfa666bf8bb2ec9aef3c7f88654f66e9a433
+# Parent  4bd4c0e74bc6ce7ef610ef902085a3609b9517f8
+Bug 1476866 - Move fillCharBufferWithTemplateStringContents into TokenStreamCharsBase so that a UTF-8 specialization can eventually be defined for it.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -435,16 +435,42 @@ TokenStreamAnyChars::TokenStreamAnyChars
+ 
+ template<typename CharT>
+ TokenStreamCharsBase<CharT>::TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length,
+                                                   size_t startOffset)
+   : TokenStreamCharsShared(cx),
+     sourceUnits(chars, length, startOffset)
+ {}
+ 
++template<>
++MOZ_MUST_USE bool
++TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
++                                                                         const char16_t* end)
++{
++    MOZ_ASSERT(this->charBuffer.length() == 0);
++
++    while (cur < end) {
++        // Template literals normalize only '\r' and "\r\n" to '\n'.  The
++        // Unicode separators need no special handling here.
++        // https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv
++        char16_t ch = *cur++;
++        if (ch == '\r') {
++            ch = '\n';
++            if (cur < end && *cur == '\n')
++                cur++;
++        }
++
++        if (!this->charBuffer.append(ch))
++            return false;
++    }
++
++    MOZ_ASSERT(cur == end);
++    return true;
++}
++
+ template<typename CharT, class AnyCharsAccess>
+ TokenStreamSpecific<CharT, AnyCharsAccess>::TokenStreamSpecific(JSContext* cx,
+                                                                 const ReadOnlyCompileOptions& options,
+                                                                 const CharT* base, size_t length)
+   : TokenStreamChars<CharT, AnyCharsAccess>(cx, base, length, options.scriptSourceOffset)
+ {}
+ 
+ bool
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1284,18 +1284,23 @@ class TokenStreamCharsBase
+     inline void consumeKnownCodeUnit(int32_t unit);
+ 
+     // Forbid accidental calls to consumeKnownCodeUnit *not* with the single
+     // unit-or-EOF type.  CharT should use SourceUnits::consumeKnownCodeUnit;
+     // CodeUnitValue() results should go through toCharT(), or better yet just
+     // use the original CharT.
+     template<typename T> inline void consumeKnownCodeUnit(T) = delete;
+ 
+-    MOZ_MUST_USE inline bool
+-    fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
++    /**
++     * Accumulate the provided range of already-validated (i.e. valid UTF-8, or
++     * anything if CharT is char16_t because JS permits lone and mispaired
++     * surrogates) raw template literal text (i.e. containing no escapes or
++     * substitutions) into |charBuffer|.
++     */
++    MOZ_MUST_USE bool fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
+ inline char16_t
+@@ -1323,42 +1328,16 @@ TokenStreamCharsBase<CharT>::consumeKnow
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+ TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+                                                    size_t length)
+ {
+     return AtomizeChars(cx, chars, length);
+ }
+ 
+-template<>
+-MOZ_MUST_USE inline bool
+-TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
+-                                                                         const char16_t* end)
+-{
+-    MOZ_ASSERT(this->charBuffer.length() == 0);
+-
+-    while (cur < end) {
+-        // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
+-        // interpreted literally inside template literal contents; only
+-        // literal CRLF sequences are normalized to '\n'.  See
+-        // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
+-        char16_t ch = *cur++;
+-        if (ch == '\r') {
+-            ch = '\n';
+-            if (cur < end && *cur == '\n')
+-                cur++;
+-        }
+-
+-        if (!this->charBuffer.append(ch))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+ template<typename CharT>
+ class SpecializedTokenStreamCharsBase;
+ 
+ template<>
+ class SpecializedTokenStreamCharsBase<char16_t>
+   : public TokenStreamCharsBase<char16_t>
+ {
+     using CharsBase = TokenStreamCharsBase<char16_t>;
+@@ -1476,16 +1455,19 @@ class GeneralTokenStreamChars
+ 
+         return token;
+     }
+ 
+     uint32_t matchUnicodeEscape(uint32_t* codePoint);
+     uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+ 
+   protected:
++    using TokenStreamCharsShared::drainCharBufferIntoAtom;
++    using CharsBase::fillCharBufferWithTemplateStringContents;
++
+     using typename CharsBase::SourceUnits;
+ 
+   protected:
+     using SpecializedCharsBase::SpecializedCharsBase;
+ 
+     TokenStreamAnyChars& anyCharsAccess() {
+         return AnyCharsAccess::anyChars(this);
+     }
+@@ -1567,16 +1549,38 @@ class GeneralTokenStreamChars
+     }
+ 
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+         return anyCharsAccess().internalUpdateLineInfoForEOL(this->sourceUnits.offset());
+     }
+ 
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
++
++  public:
++    JSAtom* getRawTemplateStringAtom() {
++        TokenStreamAnyChars& anyChars = anyCharsAccess();
++
++        MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
++                   anyChars.currentToken().type == TokenKind::NoSubsTemplate);
++        const CharT* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
++        const CharT* end;
++        if (anyChars.currentToken().type == TokenKind::TemplateHead) {
++            // Of the form    |`...${|   or   |}...${|
++            end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
++        } else {
++            // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
++            end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
++        }
++
++        if (!fillCharBufferWithTemplateStringContents(cur, end))
++            return nullptr;
++
++        return drainCharBufferIntoAtom(anyChars.cx);
++    }
+ };
+ 
+ template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+ 
+ template<class AnyCharsAccess>
+ class TokenStreamChars<char16_t, AnyCharsAccess>
+   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
+ {
+@@ -1900,37 +1904,16 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     // These functions take a |va_list*| parameter, not a |va_list| parameter,
+     // to hack around bug 1363116.  (Longer-term, the right fix is of course to
+     // not use ellipsis functions or |va_list| at all in error reporting.)
+     bool reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
+                                        bool strictMode, unsigned errorNumber, va_list* args);
+     bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
+                                          unsigned errorNumber, va_list* args);
+ 
+-    JSAtom* getRawTemplateStringAtom() {
+-        TokenStreamAnyChars& anyChars = anyCharsAccess();
+-
+-        MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
+-                   anyChars.currentToken().type == TokenKind::NoSubsTemplate);
+-        const CharT* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
+-        const CharT* end;
+-        if (anyChars.currentToken().type == TokenKind::TemplateHead) {
+-            // Of the form    |`...${|   or   |}...${|
+-            end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
+-        } else {
+-            // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
+-            end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
+-        }
+-
+-        if (!fillCharBufferWithTemplateStringContents(cur, end))
+-            return nullptr;
+-
+-        return drainCharBufferIntoAtom(anyChars.cx);
+-    }
+-
+   private:
+     // This is private because it should only be called by the tokenizer while
+     // tokenizing not by, for example, BytecodeEmitter.
+     bool reportStrictModeError(unsigned errorNumber, ...);
+ 
+     void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) {
+         switch (type) {
+             case InvalidEscapeType::None:

+ 62 - 0
frg/work-js/mozilla-release/patches/1476866-09-63a1.patch

@@ -0,0 +1,62 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531177901 25200
+#      Mon Jul 09 16:11:41 2018 -0700
+# Node ID 96e6f8645b7c00eb4bd9eab952c2c24ab1ed9ec2
+# Parent  245cd4d3a38b4ee287e9973989978b941da2f2d7
+Bug 1476866 - Implement a bare-bones TokenStreamChars specialization for UTF-8, into which subsequent UTF-8-centric functions can be added.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1579,17 +1579,16 @@ class GeneralTokenStreamChars
+ };
+ 
+ template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+ 
+ template<class AnyCharsAccess>
+ class TokenStreamChars<char16_t, AnyCharsAccess>
+   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
+ {
+-  private:
+     using CharsBase = TokenStreamCharsBase<char16_t>;
+     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<char16_t>;
+     using GeneralCharsBase = GeneralTokenStreamChars<char16_t, AnyCharsAccess>;
+     using Self = TokenStreamChars<char16_t, AnyCharsAccess>;
+ 
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+@@ -1715,16 +1714,32 @@ class TokenStreamChars<char16_t, AnyChar
+     MOZ_MUST_USE bool consumeRestOfSingleLineComment() {
+         // This operation is infallible for UTF-16 -- and this implementation
+         // approach lets the compiler boil away call-side fallibility handling.
+         infallibleConsumeRestOfSingleLineComment();
+         return true;
+     }
+ };
+ 
++template<class AnyCharsAccess>
++class TokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>
++  : public GeneralTokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>
++{
++    using CharsBase = TokenStreamCharsBase<mozilla::Utf8Unit>;
++    using SpecializedCharsBase = SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>;
++    using GeneralCharsBase = GeneralTokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>;
++    using Self = TokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>;
++
++  protected:
++    // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
++
++  protected:
++    using GeneralCharsBase::GeneralCharsBase;
++};
++
+ // TokenStream is the lexical scanner for JavaScript source text.
+ //
+ // It takes a buffer of CharT code units (currently only char16_t encoding
+ // UTF-16, but we're adding either UTF-8 or Latin-1 single-byte text soon) and
+ // linearly scans it into |Token|s.
+ //
+ // Internally the class uses a four element circular buffer |tokens| of
+ // |Token|s. As an index for |tokens|, the member |cursor_| points to the

+ 143 - 0
frg/work-js/mozilla-release/patches/1476866-10-63a1.patch

@@ -0,0 +1,143 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531962321 25200
+#      Wed Jul 18 18:05:21 2018 -0700
+# Node ID 6ac4c8ad6b9a20ba54462a2e877c594df8767401
+# Parent  96e6f8645b7c00eb4bd9eab952c2c24ab1ed9ec2
+Bug 1476866 - Move TokenStreamSpecific::computeLineOfContext to GeneralTokenStreamChars::internalComputeLineOfContext, and beef up its doc comment a little.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -803,27 +803,24 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     // This function's return value isn't a success/failure indication: it
+     // returns true if this TokenStream's location information could be used,
+     // and it returns false when that information can't be used (and so we
+     // can't provide a line of context).
+     if (!anyCharsAccess().fillExcludingContext(err, offset))
+         return true;
+ 
+     // Add a line of context from this TokenStream to help with debugging.
+-    return computeLineOfContext(err, offset);
++    return internalComputeLineOfContext(err, offset);
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+-TokenStreamSpecific<CharT, AnyCharsAccess>::computeLineOfContext(ErrorMetadata* err,
+-                                                                 uint32_t offset)
++GeneralTokenStreamChars<CharT, AnyCharsAccess>::internalComputeLineOfContext(ErrorMetadata* err,
++                                                                             uint32_t offset)
+ {
+-    // This function presumes |err| is filled in *except* for line-of-context
+-    // fields.  It exists to make |TokenStreamSpecific::computeErrorMetadata|,
+-    // above, more readable.
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+     // We only have line-start information for the current line.  If the error
+     // is on a different line, we can't easily provide context.  (This means
+     // any error in a multi-line token, e.g. an unterminated multiline string
+     // literal, won't have context.)
+     if (err->lineNumber != anyChars.lineno)
+         return true;
+@@ -837,26 +834,26 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                          offset - windowRadius :
+                          anyChars.linebase;
+ 
+     // The window must start within the portion of the current line that we
+     // actually have in our buffer.
+     if (windowStart < this->sourceUnits.startOffset())
+         windowStart = this->sourceUnits.startOffset();
+ 
+-    // The window must end within the current line, no later than
+-    // windowRadius after offset.
++    // The window must end no further than |windowRadius| after |offset| within
++    // the current line.
+     size_t windowEnd = this->sourceUnits.findEOLMax(offset, windowRadius);
+     size_t windowLength = windowEnd - windowStart;
+     MOZ_ASSERT(windowLength <= windowRadius * 2);
+ 
+     // Create the windowed string, not including the potential line
+     // terminator.
+     StringBuffer windowBuf(anyChars.cx);
+-    if (!windowBuf.append(codeUnitPtrAt(windowStart), windowLength) ||
++    if (!windowBuf.append(this->sourceUnits.codeUnitPtrAt(windowStart), windowLength) ||
+         !windowBuf.append('\0'))
+     {
+         return false;
+     }
+ 
+     err->lineOfContext.reset(windowBuf.stealChars());
+     if (!err->lineOfContext)
+         return false;
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1550,16 +1550,26 @@ class GeneralTokenStreamChars
+ 
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+         return anyCharsAccess().internalUpdateLineInfoForEOL(this->sourceUnits.offset());
+     }
+ 
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ 
++    /**
++     * Compute a line of context for an otherwise-filled-in |err| at the given
++     * offset in this token stream.
++     *
++     * This function is very-internal: almost certainly you should use one of
++     * its callers instead.  It basically exists only to make those callers
++     * more readable.
++     */
++    MOZ_MUST_USE bool internalComputeLineOfContext(ErrorMetadata* err, uint32_t offset);
++
+   public:
+     JSAtom* getRawTemplateStringAtom() {
+         TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+         MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
+                    anyChars.currentToken().type == TokenKind::NoSubsTemplate);
+         const CharT* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);
+         const CharT* end;
+@@ -1817,16 +1827,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferWithTemplateStringContents;
+     using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedChars::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePointDontNormalize;
++    using GeneralCharsBase::internalComputeLineOfContext;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using CharsBase::matchLineTerminator;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+@@ -1897,22 +1908,16 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+ 
+     // Report the given error at the given offset.
+     void errorAt(uint32_t offset, unsigned errorNumber, ...);
+     void errorAtVA(uint32_t offset, unsigned errorNumber, va_list* args);
+ 
+     // Warn at the current offset.
+     MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
+ 
+-  private:
+-    // Compute a line of context for an otherwise-filled-in |err| at the given
+-    // offset in this token stream.  (This function basically exists to make
+-    // |computeErrorMetadata| more readable and shouldn't be called elsewhere.)
+-    MOZ_MUST_USE bool computeLineOfContext(ErrorMetadata* err, uint32_t offset);
+-
+   public:
+     // Compute error metadata for an error at the given offset.
+     MOZ_MUST_USE bool computeErrorMetadata(ErrorMetadata* err, uint32_t offset);
+ 
+     // General-purpose error reporters.  You should avoid calling these
+     // directly, and instead use the more succinct alternatives (error(),
+     // warning(), &c.) in TokenStream, Parser, and BytecodeEmitter.
+     //

+ 305 - 0
frg/work-js/mozilla-release/patches/1476866-11-63a1.patch

@@ -0,0 +1,305 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531249613 25200
+#      Tue Jul 10 12:06:53 2018 -0700
+# Node ID ff1852065b5c6a4f2a1829b290f91dae26f7804f
+# Parent  0a0576ce9ce29c25af71907697496fb683784a80
+Bug 1476866 - Rename SourceUnits::findEOLMax to SourceUnits::findWindowEnd, and make it include only valid UTF-16.  r=arai
+
+diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js
+--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js
++++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js
+@@ -265,17 +265,17 @@ stubPackets.set(`ReferenceError: asdf is
+ 
+ stubPackets.set(`SyntaxError: redeclaration of let a`, {
+   "from": "server1.conn0.child1/consoleActor2",
+   "type": "pageError",
+   "pageError": {
+     "errorMessage": "SyntaxError: redeclaration of let a",
+     "errorMessageName": "JSMSG_REDECLARED_VAR",
+     "sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
+-    "lineText": "  let a, a;\n",
++    "lineText": "  let a, a;",
+     "lineNumber": 2,
+     "columnNumber": 9,
+     "category": "content javascript",
+     "timeStamp": 1487992945524,
+     "warning": false,
+     "error": false,
+     "exception": true,
+     "strict": false,
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -40,16 +40,17 @@
+ #include "vm/JSContext.h"
+ 
+ using mozilla::ArrayLength;
+ using mozilla::AssertedCast;
+ using mozilla::IsAscii;
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
+ using mozilla::MakeScopeExit;
++using mozilla::PointerRangeSize;
+ using mozilla::Utf8Unit;
+ 
+ struct ReservedWordInfo
+ {
+     const char* chars;         // C string with reserved word text
+     js::frontend::TokenKind tokentype;
+ };
+ 
+@@ -616,37 +617,67 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     unicode::UTF16Encode(codePoint, units, &numUnits);
+ 
+     MOZ_ASSERT(numUnits == 1 || numUnits == 2);
+ 
+     while (numUnits-- > 0)
+         ungetCodeUnit(units[numUnits]);
+ }
+ 
+-template<typename CharT>
++template<>
+ size_t
+-SourceUnits<CharT>::findEOLMax(size_t start, size_t max)
++SourceUnits<char16_t>::findWindowEnd(size_t offset)
+ {
+-    const CharT* p = codeUnitPtrAt(start);
+-
+-    size_t n = 0;
++    const char16_t* const initial = codeUnitPtrAt(offset);
++    const char16_t* p = initial;
++
++    auto HalfWindowSize = [&initial, &p]() { return PointerRangeSize(initial, p); };
++
+     while (true) {
+-        if (p >= limit_)
++        MOZ_ASSERT(p <= limit_);
++        MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++        if (p >= limit_ || HalfWindowSize() >= WindowRadius)
+             break;
+-        if (n >= max)
+-            break;
+-        n++;
++
++        char16_t c = *p;
+ 
+         // This stops at U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR in
+         // string and template literals.  These code points do affect line and
+         // column coordinates, even as they encode their literal values.
+-        if (isRawEOLChar(*p++))
++        if (isRawEOLChar(c))
++            break;
++
++        // Don't allow invalid UTF-16 in post-context.  (Current users don't
++        // require this, and this behavior isn't currently imposed on
++        // pre-context, but these facts might change someday.)
++
++        if (MOZ_UNLIKELY(unicode::IsTrailSurrogate(c)))
+             break;
++
++        // Optimistically consume the code unit, ungetting it below if needed.
++        p++;
++
++        // If it's not a surrogate at all, keep going.
++        if (MOZ_LIKELY(!unicode::IsLeadSurrogate(c)))
++            continue;
++
++        // Retract if the lead surrogate would stand alone at the end of the
++        // window.
++        if (HalfWindowSize() >= WindowRadius || // split pair
++            p >= limit_ || // half-pair at end of source
++            !unicode::IsTrailSurrogate(*p)) // no paired trail surrogate
++        {
++            p--;
++            break;
++        }
++
++        p++;
+     }
+-    return start + n;
++
++    return offset + HalfWindowSize();
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::advance(size_t position)
+ {
+     const CharT* end = this->sourceUnits.codeUnitPtrAt(position);
+     while (this->sourceUnits.addressOfNextCodeUnit() < end) {
+@@ -820,33 +851,33 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+ 
+     // We only have line-start information for the current line.  If the error
+     // is on a different line, we can't easily provide context.  (This means
+     // any error in a multi-line token, e.g. an unterminated multiline string
+     // literal, won't have context.)
+     if (err->lineNumber != anyChars.lineno)
+         return true;
+ 
+-    constexpr size_t windowRadius = ErrorMetadata::lineOfContextRadius;
++    constexpr size_t windowRadius = SourceUnits::WindowRadius;
+ 
+     // The window must start within the current line, no earlier than
+     // |windowRadius| characters before |offset|.
+     MOZ_ASSERT(offset >= anyChars.linebase);
+     size_t windowStart = (offset - anyChars.linebase > windowRadius) ?
+                          offset - windowRadius :
+                          anyChars.linebase;
+ 
+     // The window must start within the portion of the current line that we
+     // actually have in our buffer.
+     if (windowStart < this->sourceUnits.startOffset())
+         windowStart = this->sourceUnits.startOffset();
+ 
+     // The window must end no further than |windowRadius| after |offset| within
+     // the current line.
+-    size_t windowEnd = this->sourceUnits.findEOLMax(offset, windowRadius);
++    size_t windowEnd = this->sourceUnits.findWindowEnd(offset);
+     size_t windowLength = windowEnd - windowStart;
+     MOZ_ASSERT(windowLength <= windowRadius * 2);
+ 
+     // Create the windowed string, not including the potential line
+     // terminator.
+     StringBuffer windowBuf(anyChars.cx);
+     if (!windowBuf.append(this->sourceUnits.codeUnitPtrAt(windowStart), windowLength) ||
+         !windowBuf.append('\0'))
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1134,19 +1134,35 @@ class SourceUnits
+ 
+     static bool isRawEOLChar(int32_t c) {
+         return c == '\n' ||
+                c == '\r' ||
+                c == unicode::LINE_SEPARATOR ||
+                c == unicode::PARA_SEPARATOR;
+     }
+ 
+-    // Returns the offset of the next EOL, but stops once 'max' characters
+-    // have been scanned (*including* the char at startOffset_).
+-    size_t findEOLMax(size_t start, size_t max);
++    /**
++     * The maximum radius of code around the location of an error that should
++     * be included in a syntax error message -- this many code units to either
++     * side.  The resulting window of data is then accordinngly trimmed so that
++     * the window contains only validly-encoded data.
++     *
++     * Because this number is the same for both UTF-8 and UTF-16, windows in
++     * UTF-8 may contain fewer code points than windows in UTF-16.  As we only
++     * use this for error messages, we don't particularly care.
++     */
++    static constexpr size_t WindowRadius = ErrorMetadata::lineOfContextRadius;
++
++    /**
++     * From absolute offset |offset|, find an absolute offset, no further than
++     * |WindowRadius| code units away from |offset|, such that all code units
++     * from |offset| to that offset encode valid, non-LineTerminator code
++     * points.
++     */
++    size_t findWindowEnd(size_t offset);
+ 
+   private:
+     /** Base of buffer. */
+     const CharT* base_;
+ 
+     /** Offset of base_[0]. */
+     uint32_t startOffset_;
+ 
+diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build
+--- a/js/src/jsapi-tests/moz.build
++++ b/js/src/jsapi-tests/moz.build
+@@ -24,16 +24,17 @@ UNIFIED_SOURCES += [
+     'testDebugger.cpp',
+     'testDeepFreeze.cpp',
+     'testDefineGetterSetterNonEnumerable.cpp',
+     'testDefineProperty.cpp',
+     'testDefinePropertyIgnoredAttributes.cpp',
+     'testDeflateStringToUTF8Buffer.cpp',
+     'testDifferentNewTargetInvokeConstructor.cpp',
+     'testErrorCopying.cpp',
++    'testErrorLineOfContext.cpp',
+     'testException.cpp',
+     'testExecuteInJSMEnvironment.cpp',
+     'testExternalArrayBuffer.cpp',
+     'testExternalStrings.cpp',
+     'testFindSCCs.cpp',
+     'testForceLexicalInitialization.cpp',
+     'testForOfIterator.cpp',
+     'testForwardSetProperty.cpp',
+diff --git a/js/src/jsapi-tests/testErrorLineOfContext.cpp b/js/src/jsapi-tests/testErrorLineOfContext.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/jsapi-tests/testErrorLineOfContext.cpp
+@@ -0,0 +1,71 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "jsfriendapi.h"
++#include "jsapi-tests/tests.h"
++#include "vm/ErrorReporting.h"
++
++BEGIN_TEST(testErrorLineOfContext)
++{
++    static const char16_t fullLineR[] = u"\n  var x = @;  \r  ";
++    CHECK(testLineOfContextHasNoLineTerminator(fullLineR, ' '));
++
++    static const char16_t fullLineN[] = u"\n  var x = @; !\n  ";
++    CHECK(testLineOfContextHasNoLineTerminator(fullLineN, '!'));
++
++    static const char16_t fullLineLS[] = u"\n  var x = @; +\u2028  ";
++    CHECK(testLineOfContextHasNoLineTerminator(fullLineLS, '+'));
++
++    static const char16_t fullLinePS[] = u"\n  var x = @; #\u2029  ";
++    CHECK(testLineOfContextHasNoLineTerminator(fullLinePS, '#'));
++
++    static_assert(js::ErrorMetadata::lineOfContextRadius == 60,
++                  "current max count past offset is 60, hits 'X' below");
++
++    static const char16_t truncatedLine[] =
++        u"@ + 4567890123456789012345678901234567890123456789012345678XYZW\n";
++    CHECK(testLineOfContextHasNoLineTerminator(truncatedLine, 'X'));
++
++    return true;
++}
++
++bool
++eval(const char16_t* chars, size_t len, JS::MutableHandleValue rval)
++{
++    JS::RealmOptions globalOptions;
++    JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
++						   JS::FireOnNewGlobalHook, globalOptions));
++    CHECK(global);
++
++    JSAutoRealm ar(cx, global);
++    JS::CompileOptions options(cx);
++    return JS::Evaluate(cx, options, chars, len, rval);
++}
++
++template<size_t N>
++bool
++testLineOfContextHasNoLineTerminator(const char16_t (&chars)[N], char16_t expectedLast)
++{
++    JS::RootedValue rval(cx);
++    CHECK(!eval(chars, N - 1, &rval));
++
++    JS::RootedValue exn(cx);
++    CHECK(JS_GetPendingException(cx, &exn));
++    JS_ClearPendingException(cx);
++
++    js::ErrorReport report(cx);
++    CHECK(report.init(cx, exn, js::ErrorReport::WithSideEffects));
++
++    const auto* errorReport = report.report();
++
++    const char16_t* lineOfContext = errorReport->linebuf();
++    size_t lineOfContextLength = errorReport->linebufLength();
++
++    CHECK(lineOfContext[lineOfContextLength] == '\0');
++    char16_t last = lineOfContext[lineOfContextLength - 1];
++    CHECK(last == expectedLast);
++
++    return true;
++}
++END_TEST(testErrorLineOfContext)

+ 343 - 0
frg/work-js/mozilla-release/patches/1476866-12-63a1.patch

@@ -0,0 +1,343 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531533546 25200
+#      Fri Jul 13 18:59:06 2018 -0700
+# Node ID 30c6932eea32e4b49abb30f20b1e49c804734731
+# Parent  ff1852065b5c6a4f2a1829b290f91dae26f7804f
+Bug 1476866 - Move error-message window-start computation into SourceUnits::findWindowStart so that specialized versions can be provided for UTF-8 and UTF-16.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -619,16 +619,74 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     MOZ_ASSERT(numUnits == 1 || numUnits == 2);
+ 
+     while (numUnits-- > 0)
+         ungetCodeUnit(units[numUnits]);
+ }
+ 
+ template<>
+ size_t
++SourceUnits<char16_t>::findWindowStart(size_t offset)
++{
++    // This is JS's understanding of UTF-16 that allows lone surrogates, so
++    // we have to exclude lone surrogates from [windowStart, offset) ourselves.
++
++    const char16_t* const earliestPossibleStart = codeUnitPtrAt(startOffset_);
++
++    const char16_t* const initial = codeUnitPtrAt(offset);
++    const char16_t* p = initial;
++
++    auto HalfWindowSize = [&p, &initial]() { return PointerRangeSize(p, initial); };
++
++    while (true) {
++        MOZ_ASSERT(earliestPossibleStart <= p);
++        MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++        if (p <= earliestPossibleStart || HalfWindowSize() >= WindowRadius)
++            break;
++
++        char16_t c = p[-1];
++
++        // This stops at U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR in
++        // string and template literals.  These code points do affect line and
++        // column coordinates, even as they encode their literal values.
++        if (isRawEOLChar(c))
++            break;
++
++        // Don't allow invalid UTF-16 in pre-context.  (Current users don't
++        // require this, and this behavior isn't currently imposed on
++        // pre-context, but these facts might change someday.)
++
++        if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c)))
++            break;
++
++        // Optimistically include the code unit, reverting below if needed.
++        p--;
++
++        // If it's not a surrogate at all, keep going.
++        if (MOZ_LIKELY(!unicode::IsTrailSurrogate(c)))
++            continue;
++
++        // Stop if we don't have a usable surrogate pair.
++        if (HalfWindowSize() >= WindowRadius ||
++            p <= earliestPossibleStart || // trail surrogate at low end
++            !unicode::IsLeadSurrogate(p[-1])) // no paired lead surrogate
++        {
++            p++;
++            break;
++        }
++
++        p--;
++    }
++
++    MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++    return offset - HalfWindowSize();
++}
++
++template<>
++size_t
+ SourceUnits<char16_t>::findWindowEnd(size_t offset)
+ {
+     const char16_t* const initial = codeUnitPtrAt(offset);
+     const char16_t* p = initial;
+ 
+     auto HalfWindowSize = [&initial, &p]() { return PointerRangeSize(initial, p); };
+ 
+     while (true) {
+@@ -816,16 +874,57 @@ template<typename CharT, class AnyCharsA
+ void
+ TokenStreamSpecific<CharT, AnyCharsAccess>::currentLineAndColumn(uint32_t* line, uint32_t* column) const
+ {
+     const TokenStreamAnyChars& anyChars = anyCharsAccess();
+     uint32_t offset = anyChars.currentToken().pos.begin;
+     anyChars.srcCoords.lineNumAndColumnIndex(offset, line, column);
+ }
+ 
++template<>
++bool
++TokenStreamCharsBase<Utf8Unit>::addLineOfContext(JSContext* cx, ErrorMetadata* err,
++                                                 uint32_t offset)
++{
++    // The specialization below is almost usable if changed to be a definition
++    // for any CharT, but it demands certain UTF-8-specific functionality that
++    // has't been defined yet.  Use a placeholder definition until such
++    // functionality is in place.
++    return true;
++}
++
++template<>
++bool
++TokenStreamCharsBase<char16_t>::addLineOfContext(JSContext* cx, ErrorMetadata* err,
++                                                 uint32_t offset)
++{
++    size_t windowStart = sourceUnits.findWindowStart(offset);
++    size_t windowEnd = sourceUnits.findWindowEnd(offset);
++
++    size_t windowLength = windowEnd - windowStart;
++    MOZ_ASSERT(windowLength <= SourceUnits::WindowRadius * 2);
++
++    // Create the windowed string, not including the potential line
++    // terminator.
++    StringBuffer windowBuf(cx);
++    if (!windowBuf.append(sourceUnits.codeUnitPtrAt(windowStart), windowLength) ||
++        !windowBuf.append('\0'))
++    {
++        return false;
++    }
++
++    err->lineOfContext.reset(windowBuf.stealChars());
++    if (!err->lineOfContext)
++        return false;
++
++    err->lineLength = windowLength;
++    err->tokenOffset = offset - windowStart;
++    return true;
++}
++
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::computeErrorMetadata(ErrorMetadata* err,
+                                                                  uint32_t offset)
+ {
+     if (offset == NoOffset) {
+         anyCharsAccess().computeErrorMetadataNoOffset(err);
+         return true;
+@@ -839,69 +938,16 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         return true;
+ 
+     // Add a line of context from this TokenStream to help with debugging.
+     return internalComputeLineOfContext(err, offset);
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+-GeneralTokenStreamChars<CharT, AnyCharsAccess>::internalComputeLineOfContext(ErrorMetadata* err,
+-                                                                             uint32_t offset)
+-{
+-    TokenStreamAnyChars& anyChars = anyCharsAccess();
+-
+-    // We only have line-start information for the current line.  If the error
+-    // is on a different line, we can't easily provide context.  (This means
+-    // any error in a multi-line token, e.g. an unterminated multiline string
+-    // literal, won't have context.)
+-    if (err->lineNumber != anyChars.lineno)
+-        return true;
+-
+-    constexpr size_t windowRadius = SourceUnits::WindowRadius;
+-
+-    // The window must start within the current line, no earlier than
+-    // |windowRadius| characters before |offset|.
+-    MOZ_ASSERT(offset >= anyChars.linebase);
+-    size_t windowStart = (offset - anyChars.linebase > windowRadius) ?
+-                         offset - windowRadius :
+-                         anyChars.linebase;
+-
+-    // The window must start within the portion of the current line that we
+-    // actually have in our buffer.
+-    if (windowStart < this->sourceUnits.startOffset())
+-        windowStart = this->sourceUnits.startOffset();
+-
+-    // The window must end no further than |windowRadius| after |offset| within
+-    // the current line.
+-    size_t windowEnd = this->sourceUnits.findWindowEnd(offset);
+-    size_t windowLength = windowEnd - windowStart;
+-    MOZ_ASSERT(windowLength <= windowRadius * 2);
+-
+-    // Create the windowed string, not including the potential line
+-    // terminator.
+-    StringBuffer windowBuf(anyChars.cx);
+-    if (!windowBuf.append(this->sourceUnits.codeUnitPtrAt(windowStart), windowLength) ||
+-        !windowBuf.append('\0'))
+-    {
+-        return false;
+-    }
+-
+-    err->lineOfContext.reset(windowBuf.stealChars());
+-    if (!err->lineOfContext)
+-        return false;
+-
+-    err->lineLength = windowLength;
+-    err->tokenOffset = offset - windowStart;
+-    return true;
+-}
+-
+-
+-template<typename CharT, class AnyCharsAccess>
+-bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::reportStrictModeError(unsigned errorNumber, ...)
+ {
+     va_list args;
+     va_start(args, errorNumber);
+ 
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+     bool result = reportStrictModeErrorNumberVA(nullptr, anyChars.currentToken().pos.begin,
+                                                 anyChars.strictMode(), errorNumber, &args);
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1147,20 +1147,28 @@ class SourceUnits
+      *
+      * Because this number is the same for both UTF-8 and UTF-16, windows in
+      * UTF-8 may contain fewer code points than windows in UTF-16.  As we only
+      * use this for error messages, we don't particularly care.
+      */
+     static constexpr size_t WindowRadius = ErrorMetadata::lineOfContextRadius;
+ 
+     /**
+-     * From absolute offset |offset|, find an absolute offset, no further than
+-     * |WindowRadius| code units away from |offset|, such that all code units
+-     * from |offset| to that offset encode valid, non-LineTerminator code
+-     * points.
++     * From absolute offset |offset|, search backward to find an absolute
++     * offset within source text, no further than |WindowRadius| code units
++     * away from |offset|, such that all code points from that offset to
++     * |offset| are valid, non-LineTerminator code points.
++     */
++    size_t findWindowStart(size_t offset);
++
++    /**
++     * From absolute offset |offset|, find an absolute offset within source
++     * text, no further than |WindowRadius| code units away from |offset|, such
++     * that all code units from |offset| to that offset are valid,
++     * non-LineTerminator code points.
+      */
+     size_t findWindowEnd(size_t offset);
+ 
+   private:
+     /** Base of buffer. */
+     const CharT* base_;
+ 
+     /** Offset of base_[0]. */
+@@ -1308,16 +1316,31 @@ class TokenStreamCharsBase
+     /**
+      * Accumulate the provided range of already-validated (i.e. valid UTF-8, or
+      * anything if CharT is char16_t because JS permits lone and mispaired
+      * surrogates) raw template literal text (i.e. containing no escapes or
+      * substitutions) into |charBuffer|.
+      */
+     MOZ_MUST_USE bool fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
+ 
++    /**
++     * Add a null-terminated line of context to error information, for the line
++     * in |sourceUnits| that contains |offset|.  Also record the window's
++     * length and the offset of the error in the window.  (Don't bother adding
++     * a line of context if it would be empty.)
++     *
++     * The window will contain no LineTerminators of any kind, and it will not
++     * extend more than |SourceUnits::WindowRadius| to either side of |offset|,
++     * nor into the previous or next lines.
++     *
++     * This function is quite internal, and you probably should be calling one
++     * of its existing callers instead.
++     */
++    MOZ_MUST_USE bool addLineOfContext(JSContext* cx, ErrorMetadata* err, uint32_t offset);
++
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
+ inline char16_t
+ TokenStreamCharsBase<char16_t>::toCharT(int32_t codeUnitValue)
+@@ -1445,16 +1468,21 @@ class TokenStart
+ 
+ template<typename CharT, class AnyCharsAccess>
+ class GeneralTokenStreamChars
+   : public SpecializedTokenStreamCharsBase<CharT>
+ {
+     using CharsBase = TokenStreamCharsBase<CharT>;
+     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
+ 
++  private:
++    using CharsBase::addLineOfContext;
++    // Deliberately don't |using CharsBase::sourceUnits| because of bug 1472569.  :-(
++
++  private:
+     Token* newTokenInternal(TokenKind kind, TokenStart start, TokenKind* out);
+ 
+     /**
+      * Allocates a new Token from the given offset to the current offset,
+      * ascribes it the given kind, and sets |*out| to that kind.
+      */
+     Token* newToken(TokenKind kind, TokenStart start, TokenStreamShared::Modifier modifier,
+                     TokenKind* out)
+@@ -1567,24 +1595,35 @@ class GeneralTokenStreamChars
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+         return anyCharsAccess().internalUpdateLineInfoForEOL(this->sourceUnits.offset());
+     }
+ 
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ 
+     /**
+-     * Compute a line of context for an otherwise-filled-in |err| at the given
+-     * offset in this token stream.
++     * If possible, compute a line of context for an otherwise-filled-in |err|
++     * at the given offset in this token stream.
+      *
+      * This function is very-internal: almost certainly you should use one of
+      * its callers instead.  It basically exists only to make those callers
+      * more readable.
+      */
+-    MOZ_MUST_USE bool internalComputeLineOfContext(ErrorMetadata* err, uint32_t offset);
++    MOZ_MUST_USE bool internalComputeLineOfContext(ErrorMetadata* err, uint32_t offset) {
++        TokenStreamAnyChars& anyChars = anyCharsAccess();
++
++        // We only have line-start information for the current line.  If the error
++        // is on a different line, we can't easily provide context.  (This means
++        // any error in a multi-line token, e.g. an unterminated multiline string
++        // literal, won't have context.)
++        if (err->lineNumber != anyChars.lineno)
++            return true;
++
++        return addLineOfContext(anyChars.cx, err, offset);
++    }
+ 
+   public:
+     JSAtom* getRawTemplateStringAtom() {
+         TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+         MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
+                    anyChars.currentToken().type == TokenKind::NoSubsTemplate);
+         const CharT* cur = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.begin + 1);

+ 274 - 0
frg/work-js/mozilla-release/patches/1476866-13-63a1.patch

@@ -0,0 +1,274 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531886463 25200
+#      Tue Jul 17 21:01:03 2018 -0700
+# Node ID 670d911efa814f0b6f042bdf859abf666e4d510a
+# Parent  30c6932eea32e4b49abb30f20b1e49c804734731
+Bug 1476866 - Implement TokenStreamCharsBase::addLineOfContext that does all the work of creating a syntax-error window and works for either CharT.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -438,25 +438,22 @@ template<typename CharT>
+ TokenStreamCharsBase<CharT>::TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length,
+                                                   size_t startOffset)
+   : TokenStreamCharsShared(cx),
+     sourceUnits(chars, length, startOffset)
+ {}
+ 
+ template<>
+ MOZ_MUST_USE bool
+-TokenStreamCharsBase<char16_t>::fillCharBufferWithTemplateStringContents(const char16_t* cur,
+-                                                                         const char16_t* end)
++TokenStreamCharsBase<char16_t>::fillCharBufferFromSourceNormalizingAsciiLineBreaks(const char16_t* cur,
++                                                                                   const char16_t* end)
+ {
+     MOZ_ASSERT(this->charBuffer.length() == 0);
+ 
+     while (cur < end) {
+-        // Template literals normalize only '\r' and "\r\n" to '\n'.  The
+-        // Unicode separators need no special handling here.
+-        // https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv
+         char16_t ch = *cur++;
+         if (ch == '\r') {
+             ch = '\n';
+             if (cur < end && *cur == '\n')
+                 cur++;
+         }
+ 
+         if (!this->charBuffer.append(ch))
+@@ -876,47 +873,61 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ {
+     const TokenStreamAnyChars& anyChars = anyCharsAccess();
+     uint32_t offset = anyChars.currentToken().pos.begin;
+     anyChars.srcCoords.lineNumAndColumnIndex(offset, line, column);
+ }
+ 
+ template<>
+ bool
+-TokenStreamCharsBase<Utf8Unit>::addLineOfContext(JSContext* cx, ErrorMetadata* err,
+-                                                 uint32_t offset)
++TokenStreamCharsBase<Utf8Unit>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
+ {
+-    // The specialization below is almost usable if changed to be a definition
+-    // for any CharT, but it demands certain UTF-8-specific functionality that
+-    // has't been defined yet.  Use a placeholder definition until such
+-    // functionality is in place.
++    // The specialization below is 100% usable if tweaked to be a definition
++    // for any CharT, but it demands SourceUnits::findWindow{Start,End} and
++    // TokenStreamCharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks
++    // for UTF-8 that haven't been defined yet.  Use a placeholder definition
++    // til those are place.
+     return true;
+ }
+ 
+ template<>
+ bool
+-TokenStreamCharsBase<char16_t>::addLineOfContext(JSContext* cx, ErrorMetadata* err,
+-                                                 uint32_t offset)
++TokenStreamCharsBase<char16_t>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
+ {
++    using CharT = char16_t;
+     size_t windowStart = sourceUnits.findWindowStart(offset);
+     size_t windowEnd = sourceUnits.findWindowEnd(offset);
+ 
+     size_t windowLength = windowEnd - windowStart;
+     MOZ_ASSERT(windowLength <= SourceUnits::WindowRadius * 2);
+ 
+-    // Create the windowed string, not including the potential line
+-    // terminator.
+-    StringBuffer windowBuf(cx);
+-    if (!windowBuf.append(sourceUnits.codeUnitPtrAt(windowStart), windowLength) ||
+-        !windowBuf.append('\0'))
+-    {
++    // Don't add a useless "line" of context when the window ends up empty
++    // because of an invalid encoding at the start of a line.
++    if (windowLength == 0) {
++        MOZ_ASSERT(err->lineOfContext == nullptr,
++                   "ErrorMetadata::lineOfContext must be null so we don't "
++                   "have to set the lineLength/tokenOffset fields");
++        return true;
++    }
++
++    // We might have hit an error while processing some source code feature
++    // that's accumulating text into |this->charBuffer| -- e.g. we could be
++    // halfway into a regular expression literal, then encounter invalid UTF-8.
++    // Thus we must clear |this->charBuffer| of prior work.
++    this->charBuffer.clear();
++
++    const CharT* start = sourceUnits.codeUnitPtrAt(windowStart);
++    if (!fillCharBufferFromSourceNormalizingAsciiLineBreaks(start, start + windowLength))
+         return false;
+-    }
+-
+-    err->lineOfContext.reset(windowBuf.stealChars());
++
++    // The windowed string is null-terminated.
++    if (!this->charBuffer.append('\0'))
++        return false;
++
++    err->lineOfContext.reset(this->charBuffer.extractOrCopyRawBuffer());
+     if (!err->lineOfContext)
+         return false;
+ 
+     err->lineLength = windowLength;
+     err->tokenOffset = offset - windowStart;
+     return true;
+ }
+ 
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1309,37 +1309,37 @@ class TokenStreamCharsBase
+ 
+     // Forbid accidental calls to consumeKnownCodeUnit *not* with the single
+     // unit-or-EOF type.  CharT should use SourceUnits::consumeKnownCodeUnit;
+     // CodeUnitValue() results should go through toCharT(), or better yet just
+     // use the original CharT.
+     template<typename T> inline void consumeKnownCodeUnit(T) = delete;
+ 
+     /**
+-     * Accumulate the provided range of already-validated (i.e. valid UTF-8, or
+-     * anything if CharT is char16_t because JS permits lone and mispaired
+-     * surrogates) raw template literal text (i.e. containing no escapes or
+-     * substitutions) into |charBuffer|.
++     * Accumulate the provided range of already-validated text (valid UTF-8, or
++     * anything if CharT is char16_t because JS allows lone surrogates) into
++     * |charBuffer|.  Normalize '\r', '\n', and "\r\n" into '\n'.
+      */
+-    MOZ_MUST_USE bool fillCharBufferWithTemplateStringContents(const CharT* cur, const CharT* end);
++    MOZ_MUST_USE bool
++    fillCharBufferFromSourceNormalizingAsciiLineBreaks(const CharT* cur, const CharT* end);
+ 
+     /**
+      * Add a null-terminated line of context to error information, for the line
+      * in |sourceUnits| that contains |offset|.  Also record the window's
+      * length and the offset of the error in the window.  (Don't bother adding
+      * a line of context if it would be empty.)
+      *
+      * The window will contain no LineTerminators of any kind, and it will not
+      * extend more than |SourceUnits::WindowRadius| to either side of |offset|,
+      * nor into the previous or next lines.
+      *
+      * This function is quite internal, and you probably should be calling one
+      * of its existing callers instead.
+      */
+-    MOZ_MUST_USE bool addLineOfContext(JSContext* cx, ErrorMetadata* err, uint32_t offset);
++    MOZ_MUST_USE bool addLineOfContext(ErrorMetadata* err, uint32_t offset);
+ 
+   protected:
+     /** Code units in the source code being tokenized. */
+     SourceUnits sourceUnits;
+ };
+ 
+ template<>
+ inline char16_t
+@@ -1469,17 +1469,16 @@ class TokenStart
+ template<typename CharT, class AnyCharsAccess>
+ class GeneralTokenStreamChars
+   : public SpecializedTokenStreamCharsBase<CharT>
+ {
+     using CharsBase = TokenStreamCharsBase<CharT>;
+     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
+ 
+   private:
+-    using CharsBase::addLineOfContext;
+     // Deliberately don't |using CharsBase::sourceUnits| because of bug 1472569.  :-(
+ 
+   private:
+     Token* newTokenInternal(TokenKind kind, TokenStart start, TokenKind* out);
+ 
+     /**
+      * Allocates a new Token from the given offset to the current offset,
+      * ascribes it the given kind, and sets |*out| to that kind.
+@@ -1499,18 +1498,19 @@ class GeneralTokenStreamChars
+ 
+         return token;
+     }
+ 
+     uint32_t matchUnicodeEscape(uint32_t* codePoint);
+     uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+ 
+   protected:
++    using CharsBase::addLineOfContext;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+-    using CharsBase::fillCharBufferWithTemplateStringContents;
++    using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
+ 
+     using typename CharsBase::SourceUnits;
+ 
+   protected:
+     using SpecializedCharsBase::SpecializedCharsBase;
+ 
+     TokenStreamAnyChars& anyCharsAccess() {
+         return AnyCharsAccess::anyChars(this);
+@@ -1603,26 +1603,24 @@ class GeneralTokenStreamChars
+      * If possible, compute a line of context for an otherwise-filled-in |err|
+      * at the given offset in this token stream.
+      *
+      * This function is very-internal: almost certainly you should use one of
+      * its callers instead.  It basically exists only to make those callers
+      * more readable.
+      */
+     MOZ_MUST_USE bool internalComputeLineOfContext(ErrorMetadata* err, uint32_t offset) {
+-        TokenStreamAnyChars& anyChars = anyCharsAccess();
+-
+         // We only have line-start information for the current line.  If the error
+         // is on a different line, we can't easily provide context.  (This means
+         // any error in a multi-line token, e.g. an unterminated multiline string
+         // literal, won't have context.)
+-        if (err->lineNumber != anyChars.lineno)
++        if (err->lineNumber != anyCharsAccess().lineno)
+             return true;
+ 
+-        return addLineOfContext(anyChars.cx, err, offset);
++        return addLineOfContext(err, offset);
+     }
+ 
+   public:
+     JSAtom* getRawTemplateStringAtom() {
+         TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+         MOZ_ASSERT(anyChars.currentToken().type == TokenKind::TemplateHead ||
+                    anyChars.currentToken().type == TokenKind::NoSubsTemplate);
+@@ -1631,17 +1629,20 @@ class GeneralTokenStreamChars
+         if (anyChars.currentToken().type == TokenKind::TemplateHead) {
+             // Of the form    |`...${|   or   |}...${|
+             end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
+         } else {
+             // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
+             end = this->sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
+         }
+ 
+-        if (!fillCharBufferWithTemplateStringContents(cur, end))
++        // Template literals normalize only '\r' and "\r\n" to '\n'; Unicode
++        // separators don't need special handling.
++        // https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv
++        if (!fillCharBufferFromSourceNormalizingAsciiLineBreaks(cur, end))
+             return nullptr;
+ 
+         return drainCharBufferIntoAtom(anyChars.cx);
+     }
+ };
+ 
+ template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
+ 
+@@ -1876,17 +1877,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+     using CharsBase::atomizeSourceChars;
+     using GeneralCharsBase::badToken;
+     // Deliberately don't |using| |charBuffer| because of bug 1472569.  :-(
+     using CharsBase::consumeKnownCodeUnit;
+     using SpecializedChars::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+-    using CharsBase::fillCharBufferWithTemplateStringContents;
++    using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
+     using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedChars::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePointDontNormalize;
+     using GeneralCharsBase::internalComputeLineOfContext;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;

+ 200 - 0
frg/work-js/mozilla-release/patches/1476866-14-63a1.patch

@@ -0,0 +1,200 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531886457 25200
+#      Tue Jul 17 21:00:57 2018 -0700
+# Node ID 7da01c72860d3461d177fc3a07cbb8f0b51e6c27
+# Parent  670d911efa814f0b6f042bdf859abf666e4d510a
+Bug 1476866 - Replace SourceUnits<CharT>::isRawEOLChar (where CharT had rather uncertain meaning) with standalone IsLineTerminator of clearer meaning.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -578,33 +578,33 @@ TokenStreamChars<char16_t, AnyCharsAcces
+                 *codePoint = EOF; // sentinel value to hopefully cause errors
+ #endif
+                 MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
+                 return false;
+             }
+ 
+             *codePoint = '\n';
+         } else {
+-            MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
++            MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+         }
+ 
+         return true;
+     }
+ 
+     // Also handle a lead surrogate not paired with a trailing surrogate.
+     if (MOZ_UNLIKELY(this->sourceUnits.atEnd() ||
+                      !unicode::IsTrailSurrogate(this->sourceUnits.peekCodeUnit())))
+     {
+-        MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
++        MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+         return true;
+     }
+ 
+     // Otherwise we have a multi-unit code point.
+     *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
+-    MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
++    MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+     return true;
+ }
+ 
+ template<class AnyCharsAccess>
+ void
+ TokenStreamChars<char16_t, AnyCharsAccess>::ungetCodePointIgnoreEOL(uint32_t codePoint)
+ {
+     MOZ_ASSERT(!this->sourceUnits.atStart());
+@@ -639,17 +639,17 @@ SourceUnits<char16_t>::findWindowStart(s
+         if (p <= earliestPossibleStart || HalfWindowSize() >= WindowRadius)
+             break;
+ 
+         char16_t c = p[-1];
+ 
+         // This stops at U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR in
+         // string and template literals.  These code points do affect line and
+         // column coordinates, even as they encode their literal values.
+-        if (isRawEOLChar(c))
++        if (IsLineTerminator(c))
+             break;
+ 
+         // Don't allow invalid UTF-16 in pre-context.  (Current users don't
+         // require this, and this behavior isn't currently imposed on
+         // pre-context, but these facts might change someday.)
+ 
+         if (MOZ_UNLIKELY(unicode::IsLeadSurrogate(c)))
+             break;
+@@ -692,17 +692,17 @@ SourceUnits<char16_t>::findWindowEnd(siz
+         if (p >= limit_ || HalfWindowSize() >= WindowRadius)
+             break;
+ 
+         char16_t c = *p;
+ 
+         // This stops at U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR in
+         // string and template literals.  These code points do affect line and
+         // column coordinates, even as they encode their literal values.
+-        if (isRawEOLChar(c))
++        if (IsLineTerminator(c))
+             break;
+ 
+         // Don't allow invalid UTF-16 in post-context.  (Current users don't
+         // require this, and this behavior isn't currently imposed on
+         // pre-context, but these facts might change someday.)
+ 
+         if (MOZ_UNLIKELY(unicode::IsTrailSurrogate(c)))
+             break;
+@@ -1596,17 +1596,17 @@ static const uint8_t firstCharKinds[] = 
+ static_assert(LastCharKind < (1 << (sizeof(firstCharKinds[0]) * 8)),
+               "Elements of firstCharKinds[] are too small");
+ 
+ void
+ SpecializedTokenStreamCharsBase<char16_t>::infallibleConsumeRestOfSingleLineComment()
+ {
+     while (MOZ_LIKELY(!this->sourceUnits.atEnd())) {
+         char16_t unit = this->sourceUnits.peekCodeUnit();
+-        if (SourceUnits::isRawEOLChar(unit))
++        if (IsLineTerminator(unit))
+             return;
+ 
+         this->sourceUnits.consumeKnownCodeUnit(unit);
+     }
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+@@ -1772,27 +1772,24 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             inCharClass = true;
+         } else if (unit == ']') {
+             inCharClass = false;
+         } else if (unit == '/' && !inCharClass) {
+             // For IE compat, allow unescaped / in char classes.
+             break;
+         }
+ 
++        // NOTE: Non-ASCII LineTerminators were handled by
++        //       ProcessNonAsciiCodePoint calls above.
+         if (unit == '\r' || unit == '\n') {
+             ReportUnterminatedRegExp(unit);
+             return badToken();
+         }
+ 
+-        // We're accumulating regular expression *source* text here: source
+-        // text matching a line break will appear as U+005C REVERSE SOLIDUS
+-        // U+006E LATIN SMALL LETTER N, and |unit| here would be the latter
+-        // code point.
+-        MOZ_ASSERT(!SourceUnits::isRawEOLChar(unit));
+-
++        MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(unit)));
+         if (!this->charBuffer.append(unit))
+             return badToken();
+     } while (true);
+ 
+     int32_t unit;
+     RegExpFlag reflags = NoFlags;
+     while (true) {
+         RegExpFlag flag;
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -944,16 +944,36 @@ constexpr uint8_t
+ CodeUnitValue(mozilla::Utf8Unit unit)
+ {
+     return unit.toUint8();
+ }
+ 
+ template<typename CharT>
+ class TokenStreamCharsBase;
+ 
++template<typename T>
++inline bool
++IsLineTerminator(T) = delete;
++
++inline bool
++IsLineTerminator(char32_t codePoint)
++{
++    return codePoint == '\n' ||
++           codePoint == '\r' ||
++           codePoint == unicode::LINE_SEPARATOR ||
++           codePoint == unicode::PARA_SEPARATOR;
++}
++
++inline bool
++IsLineTerminator(char16_t unit)
++{
++    // Every LineTerminator fits in char16_t, so this is exact.
++    return IsLineTerminator(static_cast<char32_t>(unit));
++}
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //
+@@ -1127,23 +1147,16 @@ class SourceUnits
+ 
+     // Poison the SourceUnits so they can't be accessed again.
+     void poisonInDebug() {
+ #ifdef DEBUG
+         ptr = nullptr;
+ #endif
+     }
+ 
+-    static bool isRawEOLChar(int32_t c) {
+-        return c == '\n' ||
+-               c == '\r' ||
+-               c == unicode::LINE_SEPARATOR ||
+-               c == unicode::PARA_SEPARATOR;
+-    }
+-
+     /**
+      * The maximum radius of code around the location of an error that should
+      * be included in a syntax error message -- this many code units to either
+      * side.  The resulting window of data is then accordinngly trimmed so that
+      * the window contains only validly-encoded data.
+      *
+      * Because this number is the same for both UTF-8 and UTF-16, windows in
+      * UTF-8 may contain fewer code points than windows in UTF-16.  As we only

+ 174 - 0
frg/work-js/mozilla-release/patches/1476866-15-63a1.patch

@@ -0,0 +1,174 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531887197 25200
+#      Tue Jul 17 21:13:17 2018 -0700
+# Node ID 735ee4ba2523472561514447de4e7558efae9e1b
+# Parent  7da01c72860d3461d177fc3a07cbb8f0b51e6c27
+Bug 1476866 - Move TokenStreamChars::getFullAsciiCodePoint to GeneralTokenStreamChars::getFullAsciiCodePoint, because its algorithm is identical for UTF-8 and UTF-16.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1482,19 +1482,16 @@ class TokenStart
+ template<typename CharT, class AnyCharsAccess>
+ class GeneralTokenStreamChars
+   : public SpecializedTokenStreamCharsBase<CharT>
+ {
+     using CharsBase = TokenStreamCharsBase<CharT>;
+     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<CharT>;
+ 
+   private:
+-    // Deliberately don't |using CharsBase::sourceUnits| because of bug 1472569.  :-(
+-
+-  private:
+     Token* newTokenInternal(TokenKind kind, TokenStart start, TokenKind* out);
+ 
+     /**
+      * Allocates a new Token from the given offset to the current offset,
+      * ascribes it the given kind, and sets |*out| to that kind.
+      */
+     Token* newToken(TokenKind kind, TokenStart start, TokenStreamShared::Modifier modifier,
+                     TokenKind* out)
+@@ -1514,16 +1511,20 @@ class GeneralTokenStreamChars
+ 
+     uint32_t matchUnicodeEscape(uint32_t* codePoint);
+     uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+ 
+   protected:
+     using CharsBase::addLineOfContext;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
++    using TokenStreamCharsShared::isAsciiCodePoint;
++    using CharsBase::matchLineTerminator;
++    // Deliberately don't |using CharsBase::sourceUnits| because of bug 1472569.  :-(
++    using CharsBase::toCharT;
+ 
+     using typename CharsBase::SourceUnits;
+ 
+   protected:
+     using SpecializedCharsBase::SpecializedCharsBase;
+ 
+     TokenStreamAnyChars& anyCharsAccess() {
+         return AnyCharsAccess::anyChars(this);
+@@ -1600,16 +1601,50 @@ class GeneralTokenStreamChars
+     }
+ 
+     void ungetCodeUnit(int32_t c) {
+         MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
+ 
+         CharsBase::ungetCodeUnit(c);
+     }
+ 
++    /**
++     * Given a just-consumed ASCII code unit/point |lead|, consume a full code
++     * point or LineTerminatorSequence (normalizing it to '\n') and store it in
++     * |*codePoint|.  Return true on success, otherwise return false and leave
++     * |*codePoint| undefined on failure.
++     *
++     * If a LineTerminatorSequence was consumed, also update line/column info.
++     *
++     * This may change the current |sourceUnits| offset.
++     */
++    MOZ_MUST_USE bool getFullAsciiCodePoint(int32_t lead, int32_t* codePoint) {
++        MOZ_ASSERT(isAsciiCodePoint(lead),
++                   "non-ASCII code units must be handled separately");
++        MOZ_ASSERT(toCharT(lead) == this->sourceUnits.previousCodeUnit(),
++                   "getFullAsciiCodePoint called incorrectly");
++
++        if (MOZ_UNLIKELY(lead == '\r')) {
++            matchLineTerminator('\n');
++        } else if (MOZ_LIKELY(lead != '\n')) {
++            *codePoint = lead;
++            return true;
++        }
++
++        *codePoint = '\n';
++        bool ok = updateLineInfoForEOL();
++        if (!ok) {
++#ifdef DEBUG
++            *codePoint = EOF; // sentinel value to hopefully cause errors
++#endif
++            MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
++        }
++        return ok;
++    }
++
+     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+         return anyCharsAccess().internalUpdateLineInfoForEOL(this->sourceUnits.offset());
+     }
+ 
+     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
+ 
+     /**
+@@ -1704,51 +1739,16 @@ class TokenStreamChars<char16_t, AnyChar
+      * Get the next code point, converting LineTerminatorSequences to '\n' and
+      * updating internal line-counter state if needed.  Return true on success
+      * and store the code point in |*c|.  Return false and leave |*c| undefined
+      * on failure.
+      */
+     MOZ_MUST_USE bool getCodePoint(int32_t* cp);
+ 
+     /**
+-     * Given a just-consumed ASCII code unit/point |lead|, consume a full code
+-     * point or LineTerminatorSequence (normalizing it to '\n') and store it in
+-     * |*codePoint|.  Return true on success, otherwise return false and leave
+-     * |*codePoint| undefined on failure.
+-     *
+-     * If a LineTerminatorSequence was consumed, also update line/column info.
+-     *
+-     * This may change the current |sourceUnits| offset.
+-     */
+-    MOZ_MUST_USE bool getFullAsciiCodePoint(int32_t lead, int32_t* codePoint) {
+-        MOZ_ASSERT(isAsciiCodePoint(lead),
+-                   "non-ASCII code units must be handled separately");
+-        // NOTE: |this->|-qualify to avoid a gcc bug: see bug 1472569.
+-        MOZ_ASSERT(lead == this->sourceUnits.previousCodeUnit(),
+-                   "getFullAsciiCodePoint called incorrectly");
+-
+-        if (MOZ_UNLIKELY(lead == '\r')) {
+-            matchLineTerminator('\n');
+-        } else if (MOZ_LIKELY(lead != '\n')) {
+-            *codePoint = lead;
+-            return true;
+-        }
+-
+-        *codePoint = '\n';
+-        bool ok = updateLineInfoForEOL();
+-        if (!ok) {
+-#ifdef DEBUG
+-            *codePoint = EOF; // sentinel value to hopefully cause errors
+-#endif
+-            MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
+-        }
+-        return ok;
+-    }
+-
+-    /**
+      * Given a just-consumed non-ASCII code unit |lead| (which may also be a
+      * full code point, for UTF-16), consume a full code point or
+      * LineTerminatorSequence (normalizing it to '\n') and store it in
+      * |*codePoint|.  Return true on success, otherwise return false and leave
+      * |*codePoint| undefined on failure.
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+@@ -1893,17 +1893,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     // Deliberately don't |using| |charBuffer| because of bug 1472569.  :-(
+     using CharsBase::consumeKnownCodeUnit;
+     using SpecializedChars::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
+     using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+-    using SpecializedChars::getFullAsciiCodePoint;
++    using GeneralCharsBase::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePointDontNormalize;
+     using GeneralCharsBase::internalComputeLineOfContext;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using CharsBase::matchLineTerminator;
+     using GeneralCharsBase::matchUnicodeEscapeIdent;
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;

+ 334 - 0
frg/work-js/mozilla-release/patches/1477157-63a1.patch

@@ -0,0 +1,334 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533007383 -32400
+# Node ID 3efa24f1f0ce19ba688e4fecd43aba07a0e07710
+# Parent  a7dd2d39d71e5a7a848b26b414ebc60390ac79a1
+Bug 1477157 - Store the info about the existence of the default case into the switch ParseNode. r=jwalden
+
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -2339,33 +2339,33 @@ BytecodeEmitter::emitNumberOp(double dva
+ }
+ 
+ /*
+  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
+  * LLVM is deciding to inline this function which uses a lot of stack space
+  * into emitTree which is recursive and uses relatively little stack space.
+  */
+ MOZ_NEVER_INLINE bool
+-BytecodeEmitter::emitSwitch(ParseNode* pn)
+-{
+-    ParseNode* lexical = pn->pn_right;
+-    MOZ_ASSERT(lexical->isKind(ParseNodeKind::LexicalScope));
+-    ParseNode* cases = lexical->scopeBody();
++BytecodeEmitter::emitSwitch(SwitchStatement* pn)
++{
++    ParseNode& lexical = pn->lexicalForCaseList();
++    MOZ_ASSERT(lexical.isKind(ParseNodeKind::LexicalScope));
++    ParseNode* cases = lexical.scopeBody();
+     MOZ_ASSERT(cases->isKind(ParseNodeKind::StatementList));
+ 
+     SwitchEmitter se(this);
+     if (!se.emitDiscriminant(Some(pn->pn_pos.begin)))
+         return false;
+-    if (!emitTree(pn->pn_left))
++    if (!emitTree(&pn->discriminant()))
+         return false;
+ 
+     // Enter the scope before pushing the switch BreakableControl since all
+     // breaks are under this scope.
+-    if (!lexical->isEmptyScope()) {
+-        if (!se.emitLexical(lexical->scopeBindings()))
++    if (!lexical.isEmptyScope()) {
++        if (!se.emitLexical(lexical.scopeBindings()))
+             return false;
+ 
+         // A switch statement may contain hoisted functions inside its
+         // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST
+         // bodies of the cases to the case list.
+         if (cases->pn_xflags & PNX_FUNCDEFS) {
+             for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
+                 if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) {
+@@ -2374,44 +2374,36 @@ BytecodeEmitter::emitSwitch(ParseNode* p
+                 }
+             }
+         }
+     } else {
+         MOZ_ASSERT(!(cases->pn_xflags & PNX_FUNCDEFS));
+     }
+ 
+     SwitchEmitter::TableGenerator tableGen(this);
+-    uint32_t caseCount = cases->pn_count;
++    uint32_t caseCount = cases->pn_count - (pn->hasDefault() ? 1 : 0);
+     CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
+     if (caseCount == 0) {
+         tableGen.finish(0);
+-    } else if (caseCount == 1 && firstCase->isDefault()) {
+-        caseCount = 0;
+-        tableGen.finish(0);
+     } else {
+         for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
+-            if (caseNode->isDefault()) {
+-                caseCount--;  // one of the "cases" was the default
+-                continue;
+-            }
+-
+-            if (tableGen.isInvalid())
++            if (caseNode->isDefault())
+                 continue;
+ 
+             ParseNode* caseValue = caseNode->caseExpression();
+ 
+             if (caseValue->getKind() != ParseNodeKind::Number) {
+                 tableGen.setInvalid();
+-                continue;
++                break;
+             }
+ 
+             int32_t i;
+             if (!NumberEqualsInt32(caseValue->pn_dval, &i)) {
+                 tableGen.setInvalid();
+-                continue;
++                break;
+             }
+ 
+             if (!tableGen.addNumber(i))
+                 return false;
+         }
+ 
+         tableGen.finish(caseCount);
+     }
+@@ -8314,17 +8306,17 @@ BytecodeEmitter::emitTree(ParseNode* pn,
+         break;
+ 
+       case ParseNodeKind::If:
+         if (!emitIf(pn))
+             return false;
+         break;
+ 
+       case ParseNodeKind::Switch:
+-        if (!emitSwitch(pn))
++        if (!emitSwitch(&pn->as<SwitchStatement>()))
+             return false;
+         break;
+ 
+       case ParseNodeKind::While:
+         if (!emitWhile(pn))
+             return false;
+         break;
+ 
+diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
+--- a/js/src/frontend/BytecodeEmitter.h
++++ b/js/src/frontend/BytecodeEmitter.h
+@@ -686,17 +686,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitCatch(ParseNode* pn);
+     MOZ_MUST_USE bool emitIf(ParseNode* pn);
+     MOZ_MUST_USE bool emitWith(ParseNode* pn);
+ 
+     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement(const LabeledStatement* pn);
+     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn);
+     MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
+                                            EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
+-    MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(ParseNode* pn);
++    MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* pn);
+     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(ParseNode* pn);
+ 
+     enum DestructuringFlavor {
+         // Destructuring into a declaration.
+         DestructuringDeclaration,
+ 
+         // Destructuring into a formal parameter, when the formal parameters
+         // contain an expression that might be evaluated, and thus require
+diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
+--- a/js/src/frontend/FullParseHandler.h
++++ b/js/src/frontend/FullParseHandler.h
+@@ -604,19 +604,20 @@ class FullParseHandler
+ 
+     ParseNode* newForInOrOfHead(ParseNodeKind kind, ParseNode* target, ParseNode* iteratedExpr,
+                                 const TokenPos& pos)
+     {
+         MOZ_ASSERT(kind == ParseNodeKind::ForIn || kind == ParseNodeKind::ForOf);
+         return new_<TernaryNode>(kind, target, nullptr, iteratedExpr, pos);
+     }
+ 
+-    ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
+-        TokenPos pos(begin, caseList->pn_pos.end);
+-        return new_<BinaryNode>(ParseNodeKind::Switch, JSOP_NOP, pos, discriminant, caseList);
++    ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant,
++                                  ParseNode* lexicalForCaseList, bool hasDefault)
++    {
++        return new_<SwitchStatement>(begin, discriminant, lexicalForCaseList, hasDefault);
+     }
+ 
+     ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
+         return new_<CaseClause>(expr, body, begin);
+     }
+ 
+     ParseNode* newContinueStatement(PropertyName* label, const TokenPos& pos) {
+         return new_<ContinueStatement>(label, pos);
+diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
+--- a/js/src/frontend/ParseNode.h
++++ b/js/src/frontend/ParseNode.h
+@@ -253,16 +253,17 @@ IsTypeofKind(ParseNodeKind kind)
+  *
+  * <Statements>
+  * StatementList list   pn_head: list of pn_count statements
+  * If       ternary     pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
+  * Switch   binary      pn_left: discriminant
+  *                      pn_right: LexicalScope node that contains the list
+  *                        of Case nodes, with at most one
+  *                        default node.
++ *                      hasDefault: true if there's a default case
+  * Case     binary      pn_left: case-expression if CaseClause, or
+  *                            null if DefaultClause
+  *                          pn_right: StatementList node for this case's
+  *                            statements
+  * While    binary      pn_left: cond, pn_right: body
+  * DoWhile  binary      pn_left: body, pn_right: cond
+  * For      binary      pn_left: either ForIn (for-in statement),
+  *                            ForOf (for-of) or ForHead (for(;;))
+@@ -550,16 +551,17 @@ class ParseNode
+             ParseNode*  kid3;           /* else-part, default case, etc. */
+         } ternary;
+         struct {                        /* two kids if binary */
+             ParseNode*  left;
+             ParseNode*  right;
+             union {
+                 unsigned iflags;        /* JSITER_* flags for ParseNodeKind::For node */
+                 bool isStatic;          /* only for ParseNodeKind::ClassMethod */
++                bool hasDefault;        /* only for ParseNodeKind::Switch */
+             };
+         } binary;
+         struct {                        /* one kid if unary */
+             ParseNode*  kid;
+             bool        prologue;       /* directive prologue member (as
+                                            pn_prologue) */
+         } unary;
+         struct {                        /* name, labeled statement, etc. */
+@@ -1239,17 +1241,17 @@ struct CallSiteNode : public ListNode {
+ 
+     MOZ_MUST_USE bool getRawArrayValue(JSContext* cx, MutableHandleValue vp) {
+         return pn_head->getConstantValue(cx, AllowObjects, vp);
+     }
+ };
+ 
+ struct ClassMethod : public BinaryNode {
+     /*
+-     * Method defintions often keep a name and function body that overlap,
++     * Method definitions often keep a name and function body that overlap,
+      * so explicitly define the beginning and end here.
+      */
+     ClassMethod(ParseNode* name, ParseNode* body, JSOp op, bool isStatic)
+       : BinaryNode(ParseNodeKind::ClassMethod, op, TokenPos(name->pn_pos.begin, body->pn_pos.end), name, body)
+     {
+         pn_u.binary.isStatic = isStatic;
+     }
+ 
+@@ -1265,16 +1267,58 @@ struct ClassMethod : public BinaryNode {
+     ParseNode& method() const {
+         return *pn_u.binary.right;
+     }
+     bool isStatic() const {
+         return pn_u.binary.isStatic;
+     }
+ };
+ 
++struct SwitchStatement : public BinaryNode {
++    SwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* lexicalForCaseList,
++                    bool hasDefault)
++      : BinaryNode(ParseNodeKind::Switch, JSOP_NOP,
++                   TokenPos(begin, lexicalForCaseList->pn_pos.end),
++                   discriminant, lexicalForCaseList)
++    {
++#ifdef DEBUG
++        MOZ_ASSERT(lexicalForCaseList->isKind(ParseNodeKind::LexicalScope));
++        ParseNode* cases = lexicalForCaseList->scopeBody();
++        MOZ_ASSERT(cases->isKind(ParseNodeKind::StatementList));
++        bool found = false;
++        CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
++        for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
++            if (caseNode->isDefault()) {
++                found = true;
++                break;
++            }
++        }
++        MOZ_ASSERT(found == hasDefault);
++#endif
++
++        pn_u.binary.hasDefault = hasDefault;
++    }
++
++    static bool test(const ParseNode& node) {
++        bool match = node.isKind(ParseNodeKind::Switch);
++        MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
++        return match;
++    }
++
++    ParseNode& discriminant() const {
++        return *pn_u.binary.left;
++    }
++    ParseNode& lexicalForCaseList() const {
++        return *pn_u.binary.right;
++    }
++    bool hasDefault() const {
++        return pn_u.binary.hasDefault;
++    }
++};
++
+ struct ClassNames : public BinaryNode {
+     ClassNames(ParseNode* outerBinding, ParseNode* innerBinding, const TokenPos& pos)
+       : BinaryNode(ParseNodeKind::ClassNames, JSOP_NOP, pos, outerBinding, innerBinding)
+     {
+         MOZ_ASSERT_IF(outerBinding, outerBinding->isKind(ParseNodeKind::Name));
+         MOZ_ASSERT(innerBinding->isKind(ParseNodeKind::Name));
+         MOZ_ASSERT_IF(outerBinding, innerBinding->pn_atom == outerBinding->pn_atom);
+     }
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -6747,17 +6747,17 @@ GeneralParser<ParseHandler, CharT>::swit
+     }
+ 
+     caseList = finishLexicalScope(scope, caseList);
+     if (!caseList)
+         return null();
+ 
+     handler.setEndPosition(caseList, pos().end);
+ 
+-    return handler.newSwitchStatement(begin, discriminant, caseList);
++    return handler.newSwitchStatement(begin, discriminant, caseList, seenDefault);
+ }
+ 
+ template <class ParseHandler, typename CharT>
+ typename ParseHandler::Node
+ GeneralParser<ParseHandler, CharT>::continueStatement(YieldHandling yieldHandling)
+ {
+     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Continue));
+     uint32_t begin = pos().begin;
+diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
+--- a/js/src/frontend/SyntaxParseHandler.h
++++ b/js/src/frontend/SyntaxParseHandler.h
+@@ -305,17 +305,21 @@ class SyntaxParseHandler
+ 
+     Node newExprStatement(Node expr, uint32_t end) {
+         return expr == NodeUnparenthesizedString ? NodeStringExprStatement : NodeGeneric;
+     }
+ 
+     Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
+     Node newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { return NodeGeneric; }
+     Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
+-    Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
++    Node newSwitchStatement(uint32_t begin, Node discriminant, Node lexicalForCaseList,
++                            bool hasDefault)
++    {
++        return NodeGeneric;
++    }
+     Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
+     Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
+     Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
+     Node newReturnStatement(Node expr, const TokenPos& pos) { return NodeReturn; }
+     Node newExpressionBody(Node expr) { return NodeReturn; }
+     Node newWithStatement(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
+ 
+     Node newLabeledStatement(PropertyName* label, Node stmt, uint32_t begin) {

+ 327 - 0
frg/work-js/mozilla-release/patches/1477896-63a1.patch

@@ -0,0 +1,327 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1534423858 25200
+# Node ID 19dde1cd4e9f9f482fd4649c3bba0f7e2e71f6f3
+# Parent  633c5bbdc63697db3fb7786ffbc3e15a0fdd0aed
+Bug 1477896 - Add SRC_DO_WHILE replacing 2 SRC_WHILE notes for do-while. r=jandem
+
+diff --git a/js/src/frontend/DoWhileEmitter.cpp b/js/src/frontend/DoWhileEmitter.cpp
+--- a/js/src/frontend/DoWhileEmitter.cpp
++++ b/js/src/frontend/DoWhileEmitter.cpp
+@@ -26,23 +26,22 @@ DoWhileEmitter::emitBody(const Maybe<uin
+     MOZ_ASSERT(state_ == State::Start);
+ 
+     // Ensure that the column of the 'do' is set properly.
+     if (doPos) {
+         if (!bce_->updateSourceCoordNotes(*doPos))
+             return false;
+     }
+ 
+-    // Emit an annotated nop so IonBuilder can recognize the 'do' loop.
+-    if (!bce_->newSrcNote(SRC_WHILE, &noteIndex_))
+-        return false;
++    // We need a nop here to make it possible to set a breakpoint on `do`.
+     if (!bce_->emit1(JSOP_NOP))
+         return false;
+ 
+-    if (!bce_->newSrcNote(SRC_WHILE, &noteIndex2_))
++    // Emit an annotated nop so IonBuilder can recognize the 'do' loop.
++    if (!bce_->newSrcNote3(SRC_DO_WHILE, 0, 0, &noteIndex_))
+         return false;
+ 
+     loopInfo_.emplace(bce_, StatementKind::DoLoop);
+ 
+     if (!loopInfo_->emitLoopHead(bce_, bodyPos))
+         return false;
+ 
+     if (!loopInfo_->emitLoopEntry(bce_, Nothing()))
+@@ -79,28 +78,23 @@ DoWhileEmitter::emitEnd()
+     if (!bce_->tryNoteList.append(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
+                                   loopInfo_->breakTargetOffset()))
+     {
+         return false;
+     }
+ 
+     // Update the annotations with the update and back edge positions, for
+     // IonBuilder.
+-    //
+-    // Be careful: We must set noteIndex2_ before_ noteIndex in case the
+-    // noteIndex_ note gets bigger.  Otherwise noteIndex2_ can point wrong
+-    // position.
+-    if (!bce_->setSrcNoteOffset(noteIndex2_, SrcNote::DoWhile2::BackJumpOffset,
+-                                loopInfo_->loopEndOffsetFromLoopHead()))
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::CondOffset,
++                                loopInfo_->continueTargetOffsetFromLoopHead()))
+     {
+         return false;
+     }
+-    // +1 for NOP in emitBody.
+-    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile1::CondOffset,
+-                                loopInfo_->continueTargetOffsetFromLoopHead() + 1))
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile::BackJumpOffset,
++                                loopInfo_->loopEndOffsetFromLoopHead()))
+     {
+         return false;
+     }
+ 
+     if (!loopInfo_->patchBreaksAndContinues(bce_))
+         return false;
+ 
+     loopInfo_.reset();
+diff --git a/js/src/frontend/DoWhileEmitter.h b/js/src/frontend/DoWhileEmitter.h
+--- a/js/src/frontend/DoWhileEmitter.h
++++ b/js/src/frontend/DoWhileEmitter.h
+@@ -30,20 +30,18 @@ struct BytecodeEmitter;
+ //     doWhile.emitCond();
+ //     emit(cond);
+ //     doWhile.emitEnd();
+ //
+ class MOZ_STACK_CLASS DoWhileEmitter
+ {
+     BytecodeEmitter* bce_;
+ 
+-    // The source note indices for 2 SRC_WHILE's.
+-    // FIXME: Add SRC_DO_WHILE (bug 1477896).
++    // The source note index for SRC_DO_WHILE.
+     unsigned noteIndex_ = 0;
+-    unsigned noteIndex2_ = 0;
+ 
+     mozilla::Maybe<LoopControl> loopInfo_;
+ 
+ #ifdef DEBUG
+     // The state of this emitter.
+     //
+     // +-------+ emitBody +------+ emitCond +------+ emitEnd  +-----+
+     // | Start |--------->| Body |--------->| Cond |--------->| End |
+diff --git a/js/src/frontend/SourceNotes.h b/js/src/frontend/SourceNotes.h
+--- a/js/src/frontend/SourceNotes.h
++++ b/js/src/frontend/SourceNotes.h
+@@ -59,33 +59,23 @@ class SrcNote {
+     class While {
+       public:
+         enum Fields {
+             // The offset of JSOP_IFNE at the end of the loop from JSOP_GOTO.
+             BackJumpOffset,
+             Count,
+         };
+     };
+-    // SRC_WHILE for do-while: Source note for JSOP_NOP at the top of do-while
+-    //                         loop
+-    // FIXME: Add SRC_DO_WHILE (bug 1477896).
+-    class DoWhile1 {
++    // SRC_DO_WHILE: Source note for JSOP_LOOPHEAD at the top of do-while loop
++    class DoWhile {
+       public:
+         enum Fields {
+-            // The offset of the condition ops from JSOP_NOP.
++            // The offset of the condition ops from JSOP_LOOPHEAD.
+             CondOffset,
+-            Count,
+-        };
+-    };
+-    // SRC_WHILE for do-while: Source note for JSOP_LOOPHEAD at the top of
+-    //                         do-while loop
+-    // FIXME: Add SRC_DO_WHILE (bug 1477896).
+-    class DoWhile2 {
+-      public:
+-        enum Fields {
++
+             // The offset of JSOP_IFNE at the end of the loop from
+             // JSOP_LOOPHEAD.
+             BackJumpOffset,
+             Count,
+         };
+     };
+     // SRC_FOR_IN: Source note for JSOP_GOTO at the top of for-in loop,
+     //             which jumps to JSOP_LOOPENTRY.
+@@ -166,29 +156,24 @@ class SrcNote {
+         enum Fields {
+             // The file-absolute source line number of the current op.
+             Line,
+             Count
+         };
+     };
+ };
+ 
+-// FIXME: Add SRC_DO_WHILE (bug 1477896).
+-static_assert(unsigned(SrcNote::While::Count) == unsigned(SrcNote::DoWhile1::Count),
+-              "SRC_WHILE can be shared between while and do-while");
+-static_assert(unsigned(SrcNote::While::Count) == unsigned(SrcNote::DoWhile2::Count),
+-              "SRC_WHILE can be shared between while and do-while");
+-
+ #define FOR_EACH_SRC_NOTE_TYPE(M)                                                                  \
+     M(SRC_NULL,         "null",        0)  /* Terminates a note vector. */                         \
+     M(SRC_IF,           "if",          0)  /* JSOP_IFEQ bytecode is from an if-then. */            \
+     M(SRC_IF_ELSE,      "if-else",     0)  /* JSOP_IFEQ bytecode is from an if-then-else. */       \
+     M(SRC_COND,         "cond",        0)  /* JSOP_IFEQ is from conditional ?: operator. */        \
+     M(SRC_FOR,          "for",         SrcNote::For::Count) \
+     M(SRC_WHILE,        "while",       SrcNote::While::Count) \
++    M(SRC_DO_WHILE,     "do-while",    SrcNote::DoWhile::Count) \
+     M(SRC_FOR_IN,       "for-in",      SrcNote::ForIn::Count) \
+     M(SRC_FOR_OF,       "for-of",      SrcNote::ForOf::Count) \
+     M(SRC_CONTINUE,     "continue",    0)  /* JSOP_GOTO is a continue. */                          \
+     M(SRC_BREAK,        "break",       0)  /* JSOP_GOTO is a break. */                             \
+     M(SRC_BREAK2LABEL,  "break2label", 0)  /* JSOP_GOTO for 'break label'. */                      \
+     M(SRC_SWITCHBREAK,  "switchbreak", 0)  /* JSOP_GOTO is a break in a switch. */                 \
+     M(SRC_TABLESWITCH,  "tableswitch", SrcNote::TableSwitch::Count) \
+     M(SRC_CONDSWITCH,   "condswitch",  SrcNote::CondSwitch::Count) \
+@@ -196,17 +181,16 @@ static_assert(unsigned(SrcNote::While::C
+     M(SRC_ASSIGNOP,     "assignop",    0)  /* += or another assign-op follows. */                  \
+     M(SRC_CLASS_SPAN,   "class",       2)  /* The starting and ending offsets for the class, used  \
+                                               for toString correctness for default ctors. */       \
+     M(SRC_TRY,          "try",         SrcNote::Try::Count) \
+     /* All notes above here are "gettable".  See SN_IS_GETTABLE below. */                          \
+     M(SRC_COLSPAN,      "colspan",     SrcNote::ColSpan::Count) \
+     M(SRC_NEWLINE,      "newline",     0)  /* Bytecode follows a source newline. */                \
+     M(SRC_SETLINE,      "setline",     SrcNote::SetLine::Count) \
+-    M(SRC_UNUSED21,     "unused21",    0)  /* Unused. */                                           \
+     M(SRC_UNUSED22,     "unused22",    0)  /* Unused. */                                           \
+     M(SRC_UNUSED23,     "unused23",    0)  /* Unused. */                                           \
+     M(SRC_XDELTA,       "xdelta",      0)  /* 24-31 are for extended delta notes. */
+ 
+ enum SrcNoteType {
+ #define DEFINE_SRC_NOTE_TYPE(sym, name, arity) sym,
+     FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_TYPE)
+ #undef DEFINE_SRC_NOTE_TYPE
+diff --git a/js/src/jit/IonControlFlow.cpp b/js/src/jit/IonControlFlow.cpp
+--- a/js/src/jit/IonControlFlow.cpp
++++ b/js/src/jit/IonControlFlow.cpp
+@@ -259,27 +259,18 @@ ControlFlowGenerator::traverseBytecode()
+ }
+ 
+ ControlFlowGenerator::ControlStatus
+ ControlFlowGenerator::snoopControlFlow(JSOp op)
+ {
+     switch (op) {
+       case JSOP_NOP: {
+         jssrcnote* sn = GetSrcNote(gsn, script, pc);
+-        if (sn) {
+-            // do { } while (cond)
+-            if (SN_TYPE(sn) == SRC_WHILE)
+-                return processDoWhileLoop(sn);
+-            // Build a mapping such that given a basic block, whose successor
+-            // has a phi
+-
+-            // for (; ; update?)
+-            if (SN_TYPE(sn) == SRC_FOR)
+-                return processForLoop(op, sn);
+-        }
++        if (sn && SN_TYPE(sn) == SRC_FOR)
++            return processForLoop(op, sn);
+         break;
+       }
+ 
+       case JSOP_RETURN:
+       case JSOP_RETRVAL:
+         return processReturn(op);
+ 
+       case JSOP_THROW:
+@@ -307,16 +298,23 @@ ControlFlowGenerator::snoopControlFlow(J
+ 
+           default:
+             // Hard assert for now - make an error later.
+             MOZ_CRASH("unknown goto case");
+         }
+         break;
+       }
+ 
++      case JSOP_LOOPHEAD: {
++        jssrcnote* sn = GetSrcNote(gsn, script, pc);
++        if (sn && SN_TYPE(sn) == SRC_DO_WHILE)
++            return processDoWhileLoop(sn);
++        break;
++      }
++
+       case JSOP_TABLESWITCH: {
+         jssrcnote* sn = GetSrcNote(gsn, script, pc);
+         return processTableSwitch(op, sn);
+       }
+ 
+       case JSOP_CONDSWITCH:
+         return processCondSwitch();
+ 
+@@ -1500,34 +1498,32 @@ ControlFlowGenerator::processForLoop(JSO
+         return ControlStatus::Error;
+     return ControlStatus::Jumped;
+ }
+ 
+ ControlFlowGenerator::ControlStatus
+ ControlFlowGenerator::processDoWhileLoop(jssrcnote* sn)
+ {
+     // do { } while() loops have the following structure:
+-    //    NOP         ; SRC_WHILE (offset to COND)
+-    //    LOOPHEAD    ; SRC_WHILE (offset to IFNE)
++    //    NOP
++    //    LOOPHEAD    ; SRC_DO_WHILE (offsets to COND and IFNE)
+     //    LOOPENTRY
+     //    ...         ; body
+     //    ...
+     //    COND        ; start of condition
+     //    ...
+     //    IFNE ->     ; goes to LOOPHEAD
+-    int condition_offset = GetSrcNoteOffset(sn, SrcNote::DoWhile1::CondOffset);
++    int condition_offset = GetSrcNoteOffset(sn, SrcNote::DoWhile::CondOffset);
+     jsbytecode* conditionpc = pc + condition_offset;
+-
+-    jssrcnote* sn2 = GetSrcNote(gsn, script, pc + 1);
+-    int offset = GetSrcNoteOffset(sn2, SrcNote::DoWhile2::BackJumpOffset);
+-    jsbytecode* ifne = pc + offset + 1;
++    int offset = GetSrcNoteOffset(sn, SrcNote::DoWhile::BackJumpOffset);
++    jsbytecode* ifne = pc + offset;
+     MOZ_ASSERT(ifne > pc);
+ 
+     // Verify that the IFNE goes back to a loophead op.
+-    jsbytecode* loopHead = GetNextPc(pc);
++    jsbytecode* loopHead = pc;
+     MOZ_ASSERT(JSOp(*loopHead) == JSOP_LOOPHEAD);
+     MOZ_ASSERT(loopHead == ifne + GetJumpOffset(ifne));
+ 
+     jsbytecode* loopEntry = GetNextPc(loopHead);
+ 
+     CFGBlock* header = CFGBlock::New(alloc(), loopEntry);
+ 
+     CFGLoopEntry* ins = CFGLoopEntry::New(alloc(), header, 0);
+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
+@@ -2703,30 +2703,34 @@ SrcNotes(JSContext* cx, HandleScript scr
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::For::CondOffset)),
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::For::UpdateOffset)),
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::For::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
++          case SRC_WHILE:
+           case SRC_FOR_IN:
+           case SRC_FOR_OF:
+-            static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == unsigned(SrcNote::ForOf::BackJumpOffset),
+-                          "SrcNote::{ForIn,ForOf}::BackJumpOffset should be same");
++            static_assert(unsigned(SrcNote::While::BackJumpOffset) == unsigned(SrcNote::ForIn::BackJumpOffset),
++                          "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
++            static_assert(unsigned(SrcNote::While::BackJumpOffset) == unsigned(SrcNote::ForOf::BackJumpOffset),
++                          "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
+             if (!sp->jsprintf(" backjump %u",
+-                              unsigned(GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset))))
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::While::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
+-          case SRC_WHILE:
+-            if (!sp->jsprintf(" offset %u",
+-                              unsigned(GetSrcNoteOffset(sn, SrcNote::While::BackJumpOffset))))
++          case SRC_DO_WHILE:
++            if (!sp->jsprintf(" cond %u backjump %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::DoWhile::CondOffset)),
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::DoWhile::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
+           case SRC_NEXTCASE:
+             if (!sp->jsprintf(" next case offset %u",
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::NextCase::NextCaseOffset))))

+ 357 - 0
frg/work-js/mozilla-release/patches/1478045-1-63a1.patch

@@ -0,0 +1,357 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553863 25200
+#      Wed Jul 25 14:24:23 2018 -0700
+# Node ID b4a63f805c039170375033eff016d850192cf3d6
+# Parent  5b62a5042e79c5a571d0ac3d89ce2fec85bb27ba
+Bug 1478045 - Implement SourceUnits::{peek,consumeKnown}CodePoint for the uncommon cases where a code point must be gotten, tested against one or more predicates, then sometimes ungotten based on those predicates.  (This is unfortunately a bit subtle, but getting and ungetting is arguably worse, because ungetting has to unget a variable number of code units -- whereas peeking can compute that number of code units and then use it directly when the peeked code point is consumed, avoiding double-computation and increased potential for error.)  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -506,16 +506,37 @@ void
+ TokenStreamAnyChars::undoInternalUpdateLineInfoForEOL()
+ {
+     MOZ_ASSERT(prevLinebase != size_t(-1)); // we should never get more than one EOL
+     linebase = prevLinebase;
+     prevLinebase = size_t(-1);
+     lineno--;
+ }
+ 
++#ifdef DEBUG
++
++template<>
++inline void
++SourceUnits<char16_t>::assertNextCodePoint(const PeekedCodePoint<char16_t>& peeked)
++{
++    char32_t c = peeked.codePoint();
++    if (c < unicode::NonBMPMin) {
++        MOZ_ASSERT(peeked.lengthInUnits() == 1);
++        MOZ_ASSERT(ptr[0] == c);
++    } else {
++        MOZ_ASSERT(peeked.lengthInUnits() == 2);
++        char16_t lead, trail;
++        unicode::UTF16Encode(c, &lead, &trail);
++        MOZ_ASSERT(ptr[0] == lead);
++        MOZ_ASSERT(ptr[1] == trail);
++    }
++}
++
++#endif // DEBUG
++
+ template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
+ {
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+     if (MOZ_UNLIKELY(this->sourceUnits.atEnd())) {
+         anyChars.flags.isEOF = true;
+@@ -1838,63 +1859,80 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     // Check if in the middle of a template string. Have to get this out of
+     // the way first.
+     if (MOZ_UNLIKELY(modifier == TemplateTail))
+         return getStringOrTemplateToken('`', modifier, ttp);
+ 
+     // This loop runs more than once only when whitespace or comments are
+     // encountered.
+     do {
+-        int32_t unit = getCodeUnit();
++        int32_t unit = peekCodeUnit();
+         if (MOZ_UNLIKELY(unit == EOF)) {
+             MOZ_ASSERT(this->sourceUnits.atEnd());
+             anyCharsAccess().flags.isEOF = true;
+             TokenStart start(this->sourceUnits, 0);
+             newSimpleToken(TokenKind::Eof, start, modifier, ttp);
+             return true;
+         }
+ 
+         if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+             // Non-ASCII code points can only be identifiers or whitespace.
+             // It would be nice to compute these *after* discarding whitespace,
+             // but IN A WORLD where |unicode::IsSpaceOrBOM2| requires consuming
+             // a variable number of code points, it's easier to assume it's an
+             // identifier and maybe do a little wasted work, than to unget and
+             // compute and reget if whitespace.
+-            TokenStart start(this->sourceUnits, -1);
+-            const CharT* identStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+-
+-            int32_t codePoint;
+-            if (!getNonAsciiCodePoint(unit, &codePoint))
++            TokenStart start(this->sourceUnits, 0);
++            const CharT* identStart = this->sourceUnits.addressOfNextCodeUnit();
++
++            PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
++            if (peeked.isNone()) {
++                int32_t bad;
++                MOZ_ALWAYS_FALSE(getCodePoint(&bad));
+                 return badToken();
+-
+-            if (unicode::IsSpaceOrBOM2(codePoint)) {
+-                if (codePoint == '\n')
++            }
++
++            char32_t cp = peeked.codePoint();
++            if (unicode::IsSpaceOrBOM2(cp)) {
++                this->sourceUnits.consumeKnownCodePoint(peeked);
++                if (IsLineTerminator(cp)) {
++                    if (!updateLineInfoForEOL())
++                        return badToken();
++
+                     anyCharsAccess().updateFlagsForEOL();
++                }
+ 
+                 continue;
+             }
+ 
+             static_assert(isAsciiCodePoint('$'),
+                           "IdentifierStart contains '$', but as "
+                           "!IsUnicodeIDStart('$'), ensure that '$' is never "
+                           "handled here");
+             static_assert(isAsciiCodePoint('_'),
+                           "IdentifierStart contains '_', but as "
+                           "!IsUnicodeIDStart('_'), ensure that '_' is never "
+                           "handled here");
+ 
+-            if (unicode::IsUnicodeIDStart(uint32_t(codePoint)))
++            if (MOZ_LIKELY(unicode::IsUnicodeIDStart(cp))) {
++                this->sourceUnits.consumeKnownCodePoint(peeked);
++                MOZ_ASSERT(!IsLineTerminator(cp),
++                           "IdentifierStart must guarantee !IsLineTerminator "
++                           "or else we'll fail to maintain line-info/flags "
++                           "for EOL here");
++
+                 return identifierName(start, identStart, IdentifierEscapes::None, modifier, ttp);
+-
+-            ungetCodePointIgnoreEOL(codePoint);
++            }
++
+             error(JSMSG_ILLEGAL_CHARACTER);
+             return badToken();
+         } // !isAsciiCodePoint(unit)
+ 
++        consumeKnownCodeUnit(unit);
++
+         // Get the token kind, based on the first char.  The ordering of c1kind
+         // comparison is based on the frequency of tokens in real code:
+         // Parsemark (which represents typical JS code on the web) and the
+         // Unreal demo (which represents asm.js code).
+         //
+         //                  Parsemark   Unreal
+         //  OneChar         32.9%       39.7%
+         //  Space           25.0%        0.6%
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -190,16 +190,17 @@
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+ #include <stdarg.h>
+ #include <stddef.h>
++#include <stdint.h>
+ #include <stdio.h>
+ 
+ #include "jspubtd.h"
+ 
+ #include "frontend/ErrorReporter.h"
+ #include "frontend/TokenKind.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
+@@ -964,16 +965,135 @@ IsLineTerminator(char32_t codePoint)
+ 
+ inline bool
+ IsLineTerminator(char16_t unit)
+ {
+     // Every LineTerminator fits in char16_t, so this is exact.
+     return IsLineTerminator(static_cast<char32_t>(unit));
+ }
+ 
++template<typename CharT>
++struct SourceUnitTraits;
++
++template<>
++struct SourceUnitTraits<char16_t>
++{
++  public:
++    static constexpr uint8_t maxUnitsLength = 2;
++
++    static constexpr size_t lengthInUnits(char32_t codePoint) {
++        return codePoint < unicode::NonBMPMin ? 1 : 2;
++    }
++};
++
++template<>
++struct SourceUnitTraits<mozilla::Utf8Unit>
++{
++  public:
++    static constexpr uint8_t maxUnitsLength = 4;
++
++    static constexpr size_t lengthInUnits(char32_t codePoint) {
++        return codePoint < 0x80
++               ? 1
++               : codePoint < 0x800
++               ? 2
++               : codePoint < 0x10000
++               ? 3
++               : 4;
++    }
++};
++
++/**
++ * PeekedCodePoint represents the result of peeking ahead in some source text
++ * to determine the next validly-encoded code point.
++ *
++ * If there isn't a valid code point, then |isNone()|.
++ *
++ * But if there *is* a valid code point, then |!isNone()|, the code point has
++ * value |codePoint()| and its length in code units is |lengthInUnits()|.
++ *
++ * Conceptually, this class is |Maybe<struct { char32_t v; uint8_t len; }>|.
++ */
++template<typename CharT>
++class PeekedCodePoint final
++{
++    char32_t codePoint_ = 0;
++    uint8_t lengthInUnits_ = 0;
++
++  private:
++    using SourceUnitTraits = frontend::SourceUnitTraits<CharT>;
++
++    PeekedCodePoint() = default;
++
++  public:
++    /**
++     * Create a peeked code point with the given value and length in code
++     * units.
++     *
++     * While the latter value is computable from the former for both UTF-8 and
++     * JS's version of UTF-16, the caller likely computed a length in units in
++     * the course of determining the peeked value.  Passing both here avoids
++     * recomputation and lets us do a consistency-checking assertion.
++     */
++    PeekedCodePoint(char32_t codePoint, uint8_t lengthInUnits)
++      : codePoint_(codePoint),
++        lengthInUnits_(lengthInUnits)
++    {
++        MOZ_ASSERT(codePoint <= unicode::NonBMPMax);
++        MOZ_ASSERT(lengthInUnits != 0, "bad code point length");
++        MOZ_ASSERT(lengthInUnits == SourceUnitTraits::lengthInUnits(codePoint));
++    }
++
++    /** Create a PeekedCodeUnit that represents no valid code point. */
++    static PeekedCodePoint none() {
++        return PeekedCodePoint();
++    }
++
++    /** True if no code point was found, false otherwise. */
++    bool isNone() const {
++        return lengthInUnits_ == 0;
++    }
++
++    /** If a code point was found, its value. */
++    char32_t codePoint() const {
++        MOZ_ASSERT(!isNone());
++        return codePoint_;
++    }
++
++    /** If a code point was found, its length in code units. */
++    uint8_t lengthInUnits() const {
++        MOZ_ASSERT(!isNone());
++        return lengthInUnits_;
++    }
++};
++
++inline PeekedCodePoint<char16_t>
++PeekCodePoint(const char16_t* const ptr, const char16_t* const end)
++{
++    if (MOZ_UNLIKELY(ptr >= end))
++        return PeekedCodePoint<char16_t>::none();
++
++    char16_t lead = ptr[0];
++
++    char32_t c;
++    uint8_t len;
++    if (MOZ_LIKELY(!unicode::IsLeadSurrogate(lead)) ||
++        MOZ_UNLIKELY(ptr + 1 >= end ||
++                     !unicode::IsTrailSurrogate(ptr[1])))
++    {
++        c = lead;
++        len = 1;
++    } else {
++        c = unicode::UTF16Decode(lead, ptr[1]);
++        len = 2;
++    }
++
++    return PeekedCodePoint<char16_t>(c, len);
++}
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //
+@@ -1034,16 +1154,57 @@ class SourceUnits
+     CharT getCodeUnit() {
+         return *ptr++;      // this will nullptr-crash if poisoned
+     }
+ 
+     CharT peekCodeUnit() const {
+         return *ptr;        // this will nullptr-crash if poisoned
+     }
+ 
++    /**
++     * Determine the next code point in source text.  The code point is not
++     * normalized: '\r', '\n', '\u2028', and '\u2029' are returned literally.
++     * If there is no next code point because |atEnd()|, or if an encoding
++     * error is encountered, return a |PeekedCodePoint| that |isNone()|.
++     *
++     * This function does not report errors: code that attempts to get the next
++     * code point must report any error.
++     *
++     * If a next code point is found, it may be consumed by passing it to
++     * |consumeKnownCodePoint|.
++     */
++    PeekedCodePoint<CharT> peekCodePoint() const {
++        return PeekCodePoint(ptr, limit_);
++    }
++
++  private:
++#ifdef DEBUG
++    void assertNextCodePoint(const PeekedCodePoint<CharT>& peeked);
++#endif
++
++  public:
++    /**
++     * Consume a peeked code point that |!isNone()|.
++     *
++     * This call DOES NOT UPDATE LINE-STATUS.  You may need to call
++     * |updateLineInfoForEOL()| and |updateFlagsForEOL()| if this consumes a
++     * LineTerminator.  Note that if this consumes '\r', you also must consume
++     * an optional '\n' (i.e. a full LineTerminatorSequence) before doing so.
++     */
++    void consumeKnownCodePoint(const PeekedCodePoint<CharT>& peeked) {
++        MOZ_ASSERT(!peeked.isNone());
++        MOZ_ASSERT(peeked.lengthInUnits() <= remaining());
++
++#ifdef DEBUG
++        assertNextCodePoint(peeked);
++#endif
++
++        ptr += peeked.lengthInUnits();
++    }
++
+     /** Match |n| hexadecimal digits and store their value in |*out|. */
+     bool matchHexDigits(uint8_t n, char16_t* out) {
+         MOZ_ASSERT(ptr, "shouldn't peek into poisoned SourceUnits");
+         MOZ_ASSERT(n <= 4, "hexdigit value can't overflow char16_t");
+         if (n > remaining())
+             return false;
+ 
+         char16_t v = 0;

+ 39 - 0
frg/work-js/mozilla-release/patches/1478045-2-63a1.patch

@@ -0,0 +1,39 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553874 25200
+#      Wed Jul 25 14:24:34 2018 -0700
+# Node ID c79e79e350bfc7ac18d7199cb5a0ae9e4b50d78c
+# Parent  b4a63f805c039170375033eff016d850192cf3d6
+Bug 1478045 - Use SourceUnits::peekCodePoint to look for an IdentifierStart after most decimal numeric literals, rather than getting and ungetting.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1702,23 +1702,20 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     // two tokens, necessitating this unaesthetic lookahead.)
+     if (unit != EOF) {
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+             if (unicode::IsIdentifierStart(char16_t(unit))) {
+                 error(JSMSG_IDSTART_AFTER_NUMBER);
+                 return false;
+             }
+         } else {
+-            int32_t codePoint;
+-            if (!getCodePoint(&codePoint))
+-                return false;
+-
+-            ungetNonAsciiNormalizedCodePoint(codePoint);
+-
+-            if (unicode::IsIdentifierStart(uint32_t(codePoint))) {
++            // This ignores encoding errors: subsequent caller-side code to
++            // handle source text after the number will do so.
++            PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
++            if (!peeked.isNone() && unicode::IsIdentifierStart(peeked.codePoint())) {
+                 error(JSMSG_IDSTART_AFTER_NUMBER);
+                 return false;
+             }
+         }
+     }
+ 
+     noteBadToken.release();
+     newNumberToken(dval, decimalPoint, start, modifier, out);

+ 49 - 0
frg/work-js/mozilla-release/patches/1478045-3-63a1.patch

@@ -0,0 +1,49 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553874 25200
+#      Wed Jul 25 14:24:34 2018 -0700
+# Node ID 51e2ba3c67d66b80d655c897a266bbb2f9e0f511
+# Parent  c79e79e350bfc7ac18d7199cb5a0ae9e4b50d78c
+Bug 1478045 - Use SourceUnits::peekCodePoint when examining a non-ASCII code point that might terminate a directive in a comment.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1287,26 +1287,28 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             }
+ 
+             if (!this->charBuffer.append(unit))
+                 return false;
+ 
+             continue;
+         }
+ 
+-        int32_t codePoint;
+-        if (!getCodePoint(&codePoint))
+-            return false;
+-
+-        if (unicode::IsSpaceOrBOM2(codePoint)) {
+-            ungetNonAsciiNormalizedCodePoint(codePoint);
++        // This ignores encoding errors: subsequent caller-side code to
++        // handle the remaining source text in the comment will do so.
++        PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
++        if (peeked.isNone() || unicode::IsSpaceOrBOM2(peeked.codePoint()))
+             break;
+-        }
+-
+-        if (!appendCodePointToCharBuffer(codePoint))
++
++        MOZ_ASSERT(!IsLineTerminator(peeked.codePoint()),
++                   "!IsSpaceOrBOM2 must imply !IsLineTerminator or else we'll "
++                   "fail to maintain line-info/flags for EOL");
++        this->sourceUnits.consumeKnownCodePoint(peeked);
++
++        if (!appendCodePointToCharBuffer(peeked.codePoint()))
+             return false;
+     } while (true);
+ 
+     if (this->charBuffer.empty()) {
+         // The directive's URL was missing, but comments can contain anything,
+         // so it isn't an error.
+         return true;
+     }

+ 66 - 0
frg/work-js/mozilla-release/patches/1478045-4-63a1.patch

@@ -0,0 +1,66 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553875 25200
+#      Wed Jul 25 14:24:35 2018 -0700
+# Node ID 466d4573b39a20544f7166d0c10a6b931373b8b9
+# Parent  51e2ba3c67d66b80d655c897a266bbb2f9e0f511
+Bug 1478045 - Use SourceUnits::peekCodePoint when examining a non-ASCII code point that might terminate an IdentifierName.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1473,41 +1473,46 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         this->badToken();
+     });
+ 
+     // We've already consumed an initial code point in the identifer, to *know*
+     // that this is an identifier.  So no need to worry about not consuming any
+     // code points in the loop below.
+     int32_t unit;
+     while (true) {
+-        unit = getCodeUnit();
++        unit = peekCodeUnit();
+         if (unit == EOF)
+             break;
+ 
+         if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
++            consumeKnownCodeUnit(unit);
++
+             if (MOZ_UNLIKELY(!unicode::IsIdentifierPart(static_cast<char16_t>(unit)))) {
+                 // Handle a Unicode escape -- otherwise it's not part of the
+                 // identifier.
+                 uint32_t codePoint;
+                 if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint)) {
+                     ungetCodeUnit(unit);
+                     break;
+                 }
+ 
+                 escaping = IdentifierEscapes::SawUnicodeEscape;
+             }
+         } else {
+-            int32_t codePoint;
+-            if (!getNonAsciiCodePoint(unit, &codePoint))
+-                return false;
+-
+-            if (!unicode::IsIdentifierPart(uint32_t(codePoint))) {
+-                ungetNonAsciiNormalizedCodePoint(codePoint);
++            // This ignores encoding errors: subsequent caller-side code to
++            // handle source text after the IdentifierName will do so.
++            PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
++            if (peeked.isNone() || !unicode::IsIdentifierPart(peeked.codePoint()))
+                 break;
+-            }
++
++            MOZ_ASSERT(!IsLineTerminator(peeked.codePoint()),
++                       "IdentifierPart must guarantee !IsLineTerminator or "
++                       "else we'll fail to maintain line-info/flags for EOL");
++
++            this->sourceUnits.consumeKnownCodePoint(peeked);
+         }
+     }
+ 
+     JSAtom* atom;
+     if (MOZ_UNLIKELY(escaping == IdentifierEscapes::SawUnicodeEscape)) {
+         // Identifiers containing Unicode escapes have to be converted into
+         // tokenbuf before atomizing.
+         if (!putIdentInCharBuffer(identStart))

+ 62 - 0
frg/work-js/mozilla-release/patches/1478045-5-63a1.patch

@@ -0,0 +1,62 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553875 25200
+#      Wed Jul 25 14:24:35 2018 -0700
+# Node ID d1d2c7b998efa62f6d199df72a1db07cf5bbbd5b
+# Parent  466d4573b39a20544f7166d0c10a6b931373b8b9
+Bug 1478045 - Use SourceUnits::peekCodePoint when examining a non-ASCII code point after non-decimal numeric literals and a subset of decimal numeric literals.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -2084,39 +2084,31 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 // '0' not followed by [XxBbOo0-9];  scan as a decimal number.
+                 numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
+ 
+                 // NOTE: |unit| may be EOF here.  (This is permitted by case #3
+                 //       in TokenStream.h docs for this function.)
+                 return decimalNumber(unit, start, numStart, modifier, ttp);
+             }
+ 
+-            // Check for an identifier-start code point immediately after the
+-            // number.  This must be an error, and somewhat surprisingly, if
+-            // a check doesn't happen here, it never will.
+-            if (MOZ_UNLIKELY(unit == EOF)) {
+-                // Technically this isn't necessary -- ungetting EOF does
+-                // nothing -- but it's conceptually nicer if we consider all
+-                // gets requiring an unget to revert them.
+-                ungetCodeUnit(unit);
+-            } else if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+-                ungetCodeUnit(unit);
+-
++            ungetCodeUnit(unit);
++
++            // Error if an identifier-start code point appears immediately
++            // after the number.  Somewhat surprisingly, if we don't check
++            // here, we'll never check at all.
++            if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+                 if (unicode::IsIdentifierStart(char16_t(unit))) {
+                     error(JSMSG_IDSTART_AFTER_NUMBER);
+                     return badToken();
+                 }
+-            } else {
+-                int32_t codePoint;
+-                if (!getNonAsciiCodePoint(unit, &codePoint))
+-                    return badToken();
+-
+-                ungetNonAsciiNormalizedCodePoint(codePoint);
+-
+-                if (unicode::IsIdentifierStart(uint32_t(codePoint))) {
++            } else if (MOZ_LIKELY(unit != EOF)) {
++                // This ignores encoding errors: subsequent caller-side code to
++                // handle source text after the number will do so.
++                PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
++                if (!peeked.isNone() && unicode::IsIdentifierStart(peeked.codePoint())) {
+                     error(JSMSG_IDSTART_AFTER_NUMBER);
+                     return badToken();
+                 }
+             }
+ 
+             double dval;
+             const char16_t* dummy;
+             if (!GetPrefixInteger(anyCharsAccess().cx, numStart,

+ 114 - 0
frg/work-js/mozilla-release/patches/1478045-6-63a1.patch

@@ -0,0 +1,114 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553875 25200
+#      Wed Jul 25 14:24:35 2018 -0700
+# Node ID d93c6f631ca76e457c819b7bd74039395c33fded
+# Parent  d1d2c7b998efa62f6d199df72a1db07cf5bbbd5b
+Bug 1478045 - Remove TokenStreamChars::{ungetCodePointIgnoreEOL,ungetNonAsciiNormalizedCodePoint} as unused now that SourceUnits::{peek,consumeKnown}CodePoint have replaced them.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -619,32 +619,16 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     }
+ 
+     // Otherwise we have a multi-unit code point.
+     *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
+     MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+     return true;
+ }
+ 
+-template<class AnyCharsAccess>
+-void
+-TokenStreamChars<char16_t, AnyCharsAccess>::ungetCodePointIgnoreEOL(uint32_t codePoint)
+-{
+-    MOZ_ASSERT(!this->sourceUnits.atStart());
+-
+-    unsigned numUnits = 0;
+-    char16_t units[2];
+-    unicode::UTF16Encode(codePoint, units, &numUnits);
+-
+-    MOZ_ASSERT(numUnits == 1 || numUnits == 2);
+-
+-    while (numUnits-- > 0)
+-        ungetCodeUnit(units[numUnits]);
+-}
+-
+ template<>
+ size_t
+ SourceUnits<char16_t>::findWindowStart(size_t offset)
+ {
+     // This is JS's understanding of UTF-16 that allows lone surrogates, so
+     // we have to exclude lone surrogates from [windowStart, offset) ourselves.
+ 
+     const char16_t* const earliestPossibleStart = codeUnitPtrAt(startOffset_);
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1913,46 +1913,16 @@ class TokenStreamChars<char16_t, AnyChar
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+      * This may change the current |sourceUnits| offset.
+      */
+     MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* codePoint);
+ 
+     /**
+-     * Unget a full code point (ASCII or not) without altering line/column
+-     * state.  If line/column state must be updated, this must happen manually.
+-     * This method ungets a single code point, not a LineTerminatorSequence
+-     * that is multiple code points.  (Generally you shouldn't be in a state
+-     * where you've just consumed "\r\n" and want to unget that full sequence.)
+-     *
+-     * This function ordinarily should be used to unget code points that have
+-     * been consumed *without* line/column state having been updated.
+-     */
+-    void ungetCodePointIgnoreEOL(uint32_t codePoint);
+-
+-    /**
+-     * Unget an originally non-ASCII, normalized code point, including undoing
+-     * line/column updates that were performed for it.  Don't use this if the
+-     * code point was gotten *without* line/column state being updated!
+-     */
+-    void ungetNonAsciiNormalizedCodePoint(int32_t codePoint) {
+-        MOZ_ASSERT_IF(isAsciiCodePoint(codePoint),
+-                      codePoint == '\n');
+-        MOZ_ASSERT(codePoint != unicode::LINE_SEPARATOR,
+-                   "should not be ungetting un-normalized code points");
+-        MOZ_ASSERT(codePoint != unicode::PARA_SEPARATOR,
+-                   "should not be ungetting un-normalized code points");
+-
+-        ungetCodePointIgnoreEOL(codePoint);
+-        if (codePoint == '\n')
+-            anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+-    }
+-
+-    /**
+      * Consume code points til EOL/EOF following the start of a single-line
+      * comment, without consuming the EOL/EOF.
+      */
+     MOZ_MUST_USE bool consumeRestOfSingleLineComment() {
+         // This operation is infallible for UTF-16 -- and this implementation
+         // approach lets the compiler boil away call-side fallibility handling.
+         infallibleConsumeRestOfSingleLineComment();
+         return true;
+@@ -2070,19 +2040,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+     using CharsBase::peekCodeUnit;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+-    using SpecializedChars::ungetCodePointIgnoreEOL;
+     using GeneralCharsBase::ungetCodeUnit;
+-    using SpecializedChars::ungetNonAsciiNormalizedCodePoint;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     template<typename CharU> friend class TokenStreamPosition;
+ 
+   public:
+     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
+                         const CharT* base, size_t length);
+ 

+ 80 - 0
frg/work-js/mozilla-release/patches/1478170-01-63a1.patch

@@ -0,0 +1,80 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532553875 25200
+#      Wed Jul 25 14:24:35 2018 -0700
+# Node ID 66952e88e68c22576f6ddc0600d0883d0b7dba6a
+# Parent  d93c6f631ca76e457c819b7bd74039395c33fded
+Bug 1478170 - Make SourceUnits::findWindow{Start,End} const because they can/should be.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -621,17 +621,17 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     // Otherwise we have a multi-unit code point.
+     *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
+     MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+     return true;
+ }
+ 
+ template<>
+ size_t
+-SourceUnits<char16_t>::findWindowStart(size_t offset)
++SourceUnits<char16_t>::findWindowStart(size_t offset) const
+ {
+     // This is JS's understanding of UTF-16 that allows lone surrogates, so
+     // we have to exclude lone surrogates from [windowStart, offset) ourselves.
+ 
+     const char16_t* const earliestPossibleStart = codeUnitPtrAt(startOffset_);
+ 
+     const char16_t* const initial = codeUnitPtrAt(offset);
+     const char16_t* p = initial;
+@@ -679,17 +679,17 @@ SourceUnits<char16_t>::findWindowStart(s
+     }
+ 
+     MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
+     return offset - HalfWindowSize();
+ }
+ 
+ template<>
+ size_t
+-SourceUnits<char16_t>::findWindowEnd(size_t offset)
++SourceUnits<char16_t>::findWindowEnd(size_t offset) const
+ {
+     const char16_t* const initial = codeUnitPtrAt(offset);
+     const char16_t* p = initial;
+ 
+     auto HalfWindowSize = [&initial, &p]() { return PointerRangeSize(initial, p); };
+ 
+     while (true) {
+         MOZ_ASSERT(p <= limit_);
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1326,25 +1326,25 @@ class SourceUnits
+     static constexpr size_t WindowRadius = ErrorMetadata::lineOfContextRadius;
+ 
+     /**
+      * From absolute offset |offset|, search backward to find an absolute
+      * offset within source text, no further than |WindowRadius| code units
+      * away from |offset|, such that all code points from that offset to
+      * |offset| are valid, non-LineTerminator code points.
+      */
+-    size_t findWindowStart(size_t offset);
++    size_t findWindowStart(size_t offset) const;
+ 
+     /**
+      * From absolute offset |offset|, find an absolute offset within source
+      * text, no further than |WindowRadius| code units away from |offset|, such
+      * that all code units from |offset| to that offset are valid,
+      * non-LineTerminator code points.
+      */
+-    size_t findWindowEnd(size_t offset);
++    size_t findWindowEnd(size_t offset) const;
+ 
+   private:
+     /** Base of buffer. */
+     const CharT* base_;
+ 
+     /** Offset of base_[0]. */
+     uint32_t startOffset_;
+ 

+ 235 - 0
frg/work-js/mozilla-release/patches/1478170-02-63a1.patch

@@ -0,0 +1,235 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532555204 25200
+#      Wed Jul 25 14:46:44 2018 -0700
+# Node ID 0ccbc10cd6a1b7ce53f852fb8f7f81cac1ecc31f
+# Parent  66952e88e68c22576f6ddc0600d0883d0b7dba6a
+Bug 1478170 - Replace SpecializedTokenStreamCharsBase::consumeRestOfSingleLineComment with an infallible SourceUnits::consumeRestOfSingleLineComment, in light of the fact that the UTF-8 version can just stop consuming code points when an encoding error is encountered, leaving error-reporting to whatever actually tries to consume the first code point of the "next" line.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1603,25 +1603,26 @@ static const uint8_t firstCharKinds[] = 
+ #undef T_RB
+ #undef T_LC
+ #undef T_RC
+ #undef _______
+ 
+ static_assert(LastCharKind < (1 << (sizeof(firstCharKinds[0]) * 8)),
+               "Elements of firstCharKinds[] are too small");
+ 
++template<>
+ void
+-SpecializedTokenStreamCharsBase<char16_t>::infallibleConsumeRestOfSingleLineComment()
++SourceUnits<char16_t>::consumeRestOfSingleLineComment()
+ {
+-    while (MOZ_LIKELY(!this->sourceUnits.atEnd())) {
+-        char16_t unit = this->sourceUnits.peekCodeUnit();
++    while (MOZ_LIKELY(!atEnd())) {
++        char16_t unit = peekCodeUnit();
+         if (IsLineTerminator(unit))
+             return;
+ 
+-        this->sourceUnits.consumeKnownCodeUnit(unit);
++        consumeKnownCodeUnit(unit);
+     }
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStart start,
+                                                           const CharT* numStart,
+                                                           Modifier modifier, TokenKind* out)
+@@ -2202,19 +2203,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             break;
+ 
+           case '<':
+             if (anyCharsAccess().options().allowHTMLComments) {
+                 // Treat HTML begin-comment as comment-till-end-of-line.
+                 if (matchCodeUnit('!')) {
+                     if (matchCodeUnit('-')) {
+                         if (matchCodeUnit('-')) {
+-                            if (!consumeRestOfSingleLineComment())
+-                                return false;
+-
++                            this->sourceUnits.consumeRestOfSingleLineComment();
+                             continue;
+                         }
+                         ungetCodeUnit('-');
+                     }
+                     ungetCodeUnit('!');
+                 }
+             }
+             if (matchCodeUnit('<'))
+@@ -2249,19 +2248,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                     bool shouldWarn = unit == '@';
+                     if (!getDirectives(false, shouldWarn))
+                         return false;
+                 } else {
+                     // NOTE: |unit| may be EOF here.
+                     ungetCodeUnit(unit);
+                 }
+ 
+-                if (!consumeRestOfSingleLineComment())
+-                    return false;
+-
++                this->sourceUnits.consumeRestOfSingleLineComment();
+                 continue;
+             }
+ 
+             // Look for a multi-line comment.
+             if (matchCodeUnit('*')) {
+                 TokenStreamAnyChars& anyChars = anyCharsAccess();
+                 unsigned linenoBefore = anyChars.lineno;
+ 
+@@ -2308,19 +2305,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             break;
+ 
+           case '-':
+             if (matchCodeUnit('-')) {
+                 if (anyCharsAccess().options().allowHTMLComments &&
+                     !anyCharsAccess().flags.isDirtyLine)
+                 {
+                     if (matchCodeUnit('>')) {
+-                        if (!consumeRestOfSingleLineComment())
+-                            return false;
+-
++                        this->sourceUnits.consumeRestOfSingleLineComment();
+                         continue;
+                     }
+                 }
+ 
+                 simpleKind = TokenKind::Dec;
+             } else {
+                 simpleKind = matchCodeUnit('=') ? TokenKind::SubAssign : TokenKind::Sub;
+             }
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1309,16 +1309,38 @@ class SourceUnits
+     // Poison the SourceUnits so they can't be accessed again.
+     void poisonInDebug() {
+ #ifdef DEBUG
+         ptr = nullptr;
+ #endif
+     }
+ 
+     /**
++     * Consume the rest of a single-line comment (but not the EOL/EOF that
++     * terminates it).
++     *
++     * If an encoding error is encountered -- possible only for UTF-8 because
++     * JavaScript's conception of UTF-16 encompasses any sequence of 16-bit
++     * code units -- valid code points prior to the encoding error are consumed
++     * and subsequent invalid code units are not consumed.  For example, given
++     * these UTF-8 code units:
++     *
++     *   'B'   'A'  'D'  ':'   <bad code unit sequence>
++     *   0x42  0x41 0x44 0x3A  0xD0 0x00 ...
++     *
++     * the first four code units are consumed, but 0xD0 and 0x00 are not
++     * consumed because 0xD0 encodes a two-byte lead unit but 0x00 is not a
++     * valid trailing code unit.
++     *
++     * It is expected that the caller will report such an encoding error when
++     * it attempts to consume the next code point.
++     */
++    void consumeRestOfSingleLineComment();
++
++    /**
+      * The maximum radius of code around the location of an error that should
+      * be included in a syntax error message -- this many code units to either
+      * side.  The resulting window of data is then accordinngly trimmed so that
+      * the window contains only validly-encoded data.
+      *
+      * Because this number is the same for both UTF-8 and UTF-16, windows in
+      * UTF-8 may contain fewer code points than windows in UTF-16.  As we only
+      * use this for error messages, we don't particularly care.
+@@ -1560,23 +1582,16 @@ class SpecializedTokenStreamCharsBase<ch
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+ 
+     using typename CharsBase::SourceUnits;
+ 
+   protected:
+     // These APIs are only usable by UTF-16-specific code.
+ 
+     /**
+-     * Consume the rest of a single-line comment (but not the EOL/EOF that
+-     * terminates it) -- infallibly because no 16-bit code unit sequence in a
+-     * comment is an error.
+-     */
+-    void infallibleConsumeRestOfSingleLineComment();
+-
+-    /**
+      * Given |lead| already consumed, consume and return the code point encoded
+      * starting from it.  Infallible because lone surrogates in JS encode a
+      * "code point" of the same value.
+      */
+     char32_t infallibleGetNonAsciiCodePointDontNormalize(char16_t lead) {
+         MOZ_ASSERT(!isAsciiCodePoint(lead));
+         MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == lead);
+ 
+@@ -1866,17 +1881,16 @@ class TokenStreamChars<char16_t, AnyChar
+ 
+     using GeneralCharsBase::asSpecific;
+ 
+     using typename GeneralCharsBase::TokenStreamSpecific;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::getCodeUnit;
+-    using SpecializedCharsBase::infallibleConsumeRestOfSingleLineComment;
+     using SpecializedCharsBase::infallibleGetNonAsciiCodePointDontNormalize;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchLineTerminator;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     using typename GeneralCharsBase::SourceUnits;
+@@ -1911,27 +1925,16 @@ class TokenStreamChars<char16_t, AnyChar
+      * |*codePoint|.  Return true on success, otherwise return false and leave
+      * |*codePoint| undefined on failure.
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+      * This may change the current |sourceUnits| offset.
+      */
+     MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* codePoint);
+-
+-    /**
+-     * Consume code points til EOL/EOF following the start of a single-line
+-     * comment, without consuming the EOL/EOF.
+-     */
+-    MOZ_MUST_USE bool consumeRestOfSingleLineComment() {
+-        // This operation is infallible for UTF-16 -- and this implementation
+-        // approach lets the compiler boil away call-side fallibility handling.
+-        infallibleConsumeRestOfSingleLineComment();
+-        return true;
+-    }
+ };
+ 
+ template<class AnyCharsAccess>
+ class TokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>
+   : public GeneralTokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>
+ {
+     using CharsBase = TokenStreamCharsBase<mozilla::Utf8Unit>;
+     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>;
+@@ -2018,17 +2021,16 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using typename CharsBase::SourceUnits;
+ 
+   private:
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+     using CharsBase::atomizeSourceChars;
+     using GeneralCharsBase::badToken;
+     // Deliberately don't |using| |charBuffer| because of bug 1472569.  :-(
+     using CharsBase::consumeKnownCodeUnit;
+-    using SpecializedChars::consumeRestOfSingleLineComment;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
+     using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using GeneralCharsBase::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePointDontNormalize;

+ 94 - 0
frg/work-js/mozilla-release/patches/1478170-03-63a1.patch

@@ -0,0 +1,94 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532555486 25200
+#      Wed Jul 25 14:51:26 2018 -0700
+# Node ID 292bd4af4056fd252939f0b9a31ad71ce9270785
+# Parent  0ccbc10cd6a1b7ce53f852fb8f7f81cac1ecc31f
+Bug 1478170 - Implement SourceUnits::peekCodePoint for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -180,16 +180,17 @@
+  * TokenStreamSpecific declarer to specify this is more explicit), we couldn't.
+  */
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Casting.h"
+ #include "mozilla/DebugOnly.h"
++#include "mozilla/Maybe.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/PodOperations.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+@@ -1084,16 +1085,37 @@ PeekCodePoint(const char16_t* const ptr,
+     } else {
+         c = unicode::UTF16Decode(lead, ptr[1]);
+         len = 2;
+     }
+ 
+     return PeekedCodePoint<char16_t>(c, len);
+ }
+ 
++inline PeekedCodePoint<mozilla::Utf8Unit>
++PeekCodePoint(const mozilla::Utf8Unit* const ptr, const mozilla::Utf8Unit* const end)
++{
++    if (MOZ_UNLIKELY(ptr >= end))
++        return PeekedCodePoint<mozilla::Utf8Unit>::none();
++
++    const mozilla::Utf8Unit lead = ptr[0];
++    if (mozilla::IsAscii(lead))
++        return PeekedCodePoint<mozilla::Utf8Unit>(lead.toUint8(), 1);
++
++    const mozilla::Utf8Unit* afterLead = ptr + 1;
++    mozilla::Maybe<char32_t> codePoint = mozilla::DecodeOneUtf8CodePoint(lead, &afterLead, end);
++    if (codePoint.isNothing())
++        return PeekedCodePoint<mozilla::Utf8Unit>::none();
++
++    auto len = mozilla::AssertedCast<uint8_t>(mozilla::PointerRangeSize(ptr, afterLead));
++    MOZ_ASSERT(len <= 4);
++
++    return PeekedCodePoint<mozilla::Utf8Unit>(codePoint.value(), len);
++}
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //
+diff --git a/mfbt/Utf8.h b/mfbt/Utf8.h
+--- a/mfbt/Utf8.h
++++ b/mfbt/Utf8.h
+@@ -193,16 +193,23 @@ public:
+     return static_cast<uint8_t>(mValue);
+   }
+ 
+   // We currently don't expose |&mValue|.  |UnicodeData| sort of does, but
+   // that's a somewhat separate concern, justified in different comments in
+   // that other code.
+ };
+ 
++/** Returns true iff |aUnit| is an ASCII value. */
++inline bool
++IsAscii(Utf8Unit aUnit)
++{
++  return IsAscii(aUnit.toUint8());
++}
++
+ /**
+  * Returns true if the given length-delimited memory consists of a valid UTF-8
+  * string, false otherwise.
+  *
+  * A valid UTF-8 string contains no overlong-encoded code points (as one would
+  * expect) and contains no code unit sequence encoding a UTF-16 surrogate.  The
+  * string *may* contain U+0000 NULL code points.
+  */

+ 113 - 0
frg/work-js/mozilla-release/patches/1478170-04-63a1.patch

@@ -0,0 +1,113 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531979207 25200
+#      Wed Jul 18 22:46:47 2018 -0700
+# Node ID 7f427db8f6f88bf86df7adadf2cdeea98b757865
+# Parent  3e00f440f02ce6d39db36ea8a761cc626f43a552
+Bug 1478170 - Specialize TokenStreamCharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -7,24 +7,26 @@
+ // JS lexical scanner.
+ 
+ #include "frontend/TokenStream.h"
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/IntegerTypeTraits.h"
+ #include "mozilla/Likely.h"
++#include "mozilla/Maybe.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/ScopeExit.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+ #include <ctype.h>
+ #include <stdarg.h>
++#include <stdint.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <utility>
+ 
+ #include "jsexn.h"
+ #include "jsnum.h"
+ 
+ #include "frontend/BytecodeCompiler.h"
+@@ -36,20 +38,22 @@
+ #include "util/Unicode.h"
+ #include "vm/HelperThreads.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSContext.h"
+ 
+ using mozilla::ArrayLength;
+ using mozilla::AssertedCast;
++using mozilla::DecodeOneUtf8CodePoint;
+ using mozilla::IsAscii;
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
+ using mozilla::MakeScopeExit;
++using mozilla::Maybe;
+ using mozilla::PointerRangeSize;
+ using mozilla::Utf8Unit;
+ 
+ struct ReservedWordInfo
+ {
+     const char* chars;         // C string with reserved word text
+     js::frontend::TokenKind tokentype;
+ };
+@@ -459,16 +463,51 @@ TokenStreamCharsBase<char16_t>::fillChar
+         if (!this->charBuffer.append(ch))
+             return false;
+     }
+ 
+     MOZ_ASSERT(cur == end);
+     return true;
+ }
+ 
++template<>
++MOZ_MUST_USE bool
++TokenStreamCharsBase<Utf8Unit>::fillCharBufferFromSourceNormalizingAsciiLineBreaks(const Utf8Unit* cur,
++                                                                                   const Utf8Unit* end)
++{
++    MOZ_ASSERT(this->charBuffer.length() == 0);
++
++    while (cur < end) {
++        Utf8Unit unit = *cur++;
++        if (MOZ_LIKELY(IsAscii(unit))) {
++            char16_t ch = unit.toUint8();
++            if (ch == '\r') {
++                ch = '\n';
++                if (cur < end && *cur == Utf8Unit('\n'))
++                    cur++;
++            }
++
++            if (!this->charBuffer.append(ch))
++                return false;
++
++            continue;
++        }
++
++        Maybe<char32_t> ch = DecodeOneUtf8CodePoint(unit, &cur, end);
++        MOZ_ASSERT(ch.isSome(),
++                   "provided source text should already have been validated");
++
++        if (!appendCodePointToCharBuffer(ch.value()))
++            return false;
++    }
++
++    MOZ_ASSERT(cur == end);
++    return true;
++}
++
+ template<typename CharT, class AnyCharsAccess>
+ TokenStreamSpecific<CharT, AnyCharsAccess>::TokenStreamSpecific(JSContext* cx,
+                                                                 const ReadOnlyCompileOptions& options,
+                                                                 const CharT* base, size_t length)
+   : TokenStreamChars<CharT, AnyCharsAccess>(cx, base, length, options.scriptSourceOffset)
+ {}
+ 
+ bool

+ 545 - 0
frg/work-js/mozilla-release/patches/1478170-05-63a1.patch

@@ -0,0 +1,545 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531979207 25200
+#      Wed Jul 18 22:46:47 2018 -0700
+# Node ID 45b34e5af77e953970b0497f1ab20690333457d8
+# Parent  7f427db8f6f88bf86df7adadf2cdeea98b757865
+Bug 1478170 - Implement getNonAsciiCodePointDontNormalize for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -567,16 +567,203 @@ SourceUnits<char16_t>::assertNextCodePoi
+         MOZ_ASSERT(ptr[0] == lead);
+         MOZ_ASSERT(ptr[1] == trail);
+     }
+ }
+ 
+ #endif // DEBUG
+ 
+ template<class AnyCharsAccess>
++MOZ_COLD void
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::internalEncodingError(uint8_t relevantUnits,
++                                                                  unsigned errorNumber, ...)
++{
++    va_list args;
++    va_start(args, errorNumber);
++
++    do {
++        size_t offset = this->sourceUnits.offset();
++
++        ErrorMetadata err;
++
++        TokenStreamAnyChars& anyChars = anyCharsAccess();
++
++        if (bool hasLineOfContext = anyChars.fillExcludingContext(&err, offset)) {
++            if (!internalComputeLineOfContext(&err, offset))
++                break;
++
++            // As this is an encoding error, the computed window-end must be
++            // identical to the location of the error -- any further on and the
++            // window would contain invalid Unicode.
++            MOZ_ASSERT_IF(err.lineOfContext != nullptr,
++                          err.lineLength == err.tokenOffset);
++        }
++
++        auto notes = MakeUnique<JSErrorNotes>();
++        if (!notes) {
++            ReportOutOfMemory(anyChars.cx);
++            break;
++        }
++
++        // The largest encoding of a UTF-8 code point is 4 units.  (Encoding an
++        // obsolete 5- or 6-byte code point will complain only about a bad lead
++        // code unit.)
++        constexpr size_t MaxWidth = sizeof("0xHH 0xHH 0xHH 0xHH");
++
++        MOZ_ASSERT(relevantUnits > 0);
++
++        char badUnitsStr[MaxWidth];
++        char* ptr = badUnitsStr;
++        while (relevantUnits > 0) {
++            byteToString(this->sourceUnits.getCodeUnit().toUint8(), ptr);
++            ptr[4] = ' ';
++
++            ptr += 5;
++            relevantUnits--;
++        }
++
++        ptr[-1] = '\0';
++
++        uint32_t line, column;
++        anyChars.srcCoords.lineNumAndColumnIndex(offset, &line, &column);
++
++        if (!notes->addNoteASCII(anyChars.cx, anyChars.getFilename(), line, column,
++                                 GetErrorMessage, nullptr, JSMSG_BAD_CODE_UNITS, badUnitsStr))
++        {
++            break;
++        }
++
++        ReportCompileError(anyChars.cx, std::move(err), std::move(notes), JSREPORT_ERROR,
++                           errorNumber, args);
++    } while (false);
++
++    va_end(args);
++}
++
++template<class AnyCharsAccess>
++MOZ_COLD void
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::badLeadUnit(Utf8Unit lead)
++{
++    uint8_t leadValue = lead.toUint8();
++
++    char leadByteStr[5];
++    byteToTerminatedString(leadValue, leadByteStr);
++
++    internalEncodingError(1, JSMSG_BAD_LEADING_UTF8_UNIT, leadByteStr);
++}
++
++template<class AnyCharsAccess>
++MOZ_COLD void
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::notEnoughUnits(Utf8Unit lead,
++                                                           uint8_t remaining, uint8_t required)
++{
++    uint8_t leadValue = lead.toUint8();
++
++    MOZ_ASSERT(required == 2 || required == 3 || required == 4);
++    MOZ_ASSERT(remaining < 4);
++    MOZ_ASSERT(remaining < required);
++
++    char leadByteStr[5];
++    byteToTerminatedString(leadValue, leadByteStr);
++
++    // |toHexChar| produces the desired decimal numbers for values < 4.
++    const char expectedStr[] = { toHexChar(required - 1), '\0' };
++    const char actualStr[] = { toHexChar(remaining - 1), '\0' };
++
++    internalEncodingError(remaining, JSMSG_NOT_ENOUGH_CODE_UNITS,
++                          leadByteStr, expectedStr, actualStr, remaining == 2 ? " was" : "s were");
++}
++
++template<class AnyCharsAccess>
++MOZ_COLD void
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::badTrailingUnit(Utf8Unit badUnit,
++                                                            uint8_t unitsObserved)
++{
++    char badByteStr[5];
++    byteToTerminatedString(badUnit.toUint8(), badByteStr);
++
++    internalEncodingError(unitsObserved, JSMSG_BAD_TRAILING_UTF8_UNIT, badByteStr);
++}
++
++template<class AnyCharsAccess>
++MOZ_COLD void
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::badStructurallyValidCodePoint(uint32_t codePoint,
++                                                                          uint8_t codePointLength,
++                                                                          const char* reason)
++{
++    // Construct a string like "0x203D" (including null terminator) to include
++    // in the error message.  Write the string end-to-start from end to start
++    // of an adequately sized |char| array, shifting least significant nibbles
++    // off the number and writing the corresponding hex digits until done, then
++    // prefixing with "0x".  |codePointStr| points at the incrementally
++    // computed string, within |codePointCharsArray|'s bounds.
++
++    // 0x1F'FFFF is the maximum value that can fit in 3+6+6+6 unconstrained
++    // bits in a four-byte UTF-8 code unit sequence.
++    constexpr size_t MaxHexSize = sizeof("0x1F" "FFFF"); // including '\0'
++    char codePointCharsArray[MaxHexSize];
++
++    char* codePointStr = codePointCharsArray + ArrayLength(codePointCharsArray);
++    *--codePointStr = '\0';
++
++    uint32_t copy = codePoint;
++    while (copy) {
++        MOZ_ASSERT(codePointCharsArray < codePointStr);
++        *--codePointStr = toHexChar(copy & 0xF);
++        copy >>= 4;
++    }
++
++    MOZ_ASSERT(codePointCharsArray + 2 <= codePointStr);
++    *--codePointStr = 'x';
++    *--codePointStr = '0';
++
++    internalEncodingError(codePointLength, JSMSG_FORBIDDEN_UTF8_CODE_POINT, codePointStr, reason);
++}
++
++template<class AnyCharsAccess>
++MOZ_MUST_USE bool
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::getNonAsciiCodePointDontNormalize(Utf8Unit lead,
++                                                                              char32_t* codePoint)
++{
++    auto onBadLeadUnit = [this, &lead]() {
++        this->badLeadUnit(lead);
++    };
++
++    auto onNotEnoughUnits = [this, &lead](uint8_t remaining, uint8_t required) {
++        this->notEnoughUnits(lead, remaining, required);
++    };
++
++    auto onBadTrailingUnit = [this, &lead](uint8_t unitsObserved) {
++        this->badTrailingUnit(lead, unitsObserved);
++    };
++
++    auto onBadCodePoint = [this](char32_t badCodePoint, uint8_t unitsObserved) {
++        this->badCodePoint(badCodePoint, unitsObserved);
++    };
++
++    auto onNotShortestForm = [this](char32_t badCodePoint, uint8_t unitsObserved) {
++        this->notShortestForm(badCodePoint, unitsObserved);
++    };
++
++    // If a valid code point is decoded, this function call consumes its code
++    // units.  If not, it ungets the lead code unit and invokes the right error
++    // handler, so on failure we must immediately return false.
++    SourceUnitsIterator iter(this->sourceUnits);
++    Maybe<char32_t> maybeCodePoint =
++        DecodeOneUtf8CodePointInline(lead, &iter, SourceUnitsEnd(),
++                                     onBadLeadUnit, onNotEnoughUnits, onBadTrailingUnit,
++                                     onBadCodePoint, onNotShortestForm);
++    if (maybeCodePoint.isNothing())
++        return false;
++
++    *codePoint = maybeCodePoint.value();
++    return true;
++}
++
++template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
+ {
+     TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+     if (MOZ_UNLIKELY(this->sourceUnits.atEnd())) {
+         anyChars.flags.isEOF = true;
+         *cp = EOF;
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1158,16 +1158,20 @@ class SourceUnits
+     }
+ 
+     const CharT* codeUnitPtrAt(size_t offset) const {
+         MOZ_ASSERT(startOffset_ <= offset);
+         MOZ_ASSERT(offset - startOffset_ <= mozilla::PointerRangeSize(base_, limit_));
+         return base_ + (offset - startOffset_);
+     }
+ 
++    const CharT* current() const {
++        return ptr;
++    }
++
+     const CharT* limit() const {
+         return limit_;
+     }
+ 
+     CharT previousCodeUnit() {
+         MOZ_ASSERT(ptr, "can't get previous code unit if poisoned");
+         MOZ_ASSERT(!atStart(), "must have a previous code unit to get");
+         return *(ptr - 1);
+@@ -1644,23 +1648,112 @@ class SpecializedTokenStreamCharsBase<mo
+     using CharsBase = TokenStreamCharsBase<mozilla::Utf8Unit>;
+ 
+   protected:
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+ 
+   protected:
+     // These APIs are only usable by UTF-8-specific code.
+ 
++    using typename CharsBase::SourceUnits;
++
++    /**
++     * A mutable iterator-wrapper around |SourceUnits| that translates
++     * operators to calls to |SourceUnits::getCodeUnit()| and similar.
++     *
++     * This class is expected to be used in concert with |SourceUnitsEnd|.
++     */
++    class SourceUnitsIterator
++    {
++        SourceUnits& sourceUnits_;
++#ifdef DEBUG
++        // In iterator copies created by the post-increment operator, a pointer
++        // at the next source text code unit when the post-increment operator
++        // was called, cleared when the iterator is dereferenced.
++        mutable mozilla::Maybe<const mozilla::Utf8Unit*> currentBeforePostIncrement_;
++#endif
++
++      public:
++        explicit SourceUnitsIterator(SourceUnits& sourceUnits)
++          : sourceUnits_(sourceUnits)
++        {}
++
++        mozilla::Utf8Unit operator*() const {
++            // operator* is expected to get the *next* value from an iterator
++            // not pointing at the end of the underlying range.  However, the
++            // sole use of this is in the context of an expression of the form
++            // |*iter++|, that performed the |sourceUnits_.getCodeUnit()| in
++            // the |operator++(int)| below -- so dereferencing acts on a
++            // |sourceUnits_| already advanced.  Therefore the correct unit to
++            // return is the previous one.
++            MOZ_ASSERT(currentBeforePostIncrement_.value() + 1 == sourceUnits_.current());
++#ifdef DEBUG
++            currentBeforePostIncrement_.reset();
++#endif
++            return sourceUnits_.previousCodeUnit();
++        }
++
++        SourceUnitsIterator operator++(int) {
++            MOZ_ASSERT(currentBeforePostIncrement_.isNothing(),
++                       "the only valid operation on a post-incremented "
++                       "iterator is dereferencing a single time");
++
++            SourceUnitsIterator copy = *this;
++#ifdef DEBUG
++            copy.currentBeforePostIncrement_.emplace(sourceUnits_.current());
++#endif
++
++            sourceUnits_.getCodeUnit();
++            return copy;
++        }
++
++        void operator-=(size_t n) {
++            MOZ_ASSERT(currentBeforePostIncrement_.isNothing(),
++                       "the only valid operation on a post-incremented "
++                       "iterator is dereferencing a single time");
++            sourceUnits_.unskipCodeUnits(n);
++        }
++
++        mozilla::Utf8Unit operator[](ptrdiff_t index) {
++            MOZ_ASSERT(currentBeforePostIncrement_.isNothing(),
++                       "the only valid operation on a post-incremented "
++                       "iterator is dereferencing a single time");
++            MOZ_ASSERT(index == -1,
++                       "must only be called to verify the value of the "
++                       "previous code unit");
++            return sourceUnits_.previousCodeUnit();
++        }
++
++        size_t remaining() const {
++            MOZ_ASSERT(currentBeforePostIncrement_.isNothing(),
++                       "the only valid operation on a post-incremented "
++                       "iterator is dereferencing a single time");
++            return sourceUnits_.remaining();
++        }
++    };
++
++    /** A sentinel representing the end of |SourceUnits| data. */
++    class SourceUnitsEnd {};
++
++    friend inline size_t operator-(const SourceUnitsEnd& aEnd, const SourceUnitsIterator& aIter);
++
+   protected:
+     // These APIs are in both SpecializedTokenStreamCharsBase specializations
+     // and so are usable in subclasses no matter what CharT is.
+ 
+     using CharsBase::CharsBase;
+ };
+ 
++inline size_t
++operator-(const SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>::SourceUnitsEnd& aEnd,
++          const SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>::SourceUnitsIterator& aIter)
++{
++    return aIter.remaining();
++}
++
+ /** A small class encapsulating computation of the start-offset of a Token. */
+ class TokenStart
+ {
+     uint32_t startOffset_;
+ 
+   public:
+     /**
+      * Compute a starting offset that is the current offset of |sourceUnits|,
+@@ -1958,21 +2051,132 @@ template<class AnyCharsAccess>
+ class TokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>
+   : public GeneralTokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>
+ {
+     using CharsBase = TokenStreamCharsBase<mozilla::Utf8Unit>;
+     using SpecializedCharsBase = SpecializedTokenStreamCharsBase<mozilla::Utf8Unit>;
+     using GeneralCharsBase = GeneralTokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>;
+     using Self = TokenStreamChars<mozilla::Utf8Unit, AnyCharsAccess>;
+ 
++    using typename SpecializedCharsBase::SourceUnitsEnd;
++    using typename SpecializedCharsBase::SourceUnitsIterator;
++
+   protected:
++    using GeneralCharsBase::anyCharsAccess;
++    using GeneralCharsBase::internalComputeLineOfContext;
++    using TokenStreamCharsShared::isAsciiCodePoint;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+ 
++  private:
++    static char toHexChar(uint8_t nibble) {
++        MOZ_ASSERT(nibble < 16);
++        return "0123456789ABCDEF"[nibble];
++    }
++
++    static void byteToString(uint8_t n, char* str) {
++        str[0] = '0';
++        str[1] = 'x';
++        str[2] = toHexChar(n >> 4);
++        str[3] = toHexChar(n & 0xF);
++    }
++
++    static void byteToTerminatedString(uint8_t n, char* str) {
++        byteToString(n, str);
++        str[4] = '\0';
++    }
++
++    /**
++     * Report a UTF-8 encoding-related error for a code point starting AT THE
++     * CURRENT OFFSET.
++     *
++     * |relevantUnits| indicates how many code units from the current offset
++     * are potentially relevant to the reported error, such that they may be
++     * included in the error message.  For example, if at the current offset we
++     * have
++     *
++     *   0b1111'1111 ...
++     *
++     * a code unit never allowed in UTF-8, then |relevantUnits| might be 1
++     * because only that unit is relevant.  Or if we have
++     *
++     *   0b1111'0111 0b1011'0101 0b0000'0000 ...
++     *
++     * where the first two code units are a valid prefix to a four-unit code
++     * point but the third unit *isn't* a valid trailing code unit, then
++     * |relevantUnits| might be 3.
++     */
++    MOZ_COLD void internalEncodingError(uint8_t relevantUnits, unsigned errorNumber, ...);
++
++    // Don't use |internalEncodingError|!  Use one of the elaborated functions
++    // that calls it, below -- all of which should be used to indicate an error
++    // in a code point starting AT THE CURRENT OFFSET as with
++    // |internalEncodingError|.
++
++    /** Report an error for an invalid lead code unit |lead|. */
++    MOZ_COLD void badLeadUnit(mozilla::Utf8Unit lead);
++
++    /**
++     * Report an error when there aren't enough code units remaining to
++     * constitute a full code point after |lead|: only |remaining| code units
++     * were available for a code point starting with |lead|, when at least
++     * |required| code units were required.
++     */
++    MOZ_COLD void notEnoughUnits(mozilla::Utf8Unit lead, uint8_t remaining, uint8_t required);
++
++    /**
++     * Report an error for a bad trailing UTF-8 code unit, where the bad
++     * trailing unit was the last of |unitsObserved| units examined from the
++     * current offset.
++     */
++    MOZ_COLD void badTrailingUnit(mozilla::Utf8Unit badUnit, uint8_t unitsObserved);
++
++    // Helper used for both |badCodePoint| and |notShortestForm| for code units
++    // that have all the requisite high bits set/unset in a manner that *could*
++    // encode a valid code point, but the remaining bits encoding its actual
++    // value do not define a permitted value.
++    MOZ_COLD void badStructurallyValidCodePoint(uint32_t codePoint, uint8_t codePointLength,
++                                                const char* reason);
++
++    /**
++     * Report an error for UTF-8 that encodes a UTF-16 surrogate or a number
++     * outside the Unicode range.
++     */
++    MOZ_COLD void badCodePoint(uint32_t codePoint, uint8_t codePointLength) {
++        MOZ_ASSERT(unicode::IsSurrogate(codePoint) || codePoint > unicode::NonBMPMax);
++
++        badStructurallyValidCodePoint(codePoint, codePointLength,
++                                      unicode::IsSurrogate(codePoint)
++                                      ? "it's a UTF-16 surrogate"
++                                      : "the maximum code point is U+10FFFF");
++    }
++
++    /**
++     * Report an error for UTF-8 that encodes a code point not in its shortest
++     * form.
++     */
++    MOZ_COLD void notShortestForm(uint32_t codePoint, uint8_t codePointLength) {
++        MOZ_ASSERT(!unicode::IsSurrogate(codePoint));
++        MOZ_ASSERT(codePoint <= unicode::NonBMPMax);
++
++        badStructurallyValidCodePoint(codePoint, codePointLength,
++                                      "it wasn't encoded in shortest possible form");
++    }
++
+   protected:
+     using GeneralCharsBase::GeneralCharsBase;
++
++    /**
++     * Given the non-ASCII |lead| code unit just consumed, consume the rest of
++     * a non-ASCII code point.  The code point is not normalized: on success
++     * |*codePoint| may be U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR.
++     *
++     * Report an error if an invalid code point is encountered.
++     */
++    MOZ_MUST_USE bool
++    getNonAsciiCodePointDontNormalize(mozilla::Utf8Unit lead, char32_t* codePoint);
+ };
+ 
+ // TokenStream is the lexical scanner for JavaScript source text.
+ //
+ // It takes a buffer of CharT code units (currently only char16_t encoding
+ // UTF-16, but we're adding either UTF-8 or Latin-1 single-byte text soon) and
+ // linearly scans it into |Token|s.
+ //
+diff --git a/js/src/js.msg b/js/src/js.msg
+--- a/js/src/js.msg
++++ b/js/src/js.msg
+@@ -347,16 +347,23 @@ MSG_DEF(JSMSG_WHILE_AFTER_DO,          0
+ MSG_DEF(JSMSG_YIELD_IN_DEFAULT,        0, JSEXN_SYNTAXERR, "yield in default expression")
+ MSG_DEF(JSMSG_YIELD_OUTSIDE_GENERATOR, 0, JSEXN_SYNTAXERR, "yield expression is only valid in generators")
+ MSG_DEF(JSMSG_BAD_COLUMN_NUMBER,       0, JSEXN_RANGEERR, "column number out of range")
+ MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration")
+ MSG_DEF(JSMSG_DEFAULT_IN_PATTERN,      0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration")
+ MSG_DEF(JSMSG_BAD_NEWTARGET,           0, JSEXN_SYNTAXERR, "new.target only allowed within functions")
+ MSG_DEF(JSMSG_ESCAPED_KEYWORD,         0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes")
+ 
++// UTF-8 source text encoding errors
++MSG_DEF(JSMSG_BAD_LEADING_UTF8_UNIT,   1, JSEXN_SYNTAXERR, "{0} byte doesn't begin a valid UTF-8 code point")
++MSG_DEF(JSMSG_NOT_ENOUGH_CODE_UNITS,   4, JSEXN_SYNTAXERR, "{0} byte in UTF-8 must be followed by {1} bytes, but {2} byte{3} present")
++MSG_DEF(JSMSG_BAD_TRAILING_UTF8_UNIT,  1, JSEXN_SYNTAXERR, "bad trailing UTF-8 byte {0} doesn't match the pattern 0b10xxxxxx")
++MSG_DEF(JSMSG_FORBIDDEN_UTF8_CODE_POINT,2,JSEXN_SYNTAXERR, "{0} isn't a valid code point because {1}")
++MSG_DEF(JSMSG_BAD_CODE_UNITS,          1, JSEXN_NOTE, "the code units comprising this invalid code point were: {0}")
++
+ // asm.js
+ MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL,       1, JSEXN_TYPEERR, "asm.js type error: {0}")
+ MSG_DEF(JSMSG_USE_ASM_LINK_FAIL,       1, JSEXN_TYPEERR, "asm.js link error: {0}")
+ MSG_DEF(JSMSG_USE_ASM_TYPE_OK,         1, JSEXN_WARN,    "Successfully compiled asm.js code ({0})")
+ 
+ // wasm
+ MSG_DEF(JSMSG_WASM_COMPILE_WARNING,    1, JSEXN_WARN,    "WebAssembly module validated with warning: {0}")
+ MSG_DEF(JSMSG_WASM_COMPILE_ERROR,      1, JSEXN_WASMCOMPILEERROR, "{0}")
+diff --git a/js/src/util/Unicode.h b/js/src/util/Unicode.h
+--- a/js/src/util/Unicode.h
++++ b/js/src/util/Unicode.h
+@@ -577,16 +577,29 @@ IsLeadSurrogate(uint32_t codePoint)
+ }
+ 
+ inline bool
+ IsTrailSurrogate(uint32_t codePoint)
+ {
+     return codePoint >= TrailSurrogateMin && codePoint <= TrailSurrogateMax;
+ }
+ 
++/**
++ * True iff the given value is a UTF-16 surrogate.
++ *
++ * This function is intended for use in contexts where 32-bit values may need
++ * to be tested to see if they reside in the surrogate range, so it doesn't
++ * just take char16_t.
++ */
++inline bool
++IsSurrogate(uint32_t codePoint)
++{
++    return LeadSurrogateMin <= codePoint && codePoint <= TrailSurrogateMax;
++}
++
+ inline char16_t
+ LeadSurrogate(uint32_t codePoint)
+ {
+     MOZ_ASSERT(IsSupplementary(codePoint));
+ 
+     return char16_t((codePoint >> 10) + (LeadSurrogateMin - (NonBMPMin >> 10)));
+ }
+ 

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

@@ -0,0 +1,58 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532569373 25200
+#      Wed Jul 25 18:42:53 2018 -0700
+# Node ID d0847a6bfa7adddab5123dda881c3f289f2021c4
+# Parent  45b34e5af77e953970b0497f1ab20690333457d8
+Bug 1478170 - Specialize SourceUnits::consumeKnownCodePoint for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -564,16 +564,46 @@ SourceUnits<char16_t>::assertNextCodePoi
+         MOZ_ASSERT(peeked.lengthInUnits() == 2);
+         char16_t lead, trail;
+         unicode::UTF16Encode(c, &lead, &trail);
+         MOZ_ASSERT(ptr[0] == lead);
+         MOZ_ASSERT(ptr[1] == trail);
+     }
+ }
+ 
++template<>
++inline void
++SourceUnits<Utf8Unit>::assertNextCodePoint(const PeekedCodePoint<Utf8Unit>& peeked)
++{
++    char32_t c = peeked.codePoint();
++
++    // This is all roughly indulgence of paranoia only for assertions, so the
++    // reimplementation of UTF-8 encoding a code point is (we think) a virtue.
++    uint8_t expectedUnits[4] = {};
++    if (c < 0x80) {
++        expectedUnits[0] = AssertedCast<uint8_t>(c);
++    } else if (c < 0x800) {
++        expectedUnits[0] = 0b1100'0000 | (c >> 6);
++        expectedUnits[1] = 0b1000'0000 | (c & 0b11'1111);
++    } else if (c < 0x10000) {
++        expectedUnits[0] = 0b1110'0000 | (c >> 12);
++        expectedUnits[1] = 0b1000'0000 | ((c >> 6) & 0b11'1111);
++        expectedUnits[2] = 0b1000'0000 | (c & 0b11'1111);
++    } else {
++        expectedUnits[0] = 0b1110'0000 | (c >> 18);
++        expectedUnits[2] = 0b1000'0000 | ((c >> 12) & 0b11'1111);
++        expectedUnits[2] = 0b1000'0000 | ((c >> 6) & 0b11'1111);
++        expectedUnits[3] = 0b1000'0000 | (c & 0b11'1111);
++    }
++
++    MOZ_ASSERT(peeked.lengthInUnits() <= 4);
++    for (uint8_t i = 0; i < peeked.lengthInUnits(); i++)
++        MOZ_ASSERT(expectedUnits[i] == ptr[i].toUint8());
++}
++
+ #endif // DEBUG
+ 
+ template<class AnyCharsAccess>
+ MOZ_COLD void
+ TokenStreamChars<Utf8Unit, AnyCharsAccess>::internalEncodingError(uint8_t relevantUnits,
+                                                                   unsigned errorNumber, ...)
+ {
+     va_list args;

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

@@ -0,0 +1,84 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531178493 25200
+#      Mon Jul 09 16:21:33 2018 -0700
+# Node ID 46c400e4a018c1cb827266441018a5c43a84f8f5
+# Parent  d0847a6bfa7adddab5123dda881c3f289f2021c4
+Bug 1478170 - Implement consumeRestOfSingleLine for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1872,16 +1872,42 @@ SourceUnits<char16_t>::consumeRestOfSing
+         char16_t unit = peekCodeUnit();
+         if (IsLineTerminator(unit))
+             return;
+ 
+         consumeKnownCodeUnit(unit);
+     }
+ }
+ 
++template<>
++void
++SourceUnits<Utf8Unit>::consumeRestOfSingleLineComment()
++{
++    while (MOZ_LIKELY(!atEnd())) {
++        const Utf8Unit unit = peekCodeUnit();
++        if (IsSingleUnitLineTerminator(unit))
++            return;
++
++        if (MOZ_LIKELY(IsAscii(unit))) {
++            consumeKnownCodeUnit(unit);
++            continue;
++        }
++
++        PeekedCodePoint<Utf8Unit> peeked = peekCodePoint();
++        if (peeked.isNone())
++            return;
++
++        char32_t c = peeked.codePoint();
++        if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR))
++            return;
++
++        consumeKnownCodePoint(peeked);
++    }
++}
++
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStart start,
+                                                           const CharT* numStart,
+                                                           Modifier modifier, TokenKind* out)
+ {
+     // Run the bad-token code for every path out of this function except the
+     // one success-case.
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1106,16 +1106,26 @@ PeekCodePoint(const mozilla::Utf8Unit* c
+         return PeekedCodePoint<mozilla::Utf8Unit>::none();
+ 
+     auto len = mozilla::AssertedCast<uint8_t>(mozilla::PointerRangeSize(ptr, afterLead));
+     MOZ_ASSERT(len <= 4);
+ 
+     return PeekedCodePoint<mozilla::Utf8Unit>(codePoint.value(), len);
+ }
+ 
++inline bool
++IsSingleUnitLineTerminator(mozilla::Utf8Unit unit)
++{
++    // BEWARE: The Unicode line/paragraph separators don't fit in a single
++    //         UTF-8 code unit, so this test is exact for Utf8Unit but inexact
++    //         for UTF-8 as a whole.  Users must handle |unit| as start of a
++    //         Unicode LineTerminator themselves!
++    return unit == mozilla::Utf8Unit('\n') || unit == mozilla::Utf8Unit('\r');
++}
++
+ // This is the low-level interface to the JS source code buffer.  It just gets
+ // raw Unicode code units -- 16-bit char16_t units of source text that are not
+ // (always) full code points, and 8-bit units of UTF-8 source text soon.
+ // TokenStreams functions are layered on top and do some extra stuff like
+ // converting all EOL sequences to '\n', tracking the line number, and setting
+ // |flags.isEOF|.  (The "raw" in "raw Unicode code units" refers to the lack of
+ // EOL sequence normalization.)
+ //

+ 77 - 0
frg/work-js/mozilla-release/patches/1478170-08-63a1.patch

@@ -0,0 +1,77 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531979207 25200
+#      Wed Jul 18 22:46:47 2018 -0700
+# Node ID f00dc821eb42870fcbe6496052b5b1a93dcf2364
+# Parent  46c400e4a018c1cb827266441018a5c43a84f8f5
+Bug 1478170 - Specialize SourceUnits::findWindowEnd for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -986,16 +986,65 @@ SourceUnits<char16_t>::findWindowEnd(siz
+         }
+ 
+         p++;
+     }
+ 
+     return offset + HalfWindowSize();
+ }
+ 
++template<>
++size_t
++SourceUnits<Utf8Unit>::findWindowEnd(size_t offset) const
++{
++    const Utf8Unit* const initial = codeUnitPtrAt(offset);
++    const Utf8Unit* p = initial;
++
++    auto HalfWindowSize = [&initial, &p]() { return PointerRangeSize(initial, p); };
++
++    while (true) {
++        MOZ_ASSERT(p <= limit_);
++        MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++        if (p >= limit_ || HalfWindowSize() >= WindowRadius)
++            break;
++
++        // A non-encoding error might be followed by an encoding error within
++        // |maxEnd|, so we must validate as we go to not include invalid UTF-8
++        // in the computed window.  What joy!
++
++        Utf8Unit lead = *p;
++        if (mozilla::IsAscii(lead)) {
++            if (IsSingleUnitLineTerminator(lead))
++                break;
++
++            p++;
++            continue;
++        }
++
++        PeekedCodePoint<Utf8Unit> peeked = PeekCodePoint(p, limit_);
++        if (peeked.isNone())
++            break; // encoding error
++
++        char32_t c = peeked.codePoint();
++        if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR))
++            break;
++
++        MOZ_ASSERT(!IsLineTerminator(c));
++
++        uint8_t len = peeked.lengthInUnits();
++        if (HalfWindowSize() + len > WindowRadius)
++            break;
++
++        p += len;
++    }
++
++    MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++    return offset + HalfWindowSize();
++}
++
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::advance(size_t position)
+ {
+     const CharT* end = this->sourceUnits.codeUnitPtrAt(position);
+     while (this->sourceUnits.addressOfNextCodeUnit() < end) {
+         int32_t c;
+         if (!getCodePoint(&c))

+ 173 - 0
frg/work-js/mozilla-release/patches/1478170-09-63a1.patch

@@ -0,0 +1,173 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531979208 25200
+#      Wed Jul 18 22:46:48 2018 -0700
+# Node ID 26f77e15d7d256c3fda9ca3285bd7147103eb767
+# Parent  b951ce09dabe6dec84cfd2b346ce1b15527b692f
+Bug 1478170 - Specialize SourceUnits::findWindowStart for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -42,16 +42,17 @@
+ #include "vm/JSContext.h"
+ 
+ using mozilla::ArrayLength;
+ using mozilla::AssertedCast;
+ using mozilla::DecodeOneUtf8CodePoint;
+ using mozilla::IsAscii;
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
++using mozilla::IsTrailingUnit;
+ using mozilla::MakeScopeExit;
+ using mozilla::Maybe;
+ using mozilla::PointerRangeSize;
+ using mozilla::Utf8Unit;
+ 
+ struct ReservedWordInfo
+ {
+     const char* chars;         // C string with reserved word text
+@@ -935,16 +936,79 @@ SourceUnits<char16_t>::findWindowStart(s
+     }
+ 
+     MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
+     return offset - HalfWindowSize();
+ }
+ 
+ template<>
+ size_t
++SourceUnits<Utf8Unit>::findWindowStart(size_t offset) const
++{
++    // |offset| must be the location of the error or somewhere before it, so we
++    // know preceding data is valid UTF-8.
++
++    const Utf8Unit* const earliestPossibleStart = codeUnitPtrAt(startOffset_);
++
++    const Utf8Unit* const initial = codeUnitPtrAt(offset);
++    const Utf8Unit* p = initial;
++
++    auto HalfWindowSize = [&p, &initial]() { return PointerRangeSize(p, initial); };
++
++    while (true) {
++        MOZ_ASSERT(earliestPossibleStart <= p);
++        MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++        if (p <= earliestPossibleStart || HalfWindowSize() >= WindowRadius)
++            break;
++
++        // Peek backward for a line break, and only decrement if there is none.
++        uint8_t prev = p[-1].toUint8();
++
++        // First check for the ASCII LineTerminators.
++        if (prev == '\r' || prev == '\n')
++            break;
++
++        // Now check for the non-ASCII LineTerminators U+2028 LINE SEPARATOR
++        // (0xE2 0x80 0xA8) and U+2029 PARAGRAPH (0xE2 0x80 0xA9).  If there
++        // aren't three code units available, some comparison here will fail
++        // before we'd underflow.
++        if (MOZ_UNLIKELY((prev == 0xA8 || prev == 0xA9) &&
++                         p[-2].toUint8() == 0x80 &&
++                         p[-3].toUint8() == 0xE2))
++        {
++            break;
++        }
++
++        // Rewind over the non-LineTerminator.  This can't underflow
++        // |earliestPossibleStart| because it begins a code point.
++        while (IsTrailingUnit(*--p))
++            continue;
++
++        MOZ_ASSERT(earliestPossibleStart <= p);
++
++        // But if we underflowed |WindowRadius|, adjust forward and stop.
++        if (HalfWindowSize() > WindowRadius) {
++            static_assert(WindowRadius > 3,
++                          "skipping over non-lead code units below must not "
++                          "advance past |offset|");
++
++            while (IsTrailingUnit(*++p))
++                continue;
++
++            MOZ_ASSERT(HalfWindowSize() < WindowRadius);
++            break;
++        }
++    }
++
++    MOZ_ASSERT(HalfWindowSize() <= WindowRadius);
++    return offset - HalfWindowSize();
++}
++
++template<>
++size_t
+ SourceUnits<char16_t>::findWindowEnd(size_t offset) const
+ {
+     const char16_t* const initial = codeUnitPtrAt(offset);
+     const char16_t* p = initial;
+ 
+     auto HalfWindowSize = [&initial, &p]() { return PointerRangeSize(initial, p); };
+ 
+     while (true) {
+diff --git a/mfbt/Utf8.h b/mfbt/Utf8.h
+--- a/mfbt/Utf8.h
++++ b/mfbt/Utf8.h
+@@ -212,16 +212,26 @@ IsAscii(Utf8Unit aUnit)
+  * A valid UTF-8 string contains no overlong-encoded code points (as one would
+  * expect) and contains no code unit sequence encoding a UTF-16 surrogate.  The
+  * string *may* contain U+0000 NULL code points.
+  */
+ extern MFBT_API bool
+ IsValidUtf8(const void* aCodeUnits, size_t aCount);
+ 
+ /**
++ * Returns true iff |aUnit| is a UTF-8 trailing code unit matching the pattern
++ * 0b10xx'xxxx.
++ */
++inline bool
++IsTrailingUnit(Utf8Unit aUnit)
++{
++  return (aUnit.toUint8() & 0b1100'0000) == 0b1000'0000;
++}
++
++/**
+  * Given |aLeadUnit| that is a non-ASCII code unit, a pointer to an |Iter aIter|
+  * that (initially) itself points one unit past |aLeadUnit|, and
+  * |const EndIter aEnd| that denotes the end of the UTF-8 data when compared
+  * against |*aIter| using |aEnd - *aIter|:
+  *
+  * If |aLeadUnit| and subsequent code units computed using |*aIter| (up to
+  * |aEnd|) encode a valid code point -- not exceeding Unicode's range, not a
+  * surrogate, in shortest form -- then return Some(that code point) and advance
+@@ -294,30 +304,30 @@ DecodeOneUtf8CodePointInline(const Utf8U
+   auto actual = aEnd - *aIter;
+   if (MOZ_UNLIKELY(actual < remaining)) {
+     *aIter -= 1;
+     aOnNotEnoughUnits(AssertedCast<uint8_t>(actual + 1), remaining + 1);
+     return Nothing();
+   }
+ 
+   for (uint8_t i = 0; i < remaining; i++) {
+-    uint8_t unit = Utf8Unit(*(*aIter)++).toUint8();
++    const Utf8Unit unit(*(*aIter)++);
+ 
+     // Every non-leading code unit in properly encoded UTF-8 has its high
+     // bit set and the next-highest bit unset.
+-    if (MOZ_UNLIKELY((unit & 0b1100'0000) != 0b1000'0000)) {
++    if (MOZ_UNLIKELY(!IsTrailingUnit(unit))) {
+       uint8_t unitsObserved = i + 1 + 1;
+       *aIter -= unitsObserved;
+       aOnBadTrailingUnit(unitsObserved);
+       return Nothing();
+     }
+ 
+     // The code point being encoded is the concatenation of all the
+     // unconstrained bits.
+-    n = (n << 6) | (unit & 0b0011'1111);
++    n = (n << 6) | (unit.toUint8() & 0b0011'1111);
+   }
+ 
+   // UTF-16 surrogates and values outside the Unicode range are invalid.
+   if (MOZ_UNLIKELY(n > 0x10FFFF || (0xD800 <= n && n <= 0xDFFF))) {
+     uint8_t unitsObserved = remaining + 1;
+     *aIter -= unitsObserved;
+     aOnBadCodePoint(n, unitsObserved);
+     return Nothing();

+ 47 - 0
frg/work-js/mozilla-release/patches/1478170-10-63a1.patch

@@ -0,0 +1,47 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531979208 25200
+#      Wed Jul 18 22:46:48 2018 -0700
+# Node ID cafc89ca6a8788b80c279499701733e62389eb73
+# Parent  26f77e15d7d256c3fda9ca3285bd7147103eb767
+Bug 1478170 - Stop specializing TokenStreamCharsBase::addLineOfContext now that the CharT-specialized things it relies on are fully specialized.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1245,33 +1245,20 @@ template<typename CharT, class AnyCharsA
+ void
+ TokenStreamSpecific<CharT, AnyCharsAccess>::currentLineAndColumn(uint32_t* line, uint32_t* column) const
+ {
+     const TokenStreamAnyChars& anyChars = anyCharsAccess();
+     uint32_t offset = anyChars.currentToken().pos.begin;
+     anyChars.srcCoords.lineNumAndColumnIndex(offset, line, column);
+ }
+ 
+-template<>
++template<typename CharT>
+ bool
+-TokenStreamCharsBase<Utf8Unit>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
++TokenStreamCharsBase<CharT>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
+ {
+-    // The specialization below is 100% usable if tweaked to be a definition
+-    // for any CharT, but it demands SourceUnits::findWindow{Start,End} and
+-    // TokenStreamCharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks
+-    // for UTF-8 that haven't been defined yet.  Use a placeholder definition
+-    // til those are place.
+-    return true;
+-}
+-
+-template<>
+-bool
+-TokenStreamCharsBase<char16_t>::addLineOfContext(ErrorMetadata* err, uint32_t offset)
+-{
+-    using CharT = char16_t;
+     size_t windowStart = sourceUnits.findWindowStart(offset);
+     size_t windowEnd = sourceUnits.findWindowEnd(offset);
+ 
+     size_t windowLength = windowEnd - windowStart;
+     MOZ_ASSERT(windowLength <= SourceUnits::WindowRadius * 2);
+ 
+     // Don't add a useless "line" of context when the window ends up empty
+     // because of an invalid encoding at the start of a line.

+ 158 - 0
frg/work-js/mozilla-release/patches/1478170-11-63a1.patch

@@ -0,0 +1,158 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1530305169 25200
+#      Fri Jun 29 13:46:09 2018 -0700
+# Node ID 107211d728e60e9b069c2d0107241f74b575d576
+# Parent  cafc89ca6a8788b80c279499701733e62389eb73
+Bug 1478170 - Implement TokenStreamChars::getNonAsciiCodePoint for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -876,16 +876,77 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     }
+ 
+     // Otherwise we have a multi-unit code point.
+     *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
+     MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+     return true;
+ }
+ 
++template<class AnyCharsAccess>
++bool
++TokenStreamChars<Utf8Unit, AnyCharsAccess>::getNonAsciiCodePoint(int32_t unit, int32_t* codePoint)
++{
++    MOZ_ASSERT(unit != EOF);
++    MOZ_ASSERT(!isAsciiCodePoint(unit),
++               "ASCII code unit/point must be handled separately");
++
++    Utf8Unit lead = Utf8Unit(static_cast<unsigned char>(unit));
++    MOZ_ASSERT(lead == this->sourceUnits.previousCodeUnit(),
++               "getNonAsciiCodePoint called incorrectly");
++
++    auto onBadLeadUnit = [this, &lead]() {
++        this->badLeadUnit(lead);
++    };
++
++    auto onNotEnoughUnits = [this, &lead](uint_fast8_t remaining, uint_fast8_t required) {
++        this->notEnoughUnits(lead, remaining, required);
++    };
++
++    auto onBadTrailingUnit = [this, &lead](uint_fast8_t unitsObserved) {
++        this->badTrailingUnit(lead, unitsObserved);
++    };
++
++    auto onBadCodePoint = [this](char32_t badCodePoint, uint_fast8_t unitsObserved) {
++        this->badCodePoint(badCodePoint, unitsObserved);
++    };
++
++    auto onNotShortestForm = [this](char32_t badCodePoint, uint_fast8_t unitsObserved) {
++        this->notShortestForm(badCodePoint, unitsObserved);
++    };
++
++    // This consumes the full, valid code point or ungets |lead| and calls the
++    // appropriate error functor on failure.
++    SourceUnitsIterator iter(this->sourceUnits);
++    Maybe<char32_t> maybeCodePoint =
++        DecodeOneUtf8CodePoint(lead, &iter, SourceUnitsEnd(),
++                               onBadLeadUnit, onNotEnoughUnits, onBadTrailingUnit, onBadCodePoint,
++                               onNotShortestForm);
++    if (maybeCodePoint.isNothing())
++        return false;
++
++    char32_t cp = maybeCodePoint.value();
++    if (MOZ_UNLIKELY(cp == unicode::LINE_SEPARATOR || cp == unicode::PARA_SEPARATOR)) {
++        if (!updateLineInfoForEOL()) {
++#ifdef DEBUG
++            *codePoint = EOF; // sentinel value to hopefully cause errors
++#endif
++            MOZ_MAKE_MEM_UNDEFINED(codePoint, sizeof(*codePoint));
++            return false;
++        }
++
++        *codePoint = '\n';
++    } else {
++        MOZ_ASSERT(!IsLineTerminator(cp));
++        *codePoint = AssertedCast<int32_t>(cp);
++    }
++
++    return true;
++}
++
+ template<>
+ size_t
+ SourceUnits<char16_t>::findWindowStart(size_t offset) const
+ {
+     // This is JS's understanding of UTF-16 that allows lone surrogates, so
+     // we have to exclude lone surrogates from [windowStart, offset) ourselves.
+ 
+     const char16_t* const earliestPossibleStart = codeUnitPtrAt(startOffset_);
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -2013,18 +2013,16 @@ class TokenStreamChars<char16_t, AnyChar
+     using GeneralCharsBase::getCodeUnit;
+     using SpecializedCharsBase::infallibleGetNonAsciiCodePointDontNormalize;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchLineTerminator;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+-    using typename GeneralCharsBase::SourceUnits;
+-
+   protected:
+     using GeneralCharsBase::GeneralCharsBase;
+ 
+     /**
+      * Given the non-ASCII |lead| code unit just consumed, consume and return a
+      * complete non-ASCII code point.  Line/column updates are not performed,
+      * and line breaks are returned as-is without normalization.
+      */
+@@ -2069,16 +2067,17 @@ class TokenStreamChars<mozilla::Utf8Unit
+     using typename SpecializedCharsBase::SourceUnitsEnd;
+     using typename SpecializedCharsBase::SourceUnitsIterator;
+ 
+   protected:
+     using GeneralCharsBase::anyCharsAccess;
+     using GeneralCharsBase::internalComputeLineOfContext;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
++    using GeneralCharsBase::updateLineInfoForEOL;
+ 
+   private:
+     static char toHexChar(uint8_t nibble) {
+         MOZ_ASSERT(nibble < 16);
+         return "0123456789ABCDEF"[nibble];
+     }
+ 
+     static void byteToString(uint8_t n, char* str) {
+@@ -2177,16 +2176,28 @@ class TokenStreamChars<mozilla::Utf8Unit
+      * Given the non-ASCII |lead| code unit just consumed, consume the rest of
+      * a non-ASCII code point.  The code point is not normalized: on success
+      * |*codePoint| may be U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR.
+      *
+      * Report an error if an invalid code point is encountered.
+      */
+     MOZ_MUST_USE bool
+     getNonAsciiCodePointDontNormalize(mozilla::Utf8Unit lead, char32_t* codePoint);
++
++    /**
++     * Given a just-consumed non-ASCII code unit |lead|, consume a full code
++     * point or LineTerminatorSequence (normalizing it to '\n') and store it in
++     * |*codePoint|.  Return true on success, otherwise return false and leave
++     * |*codePoint| undefined on failure.
++     *
++     * If a LineTerminatorSequence was consumed, also update line/column info.
++     *
++     * This function will change the current |sourceUnits| offset.
++     */
++    MOZ_MUST_USE bool getNonAsciiCodePoint(int32_t lead, int32_t* codePoint);
+ };
+ 
+ // TokenStream is the lexical scanner for JavaScript source text.
+ //
+ // It takes a buffer of CharT code units (currently only char16_t encoding
+ // UTF-16, but we're adding either UTF-8 or Latin-1 single-byte text soon) and
+ // linearly scans it into |Token|s.
+ //

+ 172 - 0
frg/work-js/mozilla-release/patches/1478170-12-63a1.patch

@@ -0,0 +1,172 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531887186 25200
+#      Tue Jul 17 21:13:06 2018 -0700
+# Node ID 38216fdba3ddea982cc4d3178c3b2c75637f71a1
+# Parent  107211d728e60e9b069c2d0107241f74b575d576
+Bug 1478170 - Move TokenStreamChars::getCodePoint to a generalized TokenStreamSpecific::getCodePoint that works for any CharT.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -786,54 +786,16 @@ TokenStreamChars<Utf8Unit, AnyCharsAcces
+         return false;
+ 
+     *codePoint = maybeCodePoint.value();
+     return true;
+ }
+ 
+ template<class AnyCharsAccess>
+ bool
+-TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
+-{
+-    TokenStreamAnyChars& anyChars = anyCharsAccess();
+-
+-    if (MOZ_UNLIKELY(this->sourceUnits.atEnd())) {
+-        anyChars.flags.isEOF = true;
+-        *cp = EOF;
+-        return true;
+-    }
+-
+-    int32_t c = this->sourceUnits.getCodeUnit();
+-
+-    do {
+-        // Normalize the char16_t if it was a newline.
+-        if (MOZ_UNLIKELY(c == '\n'))
+-            break;
+-
+-        if (MOZ_UNLIKELY(c == '\r')) {
+-            matchLineTerminator('\n');
+-            break;
+-        }
+-
+-        if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR))
+-            break;
+-
+-        *cp = c;
+-        return true;
+-    } while (false);
+-
+-    if (!updateLineInfoForEOL())
+-        return false;
+-
+-    *cp = '\n';
+-    return true;
+-}
+-
+-template<class AnyCharsAccess>
+-bool
+ TokenStreamChars<char16_t, AnyCharsAccess>::getNonAsciiCodePoint(int32_t lead, int32_t* codePoint)
+ {
+     MOZ_ASSERT(lead != EOF);
+     MOZ_ASSERT(!isAsciiCodePoint(lead),
+                "ASCII code unit/point must be handled separately");
+     MOZ_ASSERT(lead == this->sourceUnits.previousCodeUnit(),
+                "getNonAsciiCodePoint called incorrectly");
+ 
+@@ -876,16 +838,34 @@ TokenStreamChars<char16_t, AnyCharsAcces
+     }
+ 
+     // Otherwise we have a multi-unit code point.
+     *codePoint = unicode::UTF16Decode(lead, this->sourceUnits.getCodeUnit());
+     MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(*codePoint)));
+     return true;
+ }
+ 
++template<typename CharT, class AnyCharsAccess>
++bool
++TokenStreamSpecific<CharT, AnyCharsAccess>::getCodePoint(int32_t* cp)
++{
++    int32_t unit = getCodeUnit();
++    if (unit == EOF) {
++        MOZ_ASSERT(anyCharsAccess().flags.isEOF,
++                   "flags.isEOF should have been set by getCodeUnit()");
++        *cp = EOF;
++        return true;
++    }
++
++    if (isAsciiCodePoint(unit))
++        return getFullAsciiCodePoint(unit, cp);
++
++    return getNonAsciiCodePoint(unit, cp);
++}
++
+ template<class AnyCharsAccess>
+ bool
+ TokenStreamChars<Utf8Unit, AnyCharsAccess>::getNonAsciiCodePoint(int32_t unit, int32_t* codePoint)
+ {
+     MOZ_ASSERT(unit != EOF);
+     MOZ_ASSERT(!isAsciiCodePoint(unit),
+                "ASCII code unit/point must be handled separately");
+ 
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -2029,24 +2029,16 @@ class TokenStreamChars<char16_t, AnyChar
+     MOZ_MUST_USE bool getNonAsciiCodePointDontNormalize(char16_t lead, char32_t* codePoint) {
+         // There are no encoding errors in 16-bit JS, so implement this so that
+         // the compiler knows it, too.
+         *codePoint = infallibleGetNonAsciiCodePointDontNormalize(lead);
+         return true;
+     }
+ 
+     /**
+-     * Get the next code point, converting LineTerminatorSequences to '\n' and
+-     * updating internal line-counter state if needed.  Return true on success
+-     * and store the code point in |*c|.  Return false and leave |*c| undefined
+-     * on failure.
+-     */
+-    MOZ_MUST_USE bool getCodePoint(int32_t* cp);
+-
+-    /**
+      * Given a just-consumed non-ASCII code unit |lead| (which may also be a
+      * full code point, for UTF-16), consume a full code point or
+      * LineTerminatorSequence (normalizing it to '\n') and store it in
+      * |*codePoint|.  Return true on success, otherwise return false and leave
+      * |*codePoint| undefined on failure.
+      *
+      * If a LineTerminatorSequence was consumed, also update line/column info.
+      *
+@@ -2271,17 +2263,16 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using TokenStreamCharsShared::appendCodePointToCharBuffer;
+     using CharsBase::atomizeSourceChars;
+     using GeneralCharsBase::badToken;
+     // Deliberately don't |using| |charBuffer| because of bug 1472569.  :-(
+     using CharsBase::consumeKnownCodeUnit;
+     using TokenStreamCharsShared::copyCharBufferTo;
+     using TokenStreamCharsShared::drainCharBufferIntoAtom;
+     using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks;
+-    using SpecializedChars::getCodePoint;
+     using GeneralCharsBase::getCodeUnit;
+     using GeneralCharsBase::getFullAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePoint;
+     using SpecializedChars::getNonAsciiCodePointDontNormalize;
+     using GeneralCharsBase::internalComputeLineOfContext;
+     using TokenStreamCharsShared::isAsciiCodePoint;
+     using CharsBase::matchCodeUnit;
+     using CharsBase::matchLineTerminator;
+@@ -2298,16 +2289,24 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     template<typename CharU> friend class TokenStreamPosition;
+ 
+   public:
+     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
+                         const CharT* base, size_t length);
+ 
++    /**
++     * Get the next code point, converting LineTerminatorSequences to '\n' and
++     * updating internal line-counter state if needed.  Return true on success
++     * and store the code point in |*cp|.  Return false and leave |*cp|
++     * undefined on failure.
++     */
++    MOZ_MUST_USE bool getCodePoint(int32_t* cp);
++
+     // If there is an invalid escape in a template, report it and return false,
+     // otherwise return true.
+     bool checkForInvalidTemplateEscapeError() {
+         if (anyCharsAccess().invalidTemplateEscapeType == InvalidEscapeType::None)
+             return true;
+ 
+         reportInvalidEscapeError(anyCharsAccess().invalidTemplateEscapeOffset,
+                                  anyCharsAccess().invalidTemplateEscapeType);

+ 176 - 0
frg/work-js/mozilla-release/patches/1478170-13-63a1.patch

@@ -0,0 +1,176 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531887667 25200
+#      Tue Jul 17 21:21:07 2018 -0700
+# Node ID dad6f1d062719f26f6f934c2e8a5225ab2491351
+# Parent  38216fdba3ddea982cc4d3178c3b2c75637f71a1
+Bug 1478170 - Make atomizeSourceChars take a Span<CharT>, and define a specialization for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -10,16 +10,17 @@
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/IntegerTypeTraits.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/ScopeExit.h"
++#include "mozilla/Span.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+ #include <ctype.h>
+ #include <stdarg.h>
+ #include <stdint.h>
+ #include <stdio.h>
+@@ -44,16 +45,17 @@
+ using mozilla::ArrayLength;
+ using mozilla::AssertedCast;
+ using mozilla::DecodeOneUtf8CodePoint;
+ using mozilla::IsAscii;
+ using mozilla::IsAsciiAlpha;
+ using mozilla::IsAsciiDigit;
+ using mozilla::IsTrailingUnit;
+ using mozilla::MakeScopeExit;
++using mozilla::MakeSpan;
+ using mozilla::Maybe;
+ using mozilla::PointerRangeSize;
+ using mozilla::Utf8Unit;
+ 
+ struct ReservedWordInfo
+ {
+     const char* chars;         // C string with reserved word text
+     js::frontend::TokenKind tokentype;
+@@ -1907,17 +1909,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ 
+         // Represent reserved words lacking escapes as reserved word tokens.
+         if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
+             noteBadToken.release();
+             newSimpleToken(rw->tokentype, start, modifier, out);
+             return true;
+         }
+ 
+-        atom = atomizeSourceChars(anyCharsAccess().cx, chars, length);
++        atom = atomizeSourceChars(anyCharsAccess().cx, MakeSpan(chars, length));
+     }
+     if (!atom)
+         return false;
+ 
+     noteBadToken.release();
+     newNameToken(atom->asPropertyName(), start, modifier, out);
+     return true;
+ }
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -183,16 +183,17 @@
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Casting.h"
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/MemoryChecking.h"
+ #include "mozilla/PodOperations.h"
++#include "mozilla/Span.h"
+ #include "mozilla/TextUtils.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <algorithm>
+ #include <stdarg.h>
+ #include <stddef.h>
+@@ -1479,16 +1480,36 @@ class TokenStreamCharsShared
+         charBuffer.clear();
+         return atom;
+     }
+ 
+   public:
+     CharBuffer& getCharBuffer() { return charBuffer; }
+ };
+ 
++inline mozilla::Span<const char>
++ToCharSpan(mozilla::Span<const mozilla::Utf8Unit> codeUnits)
++{
++    static_assert(alignof(char) == alignof(mozilla::Utf8Unit),
++                  "must have equal alignment to reinterpret_cast<>");
++    static_assert(sizeof(char) == sizeof(mozilla::Utf8Unit),
++                  "must have equal size to reinterpret_cast<>");
++
++    // This cast is safe for two reasons.
++    //
++    // First, per C++11 [basic.lval]p10 it is permitted to access any object's
++    // memory through |char|.
++    //
++    // Second, Utf8Unit *contains* a |char|.  Examining that memory as |char|
++    // is simply, per C++11 [basic.lval]p10, to access the memory according to
++    // the dynamic type of the object: essentially trivially safe.
++    return mozilla::MakeSpan(reinterpret_cast<const char*>(codeUnits.data()),
++                             codeUnits.size());
++}
++
+ template<typename CharT>
+ class TokenStreamCharsBase
+   : public TokenStreamCharsShared
+ {
+   protected:
+     TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
+ 
+     /**
+@@ -1500,17 +1521,17 @@ class TokenStreamCharsBase
+     void ungetCodeUnit(int32_t c) {
+         if (c == EOF)
+             return;
+ 
+         sourceUnits.ungetCodeUnit();
+     }
+ 
+     static MOZ_ALWAYS_INLINE JSAtom*
+-    atomizeSourceChars(JSContext* cx, const CharT* chars, size_t length);
++    atomizeSourceChars(JSContext* cx, mozilla::Span<const CharT> units);
+ 
+     using SourceUnits = frontend::SourceUnits<CharT>;
+ 
+     /**
+      * Try to match a non-LineTerminator ASCII code point.  Return true iff it
+      * was matched.
+      */
+     bool matchCodeUnit(char expect) {
+@@ -1593,20 +1614,29 @@ template<typename CharT>
+ inline void
+ TokenStreamCharsBase<CharT>::consumeKnownCodeUnit(int32_t unit)
+ {
+     sourceUnits.consumeKnownCodeUnit(toCharT(unit));
+ }
+ 
+ template<>
+ /* static */ MOZ_ALWAYS_INLINE JSAtom*
+-TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx, const char16_t* chars,
+-                                                   size_t length)
++TokenStreamCharsBase<char16_t>::atomizeSourceChars(JSContext* cx,
++                                                   mozilla::Span<const char16_t> units)
+ {
+-    return AtomizeChars(cx, chars, length);
++    return AtomizeChars(cx, units.data(), units.size());
++}
++
++template<>
++/* static */ MOZ_ALWAYS_INLINE JSAtom*
++TokenStreamCharsBase<mozilla::Utf8Unit>::atomizeSourceChars(JSContext* cx,
++                                                            mozilla::Span<const mozilla::Utf8Unit> units)
++{
++    auto chars = ToCharSpan(units);
++    return AtomizeUTF8Chars(cx, chars.data(), chars.size());
+ }
+ 
+ template<typename CharT>
+ class SpecializedTokenStreamCharsBase;
+ 
+ template<>
+ class SpecializedTokenStreamCharsBase<char16_t>
+   : public TokenStreamCharsBase<char16_t>

+ 32 - 0
frg/work-js/mozilla-release/patches/1478170-14-63a1.patch

@@ -0,0 +1,32 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1531887667 25200
+#      Tue Jul 17 21:21:07 2018 -0700
+# Node ID 0ad2890523ff1ea6cefe816cb1fa80f32beac2b2
+# Parent  dad6f1d062719f26f6f934c2e8a5225ab2491351
+Bug 1478170 - Instantiate TokenStreamChars for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -3149,16 +3149,20 @@ TokenKindToString(TokenKind tt)
+ 
+ template class TokenStreamCharsBase<Utf8Unit>;
+ template class TokenStreamCharsBase<char16_t>;
+ 
+ template class TokenStreamChars<char16_t, TokenStreamAnyCharsAccess>;
+ template class TokenStreamSpecific<char16_t, TokenStreamAnyCharsAccess>;
+ 
+ template class
++TokenStreamChars<Utf8Unit, ParserAnyCharsAccess<GeneralParser<FullParseHandler, Utf8Unit>>>;
++template class
++TokenStreamChars<Utf8Unit, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, Utf8Unit>>>;
++template class
+ TokenStreamChars<char16_t, ParserAnyCharsAccess<GeneralParser<FullParseHandler, char16_t>>>;
+ template class
+ TokenStreamChars<char16_t, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, char16_t>>>;
+ 
+ template class
+ TokenStreamSpecific<char16_t, ParserAnyCharsAccess<GeneralParser<FullParseHandler, char16_t>>>;
+ template class
+ TokenStreamSpecific<char16_t, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, char16_t>>>;

+ 70 - 0
frg/work-js/mozilla-release/patches/1478587-01-63a1.patch

@@ -0,0 +1,70 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574661 25200
+#      Wed Jul 25 20:11:01 2018 -0700
+# Node ID bb0dd8b2d4e2cb93766120a7ef82746892639f26
+# Parent  8d4b0cb363a4d1faf88d33d23d7a64746f725692
+Bug 1478587 - Invoke TokenStreamChars::getNonAsciiCodePointDontNormalize passing CharT lead (not int32_t).  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1823,17 +1823,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             }
+ 
+             if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint))
+                 break;
+         } else {
+             // |restoreNextRawCharAddress| undoes all gets, and this function
+             // doesn't update line/column info.
+             char32_t cp;
+-            if (!getNonAsciiCodePointDontNormalize(unit, &cp))
++            if (!getNonAsciiCodePointDontNormalize(toCharT(unit), &cp))
+                 return false;
+ 
+             codePoint = cp;
+             if (!unicode::IsIdentifierPart(codePoint))
+                 break;
+         }
+ 
+         if (!appendCodePointToCharBuffer(codePoint))
+@@ -2146,17 +2146,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '/');
+     this->charBuffer.clear();
+ 
+     auto ProcessNonAsciiCodePoint = [this](int32_t lead) {
+         MOZ_ASSERT(lead != EOF);
+         MOZ_ASSERT(!this->isAsciiCodePoint(lead));
+ 
+         char32_t codePoint;
+-        if (!this->getNonAsciiCodePointDontNormalize(lead, &codePoint))
++        if (!this->getNonAsciiCodePointDontNormalize(this->toCharT(lead), &codePoint))
+             return false;
+ 
+         if (MOZ_UNLIKELY(codePoint == unicode::LINE_SEPARATOR ||
+                          codePoint == unicode::PARA_SEPARATOR))
+         {
+             this->sourceUnits.ungetLineOrParagraphSeparator();
+             this->reportError(JSMSG_UNTERMINATED_REGEXP);
+             return false;
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -2310,16 +2310,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
+     using GeneralCharsBase::matchUnicodeEscapeIdStart;
+     using GeneralCharsBase::newAtomToken;
+     using GeneralCharsBase::newNameToken;
+     using GeneralCharsBase::newNumberToken;
+     using GeneralCharsBase::newRegExpToken;
+     using GeneralCharsBase::newSimpleToken;
+     using CharsBase::peekCodeUnit;
+     // Deliberately don't |using| |sourceUnits| because of bug 1472569.  :-(
++    using CharsBase::toCharT;
+     using GeneralCharsBase::ungetCodeUnit;
+     using GeneralCharsBase::updateLineInfoForEOL;
+ 
+     template<typename CharU> friend class TokenStreamPosition;
+ 
+   public:
+     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
+                         const CharT* base, size_t length);

+ 56 - 0
frg/work-js/mozilla-release/patches/1478587-02-63a1.patch

@@ -0,0 +1,56 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574665 25200
+#      Wed Jul 25 20:11:05 2018 -0700
+# Node ID d3595d3fd0c0e39c94d7cba5043c28be216b29a0
+# Parent  bb0dd8b2d4e2cb93766120a7ef82746892639f26
+Bug 1478587 - Implement correct handling of Unicode line/paragraph separators in template/string literals for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -2810,36 +2810,32 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             return false;
+         }
+ 
+         // Non-ASCII code points are always directly appended -- even
+         // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR that are
+         // ordinarily LineTerminatorSequences.  (They contribute their literal
+         // values to template and [as of recently] string literals, but they're
+         // line terminators when computing line/column coordinates.)  Handle
+-        // the non-ASCI case early for readability.
++        // the non-ASCII case early for readability.
+         if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+-            static_assert(mozilla::IsSame<CharT, char16_t>::value,
+-                          "need a getNonAsciiCodePoint that doesn't normalize "
+-                          "LineTerminatorSequences to correctly handle UTF-8");
+-
+-            int32_t codePoint;
+-            if (unit == unicode::LINE_SEPARATOR || unit == unicode::PARA_SEPARATOR) {
++            char32_t cp;
++            if (!getNonAsciiCodePointDontNormalize(toCharT(unit), &cp))
++                return false;
++
++            if (MOZ_UNLIKELY(cp == unicode::LINE_SEPARATOR || cp == unicode::PARA_SEPARATOR)) {
+                 if (!updateLineInfoForEOL())
+                     return false;
+ 
+                 anyCharsAccess().updateFlagsForEOL();
+-
+-                codePoint = unit;
+             } else {
+-                if (!getNonAsciiCodePoint(unit, &codePoint))
+-                    return false;
++                MOZ_ASSERT(!IsLineTerminator(cp));
+             }
+ 
+-            if (!appendCodePointToCharBuffer(codePoint))
++            if (!appendCodePointToCharBuffer(cp))
+                 return false;
+ 
+             continue;
+         }
+ 
+         if (unit == '\\') {
+             // When parsing templates, we don't immediately report errors for
+             // invalid escapes; these are handled by the parser.  We don't

+ 30 - 0
frg/work-js/mozilla-release/patches/1478587-03-63a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574668 25200
+#      Wed Jul 25 20:11:08 2018 -0700
+# Node ID 805445fc768f0159334f0e066f62c543be14c2d8
+# Parent  d3595d3fd0c0e39c94d7cba5043c28be216b29a0
+Bug 1478587 - Return the result of CodeUnitValue(), not a CharT, from GeneralTokenStreamChars::getCodeUnit.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -1920,17 +1920,17 @@ class GeneralTokenStreamChars
+      *
+      * Because of these limitations, only use this if (a) the resulting code
+      * unit is guaranteed to be ungotten (by ungetCodeUnit()) if it's an EOL,
+      * and (b) the line-related state (lineno, linebase) is not used before
+      * it's ungotten.
+      */
+     int32_t getCodeUnit() {
+         if (MOZ_LIKELY(!this->sourceUnits.atEnd()))
+-            return this->sourceUnits.getCodeUnit();
++            return CodeUnitValue(this->sourceUnits.getCodeUnit());
+ 
+         anyCharsAccess().flags.isEOF = true;
+         return EOF;
+     }
+ 
+     void ungetCodeUnit(int32_t c) {
+         MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
+ 

+ 157 - 0
frg/work-js/mozilla-release/patches/1478587-04-63a1.patch

@@ -0,0 +1,157 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574672 25200
+#      Wed Jul 25 20:11:12 2018 -0700
+# Node ID 70b1c176aa7b029b02c64e6dd075b0f4941f038b
+# Parent  805445fc768f0159334f0e066f62c543be14c2d8
+Bug 1478587 - Add CharT casts when comparing code units to particular ASCII characters.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -1489,48 +1489,48 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+ // We have encountered a '\': check for a Unicode escape sequence after it.
+ // Return the length of the escape sequence and the encoded code point (by
+ // value) if we found a Unicode escape sequence, and skip all code units
+ // involed.  Otherwise, return 0 and don't advance along the buffer.
+ template<typename CharT, class AnyCharsAccess>
+ uint32_t
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscape(uint32_t* codePoint)
+ {
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+ 
+     int32_t unit = getCodeUnit();
+     if (unit != 'u') {
+         // NOTE: |unit| may be EOF here.
+         ungetCodeUnit(unit);
+-        MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
++        MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+         return 0;
+     }
+ 
+     char16_t v;
+     unit = getCodeUnit();
+     if (JS7_ISHEX(unit) && this->sourceUnits.matchHexDigits(3, &v)) {
+         *codePoint = (JS7_UNHEX(unit) << 12) | v;
+         return 5;
+     }
+ 
+     if (unit == '{')
+         return matchExtendedUnicodeEscape(codePoint);
+ 
+     // NOTE: |unit| may be EOF here, so this ungets either one or two units.
+     ungetCodeUnit(unit);
+     ungetCodeUnit('u');
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+     return 0;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ uint32_t
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchExtendedUnicodeEscape(uint32_t* codePoint)
+ {
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '{');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('{'));
+ 
+     int32_t unit = getCodeUnit();
+ 
+     // Skip leading zeroes.
+     uint32_t leadingZeroes = 0;
+     while (unit == '0') {
+         leadingZeroes++;
+         unit = getCodeUnit();
+@@ -1551,49 +1551,49 @@ GeneralTokenStreamChars<CharT, AnyCharsA
+         (unit != EOF); // subtract a get if it didn't contribute to length
+ 
+     if (unit == '}' && (leadingZeroes > 0 || i > 0) && code <= unicode::NonBMPMax) {
+         *codePoint = code;
+         return gotten;
+     }
+ 
+     this->sourceUnits.unskipCodeUnits(gotten);
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+     return 0;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ uint32_t
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdStart(uint32_t* codePoint)
+ {
+     uint32_t length = matchUnicodeEscape(codePoint);
+     if (MOZ_LIKELY(length > 0)) {
+         if (MOZ_LIKELY(unicode::IsIdentifierStart(*codePoint)))
+             return length;
+ 
+         this->sourceUnits.unskipCodeUnits(length);
+     }
+ 
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+     return 0;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t* codePoint)
+ {
+     uint32_t length = matchUnicodeEscape(codePoint);
+     if (MOZ_LIKELY(length > 0)) {
+         if (MOZ_LIKELY(unicode::IsIdentifierPart(*codePoint)))
+             return true;
+ 
+         this->sourceUnits.unskipCodeUnits(length);
+     }
+ 
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '\\');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('\\'));
+     return false;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::getDirectives(bool isMultiline,
+                                                           bool shouldWarnDeprecated)
+ {
+@@ -2138,17 +2138,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     newNumberToken(dval, decimalPoint, start, modifier, out);
+     return true;
+ }
+ 
+ template<typename CharT, class AnyCharsAccess>
+ MOZ_MUST_USE bool
+ TokenStreamSpecific<CharT, AnyCharsAccess>::regexpLiteral(TokenStart start, TokenKind* out)
+ {
+-    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == '/');
++    MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == CharT('/'));
+     this->charBuffer.clear();
+ 
+     auto ProcessNonAsciiCodePoint = [this](int32_t lead) {
+         MOZ_ASSERT(lead != EOF);
+         MOZ_ASSERT(!this->isAsciiCodePoint(lead));
+ 
+         char32_t codePoint;
+         if (!this->getNonAsciiCodePointDontNormalize(this->toCharT(lead), &codePoint))
+@@ -2783,18 +2783,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+     auto noteBadToken = MakeScopeExit([this]() {
+         this->badToken();
+     });
+ 
+     auto ReportPrematureEndOfLiteral = [this, untilChar](unsigned errnum) {
+         // Unicode separators aren't end-of-line in template or (as of
+         // recently) string literals, so this assertion doesn't allow them.
+         MOZ_ASSERT(this->sourceUnits.atEnd() ||
+-                   this->sourceUnits.peekCodeUnit() == '\r' ||
+-                   this->sourceUnits.peekCodeUnit() == '\n',
++                   this->sourceUnits.peekCodeUnit() == CharT('\r') ||
++                   this->sourceUnits.peekCodeUnit() == CharT('\n'),
+                    "must be parked at EOF or EOL to call this function");
+ 
+         // The various errors reported here include language like "in a ''
+         // literal" or similar, with '' being '', "", or `` as appropriate.
+         const char delimiters[] = { untilChar, untilChar, '\0' };
+ 
+         this->error(errnum, delimiters);
+         return;

+ 92 - 0
frg/work-js/mozilla-release/patches/1478587-05-63a1.patch

@@ -0,0 +1,92 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574675 25200
+#      Wed Jul 25 20:11:15 2018 -0700
+# Node ID caaac3580bd799e95faf9d215c5b6bd5ed3917a5
+# Parent  70b1c176aa7b029b02c64e6dd075b0f4941f038b
+Bug 1478587 - Switch on the numeric type underlying CharT, not on CharT itself, in a couple switches in TokenStreamSpecific::getTokenInternal.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -2538,17 +2538,20 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+         // creation code for all such tokens.  All other tokens must be handled
+         // by returning (or by continuing from the loop enclosing this).
+         //
+         TokenStart start(this->sourceUnits, -1);
+         TokenKind simpleKind;
+ #ifdef DEBUG
+         simpleKind = TokenKind::Limit; // sentinel value for code after switch
+ #endif
+-        switch (static_cast<CharT>(unit)) {
++
++        // The block a ways above eliminated all non-ASCII, so cast to the
++        // smallest type possible to assist the C++ compiler.
++        switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit)))) {
+           case '.':
+             unit = getCodeUnit();
+             if (IsAsciiDigit(unit)) {
+                 return decimalNumber('.', start, this->sourceUnits.addressOfNextCodeUnit() - 2,
+                                      modifier, ttp);
+             }
+ 
+             if (unit == '.') {
+@@ -2747,17 +2750,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             break;
+ 
+           default:
+             // We consumed a bad ASCII code point/unit.  Put it back so the
+             // error location is the bad code point.
+             ungetCodeUnit(unit);
+             error(JSMSG_ILLEGAL_CHARACTER);
+             return badToken();
+-        } // switch (static_cast<CharT>(unit))
++        } // switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit))))
+ 
+         MOZ_ASSERT(simpleKind != TokenKind::Limit,
+                    "switch-statement should have set |simpleKind| before "
+                    "breaking");
+ 
+         newSimpleToken(simpleKind, start, modifier, ttp);
+         return true;
+     } while (true);
+@@ -2860,17 +2863,19 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 if (codePoint != '\n') {
+                     if (!this->charBuffer.append(unit))
+                         return false;
+                 }
+ 
+                 continue;
+             }
+ 
+-            switch (static_cast<CharT>(unit)) {
++            // The block above eliminated all non-ASCII, so cast to the
++            // smallest type possible to assist the C++ compiler.
++            switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit)))) {
+               case 'b': unit = '\b'; break;
+               case 'f': unit = '\f'; break;
+               case 'n': unit = '\n'; break;
+               case 'r': unit = '\r'; break;
+               case 't': unit = '\t'; break;
+               case 'v': unit = '\v'; break;
+ 
+               case '\r':
+@@ -3057,17 +3062,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                         else
+                             val = save;
+                     }
+                 }
+ 
+                 unit = char16_t(val);
+                 break;
+               } // default
+-            }
++            } // switch (AssertedCast<uint8_t>(CodeUnitValue(toCharT(unit))))
+ 
+             if (!this->charBuffer.append(unit))
+                 return false;
+ 
+             continue;
+         } // (unit == '\\')
+ 
+         if (unit == '\r' || unit == '\n') {

+ 30 - 0
frg/work-js/mozilla-release/patches/1478587-06-63a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574678 25200
+#      Wed Jul 25 20:11:18 2018 -0700
+# Node ID 8f8857dc9348ff0249a8d2dea82fd0915ff8f5b3
+# Parent  caaac3580bd799e95faf9d215c5b6bd5ed3917a5
+Bug 1478587 - Make ReportUnterminatedRegExp accept an int32_t unit, not a CharT unit.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -2160,17 +2160,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             this->sourceUnits.ungetLineOrParagraphSeparator();
+             this->reportError(JSMSG_UNTERMINATED_REGEXP);
+             return false;
+         }
+ 
+         return this->appendCodePointToCharBuffer(codePoint);
+     };
+ 
+-    auto ReportUnterminatedRegExp = [this](CharT unit) {
++    auto ReportUnterminatedRegExp = [this](int32_t unit) {
+         this->ungetCodeUnit(unit);
+         this->error(JSMSG_UNTERMINATED_REGEXP);
+     };
+ 
+     bool inCharClass = false;
+     do {
+         int32_t unit = getCodeUnit();
+         if (unit == EOF) {

+ 62 - 0
frg/work-js/mozilla-release/patches/1478587-07-63a1.patch

@@ -0,0 +1,62 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532659413 25200
+#      Thu Jul 26 19:43:33 2018 -0700
+# Node ID aa240ce556588cbf9439b6f48a892efe6fa01c65
+# Parent  8f8857dc9348ff0249a8d2dea82fd0915ff8f5b3
+Bug 1478587 - Implement mozilla::Utf8AsUnsignedChars to centralize UTF-8-to-unsigned-chars casts and their justifications.  r=froydnj
+
+diff --git a/mfbt/Utf8.h b/mfbt/Utf8.h
+--- a/mfbt/Utf8.h
++++ b/mfbt/Utf8.h
+@@ -193,16 +193,50 @@ public:
+     return static_cast<uint8_t>(mValue);
+   }
+ 
+   // We currently don't expose |&mValue|.  |UnicodeData| sort of does, but
+   // that's a somewhat separate concern, justified in different comments in
+   // that other code.
+ };
+ 
++/**
++ * Reinterpret the address of a UTF-8 code unit as |const unsigned char*|.
++ *
++ * Assuming proper backing has been set up, the resulting |const unsigned char*|
++ * may validly be dereferenced.
++ *
++ * No access is provided to mutate this underlying memory as |unsigned char|.
++ * Presently memory inside |Utf8Unit| is *only* stored as |char|, and we are
++ * loath to offer a way to write non-|char| data until absolutely necessary.
++ */
++inline const unsigned char*
++Utf8AsUnsignedChars(const Utf8Unit* aUnits)
++{
++  static_assert(sizeof(Utf8Unit) == sizeof(unsigned char),
++                "sizes must match to permissibly reinterpret_cast<>");
++  static_assert(alignof(Utf8Unit) == alignof(unsigned char),
++                "alignment must match to permissibly reinterpret_cast<>");
++
++  // The static_asserts above only enable the reinterpret_cast<> to occur.
++  //
++  // Dereferencing the resulting pointer is a separate question.  Any object's
++  // memory may be interpreted as |unsigned char| per C++11 [basic.lval]p10, but
++  // this doesn't guarantee what values will be observed.  If |char| is
++  // implemented to act like |unsigned char|, we're good to go: memory for the
++  // |char| in |Utf8Unit| acts as we need.  But if |char| is implemented to act
++  // like |signed char|, dereferencing produces the right value only if the
++  // |char| types all use two's-complement representation.  Every modern
++  // compiler does this, and there's a C++ proposal to standardize it.
++  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r0.html   So
++  // *technically* this is implementation-defined -- but everyone does it and
++  // this behavior is being standardized.
++  return reinterpret_cast<const unsigned char*>(aUnits);
++}
++
+ /** Returns true iff |aUnit| is an ASCII value. */
+ inline bool
+ IsAscii(Utf8Unit aUnit)
+ {
+   return IsAscii(aUnit.toUint8());
+ }
+ 
+ /**

+ 45 - 0
frg/work-js/mozilla-release/patches/1478587-08-63a1.patch

@@ -0,0 +1,45 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574682 25200
+#      Wed Jul 25 20:11:22 2018 -0700
+# Node ID f1de95a9cc69d06197a37fda8f49dc822dc5e16f
+# Parent  aa240ce556588cbf9439b6f48a892efe6fa01c65
+Bug 1478587 - Make FindReservedWord work for CharT=Utf8Unit.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -94,25 +94,32 @@ FindReservedWord(const CharT* s, size_t 
+ 
+   got_match:
+     return &reservedWords[i];
+ 
+   test_guess:
+     rw = &reservedWords[i];
+     chars = rw->chars;
+     do {
+-        if (*s++ != (unsigned char)(*chars++))
++        if (*s++ != static_cast<unsigned char>(*chars++))
+             goto no_match;
+     } while (--length != 0);
+     return rw;
+ 
+   no_match:
+     return nullptr;
+ }
+ 
++template <>
++MOZ_ALWAYS_INLINE const ReservedWordInfo*
++FindReservedWord<Utf8Unit>(const Utf8Unit* units, size_t length)
++{
++    return FindReservedWord(Utf8AsUnsignedChars(units), length);
++}
++
+ static const ReservedWordInfo*
+ FindReservedWord(JSLinearString* str)
+ {
+     JS::AutoCheckCannotGC nogc;
+     return str->hasLatin1Chars()
+            ? FindReservedWord(str->latin1Chars(nogc), str->length())
+            : FindReservedWord(str->twoByteChars(nogc), str->length());
+ }

+ 364 - 0
frg/work-js/mozilla-release/patches/1478587-09-63a1.patch

@@ -0,0 +1,364 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574685 25200
+#      Wed Jul 25 20:11:25 2018 -0700
+# Node ID 69a4d421088167f1baf44a9df12fcc705b1df3eb
+# Parent  f1de95a9cc69d06197a37fda8f49dc822dc5e16f
+Bug 1478587 - Make number-parsing functions deal with UTF-8 input.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -2108,19 +2108,21 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+             // Consume exponential digits.
+             do {
+                 unit = getCodeUnit();
+             } while (IsAsciiDigit(unit));
+         }
+ 
+         ungetCodeUnit(unit);
+ 
+-        const CharT* dummy;
+-        if (!js_strtod(anyCharsAccess().cx, numStart, this->sourceUnits.addressOfNextCodeUnit(),
+-                       &dummy, &dval))
++        // "0." and "0e..." numbers parse "." or "e..." here.  Neither range
++        // contains a number, so we can't use |FullStringToDouble|.  (Parse
++        // failures return 0.0, so we'll still get the right result.)
++        if (!StringToDouble(anyCharsAccess().cx,
++                            numStart, this->sourceUnits.addressOfNextCodeUnit(), &dval))
+         {
+            return false;
+         }
+     }
+ 
+     // Number followed by IdentifierStart is an error.  (This is the only place
+     // in ECMAScript where token boundary is inadequate to properly separate
+     // two tokens, necessitating this unaesthetic lookahead.)
+@@ -2522,23 +2524,21 @@ TokenStreamSpecific<CharT, AnyCharsAcces
+                 PeekedCodePoint<CharT> peeked = this->sourceUnits.peekCodePoint();
+                 if (!peeked.isNone() && unicode::IsIdentifierStart(peeked.codePoint())) {
+                     error(JSMSG_IDSTART_AFTER_NUMBER);
+                     return badToken();
+                 }
+             }
+ 
+             double dval;
+-            const char16_t* dummy;
+-            if (!GetPrefixInteger(anyCharsAccess().cx, numStart,
+-                                  this->sourceUnits.addressOfNextCodeUnit(), radix, &dummy, &dval))
++            if (!GetFullInteger(anyCharsAccess().cx, numStart,
++                                this->sourceUnits.addressOfNextCodeUnit(), radix, &dval))
+             {
+                 return badToken();
+             }
+-
+             newNumberToken(dval, NoDecimal, start, modifier, ttp);
+             return true;
+         }
+ 
+         MOZ_ASSERT(c1kind == Other);
+ 
+         // This handles everything else.  Simple tokens distinguished solely by
+         // TokenKind should set |simpleKind| and break, to share simple-token
+diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
+--- a/js/src/jsnum.cpp
++++ b/js/src/jsnum.cpp
+@@ -10,16 +10,17 @@
+ 
+ #include "jsnum.h"
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/RangedPtr.h"
+ #include "mozilla/TextUtils.h"
++#include "mozilla/Utf8.h"
+ 
+ #ifdef HAVE_LOCALECONV
+ #include <locale.h>
+ #endif
+ #include <math.h>
+ #include <string.h>
+ 
+ #include "jstypes.h"
+@@ -42,21 +43,24 @@
+ #include "vm/StringType-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::Abs;
+ using mozilla::ArrayLength;
+ using mozilla::AsciiAlphanumericToNumber;
+ using mozilla::IsAsciiAlphanumeric;
++using mozilla::IsAsciiDigit;
+ using mozilla::Maybe;
+ using mozilla::MinNumberValue;
+ using mozilla::NegativeInfinity;
+ using mozilla::PositiveInfinity;
+ using mozilla::RangedPtr;
++using mozilla::Utf8AsUnsignedChars;
++using mozilla::Utf8Unit;
+ 
+ using JS::AutoCheckCannotGC;
+ using JS::GenericNaN;
+ using JS::ToInt8;
+ using JS::ToInt16;
+ using JS::ToInt32;
+ using JS::ToInt64;
+ using JS::ToUint8;
+@@ -256,48 +260,70 @@ js::GetPrefixInteger(JSContext* cx, cons
+         return ComputeAccurateDecimalInteger(cx, start, s, dp);
+ 
+     if ((base & (base - 1)) == 0)
+         *dp = ComputeAccurateBinaryBaseInteger(start, s, base);
+ 
+     return true;
+ }
+ 
++namespace js {
++
+ template bool
+-js::GetPrefixInteger(JSContext* cx, const char16_t* start, const char16_t* end, int base,
+-                     const char16_t** endp, double* dp);
++GetPrefixInteger(JSContext* cx, const char16_t* start, const char16_t* end, int base,
++                 const char16_t** endp, double* dp);
+ 
+ template bool
+-js::GetPrefixInteger(JSContext* cx, const Latin1Char* start, const Latin1Char* end,
+-                     int base, const Latin1Char** endp, double* dp);
++GetPrefixInteger(JSContext* cx, const Latin1Char* start, const Latin1Char* end, int base,
++                 const Latin1Char** endp, double* dp);
+ 
++} // namespace js
++
++template <typename CharT>
+ bool
+-js::GetDecimalInteger(JSContext* cx, const char16_t* start, const char16_t* end, double* dp)
++js::GetDecimalInteger(JSContext* cx, const CharT* start, const CharT* end, double* dp)
+ {
+     MOZ_ASSERT(start <= end);
+ 
+-    const char16_t* s = start;
++    const CharT* s = start;
+     double d = 0.0;
+     for (; s < end; s++) {
+-        char16_t c = *s;
+-        MOZ_ASSERT('0' <= c && c <= '9');
++        CharT c = *s;
++        MOZ_ASSERT(IsAsciiDigit(c));
+         int digit = c - '0';
+         d = d * 10 + digit;
+     }
+ 
+     *dp = d;
+ 
+     // If we haven't reached the limit of integer precision, we're done.
+     if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT)
+         return true;
+ 
+     // Otherwise compute the correct integer from the prefix of valid digits.
+     return ComputeAccurateDecimalInteger(cx, start, s, dp);
+ }
+ 
++namespace js {
++
++template bool
++GetDecimalInteger(JSContext* cx, const char16_t* start, const char16_t* end, double* dp);
++
++template bool
++GetDecimalInteger(JSContext* cx, const Latin1Char* start, const Latin1Char* end, double* dp);
++
++template <>
++bool
++GetDecimalInteger<Utf8Unit>(JSContext* cx, const Utf8Unit* start, const Utf8Unit* end, double* dp)
++{
++    return GetDecimalInteger(cx, Utf8AsUnsignedChars(start), Utf8AsUnsignedChars(end), dp);
++}
++
++} // namespace js
++
+ static bool
+ num_parseFloat(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+ 
+     if (args.length() == 0) {
+         args.rval().setNaN();
+         return true;
+diff --git a/js/src/jsnum.h b/js/src/jsnum.h
+--- a/js/src/jsnum.h
++++ b/js/src/jsnum.h
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef jsnum_h
+ #define jsnum_h
+ 
+ #include "mozilla/Compiler.h"
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Range.h"
++#include "mozilla/Utf8.h"
+ 
+ #include "NamespaceImports.h"
+ 
+ #include "js/Conversions.h"
+ 
+ #include "vm/StringType.h"
+ 
+ 
+@@ -140,23 +141,58 @@ ParseDecimalNumber(const mozilla::Range<
+  * If [start, end) does not begin with a number with the specified base,
+  * *dp == 0 and *endp == start upon return.
+  */
+ template <typename CharT>
+ extern MOZ_MUST_USE bool
+ GetPrefixInteger(JSContext* cx, const CharT* start, const CharT* end, int base,
+                  const CharT** endp, double* dp);
+ 
++inline const char16_t*
++ToRawChars(const char16_t* units)
++{
++    return units;
++}
++
++inline const unsigned char*
++ToRawChars(const unsigned char* units)
++{
++    return units;
++}
++
++inline const unsigned char*
++ToRawChars(const mozilla::Utf8Unit* units)
++{
++    return mozilla::Utf8AsUnsignedChars(units);
++}
++
++/**
++ * Like the prior function, but [start, end) must all be digits in the given
++ * base (and so this function doesn't take a useless outparam).
++ */
++template <typename CharT>
++extern MOZ_MUST_USE bool
++GetFullInteger(JSContext* cx, const CharT* start, const CharT* end, int base, double* dp)
++{
++    decltype(ToRawChars(start)) realEnd;
++    if (GetPrefixInteger(cx, ToRawChars(start), ToRawChars(end), base, &realEnd, dp)) {
++        MOZ_ASSERT(end == static_cast<const void*>(realEnd));
++        return true;
++    }
++    return false;
++}
++
+ /*
+- * This is like GetPrefixInteger, but only deals with base 10, and doesn't have
+- * and |endp| outparam.  It should only be used when the characters are known to
+- * only contain digits.
++ * This is like GetPrefixInteger, but it only deals with base 10 and doesn't
++ * have an |endp| outparam.  It should only be used when the characters are
++ * known to only contain digits.
+  */
++template <typename CharT>
+ extern MOZ_MUST_USE bool
+-GetDecimalInteger(JSContext* cx, const char16_t* start, const char16_t* end, double* dp);
++GetDecimalInteger(JSContext* cx, const CharT* start, const CharT* end, double* dp);
+ 
+ extern MOZ_MUST_USE bool
+ StringToNumber(JSContext* cx, JSString* str, double* result);
+ 
+ /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
+ MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
+ ToNumber(JSContext* cx, JS::MutableHandleValue vp)
+ {
+@@ -206,16 +242,45 @@ num_parseInt(JSContext* cx, unsigned arg
+  */
+ template <typename CharT>
+ extern MOZ_MUST_USE bool
+ js_strtod(JSContext* cx, const CharT* begin, const CharT* end,
+           const CharT** dEnd, double* d);
+ 
+ namespace js {
+ 
++/**
++ * Like js_strtod, but for when you don't require a |dEnd| argument *and* it's
++ * possible that the number in the string will not occupy the full [begin, end)
++ * range.
++ */
++template <typename CharT>
++extern MOZ_MUST_USE bool
++StringToDouble(JSContext* cx, const CharT* begin, const CharT* end, double* d)
++{
++    decltype(ToRawChars(begin)) dummy;
++    return js_strtod(cx, ToRawChars(begin), ToRawChars(end), &dummy, d);
++}
++
++/**
++ * Like js_strtod, but for when the number always constitutes the entire range
++ * (and so |dEnd| would be a value already known).
++ */
++template <typename CharT>
++extern MOZ_MUST_USE bool
++FullStringToDouble(JSContext* cx, const CharT* begin, const CharT* end, double* d)
++{
++    decltype(ToRawChars(begin)) realEnd;
++    if (js_strtod(cx, ToRawChars(begin), ToRawChars(end), &realEnd, d)) {
++        MOZ_ASSERT(end == static_cast<const void*>(realEnd));
++        return true;
++    }
++    return false;
++}
++
+ extern MOZ_MUST_USE bool
+ num_toString(JSContext* cx, unsigned argc, Value* vp);
+ 
+ extern MOZ_MUST_USE bool
+ num_valueOf(JSContext* cx, unsigned argc, Value* vp);
+ 
+ /*
+  * Returns true if the given value is definitely an index: that is, the value
+diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp
+--- a/js/src/vm/JSONParser.cpp
++++ b/js/src/vm/JSONParser.cpp
+@@ -284,20 +284,18 @@ JSONParser<CharT>::readNumber()
+             // largest number a double can represent with integral precision),
+             // parse it using a decimal-only parser.  This comparison is
+             // conservative but faster than a fully-precise check.
+             double d = ParseDecimalNumber(chars);
+             return numberToken(negative ? -d : d);
+         }
+ 
+         double d;
+-        const CharT* dummy;
+-        if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
++        if (!GetFullInteger(cx, digitStart.get(), current.get(), 10, &d))
+             return token(OOM);
+-        MOZ_ASSERT(current == dummy);
+         return numberToken(negative ? -d : d);
+     }
+ 
+     /* (\.[0-9]+)? */
+     if (current < end && *current == '.') {
+         if (++current == end) {
+             error("missing digits after decimal point");
+             return token(Error);
+@@ -330,20 +328,18 @@ JSONParser<CharT>::readNumber()
+         }
+         while (++current < end) {
+             if (!IsAsciiDigit(*current))
+                 break;
+         }
+     }
+ 
+     double d;
+-    const CharT* finish;
+-    if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d))
++    if (!FullStringToDouble(cx, digitStart.get(), current.get(), &d))
+         return token(OOM);
+-    MOZ_ASSERT(current == finish);
+     return numberToken(negative ? -d : d);
+ }
+ 
+ static inline bool
+ IsJSONWhitespace(char16_t c)
+ {
+     return c == '\t' || c == '\r' || c == '\n' || c == ' ';
+ }

+ 32 - 0
frg/work-js/mozilla-release/patches/1478587-10-63a1.patch

@@ -0,0 +1,32 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532659502 25200
+#      Thu Jul 26 19:45:02 2018 -0700
+# Node ID eea8bd3d8e45082679dd8d44c2a18b2ccde80c1c
+# Parent  69a4d421088167f1baf44a9df12fcc705b1df3eb
+Bug 1478587 - Instantiate TokenStreamSpecific for UTF-8.  r=arai
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -3166,16 +3166,20 @@ TokenStreamChars<Utf8Unit, ParserAnyChar
+ template class
+ TokenStreamChars<Utf8Unit, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, Utf8Unit>>>;
+ template class
+ TokenStreamChars<char16_t, ParserAnyCharsAccess<GeneralParser<FullParseHandler, char16_t>>>;
+ template class
+ TokenStreamChars<char16_t, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, char16_t>>>;
+ 
+ template class
++TokenStreamSpecific<Utf8Unit, ParserAnyCharsAccess<GeneralParser<FullParseHandler, Utf8Unit>>>;
++template class
++TokenStreamSpecific<Utf8Unit, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, Utf8Unit>>>;
++template class
+ TokenStreamSpecific<char16_t, ParserAnyCharsAccess<GeneralParser<FullParseHandler, char16_t>>>;
+ template class
+ TokenStreamSpecific<char16_t, ParserAnyCharsAccess<GeneralParser<SyntaxParseHandler, char16_t>>>;
+ 
+ } // namespace frontend
+ 
+ } // namespace js
+ 

+ 142 - 0
frg/work-js/mozilla-release/patches/1478892-1-63a1.patch

@@ -0,0 +1,142 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532574742 25200
+#      Wed Jul 25 20:12:22 2018 -0700
+# Node ID a55de03eb91d84b00906c20755a2e95eae19fe48
+# Parent  eea8bd3d8e45082679dd8d44c2a18b2ccde80c1c
+Bug 1478892 - Make all parser-related classes instantiable for UTF-8 source text.  r=arai
+
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -18,16 +18,17 @@
+  */
+ 
+ #include "frontend/Parser.h"
+ 
+ #include "mozilla/Range.h"
+ #include "mozilla/Sprintf.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
++#include "mozilla/Utf8.h"
+ 
+ #include <memory>
+ #include <new>
+ 
+ #include "jsapi.h"
+ #include "jstypes.h"
+ 
+ #include "builtin/ModuleObject.h"
+@@ -55,16 +56,17 @@ using namespace js;
+ using namespace js::gc;
+ 
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::PodCopy;
+ using mozilla::PodZero;
+ using mozilla::Some;
+ using mozilla::Unused;
++using mozilla::Utf8Unit;
+ 
+ using JS::AutoGCRooter;
+ 
+ namespace js {
+ namespace frontend {
+ 
+ using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
+ using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
+@@ -4109,19 +4111,19 @@ Parser<SyntaxParseHandler, CharT>::asmJS
+     // Record that the current script source constains some AsmJS, to disable
+     // any incremental encoder, as AsmJS cannot be encoded with XDR at the
+     // moment.
+     if (ss)
+         ss->setContainsAsmJS();
+     return false;
+ }
+ 
+-template <typename CharT>
++template <>
+ bool
+-Parser<FullParseHandler, CharT>::asmJS(Node list)
++Parser<FullParseHandler, char16_t>::asmJS(Node list)
+ {
+     // Disable syntax parsing in anything nested inside the asm.js module.
+     disableSyntaxParser();
+ 
+     // We should be encountering the "use asm" directive for the first time; if
+     // the directive is already, we must have failed asm.js validation and we're
+     // reparsing. In that case, don't try to validate again. A non-null
+     // newDirectives means we're not in a normal function.
+@@ -4147,16 +4149,26 @@ Parser<FullParseHandler, CharT>::asmJS(N
+     if (!validated) {
+         pc->newDirectives->setAsmJS();
+         return false;
+     }
+ 
+     return true;
+ }
+ 
++template <>
++bool
++Parser<FullParseHandler, Utf8Unit>::asmJS(Node list)
++{
++    // Just succeed without setting the asm.js directive flag.  Given Web
++    // Assembly's rapid advance, it's probably not worth the trouble to really
++    // support UTF-8 asm.js.
++    return true;
++}
++
+ template <class ParseHandler, typename CharT>
+ inline bool
+ GeneralParser<ParseHandler, CharT>::asmJS(Node list)
+ {
+     return asFinalParser()->asmJS(list);
+ }
+ 
+ /*
+@@ -9114,19 +9126,16 @@ GeneralParser<ParseHandler, CharT>::noSu
+ }
+ 
+ template <typename CharT>
+ ParseNode*
+ Parser<FullParseHandler, CharT>::newRegExp()
+ {
+     MOZ_ASSERT(!options().selfHostingMode);
+ 
+-    static_assert(mozilla::IsSame<CharT, char16_t>::value,
+-                  "code below will need changing for UTF-8 handling");
+-
+     // Create the regexp and check its syntax.
+     const auto& chars = tokenStream.getCharBuffer();
+     RegExpFlag flags = anyChars.currentToken().regExpFlags();
+ 
+     Rooted<RegExpObject*> reobj(context);
+     reobj = RegExpObject::create(context, chars.begin(), chars.length(), flags, anyChars, alloc,
+                                  TenuredObject);
+     if (!reobj)
+@@ -9136,24 +9145,21 @@ Parser<FullParseHandler, CharT>::newRegE
+ }
+ 
+ template <typename CharT>
+ SyntaxParseHandler::Node
+ Parser<SyntaxParseHandler, CharT>::newRegExp()
+ {
+     MOZ_ASSERT(!options().selfHostingMode);
+ 
+-    static_assert(mozilla::IsSame<CharT, char16_t>::value,
+-                  "code below will need changing for UTF-8 handling");
+-
+     // Only check the regexp's syntax, but don't create a regexp object.
+     const auto& chars = tokenStream.getCharBuffer();
+     RegExpFlag flags = anyChars.currentToken().regExpFlags();
+ 
+-    mozilla::Range<const CharT> source(chars.begin(), chars.length());
++    mozilla::Range<const char16_t> source(chars.begin(), chars.length());
+     if (!js::irregexp::ParsePatternSyntax(anyChars, alloc, source, flags & UnicodeFlag))
+         return null();
+ 
+     return handler.newRegExp(SyntaxParseHandler::NodeGeneric, pos(), *this);
+ }
+ 
+ template <class ParseHandler, typename CharT>
+ typename ParseHandler::Node

+ 30 - 0
frg/work-js/mozilla-release/patches/1478892-2-63a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1532990135 25200
+#      Mon Jul 30 15:35:35 2018 -0700
+# Node ID ba7c501f82f538585c54947a9392e6f450c7c24c
+# Parent  4321a61b9f4343d7d6a89c809149e737ad6a99f7
+Bug 1478892 - Instantiate GeneralParser for UTF-8 source text.  r=arai
+
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -10202,16 +10202,18 @@ GeneralParser<ParseHandler, CharT>::expr
+                                                  PossibleError* possibleError /* = nullptr */)
+ {
+     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lp));
+     return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
+ }
+ 
+ template class PerHandlerParser<FullParseHandler>;
+ template class PerHandlerParser<SyntaxParseHandler>;
++template class GeneralParser<FullParseHandler, Utf8Unit>;
++template class GeneralParser<SyntaxParseHandler, Utf8Unit>;
+ template class GeneralParser<FullParseHandler, char16_t>;
+ template class GeneralParser<SyntaxParseHandler, char16_t>;
+ template class Parser<FullParseHandler, char16_t>;
+ template class Parser<SyntaxParseHandler, char16_t>;
+ 
+ 
+ } /* namespace frontend */
+ } /* namespace js */

+ 28 - 0
frg/work-js/mozilla-release/patches/1478892-3-63a1.patch

@@ -0,0 +1,28 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1533873862 25200
+#      Thu Aug 09 21:04:22 2018 -0700
+# Node ID f244ce374cd26b231d5309900b4648db90ad39cb
+# Parent  0328a2aa5c686a57b4dcae146063f9a727075c35
+Bug 1478892 - Instantiate Parser for UTF-8 source text.  r=arai
+
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -10206,14 +10206,16 @@ GeneralParser<ParseHandler, CharT>::expr
+ }
+ 
+ template class PerHandlerParser<FullParseHandler>;
+ template class PerHandlerParser<SyntaxParseHandler>;
+ template class GeneralParser<FullParseHandler, Utf8Unit>;
+ template class GeneralParser<SyntaxParseHandler, Utf8Unit>;
+ template class GeneralParser<FullParseHandler, char16_t>;
+ template class GeneralParser<SyntaxParseHandler, char16_t>;
++template class Parser<FullParseHandler, Utf8Unit>;
++template class Parser<SyntaxParseHandler, Utf8Unit>;
+ template class Parser<FullParseHandler, char16_t>;
+ template class Parser<SyntaxParseHandler, char16_t>;
+ 
+ 
+ } /* namespace frontend */
+ } /* namespace js */

+ 371 - 0
frg/work-js/mozilla-release/patches/1478910-63a1.patch

@@ -0,0 +1,371 @@
+# HG changeset patch
+# User Thi Huynh <so61pi.re@gmail.com>
+# Date 1534244810 0
+# Node ID 1283ee4cfb6bea6641102cd08931540688e4d2cc
+# Parent  5312e71473c402f520db9e24f5c7e5eb6795cbcf
+Bug 1478910 - Use JSMSG_AWAIT_IN_DEFAULT error for incomplete await expr in async function/generator parameter. r=arai
+
+Differential Revision: https://phabricator.services.mozilla.com/D3207
+
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -843,16 +843,17 @@ ParserBase::ParserBase(JSContext* cx, Li
+     sourceObject(cx, sourceObject),
+     keepAtoms(cx),
+     foldConstants(foldConstants),
+ #ifdef DEBUG
+     checkOptionsCalled(false),
+ #endif
+     isUnexpectedEOF_(false),
+     awaitHandling_(AwaitIsName),
++    inParametersOfAsyncFunction_(false),
+     parseGoal_(uint8_t(parseGoal))
+ {
+     cx->frontendCollectionPool().addActiveCompilation();
+     tempPoolMark = alloc.mark();
+ }
+ 
+ bool
+ ParserBase::checkOptions()
+@@ -927,16 +928,39 @@ Parser<FullParseHandler, CharT>::setAwai
+ 
+ template <class ParseHandler, typename CharT>
+ inline void
+ GeneralParser<ParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
+ {
+     asFinalParser()->setAwaitHandling(awaitHandling);
+ }
+ 
++template <typename CharT>
++void
++Parser<SyntaxParseHandler, CharT>::setInParametersOfAsyncFunction(bool inParameters)
++{
++    this->inParametersOfAsyncFunction_ = inParameters;
++}
++
++template <typename CharT>
++void
++Parser<FullParseHandler, CharT>::setInParametersOfAsyncFunction(bool inParameters)
++{
++    this->inParametersOfAsyncFunction_ = inParameters;
++    if (SyntaxParser* syntaxParser = getSyntaxParser())
++        syntaxParser->setInParametersOfAsyncFunction(inParameters);
++}
++
++template <class ParseHandler, typename CharT>
++inline void
++GeneralParser<ParseHandler, CharT>::setInParametersOfAsyncFunction(bool inParameters)
++{
++    asFinalParser()->setInParametersOfAsyncFunction(inParameters);
++}
++
+ ObjectBox*
+ ParserBase::newObjectBox(JSObject* obj)
+ {
+     MOZ_ASSERT(obj);
+ 
+     /*
+      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
+      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
+@@ -3817,16 +3841,17 @@ GeneralParser<ParseHandler, CharT>::func
+     // See below for an explanation why arrow function parameters and arrow
+     // function bodies are parsed with different yield/await settings.
+     {
+         AwaitHandling awaitHandling =
+             (funbox->isAsync() || (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()))
+             ? AwaitIsKeyword
+             : AwaitIsName;
+         AutoAwaitIsKeyword<ParseHandler, CharT> awaitIsKeyword(this, awaitHandling);
++        AutoInParametersOfAsyncFunction<ParseHandler, CharT> inParameters(this, funbox->isAsync());
+         if (!functionArguments(yieldHandling, kind, *pn))
+             return false;
+     }
+ 
+     Maybe<ParseContext::VarScope> varScope;
+     if (funbox->hasParameterExprs) {
+         varScope.emplace(this);
+         if (!varScope->init(pc))
+@@ -3878,16 +3903,17 @@ GeneralParser<ParseHandler, CharT>::func
+     // Whereas the |yield| in the function body is always parsed as a name.
+     // The same goes when parsing |await| in arrow functions.
+     YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
+     AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc->asyncKind());
+     bool inheritedStrict = pc->sc()->strict();
+     Node body;
+     {
+         AutoAwaitIsKeyword<ParseHandler, CharT> awaitIsKeyword(this, bodyAwaitHandling);
++        AutoInParametersOfAsyncFunction<ParseHandler, CharT> inParameters(this, false);
+         body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
+         if (!body)
+             return false;
+     }
+ 
+     // Revalidate the function name when we transitioned to strict mode.
+     if ((kind == FunctionSyntaxKind::Statement || kind == FunctionSyntaxKind::Expression) &&
+         fun->explicitName() &&
+@@ -8581,16 +8607,20 @@ GeneralParser<ParseHandler, CharT>::unar
+             pc->sc()->setBindingsAccessedDynamically();
+         }
+ 
+         return handler.newDelete(begin, expr);
+       }
+ 
+       case TokenKind::Await: {
+         if (pc->isAsync()) {
++            if (inParametersOfAsyncFunction()) {
++                error(JSMSG_AWAIT_IN_DEFAULT);
++                return null();
++            }
+             Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
+             if (!kid)
+                 return null();
+             pc->lastAwaitOffset = begin;
+             return handler.newAwaitExpression(begin, kid);
+         }
+       }
+ 
+diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
+--- a/js/src/frontend/Parser.h
++++ b/js/src/frontend/Parser.h
+@@ -244,16 +244,19 @@ enum class PropertyType {
+     DerivedConstructor
+ };
+ 
+ enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword };
+ 
+ template <class ParseHandler, typename CharT>
+ class AutoAwaitIsKeyword;
+ 
++template <class ParseHandler, typename CharT>
++class AutoInParametersOfAsyncFunction;
++
+ class MOZ_STACK_CLASS ParserBase
+   : public StrictModeGetter,
+     private JS::AutoGCRooter
+ {
+   private:
+     ParserBase* thisForCtor() { return this; }
+ 
+     // This is needed to cast a parser to JS::AutoGCRooter.
+@@ -292,28 +295,35 @@ class MOZ_STACK_CLASS ParserBase
+     bool checkOptionsCalled:1;
+ #endif
+ 
+     /* Unexpected end of input, i.e. Eof not at top-level. */
+     bool isUnexpectedEOF_:1;
+ 
+     /* AwaitHandling */ uint8_t awaitHandling_:2;
+ 
++    bool inParametersOfAsyncFunction_:1;
++
+     /* ParseGoal */ uint8_t parseGoal_:1;
+ 
+   public:
+     bool awaitIsKeyword() const {
+       return awaitHandling_ != AwaitIsName;
+     }
+ 
++    bool inParametersOfAsyncFunction() const {
++        return inParametersOfAsyncFunction_;
++    }
++
+     ParseGoal parseGoal() const {
+         return ParseGoal(parseGoal_);
+     }
+ 
+     template<class, typename> friend class AutoAwaitIsKeyword;
++    template<class, typename> friend class AutoInParametersOfAsyncFunction;
+ 
+     ParserBase(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
+                bool foldConstants, UsedNameTracker& usedNames,
+                ScriptSourceObject* sourceObject, ParseGoal parseGoal);
+     ~ParserBase();
+ 
+     bool checkOptions();
+ 
+@@ -685,16 +695,17 @@ class MOZ_STACK_CLASS GeneralParser
+     using Modifier = TokenStreamShared::Modifier;
+     using Position = typename TokenStream::Position;
+ 
+     using Base::PredictUninvoked;
+     using Base::PredictInvoked;
+ 
+     using Base::alloc;
+     using Base::awaitIsKeyword;
++    using Base::inParametersOfAsyncFunction;
+     using Base::parseGoal;
+ #if DEBUG
+     using Base::checkOptionsCalled;
+ #endif
+     using Base::finishFunctionScopes;
+     using Base::finishLexicalScope;
+     using Base::foldConstants;
+     using Base::getFilename;
+@@ -891,16 +902,17 @@ class MOZ_STACK_CLASS GeneralParser
+     GeneralParser(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
+                   const CharT* chars, size_t length, bool foldConstants,
+                   UsedNameTracker& usedNames, SyntaxParser* syntaxParser,
+                   LazyScript* lazyOuterFunction,
+                   ScriptSourceObject* sourceObject,
+                   ParseGoal parseGoal);
+ 
+     inline void setAwaitHandling(AwaitHandling awaitHandling);
++    inline void setInParametersOfAsyncFunction(bool inParameters);
+ 
+     /*
+      * Parse a top-level JS script.
+      */
+     Node parse();
+ 
+     /* Report the given error at the current offset. */
+     void error(unsigned errorNumber, ...);
+@@ -1350,16 +1362,17 @@ class MOZ_STACK_CLASS Parser<SyntaxParse
+ 
+     PropertyName* bindingIdentifier(YieldHandling yieldHandling) {
+         return Base::bindingIdentifier(yieldHandling);
+     }
+ 
+     // Functions present in both Parser<ParseHandler, CharT> specializations.
+ 
+     inline void setAwaitHandling(AwaitHandling awaitHandling);
++    inline void setInParametersOfAsyncFunction(bool inParameters);
+ 
+     Node newRegExp();
+ 
+     // Parse a module.
+     Node moduleBody(ModuleSharedContext* modulesc);
+ 
+     inline Node importDeclaration();
+     inline bool checkLocalExportNames(Node node);
+@@ -1468,16 +1481,19 @@ class MOZ_STACK_CLASS Parser<FullParseHa
+         return Base::bindingIdentifier(yieldHandling);
+     }
+ 
+     // Functions present in both Parser<ParseHandler, CharT> specializations.
+ 
+     friend class AutoAwaitIsKeyword<SyntaxParseHandler, CharT>;
+     inline void setAwaitHandling(AwaitHandling awaitHandling);
+ 
++    friend class AutoInParametersOfAsyncFunction<SyntaxParseHandler, CharT>;
++    inline void setInParametersOfAsyncFunction(bool inParameters);
++
+     Node newRegExp();
+ 
+     // Parse a module.
+     Node moduleBody(ModuleSharedContext* modulesc);
+ 
+     Node importDeclaration();
+     bool checkLocalExportNames(Node node);
+     bool checkExportedName(JSAtom* exportName);
+@@ -1607,16 +1623,37 @@ class MOZ_STACK_CLASS AutoAwaitIsKeyword
+             parser_->setAwaitHandling(awaitHandling);
+     }
+ 
+     ~AutoAwaitIsKeyword() {
+         parser_->setAwaitHandling(oldAwaitHandling_);
+     }
+ };
+ 
++template <class ParseHandler, typename CharT>
++class MOZ_STACK_CLASS AutoInParametersOfAsyncFunction
++{
++    using GeneralParser = frontend::GeneralParser<ParseHandler, CharT>;
++
++  private:
++    GeneralParser* parser_;
++    bool oldInParametersOfAsyncFunction_;
++
++  public:
++    AutoInParametersOfAsyncFunction(GeneralParser* parser, bool inParameters) {
++        parser_ = parser;
++        oldInParametersOfAsyncFunction_ = parser_->inParametersOfAsyncFunction_;
++        parser_->setInParametersOfAsyncFunction(inParameters);
++    }
++
++    ~AutoInParametersOfAsyncFunction() {
++        parser_->setInParametersOfAsyncFunction(oldInParametersOfAsyncFunction_);
++    }
++};
++
+ template <typename Scope>
+ extern typename Scope::Data*
+ NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc, uint32_t numBindings);
+ 
+ mozilla::Maybe<GlobalScope::Data*>
+ NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc);
+ mozilla::Maybe<EvalScope::Data*>
+ NewEvalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc);
+diff --git a/js/src/tests/non262/async-functions/await-in-parameters-of-async-func.js b/js/src/tests/non262/async-functions/await-in-parameters-of-async-func.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/tests/non262/async-functions/await-in-parameters-of-async-func.js
+@@ -0,0 +1,67 @@
++/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
++/*
++ * Any copyright is dedicated to the Public Domain.
++ * http://creativecommons.org/licenses/publicdomain/
++ * Contributor: 
++ */
++
++//-----------------------------------------------------------------------------
++var BUGNUMBER = 1478910;
++var summary = 'JSMSG_AWAIT_IN_DEFAULT error for incomplete await expr in async function/generator parameter';
++
++
++//-----------------------------------------------------------------------------
++test();
++//-----------------------------------------------------------------------------
++
++function test()
++{
++  printBugNumber(BUGNUMBER);
++  printStatus(summary);
++
++  let testAwaitInDefaultExprOfAsyncFunc = (code) => {
++  	assertThrowsInstanceOf(() => eval(code), SyntaxError, "await can't be used in default expression");
++  };
++
++  let testNoException = (code) => {
++  	assertEq(completesNormally(code), true);
++  };
++
++  // https://www.ecma-international.org/ecma-262/9.0/
++
++  // Async Generator Function Definitions : AsyncGeneratorDeclaration & AsyncGeneratorExpression
++  // async function* f() {}
++  // f = async function*() {}
++  testAwaitInDefaultExprOfAsyncFunc("async function* f(a = await) {}");
++  testAwaitInDefaultExprOfAsyncFunc("let f = async function*(a = await) {}");
++
++  testAwaitInDefaultExprOfAsyncFunc("function f(a = async function*(a = await) {}) {}");
++  testAwaitInDefaultExprOfAsyncFunc("function f() { a = async function*(a = await) {}; }");
++
++  testAwaitInDefaultExprOfAsyncFunc("async function* f() { a = async function*(a = await) {}; }");
++  testNoException("async function* f() { let a = function(a = await) {}; }");
++
++  testNoException("async function* f(a = async function*() { await 1; }) {}");
++
++  // Async Function Definitions : AsyncFunctionDeclaration & AsyncFunctionExpression
++  // async function f() {}
++  // f = async function() {}
++  testAwaitInDefaultExprOfAsyncFunc("async function f(a = await) {}");
++  testAwaitInDefaultExprOfAsyncFunc("let f = async function(a = await) {}");
++
++  testAwaitInDefaultExprOfAsyncFunc("function f(a = async function(a = await) {}) {}");
++  testAwaitInDefaultExprOfAsyncFunc("function f() { a = async function(a = await) {}; }");
++
++  testAwaitInDefaultExprOfAsyncFunc("async function f() { a = async function(a = await) {}; }");
++  testNoException("async function f() { let a = function(a = await) {}; }");
++
++  testNoException("async function f(a = async function() { await 1; }) {}");
++
++  // Async Arrow Function Definitions : AsyncArrowFunction
++  // async () => {}
++  testAwaitInDefaultExprOfAsyncFunc("async (a = await) => {}");
++
++  testNoException("async (a = async () => { await 1; }) => {}");
++
++  reportCompare(true, true, summary);
++}
+

+ 7 - 7
frg/work-js/mozilla-release/patches/1479900-2-63a1.patch

@@ -2,7 +2,7 @@
 # User Ted Campbell <tcampbell@mozilla.com>
 # User Ted Campbell <tcampbell@mozilla.com>
 # Date 1533234736 25200
 # Date 1533234736 25200
 # Node ID 819b923159847ebf0227a910e966490f4f9dc177
 # Node ID 819b923159847ebf0227a910e966490f4f9dc177
-# Parent  4ed363b9ebbbf6384f1ea283cbabb132ed9762cb
+# Parent  1efa9f0b5c83c9c80753d1d794858451cb702ba2
 Bug 1479900 - Part 2: Refactor GC relocation to use a reserved flag. r=sfink
 Bug 1479900 - Part 2: Refactor GC relocation to use a reserved flag. r=sfink
 
 
 This refactors gc::Cell derived types to start with a uintptr_t-sized
 This refactors gc::Cell derived types to start with a uintptr_t-sized
@@ -218,8 +218,7 @@ diff --git a/js/src/gc/Cell.h b/js/src/gc/Cell.h
 diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
 diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
 --- a/js/src/gc/GC.cpp
 --- a/js/src/gc/GC.cpp
 +++ b/js/src/gc/GC.cpp
 +++ b/js/src/gc/GC.cpp
-@@ -216,16 +216,17 @@
- #include "gc/GCInternals.h"
+@@ -219,16 +219,17 @@
  #include "gc/GCTrace.h"
  #include "gc/GCTrace.h"
  #include "gc/Memory.h"
  #include "gc/Memory.h"
  #include "gc/Policy.h"
  #include "gc/Policy.h"
@@ -227,6 +226,7 @@ diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
  #include "jit/BaselineJIT.h"
  #include "jit/BaselineJIT.h"
  #include "jit/IonCode.h"
  #include "jit/IonCode.h"
  #include "jit/JitcodeMap.h"
  #include "jit/JitcodeMap.h"
+ #include "jit/JitRealm.h"
 +#include "jit/MacroAssembler.h"
 +#include "jit/MacroAssembler.h"
  #include "js/SliceBudget.h"
  #include "js/SliceBudget.h"
  #include "proxy/DeadObjectProxy.h"
  #include "proxy/DeadObjectProxy.h"
@@ -236,7 +236,7 @@ diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
  #endif
  #endif
  #include "vm/Debugger.h"
  #include "vm/Debugger.h"
  #include "vm/GeckoProfiler.h"
  #include "vm/GeckoProfiler.h"
-@@ -378,16 +379,27 @@ static const int IGC_MARK_SLICE_MULTIPLI
+@@ -381,16 +382,27 @@ static const int IGC_MARK_SLICE_MULTIPLI
  const AllocKind gc::slotsToThingKind[] = {
  const AllocKind gc::slotsToThingKind[] = {
      /*  0 */ AllocKind::OBJECT0,  AllocKind::OBJECT2,  AllocKind::OBJECT2,  AllocKind::OBJECT4,
      /*  0 */ AllocKind::OBJECT0,  AllocKind::OBJECT2,  AllocKind::OBJECT2,  AllocKind::OBJECT4,
      /*  4 */ AllocKind::OBJECT4,  AllocKind::OBJECT8,  AllocKind::OBJECT8,  AllocKind::OBJECT8,
      /*  4 */ AllocKind::OBJECT4,  AllocKind::OBJECT8,  AllocKind::OBJECT8,  AllocKind::OBJECT8,
@@ -264,7 +264,7 @@ diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
                    #sizedType " is smaller than SortedArenaList::MinThingSize!"); \
                    #sizedType " is smaller than SortedArenaList::MinThingSize!"); \
      static_assert(sizeof(sizedType) >= sizeof(FreeSpan), \
      static_assert(sizeof(sizedType) >= sizeof(FreeSpan), \
                    #sizedType " is smaller than FreeSpan"); \
                    #sizedType " is smaller than FreeSpan"); \
-@@ -2416,17 +2428,17 @@ RelocateArena(Arena* arena, SliceBudget&
+@@ -2419,17 +2431,17 @@ RelocateArena(Arena* arena, SliceBudget&
      for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
      for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
          RelocateCell(zone, i.getCell(), thingKind, thingSize);
          RelocateCell(zone, i.getCell(), thingKind, thingSize);
          sliceBudget.step();
          sliceBudget.step();
@@ -283,7 +283,7 @@ diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
  }
  }
  
  
  static inline bool
  static inline bool
-@@ -8482,18 +8494,18 @@ js::gc::AssertGCThingHasType(js::gc::Cel
+@@ -8485,18 +8497,18 @@ js::gc::AssertGCThingHasType(js::gc::Cel
      if (!cell) {
      if (!cell) {
          MOZ_ASSERT(kind == JS::TraceKind::Null);
          MOZ_ASSERT(kind == JS::TraceKind::Null);
          return;
          return;
@@ -403,7 +403,7 @@ diff --git a/js/src/gc/Marking-inl.h b/js/src/gc/Marking-inl.h
 diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
 diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
 --- a/js/src/gc/Marking.cpp
 --- a/js/src/gc/Marking.cpp
 +++ b/js/src/gc/Marking.cpp
 +++ b/js/src/gc/Marking.cpp
-@@ -2821,17 +2821,17 @@ js::gc::StoreBuffer::CellPtrEdge::trace(
+@@ -2827,17 +2827,17 @@ js::gc::StoreBuffer::CellPtrEdge::trace(
  #endif
  #endif
  
  
      // Bug 1376646: Make separate store buffers for strings and objects, and
      // Bug 1376646: Make separate store buffers for strings and objects, and

+ 33 - 0
frg/work-js/mozilla-release/patches/1480306-63a1.patch

@@ -0,0 +1,33 @@
+# HG changeset patch
+# User Jan-Ivar Bruaroey <jib@mozilla.com>
+# Date 1533177977 14400
+# Node ID 8f69423e522dc1e926b1d4d029945d6bf1ce36ab
+# Parent  a89f17d30427745d1755ad123babc2fbfde73a97
+Bug 1480306: Fix unused variable variable 'hasLineOfContext' in TokenStream.cpp. r=Waldo
+
+MozReview-Commit-ID: EK1IAvCZFwv
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -621,17 +621,18 @@ TokenStreamChars<Utf8Unit, AnyCharsAcces
+ 
+     do {
+         size_t offset = this->sourceUnits.offset();
+ 
+         ErrorMetadata err;
+ 
+         TokenStreamAnyChars& anyChars = anyCharsAccess();
+ 
+-        if (bool hasLineOfContext = anyChars.fillExcludingContext(&err, offset)) {
++        bool hasLineOfContext = anyChars.fillExcludingContext(&err, offset);
++        if (hasLineOfContext) {
+             if (!internalComputeLineOfContext(&err, offset))
+                 break;
+ 
+             // As this is an encoding error, the computed window-end must be
+             // identical to the location of the error -- any further on and the
+             // window would contain invalid Unicode.
+             MOZ_ASSERT_IF(err.lineOfContext != nullptr,
+                           err.lineLength == err.tokenOffset);
+

+ 352 - 0
frg/work-js/mozilla-release/patches/1480493-63a1.patch

@@ -0,0 +1,352 @@
+# HG changeset patch
+# User Matthew Gaudet <mgaudet@mozilla.com>
+# Date 1533686512 0
+# Node ID dacdc94c62badd03b7e2ff0399d50b2d29f8a6ea
+# Parent  d602a2f69ff89abe965c77ff945c143e8014feb8
+Bug 1480493 - Remove initializer kind from JSOP_NEWINIT r=arai
+
+Differential Revision: https://phabricator.services.mozilla.com/D2675
+
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -1526,26 +1526,26 @@ BytecodeEmitter::reportExtraWarning(cons
+ 
+     bool result = parser->errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);
+ 
+     va_end(args);
+     return result;
+ }
+ 
+ bool
+-BytecodeEmitter::emitNewInit(JSProtoKey key)
++BytecodeEmitter::emitNewInit()
+ {
+     const size_t len = 1 + UINT32_INDEX_LEN;
+     ptrdiff_t offset;
+     if (!emitCheck(len, &offset))
+         return false;
+ 
+     jsbytecode* code = this->code(offset);
+     code[0] = JSOP_NEWINIT;
+-    code[1] = jsbytecode(key);
++    code[1] = 0;
+     code[2] = 0;
+     code[3] = 0;
+     code[4] = 0;
+     checkTypeSet(JSOP_NEWINIT);
+     updateDepth(offset);
+     return true;
+ }
+ 
+@@ -3542,17 +3542,17 @@ BytecodeEmitter::emitDestructuringOpsObj
+         // Duplicate the value being destructured to use as a reference base.
+         if (!emitDupAt(emitted))                                  // ... *SET RHS *LREF RHS
+             return false;
+ 
+         if (member->isKind(ParseNodeKind::Spread)) {
+             if (!updateSourceCoordNotes(member->pn_pos.begin))
+                 return false;
+ 
+-            if (!emitNewInit(JSProto_Object))                     // ... *SET RHS *LREF RHS TARGET
++            if (!emitNewInit())                                   // ... *SET RHS *LREF RHS TARGET
+                 return false;
+             if (!emit1(JSOP_DUP))                                 // ... *SET RHS *LREF RHS TARGET TARGET
+                 return false;
+             if (!emit2(JSOP_PICK, 2))                             // ... *SET RHS *LREF TARGET TARGET RHS
+                 return false;
+ 
+             if (needsRestPropertyExcludedSet) {
+                 if (!emit2(JSOP_PICK, emitted + 4))               // ... RHS *LREF TARGET TARGET RHS SET
+@@ -3636,17 +3636,17 @@ BytecodeEmitter::emitDestructuringOpsObj
+ bool
+ BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern)
+ {
+     MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
+     MOZ_ASSERT(pattern->isArity(PN_LIST));
+     MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
+ 
+     ptrdiff_t offset = this->offset();
+-    if (!emitNewInit(JSProto_Object))
++    if (!emitNewInit())
+         return false;
+ 
+     // Try to construct the shape of the object as we go, so we can emit a
+     // JSOP_NEWOBJECT with the final shape instead.
+     // In the case of computed property names and indices, we cannot fix the
+     // shape at bytecode compile time. When the shape cannot be determined,
+     // |obj| is nulled out.
+ 
+@@ -7473,17 +7473,17 @@ BytecodeEmitter::emitObject(ParseNode* p
+         return emitSingletonInitialiser(pn);
+ 
+     /*
+      * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
+      * a new object and defining (in source order) each property on the object
+      * (or mutating the object's [[Prototype]], in the case of __proto__).
+      */
+     ptrdiff_t offset = this->offset();
+-    if (!emitNewInit(JSProto_Object))
++    if (!emitNewInit())
+         return false;
+ 
+     // Try to construct the shape of the object as we go, so we can emit a
+     // JSOP_NEWOBJECT with the final shape instead.
+     // In the case of computed property names and indices, we cannot fix the
+     // shape at bytecode compile time. When the shape cannot be determined,
+     // |obj| is nulled out.
+ 
+@@ -8173,17 +8173,17 @@ BytecodeEmitter::emitClass(ParseNode* pn
+         if (!ifThenElse.emitEnd())
+             return false;
+ 
+         if (!emit1(JSOP_OBJWITHPROTO))                          // ... HERITAGE HOMEOBJ
+             return false;
+         if (!emit1(JSOP_SWAP))                                  // ... HOMEOBJ HERITAGE
+             return false;
+     } else {
+-        if (!emitNewInit(JSProto_Object))                       // ... HOMEOBJ
++        if (!emitNewInit())                                     // ... HOMEOBJ
+             return false;
+     }
+ 
+     // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
+     // is not used, an implicit value of %FunctionPrototype% is implied.
+ 
+     if (constructor) {
+         if (!emitFunction(constructor, !!heritageExpression))   // ... HOMEOBJ CONSTRUCTOR
+diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
+--- a/js/src/frontend/BytecodeEmitter.h
++++ b/js/src/frontend/BytecodeEmitter.h
+@@ -633,17 +633,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitTDZCheckIfNeeded(JSAtom* name, const NameLocation& loc);
+ 
+     MOZ_MUST_USE bool emitNameIncDec(ParseNode* pn);
+ 
+     MOZ_MUST_USE bool emitDeclarationList(ParseNode* decls);
+     MOZ_MUST_USE bool emitSingleDeclaration(ParseNode* decls, ParseNode* decl,
+                                             ParseNode* initializer);
+ 
+-    MOZ_MUST_USE bool emitNewInit(JSProtoKey key);
++    MOZ_MUST_USE bool emitNewInit();
+     MOZ_MUST_USE bool emitSingletonInitialiser(ParseNode* pn);
+ 
+     MOZ_MUST_USE bool emitPrepareIteratorResult();
+     MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
+     MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
+ 
+     MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
+         return emitGetDotGeneratorInScope(*innermostEmitterScope());
+diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp
+--- a/js/src/jit/BaselineCompiler.cpp
++++ b/js/src/jit/BaselineCompiler.cpp
+@@ -2162,36 +2162,20 @@ BaselineCompiler::emit_JSOP_NEWOBJECT()
+     frame.push(R0);
+     return true;
+ }
+ 
+ bool
+ BaselineCompiler::emit_JSOP_NEWINIT()
+ {
+     frame.syncStack(0);
+-    JSProtoKey key = JSProtoKey(GET_UINT8(pc));
+-
+-    if (key == JSProto_Array) {
+-        // Pass length in R0.
+-        masm.move32(Imm32(0), R0.scratchReg());
+-
+-        ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
+-        if (!group)
+-            return false;
+-
+-        ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::Baseline);
+-        if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
+-            return false;
+-    } else {
+-        MOZ_ASSERT(key == JSProto_Object);
+-
+-        ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline);
+-        if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
+-            return false;
+-    }
++
++    ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline);
++    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
++        return false;
+ 
+     frame.push(R0);
+     return true;
+ }
+ 
+ bool
+ BaselineCompiler::emit_JSOP_INITELEM()
+ {
+diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
+--- a/js/src/jit/CodeGenerator.cpp
++++ b/js/src/jit/CodeGenerator.cpp
+@@ -2875,29 +2875,20 @@ CodeGenerator::visitNullarySharedStub(LN
+                    "the bytecode emitter must fail to compile code that would "
+                    "produce JSOP_NEWARRAY with a length exceeding int32_t range");
+ 
+         // Pass length in R0.
+         masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
+         emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
+         break;
+       }
++      case JSOP_NEWINIT:
+       case JSOP_NEWOBJECT:
+         emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
+         break;
+-      case JSOP_NEWINIT: {
+-        JSProtoKey key = JSProtoKey(GET_UINT8(pc));
+-        if (key == JSProto_Array) {
+-            masm.move32(Imm32(0), R0.scratchReg());
+-            emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
+-        } else {
+-            emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
+-        }
+-        break;
+-      }
+       default:
+         MOZ_CRASH("Unsupported jsop in shared stubs.");
+     }
+ }
+ 
+ typedef JSFunction* (*MakeDefaultConstructorFn)(JSContext*, HandleScript,
+                                                 jsbytecode*, HandleObject);
+ static const VMFunction MakeDefaultConstructorInfo =
+diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
+--- a/js/src/jit/IonBuilder.cpp
++++ b/js/src/jit/IonBuilder.cpp
+@@ -2007,27 +2007,23 @@ IonBuilder::inspectOpcode(JSOp op)
+         for (uint32_t i = 0, n = GET_UINT16(pc); i < n; i++)
+             current->pop();
+         return Ok();
+ 
+       case JSOP_DUPAT:
+         current->pushSlot(current->stackDepth() - 1 - GET_UINT24(pc));
+         return Ok();
+ 
+-      case JSOP_NEWINIT:
+-        if (GET_UINT8(pc) == JSProto_Array)
+-            return jsop_newarray(0);
+-        return jsop_newobject();
+-
+       case JSOP_NEWARRAY:
+         return jsop_newarray(GET_UINT32(pc));
+ 
+       case JSOP_NEWARRAY_COPYONWRITE:
+         return jsop_newarray_copyonwrite();
+ 
++      case JSOP_NEWINIT:
+       case JSOP_NEWOBJECT:
+         return jsop_newobject();
+ 
+       case JSOP_INITELEM:
+       case JSOP_INITHIDDENELEM:
+         return jsop_initelem();
+ 
+       case JSOP_INITELEM_INC:
+diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
+--- a/js/src/vm/Interpreter.cpp
++++ b/js/src/vm/Interpreter.cpp
+@@ -3901,24 +3901,17 @@ CASE(JSOP_INITHIDDENELEM_SETTER)
+ END_CASE(JSOP_INITELEM_GETTER)
+ 
+ CASE(JSOP_HOLE)
+     PUSH_MAGIC(JS_ELEMENTS_HOLE);
+ END_CASE(JSOP_HOLE)
+ 
+ CASE(JSOP_NEWINIT)
+ {
+-    uint8_t i = GET_UINT8(REGS.pc);
+-    MOZ_ASSERT(i == JSProto_Array || i == JSProto_Object);
+-
+-    JSObject* obj;
+-    if (i == JSProto_Array)
+-        obj = NewArrayOperation(cx, script, REGS.pc, 0);
+-    else
+-        obj = NewObjectOperation(cx, script, REGS.pc);
++    JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
+ 
+     if (!obj)
+         goto error;
+     PUSH_OBJECT(*obj);
+ }
+ END_CASE(JSOP_NEWINIT)
+ 
+ CASE(JSOP_NEWARRAY)
+@@ -5156,18 +5149,23 @@ js::NewObjectOperation(JSContext* cx, Ha
+         if (!group)
+             return nullptr;
+ 
+         bool isUnboxed;
+         {
+             AutoSweepObjectGroup sweep(group);
+             if (group->maybePreliminaryObjects(sweep)) {
+                 group->maybePreliminaryObjects(sweep)->maybeAnalyze(cx, group);
+-                if (group->maybeUnboxedLayout(sweep))
++                if (group->maybeUnboxedLayout(sweep)) {
++                    // This sets the allocation site so that the template object
++                    // can be read back but if op is NEWINIT, then the template
++                    // is null. 
++                    MOZ_ASSERT(JSOp(*pc) != JSOP_NEWINIT);
+                     group->maybeUnboxedLayout(sweep)->setAllocationSite(script, pc);
++                }
+             }
+ 
+             if (group->shouldPreTenure(sweep) || group->maybePreliminaryObjects(sweep))
+                 newKind = TenuredObject;
+             isUnboxed = group->maybeUnboxedLayout(sweep);
+         }
+         if (isUnboxed)
+             return UnboxedPlainObject::create(cx, group, newKind);
+@@ -5175,17 +5173,16 @@ js::NewObjectOperation(JSContext* cx, Ha
+ 
+     RootedPlainObject obj(cx);
+ 
+     if (*pc == JSOP_NEWOBJECT) {
+         RootedPlainObject baseObject(cx, &script->getObject(pc)->as<PlainObject>());
+         obj = CopyInitializerObject(cx, baseObject, newKind);
+     } else {
+         MOZ_ASSERT(*pc == JSOP_NEWINIT);
+-        MOZ_ASSERT(GET_UINT8(pc) == JSProto_Object);
+         obj = NewBuiltinClassInstance<PlainObject>(cx, newKind);
+     }
+ 
+     if (!obj)
+         return nullptr;
+ 
+     if (newKind == SingletonObject) {
+         if (!JSObject::setSingleton(cx, obj))
+diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
+--- a/js/src/vm/Opcodes.h
++++ b/js/src/vm/Opcodes.h
+@@ -835,24 +835,21 @@ 1234567890123456789012345678901234567890
+      *   Stack: => val
+      */ \
+     macro(JSOP_UINT16,    88, "uint16",     NULL,         3,  0,  1,  JOF_UINT16) \
+     \
+     /* Object and array literal support. */ \
+     /*
+      * Pushes newly created object onto the stack.
+      *
+-     * This opcode takes the kind of initializer (JSProto_Array or
+-     * JSProto_Object).
+-     *
+-     * This opcode has three extra bytes so it can be exchanged with
++     * This opcode has four extra bytes so it can be exchanged with
+      * JSOP_NEWOBJECT during emit.
+      *   Category: Literals
+      *   Type: Object
+-     *   Operands: uint8_t kind (, uint24_t extra)
++     *   Operands: (uint32_t extra)
+      *   Stack: => obj
+      */ \
+     macro(JSOP_NEWINIT,   89, "newinit",    NULL,         5,  0,  1, JOF_UINT8) \
+     /*
+      * Pushes newly created array onto the stack.
+      *
+      * This opcode takes the final length, which is preallocated.
+      *   Category: Literals
+

+ 216 - 0
frg/work-js/mozilla-release/patches/1481248-63a1.patch

@@ -0,0 +1,216 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1533570223 25200
+# Node ID df05fdfe1af8936b52613cd05b81948846a9bad6
+# Parent  b20289e446893be662123b91104e35646408a578
+Bug 1481248: Use strict instead of sloppy equals for 'throw' method check in yield*. r=arai
+
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -6065,21 +6065,23 @@ BytecodeEmitter::emitAwaitInScope(Emitte
+ }
+ 
+ bool
+ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ {
+     MOZ_ASSERT(sc->isFunctionBox());
+     MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
+ 
+-    bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
++    IteratorKind iterKind = sc->asFunctionBox()->isAsync()
++                            ? IteratorKind::Async
++                            : IteratorKind::Sync;
+ 
+     if (!emitTree(iter))                                  // ITERABLE
+         return false;
+-    if (isAsyncGenerator) {
++    if (iterKind == IteratorKind::Async) {
+         if (!emitAsyncIterator())                         // NEXT ITER
+             return false;
+     } else {
+         if (!emitIterator())                              // NEXT ITER
+             return false;
+     }
+ 
+     // Initial send value is undefined.
+@@ -6097,77 +6099,62 @@ BytecodeEmitter::emitYieldStar(ParseNode
+ 
+     JumpTarget tryStart{ offset() };
+     if (!tryCatch.emitTry())                              // NEXT ITER RESULT
+         return false;
+ 
+     MOZ_ASSERT(this->stackDepth == startDepth);
+ 
+     // 11.4.3.7 AsyncGeneratorYield step 5.
+-    if (isAsyncGenerator) {
++    if (iterKind == IteratorKind::Async) {
+         if (!emitAwaitInInnermostScope())                 // NEXT ITER RESULT
+             return false;
+     }
+ 
+     // Load the generator object.
+     if (!emitGetDotGeneratorInInnermostScope())           // NEXT ITER RESULT GENOBJ
+         return false;
+ 
+     // Yield RESULT as-is, without re-boxing.
+     if (!emitYieldOp(JSOP_YIELD))                         // NEXT ITER RECEIVED
+         return false;
+ 
+     if (!tryCatch.emitCatch())                            // NEXT ITER RESULT
+         return false;
+ 
+-    stackDepth = startDepth;                              // NEXT ITER RESULT
++    MOZ_ASSERT(stackDepth == startDepth);
++
+     if (!emit1(JSOP_EXCEPTION))                           // NEXT ITER RESULT EXCEPTION
+         return false;
+     if (!emitDupAt(2))                                    // NEXT ITER RESULT EXCEPTION ITER
+         return false;
+     if (!emit1(JSOP_DUP))                                 // NEXT ITER RESULT EXCEPTION ITER ITER
+         return false;
+     if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP))   // NEXT ITER RESULT EXCEPTION ITER THROW
+         return false;
+-    if (!emit1(JSOP_DUP))                                 // NEXT ITER RESULT EXCEPTION ITER THROW THROW
+-        return false;
+-    if (!emit1(JSOP_UNDEFINED))                           // NEXT ITER RESULT EXCEPTION ITER THROW THROW UNDEFINED
+-        return false;
+-    if (!emit1(JSOP_EQ))                                  // NEXT ITER RESULT EXCEPTION ITER THROW ?EQL
+-        return false;
+-
+-    InternalIfEmitter ifThrowMethodIsNotDefined(this);
+-    if (!ifThrowMethodIsNotDefined.emitThen())            // NEXT ITER RESULT EXCEPTION ITER THROW
+-        return false;
++
+     savedDepthTemp = stackDepth;
+-    if (!emit1(JSOP_POP))                                 // NEXT ITER RESULT EXCEPTION ITER
+-        return false;
+-    // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
+-    //
+-    // If the iterator does not have a "throw" method, it calls IteratorClose
+-    // and then throws a TypeError.
+-    IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
+-    if (!emitIteratorCloseInInnermostScope(iterKind))     // NEXT ITER RESULT EXCEPTION
+-        return false;
+-    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
+-        return false;
+-    stackDepth = savedDepthTemp;
+-    if (!ifThrowMethodIsNotDefined.emitEnd())             // NEXT ITER OLDRESULT EXCEPTION ITER THROW
+-        return false;
++    InternalIfEmitter ifThrowMethodIsNotDefined(this);
++    if (!emitPushNotUndefinedOrNull())                    // NEXT ITER RESULT EXCEPTION ITER THROW NOT-UNDEF-OR-NULL
++        return false;
++
++    if (!ifThrowMethodIsNotDefined.emitThenElse())        // NEXT ITER RESULT EXCEPTION ITER THROW
++        return false;
++
+     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
+     // RESULT = ITER.throw(EXCEPTION)                     // NEXT ITER OLDRESULT EXCEPTION ITER THROW
+     if (!emit1(JSOP_SWAP))                                // NEXT ITER OLDRESULT EXCEPTION THROW ITER
+         return false;
+     if (!emit2(JSOP_PICK, 2))                             // NEXT ITER OLDRESULT THROW ITER EXCEPTION
+         return false;
+     if (!emitCall(JSOP_CALL, 1, iter))                    // NEXT ITER OLDRESULT RESULT
+         return false;
+     checkTypeSet(JSOP_CALL);
+ 
+-    if (isAsyncGenerator) {
++    if (iterKind == IteratorKind::Async) {
+         if (!emitAwaitInInnermostScope())                 // NEXT ITER OLDRESULT RESULT
+             return false;
+     }
+ 
+     if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // NEXT ITER OLDRESULT RESULT
+         return false;
+     if (!emit1(JSOP_SWAP))                                // NEXT ITER RESULT OLDRESULT
+         return false;
+@@ -6177,16 +6164,36 @@ BytecodeEmitter::emitYieldStar(ParseNode
+     JumpList checkResult;
+     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.ii.
+     //
+     // Note that there is no GOSUB to the finally block here. If the iterator has a
+     // "throw" method, it does not perform IteratorClose.
+     if (!emitJump(JSOP_GOTO, &checkResult))               // goto checkResult
+         return false;
+ 
++    stackDepth = savedDepthTemp;
++    if (!ifThrowMethodIsNotDefined.emitElse())            // NEXT ITER RESULT EXCEPTION ITER THROW
++        return false;
++
++    if (!emit1(JSOP_POP))                                 // NEXT ITER RESULT EXCEPTION ITER
++        return false;
++    // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
++    //
++    // If the iterator does not have a "throw" method, it calls IteratorClose
++    // and then throws a TypeError.
++    if (!emitIteratorCloseInInnermostScope(iterKind))     // NEXT ITER RESULT EXCEPTION
++        return false;
++    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
++        return false;
++
++    stackDepth = savedDepthTemp;
++    if (!ifThrowMethodIsNotDefined.emitEnd())
++        return false;
++
++    stackDepth = startDepth;
+     if (!tryCatch.emitFinally())
+          return false;
+ 
+     // ES 14.4.13, yield * AssignmentExpression, step 5.c
+     //
+     // Call iterator.return() for receiving a "forced return" completion from
+     // the generator.
+ 
+@@ -6298,17 +6305,17 @@ BytecodeEmitter::emitYieldStar(ParseNode
+     if (!emit1(JSOP_DUP2))                                       // RECEIVED NEXT ITER NEXT ITER
+         return false;
+     if (!emit2(JSOP_PICK, 4))                                    // NEXT ITER NEXT ITER RECEIVED
+         return false;
+     if (!emitCall(JSOP_CALL, 1, iter))                           // NEXT ITER RESULT
+         return false;
+     checkTypeSet(JSOP_CALL);
+ 
+-    if (isAsyncGenerator) {
++    if (iterKind == IteratorKind::Async) {
+         if (!emitAwaitInInnermostScope())                        // NEXT ITER RESULT RESULT
+             return false;
+     }
+ 
+     if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext))        // NEXT ITER RESULT
+         return false;
+     MOZ_ASSERT(this->stackDepth == startDepth);
+ 
+diff --git a/js/src/tests/non262/generators/yield-star-throw-htmldda.js b/js/src/tests/non262/generators/yield-star-throw-htmldda.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/tests/non262/generators/yield-star-throw-htmldda.js
+@@ -0,0 +1,28 @@
++function* g(iter) {
++    yield* iter;
++}
++
++var calledReturn = false;
++
++var it = g({
++    [Symbol.iterator]() {
++        return this;
++    },
++    next() {
++        return {done: false};
++    },
++    throw: createIsHTMLDDA(),
++    return() {
++        calledReturn = true;
++        return {done: false};
++    }
++});
++
++it.next();
++
++assertThrowsInstanceOf(() => it.throw(""), TypeError);
++
++assertEq(calledReturn, false);
++
++if (typeof reportCompare === "function")
++    reportCompare(0, 0);
+

+ 486 - 0
frg/work-js/mozilla-release/patches/1483275-1-63a1.patch

@@ -0,0 +1,486 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1521060914 14400
+# Node ID cf5e7017ffdc1ebc32f564f95de1ca91bf7a5795
+# Parent  bee7df40babdbe30ecf77afca9f18f879bf9dc26
+Bug 1483275 - Fix some SpiderMonkey unified-build conflicts. r=waldo
+
+MozReview-Commit-ID: CqFbs7149CZ
+
+diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
+--- a/js/src/frontend/TokenStream.cpp
++++ b/js/src/frontend/TokenStream.cpp
+@@ -121,17 +121,17 @@ FindReservedWord(JSLinearString* str)
+     JS::AutoCheckCannotGC nogc;
+     return str->hasLatin1Chars()
+            ? FindReservedWord(str->latin1Chars(nogc), str->length())
+            : FindReservedWord(str->twoByteChars(nogc), str->length());
+ }
+ 
+ template <typename CharT>
+ static bool
+-IsIdentifier(const CharT* chars, size_t length)
++IsIdentifierImpl(const CharT* chars, size_t length)
+ {
+     using namespace js;
+ 
+     if (length == 0)
+         return false;
+ 
+     if (!unicode::IsIdentifierStart(char16_t(*chars)))
+         return false;
+@@ -165,17 +165,17 @@ GetSingleCodePoint(const char16_t** p, c
+     return codePoint;
+ }
+ 
+ static bool
+ IsIdentifierMaybeNonBMP(const char16_t* chars, size_t length)
+ {
+     using namespace js;
+ 
+-    if (IsIdentifier(chars, length))
++    if (IsIdentifierImpl(chars, length))
+         return true;
+ 
+     if (length == 0)
+         return false;
+ 
+     const char16_t* p = chars;
+     const char16_t* end = chars + length;
+     uint32_t codePoint;
+@@ -198,30 +198,30 @@ namespace js {
+ namespace frontend {
+ 
+ bool
+ IsIdentifier(JSLinearString* str)
+ {
+     JS::AutoCheckCannotGC nogc;
+     MOZ_ASSERT(str);
+     if (str->hasLatin1Chars())
+-        return ::IsIdentifier(str->latin1Chars(nogc), str->length());
++        return ::IsIdentifierImpl(str->latin1Chars(nogc), str->length());
+     return ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
+ }
+ 
+ bool
+ IsIdentifier(const char* chars, size_t length)
+ {
+-    return ::IsIdentifier(chars, length);
++    return ::IsIdentifierImpl(chars, length);
+ }
+ 
+ bool
+ IsIdentifier(const char16_t* chars, size_t length)
+ {
+-    return ::IsIdentifier(chars, length);
++    return ::IsIdentifierImpl(chars, length);
+ }
+ 
+ bool
+ IsKeyword(JSLinearString* str)
+ {
+     if (const ReservedWordInfo* rw = FindReservedWord(str))
+         return TokenKindIsKeyword(rw->tokentype);
+ 
+diff --git a/js/src/irregexp/RegExpInterpreter.cpp b/js/src/irregexp/RegExpInterpreter.cpp
+--- a/js/src/irregexp/RegExpInterpreter.cpp
++++ b/js/src/irregexp/RegExpInterpreter.cpp
+@@ -494,15 +494,17 @@ irregexp::InterpretCode(JSContext* cx, c
+             break;
+           }
+           default:
+             MOZ_CRASH("Bad bytecode");
+         }
+     }
+ }
+ 
++#undef BYTECODE
++
+ template RegExpRunStatus
+ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const Latin1Char* chars, size_t current,
+                         size_t length, MatchPairs* matches, size_t* endIndex);
+ 
+ template RegExpRunStatus
+ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const char16_t* chars, size_t current,
+                         size_t length, MatchPairs* matches, size_t* endIndex);
+diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp
+--- a/js/src/jit/BaselineCacheIRCompiler.cpp
++++ b/js/src/jit/BaselineCacheIRCompiler.cpp
+@@ -447,17 +447,17 @@ BaselineCacheIRCompiler::emitGuardXrayEx
+     if (hasExpando) {
+         masm.branchTestObject(Assembler::NotEqual, holderAddress, failure->label());
+         masm.unboxObject(holderAddress, scratch);
+         masm.branchTestObject(Assembler::NotEqual, expandoAddress, failure->label());
+         masm.unboxObject(expandoAddress, scratch);
+ 
+         // Unwrap the expando before checking its shape.
+         masm.loadPtr(Address(scratch, ProxyObject::offsetOfReservedSlots()), scratch);
+-        masm.unboxObject(Address(scratch, detail::ProxyReservedSlots::offsetOfPrivateSlot()), scratch);
++        masm.unboxObject(Address(scratch, js::detail::ProxyReservedSlots::offsetOfPrivateSlot()), scratch);
+ 
+         masm.loadPtr(shapeWrapperAddress, scratch2.ref());
+         LoadShapeWrapperContents(masm, scratch2.ref(), scratch2.ref(), failure->label());
+         masm.branchTestObjShape(Assembler::NotEqual, scratch, *scratch2, *scratch3, scratch,
+                                 failure->label());
+ 
+         // The reserved slots on the expando should all be in fixed slots.
+         Address protoAddress(scratch, NativeObject::getFixedSlotOffset(GetXrayJitInfo()->expandoProtoSlot));
+@@ -2039,17 +2039,17 @@ BaselineCacheIRCompiler::emitLoadDOMExpa
+     AutoScratchRegister scratch(allocator, masm);
+     ValueOperand output = allocator.defineValueRegister(masm, reader.valOperandId());
+ 
+     FailurePath* failure;
+     if (!addFailurePath(&failure))
+         return false;
+ 
+     masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), scratch);
+-    Address expandoAddr(scratch, detail::ProxyReservedSlots::offsetOfPrivateSlot());
++    Address expandoAddr(scratch, js::detail::ProxyReservedSlots::offsetOfPrivateSlot());
+ 
+     // Load the ExpandoAndGeneration* in the output scratch register and guard
+     // it matches the proxy's ExpandoAndGeneration.
+     masm.loadPtr(expandoAndGenerationAddr, output.scratchReg());
+     masm.branchPrivatePtr(Assembler::NotEqual, expandoAddr, output.scratchReg(), failure->label());
+ 
+     // Guard expandoAndGeneration->generation matches the expected generation.
+     masm.branch64(Assembler::NotEqual,
+diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
+--- a/js/src/vm/ArrayBufferObject.cpp
++++ b/js/src/vm/ArrayBufferObject.cpp
+@@ -270,45 +270,45 @@ static const ClassOps ArrayBufferObjectC
+     nullptr,        /* mayResolve */
+     ArrayBufferObject::finalize,
+     nullptr,        /* call        */
+     nullptr,        /* hasInstance */
+     nullptr,        /* construct   */
+     ArrayBufferObject::trace,
+ };
+ 
+-static const JSFunctionSpec static_functions[] = {
++static const JSFunctionSpec arraybuffer_functions[] = {
+     JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
+     JS_FS_END
+ };
+ 
+-static const JSPropertySpec static_properties[] = {
++static const JSPropertySpec arraybuffer_properties[] = {
+     JS_SELF_HOSTED_SYM_GET(species, "ArrayBufferSpecies", 0),
+     JS_PS_END
+ };
+ 
+ 
+-static const JSFunctionSpec prototype_functions[] = {
++static const JSFunctionSpec arraybuffer_proto_functions[] = {
+     JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
+     JS_FS_END
+ };
+ 
+-static const JSPropertySpec prototype_properties[] = {
++static const JSPropertySpec arraybuffer_proto_properties[] = {
+     JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
+     JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
+     JS_PS_END
+ };
+ 
+ static const ClassSpec ArrayBufferObjectClassSpec = {
+     GenericCreateConstructor<ArrayBufferObject::class_constructor, 1, gc::AllocKind::FUNCTION>,
+     CreateArrayBufferPrototype,
+-    static_functions,
+-    static_properties,
+-    prototype_functions,
+-    prototype_properties
++    arraybuffer_functions,
++    arraybuffer_properties,
++    arraybuffer_proto_functions,
++    arraybuffer_proto_properties
+ };
+ 
+ static const ClassExtension ArrayBufferObjectClassExtension = {
+     nullptr,    /* weakmapKeyDelegateOp */
+     ArrayBufferObject::objectMoved
+ };
+ 
+ const Class ArrayBufferObject::class_ = {
+diff --git a/js/src/vm/ErrorReporting.cpp b/js/src/vm/ErrorReporting.cpp
+--- a/js/src/vm/ErrorReporting.cpp
++++ b/js/src/vm/ErrorReporting.cpp
+@@ -50,16 +50,23 @@ js::CompileError::throwError(JSContext* 
+     // compilation errors.  The exception will remain pending, and so long
+     // as the non-top-level "load", "eval", or "compile" native function
+     // returns false, the top-level reporter will eventually receive the
+     // uncaught exception report.
+     ErrorToException(cx, this, nullptr, nullptr);
+ }
+ 
+ bool
++js::ReportExceptionClosure::operator()(JSContext* cx)
++{
++    cx->setPendingException(exn_);
++    return false;
++}
++
++bool
+ js::ReportCompileWarning(JSContext* cx, ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
+                          unsigned flags, unsigned errorNumber, va_list args)
+ {
+     // On the main thread, report the error immediately. When compiling off
+     // thread, save the error so that the thread finishing the parse can report
+     // it later.
+     CompileError tempErr;
+     CompileError* err = &tempErr;
+@@ -121,42 +128,21 @@ js::ReportCompileError(JSContext* cx, Er
+     }
+ 
+     if (!cx->helperThread())
+         err->throwError(cx);
+ }
+ 
+ namespace {
+ 
+-class MOZ_STACK_CLASS ReportExceptionClosure
+-  : public js::ScriptEnvironmentPreparer::Closure
+-{
+-  public:
+-    explicit ReportExceptionClosure(HandleValue& exn)
+-      : exn_(exn)
+-    {
+-    }
+-
+-    bool operator()(JSContext* cx) override
+-    {
+-        cx->setPendingException(exn_);
+-        return false;
+-    }
+-
+-  private:
+-    HandleValue& exn_;
+-};
+-
+-} // anonymous namespace
+-
+ void
+ js::ReportErrorToGlobal(JSContext* cx, HandleObject global, HandleValue error)
+ {
+     MOZ_ASSERT(!cx->isExceptionPending());
+ #ifdef DEBUG
+     // No assertSameCompartment version that doesn't take JSContext...
+     if (error.isObject()) {
+         AssertSameCompartment(global, &error.toObject());
+     }
+ #endif // DEBUG
+-    ReportExceptionClosure report(error);
++    js::ReportExceptionClosure report(error);
+     PrepareScriptEnvironmentAndInvoke(cx, global, report);
+ }
+diff --git a/js/src/vm/ErrorReporting.h b/js/src/vm/ErrorReporting.h
+--- a/js/src/vm/ErrorReporting.h
++++ b/js/src/vm/ErrorReporting.h
+@@ -7,16 +7,17 @@
+ #ifndef vm_ErrorReporting_h
+ #define vm_ErrorReporting_h
+ 
+ #include "mozilla/Move.h"
+ 
+ #include <stdarg.h>
+ 
+ #include "jsapi.h" // for JSErrorNotes, JSErrorReport
++#include "jsfriendapi.h" // for ScriptEnvironmentPreparer
+ 
+ #include "js/UniquePtr.h" // for UniquePtr
+ #include "js/Utility.h" // for UniqueTwoByteChars
+ 
+ namespace js {
+ 
+ /**
+  * Metadata for a compilation error (or warning) at a particular offset, or at
+@@ -63,16 +64,28 @@ struct ErrorMetadata
+ };
+ 
+ class CompileError : public JSErrorReport
+ {
+   public:
+     void throwError(JSContext* cx);
+ };
+ 
++class MOZ_STACK_CLASS ReportExceptionClosure final
++  : public ScriptEnvironmentPreparer::Closure
++{
++    JS::HandleValue exn_;
++
++  public:
++    explicit ReportExceptionClosure(JS::HandleValue exn)
++      : exn_(exn) { }
++
++    bool operator()(JSContext* cx) override;
++};
++
+ /** Send a JSErrorReport to the warningReporter callback. */
+ extern void
+ CallWarningReporter(JSContext* cx, JSErrorReport* report);
+ 
+ /**
+  * Report a compile error during script processing prior to execution of the
+  * script.
+  */
+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
+@@ -1047,36 +1047,16 @@ InternalEnqueuePromiseJobCallback(JSCont
+     MOZ_ASSERT(job);
+     if (!cx->jobQueue->append(job)) {
+         ReportOutOfMemory(cx);
+         return false;
+     }
+     return true;
+ }
+ 
+-namespace {
+-class MOZ_STACK_CLASS ReportExceptionClosure : public ScriptEnvironmentPreparer::Closure
+-{
+-  public:
+-    explicit ReportExceptionClosure(HandleValue exn)
+-        : exn_(exn)
+-    {
+-    }
+-
+-    bool operator()(JSContext* cx) override
+-    {
+-        cx->setPendingException(exn_);
+-        return false;
+-    }
+-
+-  private:
+-    HandleValue exn_;
+-};
+-} // anonymous namespace
+-
+ JS_FRIEND_API(bool)
+ js::UseInternalJobQueues(JSContext* cx)
+ {
+     // Internal job queue handling must be set up very early. Self-hosting
+     // initialization is as good a marker for that as any.
+     MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
+                        "js::UseInternalJobQueues must be called early during runtime startup.");
+     MOZ_ASSERT(!cx->jobQueue);
+@@ -1162,17 +1142,17 @@ js::RunJobs(JSContext* cx)
+                     RootedValue exn(cx);
+                     if (cx->getPendingException(&exn)) {
+                         /*
+                          * Clear the exception, because
+                          * PrepareScriptEnvironmentAndInvoke will assert that we don't
+                          * have one.
+                          */
+                         cx->clearPendingException();
+-                        ReportExceptionClosure reportExn(exn);
++                        js::ReportExceptionClosure reportExn(exn);
+                         PrepareScriptEnvironmentAndInvoke(cx, cx->global(), reportExn);
+                     }
+                 }
+             }
+         }
+ 
+         cx->drainingJobQueue = false;
+ 
+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
+@@ -319,23 +319,23 @@ RegExpObject::initIgnoringLastIndex(JSAt
+ void
+ RegExpObject::initAndZeroLastIndex(JSAtom* source, RegExpFlag flags, JSContext* cx)
+ {
+     initIgnoringLastIndex(source, flags);
+     zeroLastIndex(cx);
+ }
+ 
+ static MOZ_ALWAYS_INLINE bool
+-IsLineTerminator(const JS::Latin1Char c)
++IsRegExpLineTerminator(const JS::Latin1Char c)
+ {
+     return c == '\n' || c == '\r';
+ }
+ 
+ static MOZ_ALWAYS_INLINE bool
+-IsLineTerminator(const char16_t c)
++IsRegExpLineTerminator(const char16_t c)
+ {
+     return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
+ }
+ 
+ static MOZ_ALWAYS_INLINE bool
+ AppendEscapedLineTerminator(StringBuffer& sb, const JS::Latin1Char c)
+ {
+     switch (c) {
+@@ -417,17 +417,17 @@ EscapeRegExpPattern(StringBuffer& sb, co
+                 }
+                 if (!sb.append('\\'))
+                     return false;
+             } else if (ch == '[') {
+                 inBrackets = true;
+             }
+         }
+ 
+-        if (IsLineTerminator(ch)) {
++        if (IsRegExpLineTerminator(ch)) {
+             // There's LineTerminator that needs escaping.
+             if (sb.empty()) {
+                 // This is the first char we've seen that needs escaping,
+                 // copy everything up to this point.
+                 if (!SetupBuffer(sb, oldChars, oldLen, it))
+                     return false;
+             }
+             if (!previousCharacterWasBackslash) {
+diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp
+--- a/js/src/vm/SharedArrayObject.cpp
++++ b/js/src/vm/SharedArrayObject.cpp
+@@ -388,43 +388,43 @@ static const ClassOps SharedArrayBufferO
+     nullptr, /* mayResolve */
+     SharedArrayBufferObject::Finalize,
+     nullptr, /* call */
+     nullptr, /* hasInstance */
+     nullptr, /* construct */
+     nullptr, /* trace */
+ };
+ 
+-static const JSFunctionSpec static_functions[] = {
++static const JSFunctionSpec sharedarrray_functions[] = {
+     JS_FS_END
+ };
+ 
+-static const JSPropertySpec static_properties[] = {
++static const JSPropertySpec sharedarrray_properties[] = {
+     JS_SELF_HOSTED_SYM_GET(species, "SharedArrayBufferSpecies", 0),
+     JS_PS_END
+ };
+ 
+-static const JSFunctionSpec prototype_functions[] = {
++static const JSFunctionSpec sharedarray_proto_functions[] = {
+     JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0),
+     JS_FS_END
+ };
+ 
+-static const JSPropertySpec prototype_properties[] = {
++static const JSPropertySpec sharedarray_proto_properties[] = {
+     JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0),
+     JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY),
+     JS_PS_END
+ };
+ 
+ static const ClassSpec SharedArrayBufferObjectClassSpec = {
+     GenericCreateConstructor<SharedArrayBufferObject::class_constructor, 1, gc::AllocKind::FUNCTION>,
+     CreateSharedArrayBufferPrototype,
+-    static_functions,
+-    static_properties,
+-    prototype_functions,
+-    prototype_properties
++    sharedarrray_functions,
++    sharedarrray_properties,
++    sharedarray_proto_functions,
++    sharedarray_proto_properties
+ };
+ 
+ const Class SharedArrayBufferObject::class_ = {
+     "SharedArrayBuffer",
+     JSCLASS_DELAY_METADATA_BUILDER |
+     JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
+     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer) |
+     JSCLASS_BACKGROUND_FINALIZE,

+ 449 - 0
frg/work-js/mozilla-release/patches/1484389-63a1.patch

@@ -0,0 +1,449 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1534776344 25200
+# Node ID 8e8b440d0128d4bb43445603137cb7575ede027b
+# Parent  356a3cbe6aa29c0449653e4fcc562a53825ec836
+Bug 1484389 - Move various SavedFrame-related functions and data types into js/public/SavedFrameAPI.h so that users aren't forced to depend on jsapi.h or jsfriendapi.h for them.  r=jandem
+
+diff --git a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp b/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp
+--- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp
++++ b/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp
+@@ -3,16 +3,17 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ // Test that the `JS::ubi::StackFrame`s we create from
+ // `mozilla::devtools::DeserializedStackFrame` instances look and behave as we would
+ // like.
+ 
+ #include "DevTools.h"
++#include "js/SavedFrameAPI.h"
+ #include "js/TypeDecls.h"
+ #include "mozilla/devtools/DeserializedNode.h"
+ 
+ using testing::Field;
+ using testing::ReturnRef;
+ 
+ // A mock DeserializedStackFrame for testing.
+ struct MockDeserializedStackFrame : public DeserializedStackFrame
+diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp
+--- a/dom/base/ChromeUtils.cpp
++++ b/dom/base/ChromeUtils.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "ChromeUtils.h"
+ 
++#include "js/SavedFrameAPI.h"
+ #include "jsfriendapi.h"
+ #include "WrapperFactory.h"
+ 
+ #include "mozilla/Base64.h"
+ #include "mozilla/BasePrincipal.h"
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/dom/IdleDeadline.h"
+ #include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
+diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp
+--- a/dom/bindings/Exceptions.cpp
++++ b/dom/bindings/Exceptions.cpp
+@@ -4,16 +4,17 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "mozilla/dom/Exceptions.h"
+ 
+ #include "js/RootingAPI.h"
+ #include "js/TypeDecls.h"
+ #include "jsapi.h"
++#include "js/SavedFrameAPI.h"
+ #include "mozilla/CycleCollectedJSContext.h"
+ #include "mozilla/dom/BindingUtils.h"
+ #include "mozilla/dom/DOMException.h"
+ #include "mozilla/dom/ScriptSettings.h"
+ #include "nsPIDOMWindow.h"
+ #include "nsServiceManagerUtils.h"
+ #include "nsThreadUtils.h"
+ #include "XPCWrapper.h"
+diff --git a/js/public/SavedFrameAPI.h b/js/public/SavedFrameAPI.h
+new file mode 100644
+--- /dev/null
++++ b/js/public/SavedFrameAPI.h
+@@ -0,0 +1,145 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++/*
++ * Functions and types related to SavedFrame objects created by the Debugger
++ * API.
++ */
++
++#ifndef js_SavedFrameAPI_h
++#define js_SavedFrameAPI_h
++
++#include "jstypes.h" // JS_FRIEND_API, JS_PUBLIC_API
++
++#include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle
++
++struct JSContext;
++class JSObject;
++struct JSPrincipals;
++
++namespace JS {
++
++/*
++ * Accessors for working with SavedFrame JSObjects
++ *
++ * Each of these functions assert that if their `HandleObject savedFrame`
++ * argument is non-null, its JSClass is the SavedFrame class (or it is a
++ * cross-compartment or Xray wrapper around an object with the SavedFrame class)
++ * and the object is not the SavedFrame.prototype object.
++ *
++ * Each of these functions will find the first SavedFrame object in the chain
++ * whose underlying stack frame principals are subsumed by the cx's current
++ * compartment's principals, and operate on that SavedFrame object. This
++ * prevents leaking information about privileged frames to un-privileged
++ * callers. As a result, the SavedFrame in parameters do _NOT_ need to be in the
++ * same compartment as the cx, and the various out parameters are _NOT_
++ * guaranteed to be in the same compartment as cx.
++
++ *
++ * You may consider or skip over self-hosted frames by passing
++ * `SavedFrameSelfHosted::Include` or `SavedFrameSelfHosted::Exclude`
++ * respectively.
++ *
++ * Additionally, it may be the case that there is no such SavedFrame object
++ * whose captured frame's principals are subsumed by the caller's compartment's
++ * principals! If the `HandleObject savedFrame` argument is null, or the
++ * caller's principals do not subsume any of the chained SavedFrame object's
++ * principals, `SavedFrameResult::AccessDenied` is returned and a (hopefully)
++ * sane default value is chosen for the out param.
++ *
++ * See also `js/src/doc/SavedFrame/SavedFrame.md`.
++ */
++
++enum class SavedFrameResult {
++    Ok,
++    AccessDenied
++};
++
++enum class SavedFrameSelfHosted {
++    Include,
++    Exclude
++};
++
++/**
++ * Given a SavedFrame JSObject, get its source property. Defaults to the empty
++ * string.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameSource(JSContext* cx, Handle<JSObject*> savedFrame,
++                    MutableHandle<JSString*> sourcep,
++                    SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++/**
++ * Given a SavedFrame JSObject, get its line property. Defaults to 0.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameLine(JSContext* cx, Handle<JSObject*> savedFrame,
++                  uint32_t* linep,
++                  SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++/**
++ * Given a SavedFrame JSObject, get its column property. Defaults to 0.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameColumn(JSContext* cx, Handle<JSObject*> savedFrame,
++                    uint32_t* columnp,
++                    SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++/**
++ * Given a SavedFrame JSObject, get its functionDisplayName string, or nullptr
++ * if SpiderMonkey was unable to infer a name for the captured frame's
++ * function. Defaults to nullptr.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameFunctionDisplayName(JSContext* cx,
++                                 Handle<JSObject*> savedFrame,
++                                 MutableHandle<JSString*> namep,
++                                 SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++/**
++ * Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameAsyncCause(JSContext* cx, Handle<JSObject*> savedFrame,
++                        MutableHandle<JSString*> asyncCausep,
++                        SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++/**
++ * Given a SavedFrame JSObject, get its asyncParent SavedFrame object or nullptr
++ * if there is no asyncParent. The `asyncParentp` out parameter is _NOT_
++ * guaranteed to be in the cx's compartment. Defaults to nullptr.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameAsyncParent(JSContext* cx, Handle<JSObject*> savedFrame,
++                         MutableHandle<JSObject*> asyncParentp,
++                         SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++/**
++ * Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if
++ * it is the oldest frame in the stack. The `parentp` out parameter is _NOT_
++ * guaranteed to be in the cx's compartment. Defaults to nullptr.
++ */
++extern JS_PUBLIC_API(SavedFrameResult)
++GetSavedFrameParent(JSContext* cx, Handle<JSObject*> savedFrame,
++                    MutableHandle<JSObject*> parentp,
++                    SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
++
++} // namespace JS
++
++namespace js {
++
++/**
++ * Get the first SavedFrame object in this SavedFrame stack whose principals are
++ * subsumed by the given |principals|. If there is no such frame, return nullptr.
++ *
++ * Do NOT pass a non-SavedFrame object here.
++ */
++extern JS_FRIEND_API(JSObject*)
++GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals,
++                           JS::Handle<JSObject*> savedFrame, JS::SavedFrameSelfHosted selfHosted);
++
++} // namespace js
++
++#endif /* js_SavedFrameAPI_h */
+diff --git a/js/src/jsapi-tests/testSavedStacks.cpp b/js/src/jsapi-tests/testSavedStacks.cpp
+--- a/js/src/jsapi-tests/testSavedStacks.cpp
++++ b/js/src/jsapi-tests/testSavedStacks.cpp
+@@ -3,16 +3,17 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "jsfriendapi.h"
+ #include "builtin/String.h"
+ 
+ #include "builtin/TestingFunctions.h"
++#include "js/SavedFrameAPI.h"
+ #include "jsapi-tests/tests.h"
+ #include "vm/ArrayObject.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/SavedStacks.h"
+ 
+ BEGIN_TEST(testSavedStacks_withNoStack)
+ {
+     JS::Realm* realm = cx->realm();
+diff --git a/js/src/jsapi.h b/js/src/jsapi.h
+--- a/js/src/jsapi.h
++++ b/js/src/jsapi.h
+@@ -6227,112 +6227,16 @@ CaptureCurrentStack(JSContext* cx, Mutab
+  * new stack object is written to |stackp|.  Returns true on success,
+  * or sets an exception and returns |false| on error.
+  */
+ extern JS_PUBLIC_API(bool)
+ CopyAsyncStack(JSContext* cx, HandleObject asyncStack,
+                HandleString asyncCause, MutableHandleObject stackp,
+                const mozilla::Maybe<size_t>& maxFrameCount);
+ 
+-/*
+- * Accessors for working with SavedFrame JSObjects
+- *
+- * Each of these functions assert that if their `HandleObject savedFrame`
+- * argument is non-null, its JSClass is the SavedFrame class (or it is a
+- * cross-compartment or Xray wrapper around an object with the SavedFrame class)
+- * and the object is not the SavedFrame.prototype object.
+- *
+- * Each of these functions will find the first SavedFrame object in the chain
+- * whose underlying stack frame principals are subsumed by the cx's current
+- * compartment's principals, and operate on that SavedFrame object. This
+- * prevents leaking information about privileged frames to un-privileged
+- * callers. As a result, the SavedFrame in parameters do _NOT_ need to be in the
+- * same compartment as the cx, and the various out parameters are _NOT_
+- * guaranteed to be in the same compartment as cx.
+- *
+- * You may consider or skip over self-hosted frames by passing
+- * `SavedFrameSelfHosted::Include` or `SavedFrameSelfHosted::Exclude`
+- * respectively.
+- *
+- * Additionally, it may be the case that there is no such SavedFrame object
+- * whose captured frame's principals are subsumed by the caller's compartment's
+- * principals! If the `HandleObject savedFrame` argument is null, or the
+- * caller's principals do not subsume any of the chained SavedFrame object's
+- * principals, `SavedFrameResult::AccessDenied` is returned and a (hopefully)
+- * sane default value is chosen for the out param.
+- *
+- * See also `js/src/doc/SavedFrame/SavedFrame.md`.
+- */
+-
+-enum class SavedFrameResult {
+-    Ok,
+-    AccessDenied
+-};
+-
+-enum class SavedFrameSelfHosted {
+-    Include,
+-    Exclude
+-};
+-
+-/**
+- * Given a SavedFrame JSObject, get its source property. Defaults to the empty
+- * string.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
+-                    SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+-/**
+- * Given a SavedFrame JSObject, get its line property. Defaults to 0.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
+-                  SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+-/**
+- * Given a SavedFrame JSObject, get its column property. Defaults to 0.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
+-                    SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+-/**
+- * Given a SavedFrame JSObject, get its functionDisplayName string, or nullptr
+- * if SpiderMonkey was unable to infer a name for the captured frame's
+- * function. Defaults to nullptr.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
+-                                 SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+-/**
+- * Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
+-                        SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+-/**
+- * Given a SavedFrame JSObject, get its asyncParent SavedFrame object or nullptr
+- * if there is no asyncParent. The `asyncParentp` out parameter is _NOT_
+- * guaranteed to be in the cx's compartment. Defaults to nullptr.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
+-                SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+-/**
+- * Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if
+- * it is the oldest frame in the stack. The `parentp` out parameter is _NOT_
+- * guaranteed to be in the cx's compartment. Defaults to nullptr.
+- */
+-extern JS_PUBLIC_API(SavedFrameResult)
+-GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
+-                    SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
+-
+ /**
+  * Given a SavedFrame JSObject stack, stringify it in the same format as
+  * Error.prototype.stack. The stringified stack out parameter is placed in the
+  * cx's compartment. Defaults to the empty string.
+  *
+  * The same notes above about SavedFrame accessors applies here as well: cx
+  * doesn't need to be in stack's compartment, and stack can be null, a
+  * SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object.
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -2874,25 +2874,16 @@ typedef long
+  *
+  * Gecko must call SetJitExceptionFilter before any JIT code is compiled and
+  * only once per process.
+  */
+ extern JS_FRIEND_API(void)
+ SetJitExceptionHandler(JitExceptionHandler handler);
+ #endif
+ 
+-/**
+- * Get the first SavedFrame object in this SavedFrame stack whose principals are
+- * subsumed by the given |principals|. If there is no such frame, return nullptr.
+- *
+- * Do NOT pass a non-SavedFrame object here.
+- */
+-extern JS_FRIEND_API(JSObject*)
+-GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted);
+-
+ extern JS_FRIEND_API(bool)
+ ReportIsNotFunction(JSContext* cx, JS::HandleValue v);
+ 
+ extern JS_FRIEND_API(JSObject*)
+ ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args);
+ 
+ /**
+  * Window and WindowProxy
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -147,16 +147,17 @@ EXPORTS.js += [
+     '../public/ProfilingStack.h',
+     '../public/ProtoKey.h',
+     '../public/Proxy.h',
+     '../public/Realm.h',
+     '../public/RefCounted.h',
+     '../public/RequiredDefines.h',
+     '../public/Result.h',
+     '../public/RootingAPI.h',
++    '../public/SavedFrameAPI.h',
+     '../public/SliceBudget.h',
+     '../public/StableStringChars.h',
+     '../public/Stream.h',
+     '../public/StructuredClone.h',
+     '../public/SweepingAPI.h',
+     '../public/TraceKind.h',
+     '../public/TracingAPI.h',
+     '../public/TrackedOptimizationInfo.h',
+diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
+--- a/js/src/vm/SavedStacks.cpp
++++ b/js/src/vm/SavedStacks.cpp
+@@ -20,16 +20,17 @@
+ #include "jsnum.h"
+ 
+ #include "gc/FreeOp.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Marking.h"
+ #include "gc/Policy.h"
+ #include "gc/Rooting.h"
+ #include "js/CharacterEncoding.h"
++#include "js/SavedFrameAPI.h"
+ #include "js/Vector.h"
+ #include "util/StringBuffer.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeckoProfiler.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/JSScript.h"
+ #include "vm/SavedFrame.h"
+ #include "vm/Time.h"
+diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
+--- a/js/xpconnect/src/XPCComponents.cpp
++++ b/js/xpconnect/src/XPCComponents.cpp
+@@ -10,16 +10,17 @@
+ #include "xpc_make_class.h"
+ #include "XPCJSWeakReference.h"
+ #include "WrapperFactory.h"
+ #include "nsJSUtils.h"
+ #include "mozJSComponentLoader.h"
+ #include "nsContentUtils.h"
+ #include "nsCycleCollector.h"
+ #include "jsfriendapi.h"
++#include "js/SavedFrameAPI.h"
+ #include "js/StructuredClone.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
+ #include "mozilla/Preferences.h"
+ #include "nsJSEnvironment.h"
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/ResultExtensions.h"
+ #include "mozilla/URLPreloader.h"

+ 7 - 7
frg/work-js/mozilla-release/patches/1485347-1-63a1.patch

@@ -3,7 +3,7 @@
 # Date 1534962482 14400
 # Date 1534962482 14400
 #      Wed Aug 22 14:28:02 2018 -0400
 #      Wed Aug 22 14:28:02 2018 -0400
 # Node ID a6aa090e485ef4e81fc6e090e12ab6d2019f21aa
 # Node ID a6aa090e485ef4e81fc6e090e12ab6d2019f21aa
-# Parent  9368a43810d3532c3dc2370d88e1aa39e1641abb
+# Parent  47fe229461d185434e43425add9242075bdab551
 Bug 1485347 - Part 1: Remove nTypeSets argument from JSScript::partiallyInit. r=jandem
 Bug 1485347 - Part 1: Remove nTypeSets argument from JSScript::partiallyInit. r=jandem
 
 
 MozReview-Commit-ID: I6xBHG8FLlq
 MozReview-Commit-ID: I6xBHG8FLlq
@@ -41,7 +41,7 @@ diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
              script->bitFields_.explicitUseStrict_ = true;
              script->bitFields_.explicitUseStrict_ = true;
          if (scriptBits & (1 << ContainsDynamicNameAccess))
          if (scriptBits & (1 << ContainsDynamicNameAccess))
              script->bitFields_.bindingsAccessedDynamically_ = true;
              script->bitFields_.bindingsAccessedDynamically_ = true;
-@@ -2745,30 +2748,27 @@ AllocScriptData(JS::Zone* zone, size_t s
+@@ -2752,30 +2755,27 @@ AllocScriptData(JS::Zone* zone, size_t s
          return nullptr;
          return nullptr;
      MOZ_ASSERT(size_t(data) % sizeof(Value) == 0);
      MOZ_ASSERT(size_t(data) % sizeof(Value) == 0);
      return data;
      return data;
@@ -73,7 +73,7 @@ diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
  
  
      if (nconsts != 0) {
      if (nconsts != 0) {
          script->setHasArray(CONSTS);
          script->setHasArray(CONSTS);
-@@ -2849,23 +2849,24 @@ JSScript::initFunctionPrototype(JSContex
+@@ -2856,23 +2856,24 @@ JSScript::initFunctionPrototype(JSContex
                                  HandleFunction functionProto)
                                  HandleFunction functionProto)
  {
  {
      uint32_t numScopes = 1;
      uint32_t numScopes = 1;
@@ -100,7 +100,7 @@ diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
      script->scopes()->vector[0].init(functionProtoScope);
      script->scopes()->vector[0].init(functionProtoScope);
  
  
      uint32_t codeLength = 1;
      uint32_t codeLength = 1;
-@@ -2958,24 +2959,24 @@ JSScript::fullyInitFromEmitter(JSContext
+@@ -2971,24 +2972,24 @@ JSScript::fullyInitFromEmitter(JSContext
      uint32_t prologueLength = bce->prologueOffset();
      uint32_t prologueLength = bce->prologueOffset();
      uint32_t nsrcnotes;
      uint32_t nsrcnotes;
      if (!bce->finishTakingSrcNotes(&nsrcnotes))
      if (!bce->finishTakingSrcNotes(&nsrcnotes))
@@ -124,9 +124,9 @@ diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp
      if (!script->createScriptData(cx, prologueLength + mainLength, nsrcnotes, natoms))
      if (!script->createScriptData(cx, prologueLength + mainLength, nsrcnotes, natoms))
          return false;
          return false;
  
  
-     jsbytecode* code = script->code();
-     PodCopy<jsbytecode>(code, bce->prologue.code.begin(), prologueLength);
-     PodCopy<jsbytecode>(code + prologueLength, bce->main.code.begin(), mainLength);
+     // Any fallible operation after JSScript::createScriptData should reset
+     // JSScript.scriptData_, in order to treat this script as uncompleted,
+     // in JSScript::isUncompleted.
 diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h
 diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h
 --- a/js/src/vm/JSScript.h
 --- a/js/src/vm/JSScript.h
 +++ b/js/src/vm/JSScript.h
 +++ b/js/src/vm/JSScript.h

+ 865 - 0
frg/work-js/mozilla-release/patches/1486730-63a1.patch

@@ -0,0 +1,865 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1535656220 -3600
+# Node ID 7d07908ee08acfa5333806b907bce7fb20c59dc1
+# Parent  1602728ee9993fbbcf3c2b3c436a663a95377005
+Bug 1486730 - Remove some unnecessary includes from js/src/frontend r=Waldo
+
+diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
+--- a/js/src/frontend/BytecodeCompiler.cpp
++++ b/js/src/frontend/BytecodeCompiler.cpp
+@@ -16,18 +16,17 @@
+ #include "frontend/Parser.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSScript.h"
+ #include "vm/TraceLogging.h"
+ #include "wasm/AsmJS.h"
+ 
+ #include "vm/EnvironmentObject-inl.h"
+-#include "vm/JSObject-inl.h"
+-#include "vm/JSScript-inl.h"
++#include "vm/JSContext-inl.h"
+ 
+ using namespace js;
+ using namespace js::frontend;
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ 
+ // The BytecodeCompiler class contains resources common to compiling scripts and
+ // function bodies.
+diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h
+--- a/js/src/frontend/BytecodeCompiler.h
++++ b/js/src/frontend/BytecodeCompiler.h
+@@ -7,17 +7,16 @@
+ #ifndef frontend_BytecodeCompiler_h
+ #define frontend_BytecodeCompiler_h
+ 
+ #include "mozilla/Maybe.h"
+ 
+ #include "NamespaceImports.h"
+ 
+ #include "vm/Scope.h"
+-#include "vm/StringType.h"
+ #include "vm/TraceLogging.h"
+ 
+ class JSLinearString;
+ 
+ namespace js {
+ 
+ class LazyScript;
+ class LifoAlloc;
+diff --git a/js/src/frontend/BytecodeControlStructures.h b/js/src/frontend/BytecodeControlStructures.h
+--- a/js/src/frontend/BytecodeControlStructures.h
++++ b/js/src/frontend/BytecodeControlStructures.h
+@@ -14,17 +14,16 @@
+ #include <stdint.h>
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/JumpList.h"
+ #include "frontend/SharedContext.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "gc/Rooting.h"
+ #include "vm/BytecodeUtil.h"
+-#include "vm/StringType.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+ struct BytecodeEmitter;
+ class EmitterScope;
+ 
+ class NestableControl : public Nestable<NestableControl>
+diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
+--- a/js/src/frontend/BytecodeEmitter.cpp
++++ b/js/src/frontend/BytecodeEmitter.cpp
+@@ -13,17 +13,16 @@
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/PodOperations.h"
+ 
+ #include <string.h>
+ 
+-#include "jsapi.h"
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/CForEmitter.h"
+ #include "frontend/DoWhileEmitter.h"
+@@ -43,20 +42,17 @@
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ #include "vm/JSScript.h"
+ #include "vm/Stack.h"
+ #include "wasm/AsmJS.h"
+ 
+ #include "frontend/ParseNode-inl.h"
+-#include "vm/EnvironmentObject-inl.h"
+-#include "vm/JSAtom-inl.h"
+-#include "vm/JSScript-inl.h"
+-#include "vm/NativeObject-inl.h"
++#include "vm/JSObject-inl.h"
+ 
+ using namespace js;
+ using namespace js::gc;
+ using namespace js::frontend;
+ 
+ using mozilla::AssertedCast;
+ using mozilla::DebugOnly;
+ using mozilla::Maybe;
+diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
+--- a/js/src/frontend/BytecodeEmitter.h
++++ b/js/src/frontend/BytecodeEmitter.h
+@@ -16,18 +16,16 @@
+ #include "frontend/EitherParser.h"
+ #include "frontend/JumpList.h"
+ #include "frontend/NameFunctions.h"
+ #include "frontend/SharedContext.h"
+ #include "frontend/SourceNotes.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Interpreter.h"
+ #include "vm/Iteration.h"
+-#include "vm/JSContext.h"
+-#include "vm/JSScript.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+ class CGConstList {
+     Vector<Value> list;
+   public:
+     explicit CGConstList(JSContext* cx) : list(cx) {}
+diff --git a/js/src/frontend/EmitterScope.cpp b/js/src/frontend/EmitterScope.cpp
+--- a/js/src/frontend/EmitterScope.cpp
++++ b/js/src/frontend/EmitterScope.cpp
+@@ -5,16 +5,18 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "frontend/EmitterScope.h"
+ 
+ #include "frontend/BytecodeEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "js/AutoByteString.h"
+ 
++#include "vm/GlobalObject.h"
++
+ using namespace js;
+ using namespace js::frontend;
+ 
+ using mozilla::DebugOnly;
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::Some;
+ 
+diff --git a/js/src/frontend/EmitterScope.h b/js/src/frontend/EmitterScope.h
+--- a/js/src/frontend/EmitterScope.h
++++ b/js/src/frontend/EmitterScope.h
+@@ -13,19 +13,21 @@
+ #include <stdint.h>
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/NameAnalysisTypes.h"
+ #include "frontend/NameCollections.h"
+ #include "frontend/ParseContext.h"
+ #include "frontend/SharedContext.h"
+ #include "js/TypeDecls.h"
+-#include "vm/Scope.h"
+ 
+ namespace js {
++
++class Scope;
++
+ namespace frontend {
+ 
+ // A scope that introduces bindings.
+ class EmitterScope : public Nestable<EmitterScope>
+ {
+     // The cache of bound names that may be looked up in the
+     // scope. Initially populated as the set of names this scope binds. As
+     // names are looked up in enclosing scopes, they are cached on the
+diff --git a/js/src/frontend/ErrorReporter.h b/js/src/frontend/ErrorReporter.h
+--- a/js/src/frontend/ErrorReporter.h
++++ b/js/src/frontend/ErrorReporter.h
+@@ -6,17 +6,20 @@
+ 
+ #ifndef frontend_ErrorReporter_h
+ #define frontend_ErrorReporter_h
+ 
+ #include <stdarg.h> // for va_list
+ #include <stddef.h> // for size_t
+ #include <stdint.h> // for uint32_t
+ 
+-#include "jsapi.h" // for JS::ReadOnlyCompileOptions
++#include "js/CompileOptions.h"
++#include "js/UniquePtr.h"
++
++class JSErrorNotes;
+ 
+ namespace js {
+ namespace frontend {
+ 
+ class ErrorReporter
+ {
+   public:
+     virtual const JS::ReadOnlyCompileOptions& options() const = 0;
+diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
+--- a/js/src/frontend/FoldConstants.cpp
++++ b/js/src/frontend/FoldConstants.cpp
+@@ -4,25 +4,23 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "frontend/FoldConstants.h"
+ 
+ #include "mozilla/FloatingPoint.h"
+ 
+ #include "jslibmath.h"
++#include "jsnum.h"
+ 
+ #include "frontend/ParseNode.h"
+ #include "frontend/Parser.h"
+ #include "js/Conversions.h"
+ #include "vm/StringType.h"
+ 
+-#include "vm/JSContext-inl.h"
+-#include "vm/JSObject-inl.h"
+-
+ using namespace js;
+ using namespace js::frontend;
+ 
+ using mozilla::IsNaN;
+ using mozilla::IsNegative;
+ using mozilla::NegativeInfinity;
+ using mozilla::PositiveInfinity;
+ using JS::GenericNaN;
+diff --git a/js/src/frontend/ForOfLoopControl.h b/js/src/frontend/ForOfLoopControl.h
+--- a/js/src/frontend/ForOfLoopControl.h
++++ b/js/src/frontend/ForOfLoopControl.h
+@@ -7,18 +7,16 @@
+ #ifndef frontend_ForOfLoopControl_h
+ #define frontend_ForOfLoopControl_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Maybe.h"
+ 
+ #include <stdint.h>
+ 
+-#include "jsapi.h"
+-
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/TryEmitter.h"
+ #include "vm/Iteration.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+ struct BytecodeEmitter;
+diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
+--- a/js/src/frontend/FullParseHandler.h
++++ b/js/src/frontend/FullParseHandler.h
+@@ -9,16 +9,17 @@
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/PodOperations.h"
+ 
+ #include <string.h>
+ 
+ #include "frontend/ParseNode.h"
+ #include "frontend/SharedContext.h"
++#include "vm/JSContext.h"
+ 
+ namespace js {
+ 
+ class RegExpObject;
+ 
+ namespace frontend {
+ 
+ enum class SourceKind {
+diff --git a/js/src/frontend/NameCollections.h b/js/src/frontend/NameCollections.h
+--- a/js/src/frontend/NameCollections.h
++++ b/js/src/frontend/NameCollections.h
+@@ -5,21 +5,22 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef frontend_NameCollections_h
+ #define frontend_NameCollections_h
+ 
+ #include "ds/InlineTable.h"
+ #include "frontend/NameAnalysisTypes.h"
+ #include "js/Vector.h"
+-#include "vm/Stack.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
++class FunctionBox;
++
+ // A pool of recyclable containers for use in the frontend. The Parser and
+ // BytecodeEmitter create many maps for name analysis that are short-lived
+ // (i.e., for the duration of parsing or emitting a lexical scope). Making
+ // them recyclable cuts down significantly on allocator churn.
+ template <typename RepresentativeCollection, typename ConcreteCollectionPool>
+ class CollectionPool
+ {
+     using RecyclableCollections = Vector<void*, 32, SystemAllocPolicy>;
+@@ -145,17 +146,16 @@ struct RecyclableAtomMapValueWrapper
+ template <typename MapValue>
+ using RecyclableNameMap = InlineMap<JSAtom*,
+                                     RecyclableAtomMapValueWrapper<MapValue>,
+                                     24,
+                                     DefaultHasher<JSAtom*>,
+                                     SystemAllocPolicy>;
+ 
+ using DeclaredNameMap = RecyclableNameMap<DeclaredNameInfo>;
+-using CheckTDZMap = RecyclableNameMap<MaybeCheckTDZ>;
+ using NameLocationMap = RecyclableNameMap<NameLocation>;
+ using AtomIndexMap = RecyclableNameMap<uint32_t>;
+ 
+ template <typename RepresentativeTable>
+ class InlineTablePool
+   : public CollectionPool<RepresentativeTable, InlineTablePool<RepresentativeTable>>
+ {
+   public:
+@@ -318,17 +318,14 @@ class PooledVectorPtr
+ 
+ #undef POOLED_COLLECTION_PTR_METHODS
+ 
+ } // namespace frontend
+ } // namespace js
+ 
+ namespace mozilla {
+ 
+-template <>
+-struct IsPod<js::MaybeCheckTDZ> : TrueType {};
+-
+ template <typename T>
+ struct IsPod<js::frontend::RecyclableAtomMapValueWrapper<T>> : IsPod<T> {};
+ 
+ } // namespace mozilla
+ 
+ #endif // frontend_NameCollections_h
+diff --git a/js/src/frontend/ParseContext-inl.h b/js/src/frontend/ParseContext-inl.h
+--- a/js/src/frontend/ParseContext-inl.h
++++ b/js/src/frontend/ParseContext-inl.h
+@@ -1,8 +1,14 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++ * vim: set ts=8 sts=4 et sw=4 tw=99:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
+ #ifndef frontend_ParseContext_inl_h
+ #define frontend_ParseContext_inl_h
+ 
+ #include "frontend/ParseContext.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+@@ -15,17 +21,16 @@ ParseContext::Statement::is<ParseContext
+ 
+ template <>
+ inline bool
+ ParseContext::Statement::is<ParseContext::ClassStatement>() const
+ {
+     return kind_ == StatementKind::Class;
+ }
+ 
+-
+ inline JS::Result<Ok, ParseContext::BreakStatementError>
+ ParseContext::checkBreakStatement(PropertyName* label)
+ {
+     // Labeled 'break' statements target the nearest labeled statements (could
+     // be any kind) with the same label. Unlabeled 'break' statements target
+     // the innermost loop or switch statement.
+     if (label) {
+         auto hasSameLabel = [&label](ParseContext::LabelStatement* stmt) {
+diff --git a/js/src/frontend/ParseContext.h b/js/src/frontend/ParseContext.h
+--- a/js/src/frontend/ParseContext.h
++++ b/js/src/frontend/ParseContext.h
+@@ -485,45 +485,19 @@ class ParseContext : public Nestable<Par
+     // the Function or Generator constructor.
+     bool isStandaloneFunctionBody_;
+ 
+     // Set when encountering a super.property inside a method. We need to mark
+     // the nearest super scope as needing a home object.
+     bool superScopeNeedsHomeObject_;
+ 
+   public:
+-    inline ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc, ErrorReporter& errorReporter,
+-        class UsedNameTracker& usedNames, Directives* newDirectives, bool isFull)
+-      : Nestable<ParseContext>(&parent),
+-        traceLog_(sc->context,
+-                  isFull
+-                  ? TraceLogger_ParsingFull
+-                  : TraceLogger_ParsingSyntax,
+-                  errorReporter),
+-        sc_(sc),
+-        errorReporter_(errorReporter),
+-        innermostStatement_(nullptr),
+-        innermostScope_(nullptr),
+-        varScope_(nullptr),
+-        positionalFormalParameterNames_(cx->frontendCollectionPool()),
+-        closedOverBindingsForLazy_(cx->frontendCollectionPool()),
+-        innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
+-        newDirectives(newDirectives),
+-        lastYieldOffset(NoYieldOffset),
+-        lastAwaitOffset(NoAwaitOffset),
+-        scriptId_(usedNames.nextScriptId()),
+-        isStandaloneFunctionBody_(false),
+-        superScopeNeedsHomeObject_(false)
+-    {
+-        if (isFunctionBox()) {
+-            if (functionBox()->function()->isNamedLambda())
+-                namedLambdaScope_.emplace(cx, parent, usedNames);
+-            functionScope_.emplace(cx, parent, usedNames);
+-        }
+-    }
++    ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc,
++                 ErrorReporter& errorReporter, UsedNameTracker& usedNames,
++                 Directives* newDirectives, bool isFull);
+ 
+     MOZ_MUST_USE bool init();
+ 
+     SharedContext* sc() {
+         return sc_;
+     }
+ 
+     // `true` if we are in the body of a function definition.
+diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp
+--- a/js/src/frontend/ParseNode.cpp
++++ b/js/src/frontend/ParseNode.cpp
+@@ -3,16 +3,18 @@
+  * This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "frontend/ParseNode-inl.h"
+ 
+ #include "mozilla/FloatingPoint.h"
+ 
++#include "jsnum.h"
++
+ #include "frontend/Parser.h"
+ 
+ #include "vm/JSContext-inl.h"
+ 
+ using namespace js;
+ using namespace js::frontend;
+ 
+ using mozilla::IsFinite;
+diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
+--- a/js/src/frontend/ParseNode.h
++++ b/js/src/frontend/ParseNode.h
+@@ -4,19 +4,20 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef frontend_ParseNode_h
+ #define frontend_ParseNode_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+-#include "builtin/ModuleObject.h"
+ #include "frontend/TokenStream.h"
++#include "vm/BytecodeUtil.h"
+ #include "vm/Printer.h"
++#include "vm/Scope.h"
+ 
+ // A few notes on lifetime of ParseNode trees:
+ //
+ // - All the `ParseNode` instances MUST BE explicitly allocated in the context's `LifoAlloc`.
+ //   This is typically implemented by the `FullParseHandler` or it can be reimplemented with
+ //   a custom `new_`.
+ //
+ // - The tree is bulk-deallocated when the parser is deallocated. Consequently, references
+diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
+--- a/js/src/frontend/Parser.cpp
++++ b/js/src/frontend/Parser.cpp
+@@ -23,17 +23,17 @@
+ #include "mozilla/Sprintf.h"
+ #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/Utf8.h"
+ 
+ #include <memory>
+ #include <new>
+ 
+-#include "jsapi.h"
++#include "jsnum.h"
+ #include "jstypes.h"
+ 
+ #include "builtin/ModuleObject.h"
+ #include "builtin/SelfHostingDefines.h"
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/FoldConstants.h"
+ #include "frontend/TokenStream.h"
+ #include "irregexp/RegExpParser.h"
+@@ -45,18 +45,16 @@
+ #include "vm/JSScript.h"
+ #include "vm/RegExpObject.h"
+ #include "vm/StringType.h"
+ #include "wasm/AsmJS.h"
+ 
+ #include "frontend/ParseContext-inl.h"
+ #include "frontend/ParseNode-inl.h"
+ #include "vm/EnvironmentObject-inl.h"
+-#include "vm/JSAtom-inl.h"
+-#include "vm/JSScript-inl.h"
+ 
+ using namespace js;
+ using namespace js::gc;
+ 
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::PodCopy;
+ using mozilla::PodZero;
+@@ -374,16 +372,47 @@ EvalSharedContext::EvalSharedContext(JSC
+                 break;
+             }
+ 
+             env = env->enclosingEnvironment();
+         }
+     }
+ }
+ 
++ParseContext::ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc,
++                           ErrorReporter& errorReporter, class UsedNameTracker& usedNames,
++                           Directives* newDirectives, bool isFull)
++  : Nestable<ParseContext>(&parent),
++    traceLog_(sc->context,
++              isFull
++              ? TraceLogger_ParsingFull
++              : TraceLogger_ParsingSyntax,
++              errorReporter),
++    sc_(sc),
++    errorReporter_(errorReporter),
++    innermostStatement_(nullptr),
++    innermostScope_(nullptr),
++    varScope_(nullptr),
++    positionalFormalParameterNames_(cx->frontendCollectionPool()),
++    closedOverBindingsForLazy_(cx->frontendCollectionPool()),
++    innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
++    newDirectives(newDirectives),
++    lastYieldOffset(NoYieldOffset),
++    lastAwaitOffset(NoAwaitOffset),
++    scriptId_(usedNames.nextScriptId()),
++    isStandaloneFunctionBody_(false),
++    superScopeNeedsHomeObject_(false)
++{
++    if (isFunctionBox()) {
++        if (functionBox()->function()->isNamedLambda())
++            namedLambdaScope_.emplace(cx, parent, usedNames);
++        functionScope_.emplace(cx, parent, usedNames);
++    }
++}
++
+ bool
+ ParseContext::init()
+ {
+     if (scriptId_ == UINT32_MAX) {
+         errorReporter_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
+         return false;
+     }
+ 
+@@ -456,16 +485,24 @@ UsedNameTracker::rewind(RewindToken toke
+ {
+     scriptCounter_ = token.scriptId;
+     scopeCounter_ = token.scopeId;
+ 
+     for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront())
+         r.front().value().resetToScope(token.scriptId, token.scopeId);
+ }
+ 
++#ifdef DEBUG
++bool
++FunctionBox::atomsAreKept()
++{
++    return context->zone()->hasKeptAtoms();
++}
++#endif
++
+ FunctionBox::FunctionBox(JSContext* cx, ObjectBox* traceListHead,
+                          JSFunction* fun, uint32_t toStringStart,
+                          Directives directives, bool extraWarnings,
+                          GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
+   : ObjectBox(fun, traceListHead),
+     SharedContext(cx, Kind::FunctionBox, directives, extraWarnings),
+     enclosingScope_(nullptr),
+     namedLambdaBindings_(nullptr),
+diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
+--- a/js/src/frontend/Parser.h
++++ b/js/src/frontend/Parser.h
+@@ -176,17 +176,18 @@
+ #include "frontend/BytecodeCompiler.h"
+ #include "frontend/FullParseHandler.h"
+ #include "frontend/NameAnalysisTypes.h"
+ #include "frontend/NameCollections.h"
+ #include "frontend/ParseContext.h"
+ #include "frontend/SharedContext.h"
+ #include "frontend/SyntaxParseHandler.h"
+ #include "frontend/TokenStream.h"
+-#include "vm/Iteration.h"
++// -include "js/CompileOptions.h"
++
+ 
+ namespace js {
+ 
+ class ModuleObject;
+ 
+ namespace frontend {
+ 
+ class ParserBase;
+diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
+--- a/js/src/frontend/SharedContext.h
++++ b/js/src/frontend/SharedContext.h
+@@ -9,19 +9,19 @@
+ 
+ #include "jspubtd.h"
+ #include "jstypes.h"
+ 
+ #include "builtin/ModuleObject.h"
+ #include "ds/InlineTable.h"
+ #include "frontend/ParseNode.h"
+ #include "frontend/TokenStream.h"
++// -include "gc/Zone.h"
+ #include "vm/BytecodeUtil.h"
+-#include "vm/EnvironmentObject.h"
+-#include "vm/JSAtom.h"
++#include "vm/JSFunction.h"
+ #include "vm/JSScript.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+ class ParseContext;
+ class ParseNode;
+ 
+@@ -404,28 +404,32 @@ class FunctionBox : public ObjectBox, pu
+ 
+     // Whether this function has nested functions.
+     bool hasInnerFunctions_:1;
+ 
+     FunctionBox(JSContext* cx, ObjectBox* traceListHead, JSFunction* fun,
+                 uint32_t toStringStart, Directives directives, bool extraWarnings,
+                 GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
+ 
++#ifdef DEBUG
++    bool atomsAreKept();
++#endif
++
+     MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
+-        MOZ_ASSERT(context->zone()->hasKeptAtoms());
++        MOZ_ASSERT(atomsAreKept());
+         return MutableHandle<LexicalScope::Data*>::fromMarkedLocation(&namedLambdaBindings_);
+     }
+ 
+     MutableHandle<FunctionScope::Data*> functionScopeBindings() {
+-        MOZ_ASSERT(context->zone()->hasKeptAtoms());
++        MOZ_ASSERT(atomsAreKept());
+         return MutableHandle<FunctionScope::Data*>::fromMarkedLocation(&functionScopeBindings_);
+     }
+ 
+     MutableHandle<VarScope::Data*> extraVarScopeBindings() {
+-        MOZ_ASSERT(context->zone()->hasKeptAtoms());
++        MOZ_ASSERT(atomsAreKept());
+         return MutableHandle<VarScope::Data*>::fromMarkedLocation(&extraVarScopeBindings_);
+     }
+ 
+     void initFromLazyFunction();
+     void initStandaloneFunction(Scope* enclosingScope);
+     void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
+ 
+     inline bool isLazyFunctionWithoutEnclosingScope() const {
+diff --git a/js/src/frontend/TDZCheckCache.h b/js/src/frontend/TDZCheckCache.h
+--- a/js/src/frontend/TDZCheckCache.h
++++ b/js/src/frontend/TDZCheckCache.h
+@@ -15,16 +15,18 @@
+ #include "js/TypeDecls.h"
+ #include "vm/Stack.h"
+ 
+ namespace js {
+ namespace frontend {
+ 
+ struct BytecodeEmitter;
+ 
++using CheckTDZMap = RecyclableNameMap<MaybeCheckTDZ>;
++
+ // A cache that tracks Temporal Dead Zone (TDZ) checks, so that any use of a
+ // lexical variable that's dominated by an earlier use, or by evaluation of its
+ // declaration (which will initialize it, perhaps to |undefined|), doesn't have
+ // to redundantly check that the lexical variable has been initialized
+ //
+ // Each basic block should have a TDZCheckCache in scope. Some NestableControl
+ // subclasses contain a TDZCheckCache.
+ //
+diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
+--- a/js/src/frontend/TokenStream.h
++++ b/js/src/frontend/TokenStream.h
+@@ -204,23 +204,25 @@
+ 
+ #include "frontend/ErrorReporter.h"
+ #include "frontend/TokenKind.h"
+ #include "js/UniquePtr.h"
+ #include "js/Vector.h"
+ #include "util/Text.h"
+ #include "util/Unicode.h"
+ #include "vm/ErrorReporting.h"
+-#include "vm/JSContext.h"
+ #include "vm/RegExpShared.h"
+-#include "vm/StringType.h"
+-
++
++struct JSContext;
+ struct KeywordInfo;
+ 
+ namespace js {
++
++class AutoKeepAtoms;
++
+ namespace frontend {
+ 
+ struct TokenPos {
+     uint32_t    begin;  // Offset of the token's first code unit.
+     uint32_t    end;    // Offset of 1 past the token's last code unit.
+ 
+     TokenPos()
+       : begin(0),
+diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h
+--- a/js/src/gc/Rooting.h
++++ b/js/src/gc/Rooting.h
+@@ -25,16 +25,17 @@ class ScriptSourceObject;
+ class SavedFrame;
+ class Shape;
+ class ObjectGroup;
+ class DebuggerArguments;
+ class DebuggerEnvironment;
+ class DebuggerFrame;
+ class DebuggerObject;
+ class Scope;
++class ModuleObject;
+ 
+ // These are internal counterparts to the public types such as HandleObject.
+ 
+ typedef JS::Handle<NativeObject*>           HandleNativeObject;
+ typedef JS::Handle<Shape*>                  HandleShape;
+ typedef JS::Handle<ObjectGroup*>            HandleObjectGroup;
+ typedef JS::Handle<JSAtom*>                 HandleAtom;
+ typedef JS::Handle<JSLinearString*>         HandleLinearString;
+@@ -43,27 +44,29 @@ typedef JS::Handle<ArrayObject*>        
+ typedef JS::Handle<PlainObject*>            HandlePlainObject;
+ typedef JS::Handle<SavedFrame*>             HandleSavedFrame;
+ typedef JS::Handle<ScriptSourceObject*>     HandleScriptSourceObject;
+ typedef JS::Handle<DebuggerArguments*>      HandleDebuggerArguments;
+ typedef JS::Handle<DebuggerEnvironment*>    HandleDebuggerEnvironment;
+ typedef JS::Handle<DebuggerFrame*>          HandleDebuggerFrame;
+ typedef JS::Handle<DebuggerObject*>         HandleDebuggerObject;
+ typedef JS::Handle<Scope*>                  HandleScope;
++typedef JS::Handle<ModuleObject*>           HandleModuleObject;
+ 
+ typedef JS::MutableHandle<Shape*>               MutableHandleShape;
+ typedef JS::MutableHandle<JSAtom*>              MutableHandleAtom;
+ typedef JS::MutableHandle<NativeObject*>        MutableHandleNativeObject;
+ typedef JS::MutableHandle<PlainObject*>         MutableHandlePlainObject;
+ typedef JS::MutableHandle<SavedFrame*>          MutableHandleSavedFrame;
+ typedef JS::MutableHandle<DebuggerArguments*>   MutableHandleDebuggerArguments;
+ typedef JS::MutableHandle<DebuggerEnvironment*> MutableHandleDebuggerEnvironment;
+ typedef JS::MutableHandle<DebuggerFrame*>       MutableHandleDebuggerFrame;
+ typedef JS::MutableHandle<DebuggerObject*>      MutableHandleDebuggerObject;
+ typedef JS::MutableHandle<Scope*>               MutableHandleScope;
++typedef JS::MutableHandle<ModuleObject*>        MutableHandleModuleObject;
+ 
+ typedef JS::Rooted<NativeObject*>           RootedNativeObject;
+ typedef JS::Rooted<Shape*>                  RootedShape;
+ typedef JS::Rooted<ObjectGroup*>            RootedObjectGroup;
+ typedef JS::Rooted<JSAtom*>                 RootedAtom;
+ typedef JS::Rooted<JSLinearString*>         RootedLinearString;
+ typedef JS::Rooted<PropertyName*>           RootedPropertyName;
+ typedef JS::Rooted<ArrayObject*>            RootedArrayObject;
+@@ -71,16 +74,17 @@ typedef JS::Rooted<GlobalObject*>       
+ typedef JS::Rooted<PlainObject*>            RootedPlainObject;
+ typedef JS::Rooted<SavedFrame*>             RootedSavedFrame;
+ typedef JS::Rooted<ScriptSourceObject*>     RootedScriptSourceObject;
+ typedef JS::Rooted<DebuggerArguments*>      RootedDebuggerArguments;
+ typedef JS::Rooted<DebuggerEnvironment*>    RootedDebuggerEnvironment;
+ typedef JS::Rooted<DebuggerFrame*>          RootedDebuggerFrame;
+ typedef JS::Rooted<DebuggerObject*>         RootedDebuggerObject;
+ typedef JS::Rooted<Scope*>                  RootedScope;
++typedef JS::Rooted<ModuleObject*>           RootedModuleObject;
+ 
+ typedef JS::GCVector<JSFunction*>   FunctionVector;
+ typedef JS::GCVector<PropertyName*> PropertyNameVector;
+ typedef JS::GCVector<Shape*>        ShapeVector;
+ typedef JS::GCVector<JSString*>     StringVector;
+ 
+ /** Interface substitute for Rooted<T> which does not root the variable's memory. */
+ template <typename T>
+diff --git a/js/src/vm/Iteration.h b/js/src/vm/Iteration.h
+--- a/js/src/vm/Iteration.h
++++ b/js/src/vm/Iteration.h
+@@ -10,17 +10,16 @@
+ /*
+  * JavaScript iterators.
+  */
+ 
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/MemoryReporting.h"
+ 
+ #include "gc/Barrier.h"
+-#include "vm/JSContext.h"
+ #include "vm/ReceiverGuard.h"
+ #include "vm/Stack.h"
+ 
+ namespace js {
+ 
+ class PropertyIteratorObject;
+ 
+ struct NativeIterator
+diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
+--- a/js/src/vm/Stack.h
++++ b/js/src/vm/Stack.h
+@@ -97,18 +97,27 @@ class Instance;
+ // the activation's "current regs", which contains the stack pointer 'sp'. In
+ // the interpreter, sp is adjusted as individual values are pushed and popped
+ // from the stack and the InterpreterRegs struct (pointed to by the
+ // InterpreterActivation) is a local var of js::Interpret.
+ 
+ enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
+ enum MaybeCheckTDZ { CheckTDZ = true, DontCheckTDZ = false };
+ 
++} // namespace js
++
++namespace mozilla {
++template <>
++struct IsPod<js::MaybeCheckTDZ> : TrueType {};
++} // namespace mozilla
++
+ /*****************************************************************************/
+ 
++namespace js {
++
+ namespace jit {
+     class BaselineFrame;
+     class RematerializedFrame;
+ } // namespace jit
+ 
+ /**
+  * Pointer to a live JS or WASM stack frame.
+  */
+@@ -2419,9 +2428,10 @@ FrameIter::isPhysicalJitFrame() const
+ inline jit::CommonFrameLayout*
+ FrameIter::physicalJitFrame() const
+ {
+     MOZ_ASSERT(isPhysicalJitFrame());
+     return jsJitFrame().current();
+ }
+ 
+ }  /* namespace js */
++
+ #endif /* vm_Stack_h */

+ 27 - 28
frg/work-js/mozilla-release/patches/1494752-604.patch

@@ -3,7 +3,7 @@
 # Date 1541688097 18000
 # Date 1541688097 18000
 #      Thu Nov 08 09:41:37 2018 -0500
 #      Thu Nov 08 09:41:37 2018 -0500
 # Node ID c264774b89130cd7759c40977835e2a0d32fd684
 # Node ID c264774b89130cd7759c40977835e2a0d32fd684
-# Parent  22f71e06ad70f2e6d8cb7ea4c5ad76660b328b4e
+# Parent  196c0e4c3e951acb5edbd04f199026d8e3fb3ce5
 Bug 1494752. r=jonco, a=RyanVM
 Bug 1494752. r=jonco, a=RyanVM
 
 
 diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
@@ -23,36 +23,35 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  #include "mozilla/Range.h"
  #include "mozilla/Range.h"
  #include "mozilla/Sprintf.h"
  #include "mozilla/Sprintf.h"
  #include "mozilla/TypeTraits.h"
  #include "mozilla/TypeTraits.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/Utf8.h"
  
  
  #include <memory>
  #include <memory>
  #include <new>
  #include <new>
+@@ -49,20 +51,22 @@
  
  
- #include "jsapi.h"
-@@ -48,20 +50,22 @@
+ #include "frontend/ParseContext-inl.h"
  #include "frontend/ParseNode-inl.h"
  #include "frontend/ParseNode-inl.h"
  #include "vm/EnvironmentObject-inl.h"
  #include "vm/EnvironmentObject-inl.h"
- #include "vm/JSAtom-inl.h"
- #include "vm/JSScript-inl.h"
  
  
  using namespace js;
  using namespace js;
  using namespace js::gc;
  using namespace js::gc;
  
  
 +using mozilla::AssertedCast;
 +using mozilla::AssertedCast;
-+using mozilla::Forward;
  using mozilla::Maybe;
  using mozilla::Maybe;
  using mozilla::Nothing;
  using mozilla::Nothing;
--using mozilla::PodCopy;
+ using mozilla::PodCopy;
  using mozilla::PodZero;
  using mozilla::PodZero;
 +using mozilla::PointerRangeSize;
 +using mozilla::PointerRangeSize;
  using mozilla::Some;
  using mozilla::Some;
+ using mozilla::Unused;
+ using mozilla::Utf8Unit;
  
  
  using JS::AutoGCRooter;
  using JS::AutoGCRooter;
  
  
  namespace js {
  namespace js {
  namespace frontend {
  namespace frontend {
- 
- using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
-@@ -1765,24 +1769,67 @@ NewEmptyBindingData(JSContext* cx, LifoA
+@@ -1855,24 +1859,67 @@ NewEmptyBindingData(JSContext* cx, LifoA
      using Data = typename Scope::Data;
      using Data = typename Scope::Data;
      size_t allocSize = SizeOfData<typename Scope::Data>(numBindings);
      size_t allocSize = SizeOfData<typename Scope::Data>(numBindings);
      auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
      auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
@@ -128,7 +127,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      BindingNameVector vars(context);
      BindingNameVector vars(context);
      BindingNameVector lets(context);
      BindingNameVector lets(context);
      BindingNameVector consts(context);
      BindingNameVector consts(context);
-@@ -1820,28 +1867,20 @@ NewGlobalScopeData(JSContext* context, P
+@@ -1910,28 +1957,20 @@ NewGlobalScopeData(JSContext* context, P
      uint32_t numBindings = vars.length() + lets.length() + consts.length();
      uint32_t numBindings = vars.length() + lets.length() + consts.length();
  
  
      if (numBindings > 0) {
      if (numBindings > 0) {
@@ -146,7 +145,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -        cursor = FreshlyInitializeBindings(cursor, lets);
 -        cursor = FreshlyInitializeBindings(cursor, lets);
 -
 -
 -        bindings->constStart = cursor - start;
 -        bindings->constStart = cursor - start;
--        cursor = FreshlyInitializeBindings(cursor, consts);
+-        Unused << FreshlyInitializeBindings(cursor, consts);
 -
 -
 -        bindings->length = numBindings;
 -        bindings->length = numBindings;
 +        InitializeBindingData(bindings, numBindings,
 +        InitializeBindingData(bindings, numBindings,
@@ -161,7 +160,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  Maybe<GlobalScope::Data*>
  Maybe<GlobalScope::Data*>
  ParserBase::newGlobalScopeData(ParseContext::Scope& scope)
  ParserBase::newGlobalScopeData(ParseContext::Scope& scope)
  {
  {
-@@ -1887,31 +1926,21 @@ NewModuleScopeData(JSContext* context, P
+@@ -1977,31 +2016,21 @@ NewModuleScopeData(JSContext* context, P
      uint32_t numBindings = imports.length() + vars.length() + lets.length() + consts.length();
      uint32_t numBindings = imports.length() + vars.length() + lets.length() + consts.length();
  
  
      if (numBindings > 0) {
      if (numBindings > 0) {
@@ -182,7 +181,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -        cursor = FreshlyInitializeBindings(cursor, lets);
 -        cursor = FreshlyInitializeBindings(cursor, lets);
 -
 -
 -        bindings->constStart = cursor - start;
 -        bindings->constStart = cursor - start;
--        cursor = FreshlyInitializeBindings(cursor, consts);
+-        Unused << FreshlyInitializeBindings(cursor, consts);
 -
 -
 -        bindings->length = numBindings;
 -        bindings->length = numBindings;
 +        InitializeBindingData(bindings, numBindings,
 +        InitializeBindingData(bindings, numBindings,
@@ -198,7 +197,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  Maybe<ModuleScope::Data*>
  Maybe<ModuleScope::Data*>
  ParserBase::newModuleScopeData(ParseContext::Scope& scope)
  ParserBase::newModuleScopeData(ParseContext::Scope& scope)
  {
  {
-@@ -1936,22 +1965,17 @@ NewEvalScopeData(JSContext* context, Par
+@@ -2026,22 +2055,17 @@ NewEvalScopeData(JSContext* context, Par
      EvalScope::Data* bindings = nullptr;
      EvalScope::Data* bindings = nullptr;
      uint32_t numBindings = vars.length();
      uint32_t numBindings = vars.length();
  
  
@@ -210,7 +209,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -        BindingName* start = bindings->trailingNames.start();
 -        BindingName* start = bindings->trailingNames.start();
 -        BindingName* cursor = start;
 -        BindingName* cursor = start;
 -
 -
--        cursor = FreshlyInitializeBindings(cursor, vars);
+-        Unused << FreshlyInitializeBindings(cursor, vars);
 -
 -
 -        bindings->length = numBindings;
 -        bindings->length = numBindings;
 +        InitializeBindingData(bindings, numBindings, vars);
 +        InitializeBindingData(bindings, numBindings, vars);
@@ -222,7 +221,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  Maybe<EvalScope::Data*>
  Maybe<EvalScope::Data*>
  ParserBase::newEvalScopeData(ParseContext::Scope& scope)
  ParserBase::newEvalScopeData(ParseContext::Scope& scope)
  {
  {
-@@ -2029,28 +2053,20 @@ NewFunctionScopeData(JSContext* context,
+@@ -2119,28 +2143,20 @@ NewFunctionScopeData(JSContext* context,
      uint32_t numBindings = positionalFormals.length() + formals.length() + vars.length();
      uint32_t numBindings = positionalFormals.length() + formals.length() + vars.length();
  
  
      if (numBindings > 0) {
      if (numBindings > 0) {
@@ -240,7 +239,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -        cursor = FreshlyInitializeBindings(cursor, formals);
 -        cursor = FreshlyInitializeBindings(cursor, formals);
 -
 -
 -        bindings->varStart = cursor - start;
 -        bindings->varStart = cursor - start;
--        cursor = FreshlyInitializeBindings(cursor, vars);
+-        Unused << FreshlyInitializeBindings(cursor, vars);
 -
 -
 -        bindings->length = numBindings;
 -        bindings->length = numBindings;
 +        InitializeBindingData(bindings, numBindings,
 +        InitializeBindingData(bindings, numBindings,
@@ -255,7 +254,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  Maybe<FunctionScope::Data*>
  Maybe<FunctionScope::Data*>
  ParserBase::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs)
  ParserBase::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs)
  {
  {
-@@ -2075,23 +2091,17 @@ NewVarScopeData(JSContext* context, Pars
+@@ -2165,23 +2181,17 @@ NewVarScopeData(JSContext* context, Pars
      VarScope::Data* bindings = nullptr;
      VarScope::Data* bindings = nullptr;
      uint32_t numBindings = vars.length();
      uint32_t numBindings = vars.length();
  
  
@@ -268,7 +267,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -        BindingName* start = bindings->trailingNames.start();
 -        BindingName* start = bindings->trailingNames.start();
 -        BindingName* cursor = start;
 -        BindingName* cursor = start;
 -
 -
--        cursor = FreshlyInitializeBindings(cursor, vars);
+-        Unused << FreshlyInitializeBindings(cursor, vars);
 -
 -
 -        bindings->length = numBindings;
 -        bindings->length = numBindings;
 +        InitializeBindingData(bindings, numBindings, vars);
 +        InitializeBindingData(bindings, numBindings, vars);
@@ -280,7 +279,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  Maybe<VarScope::Data*>
  Maybe<VarScope::Data*>
  ParserBase::newVarScopeData(ParseContext::Scope& scope)
  ParserBase::newVarScopeData(ParseContext::Scope& scope)
  {
  {
-@@ -2130,25 +2140,19 @@ NewLexicalScopeData(JSContext* context, 
+@@ -2220,25 +2230,19 @@ NewLexicalScopeData(JSContext* context, 
      uint32_t numBindings = lets.length() + consts.length();
      uint32_t numBindings = lets.length() + consts.length();
  
  
      if (numBindings > 0) {
      if (numBindings > 0) {
@@ -295,7 +294,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -        cursor = FreshlyInitializeBindings(cursor, lets);
 -        cursor = FreshlyInitializeBindings(cursor, lets);
 -
 -
 -        bindings->constStart = cursor - start;
 -        bindings->constStart = cursor - start;
--        cursor = FreshlyInitializeBindings(cursor, consts);
+-        Unused << FreshlyInitializeBindings(cursor, consts);
 -
 -
 -        bindings->length = numBindings;
 -        bindings->length = numBindings;
 +        InitializeBindingData(bindings, numBindings,
 +        InitializeBindingData(bindings, numBindings,
@@ -312,7 +311,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
 diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
 --- a/js/src/vm/Scope.cpp
 --- a/js/src/vm/Scope.cpp
 +++ b/js/src/vm/Scope.cpp
 +++ b/js/src/vm/Scope.cpp
-@@ -207,17 +207,17 @@ NewEmptyScopeData(JSContext* cx, uint32_
+@@ -210,17 +210,17 @@ NewEmptyScopeData(JSContext* cx, uint32_
          new (data) typename ConcreteScope::Data(length);
          new (data) typename ConcreteScope::Data(length);
      return UniquePtr<typename ConcreteScope::Data>(data);
      return UniquePtr<typename ConcreteScope::Data>(data);
  }
  }
@@ -331,7 +330,7 @@ diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
  
  
      uint8_t flags = bindingName->flagsForXDR();
      uint8_t flags = bindingName->flagsForXDR();
      MOZ_ASSERT(((flags << HasAtomShift) >> HasAtomShift) == flags);
      MOZ_ASSERT(((flags << HasAtomShift) >> HasAtomShift) == flags);
-@@ -226,30 +226,31 @@ XDRBindingName(XDRState<XDR_ENCODE>* xdr
+@@ -229,30 +229,31 @@ XDRBindingName(XDRState<XDR_ENCODE>* xdr
  
  
      if (hasAtom)
      if (hasAtom)
          MOZ_TRY(XDRAtom(xdr, &atom));
          MOZ_TRY(XDRAtom(xdr, &atom));
@@ -365,7 +364,7 @@ diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
  static void
  static void
  DeleteScopeData(ConcreteScopeData* data)
  DeleteScopeData(ConcreteScopeData* data)
  {
  {
-@@ -273,28 +274,32 @@ Scope::XDRSizedBindingNames(XDRState<mod
+@@ -276,28 +277,32 @@ Scope::XDRSizedBindingNames(XDRState<mod
      MOZ_TRY(xdr->codeUint32(&length));
      MOZ_TRY(xdr->codeUint32(&length));
  
  
      if (mode == XDR_ENCODE) {
      if (mode == XDR_ENCODE) {
@@ -401,7 +400,7 @@ diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
  /* static */ Scope*
  /* static */ Scope*
  Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
  Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
  {
  {
-@@ -1224,16 +1229,31 @@ GenerateWasmName(JSContext* cx, const ch
+@@ -1227,16 +1232,31 @@ GenerateWasmName(JSContext* cx, const ch
      if (!sb.append(prefix))
      if (!sb.append(prefix))
          return nullptr;
          return nullptr;
      if (!NumberValueToStringBuffer(cx, Int32Value(index), sb))
      if (!NumberValueToStringBuffer(cx, Int32Value(index), sb))
@@ -433,7 +432,7 @@ diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
      Rooted<WasmInstanceScope*> wasmInstanceScope(cx);
      Rooted<WasmInstanceScope*> wasmInstanceScope(cx);
  
  
      {
      {
-@@ -1244,38 +1264,38 @@ WasmInstanceScope::create(JSContext* cx,
+@@ -1247,38 +1267,38 @@ WasmInstanceScope::create(JSContext* cx,
          size_t globalsStart = namesCount;
          size_t globalsStart = namesCount;
          size_t globalsCount = instance->instance().metadata().globals.length();
          size_t globalsCount = instance->instance().metadata().globals.length();
          namesCount += globalsCount;
          namesCount += globalsCount;
@@ -484,7 +483,7 @@ diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
              return nullptr;
              return nullptr;
  
  
          wasmInstanceScope = &scope->as<WasmInstanceScope>();
          wasmInstanceScope = &scope->as<WasmInstanceScope>();
-@@ -1312,25 +1332,27 @@ WasmFunctionScope::create(JSContext* cx,
+@@ -1315,25 +1335,27 @@ WasmFunctionScope::create(JSContext* cx,
      if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
      if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
          return nullptr;
          return nullptr;
      uint32_t namesCount = locals.length();
      uint32_t namesCount = locals.length();

Some files were not shown because too many files changed in this diff