Browse Source

python fixes and js backports

Frank-Rainer Grahl 8 months ago
parent
commit
ce02515da4
100 changed files with 32115 additions and 835 deletions
  1. 29 0
      frg/work-js/comm-release/patches/1879726-port1398229-25319.patch
  2. 1 0
      frg/work-js/comm-release/patches/series
  3. 1 0
      frg/work-js/comm-release/patches/series-test
  4. 3 3
      frg/work-js/mozilla-release/patches/1346211-2-63a1.patch
  5. 21 21
      frg/work-js/mozilla-release/patches/1348273-63a1.patch
  6. 3 3
      frg/work-js/mozilla-release/patches/1351501-1-64a1.patch
  7. 40 37
      frg/work-js/mozilla-release/patches/1378808-1-63a1.patch
  8. 33 147
      frg/work-js/mozilla-release/patches/1378808-2-63a1.patch
  9. 61 80
      frg/work-js/mozilla-release/patches/1378808-3-63a1.patch
  10. 189 0
      frg/work-js/mozilla-release/patches/1398229-1-59a1.patch
  11. 38 0
      frg/work-js/mozilla-release/patches/1398229-2-59a1.patch
  12. 201 0
      frg/work-js/mozilla-release/patches/1398229-3-59a1.patch
  13. 32 0
      frg/work-js/mozilla-release/patches/1398229-4-59a1.patch
  14. 30 0
      frg/work-js/mozilla-release/patches/1430758-59a1.patch
  15. 105 124
      frg/work-js/mozilla-release/patches/1432135-63a1.patch
  16. 10 10
      frg/work-js/mozilla-release/patches/1436742-60a1.patch
  17. 7 7
      frg/work-js/mozilla-release/patches/1436743-60a1.patch
  18. 98 0
      frg/work-js/mozilla-release/patches/1440481-1-63a1.patch
  19. 397 0
      frg/work-js/mozilla-release/patches/1440481-2-63a1.patch
  20. 2 2
      frg/work-js/mozilla-release/patches/1441098-1-62a1.patch
  21. 1450 0
      frg/work-js/mozilla-release/patches/1453795-36-62a1.patch
  22. 1089 0
      frg/work-js/mozilla-release/patches/1453795-41-62a1.patch
  23. 98 0
      frg/work-js/mozilla-release/patches/1456006-1-63a1.patch
  24. 1449 0
      frg/work-js/mozilla-release/patches/1456006-2-63a1.patch
  25. 952 0
      frg/work-js/mozilla-release/patches/1456404-1-63a1.patch
  26. 1092 0
      frg/work-js/mozilla-release/patches/1456404-2-63a1.patch
  27. 667 0
      frg/work-js/mozilla-release/patches/1456404-3-63a1.patch
  28. 940 0
      frg/work-js/mozilla-release/patches/1456404-4-63a1.patch
  29. 485 0
      frg/work-js/mozilla-release/patches/1456404-5-63a1.patch
  30. 436 0
      frg/work-js/mozilla-release/patches/1456404-6-63a1.patch
  31. 186 0
      frg/work-js/mozilla-release/patches/1456404-7-63a1.patch
  32. 31 0
      frg/work-js/mozilla-release/patches/1460489-0-63a1.patch
  33. 371 0
      frg/work-js/mozilla-release/patches/1460489-1-63a1.patch
  34. 2508 0
      frg/work-js/mozilla-release/patches/1460489-2-63a1.patch
  35. 958 0
      frg/work-js/mozilla-release/patches/1460489-3-63a1.patch
  36. 874 0
      frg/work-js/mozilla-release/patches/1460489-4-63a1.patch
  37. 1497 0
      frg/work-js/mozilla-release/patches/1460489-5-63a1.patch
  38. 0 0
      frg/work-js/mozilla-release/patches/1461292-3-62a1.patch
  39. 20 20
      frg/work-js/mozilla-release/patches/1461672-62a1.patch
  40. 4 4
      frg/work-js/mozilla-release/patches/1465350-62a1.patch
  41. 37 29
      frg/work-js/mozilla-release/patches/1465585-3-std-62a1.patch
  42. 510 0
      frg/work-js/mozilla-release/patches/1466626-2no1-62a1.patch
  43. 529 0
      frg/work-js/mozilla-release/patches/1466626-3-62a1.patch
  44. 1 1
      frg/work-js/mozilla-release/patches/1466633-62a1.patch
  45. 67 0
      frg/work-js/mozilla-release/patches/1467275-62a1.patch
  46. 34 0
      frg/work-js/mozilla-release/patches/1467276-62a1.patch
  47. 667 0
      frg/work-js/mozilla-release/patches/1467438-1-62a1.patch
  48. 350 0
      frg/work-js/mozilla-release/patches/1467438-2-62a1.patch
  49. 381 0
      frg/work-js/mozilla-release/patches/1467438-3-62a1.patch
  50. 94 0
      frg/work-js/mozilla-release/patches/1467438-4-62a1.patch
  51. 29 0
      frg/work-js/mozilla-release/patches/1467438-5-62a1.patch
  52. 45 0
      frg/work-js/mozilla-release/patches/1467753-62a1.patch
  53. 317 0
      frg/work-js/mozilla-release/patches/1468867-1-62a1.patch
  54. 1693 0
      frg/work-js/mozilla-release/patches/1468867-2-62a1.patch
  55. 3 4
      frg/work-js/mozilla-release/patches/1469004-63a1.patch
  56. 15 15
      frg/work-js/mozilla-release/patches/1470250-1-63a1.patch
  57. 1174 0
      frg/work-js/mozilla-release/patches/1470522-63a1.patch
  58. 169 0
      frg/work-js/mozilla-release/patches/1471878-63a1.patch
  59. 799 0
      frg/work-js/mozilla-release/patches/1471931-1-63a1.patch
  60. 1552 0
      frg/work-js/mozilla-release/patches/1471931-2-63a1.patch
  61. 323 0
      frg/work-js/mozilla-release/patches/1471931-3-63a1.patch
  62. 568 0
      frg/work-js/mozilla-release/patches/1471931-4-63a1.patch
  63. 643 0
      frg/work-js/mozilla-release/patches/1471931-5-63a1.patch
  64. 500 0
      frg/work-js/mozilla-release/patches/1472211-1-63a1.patch
  65. 460 0
      frg/work-js/mozilla-release/patches/1472211-2-63a1.patch
  66. 51 0
      frg/work-js/mozilla-release/patches/1472291-1-63a1.patch
  67. 454 0
      frg/work-js/mozilla-release/patches/1472291-2-63a1.patch
  68. 33 0
      frg/work-js/mozilla-release/patches/1472666-63a1.patch
  69. 99 0
      frg/work-js/mozilla-release/patches/1472734-63a1.patch
  70. 80 0
      frg/work-js/mozilla-release/patches/1473228-63a1.patch
  71. 48 0
      frg/work-js/mozilla-release/patches/1477621-0-63a1.patch
  72. 320 0
      frg/work-js/mozilla-release/patches/1477621-1-63a1.patch
  73. 154 0
      frg/work-js/mozilla-release/patches/1477621-2-63a1.patch
  74. 124 0
      frg/work-js/mozilla-release/patches/1477621-3-63a1.patch
  75. 182 0
      frg/work-js/mozilla-release/patches/1477621-4-63a1.patch
  76. 946 0
      frg/work-js/mozilla-release/patches/1479900-1-63a1.patch
  77. 1047 0
      frg/work-js/mozilla-release/patches/1479900-2-63a1.patch
  78. 120 0
      frg/work-js/mozilla-release/patches/1480521-BACKOUT-60.patch
  79. 71 107
      frg/work-js/mozilla-release/patches/1480720-63a1.patch
  80. 24 116
      frg/work-js/mozilla-release/patches/1484948-64a1.patch
  81. 3 3
      frg/work-js/mozilla-release/patches/1486173-2-63a1.patch
  82. 30 4
      frg/work-js/mozilla-release/patches/1489698-6-65a1.patch
  83. 178 0
      frg/work-js/mozilla-release/patches/1498980-64a1.patch
  84. 39 0
      frg/work-js/mozilla-release/patches/1517546-67a1.patch
  85. 6 6
      frg/work-js/mozilla-release/patches/1522150-1-66a1.patch
  86. 33 0
      frg/work-js/mozilla-release/patches/1522491-67a1.patch
  87. 5 5
      frg/work-js/mozilla-release/patches/1533481-1-68a1.patch
  88. 7 7
      frg/work-js/mozilla-release/patches/1535226-68a1.patch
  89. 4 4
      frg/work-js/mozilla-release/patches/1539462-1only-webide-71a1.patch
  90. 21 21
      frg/work-js/mozilla-release/patches/1539780-70a1.patch
  91. 12 12
      frg/work-js/mozilla-release/patches/1566141-7-72a1.patch
  92. 4 4
      frg/work-js/mozilla-release/patches/1586358-71a1.patch
  93. 25 25
      frg/work-js/mozilla-release/patches/1590907-5-72a1.patch
  94. 277 0
      frg/work-js/mozilla-release/patches/1600664-73a1.patch
  95. 3 3
      frg/work-js/mozilla-release/patches/1614518-1-75a1.patch
  96. 3 3
      frg/work-js/mozilla-release/patches/1614518-2-75a1.patch
  97. 3 3
      frg/work-js/mozilla-release/patches/1617095-75a1.patch
  98. 3 3
      frg/work-js/mozilla-release/patches/1618620-6-75a1.patch
  99. 2 2
      frg/work-js/mozilla-release/patches/1621960-5-79a1.patch
  100. 336 0
      frg/work-js/mozilla-release/patches/1623024-1-79a1.patch

+ 29 - 0
frg/work-js/comm-release/patches/1879726-port1398229-25319.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Ian Neal <iann_cvs@blueyonder.co.uk>
+# Date 1707593542 0
+# Parent  2d045d456744009f32e073a26077f98995510260
+Bug 1879726 - Save-link-as feature should use the loading principal and context menu using nsIContentPolicy.TYPE_SAVE_AS_DOWNLOAD. r=frg a=frg
+
+diff --git a/suite/base/content/nsContextMenu.js b/suite/base/content/nsContextMenu.js
+--- a/suite/base/content/nsContextMenu.js
++++ b/suite/base/content/nsContextMenu.js
+@@ -1238,17 +1238,18 @@ nsContextMenu.prototype = {
+     // waiting for the filename.
+     function timerCallback() {
+       channel.cancel(NS_ERROR_SAVE_LINK_AS_TIMEOUT);
+     }
+ 
+     // set up a channel to do the saving
+     var channel = NetUtil.newChannel({
+                     uri: makeURI(linkURL),
+-                    loadUsingSystemPrincipal: true,
++                    loadingPrincipal: this.principal,
++                    contentPolicyType: Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD,
+                     securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
+                   });
+ 
+     channel.notificationCallbacks = new Callbacks();
+ 
+     var flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS;
+ 
+     if (bypassCache)

+ 1 - 0
frg/work-js/comm-release/patches/series

@@ -2148,6 +2148,7 @@ TOP-1872623-cancelbookmark-25319.patch
 1466297-62a1.patch
 1877001-port1407891-25319.patch
 1353704-69a1.patch
+1879726-port1398229-25319.patch
 
 
 253-release-top.patch

+ 1 - 0
frg/work-js/comm-release/patches/series-test

@@ -2148,3 +2148,4 @@ TOP-1872623-cancelbookmark-25319.patch
 1466297-62a1.patch
 1877001-port1407891-25319.patch
 1353704-69a1.patch
+1879726-port1398229-25319.patch

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

@@ -2,7 +2,7 @@
 # User Andre Bargull <andre.bargull@gmail.com>
 # Date 1534435998 25200
 # Node ID 62d58886e8d759f52c871a82dbe4d9c2a266c0c7
-# Parent  08bbd610e70b69e299d19ee786a967029802dac7
+# Parent  8e364fec49cc363a5810d1fa37c89f6c1e5265f0
 Bug 1346211 - Part 2: Split JS::ResetTimeZone into an external and internal implementation. r=Waldo
 
 diff --git a/js/public/Date.h b/js/public/Date.h
@@ -461,10 +461,10 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
 diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
 --- a/js/src/vm/Runtime.h
 +++ b/js/src/vm/Runtime.h
-@@ -35,17 +35,16 @@
- # include "js/Proxy.h" // For AutoEnterPolicy
+@@ -36,17 +36,16 @@
  #endif
  #include "js/UniquePtr.h"
+ #include "js/Utility.h"
  #include "js/Vector.h"
  #include "threading/Thread.h"
  #include "vm/Caches.h"

+ 21 - 21
frg/work-js/mozilla-release/patches/1348273-63a1.patch

@@ -2,7 +2,7 @@
 # User Gabriele Svelto <gsvelto@mozilla.com>
 # Date 1530798131 -7200
 # Node ID 42e2eeaca65d313926e962b6583d52d4bcab6d15
-# Parent  47f39bbb24f1cd1e0a91d5fa9e345f8c8374616f
+# Parent  e090ebd42c22a0d21076292fcff689058d7bc013
 Bug 1348273 - Convert crash annotations into a machine-readable list of constants; r=ted.mielczarek,njn,dholbert,mak,cpearce,mcmanus,froydnj,Dexter,jrmuizel,jchen,jimm,bz,surkov
 
 This introduces the machinery needed to generate crash annotations from a YAML
@@ -130,7 +130,7 @@ diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Plat
 diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
 --- a/docshell/base/nsDocShell.cpp
 +++ b/docshell/base/nsDocShell.cpp
-@@ -2407,18 +2407,18 @@ nsDocShell::GetUseRemoteTabs(bool* aUseR
+@@ -2417,18 +2417,18 @@ nsDocShell::GetUseRemoteTabs(bool* aUseR
    *aUseRemoteTabs = mUseRemoteTabs;
    return NS_OK;
  }
@@ -235,7 +235,7 @@ diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp
  ContentChild::AddRemoteAlertObserver(const nsString& aData,
                                       nsIObserver* aObserver)
  {
-@@ -2824,18 +2822,19 @@ ContentChild::ForceKillTimerCallback(nsI
+@@ -2831,18 +2829,19 @@ ContentChild::ForceKillTimerCallback(nsI
  
  mozilla::ipc::IPCResult
  ContentChild::RecvShutdown()
@@ -257,7 +257,7 @@ diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp
    // SchedulerGroup, there can be no other cooperative threads doing work while
    // we're running.
    if (mainThread && mainThread->RecursionDepth() > 1) {
-@@ -2878,20 +2877,21 @@ ContentChild::RecvShutdown()
+@@ -2885,20 +2884,21 @@ ContentChild::RecvShutdown()
    }
  #endif
  
@@ -1137,7 +1137,7 @@ diff --git a/ipc/glue/IPCMessageUtils.h b/ipc/glue/IPCMessageUtils.h
 diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp
 --- a/ipc/glue/MessageChannel.cpp
 +++ b/ipc/glue/MessageChannel.cpp
-@@ -671,19 +671,18 @@ MessageChannel::CanSend() const
+@@ -669,19 +669,18 @@ MessageChannel::CanSend() const
      MonitorAutoLock lock(*mMonitor);
      return Connected();
  }
@@ -1159,7 +1159,7 @@ diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp
      mWorkerLoop = nullptr;
  }
  
-@@ -701,18 +700,17 @@ MessageChannel::Clear()
+@@ -699,18 +698,17 @@ MessageChannel::Clear()
      // before mListener.  But just to be safe, mListener is a weak pointer.
  
  #if !defined(ANDROID)
@@ -1294,13 +1294,13 @@ diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp
 diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h
 --- a/ipc/glue/ProtocolUtils.h
 +++ b/ipc/glue/ProtocolUtils.h
-@@ -25,16 +25,17 @@
- #include "mozilla/ipc/MessageLink.h"
+@@ -26,16 +26,17 @@
  #include "mozilla/LinkedList.h"
  #include "mozilla/Maybe.h"
  #include "mozilla/MozPromise.h"
  #include "mozilla/Mutex.h"
  #include "mozilla/NotNull.h"
+ #include "mozilla/Scoped.h"
  #include "mozilla/UniquePtr.h"
  #include "MainThreadUtils.h"
 +#include "nsICrashReporter.h"
@@ -1312,7 +1312,7 @@ diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h
  
  template<typename T> class nsTHashtable;
  template<typename T> class nsPtrHashKey;
-@@ -690,19 +691,19 @@ private:
+@@ -691,19 +692,19 @@ private:
  
      bool mValid;
      mozilla::ipc::Transport::Mode mMode;
@@ -1334,7 +1334,7 @@ diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h
  template<class PFooParent, class PFooChild>
  nsresult
  CreateEndpoints(const PrivateIPDLInterface& aPrivate,
-@@ -712,17 +713,18 @@ CreateEndpoints(const PrivateIPDLInterfa
+@@ -713,17 +714,18 @@ CreateEndpoints(const PrivateIPDLInterfa
                  Endpoint<PFooChild>* aChildEndpoint)
  {
    MOZ_RELEASE_ASSERT(aParentDestPid);
@@ -1744,7 +1744,7 @@ new file mode 100644
 diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h
 --- a/layout/style/ServoBindings.h
 +++ b/layout/style/ServoBindings.h
-@@ -688,17 +688,17 @@ void Gecko_UnregisterProfilerThread();
+@@ -690,17 +690,17 @@ void Gecko_UnregisterProfilerThread();
  bool Gecko_DocumentRule_UseForPresentation(RawGeckoPresContextBorrowed,
                                             const nsACString* aPattern,
                                             mozilla::css::URLMatchingFunction aURLMatchingFunction);
@@ -2122,7 +2122,7 @@ diff --git a/toolkit/components/gfx/SanityTest.js b/toolkit/components/gfx/Sanit
 diff --git a/toolkit/components/terminator/nsTerminator.cpp b/toolkit/components/terminator/nsTerminator.cpp
 --- a/toolkit/components/terminator/nsTerminator.cpp
 +++ b/toolkit/components/terminator/nsTerminator.cpp
-@@ -549,14 +549,14 @@ nsTerminator::UpdateTelemetry()
+@@ -550,14 +550,14 @@ nsTerminator::UpdateTelemetry()
  }
  
  void
@@ -4627,7 +4627,7 @@ diff --git a/toolkit/crashreporter/test/unit/test_oom_annotation_windows.js b/to
 diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
 --- a/toolkit/xre/nsAppRunner.cpp
 +++ b/toolkit/xre/nsAppRunner.cpp
-@@ -1210,17 +1210,50 @@ nsXULAppInfo::GetExtraFileForID(const ns
+@@ -1199,17 +1199,50 @@ nsXULAppInfo::GetExtraFileForID(const ns
  
    return NS_OK;
  }
@@ -4679,7 +4679,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
    return CrashReporter::AppendAppNotesToCrashReport(data);
  }
  
-@@ -3299,49 +3332,49 @@ XREMain::XRE_mainInit(bool* aExitFlag)
+@@ -3288,49 +3321,49 @@ XREMain::XRE_mainInit(bool* aExitFlag)
      rv = mDirProvider.GetUserAppDataDirectory(getter_AddRefs(file));
      if (NS_SUCCEEDED(rv)) {
        CrashReporter::SetUserAppDataDirectory(file);
@@ -4742,7 +4742,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
  
      // annotate other data (user id etc)
      nsCOMPtr<nsIFile> userAppDataDir;
-@@ -3486,26 +3519,25 @@ XREMain::XRE_mainInit(bool* aExitFlag)
+@@ -3475,26 +3508,25 @@ XREMain::XRE_mainInit(bool* aExitFlag)
              cpuUpdateRevision = static_cast<int>(updateRevision[0]);
              break;
            }
@@ -4774,7 +4774,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
    if (ar == ARG_BAD) {
      PR_fprintf(PR_STDERR, "Error: argument --no-remote is invalid when argument --osint is specified\n");
      return 1;
-@@ -3618,18 +3650,19 @@ static void AnnotateSystemManufacturer()
+@@ -3607,18 +3639,19 @@ static void AnnotateSystemManufacturer()
    }
  
    VARIANT value;
@@ -4796,7 +4796,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
  static void PR_CALLBACK AnnotateSystemManufacturer_ThreadStart(void*)
  {
    HRESULT hr = CoInitialize(nullptr);
-@@ -4229,34 +4262,33 @@ void AddSandboxAnnotations()
+@@ -4218,34 +4251,33 @@ void AddSandboxAnnotations()
  {
    // Include the sandbox content level, regardless of platform
    int level = GetEffectiveContentSandboxLevel();
@@ -4833,7 +4833,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
   * the calling of appStartup->Run().
   */
  nsresult
-@@ -4300,26 +4332,28 @@ XREMain::XRE_mainRun()
+@@ -4289,26 +4321,28 @@ XREMain::XRE_mainRun()
    if (NS_SUCCEEDED(rv)) {
      nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
      rv = prefs->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
@@ -4868,7 +4868,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
  #ifdef XP_WIN
    PR_CreateThread(PR_USER_THREAD, AnnotateSystemManufacturer_ThreadStart, 0,
                    PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
-@@ -4458,17 +4492,18 @@ XREMain::XRE_mainRun()
+@@ -4447,17 +4481,18 @@ XREMain::XRE_mainRun()
    // As FilePreferences need the profile directory, we must initialize right here.
    mozilla::FilePreferences::InitDirectoriesWhitelist();
    mozilla::FilePreferences::InitPrefs();
@@ -4888,7 +4888,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
    nsCOMPtr<nsIFile> workingDir;
    rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
-@@ -4549,18 +4584,18 @@ XREMain::XRE_mainRun()
+@@ -4538,18 +4573,18 @@ XREMain::XRE_mainRun()
  
      nsCOMPtr<nsIObserverService> obsService =
        mozilla::services::GetObserverService();
@@ -4909,7 +4909,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
      rv = cmdLine->Run();
      NS_ENSURE_SUCCESS_LOG(rv, NS_ERROR_FAILURE);
  
-@@ -4595,17 +4630,17 @@ XREMain::XRE_mainRun()
+@@ -4584,17 +4619,17 @@ XREMain::XRE_mainRun()
  #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
    // If we're on Linux, we now have information about the OS capabilities
    // available to us.

+ 3 - 3
frg/work-js/mozilla-release/patches/1351501-1-64a1.patch

@@ -3,7 +3,7 @@
 # Date 1537554033 0
 #      Fri Sep 21 18:20:33 2018 +0000
 # Node ID ab2856e070b9de566ec676655ac42431cdb8c17f
-# Parent  ced758ef38797011db61371c0105bf58b54f73df
+# Parent  5c5960c2b6917011706196535126c1c4d248ae4c
 Bug 1351501, part 1 - Handlify TryPreserveWrapper r=bzbarsky
 
 The patch in the next part will need a handle to the object in
@@ -128,12 +128,12 @@ diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.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
-@@ -3211,17 +3211,17 @@ DisassWithSrc(JSContext* cx, unsigned ar
+@@ -3237,17 +3237,17 @@ DisassWithSrc(JSContext* cx, unsigned ar
      args.rval().setUndefined();
      return true;
  }
  
- #endif /* DEBUG */
+ #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
  
  /* Pretend we can always preserve wrappers for dummy DOM objects. */
  static bool

+ 40 - 37
frg/work-js/mozilla-release/patches/1378808-1-63a1.patch

@@ -2,7 +2,7 @@
 # User Logan F Smyth <loganfsmyth@gmail.com>
 # Date 1531419899 25200
 # Node ID fb38cfb1031dcd9ca730d7aeac46c8dacf24c0e7
-# Parent  b5a05c5f134c06a0f4419d2a27d53070e6831160
+# Parent  fa889b1181c60606f81c2eca2f9d9f8a39aad0bc
 Bug 1378808 - Add a new ParseNodeKind::Arguments node type for call argument lists. r=jorendorff
 
 MozReview-Commit-ID: 7L4nNHjVoZo
@@ -10,7 +10,7 @@ MozReview-Commit-ID: 7L4nNHjVoZo
 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
-@@ -2697,34 +2697,35 @@ ASTSerializer::expression(ParseNode* pn,
+@@ -2698,34 +2698,35 @@ ASTSerializer::expression(ParseNode* pn,
                 builder.unaryExpression(op, expr, &pn->pn_pos, dst);
        }
  
@@ -56,7 +56,7 @@ diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
 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
-@@ -1255,16 +1255,24 @@ BytecodeEmitter::checkSideEffects(ParseN
+@@ -1259,16 +1259,24 @@ BytecodeEmitter::checkSideEffects(ParseN
              goto restart;
          return true;
  
@@ -81,7 +81,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
          MOZ_ASSERT(pn->isArity(PN_LIST));
          MOZ_ASSERT(pn->pn_count >= 2);
          *answer = true;
-@@ -4814,17 +4822,17 @@ BytecodeEmitter::emitForOf(ParseNode* fo
+@@ -4817,17 +4825,17 @@ BytecodeEmitter::emitForOf(ParseNode* fo
  
      ParseNode* forHeadExpr = forOfHead->pn_kid3;
  
@@ -91,7 +91,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
      if (emitterMode == BytecodeEmitter::SelfHosting &&
          forHeadExpr->isKind(ParseNodeKind::Call) &&
 -        forHeadExpr->pn_head->name() == cx->names().allowContentIter)
-+        forHeadExpr->pn_left->name() == cx->names().allowContentIter)
++       forHeadExpr->pn_left->name() == cx->names().allowContentIter)
      {
          allowSelfHostedIter = true;
      }
@@ -100,7 +100,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
  
      if (!forOf.emitIterated())                            //
          return false;
-@@ -6135,45 +6143,47 @@ BytecodeEmitter::emitSelfHostedCallFunct
+@@ -6122,45 +6130,47 @@ BytecodeEmitter::emitSelfHostedCallFunct
      // invokes the callee with the correct |this| object and arguments.
      // callFunction(fun, thisArg, arg0, arg1) thus becomes:
      // - emit lookup for fun
@@ -155,7 +155,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
  
      ParseNode* thisOrNewTarget = funNode->pn_next;
      if (constructing) {
-@@ -6192,36 +6202,36 @@ BytecodeEmitter::emitSelfHostedCallFunct
+@@ -6179,36 +6189,36 @@ BytecodeEmitter::emitSelfHostedCallFunct
              return false;
      }
  
@@ -197,7 +197,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
          return false;
  
      ParseNode* kindNode = valNode->pn_next;
-@@ -6243,34 +6253,36 @@ BytecodeEmitter::emitSelfHostedForceInte
+@@ -6230,34 +6240,36 @@ BytecodeEmitter::emitSelfHostedForceInte
      if (!emit1(JSOP_UNDEFINED))
          return false;
      return true;
@@ -242,7 +242,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
          return false;
  
      ParseNode* valNode = idNode->pn_next;
-@@ -6281,45 +6293,45 @@ BytecodeEmitter::emitSelfHostedDefineDat
+@@ -6268,45 +6280,45 @@ BytecodeEmitter::emitSelfHostedDefineDat
      // but that's fine because the self-hosted code doesn't use the return
      // value.
      return emit1(JSOP_INITELEM);
@@ -296,7 +296,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
  
      if (!emitTree(idNode))
          return false;
-@@ -6338,21 +6350,21 @@ BytecodeEmitter::isRestParameter(ParseNo
+@@ -6325,21 +6337,21 @@ BytecodeEmitter::isRestParameter(ParseNo
  
      FunctionBox* funbox = sc->asFunctionBox();
      RootedFunction fun(cx, funbox->function());
@@ -322,7 +322,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
      JSAtom* name = pn->name();
      Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
      if (paramLoc && lookupName(name) == *paramLoc) {
-@@ -6472,111 +6484,32 @@ BytecodeEmitter::emitPipeline(ParseNode*
+@@ -6459,111 +6471,32 @@ BytecodeEmitter::emitPipeline(ParseNode*
  
          checkTypeSet(JSOP_CALL);
      } while ((callee = callee->pn_next));
@@ -439,7 +439,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
              // parameter:
              //
              //   function f(...args) {
-@@ -6606,25 +6539,110 @@ BytecodeEmitter::emitCallOrNew(ParseNode
+@@ -6593,25 +6526,110 @@ BytecodeEmitter::emitCallOrNew(ParseNode
  
          if (!emitArray(args, argc))
              return false;
@@ -558,7 +558,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
              if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
                  return false;
              checkTypeSet(JSOP_CALL_IGNORES_RV);
-@@ -7199,17 +7217,17 @@ BytecodeEmitter::emitArray(ParseNode* pn
+@@ -7184,17 +7202,17 @@ BytecodeEmitter::emitArray(ParseNode* pn
                  return false;
          } else {
              ParseNode* expr;
@@ -580,7 +580,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
 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
-@@ -803,16 +803,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+@@ -801,16 +801,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
  
      MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
  
@@ -601,7 +601,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter
 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
-@@ -344,16 +344,17 @@ ContainsHoistedDeclaration(JSContext* cx
+@@ -343,16 +343,17 @@ ContainsHoistedDeclaration(JSContext* cx
        case ParseNodeKind::DivAssign:
        case ParseNodeKind::ModAssign:
        case ParseNodeKind::PowAssign:
@@ -619,7 +619,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
        case ParseNodeKind::CallSiteObj:
        case ParseNodeKind::String:
        case ParseNodeKind::RegExp:
-@@ -1404,34 +1405,51 @@ FoldAdd(JSContext* cx, ParseNode** nodeP
+@@ -1402,34 +1403,51 @@ FoldAdd(JSContext* cx, ParseNode** nodeP
      return true;
  }
  
@@ -675,7 +675,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
      // If the last node in the list was replaced, pn_tail points into the wrong node.
      node->pn_tail = listp;
  
-@@ -1637,17 +1655,16 @@ Fold(JSContext* cx, ParseNode** pnp, Per
+@@ -1635,17 +1653,16 @@ Fold(JSContext* cx, ParseNode** pnp, Per
        case ParseNodeKind::Ne:
        case ParseNodeKind::Lt:
        case ParseNodeKind::Le:
@@ -693,7 +693,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
        case ParseNodeKind::Var:
        case ParseNodeKind::Const:
        case ParseNodeKind::Let:
-@@ -1689,20 +1706,24 @@ Fold(JSContext* cx, ParseNode** pnp, Per
+@@ -1687,20 +1704,24 @@ Fold(JSContext* cx, ParseNode** pnp, Per
  
        case ParseNodeKind::Elem:
          return FoldElement(cx, pnp, parser);
@@ -721,12 +721,16 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
 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
-@@ -270,26 +270,30 @@ class FullParseHandler
+@@ -267,30 +267,33 @@ class FullParseHandler
+         return true;
+     }
+ 
      void addArrayElement(ParseNode* literal, ParseNode* element) {
          MOZ_ASSERT(literal->isArity(PN_LIST));
  
          if (!element->isConstant())
              literal->pn_xflags |= PNX_NONCONST;
+-
          addList(/* list = */ literal, /* child = */ element);
      }
  
@@ -758,7 +762,7 @@ diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandl
  
      ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
                          const TokenPos& pos)
-@@ -730,23 +734,18 @@ class FullParseHandler
+@@ -729,23 +732,18 @@ class FullParseHandler
      ParseNode* newModule(const TokenPos& pos) {
          return new_<CodeNode>(ParseNodeKind::Module, JSOP_NOP, pos);
      }
@@ -905,7 +909,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
      F(TemplateStringList) \
      F(TemplateString) \
      F(TaggedTemplate) \
-@@ -366,34 +367,34 @@ IsTypeofKind(ParseNodeKind kind)
+@@ -365,34 +366,34 @@ IsTypeofKind(ParseNodeKind kind)
   * Not,
   * BitNot
   * TypeOfName, unary    pn_kid: UNARY expr
@@ -946,7 +950,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
   *                          destructuring lhs
   *                          pn_left: property id, pn_right: value
   * Shorthand binary     Same fields as Colon. This is used for object
-@@ -403,30 +404,31 @@ IsTypeofKind(ParseNodeKind kind)
+@@ -402,30 +403,31 @@ IsTypeofKind(ParseNodeKind kind)
   * Name,    name        pn_atom: name, string, or object atom
   * String               pn_op: JSOP_GETNAME, JSOP_STRING, or JSOP_OBJECT
   *                          If JSOP_GETNAME, pn_op may be JSOP_*ARG or JSOP_*VAR
@@ -984,7 +988,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
 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
-@@ -3392,34 +3392,34 @@ GeneralParser<ParseHandler, CharT>::addE
+@@ -3364,34 +3364,34 @@ GeneralParser<ParseHandler, CharT>::addE
          return false;
      }
  
@@ -1023,7 +1027,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  GeneralParser<ParseHandler, CharT>::templateLiteral(YieldHandling yieldHandling)
  {
      Node pn = noSubstitutionUntaggedTemplate();
-@@ -8638,68 +8638,71 @@ GeneralParser<ParseHandler, CharT>::assi
+@@ -8599,68 +8599,71 @@ GeneralParser<ParseHandler, CharT>::assi
              errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
              return null();
          }
@@ -1110,7 +1114,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      if (!pc->sc()->allowSuperProperty())
          return false;
  
-@@ -8735,30 +8738,37 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8696,30 +8699,37 @@ GeneralParser<ParseHandler, CharT>::memb
              // Gotten by tryNewTarget
              tt = anyChars.currentToken().type;
              Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
@@ -1157,7 +1161,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          lhs = handler.newSuperBase(thisName, pos());
          if (!lhs)
              return null();
-@@ -8821,25 +8831,26 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8782,25 +8792,26 @@ GeneralParser<ParseHandler, CharT>::memb
                      return null();
                  }
  
@@ -1189,7 +1193,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  Node thisName = newThisName();
                  if (!thisName)
                      return null();
-@@ -8848,23 +8859,16 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8809,23 +8820,16 @@ GeneralParser<ParseHandler, CharT>::memb
                  if (!nextMember)
                      return null();
              } else {
@@ -1213,7 +1217,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      if (prop == context->names().apply) {
                          op = JSOP_FUNAPPLY;
                          if (pc->isFunctionBox())
-@@ -8896,34 +8900,44 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8857,34 +8861,44 @@ GeneralParser<ParseHandler, CharT>::memb
                          // If we're in a method, mark the method as requiring
                          // support for 'super', since direct eval code can use
                          // it. (If we're not in a method, that's fine, so
@@ -1266,7 +1270,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 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
-@@ -1150,17 +1150,17 @@ class MOZ_STACK_CLASS GeneralParser
+@@ -1148,17 +1148,17 @@ class MOZ_STACK_CLASS GeneralParser
      enum FunctionBodyType { StatementListBody, ExpressionBody };
      Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
                        FunctionBodyType type);
@@ -1313,7 +1317,7 @@ diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseH
  
      Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
      Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
-@@ -423,17 +425,17 @@ class SyntaxParseHandler
+@@ -419,17 +421,17 @@ class SyntaxParseHandler
          MOZ_ASSERT(list == NodeGeneric ||
                     list == NodeUnparenthesizedArray ||
                     list == NodeUnparenthesizedObject ||
@@ -1335,7 +1339,7 @@ diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseH
 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
-@@ -411,32 +411,31 @@ ListLength(ParseNode* pn)
+@@ -452,32 +452,31 @@ ListLength(ParseNode* pn)
      MOZ_ASSERT(pn->isArity(PN_LIST));
      return pn->pn_count;
  }
@@ -1371,7 +1375,7 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
      MOZ_ASSERT(pn->isKind(ParseNodeKind::Var) || pn->isKind(ParseNodeKind::Const));
      return ListHead(pn);
  }
-@@ -2795,19 +2794,21 @@ IsArrayViewCtorName(ModuleValidator& m, 
+@@ -3557,19 +3556,21 @@ IsArrayViewCtorName(ModuleValidator& m, 
          *type = Scalar::Float64;
      } else {
          return false;
@@ -1396,7 +1400,7 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
  
      return true;
  }
-@@ -2818,17 +2819,17 @@ CheckNewArrayView(ModuleValidator& m, Pr
+@@ -3580,17 +3581,17 @@ CheckNewArrayView(ModuleValidator& m, Pr
      PropertyName* globalName = m.globalArgumentName();
      if (!globalName)
          return m.fail(newExpr, "cannot create array view without an asm.js global parameter");
@@ -1415,7 +1419,7 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
  
          if (!IsUseOfName(base, globalName))
              return m.failName(base, "expecting '%s.*Array", globalName);
-@@ -2847,17 +2848,17 @@ CheckNewArrayView(ModuleValidator& m, Pr
+@@ -3609,17 +3610,17 @@ CheckNewArrayView(ModuleValidator& m, Pr
  
          if (global->which() != ModuleValidator::Global::ArrayViewCtor)
              return m.failName(ctorExpr, "%s must be an imported array view constructor", globalName);
@@ -1432,6 +1436,5 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
  }
  
  static bool
- CheckGlobalMathImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
-                       PropertyName* field)
-
+ IsSimdValidOperationType(SimdType type, SimdOperation op)
+ {

+ 33 - 147
frg/work-js/mozilla-release/patches/1378808-2-63a1.patch

@@ -2,7 +2,7 @@
 # User Logan F Smyth <loganfsmyth@gmail.com>
 # Date 1531420145 25200
 # Node ID b789f764a1ae22d4b6f09658a9e0d79791b50125
-# Parent  fb38cfb1031dcd9ca730d7aeac46c8dacf24c0e7
+# Parent  d909c62d500eb1dc529d5be87515ed36b141dc75
 Bug 1378808 - Add a new ParseNodeKind::PropertyName to hold location information about property access name. r=jorendorff
 
 MozReview-Commit-ID: J4vHz4ln5Zt
@@ -10,7 +10,7 @@ MozReview-Commit-ID: J4vHz4ln5Zt
 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
-@@ -2736,27 +2736,27 @@ ASTSerializer::expression(ParseNode* pn,
+@@ -2737,27 +2737,27 @@ ASTSerializer::expression(ParseNode* pn,
          return pn->isKind(ParseNodeKind::New)
                 ? builder.newExpression(callee, args, &pn->pn_pos, dst)
  
@@ -42,123 +42,10 @@ diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
        }
  
        case ParseNodeKind::Elem:
-diff --git a/js/src/frontend/BinSource-auto.cpp b/js/src/frontend/BinSource-auto.cpp
---- a/js/src/frontend/BinSource-auto.cpp
-+++ b/js/src/frontend/BinSource-auto.cpp
-@@ -6188,23 +6188,28 @@ BinASTParser<Tok>::parseInterfaceStaticM
- {
-     MOZ_ASSERT(kind == BinKind::StaticMemberAssignmentTarget);
-     BINJS_TRY(CheckRecursionLimit(cx_));
- 
- #if defined(DEBUG)
-     const BinField expected_fields[2] = { BinField::Object, BinField::Property };
-     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
- #endif // defined(DEBUG)
-+    size_t nameStart;
- 
-     BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
--
-     RootedAtom property(cx_);
--    MOZ_TRY_VAR(property, tokenizer_->readAtom());
--
--    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
-+    {
-+        nameStart = tokenizer_->offset();
-+        MOZ_TRY_VAR(property, tokenizer_->readAtom());
-+
-+    }
-+
-+    BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
-+    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
-     return result;
- }
- 
- 
- /*
-  interface StaticMemberExpression : Node {
-     (Expression or Super) object;
-     IdentifierName property;
-@@ -6233,23 +6238,28 @@ BinASTParser<Tok>::parseInterfaceStaticM
- {
-     MOZ_ASSERT(kind == BinKind::StaticMemberExpression);
-     BINJS_TRY(CheckRecursionLimit(cx_));
- 
- #if defined(DEBUG)
-     const BinField expected_fields[2] = { BinField::Object, BinField::Property };
-     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
- #endif // defined(DEBUG)
-+    size_t nameStart;
- 
-     BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
--
-     RootedAtom property(cx_);
--    MOZ_TRY_VAR(property, tokenizer_->readAtom());
--
--    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
-+    {
-+        nameStart = tokenizer_->offset();
-+        MOZ_TRY_VAR(property, tokenizer_->readAtom());
-+
-+    }
-+
-+    BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
-+    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
-     return result;
- }
- 
- 
- /*
-  interface Super : Node {
-  }
- */
-diff --git a/js/src/frontend/BinSource.yaml b/js/src/frontend/BinSource.yaml
---- a/js/src/frontend/BinSource.yaml
-+++ b/js/src/frontend/BinSource.yaml
-@@ -913,22 +913,38 @@ SwitchStatementWithDefault:
-             ParseNode* next = iter->pn_next;
-             factory_.addList(cases, iter);
-             iter = next;
-         }
-         BINJS_TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
-         BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope, true));
- 
- StaticMemberAssignmentTarget:
-+    init:
-+        size_t nameStart;
-+    fields:
-+        property:
-+            block:
-+                before: |
-+                    nameStart = tokenizer_->offset();
-     build: |
--        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
-+        BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
-+        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
- 
- StaticMemberExpression:
-+    init:
-+        size_t nameStart;
-+    fields:
-+        property:
-+            block:
-+                before: |
-+                    nameStart = tokenizer_->offset();
-     build: |
--        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
-+        BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
-+        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
- 
- ThisExpression:
-     build: |
-         if (parseContext_->isFunctionBox())
-             parseContext_->functionBox()->usesThis = true;
- 
-         TokenPos pos = tokenizer_->pos(start);
-         ParseNode* thisName(nullptr);
 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
-@@ -1017,17 +1017,17 @@ BytecodeEmitter::checkSideEffects(ParseN
+@@ -3482,17 +3482,17 @@ BytecodeEmitter::checkSideEffects(ParseN
        case ParseNodeKind::Continue:
        case ParseNodeKind::Debugger:
          MOZ_ASSERT(pn->isArity(PN_NULLARY));
@@ -177,15 +64,15 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
        case ParseNodeKind::Void:
        case ParseNodeKind::Not:
          MOZ_ASSERT(pn->isArity(PN_UNARY));
-@@ -1397,16 +1397,17 @@ BytecodeEmitter::checkSideEffects(ParseN
-       case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
-       case ParseNodeKind::ImportSpec:      // by ParseNodeKind::Import
-       case ParseNodeKind::ExportBatchSpec:// by ParseNodeKind::Export
-       case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
-       case ParseNodeKind::ExportSpec:      // by ParseNodeKind::Export
-       case ParseNodeKind::CallSiteObj:      // by ParseNodeKind::TaggedTemplate
-       case ParseNodeKind::PosHolder:        // by ParseNodeKind::NewTarget
-       case ParseNodeKind::SuperBase:        // by ParseNodeKind::Elem and others
+@@ -3862,16 +3862,17 @@ BytecodeEmitter::checkSideEffects(ParseN
+       case ParseNodeKind::ImportSpecList:   // byParseNodeKind::Import
+       case ParseNodeKind::ImportSpec:       // byParseNodeKind::Import
+       case ParseNodeKind::ExportBatchSpec:  // byParseNodeKind::Export
+       case ParseNodeKind::ExportSpecList:   // byParseNodeKind::Export
+       case ParseNodeKind::ExportSpec:       // byParseNodeKind::Export
+       case ParseNodeKind::CallSiteObj:      // byParseNodeKind::TaggedTemplate
+       case ParseNodeKind::PosHolder:        // byParseNodeKind::NewTarget
+       case ParseNodeKind::SuperBase:        // byParseNodeKind::Elem and others
 +      case ParseNodeKind::PropertyName:     // by ParseNodeKind::Dot
          MOZ_CRASH("handled by parent nodes");
  
@@ -195,7 +82,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
  
      MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
                "BytecodeEmitter::checkSideEffects");
-@@ -1868,49 +1869,49 @@ BytecodeEmitter::emitTDZCheckIfNeeded(JS
+@@ -4303,49 +4304,49 @@ BytecodeEmitter::emitTDZCheckIfNeeded(JS
  }
  
  bool
@@ -256,7 +143,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
      // The non-optimized case.
      return emitTree(pn2);
  }
-@@ -1925,41 +1926,41 @@ BytecodeEmitter::emitSuperPropLHS(ParseN
+@@ -4360,41 +4361,41 @@ BytecodeEmitter::emitSuperPropLHS(ParseN
      if (!emit1(JSOP_SUPERBASE))
          return false;
      return true;
@@ -301,7 +188,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
      return true;
  }
  
-@@ -1979,17 +1980,17 @@ BytecodeEmitter::emitPropIncDec(ParseNod
+@@ -4414,17 +4415,17 @@ BytecodeEmitter::emitPropIncDec(ParseNod
          if (!emit1(JSOP_DUP2))                      // THIS OBJ THIS OBJ
              return false;
      } else {
@@ -320,7 +207,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
      if (!emit1(JSOP_ONE))                           // OBJ N? N 1
          return false;
      if (!emit1(binop))                              // OBJ N? N+1
-@@ -2005,17 +2006,17 @@ BytecodeEmitter::emitPropIncDec(ParseNod
+@@ -4440,17 +4441,17 @@ BytecodeEmitter::emitPropIncDec(ParseNod
                  return false;
              if (!emit1(JSOP_SWAP))                 // N THIS OBJ N+1
                  return false;
@@ -339,7 +226,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
  }
  
  bool
-@@ -2695,17 +2696,17 @@ BytecodeEmitter::emitDestructuringLHSRef
+@@ -5335,17 +5336,17 @@ BytecodeEmitter::emitDestructuringLHSRef
  
      switch (target->getKind()) {
        case ParseNodeKind::Dot: {
@@ -358,7 +245,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
  
        case ParseNodeKind::Elem: {
          if (target->as<PropertyByValue>().isSuper()) {
-@@ -2813,17 +2814,17 @@ BytecodeEmitter::emitSetOrInitializeDest
+@@ -5453,17 +5454,17 @@ BytecodeEmitter::emitSetOrInitializeDest
  
            case ParseNodeKind::Dot: {
              // The reference is already pushed by emitDestructuringLHSRef.
@@ -377,7 +264,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
              // The reference is already pushed by emitDestructuringLHSRef.
              if (target->as<PropertyByValue>().isSuper()) {
                  JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
-@@ -3926,21 +3927,21 @@ BytecodeEmitter::emitAssignment(ParseNod
+@@ -6565,21 +6566,21 @@ BytecodeEmitter::emitAssignment(ParseNod
  
      switch (lhs->getKind()) {
        case ParseNodeKind::Dot:
@@ -401,7 +288,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
          if (lhs->as<PropertyByValue>().isSuper()) {
              if (!emitSuperElemOperands(lhs, opt))
                  return false;
-@@ -3979,17 +3980,17 @@ BytecodeEmitter::emitAssignment(ParseNod
+@@ -6618,17 +6619,17 @@ BytecodeEmitter::emitAssignment(ParseNod
              JSOp getOp;
              if (lhs->as<PropertyAccess>().isSuper()) {
                  if (!emit1(JSOP_DUP2))
@@ -420,7 +307,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
            }
            case ParseNodeKind::Elem: {
              JSOp elemOp;
-@@ -8265,18 +8266,19 @@ BytecodeEmitter::emitTree(ParseNode* pn,
+@@ -11284,18 +11285,19 @@ BytecodeEmitter::emitTree(ParseNode* pn,
              return false;
          break;
  
@@ -444,7 +331,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
 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
-@@ -342,16 +342,17 @@ ContainsHoistedDeclaration(JSContext* cx
+@@ -341,16 +341,17 @@ ContainsHoistedDeclaration(JSContext* cx
        case ParseNodeKind::UrshAssign:
        case ParseNodeKind::MulAssign:
        case ParseNodeKind::DivAssign:
@@ -462,7 +349,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
        case ParseNodeKind::TemplateString:
        case ParseNodeKind::TemplateStringList:
        case ParseNodeKind::TaggedTemplate:
-@@ -1249,17 +1250,20 @@ FoldElement(JSContext* cx, ParseNode** n
+@@ -1247,17 +1248,20 @@ FoldElement(JSContext* cx, ParseNode** n
      }
  
      // If we don't have a name, we can't optimize to getprop.
@@ -484,7 +371,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
      return true;
  }
  
-@@ -1495,24 +1499,24 @@ FoldForHead(JSContext* cx, ParseNode* no
+@@ -1493,24 +1497,24 @@ FoldForHead(JSContext* cx, ParseNode* no
  
      return true;
  }
@@ -513,7 +400,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
  static bool
  FoldName(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& parser)
  {
-@@ -1793,16 +1797,19 @@ Fold(JSContext* cx, ParseNode** pnp, Per
+@@ -1791,16 +1795,19 @@ Fold(JSContext* cx, ParseNode** pnp, Per
  
        case ParseNodeKind::ForHead:
          return FoldForHead(cx, pn, parser);
@@ -536,7 +423,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
 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
-@@ -659,18 +659,22 @@ class FullParseHandler
+@@ -658,18 +658,22 @@ class FullParseHandler
          TokenPos pos(begin, (finallyBlock ? finallyBlock : catchScope)->pn_pos.end);
          return new_<TernaryNode>(ParseNodeKind::Try, body, catchScope, finallyBlock, pos);
      }
@@ -732,7 +619,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
      F(Label) \
      F(Object) \
      F(Call) \
-@@ -377,18 +378,19 @@ IsTypeofKind(ParseNodeKind kind)
+@@ -379,18 +380,19 @@ IsTypeofKind(ParseNodeKind kind)
   * DeleteName unary     pn_kid: Name expr
   * DeleteProp unary     pn_kid: Dot expr
   * DeleteElem unary     pn_kid: Elem expr
@@ -754,7 +641,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
   *                          pn_count: N (where N is number of args)
   * Array    list        pn_head: list of pn_count array element exprs
   *                          [,,] holes are represented by Elision nodes
-@@ -568,18 +570,17 @@ class ParseNode
+@@ -570,18 +572,17 @@ class ParseNode
          } unary;
          struct {                        /* name, labeled statement, etc. */
              union {
@@ -774,7 +661,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
          struct {
              double       value;         /* aligned numeric literal value */
              DecimalPoint decimalPoint;  /* Whether the number has a decimal point */
-@@ -1173,40 +1174,43 @@ class RegExpLiteral : public NullaryNode
+@@ -1179,40 +1180,43 @@ class RegExpLiteral : public NullaryNode
      static bool test(const ParseNode& node) {
          bool match = node.isKind(ParseNodeKind::RegExp);
          MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
@@ -829,7 +716,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
 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
-@@ -8795,17 +8795,22 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8756,17 +8756,22 @@ GeneralParser<ParseHandler, CharT>::memb
              if (!tokenStream.getToken(&tt))
                  return null();
              if (TokenKindIsPossibleIdentifierName(tt)) {
@@ -856,7 +743,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 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
-@@ -564,18 +564,22 @@ class MOZ_STACK_CLASS PerHandlerParser
+@@ -562,18 +562,22 @@ class MOZ_STACK_CLASS PerHandlerParser
      // If ParseHandler is FullParseHandler:
      //   Do nothing.
      inline void clearAbortedSyntaxParse();
@@ -884,7 +771,7 @@ diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
 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
-@@ -329,18 +329,22 @@ class SyntaxParseHandler
+@@ -325,18 +325,22 @@ class SyntaxParseHandler
      }
  
      Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; }
@@ -912,7 +799,7 @@ diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseH
 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
-@@ -588,26 +588,26 @@ NumberNodeHasFrac(ParseNode* pn)
+@@ -628,26 +628,26 @@ NumberNodeHasFrac(ParseNode* pn)
      MOZ_ASSERT(pn->isKind(ParseNodeKind::Number));
      return pn->pn_u.number.decimalPoint == HasDecimal;
  }
@@ -943,4 +830,3 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
      MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem));
      return BinaryLeft(pn);
  }
-

+ 61 - 80
frg/work-js/mozilla-release/patches/1378808-3-63a1.patch

@@ -2,13 +2,13 @@
 # User Logan F Smyth <loganfsmyth@gmail.com>
 # Date 1531421477 25200
 # Node ID 50338591c8f31326a22921c10cc470849aa4e430
-# Parent  b789f764a1ae22d4b6f09658a9e0d79791b50125
+# Parent  6b41490df55b98d9ae91f1015040a757267e01a9
 Bug 1378808 - Use ::Arguments or ::PropertyName location for method call column offsets. r=jorendorff, r=ckerschb
 
 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
-@@ -6637,27 +6637,72 @@ BytecodeEmitter::emitCallOrNew(ParseNode
+@@ -9683,27 +9683,72 @@ BytecodeEmitter::emitCallOrNew(ParseNode
              if (!emitDupAt(argc + 1))
                  return false;
          } else {
@@ -180,97 +180,78 @@ diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets.js b/js/src/
 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
-@@ -254,17 +254,17 @@ BEGIN_TEST(testSavedStacks_selfHostedFra
+@@ -247,17 +247,17 @@ BEGIN_TEST(testSavedStacks_selfHostedFra
      CHECK(result == JS::SavedFrameResult::Ok);
      CHECK_EQUAL(line, 3U);
  
      // Column
      uint32_t column = 123;
-     result = JS::GetSavedFrameColumn(cx, principals, selfHostedFrame, &column,
+     result = JS::GetSavedFrameColumn(cx, selfHostedFrame, &column,
                                       JS::SavedFrameSelfHosted::Exclude);
      CHECK(result == JS::SavedFrameResult::Ok);
 -    CHECK_EQUAL(column, 5U);
 +    CHECK_EQUAL(column, 9U);
  
      // Function display name
-     result = JS::GetSavedFrameFunctionDisplayName(cx, principals, selfHostedFrame, &str,
+     result = JS::GetSavedFrameFunctionDisplayName(cx, selfHostedFrame, &str,
                                                    JS::SavedFrameSelfHosted::Exclude);
      CHECK(result == JS::SavedFrameResult::Ok);
      lin = str->ensureLinear(cx);
      CHECK(lin);
      CHECK(js::StringEqualsAscii(lin, "one"));
-diff --git a/js/xpconnect/tests/unit/test_getCallerLocation.js b/js/xpconnect/tests/unit/test_getCallerLocation.js
---- a/js/xpconnect/tests/unit/test_getCallerLocation.js
-+++ b/js/xpconnect/tests/unit/test_getCallerLocation.js
-@@ -34,33 +34,33 @@ add_task(async function() {
-   `, 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.column, 18, "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");
-+  equal(String(frame), "it@thing.js:5:18\n", "Stringified frame");
- 
- 
-   // reportError
- 
-   let {messages} = await AddonTestUtils.promiseConsoleOutput(() => {
-     Cu.reportError("Meh", frame);
-   });
- 
-   let [msg] = messages.filter(m => m.message.includes("Meh"));
- 
-   equal(msg.stack, frame, "reportError stack frame");
--  equal(msg.message, '[JavaScript Error: "Meh" {file: "thing.js" line: 5}]\nit@thing.js:5:14\n');
-+  equal(msg.message, '[JavaScript Error: "Meh" {file: "thing.js" line: 5}]\nit@thing.js:5:18\n');
- 
-   Assert.throws(() => { Cu.reportError("Meh", {}); },
-                 err => err.result == Cr.NS_ERROR_INVALID_ARG,
-                 "reportError should throw when passed a non-SavedFrame object");
- 
- 
-   // createError
- 
-@@ -77,10 +77,10 @@ add_task(async function() {
-   equal(Cu.getGlobalForObject(error), sandbox,
-         "createError creates errors in the global of the SavedFrame");
-   equal(error.stack, String(cloned),
-         "createError creates errors with the correct stack");
- 
-   equal(error.message, "Meh", "Error message");
-   equal(error.fileName, "thing.js", "Error filename");
-   equal(error.lineNumber, 5, "Error line");
--  equal(error.columnNumber, 14, "Error column");
-+  equal(error.columnNumber, 18, "Error column");
- });
-diff --git a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
---- a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
-+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
-@@ -38,17 +38,17 @@
-                 assert_equals(e.lineNumber, 118);
-                 assert_equals(e.columnNumber, 4);
-                 assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.");
-                 return watcher.wait_for('securitypolicyviolation');
-             }))
-             .then(t.step_func(e => {
-                 assert_equals(e.blockedURI, "inline");
-                 assert_equals(e.lineNumber, 131);
--                assert_equals(e.columnNumber, 4);
-+                assert_in_array(e.columnNumber, [4, 59]);
-                 assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.");
-                 return watcher.wait_for('securitypolicyviolation');
-             }))
-             .then(t.step_func(e => {
-                 assert_equals(e.blockedURI, "inline");
-                 assert_equals(e.lineNumber, 139);
-                 assert_equals(e.columnNumber, 4);
-                 assert_equals(e.target, document, "Inline event handlers for disconnected elements target the document.");
-
+diff --git a/js/xpconnect/tests/unit/test_getCallerLocation.js.3-1378808.later b/js/xpconnect/tests/unit/test_getCallerLocation.js.3-1378808.later
+new file mode 100644
+--- /dev/null
++++ b/js/xpconnect/tests/unit/test_getCallerLocation.js.3-1378808.later
+@@ -0,0 +1,51 @@
++--- test_getCallerLocation.js
+++++ test_getCallerLocation.js
++@@ -34,33 +34,33 @@ add_task(async function() {
++   `, 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.column, 18, "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");
+++  equal(String(frame), "it@thing.js:5:18\n", "Stringified frame");
++ 
++ 
++   // reportError
++ 
++   let {messages} = await AddonTestUtils.promiseConsoleOutput(() => {
++     Cu.reportError("Meh", frame);
++   });
++ 
++   let [msg] = messages.filter(m => m.message.includes("Meh"));
++ 
++   equal(msg.stack, frame, "reportError stack frame");
++-  equal(msg.message, '[JavaScript Error: "Meh" {file: "thing.js" line: 5}]\nit@thing.js:5:14\n');
+++  equal(msg.message, '[JavaScript Error: "Meh" {file: "thing.js" line: 5}]\nit@thing.js:5:18\n');
++ 
++   Assert.throws(() => { Cu.reportError("Meh", {}); },
++                 err => err.result == Cr.NS_ERROR_INVALID_ARG,
++                 "reportError should throw when passed a non-SavedFrame object");
++ 
++ 
++   // createError
++ 
++@@ -77,10 +77,10 @@ add_task(async function() {
++   equal(Cu.getGlobalForObject(error), sandbox,
++         "createError creates errors in the global of the SavedFrame");
++   equal(error.stack, String(cloned),
++         "createError creates errors with the correct stack");
++ 
++   equal(error.message, "Meh", "Error message");
++   equal(error.fileName, "thing.js", "Error filename");
++   equal(error.lineNumber, 5, "Error line");
++-  equal(error.columnNumber, 14, "Error column");
+++  equal(error.columnNumber, 18, "Error column");
++ });

+ 189 - 0
frg/work-js/mozilla-release/patches/1398229-1-59a1.patch

@@ -0,0 +1,189 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1510831573 -3600
+# Node ID 314c6024ea272b3d53214e94ae703a707ffcc624
+# Parent  f234d6ded6daaf2f0b032d67809cbd5ccb83ddba
+Bug 1398229 - Save-link-as feature should use the loading principal - part 1 - test, r=ckerschb
+
+diff --git a/browser/components/contextualidentity/test/browser/browser.ini b/browser/components/contextualidentity/test/browser/browser.ini
+--- a/browser/components/contextualidentity/test/browser/browser.ini
++++ b/browser/components/contextualidentity/test/browser/browser.ini
+@@ -25,8 +25,12 @@ tags = openwindow
+ tags = openwindow
+ [browser_serviceworkers.js]
+ [browser_broadcastchannel.js]
+ [browser_blobUrl.js]
+ [browser_middleClick.js]
+ [browser_imageCache.js]
+ [browser_count_and_remove.js]
+ [browser_relatedTab.js]
++[browser_saveLink.js]
++support-files =
++  saveLink.sjs
++  !/toolkit/content/tests/browser/common/mockTransfer.js
+diff --git a/browser/components/contextualidentity/test/browser/browser_saveLink.js b/browser/components/contextualidentity/test/browser/browser_saveLink.js
+new file mode 100644
+--- /dev/null
++++ b/browser/components/contextualidentity/test/browser/browser_saveLink.js
+@@ -0,0 +1,111 @@
++"use strict";
++
++const BASE_ORIGIN = "https://example.com";
++const URI = BASE_ORIGIN +
++  "/browser/browser/components/contextualidentity/test/browser/saveLink.sjs";
++
++let MockFilePicker = SpecialPowers.MockFilePicker;
++MockFilePicker.init(window);
++
++add_task(async function setup() {
++  info("Setting the prefs.");
++
++  // make sure userContext is enabled.
++  await SpecialPowers.pushPrefEnv({"set": [
++    ["privacy.userContext.enabled", true]
++  ]});
++});
++
++add_task(async function test() {
++  info("Let's open a new window");
++  let win = await BrowserTestUtils.openNewBrowserWindow();
++
++  info("Opening tab with UCI: 1");
++  let tab = BrowserTestUtils.addTab(win.gBrowser, URI + "?UCI=1", {userContextId: 1});
++
++  // select tab and make sure its browser is focused
++  win.gBrowser.selectedTab = tab;
++  tab.ownerGlobal.focus();
++
++  info("Waiting to load content");
++  let browser = gBrowser.getBrowserForTab(tab);
++  await BrowserTestUtils.browserLoaded(browser);
++
++  let popupShownPromise = BrowserTestUtils.waitForEvent(win.document, "popupshown");
++
++  await BrowserTestUtils.synthesizeMouseAtCenter("#fff", {type: "contextmenu", button: 2},
++                                                 win.gBrowser.selectedBrowser);
++  info("Right clicked!");
++
++  await popupShownPromise;
++  info("Context menu opened");
++
++  info("Let's create a temporary dir");
++  let tempDir = createTemporarySaveDirectory();
++  let destFile;
++
++  MockFilePicker.displayDirectory = tempDir;
++  MockFilePicker.showCallback = fp => {
++    info("MockFilePicker showCallback");
++
++    let fileName = fp.defaultString;
++    destFile = tempDir.clone();
++    destFile.append(fileName);
++
++    MockFilePicker.setFiles([destFile]);
++    MockFilePicker.filterIndex = 1; // kSaveAsType_URL
++
++    info("MockFilePicker showCallback done");
++  };
++
++  let transferCompletePromise = new Promise((resolve) => {
++    function onTransferComplete(downloadSuccess) {
++      ok(downloadSuccess, "File should have been downloaded successfully");
++      resolve();
++    }
++
++    mockTransferCallback = onTransferComplete;
++    mockTransferRegisterer.register();
++  });
++
++  registerCleanupFunction(function() {
++    mockTransferRegisterer.unregister();
++    MockFilePicker.cleanup();
++    tempDir.remove(true);
++  });
++
++  // Select "Save Link As" option from context menu
++  let saveLinkCommand = win.document.getElementById("context-savelink");
++  info("saveLinkCommand: " + saveLinkCommand);
++  saveLinkCommand.doCommand();
++
++  let contextMenu = win.document.getElementById("contentAreaContextMenu");
++  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
++  contextMenu.hidePopup();
++  await popupHiddenPromise;
++  info("popup hidden");
++
++  await transferCompletePromise;
++
++  // Let's query the SJS to know if the download happened with the correct cookie.
++  let response = await fetch(URI + "?result=1");
++  let text = await response.text();
++  is(text, "Result:UCI=1", "Correct cookie used: -" + text + "-");
++
++  info("Closing the window");
++  await BrowserTestUtils.closeWindow(win);
++});
++
++/* import-globals-from ../../../../../toolkit/content/tests/browser/common/mockTransfer.js */
++Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js", this);
++
++function createTemporarySaveDirectory() {
++  let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
++  saveDir.append("testsavedir");
++  if (!saveDir.exists()) {
++    info("create testsavedir!");
++    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
++  }
++  info("return from createTempSaveDir: " + saveDir.path);
++  return saveDir;
++}
+diff --git a/browser/components/contextualidentity/test/browser/saveLink.sjs b/browser/components/contextualidentity/test/browser/saveLink.sjs
+new file mode 100644
+--- /dev/null
++++ b/browser/components/contextualidentity/test/browser/saveLink.sjs
+@@ -0,0 +1,45 @@
++const HTTP_ORIGIN = "http://example.com";
++const HTTPS_ORIGIN = "https://example.com";
++const URI_PATH = "/browser/browser/components/contextualidentity/test/browser/saveLink.sjs";
++
++Components.utils.importGlobalProperties(["URLSearchParams"]);
++
++function handleRequest(aRequest, aResponse) {
++  var params = new URLSearchParams(aRequest.queryString);
++
++  // This is the first request, where we set the cookie.
++  if (params.has("UCI")) {
++    aResponse.setStatusLine(aRequest.httpVersion, 200);
++    aResponse.setHeader("Set-Cookie", "UCI=" + params.get("UCI"));
++    aResponse.write("<html><body><a href='" + HTTPS_ORIGIN + URI_PATH + "?redirect=1' id='fff'>this is a link</a></body></html>");
++    return;
++  }
++
++  // Second request. This is the save-as content, but we make a redirect to see
++  // if we are able to follow it.
++  if (params.has("redirect")) {
++    aResponse.setStatusLine(aRequest.httpVersion, 302, "Found");
++    aResponse.setHeader("Location", HTTP_ORIGIN + URI_PATH + "?download=1", false);
++    aResponse.write("Redirect!");
++    return;
++  }
++
++  // This is the 3rd request where we offer the content to be saved.
++  if (params.has("download")) {
++    setState("downloadUCI", aRequest.getHeader("Cookie"));
++    aResponse.setStatusLine(aRequest.httpVersion, 200);
++    aResponse.write("All Good!");
++    return;
++  }
++
++  // This is the last request to check that the download happened with the correct cookie
++  if (params.has("result")) {
++    aResponse.setStatusLine(aRequest.httpVersion, 200);
++    aResponse.write("Result:" + getState("downloadUCI"));
++    return;
++  }
++
++  // We should not be here!
++  aResponse.setStatusLine(aRequest.httpVersion, 500);
++  aResponse.write("ERROR!!!");
++}

+ 38 - 0
frg/work-js/mozilla-release/patches/1398229-2-59a1.patch

@@ -0,0 +1,38 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1510831590 -3600
+# Node ID e7d2101e1aa91d7e171aa9687acb8807a72d5fad
+# Parent  7bcacf8815ba28b9d1cc7cc1616699c4d60b7c0b
+Bug 1398229 - Save-link-as feature should use the loading principal - part 2 - context menu using nsIContentPolicy.TYPE_SAVE_AS_DOWNLOAD, r=ckerschb
+
+diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js
+--- a/browser/base/content/nsContextMenu.js
++++ b/browser/base/content/nsContextMenu.js
+@@ -1416,24 +1416,21 @@ nsContextMenu.prototype = {
+     function timerCallback() {}
+     timerCallback.prototype = {
+       notify: function sLA_timer_notify(aTimer) {
+         channel.cancel(NS_ERROR_SAVE_LINK_AS_TIMEOUT);
+       }
+     };
+ 
+     // setting up a new channel for 'right click - save link as ...'
+-    // ideally we should use:
+-    // * doc            - as the loadingNode, and/or
+-    // * this.principal - as the loadingPrincipal
+-    // for now lets use systemPrincipal to bypass mixedContentBlocker
+-    // checks after redirects, see bug: 1136055
+     var channel = NetUtil.newChannel({
+                     uri: makeURI(linkURL),
+-                    loadUsingSystemPrincipal: true
++                    loadingPrincipal: this.principal,
++                    contentPolicyType: Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD,
++                    securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
+                   });
+ 
+     if (linkDownload)
+       channel.contentDispositionFilename = linkDownload;
+     if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
+       let docIsPrivate = PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser);
+       channel.setPrivate(docIsPrivate);
+     }

+ 201 - 0
frg/work-js/mozilla-release/patches/1398229-3-59a1.patch

@@ -0,0 +1,201 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1510831621 -3600
+# Node ID 6b4cebf12e3fd1d1603f03b84a6cfdeb200204fc
+# Parent  5f79bf0fffe9fbf5ba2aa2e06b9d11b462de8459
+Bug 1398229 - Save-link-as feature should use the loading principal - part 3 - implementation of nsIContentPolicy.TYPE_SAVE_AS_DOWNLOAD, r=ckerschb, r=tanvi
+
+diff --git a/dom/base/nsContentPolicyUtils.h b/dom/base/nsContentPolicyUtils.h
+--- a/dom/base/nsContentPolicyUtils.h
++++ b/dom/base/nsContentPolicyUtils.h
+@@ -110,16 +110,17 @@ NS_CP_ContentTypeName(uint32_t contentTy
+     CASE_RETURN( TYPE_MEDIA                       );
+     CASE_RETURN( TYPE_WEBSOCKET                   );
+     CASE_RETURN( TYPE_CSP_REPORT                  );
+     CASE_RETURN( TYPE_XSLT                        );
+     CASE_RETURN( TYPE_BEACON                      );
+     CASE_RETURN( TYPE_FETCH                       );
+     CASE_RETURN( TYPE_IMAGESET                    );
+     CASE_RETURN( TYPE_WEB_MANIFEST                );
++    CASE_RETURN( TYPE_SAVEAS_DOWNLOAD             );
+     CASE_RETURN( TYPE_INTERNAL_SCRIPT             );
+     CASE_RETURN( TYPE_INTERNAL_WORKER             );
+     CASE_RETURN( TYPE_INTERNAL_SHARED_WORKER      );
+     CASE_RETURN( TYPE_INTERNAL_EMBED              );
+     CASE_RETURN( TYPE_INTERNAL_OBJECT             );
+     CASE_RETURN( TYPE_INTERNAL_FRAME              );
+     CASE_RETURN( TYPE_INTERNAL_IFRAME             );
+     CASE_RETURN( TYPE_INTERNAL_AUDIO              );
+diff --git a/dom/base/nsIContentPolicy.idl.1398229-3.later b/dom/base/nsIContentPolicy.idl.1398229-3.later
+new file mode 100644
+--- /dev/null
++++ b/dom/base/nsIContentPolicy.idl.1398229-3.later
+@@ -0,0 +1,24 @@
++--- nsIContentPolicy.idl
+++++ nsIContentPolicy.idl
++@@ -177,16 +177,21 @@ interface nsIContentPolicy : nsISupports
++   const nsContentPolicyType TYPE_IMAGESET = 21;
++ 
++   /**
++    * Indicates a web manifest.
++    */
++   const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
++ 
++   /**
+++   * Indicates an save-as link download from the front-end code.
+++   */
+++  const nsContentPolicyType TYPE_SAVEAS_DOWNLOAD = 43;
+++
+++  /**
++    * Indicates an internal constant for scripts loaded through script
++    * elements.
++    *
++    * This will be mapped to TYPE_SCRIPT before being passed to content policy
++    * implementations.
++    */
++   const nsContentPolicyType TYPE_INTERNAL_SCRIPT = 23;
++ 
+diff --git a/dom/base/nsIContentPolicyBase.idl b/dom/base/nsIContentPolicyBase.idl
+--- a/dom/base/nsIContentPolicyBase.idl
++++ b/dom/base/nsIContentPolicyBase.idl
+@@ -177,16 +177,21 @@ interface nsIContentPolicyBase : nsISupp
+   const nsContentPolicyType TYPE_IMAGESET = 21;
+ 
+   /**
+    * Indicates a web manifest.
+    */
+   const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
+ 
+   /**
++   * Indicates an save-as link download from the front-end code.
++   */
++  const nsContentPolicyType TYPE_SAVEAS_DOWNLOAD = 43;
++
++  /**
+    * Indicates an internal constant for scripts loaded through script
+    * elements.
+    *
+    * This will be mapped to TYPE_SCRIPT before being passed to content policy
+    * implementations.
+    */
+   const nsContentPolicyType TYPE_INTERNAL_SCRIPT = 23;
+ 
+diff --git a/dom/cache/DBSchema.cpp b/dom/cache/DBSchema.cpp
+--- a/dom/cache/DBSchema.cpp
++++ b/dom/cache/DBSchema.cpp
+@@ -306,16 +306,17 @@ static_assert(nsIContentPolicy::TYPE_INV
+               nsIContentPolicy::TYPE_MEDIA == 15 &&
+               nsIContentPolicy::TYPE_WEBSOCKET == 16 &&
+               nsIContentPolicy::TYPE_CSP_REPORT == 17 &&
+               nsIContentPolicy::TYPE_XSLT == 18 &&
+               nsIContentPolicy::TYPE_BEACON == 19 &&
+               nsIContentPolicy::TYPE_FETCH == 20 &&
+               nsIContentPolicy::TYPE_IMAGESET == 21 &&
+               nsIContentPolicy::TYPE_WEB_MANIFEST == 22 &&
++              nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD == 43 &&
+               nsIContentPolicy::TYPE_INTERNAL_SCRIPT == 23 &&
+               nsIContentPolicy::TYPE_INTERNAL_WORKER == 24 &&
+               nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER == 25 &&
+               nsIContentPolicy::TYPE_INTERNAL_EMBED == 26 &&
+               nsIContentPolicy::TYPE_INTERNAL_OBJECT == 27 &&
+               nsIContentPolicy::TYPE_INTERNAL_FRAME == 28 &&
+               nsIContentPolicy::TYPE_INTERNAL_IFRAME == 29 &&
+               nsIContentPolicy::TYPE_INTERNAL_AUDIO == 30 &&
+diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp
+--- a/dom/fetch/InternalRequest.cpp
++++ b/dom/fetch/InternalRequest.cpp
+@@ -321,16 +321,19 @@ InternalRequest::MapContentPolicyTypeToR
+     context = RequestContext::Fetch;
+     break;
+   case nsIContentPolicy::TYPE_IMAGESET:
+     context = RequestContext::Imageset;
+     break;
+   case nsIContentPolicy::TYPE_WEB_MANIFEST:
+     context = RequestContext::Manifest;
+     break;
++  case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
++    context = RequestContext::Internal;
++    break;
+   default:
+     MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
+     break;
+   }
+   return context;
+ }
+ 
+ // static
+diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h
+--- a/dom/fetch/InternalRequest.h
++++ b/dom/fetch/InternalRequest.h
+@@ -48,17 +48,17 @@ namespace dom {
+  * font              | TYPE_FONT
+  * form              |
+  * frame             | TYPE_INTERNAL_FRAME
+  * hyperlink         |
+  * iframe            | TYPE_INTERNAL_IFRAME
+  * image             | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_IMAGE_FAVICON
+  * imageset          | TYPE_IMAGESET
+  * import            | Not supported by Gecko
+- * internal          | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
++ * internal          | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER, TYPE_SAVEAS_DOWNLOAD
+  * location          |
+  * manifest          | TYPE_WEB_MANIFEST
+  * object            | TYPE_INTERNAL_OBJECT
+  * ping              | TYPE_PING
+  * plugin            | TYPE_OBJECT_SUBREQUEST
+  * prefetch          |
+  * script            | TYPE_INTERNAL_SCRIPT, TYPE_INTERNAL_SCRIPT_PRELOAD
+  * sharedworker      | TYPE_INTERNAL_SHARED_WORKER
+diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
+--- a/dom/security/nsContentSecurityManager.cpp
++++ b/dom/security/nsContentSecurityManager.cpp
+@@ -473,16 +473,22 @@ DoContentSecurityChecks(nsIChannel* aCha
+     }
+ 
+     case nsIContentPolicy::TYPE_WEB_MANIFEST: {
+       mimeTypeGuess = NS_LITERAL_CSTRING("application/manifest+json");
+       requestingContext = aLoadInfo->LoadingNode();
+       break;
+     }
+ 
++    case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD: {
++      mimeTypeGuess = EmptyCString();
++      requestingContext = aLoadInfo->LoadingNode();
++      break;
++    }
++
+     default:
+       // nsIContentPolicy::TYPE_INVALID
+       MOZ_ASSERT(false, "can not perform security check without a valid contentType");
+   }
+ 
+   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
+   rv = NS_CheckContentLoadPolicy(internalContentPolicyType,
+                                  uri,
+diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
+--- a/dom/security/nsMixedContentBlocker.cpp
++++ b/dom/security/nsMixedContentBlocker.cpp
+@@ -488,16 +488,23 @@ nsMixedContentBlocker::ShouldLoad(bool a
+       return NS_OK;
+     // Creating insecure websocket connections in a secure page is blocked already
+     // in the websocket constructor. We don't need to check the blocking here
+     // and we don't want to un-block
+     case TYPE_WEBSOCKET:
+       *aDecision = ACCEPT;
+       return NS_OK;
+ 
++    // Creating insecure connections for a save-as link download is acceptable.
++    // This download is completely disconnected from the docShell, but still
++    // using the same loading principal.
++    case TYPE_SAVEAS_DOWNLOAD:
++      *aDecision = ACCEPT;
++      return NS_OK;
++
+     // Static display content is considered moderate risk for mixed content so
+     // these will be blocked according to the mixed display preference
+     case TYPE_IMAGE:
+     case TYPE_MEDIA:
+     case TYPE_OBJECT_SUBREQUEST:
+       classification = eMixedDisplay;
+       break;
+ 

+ 32 - 0
frg/work-js/mozilla-release/patches/1398229-4-59a1.patch

@@ -0,0 +1,32 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1511078027 -3600
+# Node ID c7a66beb66745e2b9549f8c49b7a241e32f883cb
+# Parent  acd7ffd10543b1b1dd70cfe9c652a44a0dbe9a41
+Bug 1398229 - Save-link-as feature should use the loading principal - part 4 - Comment updated, r=me
+
+diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
+--- a/dom/security/nsMixedContentBlocker.cpp
++++ b/dom/security/nsMixedContentBlocker.cpp
+@@ -470,17 +470,20 @@ nsMixedContentBlocker::ShouldLoad(bool a
+   // received data.
+   //
+   // TYPE_XMLHTTPREQUEST: XHR requires either same origin or CORS, so most
+   // mixed-content XHR will already be blocked by that check. This will also
+   // block HTTPS-to-HTTP XHR with CORS. The same security concerns mentioned
+   // above for WebSockets apply to XHR, and XHR should have the same security
+   // properties as WebSockets w.r.t. mixed content. XHR's handling of redirects
+   // amplifies these concerns.
+-
++  //
++  // TYPE_SAVEAS_DOWNLOAD: Save-link-as feature is used to download a resource
++  // without involving a docShell. This kind of loading must be always be
++  // allowed.
+ 
+   static_assert(TYPE_DATAREQUEST == TYPE_XMLHTTPREQUEST,
+                 "TYPE_DATAREQUEST is not a synonym for "
+                 "TYPE_XMLHTTPREQUEST");
+ 
+   switch (aContentType) {
+     // The top-level document cannot be mixed content by definition
+     case TYPE_DOCUMENT:

+ 30 - 0
frg/work-js/mozilla-release/patches/1430758-59a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1516111382 -3600
+# Node ID 2951624227ccd8ccdaf1eca58b2d9adb0ecacc9c
+# Parent  076feca14fba612f1ba714c77edd9d2260e0dbad
+Bug 1430758 - No CSP directive for nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD, r=ckerschb
+
+diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
+--- a/dom/security/nsCSPUtils.cpp
++++ b/dom/security/nsCSPUtils.cpp
+@@ -255,16 +255,19 @@ CSP_ContentTypeToDirective(nsContentPoli
+ 
+     // csp shold not block top level loads, e.g. in case
+     // of a redirect.
+     case nsIContentPolicy::TYPE_DOCUMENT:
+     // CSP can not block csp reports
+     case nsIContentPolicy::TYPE_CSP_REPORT:
+       return nsIContentSecurityPolicy::NO_DIRECTIVE;
+ 
++    case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
++      return nsIContentSecurityPolicy::NO_DIRECTIVE;
++
+     // Fall through to error for all other directives
+     default:
+       MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective");
+   }
+   return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
+ }
+ 
+ nsCSPHostSrc*

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

@@ -2,7 +2,7 @@
 # User Thi Huynh <so61pi.re@gmail.com>
 # Date 1534842295 0
 # Node ID 2102f887e46bf3cb2b6a7fb00ed33640c9cb330e
-# Parent  dedda3c4e95263c66fcbd93aed777f89804e38b3
+# Parent  73fdb585bc3e4a24ec3a4187e4b7575cfbb4f661
 Bug 1432135 - Rename TokenKind::{Lb,Rb,Lc,Rc,Lp,Rp} to their long names. r=jandem
 
 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
 --- a/js/src/frontend/Parser.cpp
 +++ b/js/src/frontend/Parser.cpp
-@@ -1745,18 +1745,18 @@ PerHandlerParser<ParseHandler>::propagat
+@@ -1741,18 +1741,18 @@ PerHandlerParser<ParseHandler>::propagat
  
  template <typename CharT>
  bool
@@ -31,7 +31,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          return false;
      }
      return true;
-@@ -2940,17 +2940,18 @@ bool
+@@ -2922,17 +2922,18 @@ bool
  GeneralParser<ParseHandler, CharT>::matchOrInsertSemicolon()
  {
      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
-@@ -3073,17 +3074,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3055,17 +3056,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();
  
-@@ -3102,17 +3103,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3084,17 +3085,17 @@ GeneralParser<ParseHandler, CharT>::func
          return false;
      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 hasDefault = false;
          bool duplicatedParam = false;
-@@ -3153,27 +3154,27 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3135,27 +3136,27 @@ GeneralParser<ParseHandler, CharT>::func
  
                  hasRest = true;
                  funbox->setHasRest();
@@ -121,7 +121,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  }
  
                  funbox->hasDestructuringArgs = true;
-@@ -3272,26 +3273,26 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3254,26 +3255,26 @@ GeneralParser<ParseHandler, CharT>::func
              if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
                  return false;
              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);
                  return false;
              }
-@@ -3372,17 +3373,17 @@ GeneralParser<ParseHandler, CharT>::addE
+@@ -3354,17 +3355,17 @@ GeneralParser<ParseHandler, CharT>::addE
      Node pn = expr(InAllowed, yieldHandling, TripledotProhibited);
      if (!pn)
          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>
-@@ -3843,17 +3844,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3825,17 +3826,17 @@ GeneralParser<ParseHandler, CharT>::func
      }
  
      // Parse the function body.
@@ -188,7 +188,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          anyChars.ungetToken();
          bodyType = ExpressionBody;
          funbox->setHasExprBody();
-@@ -3903,17 +3904,17 @@ GeneralParser<ParseHandler, CharT>::func
+@@ -3885,17 +3886,17 @@ GeneralParser<ParseHandler, CharT>::func
          // we don't need call AutoAwaitIsKeyword here.
  
          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())
              return false;
-@@ -4253,17 +4254,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -4235,17 +4236,17 @@ GeneralParser<ParseHandler, CharT>::stat
      uint32_t statementBegin = 0;
      for (;;) {
          TokenKind tt = TokenKind::Eof;
@@ -226,7 +226,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              break;
          }
          if (afterReturn) {
-@@ -4299,23 +4300,23 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -4281,23 +4282,23 @@ GeneralParser<ParseHandler, CharT>::stat
  
      return pn;
  }
@@ -252,7 +252,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      }
      return pn;
  }
-@@ -4537,52 +4538,52 @@ GeneralParser<ParseHandler, CharT>::bind
+@@ -4519,52 +4520,52 @@ GeneralParser<ParseHandler, CharT>::bind
  }
  
  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);
              uint32_t begin = pos().begin;
  
-@@ -4671,30 +4672,30 @@ GeneralParser<ParseHandler, CharT>::obje
+@@ -4653,30 +4654,30 @@ GeneralParser<ParseHandler, CharT>::obje
          if (!matched)
              break;
          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);
      if (!literal)
          return null();
-@@ -4705,17 +4706,17 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -4687,17 +4688,17 @@ GeneralParser<ParseHandler, CharT>::arra
               error(JSMSG_ARRAY_INIT_TOO_BIG);
               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 (!handler.addElision(literal, pos()))
                   return null();
-@@ -4760,34 +4761,34 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -4742,34 +4743,34 @@ GeneralParser<ParseHandler, CharT>::arra
  
               if (tt == TokenKind::TripleDot) {
                   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
  GeneralParser<ParseHandler, CharT>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
                                                                                  YieldHandling yieldHandling,
-@@ -4809,29 +4810,29 @@ GeneralParser<ParseHandler, CharT>::dest
+@@ -4791,29 +4792,29 @@ GeneralParser<ParseHandler, CharT>::dest
      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>
  typename ParseHandler::Node
-@@ -4848,18 +4849,18 @@ GeneralParser<ParseHandler, CharT>::expr
+@@ -4830,18 +4831,18 @@ GeneralParser<ParseHandler, CharT>::expr
  template <class ParseHandler, typename CharT>
  typename ParseHandler::Node
  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) {
          bool isForIn, isForOf;
          if (!matchInOrOf(&isForIn, &isForOf))
-@@ -5072,17 +5073,17 @@ GeneralParser<ParseHandler, CharT>::decl
+@@ -5054,17 +5055,17 @@ GeneralParser<ParseHandler, CharT>::decl
      do {
          MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
                        *forHeadKind == ParseNodeKind::ForHead);
@@ -472,7 +472,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              return null();
  
          handler.addList(decl, binding);
-@@ -5128,25 +5129,25 @@ GeneralParser<ParseHandler, CharT>::lexi
+@@ -5110,25 +5111,25 @@ GeneralParser<ParseHandler, CharT>::lexi
  
      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());
-@@ -5195,17 +5196,17 @@ Parser<FullParseHandler, CharT>::namedIm
+@@ -5177,17 +5178,17 @@ Parser<FullParseHandler, CharT>::namedIm
                  return false;
  
              handler.addList(importSpecSet, importSpec);
@@ -519,7 +519,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              }
          }
      } else {
-@@ -5266,17 +5267,17 @@ Parser<FullParseHandler, CharT>::importD
+@@ -5248,17 +5249,17 @@ Parser<FullParseHandler, CharT>::importD
      if (!importSpecSet)
          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
              // |import { default as a } from 'b'|.
              Node importName = newName(context->names().default_);
-@@ -5303,17 +5304,17 @@ Parser<FullParseHandler, CharT>::importD
+@@ -5285,17 +5286,17 @@ Parser<FullParseHandler, CharT>::importD
              if (!tokenStream.peekToken(&tt))
                  return null();
  
@@ -557,7 +557,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      return null();
              }
          } else {
-@@ -5740,30 +5741,30 @@ GeneralParser<ParseHandler, CharT>::chec
+@@ -5729,30 +5730,30 @@ GeneralParser<ParseHandler, CharT>::chec
  
  template <class ParseHandler, typename CharT>
  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());
-@@ -5788,17 +5789,17 @@ GeneralParser<ParseHandler, CharT>::expo
+@@ -5777,17 +5778,17 @@ GeneralParser<ParseHandler, CharT>::expo
              return null();
  
          handler.addList(kid, exportSpec);
@@ -609,7 +609,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
      }
  
-@@ -6088,17 +6089,17 @@ GeneralParser<ParseHandler, CharT>::expo
+@@ -6077,17 +6078,17 @@ GeneralParser<ParseHandler, CharT>::expo
  
      TokenKind 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:
          return exportFunctionDeclaration(begin, pos().begin);
  
-@@ -6324,17 +6325,17 @@ GeneralParser<ParseHandler, CharT>::matc
+@@ -6313,17 +6314,17 @@ GeneralParser<ParseHandler, CharT>::matc
  
  template <class ParseHandler, typename CharT>
  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
      // component.
      if (tt == TokenKind::Semi) {
-@@ -6496,17 +6497,17 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6485,17 +6486,17 @@ GeneralParser<ParseHandler, CharT>::forS
              return null();
  
          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 headKind;
  
-@@ -6576,25 +6577,25 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6565,25 +6566,25 @@ GeneralParser<ParseHandler, CharT>::forS
          }
  
          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 {
          MOZ_ASSERT(headKind == ParseNodeKind::ForIn || headKind == ParseNodeKind::ForOf);
  
-@@ -6608,17 +6609,17 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6597,17 +6598,17 @@ GeneralParser<ParseHandler, CharT>::forS
              stmt.refineForKind(StatementKind::ForInLoop);
          } else {
              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);
-@@ -6637,40 +6638,40 @@ GeneralParser<ParseHandler, CharT>::forS
+@@ -6626,40 +6627,40 @@ GeneralParser<ParseHandler, CharT>::forS
  
  template <class ParseHandler, typename CharT>
  typename ParseHandler::Node
@@ -758,7 +758,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
            case TokenKind::Default:
              if (seenDefault) {
                  error(JSMSG_TOO_MANY_DEFAULTS);
-@@ -6698,17 +6699,17 @@ GeneralParser<ParseHandler, CharT>::swit
+@@ -6687,17 +6688,17 @@ GeneralParser<ParseHandler, CharT>::swit
              return null();
  
          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);
              if (!stmt)
                  return null();
-@@ -6828,17 +6829,17 @@ GeneralParser<ParseHandler, CharT>::retu
+@@ -6817,17 +6818,17 @@ GeneralParser<ParseHandler, CharT>::retu
      Node exprNode;
      TokenKind tt = TokenKind::Eof;
      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();
        }
      }
-@@ -6871,19 +6872,19 @@ GeneralParser<ParseHandler, CharT>::yiel
+@@ -6860,19 +6861,19 @@ GeneralParser<ParseHandler, CharT>::yiel
        // quirk in the grammar.
        case TokenKind::Eol:
        // 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);
          break;
        case TokenKind::Mul:
-@@ -6912,23 +6913,23 @@ GeneralParser<ParseHandler, CharT>::with
+@@ -6901,23 +6902,23 @@ GeneralParser<ParseHandler, CharT>::with
      // use strictModeError directly.  But while 'with' is forbidden in strict
      // mode code, it doesn't even merit a warning in non-strict code.  See
      // 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)
              return null();
      }
-@@ -7009,17 +7010,17 @@ GeneralParser<ParseHandler, CharT>::thro
+@@ -6998,17 +6999,17 @@ GeneralParser<ParseHandler, CharT>::thro
  {
      MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Throw));
      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();
      }
  
-@@ -7047,41 +7048,41 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7036,41 +7037,41 @@ GeneralParser<ParseHandler, CharT>::tryS
       * kid3 is the finally statement
       *
       * catch nodes are binary.
@@ -910,7 +910,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      TokenKind tt;
      if (!tokenStream.getToken(&tt))
          return null();
-@@ -7097,30 +7098,30 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7086,30 +7087,30 @@ GeneralParser<ParseHandler, CharT>::tryS
  
          /*
           * Legal catch forms are:
@@ -945,7 +945,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
                default: {
                  if (!TokenKindIsPossibleIdentifierName(tt)) {
-@@ -7131,19 +7132,19 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7120,19 +7121,19 @@ GeneralParser<ParseHandler, CharT>::tryS
                  catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter,
                                                yieldHandling);
                  if (!catchName)
@@ -968,7 +968,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
          catchScope = finishLexicalScope(scope, catchBody);
          if (!catchScope)
-@@ -7155,34 +7156,34 @@ GeneralParser<ParseHandler, CharT>::tryS
+@@ -7144,34 +7145,34 @@ GeneralParser<ParseHandler, CharT>::tryS
  
          if (!tokenStream.getToken(&tt, TokenStream::Operand))
              return null();
@@ -1005,7 +1005,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      if (!catchScope && !finallyBlock) {
          error(JSMSG_CATCH_OR_FINALLY);
          return null();
-@@ -7212,17 +7213,17 @@ GeneralParser<ParseHandler, CharT>::catc
+@@ -7201,17 +7202,17 @@ GeneralParser<ParseHandler, CharT>::catc
      // block, so declare the name in the inner scope.
      if (!scope.addCatchParameters(pc, catchParamScope))
          return null();
@@ -1024,7 +1024,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      scope.removeCatchParameters(pc, catchParamScope);
      return finishLexicalScope(scope, list);
  }
-@@ -7327,44 +7328,44 @@ GeneralParser<ParseHandler, CharT>::clas
+@@ -7316,44 +7317,44 @@ GeneralParser<ParseHandler, CharT>::clas
      if (hasHeritage) {
          if (!tokenStream.getToken(&tt))
              return null();
@@ -1073,7 +1073,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
  
          uint32_t nameOffset;
-@@ -7400,28 +7401,28 @@ GeneralParser<ParseHandler, CharT>::clas
+@@ -7389,28 +7390,28 @@ GeneralParser<ParseHandler, CharT>::clas
              errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
              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.
          Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
                                     propType, funName);
-@@ -7489,17 +7490,17 @@ bool
+@@ -7478,17 +7479,17 @@ bool
  ParserBase::nextTokenContinuesLetDeclaration(TokenKind next)
  {
      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;
      //
      // Static semantics in §13.3.1.1 turn a LexicalDeclaration that binds
-@@ -7534,17 +7535,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7523,17 +7524,17 @@ GeneralParser<ParseHandler, CharT>::stat
          return null();
  
      TokenKind tt;
@@ -1142,7 +1142,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
        // EmptyStatement
        case TokenKind::Semi:
-@@ -7583,32 +7584,32 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7572,32 +7573,32 @@ GeneralParser<ParseHandler, CharT>::stat
          if (!tokenStream.peekToken(&next))
              return null();
  
@@ -1178,7 +1178,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              if (forbiddenLetDeclaration) {
                  error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
                  return null();
-@@ -7752,17 +7753,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7741,17 +7742,17 @@ GeneralParser<ParseHandler, CharT>::stat
          return null();
  
      TokenKind tt;
@@ -1197,7 +1197,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
        // EmptyStatement
        case TokenKind::Semi:
-@@ -7961,23 +7962,23 @@ GeneralParser<ParseHandler, CharT>::expr
+@@ -7950,23 +7951,23 @@ GeneralParser<ParseHandler, CharT>::expr
          // directly under CoverParenthesizedExpressionAndArrowParameterList,
          // and the next two tokens are closing parenthesis and arrow. If all
          // are present allow the trailing comma.
@@ -1224,7 +1224,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              }
          }
  
-@@ -8303,17 +8304,17 @@ GeneralParser<ParseHandler, CharT>::assi
+@@ -8292,17 +8293,17 @@ GeneralParser<ParseHandler, CharT>::assi
  
              TokenKind nextSameLine = TokenKind::Eof;
              if (!tokenStream.peekTokenSameLine(&nextSameLine))
@@ -1243,28 +1243,28 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          Node pn = handler.newArrowFunction(pos());
          if (!pn)
              return null();
-@@ -8616,17 +8617,17 @@ GeneralParser<ParseHandler, CharT>::assi
- 
- template <class ParseHandler, typename CharT>
- bool
- GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, Node listNode,
-                                                  bool* isSpread,
+@@ -8608,17 +8609,17 @@ typename ParseHandler::Node
+ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bool* isSpread,
                                                   PossibleError* possibleError /* = nullptr */)
  {
+     Node argsList = handler.newArguments(pos());
+     if (!argsList)
+         return null();
+ 
      bool matched;
 -    if (!tokenStream.matchToken(&matched, TokenKind::Rp, TokenStream::Operand))
 +    if (!tokenStream.matchToken(&matched, TokenKind::RightParen, TokenStream::Operand))
-         return false;
+         return null();
      if (matched) {
-         handler.setEndPosition(listNode, pos().end);
-         return true;
+         handler.setEndPosition(argsList, pos().end);
+         return argsList;
      }
  
      while (true) {
          bool spread = false;
-@@ -8654,21 +8655,21 @@ GeneralParser<ParseHandler, CharT>::argu
+@@ -8646,21 +8647,21 @@ GeneralParser<ParseHandler, CharT>::argu
          if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
-             return false;
+             return null();
          if (!matched)
              break;
  
@@ -1279,35 +1279,35 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 -    MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
 +    MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
  
-     handler.setEndPosition(listNode, pos().end);
-     return true;
+     handler.setEndPosition(argsList, pos().end);
+     return argsList;
  }
  
  bool
  ParserBase::checkAndMarkSuperScope()
  {
-@@ -8712,17 +8713,17 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8700,17 +8701,17 @@ GeneralParser<ParseHandler, CharT>::memb
+             tt = anyChars.currentToken().type;
+             Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
+                                        /* allowCallSyntax = */ false,
+                                        /* possibleError = */ nullptr, PredictInvoked);
              if (!ctorExpr)
                  return null();
  
-             lhs = handler.newNewExpression(newBegin, ctorExpr);
-             if (!lhs)
-                 return null();
- 
              bool matched;
 -            if (!tokenStream.matchToken(&matched, TokenKind::Lp))
 +            if (!tokenStream.matchToken(&matched, TokenKind::LeftParen))
                  return null();
+ 
+             bool isSpread = false;
+             Node args;
              if (matched) {
-                 bool isSpread = false;
-                 if (!argumentList(yieldHandling, lhs, &isSpread))
-                     return null();
-                 if (isSpread)
-                     handler.setOp(lhs, JSOP_SPREADNEW);
-             }
-@@ -8764,41 +8765,41 @@ GeneralParser<ParseHandler, CharT>::memb
-                 }
-                 nextMember = handler.newPropertyAccess(lhs, field, pos().end);
+                 args = argumentList(yieldHandling, &isSpread);
+             } else {
+                 args = handler.newArguments(pos());
+@@ -8768,41 +8769,41 @@ GeneralParser<ParseHandler, CharT>::memb
+ 
+                 nextMember = handler.newPropertyAccess(lhs, name);
                  if (!nextMember)
                      return null();
              } else {
@@ -1347,30 +1347,11 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      return null();
                  }
  
-                 nextMember = handler.newSuperCall(lhs);
-                 if (!nextMember)
-                     return null();
- 
-@@ -8821,17 +8822,17 @@ GeneralParser<ParseHandler, CharT>::memb
-                     return null();
-             } else {
-                 if (options().selfHostingMode && handler.isPropertyAccess(lhs)) {
-                     error(JSMSG_SELFHOSTED_METHOD_CALL);
-                     return null();
-                 }
- 
-                 TokenPos nextMemberPos = pos();
--                nextMember = tt == TokenKind::Lp
-+                nextMember = tt == TokenKind::LeftParen
-                              ? handler.newCall(nextMemberPos)
-                              : handler.newTaggedTemplate(nextMemberPos);
-                 if (!nextMember)
-                     return null();
- 
-                 JSOp op = JSOP_CALL;
-                 bool maybeAsyncArrow = false;
-                 if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
-@@ -8839,17 +8840,17 @@ GeneralParser<ParseHandler, CharT>::memb
+                 // Despite the fact that it's impossible to have |super()| in a
+                 // generator, we still inherit the yieldHandling of the
+                 // memberExpression, per spec. Curious.
+                 bool isSpread = false;
+@@ -8837,17 +8838,17 @@ GeneralParser<ParseHandler, CharT>::memb
                      // right syntax.
                      if (prop == context->names().apply) {
                          op = JSOP_FUNAPPLY;
@@ -1389,26 +1370,26 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                          // part of the CoverCallExpressionAndAsyncArrowHead
                          // syntax when the initial name is "async".
                          maybeAsyncArrow = true;
-@@ -8871,17 +8872,17 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8866,17 +8867,17 @@ GeneralParser<ParseHandler, CharT>::memb
+                         // If we're in a method, mark the method as requiring
+                         // support for 'super', since direct eval code can use
+                         // it. (If we're not in a method, that's fine, so
                          // ignore the return value.)
                          checkAndMarkSuperScope();
                      }
                  }
  
-                 handler.setBeginPosition(nextMember, lhs);
-                 handler.addList(nextMember, lhs);
- 
 -                if (tt == TokenKind::Lp) {
 +                if (tt == TokenKind::LeftParen) {
                      bool isSpread = false;
                      PossibleError* asyncPossibleError = maybeAsyncArrow ? possibleError : nullptr;
-                     if (!argumentList(yieldHandling, nextMember, &isSpread, asyncPossibleError))
+                     Node args = argumentList(yieldHandling, &isSpread, asyncPossibleError);
+                     if (!args)
                          return null();
                      if (isSpread) {
                          if (op == JSOP_EVAL)
                              op = JSOP_SPREADEVAL;
-                         else if (op == JSOP_STRICTEVAL)
-@@ -9266,28 +9267,28 @@ GeneralParser<ParseHandler, CharT>::chec
+@@ -9274,28 +9275,28 @@ GeneralParser<ParseHandler, CharT>::chec
      return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError, possibleError);
  }
  
@@ -1439,7 +1420,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      } else {
          anyChars.ungetToken();
  
-@@ -9295,17 +9296,17 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -9303,17 +9304,17 @@ GeneralParser<ParseHandler, CharT>::arra
              if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
                  error(JSMSG_ARRAY_INIT_TOO_BIG);
                  return null();
@@ -1458,7 +1439,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                      return null();
                  continue;
              }
-@@ -9356,17 +9357,17 @@ GeneralParser<ParseHandler, CharT>::arra
+@@ -9364,17 +9365,17 @@ GeneralParser<ParseHandler, CharT>::arra
                  return null();
              if (!matched)
                  break;
@@ -1477,7 +1458,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
      return literal;
  }
  
-@@ -9377,17 +9378,17 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9385,17 +9386,17 @@ GeneralParser<ParseHandler, CharT>::prop
                                                   Node propList,
                                                   PropertyType* propType,
                                                   MutableHandleAtom propAtom)
@@ -1496,7 +1477,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          // AsyncMethod[Yield, Await]:
          //   async [no LineTerminator here] PropertyName[?Yield, ?Await] ...
          //
-@@ -9403,17 +9404,17 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9411,17 +9412,17 @@ GeneralParser<ParseHandler, CharT>::prop
          //   StringLiteral
          //   NumericLiteral
          //
@@ -1515,7 +1496,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          }
      }
  
-@@ -9445,17 +9446,17 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9453,17 +9454,17 @@ GeneralParser<ParseHandler, CharT>::prop
              break;
          }
          propName = stringLiteral();
@@ -1534,7 +1515,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
        default: {
          if (!TokenKindIsPossibleIdentifierName(ltok)) {
              error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
-@@ -9501,18 +9502,18 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9509,18 +9510,18 @@ GeneralParser<ParseHandler, CharT>::prop
          if (tt == TokenKind::Number) {
              tokenStream.consumeKnownToken(TokenKind::Number);
  
@@ -1555,7 +1536,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
          propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos());
          if (!propName)
              return null();
-@@ -9529,32 +9530,32 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9537,32 +9538,32 @@ GeneralParser<ParseHandler, CharT>::prop
              error(JSMSG_BAD_PROP_ID);
              return null();
          }
@@ -1590,7 +1571,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              *propType = PropertyType::GeneratorMethod;
          else if (isAsync)
              *propType = PropertyType::AsyncMethod;
-@@ -9568,57 +9569,57 @@ GeneralParser<ParseHandler, CharT>::prop
+@@ -9576,57 +9577,57 @@ GeneralParser<ParseHandler, CharT>::prop
  }
  
  template <class ParseHandler, typename CharT>
@@ -1652,7 +1633,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              tokenStream.consumeKnownToken(TokenKind::TripleDot);
              uint32_t begin = pos().begin;
  
-@@ -9769,17 +9770,17 @@ GeneralParser<ParseHandler, CharT>::obje
+@@ -9777,17 +9778,17 @@ GeneralParser<ParseHandler, CharT>::obje
                  Node propExpr = handler.newAssignment(ParseNodeKind::Assign, lhs, rhs);
                  if (!propExpr)
                      return null();
@@ -1671,7 +1652,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                              return null();
                      }
                  }
-@@ -9803,17 +9804,17 @@ GeneralParser<ParseHandler, CharT>::obje
+@@ -9811,17 +9812,17 @@ GeneralParser<ParseHandler, CharT>::obje
          if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
              return null();
          if (!matched)
@@ -1690,7 +1671,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  }
  
  template <class ParseHandler, typename CharT>
-@@ -9966,50 +9967,50 @@ GeneralParser<ParseHandler, CharT>::prim
+@@ -9974,50 +9975,50 @@ GeneralParser<ParseHandler, CharT>::prim
  
      switch (tt) {
        case TokenKind::Function:
@@ -1748,7 +1729,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  
        case TokenKind::NoSubsTemplate:
          return noSubstitutionUntaggedTemplate();
-@@ -10077,17 +10078,17 @@ GeneralParser<ParseHandler, CharT>::prim
+@@ -10085,17 +10086,17 @@ GeneralParser<ParseHandler, CharT>::prim
              error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
              return null();
          }
@@ -1767,7 +1748,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
                  return null();
              }
          } else {
-@@ -10098,46 +10099,46 @@ GeneralParser<ParseHandler, CharT>::prim
+@@ -10106,46 +10107,46 @@ GeneralParser<ParseHandler, CharT>::prim
              if (!TokenKindIsPossibleIdentifier(next)) {
                  error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next));
                  return null();
@@ -1852,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
 --- a/js/src/frontend/TokenStream.cpp
 +++ b/js/src/frontend/TokenStream.cpp
-@@ -417,19 +417,19 @@ TokenStreamAnyChars::TokenStreamAnyChars
+@@ -422,19 +422,19 @@ TokenStreamAnyChars::TokenStreamAnyChars
      cx(cx),
      mutedErrors(options.mutedErrors()),
      strictModeGetter(smg)
@@ -1875,7 +1856,7 @@ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
    : sourceUnits(chars, length, startOffset),
      tokenbuf(cx)
  {}
-@@ -1466,24 +1466,24 @@ enum FirstCharKind {
+@@ -1527,24 +1527,24 @@ enum FirstCharKind {
  // Plus:    43: '+'
  // ZeroDigit:  48: '0'
  // Space:   9, 11, 12, 32: '\t', '\v', '\f', ' '
@@ -1909,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
 --- a/js/src/wasm/AsmJS.cpp
 +++ b/js/src/wasm/AsmJS.cpp
-@@ -7469,17 +7469,17 @@ CheckModuleExportObject(ModuleValidator&
+@@ -7470,17 +7470,17 @@ CheckModuleExportObject(ModuleValidator&
  static bool
  CheckModuleReturn(ModuleValidator& m)
  {
@@ -1928,7 +1909,7 @@ diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
      ParseNode* returnStmt = m.parser().statementListItem(YieldIsName);
      if (!returnStmt)
          return false;
-@@ -7501,17 +7501,17 @@ CheckModuleReturn(ModuleValidator& m)
+@@ -7502,17 +7502,17 @@ CheckModuleReturn(ModuleValidator& m)
  
  static bool
  CheckModuleEnd(ModuleValidator &m)

+ 10 - 10
frg/work-js/mozilla-release/patches/1436742-60a1.patch

@@ -2,7 +2,7 @@
 # User Josh Matthews <josh@joshmatthews.net>
 # Date 1518211021 18000
 # Node ID 70c39ef867018954055fd0271a1806cdaee099d4
-# Parent  ceb184f8c3e3b9854ed3c0fe563ae2a3841d3adb
+# Parent  f9be19eacc0ca4f9bec4133d53152a39279b0dcd
 Bug 1436742 - Expose docgroup used to dispatch events when possible. r=froydnj
 
 diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp
@@ -17,8 +17,8 @@ diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp
  DocGroup::Dispatch(TaskCategory aCategory,
                     already_AddRefed<nsIRunnable>&& aRunnable)
  {
--  return mTabGroup->Dispatch(aCategory, std::move(aRunnable));
-+  return mTabGroup->DispatchWithDocGroup(aCategory, std::move(aRunnable), this);
+-  return mTabGroup->Dispatch(aCategory, Move(aRunnable));
++  return mTabGroup->DispatchWithDocGroup(aCategory, Move(aRunnable), this);
  }
  
  nsISerialEventTarget*
@@ -61,15 +61,15 @@ diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
 +                                     already_AddRefed<nsIRunnable>&& aRunnable,
 +                                     dom::DocGroup* aDocGroup)
 +{
-+  return LabeledDispatch(aCategory, std::move(aRunnable), aDocGroup);
++  return LabeledDispatch(aCategory, Move(aRunnable), aDocGroup);
 +}
 +
 +nsresult
  SchedulerGroup::Dispatch(TaskCategory aCategory,
                           already_AddRefed<nsIRunnable>&& aRunnable)
  {
--  return LabeledDispatch(aCategory, std::move(aRunnable));
-+  return LabeledDispatch(aCategory, std::move(aRunnable), nullptr);
+-  return LabeledDispatch(aCategory, Move(aRunnable));
++  return LabeledDispatch(aCategory, Move(aRunnable), nullptr);
  }
  
  nsISerialEventTarget*
@@ -116,7 +116,7 @@ diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
 +                                   SchedulerGroup* aGroup,
 +                                   dom::DocGroup* aDocGroup)
    : mozilla::Runnable("SchedulerGroup::Runnable")
-   , mRunnable(std::move(aRunnable))
+   , mRunnable(Move(aRunnable))
    , mGroup(aGroup)
 +  , mDocGroup(aDocGroup)
  {
@@ -208,11 +208,11 @@ diff --git a/xpcom/threads/SchedulerGroup.h b/xpcom/threads/SchedulerGroup.h
    virtual nsresult Dispatch(TaskCategory aCategory,
                              already_AddRefed<nsIRunnable>&& aRunnable);
  
-@@ -184,33 +188,38 @@ public:
- 
+@@ -185,33 +189,38 @@ public:
    using RunnableEpochQueue = Queue<EpochQueueEntry, 32>;
  
-   RunnableEpochQueue& GetQueue(mozilla::EventQueuePriority aPriority) {
+   RunnableEpochQueue& GetQueue(mozilla::EventPriority aPriority)
+   {
      return mEventQueues[size_t(aPriority)];
    }
  

+ 7 - 7
frg/work-js/mozilla-release/patches/1436743-60a1.patch

@@ -2,13 +2,13 @@
 # User Josh Matthews <josh@joshmatthews.net>
 # Date 1518123240 18000
 # Node ID d9da3f3bf43203a0ad3de87adfd8298c5e5e85a2
-# Parent  feff75c05ea6a85a2d4d19a1a28fb1738689eb71
+# Parent  5f8a4eabe5dfd942a5568c37463fd2d3bcdc661f
 Bug 1436743 - Dispatch events via the docgroup rather than the tabgroup when possible. r=mystor
 
 diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
 --- a/docshell/base/nsDocShell.cpp
 +++ b/docshell/base/nsDocShell.cpp
-@@ -1801,16 +1801,19 @@ nsDocShell::DispatchToTabGroup(TaskCateg
+@@ -1803,16 +1803,19 @@ nsDocShell::DispatchToTabGroup(TaskCateg
    nsCOMPtr<nsIRunnable> runnable(aRunnable);
    nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
    if (!win) {
@@ -31,7 +31,7 @@ diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
 diff --git a/docshell/shistory/nsSHistory.cpp b/docshell/shistory/nsSHistory.cpp
 --- a/docshell/shistory/nsSHistory.cpp
 +++ b/docshell/shistory/nsSHistory.cpp
-@@ -1871,22 +1871,23 @@ nsSHistory::SetRootDocShell(nsIDocShell*
+@@ -1861,22 +1861,23 @@ nsSHistory::SetRootDocShell(nsIDocShell*
      // Seamonkey moves shistory between <xul:browser>s when restoring a tab.
      // Let's try not to break our friend too badly...
      if (mHistoryTracker) {
@@ -65,7 +65,7 @@ diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.c
  
  #include "nsCOMPtr.h"
  #include "jsapi.h"
- #include "js/Wrapper.h"
+ #include "jswrapper.h"
  #include "nsCRT.h"
  #include "nsError.h"
  #include "nsString.h"
@@ -103,7 +103,7 @@ diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.c
 diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
 --- a/dom/performance/Performance.cpp
 +++ b/dom/performance/Performance.cpp
-@@ -504,17 +504,22 @@ private:
+@@ -510,17 +510,22 @@ private:
    RefPtr<Performance> mPerformance;
  };
  
@@ -130,7 +130,7 @@ diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
 diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
 --- a/dom/script/ScriptLoader.cpp
 +++ b/dom/script/ScriptLoader.cpp
-@@ -1381,20 +1381,25 @@ ScriptLoader::ProcessExternalScript(nsIS
+@@ -1372,20 +1372,25 @@ ScriptLoader::ProcessExternalScript(nsIS
      LOG(("ScriptLoadRequest (%p): Created request for external script",
           request.get()));
  
@@ -165,7 +165,7 @@ diff --git a/image/imgRequestProxy.cpp b/image/imgRequestProxy.cpp
    // scheduler group is valid with or without a document, but that means
    // we will use the most generic event target possible on dispatch.
    if (aLoadingDocument) {
-     RefPtr<mozilla::dom::DocGroup> docGroup = aLoadingDocument->GetDocGroup();
+     RefPtr<dom::DocGroup> docGroup = aLoadingDocument->GetDocGroup();
      if (docGroup) {
        mTabGroup = docGroup->GetTabGroup();
        MOZ_ASSERT(mTabGroup);

+ 98 - 0
frg/work-js/mozilla-release/patches/1440481-1-63a1.patch

@@ -0,0 +1,98 @@
+# HG changeset patch
+# User Jason Orendorff <jorendorff@mozilla.com>
+# Date 1530118855 18000
+#      Wed Jun 27 12:00:55 2018 -0500
+# Node ID 59e443ff0e2f7837b60be02f1e12a9666bd95f19
+# Parent  9bdec96cf9385318ba79f0d2825616ea7bbaf456
+Bug 1440481 - Part 1: Make Debugger stepping work the same in baseline as in the interpreter. r=nbp
+
+diff --git a/js/src/jit-test/tests/debug/Frame-onStep-20.js b/js/src/jit-test/tests/debug/Frame-onStep-20.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/debug/Frame-onStep-20.js
+@@ -0,0 +1,41 @@
++// Stepping should always pause in a frame between two function calls.
++
++let g = newGlobal();
++g.evaluate(`
++    class X {
++        constructor() { this._p = 0; }
++        m() { return this; }
++        get p() { return this._p; }
++        set p(value) { this._p = value; }
++    }
++    let x = new X;
++
++    function f() { return 1; }
++    function inc(x) { return x + 1; }
++`);
++
++let dbg = Debugger(g);
++
++// `code` is a snippet of JS that performs two JS calls.
++function test(code) {
++    let hits = 0;
++    let log = "";
++    dbg.onEnterFrame = frame => {
++        if (hits++ === 0)
++            frame.onStep = () => { log += "s"; };
++        else
++            log += "E";
++    };
++
++    g.eval(code);
++    assertEq(log.includes("EE"), false, "should have received onStep between onEnterFrame events");
++    assertEq(log.match(/^s+Es+Es*$/) !== null, true,
++             "should get two calls, with steps before, between, and possibly after");
++}
++
++test("f(); f();");
++test("f() + f()");
++test("inc(f())");
++test("x.m().m()");
++test("new X().m()");
++test("x.p = x.p");  // getter, then setter
+diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp
+--- a/js/src/jit/BaselineJIT.cpp
++++ b/js/src/jit/BaselineJIT.cpp
+@@ -919,39 +919,34 @@ void
+ BaselineScript::toggleDebugTraps(JSScript* script, jsbytecode* pc)
+ {
+     MOZ_ASSERT(script->baselineScript() == this);
+ 
+     // Only scripts compiled for debug mode have toggled calls.
+     if (!hasDebugInstrumentation())
+         return;
+ 
+-    SrcNoteLineScanner scanner(script->notes(), script->lineno());
+-
+     AutoWritableJitCode awjc(method());
+ 
+     for (uint32_t i = 0; i < numPCMappingIndexEntries(); i++) {
+         PCMappingIndexEntry& entry = pcMappingIndexEntry(i);
+ 
+         CompactBufferReader reader(pcMappingReader(i));
+         jsbytecode* curPC = script->offsetToPC(entry.pcOffset);
+         uint32_t nativeOffset = entry.nativeOffset;
+ 
+         MOZ_ASSERT(script->containsPC(curPC));
+ 
+         while (reader.more()) {
+             uint8_t b = reader.readByte();
+             if (b & 0x80)
+                 nativeOffset += reader.readUnsigned();
+ 
+-            scanner.advanceTo(script->pcToOffset(curPC));
+-
+             if (!pc || pc == curPC) {
+-                bool enabled = (script->stepModeEnabled() && scanner.isLineHeader()) ||
+-                    script->hasBreakpointsAt(curPC);
++                bool enabled = script->stepModeEnabled() || script->hasBreakpointsAt(curPC);
+ 
+                 // Patch the trap.
+                 CodeLocationLabel label(method(), CodeOffset(nativeOffset));
+                 Assembler::ToggleCall(label, enabled);
+             }
+ 
+             curPC += GetBytecodeLength(curPC);
+         }

+ 397 - 0
frg/work-js/mozilla-release/patches/1440481-2-63a1.patch

@@ -0,0 +1,397 @@
+# HG changeset patch
+# User Jason Orendorff <jorendorff@mozilla.com>
+# Date 1530120195 18000
+#      Wed Jun 27 12:23:15 2018 -0500
+# Node ID 71a6537e84fe2314ed64eddb8a91ccd97b480c98
+# Parent  171297ebd0a893a499c7f6dd744b9a31cefae714
+Bug 1440481 - Part 2: Delete SrcNoteLineScanner. Use BytecodeRangeWithPosition instead. r=nbp
+
+diff --git a/js/src/vm/BytecodeUtil-inl.h b/js/src/vm/BytecodeUtil-inl.h
+--- a/js/src/vm/BytecodeUtil-inl.h
++++ b/js/src/vm/BytecodeUtil-inl.h
+@@ -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/. */
+ 
+ #ifndef vm_BytecodeUtil_inl_h
+ #define vm_BytecodeUtil_inl_h
+ 
+ #include "vm/BytecodeUtil.h"
+ 
++#include "frontend/SourceNotes.h"
+ #include "vm/JSScript.h"
+ 
+ namespace js {
+ 
+ static inline unsigned
+ GetDefCount(jsbytecode* pc)
+ {
+     /*
+@@ -106,11 +107,105 @@ class BytecodeRange {
+     void popFront() { pc += GetBytecodeLength(pc); }
+ 
+   private:
+     RootedScript script;
+     jsbytecode* pc;
+     jsbytecode* end;
+ };
+ 
++class BytecodeRangeWithPosition : private BytecodeRange
++{
++  public:
++    using BytecodeRange::empty;
++    using BytecodeRange::frontPC;
++    using BytecodeRange::frontOpcode;
++    using BytecodeRange::frontOffset;
++
++    BytecodeRangeWithPosition(JSContext* cx, JSScript* script)
++      : BytecodeRange(cx, script), lineno(script->lineno()), column(0),
++        sn(script->notes()), snpc(script->code()), isEntryPoint(false),
++        wasArtifactEntryPoint(false)
++    {
++        if (!SN_IS_TERMINATOR(sn))
++            snpc += SN_DELTA(sn);
++        updatePosition();
++        while (frontPC() != script->main())
++            popFront();
++
++        if (frontOpcode() != JSOP_JUMPTARGET)
++            isEntryPoint = true;
++        else
++            wasArtifactEntryPoint =  true;
++    }
++
++    void popFront() {
++        BytecodeRange::popFront();
++        if (empty())
++            isEntryPoint = false;
++        else
++            updatePosition();
++
++        // The following conditions are handling artifacts introduced by the
++        // bytecode emitter, such that we do not add breakpoints on empty
++        // statements of the source code of the user.
++        if (wasArtifactEntryPoint) {
++            wasArtifactEntryPoint = false;
++            isEntryPoint = true;
++        }
++
++        if (isEntryPoint && frontOpcode() == JSOP_JUMPTARGET) {
++            wasArtifactEntryPoint = isEntryPoint;
++            isEntryPoint = false;
++        }
++    }
++
++    size_t frontLineNumber() const { return lineno; }
++    size_t frontColumnNumber() const { return column; }
++
++    // Entry points are restricted to bytecode offsets that have an
++    // explicit mention in the line table.  This restriction avoids a
++    // number of failing cases caused by some instructions not having
++    // sensible (to the user) line numbers, and it is one way to
++    // implement the idea that the bytecode emitter should tell the
++    // debugger exactly which offsets represent "interesting" (to the
++    // user) places to stop.
++    bool frontIsEntryPoint() const { return isEntryPoint; }
++
++  private:
++    void updatePosition() {
++        // Determine the current line number by reading all source notes up to
++        // and including the current offset.
++        jsbytecode *lastLinePC = nullptr;
++        while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) {
++            SrcNoteType type = SN_TYPE(sn);
++            if (type == SRC_COLSPAN) {
++                ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
++                MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
++                column += colspan;
++                lastLinePC = snpc;
++            } else if (type == SRC_SETLINE) {
++                lineno = size_t(GetSrcNoteOffset(sn, 0));
++                column = 0;
++                lastLinePC = snpc;
++            } else if (type == SRC_NEWLINE) {
++                lineno++;
++                column = 0;
++                lastLinePC = snpc;
++            }
++
++            sn = SN_NEXT(sn);
++            snpc += SN_DELTA(sn);
++        }
++        isEntryPoint = lastLinePC == frontPC();
++    }
++
++    size_t lineno;
++    size_t column;
++    jssrcnote* sn;
++    jsbytecode* snpc;
++    bool isEntryPoint;
++    bool wasArtifactEntryPoint;
++};
++
+ } // namespace js
+ 
+ #endif /* vm_BytecodeUtil_inl_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
+@@ -2690,21 +2690,20 @@ GetPCCountJSON(JSContext* cx, const Scri
+         return false;
+ 
+     if (!AppendJSONProperty(buf, "opcodes"))
+         return false;
+     if (!buf.append('['))
+         return false;
+     bool comma = false;
+ 
+-    SrcNoteLineScanner scanner(script->notes(), script->lineno());
+     uint64_t hits = 0;
+ 
+-    jsbytecode* end = script->codeEnd();
+-    for (jsbytecode* pc = script->code(); pc < end; pc = GetNextPc(pc)) {
++    for (BytecodeRangeWithPosition range(cx, script); !range.empty(); range.popFront()) {
++        jsbytecode *pc = range.frontPC();
+         size_t offset = script->pcToOffset(pc);
+         JSOp op = JSOp(*pc);
+ 
+         // If the current instruction is a jump target,
+         // then update the number of hits.
+         const PCCounts* counts = sac.maybeGetPCCounts(pc);
+         if (counts)
+             hits = counts->numExec();
+@@ -2716,21 +2715,19 @@ GetPCCountJSON(JSContext* cx, const Scri
+         if (!buf.append('{'))
+             return false;
+ 
+         if (!AppendJSONProperty(buf, "id", NO_COMMA))
+             return false;
+         if (!NumberValueToStringBuffer(cx, Int32Value(offset), buf))
+             return false;
+ 
+-        scanner.advanceTo(offset);
+-
+         if (!AppendJSONProperty(buf, "line"))
+             return false;
+-        if (!NumberValueToStringBuffer(cx, Int32Value(scanner.getLine()), buf))
++        if (!NumberValueToStringBuffer(cx, Int32Value(range.frontLineNumber()), buf))
+             return false;
+ 
+         {
+             const char* name = CodeName[op];
+             if (!AppendJSONProperty(buf, "name"))
+                 return false;
+             if (!buf.append('\"'))
+                 return false;
+diff --git a/js/src/vm/BytecodeUtil.h b/js/src/vm/BytecodeUtil.h
+--- a/js/src/vm/BytecodeUtil.h
++++ b/js/src/vm/BytecodeUtil.h
+@@ -448,92 +448,16 @@ BytecodeIsJumpTarget(JSOp op)
+       case JSOP_ENDITER:
+       case JSOP_TRY:
+         return true;
+       default:
+         return false;
+     }
+ }
+ 
+-class SrcNoteLineScanner
+-{
+-    /* offset of the current JSOp in the bytecode */
+-    ptrdiff_t offset;
+-
+-    /* next src note to process */
+-    jssrcnote* sn;
+-
+-    /* line number of the current JSOp */
+-    uint32_t lineno;
+-
+-    /*
+-     * Is the current op the first one after a line change directive? Note that
+-     * multiple ops may be "first" if a line directive is used to return to a
+-     * previous line (eg, with a for loop increment expression.)
+-     */
+-    bool lineHeader;
+-
+-  public:
+-    SrcNoteLineScanner(jssrcnote* sn, uint32_t lineno)
+-        : offset(0), sn(sn), lineno(lineno), lineHeader(false)
+-    {
+-    }
+-
+-    /*
+-     * This is called repeatedly with always-advancing relpc values. The src
+-     * notes are tuples of <PC offset from prev src note, type, args>. Scan
+-     * through, updating the lineno, until the next src note is for a later
+-     * bytecode.
+-     *
+-     * When looking at the desired PC offset ('relpc'), the op is first in that
+-     * line iff there is a SRC_SETLINE or SRC_NEWLINE src note for that exact
+-     * bytecode.
+-     *
+-     * Note that a single bytecode may have multiple line-modifying notes (even
+-     * though only one should ever be needed.)
+-     */
+-    void advanceTo(ptrdiff_t relpc) {
+-        // Must always advance! If the same or an earlier PC is erroneously
+-        // passed in, we will already be past the relevant src notes
+-        MOZ_ASSERT_IF(offset > 0, relpc > offset);
+-
+-        // Next src note should be for after the current offset
+-        MOZ_ASSERT_IF(offset > 0, SN_IS_TERMINATOR(sn) || SN_DELTA(sn) > 0);
+-
+-        // The first PC requested is always considered to be a line header
+-        lineHeader = (offset == 0);
+-
+-        if (SN_IS_TERMINATOR(sn))
+-            return;
+-
+-        ptrdiff_t nextOffset;
+-        while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) {
+-            offset = nextOffset;
+-            SrcNoteType type = SN_TYPE(sn);
+-            if (type == SRC_SETLINE || type == SRC_NEWLINE) {
+-                if (type == SRC_SETLINE)
+-                    lineno = GetSrcNoteOffset(sn, 0);
+-                else
+-                    lineno++;
+-
+-                if (offset == relpc)
+-                    lineHeader = true;
+-            }
+-
+-            sn = SN_NEXT(sn);
+-        }
+-    }
+-
+-    bool isLineHeader() const {
+-        return lineHeader;
+-    }
+-
+-    uint32_t getLine() const { return lineno; }
+-};
+-
+ MOZ_ALWAYS_INLINE unsigned
+ StackUses(jsbytecode* pc)
+ {
+     JSOp op = JSOp(*pc);
+     int nuses = CodeSpec[op].nuses;
+     if (nuses >= 0)
+         return nuses;
+ 
+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
+@@ -5651,112 +5651,16 @@ EnsureScriptOffsetIsValid(JSContext* cx,
+     if (IsValidBytecodeOffset(cx, script, offset))
+         return true;
+     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_OFFSET);
+     return false;
+ }
+ 
+ namespace {
+ 
+-class BytecodeRangeWithPosition : private BytecodeRange
+-{
+-  public:
+-    using BytecodeRange::empty;
+-    using BytecodeRange::frontPC;
+-    using BytecodeRange::frontOpcode;
+-    using BytecodeRange::frontOffset;
+-
+-    BytecodeRangeWithPosition(JSContext* cx, JSScript* script)
+-      : BytecodeRange(cx, script), lineno(script->lineno()), column(0),
+-        sn(script->notes()), snpc(script->code()), isEntryPoint(false),
+-        wasArtifactEntryPoint(false)
+-    {
+-        if (!SN_IS_TERMINATOR(sn))
+-            snpc += SN_DELTA(sn);
+-        updatePosition();
+-        while (frontPC() != script->main())
+-            popFront();
+-
+-        if (frontOpcode() != JSOP_JUMPTARGET)
+-            isEntryPoint = true;
+-        else
+-            wasArtifactEntryPoint =  true;
+-    }
+-
+-    void popFront() {
+-        BytecodeRange::popFront();
+-        if (empty())
+-            isEntryPoint = false;
+-        else
+-            updatePosition();
+-
+-        // The following conditions are handling artifacts introduced by the
+-        // bytecode emitter, such that we do not add breakpoints on empty
+-        // statements of the source code of the user.
+-        if (wasArtifactEntryPoint) {
+-            wasArtifactEntryPoint = false;
+-            isEntryPoint = true;
+-        }
+-
+-        if (isEntryPoint && frontOpcode() == JSOP_JUMPTARGET) {
+-            wasArtifactEntryPoint = isEntryPoint;
+-            isEntryPoint = false;
+-        }
+-    }
+-
+-    size_t frontLineNumber() const { return lineno; }
+-    size_t frontColumnNumber() const { return column; }
+-
+-    // Entry points are restricted to bytecode offsets that have an
+-    // explicit mention in the line table.  This restriction avoids a
+-    // number of failing cases caused by some instructions not having
+-    // sensible (to the user) line numbers, and it is one way to
+-    // implement the idea that the bytecode emitter should tell the
+-    // debugger exactly which offsets represent "interesting" (to the
+-    // user) places to stop.
+-    bool frontIsEntryPoint() const { return isEntryPoint; }
+-
+-  private:
+-    void updatePosition() {
+-        /*
+-         * Determine the current line number by reading all source notes up to
+-         * and including the current offset.
+-         */
+-        jsbytecode *lastLinePC = nullptr;
+-        while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) {
+-            SrcNoteType type = SN_TYPE(sn);
+-            if (type == SRC_COLSPAN) {
+-                ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
+-                MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
+-                column += colspan;
+-                lastLinePC = snpc;
+-            } else if (type == SRC_SETLINE) {
+-                lineno = size_t(GetSrcNoteOffset(sn, 0));
+-                column = 0;
+-                lastLinePC = snpc;
+-            } else if (type == SRC_NEWLINE) {
+-                lineno++;
+-                column = 0;
+-                lastLinePC = snpc;
+-            }
+-
+-            sn = SN_NEXT(sn);
+-            snpc += SN_DELTA(sn);
+-        }
+-        isEntryPoint = lastLinePC == frontPC();
+-    }
+-
+-    size_t lineno;
+-    size_t column;
+-    jssrcnote* sn;
+-    jsbytecode* snpc;
+-    bool isEntryPoint;
+-    bool wasArtifactEntryPoint;
+-};
+-
+ /*
+  * FlowGraphSummary::populate(cx, script) computes a summary of script's
+  * control flow graph used by DebuggerScript_{getAllOffsets,getLineOffsets}.
+  *
+  * An instruction on a given line is an entry point for that line if it can be
+  * reached from (an instruction on) a different line. We distinguish between the
+  * following cases:
+  *   - hasNoEdges:

+ 2 - 2
frg/work-js/mozilla-release/patches/1441098-1-62a1.patch

@@ -3,7 +3,7 @@
 # Date 1529511000 -10800
 #      Wed Jun 20 19:10:00 2018 +0300
 # Node ID f87f53656ed51696c9b00b794f8718313f7e2721
-# Parent  f84b2e8eaa8ed58d2e5e9777eac4eb37786d34b1
+# Parent  8feda4da8978cc39eac4198f84713d3c1ce1f53d
 bug 1441098 - Part 1: Add BigInt support in BufferGrayRootsTracer. r=sfink
 
 This class is used for tracing DOM objects.
@@ -37,7 +37,7 @@ diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp
  inline void
  BufferGrayRootsTracer::bufferRoot(T* thing)
  {
-     MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
+     MOZ_ASSERT(JS::RuntimeHeapIsBusy());
      MOZ_ASSERT(thing);
      // Check if |thing| is corrupt by calling a method that touches the heap.
 -    MOZ_ASSERT(thing->getTraceKind() <= JS::TraceKind::Null);

+ 1450 - 0
frg/work-js/mozilla-release/patches/1453795-36-62a1.patch

@@ -0,0 +1,1450 @@
+# HG changeset patch
+# User Andi-Bogdan Postelnicu <bpostelnicu@mozilla.com>
+# Date 1529007971 -10800
+#      Thu Jun 14 23:26:11 2018 +0300
+# Node ID aa34ca78ad4d508e4e1c7a8ba0f278a5f83658bc
+# Parent  72106854c71e6f19bf109ea967a0017662bd561b
+Bug 1453795 - JS/JIT - Initialize member fields in classes/ structures. r=jandem
+
+diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h
+--- a/js/src/jit/BaselineFrameInfo.h
++++ b/js/src/jit/BaselineFrameInfo.h
+@@ -60,32 +60,32 @@ class StackValue
+         EvalNewTargetSlot
+ #ifdef DEBUG
+         // In debug builds, assert Kind is initialized.
+         , Uninitialized
+ #endif
+     };
+ 
+   private:
+-    Kind kind_;
++    MOZ_INIT_OUTSIDE_CTOR Kind kind_;
+ 
+-    union Data {
++    MOZ_INIT_OUTSIDE_CTOR union Data {
+         JS::Value constant;
+         ValueOperand reg;
+         uint32_t localSlot;
+         uint32_t argSlot;
+ 
+         // |constant| has a non-trivial constructor and therefore MUST be
+         // placement-new'd into existence.
+         MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
+         Data() {}
+         MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
+     } data;
+ 
+-    JSValueType knownType_;
++    MOZ_INIT_OUTSIDE_CTOR JSValueType knownType_;
+ 
+   public:
+     StackValue() {
+         reset();
+     }
+ 
+     Kind kind() const {
+         return kind_;
+diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp
+--- a/js/src/jit/BaselineJIT.cpp
++++ b/js/src/jit/BaselineJIT.cpp
+@@ -74,16 +74,26 @@ BaselineScript::BaselineScript(uint32_t 
+ # ifdef DEBUG
+     traceLoggerScriptsEnabled_(false),
+     traceLoggerEngineEnabled_(false),
+ # endif
+     traceLoggerScriptEvent_(),
+ #endif
+     postDebugPrologueOffset_(postDebugPrologueOffset),
+     flags_(0),
++    icEntriesOffset_(0),
++    icEntries_(0),
++    pcMappingIndexOffset_(0),
++    pcMappingIndexEntries_(0),
++    pcMappingOffset_(0),
++    pcMappingSize_(0),
++    bytecodeTypeMapOffset_(0),
++    yieldEntriesOffset_(0),
++    traceLoggerToggleOffsetsOffset_(0),
++    numTraceLoggerToggleOffsets_(0),
+     inlinedBytecodeLength_(0),
+     maxInliningDepth_(UINT8_MAX),
+     pendingBuilder_(nullptr),
+     controlFlowGraph_(nullptr)
+ { }
+ 
+ static bool
+ CheckFrame(InterpreterFrame* fp)
+diff --git a/js/src/jit/BytecodeAnalysis.cpp b/js/src/jit/BytecodeAnalysis.cpp
+--- a/js/src/jit/BytecodeAnalysis.cpp
++++ b/js/src/jit/BytecodeAnalysis.cpp
+@@ -13,17 +13,18 @@
+ #include "vm/JSScript-inl.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ 
+ BytecodeAnalysis::BytecodeAnalysis(TempAllocator& alloc, JSScript* script)
+   : script_(script),
+     infos_(alloc),
+-    usesEnvironmentChain_(false)
++    usesEnvironmentChain_(false),
++    hasTryFinally_(false)
+ {
+ }
+ 
+ // Bytecode range containing only catch or finally code.
+ struct CatchFinallyRange
+ {
+     uint32_t start; // Inclusive.
+     uint32_t end;   // Exclusive.
+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
+@@ -661,19 +661,17 @@ class OutOfLineTestObject : public OutOf
+     Label* ifDoesntEmulateUndefined_;
+ 
+ #ifdef DEBUG
+     bool initialized() { return ifEmulatesUndefined_ != nullptr; }
+ #endif
+ 
+   public:
+     OutOfLineTestObject()
+-#ifdef DEBUG
+       : ifEmulatesUndefined_(nullptr), ifDoesntEmulateUndefined_(nullptr)
+-#endif
+     { }
+ 
+     void accept(CodeGenerator* codegen) final {
+         MOZ_ASSERT(initialized());
+         codegen->emitOOLTestObject(objreg_, ifEmulatesUndefined_, ifDoesntEmulateUndefined_,
+                                    scratch_);
+     }
+ 
+@@ -3420,22 +3418,22 @@ CodeGenerator::visitStoreSlotT(LStoreSlo
+     if (lir->mir()->needsBarrier())
+         emitPreBarrier(dest);
+ 
+     MIRType valueType = lir->mir()->value()->type();
+ 
+     if (valueType == MIRType::ObjectOrNull) {
+         masm.storeObjectOrNull(ToRegister(lir->value()), dest);
+     } else {
+-        ConstantOrRegister value;
++        mozilla::Maybe<ConstantOrRegister> value;
+         if (lir->value()->isConstant())
+-            value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
++            value.emplace(ConstantOrRegister(lir->value()->toConstant()->toJSValue()));
+         else
+-            value = TypedOrValueRegister(valueType, ToAnyRegister(lir->value()));
+-        masm.storeUnboxedValue(value, valueType, dest, lir->mir()->slotType());
++            value.emplace(TypedOrValueRegister(valueType, ToAnyRegister(lir->value())));
++        masm.storeUnboxedValue(value.ref(), valueType, dest, lir->mir()->slotType());
+     }
+ }
+ 
+ void
+ CodeGenerator::visitStoreSlotV(LStoreSlotV* lir)
+ {
+     Register base = ToRegister(lir->slots());
+     int32_t offset = lir->mir()->slot() * sizeof(Value);
+@@ -3623,23 +3621,23 @@ CodeGenerator::visitSetPropertyPolymorph
+ 
+ void
+ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
+ {
+     Register obj = ToRegister(ins->obj());
+     Register temp1 = ToRegister(ins->temp1());
+     Register temp2 = ToRegister(ins->temp2());
+ 
+-    ConstantOrRegister value;
++    mozilla::Maybe<ConstantOrRegister> value;
+     if (ins->mir()->value()->isConstant())
+-        value = ConstantOrRegister(ins->mir()->value()->toConstant()->toJSValue());
++        value.emplace(ConstantOrRegister(ins->mir()->value()->toConstant()->toJSValue()));
+     else
+-        value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(ins->value()));
+-
+-    emitSetPropertyPolymorphic(ins, obj, temp1, temp2, value);
++        value.emplace(TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(ins->value())));
++
++    emitSetPropertyPolymorphic(ins, obj, temp1, temp2, value.ref());
+ }
+ 
+ void
+ CodeGenerator::visitElements(LElements* lir)
+ {
+     Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
+     masm.loadPtr(elements, ToRegister(lir->output()));
+ }
+@@ -9383,56 +9381,56 @@ static const VMFunction SetDenseElementI
+ 
+ void
+ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
+ {
+     Register object, elements;
+     LInstruction* ins = ool->ins();
+     const LAllocation* index;
+     MIRType valueType;
+-    ConstantOrRegister value;
++    mozilla::Maybe<ConstantOrRegister> value;
+     Register spectreTemp;
+ 
+     if (ins->isStoreElementHoleV()) {
+         LStoreElementHoleV* store = ins->toStoreElementHoleV();
+         object = ToRegister(store->object());
+         elements = ToRegister(store->elements());
+         index = store->index();
+         valueType = store->mir()->value()->type();
+-        value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
++        value.emplace(TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value)));
+         spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
+     } else if (ins->isFallibleStoreElementV()) {
+         LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
+         object = ToRegister(store->object());
+         elements = ToRegister(store->elements());
+         index = store->index();
+         valueType = store->mir()->value()->type();
+-        value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
++        value.emplace(TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value)));
+         spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
+     } else if (ins->isStoreElementHoleT()) {
+         LStoreElementHoleT* store = ins->toStoreElementHoleT();
+         object = ToRegister(store->object());
+         elements = ToRegister(store->elements());
+         index = store->index();
+         valueType = store->mir()->value()->type();
+         if (store->value()->isConstant())
+-            value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
++            value.emplace(ConstantOrRegister(store->value()->toConstant()->toJSValue()));
+         else
+-            value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
++            value.emplace(TypedOrValueRegister(valueType, ToAnyRegister(store->value())));
+         spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
+     } else { // ins->isFallibleStoreElementT()
+         LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
+         object = ToRegister(store->object());
+         elements = ToRegister(store->elements());
+         index = store->index();
+         valueType = store->mir()->value()->type();
+         if (store->value()->isConstant())
+-            value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
++            value.emplace(ConstantOrRegister(store->value()->toConstant()->toJSValue()));
+         else
+-            value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
++            value.emplace(TypedOrValueRegister(valueType, ToAnyRegister(store->value())));
+         spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
+     }
+ 
+     Register indexReg = ToRegister(index);
+ 
+     // If index == initializedLength, try to bump the initialized length inline.
+     // If index > initializedLength, call a stub. Note that this relies on the
+     // condition flags sticking from the incoming branch.
+@@ -9483,17 +9481,17 @@ CodeGenerator::visitOutOfLineStoreElemen
+         // Jump to the inline path where we will store the value.
+         masm.jump(ool->rejoinStore());
+     }
+ 
+     masm.bind(ool->callStub());
+     saveLive(ins);
+ 
+     pushArg(Imm32(ool->strict()));
+-    pushArg(value);
++    pushArg(value.ref());
+     if (index->isConstant())
+         pushArg(Imm32(ToInt32(index)));
+     else
+         pushArg(ToRegister(index));
+     pushArg(object);
+     callVM(SetDenseElementInfo, ins);
+ 
+     restoreLive(ins);
+@@ -9732,23 +9730,23 @@ CodeGenerator::visitArrayPushV(LArrayPus
+ }
+ 
+ void
+ CodeGenerator::visitArrayPushT(LArrayPushT* lir)
+ {
+     Register obj = ToRegister(lir->object());
+     Register elementsTemp = ToRegister(lir->temp());
+     Register length = ToRegister(lir->output());
+-    ConstantOrRegister value;
++    mozilla::Maybe<ConstantOrRegister> value;
+     if (lir->value()->isConstant())
+-        value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
++        value.emplace(ConstantOrRegister(lir->value()->toConstant()->toJSValue()));
+     else
+-        value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
++        value.emplace(TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value())));
+     Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
+-    emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
++    emitArrayPush(lir, obj, value.ref(), elementsTemp, length, spectreTemp);
+ }
+ 
+ typedef JSObject* (*ArraySliceDenseFn)(JSContext*, HandleObject, int32_t, int32_t, HandleObject);
+ static const VMFunction ArraySliceDenseInfo =
+     FunctionInfo<ArraySliceDenseFn>(array_slice_dense, "array_slice_dense");
+ 
+ void
+ CodeGenerator::visitArraySlice(LArraySlice* lir)
+@@ -11714,92 +11712,91 @@ CodeGenerator::visitLoadElementFromState
+         // Add table entries if the table is inlined.
+         for (size_t i = 0, e = array->numElements(); i < e; i++)
+             jumpTable->addTableEntry(masm);
+     }
+ 
+     // Add inlined code for loading arguments from where they are allocated.
+     for (size_t i = 0, e = array->numElements(); i < e; i++) {
+         MDefinition* elem = array->getElement(i);
+-        ConstantOrRegister input;
++        mozilla::Maybe<ConstantOrRegister> input;
+ 
+         jumpTable->addCodeEntry(masm);
+         Register typeReg = Register::Invalid();
+         const LAllocation* a = lir->getOperand(1 + BOX_PIECES * i);
+         if (a->isBogus()) {
+             if (elem->type() == MIRType::Null) {
+-                input = NullValue();
++                input.emplace(NullValue());
+             } else if (elem->type() == MIRType::Undefined) {
+-                input = UndefinedValue();
++                input.emplace(UndefinedValue());
+             } else if (elem->isConstant() && elem->isEmittedAtUses()) {
+-                input = elem->toConstant()->toJSValue();
++                input.emplace(elem->toConstant()->toJSValue());
+             } else {
+                 MOZ_CRASH("Unsupported element constant allocation.");
+             }
+         } else if (a->isMemory()) {
+             if (elem->type() == MIRType::Double) {
+                 masm.loadDouble(ToAddress(a), tempD);
+-                input = TypedOrValueRegister(elem->type(), AnyRegister(tempD));
++                input.emplace(TypedOrValueRegister(elem->type(), AnyRegister(tempD)));
+             } else if (elem->type() == MIRType::Value) {
+                 typeReg = temp0;
+                 masm.loadPtr(ToAddress(a), temp0);
+ #ifdef JS_PUNBOX64
+-                input = TypedOrValueRegister(ValueOperand(temp0));
++                input.emplace(TypedOrValueRegister(ValueOperand(temp0)));
+ #endif
+             } else {
+                 typeReg = temp0;
+                 size_t width = StackSlotAllocator::width(LDefinition::TypeFrom(elem->type()));
+                 if (width == 4)
+                     masm.load32(ToAddress(a), temp0);
+                 else if (width == 8)
+                     masm.loadPtr(ToAddress(a), temp0);
+                 else
+                     MOZ_CRASH("Unsupported load size");
+-                input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
++                input.emplace(TypedOrValueRegister(elem->type(), AnyRegister(typeReg)));
+             }
+         } else if (a->isGeneralReg()) {
+             typeReg = ToRegister(a);
+-            input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
+ #ifdef JS_PUNBOX64
+             if (elem->type() != MIRType::Value)
+-                input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
++                input.emplace(TypedOrValueRegister(elem->type(), AnyRegister(typeReg)));
+             else
+-                input = TypedOrValueRegister(ValueOperand(typeReg));
++                input.emplace(TypedOrValueRegister(ValueOperand(typeReg)));
+ #else
+             if (elem->type() != MIRType::Value)
+-                input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
++                input.emplace(TypedOrValueRegister(elem->type(), AnyRegister(typeReg)));
+ #endif
+         } else if (a->isFloatReg()) {
+-            input = TypedOrValueRegister(elem->type(), AnyRegister(ToFloatRegister(a)));
++            input.emplace(TypedOrValueRegister(elem->type(), AnyRegister(ToFloatRegister(a))));
+         } else if (a->isConstantValue()) {
+-            input = a->toConstant()->toJSValue();
++            input.emplace(a->toConstant()->toJSValue());
+         } else {
+             MOZ_CRASH("Unsupported element allocation.");
+         }
+ 
+ #ifdef JS_NUNBOX32
+         if (elem->type() == MIRType::Value) {
+             static_assert(TYPE_INDEX == 0, "Unexpected type allocation index");
+             static_assert(PAYLOAD_INDEX == 1, "Unexpected payload allocation index");
+             const LAllocation* a1 = lir->getOperand(1 + BOX_PIECES * i + 1);
+             MOZ_ASSERT(!a1->isBogus());
+             MOZ_ASSERT(typeReg != Register::Invalid());
+             if (a1->isMemory()) {
+                 masm.loadPtr(ToAddress(a1), temp1);
+-                input = TypedOrValueRegister(ValueOperand(typeReg, temp1));
++                input.emplace(TypedOrValueRegister(ValueOperand(typeReg, temp1)));
+             } else if (a1->isGeneralReg()) {
+-                input = TypedOrValueRegister(ValueOperand(typeReg, ToRegister(a1)));
++                input.emplace(TypedOrValueRegister(ValueOperand(typeReg, ToRegister(a1))));
+             } else {
+                 MOZ_CRASH("Unsupported Value allocation.");
+             }
+         } else {
+             MOZ_ASSERT(lir->getOperand(1 + BOX_PIECES * i + 1)->isBogus());
+         }
+ #endif
+-        masm.moveValue(input, out);
++        masm.moveValue(input.ref(), out);
+ 
+         // For the last entry, fall-through.
+         if (i + 1 < e)
+             masm.jump(&join);
+     }
+ 
+     addOutOfLineCode(jumpTable, lir->mir());
+     masm.bind(&join);
+diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h
+--- a/js/src/jit/CompileInfo.h
++++ b/js/src/jit/CompileInfo.h
+@@ -247,17 +247,17 @@ class CompileInfo
+         // If the script uses an environment in body, the environment chain
+         // will need to be observable.
+         needsBodyEnvironmentObject_ = script->needsBodyEnvironment();
+         funNeedsSomeEnvironmentObject_ = fun ? fun->needsSomeEnvironmentObject() : false;
+     }
+ 
+     explicit CompileInfo(unsigned nlocals)
+       : script_(nullptr), fun_(nullptr), osrPc_(nullptr),
+-        analysisMode_(Analysis_None), scriptNeedsArgsObj_(false),
++        analysisMode_(Analysis_None), scriptNeedsArgsObj_(false), hadOverflowBailout_(false),
+         mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr),
+         needsBodyEnvironmentObject_(false), funNeedsSomeEnvironmentObject_(false)
+     {
+         nimplicit_ = 0;
+         nargs_ = 0;
+         nlocals_ = nlocals;
+         nstack_ = 1;  /* For FunctionCompiler::pushPhiInput/popPhiOutput */
+         nslots_ = nlocals_ + nstack_;
+diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
+--- a/js/src/jit/Ion.cpp
++++ b/js/src/jit/Ion.cpp
+@@ -386,17 +386,18 @@ JSContext::allocateOsrTempData(size_t si
+ void
+ JSContext::freeOsrTempData()
+ {
+     js_free(osrTempData_);
+     osrTempData_ = nullptr;
+ }
+ 
+ JitRealm::JitRealm()
+-  : stubCodes_(nullptr)
++  : stubCodes_(nullptr),
++    stringsCanBeInNursery(false)
+ {
+ }
+ 
+ JitRealm::~JitRealm()
+ {
+     js_delete(stubCodes_);
+ }
+ 
+@@ -839,28 +840,34 @@ IonScript::IonScript(IonCompilationId co
+     runtimeSize_(0),
+     icIndex_(0),
+     icEntries_(0),
+     safepointIndexOffset_(0),
+     safepointIndexEntries_(0),
+     safepointsStart_(0),
+     safepointsSize_(0),
+     frameSlots_(0),
++    argumentSlots_(0),
+     frameSize_(0),
+     bailoutTable_(0),
+     bailoutEntries_(0),
+     osiIndexOffset_(0),
+     osiIndexEntries_(0),
+     snapshots_(0),
+     snapshotsListSize_(0),
+     snapshotsRVATableSize_(0),
++    recovers_(0),
++    recoversSize_(0),
+     constantTable_(0),
+     constantEntries_(0),
++    sharedStubList_(0),
++    sharedStubEntries_(0),
+     invalidationCount_(0),
+     compilationId_(compilationId),
++    optimizationLevel_(OptimizationLevel::Normal),
+     osrPcMismatchCounter_(0),
+     fallbackStubSpace_()
+ {
+ }
+ 
+ IonScript*
+ IonScript::New(JSContext* cx, IonCompilationId compilationId,
+                uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize,
+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
+@@ -131,16 +131,17 @@ IonBuilder::IonBuilder(JSContext* analys
+     analysisContext(analysisContext),
+     baselineFrame_(baselineFrame),
+     constraints_(constraints),
+     thisTypes(nullptr),
+     argTypes(nullptr),
+     typeArray(nullptr),
+     typeArrayHint(0),
+     bytecodeTypeMap(nullptr),
++    current(nullptr),
+     loopDepth_(loopDepth),
+     blockWorklist(*temp),
+     cfgCurrent(nullptr),
+     cfg(nullptr),
+     trackedOptimizationSites_(*temp),
+     lexicalCheck_(nullptr),
+     callerResumePoint_(nullptr),
+     callerBuilder_(nullptr),
+diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h
+--- a/js/src/jit/IonCode.h
++++ b/js/src/jit/IonCode.h
+@@ -63,20 +63,17 @@ class JitCode : public gc::TenuredCell
+     uint32_t dataRelocTableBytes_;    // Size of the data relocation table.
+     uint8_t headerSize_ : 5;          // Number of bytes allocated before codeStart.
+     uint8_t kind_ : 3;                // jit::CodeKind, for the memory reporters.
+     bool invalidated_ : 1;            // Whether the code object has been invalidated.
+                                       // This is necessary to prevent GC tracing.
+     bool hasBytecodeMap_ : 1;         // Whether the code object has been registered with
+                                       // native=>bytecode mapping tables.
+ 
+-    JitCode()
+-      : code_(nullptr),
+-        pool_(nullptr)
+-    { }
++    JitCode() = delete;
+     JitCode(uint8_t* code, uint32_t bufferSize, uint32_t headerSize, ExecutablePool* pool,
+             CodeKind kind)
+       : code_(code),
+         pool_(pool),
+         bufferSize_(bufferSize),
+         insnSize_(0),
+         dataSize_(0),
+         jumpRelocTableBytes_(0),
+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
+@@ -10,16 +10,17 @@
+ 
+ using namespace js;
+ using namespace js::jit;
+ using mozilla::DebugOnly;
+ 
+ ControlFlowGenerator::ControlFlowGenerator(TempAllocator& temp, JSScript* script)
+   : script(script),
+     current(nullptr),
++    pc(nullptr),
+     alloc_(temp),
+     blocks_(temp),
+     cfgStack_(temp),
+     loops_(temp),
+     switches_(temp),
+     labels_(temp),
+     aborted_(false),
+     checkedTryFinally_(false)
+diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h
+--- a/js/src/jit/IonOptimizationLevels.h
++++ b/js/src/jit/IonOptimizationLevels.h
+@@ -144,17 +144,46 @@ class OptimizationInfo
+     // are inlined, as a fraction of compilerWarmUpThreshold.
+     double inliningWarmUpThresholdFactor_;
+ 
+     // How many invocations or loop iterations are needed before a function
+     // is hot enough to recompile the outerScript to inline that function,
+     // as a multiplication of inliningWarmUpThreshold.
+     uint32_t inliningRecompileThresholdFactor_;
+ 
+-    OptimizationInfo()
++    constexpr OptimizationInfo()
++      : level_(OptimizationLevel::Normal),
++        eaa_(false),
++        ama_(false),
++        edgeCaseAnalysis_(false),
++        eliminateRedundantChecks_(false),
++        inlineInterpreted_(false),
++        inlineNative_(false),
++        eagerSimdUnbox_(false),
++        gvn_(false),
++        licm_(false),
++        rangeAnalysis_(false),
++        loopUnrolling_(false),
++        reordering_(false),
++        autoTruncate_(false),
++        sincos_(false),
++        sink_(false),
++        registerAllocator_(RegisterAllocator_Backtracking),
++        inlineMaxBytecodePerCallSiteHelperThread_(0),
++        inlineMaxBytecodePerCallSiteMainThread_(0),
++        inlineMaxCalleeInlinedBytecodeLength_(0),
++        inlineMaxTotalBytecodeLength_(0),
++        inliningMaxCallerBytecodeLength_(0),
++        maxInlineDepth_(0),
++        scalarReplacement_(false),
++        smallFunctionMaxInlineDepth_(0),
++        compilerWarmUpThreshold_(0),
++        compilerSmallFunctionWarmUpThreshold_(0),
++        inliningWarmUpThresholdFactor_(0.0),
++        inliningRecompileThresholdFactor_(0)
+     { }
+ 
+     void initNormalOptimizationInfo();
+     void initWasmOptimizationInfo();
+ 
+     OptimizationLevel level() const {
+         return level_;
+     }
+diff --git a/js/src/jit/JitAllocPolicy.h b/js/src/jit/JitAllocPolicy.h
+--- a/js/src/jit/JitAllocPolicy.h
++++ b/js/src/jit/JitAllocPolicy.h
+@@ -7,16 +7,18 @@
+ #ifndef jit_JitAllocPolicy_h
+ #define jit_JitAllocPolicy_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/GuardObjects.h"
+ #include "mozilla/OperatorNewExtensions.h"
+ #include "mozilla/TypeTraits.h"
+ 
++#include <utility>
++
+ #include "ds/LifoAlloc.h"
+ #include "jit/InlineList.h"
+ #include "jit/Ion.h"
+ #include "vm/JSContext.h"
+ 
+ namespace js {
+ namespace jit {
+ 
+@@ -184,21 +186,23 @@ class TempObjectPool
+   public:
+     TempObjectPool()
+       : alloc_(nullptr)
+     {}
+     void setAllocator(TempAllocator& alloc) {
+         MOZ_ASSERT(freed_.empty());
+         alloc_ = &alloc;
+     }
+-    T* allocate() {
++    template <typename... Args>
++    T* allocate(Args&&... args) {
+         MOZ_ASSERT(alloc_);
+         if (freed_.empty())
+-            return new(alloc_->fallible()) T();
+-        return freed_.popFront();
++            return new (alloc_->fallible()) T(std::forward<Args>(args)...);
++        T* res = freed_.popFront();
++        return new (res) T(std::forward<Args>(args)...);
+     }
+     void free(T* obj) {
+         freed_.pushFront(obj);
+     }
+     void clear() {
+         freed_.clear();
+     }
+ };
+diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
+--- a/js/src/jit/JitFrames.cpp
++++ b/js/src/jit/JitFrames.cpp
+@@ -1536,16 +1536,17 @@ SnapshotIterator::SnapshotIterator(const
+     instructionResults_(nullptr)
+ {
+ }
+ 
+ SnapshotIterator::SnapshotIterator()
+   : snapshot_(nullptr, 0, 0, 0),
+     recover_(snapshot_, nullptr, 0),
+     fp_(nullptr),
++    machine_(nullptr),
+     ionScript_(nullptr),
+     instructionResults_(nullptr)
+ {
+ }
+ 
+ int32_t
+ SnapshotIterator::readOuterNumActualArgs() const
+ {
+@@ -2049,28 +2050,32 @@ SnapshotIterator::maybeReadAllocByIndex(
+         skip();
+ 
+     return s;
+ }
+ 
+ InlineFrameIterator::InlineFrameIterator(JSContext* cx, const JSJitFrameIter* iter)
+   : calleeTemplate_(cx),
+     calleeRVA_(),
+-    script_(cx)
++    script_(cx),
++    pc_(nullptr),
++    numActualArgs_(0)
+ {
+     resetOn(iter);
+ }
+ 
+ InlineFrameIterator::InlineFrameIterator(JSContext* cx, const InlineFrameIterator* iter)
+   : frame_(iter ? iter->frame_ : nullptr),
+     framesRead_(0),
+     frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
+     calleeTemplate_(cx),
+     calleeRVA_(),
+-    script_(cx)
++    script_(cx),
++    pc_(nullptr),
++    numActualArgs_(0)
+ {
+     if (frame_) {
+         machine_ = iter->machine_;
+         start_ = SnapshotIterator(*frame_, &machine_);
+ 
+         // findNextFrame will iterate to the next frame and init. everything.
+         // Therefore to settle on the same frame, we report one frame less readed.
+         framesRead_ = iter->framesRead_ - 1;
+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
+@@ -225,18 +225,17 @@ static const uint32_t NO_FRAME_SIZE_CLAS
+ class FrameSizeClass
+ {
+     uint32_t class_;
+ 
+     explicit FrameSizeClass(uint32_t class_) : class_(class_)
+     { }
+ 
+   public:
+-    FrameSizeClass()
+-    { }
++    FrameSizeClass() = delete;
+ 
+     static FrameSizeClass None() {
+         return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID);
+     }
+     static FrameSizeClass FromClass(uint32_t class_) {
+         return FrameSizeClass(class_);
+     }
+ 
+diff --git a/js/src/jit/JitRealm.h b/js/src/jit/JitRealm.h
+--- a/js/src/jit/JitRealm.h
++++ b/js/src/jit/JitRealm.h
+@@ -27,18 +27,26 @@
+ namespace js {
+ namespace jit {
+ 
+ class FrameSizeClass;
+ 
+ struct EnterJitData
+ {
+     explicit EnterJitData(JSContext* cx)
+-      : envChain(cx),
+-        result(cx)
++      : jitcode(nullptr),
++        osrFrame(nullptr),
++        calleeToken(nullptr),
++        maxArgv(nullptr),
++        maxArgc(0),
++        numActualArgs(0),
++        osrNumStackValues(0),
++        envChain(cx),
++        result(cx),
++        constructing(false)
+     {}
+ 
+     uint8_t* jitcode;
+     InterpreterFrame* osrFrame;
+ 
+     void* calleeToken;
+ 
+     Value* maxArgv;
+diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h
+--- a/js/src/jit/LIR.h
++++ b/js/src/jit/LIR.h
+@@ -1459,31 +1459,31 @@ class LSnapshot : public TempObject
+ 
+ struct SafepointSlotEntry {
+     // Flag indicating whether this is a slot in the stack or argument space.
+     uint32_t stack:1;
+ 
+     // Byte offset of the slot, as in LStackSlot or LArgument.
+     uint32_t slot:31;
+ 
+-    SafepointSlotEntry() { }
++    SafepointSlotEntry() : stack(0), slot(0) { }
+     SafepointSlotEntry(bool stack, uint32_t slot)
+       : stack(stack), slot(slot)
+     { }
+     explicit SafepointSlotEntry(const LAllocation* a)
+       : stack(a->isStackSlot()), slot(a->memorySlot())
+     { }
+ };
+ 
+ struct SafepointNunboxEntry {
+     uint32_t typeVreg;
+     LAllocation type;
+     LAllocation payload;
+ 
+-    SafepointNunboxEntry() { }
++    SafepointNunboxEntry() : typeVreg(0) { }
+     SafepointNunboxEntry(uint32_t typeVreg, LAllocation type, LAllocation payload)
+       : typeVreg(typeVreg), type(type), payload(payload)
+     { }
+ };
+ 
+ class LSafepoint : public TempObject
+ {
+     typedef SafepointSlotEntry SlotEntry;
+diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp
+--- a/js/src/jit/MIRGraph.cpp
++++ b/js/src/jit/MIRGraph.cpp
+@@ -484,16 +484,18 @@ MBasicBlock::New(MIRGraph& graph, const 
+ 
+ MBasicBlock::MBasicBlock(MIRGraph& graph, const CompileInfo& info, BytecodeSite* site, Kind kind)
+   : unreachable_(false),
+     specialized_(false),
+     graph_(graph),
+     info_(info),
+     predecessors_(graph.alloc()),
+     stackPosition_(info_.firstStackSlot()),
++    id_(0),
++    domIndex_(0),
+     numDominated_(0),
+     pc_(site->pc()),
+     lir_(nullptr),
+     callerResumePoint_(nullptr),
+     entryResumePoint_(nullptr),
+     outerResumePoint_(nullptr),
+     successorWithPhis_(nullptr),
+     positionInPhiSuccessor_(0),
+diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
+--- a/js/src/jit/MacroAssembler.cpp
++++ b/js/src/jit/MacroAssembler.cpp
+@@ -2803,16 +2803,17 @@ MacroAssembler::alignJitStackBasedOnNArg
+ 
+ // ===============================================================
+ 
+ MacroAssembler::MacroAssembler(JSContext* cx)
+   : framePushed_(0),
+ #ifdef DEBUG
+     inCall_(false),
+ #endif
++    dynamicAlignment_(false),
+     emitProfilingInstrumentation_(false)
+ {
+     jitContext_.emplace(cx, (js::jit::TempAllocator*)nullptr);
+     alloc_.emplace(cx);
+     moveResolver_.setAllocator(*jitContext_->temp);
+ #if defined(JS_CODEGEN_ARM)
+     initWithAllocator();
+     m_buffer.id = GetJitContext()->getNextAssemblerId();
+@@ -2822,16 +2823,17 @@ MacroAssembler::MacroAssembler(JSContext
+ #endif
+ }
+ 
+ MacroAssembler::MacroAssembler()
+   : framePushed_(0),
+ #ifdef DEBUG
+     inCall_(false),
+ #endif
++    dynamicAlignment_(false),
+     emitProfilingInstrumentation_(false)
+ {
+     JitContext* jcx = GetJitContext();
+ 
+     if (!jcx->temp) {
+         JSContext* cx = jcx->cx;
+         MOZ_ASSERT(cx);
+         alloc_.emplace(cx);
+@@ -2848,16 +2850,17 @@ MacroAssembler::MacroAssembler()
+ #endif
+ }
+ 
+ MacroAssembler::MacroAssembler(WasmToken, TempAllocator& alloc)
+   : framePushed_(0),
+ #ifdef DEBUG
+     inCall_(false),
+ #endif
++    dynamicAlignment_(false),
+     emitProfilingInstrumentation_(false)
+ {
+     moveResolver_.setAllocator(alloc);
+ 
+ #if defined(JS_CODEGEN_ARM)
+     initWithAllocator();
+     m_buffer.id = 0;
+ #elif defined(JS_CODEGEN_ARM64)
+diff --git a/js/src/jit/MoveResolver.cpp b/js/src/jit/MoveResolver.cpp
+--- a/js/src/jit/MoveResolver.cpp
++++ b/js/src/jit/MoveResolver.cpp
+@@ -11,16 +11,17 @@
+ 
+ #include "jit/MacroAssembler.h"
+ #include "jit/RegisterSets.h"
+ 
+ using namespace js;
+ using namespace js::jit;
+ 
+ MoveOperand::MoveOperand(MacroAssembler& masm, const ABIArg& arg)
++  : disp_(0)
+ {
+     switch (arg.kind()) {
+       case ABIArg::GPR:
+         kind_ = REG;
+         code_ = arg.gpr().code();
+         break;
+ #ifdef JS_CODEGEN_REGISTER_PAIR
+       case ABIArg::GPR_PAIR:
+@@ -59,20 +60,19 @@ MoveResolver::resetState()
+     curCycles_ = 0;
+ }
+ 
+ bool
+ MoveResolver::addMove(const MoveOperand& from, const MoveOperand& to, MoveOp::Type type)
+ {
+     // Assert that we're not doing no-op moves.
+     MOZ_ASSERT(!(from == to));
+-    PendingMove* pm = movePool_.allocate();
++    PendingMove* pm = movePool_.allocate(from, to, type);
+     if (!pm)
+         return false;
+-    new (pm) PendingMove(from, to, type);
+     pending_.pushBack(pm);
+     return true;
+ }
+ 
+ // Given move (A -> B), this function attempts to find any move (B -> *) in the
+ // pending move list, and returns the first one.
+ MoveResolver::PendingMove*
+ MoveResolver::findBlockingMove(const PendingMove* last)
+@@ -200,24 +200,24 @@ MoveResolver::resolve()
+     // This logic is only applicable because ARM only uses registers d0-d15,
+     // all of which alias s0-s31. Double registers d16-d31 are unused.
+     // Therefore there is never a double move that cannot be split.
+     // If this changes in the future, the algorithm will have to be fixed.
+     for (auto iter = pending_.begin(); iter != pending_.end(); ++iter) {
+         PendingMove* pm = *iter;
+ 
+         if (isDoubleAliasedAsSingle(pm->from()) || isDoubleAliasedAsSingle(pm->to())) {
+-            PendingMove* lower = movePool_.allocate();
++            MoveOperand fromLower = SplitIntoLowerHalf(pm->from());
++            MoveOperand toLower = SplitIntoLowerHalf(pm->to());
++
++            PendingMove* lower = movePool_.allocate(fromLower, toLower, MoveOp::FLOAT32);
+             if (!lower)
+                 return false;
+ 
+             // Insert the new node before the current position to not affect iteration.
+-            MoveOperand fromLower = SplitIntoLowerHalf(pm->from());
+-            MoveOperand toLower = SplitIntoLowerHalf(pm->to());
+-            new (lower) PendingMove(fromLower, toLower, MoveOp::FLOAT32);
+             pending_.insertBefore(pm, lower);
+ 
+             // Overwrite pm in place for the upper move. Iteration proceeds as normal.
+             MoveOperand fromUpper = SplitIntoUpperHalf(pm->from());
+             MoveOperand toUpper = SplitIntoUpperHalf(pm->to());
+             pm->overwrite(fromUpper, toUpper, MoveOp::FLOAT32);
+         }
+     }
+diff --git a/js/src/jit/MoveResolver.h b/js/src/jit/MoveResolver.h
+--- a/js/src/jit/MoveResolver.h
++++ b/js/src/jit/MoveResolver.h
+@@ -40,21 +40,20 @@ class MoveOperand
+     };
+ 
+   private:
+     Kind kind_;
+     uint32_t code_;
+     int32_t disp_;
+ 
+   public:
+-    MoveOperand()
++    MoveOperand() = delete;
++    explicit MoveOperand(Register reg) : kind_(REG), code_(reg.code()), disp_(0)
+     { }
+-    explicit MoveOperand(Register reg) : kind_(REG), code_(reg.code())
+-    { }
+-    explicit MoveOperand(FloatRegister reg) : kind_(FLOAT_REG), code_(reg.code())
++    explicit MoveOperand(FloatRegister reg) : kind_(FLOAT_REG), code_(reg.code()), disp_(0)
+     { }
+     MoveOperand(Register reg, int32_t disp, Kind kind = MEMORY)
+         : kind_(kind),
+         code_(reg.code()),
+         disp_(disp)
+     {
+         MOZ_ASSERT(isMemoryOrEffectiveAddress());
+ 
+@@ -202,18 +201,17 @@ class MoveOp
+     // of the cycle. For example, given these moves:
+     //       INT32 move a -> b
+     //     GENERAL move b -> a
+     // the move resolver starts by copying b into a temporary location, so that
+     // the last move can read it. This copy needs to use use type GENERAL.
+     Type endCycleType_;
+ 
+   public:
+-    MoveOp()
+-    { }
++    MoveOp() = delete;
+     MoveOp(const MoveOperand& from, const MoveOperand& to, Type type)
+       : from_(from),
+         to_(to),
+         cycleBegin_(false),
+         cycleEnd_(false),
+         cycleBeginSlot_(-1),
+         cycleEndSlot_(-1),
+         type_(type),
+@@ -265,18 +263,18 @@ class MoveOp
+ class MoveResolver
+ {
+   private:
+     struct PendingMove
+       : public MoveOp,
+         public TempObject,
+         public InlineListNode<PendingMove>
+     {
+-        PendingMove()
+-        { }
++        PendingMove() = delete;
++
+         PendingMove(const MoveOperand& from, const MoveOperand& to, Type type)
+           : MoveOp(from, to, type)
+         { }
+ 
+         void setCycleBegin(Type endCycleType, int cycleSlot) {
+             MOZ_ASSERT(!cycleBegin_);
+             cycleBegin_ = true;
+             cycleBeginSlot_ = cycleSlot;
+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
+@@ -449,17 +449,19 @@ struct IonTrackedTypeWithAddendum
+             JSScript* script;
+             uint32_t offset;
+         };
+         JSFunction* constructor;
+     };
+ 
+     explicit IonTrackedTypeWithAddendum(TypeSet::Type type)
+       : type(type),
+-        hasAddendum(HasNothing)
++        hasAddendum(HasNothing),
++        script(nullptr),
++        offset(0)
+     { }
+ 
+     IonTrackedTypeWithAddendum(TypeSet::Type type, JSScript* script, uint32_t offset)
+       : type(type),
+         hasAddendum(HasAllocationSite),
+         script(script),
+         offset(offset)
+     { }
+diff --git a/js/src/jit/RangeAnalysis.h b/js/src/jit/RangeAnalysis.h
+--- a/js/src/jit/RangeAnalysis.h
++++ b/js/src/jit/RangeAnalysis.h
+@@ -190,25 +190,25 @@ class Range : public TempObject {
+     // 2) hasInt32UpperBound_ == false implies upper_ == JSVAL_INT_MAX
+     //
+     // As a second and less precise range analysis, we represent the maximal
+     // exponent taken by a value. The exponent is calculated by taking the
+     // absolute value and looking at the position of the highest bit.  All
+     // exponent computation have to be over-estimations of the actual result. On
+     // the Int32 this over approximation is rectified.
+ 
+-    int32_t lower_;
+-    int32_t upper_;
++    MOZ_INIT_OUTSIDE_CTOR int32_t lower_;
++    MOZ_INIT_OUTSIDE_CTOR int32_t upper_;
+ 
+-    bool hasInt32LowerBound_;
+-    bool hasInt32UpperBound_;
++    MOZ_INIT_OUTSIDE_CTOR bool hasInt32LowerBound_;
++    MOZ_INIT_OUTSIDE_CTOR bool hasInt32UpperBound_;
+ 
+-    FractionalPartFlag canHaveFractionalPart_ : 1;
+-    NegativeZeroFlag canBeNegativeZero_ : 1;
+-    uint16_t max_exponent_;
++    MOZ_INIT_OUTSIDE_CTOR FractionalPartFlag canHaveFractionalPart_ : 1;
++    MOZ_INIT_OUTSIDE_CTOR NegativeZeroFlag canBeNegativeZero_ : 1;
++    MOZ_INIT_OUTSIDE_CTOR uint16_t max_exponent_;
+ 
+     // Any symbolic lower or upper bound computed for this term.
+     const SymbolicBound* symbolicLower_;
+     const SymbolicBound* symbolicUpper_;
+ 
+     // This function simply makes several MOZ_ASSERTs to verify the internal
+     // consistency of this range.
+     void assertInvariants() const {
+diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h
+--- a/js/src/jit/RegisterSets.h
++++ b/js/src/jit/RegisterSets.h
+@@ -241,18 +241,17 @@ class ConstantOrRegister
+         // placement-new'd into existence.
+         MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
+         U() {}
+         MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
+     } data;
+ 
+   public:
+ 
+-    ConstantOrRegister()
+-    {}
++    ConstantOrRegister() = delete;
+ 
+     MOZ_IMPLICIT ConstantOrRegister(const Value& value)
+       : constant_(true)
+     {
+         MOZ_ASSERT(constant());
+         new (&data.constant) Value(value);
+     }
+ 
+diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp
+--- a/js/src/jit/RematerializedFrame.cpp
++++ b/js/src/jit/RematerializedFrame.cpp
+@@ -31,23 +31,26 @@ struct CopyValueToRematerializedFrame
+         *slots++ = v;
+     }
+ };
+ 
+ RematerializedFrame::RematerializedFrame(JSContext* cx, uint8_t* top, unsigned numActualArgs,
+                                          InlineFrameIterator& iter, MaybeReadFallback& fallback)
+   : prevUpToDate_(false),
+     isDebuggee_(iter.script()->isDebuggee()),
++    hasInitialEnv_(false),
+     isConstructing_(iter.isConstructing()),
+     hasCachedSavedFrame_(false),
+     top_(top),
+     pc_(iter.pc()),
+     frameNo_(iter.frameNo()),
+     numActualArgs_(numActualArgs),
+-    script_(iter.script())
++    script_(iter.script()),
++    envChain_(nullptr),
++    argsObj_(nullptr)
+ {
+     if (iter.isFunctionFrame())
+         callee_ = iter.callee(fallback);
+     else
+         callee_ = nullptr;
+ 
+     CopyValueToRematerializedFrame op(slots_);
+     iter.readFrameArgsAndLocals(cx, op, op, &envChain_, &hasInitialEnv_, &returnValue_,
+diff --git a/js/src/jit/Safepoints.cpp b/js/src/jit/Safepoints.cpp
+--- a/js/src/jit/Safepoints.cpp
++++ b/js/src/jit/Safepoints.cpp
+@@ -390,17 +390,19 @@ SafepointWriter::endEntry()
+ {
+     JitSpew(JitSpew_Safepoints, "    -- entry ended at %d", uint32_t(stream_.length()));
+ }
+ 
+ SafepointReader::SafepointReader(IonScript* script, const SafepointIndex* si)
+   : stream_(script->safepoints() + si->safepointOffset(),
+             script->safepoints() + script->safepointsSize()),
+     frameSlots_((script->frameSlots() / sizeof(intptr_t)) + 1), // Stack slot counts are inclusive.
+-    argumentSlots_(script->argumentSlots() / sizeof(intptr_t))
++    argumentSlots_(script->argumentSlots() / sizeof(intptr_t)),
++    nunboxSlotsRemaining_(0),
++    slotsOrElementsSlotsRemaining_(0)
+ {
+     osiCallPointOffset_ = stream_.readUnsigned();
+ 
+     // gcSpills is a subset of allGprSpills.
+     allGprSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_));
+     if (allGprSpills_.empty()) {
+         gcSpills_ = allGprSpills_;
+         valueSpills_ = allGprSpills_;
+diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp
+--- a/js/src/jit/ScalarReplacement.cpp
++++ b/js/src/jit/ScalarReplacement.cpp
+@@ -369,16 +369,17 @@ class ObjectMemoryView : public MDefinit
+     void loadOffset(MInstruction* ins, size_t offset);
+     void visitObjectGuard(MInstruction* ins, MDefinition* operand);
+ };
+ 
+ const char* ObjectMemoryView::phaseName = "Scalar Replacement of Object";
+ 
+ ObjectMemoryView::ObjectMemoryView(TempAllocator& alloc, MInstruction* obj)
+   : alloc_(alloc),
++    undefinedVal_(nullptr),
+     obj_(obj),
+     startBlock_(obj->block()),
+     state_(nullptr),
+     lastResumePoint_(nullptr),
+     oom_(false)
+ {
+     // Annotate snapshots RValue such that we recover the store first.
+     obj_->setIncompleteObject();
+diff --git a/js/src/jit/StupidAllocator.h b/js/src/jit/StupidAllocator.h
+--- a/js/src/jit/StupidAllocator.h
++++ b/js/src/jit/StupidAllocator.h
+@@ -48,17 +48,18 @@ class StupidAllocator : public RegisterA
+     // Type indicating an index into registers.
+     typedef uint32_t RegisterIndex;
+ 
+     // Information about each virtual register.
+     Vector<LDefinition*, 0, SystemAllocPolicy> virtualRegisters;
+ 
+   public:
+     StupidAllocator(MIRGenerator* mir, LIRGenerator* lir, LIRGraph& graph)
+-      : RegisterAllocator(mir, lir, graph)
++      : RegisterAllocator(mir, lir, graph),
++        registerCount(0)
+     {
+     }
+ 
+     MOZ_MUST_USE bool go();
+ 
+   private:
+     MOZ_MUST_USE bool init();
+ 
+diff --git a/js/src/jit/TypedObjectPrediction.h b/js/src/jit/TypedObjectPrediction.h
+--- a/js/src/jit/TypedObjectPrediction.h
++++ b/js/src/jit/TypedObjectPrediction.h
+@@ -113,17 +113,18 @@ class TypedObjectPrediction {
+                              size_t* index) const;
+ 
+   public:
+ 
+     ///////////////////////////////////////////////////////////////////////////
+     // Constructing a prediction. Generally, you start with an empty
+     // prediction and invoke addDescr() repeatedly.
+ 
+-    TypedObjectPrediction() {
++    TypedObjectPrediction()
++      : data_() {
+         kind_ = Empty;
+     }
+ 
+     explicit TypedObjectPrediction(const TypeDescr& descr) {
+         setDescr(descr);
+     }
+ 
+     TypedObjectPrediction(const StructTypeDescr& descr, size_t fields) {
+diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp
+--- a/js/src/jit/arm/Trampoline-arm.cpp
++++ b/js/src/jit/arm/Trampoline-arm.cpp
+@@ -794,17 +794,16 @@ JitRuntime::generateVMWrapper(JSContext*
+ 
+     masm.setupUnalignedABICall(regs.getAny());
+     masm.passABIArg(cxreg);
+ 
+     size_t argDisp = 0;
+ 
+     // Copy any arguments.
+     for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
+-        MoveOperand from;
+         switch (f.argProperties(explicitArg)) {
+           case VMFunction::WordByValue:
+             masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+             argDisp += sizeof(void*);
+             break;
+           case VMFunction::DoubleByValue:
+             // Values should be passed by reference, not by value, so we assert
+             // that the argument is a double-precision float.
+diff --git a/js/src/jit/arm64/Trampoline-arm64.cpp b/js/src/jit/arm64/Trampoline-arm64.cpp
+--- a/js/src/jit/arm64/Trampoline-arm64.cpp
++++ b/js/src/jit/arm64/Trampoline-arm64.cpp
+@@ -610,17 +610,16 @@ JitRuntime::generateVMWrapper(JSContext*
+ 
+     masm.setupUnalignedABICall(regs.getAny());
+     masm.passABIArg(reg_cx);
+ 
+     size_t argDisp = 0;
+ 
+     // Copy arguments.
+     for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
+-        MoveOperand from;
+         switch (f.argProperties(explicitArg)) {
+           case VMFunction::WordByValue:
+             masm.passABIArg(MoveOperand(argsBase, argDisp),
+                             (f.argPassedInFloatReg(explicitArg) ? MoveOp::DOUBLE : MoveOp::GENERAL));
+             argDisp += sizeof(void*);
+             break;
+ 
+           case VMFunction::WordByRef:
+diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp
+--- a/js/src/jit/shared/CodeGenerator-shared.cpp
++++ b/js/src/jit/shared/CodeGenerator-shared.cpp
+@@ -70,17 +70,18 @@ CodeGeneratorShared::CodeGeneratorShared
+     trackedOptimizationsTypesTableOffset_(0),
+     trackedOptimizationsAttemptsTableOffset_(0),
+     osrEntryOffset_(0),
+     skipArgCheckEntryOffset_(0),
+ #ifdef CHECK_OSIPOINT_REGISTERS
+     checkOsiPointRegisters(JitOptions.checkOsiPointRegisters),
+ #endif
+     frameDepth_(graph->paddedLocalSlotsSize() + graph->argumentsSize()),
+-    frameInitialAdjustment_(0)
++    frameInitialAdjustment_(0),
++    frameClass_(FrameSizeClass::None())
+ {
+     if (gen->isProfilerInstrumentationEnabled())
+         masm.enableProfilingInstrumentation();
+ 
+     if (gen->compilingWasm()) {
+         // Since wasm uses the system ABI which does not necessarily use a
+         // regular array where all slots are sizeof(Value), it maintains the max
+         // argument stack depth separately.
+@@ -102,17 +103,17 @@ CodeGeneratorShared::CodeGeneratorShared
+             // instead relies on the a priori stack adjustment. This must be the
+             // last adjustment of frameDepth_.
+             frameDepth_ += ComputeByteAlignment(sizeof(wasm::Frame) + frameDepth_,
+                                                 WasmStackAlignment);
+         }
+ 
+         // FrameSizeClass is only used for bailing, which cannot happen in
+         // wasm code.
+-        frameClass_ = FrameSizeClass::None();
++        MOZ_ASSERT(frameClass_ == FrameSizeClass::None());
+     } else {
+         frameClass_ = FrameSizeClass::FromDepth(frameDepth_);
+     }
+ }
+ 
+ bool
+ CodeGeneratorShared::generatePrologue()
+ {
+diff --git a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
++++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+@@ -238,16 +238,17 @@ class BranchDeadlineSet
+             earliest_ = deadline;
+             earliestRange_ = rangeIdx;
+         }
+         return true;
+     }
+ 
+   public:
+     explicit BranchDeadlineSet(LifoAlloc& alloc)
++      : earliestRange_(0)
+     {
+         // Manually construct vectors in the uninitialized aligned storage.
+         // This is because C++ arrays can otherwise only be constructed with
+         // the default constructor.
+         for (unsigned r = 0; r < NumRanges; r++)
+             new (&vectorForRange(r)) RangeVector(alloc);
+     }
+ 
+diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h
+--- a/js/src/jit/shared/Lowering-shared.h
++++ b/js/src/jit/shared/Lowering-shared.h
+@@ -32,16 +32,17 @@ class LIRGeneratorShared
+     MResumePoint* lastResumePoint_;
+     LRecoverInfo* cachedRecoverInfo_;
+     LOsiPoint* osiPoint_;
+ 
+     LIRGeneratorShared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
+       : gen(gen),
+         graph(graph),
+         lirGraph_(lirGraph),
++        current(nullptr),
+         lastResumePoint_(nullptr),
+         cachedRecoverInfo_(nullptr),
+         osiPoint_(nullptr)
+     { }
+ 
+     MIRGenerator* mir() {
+         return gen;
+     }
+diff --git a/js/src/jit/x64/Assembler-x64.cpp b/js/src/jit/x64/Assembler-x64.cpp
+--- a/js/src/jit/x64/Assembler-x64.cpp
++++ b/js/src/jit/x64/Assembler-x64.cpp
+@@ -257,17 +257,19 @@ class RelocationIterator
+ {
+     CompactBufferReader reader_;
+     uint32_t tableStart_;
+     uint32_t offset_;
+     uint32_t extOffset_;
+ 
+   public:
+     explicit RelocationIterator(CompactBufferReader& reader)
+-      : reader_(reader)
++      : reader_(reader),
++        offset_(0),
++        extOffset_(0)
+     {
+         tableStart_ = reader_.readFixedUint32_t();
+     }
+ 
+     bool read() {
+         if (!reader_.more())
+             return false;
+         offset_ = reader_.readUnsigned();
+diff --git a/js/src/jit/x64/Bailouts-x64.cpp b/js/src/jit/x64/Bailouts-x64.cpp
+--- a/js/src/jit/x64/Bailouts-x64.cpp
++++ b/js/src/jit/x64/Bailouts-x64.cpp
+@@ -42,32 +42,34 @@ class BailoutStack
+ } // namespace js
+ 
+ #if defined(_WIN32)
+ # pragma pack(pop)
+ #endif
+ 
+ BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
+                                    BailoutStack* bailout)
+-  : machine_(bailout->machineState())
++  : machine_(bailout->machineState()),
++    activation_(nullptr)
+ {
+     uint8_t* sp = bailout->parentStackPointer();
+     framePointer_ = sp + bailout->frameSize();
+     topFrameSize_ = framePointer_ - sp;
+ 
+     JSScript* script = ScriptFromCalleeToken(((JitFrameLayout*) framePointer_)->calleeToken());
+     topIonScript_ = script->ionScript();
+ 
+     attachOnJitActivation(activations);
+     snapshotOffset_ = bailout->snapshotOffset();
+ }
+ 
+ BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
+                                    InvalidationBailoutStack* bailout)
+-  : machine_(bailout->machine())
++  : machine_(bailout->machine()),
++    activation_(nullptr)
+ {
+     framePointer_ = (uint8_t*) bailout->fp();
+     topFrameSize_ = framePointer_ - bailout->sp();
+     topIonScript_ = bailout->ionScript();
+     attachOnJitActivation(activations);
+ 
+     uint8_t* returnAddressToFp_ = bailout->osiPointReturnAddress();
+     const OsiIndex* osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
+diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp
+--- a/js/src/jit/x64/Trampoline-x64.cpp
++++ b/js/src/jit/x64/Trampoline-x64.cpp
+@@ -681,17 +681,16 @@ JitRuntime::generateVMWrapper(JSContext*
+ 
+     masm.setupUnalignedABICall(regs.getAny());
+     masm.passABIArg(cxreg);
+ 
+     size_t argDisp = 0;
+ 
+     // Copy arguments.
+     for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
+-        MoveOperand from;
+         switch (f.argProperties(explicitArg)) {
+           case VMFunction::WordByValue:
+             if (f.argPassedInFloatReg(explicitArg))
+                 masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
+             else
+                 masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+             argDisp += sizeof(void*);
+             break;
+diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp
+--- a/js/src/jit/x86/Trampoline-x86.cpp
++++ b/js/src/jit/x86/Trampoline-x86.cpp
+@@ -695,17 +695,16 @@ JitRuntime::generateVMWrapper(JSContext*
+ 
+     masm.setupUnalignedABICall(regs.getAny());
+     masm.passABIArg(cxreg);
+ 
+     size_t argDisp = 0;
+ 
+     // Copy arguments.
+     for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
+-        MoveOperand from;
+         switch (f.argProperties(explicitArg)) {
+           case VMFunction::WordByValue:
+             masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
+             argDisp += sizeof(void*);
+             break;
+           case VMFunction::DoubleByValue:
+             // We don't pass doubles in float registers on x86, so no need
+             // to check for argPassedInFloatReg.

+ 1089 - 0
frg/work-js/mozilla-release/patches/1453795-41-62a1.patch

@@ -0,0 +1,1089 @@
+# HG changeset patch
+# User Andi-Bogdan Postelnicu <bpostelnicu@mozilla.com>
+# Date 1529759656 -10800
+#      Sat Jun 23 16:14:16 2018 +0300
+# Node ID 6a76baf321797f3831aeffaab4eb852e9383f213
+# Parent  64ba408163f2f1ab0a97e8d35827cf820fcb950b
+Bug 1453795 - JS - Initialize member fields in classes/ structures. r=waldoo
+
+diff --git a/js/src/ds/OrderedHashTable.h b/js/src/ds/OrderedHashTable.h
+--- a/js/src/ds/OrderedHashTable.h
++++ b/js/src/ds/OrderedHashTable.h
+@@ -97,16 +97,19 @@ class OrderedHashTable
+         }
+     }
+ 
+   public:
+     OrderedHashTable(AllocPolicy& ap, mozilla::HashCodeScrambler hcs)
+       : hashTable(nullptr),
+         data(nullptr),
+         dataLength(0),
++        dataCapacity(0),
++        liveCount(0),
++        hashShift(0),
+         ranges(nullptr),
+         nurseryRanges(nullptr),
+         alloc(ap),
+         hcs(hcs)
+     {}
+ 
+     MOZ_MUST_USE bool init() {
+         MOZ_ASSERT(!hashTable, "init must be called at most once");
+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
+@@ -1691,17 +1691,18 @@ class MOZ_STACK_CLASS TryEmitter
+ 
+   public:
+     TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
+       : bce_(bce),
+         kind_(kind),
+         controlKind_(controlKind),
+         depth_(0),
+         noteIndex_(0),
+-        tryStart_(0)
++        tryStart_(0),
++        tryEnd_{}
+ #ifdef DEBUG
+       , state_(State::Start)
+ #endif
+     {
+         if (controlKind_ == ControlKind::Syntactic)
+             controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
+         finallyStart_.offset = 0;
+     }
+@@ -2506,16 +2507,17 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
+   : sc(sc),
+     cx(sc->context),
+     parent(parent),
+     script(cx, script),
+     lazyScript(cx, lazyScript),
+     prologue(cx, lineNum),
+     main(cx, lineNum),
+     current(&main),
++    parser(nullptr),
+     atomIndices(cx->frontendCollectionPool()),
+     firstLine(lineNum),
+     maxFixedSlots(0),
+     maxStackDepth(0),
+     stackDepth(0),
+     emitLevel(0),
+     bodyScopeIndex(UINT32_MAX),
+     varEmitterScope(nullptr),
+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
+@@ -108,17 +108,19 @@ struct RecyclableAtomMapValueWrapper
+         uint64_t dummy;
+     };
+ 
+     static void assertInvariant() {
+         static_assert(sizeof(Wrapped) <= sizeof(uint64_t),
+                       "Can only recycle atom maps with values smaller than uint64");
+     }
+ 
+-    RecyclableAtomMapValueWrapper() {
++    RecyclableAtomMapValueWrapper()
++      : dummy(0)
++    {
+         assertInvariant();
+     }
+ 
+     MOZ_IMPLICIT RecyclableAtomMapValueWrapper(Wrapped w)
+       : wrapped(w)
+     {
+         assertInvariant();
+     }
+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
+@@ -191,17 +191,20 @@ struct KeywordInfo;
+ 
+ namespace js {
+ namespace frontend {
+ 
+ struct TokenPos {
+     uint32_t    begin;  // Offset of the token's first char.
+     uint32_t    end;    // Offset of 1 past the token's last char.
+ 
+-    TokenPos() {}
++    TokenPos()
++      : begin(0),
++        end(0)
++    {}
+     TokenPos(uint32_t begin, uint32_t end) : begin(begin), end(end) {}
+ 
+     // Return a TokenPos that covers left, right, and anything in between.
+     static TokenPos box(const TokenPos& left, const TokenPos& right) {
+         MOZ_ASSERT(left.begin <= left.end);
+         MOZ_ASSERT(left.end <= right.begin);
+         MOZ_ASSERT(right.begin <= right.end);
+         return TokenPos(left.begin, right.end);
+diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h
+--- a/js/src/gc/Nursery.h
++++ b/js/src/gc/Nursery.h
+@@ -429,26 +429,22 @@ class Nursery
+         mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount, mozilla::TimeStamp>;
+     using ProfileDurations =
+         mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount, mozilla::TimeDuration>;
+ 
+     ProfileTimes startTimes_;
+     ProfileDurations profileDurations_;
+     ProfileDurations totalDurations_;
+ 
+-    /*
+-     * This data is initialised only if the nursery is enabled and after at
+-     * least one call to Nursery::collect()
+-     */
+     struct {
+-        JS::gcreason::Reason reason;
+-        size_t nurseryCapacity;
+-        size_t nurseryLazyCapacity;
+-        size_t nurseryUsedBytes;
+-        size_t tenuredBytes;
++        JS::gcreason::Reason reason = JS::gcreason::NO_REASON;
++        size_t nurseryCapacity = 0;
++        size_t nurseryLazyCapacity = 0;
++        size_t nurseryUsedBytes = 0;
++        size_t tenuredBytes = 0;
+     } previousGC;
+ 
+     /*
+      * Calculate the promotion rate of the most recent minor GC.
+      * The valid_for_tenuring parameter is used to return whether this
+      * promotion rate is accurate enough (the nursery was full enough) to be
+      * used for tenuring and other decisions.
+      *
+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
+@@ -129,17 +129,19 @@ class FakeMutableHandle : public js::Mut
+         *ptr = v;
+     }
+ 
+     DECLARE_POINTER_CONSTREF_OPS(T);
+     DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
+     DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
+ 
+   private:
+-    FakeMutableHandle() {}
++    FakeMutableHandle()
++      : ptr(nullptr)
++    {}
+     DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T);
+ 
+     T* ptr;
+ };
+ 
+ template <typename T> class MaybeRooted<T, NoGC>
+ {
+   public:
+diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp
+--- a/js/src/gc/Statistics.cpp
++++ b/js/src/gc/Statistics.cpp
+@@ -722,16 +722,19 @@ Statistics::Statistics(JSRuntime* rt)
+   : runtime(rt),
+     gcTimerFile(nullptr),
+     gcDebugFile(nullptr),
+     nonincrementalReason_(gc::AbortReason::None),
+     preBytes(0),
+     thresholdTriggered(false),
+     triggerAmount(0.0),
+     triggerThreshold(0.0),
++    startingMinorGCNumber(0),
++    startingMajorGCNumber(0),
++    startingSliceNumber(0),
+     maxPauseInInterval(0),
+     sliceCallback(nullptr),
+     nurseryCollectionCallback(nullptr),
+     aborted(false),
+     enableProfiling_(false),
+     sliceCount_(0)
+ {
+     for (auto& count : counts)
+diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h
+--- a/js/src/gc/Statistics.h
++++ b/js/src/gc/Statistics.h
+@@ -216,17 +216,18 @@ struct Statistics
+     struct SliceData {
+         SliceData(SliceBudget budget, JS::gcreason::Reason reason,
+                   TimeStamp start, size_t startFaults, gc::State initialState)
+           : budget(budget), reason(reason),
+             initialState(initialState),
+             finalState(gc::State::NotActive),
+             resetReason(gc::AbortReason::None),
+             start(start),
+-            startFaults(startFaults)
++            startFaults(startFaults),
++            endFaults(0)
+         {}
+ 
+         SliceBudget budget;
+         JS::gcreason::Reason reason;
+         gc::State initialState, finalState;
+         gc::AbortReason resetReason;
+         TimeStamp start, end;
+         size_t startFaults, endFaults;
+diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp
+--- a/js/src/irregexp/RegExpEngine.cpp
++++ b/js/src/irregexp/RegExpEngine.cpp
+@@ -1647,16 +1647,17 @@ IsLatin1Equivalent(char16_t c, RegExpCom
+ }
+ 
+ // Attempts to compile the regexp using an Irregexp code generator.  Returns
+ // a fixed array or a null handle depending on whether it succeeded.
+ RegExpCompiler::RegExpCompiler(JSContext* cx, LifoAlloc* alloc, int capture_count,
+                                bool ignore_case, bool latin1, bool match_only, bool unicode)
+   : next_register_(2 * (capture_count + 1)),
+     recursion_depth_(0),
++    macro_assembler_(nullptr),
+     ignore_case_(ignore_case),
+     latin1_(latin1),
+     match_only_(match_only),
+     unicode_(unicode),
+     reg_exp_too_big_(false),
+     current_expansion_factor_(1),
+     frequency_collator_(),
+     cx_(cx),
+diff --git a/js/src/irregexp/RegExpEngine.h b/js/src/irregexp/RegExpEngine.h
+--- a/js/src/irregexp/RegExpEngine.h
++++ b/js/src/irregexp/RegExpEngine.h
+@@ -681,16 +681,17 @@ class ActionNode : public SeqRegExpNode
+         BEGIN_SUBMATCH,
+         POSITIVE_SUBMATCH_SUCCESS,
+         EMPTY_MATCH_CHECK,
+         CLEAR_CAPTURES
+     };
+ 
+     ActionNode(ActionType action_type, RegExpNode* on_success)
+       : SeqRegExpNode(on_success),
++        data_{},
+         action_type_(action_type)
+     {}
+ 
+     static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
+     static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
+     static ActionNode* StorePosition(int reg,
+                                      bool is_capture,
+                                      RegExpNode* on_success);
+diff --git a/js/src/jsapi-tests/testPrivateGCThingValue.cpp b/js/src/jsapi-tests/testPrivateGCThingValue.cpp
+--- a/js/src/jsapi-tests/testPrivateGCThingValue.cpp
++++ b/js/src/jsapi-tests/testPrivateGCThingValue.cpp
+@@ -19,16 +19,18 @@ class TestTracer : public JS::CallbackTr
+ 
+   public:
+     js::gc::Cell* expectedCell;
+     JS::TraceKind expectedKind;
+     bool found;
+ 
+     explicit TestTracer(JSContext* cx)
+       : JS::CallbackTracer(cx),
++        expectedCell(nullptr),
++        expectedKind(static_cast<JS::TraceKind>(0)),
+         found(false)
+     { }
+ };
+ 
+ static const JSClass TestClass = {
+     "TestClass",
+     JSCLASS_HAS_RESERVED_SLOTS(1)
+ };
+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
+@@ -474,17 +474,21 @@ class ExternalData {
+  */
+ class AutoLeaveZeal
+ {
+     JSContext* cx_;
+     uint32_t zealBits_;
+     uint32_t frequency_;
+ 
+   public:
+-    explicit AutoLeaveZeal(JSContext* cx) : cx_(cx) {
++    explicit AutoLeaveZeal(JSContext* cx)
++      : cx_(cx),
++        zealBits_(0),
++        frequency_(0)
++    {
+         uint32_t dummy;
+         JS_GetGCZealBits(cx_, &zealBits_, &frequency_, &dummy);
+         JS_SetGCZeal(cx_, 0, 0);
+         JS::PrepareForFullGC(cx_);
+         JS::NonIncrementalGC(cx_, GC_SHRINK, JS::gcreason::DEBUG_GC);
+     }
+     ~AutoLeaveZeal() {
+         JS_SetGCZeal(cx_, 0, 0);
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -6869,17 +6869,20 @@ JS::AutoSaveExceptionState::~AutoSaveExc
+             context->overRecursed_ = wasOverRecursed;
+             context->throwing = true;
+             context->unwrappedException() = exceptionValue;
+         }
+     }
+ }
+ 
+ struct JSExceptionState {
+-    explicit JSExceptionState(JSContext* cx) : exception(cx) {}
++    explicit JSExceptionState(JSContext* cx)
++      : throwing(false),
++        exception(cx)
++    {}
+     bool throwing;
+     PersistentRootedValue exception;
+ };
+ 
+ JS_PUBLIC_API(JSExceptionState*)
+ JS_SaveExceptionState(JSContext* cx)
+ {
+     JSExceptionState* state;
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -1426,17 +1426,17 @@ class MOZ_STACK_CLASS JS_FRIEND_API(Auto
+      * 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_;
+-    union {
++    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:
+diff --git a/js/src/vm/BytecodeUtil.h b/js/src/vm/BytecodeUtil.h
+--- a/js/src/vm/BytecodeUtil.h
++++ b/js/src/vm/BytecodeUtil.h
+@@ -468,17 +468,17 @@ class SrcNoteLineScanner
+      * Is the current op the first one after a line change directive? Note that
+      * multiple ops may be "first" if a line directive is used to return to a
+      * previous line (eg, with a for loop increment expression.)
+      */
+     bool lineHeader;
+ 
+   public:
+     SrcNoteLineScanner(jssrcnote* sn, uint32_t lineno)
+-        : offset(0), sn(sn), lineno(lineno)
++        : offset(0), sn(sn), lineno(lineno), lineHeader(false)
+     {
+     }
+ 
+     /*
+      * This is called repeatedly with always-advancing relpc values. The src
+      * notes are tuples of <PC offset from prev src note, type, args>. Scan
+      * through, updating the lineno, until the next src note is for a later
+      * bytecode.
+diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
+--- a/js/src/vm/Caches.h
++++ b/js/src/vm/Caches.h
+@@ -78,17 +78,17 @@ struct EvalCacheEntry
+     }
+ };
+ 
+ struct EvalCacheLookup
+ {
+     explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
+     RootedLinearString str;
+     RootedScript callerScript;
+-    jsbytecode* pc;
++    MOZ_INIT_OUTSIDE_CTOR jsbytecode* pc;
+ };
+ 
+ struct EvalCacheHashPolicy
+ {
+     typedef EvalCacheLookup Lookup;
+ 
+     static HashNumber hash(const Lookup& l);
+     static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
+diff --git a/js/src/vm/Compression.cpp b/js/src/vm/Compression.cpp
+--- a/js/src/vm/Compression.cpp
++++ b/js/src/vm/Compression.cpp
+@@ -40,16 +40,23 @@ Compressor::Compressor(const unsigned ch
+     MOZ_ASSERT(inplen > 0);
+     zs.opaque = nullptr;
+     zs.next_in = (Bytef*)inp;
+     zs.avail_in = 0;
+     zs.next_out = nullptr;
+     zs.avail_out = 0;
+     zs.zalloc = zlib_alloc;
+     zs.zfree = zlib_free;
++    zs.total_in = 0;
++    zs.total_out = 0;
++    zs.msg = nullptr;
++    zs.state = nullptr;
++    zs.data_type = 0;
++    zs.adler = 0;
++    zs.reserved = 0;
+ 
+     // Reserve space for the CompressedDataHeader.
+     outbytes = sizeof(CompressedDataHeader);
+ }
+ 
+ Compressor::~Compressor()
+ {
+     if (initialized) {
+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
+@@ -4227,19 +4227,23 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
+         cx(cx),
+         debugger(dbg),
+         iterMarker(&cx->runtime()->gc),
+         realms(cx->zone()),
+         url(cx),
+         displayURLString(cx),
+         hasSource(false),
+         source(cx, AsVariant(static_cast<ScriptSourceObject*>(nullptr))),
++        hasLine(false),
++        line(0),
++        innermost(false),
+         innermostForRealm(cx->zone()),
+         vector(cx, ScriptVector(cx)),
+-        wasmInstanceVector(cx, WasmInstanceObjectVector(cx))
++        wasmInstanceVector(cx, WasmInstanceObjectVector(cx)),
++        oom(false)
+     {}
+ 
+     /*
+      * Initialize this ScriptQuery. Raise an error and return false if we
+      * haven't enough memory.
+      */
+     bool init() {
+         if (!realms.init() ||
+@@ -5461,17 +5465,20 @@ DebuggerScript_getStartLine(JSContext* c
+     return true;
+ }
+ 
+ struct DebuggerScriptGetLineCountMatcher
+ {
+     JSContext* cx_;
+     double totalLines;
+ 
+-    explicit DebuggerScriptGetLineCountMatcher(JSContext* cx) : cx_(cx) {}
++    explicit DebuggerScriptGetLineCountMatcher(JSContext* cx)
++      : cx_(cx),
++        totalLines(0.0)
++    {}
+     using ReturnType = bool;
+ 
+     ReturnType match(HandleScript script) {
+         totalLines = double(GetScriptLineExtent(script));
+         return true;
+     }
+     ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+         uint32_t result;
+@@ -6685,17 +6692,21 @@ DebuggerScript_clearAllBreakpoints(JSCon
+ 
+ class DebuggerScriptIsInCatchScopeMatcher
+ {
+     JSContext* cx_;
+     size_t offset_;
+     bool isInCatch_;
+ 
+   public:
+-    explicit DebuggerScriptIsInCatchScopeMatcher(JSContext* cx, size_t offset) : cx_(cx), offset_(offset) { }
++    explicit DebuggerScriptIsInCatchScopeMatcher(JSContext* cx, size_t offset)
++      : cx_(cx),
++        offset_(offset),
++        isInCatch_(false)
++    { }
+     using ReturnType = bool;
+ 
+     inline bool isInCatch() const { return isInCatch_; }
+ 
+     ReturnType match(HandleScript script) {
+         if (!EnsureScriptOffsetIsValid(cx_, script, offset_))
+             return false;
+ 
+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
+@@ -1611,17 +1611,19 @@ ScriptSource::chunkChars(JSContext* cx, 
+         return nullptr;
+     }
+     return ret;
+ }
+ 
+ ScriptSource::PinnedChars::PinnedChars(JSContext* cx, ScriptSource* source,
+                                        UncompressedSourceCache::AutoHoldEntry& holder,
+                                        size_t begin, size_t len)
+-  : source_(source)
++  : stack_(nullptr),
++    prev_(nullptr),
++    source_(source)
+ {
+     chars_ = source->chars(cx, holder, begin, len);
+     if (chars_) {
+         stack_ = &source->pinnedCharsStack_;
+         prev_ = *stack_;
+         *stack_ = this;
+     }
+ }
+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
+@@ -2095,16 +2095,17 @@ class JSScript : public js::gc::TenuredC
+     {
+         JS::RootedScript script_;
+         JSContext* cx_;
+         bool oldDoNotRelazify_;
+       public:
+         explicit AutoDelazify(JSContext* cx, JS::HandleFunction fun = nullptr)
+             : script_(cx)
+             , cx_(cx)
++            , oldDoNotRelazify_(false)
+         {
+             holdScript(fun);
+         }
+ 
+         ~AutoDelazify()
+         {
+             dropScript();
+         }
+diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
+--- a/js/src/vm/ObjectGroup.h
++++ b/js/src/vm/ObjectGroup.h
+@@ -623,17 +623,21 @@ class ObjectGroupRealm
+ 
+     // This cache is purged on GC.
+     class DefaultNewGroupCache
+     {
+         ObjectGroup* group_;
+         JSObject* associated_;
+ 
+       public:
+-        DefaultNewGroupCache() { purge(); }
++        DefaultNewGroupCache()
++          : associated_(nullptr)
++        {
++            purge();
++        }
+ 
+         void purge() {
+             group_ = nullptr;
+         }
+         void put(ObjectGroup* group, JSObject* associated) {
+             group_ = group;
+             associated_ = associated;
+         }
+diff --git a/js/src/vm/RegExpShared.h b/js/src/vm/RegExpShared.h
+--- a/js/src/vm/RegExpShared.h
++++ b/js/src/vm/RegExpShared.h
+@@ -229,17 +229,19 @@ class RegExpShared : public gc::TenuredC
+ };
+ 
+ class RegExpZone
+ {
+     struct Key {
+         JSAtom* atom;
+         uint16_t flag;
+ 
+-        Key() {}
++        Key()
++          : atom(nullptr), flag(0)
++        { }
+         Key(JSAtom* atom, RegExpFlag flag)
+           : atom(atom), flag(flag)
+         { }
+         MOZ_IMPLICIT Key(const ReadBarriered<RegExpShared*>& shared)
+           : atom(shared.unbarrieredGet()->getSource()),
+             flag(shared.unbarrieredGet()->getFlags())
+         { }
+ 
+diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
+--- a/js/src/vm/Shape.h
++++ b/js/src/vm/Shape.h
+@@ -1529,17 +1529,18 @@ class MutableWrappedPtrOperations<StackS
+ 
+ inline
+ Shape::Shape(const StackShape& other, uint32_t nfixed)
+   : base_(other.base),
+     propid_(other.propid),
+     immutableFlags(other.immutableFlags),
+     attrs(other.attrs),
+     mutableFlags(other.mutableFlags),
+-    parent(nullptr)
++    parent(nullptr),
++    listp(nullptr)
+ {
+     setNumFixedSlots(nfixed);
+ 
+ #ifdef DEBUG
+     gc::AllocKind allocKind = getAllocKind();
+     MOZ_ASSERT_IF(other.isAccessorShape(), allocKind == gc::AllocKind::ACCESSOR_SHAPE);
+     MOZ_ASSERT_IF(allocKind == gc::AllocKind::SHAPE, !other.isAccessorShape());
+ #endif
+@@ -1563,17 +1564,18 @@ class NurseryShapesRef : public gc::Buff
+ 
+ inline
+ Shape::Shape(UnownedBaseShape* base, uint32_t nfixed)
+   : base_(base),
+     propid_(JSID_EMPTY),
+     immutableFlags(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
+     attrs(0),
+     mutableFlags(0),
+-    parent(nullptr)
++    parent(nullptr),
++    listp(nullptr)
+ {
+     MOZ_ASSERT(base);
+     kids.setNull();
+ }
+ 
+ inline GetterOp
+ Shape::getter() const
+ {
+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
+@@ -1666,17 +1666,17 @@ class JitActivation : public Activation
+     mozilla::Maybe<wasm::TrapData> wasmTrapData_;
+ 
+     void clearRematerializedFrames();
+ 
+ #ifdef CHECK_OSIPOINT_REGISTERS
+   protected:
+     // Used to verify that live registers don't change between a VM call and
+     // the OsiPoint that follows it. Protected to silence Clang warning.
+-    uint32_t checkRegs_;
++    uint32_t checkRegs_ = 0;
+     RegisterDump regs_;
+ #endif
+ 
+   public:
+     explicit JitActivation(JSContext* cx);
+     ~JitActivation();
+ 
+     bool isProfiling() const {
+diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h
+--- a/js/src/vm/TraceLogging.h
++++ b/js/src/vm/TraceLogging.h
+@@ -570,32 +570,34 @@ class MOZ_RAII AutoTraceLog
+     bool executed;
+     AutoTraceLog* prev;
+ 
+   public:
+     AutoTraceLog(TraceLoggerThread* logger,
+                  const TraceLoggerEvent& event MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+       : logger(logger),
+         isEvent(true),
+-        executed(false)
++        executed(false),
++        prev(nullptr)
+     {
+         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+         payload.event = &event;
+         if (logger) {
+             logger->startEvent(event);
+ 
+             prev = logger->top;
+             logger->top = this;
+         }
+     }
+ 
+     AutoTraceLog(TraceLoggerThread* logger, TraceLoggerTextId id MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+       : logger(logger),
+         isEvent(false),
+-        executed(false)
++        executed(false),
++        prev(nullptr)
+     {
+         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+         payload.id = id;
+         if (logger) {
+             logger->startEvent(id);
+ 
+             prev = logger->top;
+             logger->top = this;
+diff --git a/js/src/vm/TraceLoggingGraph.h b/js/src/vm/TraceLoggingGraph.h
+--- a/js/src/vm/TraceLoggingGraph.h
++++ b/js/src/vm/TraceLoggingGraph.h
+@@ -125,16 +125,20 @@ class TraceLoggerGraph
+         {
+             start_ = start;
+             stop_ = stop;
+             u.s.textId_ = textId;
+             u.s.hasChildren_ = hasChildren;
+             nextId_ = nextId;
+         }
+         TreeEntry()
++          : start_(0),
++            stop_(0),
++            u{},
++            nextId_(0)
+         { }
+         uint64_t start() {
+             return start_;
+         }
+         uint64_t stop() {
+             return stop_;
+         }
+         uint32_t textId() {
+diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h
+--- a/js/src/vm/TraceLoggingTypes.h
++++ b/js/src/vm/TraceLoggingTypes.h
+@@ -157,17 +157,19 @@ class ContinuousSpace {
+     uint32_t size_;
+     uint32_t capacity_;
+ 
+     // The maximum number of bytes of RAM a continuous space structure can take.
+     static const uint32_t LIMIT = 200 * 1024 * 1024;
+ 
+   public:
+     ContinuousSpace ()
+-     : data_(nullptr)
++     : data_(nullptr),
++       size_(0),
++       capacity_(0)
+     { }
+ 
+     bool init() {
+         capacity_ = 64;
+         size_ = 0;
+         data_ = (T*) js_malloc(capacity_ * sizeof(T));
+         if (!data_)
+             return false;
+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
+@@ -333,16 +333,17 @@ struct js::AsmJSMetadata : Metadata, Asm
+     }
+     uint32_t srcEndAfterCurly() const {
+         return srcStart + srcLengthWithRightBrace;
+     }
+ 
+     AsmJSMetadata()
+       : Metadata(ModuleKind::AsmJS),
+         cacheResult(CacheResult::Miss),
++        toStringStart(0),
+         srcStart(0),
+         strict(false)
+     {}
+     ~AsmJSMetadata() override {}
+ 
+     const AsmJSExport& lookupAsmJSExport(uint32_t funcIndex) const {
+         // The AsmJSExportVector isn't stored in sorted order so do a linear
+         // search. This is for the super-cold and already-expensive toString()
+@@ -1519,17 +1520,17 @@ class MOZ_STACK_CLASS ModuleValidator
+                 SimdType type_;
+                 SimdOperation which_;
+             } simdOp;
+ 
+             // |varOrConst|, through |varOrConst.literalValue_|, has a
+             // non-trivial constructor and therefore MUST be placement-new'd
+             // into existence.
+             MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
+-            U() {}
++            U() : funcDefIndex_(0) {}
+             MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
+         } u;
+ 
+         friend class ModuleValidator;
+         friend class js::LifoAlloc;
+ 
+         explicit Global(Which which) : which_(which) {}
+ 
+@@ -1610,17 +1611,17 @@ class MOZ_STACK_CLASS ModuleValidator
+         enum Kind { Function, Constant };
+         Kind kind;
+ 
+         union {
+             double cst;
+             AsmJSMathBuiltinFunction func;
+         } u;
+ 
+-        MathBuiltin() : kind(Kind(-1)) {}
++        MathBuiltin() : kind(Kind(-1)), u{} {}
+         explicit MathBuiltin(double cst) : kind(Constant) {
+             u.cst = cst;
+         }
+         explicit MathBuiltin(AsmJSMathBuiltinFunction func) : kind(Function) {
+             u.func = func;
+         }
+     };
+ 
+diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
+--- a/js/src/wasm/WasmBaselineCompile.cpp
++++ b/js/src/wasm/WasmBaselineCompile.cpp
+@@ -1005,16 +1005,18 @@ using ScratchI8 = ScratchI32;
+ BaseLocalIter::BaseLocalIter(const ValTypeVector& locals, size_t argsLength, bool debugEnabled)
+   : locals_(locals),
+     argsLength_(argsLength),
+     argsRange_(locals.begin(), argsLength),
+     argsIter_(argsRange_),
+     index_(0),
+     localSize_(debugEnabled ? DebugFrame::offsetOfFrame() : 0),
+     reservedSize_(localSize_),
++    frameOffset_(0),
++    mirType_(MIRType::Undefined),
+     done_(false)
+ {
+     MOZ_ASSERT(argsLength <= locals.length());
+     settle();
+ }
+ 
+ int32_t
+ BaseLocalIter::pushLocal(size_t nbytes)
+diff --git a/js/src/wasm/WasmFrameIter.cpp b/js/src/wasm/WasmFrameIter.cpp
+--- a/js/src/wasm/WasmFrameIter.cpp
++++ b/js/src/wasm/WasmFrameIter.cpp
+@@ -35,17 +35,18 @@ using mozilla::Maybe;
+ 
+ WasmFrameIter::WasmFrameIter(JitActivation* activation, wasm::Frame* fp)
+   : activation_(activation),
+     code_(nullptr),
+     codeRange_(nullptr),
+     lineOrBytecode_(0),
+     fp_(fp ? fp : activation->wasmExitFP()),
+     unwoundIonCallerFP_(nullptr),
+-    unwind_(Unwind::False)
++    unwind_(Unwind::False),
++    unwoundAddressOfReturnAddress_(nullptr)
+ {
+     MOZ_ASSERT(fp_);
+ 
+     // When the stack is captured during a trap (viz., to create the .stack
+     // for an Error object), use the pc/bytecode information captured by the
+     // signal handler in the runtime.
+ 
+     if (activation->isWasmTrapping()) {
+diff --git a/js/src/wasm/WasmFrameIter.h b/js/src/wasm/WasmFrameIter.h
+--- a/js/src/wasm/WasmFrameIter.h
++++ b/js/src/wasm/WasmFrameIter.h
+@@ -93,32 +93,35 @@ class WasmFrameIter
+ enum class SymbolicAddress;
+ 
+ // An ExitReason describes the possible reasons for leaving compiled wasm
+ // code or the state of not having left compiled wasm code
+ // (ExitReason::None). It is either a known reason, or a enumeration to a native
+ // function that is used for better display in the profiler.
+ class ExitReason
+ {
+-    uint32_t payload_;
+-
+-    ExitReason() {}
+-
+   public:
+     enum class Fixed : uint32_t
+     {
+         None,            // default state, the pc is in wasm code
+         FakeInterpEntry, // slow-path entry call from C++ WasmCall()
+         ImportJit,       // fast-path call directly into JIT code
+         ImportInterp,    // slow-path call into C++ Invoke()
+         BuiltinNative,   // fast-path call directly into native C++ code
+         Trap,            // call to trap handler
+         DebugTrap        // call to debug trap handler
+     };
+ 
++  private:
++    uint32_t payload_;
++
++    ExitReason() : ExitReason(Fixed::None) {}
++
++  public:
++
+     MOZ_IMPLICIT ExitReason(Fixed exitReason)
+       : payload_(0x0 | (uint32_t(exitReason) << 1))
+     {
+         MOZ_ASSERT(isFixed());
+         MOZ_ASSERT_IF(isNone(), payload_ == 0);
+     }
+ 
+     explicit ExitReason(SymbolicAddress sym)
+diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp
+--- a/js/src/wasm/WasmJS.cpp
++++ b/js/src/wasm/WasmJS.cpp
+@@ -2887,16 +2887,17 @@ class CompileStreamTask : public Promise
+     CompileStreamTask(JSContext* cx, Handle<PromiseObject*> promise,
+                       CompileArgs& compileArgs, bool instantiate,
+                       HandleObject importObj)
+       : PromiseHelperTask(cx, promise),
+         compileArgs_(&compileArgs),
+         instantiate_(instantiate),
+         importObj_(cx, importObj),
+         streamState_(mutexid::WasmStreamStatus, Env),
++        codeSection_{},
+         codeStreamEnd_(nullptr),
+         exclusiveCodeStreamEnd_(mutexid::WasmCodeStreamEnd, nullptr),
+         exclusiveTailBytes_(mutexid::WasmTailBytesPtr, nullptr),
+         streamFailed_(false)
+     {
+         MOZ_ASSERT_IF(importObj_, instantiate_);
+     }
+ };
+diff --git a/js/src/wasm/WasmOpIter.h b/js/src/wasm/WasmOpIter.h
+--- a/js/src/wasm/WasmOpIter.h
++++ b/js/src/wasm/WasmOpIter.h
+@@ -233,16 +233,18 @@ Classify(OpBytes op);
+ template <typename Value>
+ struct LinearMemoryAddress
+ {
+     Value base;
+     uint32_t offset;
+     uint32_t align;
+ 
+     LinearMemoryAddress()
++      : offset(0),
++        align(0)
+     {}
+     LinearMemoryAddress(Value base, uint32_t offset, uint32_t align)
+       : base(base), offset(offset), align(align)
+     {}
+ };
+ 
+ template <typename ControlItem>
+ class ControlStackEntry
+diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp
+--- a/js/src/wasm/WasmTextToBinary.cpp
++++ b/js/src/wasm/WasmTextToBinary.cpp
+@@ -162,17 +162,18 @@ class WasmToken
+       : kind_(Kind::Invalid),
+         begin_(nullptr),
+         end_(nullptr),
+         u()
+     { }
+     WasmToken(Kind kind, const char16_t* begin, const char16_t* end)
+       : kind_(kind),
+         begin_(begin),
+-        end_(end)
++        end_(end),
++        u{}
+     {
+         MOZ_ASSERT(kind_ != Error);
+         MOZ_ASSERT(kind_ != Invalid);
+         MOZ_ASSERT((kind == EndOfFile) == (begin == end));
+     }
+     explicit WasmToken(uint32_t index, const char16_t* begin, const char16_t* end)
+       : kind_(Index),
+         begin_(begin),
+@@ -245,17 +246,18 @@ class WasmToken
+         MOZ_ASSERT(begin != end);
+         MOZ_ASSERT(kind_ == AtomicCmpXchg || kind_ == AtomicLoad || kind_ == AtomicRMW ||
+                    kind_ == AtomicStore || kind_ == Wait || kind_ == Wake);
+         u.threadOp_ = op;
+     }
+     explicit WasmToken(const char16_t* begin)
+       : kind_(Error),
+         begin_(begin),
+-        end_(begin)
++        end_(begin),
++        u{}
+     {}
+     Kind kind() const {
+         MOZ_ASSERT(kind_ != Kind::Invalid);
+         return kind_;
+     }
+     const char16_t* begin() const {
+         return begin_;
+     }
+diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h
+--- a/js/src/wasm/WasmTypes.h
++++ b/js/src/wasm/WasmTypes.h
+@@ -768,17 +768,17 @@ class InitExpr
+   private:
+     Kind kind_;
+     union U {
+         Val val_;
+         struct {
+             uint32_t index_;
+             ValType type_;
+         } global;
+-        U() {}
++        U() : global{} {}
+     } u;
+ 
+   public:
+     InitExpr() = default;
+ 
+     explicit InitExpr(Val val) : kind_(Kind::Constant) {
+         u.val_ = val;
+     }
+@@ -891,17 +891,17 @@ class GlobalDesc
+     union V {
+         struct {
+             union U {
+                 InitExpr initial_;
+                 struct {
+                     ValType type_;
+                     uint32_t index_;
+                 } import;
+-                U() {}
++                U() : import{} {}
+             } val;
+             unsigned offset_;
+             bool isMutable_;
+             bool isWasm_;
+             bool isExport_;
+         } var;
+         Val cst_;
+         V() {}
+@@ -1474,17 +1474,20 @@ class CallSiteDesc
+     enum Kind {
+         Func,       // pc-relative call to a specific function
+         Dynamic,    // dynamic callee called via register
+         Symbolic,   // call to a single symbolic callee
+         EnterFrame, // call to a enter frame handler
+         LeaveFrame, // call to a leave frame handler
+         Breakpoint  // call to instruction breakpoint
+     };
+-    CallSiteDesc() {}
++    CallSiteDesc()
++      : lineOrBytecode_(0),
++        kind_(0)
++    {}
+     explicit CallSiteDesc(Kind kind)
+       : lineOrBytecode_(0), kind_(kind)
+     {
+         MOZ_ASSERT(kind == Kind(kind_));
+     }
+     CallSiteDesc(uint32_t lineOrBytecode, Kind kind)
+       : lineOrBytecode_(lineOrBytecode), kind_(kind)
+     {
+@@ -1495,17 +1498,17 @@ class CallSiteDesc
+     Kind kind() const { return Kind(kind_); }
+ };
+ 
+ class CallSite : public CallSiteDesc
+ {
+     uint32_t returnAddressOffset_;
+ 
+   public:
+-    CallSite() {}
++    CallSite() : returnAddressOffset_(0) {}
+ 
+     CallSite(CallSiteDesc desc, uint32_t returnAddressOffset)
+       : CallSiteDesc(desc),
+         returnAddressOffset_(returnAddressOffset)
+     { }
+ 
+     void offsetBy(int32_t delta) { returnAddressOffset_ += delta; }
+     uint32_t returnAddressOffset() const { return returnAddressOffset_; }
+@@ -1873,17 +1876,17 @@ class CalleeDesc
+         // Like Builtin, but automatically passes Instance* as first argument.
+         BuiltinInstanceMethod
+     };
+ 
+   private:
+     // which_ shall be initialized in the static constructors
+     MOZ_INIT_OUTSIDE_CTOR Which which_;
+     union U {
+-        U() {}
++        U() : funcIndex_(0) {}
+         uint32_t funcIndex_;
+         struct {
+             uint32_t globalDataOffset_;
+         } import;
+         struct {
+             uint32_t globalDataOffset_;
+             uint32_t minLength_;
+             bool external_;

+ 98 - 0
frg/work-js/mozilla-release/patches/1456006-1-63a1.patch

@@ -0,0 +1,98 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532070836 -32400
+# Node ID 74b3d9d91b3e2432fd30a1c36a140ad730076ba6
+# Parent  b2c8594ec4c3c9e7010f02129a80a5d6fdefb0d4
+Bug 1456006 - Part 0: Add reportError and reportExtraWarning variants to receive offset instead of 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
+@@ -1492,32 +1492,62 @@ BytecodeEmitter::reportError(ParseNode* 
+     va_list args;
+     va_start(args, errorNumber);
+ 
+     parser->errorReporter().errorAtVA(offset, errorNumber, &args);
+ 
+     va_end(args);
+ }
+ 
++void
++BytecodeEmitter::reportError(const Maybe<uint32_t>& maybeOffset, unsigned errorNumber, ...)
++{
++    MOZ_ASSERT_IF(!maybeOffset, this->scriptStartOffsetSet);
++    uint32_t offset = maybeOffset ? *maybeOffset : this->scriptStartOffset;
++
++    va_list args;
++    va_start(args, errorNumber);
++
++    parser->errorReporter().errorAtVA(offset, errorNumber, &args);
++
++    va_end(args);
++}
++
+ bool
+ BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
+ {
+     MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet);
+     uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset;
+ 
+     va_list args;
+     va_start(args, errorNumber);
+ 
+     bool result = parser->errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);
+ 
+     va_end(args);
+     return result;
+ }
+ 
+ bool
++BytecodeEmitter::reportExtraWarning(const Maybe<uint32_t>& maybeOffset,
++                                    unsigned errorNumber, ...)
++{
++    MOZ_ASSERT_IF(!maybeOffset, this->scriptStartOffsetSet);
++    uint32_t offset = maybeOffset ? *maybeOffset : this->scriptStartOffset;
++
++    va_list args;
++    va_start(args, errorNumber);
++
++    bool result = parser->errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);
++
++    va_end(args);
++    return result;
++}
++
++bool
+ BytecodeEmitter::emitNewInit(JSProtoKey key)
+ {
+     const size_t len = 1 + UINT32_INDEX_LEN;
+     ptrdiff_t offset;
+     if (!emitCheck(len, &offset))
+         return false;
+ 
+     jsbytecode* code = this->code(offset);
+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
+@@ -416,17 +416,21 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     void setScriptStartOffsetIfUnset(TokenPos pos) {
+         if (!scriptStartOffsetSet) {
+             scriptStartOffset = pos.begin;
+             scriptStartOffsetSet = true;
+         }
+     }
+ 
+     void reportError(ParseNode* pn, unsigned errorNumber, ...);
++    void reportError(const mozilla::Maybe<uint32_t>& maybeOffset,
++                     unsigned errorNumber, ...);
+     bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
++    bool reportExtraWarning(const mozilla::Maybe<uint32_t>& maybeOffset,
++                            unsigned errorNumber, ...);
+ 
+     // If pn contains a useful expression, return true with *answer set to true.
+     // If pn contains a useless expression, return true with *answer set to
+     // false. Return false on error.
+     //
+     // The caller should initialize *answer to false and invoke this function on
+     // an expression statement or similar subtree to decide whether the tree
+     // could produce code that has any side effects.  For an expression

+ 1449 - 0
frg/work-js/mozilla-release/patches/1456006-2-63a1.patch

@@ -0,0 +1,1449 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532070836 -32400
+# Node ID d2cfbb2fcc82ea270d177a3200c6d69b97bc0053
+# Parent  dbba1e4333bdbcf6aca7b6b6f8091fcb07a418fb
+Bug 1456006 - Part 1: Add SwitchEmitter. 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
+@@ -24,16 +24,17 @@
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/EmitterScope.h"
+ #include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
++#include "frontend/SwitchEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "frontend/TryEmitter.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+@@ -2322,354 +2323,142 @@ 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* cases = pn->pn_right;
+-    MOZ_ASSERT(cases->isKind(ParseNodeKind::LexicalScope) ||
+-               cases->isKind(ParseNodeKind::StatementList));
+-
+-    // Ensure that the column of the switch statement is set properly.
+-    if (!updateSourceCoordNotes(pn->pn_pos.begin))
+-        return false;
+-
+-    // Emit code for the discriminant.
++    ParseNode* lexical = pn->pn_right;
++    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))
+         return false;
+ 
+     // Enter the scope before pushing the switch BreakableControl since all
+     // breaks are under this scope.
+-    Maybe<TDZCheckCache> tdzCache;
+-    Maybe<EmitterScope> emitterScope;
+-    if (cases->isKind(ParseNodeKind::LexicalScope)) {
+-        if (!cases->isEmptyScope()) {
+-            tdzCache.emplace(this);
+-            emitterScope.emplace(this);
+-            if (!emitterScope->enterLexical(this, ScopeKind::Lexical, cases->scopeBindings()))
+-                return false;
+-        }
+-
+-        // Advance |cases| to refer to the switch case list.
+-        cases = cases->scopeBody();
++    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) {
+-            MOZ_ASSERT(emitterScope);
+             for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
+                 if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) {
+                     if (!emitHoistedFunctionsInList(caseNode->pn_right))
+                         return false;
+                 }
+             }
+         }
+-    }
+-
+-    // After entering the scope, push the switch control.
+-    BreakableControl controlInfo(this, StatementKind::Switch);
+-
+-    ptrdiff_t top = offset();
+-
+-    // Switch bytecodes run from here till end of final case.
++    } else {
++        MOZ_ASSERT(!(cases->pn_xflags & PNX_FUNCDEFS));
++    }
++
++    SwitchEmitter::TableGenerator tableGen(this);
+     uint32_t caseCount = cases->pn_count;
+-    if (caseCount > JS_BIT(16)) {
+-        reportError(pn, JSMSG_TOO_MANY_CASES);
+-        return false;
+-    }
+-
+-    // Try for most optimal, fall back if not dense ints.
+-    JSOp switchOp = JSOP_TABLESWITCH;
+-    uint32_t tableLength = 0;
+-    int32_t low, high;
+-    bool hasDefault = false;
+     CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
+-    if (caseCount == 0 ||
+-        (caseCount == 1 && (hasDefault = firstCase->isDefault())))
+-    {
+-        low = 0;
+-        high = -1;
++    if (caseCount == 0) {
++        tableGen.finish(0);
++    } else if (caseCount == 1 && firstCase->isDefault()) {
++        caseCount = 0;
++        tableGen.finish(0);
+     } else {
+-        Vector<size_t, 128, SystemAllocPolicy> intmap;
+-        int32_t intmapBitLength = 0;
+-
+-        low  = JSVAL_INT_MAX;
+-        high = JSVAL_INT_MIN;
+-
+         for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
+             if (caseNode->isDefault()) {
+-                hasDefault = true;
+                 caseCount--;  // one of the "cases" was the default
+                 continue;
+             }
+ 
+-            if (switchOp == JSOP_CONDSWITCH)
++            if (tableGen.isInvalid())
+                 continue;
+ 
+-            MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
+-
+             ParseNode* caseValue = caseNode->caseExpression();
+ 
+             if (caseValue->getKind() != ParseNodeKind::Number) {
+-                switchOp = JSOP_CONDSWITCH;
++                tableGen.setInvalid();
+                 continue;
+             }
+ 
+             int32_t i;
+             if (!NumberEqualsInt32(caseValue->pn_dval, &i)) {
+-                switchOp = JSOP_CONDSWITCH;
+-                continue;
+-            }
+-
+-            if (unsigned(i + int(JS_BIT(15))) >= unsigned(JS_BIT(16))) {
+-                switchOp = JSOP_CONDSWITCH;
+-                continue;
+-            }
+-            if (i < low)
+-                low = i;
+-            if (i > high)
+-                high = i;
+-
+-            // Check for duplicates, which require a JSOP_CONDSWITCH.
+-            // We bias i by 65536 if it's negative, and hope that's a rare
+-            // case (because it requires a malloc'd bitmap).
+-            if (i < 0)
+-                i += JS_BIT(16);
+-            if (i >= intmapBitLength) {
+-                size_t newLength = NumWordsForBitArrayOfLength(i + 1);
+-                if (!intmap.resize(newLength)) {
+-                    ReportOutOfMemory(cx);
+-                    return false;
+-                }
+-                intmapBitLength = newLength * BitArrayElementBits;
+-            }
+-            if (IsBitArrayElementSet(intmap.begin(), intmap.length(), i)) {
+-                switchOp = JSOP_CONDSWITCH;
++                tableGen.setInvalid();
+                 continue;
+             }
+-            SetBitArrayElement(intmap.begin(), intmap.length(), i);
+-        }
+-
+-        // Compute table length and select condswitch instead if overlarge or
+-        // more than half-sparse.
+-        if (switchOp == JSOP_TABLESWITCH) {
+-            tableLength = uint32_t(high - low + 1);
+-            if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
+-                switchOp = JSOP_CONDSWITCH;
+-        }
+-    }
+-
+-    // The note has one or two offsets: first tells total switch code length;
+-    // second (if condswitch) tells offset to first JSOP_CASE.
+-    unsigned noteIndex;
+-    size_t switchSize;
+-    if (switchOp == JSOP_CONDSWITCH) {
+-        // 0 bytes of immediate for unoptimized switch.
+-        switchSize = 0;
+-        if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, &noteIndex))
++
++            if (!tableGen.addNumber(i))
++                return false;
++        }
++
++        tableGen.finish(caseCount);
++    }
++
++    if (!se.validateCaseCount(caseCount))
++        return false;
++
++    bool isTableSwitch = tableGen.isValid();
++    if (isTableSwitch) {
++        if (!se.emitTable(tableGen))
+             return false;
+     } else {
+-        MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
+-
+-        // 3 offsets (len, low, high) before the table, 1 per entry.
+-        switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableLength));
+-        if (!newSrcNote2(SRC_TABLESWITCH, 0, &noteIndex))
+-            return false;
+-    }
+-
+-    // Emit switchOp followed by switchSize bytes of jump or lookup table.
+-    MOZ_ASSERT(top == offset());
+-    if (!emitN(switchOp, switchSize))
+-        return false;
+-
+-    Vector<CaseClause*, 32, SystemAllocPolicy> table;
+-
+-    JumpList condSwitchDefaultOff;
+-    if (switchOp == JSOP_CONDSWITCH) {
+-        unsigned caseNoteIndex;
+-        bool beforeCases = true;
+-        ptrdiff_t lastCaseOffset = -1;
+-
+-        // The case conditions need their own TDZ cache since they might not
+-        // all execute.
+-        TDZCheckCache tdzCache(this);
++        if (!se.emitCond())
++            return false;
+ 
+         // Emit code for evaluating cases and jumping to case statements.
+         for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
++            if (caseNode->isDefault())
++                continue;
++
+             ParseNode* caseValue = caseNode->caseExpression();
+-
+             // If the expression is a literal, suppress line number emission so
+             // that debugging works more naturally.
+-            if (caseValue) {
+-                if (!emitTree(caseValue, ValueUsage::WantValue,
+-                              caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
+-                {
+-                    return false;
+-                }
+-            }
+-
+-            if (!beforeCases) {
+-                // prevCase is the previous JSOP_CASE's bytecode offset.
+-                if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
+-                    return false;
+-            }
+-            if (!caseValue) {
+-                // This is the default clause.
+-                continue;
+-            }
+-
+-            if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex))
+-                return false;
+-
+-            // The case clauses are produced before any of the case body. The
+-            // JumpList is saved on the parsed tree, then later restored and
+-            // patched when generating the cases body.
+-            JumpList caseJump;
+-            if (!emitJump(JSOP_CASE, &caseJump))
+-                return false;
+-            caseNode->setOffset(caseJump.offset);
+-            lastCaseOffset = caseJump.offset;
+-
+-            if (beforeCases) {
+-                // Switch note's second offset is to first JSOP_CASE.
+-                unsigned noteCount = notes().length();
+-                if (!setSrcNoteOffset(noteIndex, 1, lastCaseOffset - top))
+-                    return false;
+-                unsigned noteCountDelta = notes().length() - noteCount;
+-                if (noteCountDelta != 0)
+-                    caseNoteIndex += noteCountDelta;
+-                beforeCases = false;
+-            }
+-        }
+-
+-        // If we didn't have an explicit default (which could fall in between
+-        // cases, preventing us from fusing this setSrcNoteOffset with the call
+-        // in the loop above), link the last case to the implicit default for
+-        // the benefit of IonBuilder.
+-        if (!hasDefault &&
+-            !beforeCases &&
+-            !setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
+-        {
+-            return false;
+-        }
+-
+-        // Emit default even if no explicit default statement.
+-        if (!emitJump(JSOP_DEFAULT, &condSwitchDefaultOff))
+-            return false;
+-    } else {
+-        MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
+-
+-        // skip default offset.
+-        jsbytecode* pc = code(top + JUMP_OFFSET_LEN);
+-
+-        // Fill in switch bounds, which we know fit in 16-bit offsets.
+-        SET_JUMP_OFFSET(pc, low);
+-        pc += JUMP_OFFSET_LEN;
+-        SET_JUMP_OFFSET(pc, high);
+-        pc += JUMP_OFFSET_LEN;
+-
+-        if (tableLength != 0) {
+-            if (!table.growBy(tableLength)) {
+-                ReportOutOfMemory(cx);
++            if (!emitTree(caseValue, ValueUsage::WantValue,
++                          caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
++            {
+                 return false;
+             }
+ 
+-            for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
+-                if (ParseNode* caseValue = caseNode->caseExpression()) {
+-                    MOZ_ASSERT(caseValue->isKind(ParseNodeKind::Number));
+-
+-                    int32_t i = int32_t(caseValue->pn_dval);
+-                    MOZ_ASSERT(double(i) == caseValue->pn_dval);
+-
+-                    i -= low;
+-                    MOZ_ASSERT(uint32_t(i) < tableLength);
+-                    MOZ_ASSERT(!table[i]);
+-                    table[i] = caseNode;
+-                }
+-            }
+-        }
+-    }
+-
+-    JumpTarget defaultOffset{ -1 };
++            if (!se.emitCaseJump())
++                return false;
++        }
++    }
+ 
+     // Emit code for each case's statements.
+     for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
+-        if (switchOp == JSOP_CONDSWITCH && !caseNode->isDefault()) {
+-            // The case offset got saved in the caseNode structure after
+-            // emitting the JSOP_CASE jump instruction above.
+-            JumpList caseCond;
+-            caseCond.offset = caseNode->offset();
+-            if (!emitJumpTargetAndPatch(caseCond))
+-                return false;
+-        }
+-
+-        JumpTarget here;
+-        if (!emitJumpTarget(&here))
+-            return false;
+-        if (caseNode->isDefault())
+-            defaultOffset = here;
+-
+-        // If this is emitted as a TABLESWITCH, we'll need to know this case's
+-        // offset later when emitting the table. Store it in the node's
+-        // pn_offset (giving the field a different meaning vs. how we used it
+-        // on the immediately preceding line of code).
+-        caseNode->setOffset(here.offset);
+-
+-        TDZCheckCache tdzCache(this);
++        if (caseNode->isDefault()) {
++            if (!se.emitDefaultBody())
++                return false;
++        } else {
++            if (isTableSwitch) {
++                ParseNode* caseValue = caseNode->caseExpression();
++                MOZ_ASSERT(caseValue->isKind(ParseNodeKind::Number));
++
++                int32_t i = int32_t(caseValue->pn_dval);
++                MOZ_ASSERT(double(i) == caseValue->pn_dval);
++
++                if (!se.emitCaseBody(i, tableGen))
++                    return false;
++            } else {
++                if (!se.emitCaseBody())
++                    return false;
++            }
++        }
+ 
+         if (!emitTree(caseNode->statementList()))
+             return false;
+     }
+ 
+-    if (!hasDefault) {
+-        // If no default case, offset for default is to end of switch.
+-        if (!emitJumpTarget(&defaultOffset))
+-            return false;
+-    }
+-    MOZ_ASSERT(defaultOffset.offset != -1);
+-
+-    // Set the default offset (to end of switch if no default).
+-    jsbytecode* pc;
+-    if (switchOp == JSOP_CONDSWITCH) {
+-        pc = nullptr;
+-        patchJumpsToTarget(condSwitchDefaultOff, defaultOffset);
+-    } else {
+-        MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
+-        pc = code(top);
+-        SET_JUMP_OFFSET(pc, defaultOffset.offset - top);
+-        pc += JUMP_OFFSET_LEN;
+-    }
+-
+-    // Set the SRC_SWITCH note's offset operand to tell end of switch.
+-    if (!setSrcNoteOffset(noteIndex, 0, lastNonJumpTargetOffset() - top))
+-        return false;
+-
+-    if (switchOp == JSOP_TABLESWITCH) {
+-        // Skip over the already-initialized switch bounds.
+-        pc += 2 * JUMP_OFFSET_LEN;
+-
+-        // Fill in the jump table, if there is one.
+-        for (uint32_t i = 0; i < tableLength; i++) {
+-            CaseClause* caseNode = table[i];
+-            ptrdiff_t off = caseNode ? caseNode->offset() - top : 0;
+-            SET_JUMP_OFFSET(pc, off);
+-            pc += JUMP_OFFSET_LEN;
+-        }
+-    }
+-
+-    // Patch breaks before leaving the scope, as all breaks are under the
+-    // lexical scope if it exists.
+-    if (!controlInfo.patchBreaks(this))
+-        return false;
+-
+-    if (emitterScope && !emitterScope->leave(this))
++    if (!se.emitEnd())
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::isRunOnceLambda()
+ {
+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
+@@ -252,26 +252,23 @@ IsTypeofKind(ParseNodeKind kind)
+  *                          pn_count: 1 + number of formal parameters
+  *                          pn_tree: ParamsBody or StatementList node
+  * Spread   unary       pn_kid: expression being spread
+  *
+  * <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: list of Case nodes, with at most one
+- *                            default node, or if there are let bindings
+- *                            in the top level of the switch body's cases, a
+- *                            LexicalScope node that contains the list of
+- *                            Case nodes.
++ *                      pn_right: LexicalScope node that contains the list
++ *                        of Case nodes, with at most one
++ *                        default node.
+  * Case     binary      pn_left: case-expression if CaseClause, or
+  *                            null if DefaultClause
+  *                          pn_right: StatementList node for this case's
+  *                            statements
+- *                          pn_u.binary.offset: scratch space for the emitter
+  * 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(;;))
+  *                          pn_right: body
+  * ForIn    ternary     pn_kid1: declaration or expression to left of 'in'
+  *                          pn_kid2: null
+  *                          pn_kid3: object expr to right of 'in'
+@@ -557,17 +554,16 @@ 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 */
+-                uint32_t offset;        /* for the emitter's use on ParseNodeKind::Case nodes */
+             };
+         } binary;
+         struct {                        /* one kid if unary */
+             ParseNode*  kid;
+             bool        prologue;       /* directive prologue member (as
+                                            pn_prologue) */
+         } unary;
+         struct {                        /* name, labeled statement, etc. */
+@@ -1020,20 +1016,16 @@ class CaseClause : public BinaryNode
+ 
+     ParseNode* caseExpression() const { return pn_left; }
+     bool isDefault() const { return !caseExpression(); }
+     ParseNode* statementList() const { return pn_right; }
+ 
+     // The next CaseClause in the same switch statement.
+     CaseClause* next() const { return pn_next ? &pn_next->as<CaseClause>() : nullptr; }
+ 
+-    // Scratch space used by the emitter.
+-    uint32_t offset() const { return pn_u.binary.offset; }
+-    void setOffset(uint32_t u) { pn_u.binary.offset = u; }
+-
+     static bool test(const ParseNode& node) {
+         bool match = node.isKind(ParseNodeKind::Case);
+         MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
+         MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
+         return match;
+     }
+ };
+ 
+diff --git a/js/src/frontend/SwitchEmitter.cpp b/js/src/frontend/SwitchEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/SwitchEmitter.cpp
+@@ -0,0 +1,425 @@
++/* -*- 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 "frontend/SwitchEmitter.h"
++
++#include "jsutil.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/SharedContext.h"
++#include "frontend/SourceNotes.h"
++#include "vm/BytecodeUtil.h"
++#include "vm/Opcodes.h"
++#include "vm/Runtime.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++
++bool
++SwitchEmitter::TableGenerator::addNumber(int32_t caseValue)
++{
++    if (isInvalid())
++        return true;
++
++    if (unsigned(caseValue + int(JS_BIT(15))) >= unsigned(JS_BIT(16))) {
++        setInvalid();
++        return true;
++    }
++
++    if (intmap_.isNothing())
++        intmap_.emplace();
++
++    low_ = std::min(low_, caseValue);
++    high_ = std::max(high_, caseValue);
++
++    // Check for duplicates, which require a JSOP_CONDSWITCH.
++    // We bias caseValue by 65536 if it's negative, and hope that's a rare case
++    // (because it requires a malloc'd bitmap).
++    if (caseValue < 0)
++        caseValue += JS_BIT(16);
++    if (caseValue >= intmapBitLength_) {
++        size_t newLength = NumWordsForBitArrayOfLength(caseValue + 1);
++        if (!intmap_->resize(newLength)) {
++            ReportOutOfMemory(bce_->cx);
++            return false;
++        }
++        intmapBitLength_ = newLength * BitArrayElementBits;
++    }
++    if (IsBitArrayElementSet(intmap_->begin(), intmap_->length(), caseValue)) {
++        // Duplicate entry is not supported in table switch.
++        setInvalid();
++        return true;
++    }
++    SetBitArrayElement(intmap_->begin(), intmap_->length(), caseValue);
++    return true;
++}
++
++void
++SwitchEmitter::TableGenerator::finish(uint32_t caseCount)
++{
++    intmap_.reset();
++
++#ifdef DEBUG
++    finished_ = true;
++#endif
++
++    if (isInvalid())
++        return;
++
++    if (caseCount == 0) {
++        low_ = 0;
++        high_ = -1;
++        return;
++    }
++
++    // Compute table length and select condswitch instead if overlarge
++    // or more than half-sparse.
++    tableLength_ = uint32_t(high_ - low_ + 1);
++    if (tableLength_ >= JS_BIT(16) || tableLength_ > 2 * caseCount)
++        setInvalid();
++}
++
++uint32_t
++SwitchEmitter::TableGenerator::toCaseIndex(int32_t caseValue) const
++{
++    MOZ_ASSERT(finished_);
++    MOZ_ASSERT(isValid());
++    uint32_t caseIndex = uint32_t(caseValue - low_);
++    MOZ_ASSERT(caseIndex < tableLength_);
++    return caseIndex;
++}
++
++uint32_t
++SwitchEmitter::TableGenerator::tableLength() const
++{
++    MOZ_ASSERT(finished_);
++    MOZ_ASSERT(isValid());
++    return tableLength_;
++}
++
++SwitchEmitter::SwitchEmitter(BytecodeEmitter* bce)
++  : bce_(bce)
++{}
++
++bool
++SwitchEmitter::emitDiscriminant(const Maybe<uint32_t>& switchPos)
++{
++    MOZ_ASSERT(state_ == State::Start);
++    switchPos_ = switchPos;
++
++    if (switchPos_) {
++        // Ensure that the column of the switch statement is set properly.
++        if (!bce_->updateSourceCoordNotes(*switchPos_))
++            return false;
++    }
++
++    state_ = State::Discriminant;
++    return true;
++}
++
++bool
++SwitchEmitter::emitLexical(Handle<LexicalScope::Data*> bindings)
++{
++    MOZ_ASSERT(state_ == State::Discriminant);
++    MOZ_ASSERT(bindings);
++
++    tdzCacheLexical_.emplace(bce_);
++    emitterScope_.emplace(bce_);
++    if (!emitterScope_->enterLexical(bce_, ScopeKind::Lexical, bindings))
++        return false;
++
++    state_ = State::Lexical;
++    return true;
++}
++
++bool
++SwitchEmitter::validateCaseCount(uint32_t caseCount)
++{
++    MOZ_ASSERT(state_ == State::Discriminant || state_ == State::Lexical);
++    if (caseCount > JS_BIT(16)) {
++        bce_->reportError(switchPos_, JSMSG_TOO_MANY_CASES);
++        return false;
++    }
++    caseCount_ = caseCount;
++
++    state_ = State::CaseCount;
++    return true;
++}
++
++bool
++SwitchEmitter::emitCond()
++{
++    MOZ_ASSERT(state_ == State::CaseCount);
++
++    kind_ = Kind::Cond;
++
++    // After entering the scope if necessary, push the switch control.
++    controlInfo_.emplace(bce_, StatementKind::Switch);
++    top_ = bce_->offset();
++
++    if (!caseOffsets_.resize(caseCount_)) {
++        ReportOutOfMemory(bce_->cx);
++        return false;
++    }
++
++    // The note has two offsets: first tells total switch code length;
++    // second tells offset to first JSOP_CASE.
++    if (!bce_->newSrcNote3(SRC_CONDSWITCH, 0, 0, &noteIndex_))
++        return false;
++
++    MOZ_ASSERT(top_ == bce_->offset());
++    if (!bce_->emitN(JSOP_CONDSWITCH, 0))
++        return false;
++
++    tdzCacheCaseAndBody_.emplace(bce_);
++
++    state_ = State::Cond;
++    return true;
++}
++
++bool
++SwitchEmitter::emitTable(const TableGenerator& tableGen)
++{
++    MOZ_ASSERT(state_ == State::CaseCount);
++    kind_ = Kind::Table;
++
++    // After entering the scope if necessary, push the switch control.
++    controlInfo_.emplace(bce_, StatementKind::Switch);
++    top_ = bce_->offset();
++
++    // The note has one offset that tells total switch code length.
++
++    // 3 offsets (len, low, high) before the table, 1 per entry.
++    size_t switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableGen.tableLength()));
++    if (!bce_->newSrcNote2(SRC_TABLESWITCH, 0, &noteIndex_))
++        return false;
++
++    if (!caseOffsets_.resize(tableGen.tableLength())) {
++        ReportOutOfMemory(bce_->cx);
++        return false;
++    }
++
++    MOZ_ASSERT(top_ == bce_->offset());
++    if (!bce_->emitN(JSOP_TABLESWITCH, switchSize))
++        return false;
++
++    // Skip default offset.
++    jsbytecode* pc = bce_->code(top_ + JUMP_OFFSET_LEN);
++
++    // Fill in switch bounds, which we know fit in 16-bit offsets.
++    SET_JUMP_OFFSET(pc, tableGen.low());
++    SET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN, tableGen.high());
++
++    state_ = State::Table;
++    return true;
++}
++
++bool
++SwitchEmitter::emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault)
++{
++    MOZ_ASSERT(kind_ == Kind::Cond);
++
++    if (state_ == State::Case) {
++        // Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE or
++        // JSOP_DEFAULT for the benefit of IonBuilder.
++        if (!bce_->setSrcNoteOffset(caseNoteIndex_, 0, bce_->offset() - lastCaseOffset_))
++            return false;
++    }
++
++    if (isDefault) {
++        if (!bce_->emitJump(JSOP_DEFAULT, &condSwitchDefaultOffset_))
++            return false;
++        return true;
++    }
++
++    if (!bce_->newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex_))
++        return false;
++
++    JumpList caseJump;
++    if (!bce_->emitJump(JSOP_CASE, &caseJump))
++        return false;
++    caseOffsets_[caseIndex] = caseJump.offset;
++    lastCaseOffset_ = caseJump.offset;
++
++    if (state_ == State::Cond) {
++        // Switch note's second offset is to first JSOP_CASE.
++        unsigned noteCount = bce_->notes().length();
++        if (!bce_->setSrcNoteOffset(noteIndex_, 1, lastCaseOffset_ - top_))
++            return false;
++        unsigned noteCountDelta = bce_->notes().length() - noteCount;
++        if (noteCountDelta != 0)
++            caseNoteIndex_ += noteCountDelta;
++    }
++
++    return true;
++}
++
++bool
++SwitchEmitter::emitCaseJump()
++{
++    MOZ_ASSERT(kind_ == Kind::Cond);
++    MOZ_ASSERT(state_ == State::Cond || state_ == State::Case);
++    if (!emitCaseOrDefaultJump(caseIndex_, false))
++        return false;
++    caseIndex_++;
++
++    state_ = State::Case;
++    return true;
++}
++
++bool
++SwitchEmitter::emitImplicitDefault()
++{
++    MOZ_ASSERT(kind_ == Kind::Cond);
++    MOZ_ASSERT(state_ == State::Cond || state_ == State::Case);
++    if (!emitCaseOrDefaultJump(0, true))
++        return false;
++
++    caseIndex_ = 0;
++
++    // No internal state after emitting default jump.
++    return true;
++}
++
++bool
++SwitchEmitter::emitCaseBody()
++{
++    MOZ_ASSERT(kind_ == Kind::Cond);
++    MOZ_ASSERT(state_ == State::Cond || state_ == State::Case ||
++               state_ == State::CaseBody || state_ == State::DefaultBody);
++
++    tdzCacheCaseAndBody_.reset();
++
++    if (state_ == State::Cond || state_ == State::Case) {
++        // For cond switch, JSOP_DEFAULT is always emitted.
++        if (!emitImplicitDefault())
++            return false;
++    }
++
++    JumpList caseJump;
++    caseJump.offset = caseOffsets_[caseIndex_];
++    if (!bce_->emitJumpTargetAndPatch(caseJump))
++        return false;
++
++    JumpTarget here;
++    if (!bce_->emitJumpTarget(&here))
++        return false;
++    caseIndex_++;
++
++    tdzCacheCaseAndBody_.emplace(bce_);
++
++    state_ = State::CaseBody;
++    return true;
++}
++
++bool
++SwitchEmitter::emitCaseBody(int32_t caseValue, const TableGenerator& tableGen)
++{
++    MOZ_ASSERT(kind_ == Kind::Table);
++    MOZ_ASSERT(state_ == State::Table ||
++               state_ == State::CaseBody || state_ == State::DefaultBody);
++
++    tdzCacheCaseAndBody_.reset();
++
++    JumpTarget here;
++    if (!bce_->emitJumpTarget(&here))
++        return false;
++    caseOffsets_[tableGen.toCaseIndex(caseValue)] = here.offset;
++
++    tdzCacheCaseAndBody_.emplace(bce_);
++
++    state_ = State::CaseBody;
++    return true;
++}
++
++bool
++SwitchEmitter::emitDefaultBody()
++{
++    MOZ_ASSERT(state_ == State::Cond || state_ == State::Table ||
++               state_ == State::Case ||
++               state_ == State::CaseBody);
++    MOZ_ASSERT(!hasDefault_);
++
++    tdzCacheCaseAndBody_.reset();
++
++    if (state_ == State::Cond || state_ == State::Case) {
++        // For cond switch, JSOP_DEFAULT is always emitted.
++        if (!emitImplicitDefault())
++            return false;
++    }
++    JumpTarget here;
++    if (!bce_->emitJumpTarget(&here))
++        return false;
++    defaultJumpTargetOffset_ = here;
++
++    tdzCacheCaseAndBody_.emplace(bce_);
++
++    hasDefault_ = true;
++    state_ = State::DefaultBody;
++    return true;
++}
++
++bool
++SwitchEmitter::emitEnd()
++{
++    MOZ_ASSERT(state_ == State::Cond || state_ == State::Table ||
++               state_ == State::CaseBody || state_ == State::DefaultBody);
++
++    tdzCacheCaseAndBody_.reset();
++
++    if (!hasDefault_) {
++        // If no default case, offset for default is to end of switch.
++        if (!bce_->emitJumpTarget(&defaultJumpTargetOffset_))
++            return false;
++    }
++    MOZ_ASSERT(defaultJumpTargetOffset_.offset != -1);
++
++    // Set the default offset (to end of switch if no default).
++    jsbytecode* pc;
++    if (kind_ == Kind::Cond) {
++        pc = nullptr;
++        bce_->patchJumpsToTarget(condSwitchDefaultOffset_, defaultJumpTargetOffset_);
++    } else {
++        // Fill in the default jump target.
++        pc = bce_->code(top_);
++        SET_JUMP_OFFSET(pc, defaultJumpTargetOffset_.offset - top_);
++        pc += JUMP_OFFSET_LEN;
++    }
++
++    // Set the SRC_SWITCH note's offset operand to tell end of switch.
++    if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->lastNonJumpTargetOffset() - top_))
++        return false;
++
++    if (kind_ == Kind::Table) {
++        // Skip over the already-initialized switch bounds.
++        pc += 2 * JUMP_OFFSET_LEN;
++
++        // Fill in the jump table, if there is one.
++        for (uint32_t i = 0, length = caseOffsets_.length(); i < length; i++) {
++            ptrdiff_t off = caseOffsets_[i];
++            SET_JUMP_OFFSET(pc, off == 0 ? 0 : off - top_);
++            pc += JUMP_OFFSET_LEN;
++        }
++    }
++
++    // Patch breaks before leaving the scope, as all breaks are under the
++    // lexical scope if it exists.
++    if (!controlInfo_->patchBreaks(bce_))
++        return false;
++
++    if (emitterScope_ && !emitterScope_->leave(bce_))
++        return false;
++
++    emitterScope_.reset();
++    tdzCacheLexical_.reset();
++
++    controlInfo_.reset();
++
++    state_ = State::End;
++    return true;
++}
+diff --git a/js/src/frontend/SwitchEmitter.h b/js/src/frontend/SwitchEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/SwitchEmitter.h
+@@ -0,0 +1,469 @@
++/* -*- 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_SwitchEmitter_h
++#define frontend_SwitchEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stddef.h>
++#include <stdint.h>
++
++#include "frontend/BytecodeControlStructures.h"
++#include "frontend/EmitterScope.h"
++#include "frontend/JumpList.h"
++#include "frontend/TDZCheckCache.h"
++#include "gc/Rooting.h"
++#include "js/AllocPolicy.h"
++#include "js/Value.h"
++#include "js/Vector.h"
++#include "vm/Scope.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++
++// Class for emitting bytecode for switch-case-default block.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `switch (discriminant) { case c1_expr: c1_body; }`
++//     SwitchEmitter se(this);
++//     se.emitDiscriminant(Some(offset_of_switch));
++//     emit(discriminant);
++//
++//     se.validateCaseCount(1);
++//     se.emitCond();
++//
++//     emit(c1_expr);
++//     se.emitCaseJump();
++//
++//     se.emitCaseBody();
++//     emit(c1_body);
++//
++//     se.emitEnd();
++//
++//   `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body;
++//                            default: def_body; }`
++//     SwitchEmitter se(this);
++//     se.emitDiscriminant(Some(offset_of_switch));
++//     emit(discriminant);
++//
++//     se.validateCaseCount(2);
++//     se.emitCond();
++//
++//     emit(c1_expr);
++//     se.emitCaseJump();
++//
++//     emit(c2_expr);
++//     se.emitCaseJump();
++//
++//     se.emitCaseBody();
++//     emit(c1_body);
++//
++//     se.emitCaseBody();
++//     emit(c2_body);
++//
++//     se.emitDefaultBody();
++//     emit(def_body);
++//
++//     se.emitEnd();
++//
++//   `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body; }`
++//   with Table Switch
++//     SwitchEmitter::TableGenerator tableGen(this);
++//     tableGen.addNumber(c1_expr_value);
++//     tableGen.addNumber(c2_expr_value);
++//     tableGen.finish(2);
++//
++//     // If `!tableGen.isValid()` here, `emitCond` should be used instead.
++//
++//     SwitchEmitter se(this);
++//     se.emitDiscriminant(Some(offset_of_switch));
++//     emit(discriminant);
++//     se.validateCaseCount(2);
++//     se.emitTable(tableGen);
++//
++//     se.emitCaseBody(c1_expr_value, tableGen);
++//     emit(c1_body);
++//
++//     se.emitCaseBody(c2_expr_value, tableGen);
++//     emit(c2_body);
++//
++//     se.emitEnd();
++//
++//   `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body;
++//                            default: def_body; }`
++//   with Table Switch
++//     SwitchEmitter::TableGenerator tableGen(bce);
++//     tableGen.addNumber(c1_expr_value);
++//     tableGen.addNumber(c2_expr_value);
++//     tableGen.finish(2);
++//
++//     // If `!tableGen.isValid()` here, `emitCond` should be used instead.
++//
++//     SwitchEmitter se(this);
++//     se.emitDiscriminant(Some(offset_of_switch));
++//     emit(discriminant);
++//     se.validateCaseCount(2);
++//     se.emitTable(tableGen);
++//
++//     se.emitCaseBody(c1_expr_value, tableGen);
++//     emit(c1_body);
++//
++//     se.emitCaseBody(c2_expr_value, tableGen);
++//     emit(c2_body);
++//
++//     se.emitDefaultBody();
++//     emit(def_body);
++//
++//     se.emitEnd();
++//
++//   `switch (discriminant) { case c1_expr: c1_body; }`
++//   in case c1_body contains lexical bindings
++//     SwitchEmitter se(this);
++//     se.emitDiscriminant(Some(offset_of_switch));
++//     emit(discriminant);
++//
++//     se.validateCaseCount(1);
++//
++//     se.emitLexical(bindings);
++//
++//     se.emitCond();
++//
++//     emit(c1_expr);
++//     se.emitCaseJump();
++//
++//     se.emitCaseBody();
++//     emit(c1_body);
++//
++//     se.emitEnd();
++//
++//   `switch (discriminant) { case c1_expr: c1_body; }`
++//   in case c1_body contains hosted functions
++//     SwitchEmitter se(this);
++//     se.emitDiscriminant(Some(offset_of_switch));
++//     emit(discriminant);
++//
++//     se.validateCaseCount(1);
++//
++//     se.emitLexical(bindings);
++//     emit(hosted functions);
++//
++//     se.emitCond();
++//
++//     emit(c1_expr);
++//     se.emitCaseJump();
++//
++//     se.emitCaseBody();
++//     emit(c1_body);
++//
++//     se.emitEnd();
++//
++class MOZ_STACK_CLASS SwitchEmitter
++{
++    // Bytecode for each case.
++    //
++    // Cond Switch
++    //     {discriminant}
++    //     JSOP_CONDSWITCH
++    //
++    //     {c1_expr}
++    //     JSOP_CASE c1
++    //
++    //     JSOP_JUMPTARGET
++    //     {c2_expr}
++    //     JSOP_CASE c2
++    //
++    //     ...
++    //
++    //     JSOP_JUMPTARGET
++    //     JSOP_DEFAULT default
++    //
++    //   c1:
++    //     JSOP_JUMPTARGET
++    //     {c1_body}
++    //     JSOP_GOTO end
++    //
++    //   c2:
++    //     JSOP_JUMPTARGET
++    //     {c2_body}
++    //     JSOP_GOTO end
++    //
++    //   default:
++    //   end:
++    //     JSOP_JUMPTARGET
++    //
++    // Table Switch
++    //     {discriminant}
++    //     JSOP_TABLESWITCH c1, c2, ...
++    //
++    //   c1:
++    //     JSOP_JUMPTARGET
++    //     {c1_body}
++    //     JSOP_GOTO end
++    //
++    //   c2:
++    //     JSOP_JUMPTARGET
++    //     {c2_body}
++    //     JSOP_GOTO end
++    //
++    //   ...
++    //
++    //   end:
++    //     JSOP_JUMPTARGET
++
++  public:
++    enum class Kind {
++        Table,
++        Cond
++    };
++
++    // Class for generating optimized table switch data.
++    class MOZ_STACK_CLASS TableGenerator
++    {
++        BytecodeEmitter* bce_;
++
++        // Bit array for given numbers.
++        mozilla::Maybe<js::Vector<size_t, 128, SystemAllocPolicy>> intmap_;
++
++        // The length of the intmap_.
++        int32_t intmapBitLength_ = 0;
++
++        // The length of the table.
++        uint32_t tableLength_ = 0;
++
++        // The lower and higher bounds of the table.
++        int32_t low_ = JSVAL_INT_MAX, high_ = JSVAL_INT_MIN;
++
++        // Whether the table is still valid.
++        bool valid_= true;
++
++#ifdef DEBUG
++        bool finished_ = false;
++#endif
++
++      public:
++        explicit TableGenerator(BytecodeEmitter* bce)
++          : bce_(bce)
++        {}
++
++        void setInvalid() {
++            valid_ = false;
++        }
++        MOZ_MUST_USE bool isValid() const {
++            return valid_;
++        }
++        MOZ_MUST_USE bool isInvalid() const {
++            return !valid_;
++        }
++
++        // Add the given number to the table.  The number is the value of
++        // `expr` for `case expr:` syntax.
++        MOZ_MUST_USE bool addNumber(int32_t caseValue);
++
++        // Finish generating the table.
++        // `caseCount` should be the number of cases in the switch statement,
++        // excluding the default case.
++        void finish(uint32_t caseCount);
++
++      private:
++        friend SwitchEmitter;
++
++        // The following methods can be used only after calling `finish`.
++
++        // Returns the lower bound of the added numbers.
++        int32_t low() const {
++            MOZ_ASSERT(finished_);
++            return low_;
++        }
++
++        // Returns the higher bound of the numbers.
++        int32_t high() const {
++            MOZ_ASSERT(finished_);
++            return high_;
++        }
++
++        // Returns the index in SwitchEmitter.caseOffsets_ for table switch.
++        uint32_t toCaseIndex(int32_t caseValue) const;
++
++        // Returns the length of the table.
++        // This method can be called only if `isValid()` is true.
++        uint32_t tableLength() const;
++    };
++
++  private:
++    BytecodeEmitter* bce_;
++
++    // `kind_` should be set to the correct value in emitCond/emitTable.
++    Kind kind_ = Kind::Cond;
++
++    // True if there's explicit default case.
++    bool hasDefault_ = false;
++
++    // The source note index for SRC_CONDSWITCH.
++    unsigned noteIndex_ = 0;
++
++    // Source note index of the previous SRC_NEXTCASE.
++    unsigned caseNoteIndex_ = 0;
++
++    // The number of cases in the switch statement, excluding the default case.
++    uint32_t caseCount_ = 0;
++
++    // Internal index for case jump and case body, used by cond switch.
++    uint32_t caseIndex_ = 0;
++
++    // Bytecode offset after emitting `discriminant`.
++    ptrdiff_t top_ = 0;
++
++    // Bytecode offset of the previous JSOP_CASE.
++    ptrdiff_t lastCaseOffset_ = 0;
++
++    // Bytecode offset of the JSOP_JUMPTARGET for default body.
++    JumpTarget defaultJumpTargetOffset_ = { -1 };
++
++    // Bytecode offset of the JSOP_DEFAULT.
++    JumpList condSwitchDefaultOffset_;
++
++    // Instantiated when there's lexical scope for entire switch.
++    mozilla::Maybe<TDZCheckCache> tdzCacheLexical_;
++    mozilla::Maybe<EmitterScope> emitterScope_;
++
++    // Instantiated while emitting case expression and case/default body.
++    mozilla::Maybe<TDZCheckCache> tdzCacheCaseAndBody_;
++
++    // Control for switch.
++    mozilla::Maybe<BreakableControl> controlInfo_;
++
++    mozilla::Maybe<uint32_t> switchPos_;
++
++    // Cond Switch:
++    //   Offset of each JSOP_CASE.
++    // Table Switch:
++    //   Offset of each JSOP_JUMPTARGET for case.
++    js::Vector<ptrdiff_t, 32, SystemAllocPolicy> caseOffsets_;
++
++    // The state of this emitter.
++    //
++    // +-------+ emitDiscriminant +--------------+
++    // | Start |----------------->| Discriminant |-+
++    // +-------+                  +--------------+ |
++    //                                             |
++    // +-------------------------------------------+
++    // |
++    // |                              validateCaseCount +-----------+
++    // +->+------------------------>+------------------>| CaseCount |-+
++    //    |                         ^                   +-----------+ |
++    //    | emitLexical +---------+ |                                 |
++    //    +------------>| Lexical |-+                                 |
++    //                  +---------+                                   |
++    //                                                                |
++    // +--------------------------------------------------------------+
++    // |
++    // | emitTable +-------+
++    // +---------->| Table |---------------------------->+-+
++    // |           +-------+                             ^ |
++    // |                                                 | |
++    // | emitCond  +------+                              | |
++    // +---------->| Cond |-+------------------------>+->+ |
++    //             +------+ |                         ^    |
++    //                      |                         |    |
++    //                      |    emitCase +------+    |    |
++    //                      +->+--------->| Case |->+-+    |
++    //                         ^          +------+  |      |
++    //                         |                    |      |
++    //                         +--------------------+      |
++    //                                                     |
++    // +---------------------------------------------------+
++    // |
++    // |                                              emitEnd +-----+
++    // +-+----------------------------------------->+-------->| End |
++    //   |                                          ^         +-----+
++    //   |      emitCaseBody    +----------+        |
++    //   +->+-+---------------->| CaseBody |--->+-+-+
++    //      ^ |                 +----------+    ^ |
++    //      | |                                 | |
++    //      | | emitDefaultBody +-------------+ | |
++    //      | +---------------->| DefaultBody |-+ |
++    //      |                   +-------------+   |
++    //      |                                     |
++    //      +-------------------------------------+
++    //
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitDiscriminant.
++        Discriminant,
++
++        // After calling validateCaseCount.
++        CaseCount,
++
++        // After calling emitLexical.
++        Lexical,
++
++        // After calling emitCond.
++        Cond,
++
++        // After calling emitTable.
++        Table,
++
++        // After calling emitCase.
++        Case,
++
++        // After calling emitCaseBody.
++        CaseBody,
++
++        // After calling emitDefaultBody.
++        DefaultBody,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++
++  public:
++    explicit SwitchEmitter(BytecodeEmitter* bce);
++
++    // `switchPos` is the offset in the source code for the character below:
++    //
++    //   switch ( cond ) { ... }
++    //   ^
++    //   |
++    //   switchPos
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitDiscriminant(const mozilla::Maybe<uint32_t>& switchPos);
++
++    // `caseCount` should be the number of cases in the switch statement,
++    // excluding the default case.
++    MOZ_MUST_USE bool validateCaseCount(uint32_t caseCount);
++
++    // `bindings` is a lexical scope for the entire switch, in case there's
++    // let/const effectively directly under case or default blocks.
++    MOZ_MUST_USE bool emitLexical(Handle<LexicalScope::Data*> bindings);
++
++    MOZ_MUST_USE bool emitCond();
++    MOZ_MUST_USE bool emitTable(const TableGenerator& tableGen);
++
++    MOZ_MUST_USE bool emitCaseJump();
++
++    MOZ_MUST_USE bool emitCaseBody();
++    MOZ_MUST_USE bool emitCaseBody(int32_t caseValue, const TableGenerator& tableGen);
++    MOZ_MUST_USE bool emitDefaultBody();
++    MOZ_MUST_USE bool emitEnd();
++
++  private:
++    MOZ_MUST_USE bool emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault);
++    MOZ_MUST_USE bool emitImplicitDefault();
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_SwitchEmitter_h */
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -212,16 +212,17 @@ UNIFIED_SOURCES += [
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
+     'frontend/ForOfLoopControl.cpp',
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
++    'frontend/SwitchEmitter.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+     'frontend/TryEmitter.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',
+     'gc/GC.cpp',
+     'gc/GCTrace.cpp',

+ 952 - 0
frg/work-js/mozilla-release/patches/1456404-1-63a1.patch

@@ -0,0 +1,952 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854957 -32400
+#      Fri Aug 10 07:49:17 2018 +0900
+# Node ID e20a86a9b5756d9bf2ec3c48b1c7ddbdb95a9eba
+# Parent  60a38b319b323f9b8c44040eedecb49715a129b0
+Bug 1456404 - Part 1: Move loop related bytecode/offset handling to LoopControl. r=jwalden
+
+diff --git a/js/src/frontend/BytecodeControlStructures.cpp b/js/src/frontend/BytecodeControlStructures.cpp
+--- a/js/src/frontend/BytecodeControlStructures.cpp
++++ b/js/src/frontend/BytecodeControlStructures.cpp
+@@ -3,20 +3,23 @@
+  * 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/BytecodeControlStructures.h"
+ 
+ #include "frontend/BytecodeEmitter.h"
+ #include "frontend/EmitterScope.h"
++#include "vm/Opcodes.h"
+ 
+ using namespace js;
+ using namespace js::frontend;
+ 
++using mozilla::Maybe;
++
+ NestableControl::NestableControl(BytecodeEmitter* bce, StatementKind kind)
+   : Nestable<NestableControl>(&bce->innermostNestableControl),
+     kind_(kind),
+     emitterScope_(bce->innermostEmitterScopeNoCheck())
+ {}
+ 
+ BreakableControl::BreakableControl(BytecodeEmitter* bce, StatementKind kind)
+   : NestableControl(bce, kind)
+@@ -33,18 +36,17 @@ BreakableControl::patchBreaks(BytecodeEm
+ LabelControl::LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
+   : BreakableControl(bce, StatementKind::Label),
+     label_(bce->cx, label),
+     startOffset_(startOffset)
+ {}
+ 
+ LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
+   : BreakableControl(bce, loopKind),
+-    tdzCache_(bce),
+-    continueTarget({ -1 })
++    tdzCache_(bce)
+ {
+     MOZ_ASSERT(is<LoopControl>());
+ 
+     LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
+ 
+     stackDepth_ = bce->stackDepth;
+     loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
+ 
+@@ -71,38 +73,102 @@ LoopControl::LoopControl(BytecodeEmitter
+         canIonOsr_ = (enclosingLoop->canIonOsr_ &&
+                       stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
+     } else {
+         canIonOsr_ = stackDepth_ == loopSlots;
+     }
+ }
+ 
+ bool
++LoopControl::emitContinueTarget(BytecodeEmitter* bce)
++{
++    if (!bce->emitJumpTarget(&continueTarget_))
++        return false;
++    return true;
++}
++
++bool
+ LoopControl::emitSpecialBreakForDone(BytecodeEmitter* bce)
+ {
+     // This doesn't pop stack values, nor handle any other controls.
+     // Should be called on the toplevel of the loop.
+     MOZ_ASSERT(bce->stackDepth == stackDepth_);
+     MOZ_ASSERT(bce->innermostNestableControl == this);
+ 
+     if (!bce->newSrcNote(SRC_BREAK))
+         return false;
+     if (!bce->emitJump(JSOP_GOTO, &breaks))
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
++LoopControl::emitEntryJump(BytecodeEmitter* bce)
++{
++    if (!bce->emitJump(JSOP_GOTO, &entryJump_))
++        return false;
++    return true;
++}
++
++bool
++LoopControl::emitLoopHead(BytecodeEmitter* bce, const Maybe<uint32_t>& nextPos)
++{
++    if (nextPos) {
++        if (!bce->updateSourceCoordNotes(*nextPos))
++            return false;
++    }
++
++    head_ = { bce->offset() };
++    if (!bce->emit1(JSOP_LOOPHEAD))
++        return false;
++
++    return true;
++}
++
++bool
++LoopControl::emitLoopEntry(BytecodeEmitter* bce, const Maybe<uint32_t>& nextPos)
++{
++    if (nextPos) {
++        if (!bce->updateSourceCoordNotes(*nextPos))
++            return false;
++    }
++
++    JumpTarget entry = { bce->offset() };
++    bce->patchJumpsToTarget(entryJump_, entry);
++
++    MOZ_ASSERT(loopDepth_ > 0);
++
++    uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loopDepth_,
++                                                               canIonOsr_);
++    if (!bce->emit2(JSOP_LOOPENTRY, loopDepthAndFlags))
++        return false;
++
++    return true;
++}
++
++bool
++LoopControl::emitLoopEnd(BytecodeEmitter* bce, JSOp op)
++{
++    JumpList beq;
++    if (!bce->emitBackwardJump(op, head_, &beq, &breakTarget_))
++        return false;
++
++    loopEndOffset_ = beq.offset;
++
++    return true;
++}
++
++bool
+ LoopControl::patchBreaksAndContinues(BytecodeEmitter* bce)
+ {
+-    MOZ_ASSERT(continueTarget.offset != -1);
++    MOZ_ASSERT(continueTarget_.offset != -1);
+     if (!patchBreaks(bce))
+         return false;
+-    bce->patchJumpsToTarget(continues, continueTarget);
++    bce->patchJumpsToTarget(continues, continueTarget_);
+     return true;
+ }
+ 
+ TryFinallyControl::TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
+   : NestableControl(bce, kind),
+     emittingSubroutine_(false)
+ {
+     MOZ_ASSERT(is<TryFinallyControl>());
+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
+@@ -3,25 +3,27 @@
+  * 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_BytecodeControlStructures_h
+ #define frontend_BytecodeControlStructures_h
+ 
+ #include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
+ 
+ #include <stddef.h>
+ #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;
+ 
+@@ -98,44 +100,127 @@ NestableControl::is<LabelControl>() cons
+ }
+ 
+ class LoopControl : public BreakableControl
+ {
+     // Loops' children are emitted in dominance order, so they can always
+     // have a TDZCheckCache.
+     TDZCheckCache tdzCache_;
+ 
++    // Here's the basic structure of a loop:
++    //
++    //     # Entry jump
++    //     JSOP_GOTO entry
++    //
++    //   head:
++    //     JSOP_LOOPHEAD
++    //     {loop body after branch}
++    //
++    //   entry:
++    //     JSOP_ENTRY
++    //     {loop body before branch}
++    //
++    //     # Loop end, backward jump
++    //     JSOP_GOTO/JSOP_IFNE head
++    //
++    //   breakTarget:
++    //
++    // `continueTarget` can be placed in arbitrary place by calling
++    // `setContinueTarget` or `emitContinueTarget` (see comment above them for
++    // more details).
++
++    // The offset of backward jump at the end of loop.
++    ptrdiff_t loopEndOffset_ = -1;
++
++    // The jump into JSOP_LOOPENTRY.
++    JumpList entryJump_;
++
++    // The bytecode offset of JSOP_LOOPHEAD.
++    JumpTarget head_ = { -1 };
++
++    // The target of break statement jumps.
++    JumpTarget breakTarget_ = { -1 };
++
++    // The target of continue statement jumps, e.g., the update portion of a
++    // for(;;) loop.
++    JumpTarget continueTarget_ = { -1 };
++
+     // Stack depth when this loop was pushed on the control stack.
+     int32_t stackDepth_;
+ 
+     // The loop nesting depth. Used as a hint to Ion.
+     uint32_t loopDepth_;
+ 
+     // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
+     bool canIonOsr_;
+ 
+   public:
+-    // The target of continue statement jumps, e.g., the update portion of a
+-    // for(;;) loop.
+-    JumpTarget continueTarget;
+-
+     // Offset of the last continue in the loop.
+     JumpList continues;
+ 
+     LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
+ 
+-    uint32_t loopDepth() const {
+-        return loopDepth_;
++    ptrdiff_t headOffset() const {
++        return head_.offset;
++    }
++    ptrdiff_t loopEndOffset() const {
++        return loopEndOffset_;
++    }
++    ptrdiff_t breakTargetOffset() const {
++        return breakTarget_.offset;
++    }
++    ptrdiff_t continueTargetOffset() const {
++        return continueTarget_.offset;
++    }
++
++    // The offset of the backward jump at the loop end from the loop's top, in
++    // case there was an entry jump.
++    ptrdiff_t loopEndOffsetFromEntryJump() const {
++        return loopEndOffset_ - entryJump_.offset;
++    }
++
++    // The offset of the backward jump at the loop end from the loop's top, in
++    // case there was no entry jump.
++    ptrdiff_t loopEndOffsetFromLoopHead() const {
++        return loopEndOffset_ - head_.offset;
+     }
+ 
+-    bool canIonOsr() const {
+-        return canIonOsr_;
++    // The offset of the continue target from the loop's top, in case there was
++    // no entry jump.
++    ptrdiff_t continueTargetOffsetFromLoopHead() const {
++        return continueTarget_.offset - head_.offset;
+     }
+ 
++    // A continue target can be specified by the following 2 ways:
++    //   * Use the existing JUMPTARGET by calling `setContinueTarget` with
++    //     the offset of the JUMPTARGET
++    //   * Generate a new JUMPTARGETby calling `emitContinueTarget`
++    void setContinueTarget(ptrdiff_t offset) {
++        continueTarget_.offset = offset;
++    }
++    MOZ_MUST_USE bool emitContinueTarget(BytecodeEmitter* bce);
++
++    // Emit a jump to break target from the top level of the loop.
+     MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce);
++
++    MOZ_MUST_USE bool emitEntryJump(BytecodeEmitter* bce);
++
++    // `nextPos` is the offset in the source code for the character that
++    // corresponds to the next instruction after JSOP_LOOPHEAD.
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitLoopHead(BytecodeEmitter* bce,
++                                   const mozilla::Maybe<uint32_t>& nextPos);
++
++    // `nextPos` is the offset in the source code for the character that
++    // corresponds to the next instruction after JSOP_LOOPENTRY.
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitLoopEntry(BytecodeEmitter* bce,
++                                    const mozilla::Maybe<uint32_t>& nextPos);
++
++    MOZ_MUST_USE bool emitLoopEnd(BytecodeEmitter* bce, JSOp op);
+     MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce);
+ };
+ template <>
+ inline bool
+ NestableControl::is<LoopControl>() const
+ {
+     return StatementKindIsLoop(kind_);
+ }
+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
+@@ -510,61 +510,32 @@ BytecodeEmitter::updateSourceCoordNotes(
+             return true;
+         if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan)))
+             return false;
+         current->lastColumn = columnIndex;
+     }
+     return true;
+ }
+ 
+-bool
+-BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top)
+-{
+-    if (nextpn) {
+-        /*
+-         * Try to give the JSOP_LOOPHEAD the same line number as the next
+-         * instruction. nextpn is often a block, in which case the next
+-         * instruction typically comes from the first statement inside.
+-         */
+-        if (nextpn->isKind(ParseNodeKind::LexicalScope))
+-            nextpn = nextpn->scopeBody();
+-        MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST));
+-        if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
+-            nextpn = nextpn->pn_head;
+-        if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
+-            return false;
+-    }
+-
+-    *top = { offset() };
+-    return emit1(JSOP_LOOPHEAD);
+-}
+-
+-bool
+-BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump)
+-{
+-    if (nextpn) {
+-        /* Update the line number, as for LOOPHEAD. */
+-        if (nextpn->isKind(ParseNodeKind::LexicalScope))
+-            nextpn = nextpn->scopeBody();
+-        MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST));
+-        if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
+-            nextpn = nextpn->pn_head;
+-        if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
+-            return false;
+-    }
+-
+-    JumpTarget entry{ offset() };
+-    patchJumpsToTarget(entryJump, entry);
+-
+-    LoopControl& loopInfo = innermostNestableControl->as<LoopControl>();
+-    MOZ_ASSERT(loopInfo.loopDepth() > 0);
+-
+-    uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loopInfo.loopDepth(),
+-                                                               loopInfo.canIonOsr());
+-    return emit2(JSOP_LOOPENTRY, loopDepthAndFlags);
++Maybe<uint32_t>
++BytecodeEmitter::getOffsetForLoop(ParseNode* nextpn)
++{
++    if (!nextpn)
++        return Nothing();
++
++    // Try to give the JSOP_LOOPHEAD and JSOP_LOOPENTRY the same line number as
++    // the next instruction. nextpn is often a block, in which case the next
++    // instruction typically comes from the first statement inside.
++    if (nextpn->isKind(ParseNodeKind::LexicalScope))
++        nextpn = nextpn->scopeBody();
++    MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST));
++    if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
++        nextpn = nextpn->pn_head;
++
++    return Some(nextpn->pn_pos.begin);
+ }
+ 
+ void
+ BytecodeEmitter::checkTypeSet(JSOp op)
+ {
+     if (CodeSpec[op].format & JOF_TYPESET) {
+         if (typesetCount < UINT16_MAX)
+             typesetCount++;
+@@ -4675,32 +4646,28 @@ BytecodeEmitter::emitSpread(bool allowSe
+     // find the loop-closing jump.
+     unsigned noteIndex;
+     if (!newSrcNote(SRC_FOR_OF, &noteIndex))
+         return false;
+ 
+     // Jump down to the loop condition to minimize overhead, assuming at least
+     // one iteration.  (This is also what we do for loops; whether this
+     // assumption holds for spreads is an unanswered question.)
+-    JumpList initialJump;
+-    if (!emitJump(JSOP_GOTO, &initialJump))               // NEXT ITER ARR I (during the goto)
+-        return false;
+-
+-    JumpTarget top{ -1 };
+-    if (!emitLoopHead(nullptr, &top))                     // NEXT ITER ARR I
++    if (!loopInfo.emitEntryJump(this))                    // NEXT ITER ARR I (during the goto)
++        return false;
++
++    if (!loopInfo.emitLoopHead(this, Nothing()))          // NEXT ITER ARR I
+         return false;
+ 
+     // When we enter the goto above, we have NEXT ITER ARR I on the stack. But
+     // when we reach this point on the loop backedge (if spreading produces at
+     // least one value), we've additionally pushed a RESULT iteration value.
+     // Increment manually to reflect this.
+     this->stackDepth++;
+ 
+-    JumpList beq;
+-    JumpTarget breakTarget{ -1 };
+     {
+ #ifdef DEBUG
+         auto loopDepth = this->stackDepth;
+ #endif
+ 
+         // Emit code to assign result.value to the iteration variable.
+         if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER ARR I VALUE
+             return false;
+@@ -4708,46 +4675,49 @@ BytecodeEmitter::emitSpread(bool allowSe
+             return false;
+ 
+         MOZ_ASSERT(this->stackDepth == loopDepth - 1);
+ 
+         // Spread operations can't contain |continue|, so don't bother setting loop
+         // and enclosing "update" offsets, as we do with for-loops.
+ 
+         // COME FROM the beginning of the loop to here.
+-        if (!emitLoopEntry(nullptr, initialJump))         // NEXT ITER ARR I
++        if (!loopInfo.emitLoopEntry(this, Nothing()))     // NEXT ITER ARR I
+             return false;
+ 
+         if (!emitDupAt(3))                                // NEXT ITER ARR I NEXT
+             return false;
+         if (!emitDupAt(3))                                // NEXT ITER ARR I NEXT ITER
+             return false;
+         if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted))  // ITER ARR I RESULT
+             return false;
+         if (!emit1(JSOP_DUP))                             // NEXT ITER ARR I RESULT RESULT
+             return false;
+         if (!emitAtomOp(cx->names().done, JSOP_GETPROP))  // NEXT ITER ARR I RESULT DONE
+             return false;
+ 
+-        if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget)) // NEXT ITER ARR I RESULT
++        if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ))       // NEXT ITER ARR I RESULT
+             return false;
+ 
+         MOZ_ASSERT(this->stackDepth == loopDepth);
+     }
+ 
+     // Let Ion know where the closing jump of this loop is.
+-    if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
++1    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+         return false;
+ 
+     // No breaks or continues should occur in spreads.
+     MOZ_ASSERT(loopInfo.breaks.offset == -1);
+     MOZ_ASSERT(loopInfo.continues.offset == -1);
+ 
+-    if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
+-        return false;
++    if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
++                            loopInfo.breakTargetOffset()))
++    {
++        return false;
++    }
+ 
+     if (!emit2(JSOP_PICK, 4))                             // ITER ARR FINAL_INDEX RESULT NEXT
+         return false;
+     if (!emit2(JSOP_PICK, 4))                             // ARR FINAL_INDEX RESULT NEXT ITER
+         return false;
+ 
+     return emitPopN(3);                                   // ARR FINAL_INDEX
+ }
+@@ -4866,22 +4836,20 @@ BytecodeEmitter::emitForOf(ParseNode* fo
+ 
+     ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
+ 
+     // Annotate so IonMonkey can find the loop-closing jump.
+     unsigned noteIndex;
+     if (!newSrcNote(SRC_FOR_OF, &noteIndex))
+         return false;
+ 
+-    JumpList initialJump;
+-    if (!emitJump(JSOP_GOTO, &initialJump))               // NEXT ITER UNDEF
+-        return false;
+-
+-    JumpTarget top{ -1 };
+-    if (!emitLoopHead(nullptr, &top))                     // NEXT ITER UNDEF
++    if (!loopInfo.emitEntryJump(this))                    // NEXT ITER UNDEF
++        return false;
++
++    if (!loopInfo.emitLoopHead(this, Nothing()))          // NEXT ITER UNDEF
+         return false;
+ 
+     // If the loop had an escaping lexical declaration, replace the current
+     // environment with an dead zoned one to implement TDZ semantics.
+     if (headLexicalEmitterScope) {
+         // The environment chain only includes an environment for the for-of
+         // loop head *if* a scope binding is captured, thereby requiring
+         // recreation each iteration. If a lexical scope exists for the head,
+@@ -4898,18 +4866,16 @@ BytecodeEmitter::emitForOf(ParseNode* fo
+                 return false;
+         }
+ 
+         // For uncaptured bindings, put them back in TDZ.
+         if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
+             return false;
+     }
+ 
+-    JumpList beq;
+-    JumpTarget breakTarget{ -1 };
+     {
+ #ifdef DEBUG
+         auto loopDepth = this->stackDepth;
+ #endif
+ 
+         // Make sure this code is attributed to the "for".
+         if (!updateSourceCoordNotes(forOfHead->pn_pos.begin))
+             return false;
+@@ -4975,39 +4941,41 @@ BytecodeEmitter::emitForOf(ParseNode* fo
+             return false;
+ 
+         MOZ_ASSERT(stackDepth == loopDepth,
+                    "the stack must be balanced around the for-of body");
+ 
+         if (!loopInfo.emitEndCodeNeedingIteratorClose(this))
+             return false;
+ 
+-        // Set offset for continues.
+-        loopInfo.continueTarget = { offset() };
+-
+-        if (!emitLoopEntry(forHeadExpr, initialJump))     // NEXT ITER UNDEF
+-            return false;
++        loopInfo.setContinueTarget(offset());
++
++        if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(forHeadExpr)))
++            return false;                                 // NEXT ITER UNDEF
+ 
+         if (!emit1(JSOP_FALSE))                           // NEXT ITER UNDEF FALSE
+             return false;
+-        if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
+-            return false;                                 // NEXT ITER UNDEF
++        if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ))       // NEXT ITER UNDEF
++            return false;
+ 
+         MOZ_ASSERT(this->stackDepth == loopDepth);
+     }
+ 
+     // Let Ion know where the closing jump of this loop is.
+-    if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
++    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+         return false;
+ 
+     if (!loopInfo.patchBreaksAndContinues(this))
+         return false;
+ 
+-    if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
+-        return false;
++    if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
++                            loopInfo.breakTargetOffset()))
++    {
++        return false;
++    }
+ 
+     return emitPopN(3);                                   //
+ }
+ 
+ bool
+ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitterScope)
+ {
+     MOZ_ASSERT(forInLoop->isKind(ParseNodeKind::For));
+@@ -5064,22 +5032,20 @@ BytecodeEmitter::emitForIn(ParseNode* fo
+ 
+     /* Annotate so IonMonkey can find the loop-closing jump. */
+     unsigned noteIndex;
+     if (!newSrcNote(SRC_FOR_IN, &noteIndex))
+         return false;
+ 
+     // Jump down to the loop condition to minimize overhead (assuming at least
+     // one iteration, just like the other loop forms).
+-    JumpList initialJump;
+-    if (!emitJump(JSOP_GOTO, &initialJump))               // ITER ITERVAL
+-        return false;
+-
+-    JumpTarget top{ -1 };
+-    if (!emitLoopHead(nullptr, &top))                     // ITER ITERVAL
++    if (!loopInfo.emitEntryJump(this))                    // ITER ITERVAL
++        return false;
++
++    if (!loopInfo.emitLoopHead(this, Nothing()))          // ITER ITERVAL
+         return false;
+ 
+     // If the loop had an escaping lexical declaration, replace the current
+     // environment with an dead zoned one to implement TDZ semantics.
+     if (headLexicalEmitterScope) {
+         // The environment chain only includes an environment for the for-in
+         // loop head *if* a scope binding is captured, thereby requiring
+         // recreation each iteration. If a lexical scope exists for the head,
+@@ -5117,48 +5083,46 @@ BytecodeEmitter::emitForIn(ParseNode* fo
+     }
+ 
+     // Perform the loop body.
+     ParseNode* forBody = forInLoop->pn_right;
+     if (!emitTree(forBody))                               // ITER ITERVAL
+         return false;
+ 
+     // Set offset for continues.
+-    loopInfo.continueTarget = { offset() };
++    loopInfo.setContinueTarget(offset());
+ 
+     // Make sure this code is attributed to the "for".
+     if (!updateSourceCoordNotes(forInHead->pn_pos.begin))
+         return false;
+ 
+-    if (!emitLoopEntry(nullptr, initialJump))             // ITER ITERVAL
++    if (!loopInfo.emitLoopEntry(this, Nothing()))         // ITER ITERVAL
+         return false;
+     if (!emit1(JSOP_POP))                                 // ITER
+         return false;
+     if (!emit1(JSOP_MOREITER))                            // ITER NEXTITERVAL?
+         return false;
+     if (!emit1(JSOP_ISNOITER))                            // ITER NEXTITERVAL? ISNOITER
+         return false;
+ 
+-    JumpList beq;
+-    JumpTarget breakTarget{ -1 };
+-    if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
+-        return false;                                     // ITER NEXTITERVAL
++    if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ))           // ITER NEXTITERVAL
++        return false;
+ 
+     // Set the srcnote offset so we can find the closing jump.
+-    if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
++    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+         return false;
+ 
+     if (!loopInfo.patchBreaksAndContinues(this))
+         return false;
+ 
+     // Pop the enumeration value.
+     if (!emit1(JSOP_POP))                                 // ITER
+         return false;
+ 
+-    if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, top.offset, offset()))
++    if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, loopInfo.headOffset(), offset()))
+         return false;
+ 
+     return emit1(JSOP_ENDITER);                           //
+ }
+ 
+ /* C-style `for (init; cond; update) ...` loop. */
+ bool
+ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
+@@ -5239,39 +5203,39 @@ BytecodeEmitter::emitCStyleFor(ParseNode
+      * from the top local variable by the length of the JSOP_GOTO
+      * emitted in between tmp and top if this loop has a condition.
+      */
+     unsigned noteIndex;
+     if (!newSrcNote(SRC_FOR, &noteIndex))
+         return false;
+     if (!emit1(JSOP_NOP))
+         return false;
+-    ptrdiff_t tmp = offset();
+-
+-    JumpList jmp;
++    ptrdiff_t top = offset();
++
+     if (forHead->pn_kid2) {
+         /* Goto the loop condition, which branches back to iterate. */
+-        if (!emitJump(JSOP_GOTO, &jmp))
++        if (!loopInfo.emitEntryJump(this))
+             return false;
+     }
+ 
+     /* Emit code for the loop body. */
+-    JumpTarget top{ -1 };
+-    if (!emitLoopHead(forBody, &top))
+-        return false;
+-    if (jmp.offset == -1 && !emitLoopEntry(forBody, jmp))
+-        return false;
++    if (!loopInfo.emitLoopHead(this, getOffsetForLoop(forBody)))
++        return false;
++    if (!forHead->pn_kid2) {
++        if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(forBody)))
++            return false;
++    }
+ 
+     if (!emitTreeInBranch(forBody))
+         return false;
+ 
+     // Set loop and enclosing "update" offsets, for continue.  Note that we
+     // continue to immediately *before* the block-freshening: continuing must
+     // refresh the block.
+-    if (!emitJumpTarget(&loopInfo.continueTarget))
++    if (!loopInfo.emitContinueTarget(this))
+         return false;
+ 
+     // ES 13.7.4.8 step 3.e. The per-iteration freshening.
+     if (forLoopRequiresFreshening) {
+         MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+         MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+ 
+         if (headLexicalEmitterScope->hasEnvironment()) {
+@@ -5301,49 +5265,49 @@ BytecodeEmitter::emitCStyleFor(ParseNode
+             current->lastColumn = 0;
+         }
+     }
+ 
+     ptrdiff_t tmp3 = offset();
+ 
+     if (forHead->pn_kid2) {
+         /* Fix up the goto from top to target the loop condition. */
+-        MOZ_ASSERT(jmp.offset >= 0);
+-        if (!emitLoopEntry(forHead->pn_kid2, jmp))
++        if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(forHead->pn_kid2)))
+             return false;
+ 
+         if (!emitTree(forHead->pn_kid2))
+             return false;
+     } else if (!forHead->pn_kid3) {
+         // If there is no condition clause and no update clause, mark
+         // the loop-ending "goto" with the location of the "for".
+         // This ensures that the debugger will stop on each loop
+         // iteration.
+         if (!updateSourceCoordNotes(pn->pn_pos.begin))
+             return false;
+     }
+ 
+     /* Set the first note offset so we can find the loop condition. */
+-    if (!setSrcNoteOffset(noteIndex, 0, tmp3 - tmp))
+-        return false;
+-    if (!setSrcNoteOffset(noteIndex, 1, loopInfo.continueTarget.offset - tmp))
++    if (!setSrcNoteOffset(noteIndex, 0, tmp3 - top))
++        return false;
++    if (!setSrcNoteOffset(noteIndex, 1, loopInfo.continueTargetOffset() - top))
+         return false;
+ 
+     /* If no loop condition, just emit a loop-closing jump. */
+-    JumpList beq;
+-    JumpTarget breakTarget{ -1 };
+-    if (!emitBackwardJump(forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO, top, &beq, &breakTarget))
++    if (!loopInfo.emitLoopEnd(this, forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO))
+         return false;
+ 
+     /* The third note offset helps us find the loop-closing jump. */
+-    if (!setSrcNoteOffset(noteIndex, 2, beq.offset - tmp))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
+-        return false;
++    if (!setSrcNoteOffset(noteIndex, 2, loopInfo.loopEndOffset() - top))
++        return false;
++
++    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, loopInfo.headOffset(),
++                            loopInfo.breakTargetOffset()))
++    {
++        return false;
++    }
+ 
+     if (!loopInfo.patchBreaksAndContinues(this))
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+@@ -5654,55 +5618,55 @@ BytecodeEmitter::emitDo(ParseNode* pn)
+     if (!emit1(JSOP_NOP))
+         return false;
+ 
+     unsigned noteIndex2;
+     if (!newSrcNote(SRC_WHILE, &noteIndex2))
+         return false;
+ 
+     /* Compile the loop body. */
+-    JumpTarget top;
+-    if (!emitLoopHead(pn->pn_left, &top))
+-        return false;
+-
+     LoopControl loopInfo(this, StatementKind::DoLoop);
+ 
+-    JumpList empty;
+-    if (!emitLoopEntry(nullptr, empty))
++    if (!loopInfo.emitLoopHead(this, getOffsetForLoop(pn->pn_left)))
++        return false;
++
++    if (!loopInfo.emitLoopEntry(this, Nothing()))
+         return false;
+ 
+     if (!emitTree(pn->pn_left))
+         return false;
+ 
+     // Set the offset for continues.
+-    if (!emitJumpTarget(&loopInfo.continueTarget))
++    if (!loopInfo.emitContinueTarget(this))
+         return false;
+ 
+     /* Compile the loop condition, now that continues know where to go. */
+     if (!emitTree(pn->pn_right))
+         return false;
+ 
+-    JumpList beq;
+-    JumpTarget breakTarget{ -1 };
+-    if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
+-        return false;
++    if (!loopInfo.emitLoopEnd(this, JSOP_IFNE))
++        return false;
++
++    if (!tryNoteList.append(JSTRY_LOOP, 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.
+      */
+-    if (!setSrcNoteOffset(noteIndex2, 0, beq.offset - top.offset))
+-        return false;
+-    if (!setSrcNoteOffset(noteIndex, 0, 1 + (loopInfo.continueTarget.offset - top.offset)))
++    if (!setSrcNoteOffset(noteIndex2, 0, loopInfo.loopEndOffsetFromLoopHead()))
++        return false;
++    // +1 for NOP above.
++    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.continueTargetOffsetFromLoopHead() + 1))
+         return false;
+ 
+     if (!loopInfo.patchBreaksAndContinues(this))
+         return false;
+ 
+     return true;
+ }
+ 
+@@ -5738,46 +5702,46 @@ BytecodeEmitter::emitWhile(ParseNode* pn
+             return false;
+     }
+ 
+     JumpTarget top{ -1 };
+     if (!emitJumpTarget(&top))
+         return false;
+ 
+     LoopControl loopInfo(this, StatementKind::WhileLoop);
+-    loopInfo.continueTarget = top;
++    loopInfo.setContinueTarget(top.offset);
+ 
+     unsigned noteIndex;
+     if (!newSrcNote(SRC_WHILE, &noteIndex))
+         return false;
+ 
+-    JumpList jmp;
+-    if (!emitJump(JSOP_GOTO, &jmp))
+-        return false;
+-
+-    if (!emitLoopHead(pn->pn_right, &top))
++    if (!loopInfo.emitEntryJump(this))
++        return false;
++
++    if (!loopInfo.emitLoopHead(this, getOffsetForLoop(pn->pn_right)))
+         return false;
+ 
+     if (!emitTreeInBranch(pn->pn_right))
+         return false;
+ 
+-    if (!emitLoopEntry(pn->pn_left, jmp))
++    if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(pn->pn_left)))
+         return false;
+     if (!emitTree(pn->pn_left))
+         return false;
+ 
+-    JumpList beq;
+-    JumpTarget breakTarget{ -1 };
+-    if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
+-        return false;
+-
+-    if (!setSrcNoteOffset(noteIndex, 0, beq.offset - jmp.offset))
++    if (!loopInfo.emitLoopEnd(this, JSOP_IFNE))
++        return false;
++
++    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, loopInfo.headOffset(),
++                            loopInfo.breakTargetOffset()))
++    {
++        return false;
++    }
++
++    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+         return false;
+ 
+     if (!loopInfo.patchBreaksAndContinues(this))
+         return false;
+ 
+     return true;
+ }
+ 
+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
+@@ -547,18 +547,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump,
+                                        JumpTarget* fallthrough);
+     void patchJumpsToTarget(JumpList jump, JumpTarget target);
+     MOZ_MUST_USE bool emitJumpTargetAndPatch(JumpList jump);
+ 
+     MOZ_MUST_USE bool emitCall(JSOp op, uint16_t argc, ParseNode* pn = nullptr);
+     MOZ_MUST_USE bool emitCallIncDec(ParseNode* incDec);
+ 
+-    MOZ_MUST_USE bool emitLoopHead(ParseNode* nextpn, JumpTarget* top);
+-    MOZ_MUST_USE bool emitLoopEntry(ParseNode* nextpn, JumpList entryJump);
++    mozilla::Maybe<uint32_t> getOffsetForLoop(ParseNode* nextpn);
+ 
+     MOZ_MUST_USE bool emitGoto(NestableControl* target, JumpList* jumplist,
+                                SrcNoteType noteType = SRC_NULL);
+ 
+     MOZ_MUST_USE bool emitIndex32(JSOp op, uint32_t index);
+     MOZ_MUST_USE bool emitIndexOp(JSOp op, uint32_t index);
+ 
+     MOZ_MUST_USE bool emitAtomOp(JSAtom* atom, JSOp op);

+ 1092 - 0
frg/work-js/mozilla-release/patches/1456404-2-63a1.patch

@@ -0,0 +1,1092 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854957 -32400
+#      Fri Aug 10 07:49:17 2018 +0900
+# Node ID 6dbce3046bd95e61ced3487cb3d6e5bf4310983f
+# Parent  e20a86a9b5756d9bf2ec3c48b1c7ddbdb95a9eba
+Bug 1456404 - Part 2: Add CForEmitter. 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
+@@ -20,16 +20,17 @@
+ 
+ #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/EmitterScope.h"
+ #include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/SwitchEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "frontend/TryEmitter.h"
+ #include "vm/BytecodeUtil.h"
+@@ -4780,17 +4781,17 @@ BytecodeEmitter::emitInitializeForInOrOf
+                "for-in/of loop destructuring declarations can't have initializers");
+ 
+     MOZ_ASSERT(target->isKind(ParseNodeKind::Array) ||
+                target->isKind(ParseNodeKind::Object));
+     return emitDestructuringOps(target, DestructuringDeclaration);
+ }
+ 
+ bool
+-BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitterScope)
++BytecodeEmitter::emitForOf(ParseNode* forOfLoop, const EmitterScope* headLexicalEmitterScope)
+ {
+     MOZ_ASSERT(forOfLoop->isKind(ParseNodeKind::For));
+     MOZ_ASSERT(forOfLoop->isArity(PN_BINARY));
+ 
+     ParseNode* forOfHead = forOfLoop->pn_left;
+     MOZ_ASSERT(forOfHead->isKind(ParseNodeKind::ForOf));
+     MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
+ 
+@@ -4971,17 +4972,17 @@ BytecodeEmitter::emitForOf(ParseNode* fo
+     {
+         return false;
+     }
+ 
+     return emitPopN(3);                                   //
+ }
+ 
+ bool
+-BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitterScope)
++BytecodeEmitter::emitForIn(ParseNode* forInLoop, const EmitterScope* headLexicalEmitterScope)
+ {
+     MOZ_ASSERT(forInLoop->isKind(ParseNodeKind::For));
+     MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
+     MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
+ 
+     ParseNode* forInHead = forInLoop->pn_left;
+     MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
+     MOZ_ASSERT(forInHead->isArity(PN_TERNARY));
+@@ -5120,203 +5121,92 @@ BytecodeEmitter::emitForIn(ParseNode* fo
+     if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, loopInfo.headOffset(), offset()))
+         return false;
+ 
+     return emit1(JSOP_ENDITER);                           //
+ }
+ 
+ /* C-style `for (init; cond; update) ...` loop. */
+ bool
+-BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
+-{
+-    LoopControl loopInfo(this, StatementKind::ForLoop);
+-
++BytecodeEmitter::emitCStyleFor(ParseNode* pn, const EmitterScope* headLexicalEmitterScope)
++{
+     ParseNode* forHead = pn->pn_left;
+     ParseNode* forBody = pn->pn_right;
++    ParseNode* init = forHead->pn_kid1;
++    ParseNode* cond = forHead->pn_kid2;
++    ParseNode* update = forHead->pn_kid3;
++    bool isLet = init && init->isKind(ParseNodeKind::Let);
++
++    CForEmitter cfor(this, isLet ? headLexicalEmitterScope : nullptr);
++
++    if (!cfor.emitInit(init ? Some(init->pn_pos.begin) : Nothing()))
++        return false;                                     //
+ 
+     // If the head of this for-loop declared any lexical variables, the parser
+     // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
+-    // representing the implicit scope of those variables. By the time we get here,
+-    // we have already entered that scope. So far, so good.
+-    //
+-    // ### Scope freshening
+-    //
+-    // Each iteration of a `for (let V...)` loop creates a fresh loop variable
+-    // binding for V, even if the loop is a C-style `for(;;)` loop:
+-    //
+-    //     var funcs = [];
+-    //     for (let i = 0; i < 2; i++)
+-    //         funcs.push(function() { return i; });
+-    //     assertEq(funcs[0](), 0);  // the two closures capture...
+-    //     assertEq(funcs[1](), 1);  // ...two different `i` bindings
+-    //
+-    // This is implemented by "freshening" the implicit block -- changing the
+-    // scope chain to a fresh clone of the instantaneous block object -- each
+-    // iteration, just before evaluating the "update" in for(;;) loops.
+-    //
+-    // No freshening occurs in `for (const ...;;)` as there's no point: you
+-    // can't reassign consts. This is observable through the Debugger API. (The
+-    // ES6 spec also skips cloning the environment in this case.)
+-    bool forLoopRequiresFreshening = false;
+-    if (ParseNode* init = forHead->pn_kid1) {
++    // representing the implicit scope of those variables. By the time we get
++    // here, we have already entered that scope. So far, so good.
++    if (init) {
+         // Emit the `init` clause, whether it's an expression or a variable
+         // declaration. (The loop variables were hoisted into an enclosing
+         // scope, but we still need to emit code for the initializers.)
+-        if (!updateSourceCoordNotes(init->pn_pos.begin))
+-            return false;
+         if (init->isForLoopDeclaration()) {
+-            if (!emitTree(init))
++            if (!emitTree(init))                          //
+                 return false;
+         } else {
+             // 'init' is an expression, not a declaration. emitTree left its
+             // value on the stack.
+-            if (!emitTree(init, ValueUsage::IgnoreValue))
+-                return false;
+-            if (!emit1(JSOP_POP))
+-                return false;
+-        }
+-
+-        // ES 13.7.4.8 step 2. The initial freshening.
+-        //
+-        // If an initializer let-declaration may be captured during loop iteration,
+-        // the current scope has an environment.  If so, freshen the current
+-        // environment to expose distinct bindings for each loop iteration.
+-        forLoopRequiresFreshening = init->isKind(ParseNodeKind::Let) && headLexicalEmitterScope;
+-        if (forLoopRequiresFreshening) {
+-            // The environment chain only includes an environment for the for(;;)
+-            // loop head's let-declaration *if* a scope binding is captured, thus
+-            // requiring a fresh environment each iteration. If a lexical scope
+-            // exists for the head, it must be the innermost one. If that scope
+-            // has closed-over bindings inducing an environment, recreate the
+-            // current environment.
+-            MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+-            MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+-
+-            if (headLexicalEmitterScope->hasEnvironment()) {
+-                if (!emit1(JSOP_FRESHENLEXICALENV))
+-                    return false;
+-            }
+-        }
+-    }
+-
+-    /*
+-     * NB: the SRC_FOR note has offsetBias 1 (JSOP_NOP_LENGTH).
+-     * Use tmp to hold the biased srcnote "top" offset, which differs
+-     * from the top local variable by the length of the JSOP_GOTO
+-     * emitted in between tmp and top if this loop has a condition.
+-     */
+-    unsigned noteIndex;
+-    if (!newSrcNote(SRC_FOR, &noteIndex))
+-        return false;
+-    if (!emit1(JSOP_NOP))
+-        return false;
+-    ptrdiff_t top = offset();
+-
+-    if (forHead->pn_kid2) {
+-        /* Goto the loop condition, which branches back to iterate. */
+-        if (!loopInfo.emitEntryJump(this))
+-            return false;
+-    }
+-
+-    /* Emit code for the loop body. */
+-    if (!loopInfo.emitLoopHead(this, getOffsetForLoop(forBody)))
+-        return false;
+-    if (!forHead->pn_kid2) {
+-        if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(forBody)))
+-            return false;
+-    }
+-
+-    if (!emitTreeInBranch(forBody))
+-        return false;
+-
+-    // Set loop and enclosing "update" offsets, for continue.  Note that we
+-    // continue to immediately *before* the block-freshening: continuing must
+-    // refresh the block.
+-    if (!loopInfo.emitContinueTarget(this))
+-        return false;
+-
+-    // ES 13.7.4.8 step 3.e. The per-iteration freshening.
+-    if (forLoopRequiresFreshening) {
+-        MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+-        MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+-
+-        if (headLexicalEmitterScope->hasEnvironment()) {
+-            if (!emit1(JSOP_FRESHENLEXICALENV))
+-                return false;
+-        }
++            if (!emitTree(init, ValueUsage::IgnoreValue)) // VAL
++                return false;
++            if (!emit1(JSOP_POP))                         //
++                return false;
++        }
++    }
++
++    if (!cfor.emitBody(cond ? CForEmitter::Cond::Present : CForEmitter::Cond::Missing,
++                       getOffsetForLoop(forBody)))        //
++    {
++        return false;
++    }
++
++    if (!emitTree(forBody))                               //
++        return false;
++
++    if (!cfor.emitUpdate(update ? CForEmitter::Update::Present : CForEmitter::Update::Missing,
++                         update ? Some(update->pn_pos.begin) : Nothing()))
++    {                                                     //
++        return false;
+     }
+ 
+     // Check for update code to do before the condition (if any).
+-    // The update code may not be executed at all; it needs its own TDZ cache.
+-    if (ParseNode* update = forHead->pn_kid3) {
+-        TDZCheckCache tdzCache(this);
+-
+-        if (!updateSourceCoordNotes(update->pn_pos.begin))
+-            return false;
+-        if (!emitTree(update, ValueUsage::IgnoreValue))
+-            return false;
+-        if (!emit1(JSOP_POP))
+-            return false;
+-
+-        /* Restore the absolute line number for source note readers. */
+-        uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.end);
+-        if (currentLine() != lineNum) {
+-            if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum)))
+-                return false;
+-            current->currentLine = lineNum;
+-            current->lastColumn = 0;
+-        }
+-    }
+-
+-    ptrdiff_t tmp3 = offset();
+-
+-    if (forHead->pn_kid2) {
+-        /* Fix up the goto from top to target the loop condition. */
+-        if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(forHead->pn_kid2)))
+-            return false;
+-
+-        if (!emitTree(forHead->pn_kid2))
+-            return false;
+-    } else if (!forHead->pn_kid3) {
+-        // If there is no condition clause and no update clause, mark
+-        // the loop-ending "goto" with the location of the "for".
+-        // This ensures that the debugger will stop on each loop
+-        // iteration.
+-        if (!updateSourceCoordNotes(pn->pn_pos.begin))
+-            return false;
+-    }
+-
+-    /* Set the first note offset so we can find the loop condition. */
+-    if (!setSrcNoteOffset(noteIndex, 0, tmp3 - top))
+-        return false;
+-    if (!setSrcNoteOffset(noteIndex, 1, loopInfo.continueTargetOffset() - top))
+-        return false;
+-
+-    /* If no loop condition, just emit a loop-closing jump. */
+-    if (!loopInfo.emitLoopEnd(this, forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO))
+-        return false;
+-
+-    /* The third note offset helps us find the loop-closing jump. */
+-    if (!setSrcNoteOffset(noteIndex, 2, loopInfo.loopEndOffset() - top))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, loopInfo.headOffset(),
+-                            loopInfo.breakTargetOffset()))
++    if (update) {
++        if (!emitTree(update, ValueUsage::IgnoreValue))   // VAL
++            return false;
++    }
++
++    if (!cfor.emitCond(Some(pn->pn_pos.begin),
++                       cond ? Some(cond->pn_pos.begin) : Nothing(),
++                       Some(pn->pn_pos.end)))             //
+     {
+         return false;
+     }
+ 
+-    if (!loopInfo.patchBreaksAndContinues(this))
++    if (cond) {
++        if (!emitTree(cond))                              // VAL
++            return false;
++    }
++
++    if (!cfor.emitEnd())                                  //
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+-BytecodeEmitter::emitFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
++BytecodeEmitter::emitFor(ParseNode* pn, const EmitterScope* headLexicalEmitterScope)
+ {
+     MOZ_ASSERT(pn->isKind(ParseNodeKind::For));
+ 
+     if (pn->pn_left->isKind(ParseNodeKind::ForHead))
+         return emitCStyleFor(pn, headLexicalEmitterScope);
+ 
+     if (!updateLineNumberNotes(pn->pn_pos.begin))
+         return false;
+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
+@@ -812,20 +812,21 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitSelfHostedAllowContentIter(ParseNode* pn);
+     MOZ_MUST_USE bool emitSelfHostedDefineDataProperty(ParseNode* pn);
+     MOZ_MUST_USE bool emitSelfHostedGetPropertySuper(ParseNode* pn);
+     MOZ_MUST_USE bool emitSelfHostedHasOwn(ParseNode* pn);
+ 
+     MOZ_MUST_USE bool emitDo(ParseNode* pn);
+     MOZ_MUST_USE bool emitWhile(ParseNode* pn);
+ 
+-    MOZ_MUST_USE bool emitFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope = nullptr);
+-    MOZ_MUST_USE bool emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope);
+-    MOZ_MUST_USE bool emitForIn(ParseNode* pn, EmitterScope* headLexicalEmitterScope);
+-    MOZ_MUST_USE bool emitForOf(ParseNode* pn, EmitterScope* headLexicalEmitterScope);
++    MOZ_MUST_USE bool emitFor(ParseNode* pn,
++                              const EmitterScope* headLexicalEmitterScope = nullptr);
++    MOZ_MUST_USE bool emitCStyleFor(ParseNode* pn, const EmitterScope* headLexicalEmitterScope);
++    MOZ_MUST_USE bool emitForIn(ParseNode* pn, const EmitterScope* headLexicalEmitterScope);
++    MOZ_MUST_USE bool emitForOf(ParseNode* pn, const EmitterScope* headLexicalEmitterScope);
+ 
+     MOZ_MUST_USE bool emitInitializeForInOrOfTarget(ParseNode* forHead);
+ 
+     MOZ_MUST_USE bool emitBreak(PropertyName* label);
+     MOZ_MUST_USE bool emitContinue(PropertyName* label);
+ 
+     MOZ_MUST_USE bool emitFunctionFormalParametersAndBody(ParseNode* pn);
+     MOZ_MUST_USE bool emitFunctionFormalParameters(ParseNode* pn);
+diff --git a/js/src/frontend/CForEmitter.cpp b/js/src/frontend/CForEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/CForEmitter.cpp
+@@ -0,0 +1,235 @@
++/* -*- 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 "frontend/CForEmitter.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/EmitterScope.h"
++#include "frontend/SourceNotes.h"
++#include "vm/Opcodes.h"
++#include "vm/Scope.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++
++CForEmitter::CForEmitter(BytecodeEmitter* bce,
++                         const EmitterScope* headLexicalEmitterScopeForLet)
++  : bce_(bce),
++    headLexicalEmitterScopeForLet_(headLexicalEmitterScopeForLet)
++{}
++
++bool
++CForEmitter::emitInit(const Maybe<uint32_t>& initPos)
++{
++    MOZ_ASSERT(state_ == State::Start);
++
++    loopInfo_.emplace(bce_, StatementKind::ForLoop);
++
++    if (initPos) {
++        if (!bce_->updateSourceCoordNotes(*initPos))
++            return false;
++    }
++
++#ifdef DEBUG
++    state_ = State::Init;
++#endif
++    return true;
++}
++
++bool
++CForEmitter::emitBody(Cond cond, const Maybe<uint32_t>& bodyPos)
++{
++    MOZ_ASSERT(state_ == State::Init);
++    cond_ = cond;
++
++    // ES 13.7.4.8 step 2. The initial freshening.
++    //
++    // If an initializer let-declaration may be captured during loop
++    // iteration, the current scope has an environment.  If so, freshen the
++    // current environment to expose distinct bindings for each loop
++    // iteration.
++    if (headLexicalEmitterScopeForLet_) {
++        // The environment chain only includes an environment for the
++        // for(;;) loop head's let-declaration *if* a scope binding is
++        // captured, thus requiring a fresh environment each iteration. If
++        // a lexical scope exists for the head, it must be the innermost
++        // one. If that scope has closed-over bindings inducing an
++        // environment, recreate the current environment.
++        MOZ_ASSERT(headLexicalEmitterScopeForLet_ == bce_->innermostEmitterScope());
++        MOZ_ASSERT(headLexicalEmitterScopeForLet_->scope(bce_)->kind() == ScopeKind::Lexical);
++
++        if (headLexicalEmitterScopeForLet_->hasEnvironment()) {
++            if (!bce_->emit1(JSOP_FRESHENLEXICALENV))
++                return false;
++        }
++    }
++
++    // NB: the SRC_FOR note has offsetBias 1 (JSOP_NOP_LENGTH).
++    if (!bce_->newSrcNote(SRC_FOR, &noteIndex_))
++        return false;
++    if (!bce_->emit1(JSOP_NOP))
++        return false;
++
++    biasedTop_ = bce_->offset();
++
++    if (cond_ == Cond::Present) {
++        // Goto the loop condition, which branches back to iterate.
++        if (!loopInfo_->emitEntryJump(bce_))
++            return false;
++    }
++
++    if (!loopInfo_->emitLoopHead(bce_, bodyPos))
++        return false;
++
++    if (cond_ == Cond::Missing) {
++        if (!loopInfo_->emitLoopEntry(bce_, bodyPos))
++            return false;
++    }
++
++    tdzCache_.emplace(bce_);
++
++#ifdef DEBUG
++    state_ = State::Body;
++#endif
++    return true;
++}
++
++bool
++CForEmitter::emitUpdate(Update update, const Maybe<uint32_t>& updatePos)
++{
++    MOZ_ASSERT(state_ == State::Body);
++    update_ = update;
++    tdzCache_.reset();
++
++    // Set loop and enclosing "update" offsets, for continue.  Note that we
++    // continue to immediately *before* the block-freshening: continuing must
++    // refresh the block.
++    if (!loopInfo_->emitContinueTarget(bce_))
++        return false;
++
++    // ES 13.7.4.8 step 3.e. The per-iteration freshening.
++    if (headLexicalEmitterScopeForLet_) {
++        MOZ_ASSERT(headLexicalEmitterScopeForLet_ == bce_->innermostEmitterScope());
++        MOZ_ASSERT(headLexicalEmitterScopeForLet_->scope(bce_)->kind() == ScopeKind::Lexical);
++
++        if (headLexicalEmitterScopeForLet_->hasEnvironment()) {
++            if (!bce_->emit1(JSOP_FRESHENLEXICALENV))
++                return false;
++        }
++    }
++
++    // The update code may not be executed at all; it needs its own TDZ
++    // cache.
++    if (update_ == Update::Present) {
++        tdzCache_.emplace(bce_);
++
++        if (updatePos) {
++            if (!bce_->updateSourceCoordNotes(*updatePos))
++                return false;
++        }
++    }
++
++#ifdef DEBUG
++    state_ = State::Update;
++#endif
++    return true;
++}
++
++bool
++CForEmitter::emitCond(const Maybe<uint32_t>& forPos,
++                      const Maybe<uint32_t>& condPos,
++                      const Maybe<uint32_t>& endPos)
++{
++    MOZ_ASSERT(state_ == State::Update);
++
++    if (update_ == Update::Present) {
++        if (!bce_->emit1(JSOP_POP))                   //
++            return false;
++
++        // Restore the absolute line number for source note readers.
++        if (endPos) {
++            uint32_t lineNum =
++                bce_->parser->errorReporter().lineAt(*endPos);
++            if (bce_->currentLine() != lineNum) {
++                if (!bce_->newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum)))
++                    return false;
++                bce_->current->currentLine = lineNum;
++                bce_->current->lastColumn = 0;
++            }
++        }
++    }
++
++    if (update_ == Update::Present)
++        tdzCache_.reset();
++
++    condOffset_ = bce_->offset();
++
++    if (cond_ == Cond::Present) {
++        if (!loopInfo_->emitLoopEntry(bce_, condPos))
++            return false;
++    } else if (update_ == Update::Missing) {
++        // If there is no condition clause and no update clause, mark
++        // the loop-ending "goto" with the location of the "for".
++        // This ensures that the debugger will stop on each loop
++        // iteration.
++        if (forPos) {
++            if (!bce_->updateSourceCoordNotes(*forPos))
++                return false;
++        }
++    }
++
++#ifdef DEBUG
++    state_ = State::Cond;
++#endif
++    return true;
++}
++
++bool
++CForEmitter::emitEnd()
++{
++    MOZ_ASSERT(state_ == State::Cond);
++    // Set the first note offset so we can find the loop condition.
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::For::CondOffset,
++                                condOffset_ - biasedTop_))
++    {
++        return false;
++    }
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::For::UpdateOffset,
++                                loopInfo_->continueTargetOffset() - biasedTop_))
++    {
++        return false;
++    }
++
++    // If no loop condition, just emit a loop-closing jump.
++    if (!loopInfo_->emitLoopEnd(bce_, cond_ == Cond::Present ? JSOP_IFNE : JSOP_GOTO))
++        return false;                                 //
++
++    // The third note offset helps us find the loop-closing jump.
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::For::BackJumpOffset,
++                                loopInfo_->loopEndOffset() - biasedTop_))
++
++    {
++        return false;
++    }
++
++    if (!bce_->tryNoteList.append(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
++                                  loopInfo_->breakTargetOffset()))
++    {
++        return false;
++    }
++
++    if (!loopInfo_->patchBreaksAndContinues(bce_))
++        return false;
++
++    loopInfo_.reset();
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/CForEmitter.h b/js/src/frontend/CForEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/CForEmitter.h
+@@ -0,0 +1,196 @@
++/* -*- 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_CForEmitter_h
++#define frontend_CForEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stddef.h>
++#include <stdint.h>
++
++#include "frontend/BytecodeControlStructures.h"
++#include "frontend/TDZCheckCache.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++class EmitterScope;
++
++// Class for emitting bytecode for c-style for block.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `for (init; cond; update) body`
++//     CForEmitter cfor(this, headLexicalEmitterScopeForLet or nullptr);
++//     cfor.emitInit(Some(offset_of_init));
++//     emit(init); // without pushing value
++//     cfor.emitBody(CForEmitter::Cond::Present, Some(offset_of_body));
++//     emit(body);
++//     cfor.emitUpdate(CForEmitter::Update::Present, Some(offset_of_update)));
++//     emit(update);
++//     cfor.emitCond(Some(offset_of_for),
++//                   Some(offset_of_cond),
++//                   Some(offset_of_end));
++//     emit(cond);
++//     cfor.emitEnd();
++//
++//   `for (;;) body`
++//     CForEmitter cfor(this, nullptr);
++//     cfor.emitInit(Nothing());
++//     cfor.emitBody(CForEmitter::Cond::Missing, Some(offset_of_body));
++//     emit(body);
++//     cfor.emitUpdate(CForEmitter::Update::Missing, Nothing());
++//     cfor.emitCond(Some(offset_of_for),
++//                   Nothing(),
++//                   Some(offset_of_end));
++//     cfor.emitEnd();
++//
++class MOZ_STACK_CLASS CForEmitter
++{
++    // Basic structure of the bytecode (not complete).
++    //
++    // If `cond` is not empty:
++    //     {init}
++    //     JSOP_GOTO entry
++    //   loop:
++    //     {body}
++    //     {update}
++    //   entry:
++    //     {cond}
++    //     JSOP_IFNE loop
++    //
++    // If `cond` is empty:
++    //     {init}
++    //   loop:
++    //     {body}
++    //     {update}
++    //     JSOP_GOTO loop
++    //
++  public:
++    enum class Cond {
++        Missing,
++        Present
++    };
++    enum class Update {
++        Missing,
++        Present
++    };
++
++  private:
++    BytecodeEmitter* bce_;
++
++    // The source note index for SRC_FOR.
++    unsigned noteIndex_ = 0;
++
++    // The bytecode offset of loop condition.
++    // Not the bytecode offset of loop condition expression itself.
++    ptrdiff_t condOffset_ = 0;
++
++    // The base bytecode offset used by SRC_FOR.
++    ptrdiff_t biasedTop_ = 0;
++
++    // Whether the c-style for loop has `cond` and `update`.
++    Cond cond_ = Cond::Missing;
++    Update update_ = Update::Missing;
++
++    mozilla::Maybe<LoopControl> loopInfo_;
++
++    // The lexical scope to be freshened for each iteration.
++    // See the comment in `emitBody` for more details.
++    //
++    // ### Scope freshening
++    //
++    // Each iteration of a `for (let V...)` loop creates a fresh loop variable
++    // binding for V, even if the loop is a C-style `for(;;)` loop:
++    //
++    //     var funcs = [];
++    //     for (let i = 0; i < 2; i++)
++    //         funcs.push(function() { return i; });
++    //     assertEq(funcs[0](), 0);  // the two closures capture...
++    //     assertEq(funcs[1](), 1);  // ...two different `i` bindings
++    //
++    // This is implemented by "freshening" the implicit block -- changing the
++    // scope chain to a fresh clone of the instantaneous block object -- each
++    // iteration, just before evaluating the "update" in for(;;) loops.
++    //
++    // ECMAScript doesn't freshen in `for (const ...;;)`.  Lack of freshening
++    // isn't directly observable in-language because `const`s can't be mutated,
++    // but it *can* be observed in the Debugger API.
++    const EmitterScope* headLexicalEmitterScopeForLet_;
++
++    mozilla::Maybe<TDZCheckCache> tdzCache_;
++
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitInit +------+ emitBody +------+ emitUpdate +--------+
++    // | Start |--------->| Init |--------->| Body |----------->| Update |-+
++    // +-------+          +------+          +------+            +--------+ |
++    //                                                                     |
++    //                                   +---------------------------------+
++    //                                   |
++    //                                   | emitCond +------+ emitEnd +-----+
++    //                                   +--------->| Cond |-------->| End |
++    //                                              +------+         +-----+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitInit.
++        Init,
++
++        // After calling emitBody.
++        Body,
++
++        // After calling emitUpdate.
++        Update,
++
++        // After calling emitCond.
++        Cond,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  public:
++    CForEmitter(BytecodeEmitter* bce, const EmitterScope* headLexicalEmitterScopeForLet);
++
++    // Parameters are the offset in the source code for each character below:
++    //
++    //   for ( x = 10 ; x < 20 ; x ++ ) { f(x); }
++    //   ^     ^        ^        ^      ^       ^
++    //   |     |        |        |      |       |
++    //   |     |        |        |      |       endPos
++    //   |     |        |        |      |
++    //   |     |        |        |      bodyPos
++    //   |     |        |        |
++    //   |     |        |        updatePos
++    //   |     |        |
++    //   |     |        condPos
++    //   |     |
++    //   |     initPos
++    //   |
++    //   forPos
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitInit(const mozilla::Maybe<uint32_t>& initPos);
++    MOZ_MUST_USE bool emitBody(Cond cond, const mozilla::Maybe<uint32_t>& bodyPos);
++    MOZ_MUST_USE bool emitUpdate(Update update, const mozilla::Maybe<uint32_t>& updatePos);
++    MOZ_MUST_USE bool emitCond(const mozilla::Maybe<uint32_t>& forPos,
++                               const mozilla::Maybe<uint32_t>& condPos,
++                               const mozilla::Maybe<uint32_t>& endPos);
++    MOZ_MUST_USE bool emitEnd();
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_CForEmitter_h */
+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
+@@ -361,17 +361,17 @@ EmitterScope::appendScopeNote(BytecodeEm
+                "Scope notes are not needed for body-level scopes.");
+     noteIndex_ = bce->scopeNoteList.length();
+     return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
+                                      enclosingInFrame() ? enclosingInFrame()->noteIndex()
+                                                         : ScopeNote::NoScopeNoteIndex);
+ }
+ 
+ bool
+-EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart, uint32_t slotEnd)
++EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart, uint32_t slotEnd) const
+ {
+     // Lexical bindings throw ReferenceErrors if they are used before
+     // initialization. See ES6 8.1.1.1.6.
+     //
+     // For completeness, lexical bindings are initialized in ES6 by calling
+     // InitializeBinding, after which touching the binding will no longer
+     // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
+     // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
+@@ -952,17 +952,17 @@ EmitterScope::enterWith(BytecodeEmitter*
+ 
+     if (!appendScopeNote(bce))
+         return false;
+ 
+     return checkEnvironmentChainLength(bce);
+ }
+ 
+ bool
+-EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
++EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce) const
+ {
+     return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
+ }
+ 
+ bool
+ EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
+ {
+     // If we aren't leaving the scope due to a non-local jump (e.g., break),
+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
+@@ -82,34 +82,34 @@ class EmitterScope : public Nestable<Emi
+ 
+     template <typename ScopeCreator>
+     MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
+     template <typename ScopeCreator>
+     MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
+     MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
+ 
+     MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
+-                                             uint32_t slotEnd);
++                                             uint32_t slotEnd) const;
+ 
+   public:
+     explicit EmitterScope(BytecodeEmitter* bce);
+ 
+     void dump(BytecodeEmitter* bce);
+ 
+     MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
+                                    Handle<LexicalScope::Data*> bindings);
+     MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
+     MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
+     MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
+     MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
+     MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
+     MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
+     MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
+     MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
+-    MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
++    MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce) const;
+ 
+     MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
+ 
+     uint32_t index() const {
+         MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?");
+         return scopeIndex_;
+     }
+ 
+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
+@@ -32,16 +32,33 @@ namespace js {
+  * SRC_COLSPAN, SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
+  *
+  * NB: the js_SrcNoteSpec array in BytecodeEmitter.cpp is indexed by this
+  * enum, so its initializers need to match the order here.
+  */
+ 
+ class SrcNote {
+   public:
++    // SRC_FOR: Source note for JSOP_NOP at the top of C-style for loop,
++    //          which is placed after init expression/declaration ops.
++    class For {
++      public:
++        enum Fields {
++            // The offset of the condition expression ops from JSOP_NOP.
++            CondOffset,
++
++            // The offset of the update expression ops from JSOP_NOP.
++            UpdateOffset,
++
++            // The offset of JSOP_GOTO/JSOP_IFNE at the end of the loop from
++            // JSOP_NOP.
++            BackJumpOffset,
++            Count,
++        };
++    };
+     // SRC_TABLESWITCH: Source note for JSOP_TABLESWITCH.
+     class TableSwitch {
+       public:
+         enum Fields {
+             // The offset of the end of switch (the first non-JumpTarget op
+             // after switch) from JSOP_TABLESWITCH.
+             EndOffset,
+             Count
+@@ -101,17 +118,17 @@ class SrcNote {
+     };
+ };
+ 
+ #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",         3)  /* JSOP_NOP or JSOP_POP in for(;;) loop head. */        \
++    M(SRC_FOR,          "for",         SrcNote::For::Count) \
+     M(SRC_WHILE,        "while",       1)  /* JSOP_GOTO to for or while loop condition from before \
+                                               loop, else JSOP_NOP at top of do-while loop. */      \
+     M(SRC_FOR_IN,       "for-in",      1)  /* JSOP_GOTO to for-in loop condition from before       \
+                                               loop. */                                             \
+     M(SRC_FOR_OF,       "for-of",      1)  /* JSOP_GOTO to for-of loop condition from before       \
+                                               loop. */                                             \
+     M(SRC_CONTINUE,     "continue",    0)  /* JSOP_GOTO is a continue. */                          \
+     M(SRC_BREAK,        "break",       0)  /* JSOP_GOTO is a break. */                             \
+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
+@@ -1429,60 +1429,61 @@ ControlFlowGenerator::maybeLoop(JSOp op,
+ 
+ ControlFlowGenerator::ControlStatus
+ ControlFlowGenerator::processForLoop(JSOp op, jssrcnote* sn)
+ {
+     // Skip the NOP.
+     MOZ_ASSERT(op == JSOP_NOP);
+     pc = GetNextPc(pc);
+ 
+-    jsbytecode* condpc = pc + GetSrcNoteOffset(sn, 0);
+-    jsbytecode* updatepc = pc + GetSrcNoteOffset(sn, 1);
+-    jsbytecode* ifne = pc + GetSrcNoteOffset(sn, 2);
+-    jsbytecode* exitpc = GetNextPc(ifne);
++    jsbytecode* condpc = pc + GetSrcNoteOffset(sn, SrcNote::For::CondOffset);
++    jsbytecode* updatepc = pc + GetSrcNoteOffset(sn, SrcNote::For::UpdateOffset);
++    jsbytecode* backjumppc = pc + GetSrcNoteOffset(sn, SrcNote::For::BackJumpOffset);
++    jsbytecode* exitpc = GetNextPc(backjumppc);
+ 
+     // for loops have the following structures:
+     //
+-    //   NOP or POP
+-    //   [GOTO cond | NOP]
++    //   NOP
++    //   [GOTO cond]
+     //   LOOPHEAD
+     // body:
+     //    ; [body]
+-    // [increment:]
++    // [update:]
+     //   [FRESHENBLOCKSCOPE, if needed by a cloned block]
+-    //    ; [increment]
++    //    ; [update]
+     // [cond:]
+     //   LOOPENTRY
+-    //   GOTO body
++    //    ; [cond]
++    //   [GOTO body | IFNE body]
+     //
+-    // If there is a condition (condpc != ifne), this acts similar to a while
++    // If there is a condition (condpc != backjumppc), this acts similar to a while
+     // loop otherwise, it acts like a do-while loop.
+     //
+     // Note that currently Ion does not compile pushblockscope/popblockscope as
+     // necessary prerequisites to freshenblockscope.  So the code below doesn't
+     // and needn't consider the implications of freshenblockscope.
+     jsbytecode* bodyStart = pc;
+     jsbytecode* bodyEnd = updatepc;
+     jsbytecode* loopEntry = condpc;
+-    if (condpc != ifne) {
++    if (condpc != backjumppc) {
+         MOZ_ASSERT(JSOp(*bodyStart) == JSOP_GOTO);
+         MOZ_ASSERT(bodyStart + GetJumpOffset(bodyStart) == condpc);
+         bodyStart = GetNextPc(bodyStart);
+     } else {
+         // No loop condition, such as for(j = 0; ; j++)
+         if (op != JSOP_NOP) {
+             // If the loop starts with POP, we have to skip a NOP.
+             MOZ_ASSERT(JSOp(*bodyStart) == JSOP_NOP);
+             bodyStart = GetNextPc(bodyStart);
+         }
+         loopEntry = GetNextPc(bodyStart);
+     }
+     jsbytecode* loopHead = bodyStart;
+     MOZ_ASSERT(JSOp(*bodyStart) == JSOP_LOOPHEAD);
+-    MOZ_ASSERT(ifne + GetJumpOffset(ifne) == bodyStart);
++    MOZ_ASSERT(backjumppc + GetJumpOffset(backjumppc) == bodyStart);
+     bodyStart = GetNextPc(bodyStart);
+ 
+     MOZ_ASSERT(JSOp(*loopEntry) == JSOP_LOOPENTRY);
+ 
+     CFGBlock* header = CFGBlock::New(alloc(), loopEntry);
+ 
+     CFGLoopEntry* ins = CFGLoopEntry::New(alloc(), header, 0);
+     if (LoopEntryCanIonOsr(loopEntry))
+@@ -1490,34 +1491,34 @@ ControlFlowGenerator::processForLoop(JSO
+ 
+     current->setStopIns(ins);
+     current->setStopPc(pc);
+ 
+     // If there is no condition, we immediately parse the body. Otherwise, we
+     // parse the condition.
+     jsbytecode* stopAt;
+     CFGState::State initial;
+-    if (condpc != ifne) {
++    if (condpc != backjumppc) {
+         pc = condpc;
+-        stopAt = ifne;
++        stopAt = backjumppc;
+         initial = CFGState::FOR_LOOP_COND;
+     } else {
+         pc = bodyStart;
+         stopAt = bodyEnd;
+         initial = CFGState::FOR_LOOP_BODY;
+     }
+ 
+     if (!pushLoop(initial, stopAt, current,
+                   loopHead, pc, bodyStart, bodyEnd, exitpc, updatepc))
+     {
+         return ControlStatus::Error;
+     }
+ 
+     CFGState& state = cfgStack_.back();
+-    state.loop.condpc = (condpc != ifne) ? condpc : nullptr;
++    state.loop.condpc = (condpc != backjumppc) ? condpc : nullptr;
+     state.loop.updatepc = (updatepc != condpc) ? updatepc : nullptr;
+     if (state.loop.updatepc)
+         state.loop.updateEnd = condpc;
+ 
+     current = header;
+     if (!addBlock(current))
+         return ControlStatus::Error;
+     return ControlStatus::Jumped;
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -206,16 +206,17 @@ UNIFIED_SOURCES += [
+     'builtin/WeakSetObject.cpp',
+     'devtools/sharkctl.cpp',
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
++    'frontend/CForEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
+     'frontend/ForOfLoopControl.cpp',
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/SwitchEmitter.cpp',
+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
+@@ -2738,20 +2738,20 @@ SrcNotes(JSContext* cx, HandleScript scr
+                 return false;
+             break;
+ 
+           case SRC_NEWLINE:
+             ++lineno;
+             break;
+ 
+           case SRC_FOR:
+-            if (!sp->jsprintf(" cond %u update %u tail %u",
+-                              unsigned(GetSrcNoteOffset(sn, 0)),
+-                              unsigned(GetSrcNoteOffset(sn, 1)),
+-                              unsigned(GetSrcNoteOffset(sn, 2))))
++            if (!sp->jsprintf(" cond %u update %u backjump %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::For::CondOffset)),
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::For::UpdateOffset)),
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::For::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
+           case SRC_FOR_IN:
+           case SRC_FOR_OF:
+             if (!sp->jsprintf(" closingjump %u", unsigned(GetSrcNoteOffset(sn, 0))))

+ 667 - 0
frg/work-js/mozilla-release/patches/1456404-3-63a1.patch

@@ -0,0 +1,667 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854957 -32400
+#      Fri Aug 10 07:49:17 2018 +0900
+# Node ID b4a44d463eaaca925d705d6145f24d9f18c59a7a
+# Parent  6dbce3046bd95e61ced3487cb3d6e5bf4310983f
+Bug 1456404 - Part 3: Add ForInEmitter. 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
+@@ -22,16 +22,17 @@
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/CForEmitter.h"
+ #include "frontend/EmitterScope.h"
++#include "frontend/ForInEmitter.h"
+ #include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/SwitchEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "frontend/TryEmitter.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+@@ -4982,16 +4983,18 @@ BytecodeEmitter::emitForIn(ParseNode* fo
+     MOZ_ASSERT(forInLoop->isKind(ParseNodeKind::For));
+     MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
+     MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
+ 
+     ParseNode* forInHead = forInLoop->pn_left;
+     MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
+     MOZ_ASSERT(forInHead->isArity(PN_TERNARY));
+ 
++    ForInEmitter forIn(this, headLexicalEmitterScope);
++
+     // Annex B: Evaluate the var-initializer expression if present.
+     // |for (var i = initializer in expr) { ... }|
+     ParseNode* forInTarget = forInHead->pn_kid1;
+     if (parser->astGenerator().isDeclarationList(forInTarget)) {
+         ParseNode* decl = parser->astGenerator().singleBindingFromDeclaration(forInTarget);
+         if (decl->isKind(ParseNodeKind::Name)) {
+             if (ParseNode* initializer = decl->expr()) {
+                 MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Var),
+@@ -5009,124 +5012,48 @@ BytecodeEmitter::emitForIn(ParseNode* fo
+ 
+                 // Pop the initializer.
+                 if (!emit1(JSOP_POP))
+                     return false;
+             }
+         }
+     }
+ 
++    if (!forIn.emitIterated())                            //
++        return false;
++
+     // Evaluate the expression being iterated.
+     ParseNode* expr = forInHead->pn_kid3;
+-    if (!emitTreeInBranch(expr))                          // EXPR
++    if (!emitTree(expr))                                  // EXPR
+         return false;
+ 
+     MOZ_ASSERT(forInLoop->pn_iflags == 0);
+ 
+-    if (!emit1(JSOP_ITER))                                // ITER
+-        return false;
+-
+-    // For-in loops have both the iterator and the value on the stack. Push
+-    // undefined to balance the stack.
+-    if (!emit1(JSOP_UNDEFINED))                           // ITER ITERVAL
+-        return false;
+-
+-    LoopControl loopInfo(this, StatementKind::ForInLoop);
+-
+-    /* Annotate so IonMonkey can find the loop-closing jump. */
+-    unsigned noteIndex;
+-    if (!newSrcNote(SRC_FOR_IN, &noteIndex))
+-        return false;
+-
+-    // Jump down to the loop condition to minimize overhead (assuming at least
+-    // one iteration, just like the other loop forms).
+-    if (!loopInfo.emitEntryJump(this))                    // ITER ITERVAL
+-        return false;
+-
+-    if (!loopInfo.emitLoopHead(this, Nothing()))          // ITER ITERVAL
+-        return false;
+-
+-    // If the loop had an escaping lexical declaration, replace the current
+-    // environment with an dead zoned one to implement TDZ semantics.
+-    if (headLexicalEmitterScope) {
+-        // The environment chain only includes an environment for the for-in
+-        // loop head *if* a scope binding is captured, thereby requiring
+-        // recreation each iteration. If a lexical scope exists for the head,
+-        // it must be the innermost one. If that scope has closed-over
+-        // bindings inducing an environment, recreate the current environment.
+-        MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Let) ||
+-                   forInTarget->isKind(ParseNodeKind::Const));
+-        MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+-        MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+-
+-        if (headLexicalEmitterScope->hasEnvironment()) {
+-            if (!emit1(JSOP_RECREATELEXICALENV))          // ITER ITERVAL
+-                return false;
+-        }
+-
+-        // For uncaptured bindings, put them back in TDZ.
+-        if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
+-            return false;
+-    }
+-
+-    {
+-#ifdef DEBUG
+-        auto loopDepth = this->stackDepth;
+-#endif
+-        MOZ_ASSERT(loopDepth >= 2);
+-
+-        if (!emit1(JSOP_ITERNEXT))                        // ITER ITERVAL
+-            return false;
+-
+-        if (!emitInitializeForInOrOfTarget(forInHead))    // ITER ITERVAL
+-            return false;
+-
+-        MOZ_ASSERT(this->stackDepth == loopDepth,
+-                   "iterator and iterval must be left on the stack");
+-    }
++    MOZ_ASSERT_IF(headLexicalEmitterScope,
++                  forInTarget->isKind(ParseNodeKind::Let) ||
++                  forInTarget->isKind(ParseNodeKind::Const));
++
++    if (!forIn.emitInitialize())                          // ITER ITERVAL
++        return false;
++
++    if (!emitInitializeForInOrOfTarget(forInHead))        // ITER ITERVAL
++        return false;
++
++    if (!forIn.emitBody())                                // ITER ITERVAL
++        return false;
+ 
+     // Perform the loop body.
+     ParseNode* forBody = forInLoop->pn_right;
+     if (!emitTree(forBody))                               // ITER ITERVAL
+         return false;
+ 
+-    // Set offset for continues.
+-    loopInfo.setContinueTarget(offset());
+-
+-    // Make sure this code is attributed to the "for".
+-    if (!updateSourceCoordNotes(forInHead->pn_pos.begin))
+-        return false;
+-
+-    if (!loopInfo.emitLoopEntry(this, Nothing()))         // ITER ITERVAL
+-        return false;
+-    if (!emit1(JSOP_POP))                                 // ITER
+-        return false;
+-    if (!emit1(JSOP_MOREITER))                            // ITER NEXTITERVAL?
+-        return false;
+-    if (!emit1(JSOP_ISNOITER))                            // ITER NEXTITERVAL? ISNOITER
+-        return false;
+-
+-    if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ))           // ITER NEXTITERVAL
+-        return false;
+-
+-    // Set the srcnote offset so we can find the closing jump.
+-    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+-        return false;
+-
+-    if (!loopInfo.patchBreaksAndContinues(this))
+-        return false;
+-
+-    // Pop the enumeration value.
+-    if (!emit1(JSOP_POP))                                 // ITER
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, loopInfo.headOffset(), offset()))
+-        return false;
+-
+-    return emit1(JSOP_ENDITER);                           //
++    if (!forIn.emitEnd(Some(forInHead->pn_pos.begin)))    //
++        return false;
++
++    return true;
+ }
+ 
+ /* C-style `for (init; cond; update) ...` loop. */
+ bool
+ BytecodeEmitter::emitCStyleFor(ParseNode* pn, const EmitterScope* headLexicalEmitterScope)
+ {
+     ParseNode* forHead = pn->pn_left;
+     ParseNode* forBody = pn->pn_right;
+diff --git a/js/src/frontend/ForInEmitter.cpp b/js/src/frontend/ForInEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/ForInEmitter.cpp
+@@ -0,0 +1,170 @@
++/* -*- 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 "frontend/ForInEmitter.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/EmitterScope.h"
++#include "frontend/SourceNotes.h"
++#include "vm/Opcodes.h"
++#include "vm/Scope.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++using mozilla::Nothing;
++
++ForInEmitter::ForInEmitter(BytecodeEmitter* bce, const EmitterScope* headLexicalEmitterScope)
++  : bce_(bce),
++    headLexicalEmitterScope_(headLexicalEmitterScope)
++{}
++
++bool
++ForInEmitter::emitIterated()
++{
++    MOZ_ASSERT(state_ == State::Start);
++    tdzCacheForIteratedValue_.emplace(bce_);
++
++#ifdef DEBUG
++    state_ = State::Iterated;
++#endif
++    return true;
++}
++
++bool
++ForInEmitter::emitInitialize()
++{
++    MOZ_ASSERT(state_ == State::Iterated);
++    tdzCacheForIteratedValue_.reset();
++
++    if (!bce_->emit1(JSOP_ITER))                      // ITER
++        return false;
++
++    // For-in loops have both the iterator and the value on the stack. Push
++    // undefined to balance the stack.
++    if (!bce_->emit1(JSOP_UNDEFINED))                 // ITER ITERVAL
++        return false;
++
++    loopInfo_.emplace(bce_, StatementKind::ForInLoop);
++
++    // Annotate so IonMonkey can find the loop-closing jump.
++    if (!bce_->newSrcNote(SRC_FOR_IN, &noteIndex_))
++        return false;
++
++    // Jump down to the loop condition to minimize overhead (assuming at
++    // least one iteration, just like the other loop forms).
++    if (!loopInfo_->emitEntryJump(bce_))              // ITER ITERVAL
++        return false;
++
++    if (!loopInfo_->emitLoopHead(bce_, Nothing()))    // ITER ITERVAL
++        return false;
++
++    // If the loop had an escaping lexical declaration, reset the declaration's
++    // bindings to uninitialized to implement TDZ semantics.
++    if (headLexicalEmitterScope_) {
++        // The environment chain only includes an environment for the
++        // for-in loop head *if* a scope binding is captured, thereby
++        // requiring recreation each iteration. If a lexical scope exists
++        // for the head, it must be the innermost one. If that scope has
++        // closed-over bindings inducing an environment, recreate the
++        // current environment.
++        MOZ_ASSERT(headLexicalEmitterScope_ == bce_->innermostEmitterScope());
++        MOZ_ASSERT(headLexicalEmitterScope_->scope(bce_)->kind() == ScopeKind::Lexical);
++
++        if (headLexicalEmitterScope_->hasEnvironment()) {
++            if (!bce_->emit1(JSOP_RECREATELEXICALENV))
++                return false;                         // ITER ITERVAL
++        }
++
++        // For uncaptured bindings, put them back in TDZ.
++        if (!headLexicalEmitterScope_->deadZoneFrameSlots(bce_))
++            return false;
++    }
++
++#ifdef DEBUG
++    loopDepth_ = bce_->stackDepth;
++#endif
++    MOZ_ASSERT(loopDepth_ >= 2);
++
++    if (!bce_->emit1(JSOP_ITERNEXT))                  // ITER ITERVAL
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Initialize;
++#endif
++    return true;
++}
++
++bool
++ForInEmitter::emitBody()
++{
++    MOZ_ASSERT(state_ == State::Initialize);
++
++    MOZ_ASSERT(bce_->stackDepth == loopDepth_,
++               "iterator and iterval must be left on the stack");
++
++#ifdef DEBUG
++    state_ = State::Body;
++#endif
++    return true;
++}
++
++bool
++ForInEmitter::emitEnd(const Maybe<uint32_t>& forPos)
++{
++    MOZ_ASSERT(state_ == State::Body);
++
++    loopInfo_->setContinueTarget(bce_->offset());
++
++    if (forPos) {
++        // Make sure this code is attributed to the "for".
++        if (!bce_->updateSourceCoordNotes(*forPos))
++            return false;
++    }
++
++    if (!loopInfo_->emitLoopEntry(bce_, Nothing()))   // ITER ITERVAL
++        return false;
++    if (!bce_->emit1(JSOP_POP))                       // ITER
++        return false;
++    if (!bce_->emit1(JSOP_MOREITER))                  // ITER NEXTITERVAL?
++        return false;
++    if (!bce_->emit1(JSOP_ISNOITER))                  // ITER NEXTITERVAL? ISNOITER
++        return false;
++
++    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ))     // ITER NEXTITERVAL
++        return false;
++
++    // Set the srcnote offset so we can find the closing jump.
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::ForIn::BackJumpOffset,
++                                loopInfo_->loopEndOffsetFromEntryJump()))
++    {
++        return false;
++    }
++
++    if (!loopInfo_->patchBreaksAndContinues(bce_))
++        return false;
++
++    // Pop the enumeration value.
++    if (!bce_->emit1(JSOP_POP))                       // ITER
++        return false;
++
++    if (!bce_->tryNoteList.append(JSTRY_FOR_IN, bce_->stackDepth, loopInfo_->headOffset(),
++                                  bce_->offset()))
++    {
++        return false;
++    }
++
++    if (!bce_->emit1(JSOP_ENDITER))                   //
++        return false;
++
++    loopInfo_.reset();
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/ForInEmitter.h b/js/src/frontend/ForInEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/ForInEmitter.h
+@@ -0,0 +1,122 @@
++/* -*- 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_ForInEmitter_h
++#define frontend_ForInEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stdint.h>
++
++#include "frontend/BytecodeControlStructures.h"
++#include "frontend/TDZCheckCache.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++class EmitterScope;
++
++// Class for emitting bytecode for for-in loop.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `for (init in iterated) body`
++//     // headLexicalEmitterScope: lexical scope for init
++//     ForInEmitter forIn(this, headLexicalEmitterScope);
++//     forIn.emitIterated();
++//     emit(iterated);
++//     forIn.emitInitialize();
++//     emit(init);
++//     forIn.emitBody();
++//     emit(body);
++//     forIn.emitEnd(Some(offset_of_for));
++//
++class MOZ_STACK_CLASS ForInEmitter
++{
++    BytecodeEmitter* bce_;
++
++    // The source note index for SRC_FOR_IN.
++    unsigned noteIndex_ = 0;
++
++#ifdef DEBUG
++    // The stack depth before emitting initialize code inside loop.
++    int32_t loopDepth_;
++#endif
++
++    mozilla::Maybe<LoopControl> loopInfo_;
++
++    // The lexical scope to be freshened for each iteration.  See the comment
++    // in `emitBody` for more details.  Can be nullptr if there's no lexical
++    // scope.
++    const EmitterScope* headLexicalEmitterScope_;
++
++    // Cache for the iterated value.
++    // (The cache for the iteration body is inside `loopInfo_`)
++    //
++    // The iterated value needs its own TDZCheckCache, separated from both the
++    // enclosing block and the iteration body, in order to make the sanity check
++    // in Ion work properly.
++    // In term of the execution order, the TDZCheckCache for the iterated value
++    // dominates the one for the iteration body, that means the checks in the
++    // iteration body is dead, and we can optimize them away.  But the sanity
++    // check in Ion doesn't know it's dead.
++    // (see bug 1368360 for more context)
++    mozilla::Maybe<TDZCheckCache> tdzCacheForIteratedValue_;
++
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitIterated +----------+ emitInitialize +------------+
++    // | Start |------------->| Iterated |--------------->| Initialize |-+
++    // +-------+              +----------+                +------------+ |
++    //                                                                   |
++    //                                +----------------------------------+
++    //                                |
++    //                                | emitBody +------+ emitEnd  +-----+
++    //                                +----------| Body |--------->| End |
++    //                                           +------+          +-----+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitIterated.
++        Iterated,
++
++        // After calling emitInitialize.
++        Initialize,
++
++        // After calling emitBody.
++        Body,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  public:
++    ForInEmitter(BytecodeEmitter* bce, const EmitterScope* headLexicalEmitterScope);
++
++    // Parameters are the offset in the source code for each character below:
++    //
++    //   for ( var x in obj ) { ... }
++    //   ^
++    //   |
++    //   forPos
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitIterated();
++    MOZ_MUST_USE bool emitInitialize();
++    MOZ_MUST_USE bool emitBody();
++    MOZ_MUST_USE bool emitEnd(const mozilla::Maybe<uint32_t>& forPos);
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_ForInEmitter_h */
+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
+@@ -49,16 +49,26 @@ class SrcNote {
+             UpdateOffset,
+ 
+             // The offset of JSOP_GOTO/JSOP_IFNE at the end of the loop from
+             // JSOP_NOP.
+             BackJumpOffset,
+             Count,
+         };
+     };
++    // SRC_FOR_IN: Source note for JSOP_GOTO at the top of for-in loop,
++    //             which jumps to JSOP_LOOPENTRY.
++    class ForIn {
++      public:
++        enum Fields {
++            // The offset of JSOP_IFEQ at the end of the loop from JSOP_GOTO.
++            BackJumpOffset,
++            Count,
++        };
++    };
+     // SRC_TABLESWITCH: Source note for JSOP_TABLESWITCH.
+     class TableSwitch {
+       public:
+         enum Fields {
+             // The offset of the end of switch (the first non-JumpTarget op
+             // after switch) from JSOP_TABLESWITCH.
+             EndOffset,
+             Count
+@@ -121,18 +131,17 @@ class SrcNote {
+ #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",       1)  /* JSOP_GOTO to for or while loop condition from before \
+                                               loop, else JSOP_NOP at top of do-while loop. */      \
+-    M(SRC_FOR_IN,       "for-in",      1)  /* JSOP_GOTO to for-in loop condition from before       \
+-                                              loop. */                                             \
++    M(SRC_FOR_IN,       "for-in",      SrcNote::ForIn::Count) \
+     M(SRC_FOR_OF,       "for-of",      1)  /* JSOP_GOTO to for-of loop condition from before       \
+                                               loop. */                                             \
+     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) \
+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
+@@ -902,56 +902,60 @@ ControlFlowGenerator::processWhileOrForI
+     // while (cond) { } loops have the following structure:
+     //    GOTO cond   ; SRC_WHILE (offset to IFNE)
+     //    LOOPHEAD
+     //    ...
+     //  cond:
+     //    LOOPENTRY
+     //    ...
+     //    IFNE        ; goes to LOOPHEAD
+-    // for (x in y) { } loops are similar; the cond will be a MOREITER.
++    // for-in/for-of loops are similar;
++    // for-in has IFEQ as the back jump, and the cond will be a MOREITER.
+     MOZ_ASSERT(SN_TYPE(sn) == SRC_FOR_OF || SN_TYPE(sn) == SRC_FOR_IN || SN_TYPE(sn) == SRC_WHILE);
+-    int ifneOffset = GetSrcNoteOffset(sn, 0);
+-    jsbytecode* ifne = pc + ifneOffset;
+-    MOZ_ASSERT(ifne > pc);
++    // FIXME: Replaced in the subsequent patch.
++    static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == 0,
++                  "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
++    int backjumppcOffset = GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset);
++    jsbytecode* backjumppc = pc + backjumppcOffset;
++    MOZ_ASSERT(backjumppc > pc);
+ 
+-    // Verify that the IFNE goes back to a loophead op.
++    // Verify that the back jump goes back to a loophead op.
+     MOZ_ASSERT(JSOp(*GetNextPc(pc)) == JSOP_LOOPHEAD);
+-    MOZ_ASSERT(GetNextPc(pc) == ifne + GetJumpOffset(ifne));
++    MOZ_ASSERT(GetNextPc(pc) == backjumppc + GetJumpOffset(backjumppc));
+ 
+     jsbytecode* loopEntry = pc + GetJumpOffset(pc);
+ 
+     size_t stackPhiCount;
+     if (SN_TYPE(sn) == SRC_FOR_OF)
+         stackPhiCount = 3;
+     else if (SN_TYPE(sn) == SRC_FOR_IN)
+         stackPhiCount = 1;
+     else
+         stackPhiCount = 0;
+ 
+     // Skip past the JSOP_LOOPHEAD for the body start.
+     jsbytecode* loopHead = GetNextPc(pc);
+     jsbytecode* bodyStart = GetNextPc(loopHead);
+     jsbytecode* bodyEnd = pc + GetJumpOffset(pc);
+-    jsbytecode* exitpc = GetNextPc(ifne);
++    jsbytecode* exitpc = GetNextPc(backjumppc);
+     jsbytecode* continuepc = pc;
+ 
+     CFGBlock* header = CFGBlock::New(alloc(), loopEntry);
+ 
+     CFGLoopEntry* ins = CFGLoopEntry::New(alloc(), header, stackPhiCount);
+     if (LoopEntryCanIonOsr(loopEntry))
+         ins->setCanOsr();
+ 
+     if (SN_TYPE(sn) == SRC_FOR_IN)
+         ins->setIsForIn();
+ 
+     current->setStopIns(ins);
+     current->setStopPc(pc);
+ 
+-    if (!pushLoop(CFGState::WHILE_LOOP_COND, ifne, current,
++    if (!pushLoop(CFGState::WHILE_LOOP_COND, backjumppc, current,
+                   loopHead, bodyEnd, bodyStart, bodyEnd, exitpc, continuepc))
+     {
+         return ControlStatus::Error;
+     }
+ 
+     // Parse the condition first.
+     current = header;
+     pc = header->startPc();
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -209,16 +209,17 @@ UNIFIED_SOURCES += [
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/CForEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
++    'frontend/ForInEmitter.cpp',
+     'frontend/ForOfLoopControl.cpp',
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/SwitchEmitter.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+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
+@@ -2749,18 +2749,24 @@ SrcNotes(JSContext* cx, HandleScript scr
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::For::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
+           case SRC_FOR_IN:
+           case SRC_FOR_OF:
+-            if (!sp->jsprintf(" closingjump %u", unsigned(GetSrcNoteOffset(sn, 0))))
++            // FIXME: replaced in the subsequent patch.
++            static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == 0,
++                          "SrcNote::{ForIn,ForOf}::BackJumpOffset should be same");
++            if (!sp->jsprintf(" backjump %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset))))
++            {
+                 return false;
++            }
+             break;
+ 
+           case SRC_WHILE:
+             if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                 return false;
+             break;
+ 
+           case SRC_NEXTCASE:

+ 940 - 0
frg/work-js/mozilla-release/patches/1456404-4-63a1.patch

@@ -0,0 +1,940 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854958 -32400
+#      Fri Aug 10 07:49:18 2018 +0900
+# Node ID b355131844eaba786b4c86479e17f48a96ead435
+# Parent  b4a44d463eaaca925d705d6145f24d9f18c59a7a
+Bug 1456404 - Part 4: Add ForOfEmitter. 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
+@@ -23,16 +23,17 @@
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/CForEmitter.h"
+ #include "frontend/EmitterScope.h"
+ #include "frontend/ForInEmitter.h"
++#include "frontend/ForOfEmitter.h"
+ #include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/SwitchEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "frontend/TryEmitter.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+@@ -385,21 +386,29 @@ BytecodeEmitter::emitJumpTargetAndPatch(
+     JumpTarget target;
+     if (!emitJumpTarget(&target))
+         return false;
+     patchJumpsToTarget(jump, target);
+     return true;
+ }
+ 
+ bool
++BytecodeEmitter::emitCall(JSOp op, uint16_t argc, const Maybe<uint32_t>& sourceCoordOffset)
++{
++    if (sourceCoordOffset.isSome()) {
++        if (!updateSourceCoordNotes(*sourceCoordOffset))
++            return false;
++    }
++    return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
++}
++
++bool
+ BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn)
+ {
+-    if (pn && !updateSourceCoordNotes(pn->pn_pos.begin))
+-        return false;
+-    return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
++    return emitCall(op, argc, pn ? Some(pn->pn_pos.begin) : Nothing());
+ }
+ 
+ bool
+ BytecodeEmitter::emitDupAt(unsigned slotFromTop)
+ {
+     MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
+ 
+     if (slotFromTop == 0)
+@@ -2834,26 +2843,27 @@ BytecodeEmitter::emitSetOrInitializeDest
+         if (!emit1(JSOP_POP))
+             return false;
+     }
+ 
+     return true;
+ }
+ 
+ bool
+-BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
++BytecodeEmitter::emitIteratorNext(const Maybe<uint32_t>& callSourceCoordOffset,
++                                  IteratorKind iterKind /* = IteratorKind::Sync */,
+                                   bool allowSelfHosted /* = false */)
+ {
+     MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
+                ".next() iteration is prohibited in self-hosted code because it "
+                "can run user-modifiable iteration code");
+ 
+     MOZ_ASSERT(this->stackDepth >= 2);                    // ... NEXT ITER
+ 
+-    if (!emitCall(JSOP_CALL, 0, pn))                      // ... RESULT
++    if (!emitCall(JSOP_CALL, 0, callSourceCoordOffset))   // ... RESULT
+         return false;
+ 
+     if (iterKind == IteratorKind::Async) {
+         if (!emitAwaitInInnermostScope())                 // ... RESULT
+             return false;
+     }
+ 
+     if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
+@@ -3376,17 +3386,17 @@ BytecodeEmitter::emitDestructuringOpsArr
+             if (!ifAlreadyDone.emitElse())                        // ... OBJ NEXT ITER *LREF
+                 return false;
+         }
+ 
+         if (!emitDupAt(emitted + 1))                              // ... OBJ NEXT ITER *LREF NEXT
+             return false;
+         if (!emitDupAt(emitted + 1))                              // ... OBJ NEXT ITER *LREF NEXT ITER
+             return false;
+-        if (!emitIteratorNext(pattern))                           // ... OBJ NEXT ITER *LREF RESULT
++        if (!emitIteratorNext(Some(pattern->pn_pos.begin)))       // ... OBJ NEXT ITER *LREF RESULT
+             return false;
+         if (!emit1(JSOP_DUP))                                     // ... OBJ NEXT ITER *LREF RESULT RESULT
+             return false;
+         if (!emitAtomOp(cx->names().done, JSOP_GETPROP))          // ... OBJ NEXT ITER *LREF RESULT DONE
+             return false;
+ 
+         if (!emit1(JSOP_DUP))                                     // ... OBJ NEXT ITER *LREF RESULT DONE DONE
+             return false;
+@@ -4684,32 +4694,35 @@ BytecodeEmitter::emitSpread(bool allowSe
+         // COME FROM the beginning of the loop to here.
+         if (!loopInfo.emitLoopEntry(this, Nothing()))     // NEXT ITER ARR I
+             return false;
+ 
+         if (!emitDupAt(3))                                // NEXT ITER ARR I NEXT
+             return false;
+         if (!emitDupAt(3))                                // NEXT ITER ARR I NEXT ITER
+             return false;
+-        if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted))  // ITER ARR I RESULT
+-            return false;
++        if (!emitIteratorNext(Nothing(), IteratorKind::Sync, allowSelfHosted))
++            return false;                                 // ITER ARR I RESULT
+         if (!emit1(JSOP_DUP))                             // NEXT ITER ARR I RESULT RESULT
+             return false;
+         if (!emitAtomOp(cx->names().done, JSOP_GETPROP))  // NEXT ITER ARR I RESULT DONE
+             return false;
+ 
+         if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ))       // NEXT ITER ARR I RESULT
+             return false;
+ 
+         MOZ_ASSERT(this->stackDepth == loopDepth);
+     }
+ 
+     // Let Ion know where the closing jump of this loop is.
+-1    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+-        return false;
++    if (!setSrcNoteOffset(noteIndex, SrcNote::ForOf::BackJumpOffset,
++                          loopInfo.loopEndOffsetFromEntryJump()))
++    {
++        return false;
++    }
+ 
+     // No breaks or continues should occur in spreads.
+     MOZ_ASSERT(loopInfo.breaks.offset == -1);
+     MOZ_ASSERT(loopInfo.continues.offset == -1);
+ 
+     if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
+                             loopInfo.breakTargetOffset()))
+     {
+@@ -4810,176 +4823,48 @@ BytecodeEmitter::emitForOf(ParseNode* fo
+     bool allowSelfHostedIter = false;
+     if (emitterMode == BytecodeEmitter::SelfHosting &&
+         forHeadExpr->isKind(ParseNodeKind::Call) &&
+         forHeadExpr->pn_head->name() == cx->names().allowContentIter)
+     {
+         allowSelfHostedIter = true;
+     }
+ 
+-    // Evaluate the expression being iterated. The forHeadExpr should use a
+-    // distinct TDZCheckCache to evaluate since (abstractly) it runs in its own
+-    // LexicalEnvironment.
+-    if (!emitTreeInBranch(forHeadExpr))                   // ITERABLE
+-        return false;
+-    if (iterKind == IteratorKind::Async) {
+-        if (!emitAsyncIterator())                         // NEXT ITER
+-            return false;
+-    } else {
+-        if (!emitIterator())                              // NEXT ITER
+-            return false;
+-    }
+-
+-    int32_t iterDepth = stackDepth;
+-
+-    // For-of loops have the iterator next method, the iterator itself, and
+-    // the result.value on the stack.
+-    // Push an undefined to balance the stack.
+-    if (!emit1(JSOP_UNDEFINED))                           // NEXT ITER UNDEF
+-        return false;
+-
+-    ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
+-
+-    // Annotate so IonMonkey can find the loop-closing jump.
+-    unsigned noteIndex;
+-    if (!newSrcNote(SRC_FOR_OF, &noteIndex))
+-        return false;
+-
+-    if (!loopInfo.emitEntryJump(this))                    // NEXT ITER UNDEF
+-        return false;
+-
+-    if (!loopInfo.emitLoopHead(this, Nothing()))          // NEXT ITER UNDEF
+-        return false;
+-
+-    // If the loop had an escaping lexical declaration, replace the current
+-    // environment with an dead zoned one to implement TDZ semantics.
++    ForOfEmitter forOf(this, headLexicalEmitterScope, allowSelfHostedIter, iterKind);
++
++    if (!forOf.emitIterated())                            //
++        return false;
++
++    if (!emitTree(forHeadExpr))                           // ITERABLE
++        return false;
++
+     if (headLexicalEmitterScope) {
+-        // The environment chain only includes an environment for the for-of
+-        // loop head *if* a scope binding is captured, thereby requiring
+-        // recreation each iteration. If a lexical scope exists for the head,
+-        // it must be the innermost one. If that scope has closed-over
+-        // bindings inducing an environment, recreate the current environment.
+         DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
+         MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::Let) ||
+                    forOfTarget->isKind(ParseNodeKind::Const));
+-        MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+-        MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+-
+-        if (headLexicalEmitterScope->hasEnvironment()) {
+-            if (!emit1(JSOP_RECREATELEXICALENV))          // NEXT ITER UNDEF
+-                return false;
+-        }
+-
+-        // For uncaptured bindings, put them back in TDZ.
+-        if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
+-            return false;
+-    }
+-
+-    {
+-#ifdef DEBUG
+-        auto loopDepth = this->stackDepth;
+-#endif
+-
+-        // Make sure this code is attributed to the "for".
+-        if (!updateSourceCoordNotes(forOfHead->pn_pos.begin))
+-            return false;
+-
+-        if (!emit1(JSOP_POP))                             // NEXT ITER
+-            return false;
+-        if (!emit1(JSOP_DUP2))                            // NEXT ITER NEXT ITER
+-            return false;
+-
+-        if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter))
+-            return false;                                 // NEXT ITER RESULT
+-
+-        if (!emit1(JSOP_DUP))                             // NEXT ITER RESULT RESULT
+-            return false;
+-        if (!emitAtomOp(cx->names().done, JSOP_GETPROP))  // NEXT ITER RESULT DONE
+-            return false;
+-
+-        InternalIfEmitter ifDone(this);
+-
+-        if (!ifDone.emitThen())                           // NEXT ITER RESULT
+-            return false;
+-
+-        // Remove RESULT from the stack to release it.
+-        if (!emit1(JSOP_POP))                             // NEXT ITER
+-            return false;
+-        if (!emit1(JSOP_UNDEFINED))                       // NEXT ITER UNDEF
+-            return false;
+-
+-        // If the iteration is done, leave loop here, instead of the branch at
+-        // the end of the loop.
+-        if (!loopInfo.emitSpecialBreakForDone(this))      // NEXT ITER UNDEF
+-            return false;
+-
+-        if (!ifDone.emitEnd())                            // NEXT ITER RESULT
+-            return false;
+-
+-        // Emit code to assign result.value to the iteration variable.
+-        //
+-        // Note that ES 13.7.5.13, step 5.c says getting result.value does not
+-        // call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
+-        if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER VALUE
+-            return false;
+-
+-        if (!loopInfo.emitBeginCodeNeedingIteratorClose(this))
+-            return false;
+-
+-        if (!emitInitializeForInOrOfTarget(forOfHead))    // NEXT ITER VALUE
+-            return false;
+-
+-        MOZ_ASSERT(stackDepth == loopDepth,
+-                   "the stack must be balanced around the initializing "
+-                   "operation");
+-
+-        // Remove VALUE from the stack to release it.
+-        if (!emit1(JSOP_POP))                             // NEXT ITER
+-            return false;
+-        if (!emit1(JSOP_UNDEFINED))                       // NEXT ITER UNDEF
+-            return false;
+-
+-        // Perform the loop body.
+-        ParseNode* forBody = forOfLoop->pn_right;
+-        if (!emitTree(forBody))                           // NEXT ITER UNDEF
+-            return false;
+-
+-        MOZ_ASSERT(stackDepth == loopDepth,
+-                   "the stack must be balanced around the for-of body");
+-
+-        if (!loopInfo.emitEndCodeNeedingIteratorClose(this))
+-            return false;
+-
+-        loopInfo.setContinueTarget(offset());
+-
+-        if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(forHeadExpr)))
+-            return false;                                 // NEXT ITER UNDEF
+-
+-        if (!emit1(JSOP_FALSE))                           // NEXT ITER UNDEF FALSE
+-            return false;
+-        if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ))       // NEXT ITER UNDEF
+-            return false;
+-
+-        MOZ_ASSERT(this->stackDepth == loopDepth);
+-    }
+-
+-    // Let Ion know where the closing jump of this loop is.
+-    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+-        return false;
+-
+-    if (!loopInfo.patchBreaksAndContinues(this))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
+-                            loopInfo.breakTargetOffset()))
+-    {
+-        return false;
+-    }
+-
+-    return emitPopN(3);                                   //
++    }
++
++    if (!forOf.emitInitialize(Some(forOfHead->pn_pos.begin)))
++        return false;                                     // NEXT ITER VALUE
++
++    if (!emitInitializeForInOrOfTarget(forOfHead))        // NEXT ITER VALUE
++        return false;
++
++    if (!forOf.emitBody())                                // NEXT ITER UNDEF
++        return false;
++
++    // Perform the loop body.
++    ParseNode* forBody = forOfLoop->pn_right;
++    if (!emitTree(forBody))                               // NEXT ITER UNDEF
++        return false;
++
++    if (!forOf.emitEnd(Some(forHeadExpr->pn_pos.begin)))  //
++        return false;
++
++    return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitForIn(ParseNode* forInLoop, const EmitterScope* headLexicalEmitterScope)
+ {
+     MOZ_ASSERT(forInLoop->isKind(ParseNodeKind::For));
+     MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
+     MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
+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
+@@ -544,16 +544,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitJumpTarget(JumpTarget* target);
+     MOZ_MUST_USE bool emitJumpNoFallthrough(JSOp op, JumpList* jump);
+     MOZ_MUST_USE bool emitJump(JSOp op, JumpList* jump);
+     MOZ_MUST_USE bool emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump,
+                                        JumpTarget* fallthrough);
+     void patchJumpsToTarget(JumpList jump, JumpTarget target);
+     MOZ_MUST_USE bool emitJumpTargetAndPatch(JumpList jump);
+ 
++    MOZ_MUST_USE bool emitCall(JSOp op, uint16_t argc,
++                               const mozilla::Maybe<uint32_t>& sourceCoordOffset);
+     MOZ_MUST_USE bool emitCall(JSOp op, uint16_t argc, ParseNode* pn = nullptr);
+     MOZ_MUST_USE bool emitCallIncDec(ParseNode* incDec);
+ 
+     mozilla::Maybe<uint32_t> getOffsetForLoop(ParseNode* nextpn);
+ 
+     MOZ_MUST_USE bool emitGoto(NestableControl* target, JumpList* jumplist,
+                                SrcNoteType noteType = SRC_NULL);
+ 
+@@ -741,17 +743,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     // emitIterator expects the iterable to already be on the stack.
+     // It will replace that stack value with the corresponding iterator
+     MOZ_MUST_USE bool emitIterator();
+ 
+     MOZ_MUST_USE bool emitAsyncIterator();
+ 
+     // Pops iterator from the top of the stack. Pushes the result of |.next()|
+     // onto the stack.
+-    MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
++    MOZ_MUST_USE bool emitIteratorNext(const mozilla::Maybe<uint32_t>& callSourceCoordOffset,
++                                       IteratorKind kind = IteratorKind::Sync,
+                                        bool allowSelfHosted = false);
+     MOZ_MUST_USE bool emitIteratorCloseInScope(EmitterScope& currentScope,
+                                                IteratorKind iterKind = IteratorKind::Sync,
+                                                CompletionKind completionKind = CompletionKind::Normal,
+                                                bool allowSelfHosted = false);
+     MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
+                                                         CompletionKind completionKind = CompletionKind::Normal,
+                                                         bool allowSelfHosted = false) {
+diff --git a/js/src/frontend/ForOfEmitter.cpp b/js/src/frontend/ForOfEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/ForOfEmitter.cpp
+@@ -0,0 +1,233 @@
++/* -*- 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 "frontend/ForOfEmitter.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/EmitterScope.h"
++#include "frontend/IfEmitter.h"
++#include "frontend/SourceNotes.h"
++#include "vm/Opcodes.h"
++#include "vm/Scope.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++using mozilla::Nothing;
++
++ForOfEmitter::ForOfEmitter(BytecodeEmitter* bce, const EmitterScope* headLexicalEmitterScope,
++                           bool allowSelfHostedIter, IteratorKind iterKind)
++  : bce_(bce),
++    allowSelfHostedIter_(allowSelfHostedIter),
++    iterKind_(iterKind),
++    headLexicalEmitterScope_(headLexicalEmitterScope)
++{}
++
++bool
++ForOfEmitter::emitIterated()
++{
++    MOZ_ASSERT(state_ == State::Start);
++
++    // Evaluate the expression being iterated. The forHeadExpr should use a
++    // distinct TDZCheckCache to evaluate since (abstractly) it runs in its
++    // own LexicalEnvironment.
++    tdzCacheForIteratedValue_.emplace(bce_);
++
++#ifdef DEBUG
++    state_ = State::Iterated;
++#endif
++    return true;
++}
++
++bool
++ForOfEmitter::emitInitialize(const Maybe<uint32_t>& forPos)
++{
++    MOZ_ASSERT(state_ == State::Iterated);
++
++    tdzCacheForIteratedValue_.reset();
++
++    if (iterKind_ == IteratorKind::Async) {
++        if (!bce_->emitAsyncIterator())               // NEXT ITER
++            return false;
++    } else {
++        if (!bce_->emitIterator())                    // NEXT ITER
++            return false;
++    }
++
++    int32_t iterDepth = bce_->stackDepth;
++
++    // For-of loops have the iterator next method, the iterator itself, and
++    // the result.value on the stack.
++    // Push an undefined to balance the stack.
++    if (!bce_->emit1(JSOP_UNDEFINED))                 // NEXT ITER UNDEF
++        return false;
++
++    loopInfo_.emplace(bce_, iterDepth, allowSelfHostedIter_, iterKind_);
++
++    // Annotate so IonMonkey can find the loop-closing jump.
++    if (!bce_->newSrcNote(SRC_FOR_OF, &noteIndex_))
++        return false;
++
++    if (!loopInfo_->emitEntryJump(bce_))              // NEXT ITER UNDEF
++        return false;
++
++    if (!loopInfo_->emitLoopHead(bce_, Nothing()))    // NEXT ITER UNDEF
++        return false;
++
++    // If the loop had an escaping lexical declaration, replace the current
++    // environment with an dead zoned one to implement TDZ semantics.
++    if (headLexicalEmitterScope_) {
++        // The environment chain only includes an environment for the for-of
++        // loop head *if* a scope binding is captured, thereby requiring
++        // recreation each iteration. If a lexical scope exists for the head,
++        // it must be the innermost one. If that scope has closed-over
++        // bindings inducing an environment, recreate the current environment.
++        MOZ_ASSERT(headLexicalEmitterScope_ == bce_->innermostEmitterScope());
++        MOZ_ASSERT(headLexicalEmitterScope_->scope(bce_)->kind() == ScopeKind::Lexical);
++
++        if (headLexicalEmitterScope_->hasEnvironment()) {
++            if (!bce_->emit1(JSOP_RECREATELEXICALENV))
++                return false;                         // NEXT ITER UNDEF
++        }
++
++        // For uncaptured bindings, put them back in TDZ.
++        if (!headLexicalEmitterScope_->deadZoneFrameSlots(bce_))
++            return false;
++    }
++
++#ifdef DEBUG
++    loopDepth_ = bce_->stackDepth;
++#endif
++
++    // Make sure this code is attributed to the "for".
++    if (forPos) {
++        if (!bce_->updateSourceCoordNotes(*forPos))
++            return false;
++    }
++
++    if (!bce_->emit1(JSOP_POP))                       // NEXT ITER
++        return false;
++    if (!bce_->emit1(JSOP_DUP2))                      // NEXT ITER NEXT ITER
++        return false;
++
++    if (!bce_->emitIteratorNext(forPos, iterKind_, allowSelfHostedIter_))
++        return false;                                 // NEXT ITER RESULT
++
++    if (!bce_->emit1(JSOP_DUP))                       // NEXT ITER RESULT RESULT
++        return false;
++    if (!bce_->emitAtomOp(bce_->cx->names().done, JSOP_GETPROP))
++        return false;                                 // NEXT ITER RESULT DONE
++
++    InternalIfEmitter ifDone(bce_);
++
++    if (!ifDone.emitThen())                           // NEXT ITER RESULT
++        return false;
++
++    // Remove RESULT from the stack to release it.
++    if (!bce_->emit1(JSOP_POP))                       // NEXT ITER
++        return false;
++    if (!bce_->emit1(JSOP_UNDEFINED))                 // NEXT ITER UNDEF
++        return false;
++
++    // If the iteration is done, leave loop here, instead of the branch at
++    // the end of the loop.
++    if (!loopInfo_->emitSpecialBreakForDone(bce_))    // NEXT ITER UNDEF
++        return false;
++
++    if (!ifDone.emitEnd())                            // NEXT ITER RESULT
++        return false;
++
++    // Emit code to assign result.value to the iteration variable.
++    //
++    // Note that ES 13.7.5.13, step 5.c says getting result.value does not
++    // call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
++    if (!bce_->emitAtomOp(bce_->cx->names().value, JSOP_GETPROP))
++        return false;                                 // NEXT ITER VALUE
++
++    if (!loopInfo_->emitBeginCodeNeedingIteratorClose(bce_))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Initialize;
++#endif
++    return true;
++}
++
++bool
++ForOfEmitter::emitBody()
++{
++    MOZ_ASSERT(state_ == State::Initialize);
++
++    MOZ_ASSERT(bce_->stackDepth == loopDepth_,
++               "the stack must be balanced around the initializing "
++               "operation");
++
++    // Remove VALUE from the stack to release it.
++    if (!bce_->emit1(JSOP_POP))                       // NEXT ITER
++        return false;
++    if (!bce_->emit1(JSOP_UNDEFINED))                 // NEXT ITER UNDEF
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Body;
++#endif
++    return true;
++}
++
++bool
++ForOfEmitter::emitEnd(const Maybe<uint32_t>& iteratedPos)
++{
++    MOZ_ASSERT(state_ == State::Body);
++
++    MOZ_ASSERT(bce_->stackDepth == loopDepth_,
++               "the stack must be balanced around the for-of body");
++
++    if (!loopInfo_->emitEndCodeNeedingIteratorClose(bce_))
++        return false;
++
++    loopInfo_->setContinueTarget(bce_->offset());
++
++    // We use the iterated value's position to attribute JSOP_LOOPENTRY,
++    // which corresponds to the iteration protocol.
++    // This is a bit misleading for 2nd and later iterations and might need
++    // some fix (bug 1482003).
++    if (!loopInfo_->emitLoopEntry(bce_, iteratedPos))
++        return false;
++
++    if (!bce_->emit1(JSOP_FALSE))                     // NEXT ITER UNDEF FALSE
++        return false;
++    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ))     // NEXT ITER UNDEF
++        return false;
++
++    MOZ_ASSERT(bce_->stackDepth == loopDepth_);
++
++    // Let Ion know where the closing jump of this loop is.
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::ForOf::BackJumpOffset,
++                                loopInfo_->loopEndOffsetFromEntryJump()))
++    {
++        return false;
++    }
++
++    if (!loopInfo_->patchBreaksAndContinues(bce_))
++        return false;
++
++    if (!bce_->tryNoteList.append(JSTRY_FOR_OF, bce_->stackDepth, loopInfo_->headOffset(),
++                                  loopInfo_->breakTargetOffset()))
++    {
++        return false;
++    }
++
++    if (!bce_->emitPopN(3))                           //
++        return false;
++
++    loopInfo_.reset();
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/ForOfEmitter.h b/js/src/frontend/ForOfEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/ForOfEmitter.h
+@@ -0,0 +1,123 @@
++/* -*- 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_ForOfEmitter_h
++#define frontend_ForOfEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stdint.h>
++
++#include "frontend/ForOfLoopControl.h"
++#include "frontend/JumpList.h"
++#include "frontend/TDZCheckCache.h"
++#include "vm/Iteration.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++class EmitterScope;
++
++// Class for emitting bytecode for for-of loop.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `for (init of iterated) body`
++//     // headLexicalEmitterScope: lexical scope for init
++//     ForOfEmitter forOf(this, headLexicalEmitterScope);
++//     forOf.emitIterated();
++//     emit(iterated);
++//     forOf.emitInitialize(Some(offset_of_for));
++//     emit(init);
++//     forOf.emitBody();
++//     emit(body);
++//     forOf.emitEnd(Some(offset_of_iterated));
++//
++class MOZ_STACK_CLASS ForOfEmitter
++{
++    BytecodeEmitter* bce_;
++
++    // The source note index for SRC_FOR_OF.
++    unsigned noteIndex_ = 0;
++
++#ifdef DEBUG
++    // The stack depth before emitting IteratorNext code inside loop.
++    int32_t loopDepth_ = 0;
++#endif
++
++    bool allowSelfHostedIter_;
++    IteratorKind iterKind_;
++
++    // Jump from into JSOP_LOOPENTRY.
++    JumpList initialJump_;
++
++    mozilla::Maybe<ForOfLoopControl> loopInfo_;
++
++    // The lexical scope to be freshened for each iteration.
++    // See the comment in `emitBody` for more details.
++    const EmitterScope* headLexicalEmitterScope_;
++
++    // Cache for the iterated value.
++    // (The cache for the iteration body is inside `loopInfo_`)
++    mozilla::Maybe<TDZCheckCache> tdzCacheForIteratedValue_;
++
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitIterated +----------+ emitInitialize +------------+
++    // | Start |------------->| Iterated |--------------->| Initialize |-+
++    // +-------+              +----------+                +------------+ |
++    //                                                                   |
++    //                                +----------------------------------+
++    //                                |
++    //                                | emitBody +------+ emitEnd  +-----+
++    //                                +----------| Body |--------->| End |
++    //                                           +------+          +-----+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitIterated.
++        Iterated,
++
++        // After calling emitInitialize.
++        Initialize,
++
++        // After calling emitBody.
++        Body,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  public:
++    ForOfEmitter(BytecodeEmitter* bce, const EmitterScope* headLexicalEmitterScope,
++                 bool allowSelfHostedIter, IteratorKind iterKind);
++
++    // The offset in the source code for each character below:
++    //
++    //   for ( var x of obj ) { ... }
++    //   ^              ^
++    //   |              |
++    //   |              iteratedPos
++    //   |
++    //   forPos
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitIterated();
++    MOZ_MUST_USE bool emitInitialize(const mozilla::Maybe<uint32_t>& forPos);
++    MOZ_MUST_USE bool emitBody();
++    MOZ_MUST_USE bool emitEnd(const mozilla::Maybe<uint32_t>& iteratedPos);
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_ForOfEmitter_h */
+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,16 +59,26 @@ class SrcNote {
+     class ForIn {
+       public:
+         enum Fields {
+             // The offset of JSOP_IFEQ at the end of the loop from JSOP_GOTO.
+             BackJumpOffset,
+             Count,
+         };
+     };
++    // SRC_FOR_OF: Source note for JSOP_GOTO at the top of for-of loop,
++    //             which jumps to JSOP_LOOPENTRY.
++    class ForOf {
++      public:
++        enum Fields {
++            // The offset of JSOP_IFEQ at the end of the loop from JSOP_GOTO.
++            BackJumpOffset,
++            Count,
++        };
++    };
+     // SRC_TABLESWITCH: Source note for JSOP_TABLESWITCH.
+     class TableSwitch {
+       public:
+         enum Fields {
+             // The offset of the end of switch (the first non-JumpTarget op
+             // after switch) from JSOP_TABLESWITCH.
+             EndOffset,
+             Count
+@@ -132,18 +142,17 @@ class SrcNote {
+     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",       1)  /* JSOP_GOTO to for or while loop condition from before \
+                                               loop, else JSOP_NOP at top of do-while loop. */      \
+     M(SRC_FOR_IN,       "for-in",      SrcNote::ForIn::Count) \
+-    M(SRC_FOR_OF,       "for-of",      1)  /* JSOP_GOTO to for-of loop condition from before       \
+-                                              loop. */                                             \
++    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) \
+     M(SRC_NEXTCASE,     "nextcase",    SrcNote::NextCase::Count) \
+     M(SRC_ASSIGNOP,     "assignop",    0)  /* += or another assign-op follows. */                  \
+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
+@@ -288,17 +288,17 @@ ControlFlowGenerator::snoopControlFlow(J
+ 
+           case SRC_SWITCHBREAK:
+             return processSwitchBreak(op);
+ 
+           case SRC_WHILE:
+           case SRC_FOR_IN:
+           case SRC_FOR_OF:
+             // while (cond) { }
+-            return processWhileOrForInLoop(sn);
++            return processWhileOrForInOrForOfLoop(sn);
+ 
+           default:
+             // Hard assert for now - make an error later.
+             MOZ_CRASH("unknown goto case");
+         }
+         break;
+       }
+ 
+@@ -892,32 +892,34 @@ ControlFlowGenerator::processForUpdateEn
+         // sure we capture the right stack.
+         current->setStartPc(entry->successor()->startPc());
+         current->setStopPc(entry->successor()->startPc());
+     }
+     return finishLoop(state, state.loop.successor);
+ }
+ 
+ ControlFlowGenerator::ControlStatus
+-ControlFlowGenerator::processWhileOrForInLoop(jssrcnote* sn)
++ControlFlowGenerator::processWhileOrForInOrForOfLoop(jssrcnote* sn)
+ {
+     // while (cond) { } loops have the following structure:
+     //    GOTO cond   ; SRC_WHILE (offset to IFNE)
+     //    LOOPHEAD
+     //    ...
+     //  cond:
+     //    LOOPENTRY
+     //    ...
+     //    IFNE        ; goes to LOOPHEAD
+-    // for-in/for-of loops are similar;
+-    // for-in has IFEQ as the back jump, and the cond will be a MOREITER.
++    // for-in/for-of loops are similar; for-in/for-of have IFEQ as the back
++    // jump, and the cond of for-in will be a MOREITER.
+     MOZ_ASSERT(SN_TYPE(sn) == SRC_FOR_OF || SN_TYPE(sn) == SRC_FOR_IN || SN_TYPE(sn) == SRC_WHILE);
+     // FIXME: Replaced in the subsequent patch.
+     static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == 0,
+                   "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
++    static_assert(unsigned(SrcNote::ForOf::BackJumpOffset) == 0,
++                  "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
+     int backjumppcOffset = GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset);
+     jsbytecode* backjumppc = pc + backjumppcOffset;
+     MOZ_ASSERT(backjumppc > pc);
+ 
+     // Verify that the back jump goes back to a loophead op.
+     MOZ_ASSERT(JSOp(*GetNextPc(pc)) == JSOP_LOOPHEAD);
+     MOZ_ASSERT(GetNextPc(pc) == backjumppc + GetJumpOffset(backjumppc));
+ 
+diff --git a/js/src/jit/IonControlFlow.h b/js/src/jit/IonControlFlow.h
+--- a/js/src/jit/IonControlFlow.h
++++ b/js/src/jit/IonControlFlow.h
+@@ -849,17 +849,17 @@ class ControlFlowGenerator
+     ControlStatus processDoWhileBodyEnd(CFGState& state);
+     ControlStatus processDoWhileCondEnd(CFGState& state);
+     ControlStatus processWhileCondEnd(CFGState& state);
+     ControlStatus processWhileBodyEnd(CFGState& state);
+     ControlStatus processForLoop(JSOp op, jssrcnote* sn);
+     ControlStatus processForCondEnd(CFGState& state);
+     ControlStatus processForBodyEnd(CFGState& state);
+     ControlStatus processForUpdateEnd(CFGState& state);
+-    ControlStatus processWhileOrForInLoop(jssrcnote* sn);
++    ControlStatus processWhileOrForInOrForOfLoop(jssrcnote* sn);
+     ControlStatus processNextTableSwitchCase(CFGState& state);
+     ControlStatus processCondSwitch();
+     ControlStatus processCondSwitchCase(CFGState& state);
+     ControlStatus processCondSwitchDefault(CFGState& state);
+     ControlStatus processCondSwitchBody(CFGState& state);
+     ControlStatus processSwitchBreak(JSOp op);
+     ControlStatus processSwitchEnd(DeferredEdge* breaks, jsbytecode* exitpc);
+     ControlStatus processTry();
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -210,16 +210,17 @@ UNIFIED_SOURCES += [
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/CForEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
+     'frontend/ForInEmitter.cpp',
++    'frontend/ForOfEmitter.cpp',
+     'frontend/ForOfLoopControl.cpp',
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/SwitchEmitter.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+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
+@@ -2749,18 +2749,17 @@ SrcNotes(JSContext* cx, HandleScript scr
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::For::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
+           case SRC_FOR_IN:
+           case SRC_FOR_OF:
+-            // FIXME: replaced in the subsequent patch.
+-            static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == 0,
++            static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == unsigned(SrcNote::ForOf::BackJumpOffset),
+                           "SrcNote::{ForIn,ForOf}::BackJumpOffset should be same");
+             if (!sp->jsprintf(" backjump %u",
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 

+ 485 - 0
frg/work-js/mozilla-release/patches/1456404-5-63a1.patch

@@ -0,0 +1,485 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854958 -32400
+#      Fri Aug 10 07:49:18 2018 +0900
+# Node ID 91e18d8d1e48340f27242342f20f047389af6703
+# Parent  b355131844eaba786b4c86479e17f48a96ead435
+Bug 1456404 - Part 5: Add WhileEmitter. 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
+@@ -30,16 +30,17 @@
+ #include "frontend/ForInEmitter.h"
+ #include "frontend/ForOfEmitter.h"
+ #include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/SwitchEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "frontend/TryEmitter.h"
++#include "frontend/WhileEmitter.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ #include "vm/JSScript.h"
+ #include "vm/Stack.h"
+@@ -5370,83 +5371,30 @@ BytecodeEmitter::emitDo(ParseNode* pn)
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitWhile(ParseNode* pn)
+ {
+-    /*
+-     * Minimize bytecodes issued for one or more iterations by jumping to
+-     * the condition below the body and closing the loop if the condition
+-     * is true with a backward branch. For iteration count i:
+-     *
+-     *  i    test at the top                 test at the bottom
+-     *  =    ===============                 ==================
+-     *  0    ifeq-pass                       goto; ifne-fail
+-     *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
+-     *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
+-     *  . . .
+-     *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
+-     */
+-
+-    // If we have a single-line while, like "while (x) ;", we want to
+-    // emit the line note before the initial goto, so that the
+-    // debugger sees a single entry point.  This way, if there is a
+-    // breakpoint on the line, it will only fire once; and "next"ing
+-    // will skip the whole loop.  However, for the multi-line case we
+-    // want to emit the line note after the initial goto, so that
+-    // "cont" stops on each iteration -- but without a stop before the
+-    // first iteration.
+-    if (parser->errorReporter().lineAt(pn->pn_pos.begin) ==
+-        parser->errorReporter().lineAt(pn->pn_pos.end))
+-    {
+-        if (!updateSourceCoordNotes(pn->pn_pos.begin))
+-            return false;
+-    }
+-
+-    JumpTarget top{ -1 };
+-    if (!emitJumpTarget(&top))
+-        return false;
+-
+-    LoopControl loopInfo(this, StatementKind::WhileLoop);
+-    loopInfo.setContinueTarget(top.offset);
+-
+-    unsigned noteIndex;
+-    if (!newSrcNote(SRC_WHILE, &noteIndex))
+-        return false;
+-
+-    if (!loopInfo.emitEntryJump(this))
+-        return false;
+-
+-    if (!loopInfo.emitLoopHead(this, getOffsetForLoop(pn->pn_right)))
+-        return false;
+-
+-    if (!emitTreeInBranch(pn->pn_right))
+-        return false;
+-
+-    if (!loopInfo.emitLoopEntry(this, getOffsetForLoop(pn->pn_left)))
+-        return false;
++    WhileEmitter wh(this);
++    if (!wh.emitBody(Some(pn->pn_pos.begin), getOffsetForLoop(pn->pn_right), Some(pn->pn_pos.end)))
++        return false;
++
++    if (!emitTree(pn->pn_right))
++        return false;
++
++    if (!wh.emitCond(getOffsetForLoop(pn->pn_left)))
++        return false;
++
+     if (!emitTree(pn->pn_left))
+         return false;
+ 
+-    if (!loopInfo.emitLoopEnd(this, JSOP_IFNE))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_LOOP, stackDepth, loopInfo.headOffset(),
+-                            loopInfo.breakTargetOffset()))
+-    {
+-        return false;
+-    }
+-
+-    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.loopEndOffsetFromEntryJump()))
+-        return false;
+-
+-    if (!loopInfo.patchBreaksAndContinues(this))
++    if (!wh.emitEnd())
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitBreak(PropertyName* label)
+ {
+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
+@@ -49,16 +49,26 @@ class SrcNote {
+             UpdateOffset,
+ 
+             // The offset of JSOP_GOTO/JSOP_IFNE at the end of the loop from
+             // JSOP_NOP.
+             BackJumpOffset,
+             Count,
+         };
+     };
++    // SRC_WHILE: Source note for JSOP_GOTO at the top of while loop,
++    //            which jumps to JSOP_LOOPENTRY.
++    class While {
++      public:
++        enum Fields {
++            // The offset of JSOP_IFNE at the end of the loop from JSOP_GOTO.
++            BackJumpOffset,
++            Count,
++        };
++    };
+     // SRC_FOR_IN: Source note for JSOP_GOTO at the top of for-in loop,
+     //             which jumps to JSOP_LOOPENTRY.
+     class ForIn {
+       public:
+         enum Fields {
+             // The offset of JSOP_IFEQ at the end of the loop from JSOP_GOTO.
+             BackJumpOffset,
+             Count,
+@@ -139,18 +149,17 @@ class SrcNote {
+ };
+ 
+ #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",       1)  /* JSOP_GOTO to for or while loop condition from before \
+-                                              loop, else JSOP_NOP at top of do-while loop. */      \
++    M(SRC_WHILE,        "while",       SrcNote::While::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) \
+diff --git a/js/src/frontend/WhileEmitter.cpp b/js/src/frontend/WhileEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/WhileEmitter.cpp
+@@ -0,0 +1,126 @@
++/* -*- 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 "frontend/WhileEmitter.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/SourceNotes.h"
++#include "vm/Opcodes.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++
++WhileEmitter::WhileEmitter(BytecodeEmitter* bce)
++  : bce_(bce)
++{}
++
++bool
++WhileEmitter::emitBody(const Maybe<uint32_t>& whilePos,
++                       const Maybe<uint32_t>& bodyPos,
++                       const Maybe<uint32_t>& endPos)
++{
++    MOZ_ASSERT(state_ == State::Start);
++
++    // Minimize bytecodes issued for one or more iterations by jumping to
++    // the condition below the body and closing the loop if the condition
++    // is true with a backward branch. For iteration count i:
++    //
++    //  i    test at the top                 test at the bottom
++    //  =    ===============                 ==================
++    //  0    ifeq-pass                       goto; ifne-fail
++    //  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
++    //  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
++    //  . . .
++    //  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
++
++    // If we have a single-line while, like "while (x) ;", we want to
++    // emit the line note before the initial goto, so that the
++    // debugger sees a single entry point.  This way, if there is a
++    // breakpoint on the line, it will only fire once; and "next"ing
++    // will skip the whole loop.  However, for the multi-line case we
++    // want to emit the line note after the initial goto, so that
++    // "cont" stops on each iteration -- but without a stop before the
++    // first iteration.
++    if (whilePos && endPos &&
++        bce_->parser->errorReporter().lineAt(*whilePos) ==
++        bce_->parser->errorReporter().lineAt(*endPos))
++    {
++        if (!bce_->updateSourceCoordNotes(*whilePos))
++            return false;
++    }
++
++    JumpTarget top = { -1 };
++    if (!bce_->emitJumpTarget(&top))
++        return false;
++
++    loopInfo_.emplace(bce_, StatementKind::WhileLoop);
++    loopInfo_->setContinueTarget(top.offset);
++
++    if (!bce_->newSrcNote(SRC_WHILE, &noteIndex_))
++        return false;
++
++    if (!loopInfo_->emitEntryJump(bce_))
++        return false;
++
++    if (!loopInfo_->emitLoopHead(bce_, bodyPos))
++        return false;
++
++    tdzCacheForBody_.emplace(bce_);
++
++#ifdef DEBUG
++    state_ = State::Body;
++#endif
++    return true;
++}
++
++bool
++WhileEmitter::emitCond(const Maybe<uint32_t>& condPos)
++{
++    MOZ_ASSERT(state_ == State::Body);
++
++    tdzCacheForBody_.reset();
++
++    if (!loopInfo_->emitLoopEntry(bce_, condPos))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Cond;
++#endif
++    return true;
++}
++
++bool
++WhileEmitter::emitEnd()
++{
++    MOZ_ASSERT(state_ == State::Cond);
++
++    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFNE))
++        return false;
++
++    if (!bce_->tryNoteList.append(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
++                                  loopInfo_->breakTargetOffset()))
++    {
++        return false;
++    }
++
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::While::BackJumpOffset,
++                                loopInfo_->loopEndOffsetFromEntryJump()))
++    {
++        return false;
++    }
++
++    if (!loopInfo_->patchBreaksAndContinues(bce_))
++        return false;
++
++    loopInfo_.reset();
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/WhileEmitter.h b/js/src/frontend/WhileEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/WhileEmitter.h
+@@ -0,0 +1,99 @@
++/* -*- 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_WhileEmitter_h
++#define frontend_WhileEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stdint.h>
++
++#include "frontend/BytecodeControlStructures.h"
++#include "frontend/TDZCheckCache.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++
++// Class for emitting bytecode for while loop.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `while (cond) body`
++//     WhileEmitter wh(this);
++//     wh.emitBody(Some(offset_of_while),
++//                 Some(offset_of_body),
++//                 Some(offset_of_end));
++//     emit(body);
++//     wh.emitCond(Some(offset_of_cond));
++//     emit(cond);
++//     wh.emitEnd();
++//
++class MOZ_STACK_CLASS WhileEmitter
++{
++    BytecodeEmitter* bce_;
++
++    // The source note index for SRC_WHILE.
++    unsigned noteIndex_ = 0;
++
++    mozilla::Maybe<LoopControl> loopInfo_;
++
++    // Cache for the loop body, which is enclosed by the cache in `loopInfo_`,
++    // which is effectively for the loop condition.
++    mozilla::Maybe<TDZCheckCache> tdzCacheForBody_;
++
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitBody +------+ emitCond +------+ emitEnd  +-----+
++    // | Start |--------->| Body |--------->| Cond |--------->| End |
++    // +-------+          +------+          +------+          +-----+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitBody.
++        Body,
++
++        // After calling emitCond.
++        Cond,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  public:
++    explicit WhileEmitter(BytecodeEmitter* bce);
++
++    // Parameters are the offset in the source code for each character below:
++    //
++    //   while ( x < 20 ) { ... }
++    //   ^       ^        ^     ^
++    //   |       |        |     |
++    //   |       |        |     endPos_
++    //   |       |        |
++    //   |       |        bodyPos_
++    //   |       |
++    //   |       condPos_
++    //   |
++    //   whilePos_
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitBody(const mozilla::Maybe<uint32_t>& whilePos,
++                               const mozilla::Maybe<uint32_t>& bodyPos,
++                               const mozilla::Maybe<uint32_t>& endPos);
++    MOZ_MUST_USE bool emitCond(const mozilla::Maybe<uint32_t>& condPos);
++    MOZ_MUST_USE bool emitEnd();
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_WhileEmitter_h */
+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
+@@ -905,22 +905,21 @@ ControlFlowGenerator::processWhileOrForI
+     //    ...
+     //  cond:
+     //    LOOPENTRY
+     //    ...
+     //    IFNE        ; goes to LOOPHEAD
+     // for-in/for-of loops are similar; for-in/for-of have IFEQ as the back
+     // jump, and the cond of for-in will be a MOREITER.
+     MOZ_ASSERT(SN_TYPE(sn) == SRC_FOR_OF || SN_TYPE(sn) == SRC_FOR_IN || SN_TYPE(sn) == SRC_WHILE);
+-    // FIXME: Replaced in the subsequent patch.
+-    static_assert(unsigned(SrcNote::ForIn::BackJumpOffset) == 0,
++    static_assert(unsigned(SrcNote::While::BackJumpOffset) == unsigned(SrcNote::ForIn::BackJumpOffset),
+                   "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
+-    static_assert(unsigned(SrcNote::ForOf::BackJumpOffset) == 0,
++    static_assert(unsigned(SrcNote::While::BackJumpOffset) == unsigned(SrcNote::ForOf::BackJumpOffset),
+                   "SrcNote::{While,ForIn,ForOf}::BackJumpOffset should be same");
+-    int backjumppcOffset = GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset);
++    int backjumppcOffset = GetSrcNoteOffset(sn, SrcNote::While::BackJumpOffset);
+     jsbytecode* backjumppc = pc + backjumppcOffset;
+     MOZ_ASSERT(backjumppc > pc);
+ 
+     // Verify that the back jump goes back to a loophead op.
+     MOZ_ASSERT(JSOp(*GetNextPc(pc)) == JSOP_LOOPHEAD);
+     MOZ_ASSERT(GetNextPc(pc) == backjumppc + GetJumpOffset(backjumppc));
+ 
+     jsbytecode* loopEntry = pc + GetJumpOffset(pc);
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -220,16 +220,17 @@ UNIFIED_SOURCES += [
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/SwitchEmitter.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+     'frontend/TryEmitter.cpp',
++    'frontend/WhileEmitter.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',
+     'gc/GC.cpp',
+     'gc/GCTrace.cpp',
+     'gc/Marking.cpp',
+     'gc/Memory.cpp',
+     'gc/Nursery.cpp',
+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
+@@ -2759,18 +2759,21 @@ SrcNotes(JSContext* cx, HandleScript scr
+             if (!sp->jsprintf(" backjump %u",
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::ForIn::BackJumpOffset))))
+             {
+                 return false;
+             }
+             break;
+ 
+           case SRC_WHILE:
+-            if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0))))
++            if (!sp->jsprintf(" offset %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::While::BackJumpOffset))))
++            {
+                 return false;
++            }
+             break;
+ 
+           case SRC_NEXTCASE:
+             if (!sp->jsprintf(" next case offset %u",
+                               unsigned(GetSrcNoteOffset(sn, SrcNote::NextCase::NextCaseOffset))))
+             {
+                 return false;
+             }

+ 436 - 0
frg/work-js/mozilla-release/patches/1456404-6-63a1.patch

@@ -0,0 +1,436 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854958 -32400
+#      Fri Aug 10 07:49:18 2018 +0900
+# Node ID 61ec9ed5da1aa0a2654ea251223b561cab60073b
+# Parent  91e18d8d1e48340f27242342f20f047389af6703
+Bug 1456404 - Part 6: Add DoWhileEmitter. 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
+@@ -21,16 +21,17 @@
+ #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"
+ #include "frontend/EmitterScope.h"
+ #include "frontend/ForInEmitter.h"
+ #include "frontend/ForOfEmitter.h"
+ #include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/SwitchEmitter.h"
+ #include "frontend/TDZCheckCache.h"
+@@ -5305,74 +5306,31 @@ BytecodeEmitter::emitAsyncWrapper(unsign
+             return false;
+     }
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitDo(ParseNode* pn)
+ {
+-    // Ensure that the column of the 'do' is set properly.
+-    if (!updateSourceCoordNotes(pn->pn_pos.begin))
+-        return false;
+-
+-    /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
+-    unsigned noteIndex;
+-    if (!newSrcNote(SRC_WHILE, &noteIndex))
+-        return false;
+-    if (!emit1(JSOP_NOP))
+-        return false;
+-
+-    unsigned noteIndex2;
+-    if (!newSrcNote(SRC_WHILE, &noteIndex2))
+-        return false;
+-
+-    /* Compile the loop body. */
+-    LoopControl loopInfo(this, StatementKind::DoLoop);
+-
+-    if (!loopInfo.emitLoopHead(this, getOffsetForLoop(pn->pn_left)))
+-        return false;
+-
+-    if (!loopInfo.emitLoopEntry(this, Nothing()))
++    DoWhileEmitter doWhile(this);
++
++    if (!doWhile.emitBody(Some(pn->pn_pos.begin), getOffsetForLoop(pn->pn_left)))
+         return false;
+ 
+     if (!emitTree(pn->pn_left))
+         return false;
+ 
+-    // Set the offset for continues.
+-    if (!loopInfo.emitContinueTarget(this))
+-        return false;
+-
+-    /* Compile the loop condition, now that continues know where to go. */
++    if (!doWhile.emitCond())
++        return false;
++
+     if (!emitTree(pn->pn_right))
+         return false;
+ 
+-    if (!loopInfo.emitLoopEnd(this, JSOP_IFNE))
+-        return false;
+-
+-    if (!tryNoteList.append(JSTRY_LOOP, 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.
+-     */
+-    if (!setSrcNoteOffset(noteIndex2, 0, loopInfo.loopEndOffsetFromLoopHead()))
+-        return false;
+-    // +1 for NOP above.
+-    if (!setSrcNoteOffset(noteIndex, 0, loopInfo.continueTargetOffsetFromLoopHead() + 1))
+-        return false;
+-
+-    if (!loopInfo.patchBreaksAndContinues(this))
++    if (!doWhile.emitEnd())
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitWhile(ParseNode* pn)
+ {
+diff --git a/js/src/frontend/DoWhileEmitter.cpp b/js/src/frontend/DoWhileEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/DoWhileEmitter.cpp
+@@ -0,0 +1,112 @@
++/* -*- 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 "frontend/DoWhileEmitter.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/SourceNotes.h"
++#include "vm/Opcodes.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++using mozilla::Nothing;
++
++DoWhileEmitter::DoWhileEmitter(BytecodeEmitter* bce)
++  : bce_(bce)
++{}
++
++bool
++DoWhileEmitter::emitBody(const Maybe<uint32_t>& doPos, const Maybe<uint32_t>& bodyPos)
++{
++    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;
++    if (!bce_->emit1(JSOP_NOP))
++        return false;
++
++    if (!bce_->newSrcNote(SRC_WHILE, &noteIndex2_))
++        return false;
++
++    loopInfo_.emplace(bce_, StatementKind::DoLoop);
++
++    if (!loopInfo_->emitLoopHead(bce_, bodyPos))
++        return false;
++
++    if (!loopInfo_->emitLoopEntry(bce_, Nothing()))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Body;
++#endif
++    return true;
++}
++
++bool
++DoWhileEmitter::emitCond()
++{
++    MOZ_ASSERT(state_ == State::Body);
++
++    if (!loopInfo_->emitContinueTarget(bce_))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::Cond;
++#endif
++    return true;
++}
++
++bool
++DoWhileEmitter::emitEnd()
++{
++    MOZ_ASSERT(state_ == State::Cond);
++
++    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFNE))
++        return false;
++
++    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()))
++    {
++        return false;
++    }
++    // +1 for NOP in emitBody.
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::DoWhile1::CondOffset,
++                                loopInfo_->continueTargetOffsetFromLoopHead() + 1))
++    {
++        return false;
++    }
++
++    if (!loopInfo_->patchBreaksAndContinues(bce_))
++        return false;
++
++    loopInfo_.reset();
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/DoWhileEmitter.h b/js/src/frontend/DoWhileEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/DoWhileEmitter.h
+@@ -0,0 +1,89 @@
++/* -*- 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_DoWhileEmitter_h
++#define frontend_DoWhileEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stdint.h>
++
++#include "frontend/BytecodeControlStructures.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++
++// Class for emitting bytecode for do-while loop.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `do body while (cond);`
++//     DoWhileEmitter doWhile(this);
++//     doWhile.emitBody(Some(offset_of_do), Some(offset_of_body));
++//     emit(body);
++//     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).
++    unsigned noteIndex_ = 0;
++    unsigned noteIndex2_ = 0;
++
++    mozilla::Maybe<LoopControl> loopInfo_;
++
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitBody +------+ emitCond +------+ emitEnd  +-----+
++    // | Start |--------->| Body |--------->| Cond |--------->| End |
++    // +-------+          +------+          +------+          +-----+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitBody.
++        Body,
++
++        // After calling emitCond.
++        Cond,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_ = State::Start;
++#endif
++
++  public:
++    explicit DoWhileEmitter(BytecodeEmitter* bce);
++
++    // Parameters are the offset in the source code for each character below:
++    //
++    //   do { ... } while ( x < 20 );
++    //   ^  ^
++    //   |  |
++    //   |  bodyPos
++    //   |
++    //   doPos
++    //
++    // Can be Nothing() if not available.
++    MOZ_MUST_USE bool emitBody(const mozilla::Maybe<uint32_t>& doPos,
++                               const mozilla::Maybe<uint32_t>& bodyPos);
++    MOZ_MUST_USE bool emitCond();
++    MOZ_MUST_USE bool emitEnd();
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_DoWhileEmitter_h */
+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,16 +59,39 @@ 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 {
++      public:
++        enum Fields {
++            // The offset of the condition ops from JSOP_NOP.
++            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.
+     class ForIn {
+       public:
+         enum Fields {
+             // The offset of JSOP_IFEQ at the end of the loop from JSOP_GOTO.
+             BackJumpOffset,
+             Count,
+@@ -143,16 +166,22 @@ 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_FOR_IN,       "for-in",      SrcNote::ForIn::Count) \
+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
+@@ -1536,21 +1536,21 @@ ControlFlowGenerator::processDoWhileLoop
+     //    NOP         ; SRC_WHILE (offset to COND)
+     //    LOOPHEAD    ; SRC_WHILE (offset to IFNE)
+     //    LOOPENTRY
+     //    ...         ; body
+     //    ...
+     //    COND        ; start of condition
+     //    ...
+     //    IFNE ->     ; goes to LOOPHEAD
+-    int condition_offset = GetSrcNoteOffset(sn, 0);
++    int condition_offset = GetSrcNoteOffset(sn, SrcNote::DoWhile1::CondOffset);
+     jsbytecode* conditionpc = pc + condition_offset;
+ 
+     jssrcnote* sn2 = GetSrcNote(gsn, script, pc + 1);
+-    int offset = GetSrcNoteOffset(sn2, 0);
++    int offset = GetSrcNoteOffset(sn2, SrcNote::DoWhile2::BackJumpOffset);
+     jsbytecode* ifne = pc + offset + 1;
+     MOZ_ASSERT(ifne > pc);
+ 
+     // Verify that the IFNE goes back to a loophead op.
+     jsbytecode* loopHead = GetNextPc(pc);
+     MOZ_ASSERT(JSOp(*loopHead) == JSOP_LOOPHEAD);
+     MOZ_ASSERT(loopHead == ifne + GetJumpOffset(ifne));
+ 
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -207,16 +207,17 @@ UNIFIED_SOURCES += [
+     'devtools/sharkctl.cpp',
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/CForEmitter.cpp',
++    'frontend/DoWhileEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
+     'frontend/ForInEmitter.cpp',
+     'frontend/ForOfEmitter.cpp',
+     'frontend/ForOfLoopControl.cpp',
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',

+ 186 - 0
frg/work-js/mozilla-release/patches/1456404-7-63a1.patch

@@ -0,0 +1,186 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1533854958 -32400
+#      Fri Aug 10 07:49:18 2018 +0900
+# Node ID 65c4fa236298578b59f3d32893ff69f96793c608
+# Parent  61ec9ed5da1aa0a2654ea251223b561cab60073b
+Bug 1456404 - Part 7: Remove unused code/comment for SRC_FOR. 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
+@@ -4227,20 +4227,16 @@ BytecodeEmitter::emitCallSiteObject(Pars
+ 
+     ObjectBox* objbox2 = parser->newObjectBox(&value.toObject());
+     if (!objbox2)
+         return false;
+ 
+     return emitObjectPairOp(objbox1, objbox2, JSOP_CALLSITEOBJ);
+ }
+ 
+-/* See the SRC_FOR source note offsetBias comments later in this file. */
+-JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
+-JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
+-
+ namespace {
+ 
+ class EmitLevelManager
+ {
+     BytecodeEmitter* bce;
+   public:
+     explicit EmitLevelManager(BytecodeEmitter* bce) : bce(bce) { bce->emitLevel++; }
+     ~EmitLevelManager() { bce->emitLevel--; }
+@@ -8604,20 +8600,16 @@ void
+ CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
+ {
+     MOZ_ASSERT(length() == array.length());
+ 
+     for (unsigned i = 0; i < length(); i++)
+         array[i] = prologueLength + list[i];
+ }
+ 
+-/*
+- * We should try to get rid of offsetBias (always 0 or 1, where 1 is
+- * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR.
+- */
+ const JSSrcNoteSpec js_SrcNoteSpec[] = {
+ #define DEFINE_SRC_NOTE_SPEC(sym, name, arity) { name, arity },
+     FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_SPEC)
+ #undef DEFINE_SRC_NOTE_SPEC
+ };
+ 
+ static int
+ SrcNoteArity(jssrcnote* sn)
+diff --git a/js/src/frontend/CForEmitter.cpp b/js/src/frontend/CForEmitter.cpp
+--- a/js/src/frontend/CForEmitter.cpp
++++ b/js/src/frontend/CForEmitter.cpp
+@@ -64,17 +64,16 @@ CForEmitter::emitBody(Cond cond, const M
+         MOZ_ASSERT(headLexicalEmitterScopeForLet_->scope(bce_)->kind() == ScopeKind::Lexical);
+ 
+         if (headLexicalEmitterScopeForLet_->hasEnvironment()) {
+             if (!bce_->emit1(JSOP_FRESHENLEXICALENV))
+                 return false;
+         }
+     }
+ 
+-    // NB: the SRC_FOR note has offsetBias 1 (JSOP_NOP_LENGTH).
+     if (!bce_->newSrcNote(SRC_FOR, &noteIndex_))
+         return false;
+     if (!bce_->emit1(JSOP_NOP))
+         return false;
+ 
+     biasedTop_ = bce_->offset();
+ 
+     if (cond_ == Cond::Present) {
+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
+@@ -257,20 +257,30 @@ ControlFlowGenerator::traverseBytecode()
+         pc += CodeSpec[op].length;
+     }
+ }
+ 
+ ControlFlowGenerator::ControlStatus
+ ControlFlowGenerator::snoopControlFlow(JSOp op)
+ {
+     switch (op) {
+-      case JSOP_POP:
+       case JSOP_NOP: {
+         jssrcnote* sn = GetSrcNote(gsn, script, pc);
+-        return maybeLoop(op, sn);
++        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);
++        }
++        break;
+       }
+ 
+       case JSOP_RETURN:
+       case JSOP_RETRVAL:
+         return processReturn(op);
+ 
+       case JSOP_THROW:
+         return processThrow();
+@@ -1390,54 +1400,16 @@ ControlFlowGenerator::processAndOrEnd(CF
+ 
+     if (!addBlock(current))
+         return ControlStatus::Error;
+ 
+     return ControlStatus::Joined;
+ }
+ 
+ ControlFlowGenerator::ControlStatus
+-ControlFlowGenerator::maybeLoop(JSOp op, jssrcnote* sn)
+-{
+-    // This function looks at the opcode and source note and tries to
+-    // determine the structure of the loop. For some opcodes, like
+-    // POP/NOP which are not explicitly control flow, this source note is
+-    // optional. For opcodes with control flow, like GOTO, an unrecognized
+-    // or not-present source note is a compilation failure.
+-    switch (op) {
+-      case JSOP_POP:
+-        // for (init; ; update?) ...
+-        if (sn && SN_TYPE(sn) == SRC_FOR) {
+-            MOZ_CRASH("Not supported anymore?");
+-            return processForLoop(op, sn);
+-        }
+-        break;
+-
+-      case JSOP_NOP:
+-        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);
+-        }
+-        break;
+-
+-      default:
+-        MOZ_CRASH("unexpected opcode");
+-    }
+-
+-    return ControlStatus::None;
+-}
+-
+-ControlFlowGenerator::ControlStatus
+ ControlFlowGenerator::processForLoop(JSOp op, jssrcnote* sn)
+ {
+     // Skip the NOP.
+     MOZ_ASSERT(op == JSOP_NOP);
+     pc = GetNextPc(pc);
+ 
+     jsbytecode* condpc = pc + GetSrcNoteOffset(sn, SrcNote::For::CondOffset);
+     jsbytecode* updatepc = pc + GetSrcNoteOffset(sn, SrcNote::For::UpdateOffset);
+diff --git a/js/src/jit/IonControlFlow.h b/js/src/jit/IonControlFlow.h
+--- a/js/src/jit/IonControlFlow.h
++++ b/js/src/jit/IonControlFlow.h
+@@ -864,17 +864,16 @@ class ControlFlowGenerator
+     ControlStatus processSwitchEnd(DeferredEdge* breaks, jsbytecode* exitpc);
+     ControlStatus processTry();
+     ControlStatus processTryEnd(CFGState& state);
+     ControlStatus processThrow();
+     ControlStatus processTableSwitch(JSOp op, jssrcnote* sn);
+     ControlStatus processContinue(JSOp op);
+     ControlStatus processBreak(JSOp op, jssrcnote* sn);
+     ControlStatus processReturn(JSOp op);
+-    ControlStatus maybeLoop(JSOp op, jssrcnote* sn);
+     ControlStatus snoopControlFlow(JSOp op);
+     ControlStatus processBrokenLoop(CFGState& state);
+     ControlStatus finishLoop(CFGState& state, CFGBlock* successor);
+     ControlStatus processAndOr(JSOp op);
+     ControlStatus processAndOrEnd(CFGState& state);
+     ControlStatus processLabel();
+     ControlStatus processLabelEnd(CFGState& state);
+ 

+ 31 - 0
frg/work-js/mozilla-release/patches/1460489-0-63a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531358653 -32400
+#      Thu Jul 12 10:24:13 2018 +0900
+# Node ID 88dade249df039296591aa949ecbd122b2f20deb
+# Parent  669f084e89140b0e75d8236bcfecf97d71cb259e
+Bug 1460489 - Part 0: Include necessary headers in Nestable.h. r=jwalden
+
+diff --git a/js/src/ds/Nestable.h b/js/src/ds/Nestable.h
+--- a/js/src/ds/Nestable.h
++++ b/js/src/ds/Nestable.h
+@@ -2,16 +2,19 @@
+  * 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 ds_Nestable_h
+ #define ds_Nestable_h
+ 
++#include "mozilla/Assertions.h"
++#include "mozilla/Attributes.h"
++
+ namespace js {
+ 
+ // A base class for nestable structures.
+ template <typename Concrete>
+ class MOZ_STACK_CLASS Nestable
+ {
+     Concrete** stack_;
+     Concrete*  enclosing_;

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

@@ -0,0 +1,371 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531358653 -32400
+#      Thu Jul 12 10:24:13 2018 +0900
+# Node ID 9392aa3091188fafba39e6fd4d3781b13eac6341
+# Parent  88dade249df039296591aa949ecbd122b2f20deb
+Bug 1460489 - Part 1: Move TDZCheckCache to TDZCheckCache.{cpp.h}. 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
+@@ -20,16 +20,17 @@
+ 
+ #include "jsapi.h"
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/Parser.h"
++#include "frontend/TDZCheckCache.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ #include "vm/JSScript.h"
+ #include "vm/Stack.h"
+@@ -71,50 +72,16 @@ ParseNodeRequiresSpecialLineNumberNotes(
+     // Functions usually shouldn't have location information (bug 1431202).
+ 
+     ParseNodeKind kind = pn->getKind();
+     return kind == ParseNodeKind::While ||
+            kind == ParseNodeKind::For ||
+            kind == ParseNodeKind::Function;
+ }
+ 
+-// 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.
+-//
+-// When a scope containing lexical variables is entered, all such variables are
+-// marked as CheckTDZ.  When a lexical variable is accessed, its entry is
+-// checked.  If it's CheckTDZ, a JSOP_CHECKLEXICAL is emitted and then the
+-// entry is marked DontCheckTDZ.  If it's DontCheckTDZ, no check is emitted
+-// because a prior check would have already failed.  Finally, because
+-// evaluating a lexical variable declaration initializes it (after any
+-// initializer is evaluated), evaluating a lexical declaration marks its entry
+-// as DontCheckTDZ.
+-class BytecodeEmitter::TDZCheckCache : public Nestable<BytecodeEmitter::TDZCheckCache>
+-{
+-    PooledMapPtr<CheckTDZMap> cache_;
+-
+-    MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
+-        return cache_ || cache_.acquire(bce->cx);
+-    }
+-
+-  public:
+-    explicit TDZCheckCache(BytecodeEmitter* bce)
+-      : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
+-        cache_(bce->cx->frontendCollectionPool())
+-    { }
+-
+-    Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
+-    MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check);
+-};
+-
+ class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
+ {
+     StatementKind kind_;
+ 
+     // The innermost scope when this was pushed.
+     EmitterScope* emitterScope_;
+ 
+   protected:
+@@ -228,17 +195,17 @@ class LabelControl : public BreakableCon
+         return startOffset_;
+     }
+ };
+ 
+ class LoopControl : public BreakableControl
+ {
+     // Loops' children are emitted in dominance order, so they can always
+     // have a TDZCheckCache.
+-    BytecodeEmitter::TDZCheckCache tdzCache_;
++    TDZCheckCache tdzCache_;
+ 
+     // Stack depth when this loop was pushed on the control stack.
+     int32_t stackDepth_;
+ 
+     // The loop nesting depth. Used as a hint to Ion.
+     uint32_t loopDepth_;
+ 
+     // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
+@@ -1460,65 +1427,16 @@ BytecodeEmitter::EmitterScope::leave(Byt
+             uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
+             bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
+         }
+     }
+ 
+     return true;
+ }
+ 
+-Maybe<MaybeCheckTDZ>
+-BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
+-{
+-    if (!ensureCache(bce))
+-        return Nothing();
+-
+-    CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
+-    if (p)
+-        return Some(p->value().wrapped);
+-
+-    MaybeCheckTDZ rv = CheckTDZ;
+-    for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
+-        if (it->cache_) {
+-            if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
+-                rv = p2->value();
+-                break;
+-            }
+-        }
+-    }
+-
+-    if (!cache_->add(p, name, rv)) {
+-        ReportOutOfMemory(bce->cx);
+-        return Nothing();
+-    }
+-
+-    return Some(rv);
+-}
+-
+-bool
+-BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
+-                                             MaybeCheckTDZ check)
+-{
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
+-    if (p) {
+-        MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.");
+-        p->value() = check;
+-    } else {
+-        if (!cache_->add(p, name, check)) {
+-            ReportOutOfMemory(bce->cx);
+-            return false;
+-        }
+-    }
+-
+-    return true;
+-}
+-
+ // Class for emitting bytecode for blocks like try-catch-finally.
+ //
+ // Usage: (check for the return value is omitted for simplicity)
+ //
+ //   `try { try_block } catch (ex) { catch_block }`
+ //     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
+ //                         TryEmitter::ControlKind::Syntactic);
+ //     tryCatch.emitTry();
+@@ -2009,18 +1927,16 @@ class MOZ_STACK_CLASS IfEmitter
+         MayContainLexicalAccessInBranch,
+ 
+         // For internally used branches which don't touch lexical variables
+         // inside then-clause, else-clause, nor else-if condition.
+         NoLexicalAccessInBranch
+     };
+ 
+   private:
+-    using TDZCheckCache = BytecodeEmitter::TDZCheckCache;
+-
+     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_;
+ 
+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
+@@ -170,19 +170,20 @@ enum class ValueUsage {
+     WantValue,
+ 
+     // Pass this when emitting an expression if the expression's value is
+     // definitely unused by later instructions. You must make sure the next
+     // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar.
+     IgnoreValue
+ };
+ 
++class TDZCheckCache;
++
+ struct MOZ_STACK_CLASS BytecodeEmitter
+ {
+-    class TDZCheckCache;
+     class NestableControl;
+     class EmitterScope;
+ 
+     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
+ 
+     JSContext* const cx;
+ 
+     BytecodeEmitter* const parent;  /* enclosing function or global context */
+diff --git a/js/src/frontend/TDZCheckCache.cpp b/js/src/frontend/TDZCheckCache.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/TDZCheckCache.cpp
+@@ -0,0 +1,76 @@
++/* -*- 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 "frontend/TDZCheckCache.h"
++
++#include "frontend/BytecodeEmitter.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++using mozilla::Nothing;
++using mozilla::Some;
++
++TDZCheckCache::TDZCheckCache(BytecodeEmitter* bce)
++  : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
++    cache_(bce->cx->frontendCollectionPool())
++{}
++
++bool
++TDZCheckCache::ensureCache(BytecodeEmitter* bce)
++{
++    return cache_ || cache_.acquire(bce->cx);
++}
++
++Maybe<MaybeCheckTDZ>
++TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
++{
++    if (!ensureCache(bce))
++        return Nothing();
++
++    CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
++    if (p)
++        return Some(p->value().wrapped);
++
++    MaybeCheckTDZ rv = CheckTDZ;
++    for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
++        if (it->cache_) {
++            if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
++                rv = p2->value();
++                break;
++            }
++        }
++    }
++
++    if (!cache_->add(p, name, rv)) {
++        ReportOutOfMemory(bce->cx);
++        return Nothing();
++    }
++
++    return Some(rv);
++}
++
++bool
++TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
++                            MaybeCheckTDZ check)
++{
++    if (!ensureCache(bce))
++        return false;
++
++    CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
++    if (p) {
++        MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.");
++        p->value() = check;
++    } else {
++        if (!cache_->add(p, name, check)) {
++            ReportOutOfMemory(bce->cx);
++            return false;
++        }
++    }
++
++    return true;
++}
+diff --git a/js/src/frontend/TDZCheckCache.h b/js/src/frontend/TDZCheckCache.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/TDZCheckCache.h
+@@ -0,0 +1,55 @@
++/* -*- 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_TDZCheckCache_h
++#define frontend_TDZCheckCache_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include "ds/Nestable.h"
++#include "frontend/NameCollections.h"
++#include "js/TypeDecls.h"
++#include "vm/Stack.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++
++// 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.
++//
++// When a scope containing lexical variables is entered, all such variables are
++// marked as CheckTDZ.  When a lexical variable is accessed, its entry is
++// checked.  If it's CheckTDZ, a JSOP_CHECKLEXICAL is emitted and then the
++// entry is marked DontCheckTDZ.  If it's DontCheckTDZ, no check is emitted
++// because a prior check would have already failed.  Finally, because
++// evaluating a lexical variable declaration initializes it (after any
++// initializer is evaluated), evaluating a lexical declaration marks its entry
++// as DontCheckTDZ.
++class TDZCheckCache : public Nestable<TDZCheckCache>
++{
++    PooledMapPtr<CheckTDZMap> cache_;
++
++    MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce);
++
++  public:
++    explicit TDZCheckCache(BytecodeEmitter* bce);
++
++    mozilla::Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
++    MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check);
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_TDZCheckCache_h */
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -209,16 +209,17 @@ UNIFIED_SOURCES += [
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/FoldConstants.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
++    'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',
+     'gc/GC.cpp',
+     'gc/GCTrace.cpp',
+     'gc/Marking.cpp',
+     'gc/Memory.cpp',

+ 2508 - 0
frg/work-js/mozilla-release/patches/1460489-2-63a1.patch

@@ -0,0 +1,2508 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531358653 -32400
+#      Thu Jul 12 10:24:13 2018 +0900
+# Node ID 73895cf7ece580c7acb74830d2afae111e652110
+# Parent  9392aa3091188fafba39e6fd4d3781b13eac6341
+Bug 1460489 - Part 2: Move EmitterScope to EmitterScope.{cpp.h}. 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
+@@ -19,16 +19,17 @@
+ #include <string.h>
+ 
+ #include "jsapi.h"
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
++#include "frontend/EmitterScope.h"
+ #include "frontend/Parser.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+@@ -308,1135 +309,16 @@ class TryFinallyControl : public Bytecod
+         emittingSubroutine_ = true;
+     }
+ 
+     bool emittingSubroutine() const {
+         return emittingSubroutine_;
+     }
+ };
+ 
+-static inline void
+-MarkAllBindingsClosedOver(LexicalScope::Data& data)
+-{
+-    TrailingNamesArray& names = data.trailingNames;
+-    for (uint32_t i = 0; i < data.length; i++)
+-        names[i] = BindingName(names[i].name(), true);
+-}
+-
+-// A scope that introduces bindings.
+-class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::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
+-    // current scope.
+-    PooledMapPtr<NameLocationMap> nameCache_;
+-
+-    // If this scope's cache does not include free names, such as the
+-    // global scope, the NameLocation to return.
+-    Maybe<NameLocation> fallbackFreeNameLocation_;
+-
+-    // True if there is a corresponding EnvironmentObject on the environment
+-    // chain, false if all bindings are stored in frame slots on the stack.
+-    bool hasEnvironment_;
+-
+-    // The number of enclosing environments. Used for error checking.
+-    uint8_t environmentChainLength_;
+-
+-    // The next usable slot on the frame for not-closed over bindings.
+-    //
+-    // The initial frame slot when assigning slots to bindings is the
+-    // enclosing scope's nextFrameSlot. For the first scope in a frame,
+-    // the initial frame slot is 0.
+-    uint32_t nextFrameSlot_;
+-
+-    // The index in the BytecodeEmitter's interned scope vector, otherwise
+-    // ScopeNote::NoScopeIndex.
+-    uint32_t scopeIndex_;
+-
+-    // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
+-    // block scope note list. Otherwise ScopeNote::NoScopeNote.
+-    uint32_t noteIndex_;
+-
+-    MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
+-        return nameCache_.acquire(bce->cx);
+-    }
+-
+-    template <typename BindingIter>
+-    MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi) {
+-        if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
+-            bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
+-        {
+-            bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
+-            return false;
+-        }
+-        return true;
+-    }
+-
+-    MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
+-        uint32_t hops;
+-        if (EmitterScope* emitterScope = enclosing(&bce))
+-            hops = emitterScope->environmentChainLength_;
+-        else
+-            hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
+-
+-        if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
+-            bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
+-            return false;
+-        }
+-
+-        environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
+-        return true;
+-    }
+-
+-    void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
+-        nextFrameSlot_ = bi.nextFrameSlot();
+-        if (nextFrameSlot_ > bce->maxFixedSlots)
+-            bce->maxFixedSlots = nextFrameSlot_;
+-        MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
+-                      (bce->sc->asFunctionBox()->isGenerator() ||
+-                       bce->sc->asFunctionBox()->isAsync()),
+-                      bce->maxFixedSlots == 0);
+-    }
+-
+-    MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc) {
+-        NameLocationMap& cache = *nameCache_;
+-        NameLocationMap::AddPtr p = cache.lookupForAdd(name);
+-        MOZ_ASSERT(!p);
+-        if (!cache.add(p, name, loc)) {
+-            ReportOutOfMemory(bce->cx);
+-            return false;
+-        }
+-        return true;
+-    }
+-
+-    Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name) {
+-        if (NameLocationMap::Ptr p = nameCache_->lookup(name))
+-            return Some(p->value().wrapped);
+-        if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
+-            return fallbackFreeNameLocation_;
+-        return Nothing();
+-    }
+-
+-    friend bool BytecodeEmitter::needsImplicitThis();
+-
+-    EmitterScope* enclosing(BytecodeEmitter** bce) const {
+-        // There is an enclosing scope with access to the same frame.
+-        if (EmitterScope* inFrame = enclosingInFrame())
+-            return inFrame;
+-
+-        // We are currently compiling the enclosing script, look in the
+-        // enclosing BCE.
+-        if ((*bce)->parent) {
+-            *bce = (*bce)->parent;
+-            return (*bce)->innermostEmitterScopeNoCheck();
+-        }
+-
+-        return nullptr;
+-    }
+-
+-    Scope* enclosingScope(BytecodeEmitter* bce) const {
+-        if (EmitterScope* es = enclosing(&bce))
+-            return es->scope(bce);
+-
+-        // The enclosing script is already compiled or the current script is the
+-        // global script.
+-        return bce->sc->compilationEnclosingScope();
+-    }
+-
+-    static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
+-        // '.generator' cannot be accessed by name.
+-        return name != bce->cx->names().dotGenerator;
+-    }
+-
+-    static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops);
+-    NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
+-
+-    template <typename ScopeCreator>
+-    MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
+-    template <typename ScopeCreator>
+-    MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
+-    MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
+-
+-    MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
+-                                             uint32_t slotEnd);
+-
+-  public:
+-    explicit EmitterScope(BytecodeEmitter* bce)
+-      : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
+-        nameCache_(bce->cx->frontendCollectionPool()),
+-        hasEnvironment_(false),
+-        environmentChainLength_(0),
+-        nextFrameSlot_(0),
+-        scopeIndex_(ScopeNote::NoScopeIndex),
+-        noteIndex_(ScopeNote::NoScopeNoteIndex)
+-    { }
+-
+-    void dump(BytecodeEmitter* bce);
+-
+-    MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
+-                                   Handle<LexicalScope::Data*> bindings);
+-    MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
+-    MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
+-    MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
+-    MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
+-    MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
+-    MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
+-    MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
+-    MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
+-    MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
+-
+-    MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
+-
+-    uint32_t index() const {
+-        MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?");
+-        return scopeIndex_;
+-    }
+-
+-    uint32_t noteIndex() const {
+-        return noteIndex_;
+-    }
+-
+-    Scope* scope(const BytecodeEmitter* bce) const {
+-        return bce->scopeList.vector[index()];
+-    }
+-
+-    bool hasEnvironment() const {
+-        return hasEnvironment_;
+-    }
+-
+-    // The first frame slot used.
+-    uint32_t frameSlotStart() const {
+-        if (EmitterScope* inFrame = enclosingInFrame())
+-            return inFrame->nextFrameSlot_;
+-        return 0;
+-    }
+-
+-    // The last frame slot used + 1.
+-    uint32_t frameSlotEnd() const {
+-        return nextFrameSlot_;
+-    }
+-
+-    EmitterScope* enclosingInFrame() const {
+-        return Nestable<EmitterScope>::enclosing();
+-    }
+-
+-    NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
+-        if (Maybe<NameLocation> loc = lookupInCache(bce, name))
+-            return *loc;
+-        return searchAndCache(bce, name);
+-    }
+-
+-    Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
+-};
+-
+-void
+-BytecodeEmitter::EmitterScope::dump(BytecodeEmitter* bce)
+-{
+-    fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
+-
+-    for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
+-        const NameLocation& l = r.front().value();
+-
+-        JSAutoByteString bytes;
+-        if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
+-            return;
+-        if (l.kind() != NameLocation::Kind::Dynamic)
+-            fprintf(stdout, "  %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
+-        else
+-            fprintf(stdout, "  %s ", bytes.ptr());
+-
+-        switch (l.kind()) {
+-          case NameLocation::Kind::Dynamic:
+-            fprintf(stdout, "dynamic\n");
+-            break;
+-          case NameLocation::Kind::Global:
+-            fprintf(stdout, "global\n");
+-            break;
+-          case NameLocation::Kind::Intrinsic:
+-            fprintf(stdout, "intrinsic\n");
+-            break;
+-          case NameLocation::Kind::NamedLambdaCallee:
+-            fprintf(stdout, "named lambda callee\n");
+-            break;
+-          case NameLocation::Kind::Import:
+-            fprintf(stdout, "import\n");
+-            break;
+-          case NameLocation::Kind::ArgumentSlot:
+-            fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
+-            break;
+-          case NameLocation::Kind::FrameSlot:
+-            fprintf(stdout, "frame slot=%u\n", l.frameSlot());
+-            break;
+-          case NameLocation::Kind::EnvironmentCoordinate:
+-            fprintf(stdout, "environment hops=%u slot=%u\n",
+-                    l.environmentCoordinate().hops(), l.environmentCoordinate().slot());
+-            break;
+-          case NameLocation::Kind::DynamicAnnexBVar:
+-            fprintf(stdout, "dynamic annex b var\n");
+-            break;
+-        }
+-    }
+-
+-    fprintf(stdout, "\n");
+-}
+-
+-template <typename ScopeCreator>
+-bool
+-BytecodeEmitter::EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope)
+-{
+-    RootedScope enclosing(bce->cx, enclosingScope(bce));
+-    Scope* scope = createScope(bce->cx, enclosing);
+-    if (!scope)
+-        return false;
+-    hasEnvironment_ = scope->hasEnvironment();
+-    scopeIndex_ = bce->scopeList.length();
+-    return bce->scopeList.append(scope);
+-}
+-
+-template <typename ScopeCreator>
+-bool
+-BytecodeEmitter::EmitterScope::internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope)
+-{
+-    MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX, "There can be only one body scope");
+-    bce->bodyScopeIndex = bce->scopeList.length();
+-    return internScope(bce, createScope);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::appendScopeNote(BytecodeEmitter* bce)
+-{
+-    MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
+-               "Scope notes are not needed for body-level scopes.");
+-    noteIndex_ = bce->scopeNoteList.length();
+-    return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
+-                                     enclosingInFrame() ? enclosingInFrame()->noteIndex()
+-                                                        : ScopeNote::NoScopeNoteIndex);
+-}
+-
+-#ifdef DEBUG
+-static bool
+-NameIsOnEnvironment(Scope* scope, JSAtom* name)
+-{
+-    for (BindingIter bi(scope); bi; bi++) {
+-        // If found, the name must already be on the environment or an import,
+-        // or else there is a bug in the closed-over name analysis in the
+-        // Parser.
+-        if (bi.name() == name) {
+-            BindingLocation::Kind kind = bi.location().kind();
+-
+-            if (bi.hasArgumentSlot()) {
+-                JSScript* script = scope->as<FunctionScope>().script();
+-                if (!script->strict() && !script->functionHasParameterExprs()) {
+-                    // Check for duplicate positional formal parameters.
+-                    for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
+-                        if (bi2.name() == name)
+-                            kind = bi2.location().kind();
+-                    }
+-                }
+-            }
+-
+-            return kind == BindingLocation::Kind::Global ||
+-                   kind == BindingLocation::Kind::Environment ||
+-                   kind == BindingLocation::Kind::Import;
+-        }
+-    }
+-
+-    // If not found, assume it's on the global or dynamically accessed.
+-    return true;
+-}
+-#endif
+-
+-/* static */ NameLocation
+-BytecodeEmitter::EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops)
+-{
+-    for (ScopeIter si(scope); si; si++) {
+-        MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
+-
+-        bool hasEnv = si.hasSyntacticEnvironment();
+-
+-        switch (si.kind()) {
+-          case ScopeKind::Function:
+-            if (hasEnv) {
+-                JSScript* script = si.scope()->as<FunctionScope>().script();
+-                if (script->funHasExtensibleScope())
+-                    return NameLocation::Dynamic();
+-
+-                for (BindingIter bi(si.scope()); bi; bi++) {
+-                    if (bi.name() != name)
+-                        continue;
+-
+-                    BindingLocation bindLoc = bi.location();
+-                    if (bi.hasArgumentSlot() &&
+-                        !script->strict() &&
+-                        !script->functionHasParameterExprs())
+-                    {
+-                        // Check for duplicate positional formal parameters.
+-                        for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
+-                            if (bi2.name() == name)
+-                                bindLoc = bi2.location();
+-                        }
+-                    }
+-
+-                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
+-                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
+-                }
+-            }
+-            break;
+-
+-          case ScopeKind::FunctionBodyVar:
+-          case ScopeKind::ParameterExpressionVar:
+-          case ScopeKind::Lexical:
+-          case ScopeKind::NamedLambda:
+-          case ScopeKind::StrictNamedLambda:
+-          case ScopeKind::SimpleCatch:
+-          case ScopeKind::Catch:
+-            if (hasEnv) {
+-                for (BindingIter bi(si.scope()); bi; bi++) {
+-                    if (bi.name() != name)
+-                        continue;
+-
+-                    // The name must already have been marked as closed
+-                    // over. If this assertion is hit, there is a bug in the
+-                    // name analysis.
+-                    BindingLocation bindLoc = bi.location();
+-                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
+-                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
+-                }
+-            }
+-            break;
+-
+-          case ScopeKind::Module:
+-            if (hasEnv) {
+-                for (BindingIter bi(si.scope()); bi; bi++) {
+-                    if (bi.name() != name)
+-                        continue;
+-
+-                    BindingLocation bindLoc = bi.location();
+-
+-                    // Imports are on the environment but are indirect
+-                    // bindings and must be accessed dynamically instead of
+-                    // using an EnvironmentCoordinate.
+-                    if (bindLoc.kind() == BindingLocation::Kind::Import) {
+-                        MOZ_ASSERT(si.kind() == ScopeKind::Module);
+-                        return NameLocation::Import();
+-                    }
+-
+-                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
+-                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
+-                }
+-            }
+-            break;
+-
+-          case ScopeKind::Eval:
+-          case ScopeKind::StrictEval:
+-            // As an optimization, if the eval doesn't have its own var
+-            // environment and its immediate enclosing scope is a global
+-            // scope, all accesses are global.
+-            if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
+-                return NameLocation::Global(BindingKind::Var);
+-            return NameLocation::Dynamic();
+-
+-          case ScopeKind::Global:
+-            return NameLocation::Global(BindingKind::Var);
+-
+-          case ScopeKind::With:
+-          case ScopeKind::NonSyntactic:
+-            return NameLocation::Dynamic();
+-
+-          case ScopeKind::WasmInstance:
+-          case ScopeKind::WasmFunction:
+-            MOZ_CRASH("No direct eval inside wasm functions");
+-        }
+-
+-        if (hasEnv) {
+-            MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
+-            hops++;
+-        }
+-    }
+-
+-    MOZ_CRASH("Malformed scope chain");
+-}
+-
+-NameLocation
+-BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name)
+-{
+-    Maybe<NameLocation> loc;
+-    uint8_t hops = hasEnvironment() ? 1 : 0;
+-    DebugOnly<bool> inCurrentScript = enclosingInFrame();
+-
+-    // Start searching in the current compilation.
+-    for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
+-        loc = es->lookupInCache(bce, name);
+-        if (loc) {
+-            if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
+-                *loc = loc->addHops(hops);
+-            break;
+-        }
+-
+-        if (es->hasEnvironment())
+-            hops++;
+-
+-#ifdef DEBUG
+-        if (!es->enclosingInFrame())
+-            inCurrentScript = false;
+-#endif
+-    }
+-
+-    // If the name is not found in the current compilation, walk the Scope
+-    // chain encompassing the compilation.
+-    if (!loc) {
+-        inCurrentScript = false;
+-        loc = Some(searchInEnclosingScope(name, bce->sc->compilationEnclosingScope(), hops));
+-    }
+-
+-    // Each script has its own frame. A free name that is accessed
+-    // from an inner script must not be a frame slot access. If this
+-    // assertion is hit, it is a bug in the free name analysis in the
+-    // parser.
+-    MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
+-
+-    // It is always correct to not cache the location. Ignore OOMs to make
+-    // lookups infallible.
+-    if (!putNameInCache(bce, name, *loc))
+-        bce->cx->recoverFromOutOfMemory();
+-
+-    return *loc;
+-}
+-
+-Maybe<NameLocation>
+-BytecodeEmitter::EmitterScope::locationBoundInScope(JSAtom* name, EmitterScope* target)
+-{
+-    // The target scope must be an intra-frame enclosing scope of this
+-    // one. Count the number of extra hops to reach it.
+-    uint8_t extraHops = 0;
+-    for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
+-        if (es->hasEnvironment())
+-            extraHops++;
+-    }
+-
+-    // Caches are prepopulated with bound names. So if the name is bound in a
+-    // particular scope, it must already be in the cache. Furthermore, don't
+-    // consult the fallback location as we only care about binding names.
+-    Maybe<NameLocation> loc;
+-    if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
+-        NameLocation l = p->value().wrapped;
+-        if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
+-            loc = Some(l.addHops(extraHops));
+-        else
+-            loc = Some(l);
+-    }
+-    return loc;
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
+-                                                      uint32_t slotEnd)
+-{
+-    // Lexical bindings throw ReferenceErrors if they are used before
+-    // initialization. See ES6 8.1.1.1.6.
+-    //
+-    // For completeness, lexical bindings are initialized in ES6 by calling
+-    // InitializeBinding, after which touching the binding will no longer
+-    // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
+-    // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
+-    if (slotStart != slotEnd) {
+-        if (!bce->emit1(JSOP_UNINITIALIZED))
+-            return false;
+-        for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
+-            if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot))
+-                return false;
+-        }
+-        if (!bce->emit1(JSOP_POP))
+-            return false;
+-    }
+-
+-    return true;
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
+-{
+-    return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
+-                                            Handle<LexicalScope::Data*> bindings)
+-{
+-    MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // Marks all names as closed over if the context requires it. This
+-    // cannot be done in the Parser as we may not know if the context requires
+-    // all bindings to be closed over until after parsing is finished. For
+-    // example, legacy generators require all bindings to be closed over but
+-    // it is unknown if a function is a legacy generator until the first
+-    // 'yield' expression is parsed.
+-    //
+-    // This is not a problem with other scopes, as all other scopes with
+-    // bindings are body-level. At the time of their creation, whether or not
+-    // the context requires all bindings to be closed over is already known.
+-    if (bce->sc->allBindingsClosedOver())
+-        MarkAllBindingsClosedOver(*bindings);
+-
+-    // Resolve bindings.
+-    TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
+-    uint32_t firstFrameSlot = frameSlotStart();
+-    BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
+-    for (; bi; bi++) {
+-        if (!checkSlotLimits(bce, bi))
+-            return false;
+-
+-        NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-        if (!putNameInCache(bce, bi.name(), loc))
+-            return false;
+-
+-        if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
+-            return false;
+-    }
+-
+-    updateFrameFixedSlots(bce, bi);
+-
+-    // Create and intern the VM scope.
+-    auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
+-                                                        HandleScope enclosing)
+-    {
+-        return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
+-    };
+-    if (!internScope(bce, createScope))
+-        return false;
+-
+-    if (ScopeKindIsInBody(kind) && hasEnvironment()) {
+-        // After interning the VM scope we can get the scope index.
+-        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV))
+-            return false;
+-    }
+-
+-    // Lexical scopes need notes to be mapped from a pc.
+-    if (!appendScopeNote(bce))
+-        return false;
+-
+-    // Put frame slots in TDZ. Environment slots are poisoned during
+-    // environment creation.
+-    //
+-    // This must be done after appendScopeNote to be considered in the extent
+-    // of the scope.
+-    if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-    MOZ_ASSERT(funbox->namedLambdaBindings());
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // See comment in enterLexical about allBindingsClosedOver.
+-    if (funbox->allBindingsClosedOver())
+-        MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
+-
+-    BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, /* isNamedLambda = */ true);
+-    MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
+-
+-    // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
+-    // not a frame slot. Do not update frame slot information.
+-    NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-    if (!putNameInCache(bce, bi.name(), loc))
+-        return false;
+-
+-    bi++;
+-    MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
+-
+-    auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
+-        ScopeKind scopeKind =
+-            funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
+-        return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
+-                                    LOCALNO_LIMIT, enclosing);
+-    };
+-    if (!internScope(bce, createScope))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // Parameter expressions var scopes have no pre-set bindings and are
+-    // always extensible, as they are needed for eval.
+-    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
+-
+-    // Create and intern the VM scope.
+-    uint32_t firstFrameSlot = frameSlotStart();
+-    auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
+-        return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
+-                                /* data = */ nullptr, firstFrameSlot,
+-                                /* needsEnvironment = */ true, enclosing);
+-    };
+-    if (!internScope(bce, createScope))
+-        return false;
+-
+-    MOZ_ASSERT(hasEnvironment());
+-    if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
+-        return false;
+-
+-    // The extra var scope needs a note to be mapped from a pc.
+-    if (!appendScopeNote(bce))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    // If there are parameter expressions, there is an extra var scope.
+-    if (!funbox->hasExtraBodyVarScope())
+-        bce->setVarEmitterScope(this);
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // Resolve body-level bindings, if there are any.
+-    auto bindings = funbox->functionScopeBindings();
+-    Maybe<uint32_t> lastLexicalSlot;
+-    if (bindings) {
+-        NameLocationMap& cache = *nameCache_;
+-
+-        BindingIter bi(*bindings, funbox->hasParameterExprs);
+-        for (; bi; bi++) {
+-            if (!checkSlotLimits(bce, bi))
+-                return false;
+-
+-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-            NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
+-
+-            // The only duplicate bindings that occur are simple formal
+-            // parameters, in which case the last position counts, so update the
+-            // location.
+-            if (p) {
+-                MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
+-                MOZ_ASSERT(!funbox->hasDestructuringArgs);
+-                MOZ_ASSERT(!funbox->hasRest());
+-                p->value() = loc;
+-                continue;
+-            }
+-
+-            if (!cache.add(p, bi.name(), loc)) {
+-                ReportOutOfMemory(bce->cx);
+-                return false;
+-            }
+-        }
+-
+-        updateFrameFixedSlots(bce, bi);
+-    } else {
+-        nextFrameSlot_ = 0;
+-    }
+-
+-    // If the function's scope may be extended at runtime due to sloppy direct
+-    // eval and there is no extra var scope, any names beyond the function
+-    // scope must be accessed dynamically as we don't know if the name will
+-    // become a 'var' binding due to direct eval.
+-    if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
+-        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
+-
+-    // In case of parameter expressions, the parameters are lexical
+-    // bindings and have TDZ.
+-    if (funbox->hasParameterExprs && nextFrameSlot_) {
+-        uint32_t paramFrameSlotEnd = 0;
+-        for (BindingIter bi(*bindings, true); bi; bi++) {
+-            if (!BindingKindIsLexical(bi.kind()))
+-                break;
+-
+-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-            if (loc.kind() == NameLocation::Kind::FrameSlot) {
+-                MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
+-                paramFrameSlotEnd = loc.frameSlot() + 1;
+-            }
+-        }
+-
+-        if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd))
+-            return false;
+-    }
+-
+-    // Create and intern the VM scope.
+-    auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
+-        RootedFunction fun(cx, funbox->function());
+-        return FunctionScope::create(cx, funbox->functionScopeBindings(),
+-                                     funbox->hasParameterExprs,
+-                                     funbox->needsCallObjectRegardlessOfBindings(),
+-                                     fun, enclosing);
+-    };
+-    if (!internBodyScope(bce, createScope))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
+-{
+-    MOZ_ASSERT(funbox->hasParameterExprs);
+-    MOZ_ASSERT(funbox->extraVarScopeBindings() ||
+-               funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    // The extra var scope is never popped once it's entered. It replaces the
+-    // function scope as the var emitter scope.
+-    bce->setVarEmitterScope(this);
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // Resolve body-level bindings, if there are any.
+-    uint32_t firstFrameSlot = frameSlotStart();
+-    if (auto bindings = funbox->extraVarScopeBindings()) {
+-        BindingIter bi(*bindings, firstFrameSlot);
+-        for (; bi; bi++) {
+-            if (!checkSlotLimits(bce, bi))
+-                return false;
+-
+-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-            if (!putNameInCache(bce, bi.name(), loc))
+-                return false;
+-        }
+-
+-        updateFrameFixedSlots(bce, bi);
+-    } else {
+-        nextFrameSlot_ = firstFrameSlot;
+-    }
+-
+-    // If the extra var scope may be extended at runtime due to sloppy
+-    // direct eval, any names beyond the var scope must be accessed
+-    // dynamically as we don't know if the name will become a 'var' binding
+-    // due to direct eval.
+-    if (funbox->hasExtensibleScope())
+-        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
+-
+-    // Create and intern the VM scope.
+-    auto createScope = [funbox, firstFrameSlot](JSContext* cx, HandleScope enclosing) {
+-        return VarScope::create(cx, ScopeKind::FunctionBodyVar,
+-                                funbox->extraVarScopeBindings(), firstFrameSlot,
+-                                funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
+-                                enclosing);
+-    };
+-    if (!internScope(bce, createScope))
+-        return false;
+-
+-    if (hasEnvironment()) {
+-        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
+-            return false;
+-    }
+-
+-    // The extra var scope needs a note to be mapped from a pc.
+-    if (!appendScopeNote(bce))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-class DynamicBindingIter : public BindingIter
+-{
+-  public:
+-    explicit DynamicBindingIter(GlobalSharedContext* sc)
+-      : BindingIter(*sc->bindings)
+-    { }
+-
+-    explicit DynamicBindingIter(EvalSharedContext* sc)
+-      : BindingIter(*sc->bindings, /* strict = */ false)
+-    {
+-        MOZ_ASSERT(!sc->strict());
+-    }
+-
+-    JSOp bindingOp() const {
+-        switch (kind()) {
+-          case BindingKind::Var:
+-            return JSOP_DEFVAR;
+-          case BindingKind::Let:
+-            return JSOP_DEFLET;
+-          case BindingKind::Const:
+-            return JSOP_DEFCONST;
+-          default:
+-            MOZ_CRASH("Bad BindingKind");
+-        }
+-    }
+-};
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    bce->setVarEmitterScope(this);
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
+-        // In self-hosting, it is incorrect to consult the global scope because
+-        // self-hosted scripts are cloned into their target compartments before
+-        // they are run. Instead of Global, Intrinsic is used for all names.
+-        //
+-        // Intrinsic lookups are redirected to the special intrinsics holder
+-        // in the global object, into which any missing values are cloned
+-        // lazily upon first access.
+-        fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
+-
+-        auto createScope = [](JSContext* cx, HandleScope enclosing) {
+-            MOZ_ASSERT(!enclosing);
+-            return &cx->global()->emptyGlobalScope();
+-        };
+-        return internBodyScope(bce, createScope);
+-    }
+-
+-    // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
+-    if (globalsc->bindings) {
+-        for (DynamicBindingIter bi(globalsc); bi; bi++) {
+-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-            JSAtom* name = bi.name();
+-            if (!putNameInCache(bce, name, loc))
+-                return false;
+-
+-            // Define the name in the prologue. Do not emit DEFVAR for
+-            // functions that we'll emit DEFFUN for.
+-            if (bi.isTopLevelFunction())
+-                continue;
+-
+-            if (!bce->emitAtomOp(name, bi.bindingOp()))
+-                return false;
+-        }
+-    }
+-
+-    // Note that to save space, we don't add free names to the cache for
+-    // global scopes. They are assumed to be global vars in the syntactic
+-    // global scope, dynamic accesses under non-syntactic global scope.
+-    if (globalsc->scopeKind() == ScopeKind::Global)
+-        fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
+-    else
+-        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
+-
+-    auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
+-        MOZ_ASSERT(!enclosing);
+-        return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
+-    };
+-    return internBodyScope(bce, createScope);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    bce->setVarEmitterScope(this);
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // For simplicity, treat all free name lookups in eval scripts as dynamic.
+-    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
+-
+-    // Create the `var` scope. Note that there is also a lexical scope, created
+-    // separately in emitScript().
+-    auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
+-        ScopeKind scopeKind = evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
+-        return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
+-    };
+-    if (!internBodyScope(bce, createScope))
+-        return false;
+-
+-    if (hasEnvironment()) {
+-        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
+-            return false;
+-    } else {
+-        // Resolve binding names and emit DEFVAR prologue ops if we don't have
+-        // an environment (i.e., a sloppy eval not in a parameter expression).
+-        // Eval scripts always have their own lexical scope, but non-strict
+-        // scopes may introduce 'var' bindings to the nearest var scope.
+-        //
+-        // TODO: We may optimize strict eval bindings in the future to be on
+-        // the frame. For now, handle everything dynamically.
+-        if (!hasEnvironment() && evalsc->bindings) {
+-            for (DynamicBindingIter bi(evalsc); bi; bi++) {
+-                MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR);
+-
+-                if (bi.isTopLevelFunction())
+-                    continue;
+-
+-                if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR))
+-                    return false;
+-            }
+-        }
+-
+-        // As an optimization, if the eval does not have its own var
+-        // environment and is directly enclosed in a global scope, then all
+-        // free name lookups are global.
+-        if (scope(bce)->enclosing()->is<GlobalScope>())
+-            fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
+-    }
+-
+-    return true;
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    bce->setVarEmitterScope(this);
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // Resolve body-level bindings, if there are any.
+-    TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
+-    Maybe<uint32_t> firstLexicalFrameSlot;
+-    if (ModuleScope::Data* bindings = modulesc->bindings) {
+-        BindingIter bi(*bindings);
+-        for (; bi; bi++) {
+-            if (!checkSlotLimits(bce, bi))
+-                return false;
+-
+-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
+-            if (!putNameInCache(bce, bi.name(), loc))
+-                return false;
+-
+-            if (BindingKindIsLexical(bi.kind())) {
+-                if (loc.kind() == NameLocation::Kind::FrameSlot && !firstLexicalFrameSlot)
+-                    firstLexicalFrameSlot = Some(loc.frameSlot());
+-
+-                if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
+-                    return false;
+-            }
+-        }
+-
+-        updateFrameFixedSlots(bce, bi);
+-    } else {
+-        nextFrameSlot_ = 0;
+-    }
+-
+-    // Modules are toplevel, so any free names are global.
+-    fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
+-
+-    // Put lexical frame slots in TDZ. Environment slots are poisoned during
+-    // environment creation.
+-    if (firstLexicalFrameSlot) {
+-        if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
+-            return false;
+-    }
+-
+-    // Create and intern the VM scope.
+-    auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
+-        return ModuleScope::create(cx, modulesc->bindings, modulesc->module(), enclosing);
+-    };
+-    if (!internBodyScope(bce, createScope))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
+-{
+-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+-
+-    if (!ensureCache(bce))
+-        return false;
+-
+-    // 'with' make all accesses dynamic and unanalyzable.
+-    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
+-
+-    auto createScope = [](JSContext* cx, HandleScope enclosing) {
+-        return WithScope::create(cx, enclosing);
+-    };
+-    if (!internScope(bce, createScope))
+-        return false;
+-
+-    if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH))
+-        return false;
+-
+-    if (!appendScopeNote(bce))
+-        return false;
+-
+-    return checkEnvironmentChainLength(bce);
+-}
+-
+-bool
+-BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
+-{
+-    // If we aren't leaving the scope due to a non-local jump (e.g., break),
+-    // we must be the innermost scope.
+-    MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
+-
+-    ScopeKind kind = scope(bce)->kind();
+-    switch (kind) {
+-      case ScopeKind::Lexical:
+-      case ScopeKind::SimpleCatch:
+-      case ScopeKind::Catch:
+-        if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
+-            return false;
+-        break;
+-
+-      case ScopeKind::With:
+-        if (!bce->emit1(JSOP_LEAVEWITH))
+-            return false;
+-        break;
+-
+-      case ScopeKind::ParameterExpressionVar:
+-        MOZ_ASSERT(hasEnvironment());
+-        if (!bce->emit1(JSOP_POPVARENV))
+-            return false;
+-        break;
+-
+-      case ScopeKind::Function:
+-      case ScopeKind::FunctionBodyVar:
+-      case ScopeKind::NamedLambda:
+-      case ScopeKind::StrictNamedLambda:
+-      case ScopeKind::Eval:
+-      case ScopeKind::StrictEval:
+-      case ScopeKind::Global:
+-      case ScopeKind::NonSyntactic:
+-      case ScopeKind::Module:
+-        break;
+-
+-      case ScopeKind::WasmInstance:
+-      case ScopeKind::WasmFunction:
+-        MOZ_CRASH("No wasm function scopes in JS");
+-    }
+-
+-    // Finish up the scope if we are leaving it in LIFO fashion.
+-    if (!nonLocal) {
+-        // Popping scopes due to non-local jumps generate additional scope
+-        // notes. See NonLocalExitControl::prepareForNonLocalJump.
+-        if (ScopeKindIsInBody(kind)) {
+-            // The extra function var scope is never popped once it's pushed,
+-            // so its scope note extends until the end of any possible code.
+-            uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
+-            bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
+-        }
+-    }
+-
+-    return true;
+-}
+-
+ // Class for emitting bytecode for blocks like try-catch-finally.
+ //
+ // Usage: (check for the return value is omitted for simplicity)
+ //
+ //   `try { try_block } catch (ex) { catch_block }`
+ //     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
+ //                         TryEmitter::ControlKind::Syntactic);
+ //     tryCatch.emitTry();
+@@ -2217,18 +1099,16 @@ class MOZ_STACK_CLASS InternalIfEmitter 
+   public:
+     explicit InternalIfEmitter(BytecodeEmitter* bce)
+       : IfEmitter(bce, Kind::NoLexicalAccessInBranch)
+     {}
+ };
+ 
+ class ForOfLoopControl : public LoopControl
+ {
+-    using EmitterScope = BytecodeEmitter::EmitterScope;
+-
+     // The stack depth of the iterator.
+     int32_t iterDepth_;
+ 
+     // for-of loops, when throwing from non-iterator code (i.e. from the body
+     // or from evaluating the LHS of the loop condition), need to call
+     // IteratorClose.  This is done by enclosing non-iterator code with
+     // try-catch and call IteratorClose in `catch` block.
+     // If IteratorClose itself throws, we must not re-call IteratorClose. Since
+@@ -2977,17 +1857,17 @@ class NonLocalExitControl
+     BytecodeEmitter* bce_;
+     const uint32_t savedScopeNoteIndex_;
+     const int savedDepth_;
+     uint32_t openScopeNoteIndex_;
+     Kind kind_;
+ 
+     NonLocalExitControl(const NonLocalExitControl&) = delete;
+ 
+-    MOZ_MUST_USE bool leaveScope(BytecodeEmitter::EmitterScope* scope);
++    MOZ_MUST_USE bool leaveScope(EmitterScope* scope);
+ 
+   public:
+     NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
+       : bce_(bce),
+         savedScopeNoteIndex_(bce->scopeNoteList.length()),
+         savedDepth_(bce->stackDepth),
+         openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
+         kind_(kind)
+@@ -3002,17 +1882,17 @@ class NonLocalExitControl
+     MOZ_MUST_USE bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
+ 
+     MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
+         return prepareForNonLocalJump(nullptr);
+     }
+ };
+ 
+ bool
+-NonLocalExitControl::leaveScope(BytecodeEmitter::EmitterScope* es)
++NonLocalExitControl::leaveScope(EmitterScope* es)
+ {
+     if (!es->leave(bce_, /* nonLocal = */ true))
+         return false;
+ 
+     // As we pop each scope due to the non-local jump, emit notes that
+     // record the extent of the enclosing scope. These notes will have
+     // their ends recorded in ~NonLocalExitControl().
+     uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
+@@ -3028,17 +1908,16 @@ NonLocalExitControl::leaveScope(Bytecode
+ 
+ /*
+  * Emit additional bytecode(s) for non-local jumps.
+  */
+ bool
+ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
+ {
+     using NestableControl = BytecodeEmitter::NestableControl;
+-    using EmitterScope = BytecodeEmitter::EmitterScope;
+ 
+     EmitterScope* es = bce_->innermostEmitterScope();
+     int npops = 0;
+ 
+     AutoCheckUnstableEmitterScope cues(bce_);
+ 
+     // For 'continue', 'break', and 'return' statements, emit IteratorClose
+     // bytecode inline. 'continue' statements do not call IteratorClose for
+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
+@@ -170,22 +170,22 @@ enum class ValueUsage {
+     WantValue,
+ 
+     // Pass this when emitting an expression if the expression's value is
+     // definitely unused by later instructions. You must make sure the next
+     // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar.
+     IgnoreValue
+ };
+ 
++class EmitterScope;
+ class TDZCheckCache;
+ 
+ struct MOZ_STACK_CLASS BytecodeEmitter
+ {
+     class NestableControl;
+-    class EmitterScope;
+ 
+     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
+ 
+     JSContext* const cx;
+ 
+     BytecodeEmitter* const parent;  /* enclosing function or global context */
+ 
+     Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
+diff --git a/js/src/frontend/EmitterScope.cpp b/js/src/frontend/EmitterScope.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/EmitterScope.cpp
+@@ -0,0 +1,1060 @@
++/* -*- 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 "frontend/EmitterScope.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/TDZCheckCache.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::DebugOnly;
++using mozilla::Maybe;
++using mozilla::Nothing;
++using mozilla::Some;
++
++EmitterScope::EmitterScope(BytecodeEmitter* bce)
++  : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
++    nameCache_(bce->cx->frontendCollectionPool()),
++    hasEnvironment_(false),
++    environmentChainLength_(0),
++    nextFrameSlot_(0),
++    scopeIndex_(ScopeNote::NoScopeIndex),
++    noteIndex_(ScopeNote::NoScopeNoteIndex)
++{}
++
++static inline void
++MarkAllBindingsClosedOver(LexicalScope::Data& data)
++{
++    TrailingNamesArray& names = data.trailingNames;
++    for (uint32_t i = 0; i < data.length; i++)
++        names[i] = BindingName(names[i].name(), true);
++}
++
++bool
++EmitterScope::ensureCache(BytecodeEmitter* bce)
++{
++    return nameCache_.acquire(bce->cx);
++}
++
++template <typename BindingIter>
++bool
++EmitterScope::checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi)
++{
++    if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
++        bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
++    {
++        bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
++        return false;
++    }
++    return true;
++}
++
++bool
++EmitterScope::checkEnvironmentChainLength(BytecodeEmitter* bce)
++{
++    uint32_t hops;
++    if (EmitterScope* emitterScope = enclosing(&bce))
++        hops = emitterScope->environmentChainLength_;
++    else
++        hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
++
++    if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
++        bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
++        return false;
++    }
++
++    environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
++    return true;
++}
++
++void
++EmitterScope::updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi)
++{
++    nextFrameSlot_ = bi.nextFrameSlot();
++    if (nextFrameSlot_ > bce->maxFixedSlots)
++        bce->maxFixedSlots = nextFrameSlot_;
++    MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
++                  (bce->sc->asFunctionBox()->isGenerator() ||
++                   bce->sc->asFunctionBox()->isAsync()),
++                  bce->maxFixedSlots == 0);
++}
++
++bool
++EmitterScope::putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc)
++{
++    NameLocationMap& cache = *nameCache_;
++    NameLocationMap::AddPtr p = cache.lookupForAdd(name);
++    MOZ_ASSERT(!p);
++    if (!cache.add(p, name, loc)) {
++        ReportOutOfMemory(bce->cx);
++        return false;
++    }
++    return true;
++}
++
++Maybe<NameLocation>
++EmitterScope::lookupInCache(BytecodeEmitter* bce, JSAtom* name)
++{
++    if (NameLocationMap::Ptr p = nameCache_->lookup(name))
++        return Some(p->value().wrapped);
++    if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
++        return fallbackFreeNameLocation_;
++    return Nothing();
++}
++
++EmitterScope*
++EmitterScope::enclosing(BytecodeEmitter** bce) const
++{
++    // There is an enclosing scope with access to the same frame.
++    if (EmitterScope* inFrame = enclosingInFrame())
++        return inFrame;
++
++    // We are currently compiling the enclosing script, look in the
++    // enclosing BCE.
++    if ((*bce)->parent) {
++        *bce = (*bce)->parent;
++        return (*bce)->innermostEmitterScopeNoCheck();
++    }
++
++    return nullptr;
++}
++
++Scope*
++EmitterScope::enclosingScope(BytecodeEmitter* bce) const
++{
++    if (EmitterScope* es = enclosing(&bce))
++        return es->scope(bce);
++
++    // The enclosing script is already compiled or the current script is the
++    // global script.
++    return bce->sc->compilationEnclosingScope();
++}
++
++/* static */ bool
++EmitterScope::nameCanBeFree(BytecodeEmitter* bce, JSAtom* name)
++{
++    // '.generator' cannot be accessed by name.
++    return name != bce->cx->names().dotGenerator;
++}
++
++#ifdef DEBUG
++static bool
++NameIsOnEnvironment(Scope* scope, JSAtom* name)
++{
++    for (BindingIter bi(scope); bi; bi++) {
++        // If found, the name must already be on the environment or an import,
++        // or else there is a bug in the closed-over name analysis in the
++        // Parser.
++        if (bi.name() == name) {
++            BindingLocation::Kind kind = bi.location().kind();
++
++            if (bi.hasArgumentSlot()) {
++                JSScript* script = scope->as<FunctionScope>().script();
++                if (!script->strict() && !script->functionHasParameterExprs()) {
++                    // Check for duplicate positional formal parameters.
++                    for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
++                        if (bi2.name() == name)
++                            kind = bi2.location().kind();
++                    }
++                }
++            }
++
++            return kind == BindingLocation::Kind::Global ||
++                   kind == BindingLocation::Kind::Environment ||
++                   kind == BindingLocation::Kind::Import;
++        }
++    }
++
++    // If not found, assume it's on the global or dynamically accessed.
++    return true;
++}
++#endif
++
++/* static */ NameLocation
++EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops)
++{
++    for (ScopeIter si(scope); si; si++) {
++        MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
++
++        bool hasEnv = si.hasSyntacticEnvironment();
++
++        switch (si.kind()) {
++          case ScopeKind::Function:
++            if (hasEnv) {
++                JSScript* script = si.scope()->as<FunctionScope>().script();
++                if (script->funHasExtensibleScope())
++                    return NameLocation::Dynamic();
++
++                for (BindingIter bi(si.scope()); bi; bi++) {
++                    if (bi.name() != name)
++                        continue;
++
++                    BindingLocation bindLoc = bi.location();
++                    if (bi.hasArgumentSlot() &&
++                        !script->strict() &&
++                        !script->functionHasParameterExprs())
++                    {
++                        // Check for duplicate positional formal parameters.
++                        for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
++                            if (bi2.name() == name)
++                                bindLoc = bi2.location();
++                        }
++                    }
++
++                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
++                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
++                }
++            }
++            break;
++
++          case ScopeKind::FunctionBodyVar:
++          case ScopeKind::ParameterExpressionVar:
++          case ScopeKind::Lexical:
++          case ScopeKind::NamedLambda:
++          case ScopeKind::StrictNamedLambda:
++          case ScopeKind::SimpleCatch:
++          case ScopeKind::Catch:
++            if (hasEnv) {
++                for (BindingIter bi(si.scope()); bi; bi++) {
++                    if (bi.name() != name)
++                        continue;
++
++                    // The name must already have been marked as closed
++                    // over. If this assertion is hit, there is a bug in the
++                    // name analysis.
++                    BindingLocation bindLoc = bi.location();
++                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
++                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
++                }
++            }
++            break;
++
++          case ScopeKind::Module:
++            if (hasEnv) {
++                for (BindingIter bi(si.scope()); bi; bi++) {
++                    if (bi.name() != name)
++                        continue;
++
++                    BindingLocation bindLoc = bi.location();
++
++                    // Imports are on the environment but are indirect
++                    // bindings and must be accessed dynamically instead of
++                    // using an EnvironmentCoordinate.
++                    if (bindLoc.kind() == BindingLocation::Kind::Import) {
++                        MOZ_ASSERT(si.kind() == ScopeKind::Module);
++                        return NameLocation::Import();
++                    }
++
++                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
++                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
++                }
++            }
++            break;
++
++          case ScopeKind::Eval:
++          case ScopeKind::StrictEval:
++            // As an optimization, if the eval doesn't have its own var
++            // environment and its immediate enclosing scope is a global
++            // scope, all accesses are global.
++            if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
++                return NameLocation::Global(BindingKind::Var);
++            return NameLocation::Dynamic();
++
++          case ScopeKind::Global:
++            return NameLocation::Global(BindingKind::Var);
++
++          case ScopeKind::With:
++          case ScopeKind::NonSyntactic:
++            return NameLocation::Dynamic();
++
++          case ScopeKind::WasmInstance:
++          case ScopeKind::WasmFunction:
++            MOZ_CRASH("No direct eval inside wasm functions");
++        }
++
++        if (hasEnv) {
++            MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
++            hops++;
++        }
++    }
++
++    MOZ_CRASH("Malformed scope chain");
++}
++
++NameLocation
++EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name)
++{
++    Maybe<NameLocation> loc;
++    uint8_t hops = hasEnvironment() ? 1 : 0;
++    DebugOnly<bool> inCurrentScript = enclosingInFrame();
++
++    // Start searching in the current compilation.
++    for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
++        loc = es->lookupInCache(bce, name);
++        if (loc) {
++            if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
++                *loc = loc->addHops(hops);
++            break;
++        }
++
++        if (es->hasEnvironment())
++            hops++;
++
++#ifdef DEBUG
++        if (!es->enclosingInFrame())
++            inCurrentScript = false;
++#endif
++    }
++
++    // If the name is not found in the current compilation, walk the Scope
++    // chain encompassing the compilation.
++    if (!loc) {
++        inCurrentScript = false;
++        loc = Some(searchInEnclosingScope(name, bce->sc->compilationEnclosingScope(), hops));
++    }
++
++    // Each script has its own frame. A free name that is accessed
++    // from an inner script must not be a frame slot access. If this
++    // assertion is hit, it is a bug in the free name analysis in the
++    // parser.
++    MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
++
++    // It is always correct to not cache the location. Ignore OOMs to make
++    // lookups infallible.
++    if (!putNameInCache(bce, name, *loc))
++        bce->cx->recoverFromOutOfMemory();
++
++    return *loc;
++}
++
++template <typename ScopeCreator>
++bool
++EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope)
++{
++    RootedScope enclosing(bce->cx, enclosingScope(bce));
++    Scope* scope = createScope(bce->cx, enclosing);
++    if (!scope)
++        return false;
++    hasEnvironment_ = scope->hasEnvironment();
++    scopeIndex_ = bce->scopeList.length();
++    return bce->scopeList.append(scope);
++}
++
++template <typename ScopeCreator>
++bool
++EmitterScope::internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope)
++{
++    MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX, "There can be only one body scope");
++    bce->bodyScopeIndex = bce->scopeList.length();
++    return internScope(bce, createScope);
++}
++
++bool
++EmitterScope::appendScopeNote(BytecodeEmitter* bce)
++{
++    MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
++               "Scope notes are not needed for body-level scopes.");
++    noteIndex_ = bce->scopeNoteList.length();
++    return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
++                                     enclosingInFrame() ? enclosingInFrame()->noteIndex()
++                                                        : ScopeNote::NoScopeNoteIndex);
++}
++
++bool
++EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart, uint32_t slotEnd)
++{
++    // Lexical bindings throw ReferenceErrors if they are used before
++    // initialization. See ES6 8.1.1.1.6.
++    //
++    // For completeness, lexical bindings are initialized in ES6 by calling
++    // InitializeBinding, after which touching the binding will no longer
++    // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
++    // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
++    if (slotStart != slotEnd) {
++        if (!bce->emit1(JSOP_UNINITIALIZED))
++            return false;
++        for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
++            if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot))
++                return false;
++        }
++        if (!bce->emit1(JSOP_POP))
++            return false;
++    }
++
++    return true;
++}
++
++void
++EmitterScope::dump(BytecodeEmitter* bce)
++{
++    fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
++
++    for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
++        const NameLocation& l = r.front().value();
++
++        JSAutoByteString bytes;
++        if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
++            return;
++        if (l.kind() != NameLocation::Kind::Dynamic)
++            fprintf(stdout, "  %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
++        else
++            fprintf(stdout, "  %s ", bytes.ptr());
++
++        switch (l.kind()) {
++          case NameLocation::Kind::Dynamic:
++            fprintf(stdout, "dynamic\n");
++            break;
++          case NameLocation::Kind::Global:
++            fprintf(stdout, "global\n");
++            break;
++          case NameLocation::Kind::Intrinsic:
++            fprintf(stdout, "intrinsic\n");
++            break;
++          case NameLocation::Kind::NamedLambdaCallee:
++            fprintf(stdout, "named lambda callee\n");
++            break;
++          case NameLocation::Kind::Import:
++            fprintf(stdout, "import\n");
++            break;
++          case NameLocation::Kind::ArgumentSlot:
++            fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
++            break;
++          case NameLocation::Kind::FrameSlot:
++            fprintf(stdout, "frame slot=%u\n", l.frameSlot());
++            break;
++          case NameLocation::Kind::EnvironmentCoordinate:
++            fprintf(stdout, "environment hops=%u slot=%u\n",
++                    l.environmentCoordinate().hops(), l.environmentCoordinate().slot());
++            break;
++          case NameLocation::Kind::DynamicAnnexBVar:
++            fprintf(stdout, "dynamic annex b var\n");
++            break;
++        }
++    }
++
++    fprintf(stdout, "\n");
++}
++
++bool
++EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
++                           Handle<LexicalScope::Data*> bindings)
++{
++    MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    if (!ensureCache(bce))
++        return false;
++
++    // Marks all names as closed over if the context requires it. This
++    // cannot be done in the Parser as we may not know if the context requires
++    // all bindings to be closed over until after parsing is finished. For
++    // example, legacy generators require all bindings to be closed over but
++    // it is unknown if a function is a legacy generator until the first
++    // 'yield' expression is parsed.
++    //
++    // This is not a problem with other scopes, as all other scopes with
++    // bindings are body-level. At the time of their creation, whether or not
++    // the context requires all bindings to be closed over is already known.
++    if (bce->sc->allBindingsClosedOver())
++        MarkAllBindingsClosedOver(*bindings);
++
++    // Resolve bindings.
++    TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
++    uint32_t firstFrameSlot = frameSlotStart();
++    BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
++    for (; bi; bi++) {
++        if (!checkSlotLimits(bce, bi))
++            return false;
++
++        NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++        if (!putNameInCache(bce, bi.name(), loc))
++            return false;
++
++        if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
++            return false;
++    }
++
++    updateFrameFixedSlots(bce, bi);
++
++    // Create and intern the VM scope.
++    auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
++                                                        HandleScope enclosing)
++    {
++        return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
++    };
++    if (!internScope(bce, createScope))
++        return false;
++
++    if (ScopeKindIsInBody(kind) && hasEnvironment()) {
++        // After interning the VM scope we can get the scope index.
++        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV))
++            return false;
++    }
++
++    // Lexical scopes need notes to be mapped from a pc.
++    if (!appendScopeNote(bce))
++        return false;
++
++    // Put frame slots in TDZ. Environment slots are poisoned during
++    // environment creation.
++    //
++    // This must be done after appendScopeNote to be considered in the extent
++    // of the scope.
++    if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++bool
++EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++    MOZ_ASSERT(funbox->namedLambdaBindings());
++
++    if (!ensureCache(bce))
++        return false;
++
++    // See comment in enterLexical about allBindingsClosedOver.
++    if (funbox->allBindingsClosedOver())
++        MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
++
++    BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, /* isNamedLambda = */ true);
++    MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
++
++    // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
++    // not a frame slot. Do not update frame slot information.
++    NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++    if (!putNameInCache(bce, bi.name(), loc))
++        return false;
++
++    bi++;
++    MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
++
++    auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
++        ScopeKind scopeKind =
++            funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
++        return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
++                                    LOCALNO_LIMIT, enclosing);
++    };
++    if (!internScope(bce, createScope))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++bool
++EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    // If there are parameter expressions, there is an extra var scope.
++    if (!funbox->hasExtraBodyVarScope())
++        bce->setVarEmitterScope(this);
++
++    if (!ensureCache(bce))
++        return false;
++
++    // Resolve body-level bindings, if there are any.
++    auto bindings = funbox->functionScopeBindings();
++    Maybe<uint32_t> lastLexicalSlot;
++    if (bindings) {
++        NameLocationMap& cache = *nameCache_;
++
++        BindingIter bi(*bindings, funbox->hasParameterExprs);
++        for (; bi; bi++) {
++            if (!checkSlotLimits(bce, bi))
++                return false;
++
++            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++            NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
++
++            // The only duplicate bindings that occur are simple formal
++            // parameters, in which case the last position counts, so update the
++            // location.
++            if (p) {
++                MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
++                MOZ_ASSERT(!funbox->hasDestructuringArgs);
++                MOZ_ASSERT(!funbox->hasRest());
++                p->value() = loc;
++                continue;
++            }
++
++            if (!cache.add(p, bi.name(), loc)) {
++                ReportOutOfMemory(bce->cx);
++                return false;
++            }
++        }
++
++        updateFrameFixedSlots(bce, bi);
++    } else {
++        nextFrameSlot_ = 0;
++    }
++
++    // If the function's scope may be extended at runtime due to sloppy direct
++    // eval and there is no extra var scope, any names beyond the function
++    // scope must be accessed dynamically as we don't know if the name will
++    // become a 'var' binding due to direct eval.
++    if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
++        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
++
++    // In case of parameter expressions, the parameters are lexical
++    // bindings and have TDZ.
++    if (funbox->hasParameterExprs && nextFrameSlot_) {
++        uint32_t paramFrameSlotEnd = 0;
++        for (BindingIter bi(*bindings, true); bi; bi++) {
++            if (!BindingKindIsLexical(bi.kind()))
++                break;
++
++            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++            if (loc.kind() == NameLocation::Kind::FrameSlot) {
++                MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
++                paramFrameSlotEnd = loc.frameSlot() + 1;
++            }
++        }
++
++        if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd))
++            return false;
++    }
++
++    // Create and intern the VM scope.
++    auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
++        RootedFunction fun(cx, funbox->function());
++        return FunctionScope::create(cx, funbox->functionScopeBindings(),
++                                     funbox->hasParameterExprs,
++                                     funbox->needsCallObjectRegardlessOfBindings(),
++                                     fun, enclosing);
++    };
++    if (!internBodyScope(bce, createScope))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++bool
++EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
++{
++    MOZ_ASSERT(funbox->hasParameterExprs);
++    MOZ_ASSERT(funbox->extraVarScopeBindings() ||
++               funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    // The extra var scope is never popped once it's entered. It replaces the
++    // function scope as the var emitter scope.
++    bce->setVarEmitterScope(this);
++
++    if (!ensureCache(bce))
++        return false;
++
++    // Resolve body-level bindings, if there are any.
++    uint32_t firstFrameSlot = frameSlotStart();
++    if (auto bindings = funbox->extraVarScopeBindings()) {
++        BindingIter bi(*bindings, firstFrameSlot);
++        for (; bi; bi++) {
++            if (!checkSlotLimits(bce, bi))
++                return false;
++
++            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++            if (!putNameInCache(bce, bi.name(), loc))
++                return false;
++        }
++
++        updateFrameFixedSlots(bce, bi);
++    } else {
++        nextFrameSlot_ = firstFrameSlot;
++    }
++
++    // If the extra var scope may be extended at runtime due to sloppy
++    // direct eval, any names beyond the var scope must be accessed
++    // dynamically as we don't know if the name will become a 'var' binding
++    // due to direct eval.
++    if (funbox->hasExtensibleScope())
++        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
++
++    // Create and intern the VM scope.
++    auto createScope = [funbox, firstFrameSlot](JSContext* cx, HandleScope enclosing) {
++        return VarScope::create(cx, ScopeKind::FunctionBodyVar,
++                                funbox->extraVarScopeBindings(), firstFrameSlot,
++                                funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
++                                enclosing);
++    };
++    if (!internScope(bce, createScope))
++        return false;
++
++    if (hasEnvironment()) {
++        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
++            return false;
++    }
++
++    // The extra var scope needs a note to be mapped from a pc.
++    if (!appendScopeNote(bce))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++bool
++EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    if (!ensureCache(bce))
++        return false;
++
++    // Parameter expressions var scopes have no pre-set bindings and are
++    // always extensible, as they are needed for eval.
++    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
++
++    // Create and intern the VM scope.
++    uint32_t firstFrameSlot = frameSlotStart();
++    auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
++        return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
++                                /* data = */ nullptr, firstFrameSlot,
++                                /* needsEnvironment = */ true, enclosing);
++    };
++    if (!internScope(bce, createScope))
++        return false;
++
++    MOZ_ASSERT(hasEnvironment());
++    if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
++        return false;
++
++    // The extra var scope needs a note to be mapped from a pc.
++    if (!appendScopeNote(bce))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++class DynamicBindingIter : public BindingIter
++{
++  public:
++    explicit DynamicBindingIter(GlobalSharedContext* sc)
++      : BindingIter(*sc->bindings)
++    { }
++
++    explicit DynamicBindingIter(EvalSharedContext* sc)
++      : BindingIter(*sc->bindings, /* strict = */ false)
++    {
++        MOZ_ASSERT(!sc->strict());
++    }
++
++    JSOp bindingOp() const {
++        switch (kind()) {
++          case BindingKind::Var:
++            return JSOP_DEFVAR;
++          case BindingKind::Let:
++            return JSOP_DEFLET;
++          case BindingKind::Const:
++            return JSOP_DEFCONST;
++          default:
++            MOZ_CRASH("Bad BindingKind");
++        }
++    }
++};
++
++bool
++EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    bce->setVarEmitterScope(this);
++
++    if (!ensureCache(bce))
++        return false;
++
++    if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
++        // In self-hosting, it is incorrect to consult the global scope because
++        // self-hosted scripts are cloned into their target compartments before
++        // they are run. Instead of Global, Intrinsic is used for all names.
++        //
++        // Intrinsic lookups are redirected to the special intrinsics holder
++        // in the global object, into which any missing values are cloned
++        // lazily upon first access.
++        fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
++
++        auto createScope = [](JSContext* cx, HandleScope enclosing) {
++            MOZ_ASSERT(!enclosing);
++            return &cx->global()->emptyGlobalScope();
++        };
++        return internBodyScope(bce, createScope);
++    }
++
++    // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
++    if (globalsc->bindings) {
++        for (DynamicBindingIter bi(globalsc); bi; bi++) {
++            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++            JSAtom* name = bi.name();
++            if (!putNameInCache(bce, name, loc))
++                return false;
++
++            // Define the name in the prologue. Do not emit DEFVAR for
++            // functions that we'll emit DEFFUN for.
++            if (bi.isTopLevelFunction())
++                continue;
++
++            if (!bce->emitAtomOp(name, bi.bindingOp()))
++                return false;
++        }
++    }
++
++    // Note that to save space, we don't add free names to the cache for
++    // global scopes. They are assumed to be global vars in the syntactic
++    // global scope, dynamic accesses under non-syntactic global scope.
++    if (globalsc->scopeKind() == ScopeKind::Global)
++        fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
++    else
++        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
++
++    auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
++        MOZ_ASSERT(!enclosing);
++        return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
++    };
++    return internBodyScope(bce, createScope);
++}
++
++bool
++EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    bce->setVarEmitterScope(this);
++
++    if (!ensureCache(bce))
++        return false;
++
++    // For simplicity, treat all free name lookups in eval scripts as dynamic.
++    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
++
++    // Create the `var` scope. Note that there is also a lexical scope, created
++    // separately in emitScript().
++    auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
++        ScopeKind scopeKind = evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
++        return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
++    };
++    if (!internBodyScope(bce, createScope))
++        return false;
++
++    if (hasEnvironment()) {
++        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
++            return false;
++    } else {
++        // Resolve binding names and emit DEFVAR prologue ops if we don't have
++        // an environment (i.e., a sloppy eval not in a parameter expression).
++        // Eval scripts always have their own lexical scope, but non-strict
++        // scopes may introduce 'var' bindings to the nearest var scope.
++        //
++        // TODO: We may optimize strict eval bindings in the future to be on
++        // the frame. For now, handle everything dynamically.
++        if (!hasEnvironment() && evalsc->bindings) {
++            for (DynamicBindingIter bi(evalsc); bi; bi++) {
++                MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR);
++
++                if (bi.isTopLevelFunction())
++                    continue;
++
++                if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR))
++                    return false;
++            }
++        }
++
++        // As an optimization, if the eval does not have its own var
++        // environment and is directly enclosed in a global scope, then all
++        // free name lookups are global.
++        if (scope(bce)->enclosing()->is<GlobalScope>())
++            fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
++    }
++
++    return true;
++}
++
++bool
++EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    bce->setVarEmitterScope(this);
++
++    if (!ensureCache(bce))
++        return false;
++
++    // Resolve body-level bindings, if there are any.
++    TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
++    Maybe<uint32_t> firstLexicalFrameSlot;
++    if (ModuleScope::Data* bindings = modulesc->bindings) {
++        BindingIter bi(*bindings);
++        for (; bi; bi++) {
++            if (!checkSlotLimits(bce, bi))
++                return false;
++
++            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
++            if (!putNameInCache(bce, bi.name(), loc))
++                return false;
++
++            if (BindingKindIsLexical(bi.kind())) {
++                if (loc.kind() == NameLocation::Kind::FrameSlot && !firstLexicalFrameSlot)
++                    firstLexicalFrameSlot = Some(loc.frameSlot());
++
++                if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
++                    return false;
++            }
++        }
++
++        updateFrameFixedSlots(bce, bi);
++    } else {
++        nextFrameSlot_ = 0;
++    }
++
++    // Modules are toplevel, so any free names are global.
++    fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
++
++    // Put lexical frame slots in TDZ. Environment slots are poisoned during
++    // environment creation.
++    if (firstLexicalFrameSlot) {
++        if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
++            return false;
++    }
++
++    // Create and intern the VM scope.
++    auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
++        return ModuleScope::create(cx, modulesc->bindings, modulesc->module(), enclosing);
++    };
++    if (!internBodyScope(bce, createScope))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++bool
++EmitterScope::enterWith(BytecodeEmitter* bce)
++{
++    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
++
++    if (!ensureCache(bce))
++        return false;
++
++    // 'with' make all accesses dynamic and unanalyzable.
++    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
++
++    auto createScope = [](JSContext* cx, HandleScope enclosing) {
++        return WithScope::create(cx, enclosing);
++    };
++    if (!internScope(bce, createScope))
++        return false;
++
++    if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH))
++        return false;
++
++    if (!appendScopeNote(bce))
++        return false;
++
++    return checkEnvironmentChainLength(bce);
++}
++
++bool
++EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
++{
++    return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
++}
++
++bool
++EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
++{
++    // If we aren't leaving the scope due to a non-local jump (e.g., break),
++    // we must be the innermost scope.
++    MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
++
++    ScopeKind kind = scope(bce)->kind();
++    switch (kind) {
++      case ScopeKind::Lexical:
++      case ScopeKind::SimpleCatch:
++      case ScopeKind::Catch:
++        if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
++            return false;
++        break;
++
++      case ScopeKind::With:
++        if (!bce->emit1(JSOP_LEAVEWITH))
++            return false;
++        break;
++
++      case ScopeKind::ParameterExpressionVar:
++        MOZ_ASSERT(hasEnvironment());
++        if (!bce->emit1(JSOP_POPVARENV))
++            return false;
++        break;
++
++      case ScopeKind::Function:
++      case ScopeKind::FunctionBodyVar:
++      case ScopeKind::NamedLambda:
++      case ScopeKind::StrictNamedLambda:
++      case ScopeKind::Eval:
++      case ScopeKind::StrictEval:
++      case ScopeKind::Global:
++      case ScopeKind::NonSyntactic:
++      case ScopeKind::Module:
++        break;
++
++      case ScopeKind::WasmInstance:
++      case ScopeKind::WasmFunction:
++        MOZ_CRASH("No wasm function scopes in JS");
++    }
++
++    // Finish up the scope if we are leaving it in LIFO fashion.
++    if (!nonLocal) {
++        // Popping scopes due to non-local jumps generate additional scope
++        // notes. See NonLocalExitControl::prepareForNonLocalJump.
++        if (ScopeKindIsInBody(kind)) {
++            // The extra function var scope is never popped once it's pushed,
++            // so its scope note extends until the end of any possible code.
++            uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
++            bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
++        }
++    }
++
++    return true;
++}
++
++Scope*
++EmitterScope::scope(const BytecodeEmitter* bce) const
++{
++    return bce->scopeList.vector[index()];
++}
++
++NameLocation
++EmitterScope::lookup(BytecodeEmitter* bce, JSAtom* name)
++{
++    if (Maybe<NameLocation> loc = lookupInCache(bce, name))
++        return *loc;
++    return searchAndCache(bce, name);
++}
++
++Maybe<NameLocation>
++EmitterScope::locationBoundInScope(JSAtom* name, EmitterScope* target)
++{
++    // The target scope must be an intra-frame enclosing scope of this
++    // one. Count the number of extra hops to reach it.
++    uint8_t extraHops = 0;
++    for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
++        if (es->hasEnvironment())
++            extraHops++;
++    }
++
++    // Caches are prepopulated with bound names. So if the name is bound in a
++    // particular scope, it must already be in the cache. Furthermore, don't
++    // consult the fallback location as we only care about binding names.
++    Maybe<NameLocation> loc;
++    if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
++        NameLocation l = p->value().wrapped;
++        if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
++            loc = Some(l.addHops(extraHops));
++        else
++            loc = Some(l);
++    }
++    return loc;
++}
+diff --git a/js/src/frontend/EmitterScope.h b/js/src/frontend/EmitterScope.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/EmitterScope.h
+@@ -0,0 +1,150 @@
++/* -*- 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_EmitterScope_h
++#define frontend_EmitterScope_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#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 {
++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
++    // current scope.
++    PooledMapPtr<NameLocationMap> nameCache_;
++
++    // If this scope's cache does not include free names, such as the
++    // global scope, the NameLocation to return.
++    mozilla::Maybe<NameLocation> fallbackFreeNameLocation_;
++
++    // True if there is a corresponding EnvironmentObject on the environment
++    // chain, false if all bindings are stored in frame slots on the stack.
++    bool hasEnvironment_;
++
++    // The number of enclosing environments. Used for error checking.
++    uint8_t environmentChainLength_;
++
++    // The next usable slot on the frame for not-closed over bindings.
++    //
++    // The initial frame slot when assigning slots to bindings is the
++    // enclosing scope's nextFrameSlot. For the first scope in a frame,
++    // the initial frame slot is 0.
++    uint32_t nextFrameSlot_;
++
++    // The index in the BytecodeEmitter's interned scope vector, otherwise
++    // ScopeNote::NoScopeIndex.
++    uint32_t scopeIndex_;
++
++    // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
++    // block scope note list. Otherwise ScopeNote::NoScopeNote.
++    uint32_t noteIndex_;
++
++    MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce);
++
++    template <typename BindingIter>
++    MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi);
++
++    MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce);
++
++    void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi);
++
++    MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc);
++
++    mozilla::Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name);
++
++    EmitterScope* enclosing(BytecodeEmitter** bce) const;
++
++    Scope* enclosingScope(BytecodeEmitter* bce) const;
++
++    static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name);
++
++    static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops);
++    NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
++
++    template <typename ScopeCreator>
++    MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
++    template <typename ScopeCreator>
++    MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
++    MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
++
++    MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
++                                             uint32_t slotEnd);
++
++  public:
++    explicit EmitterScope(BytecodeEmitter* bce);
++
++    void dump(BytecodeEmitter* bce);
++
++    MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
++                                   Handle<LexicalScope::Data*> bindings);
++    MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
++    MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
++    MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
++    MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
++    MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
++    MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
++    MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
++    MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
++    MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
++
++    MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
++
++    uint32_t index() const {
++        MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?");
++        return scopeIndex_;
++    }
++
++    uint32_t noteIndex() const {
++        return noteIndex_;
++    }
++
++    Scope* scope(const BytecodeEmitter* bce) const;
++
++    bool hasEnvironment() const {
++        return hasEnvironment_;
++    }
++
++    // The first frame slot used.
++    uint32_t frameSlotStart() const {
++        if (EmitterScope* inFrame = enclosingInFrame())
++            return inFrame->nextFrameSlot_;
++        return 0;
++    }
++
++    // The last frame slot used + 1.
++    uint32_t frameSlotEnd() const {
++        return nextFrameSlot_;
++    }
++
++    EmitterScope* enclosingInFrame() const {
++        return Nestable<EmitterScope>::enclosing();
++    }
++
++    NameLocation lookup(BytecodeEmitter* bce, JSAtom* name);
++
++    mozilla::Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_EmitterScope_h */
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -206,16 +206,17 @@ UNIFIED_SOURCES += [
+     'builtin/WeakMapObject.cpp',
+     'builtin/WeakSetObject.cpp',
+     'devtools/sharkctl.cpp',
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeEmitter.cpp',
++    'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',

+ 958 - 0
frg/work-js/mozilla-release/patches/1460489-3-63a1.patch

@@ -0,0 +1,958 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531358653 -32400
+#      Thu Jul 12 10:24:13 2018 +0900
+# Node ID 2bdd1b1c3fb8326357febb481f9015fccc73b06c
+# Parent  298983d311f181b4f103225f17a48815a1554f30
+Bug 1460489 - Part 3: Move NestableControl classes except ForOfLoopControl to BytecodeControlStructures.{cpp.h}. r=jwalden
+
+diff --git a/js/src/frontend/BytecodeControlStructures.cpp b/js/src/frontend/BytecodeControlStructures.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/BytecodeControlStructures.cpp
+@@ -0,0 +1,109 @@
++/* -*- 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 "frontend/BytecodeControlStructures.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/EmitterScope.h"
++
++using namespace js;
++using namespace js::frontend;
++
++NestableControl::NestableControl(BytecodeEmitter* bce, StatementKind kind)
++  : Nestable<NestableControl>(&bce->innermostNestableControl),
++    kind_(kind),
++    emitterScope_(bce->innermostEmitterScopeNoCheck())
++{}
++
++BreakableControl::BreakableControl(BytecodeEmitter* bce, StatementKind kind)
++  : NestableControl(bce, kind)
++{
++    MOZ_ASSERT(is<BreakableControl>());
++}
++
++bool
++BreakableControl::patchBreaks(BytecodeEmitter* bce)
++{
++    return bce->emitJumpTargetAndPatch(breaks);
++}
++
++LabelControl::LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
++  : BreakableControl(bce, StatementKind::Label),
++    label_(bce->cx, label),
++    startOffset_(startOffset)
++{}
++
++LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
++  : BreakableControl(bce, loopKind),
++    tdzCache_(bce),
++    continueTarget({ -1 })
++{
++    MOZ_ASSERT(is<LoopControl>());
++
++    LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
++
++    stackDepth_ = bce->stackDepth;
++    loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
++
++    int loopSlots;
++    if (loopKind == StatementKind::Spread) {
++        // The iterator next method, the iterator, the result array, and
++        // the current array index are on the stack.
++        loopSlots = 4;
++    } else if (loopKind == StatementKind::ForOfLoop) {
++        // The iterator next method, the iterator, and the current value
++        // are on the stack.
++        loopSlots = 3;
++    } else if (loopKind == StatementKind::ForInLoop) {
++        // The iterator and the current value are on the stack.
++        loopSlots = 2;
++    } else {
++        // No additional loop values are on the stack.
++        loopSlots = 0;
++    }
++
++    MOZ_ASSERT(loopSlots <= stackDepth_);
++
++    if (enclosingLoop) {
++        canIonOsr_ = (enclosingLoop->canIonOsr_ &&
++                      stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
++    } else {
++        canIonOsr_ = stackDepth_ == loopSlots;
++    }
++}
++
++bool
++LoopControl::emitSpecialBreakForDone(BytecodeEmitter* bce)
++{
++    // This doesn't pop stack values, nor handle any other controls.
++    // Should be called on the toplevel of the loop.
++    MOZ_ASSERT(bce->stackDepth == stackDepth_);
++    MOZ_ASSERT(bce->innermostNestableControl == this);
++
++    if (!bce->newSrcNote(SRC_BREAK))
++        return false;
++    if (!bce->emitJump(JSOP_GOTO, &breaks))
++        return false;
++
++    return true;
++}
++
++bool
++LoopControl::patchBreaksAndContinues(BytecodeEmitter* bce)
++{
++    MOZ_ASSERT(continueTarget.offset != -1);
++    if (!patchBreaks(bce))
++        return false;
++    bce->patchJumpsToTarget(continues, continueTarget);
++    return true;
++}
++
++TryFinallyControl::TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
++  : NestableControl(bce, kind),
++    emittingSubroutine_(false)
++{
++    MOZ_ASSERT(is<TryFinallyControl>());
++}
+diff --git a/js/src/frontend/BytecodeControlStructures.h b/js/src/frontend/BytecodeControlStructures.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/BytecodeControlStructures.h
+@@ -0,0 +1,171 @@
++/* -*- 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_BytecodeControlStructures_h
++#define frontend_BytecodeControlStructures_h
++
++#include "mozilla/Attributes.h"
++
++#include <stddef.h>
++#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/StringType.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++class EmitterScope;
++
++class NestableControl : public Nestable<NestableControl>
++{
++    StatementKind kind_;
++
++    // The innermost scope when this was pushed.
++    EmitterScope* emitterScope_;
++
++  protected:
++    NestableControl(BytecodeEmitter* bce, StatementKind kind);
++
++  public:
++    using Nestable<NestableControl>::enclosing;
++    using Nestable<NestableControl>::findNearest;
++
++    StatementKind kind() const {
++        return kind_;
++    }
++
++    EmitterScope* emitterScope() const {
++        return emitterScope_;
++    }
++
++    template <typename T> bool is() const;
++
++    template <typename T> T& as() {
++        MOZ_ASSERT(this->is<T>());
++        return static_cast<T&>(*this);
++    }
++};
++
++class BreakableControl : public NestableControl
++{
++  public:
++    // Offset of the last break.
++    JumpList breaks;
++
++    BreakableControl(BytecodeEmitter* bce, StatementKind kind);
++
++    MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce);
++};
++template <>
++inline bool
++NestableControl::is<BreakableControl>() const
++{
++    return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
++}
++
++class LabelControl : public BreakableControl
++{
++    RootedAtom label_;
++
++    // The code offset when this was pushed. Used for effectfulness checking.
++    ptrdiff_t startOffset_;
++
++  public:
++    LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset);
++
++    HandleAtom label() const {
++        return label_;
++    }
++
++    ptrdiff_t startOffset() const {
++        return startOffset_;
++    }
++};
++template <>
++inline bool
++NestableControl::is<LabelControl>() const
++{
++    return kind_ == StatementKind::Label;
++}
++
++class LoopControl : public BreakableControl
++{
++    // Loops' children are emitted in dominance order, so they can always
++    // have a TDZCheckCache.
++    TDZCheckCache tdzCache_;
++
++    // Stack depth when this loop was pushed on the control stack.
++    int32_t stackDepth_;
++
++    // The loop nesting depth. Used as a hint to Ion.
++    uint32_t loopDepth_;
++
++    // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
++    bool canIonOsr_;
++
++  public:
++    // The target of continue statement jumps, e.g., the update portion of a
++    // for(;;) loop.
++    JumpTarget continueTarget;
++
++    // Offset of the last continue in the loop.
++    JumpList continues;
++
++    LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
++
++    uint32_t loopDepth() const {
++        return loopDepth_;
++    }
++
++    bool canIonOsr() const {
++        return canIonOsr_;
++    }
++
++    MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce);
++    MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce);
++};
++template <>
++inline bool
++NestableControl::is<LoopControl>() const
++{
++    return StatementKindIsLoop(kind_);
++}
++
++class TryFinallyControl : public NestableControl
++{
++    bool emittingSubroutine_;
++
++  public:
++    // The subroutine when emitting a finally block.
++    JumpList gosubs;
++
++    TryFinallyControl(BytecodeEmitter* bce, StatementKind kind);
++
++    void setEmittingSubroutine() {
++        emittingSubroutine_ = true;
++    }
++
++    bool emittingSubroutine() const {
++        return emittingSubroutine_;
++    }
++};
++template <>
++inline bool
++NestableControl::is<TryFinallyControl>() const
++{
++    return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
++}
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_BytecodeControlStructures_h */
+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
+@@ -19,16 +19,17 @@
+ #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/EmitterScope.h"
+ #include "frontend/Parser.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+@@ -52,273 +53,31 @@ using mozilla::DebugOnly;
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::NumberEqualsInt32;
+ using mozilla::NumberIsInt32;
+ using mozilla::PodCopy;
+ using mozilla::Some;
+ using mozilla::Unused;
+ 
+-class BreakableControl;
+-class LabelControl;
+-class LoopControl;
+-class ForOfLoopControl;
+-class TryFinallyControl;
+-
+ static bool
+ ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn)
+ {
+     // The few node types listed below are exceptions to the usual
+     // location-source-note-emitting code in BytecodeEmitter::emitTree().
+     // Single-line `while` loops and C-style `for` loops require careful
+     // handling to avoid strange stepping behavior.
+     // Functions usually shouldn't have location information (bug 1431202).
+ 
+     ParseNodeKind kind = pn->getKind();
+     return kind == ParseNodeKind::While ||
+            kind == ParseNodeKind::For ||
+            kind == ParseNodeKind::Function;
+ }
+ 
+-class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
+-{
+-    StatementKind kind_;
+-
+-    // The innermost scope when this was pushed.
+-    EmitterScope* emitterScope_;
+-
+-  protected:
+-    NestableControl(BytecodeEmitter* bce, StatementKind kind)
+-      : Nestable<NestableControl>(&bce->innermostNestableControl),
+-        kind_(kind),
+-        emitterScope_(bce->innermostEmitterScopeNoCheck())
+-    { }
+-
+-  public:
+-    using Nestable<NestableControl>::enclosing;
+-    using Nestable<NestableControl>::findNearest;
+-
+-    StatementKind kind() const {
+-        return kind_;
+-    }
+-
+-    EmitterScope* emitterScope() const {
+-        return emitterScope_;
+-    }
+-
+-    template <typename T>
+-    bool is() const;
+-
+-    template <typename T>
+-    T& as() {
+-        MOZ_ASSERT(this->is<T>());
+-        return static_cast<T&>(*this);
+-    }
+-};
+-
+-// Template specializations are disallowed in different namespaces; specialize
+-// all the NestableControl subtypes up front.
+-namespace js {
+-namespace frontend {
+-
+-template <>
+-bool
+-BytecodeEmitter::NestableControl::is<BreakableControl>() const
+-{
+-    return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
+-}
+-
+-template <>
+-bool
+-BytecodeEmitter::NestableControl::is<LabelControl>() const
+-{
+-    return kind_ == StatementKind::Label;
+-}
+-
+-template <>
+-bool
+-BytecodeEmitter::NestableControl::is<LoopControl>() const
+-{
+-    return StatementKindIsLoop(kind_);
+-}
+-
+-template <>
+-bool
+-BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const
+-{
+-    return kind_ == StatementKind::ForOfLoop;
+-}
+-
+-template <>
+-bool
+-BytecodeEmitter::NestableControl::is<TryFinallyControl>() const
+-{
+-    return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
+-}
+-
+-} // namespace frontend
+-} // namespace js
+-
+-class BreakableControl : public BytecodeEmitter::NestableControl
+-{
+-  public:
+-    // Offset of the last break.
+-    JumpList breaks;
+-
+-    BreakableControl(BytecodeEmitter* bce, StatementKind kind)
+-      : NestableControl(bce, kind)
+-    {
+-        MOZ_ASSERT(is<BreakableControl>());
+-    }
+-
+-    MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce) {
+-        return bce->emitJumpTargetAndPatch(breaks);
+-    }
+-};
+-
+-class LabelControl : public BreakableControl
+-{
+-    RootedAtom label_;
+-
+-    // The code offset when this was pushed. Used for effectfulness checking.
+-    ptrdiff_t startOffset_;
+-
+-  public:
+-    LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
+-      : BreakableControl(bce, StatementKind::Label),
+-        label_(bce->cx, label),
+-        startOffset_(startOffset)
+-    { }
+-
+-    HandleAtom label() const {
+-        return label_;
+-    }
+-
+-    ptrdiff_t startOffset() const {
+-        return startOffset_;
+-    }
+-};
+-
+-class LoopControl : public BreakableControl
+-{
+-    // Loops' children are emitted in dominance order, so they can always
+-    // have a TDZCheckCache.
+-    TDZCheckCache tdzCache_;
+-
+-    // Stack depth when this loop was pushed on the control stack.
+-    int32_t stackDepth_;
+-
+-    // The loop nesting depth. Used as a hint to Ion.
+-    uint32_t loopDepth_;
+-
+-    // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
+-    bool canIonOsr_;
+-
+-  public:
+-    // The target of continue statement jumps, e.g., the update portion of a
+-    // for(;;) loop.
+-    JumpTarget continueTarget;
+-
+-    // Offset of the last continue in the loop.
+-    JumpList continues;
+-
+-    LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
+-      : BreakableControl(bce, loopKind),
+-        tdzCache_(bce),
+-        continueTarget({ -1 })
+-    {
+-        MOZ_ASSERT(is<LoopControl>());
+-
+-        LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
+-
+-        stackDepth_ = bce->stackDepth;
+-        loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
+-
+-        int loopSlots;
+-        if (loopKind == StatementKind::Spread) {
+-            // The iterator next method, the iterator, the result array, and
+-            // the current array index are on the stack.
+-            loopSlots = 4;
+-        } else if (loopKind == StatementKind::ForOfLoop) {
+-            // The iterator next method, the iterator, and the current value
+-            // are on the stack.
+-            loopSlots = 3;
+-        } else if (loopKind == StatementKind::ForInLoop) {
+-            // The iterator and the current value are on the stack.
+-            loopSlots = 2;
+-        } else {
+-            // No additional loop values are on the stack.
+-            loopSlots = 0;
+-        }
+-
+-        MOZ_ASSERT(loopSlots <= stackDepth_);
+-
+-        if (enclosingLoop) {
+-            canIonOsr_ = (enclosingLoop->canIonOsr_ &&
+-                          stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
+-        } else {
+-            canIonOsr_ = stackDepth_ == loopSlots;
+-        }
+-    }
+-
+-    uint32_t loopDepth() const {
+-        return loopDepth_;
+-    }
+-
+-    bool canIonOsr() const {
+-        return canIonOsr_;
+-    }
+-
+-    MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
+-        // This doesn't pop stack values, nor handle any other controls.
+-        // Should be called on the toplevel of the loop.
+-        MOZ_ASSERT(bce->stackDepth == stackDepth_);
+-        MOZ_ASSERT(bce->innermostNestableControl == this);
+-
+-        if (!bce->newSrcNote(SRC_BREAK))
+-            return false;
+-        if (!bce->emitJump(JSOP_GOTO, &breaks))
+-            return false;
+-
+-        return true;
+-    }
+-
+-    MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
+-        MOZ_ASSERT(continueTarget.offset != -1);
+-        if (!patchBreaks(bce))
+-            return false;
+-        bce->patchJumpsToTarget(continues, continueTarget);
+-        return true;
+-    }
+-};
+-
+-class TryFinallyControl : public BytecodeEmitter::NestableControl
+-{
+-    bool emittingSubroutine_;
+-
+-  public:
+-    // The subroutine when emitting a finally block.
+-    JumpList gosubs;
+-
+-    TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
+-      : NestableControl(bce, kind),
+-        emittingSubroutine_(false)
+-    {
+-        MOZ_ASSERT(is<TryFinallyControl>());
+-    }
+-
+-    void setEmittingSubroutine() {
+-        emittingSubroutine_ = true;
+-    }
+-
+-    bool emittingSubroutine() const {
+-        return emittingSubroutine_;
+-    }
+-};
+-
+ // Class for emitting bytecode for blocks like try-catch-finally.
+ //
+ // Usage: (check for the return value is omitted for simplicity)
+ //
+ //   `try { try_block } catch (ex) { catch_block }`
+ //     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
+ //                         TryEmitter::ControlKind::Syntactic);
+ //     tryCatch.emitTry();
+@@ -1289,16 +1048,28 @@ class ForOfLoopControl : public LoopCont
+             if (!bce->emit1(JSOP_POP))                    //
+                 return false;
+         }
+ 
+         return true;
+     }
+ };
+ 
++namespace js {
++namespace frontend {
++
++template <>
++bool
++NestableControl::is<ForOfLoopControl>() const
++{
++    return kind_ == StatementKind::ForOfLoop;
++}
++
++} // namespace frontend
++} // namespace js
+ 
+ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
+                                  SharedContext* sc, HandleScript script,
+                                  Handle<LazyScript*> lazyScript,
+                                  uint32_t lineNum, EmitterMode emitterMode)
+   : sc(sc),
+     cx(sc->context),
+     parent(parent),
+@@ -1539,37 +1310,16 @@ BytecodeEmitter::emitJumpTarget(JumpTarg
+ 
+     target->offset = off;
+     current->lastTarget.offset = off;
+     if (!emit1(JSOP_JUMPTARGET))
+         return false;
+     return true;
+ }
+ 
+-void
+-JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
+-{
+-    SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
+-    offset = jumpOffset;
+-}
+-
+-void
+-JumpList::patchAll(jsbytecode* code, JumpTarget target)
+-{
+-    ptrdiff_t delta;
+-    for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
+-        jsbytecode* pc = &code[jumpOffset];
+-        MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL);
+-        delta = GET_JUMP_OFFSET(pc);
+-        MOZ_ASSERT(delta < 0);
+-        ptrdiff_t span = target.offset - jumpOffset;
+-        SET_JUMP_OFFSET(pc, span);
+-    }
+-}
+-
+ bool
+ BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump)
+ {
+     ptrdiff_t offset;
+     if (!emitCheck(5, &offset))
+         return false;
+ 
+     jsbytecode* code = this->code(offset);
+@@ -1876,17 +1626,17 @@ class NonLocalExitControl
+     { }
+ 
+     ~NonLocalExitControl() {
+         for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length(); n++)
+             bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
+         bce_->stackDepth = savedDepth_;
+     }
+ 
+-    MOZ_MUST_USE bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
++    MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
+ 
+     MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
+         return prepareForNonLocalJump(nullptr);
+     }
+ };
+ 
+ bool
+ NonLocalExitControl::leaveScope(EmitterScope* es)
+@@ -1907,20 +1657,18 @@ NonLocalExitControl::leaveScope(EmitterS
+ 
+     return true;
+ }
+ 
+ /*
+  * Emit additional bytecode(s) for non-local jumps.
+  */
+ bool
+-NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
+-{
+-    using NestableControl = BytecodeEmitter::NestableControl;
+-
++NonLocalExitControl::prepareForNonLocalJump(NestableControl* target)
++{
+     EmitterScope* es = bce_->innermostEmitterScope();
+     int npops = 0;
+ 
+     AutoCheckUnstableEmitterScope cues(bce_);
+ 
+     // For 'continue', 'break', and 'return' statements, emit IteratorClose
+     // bytecode inline. 'continue' statements do not call IteratorClose for
+     // the loop they are continuing.
+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
+@@ -9,16 +9,17 @@
+ #ifndef frontend_BytecodeEmitter_h
+ #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/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"
+ 
+@@ -106,90 +107,34 @@ struct CGYieldAndAwaitOffsetList {
+ static constexpr size_t MaxBytecodeLength = INT32_MAX;
+ static constexpr size_t MaxSrcNotesLength = INT32_MAX;
+ 
+ // Have a few inline elements, so as to avoid heap allocation for tiny
+ // sequences.  See bug 1390526.
+ typedef Vector<jsbytecode, 64> BytecodeVector;
+ typedef Vector<jssrcnote, 64> SrcNotesVector;
+ 
+-// Linked list of jump instructions that need to be patched. The linked list is
+-// stored in the bytes of the incomplete bytecode that will be patched, so no
+-// extra memory is needed, and patching the instructions destroys the list.
+-//
+-// Example:
+-//
+-//     JumpList brList;
+-//     if (!emitJump(JSOP_IFEQ, &brList))
+-//         return false;
+-//     ...
+-//     JumpTarget label;
+-//     if (!emitJumpTarget(&label))
+-//         return false;
+-//     ...
+-//     if (!emitJump(JSOP_GOTO, &brList))
+-//         return false;
+-//     ...
+-//     patchJumpsToTarget(brList, label);
+-//
+-//                 +-> -1
+-//                 |
+-//                 |
+-//    ifeq ..   <+ +                +-+   ifeq ..
+-//    ..         |                  |     ..
+-//  label:       |                  +-> label:
+-//    jumptarget |                  |     jumptarget
+-//    ..         |                  |     ..
+-//    goto .. <+ +                  +-+   goto .. <+
+-//             |                                   |
+-//             |                                   |
+-//             +                                   +
+-//           brList                              brList
+-//
+-//       |                                  ^
+-//       +------- patchJumpsToTarget -------+
+-//
+-
+-// Offset of a jump target instruction, used for patching jump instructions.
+-struct JumpTarget {
+-    ptrdiff_t offset;
+-};
+-
+-struct JumpList {
+-    // -1 is used to mark the end of jump lists.
+-    JumpList() : offset(-1) {}
+-    ptrdiff_t offset;
+-
+-    // Add a jump instruction to the list.
+-    void push(jsbytecode* code, ptrdiff_t jumpOffset);
+-
+-    // Patch all jump instructions in this list to jump to `target`.  This
+-    // clobbers the list.
+-    void patchAll(jsbytecode* code, JumpTarget target);
+-};
+-
+ // Used to control whether JSOP_CALL_IGNORES_RV is emitted for function calls.
+ enum class ValueUsage {
+     // Assume the value of the current expression may be used. This is always
+     // correct but prohibits JSOP_CALL_IGNORES_RV.
+     WantValue,
+ 
+     // Pass this when emitting an expression if the expression's value is
+     // definitely unused by later instructions. You must make sure the next
+     // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar.
+     IgnoreValue
+ };
+ 
+ class EmitterScope;
++class NestableControl;
+ class TDZCheckCache;
+ 
+ struct MOZ_STACK_CLASS BytecodeEmitter
+ {
+-    class NestableControl;
+-
+     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
+ 
+     JSContext* const cx;
+ 
+     BytecodeEmitter* const parent;  /* enclosing function or global context */
+ 
+     Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
+ 
+diff --git a/js/src/frontend/JumpList.cpp b/js/src/frontend/JumpList.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/JumpList.cpp
+@@ -0,0 +1,33 @@
++/* -*- 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 "frontend/JumpList.h"
++
++#include "vm/BytecodeUtil.h"
++
++using namespace js;
++using namespace js::frontend;
++
++void
++JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
++{
++    SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
++    offset = jumpOffset;
++}
++
++void
++JumpList::patchAll(jsbytecode* code, JumpTarget target)
++{
++    ptrdiff_t delta;
++    for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
++        jsbytecode* pc = &code[jumpOffset];
++        MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL);
++        delta = GET_JUMP_OFFSET(pc);
++        MOZ_ASSERT(delta < 0);
++        ptrdiff_t span = target.offset - jumpOffset;
++        SET_JUMP_OFFSET(pc, span);
++    }
++}
+diff --git a/js/src/frontend/JumpList.h b/js/src/frontend/JumpList.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/JumpList.h
+@@ -0,0 +1,75 @@
++/* -*- 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_JumpList_h
++#define frontend_JumpList_h
++
++#include <stddef.h>
++
++#include "js/TypeDecls.h"
++
++namespace js {
++namespace frontend {
++
++// Linked list of jump instructions that need to be patched. The linked list is
++// stored in the bytes of the incomplete bytecode that will be patched, so no
++// extra memory is needed, and patching the instructions destroys the list.
++//
++// Example:
++//
++//     JumpList brList;
++//     if (!emitJump(JSOP_IFEQ, &brList))
++//         return false;
++//     ...
++//     JumpTarget label;
++//     if (!emitJumpTarget(&label))
++//         return false;
++//     ...
++//     if (!emitJump(JSOP_GOTO, &brList))
++//         return false;
++//     ...
++//     patchJumpsToTarget(brList, label);
++//
++//                 +-> -1
++//                 |
++//                 |
++//    ifeq ..   <+ +                +-+   ifeq ..
++//    ..         |                  |     ..
++//  label:       |                  +-> label:
++//    jumptarget |                  |     jumptarget
++//    ..         |                  |     ..
++//    goto .. <+ +                  +-+   goto .. <+
++//             |                                   |
++//             |                                   |
++//             +                                   +
++//           brList                              brList
++//
++//       |                                  ^
++//       +------- patchJumpsToTarget -------+
++//
++
++// Offset of a jump target instruction, used for patching jump instructions.
++struct JumpTarget {
++    ptrdiff_t offset;
++};
++
++struct JumpList {
++    JumpList() {}
++    // -1 is used to mark the end of jump lists.
++    ptrdiff_t offset = -1;
++
++    // Add a jump instruction to the list.
++    void push(jsbytecode* code, ptrdiff_t jumpOffset);
++
++    // Patch all jump instructions in this list to jump to `target`.  This
++    // clobbers the list.
++    void patchAll(jsbytecode* code, JumpTarget target);
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_JumpList_h */
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -203,19 +203,21 @@ UNIFIED_SOURCES += [
+     'builtin/TypedObject.cpp',
+     'builtin/WeakMapObject.cpp',
+     'builtin/WeakSetObject.cpp',
+     'devtools/sharkctl.cpp',
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
++    'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
++    'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',
+     'gc/GC.cpp',

+ 874 - 0
frg/work-js/mozilla-release/patches/1460489-4-63a1.patch

@@ -0,0 +1,874 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531358654 -32400
+#      Thu Jul 12 10:24:14 2018 +0900
+# Node ID 1f631b52845bdd5a67e9d284f38d69a58bd47e36
+# Parent  2bdd1b1c3fb8326357febb481f9015fccc73b06c
+Bug 1460489 - Part 4: Move IfEmitter to IfEmitter.{cpp.h}. 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
+@@ -21,16 +21,17 @@
+ #include "jsapi.h"
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/EmitterScope.h"
++#include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/TDZCheckCache.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+@@ -495,377 +496,16 @@ class MOZ_STACK_CLASS TryEmitter
+ 
+ #ifdef DEBUG
+         state_ = State::End;
+ #endif
+         return true;
+     }
+ };
+ 
+-// 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
+-{
+-  public:
+-    // 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.
+-    //
+-    // See the comment for TDZCheckCache class for more details.
+-    enum class Kind {
+-        // For syntactic branches (if, if-else, and conditional expression),
+-        // 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_;
+-
+-    // 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_;
+-    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_;
+-#endif
+-
+-  protected:
+-    // For InternalIfEmitter.
+-    IfEmitter(BytecodeEmitter* bce, Kind kind)
+-      : bce_(bce)
+-      , thenDepth_(0)
+-      , kind_(kind)
+-#ifdef DEBUG
+-      , pushed_(0)
+-      , calculatedPushed_(false)
+-      , state_(State::Start)
+-#endif
+-    {}
+-
+-  public:
+-    explicit IfEmitter(BytecodeEmitter* bce)
+-      : IfEmitter(bce, Kind::MayContainLexicalAccessInBranch)
+-    {}
+-
+-  private:
+-    MOZ_MUST_USE bool emitIfInternal(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_))
+-            return false;
+-
+-        // To restore stack depth in else part, save depth of the then part.
+-#ifdef DEBUG
+-        // If DEBUG, this is also necessary to calculate |pushed_|.
+-        thenDepth_ = bce_->stackDepth;
+-#else
+-        if (type == SRC_COND || type == SRC_IF_ELSE)
+-            thenDepth_ = bce_->stackDepth;
+-#endif
+-
+-        // Enclose then-branch with TDZCheckCache.
+-        if (kind_ == Kind::MayContainLexicalAccessInBranch)
+-            tdzCache_.emplace(bce_);
+-
+-        return true;
+-    }
+-
+-    void calculateOrCheckPushed() {
+-#ifdef DEBUG
+-        if (!calculatedPushed_) {
+-            pushed_ = bce_->stackDepth - thenDepth_;
+-            calculatedPushed_ = true;
+-        } else {
+-            MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
+-        }
+-#endif
+-    }
+-
+-  public:
+-    MOZ_MUST_USE bool emitThen() {
+-        MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
+-        if (!emitIfInternal(SRC_IF))
+-            return false;
+-
+-#ifdef DEBUG
+-        state_ = State::Then;
+-#endif
+-        return true;
+-    }
+-
+-    MOZ_MUST_USE bool emitCond() {
+-        MOZ_ASSERT(state_ == State::Start);
+-        if (!emitIfInternal(SRC_COND))
+-            return false;
+-
+-#ifdef DEBUG
+-        state_ = State::Cond;
+-#endif
+-        return true;
+-    }
+-
+-    MOZ_MUST_USE bool emitThenElse() {
+-        MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
+-        if (!emitIfInternal(SRC_IF_ELSE))
+-            return false;
+-
+-#ifdef DEBUG
+-        state_ = State::ThenElse;
+-#endif
+-        return true;
+-    }
+-
+-  private:
+-    MOZ_MUST_USE bool emitElseInternal() {
+-        calculateOrCheckPushed();
+-
+-        // The end of TDZCheckCache for then-clause.
+-        if (kind_ == Kind::MayContainLexicalAccessInBranch) {
+-            MOZ_ASSERT(tdzCache_.isSome());
+-            tdzCache_.reset();
+-        }
+-
+-        // Emit a jump from the end of our then part around the else part. The
+-        // patchJumpsToTarget call at the bottom of this function will fix up
+-        // the offset with jumpsAroundElse value.
+-        if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_))
+-            return false;
+-
+-        // Ensure the branch-if-false comes here, then emit the else.
+-        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;
+-    }
+-
+-  public:
+-    MOZ_MUST_USE bool 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;
+-    }
+-
+-    MOZ_MUST_USE bool emitElseIf() {
+-        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;
+-    }
+-
+-    MOZ_MUST_USE bool 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();
+-
+-        if (jumpAroundThen_.offset != -1) {
+-            // No else part for the last branch, fixup the branch-if-false to
+-            // come here.
+-            if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
+-                return false;
+-        }
+-
+-        // Patch all the jumps around else parts.
+-        if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
+-            return false;
+-
+-#ifdef DEBUG
+-        state_ = State::End;
+-#endif
+-        return true;
+-    }
+-
+-#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
+-};
+-
+-// 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.
+-class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter
+-{
+-  public:
+-    explicit InternalIfEmitter(BytecodeEmitter* bce)
+-      : IfEmitter(bce, Kind::NoLexicalAccessInBranch)
+-    {}
+-};
+-
+ class ForOfLoopControl : public LoopControl
+ {
+     // The stack depth of the iterator.
+     int32_t iterDepth_;
+ 
+     // for-of loops, when throwing from non-iterator code (i.e. from the body
+     // or from evaluating the LHS of the loop condition), need to call
+     // IteratorClose.  This is done by enclosing non-iterator code with
+diff --git a/js/src/frontend/IfEmitter.cpp b/js/src/frontend/IfEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/IfEmitter.cpp
+@@ -0,0 +1,219 @@
++/* -*- 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 "frontend/IfEmitter.h"
++
++#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)
++  : bce_(bce),
++    thenDepth_(0),
++    kind_(kind)
++#ifdef DEBUG
++  , pushed_(0),
++    calculatedPushed_(false),
++    state_(State::Start)
++#endif
++{}
++
++IfEmitter::IfEmitter(BytecodeEmitter* bce)
++  : IfEmitter(bce, Kind::MayContainLexicalAccessInBranch)
++{}
++
++bool
++IfEmitter::emitIfInternal(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_))
++        return false;
++
++    // To restore stack depth in else part, save depth of the then part.
++#ifdef DEBUG
++    // If DEBUG, this is also necessary to calculate |pushed_|.
++    thenDepth_ = bce_->stackDepth;
++#else
++    if (type == SRC_COND || type == SRC_IF_ELSE)
++        thenDepth_ = bce_->stackDepth;
++#endif
++
++    // Enclose then-branch with TDZCheckCache.
++    if (kind_ == Kind::MayContainLexicalAccessInBranch)
++        tdzCache_.emplace(bce_);
++
++    return true;
++}
++
++void
++IfEmitter::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()
++{
++    calculateOrCheckPushed();
++
++    // The end of TDZCheckCache for then-clause.
++    if (kind_ == Kind::MayContainLexicalAccessInBranch) {
++        MOZ_ASSERT(tdzCache_.isSome());
++        tdzCache_.reset();
++    }
++
++    // Emit a jump from the end of our then part around the else part. The
++    // patchJumpsToTarget call at the bottom of this function will fix up
++    // the offset with jumpsAroundElse value.
++    if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_))
++        return false;
++
++    // Ensure the branch-if-false comes here, then emit the else.
++    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()
++{
++    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();
++
++    if (jumpAroundThen_.offset != -1) {
++        // No else part for the last branch, fixup the branch-if-false to
++        // come here.
++        if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
++            return false;
++    }
++
++    // Patch all the jumps around else parts.
++    if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
++        return false;
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
++
++InternalIfEmitter::InternalIfEmitter(BytecodeEmitter* bce)
++  : IfEmitter(bce, Kind::NoLexicalAccessInBranch)
++{}
+diff --git a/js/src/frontend/IfEmitter.h b/js/src/frontend/IfEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/IfEmitter.h
+@@ -0,0 +1,217 @@
++/* -*- 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_IfEmitter_h
++#define frontend_IfEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stdint.h>
++
++#include "frontend/JumpList.h"
++#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
++{
++  public:
++    // 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.
++    //
++    // See the comment for TDZCheckCache class for more details.
++    enum class Kind {
++        // For syntactic branches (if, if-else, and conditional expression),
++        // 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_;
++
++    // 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_;
++#endif
++
++  protected:
++    // For InternalIfEmitter.
++    IfEmitter(BytecodeEmitter* bce, Kind kind);
++
++  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 which doesn't touch
++// lexical variables.
++//
++// See the comments above NoLexicalAccessInBranch for more details when to use
++// this instead of IfEmitter.
++class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter
++{
++  public:
++    explicit InternalIfEmitter(BytecodeEmitter* bce);
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_IfEmitter_h */
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -209,16 +209,17 @@ UNIFIED_SOURCES += [
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
++    'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',

+ 1497 - 0
frg/work-js/mozilla-release/patches/1460489-5-63a1.patch

@@ -0,0 +1,1497 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1531358654 -32400
+#      Thu Jul 12 10:24:14 2018 +0900
+# Node ID 8aeed50db2a79de718e0f9688d48531f9ddc4630
+# Parent  1f631b52845bdd5a67e9d284f38d69a58bd47e36
+Bug 1460489 - Part 5: Move TryEmitter and ForOfLoopControl to TryEmitter.{cpp.h} and ForOfLoopControl.{cpp.h} . 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
+@@ -21,19 +21,21 @@
+ #include "jsapi.h"
+ #include "jsnum.h"
+ #include "jstypes.h"
+ #include "jsutil.h"
+ 
+ #include "ds/Nestable.h"
+ #include "frontend/BytecodeControlStructures.h"
+ #include "frontend/EmitterScope.h"
++#include "frontend/ForOfLoopControl.h"
+ #include "frontend/IfEmitter.h"
+ #include "frontend/Parser.h"
+ #include "frontend/TDZCheckCache.h"
++#include "frontend/TryEmitter.h"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Debugger.h"
+ #include "vm/GeneratorObject.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSFunction.h"
+ #include "vm/JSScript.h"
+ #include "vm/Stack.h"
+@@ -69,649 +71,16 @@ ParseNodeRequiresSpecialLineNumberNotes(
+     // Functions usually shouldn't have location information (bug 1431202).
+ 
+     ParseNodeKind kind = pn->getKind();
+     return kind == ParseNodeKind::While ||
+            kind == ParseNodeKind::For ||
+            kind == ParseNodeKind::Function;
+ }
+ 
+-// Class for emitting bytecode for blocks like try-catch-finally.
+-//
+-// Usage: (check for the return value is omitted for simplicity)
+-//
+-//   `try { try_block } catch (ex) { catch_block }`
+-//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
+-//                         TryEmitter::ControlKind::Syntactic);
+-//     tryCatch.emitTry();
+-//     emit(try_block);
+-//     tryCatch.emitCatch();
+-//     emit(ex and catch_block); // use JSOP_EXCEPTION to get exception
+-//     tryCatch.emitEnd();
+-//
+-//   `try { try_block } finally { finally_block }`
+-//     TryEmitter tryCatch(this, TryEmitter::Kind::TryFinally,
+-//                         TryEmitter::ControlKind::Syntactic);
+-//     tryCatch.emitTry();
+-//     emit(try_block);
+-//     // finally_pos: The "{" character's position in the source code text.
+-//     tryCatch.emitFinally(Some(finally_pos));
+-//     emit(finally_block);
+-//     tryCatch.emitEnd();
+-//
+-//   `try { try_block } catch (ex) {catch_block} finally { finally_block }`
+-//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
+-//                         TryEmitter::ControlKind::Syntactic);
+-//     tryCatch.emitTry();
+-//     emit(try_block);
+-//     tryCatch.emitCatch();
+-//     emit(ex and catch_block);
+-//     tryCatch.emitFinally(Some(finally_pos));
+-//     emit(finally_block);
+-//     tryCatch.emitEnd();
+-//
+-class MOZ_STACK_CLASS TryEmitter
+-{
+-  public:
+-    enum class Kind {
+-        TryCatch,
+-        TryCatchFinally,
+-        TryFinally
+-    };
+-
+-    // Syntactic try-catch-finally and internally used non-syntactic
+-    // try-catch-finally behave differently for 2 points.
+-    //
+-    // The first one is whether TryFinallyControl is used or not.
+-    // See the comment for `controlInfo_`.
+-    //
+-    // The second one is whether the catch and finally blocks handle the frame's
+-    // return value.  For syntactic try-catch-finally, the bytecode marked with
+-    // "*" are emitted to clear return value with `undefined` before the catch
+-    // block and the finally block, and also to save/restore the return value
+-    // before/after the finally block.
+-    //
+-    //     JSOP_TRY
+-    //
+-    //     try_body...
+-    //
+-    //     JSOP_GOSUB finally
+-    //     JSOP_JUMPTARGET
+-    //     JSOP_GOTO end:
+-    //
+-    //   catch:
+-    //     JSOP_JUMPTARGET
+-    //   * JSOP_UNDEFINED
+-    //   * JSOP_SETRVAL
+-    //
+-    //     catch_body...
+-    //
+-    //     JSOP_GOSUB finally
+-    //     JSOP_JUMPTARGET
+-    //     JSOP_GOTO end
+-    //
+-    //   finally:
+-    //     JSOP_JUMPTARGET
+-    //   * JSOP_GETRVAL
+-    //   * JSOP_UNDEFINED
+-    //   * JSOP_SETRVAL
+-    //
+-    //     finally_body...
+-    //
+-    //   * JSOP_SETRVAL
+-    //     JSOP_NOP
+-    //
+-    //   end:
+-    //     JSOP_JUMPTARGET
+-    //
+-    // For syntactic try-catch-finally, Syntactic should be used.
+-    // For non-syntactic try-catch-finally, NonSyntactic should be used.
+-    enum class ControlKind {
+-        Syntactic,
+-        NonSyntactic
+-    };
+-
+-  private:
+-    BytecodeEmitter* bce_;
+-    Kind kind_;
+-    ControlKind controlKind_;
+-
+-    // Track jumps-over-catches and gosubs-to-finally for later fixup.
+-    //
+-    // When a finally block is active, non-local jumps (including
+-    // jumps-over-catches) result in a GOSUB being written into the bytecode
+-    // stream and fixed-up later.
+-    //
+-    // For non-syntactic try-catch-finally, all that handling is skipped.
+-    // The non-syntactic try-catch-finally must:
+-    //   * have only one catch block
+-    //   * have JSOP_GOTO at the end of catch-block
+-    //   * have no non-local-jump
+-    //   * don't use finally block for normal completion of try-block and
+-    //     catch-block
+-    //
+-    // Additionally, a finally block may be emitted for non-syntactic
+-    // try-catch-finally, even if the kind is TryCatch, because GOSUBs are not
+-    // emitted.
+-    Maybe<TryFinallyControl> controlInfo_;
+-
+-    // The stack depth before emitting JSOP_TRY.
+-    int depth_;
+-
+-    // The source note index for SRC_TRY.
+-    unsigned noteIndex_;
+-
+-    // The offset after JSOP_TRY.
+-    ptrdiff_t tryStart_;
+-
+-    // JSOP_JUMPTARGET after the entire try-catch-finally block.
+-    JumpList catchAndFinallyJump_;
+-
+-    // The offset of JSOP_GOTO at the end of the try block.
+-    JumpTarget tryEnd_;
+-
+-    // The offset of JSOP_JUMPTARGET at the beginning of the finally block.
+-    JumpTarget finallyStart_;
+-
+-#ifdef DEBUG
+-    // The state of this emitter.
+-    //
+-    // +-------+ emitTry +-----+   emitCatch +-------+      emitEnd  +-----+
+-    // | Start |-------->| Try |-+---------->| Catch |-+->+--------->| End |
+-    // +-------+         +-----+ |           +-------+ |  ^          +-----+
+-    //                           |                     |  |
+-    //                           |  +------------------+  +----+
+-    //                           |  |                          |
+-    //                           |  v emitFinally +---------+  |
+-    //                           +->+------------>| Finally |--+
+-    //                                            +---------+
+-    enum class State {
+-        // The initial state.
+-        Start,
+-
+-        // After calling emitTry.
+-        Try,
+-
+-        // After calling emitCatch.
+-        Catch,
+-
+-        // After calling emitFinally.
+-        Finally,
+-
+-        // After calling emitEnd.
+-        End
+-    };
+-    State state_;
+-#endif
+-
+-    bool hasCatch() const {
+-        return kind_ == Kind::TryCatch || kind_ == Kind::TryCatchFinally;
+-    }
+-    bool hasFinally() const {
+-        return kind_ == Kind::TryCatchFinally || kind_ == Kind::TryFinally;
+-    }
+-
+-  public:
+-    TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
+-      : bce_(bce),
+-        kind_(kind),
+-        controlKind_(controlKind),
+-        depth_(0),
+-        noteIndex_(0),
+-        tryStart_(0),
+-        tryEnd_{}
+-#ifdef DEBUG
+-      , state_(State::Start)
+-#endif
+-    {
+-        if (controlKind_ == ControlKind::Syntactic)
+-            controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
+-        finallyStart_.offset = 0;
+-    }
+-
+-    // Emits JSOP_GOTO to the end of try-catch-finally.
+-    // Used in `yield*`.
+-    MOZ_MUST_USE bool emitJumpOverCatchAndFinally() {
+-        if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
+-            return false;
+-        return true;
+-    }
+-
+-    MOZ_MUST_USE bool emitTry() {
+-        MOZ_ASSERT(state_ == State::Start);
+-
+-        // Since an exception can be thrown at any place inside the try block,
+-        // we need to restore the stack and the scope chain before we transfer
+-        // the control to the exception handler.
+-        //
+-        // For that we store in a try note associated with the catch or
+-        // finally block the stack depth upon the try entry. The interpreter
+-        // uses this depth to properly unwind the stack and the scope chain.
+-        depth_ = bce_->stackDepth;
+-
+-        // Record the try location, then emit the try block.
+-        if (!bce_->newSrcNote(SRC_TRY, &noteIndex_))
+-            return false;
+-        if (!bce_->emit1(JSOP_TRY))
+-            return false;
+-        tryStart_ = bce_->offset();
+-
+-#ifdef DEBUG
+-        state_ = State::Try;
+-#endif
+-        return true;
+-    }
+-
+-  private:
+-    MOZ_MUST_USE bool emitTryEnd() {
+-        MOZ_ASSERT(state_ == State::Try);
+-        MOZ_ASSERT(depth_ == bce_->stackDepth);
+-
+-        // GOSUB to finally, if present.
+-        if (hasFinally() && controlInfo_) {
+-            if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
+-                return false;
+-        }
+-
+-        // Source note points to the jump at the end of the try block.
+-        if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
+-            return false;
+-
+-        // Emit jump over catch and/or finally.
+-        if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
+-            return false;
+-
+-        if (!bce_->emitJumpTarget(&tryEnd_))
+-            return false;
+-
+-        return true;
+-    }
+-
+-  public:
+-    MOZ_MUST_USE bool emitCatch() {
+-        MOZ_ASSERT(state_ == State::Try);
+-        if (!emitTryEnd())
+-            return false;
+-
+-        MOZ_ASSERT(bce_->stackDepth == depth_);
+-
+-        if (controlKind_ == ControlKind::Syntactic) {
+-            // Clear the frame's return value that might have been set by the
+-            // try block:
+-            //
+-            //   eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
+-            if (!bce_->emit1(JSOP_UNDEFINED))
+-                return false;
+-            if (!bce_->emit1(JSOP_SETRVAL))
+-                return false;
+-        }
+-
+-#ifdef DEBUG
+-        state_ = State::Catch;
+-#endif
+-        return true;
+-    }
+-
+-  private:
+-    MOZ_MUST_USE bool emitCatchEnd() {
+-        MOZ_ASSERT(state_ == State::Catch);
+-
+-        if (!controlInfo_)
+-            return true;
+-
+-        // gosub <finally>, if required.
+-        if (hasFinally()) {
+-            if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
+-                return false;
+-            MOZ_ASSERT(bce_->stackDepth == depth_);
+-
+-            // Jump over the finally block.
+-            if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
+-                return false;
+-        }
+-
+-        return true;
+-    }
+-
+-  public:
+-    // If `finallyPos` is specified, it's an offset of the finally block's
+-    // "{" character in the source code text, to improve line:column number in
+-    // the error reporting.
+-    // For non-syntactic try-catch-finally, `finallyPos` can be omitted.
+-    MOZ_MUST_USE bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
+-        // If we are using controlInfo_ (i.e., emitting a syntactic try
+-        // blocks), we must have specified up front if there will be a finally
+-        // close. For internal non-syntactic try blocks, like those emitted for
+-        // yield* and IteratorClose inside for-of loops, we can emitFinally even
+-        // without specifying up front, since the internal non-syntactic try
+-        // blocks emit no GOSUBs.
+-        if (!controlInfo_) {
+-            if (kind_ == Kind::TryCatch)
+-                kind_ = Kind::TryCatchFinally;
+-        } else {
+-            MOZ_ASSERT(hasFinally());
+-        }
+-
+-        if (!hasCatch()) {
+-            MOZ_ASSERT(state_ == State::Try);
+-            if (!emitTryEnd())
+-                return false;
+-        } else {
+-            MOZ_ASSERT(state_ == State::Catch);
+-            if (!emitCatchEnd())
+-                return false;
+-        }
+-
+-        MOZ_ASSERT(bce_->stackDepth == depth_);
+-
+-        if (!bce_->emitJumpTarget(&finallyStart_))
+-            return false;
+-
+-        if (controlInfo_) {
+-            // Fix up the gosubs that might have been emitted before non-local
+-            // jumps to the finally code.
+-            bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
+-
+-            // Indicate that we're emitting a subroutine body.
+-            controlInfo_->setEmittingSubroutine();
+-        }
+-        if (finallyPos) {
+-            if (!bce_->updateSourceCoordNotes(finallyPos.value()))
+-                return false;
+-        }
+-        if (!bce_->emit1(JSOP_FINALLY))
+-            return false;
+-
+-        if (controlKind_ == ControlKind::Syntactic) {
+-            if (!bce_->emit1(JSOP_GETRVAL))
+-                return false;
+-
+-            // Clear the frame's return value to make break/continue return
+-            // correct value even if there's no other statement before them:
+-            //
+-            //   eval("x: try { 1 } finally { break x; }"); // undefined, not 1
+-            if (!bce_->emit1(JSOP_UNDEFINED))
+-                return false;
+-            if (!bce_->emit1(JSOP_SETRVAL))
+-                return false;
+-        }
+-
+-#ifdef DEBUG
+-        state_ = State::Finally;
+-#endif
+-        return true;
+-    }
+-
+-  private:
+-    MOZ_MUST_USE bool emitFinallyEnd() {
+-        MOZ_ASSERT(state_ == State::Finally);
+-
+-        if (controlKind_ == ControlKind::Syntactic) {
+-            if (!bce_->emit1(JSOP_SETRVAL))
+-                return false;
+-        }
+-
+-        if (!bce_->emit1(JSOP_RETSUB))
+-            return false;
+-
+-        bce_->hasTryFinally = true;
+-        return true;
+-    }
+-
+-  public:
+-    MOZ_MUST_USE bool emitEnd() {
+-        if (!hasFinally()) {
+-            MOZ_ASSERT(state_ == State::Catch);
+-            if (!emitCatchEnd())
+-                return false;
+-        } else {
+-            MOZ_ASSERT(state_ == State::Finally);
+-            if (!emitFinallyEnd())
+-                return false;
+-        }
+-
+-        MOZ_ASSERT(bce_->stackDepth == depth_);
+-
+-        // ReconstructPCStack needs a NOP here to mark the end of the last
+-        // catch block.
+-        if (!bce_->emit1(JSOP_NOP))
+-            return false;
+-
+-        // Fix up the end-of-try/catch jumps to come here.
+-        if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_))
+-            return false;
+-
+-        // Add the try note last, to let post-order give us the right ordering
+-        // (first to last for a given nesting level, inner to outer by level).
+-        if (hasCatch()) {
+-            if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_, tryEnd_.offset))
+-                return false;
+-        }
+-
+-        // If we've got a finally, mark try+catch region with additional
+-        // trynote to catch exceptions (re)thrown from a catch block or
+-        // for the try{}finally{} case.
+-        if (hasFinally()) {
+-            if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_, finallyStart_.offset))
+-                return false;
+-        }
+-
+-#ifdef DEBUG
+-        state_ = State::End;
+-#endif
+-        return true;
+-    }
+-};
+-
+-class ForOfLoopControl : public LoopControl
+-{
+-    // The stack depth of the iterator.
+-    int32_t iterDepth_;
+-
+-    // for-of loops, when throwing from non-iterator code (i.e. from the body
+-    // or from evaluating the LHS of the loop condition), need to call
+-    // IteratorClose.  This is done by enclosing non-iterator code with
+-    // try-catch and call IteratorClose in `catch` block.
+-    // If IteratorClose itself throws, we must not re-call IteratorClose. Since
+-    // non-local jumps like break and return call IteratorClose, whenever a
+-    // non-local jump is emitted, we must tell catch block not to perform
+-    // IteratorClose.
+-    //
+-    //   for (x of y) {
+-    //     // Operations for iterator (IteratorNext etc) are outside of
+-    //     // try-block.
+-    //     try {
+-    //       ...
+-    //       if (...) {
+-    //         // Before non-local jump, clear iterator on the stack to tell
+-    //         // catch block not to perform IteratorClose.
+-    //         tmpIterator = iterator;
+-    //         iterator = undefined;
+-    //         IteratorClose(tmpIterator, { break });
+-    //         break;
+-    //       }
+-    //       ...
+-    //     } catch (e) {
+-    //       // Just throw again when iterator is cleared by non-local jump.
+-    //       if (iterator === undefined)
+-    //         throw e;
+-    //       IteratorClose(iterator, { throw, e });
+-    //     }
+-    //   }
+-    Maybe<TryEmitter> tryCatch_;
+-
+-    // Used to track if any yields were emitted between calls to to
+-    // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
+-    uint32_t numYieldsAtBeginCodeNeedingIterClose_;
+-
+-    bool allowSelfHosted_;
+-
+-    IteratorKind iterKind_;
+-
+-  public:
+-    ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
+-                     IteratorKind iterKind)
+-      : LoopControl(bce, StatementKind::ForOfLoop),
+-        iterDepth_(iterDepth),
+-        numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
+-        allowSelfHosted_(allowSelfHosted),
+-        iterKind_(iterKind)
+-    {
+-    }
+-
+-    bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
+-        tryCatch_.emplace(bce, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
+-
+-        if (!tryCatch_->emitTry())
+-            return false;
+-
+-        MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
+-        numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
+-
+-        return true;
+-    }
+-
+-    bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
+-        if (!tryCatch_->emitCatch())              // ITER ...
+-            return false;
+-
+-        if (!bce->emit1(JSOP_EXCEPTION))          // ITER ... EXCEPTION
+-            return false;
+-        unsigned slotFromTop = bce->stackDepth - iterDepth_;
+-        if (!bce->emitDupAt(slotFromTop))         // ITER ... EXCEPTION ITER
+-            return false;
+-
+-        // If ITER is undefined, it means the exception is thrown by
+-        // IteratorClose for non-local jump, and we should't perform
+-        // IteratorClose again here.
+-        if (!bce->emit1(JSOP_UNDEFINED))          // ITER ... EXCEPTION ITER UNDEF
+-            return false;
+-        if (!bce->emit1(JSOP_STRICTNE))           // ITER ... EXCEPTION NE
+-            return false;
+-
+-        InternalIfEmitter ifIteratorIsNotClosed(bce);
+-        if (!ifIteratorIsNotClosed.emitThen())    // ITER ... EXCEPTION
+-            return false;
+-
+-        MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
+-        if (!bce->emitDupAt(slotFromTop))         // ITER ... EXCEPTION ITER
+-            return false;
+-        if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
+-            return false;                         // ITER ... EXCEPTION
+-
+-        if (!ifIteratorIsNotClosed.emitEnd())     // ITER ... EXCEPTION
+-            return false;
+-
+-        if (!bce->emit1(JSOP_THROW))              // ITER ...
+-            return false;
+-
+-        // If any yields were emitted, then this for-of loop is inside a star
+-        // generator and must handle the case of Generator.return. Like in
+-        // yield*, it is handled with a finally block.
+-        uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
+-        if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
+-            if (!tryCatch_->emitFinally())
+-                return false;
+-
+-            InternalIfEmitter ifGeneratorClosing(bce);
+-            if (!bce->emit1(JSOP_ISGENCLOSING))   // ITER ... FTYPE FVALUE CLOSING
+-                return false;
+-            if (!ifGeneratorClosing.emitThen())   // ITER ... FTYPE FVALUE
+-                return false;
+-            if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
+-                return false;
+-            if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
+-                return false;                     // ITER ... FTYPE FVALUE
+-            if (!ifGeneratorClosing.emitEnd())    // ITER ... FTYPE FVALUE
+-                return false;
+-        }
+-
+-        if (!tryCatch_->emitEnd())
+-            return false;
+-
+-        tryCatch_.reset();
+-        numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
+-
+-        return true;
+-    }
+-
+-    bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
+-                                           CompletionKind completionKind = CompletionKind::Normal) {
+-        return emitIteratorCloseInScope(bce,  *bce->innermostEmitterScope(), completionKind);
+-    }
+-
+-    bool emitIteratorCloseInScope(BytecodeEmitter* bce,
+-                                  EmitterScope& currentScope,
+-                                  CompletionKind completionKind = CompletionKind::Normal) {
+-        ptrdiff_t start = bce->offset();
+-        if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
+-                                           allowSelfHosted_))
+-        {
+-            return false;
+-        }
+-        ptrdiff_t end = bce->offset();
+-        return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
+-    }
+-
+-    bool 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
+-        // try-catch block.
+-        if (!bce->emit1(JSOP_POP))                        // NEXT ITER
+-            return false;
+-
+-        // Pop the iterator's next method.
+-        if (!bce->emit1(JSOP_SWAP))                       // ITER NEXT
+-            return false;
+-        if (!bce->emit1(JSOP_POP))                        // ITER
+-            return false;
+-
+-        // Clear ITER slot on the stack to tell catch block to avoid performing
+-        // IteratorClose again.
+-        if (!bce->emit1(JSOP_UNDEFINED))                  // ITER UNDEF
+-            return false;
+-        if (!bce->emit1(JSOP_SWAP))                       // UNDEF ITER
+-            return false;
+-
+-        if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) // UNDEF
+-            return false;
+-
+-        if (isTarget) {
+-            // At the level of the target block, there's bytecode after the
+-            // loop that will pop the next method, the iterator, and the
+-            // value, so push two undefineds to balance the stack.
+-            if (!bce->emit1(JSOP_UNDEFINED))              // UNDEF UNDEF
+-                return false;
+-            if (!bce->emit1(JSOP_UNDEFINED))              // UNDEF UNDEF UNDEF
+-                return false;
+-        } else {
+-            if (!bce->emit1(JSOP_POP))                    //
+-                return false;
+-        }
+-
+-        return true;
+-    }
+-};
+-
+-namespace js {
+-namespace frontend {
+-
+-template <>
+-bool
+-NestableControl::is<ForOfLoopControl>() const
+-{
+-    return kind_ == StatementKind::ForOfLoop;
+-}
+-
+-} // namespace frontend
+-} // namespace js
+-
+ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
+                                  SharedContext* sc, HandleScript script,
+                                  Handle<LazyScript*> lazyScript,
+                                  uint32_t lineNum, EmitterMode emitterMode)
+   : sc(sc),
+     cx(sc->context),
+     parent(parent),
+     script(cx, script),
+diff --git a/js/src/frontend/ForOfLoopControl.cpp b/js/src/frontend/ForOfLoopControl.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/ForOfLoopControl.cpp
+@@ -0,0 +1,169 @@
++/* -*- 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 "frontend/ForOfLoopControl.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/EmitterScope.h"
++#include "frontend/IfEmitter.h"
++
++using namespace js;
++using namespace js::frontend;
++
++ForOfLoopControl::ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
++                                   IteratorKind iterKind)
++  : LoopControl(bce, StatementKind::ForOfLoop),
++    iterDepth_(iterDepth),
++    numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
++    allowSelfHosted_(allowSelfHosted),
++    iterKind_(iterKind)
++{}
++
++bool
++ForOfLoopControl::emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce)
++{
++    tryCatch_.emplace(bce, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
++
++    if (!tryCatch_->emitTry())
++        return false;
++
++    MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
++    numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
++
++    return true;
++}
++
++bool
++ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce)
++{
++    if (!tryCatch_->emitCatch())              // ITER ...
++        return false;
++
++    if (!bce->emit1(JSOP_EXCEPTION))          // ITER ... EXCEPTION
++        return false;
++    unsigned slotFromTop = bce->stackDepth - iterDepth_;
++    if (!bce->emitDupAt(slotFromTop))         // ITER ... EXCEPTION ITER
++        return false;
++
++    // If ITER is undefined, it means the exception is thrown by
++    // IteratorClose for non-local jump, and we should't perform
++    // IteratorClose again here.
++    if (!bce->emit1(JSOP_UNDEFINED))          // ITER ... EXCEPTION ITER UNDEF
++        return false;
++    if (!bce->emit1(JSOP_STRICTNE))           // ITER ... EXCEPTION NE
++        return false;
++
++    InternalIfEmitter ifIteratorIsNotClosed(bce);
++    if (!ifIteratorIsNotClosed.emitThen())    // ITER ... EXCEPTION
++        return false;
++
++    MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
++    if (!bce->emitDupAt(slotFromTop))         // ITER ... EXCEPTION ITER
++        return false;
++    if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
++        return false;                         // ITER ... EXCEPTION
++
++    if (!ifIteratorIsNotClosed.emitEnd())     // ITER ... EXCEPTION
++        return false;
++
++    if (!bce->emit1(JSOP_THROW))              // ITER ...
++        return false;
++
++    // If any yields were emitted, then this for-of loop is inside a star
++    // generator and must handle the case of Generator.return. Like in
++    // yield*, it is handled with a finally block.
++    uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
++    if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
++        if (!tryCatch_->emitFinally())
++            return false;
++
++        InternalIfEmitter ifGeneratorClosing(bce);
++        if (!bce->emit1(JSOP_ISGENCLOSING))   // ITER ... FTYPE FVALUE CLOSING
++            return false;
++        if (!ifGeneratorClosing.emitThen())   // ITER ... FTYPE FVALUE
++            return false;
++        if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
++            return false;
++        if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
++            return false;                     // ITER ... FTYPE FVALUE
++        if (!ifGeneratorClosing.emitEnd())    // ITER ... FTYPE FVALUE
++            return false;
++    }
++
++    if (!tryCatch_->emitEnd())
++        return false;
++
++    tryCatch_.reset();
++    numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
++
++    return true;
++}
++
++bool
++ForOfLoopControl::emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
++                                                    CompletionKind completionKind /* = CompletionKind::Normal */)
++{
++    return emitIteratorCloseInScope(bce,  *bce->innermostEmitterScope(), completionKind);
++}
++
++bool
++ForOfLoopControl::emitIteratorCloseInScope(BytecodeEmitter* bce,
++                                           EmitterScope& currentScope,
++                                           CompletionKind completionKind /* = CompletionKind::Normal */)
++{
++    ptrdiff_t start = bce->offset();
++    if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
++                                       allowSelfHosted_))
++    {
++        return false;
++    }
++    ptrdiff_t end = bce->offset();
++    return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
++}
++
++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
++    // try-catch block.
++    if (!bce->emit1(JSOP_POP))                        // NEXT ITER
++        return false;
++
++    // Pop the iterator's next method.
++    if (!bce->emit1(JSOP_SWAP))                       // ITER NEXT
++        return false;
++    if (!bce->emit1(JSOP_POP))                        // ITER
++        return false;
++
++    // Clear ITER slot on the stack to tell catch block to avoid performing
++    // IteratorClose again.
++    if (!bce->emit1(JSOP_UNDEFINED))                  // ITER UNDEF
++        return false;
++    if (!bce->emit1(JSOP_SWAP))                       // UNDEF ITER
++        return false;
++
++    if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) // UNDEF
++        return false;
++
++    if (isTarget) {
++        // At the level of the target block, there's bytecode after the
++        // loop that will pop the next method, the iterator, and the
++        // value, so push two undefineds to balance the stack.
++        if (!bce->emit1(JSOP_UNDEFINED))              // UNDEF UNDEF
++            return false;
++        if (!bce->emit1(JSOP_UNDEFINED))              // UNDEF UNDEF UNDEF
++            return false;
++    } else {
++        if (!bce->emit1(JSOP_POP))                    //
++            return false;
++    }
++
++    return true;
++}
+diff --git a/js/src/frontend/ForOfLoopControl.h b/js/src/frontend/ForOfLoopControl.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/ForOfLoopControl.h
+@@ -0,0 +1,99 @@
++/* -*- 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_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;
++class EmitterScope;
++
++class ForOfLoopControl : public LoopControl
++{
++    // The stack depth of the iterator.
++    int32_t iterDepth_;
++
++    // for-of loops, when throwing from non-iterator code (i.e. from the body
++    // or from evaluating the LHS of the loop condition), need to call
++    // IteratorClose.  This is done by enclosing non-iterator code with
++    // try-catch and call IteratorClose in `catch` block.
++    // If IteratorClose itself throws, we must not re-call IteratorClose. Since
++    // non-local jumps like break and return call IteratorClose, whenever a
++    // non-local jump is emitted, we must tell catch block not to perform
++    // IteratorClose.
++    //
++    //   for (x of y) {
++    //     // Operations for iterator (IteratorNext etc) are outside of
++    //     // try-block.
++    //     try {
++    //       ...
++    //       if (...) {
++    //         // Before non-local jump, clear iterator on the stack to tell
++    //         // catch block not to perform IteratorClose.
++    //         tmpIterator = iterator;
++    //         iterator = undefined;
++    //         IteratorClose(tmpIterator, { break });
++    //         break;
++    //       }
++    //       ...
++    //     } catch (e) {
++    //       // Just throw again when iterator is cleared by non-local jump.
++    //       if (iterator === undefined)
++    //         throw e;
++    //       IteratorClose(iterator, { throw, e });
++    //     }
++    //   }
++    mozilla::Maybe<TryEmitter> tryCatch_;
++
++    // Used to track if any yields were emitted between calls to to
++    // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
++    uint32_t numYieldsAtBeginCodeNeedingIterClose_;
++
++    bool allowSelfHosted_;
++
++    IteratorKind iterKind_;
++
++  public:
++    ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
++                     IteratorKind iterKind);
++
++    MOZ_MUST_USE bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce);
++    MOZ_MUST_USE bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce);
++
++    MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
++                                                        CompletionKind completionKind = CompletionKind::Normal);
++    MOZ_MUST_USE bool emitIteratorCloseInScope(BytecodeEmitter* bce,
++                                               EmitterScope& currentScope,
++                                               CompletionKind completionKind = CompletionKind::Normal);
++
++    MOZ_MUST_USE bool emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
++                                                          EmitterScope& currentScope,
++                                                          bool isTarget);
++};
++template <>
++inline bool
++NestableControl::is<ForOfLoopControl>() const
++{
++    return kind_ == StatementKind::ForOfLoop;
++}
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_ForOfLoopControl_h */
+diff --git a/js/src/frontend/TryEmitter.cpp b/js/src/frontend/TryEmitter.cpp
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/TryEmitter.cpp
+@@ -0,0 +1,271 @@
++/* -*- 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 "frontend/TryEmitter.h"
++
++#include "frontend/BytecodeEmitter.h"
++#include "frontend/SourceNotes.h"
++#include "vm/Opcodes.h"
++
++using namespace js;
++using namespace js::frontend;
++
++using mozilla::Maybe;
++
++TryEmitter::TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
++  : bce_(bce),
++    kind_(kind),
++    controlKind_(controlKind),
++    depth_(0),
++    noteIndex_(0),
++    tryStart_(0)
++#ifdef DEBUG
++  , state_(State::Start)
++#endif
++{
++    if (controlKind_ == ControlKind::Syntactic)
++        controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
++    finallyStart_.offset = 0;
++}
++
++// Emits JSOP_GOTO to the end of try-catch-finally.
++// Used in `yield*`.
++bool
++TryEmitter::emitJumpOverCatchAndFinally()
++{
++    if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
++        return false;
++    return true;
++}
++
++bool
++TryEmitter::emitTry()
++{
++    MOZ_ASSERT(state_ == State::Start);
++
++    // Since an exception can be thrown at any place inside the try block,
++    // we need to restore the stack and the scope chain before we transfer
++    // the control to the exception handler.
++    //
++    // For that we store in a try note associated with the catch or
++    // finally block the stack depth upon the try entry. The interpreter
++    // uses this depth to properly unwind the stack and the scope chain.
++    depth_ = bce_->stackDepth;
++
++    // Record the try location, then emit the try block.
++    if (!bce_->newSrcNote(SRC_TRY, &noteIndex_))
++        return false;
++    if (!bce_->emit1(JSOP_TRY))
++        return false;
++    tryStart_ = bce_->offset();
++
++#ifdef DEBUG
++    state_ = State::Try;
++#endif
++    return true;
++}
++
++bool
++TryEmitter::emitTryEnd()
++{
++    MOZ_ASSERT(state_ == State::Try);
++    MOZ_ASSERT(depth_ == bce_->stackDepth);
++
++    // GOSUB to finally, if present.
++    if (hasFinally() && controlInfo_) {
++        if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
++            return false;
++    }
++
++    // Source note points to the jump at the end of the try block.
++    if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
++        return false;
++
++    // Emit jump over catch and/or finally.
++    if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
++        return false;
++
++    if (!bce_->emitJumpTarget(&tryEnd_))
++        return false;
++
++    return true;
++}
++
++bool
++TryEmitter::emitCatch()
++{
++    MOZ_ASSERT(state_ == State::Try);
++    if (!emitTryEnd())
++        return false;
++
++    MOZ_ASSERT(bce_->stackDepth == depth_);
++
++    if (controlKind_ == ControlKind::Syntactic) {
++        // Clear the frame's return value that might have been set by the
++        // try block:
++        //
++        //   eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
++        if (!bce_->emit1(JSOP_UNDEFINED))
++            return false;
++        if (!bce_->emit1(JSOP_SETRVAL))
++            return false;
++    }
++
++#ifdef DEBUG
++    state_ = State::Catch;
++#endif
++    return true;
++}
++
++bool
++TryEmitter::emitCatchEnd()
++{
++    MOZ_ASSERT(state_ == State::Catch);
++
++    if (!controlInfo_)
++        return true;
++
++    // gosub <finally>, if required.
++    if (hasFinally()) {
++        if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
++            return false;
++        MOZ_ASSERT(bce_->stackDepth == depth_);
++
++        // Jump over the finally block.
++        if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
++            return false;
++    }
++
++    return true;
++}
++
++bool
++TryEmitter::emitFinally(const Maybe<uint32_t>& finallyPos /* = Nothing() */)
++{
++    // If we are using controlInfo_ (i.e., emitting a syntactic try
++    // blocks), we must have specified up front if there will be a finally
++    // close. For internal non-syntactic try blocks, like those emitted for
++    // yield* and IteratorClose inside for-of loops, we can emitFinally even
++    // without specifying up front, since the internal non-syntactic try
++    // blocks emit no GOSUBs.
++    if (!controlInfo_) {
++        if (kind_ == Kind::TryCatch)
++            kind_ = Kind::TryCatchFinally;
++    } else {
++        MOZ_ASSERT(hasFinally());
++    }
++
++    if (!hasCatch()) {
++        MOZ_ASSERT(state_ == State::Try);
++        if (!emitTryEnd())
++            return false;
++    } else {
++        MOZ_ASSERT(state_ == State::Catch);
++        if (!emitCatchEnd())
++            return false;
++    }
++
++    MOZ_ASSERT(bce_->stackDepth == depth_);
++
++    if (!bce_->emitJumpTarget(&finallyStart_))
++        return false;
++
++    if (controlInfo_) {
++        // Fix up the gosubs that might have been emitted before non-local
++        // jumps to the finally code.
++        bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
++
++        // Indicate that we're emitting a subroutine body.
++        controlInfo_->setEmittingSubroutine();
++    }
++    if (finallyPos) {
++        if (!bce_->updateSourceCoordNotes(finallyPos.value()))
++            return false;
++    }
++    if (!bce_->emit1(JSOP_FINALLY))
++        return false;
++
++    if (controlKind_ == ControlKind::Syntactic) {
++        if (!bce_->emit1(JSOP_GETRVAL))
++            return false;
++
++        // Clear the frame's return value to make break/continue return
++        // correct value even if there's no other statement before them:
++        //
++        //   eval("x: try { 1 } finally { break x; }"); // undefined, not 1
++        if (!bce_->emit1(JSOP_UNDEFINED))
++            return false;
++        if (!bce_->emit1(JSOP_SETRVAL))
++            return false;
++    }
++
++#ifdef DEBUG
++    state_ = State::Finally;
++#endif
++    return true;
++}
++
++bool
++TryEmitter::emitFinallyEnd()
++{
++    MOZ_ASSERT(state_ == State::Finally);
++
++    if (controlKind_ == ControlKind::Syntactic) {
++        if (!bce_->emit1(JSOP_SETRVAL))
++            return false;
++    }
++
++    if (!bce_->emit1(JSOP_RETSUB))
++        return false;
++
++    bce_->hasTryFinally = true;
++    return true;
++}
++
++bool
++TryEmitter::emitEnd()
++{
++    if (!hasFinally()) {
++        MOZ_ASSERT(state_ == State::Catch);
++        if (!emitCatchEnd())
++            return false;
++    } else {
++        MOZ_ASSERT(state_ == State::Finally);
++        if (!emitFinallyEnd())
++            return false;
++    }
++
++    MOZ_ASSERT(bce_->stackDepth == depth_);
++
++    // ReconstructPCStack needs a NOP here to mark the end of the last
++    // catch block.
++    if (!bce_->emit1(JSOP_NOP))
++        return false;
++
++    // Fix up the end-of-try/catch jumps to come here.
++    if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_))
++        return false;
++
++    // Add the try note last, to let post-order give us the right ordering
++    // (first to last for a given nesting level, inner to outer by level).
++    if (hasCatch()) {
++        if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_, tryEnd_.offset))
++            return false;
++    }
++
++    // If we've got a finally, mark try+catch region with additional
++    // trynote to catch exceptions (re)thrown from a catch block or
++    // for the try{}finally{} case.
++    if (hasFinally()) {
++        if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_, finallyStart_.offset))
++            return false;
++    }
++
++#ifdef DEBUG
++    state_ = State::End;
++#endif
++    return true;
++}
+diff --git a/js/src/frontend/TryEmitter.h b/js/src/frontend/TryEmitter.h
+new file mode 100644
+--- /dev/null
++++ b/js/src/frontend/TryEmitter.h
+@@ -0,0 +1,227 @@
++/* -*- 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_TryEmitter_h
++#define frontend_TryEmitter_h
++
++#include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
++
++#include <stddef.h>
++#include <stdint.h>
++
++#include "frontend/BytecodeControlStructures.h"
++#include "frontend/JumpList.h"
++#include "frontend/TDZCheckCache.h"
++
++namespace js {
++namespace frontend {
++
++struct BytecodeEmitter;
++
++// Class for emitting bytecode for blocks like try-catch-finally.
++//
++// Usage: (check for the return value is omitted for simplicity)
++//
++//   `try { try_block } catch (ex) { catch_block }`
++//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
++//                         TryEmitter::ControlKind::Syntactic);
++//     tryCatch.emitTry();
++//     emit(try_block);
++//     tryCatch.emitCatch();
++//     emit(ex and catch_block); // use JSOP_EXCEPTION to get exception
++//     tryCatch.emitEnd();
++//
++//   `try { try_block } finally { finally_block }`
++//     TryEmitter tryCatch(this, TryEmitter::Kind::TryFinally,
++//                         TryEmitter::ControlKind::Syntactic);
++//     tryCatch.emitTry();
++//     emit(try_block);
++//     // finally_pos: The "{" character's position in the source code text.
++//     tryCatch.emitFinally(Some(finally_pos));
++//     emit(finally_block);
++//     tryCatch.emitEnd();
++//
++//   `try { try_block } catch (ex) {catch_block} finally { finally_block }`
++//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
++//                         TryEmitter::ControlKind::Syntactic);
++//     tryCatch.emitTry();
++//     emit(try_block);
++//     tryCatch.emitCatch();
++//     emit(ex and catch_block);
++//     tryCatch.emitFinally(Some(finally_pos));
++//     emit(finally_block);
++//     tryCatch.emitEnd();
++//
++class MOZ_STACK_CLASS TryEmitter
++{
++  public:
++    enum class Kind {
++        TryCatch,
++        TryCatchFinally,
++        TryFinally
++    };
++
++    // Syntactic try-catch-finally and internally used non-syntactic
++    // try-catch-finally behave differently for 2 points.
++    //
++    // The first one is whether TryFinallyControl is used or not.
++    // See the comment for `controlInfo_`.
++    //
++    // The second one is whether the catch and finally blocks handle the frame's
++    // return value.  For syntactic try-catch-finally, the bytecode marked with
++    // "*" are emitted to clear return value with `undefined` before the catch
++    // block and the finally block, and also to save/restore the return value
++    // before/after the finally block.
++    //
++    //     JSOP_TRY
++    //
++    //     try_body...
++    //
++    //     JSOP_GOSUB finally
++    //     JSOP_JUMPTARGET
++    //     JSOP_GOTO end:
++    //
++    //   catch:
++    //     JSOP_JUMPTARGET
++    //   * JSOP_UNDEFINED
++    //   * JSOP_SETRVAL
++    //
++    //     catch_body...
++    //
++    //     JSOP_GOSUB finally
++    //     JSOP_JUMPTARGET
++    //     JSOP_GOTO end
++    //
++    //   finally:
++    //     JSOP_JUMPTARGET
++    //   * JSOP_GETRVAL
++    //   * JSOP_UNDEFINED
++    //   * JSOP_SETRVAL
++    //
++    //     finally_body...
++    //
++    //   * JSOP_SETRVAL
++    //     JSOP_NOP
++    //
++    //   end:
++    //     JSOP_JUMPTARGET
++    //
++    // For syntactic try-catch-finally, Syntactic should be used.
++    // For non-syntactic try-catch-finally, NonSyntactic should be used.
++    enum class ControlKind {
++        Syntactic,
++        NonSyntactic
++    };
++
++  private:
++    BytecodeEmitter* bce_;
++    Kind kind_;
++    ControlKind controlKind_;
++
++    // Track jumps-over-catches and gosubs-to-finally for later fixup.
++    //
++    // When a finally block is active, non-local jumps (including
++    // jumps-over-catches) result in a GOSUB being written into the bytecode
++    // stream and fixed-up later.
++    //
++    // For non-syntactic try-catch-finally, all that handling is skipped.
++    // The non-syntactic try-catch-finally must:
++    //   * have only one catch block
++    //   * have JSOP_GOTO at the end of catch-block
++    //   * have no non-local-jump
++    //   * don't use finally block for normal completion of try-block and
++    //     catch-block
++    //
++    // Additionally, a finally block may be emitted for non-syntactic
++    // try-catch-finally, even if the kind is TryCatch, because GOSUBs are not
++    // emitted.
++    mozilla::Maybe<TryFinallyControl> controlInfo_;
++
++    // The stack depth before emitting JSOP_TRY.
++    int depth_;
++
++    // The source note index for SRC_TRY.
++    unsigned noteIndex_;
++
++    // The offset after JSOP_TRY.
++    ptrdiff_t tryStart_;
++
++    // JSOP_JUMPTARGET after the entire try-catch-finally block.
++    JumpList catchAndFinallyJump_;
++
++    // The offset of JSOP_GOTO at the end of the try block.
++    JumpTarget tryEnd_;
++
++    // The offset of JSOP_JUMPTARGET at the beginning of the finally block.
++    JumpTarget finallyStart_;
++
++#ifdef DEBUG
++    // The state of this emitter.
++    //
++    // +-------+ emitTry +-----+   emitCatch +-------+      emitEnd  +-----+
++    // | Start |-------->| Try |-+---------->| Catch |-+->+--------->| End |
++    // +-------+         +-----+ |           +-------+ |  ^          +-----+
++    //                           |                     |  |
++    //                           |  +------------------+  +----+
++    //                           |  |                          |
++    //                           |  v emitFinally +---------+  |
++    //                           +->+------------>| Finally |--+
++    //                                            +---------+
++    enum class State {
++        // The initial state.
++        Start,
++
++        // After calling emitTry.
++        Try,
++
++        // After calling emitCatch.
++        Catch,
++
++        // After calling emitFinally.
++        Finally,
++
++        // After calling emitEnd.
++        End
++    };
++    State state_;
++#endif
++
++    bool hasCatch() const {
++        return kind_ == Kind::TryCatch || kind_ == Kind::TryCatchFinally;
++    }
++    bool hasFinally() const {
++        return kind_ == Kind::TryCatchFinally || kind_ == Kind::TryFinally;
++    }
++
++  public:
++    TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind);
++
++    // Emits JSOP_GOTO to the end of try-catch-finally.
++    // Used in `yield*`.
++    MOZ_MUST_USE bool emitJumpOverCatchAndFinally();
++
++    MOZ_MUST_USE bool emitTry();
++    MOZ_MUST_USE bool emitCatch();
++
++    // If `finallyPos` is specified, it's an offset of the finally block's
++    // "{" character in the source code text, to improve line:column number in
++    // the error reporting.
++    // For non-syntactic try-catch-finally, `finallyPos` can be omitted.
++    MOZ_MUST_USE bool emitFinally(const mozilla::Maybe<uint32_t>& finallyPos = mozilla::Nothing());
++
++    MOZ_MUST_USE bool emitEnd();
++
++  private:
++    MOZ_MUST_USE bool emitTryEnd();
++    MOZ_MUST_USE bool emitCatchEnd();
++    MOZ_MUST_USE bool emitFinallyEnd();
++};
++
++} /* namespace frontend */
++} /* namespace js */
++
++#endif /* frontend_TryEmitter_h */
+diff --git a/js/src/moz.build b/js/src/moz.build
+--- a/js/src/moz.build
++++ b/js/src/moz.build
+@@ -209,22 +209,24 @@ UNIFIED_SOURCES += [
+     'ds/Bitmap.cpp',
+     'ds/LifoAlloc.cpp',
+     'ds/MemoryProtectionExceptionHandler.cpp',
+     'frontend/BytecodeCompiler.cpp',
+     'frontend/BytecodeControlStructures.cpp',
+     'frontend/BytecodeEmitter.cpp',
+     'frontend/EmitterScope.cpp',
+     'frontend/FoldConstants.cpp',
++    'frontend/ForOfLoopControl.cpp',
+     'frontend/IfEmitter.cpp',
+     'frontend/JumpList.cpp',
+     'frontend/NameFunctions.cpp',
+     'frontend/ParseNode.cpp',
+     'frontend/TDZCheckCache.cpp',
+     'frontend/TokenStream.cpp',
++    'frontend/TryEmitter.cpp',
+     'gc/Allocator.cpp',
+     'gc/AtomMarking.cpp',
+     'gc/Barrier.cpp',
+     'gc/GC.cpp',
+     'gc/GCTrace.cpp',
+     'gc/Marking.cpp',
+     'gc/Memory.cpp',
+     'gc/Nursery.cpp',

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


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

@@ -2,7 +2,7 @@
 # User Nicolas B. Pierron <nicolas.b.pierron@gmail.com>
 # Date 1526910004 0
 # Node ID 7ae884246635638898303dbceb50901a18fb5bf0
-# Parent  289ba9efaf5f522109ec4963d556c6d103ca6ed8
+# Parent  43a0d31fcf89c4e42d67b54de821d2d651ac8290
 Bug 1461672 - Remove Telemetry probe added to tune the JSBC. r=francois,bkelly
 
 And while we are on it kick CollectScriptTelemetry() too for the SeaMonkey branch.
@@ -84,7 +84,7 @@ diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
  
    // This would be called when document get activated by specific user gestures
    // and propagate the user activation flag to its parent.
-@@ -3718,19 +3713,16 @@ protected:
+@@ -3723,19 +3718,16 @@ protected:
    // Flags for use counters used directly by this document.
    std::bitset<mozilla::eUseCounter_Count> mUseCounters;
    // Flags for use counters used by any child documents of this document.
@@ -201,7 +201,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
  // This is how IE seems to filter out a window's onload handler from a
  // <script for=... event=...> element.
  
-@@ -1515,17 +1463,16 @@ ScriptLoader::ProcessInlineScript(nsIScr
+@@ -1493,17 +1441,16 @@ ScriptLoader::ProcessInlineScript(nsIScr
                        SRIMetadata(), // SRI doesn't apply
                        mDocument->GetReferrerPolicy());
    request->mIsInline = true;
@@ -219,7 +219,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    request->SetScriptMode(false, aElement->GetScriptAsync());
  
    LOG(("ScriptLoadRequest (%p): Created request for inline script",
-@@ -2196,19 +2143,16 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+@@ -2167,19 +2114,16 @@ ScriptLoader::EvaluateScript(ScriptLoadR
  
    nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
    nsIDocument* ownerDoc = scriptContent->OwnerDoc();
@@ -239,7 +239,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
      return NS_ERROR_FAILURE;
    }
  
-@@ -2283,65 +2227,47 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+@@ -2254,65 +2198,47 @@ ScriptLoader::EvaluateScript(ScriptLoadR
        rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
  
        if (NS_SUCCEEDED(rv)) {
@@ -305,7 +305,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
              aRequest->mScript = script;
              HoldJSObjects(aRequest);
              TRACE_FOR_TEST(aRequest->mElement, "scriptloader_encode");
-@@ -2449,17 +2375,16 @@ ScriptLoader::EncodeBytecode()
+@@ -2420,17 +2346,16 @@ ScriptLoader::EncodeBytecode()
    }
  
    nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext();
@@ -323,7 +323,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
      request->mScriptBytecode.clearAndFree();
      request->DropBytecodeCacheReferences();
    }
-@@ -2474,62 +2399,54 @@ ScriptLoader::EncodeRequestBytecode(JSCo
+@@ -2445,62 +2370,54 @@ ScriptLoader::EncodeRequestBytecode(JSCo
    auto bytecodeFailed = mozilla::MakeScopeExit([&]() {
      TRACE_FOR_TEST_NONE(aRequest->mElement, "scriptloader_bytecode_failed");
    });
@@ -386,7 +386,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    // If the document went away prematurely, we still want to set this, in order
    // to avoid queuing more scripts.
    mGiveUpEncoding = true;
-@@ -2775,20 +2692,16 @@ ScriptLoader::ConvertToUTF16(nsIChannel*
+@@ -2746,20 +2663,16 @@ ScriptLoader::ConvertToUTF16(nsIChannel*
    Tie(result, read, written, hadErrors) =
      unicodeDecoder->DecodeToUTF16(data, MakeSpan(aBufOut, unicodeLength), true);
    MOZ_ASSERT(result == kInputEmpty);
@@ -407,7 +407,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
                                 ScriptLoadRequest* aRequest,
                                 nsresult aChannelStatus,
                                 nsresult aSRIStatus,
-@@ -3093,17 +3006,16 @@ ScriptLoader::PrepareLoadedRequest(Scrip
+@@ -3064,17 +2977,16 @@ ScriptLoader::PrepareLoadedRequest(Scrip
    if (NS_FAILED(aStatus)) {
      return aStatus;
    }
@@ -428,14 +428,14 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
 diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
 --- a/toolkit/components/telemetry/Histograms.json
 +++ b/toolkit/components/telemetry/Histograms.json
-@@ -8939,168 +8939,16 @@
-   "WEBRTC_ICE_CHECKING_RATE": {
+@@ -9185,168 +9185,16 @@
      "record_in_processes": ["main", "content"],
-     "alert_emails": ["webrtc-ice-telemetry-alerts@mozilla.com"],
-     "bug_numbers": [1188391,1319268],
-     "expires_in_version": "58",
-     "kind": "boolean",
-     "description": "The number of ICE connections which immediately failed (0) vs. reached at least checking state (1)."
+     "alert_emails": ["danderson@mozilla.com"],
+     "expires_in_version": "never",
+     "kind": "enumerated",
+     "bug_numbers": [1229961],
+     "n_values": 12,
+     "description": "Plugin drawing model. 0 when windowed, otherwise NPDrawingModel + 1."
    },
 -  "DOM_SCRIPT_SRC_ENCODING": {
 -    "record_in_processes": ["main", "content"],
@@ -600,15 +600,15 @@ diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/t
 diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/components/telemetry/histogram-whitelists.json
 --- a/toolkit/components/telemetry/histogram-whitelists.json
 +++ b/toolkit/components/telemetry/histogram-whitelists.json
-@@ -1255,17 +1255,16 @@
-     "DEVTOOLS_SCRATCHPAD_WINDOW_OPENED_COUNT",
-     "DEVTOOLS_SHADEREDITOR_OPENED_COUNT",
-     "DEVTOOLS_STORAGE_OPENED_COUNT",
+@@ -1307,17 +1307,16 @@
      "DEVTOOLS_STYLEEDITOR_OPENED_COUNT",
      "DEVTOOLS_TILT_OPENED_COUNT",
      "DEVTOOLS_TOOLBOX_OPENED_COUNT",
      "DEVTOOLS_WEBAUDIOEDITOR_OPENED_COUNT",
      "DEVTOOLS_WEBCONSOLE_OPENED_COUNT",
+     "DEVTOOLS_WEBIDE_IMPORT_PROJECT_COUNT",
+     "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT",
+     "DEVTOOLS_WEBIDE_OPENED_COUNT",
 -    "DOM_SCRIPT_SRC_ENCODING",
      "ENABLE_PRIVILEGE_EVER_CALLED",
      "FENNEC_DISTRIBUTION_REFERRER_INVALID",

+ 4 - 4
frg/work-js/mozilla-release/patches/mozilla-central-push_422800.patch → frg/work-js/mozilla-release/patches/1465350-62a1.patch

@@ -3,13 +3,13 @@
 # Date 1528908441 25200
 #      Wed Jun 13 09:47:21 2018 -0700
 # Node ID 6350b1a6097e821b836c7a83924259f3b64d0b70
-# Parent  1d498636e0d5b5090691cb05dd7c0af09b4c2949
+# Parent  a8665bd0979706b6b1742271fa0a71ed97f92564
 Bug 1465350 - Use UniquePtr instead of ScopedJSFreePtr for JSErrorReporter. r=Waldo
 
 diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
 --- a/js/src/jsapi.cpp
 +++ b/js/src/jsapi.cpp
-@@ -7088,17 +7088,17 @@ JSErrorNotes::copy(JSContext* cx)
+@@ -7067,17 +7067,17 @@ JSErrorNotes::copy(JSContext* cx)
  {
      auto copiedNotes = MakeUnique<JSErrorNotes>();
      if (!copiedNotes) {
@@ -164,7 +164,7 @@ diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
  
      // Flag the error report passed in to indicate an exception was raised.
      reportp->flags |= JSREPORT_EXCEPTION;
-@@ -985,17 +984,17 @@ ErrorReport::populateUncaughtExceptionRe
+@@ -1050,17 +1049,17 @@ ErrorReport::populateUncaughtExceptionRe
      toStringResult_ = ownedReport.message();
      reportp = &ownedReport;
      return true;
@@ -183,7 +183,7 @@ diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
  
      RootedString message(cx, err->getMessage());
      if (message && !cx->compartment()->wrap(cx, &message))
-@@ -1007,34 +1006,36 @@ js::CopyErrorObject(JSContext* cx, Handl
+@@ -1072,34 +1071,36 @@ js::CopyErrorObject(JSContext* cx, Handl
      if (!cx->compartment()->wrap(cx, &stack))
          return nullptr;
      uint32_t lineNumber = err->lineNumber();

+ 37 - 29
frg/work-js/mozilla-release/patches/1465585-3-std-62a1.patch

@@ -3,7 +3,7 @@
 # Date 1527707735 -7200
 #      Wed May 30 21:15:35 2018 +0200
 # Node ID b54db66223586b4e04f5cb926fccdacf8a176b91
-# Parent  7046ddeeab9e995f6fedcff20c446cadc4d1f76e
+# Parent  fbb0663a2e32d3725f96585754bbdef1a4e4b68d
 Bug 1465585: Switch from mozilla::Move to std::move. r=froydnj
 
 This was done automatically replacing:
@@ -1281,7 +1281,7 @@ diff --git a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h b/devtools/shar
 diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
 --- a/docshell/base/nsDocShell.cpp
 +++ b/docshell/base/nsDocShell.cpp
-@@ -5552,17 +5552,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
+@@ -5555,17 +5555,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
      // Stack variables to ensure changes to the member variables don't affect to
      // the call.
      nsCOMPtr<nsIURI> currentURI = mCurrentURI;
@@ -1300,7 +1300,7 @@ diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
                        referrerURI,
                        referrerPolicy,
                        triggeringPrincipal,
-@@ -12808,17 +12808,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
+@@ -12811,17 +12811,17 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
    }
  
@@ -1319,7 +1319,7 @@ diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
                      referrerURI,
                      referrerPolicy,
                      triggeringPrincipal,
-@@ -14863,17 +14863,17 @@ nsDocShell::NotifyJSRunToCompletionStart
+@@ -14866,17 +14866,17 @@ nsDocShell::NotifyJSRunToCompletionStart
                                           const uint32_t aLineNumber,
                                           JS::Handle<JS::Value> aAsyncStack,
                                           const char* aAsyncCause)
@@ -2432,8 +2432,8 @@ diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp
  DocGroup::Dispatch(TaskCategory aCategory,
                     already_AddRefed<nsIRunnable>&& aRunnable)
  {
--  return mTabGroup->Dispatch(aCategory, Move(aRunnable));
-+  return mTabGroup->Dispatch(aCategory, std::move(aRunnable));
+-  return mTabGroup->DispatchWithDocGroup(aCategory, Move(aRunnable), this);
++  return mTabGroup->DispatchWithDocGroup(aCategory, std::move(aRunnable), this);
  }
  
  nsISerialEventTarget*
@@ -3069,7 +3069,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
    MOZ_ASSERT(NS_IsMainThread());
    MOZ_ASSERT(aSelector);
  
-@@ -3198,19 +3198,19 @@ nsIDocument::GetDocGroup() const
+@@ -3194,19 +3194,19 @@ nsIDocument::GetDocGroup() const
  }
  
  nsresult
@@ -3092,7 +3092,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
    if (mDocGroup) {
      return mDocGroup->EventTargetFor(aCategory);
    }
-@@ -6627,17 +6627,17 @@ nsIDocument::CreateNodeIterator(nsINode&
+@@ -6623,17 +6623,17 @@ nsIDocument::CreateNodeIterator(nsINode&
  
  already_AddRefed<NodeIterator>
  nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
@@ -3111,7 +3111,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
                               uint32_t aWhatToShow,
                               nsIDOMNodeFilter *aFilter,
                               uint8_t aOptionalArgc,
-@@ -6667,17 +6667,17 @@ nsIDocument::CreateTreeWalker(nsINode& a
+@@ -6663,17 +6663,17 @@ nsIDocument::CreateTreeWalker(nsINode& a
    return CreateTreeWalker(aRoot, aWhatToShow, NodeFilterHolder(aFilter), rv);
  }
  
@@ -3130,7 +3130,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
  nsDocument::GetDefaultView(mozIDOMWindowProxy** aDefaultView)
  {
    *aDefaultView = nullptr;
-@@ -6926,17 +6926,17 @@ nsDocument::NotifyPossibleTitleChange(bo
+@@ -6922,17 +6922,17 @@ nsDocument::NotifyPossibleTitleChange(bo
  
    MOZ_RELEASE_ASSERT(NS_IsMainThread());
    RefPtr<nsRunnableMethod<nsDocument, void, false>> event =
@@ -3149,7 +3149,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
  {
    mPendingTitleChangeEvent.Forget();
    mHaveFiredTitleChange = true;
-@@ -10163,17 +10163,17 @@ nsIDocument::FlushPendingLinkUpdates()
+@@ -10159,17 +10159,17 @@ nsIDocument::FlushPendingLinkUpdates()
    if (mFlushingPendingLinkUpdates) {
      return;
    }
@@ -3168,7 +3168,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
          if (element->IsInComposedDoc()) {
            element->UpdateLinkState(link->LinkState());
          }
-@@ -11102,17 +11102,17 @@ ResetFullScreen(nsIDocument* aDocument, 
+@@ -11098,17 +11098,17 @@ ResetFullScreen(nsIDocument* aDocument, 
  // Since nsIDocument::ExitFullscreenInDocTree() could be called from
  // Element::UnbindFromTree() where it is not safe to synchronously run
  // script. This runnable is the script part of that function.
@@ -3187,7 +3187,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
      // Dispatch MozDOMFullscreen:Exited to the last document in
      // the list since we want this event to follow the same path
      // MozDOMFullscreen:Entered dispatched.
-@@ -11172,17 +11172,17 @@ nsIDocument::ExitFullscreenInDocTree(nsI
+@@ -11168,17 +11168,17 @@ nsIDocument::ExitFullscreenInDocTree(nsI
  
    NS_ASSERTION(!root->GetFullscreenElement(),
      "Fullscreen root should no longer be a fullscreen doc...");
@@ -3206,7 +3206,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
    if (aDoc->IsFullscreenLeaf()) {
      nsIDocument** result = static_cast<nsIDocument**>(aData);
      *result = aDoc;
-@@ -11299,23 +11299,23 @@ nsDocument::RestorePreviousFullScreenSta
+@@ -11295,23 +11295,23 @@ nsDocument::RestorePreviousFullScreenSta
    }
  }
  
@@ -3232,7 +3232,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
  
  void
  nsDocument::AsyncRequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
-@@ -11323,17 +11323,17 @@ nsDocument::AsyncRequestFullScreen(Uniqu
+@@ -11319,17 +11319,17 @@ nsDocument::AsyncRequestFullScreen(Uniqu
    if (!aRequest->GetElement()) {
      MOZ_ASSERT_UNREACHABLE(
        "Must pass non-null element to nsDocument::AsyncRequestFullScreen");
@@ -3251,7 +3251,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
  {
    RefPtr<AsyncEventDispatcher> asyncDispatcher =
      new AsyncEventDispatcher(this,
-@@ -11507,17 +11507,17 @@ nsresult nsDocument::RemoteFrameFullscre
+@@ -11503,17 +11503,17 @@ nsresult nsDocument::RemoteFrameFullscre
  {
    // Ensure the frame element is the fullscreen element in this document.
    // If the frame element is already the fullscreen element in this document,
@@ -3270,7 +3270,7 @@ diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
  {
    RestorePreviousFullScreenState();
    return NS_OK;
-@@ -11805,17 +11805,17 @@ nsDocument::RequestFullScreen(UniquePtr<
+@@ -11801,17 +11801,17 @@ nsDocument::RequestFullScreen(UniquePtr<
    }
  
    // We don't need to check element ready before this point, because
@@ -16434,7 +16434,7 @@ diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp
 diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
 --- a/dom/script/ScriptLoader.cpp
 +++ b/dom/script/ScriptLoader.cpp
-@@ -1373,17 +1373,17 @@ ScriptLoader::ProcessExternalScript(nsIS
+@@ -1322,17 +1322,17 @@ ScriptLoader::ProcessExternalScript(nsIS
      if (!principal) {
        principal = aScriptContent->NodePrincipal();
      }
@@ -53616,7 +53616,7 @@ diff --git a/xpcom/threads/Queue.h b/xpcom/threads/Queue.h
 diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
 --- a/xpcom/threads/SchedulerGroup.cpp
 +++ b/xpcom/threads/SchedulerGroup.cpp
-@@ -140,17 +140,17 @@ SchedulerEventTarget::DispatchFromScript
+@@ -141,17 +141,17 @@ SchedulerEventTarget::DispatchFromScript
  }
  
  NS_IMETHODIMP
@@ -53635,7 +53635,7 @@ diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
    return NS_ERROR_NOT_IMPLEMENTED;
  }
  
-@@ -167,19 +167,19 @@ SchedulerEventTarget::IsOnCurrentThreadI
+@@ -168,19 +168,19 @@ SchedulerEventTarget::IsOnCurrentThreadI
    return NS_IsMainThread();
  }
  
@@ -53657,17 +53657,25 @@ diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
  {
    if (gEarliestUnprocessedVsync) {
      // If we've seen a vsync already, but haven't handled it, keep the
-@@ -212,17 +212,17 @@ SchedulerGroup::SchedulerGroup()
-     sTlsValidatingAccess.infallibleInit();
+@@ -214,24 +214,24 @@ SchedulerGroup::SchedulerGroup()
    }
  }
  
+ nsresult
+ SchedulerGroup::DispatchWithDocGroup(TaskCategory aCategory,
+                                      already_AddRefed<nsIRunnable>&& aRunnable,
+                                      dom::DocGroup* aDocGroup)
+ {
+-  return LabeledDispatch(aCategory, Move(aRunnable), aDocGroup);
++  return LabeledDispatch(aCategory, std::move(aRunnable), aDocGroup);
+ }
+ 
  nsresult
  SchedulerGroup::Dispatch(TaskCategory aCategory,
                           already_AddRefed<nsIRunnable>&& aRunnable)
  {
--  return LabeledDispatch(aCategory, Move(aRunnable));
-+  return LabeledDispatch(aCategory, std::move(aRunnable));
+-  return LabeledDispatch(aCategory, Move(aRunnable), nullptr);
++  return LabeledDispatch(aCategory, std::move(aRunnable), nullptr);
  }
  
  nsISerialEventTarget*
@@ -53676,7 +53684,7 @@ diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
    MOZ_ASSERT(aCategory != TaskCategory::Count);
    MOZ_ASSERT(mEventTargets[size_t(aCategory)]);
    return mEventTargets[size_t(aCategory)];
-@@ -312,17 +312,17 @@ SchedulerGroup::LabeledDispatch(TaskCate
+@@ -322,17 +322,17 @@ SchedulerGroup::LabeledDispatch(TaskCate
  
  /*static*/ nsresult
  SchedulerGroup::InternalUnlabeledDispatch(TaskCategory aCategory,
@@ -53695,25 +53703,25 @@ diff --git a/xpcom/threads/SchedulerGroup.cpp b/xpcom/threads/SchedulerGroup.cpp
      // Dispatch failed.  This is a situation where we would have used
      // NS_DispatchToMainThread rather than calling into the SchedulerGroup
      // machinery, and the caller would be expecting to leak the nsIRunnable
-@@ -348,17 +348,17 @@ SchedulerGroup::SetValidatingAccess(Vali
-   dom::AutoJSAPI jsapi;
+@@ -359,17 +359,17 @@ SchedulerGroup::SetValidatingAccess(Vali
    jsapi.Init();
    js::EnableAccessValidation(jsapi.cx(), validating);
  }
  
  SchedulerGroup::Runnable::Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
-                                    SchedulerGroup* aGroup)
+                                    SchedulerGroup* aGroup,
+                                    dom::DocGroup* aDocGroup)
    : mozilla::Runnable("SchedulerGroup::Runnable")
 -  , mRunnable(Move(aRunnable))
 +  , mRunnable(std::move(aRunnable))
    , mGroup(aGroup)
+   , mDocGroup(aDocGroup)
  {
  }
  
  bool
  SchedulerGroup::Runnable::GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups)
  {
-   aGroups.Clear();
 diff --git a/xpcom/threads/SharedThreadPool.h b/xpcom/threads/SharedThreadPool.h
 --- a/xpcom/threads/SharedThreadPool.h
 +++ b/xpcom/threads/SharedThreadPool.h

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

@@ -0,0 +1,510 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1529921688 25200
+# Node ID fd737ab7af6f92b160409b66dcd3f85c68b552a9
+# Parent  7dc17148a3096e2eac4d3b5d46c4a54854261f81
+Bug 1466626 - Part 2: Add missing OOM handling in various places. r=jonco
+
+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
+@@ -2117,19 +2117,24 @@ InlineTypedObject::obj_moved(JSObject* d
+ }
+ 
+ ArrayBufferObject*
+ InlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx)
+ {
+     ObjectRealm& realm = ObjectRealm::get(this);
+     if (!realm.lazyArrayBuffers) {
+         auto table = cx->make_unique<ObjectWeakMap>(cx);
+-        if (!table || !table->init())
++        if (!table)
+             return nullptr;
+ 
++        if (!table->init()) {
++            ReportOutOfMemory(cx);
++            return nullptr;
++        }
++
+         realm.lazyArrayBuffers = std::move(table);
+     }
+ 
+     ObjectWeakMap* table = realm.lazyArrayBuffers.get();
+ 
+     JSObject* obj = table->lookup(this);
+     if (obj)
+         return &obj->as<ArrayBufferObject>();
+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
+@@ -181,17 +181,17 @@ ParseContext::Scope::dump(ParseContext* 
+ bool
+ ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc, FunctionBox* funbox)
+ {
+     if (!possibleAnnexBFunctionBoxes_) {
+         if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->context))
+             return false;
+     }
+ 
+-    return possibleAnnexBFunctionBoxes_->append(funbox);
++    return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
+ }
+ 
+ bool
+ ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc)
+ {
+     // Strict mode doesn't have wack Annex B function semantics.
+     if (pc->sc()->strict() ||
+         !possibleAnnexBFunctionBoxes_ ||
+diff --git a/js/src/jit-test/tests/auto-regress/bug1466626-1.js b/js/src/jit-test/tests/auto-regress/bug1466626-1.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/auto-regress/bug1466626-1.js
+@@ -0,0 +1,8 @@
++if (!("oomTest" in this))
++    quit();
++
++oomTest(function() {
++    for (var i = 0; i < 10; ++i) {
++        Promise.resolve().then();
++    }
++});
+diff --git a/js/src/jit-test/tests/auto-regress/bug1466626-2.js b/js/src/jit-test/tests/auto-regress/bug1466626-2.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/auto-regress/bug1466626-2.js
+@@ -0,0 +1,19 @@
++if (!("oomTest" in this))
++    quit();
++
++var globals = [];
++for (var i = 0; i < 24; ++i) {
++    var g = newGlobal();
++    g.eval(`
++        function f(){}
++        var env = {};
++    `);
++    globals.push(g);
++}
++
++var i = 0;
++oomTest(function() {
++    globals[(i++) % globals.length].eval(`
++        this.clone(this.f, this.env);
++    `);
++});
+diff --git a/js/src/jit-test/tests/auto-regress/bug1466626-3.js b/js/src/jit-test/tests/auto-regress/bug1466626-3.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/auto-regress/bug1466626-3.js
+@@ -0,0 +1,14 @@
++if (!("oomTest" in this))
++    quit();
++
++var g = newGlobal();
++
++var i = 0;
++oomTest(function() {
++    var s = String.fromCharCode((i++) & 0xffff);
++    var r = "";
++    for (var j = 0; j < 1000; ++j) {
++        r = s + r;
++    }
++    g.String.prototype.toString.call(r);
++});
+diff --git a/js/src/jit-test/tests/auto-regress/bug1466626-4.js b/js/src/jit-test/tests/auto-regress/bug1466626-4.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/auto-regress/bug1466626-4.js
+@@ -0,0 +1,11 @@
++if (!("oomTest" in this))
++    quit();
++
++var source = "{";
++for (var i = 0; i < 120; ++i)
++    source += `function f${i}(){}`
++source += "}";
++
++oomTest(function() {
++    Function(source);
++});
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -7011,18 +7011,20 @@ JSErrorNotes::addNoteASCII(JSContext* cx
+     va_list ap;
+     va_start(ap, errorNumber);
+     auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef,
+                                   errorNumber, ArgumentsAreASCII, ap);
+     va_end(ap);
+ 
+     if (!note)
+         return false;
+-    if (!notes_.append(std::move(note)))
+-        return false;
++    if (!notes_.append(std::move(note))) {
++        ReportOutOfMemory(cx);
++        return false;
++    }
+     return true;
+ }
+ 
+ bool
+ JSErrorNotes::addNoteLatin1(JSContext* cx,
+                             const char* filename, unsigned lineno, unsigned column,
+                             JSErrorCallback errorCallback, void* userRef,
+                             const unsigned errorNumber, ...)
+@@ -7030,18 +7032,20 @@ JSErrorNotes::addNoteLatin1(JSContext* c
+     va_list ap;
+     va_start(ap, errorNumber);
+     auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef,
+                                   errorNumber, ArgumentsAreLatin1, ap);
+     va_end(ap);
+ 
+     if (!note)
+         return false;
+-    if (!notes_.append(std::move(note)))
+-        return false;
++    if (!notes_.append(std::move(note))) {
++        ReportOutOfMemory(cx);
++        return false;
++    }
+     return true;
+ }
+ 
+ bool
+ JSErrorNotes::addNoteUTF8(JSContext* cx,
+                           const char* filename, unsigned lineno, unsigned column,
+                           JSErrorCallback errorCallback, void* userRef,
+                           const unsigned errorNumber, ...)
+@@ -7049,18 +7053,20 @@ JSErrorNotes::addNoteUTF8(JSContext* cx,
+     va_list ap;
+     va_start(ap, errorNumber);
+     auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef,
+                                   errorNumber, ArgumentsAreUTF8, ap);
+     va_end(ap);
+ 
+     if (!note)
+         return false;
+-    if (!notes_.append(std::move(note)))
+-        return false;
++    if (!notes_.append(std::move(note))) {
++        ReportOutOfMemory(cx);
++        return false;
++    }
+     return true;
+ }
+ 
+ JS_PUBLIC_API(size_t)
+ JSErrorNotes::length()
+ {
+     return notes_.length();
+ }
+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
+@@ -5773,31 +5773,44 @@ ConsumeBufferSource(JSContext* cx, JS::H
+     SharedMem<uint8_t*> dataPointer;
+     size_t byteLength;
+     if (!IsBufferSource(obj, &dataPointer, &byteLength)) {
+         JS_ReportErrorASCII(cx, "shell streaming consumes a buffer source (buffer or view)");
+         return false;
+     }
+ 
+     auto job = cx->make_unique<BufferStreamJob>(consumer);
+-    if (!job || !job->bytes.resize(byteLength))
+-        return false;
++    if (!job)
++        return false;
++
++    if (!job->bytes.resize(byteLength)) {
++        JS_ReportOutOfMemory(cx);
++        return false;
++    }
+ 
+     memcpy(job->bytes.begin(), dataPointer.unwrap(), byteLength);
+ 
+     BufferStreamJob* jobPtr = job.get();
+ 
+     {
+         auto state = bufferStreamState->lock();
+         MOZ_ASSERT(!state->shutdown);
+-        if (!state->jobs.append(std::move(job)))
+-            return false;
+-    }
+-
+-    return jobPtr->thread.init(BufferStreamMain, jobPtr);
++        if (!state->jobs.append(std::move(job))) {
++            JS_ReportOutOfMemory(cx);
++            return false;
++        }
++    }
++
++    {
++        AutoEnterOOMUnsafeRegion oomUnsafe;
++        if (!jobPtr->thread.init(BufferStreamMain, jobPtr))
++            oomUnsafe.crash("ConsumeBufferSource");
++    }
++
++    return true;
+ }
+ 
+ static bool
+ SetBufferStreamParams(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (!args.requireAtLeast(cx, "setBufferStreamParams", 2))
+         return false;
+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
+@@ -1040,17 +1040,21 @@ JSContext::recoverFromOutOfMemory()
+ }
+ 
+ static bool
+ InternalEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job,
+                                   JS::HandleObject allocationSite,
+                                   JS::HandleObject incumbentGlobal, void* data)
+ {
+     MOZ_ASSERT(job);
+-    return cx->jobQueue->append(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)
+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
+@@ -3747,30 +3747,39 @@ JSScript::destroyDebugScript(FreeOp* fop
+ bool
+ JSScript::ensureHasDebugScript(JSContext* cx)
+ {
+     if (bitFields_.hasDebugScript_)
+         return true;
+ 
+     size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
+     UniqueDebugScript debug(reinterpret_cast<DebugScript*>(zone()->pod_calloc<uint8_t>(nbytes)));
+-    if (!debug)
++    if (!debug) {
++        ReportOutOfMemory(cx);
+         return false;
++    }
+ 
+     /* Create realm's debugScriptMap if necessary. */
+     if (!realm()->debugScriptMap) {
+         auto map = cx->make_unique<DebugScriptMap>();
+-        if (!map || !map->init())
++        if (!map)
+             return false;
+ 
++        if (!map->init()) {
++            ReportOutOfMemory(cx);
++            return false;
++        }
++
+         realm()->debugScriptMap = std::move(map);
+     }
+ 
+-    if (!realm()->debugScriptMap->putNew(this, std::move(debug)))
++    if (!realm()->debugScriptMap->putNew(this, std::move(debug))) {
++        ReportOutOfMemory(cx);
+         return false;
++    }
+ 
+     bitFields_.hasDebugScript_ = true; // safe to set this;  we can't fail after this point
+ 
+     /*
+      * Ensure that any Interpret() instances running on this script have
+      * interrupts enabled. The interrupts must stay enabled until the
+      * debug state is destroyed.
+      */
+diff --git a/js/src/vm/Realm.cpp.2-1466626.later b/js/src/vm/Realm.cpp.2-1466626.later
+new file mode 100644
+--- /dev/null
++++ b/js/src/vm/Realm.cpp.2-1466626.later
+@@ -0,0 +1,28 @@
++--- Realm.cpp
+++++ Realm.cpp
++@@ -200,19 +200,24 @@ struct CheckGCThingAfterMovingGCFunctor 
++ 
++ LexicalEnvironmentObject*
++ ObjectRealm::getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, HandleObject enclosing)
++ {
++     MOZ_ASSERT(&ObjectRealm::get(enclosing) == this);
++ 
++     if (!nonSyntacticLexicalEnvironments_) {
++         auto map = cx->make_unique<ObjectWeakMap>(cx);
++-        if (!map || !map->init())
+++        if (!map)
++             return nullptr;
++ 
+++        if (!map->init()) {
+++            ReportOutOfMemory(cx);
+++            return nullptr;
+++        }
+++
++         nonSyntacticLexicalEnvironments_ = std::move(map);
++     }
++ 
++     // If a wrapped WithEnvironmentObject was passed in, unwrap it, as we may
++     // be creating different WithEnvironmentObject wrappers each time.
++     RootedObject key(cx, enclosing);
++     if (enclosing->is<WithEnvironmentObject>()) {
++         MOZ_ASSERT(!enclosing->as<WithEnvironmentObject>().isSyntactic());
+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
+@@ -275,65 +275,68 @@ AllocChars(JSString* str, size_t length,
+     *capacity = numChars - 1;
+ 
+     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
+     *chars = str->zone()->pod_malloc<CharT>(numChars);
+     return *chars != nullptr;
+ }
+ 
+ UniquePtr<Latin1Char[], JS::FreePolicy>
+-JSRope::copyLatin1CharsZ(JSContext* cx) const
++JSRope::copyLatin1CharsZ(JSContext* maybecx) const
+ {
+-    return copyCharsInternal<Latin1Char>(cx, true);
++    return copyCharsInternal<Latin1Char>(maybecx, true);
+ }
+ 
+ UniqueTwoByteChars
+-JSRope::copyTwoByteCharsZ(JSContext* cx) const
++JSRope::copyTwoByteCharsZ(JSContext* maybecx) const
+ {
+-    return copyCharsInternal<char16_t>(cx, true);
++    return copyCharsInternal<char16_t>(maybecx, true);
+ }
+ 
+ UniquePtr<Latin1Char[], JS::FreePolicy>
+-JSRope::copyLatin1Chars(JSContext* cx) const
++JSRope::copyLatin1Chars(JSContext* maybecx) const
+ {
+-    return copyCharsInternal<Latin1Char>(cx, false);
++    return copyCharsInternal<Latin1Char>(maybecx, false);
+ }
+ 
+ UniqueTwoByteChars
+-JSRope::copyTwoByteChars(JSContext* cx) const
++JSRope::copyTwoByteChars(JSContext* maybecx) const
+ {
+-    return copyCharsInternal<char16_t>(cx, false);
++    return copyCharsInternal<char16_t>(maybecx, false);
+ }
+ 
+ template <typename CharT>
+ UniquePtr<CharT[], JS::FreePolicy>
+-JSRope::copyCharsInternal(JSContext* cx, bool nullTerminate) const
++JSRope::copyCharsInternal(JSContext* maybecx, bool nullTerminate) const
+ {
+     // Left-leaning ropes are far more common than right-leaning ropes, so
+     // perform a non-destructive traversal of the rope, right node first,
+     // splatting each node's characters into a contiguous buffer.
+ 
+     size_t n = length();
+ 
+     UniquePtr<CharT[], JS::FreePolicy> out;
+-    if (cx)
+-        out.reset(cx->pod_malloc<CharT>(n + 1));
++    if (maybecx)
++        out.reset(maybecx->pod_malloc<CharT>(n + 1));
+     else
+         out.reset(js_pod_malloc<CharT>(n + 1));
+ 
+     if (!out)
+         return nullptr;
+ 
+     Vector<const JSString*, 8, SystemAllocPolicy> nodeStack;
+     const JSString* str = this;
+     CharT* end = out.get() + str->length();
+     while (true) {
+         if (str->isRope()) {
+-            if (!nodeStack.append(str->asRope().leftChild()))
++            if (!nodeStack.append(str->asRope().leftChild())) {
++                if (maybecx)
++                    ReportOutOfMemory(maybecx);
+                 return nullptr;
++            }
+             str = str->asRope().rightChild();
+         } else {
+             end -= str->length();
+             CopyChars(end, str->asLinear());
+             if (nodeStack.empty())
+                 break;
+             str = nodeStack.popCopy();
+         }
+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
+@@ -685,24 +685,24 @@ class JSRope : public JSString
+ 
+   public:
+     template <js::AllowGC allowGC>
+     static inline JSRope* new_(JSContext* cx,
+                                typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
+                                typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
+                                size_t length, js::gc::InitialHeap = js::gc::DefaultHeap);
+ 
+-    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1Chars(JSContext* cx) const;
+-    JS::UniqueTwoByteChars copyTwoByteChars(JSContext* cx) const;
++    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1Chars(JSContext* maybecx) const;
++    JS::UniqueTwoByteChars copyTwoByteChars(JSContext* maybecx) const;
+ 
+-    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1CharsZ(JSContext* cx) const;
+-    JS::UniqueTwoByteChars copyTwoByteCharsZ(JSContext* cx) const;
++    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1CharsZ(JSContext* maybecx) const;
++    JS::UniqueTwoByteChars copyTwoByteCharsZ(JSContext* maybecx) const;
+ 
+     template <typename CharT>
+-    js::UniquePtr<CharT[], JS::FreePolicy> copyChars(JSContext* cx) const;
++    js::UniquePtr<CharT[], JS::FreePolicy> copyChars(JSContext* maybecx) const;
+ 
+     // Hash function specific for ropes that avoids allocating a temporary
+     // string. There are still allocations internally so it's technically
+     // fallible.
+     //
+     // Returns the same value as if this were a linear string being hashed.
+     MOZ_MUST_USE bool hash(uint32_t* outhHash) const;
+ 
+@@ -1734,26 +1734,26 @@ template<>
+ MOZ_ALWAYS_INLINE const JS::Latin1Char*
+ JSLinearString::chars(const JS::AutoRequireNoGC& nogc) const
+ {
+     return rawLatin1Chars();
+ }
+ 
+ template <>
+ MOZ_ALWAYS_INLINE js::UniquePtr<JS::Latin1Char[], JS::FreePolicy>
+-JSRope::copyChars<JS::Latin1Char>(JSContext* cx) const
++JSRope::copyChars<JS::Latin1Char>(JSContext* maybecx) const
+ {
+-    return copyLatin1Chars(cx);
++    return copyLatin1Chars(maybecx);
+ }
+ 
+ template <>
+ MOZ_ALWAYS_INLINE JS::UniqueTwoByteChars
+-JSRope::copyChars<char16_t>(JSContext* cx) const
++JSRope::copyChars<char16_t>(JSContext* maybecx) const
+ {
+-    return copyTwoByteChars(cx);
++    return copyTwoByteChars(maybecx);
+ }
+ 
+ template<>
+ MOZ_ALWAYS_INLINE bool
+ JSThinInlineString::lengthFits<JS::Latin1Char>(size_t length)
+ {
+     return length <= MAX_LENGTH_LATIN1;
+ }

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

@@ -0,0 +1,529 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1529921689 25200
+# Node ID 3967e4340805a5ef860544579ccd1c7ff21f4f32
+# Parent  85b2f1a1b5ba487b1bf56fafc91a322236faa009
+Bug 1466626 - Part 3: Don't call ReportOutOfMemory twice when used with JSContext allocation. r=jonco
+
+diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp
+--- a/js/src/builtin/MapObject.cpp
++++ b/js/src/builtin/MapObject.cpp
+@@ -646,17 +646,20 @@ MapObject::set(JSContext* cx, HandleObje
+     return true;
+ }
+ 
+ MapObject*
+ MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
+ {
+     auto map = cx->make_unique<ValueMap>(cx->zone(),
+                                          cx->realm()->randomHashCodeScrambler());
+-    if (!map || !map->init()) {
++    if (!map)
++        return nullptr;
++
++    if (!map->init()) {
+         ReportOutOfMemory(cx);
+         return nullptr;
+     }
+ 
+     MapObject* mapObj = NewObjectWithClassProto<MapObject>(cx,  proto);
+     if (!mapObj)
+         return nullptr;
+ 
+@@ -1329,17 +1332,20 @@ SetObject::add(JSContext* cx, HandleObje
+     return true;
+ }
+ 
+ SetObject*
+ SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
+ {
+     auto set = cx->make_unique<ValueSet>(cx->zone(),
+                                          cx->realm()->randomHashCodeScrambler());
+-    if (!set || !set->init()) {
++    if (!set)
++        return nullptr;
++
++    if (!set->init()) {
+         ReportOutOfMemory(cx);
+         return nullptr;
+     }
+ 
+     SetObject* obj = NewObjectWithClassProto<SetObject>(cx, proto);
+     if (!obj)
+         return nullptr;
+ 
+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
+@@ -3594,36 +3594,32 @@ ImplicitConvert(JSContext* cx,
+       case TYPE_unsigned_char: {
+         // Convert from UTF-16 to UTF-8.
+         size_t nbytes = GetDeflatedUTF8StringLength(cx, sourceLinear);
+         if (nbytes == (size_t) -1)
+           return false;
+ 
+         char** charBuffer = static_cast<char**>(buffer);
+         *charBuffer = cx->pod_malloc<char>(nbytes + 1);
+-        if (!*charBuffer) {
+-          JS_ReportAllocationOverflow(cx);
++        if (!*charBuffer)
+           return false;
+-        }
+ 
+         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceLinear, *charBuffer, &nbytes));
+         (*charBuffer)[nbytes] = 0;
+         *freePointer = true;
+         break;
+       }
+       case TYPE_char16_t: {
+         // Copy the char16_t string data. (We could provide direct access to the
+         // JSString's buffer, but this approach is safer if the caller happens
+         // to modify the string.)
+         char16_t** char16Buffer = static_cast<char16_t**>(buffer);
+         *char16Buffer = cx->pod_malloc<char16_t>(sourceLength + 1);
+-        if (!*char16Buffer) {
+-          JS_ReportAllocationOverflow(cx);
++        if (!*char16Buffer)
+           return false;
+-        }
+ 
+         *freePointer = true;
+         if (sourceLinear->hasLatin1Chars()) {
+             AutoCheckCannotGC nogc;
+             CopyAndInflateChars(*char16Buffer, sourceLinear->latin1Chars(nogc), sourceLength);
+         } else {
+             AutoCheckCannotGC nogc;
+             mozilla::PodCopy(*char16Buffer, sourceLinear->twoByteChars(nogc), sourceLength);
+@@ -3776,20 +3772,18 @@ ImplicitConvert(JSContext* cx,
+           return ArrayLengthMismatch(cx, targetLength, targetType,
+                                      size_t(sourceLength), val, convType);
+         }
+ 
+         // Convert into an intermediate, in case of failure.
+         size_t elementSize = CType::GetSize(baseType);
+         size_t arraySize = elementSize * targetLength;
+         auto intermediate = cx->make_pod_array<char>(arraySize);
+-        if (!intermediate) {
+-          JS_ReportAllocationOverflow(cx);
++        if (!intermediate)
+           return false;
+-        }
+ 
+         RootedValue item(cx);
+         for (uint32_t i = 0; i < sourceLength; ++i) {
+           if (!JS_GetElement(cx, valObj, i, &item))
+             return false;
+ 
+           char* data = intermediate.get() + elementSize * i;
+           if (!ImplicitConvert(cx, item, baseType, data, convType, nullptr,
+@@ -3860,20 +3854,18 @@ ImplicitConvert(JSContext* cx,
+       // specification, convert the fields.
+       Rooted<IdVector> props(cx, IdVector(cx));
+       if (!JS_Enumerate(cx, valObj, &props))
+         return false;
+ 
+       // Convert into an intermediate, in case of failure.
+       size_t structSize = CType::GetSize(targetType);
+       auto intermediate = cx->make_pod_array<char>(structSize);
+-      if (!intermediate) {
+-        JS_ReportAllocationOverflow(cx);
++      if (!intermediate)
+         return false;
+-      }
+ 
+       const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
+       if (props.length() != fields->count()) {
+         return FieldCountMismatch(cx, fields->count(), targetType,
+                                   props.length(), val, convType,
+                                   funObj, argIndex);
+       }
+ 
+@@ -5737,29 +5729,25 @@ ArrayType::BuildFFIType(JSContext* cx, J
+   // Create an ffi_type to represent the array. This is necessary for the case
+   // where the array is part of a struct. Since libffi has no intrinsic
+   // support for array types, we approximate it by creating a struct type
+   // with elements of type 'baseType' and with appropriate size and alignment
+   // values. It would be nice to not do all the work of setting up 'elements',
+   // but some libffi platforms currently require that it be meaningful. I'm
+   // looking at you, x86_64.
+   auto ffiType = cx->make_unique<ffi_type>();
+-  if (!ffiType) {
+-    JS_ReportOutOfMemory(cx);
++  if (!ffiType)
+     return nullptr;
+-  }
+ 
+   ffiType->type = FFI_TYPE_STRUCT;
+   ffiType->size = CType::GetSize(obj);
+   ffiType->alignment = CType::GetAlignment(obj);
+   ffiType->elements = cx->pod_malloc<ffi_type*>(length + 1);
+-  if (!ffiType->elements) {
+-    JS_ReportAllocationOverflow(cx);
++  if (!ffiType->elements)
+     return nullptr;
+-  }
+ 
+   for (size_t i = 0; i < length; ++i)
+     ffiType->elements[i] = ffiBaseType;
+   ffiType->elements[length] = nullptr;
+ 
+   return ffiType;
+ }
+ 
+@@ -6250,28 +6238,24 @@ StructType::BuildFFIType(JSContext* cx, 
+ 
+   const FieldInfoHash* fields = GetFieldInfo(obj);
+   size_t len = fields->count();
+ 
+   size_t structSize = CType::GetSize(obj);
+   size_t structAlign = CType::GetAlignment(obj);
+ 
+   auto ffiType = cx->make_unique<ffi_type>();
+-  if (!ffiType) {
+-    JS_ReportOutOfMemory(cx);
++  if (!ffiType)
+     return nullptr;
+-  }
+   ffiType->type = FFI_TYPE_STRUCT;
+ 
+   size_t count = len != 0 ? len + 1 : 2;
+   auto elements = cx->make_pod_array<ffi_type*>(count);
+-  if (!elements) {
+-    JS_ReportOutOfMemory(cx);
++  if (!elements)
+     return nullptr;
+-  }
+ 
+   if (len != 0) {
+     elements[len] = nullptr;
+ 
+     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
+       const FieldInfoHash::Entry& entry = r.front();
+       ffi_type* fieldType = CType::GetFFIType(cx, entry.value().mType);
+       if (!fieldType)
+@@ -6896,20 +6880,18 @@ FunctionType::BuildSymbolName(JSContext*
+ static bool
+ CreateFunctionInfo(JSContext* cx,
+                    HandleObject typeObj,
+                    HandleValue abiType,
+                    HandleObject returnType,
+                    const HandleValueArray& args)
+ {
+   FunctionInfo* fninfo(cx->new_<FunctionInfo>());
+-  if (!fninfo) {
+-    JS_ReportOutOfMemory(cx);
+-    return false;
+-  }
++  if (!fninfo)
++    return false;
+ 
+   // Stash the FunctionInfo in a reserved slot.
+   JS_SetReservedSlot(typeObj, SLOT_FNINFO, PrivateValue(fninfo));
+ 
+   ffi_abi abi;
+   if (!GetABI(cx, abiType, &abi)) {
+     JS_ReportErrorASCII(cx, "Invalid ABI specification");
+     return false;
+@@ -7716,20 +7698,18 @@ CData::Create(JSContext* cx,
+     JS_SetReservedSlot(dataObj, SLOT_REFERENT, ObjectValue(*refObj));
+ 
+   // Set our ownership flag.
+   JS_SetReservedSlot(dataObj, SLOT_OWNS, BooleanValue(ownResult));
+ 
+   // attach the buffer. since it might not be 2-byte aligned, we need to
+   // allocate an aligned space for it and store it there. :(
+   char** buffer = cx->new_<char*>();
+-  if (!buffer) {
+-    JS_ReportOutOfMemory(cx);
++  if (!buffer)
+     return nullptr;
+-  }
+ 
+   char* data;
+   if (!ownResult) {
+     data = static_cast<char*>(source);
+   } else {
+     // Initialize our own buffer.
+     size_t size = CType::GetSize(typeObj);
+     data = dataObj->zone()->pod_malloc<char>(size);
+@@ -8718,20 +8698,18 @@ Int64Base::Construct(JSContext* cx,
+ {
+   const JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
+   RootedObject result(cx, JS_NewObjectWithGivenProto(cx, clasp, proto));
+   if (!result)
+     return nullptr;
+ 
+   // attach the Int64's data
+   uint64_t* buffer = cx->new_<uint64_t>(data);
+-  if (!buffer) {
+-    JS_ReportOutOfMemory(cx);
++  if (!buffer)
+     return nullptr;
+-  }
+ 
+   JS_SetReservedSlot(result, SLOT_INT64, PrivateValue(buffer));
+ 
+   if (!JS_FreezeObject(cx, result))
+     return nullptr;
+ 
+   return result;
+ }
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -6115,20 +6115,18 @@ EncodeLatin1(JSContext* cx, JSString* st
+         return nullptr;
+ 
+     JS::AutoCheckCannotGC nogc;
+     if (linear->hasTwoByteChars())
+         return JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->twoByteRange(nogc)).c_str();
+ 
+     size_t len = str->length();
+     Latin1Char* buf = cx->pod_malloc<Latin1Char>(len + 1);
+-    if (!buf) {
+-        ReportOutOfMemory(cx);
++    if (!buf)
+         return nullptr;
+-    }
+ 
+     mozilla::PodCopy(buf, linear->latin1Chars(nogc), len);
+     buf[len] = '\0';
+     return reinterpret_cast<char*>(buf);
+ }
+ 
+ JS_PUBLIC_API(char*)
+ JS_EncodeString(JSContext* cx, JSString* str)
+diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp
+--- a/js/src/perf/jsperf.cpp
++++ b/js/src/perf/jsperf.cpp
+@@ -195,20 +195,18 @@ pm_construct(JSContext* cx, unsigned arg
+     JS::RootedObject obj(cx, JS_NewObjectForConstructor(cx, &pm_class, args));
+     if (!obj)
+         return false;
+ 
+     if (!JS_FreezeObject(cx, obj))
+         return false;
+ 
+     PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask));
+-    if (!p) {
+-        JS_ReportOutOfMemory(cx);
++    if (!p)
+         return false;
+-    }
+ 
+     JS_SetPrivate(obj, p);
+     args.rval().setObject(*obj);
+     return true;
+ }
+ 
+ static void
+ pm_finalize(JSFreeOp* fop, JSObject* obj)
+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
+@@ -2983,19 +2983,17 @@ js::GetCodeCoverageSummary(JSContext* cx
+ 
+     if (out.hadOutOfMemory()) {
+         JS_ReportOutOfMemory(cx);
+         return nullptr;
+     }
+ 
+     ptrdiff_t len = out.stringEnd() - out.string();
+     char* res = cx->pod_malloc<char>(len + 1);
+-    if (!res) {
+-        JS_ReportOutOfMemory(cx);
++    if (!res)
+         return nullptr;
+-    }
+ 
+     js_memcpy(res, out.string(), len);
+     res[len] = 0;
+     if (length)
+         *length = len;
+     return res;
+ }
+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
+@@ -2518,17 +2518,20 @@ CanUseDebugEnvironmentMaps(JSContext* cx
+ DebugEnvironments*
+ DebugEnvironments::ensureRealmData(JSContext* cx)
+ {
+     Realm* realm = cx->realm();
+     if (auto* debugEnvs = realm->debugEnvs())
+         return debugEnvs;
+ 
+     auto debugEnvs = cx->make_unique<DebugEnvironments>(cx, cx->zone());
+-    if (!debugEnvs || !debugEnvs->init()) {
++    if (!debugEnvs)
++        return nullptr;
++
++    if (!debugEnvs->init()) {
+         ReportOutOfMemory(cx);
+         return nullptr;
+     }
+ 
+     realm->debugEnvsRef() = std::move(debugEnvs);
+     return realm->debugEnvs();
+ }
+ 
+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
+@@ -1051,17 +1051,20 @@ JSScript::initScriptCounts(JSContext* cx
+     }
+ 
+     for (size_t i = 0; i < jumpTargets.length(); i++)
+         base.infallibleEmplaceBack(pcToOffset(jumpTargets[i]));
+ 
+     // Create realm's scriptCountsMap if necessary.
+     if (!realm()->scriptCountsMap) {
+         auto map = cx->make_unique<ScriptCountsMap>();
+-        if (!map || !map->init()) {
++        if (!map)
++            return false;
++
++        if (!map->init()) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+ 
+         realm()->scriptCountsMap = std::move(map);
+     }
+ 
+     // Allocate the ScriptCounts.
+@@ -2692,17 +2695,20 @@ JSScript::initScriptName(JSContext* cx)
+     MOZ_ASSERT(!hasScriptName());
+ 
+     if (!filename())
+         return true;
+ 
+     // Create realm's scriptNameMap if necessary.
+     if (!realm()->scriptNameMap) {
+         auto map = cx->make_unique<ScriptNameMap>();
+-        if (!map || !map->init()) {
++        if (!map)
++            return false;
++
++        if (!map->init()) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+ 
+         realm()->scriptNameMap = std::move(map);
+     }
+ 
+     UniqueChars name = DuplicateString(filename());
+diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
+--- a/js/src/vm/ObjectGroup.cpp
++++ b/js/src/vm/ObjectGroup.cpp
+@@ -524,17 +524,20 @@ ObjectGroup::defaultNewGroup(JSContext* 
+         return group;
+ 
+     AutoEnterAnalysis enter(cx);
+ 
+     ObjectGroupRealm::NewTable*& table = groups.defaultNewTable;
+ 
+     if (!table) {
+         table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
+-        if (!table || !table->init()) {
++        if (!table)
++            return nullptr;
++
++        if (!table->init()) {
+             js_delete(table);
+             table = nullptr;
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+     }
+ 
+     if (proto.isObject() && !proto.toObject()->isDelegate()) {
+@@ -624,17 +627,20 @@ ObjectGroup::lazySingletonGroup(JSContex
+                                 TaggedProto proto)
+ {
+     MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
+ 
+     ObjectGroupRealm::NewTable*& table = realm.lazyTable;
+ 
+     if (!table) {
+         table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
+-        if (!table || !table->init()) {
++        if (!table)
++            return nullptr;
++
++        if (!table->init()) {
+             ReportOutOfMemory(cx);
+             js_delete(table);
+             table = nullptr;
+             return nullptr;
+         }
+     }
+ 
+     ObjectGroupRealm::NewTable::AddPtr p =
+@@ -850,17 +856,20 @@ ObjectGroup::newArrayObject(JSContext* c
+         }
+     }
+ 
+     ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+     ObjectGroupRealm::ArrayObjectTable*& table = realm.arrayObjectTable;
+ 
+     if (!table) {
+         table = cx->new_<ObjectGroupRealm::ArrayObjectTable>();
+-        if (!table || !table->init()) {
++        if (!table)
++            return nullptr;
++
++        if (!table->init()) {
+             ReportOutOfMemory(cx);
+             js_delete(table);
+             table = nullptr;
+             return nullptr;
+         }
+     }
+ 
+     ObjectGroupRealm::ArrayObjectKey key(elementType);
+@@ -1173,17 +1182,20 @@ ObjectGroup::newPlainObject(JSContext* c
+     if (newKind == SingletonObject || nproperties == 0 || nproperties >= PropertyTree::MAX_HEIGHT)
+         return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
+ 
+     ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+     ObjectGroupRealm::PlainObjectTable*& table = realm.plainObjectTable;
+ 
+     if (!table) {
+         table = cx->new_<ObjectGroupRealm::PlainObjectTable>();
+-        if (!table || !table->init()) {
++        if (!table)
++            return nullptr;
++
++        if (!table->init()) {
+             ReportOutOfMemory(cx);
+             js_delete(table);
+             table = nullptr;
+             return nullptr;
+         }
+     }
+ 
+     ObjectGroupRealm::PlainObjectKey::Lookup lookup(properties, nproperties);
+@@ -1439,17 +1451,20 @@ ObjectGroup::allocationSiteGroup(JSConte
+         return defaultNewGroup(cx, kind);
+     }
+ 
+     ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+     ObjectGroupRealm::AllocationSiteTable*& table = realm.allocationSiteTable;
+ 
+     if (!table) {
+         table = cx->new_<ObjectGroupRealm::AllocationSiteTable>(cx->zone());
+-        if (!table || !table->init()) {
++        if (!table)
++            return nullptr;
++
++        if (!table->init()) {
+             ReportOutOfMemory(cx);
+             js_delete(table);
+             table = nullptr;
+             return nullptr;
+         }
+     }
+ 
+     RootedScript script(cx, scriptArg);

+ 1 - 1
frg/work-js/mozilla-release/patches/mozilla-central-push_422056.patch → frg/work-js/mozilla-release/patches/1466633-62a1.patch

@@ -3,7 +3,7 @@
 # Date 1528245672 25200
 #      Tue Jun 05 17:41:12 2018 -0700
 # Node ID 2492ed8bf219cf0feadc4626de3db3dce30ad722
-# Parent  0ffe269f5e96c70120a935cf322397e3baf6103b
+# Parent  e7d85bbf9ba98a36243f40dec471ab47191cf433
 Bug 1466633 - GCManagedDeletePolicy: do not clear edges during GC, r=jonco
 
 diff --git a/js/src/gc/DeletePolicy.h b/js/src/gc/DeletePolicy.h

+ 67 - 0
frg/work-js/mozilla-release/patches/1467275-62a1.patch

@@ -0,0 +1,67 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1529012747 25200
+# Node ID 845878e00f84fe3f3213cb167c200ea7c73e47c8
+# Parent  a66a884fb46f23ac57ca39a006a10561a5e3a3de
+Bug 1467275 - Don't leak |chars| when an error occurs after its allocation in JS_BufferIsCompilableUnit.  r=anba
+
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -4383,17 +4383,18 @@ JS_PUBLIC_API(bool)
+ JS_BufferIsCompilableUnit(JSContext* cx, HandleObject obj, const char* utf8, size_t length)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+     assertSameCompartment(cx, obj);
+ 
+     cx->clearPendingException();
+ 
+-    char16_t* chars = JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get();
++    UniquePtr<char16_t> chars
++        { JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get() };
+     if (!chars)
+         return true;
+ 
+     // Return true on any out-of-memory error or non-EOF-related syntax error, so our
+     // caller doesn't try to collect more buffered source.
+     bool result = true;
+ 
+     CompileOptions options(cx);
+@@ -4402,34 +4403,33 @@ JS_BufferIsCompilableUnit(JSContext* cx,
+         return false;
+ 
+     RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
+                                                                                  mozilla::Nothing()));
+     if (!sourceObject)
+         return false;
+ 
+     frontend::Parser<frontend::FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(),
+-                                                                  options, chars, length,
++                                                                  options, chars.get(), length,
+                                                                   /* foldConstants = */ true,
+                                                                   usedNames, nullptr, nullptr,
+                                                                   sourceObject,
+                                                                   frontend::ParseGoal::Script);
+     JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr);
+     if (!parser.checkOptions() || !parser.parse()) {
+         // We ran into an error. If it was because we ran out of source, we
+         // return false so our caller knows to try to collect more buffered
+         // source.
+         if (parser.isUnexpectedEOF())
+             result = false;
+ 
+         cx->clearPendingException();
+     }
+     JS::SetWarningReporter(cx, older);
+ 
+-    js_free(chars);
+     return result;
+ }
+ 
+ JS_PUBLIC_API(JSObject*)
+ JS_GetGlobalFromScript(JSScript* script)
+ {
+     MOZ_ASSERT(!script->isCachedEval());
+     return &script->global();
+

+ 34 - 0
frg/work-js/mozilla-release/patches/1467276-62a1.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Jeff Walden <jwalden@mit.edu>
+# Date 1529012384 25200
+# Node ID 6625e63ecaf5af69387fac13b2c0ac0ce22cc69b
+# Parent  e7dddbdf81c3b7c9c0774eb84a35926e155b1342
+Bug 1467276 - Properly free |result| in DecompileAtPCForStackDump after its use, including when that use fails.  r=anba
+
+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
+@@ -2182,20 +2182,19 @@ DecompileAtPCForStackDump(JSContext* cx,
+ 
+     if (!ed.decompilePC(offsetAndDefIndex))
+         return false;
+ 
+     char* result;
+     if (!ed.getOutput(&result))
+         return false;
+ 
+-    if (!sp->put(result))
+-        return false;
+-
+-    return true;
++    bool ok = sp->put(result);
++    js_free(result);
++    return ok;
+ }
+ #endif /* DEBUG */
+ 
+ static bool
+ FindStartPC(JSContext* cx, const FrameIter& iter, int spindex, int skipStackHits, const Value& v,
+             jsbytecode** valuepc, uint8_t* defIndex)
+ {
+     jsbytecode* current = *valuepc;

+ 667 - 0
frg/work-js/mozilla-release/patches/1467438-1-62a1.patch

@@ -0,0 +1,667 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1529699379 25200
+#      Fri Jun 22 13:29:39 2018 -0700
+# Node ID d600ad533a95d45ae773c0888fb6093e711fe6b6
+# Parent  fed8c66bc594e8c9556ecf8e925c31d9ef0ac639
+Bug 1467438 - Part 1: Replace ScopedJSFreePtr with UniqueChars/UniqueTwoByteChars. r=sfink
+
+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
+@@ -3347,17 +3347,17 @@ reflect_parse(JSContext* cx, uint32_t ar
+                                   "Reflect.parse", "0", "s");
+         return false;
+     }
+ 
+     RootedString src(cx, ToString<CanGC>(cx, args[0]));
+     if (!src)
+         return false;
+ 
+-    ScopedJSFreePtr<char> filename;
++    UniqueChars filename;
+     uint32_t lineno = 1;
+     bool loc = true;
+     RootedObject builder(cx);
+     ParseGoal target = ParseGoal::Script;
+ 
+     RootedValue arg(cx, args.get(1));
+ 
+     if (!arg.isNullOrUndefined()) {
+@@ -3387,17 +3387,17 @@ reflect_parse(JSContext* cx, uint32_t ar
+             if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
+                 return false;
+ 
+             if (!prop.isNullOrUndefined()) {
+                 RootedString str(cx, ToString<CanGC>(cx, prop));
+                 if (!str)
+                     return false;
+ 
+-                filename = JS_EncodeString(cx, str);
++                filename.reset(JS_EncodeString(cx, str));
+                 if (!filename)
+                     return false;
+             }
+ 
+             /* config.line */
+             RootedId lineId(cx, NameToId(cx->names().line));
+             RootedValue oneValue(cx, Int32Value(1));
+             if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
+@@ -3449,30 +3449,30 @@ reflect_parse(JSContext* cx, uint32_t ar
+             target = ParseGoal::Module;
+         } else {
+             JS_ReportErrorASCII(cx, "Bad target value, expected 'script' or 'module'");
+             return false;
+         }
+     }
+ 
+     /* Extract the builder methods first to report errors before parsing. */
+-    ASTSerializer serialize(cx, loc, filename, lineno);
++    ASTSerializer serialize(cx, loc, filename.get(), lineno);
+     if (!serialize.init(builder))
+         return false;
+ 
+     JSLinearString* linear = src->ensureLinear(cx);
+     if (!linear)
+         return false;
+ 
+     AutoStableStringChars linearChars(cx);
+     if (!linearChars.initTwoByte(cx, linear))
+         return false;
+ 
+     CompileOptions options(cx);
+-    options.setFileAndLine(filename, lineno);
++    options.setFileAndLine(filename.get(), lineno);
+     options.setCanLazilyParse(false);
+     options.allowHTMLComments = target == ParseGoal::Script;
+     mozilla::Range<const char16_t> chars = linearChars.twoByteRange();
+     UsedNameTracker usedNames(cx);
+     if (!usedNames.init())
+         return false;
+ 
+     RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -6630,17 +6630,17 @@ JS_ObjectIsDate(JSContext* cx, HandleObj
+  * Regular Expressions.
+  */
+ JS_PUBLIC_API(JSObject*)
+ JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+ 
+-    ScopedJSFreePtr<char16_t> chars(InflateString(cx, bytes, length));
++    UniqueTwoByteChars chars(InflateString(cx, bytes, length));
+     if (!chars)
+         return nullptr;
+ 
+     return RegExpObject::create(cx, chars.get(), length, RegExpFlag(flags), cx->tempLifoAlloc(),
+                                 GenericObject);
+ }
+ 
+ JS_PUBLIC_API(JSObject*)
+diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
+--- a/js/src/jsnum.cpp
++++ b/js/src/jsnum.cpp
+@@ -81,32 +81,32 @@ EnsureDtoaState(JSContext* cx)
+  * Call js_strtod_harder to get the correct answer.
+  */
+ template <typename CharT>
+ static bool
+ ComputeAccurateDecimalInteger(JSContext* cx, const CharT* start, const CharT* end,
+                               double* dp)
+ {
+     size_t length = end - start;
+-    ScopedJSFreePtr<char> cstr(cx->pod_malloc<char>(length + 1));
++    UniqueChars cstr(cx->pod_malloc<char>(length + 1));
+     if (!cstr)
+         return false;
+ 
+     for (size_t i = 0; i < length; i++) {
+         char c = char(start[i]);
+         MOZ_ASSERT(IsAsciiAlphanumeric(c));
+         cstr[i] = c;
+     }
+     cstr[length] = 0;
+ 
+     if (!EnsureDtoaState(cx))
+         return false;
+ 
+     char* estr;
+-    *dp = js_strtod_harder(cx->dtoaState, cstr, &estr);
++    *dp = js_strtod_harder(cx->dtoaState, cstr.get(), &estr);
+ 
+     return true;
+ }
+ 
+ namespace {
+ 
+ template <typename CharT>
+ class BinaryDigitReader
+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
+@@ -853,33 +853,33 @@ RunFile(JSContext* cx, const char* filen
+ static bool
+ InitModuleLoader(JSContext* cx)
+ {
+ 
+     // Decompress and evaluate the embedded module loader source to initialize
+     // the module loader for the current compartment.
+ 
+     uint32_t srcLen = moduleloader::GetRawScriptsSize();
+-    ScopedJSFreePtr<char> src(cx->pod_malloc<char>(srcLen));
++    UniqueChars src(cx->pod_malloc<char>(srcLen));
+     if (!src || !DecompressString(moduleloader::compressedSources, moduleloader::GetCompressedSize(),
+                                   reinterpret_cast<unsigned char*>(src.get()), srcLen))
+     {
+         return false;
+     }
+ 
+     CompileOptions options(cx);
+     options.setIntroductionType("shell module loader");
+     options.setFileAndLine("shell/ModuleLoader.js", 1);
+     options.setSelfHostingMode(false);
+     options.setCanLazilyParse(false);
+     options.werrorOption = true;
+     options.strictOption = true;
+ 
+     RootedValue rv(cx);
+-    return Evaluate(cx, options, src, srcLen, &rv);
++    return Evaluate(cx, options, src.get(), srcLen, &rv);
+ }
+ 
+ static bool
+ GetLoaderObject(JSContext* cx, MutableHandleObject resultOut)
+ {
+     // Look up the |Reflect.Loader| object that has been defined by the module
+     // loader.
+ 
+diff --git a/js/src/util/StringBuffer.cpp b/js/src/util/StringBuffer.cpp
+--- a/js/src/util/StringBuffer.cpp
++++ b/js/src/util/StringBuffer.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 "util/StringBuffer.h"
+ 
+ #include "mozilla/Range.h"
++#include "mozilla/Unused.h"
+ 
+ #include "vm/JSObject-inl.h"
+ #include "vm/StringType-inl.h"
+ 
+ using namespace js;
+ 
+ template <typename CharT, class Buffer>
+ static CharT*
+@@ -74,31 +75,31 @@ StringBuffer::inflateChars()
+ template <typename CharT, class Buffer>
+ static JSFlatString*
+ FinishStringFlat(JSContext* cx, StringBuffer& sb, Buffer& cb)
+ {
+     size_t len = sb.length();
+     if (!sb.append('\0'))
+         return nullptr;
+ 
+-    ScopedJSFreePtr<CharT> buf(ExtractWellSized<CharT>(cx, cb));
++    UniquePtr<CharT[], JS::FreePolicy> buf(ExtractWellSized<CharT>(cx, cb));
+     if (!buf)
+         return nullptr;
+ 
+     JSFlatString* str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
+     if (!str)
+         return nullptr;
+ 
+     /*
+      * The allocation was made on a TempAllocPolicy, so account for the string
+      * data on the string's zone.
+      */
+     cx->updateMallocCounter(sizeof(CharT) * len);
+ 
+-    buf.forget();
++    mozilla::Unused << buf.release();
+     return str;
+ }
+ 
+ JSFlatString*
+ StringBuffer::finishString()
+ {
+     size_t len = length();
+     if (len == 0)
+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
+@@ -277,32 +277,32 @@ CopyStringPure(JSContext* cx, JSString* 
+             return nullptr;
+ 
+         return chars.isLatin1()
+                ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len)
+                : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
+     }
+ 
+     if (str->hasLatin1Chars()) {
+-        ScopedJSFreePtr<Latin1Char> copiedChars;
+-        if (!str->asRope().copyLatin1CharsZ(cx, copiedChars))
++        UniquePtr<Latin1Char[], JS::FreePolicy> copiedChars = str->asRope().copyLatin1CharsZ(cx);
++        if (!copiedChars)
+             return nullptr;
+ 
+-        auto* rawCopiedChars = copiedChars.forget();
++        auto* rawCopiedChars = copiedChars.release();
+         auto* result = NewString<CanGC>(cx, rawCopiedChars, len);
+         if (!result)
+             js_free(rawCopiedChars);
+         return result;
+     }
+ 
+-    ScopedJSFreePtr<char16_t> copiedChars;
+-    if (!str->asRope().copyTwoByteCharsZ(cx, copiedChars))
++    UniqueTwoByteChars copiedChars = str->asRope().copyTwoByteCharsZ(cx);
++    if (!copiedChars)
+         return nullptr;
+ 
+-    auto* rawCopiedChars = copiedChars.forget();
++    auto* rawCopiedChars = copiedChars.release();
+     auto* result = NewStringDontDeflate<CanGC>(cx, rawCopiedChars, len);
+     if (!result)
+         js_free(rawCopiedChars);
+     return result;
+ }
+ 
+ bool
+ JSCompartment::wrap(JSContext* cx, MutableHandleString strp)
+diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp
+--- a/js/src/vm/MemoryMetrics.cpp
++++ b/js/src/vm/MemoryMetrics.cpp
+@@ -76,34 +76,36 @@ InefficientNonFlatteningStringHashPolicy
+ template <typename Char1, typename Char2>
+ static bool
+ EqualStringsPure(JSString* s1, JSString* s2)
+ {
+     if (s1->length() != s2->length())
+         return false;
+ 
+     const Char1* c1;
+-    ScopedJSFreePtr<Char1> ownedChars1;
++    UniquePtr<Char1[], JS::FreePolicy> ownedChars1;
+     JS::AutoCheckCannotGC nogc;
+     if (s1->isLinear()) {
+         c1 = s1->asLinear().chars<Char1>(nogc);
+     } else {
+-        if (!s1->asRope().copyChars<Char1>(/* tcx */ nullptr, ownedChars1))
++        ownedChars1 = s1->asRope().copyChars<Char1>(/* tcx */ nullptr);
++        if (!ownedChars1)
+             MOZ_CRASH("oom");
+-        c1 = ownedChars1;
++        c1 = ownedChars1.get();
+     }
+ 
+     const Char2* c2;
+-    ScopedJSFreePtr<Char2> ownedChars2;
++    UniquePtr<Char2[], JS::FreePolicy> ownedChars2;
+     if (s2->isLinear()) {
+         c2 = s2->asLinear().chars<Char2>(nogc);
+     } else {
+-        if (!s2->asRope().copyChars<Char2>(/* tcx */ nullptr, ownedChars2))
++        ownedChars2 = s2->asRope().copyChars<Char2>(/* tcx */ nullptr);
++        if (!ownedChars2)
+             MOZ_CRASH("oom");
+-        c2 = ownedChars2;
++        c2 = ownedChars2.get();
+     }
+ 
+     return EqualChars(c1, c2, s1->length());
+ }
+ 
+ /* static */ bool
+ InefficientNonFlatteningStringHashPolicy::match(const JSString* const& k, const Lookup& l)
+ {
+@@ -143,24 +145,25 @@ NotableStringInfo::NotableStringInfo()
+ {
+ }
+ 
+ template <typename CharT>
+ static void
+ StoreStringChars(char* buffer, size_t bufferSize, JSString* str)
+ {
+     const CharT* chars;
+-    ScopedJSFreePtr<CharT> ownedChars;
++    UniquePtr<CharT[], JS::FreePolicy> ownedChars;
+     JS::AutoCheckCannotGC nogc;
+     if (str->isLinear()) {
+         chars = str->asLinear().chars<CharT>(nogc);
+     } else {
+-        if (!str->asRope().copyChars<CharT>(/* tcx */ nullptr, ownedChars))
++        ownedChars = str->asRope().copyChars<CharT>(/* tcx */ nullptr);
++        if (!ownedChars)
+             MOZ_CRASH("oom");
+-        chars = ownedChars;
++        chars = ownedChars.get();
+     }
+ 
+     // We might truncate |str| even if it's much shorter than 1024 chars, if
+     // |str| contains unicode chars.  Since this is just for a memory reporter,
+     // we don't care.
+     PutEscapedString(buffer, bufferSize, chars, str->length(), /* quote */ 0);
+ }
+ 
+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
+@@ -2966,24 +2966,24 @@ JSRuntime::initSelfHosting(JSContext* cx
+     FillSelfHostingCompileOptions(options);
+ 
+     RootedValue rv(cx);
+ 
+     uint32_t srcLen = GetRawScriptsSize();
+ 
+     const unsigned char* compressed = compressedSources;
+     uint32_t compressedLen = GetCompressedSize();
+-    ScopedJSFreePtr<char> src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
++    UniqueChars src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
+     if (!src || !DecompressString(compressed, compressedLen,
+                                   reinterpret_cast<unsigned char*>(src.get()), srcLen))
+     {
+         return false;
+     }
+ 
+-    if (!Evaluate(cx, options, src, srcLen, &rv))
++    if (!Evaluate(cx, options, src.get(), srcLen, &rv))
+         return false;
+ 
+     if (!VerifyGlobalNames(cx, shg))
+         return false;
+ 
+     return true;
+ }
+ 
+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
+@@ -274,81 +274,82 @@ AllocChars(JSString* str, size_t length,
+     /* Like length, capacity does not include the null char, so take it out. */
+     *capacity = numChars - 1;
+ 
+     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
+     *chars = str->zone()->pod_malloc<CharT>(numChars);
+     return *chars != nullptr;
+ }
+ 
+-bool
+-JSRope::copyLatin1CharsZ(JSContext* cx, ScopedJSFreePtr<Latin1Char>& out) const
++UniquePtr<Latin1Char[], JS::FreePolicy>
++JSRope::copyLatin1CharsZ(JSContext* cx) const
+ {
+-    return copyCharsInternal<Latin1Char>(cx, out, true);
++    return copyCharsInternal<Latin1Char>(cx, true);
+ }
+ 
+-bool
+-JSRope::copyTwoByteCharsZ(JSContext* cx, ScopedJSFreePtr<char16_t>& out) const
++UniqueTwoByteChars
++JSRope::copyTwoByteCharsZ(JSContext* cx) const
+ {
+-    return copyCharsInternal<char16_t>(cx, out, true);
++    return copyCharsInternal<char16_t>(cx, true);
+ }
+ 
+-bool
+-JSRope::copyLatin1Chars(JSContext* cx, ScopedJSFreePtr<Latin1Char>& out) const
++UniquePtr<Latin1Char[], JS::FreePolicy>
++JSRope::copyLatin1Chars(JSContext* cx) const
+ {
+-    return copyCharsInternal<Latin1Char>(cx, out, false);
++    return copyCharsInternal<Latin1Char>(cx, false);
+ }
+ 
+-bool
+-JSRope::copyTwoByteChars(JSContext* cx, ScopedJSFreePtr<char16_t>& out) const
++UniqueTwoByteChars
++JSRope::copyTwoByteChars(JSContext* cx) const
+ {
+-    return copyCharsInternal<char16_t>(cx, out, false);
++    return copyCharsInternal<char16_t>(cx, false);
+ }
+ 
+ template <typename CharT>
+-bool
+-JSRope::copyCharsInternal(JSContext* cx, ScopedJSFreePtr<CharT>& out,
+-                          bool nullTerminate) const
++UniquePtr<CharT[], JS::FreePolicy>
++JSRope::copyCharsInternal(JSContext* cx, bool nullTerminate) const
+ {
+     // Left-leaning ropes are far more common than right-leaning ropes, so
+     // perform a non-destructive traversal of the rope, right node first,
+     // splatting each node's characters into a contiguous buffer.
+ 
+     size_t n = length();
++
++    UniquePtr<CharT[], JS::FreePolicy> out;
+     if (cx)
+         out.reset(cx->pod_malloc<CharT>(n + 1));
+     else
+         out.reset(js_pod_malloc<CharT>(n + 1));
+ 
+     if (!out)
+-        return false;
++        return nullptr;
+ 
+     Vector<const JSString*, 8, SystemAllocPolicy> nodeStack;
+     const JSString* str = this;
+-    CharT* end = out + str->length();
++    CharT* end = out.get() + str->length();
+     while (true) {
+         if (str->isRope()) {
+             if (!nodeStack.append(str->asRope().leftChild()))
+-                return false;
++                return nullptr;
+             str = str->asRope().rightChild();
+         } else {
+             end -= str->length();
+             CopyChars(end, str->asLinear());
+             if (nodeStack.empty())
+                 break;
+             str = nodeStack.popCopy();
+         }
+     }
+ 
+-    MOZ_ASSERT(end == out);
++    MOZ_ASSERT(end == out.get());
+ 
+     if (nullTerminate)
+         out[n] = 0;
+ 
+-    return true;
++    return out;
+ }
+ 
+ template <typename CharT>
+ void AddStringToHash(uint32_t* hash, const CharT* chars, size_t len)
+ {
+     // It's tempting to use |HashString| instead of this loop, but that's
+     // slightly different than our existing implementation for non-ropes. We
+     // want to pretend we have a contiguous set of chars so we need to
+@@ -1497,31 +1498,31 @@ static JSFlatString*
+ NewStringDeflated(JSContext* cx, const char16_t* s, size_t n)
+ {
+     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+         return str;
+ 
+     if (JSInlineString::lengthFits<Latin1Char>(n))
+         return NewInlineStringDeflated<allowGC>(cx, mozilla::Range<const char16_t>(s, n));
+ 
+-    ScopedJSFreePtr<Latin1Char> news(cx->pod_malloc<Latin1Char>(n + 1));
++    UniquePtr<Latin1Char[], JS::FreePolicy> news(cx->pod_malloc<Latin1Char>(n + 1));
+     if (!news)
+         return nullptr;
+ 
+     for (size_t i = 0; i < n; i++) {
+         MOZ_ASSERT(s[i] <= JSString::MAX_LATIN1_CHAR);
+-        news.get()[i] = Latin1Char(s[i]);
++        news[i] = Latin1Char(s[i]);
+     }
+     news[n] = '\0';
+ 
+     JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
+     if (!str)
+         return nullptr;
+ 
+-    news.forget();
++    mozilla::Unused << news.release();
+     return str;
+ }
+ 
+ template <AllowGC allowGC>
+ static JSFlatString*
+ NewStringDeflated(JSContext* cx, const Latin1Char* s, size_t n)
+ {
+     MOZ_CRASH("Shouldn't be called for Latin1 chars");
+@@ -1599,31 +1600,31 @@ JSFlatString*
+ NewStringCopyNDontDeflate(JSContext* cx, const CharT* s, size_t n)
+ {
+     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+         return str;
+ 
+     if (JSInlineString::lengthFits<CharT>(n))
+         return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
+ 
+-    ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
++    UniquePtr<CharT[], JS::FreePolicy> news(cx->pod_malloc<CharT>(n + 1));
+     if (!news) {
+         if (!allowGC)
+             cx->recoverFromOutOfMemory();
+         return nullptr;
+     }
+ 
+     PodCopy(news.get(), s, n);
+     news[n] = 0;
+ 
+     JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
+     if (!str)
+         return nullptr;
+ 
+-    news.forget();
++    mozilla::Unused << news.release();
+     return str;
+ }
+ 
+ template JSFlatString*
+ NewStringCopyNDontDeflate<CanGC>(JSContext* cx, const char16_t* s, size_t n);
+ 
+ template JSFlatString*
+ NewStringCopyNDontDeflate<NoGC>(JSContext* cx, const char16_t* s, size_t n);
+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
+@@ -17,16 +17,17 @@
+ #include "builtin/String.h"
+ #include "gc/Barrier.h"
+ #include "gc/Cell.h"
+ #include "gc/Heap.h"
+ #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 JSDependentString;
+ class JSExtensibleString;
+ class JSExternalString;
+ class JSInlineString;
+ class JSRope;
+@@ -661,18 +662,18 @@ class JSString : public js::gc::Cell
+     JSString() = delete;
+     JSString(const JSString& other) = delete;
+     void operator=(const JSString& other) = delete;
+ };
+ 
+ class JSRope : public JSString
+ {
+     template <typename CharT>
+-    bool copyCharsInternal(JSContext* cx, js::ScopedJSFreePtr<CharT>& out,
+-                           bool nullTerminate) const;
++    js::UniquePtr<CharT[], JS::FreePolicy> copyCharsInternal(JSContext* cx,
++                                                             bool nullTerminate) const;
+ 
+     enum UsingBarrier { WithIncrementalBarrier, NoBarrier };
+ 
+     template<UsingBarrier b, typename CharT>
+     JSFlatString* flattenInternal(JSContext* cx);
+ 
+     template<UsingBarrier b>
+     JSFlatString* flattenInternal(JSContext* cx);
+@@ -684,26 +685,24 @@ class JSRope : public JSString
+ 
+   public:
+     template <js::AllowGC allowGC>
+     static inline JSRope* new_(JSContext* cx,
+                                typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
+                                typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
+                                size_t length, js::gc::InitialHeap = js::gc::DefaultHeap);
+ 
+-    bool copyLatin1Chars(JSContext* cx,
+-                         js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
+-    bool copyTwoByteChars(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
++    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1Chars(JSContext* cx) const;
++    JS::UniqueTwoByteChars copyTwoByteChars(JSContext* cx) const;
+ 
+-    bool copyLatin1CharsZ(JSContext* cx,
+-                          js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
+-    bool copyTwoByteCharsZ(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
++    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1CharsZ(JSContext* cx) const;
++    JS::UniqueTwoByteChars copyTwoByteCharsZ(JSContext* cx) const;
+ 
+     template <typename CharT>
+-    bool copyChars(JSContext* cx, js::ScopedJSFreePtr<CharT>& out) const;
++    js::UniquePtr<CharT[], JS::FreePolicy> copyChars(JSContext* cx) const;
+ 
+     // Hash function specific for ropes that avoids allocating a temporary
+     // string. There are still allocations internally so it's technically
+     // fallible.
+     //
+     // Returns the same value as if this were a linear string being hashed.
+     MOZ_MUST_USE bool hash(uint32_t* outhHash) const;
+ 
+@@ -1734,28 +1733,27 @@ JSLinearString::chars(const JS::AutoRequ
+ template<>
+ MOZ_ALWAYS_INLINE const JS::Latin1Char*
+ JSLinearString::chars(const JS::AutoRequireNoGC& nogc) const
+ {
+     return rawLatin1Chars();
+ }
+ 
+ template <>
+-MOZ_ALWAYS_INLINE bool
+-JSRope::copyChars<JS::Latin1Char>(JSContext* cx,
+-                                  js::ScopedJSFreePtr<JS::Latin1Char>& out) const
++MOZ_ALWAYS_INLINE js::UniquePtr<JS::Latin1Char[], JS::FreePolicy>
++JSRope::copyChars<JS::Latin1Char>(JSContext* cx) const
+ {
+-    return copyLatin1Chars(cx, out);
++    return copyLatin1Chars(cx);
+ }
+ 
+ template <>
+-MOZ_ALWAYS_INLINE bool
+-JSRope::copyChars<char16_t>(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const
++MOZ_ALWAYS_INLINE JS::UniqueTwoByteChars
++JSRope::copyChars<char16_t>(JSContext* cx) const
+ {
+-    return copyTwoByteChars(cx, out);
++    return copyTwoByteChars(cx);
+ }
+ 
+ template<>
+ MOZ_ALWAYS_INLINE bool
+ JSThinInlineString::lengthFits<JS::Latin1Char>(size_t length)
+ {
+     return length <= MAX_LENGTH_LATIN1;
+ }

+ 350 - 0
frg/work-js/mozilla-release/patches/1467438-2-62a1.patch

@@ -0,0 +1,350 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1529699379 25200
+#      Fri Jun 22 13:29:39 2018 -0700
+# Node ID 390ba7756cae841c7cb6b0b2787b3cc7347bda69
+# Parent  d600ad533a95d45ae773c0888fb6093e711fe6b6
+Bug 1467438 - Part 2: Replace remaining ScopedJSFreePtr with UniquePtr. r=sfink
+
+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
+@@ -34,16 +34,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/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;
+@@ -8388,35 +8389,34 @@ CDataFinalizer::Construct(JSContext* cx,
+   size_t sizeArg;
+   RootedValue valData(cx, args[0]);
+   if (!CType::GetSafeSize(objArgType, &sizeArg)) {
+     RootedValue valCodeType(cx, ObjectValue(*objCodeType));
+     return TypeError(cx, "a function with one known size argument",
+                      valCodeType);
+   }
+ 
+-  ScopedJSFreePtr<void> cargs(malloc(sizeArg));
++  UniquePtr<void, JS::FreePolicy> cargs(malloc(sizeArg));
+ 
+   if (!ImplicitConvert(cx, valData, objArgType, cargs.get(),
+                        ConversionType::Finalizer, &freePointer,
+                        objCodePtrType, 0)) {
+     return false;
+   }
+   if (freePointer) {
+     // Note: We could handle that case, if necessary.
+     JS_ReportErrorASCII(cx, "Internal Error during CDataFinalizer. Object cannot be represented");
+     return false;
+   }
+ 
+   // 4. Prepare buffer for holding return value
+ 
+-  ScopedJSFreePtr<void> rvalue;
++  UniquePtr<void, JS::FreePolicy> rvalue;
+   if (CType::GetTypeCode(returnType) != TYPE_void_t) {
+-    rvalue = malloc(Align(CType::GetSize(returnType),
+-                          sizeof(ffi_arg)));
++    rvalue.reset(malloc(Align(CType::GetSize(returnType), sizeof(ffi_arg))));
+   } //Otherwise, simply do not allocate
+ 
+   // 5. Create |objResult|
+ 
+   JSObject* objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto);
+   if (!objResult) {
+     return false;
+   }
+@@ -8460,28 +8460,28 @@ CDataFinalizer::Construct(JSContext* cx,
+   ffi_type* rtype = CType::GetFFIType(cx, funInfoFinalizer->mReturnType);
+   if (!rtype) {
+     JS_ReportErrorASCII(cx, "Internal Error: "
+                         "Could not access ffi type of CDataFinalizer");
+     return false;
+   }
+ 
+   // 7. Store C information as private
+-  ScopedJSFreePtr<CDataFinalizer::Private>
++  UniquePtr<CDataFinalizer::Private, JS::FreePolicy>
+     p((CDataFinalizer::Private*)malloc(sizeof(CDataFinalizer::Private)));
+ 
+   memmove(&p->CIF, &funInfoFinalizer->mCIF, sizeof(ffi_cif));
+ 
+-  p->cargs = cargs.forget();
+-  p->rvalue = rvalue.forget();
++  p->cargs = cargs.release();
++  p->rvalue = rvalue.release();
+   p->cargs_size = sizeArg;
+   p->code = code;
+ 
+ 
+-  JS_SetPrivate(objResult, p.forget());
++  JS_SetPrivate(objResult, p.release());
+   args.rval().setObject(*objResult);
+   return true;
+ }
+ 
+ 
+ /*
+  * Actually call the finalizer. Does not perform any cleanup on the object.
+  *
+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
+@@ -32,16 +32,17 @@
+ #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 "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"
+ #include "vm/BytecodeUtil.h"
+ #include "vm/Compression.h"
+ #include "vm/Debugger.h"
+@@ -3446,17 +3447,17 @@ js::detail::CopyScript(JSContext* cx, Ha
+     uint32_t nscopes   = src->scopes()->length;
+     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
+     uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
+     uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
+ 
+     /* Script data */
+ 
+     size_t size = src->dataSize();
+-    ScopedJSFreePtr<uint8_t> data(AllocScriptData(cx->zone(), size));
++    UniquePtr<uint8_t, JS::FreePolicy> data(AllocScriptData(cx->zone(), size));
+     if (size && !data) {
+         ReportOutOfMemory(cx);
+         return false;
+     }
+ 
+     /* Scopes */
+ 
+     // The passed in scopes vector contains body scopes that needed to be
+@@ -3514,17 +3515,17 @@ js::detail::CopyScript(JSContext* cx, Ha
+             }
+ 
+             if (!clone || !objects.append(clone))
+                 return false;
+         }
+     }
+ 
+     /* This assignment must occur before all the Rebase calls. */
+-    dst->data = data.forget();
++    dst->data = data.release();
+     dst->dataSize_ = size;
+     MOZ_ASSERT(bool(dst->data) == bool(src->data));
+     if (dst->data)
+         memcpy(dst->data, src->data, size);
+ 
+     if (cx->zone() != src->zoneFromAnyThread()) {
+         for (size_t i = 0; i < src->scriptData()->natoms(); i++)
+             cx->markAtom(src->scriptData()->atoms()[i]);
+@@ -4250,30 +4251,33 @@ LazyScript::CreateRaw(JSContext* cx, Han
+ 
+     // Reset runtime flags to obtain a fresh LazyScript.
+     p.hasBeenCloned = false;
+     p.treatAsRunOnce = false;
+ 
+     size_t bytes = (p.numClosedOverBindings * sizeof(JSAtom*))
+                  + (p.numInnerFunctions * sizeof(GCPtrFunction));
+ 
+-    ScopedJSFreePtr<uint8_t> table(bytes ? fun->zone()->pod_malloc<uint8_t>(bytes) : nullptr);
+-    if (bytes && !table) {
+-        ReportOutOfMemory(cx);
+-        return nullptr;
++    UniquePtr<uint8_t, JS::FreePolicy> table;
++    if (bytes) {
++        table.reset(fun->zone()->pod_malloc<uint8_t>(bytes));
++        if (!table) {
++            ReportOutOfMemory(cx);
++            return nullptr;
++        }
+     }
+ 
+     LazyScript* res = Allocate<LazyScript>(cx);
+     if (!res)
+         return nullptr;
+ 
+     cx->realm()->scheduleDelazificationForDebugger();
+ 
+-    return new (res) LazyScript(fun, *sourceObject, table.forget(), packed, sourceStart, sourceEnd,
+-                                toStringStart, lineno, column);
++    return new (res) LazyScript(fun, *sourceObject, table.release(), packed, sourceStart,
++                                sourceEnd, toStringStart, lineno, column);
+ }
+ 
+ /* static */ LazyScript*
+ LazyScript::Create(JSContext* cx, HandleFunction fun,
+                    HandleScriptSourceObject sourceObject,
+                    const frontend::AtomVector& closedOverBindings,
+                    Handle<GCVector<JSFunction*, 8>> innerFunctions,
+                    uint32_t sourceStart, uint32_t sourceEnd,
+diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
+--- a/js/src/vm/ObjectGroup.cpp
++++ b/js/src/vm/ObjectGroup.cpp
+@@ -2,26 +2,28 @@
+  * 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/ObjectGroup.h"
+ 
+ #include "mozilla/Maybe.h"
++#include "mozilla/Unused.h"
+ 
+ #include "jsexn.h"
+ 
+ #include "builtin/DataViewObject.h"
+ #include "gc/FreeOp.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Policy.h"
+ #include "gc/StoreBuffer.h"
+ #include "gc/Zone.h"
+ #include "js/CharacterEncoding.h"
++#include "js/UniquePtr.h"
+ #include "vm/ArrayObject.h"
+ #include "vm/JSObject.h"
+ #include "vm/RegExpObject.h"
+ #include "vm/Shape.h"
+ #include "vm/TaggedProto.h"
+ 
+ #include "gc/Marking-inl.h"
+ #include "vm/UnboxedObject-inl.h"
+@@ -1225,53 +1227,53 @@ ObjectGroup::newPlainObject(JSContext* c
+         // will try to use an unboxed layout for the group.
+         PreliminaryObjectArrayWithTemplate* preliminaryObjects =
+             cx->new_<PreliminaryObjectArrayWithTemplate>(obj->lastProperty());
+         if (!preliminaryObjects)
+             return nullptr;
+         group->setPreliminaryObjects(preliminaryObjects);
+         preliminaryObjects->registerNewObject(obj);
+ 
+-        ScopedJSFreePtr<jsid> ids(group->zone()->pod_calloc<jsid>(nproperties));
++        UniquePtr<jsid[], JS::FreePolicy> ids(group->zone()->pod_calloc<jsid>(nproperties));
+         if (!ids) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+ 
+-        ScopedJSFreePtr<TypeSet::Type> types(
++        UniquePtr<TypeSet::Type[], JS::FreePolicy> types(
+             group->zone()->pod_calloc<TypeSet::Type>(nproperties));
+         if (!types) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+ 
+         for (size_t i = 0; i < nproperties; i++) {
+             ids[i] = properties[i].id;
+             types[i] = GetValueTypeForTable(obj->getSlot(i));
+             AddTypePropertyId(cx, group, nullptr, IdToTypeId(ids[i]), types[i]);
+         }
+ 
+         ObjectGroupRealm::PlainObjectKey key;
+-        key.properties = ids;
++        key.properties = ids.get();
+         key.nproperties = nproperties;
+         MOZ_ASSERT(ObjectGroupRealm::PlainObjectKey::match(key, lookup));
+ 
+         ObjectGroupRealm::PlainObjectEntry entry;
+         entry.group.set(group);
+         entry.shape.set(obj->lastProperty());
+-        entry.types = types;
++        entry.types = types.get();
+ 
+         ObjectGroupRealm::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup);
+         if (!table->add(np, key, entry)) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+ 
+-        ids.forget();
+-        types.forget();
++        mozilla::Unused << ids.release();
++        mozilla::Unused << types.release();
+ 
+         return obj;
+     }
+ 
+     RootedObjectGroup group(cx, p->value().group);
+ 
+     // AutoSweepObjectGroup checks no GC happens in its scope, so we use Maybe
+     // and reset() it before GC calls.
+diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
+--- a/js/src/vm/TypedArrayObject.cpp
++++ b/js/src/vm/TypedArrayObject.cpp
+@@ -25,16 +25,17 @@
+ 
+ #include "builtin/Array.h"
+ #include "builtin/DataViewObject.h"
+ #include "builtin/TypedObjectConstants.h"
+ #include "gc/Barrier.h"
+ #include "gc/Marking.h"
+ #include "jit/InlinableNatives.h"
+ #include "js/Conversions.h"
++#include "js/UniquePtr.h"
+ #include "js/Wrapper.h"
+ #include "util/Windows.h"
+ #include "vm/ArrayBufferObject.h"
+ #include "vm/GlobalObject.h"
+ #include "vm/Interpreter.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/PIC.h"
+@@ -647,33 +648,31 @@ class TypedArrayObjectTemplate : public 
+                                   ? GetGCObjectKind(clasp)
+                                   : AllocKindForLazyBuffer(nbytes);
+         MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
+         allocKind = GetBackgroundAllocKind(allocKind);
+         RootedObjectGroup group(cx, templateObj->group());
+ 
+         NewObjectKind newKind = TenuredObject;
+ 
+-        ScopedJSFreePtr<void> buf;
++        UniquePtr<void, JS::FreePolicy> buf;
+         if (!fitsInline && len > 0) {
+-            buf = cx->zone()->pod_malloc<uint8_t>(nbytes);
++            buf.reset(cx->zone()->pod_calloc<uint8_t>(nbytes));
+             if (!buf) {
+                 ReportOutOfMemory(cx);
+                 return nullptr;
+             }
+-
+-            memset(buf, 0, nbytes);
+         }
+ 
+         TypedArrayObject* obj = NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind);
+         if (!obj)
+             return nullptr;
+ 
+         initTypedArraySlots(obj, len);
+-        initTypedArrayData(cx, obj, len, buf.forget(), allocKind);
++        initTypedArrayData(cx, obj, len, buf.release(), allocKind);
+ 
+         return obj;
+     }
+ 
+     // ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
+     // 22.2.4.1 TypedArray ( )
+     // 22.2.4.2 TypedArray ( length )
+     // 22.2.4.3 TypedArray ( typedArray )

+ 381 - 0
frg/work-js/mozilla-release/patches/1467438-3-62a1.patch

@@ -0,0 +1,381 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1529699380 25200
+#      Fri Jun 22 13:29:40 2018 -0700
+# Node ID e4d237883ed6b8f6694f1e0af63d60a19625958b
+# Parent  e05873940e0157d407fb2e8892abadf0e57d1a22
+Bug 1467438 - Part 3: Replace ScopedJSDeletePtr with UniquePtr. r=sfink
+
+diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
+--- a/js/src/jit/Ion.cpp
++++ b/js/src/jit/Ion.cpp
+@@ -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/Ion.h"
+ 
+ #include "mozilla/IntegerPrintfMacros.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/ThreadLocal.h"
++#include "mozilla/Unused.h"
+ 
+ #include "gc/FreeOp.h"
+ #include "gc/Marking.h"
+ #include "jit/AliasAnalysis.h"
+ #include "jit/AlignmentMaskAnalysis.h"
+ #include "jit/BacktrackingAllocator.h"
+ #include "jit/BaselineFrame.h"
+ #include "jit/BaselineInspector.h"
+@@ -41,16 +42,17 @@
+ #include "jit/PerfSpewer.h"
+ #include "jit/RangeAnalysis.h"
+ #include "jit/ScalarReplacement.h"
+ #include "jit/Sink.h"
+ #include "jit/StupidAllocator.h"
+ #include "jit/ValueNumbering.h"
+ #include "jit/WasmBCE.h"
+ #include "js/Printf.h"
++#include "js/UniquePtr.h"
+ #include "util/Windows.h"
+ #include "vm/Debugger.h"
+ #include "vm/HelperThreads.h"
+ #include "vm/JSCompartment.h"
+ #include "vm/TraceLogging.h"
+ #include "vtune/VTuneWrapper.h"
+ 
+ #include "gc/PrivateIterators-inl.h"
+@@ -2040,23 +2042,21 @@ IonCompile(JSContext* cx, JSScript* scri
+     AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
+ 
+     // Make sure the script's canonical function isn't lazy. We can't de-lazify
+     // it in a helper thread.
+     script->ensureNonLazyCanonicalFunction();
+ 
+     TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
+ 
+-    LifoAlloc* alloc = cx->new_<LifoAlloc>(TempAllocator::PreferredLifoChunkSize);
++    auto alloc = cx->make_unique<LifoAlloc>(TempAllocator::PreferredLifoChunkSize);
+     if (!alloc)
+         return AbortReason::Alloc;
+ 
+-    ScopedJSDeletePtr<LifoAlloc> autoDelete(alloc);
+-
+-    TempAllocator* temp = alloc->new_<TempAllocator>(alloc);
++    TempAllocator* temp = alloc->new_<TempAllocator>(alloc.get());
+     if (!temp)
+         return AbortReason::Alloc;
+ 
+     JitContext jctx(cx, temp);
+ 
+     if (!cx->realm()->ensureJitRealmExists(cx))
+         return AbortReason::Alloc;
+ 
+@@ -2179,34 +2179,33 @@ IonCompile(JSContext* cx, JSScript* scri
+             return AbortReason::Alloc;
+         }
+ 
+         if (!recompile)
+             builderScript->setIonScript(cx->runtime(), ION_COMPILING_SCRIPT);
+ 
+         // The allocator and associated data will be destroyed after being
+         // processed in the finishedOffThreadCompilations list.
+-        autoDelete.forget();
++        mozilla::Unused << alloc.release();
+ 
+         return AbortReason::NoAbort;
+     }
+ 
+     bool succeeded = false;
+     {
+-        ScopedJSDeletePtr<CodeGenerator> codegen;
+         AutoEnterAnalysis enter(cx);
+-        codegen = CompileBackEnd(builder);
++        UniquePtr<CodeGenerator> codegen(CompileBackEnd(builder));
+         if (!codegen) {
+             JitSpew(JitSpew_IonAbort, "Failed during back-end compilation.");
+             if (cx->isExceptionPending())
+                 return AbortReason::Error;
+             return AbortReason::Disable;
+         }
+ 
+-        succeeded = LinkCodeGen(cx, builder, codegen);
++        succeeded = LinkCodeGen(cx, builder, codegen.get());
+     }
+ 
+     if (succeeded)
+         return AbortReason::NoAbort;
+     if (cx->isExceptionPending())
+         return AbortReason::Error;
+     return AbortReason::Disable;
+ }
+diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp
+--- a/js/src/vm/HelperThreads.cpp
++++ b/js/src/vm/HelperThreads.cpp
+@@ -9,16 +9,17 @@
+ #include "mozilla/Maybe.h"
+ #include "mozilla/ScopeExit.h"
+ #include "mozilla/Unused.h"
+ 
+ #include "builtin/Promise.h"
+ #include "frontend/BytecodeCompiler.h"
+ #include "gc/GCInternals.h"
+ #include "jit/IonBuilder.h"
++#include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ #include "threading/CpuCount.h"
+ #include "util/NativeStack.h"
+ #include "vm/Debugger.h"
+ #include "vm/ErrorReporting.h"
+ #include "vm/SharedImmutableStringsCache.h"
+ #include "vm/Time.h"
+ #include "vm/TraceLogging.h"
+@@ -784,64 +785,60 @@ StartOffThreadParseTask(JSContext* cx, P
+     return true;
+ }
+ 
+ bool
+ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
+                               const char16_t* chars, size_t length,
+                               JS::OffThreadCompileCallback callback, void* callbackData)
+ {
+-    ScopedJSDeletePtr<ParseTask> task;
+-    task = cx->new_<ScriptParseTask>(cx, chars, length, callback, callbackData);
+-    if (!task || !StartOffThreadParseTask(cx, task, options))
++    auto task = cx->make_unique<ScriptParseTask>(cx, chars, length, callback, callbackData);
++    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
+         return false;
+ 
+-    task.forget();
++    Unused << task.release();
+     return true;
+ }
+ 
+ bool
+ js::StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
+                               const char16_t* chars, size_t length,
+                               JS::OffThreadCompileCallback callback, void* callbackData)
+ {
+-    ScopedJSDeletePtr<ParseTask> task;
+-    task = cx->new_<ModuleParseTask>(cx, chars, length, callback, callbackData);
+-    if (!task || !StartOffThreadParseTask(cx, task, options))
++    auto task = cx->make_unique<ModuleParseTask>(cx, chars, length, callback, callbackData);
++    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
+         return false;
+ 
+-    task.forget();
++    Unused << task.release();
+     return true;
+ }
+ 
+ bool
+ js::StartOffThreadDecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
+                                const JS::TranscodeRange& range,
+                                JS::OffThreadCompileCallback callback, void* callbackData)
+ {
+-    ScopedJSDeletePtr<ParseTask> task;
+-    task = cx->new_<ScriptDecodeTask>(cx, range, callback, callbackData);
+-    if (!task || !StartOffThreadParseTask(cx, task, options))
++    auto task = cx->make_unique<ScriptDecodeTask>(cx, range, callback, callbackData);
++    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
+         return false;
+ 
+-    task.forget();
++    Unused << task.release();
+     return true;
+ }
+ 
+ bool
+ js::StartOffThreadDecodeMultiScripts(JSContext* cx, const ReadOnlyCompileOptions& options,
+                                      JS::TranscodeSources& sources,
+                                      JS::OffThreadCompileCallback callback, void* callbackData)
+ {
+-    ScopedJSDeletePtr<ParseTask> task;
+-    task = cx->new_<MultiScriptsDecodeTask>(cx, sources, callback, callbackData);
+-    if (!task || !StartOffThreadParseTask(cx, task, options))
++    auto task = cx->make_unique<MultiScriptsDecodeTask>(cx, sources, callback, callbackData);
++    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
+         return false;
+ 
+-    task.forget();
++    Unused << task.release();
+     return true;
+ }
+ 
+ void
+ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
+ {
+     MOZ_ASSERT(!OffThreadParsingMustWaitForGC(rt));
+ 
+@@ -1605,43 +1602,42 @@ GlobalHelperThreadState::removeFinishedP
+ 
+ template <typename F, typename>
+ bool
+ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
+                                          JS::OffThreadToken* token, F&& finishCallback)
+ {
+     MOZ_ASSERT(cx->realm());
+ 
+-    ScopedJSDeletePtr<ParseTask> parseTask(removeFinishedParseTask(kind, token));
++    Rooted<UniquePtr<ParseTask>> parseTask(cx, removeFinishedParseTask(kind, token));
+ 
+     // Make sure we have all the constructors we need for the prototype
+     // remapping below, since we can't GC while that's happening.
+     if (!EnsureParserCreatedClasses(cx, kind)) {
+-        LeaveParseTaskZone(cx->runtime(), parseTask);
++        LeaveParseTaskZone(cx->runtime(), parseTask.get().get());
+         return false;
+     }
+ 
+-    mergeParseTaskRealm(cx, parseTask, cx->realm());
++    mergeParseTaskRealm(cx, parseTask.get().get(), cx->realm());
+ 
+-    bool ok = finishCallback(parseTask);
++    bool ok = finishCallback(parseTask.get().get());
+ 
+     for (auto& script : parseTask->scripts)
+         releaseAssertSameCompartment(cx, script);
+ 
+     if (!parseTask->finish(cx) || !ok)
+         return false;
+ 
+     // Report out of memory errors eagerly, or errors could be malformed.
+     if (parseTask->outOfMemory) {
+         ReportOutOfMemory(cx);
+         return false;
+     }
+ 
+-    // Report any error or warnings generated during the parse, and inform the
+-    // debugger about the compiled scripts.
++    // Report any error or warnings generated during the parse.
+     for (size_t i = 0; i < parseTask->errors.length(); i++)
+         parseTask->errors[i]->throwError(cx);
+     if (parseTask->overRecursed)
+         ReportOverRecursed(cx);
+     if (cx->isExceptionPending())
+         return false;
+ 
+     return true;
+diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
+--- a/js/src/vm/TypeInference.cpp
++++ b/js/src/vm/TypeInference.cpp
+@@ -21,16 +21,17 @@
+ #include "gc/HashUtil.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/CompileInfo.h"
+ #include "jit/Ion.h"
+ #include "jit/IonAnalysis.h"
+ #include "jit/JitRealm.h"
+ #include "jit/OptimizationTracking.h"
+ #include "js/MemoryMetrics.h"
++#include "js/UniquePtr.h"
+ #include "vm/HelperThreads.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ #include "vm/JSScript.h"
+ #include "vm/Opcodes.h"
+ #include "vm/Printer.h"
+ #include "vm/Shape.h"
+ #include "vm/Time.h"
+@@ -3636,17 +3637,17 @@ PreliminaryObjectArrayWithTemplate::mayb
+ {
+     // Don't perform the analyses until sufficient preliminary objects have
+     // been allocated.
+     if (!force && !full())
+         return;
+ 
+     AutoEnterAnalysis enter(cx);
+ 
+-    ScopedJSDeletePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
++    UniquePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
+     group->detachPreliminaryObjects();
+ 
+     MOZ_ASSERT(shape());
+     MOZ_ASSERT(shape()->slotSpan() != 0);
+     MOZ_ASSERT(OnlyHasDataProperties(shape()));
+ 
+     // Make sure all the preliminary objects reflect the properties originally
+     // in the template object.
+@@ -3658,17 +3659,17 @@ PreliminaryObjectArrayWithTemplate::mayb
+ 
+         if (obj->inDictionaryMode() || !OnlyHasDataProperties(obj->lastProperty()))
+             return;
+ 
+         if (CommonPrefix(obj->lastProperty(), shape()) != shape())
+             return;
+     }
+ 
+-    TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects);
++    TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects.get());
+     AutoSweepObjectGroup sweep(group);
+     if (group->maybeUnboxedLayout(sweep))
+         return;
+ 
+     // We weren't able to use an unboxed layout, but since the preliminary
+     // objects still reflect the template object's properties, and all
+     // objects in the future will be created with those properties, the
+     // properties can be marked as definite for objects in the group.
+@@ -3687,41 +3688,41 @@ TypeNewScript::make(JSContext* cx, Objec
+     AutoSweepObjectGroup sweep(group);
+     MOZ_ASSERT(cx->zone()->types.activeAnalysis);
+     MOZ_ASSERT(!group->newScript(sweep));
+     MOZ_ASSERT(!group->maybeUnboxedLayout(sweep));
+ 
+     if (group->unknownProperties(sweep))
+         return true;
+ 
+-    ScopedJSDeletePtr<TypeNewScript> newScript(cx->new_<TypeNewScript>());
++    auto newScript = cx->make_unique<TypeNewScript>();
+     if (!newScript)
+         return false;
+ 
+     newScript->function_ = fun;
+ 
+     newScript->preliminaryObjects = group->zone()->new_<PreliminaryObjectArray>();
+     if (!newScript->preliminaryObjects)
+         return true;
+ 
+-    group->setNewScript(newScript.forget());
++    group->setNewScript(newScript.release());
+ 
+     gc::gcTracer.traceTypeNewScript(group);
+     return true;
+ }
+ 
+ // Make a TypeNewScript with the same initializer list as |newScript| but with
+ // a new template object.
+ /* static */ TypeNewScript*
+ TypeNewScript::makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
+                                  PlainObject* templateObject)
+ {
+     MOZ_RELEASE_ASSERT(cx->zone()->types.activeAnalysis);
+ 
+-    ScopedJSDeletePtr<TypeNewScript> nativeNewScript(cx->new_<TypeNewScript>());
++    auto nativeNewScript = cx->make_unique<TypeNewScript>();
+     if (!nativeNewScript)
+         return nullptr;
+ 
+     nativeNewScript->function_ = newScript->function();
+     nativeNewScript->templateObject_ = templateObject;
+ 
+     Initializer* cursor = newScript->initializerList;
+     while (cursor->kind != Initializer::DONE) { cursor++; }
+@@ -3729,17 +3730,17 @@ TypeNewScript::makeNativeVersion(JSConte
+ 
+     nativeNewScript->initializerList = cx->zone()->pod_calloc<Initializer>(initializerLength);
+     if (!nativeNewScript->initializerList) {
+         ReportOutOfMemory(cx);
+         return nullptr;
+     }
+     PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
+ 
+-    return nativeNewScript.forget();
++    return nativeNewScript.release();
+ }
+ 
+ size_t
+ TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+ {
+     size_t n = mallocSizeOf(this);
+     n += mallocSizeOf(preliminaryObjects);
+     n += mallocSizeOf(initializerList);

+ 94 - 0
frg/work-js/mozilla-release/patches/1467438-4-62a1.patch

@@ -0,0 +1,94 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1528400020 25200
+#      Thu Jun 07 12:33:40 2018 -0700
+# Node ID 007392eca49c8fbad109ce5f6030a79a76fd6cbb
+# Parent  4789a350ec7ff9ed4d6f300bcecdde771f54cc77
+Bug 1467438 - Part 4: Remove ScopedJSFreePtr, ScopedJSDeletePtr, and ScopedReleasePtr. r=sfink
+
+diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h
+--- a/ipc/glue/ProtocolUtils.h
++++ b/ipc/glue/ProtocolUtils.h
+@@ -24,16 +24,17 @@
+ #include "mozilla/ipc/Shmem.h"
+ #include "mozilla/ipc/Transport.h"
+ #include "mozilla/ipc/MessageLink.h"
+ #include "mozilla/LinkedList.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/MozPromise.h"
+ #include "mozilla/Mutex.h"
+ #include "mozilla/NotNull.h"
++#include "mozilla/Scoped.h"
+ #include "mozilla/UniquePtr.h"
+ #include "MainThreadUtils.h"
+ #include "nsILabelableRunnable.h"
+ 
+ #if defined(ANDROID) && defined(DEBUG)
+ #include <android/log.h>
+ #endif
+ 
+diff --git a/js/public/Utility.h b/js/public/Utility.h
+--- a/js/public/Utility.h
++++ b/js/public/Utility.h
+@@ -7,17 +7,16 @@
+ #ifndef js_Utility_h
+ #define js_Utility_h
+ 
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Atomics.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Compiler.h"
+ #include "mozilla/Move.h"
+-#include "mozilla/Scoped.h"
+ #include "mozilla/TemplateLib.h"
+ #include "mozilla/UniquePtr.h"
+ #include "mozilla/WrappingOperations.h"
+ 
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ #ifdef JS_OOM_DO_BACKTRACES
+@@ -601,43 +600,16 @@ js_pod_realloc(T* prior, size_t oldSize,
+ {
+     MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
+     size_t bytes;
+     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
+         return nullptr;
+     return static_cast<T*>(js_realloc(prior, bytes));
+ }
+ 
+-namespace js {
+-
+-template<typename T>
+-struct ScopedFreePtrTraits
+-{
+-    typedef T* type;
+-    static T* empty() { return nullptr; }
+-    static void release(T* ptr) { js_free(ptr); }
+-};
+-SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
+-
+-template <typename T>
+-struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
+-{
+-    static void release(T* ptr) { js_delete(ptr); }
+-};
+-SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
+-
+-template <typename T>
+-struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
+-{
+-    static void release(T* ptr) { if (ptr) ptr->release(); }
+-};
+-SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
+-
+-} /* namespace js */
+-
+ namespace JS {
+ 
+ template<typename T>
+ struct DeletePolicy
+ {
+     constexpr DeletePolicy() {}
+ 
+     template<typename U>

+ 29 - 0
frg/work-js/mozilla-release/patches/1467438-5-62a1.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Steve Fink <sfink@mozilla.com>
+# Date 1529718428 25200
+#      Fri Jun 22 18:47:08 2018 -0700
+# Node ID d1c6061c19e85326c82dad8782534e1d0f7979e6
+# Parent  4b799334c53e22916e3402aafbecde7569134ec0
+Bug 1467438 - Need to include Scoped.h (unified bustage) on a CLOSED TREE
+
+diff --git a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp
+--- a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp
++++ b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp
+@@ -13,16 +13,17 @@
+ #include "mozilla/UniquePtr.h"
+ #include "nsClassHashtable.h"
+ #include "nsDataHashtable.h"
+ #include "nsILocalFile.h"
+ #include "nsIObserverService.h"
+ #include "nsProxyRelease.h"
+ #include "nsTArray.h"
+ #include "mozilla/Logging.h"
++#include "mozilla/Scoped.h"
+ 
+ namespace mozilla {
+ 
+ // Enclose everything which is not exported in an anonymous namespace.
+ namespace {
+ 
+ /**
+  * An event used to notify the main thread when an error happens.

+ 45 - 0
frg/work-js/mozilla-release/patches/1467753-62a1.patch

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

+ 317 - 0
frg/work-js/mozilla-release/patches/1468867-1-62a1.patch

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

+ 1693 - 0
frg/work-js/mozilla-release/patches/1468867-2-62a1.patch

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

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

@@ -2,7 +2,7 @@
 # User Jon Coppeard <jcoppeard@mozilla.com>
 # Date 1534174754 -3600
 # Node ID 08bf805f6f0ef61f68686ef1ca2cc6f750a2cfa0
-# Parent  5660b9d6ef1edb68673d2fd8abc75873ab08f4f7
+# Parent  59621353be1bc58df90c0629eb16869513f187e5
 Bug 1469004 - Add an API to create a module namespace object r=anba
 
 diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js
@@ -56,7 +56,7 @@ diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js
 diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp
 --- a/js/src/builtin/ModuleObject.cpp
 +++ b/js/src/builtin/ModuleObject.cpp
-@@ -1152,16 +1152,32 @@ ModuleObject::Instantiate(JSContext* cx,
+@@ -1166,16 +1166,32 @@ ModuleObject::Instantiate(JSContext* cx,
  }
  
  /* static */ bool
@@ -115,7 +115,7 @@ diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h
 diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
 --- a/js/src/vm/CommonPropertyNames.h
 +++ b/js/src/vm/CommonPropertyNames.h
-@@ -155,16 +155,17 @@
+@@ -156,16 +156,17 @@
      macro(Generator, Generator, "Generator") \
      macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
      macro(GeneratorNext, GeneratorNext, "GeneratorNext") \
@@ -133,4 +133,3 @@ diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
      macro(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \
      macro(GetTypeError, GetTypeError, "GetTypeError") \
      macro(global, global, "global") \
-

+ 15 - 15
frg/work-js/mozilla-release/patches/1470250-1-63a1.patch

@@ -2,7 +2,7 @@
 # User Jan de Mooij <jdemooij@mozilla.com>
 # Date 1529998925 -7200
 # Node ID 2f70bd2a3a9b4ee46613b08533bb106e9a73cd20
-# Parent  269d6ae997b0a737e5c6381f5b274987094dbd64
+# Parent  1cfb06673d7e226ff603e787d0d538a4919237ce
 Bug 1470250 part 1 - Use correct realm in ObjectGroupRealm::makeGroup. r=luke
 
 diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp
@@ -28,7 +28,7 @@ diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp
      resultPairObj->initDenseElement(0, NullValue());
      resultPairObj->initDenseElement(1, NullValue());
  
-@@ -1199,17 +1200,18 @@ SetIteratorObject::next(Handle<SetIterat
+@@ -1202,17 +1203,18 @@ SetIteratorObject::next(Handle<SetIterat
  /* static */ JSObject*
  SetIteratorObject::createResult(JSContext* cx)
  {
@@ -164,7 +164,7 @@ diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp
 diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
 --- a/js/src/vm/ObjectGroup.cpp
 +++ b/js/src/vm/ObjectGroup.cpp
-@@ -317,18 +317,18 @@ JSObject::makeLazyGroup(JSContext* cx, H
+@@ -319,18 +319,18 @@ JSObject::makeLazyGroup(JSContext* cx, H
  
      if (obj->isNative() && obj->as<NativeObject>().isIndexed())
          initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
@@ -185,7 +185,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
      /* Fill in the type according to the state of this object. */
  
      if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
-@@ -570,17 +570,18 @@ ObjectGroup::defaultNewGroup(JSContext* 
+@@ -575,17 +575,18 @@ ObjectGroup::defaultNewGroup(JSContext* 
          return group;
      }
  
@@ -205,7 +205,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
          ReportOutOfMemory(cx);
          return nullptr;
      }
-@@ -613,19 +614,23 @@ ObjectGroup::defaultNewGroup(JSContext* 
+@@ -618,19 +619,23 @@ ObjectGroup::defaultNewGroup(JSContext* 
          AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type());
      }
  
@@ -228,9 +228,9 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
  
      if (!table) {
          table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
-         if (!table || !table->init()) {
-             ReportOutOfMemory(cx);
-@@ -643,17 +648,19 @@ ObjectGroup::lazySingletonGroup(JSContex
+         if (!table)
+             return nullptr;
+@@ -651,17 +656,19 @@ ObjectGroup::lazySingletonGroup(JSContex
  
          return group;
      }
@@ -251,7 +251,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
          ReportOutOfMemory(cx);
          return nullptr;
      }
-@@ -867,17 +874,17 @@ ObjectGroup::newArrayObject(JSContext* c
+@@ -878,17 +885,17 @@ ObjectGroup::newArrayObject(JSContext* c
      RootedObjectGroup group(cx);
      if (p) {
          group = p->value();
@@ -270,7 +270,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
          if (!p.add(cx, *table, ObjectGroupRealm::ArrayObjectKey(elementType), group))
              return nullptr;
      }
-@@ -1191,17 +1198,18 @@ ObjectGroup::newPlainObject(JSContext* c
+@@ -1205,17 +1212,18 @@ ObjectGroup::newPlainObject(JSContext* c
          if (!CanShareObjectGroup(properties, nproperties))
              return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
  
@@ -290,7 +290,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
          RootedPlainObject obj(cx, NewObjectWithGroup<PlainObject>(cx, group,
                                                                    allocKind, TenuredObject));
          if (!obj || !AddPlainObjectProperties(cx, obj, properties, nproperties))
-@@ -1463,17 +1471,18 @@ ObjectGroup::allocationSiteGroup(JSConte
+@@ -1480,17 +1488,18 @@ ObjectGroup::allocationSiteGroup(JSConte
  
      ObjectGroupRealm::AllocationSiteTable::AddPtr p = table->lookupForAdd(key);
      if (p)
@@ -310,7 +310,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
          // Keep track of the preliminary objects with this group, so we can try
          // to use an unboxed layout for the object once some are allocated.
          Shape* shape = script->getObject(pc)->as<PlainObject>().lastProperty();
-@@ -1667,26 +1676,26 @@ ObjectGroupRealm::replaceDefaultNewGroup
+@@ -1684,26 +1693,26 @@ ObjectGroupRealm::replaceDefaultNewGroup
          AutoEnterOOMUnsafeRegion oomUnsafe;
          if (!defaultNewTable->putNew(lookup, NewEntry(group, associated)))
              oomUnsafe.crash("Inconsistent object table");
@@ -339,7 +339,7 @@ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
  ObjectGroup*
  ObjectGroupRealm::getStringSplitStringGroup(JSContext* cx)
  {
-@@ -1702,17 +1711,17 @@ ObjectGroupRealm::getStringSplitStringGr
+@@ -1719,17 +1728,17 @@ ObjectGroupRealm::getStringSplitStringGr
  
      const Class* clasp = GetClassForProtoKey(JSProto_Array);
  
@@ -380,7 +380,7 @@ diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
  #ifdef DEBUG
      static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group);
  #endif
-@@ -690,17 +690,17 @@ class ObjectGroupRealm
+@@ -694,17 +694,17 @@ class ObjectGroupRealm
  
      void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                      JSProtoKey kind, ObjectGroup* group);
@@ -402,7 +402,7 @@ diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.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
-@@ -1226,17 +1226,18 @@ RegExpRealm::createMatchResultTemplateOb
+@@ -1224,17 +1224,18 @@ RegExpRealm::createMatchResultTemplateOb
      /* Create template array object */
      RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount,
                                                                    nullptr, TenuredObject));

+ 1174 - 0
frg/work-js/mozilla-release/patches/1470522-63a1.patch

@@ -0,0 +1,1174 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1529102325 14400
+# Node ID 22123be00ffb183377048bcc7d8ace84f2a352a4
+# Parent  e9a8f9b1b705b81aa7e31254e4b97e7f3a0de35c
+Bug 1470522 - Enable JS dump functions under JS_JITSPEW. r=jandem
+
+MozReview-Commit-ID: 5WWncxovx2M
+
+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
+@@ -3262,17 +3262,17 @@ DisableTraceLogger(JSContext* cx, unsign
+     CallArgs args = CallArgsFromVp(argc, vp);
+     TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
+     args.rval().setBoolean(TraceLoggerDisable(logger));
+ 
+     return true;
+ }
+ #endif
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ static bool
+ DumpObject(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     RootedObject obj(cx, ToObject(cx, args.get(0)));
+     if (!obj)
+         return false;
+ 
+@@ -5749,17 +5749,17 @@ gc::ZealModeHelpText),
+ 
+     JS_FN_HELP("shortestPaths", ShortestPaths, 3, 0,
+ "shortestPaths(start, targets, maxNumPaths)",
+ "  Return an array of arrays of shortest retaining paths. There is an array of\n"
+ "  shortest retaining paths for each object in |targets|. The maximum number of\n"
+ "  paths in each of those arrays is bounded by |maxNumPaths|. Each element in a\n"
+ "  path is of the form |{ predecessor, edge }|."),
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     JS_FN_HELP("dumpObject", DumpObject, 1, 0,
+ "dumpObject()",
+ "  Dump an internal representation of an object."),
+ #endif
+ 
+     JS_FN_HELP("sharedMemoryEnabled", SharedMemoryEnabled, 0, 0,
+ "sharedMemoryEnabled()",
+ "  Return true if SharedArrayBuffer and Atomics are enabled"),
+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
+@@ -310,17 +310,17 @@ JSJitFrameIter::numActualArgs() const
+ void
+ JSJitFrameIter::dumpBaseline() const
+ {
+     MOZ_ASSERT(isBaselineJS());
+ 
+     fprintf(stderr, " JS Baseline frame\n");
+     if (isFunctionFrame()) {
+         fprintf(stderr, "  callee fun: ");
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         DumpObject(callee());
+ #else
+         fprintf(stderr, "?\n");
+ #endif
+     } else {
+         fprintf(stderr, "  global frame, no callee\n");
+     }
+ 
+@@ -336,17 +336,17 @@ JSJitFrameIter::dumpBaseline() const
+     fprintf(stderr, "  current op: %s\n", CodeName[*pc]);
+ 
+     fprintf(stderr, "  actual args: %d\n", numActualArgs());
+ 
+     BaselineFrame* frame = baselineFrame();
+ 
+     for (unsigned i = 0; i < frame->numValueSlots(); i++) {
+         fprintf(stderr, "  slot %u: ", i);
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         Value* v = frame->valueSlot(i);
+         DumpValue(*v);
+ #else
+         fprintf(stderr, "?\n");
+ #endif
+     }
+ }
+ 
+diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
+--- a/js/src/jit/JitFrames.cpp
++++ b/js/src/jit/JitFrames.cpp
+@@ -2333,17 +2333,17 @@ SnapshotIterator::warnUnreadableAllocati
+ }
+ 
+ struct DumpOp {
+     explicit DumpOp(unsigned int i) : i_(i) {}
+ 
+     unsigned int i_;
+     void operator()(const Value& v) {
+         fprintf(stderr, "  actual (arg %d): ", i_);
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         DumpValue(v);
+ #else
+         fprintf(stderr, "?\n");
+ #endif
+         i_++;
+     }
+ };
+ 
+@@ -2356,17 +2356,17 @@ InlineFrameIterator::dump() const
+         fprintf(stderr, " JS frame (inlined)\n");
+     else
+         fprintf(stderr, " JS frame\n");
+ 
+     bool isFunction = false;
+     if (isFunctionFrame()) {
+         isFunction = true;
+         fprintf(stderr, "  callee fun: ");
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         DumpObject(callee(fallback));
+ #else
+         fprintf(stderr, "?\n");
+ #endif
+     } else {
+         fprintf(stderr, "  global frame, no callee\n");
+     }
+ 
+@@ -2395,17 +2395,17 @@ InlineFrameIterator::dump() const
+                     DumpOp d(calleeTemplate()->nargs());
+                     unaliasedForEachActual(TlsContext.get(), d, ReadFrame_Overflown, fallback);
+                 }
+ 
+                 fprintf(stderr, "  slot %d: ", int(i - 2 - calleeTemplate()->nargs()));
+             }
+         } else
+             fprintf(stderr, "  slot %u: ", i);
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         DumpValue(si.maybeRead(fallback));
+ #else
+         fprintf(stderr, "?\n");
+ #endif
+     }
+ 
+     fputc('\n', stderr);
+ }
+diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp
+--- a/js/src/jsfriendapi.cpp
++++ b/js/src/jsfriendapi.cpp
+@@ -664,17 +664,17 @@ JS_FRIEND_API(JSObject*)
+ JS_CloneObject(JSContext* cx, HandleObject obj, HandleObject protoArg)
+ {
+     // |obj| might be in a different compartment.
+     assertSameCompartment(cx, protoArg);
+     Rooted<TaggedProto> proto(cx, TaggedProto(protoArg.get()));
+     return CloneObject(cx, obj, proto);
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ // We don't want jsfriendapi.h to depend on GenericPrinter,
+ // so these functions are declared directly in the cpp.
+ 
+ namespace js {
+ 
+ extern JS_FRIEND_API(void)
+ DumpString(JSString* str, js::GenericPrinter& out);
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -235,17 +235,17 @@ JS_FRIEND_API(bool)
+ AddRawValueRoot(JSContext* cx, JS::Value* vp, const char* name);
+ 
+ JS_FRIEND_API(void)
+ RemoveRawValueRoot(JSContext* cx, JS::Value* vp);
+ 
+ JS_FRIEND_API(JSAtom*)
+ GetPropertyNameFromPC(JSScript* script, jsbytecode* pc);
+ 
+-#ifdef JS_DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ /*
+  * Routines to print out values during debugging. These are FRIEND_API to help
+  * the debugger find them and to support temporarily hacking js::Dump* calls
+  * into other code. Note that there are overloads that do not require the FILE*
+  * parameter, which will default to stderr.
+  */
+ 
+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
+@@ -2603,17 +2603,17 @@ PCToLine(JSContext* cx, unsigned argc, V
+         return false;
+     lineno = PCToLineNumber(script, script->offsetToPC(i));
+     if (!lineno)
+         return false;
+     args.rval().setInt32(lineno);
+     return true;
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ static void
+ UpdateSwitchTableBounds(JSContext* cx, HandleScript script, unsigned offset,
+                         unsigned* start, unsigned* end)
+ {
+     jsbytecode* pc;
+     JSOp op;
+     ptrdiff_t jmplen;
+@@ -2716,26 +2716,26 @@ SrcNotes(JSContext* cx, HandleScript scr
+ 
+           case SRC_WHILE:
+           case SRC_NEXTCASE:
+             if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                 return false;
+             break;
+ 
+           case SRC_TABLESWITCH: {
+-            JSOp op = JSOp(script->code()[offset]);
++            mozilla::DebugOnly<JSOp> op = JSOp(script->code()[offset]);
+             MOZ_ASSERT(op == JSOP_TABLESWITCH);
+             if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                 return false;
+             UpdateSwitchTableBounds(cx, script, offset,
+                                     &switchTableStart, &switchTableEnd);
+             break;
+           }
+           case SRC_CONDSWITCH: {
+-            JSOp op = JSOp(script->code()[offset]);
++            mozilla::DebugOnly<JSOp> op = JSOp(script->code()[offset]);
+             MOZ_ASSERT(op == JSOP_CONDSWITCH);
+             if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                 return false;
+             if (unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1)) {
+                 if (!sp->jsprintf(" first case offset %u", caseOff))
+                     return false;
+             }
+             UpdateSwitchTableBounds(cx, script, offset,
+@@ -3207,17 +3207,17 @@ DisassWithSrc(JSContext* cx, unsigned ar
+ 
+         fprintf(gOutFile->fp, "%s\n", sprinter.string());
+     }
+ 
+     args.rval().setUndefined();
+     return true;
+ }
+ 
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ /* Pretend we can always preserve wrappers for dummy DOM objects. */
+ static bool
+ DummyPreserveWrapperCallback(JSContext* cx, JSObject* obj)
+ {
+     return true;
+ }
+ 
+@@ -4092,17 +4092,17 @@ ClearLastWarning(JSContext* cx, unsigned
+     }
+ 
+     sc->lastWarning.setNull();
+ 
+     args.rval().setUndefined();
+     return true;
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ static bool
+ StackDump(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+ 
+     if (!gOutFile->isOpen()) {
+         JS_ReportErrorASCII(cx, "output file is closed");
+         return false;
+@@ -6686,17 +6686,17 @@ static const JSFunctionSpecWithHelp shel
+     JS_FN_HELP("stopTimingMutator", StopTimingMutator, 0, 0,
+ "stopTimingMutator()",
+ "  Stop accounting time to mutator vs GC and dump the results."),
+ 
+     JS_FN_HELP("throwError", ThrowError, 0, 0,
+ "throwError()",
+ "  Throw an error from JS_ReportError."),
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     JS_FN_HELP("disassemble", DisassembleToString, 1, 0,
+ "disassemble([fun/code])",
+ "  Return the disassembly for the given function or code.\n"
+ "  All disassembly functions take these options as leading string arguments:\n"
+ "    \"-r\" (disassemble recursively)\n"
+ "    \"-l\" (show line numbers)\n"
+ "    \"-S\" (omit source notes)"),
+ 
+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
+@@ -324,38 +324,38 @@ class BytecodeParser
+   private:
+     class Bytecode
+     {
+       public:
+         explicit Bytecode(const LifoAllocPolicy<Fallible>& alloc)
+           : parsed(false),
+             stackDepth(0),
+             offsetStack(nullptr)
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+             ,
+             stackDepthAfter(0),
+             offsetStackAfter(nullptr),
+             jumpOrigins(alloc)
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+         {}
+ 
+         // Whether this instruction has been analyzed to get its output defines
+         // and stack.
+         bool parsed : 1;
+ 
+         // Stack depth before this opcode.
+         uint32_t stackDepth;
+ 
+         // Pointer to array of |stackDepth| offsets.  An element at position N
+         // in the array is the offset of the opcode that defined the
+         // corresponding stack slot.  The top of the stack is at position
+         // |stackDepth - 1|.
+         OffsetAndDefIndex* offsetStack;
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         // stack depth after this opcode.
+         uint32_t stackDepthAfter;
+ 
+         // Pointer to array of |stackDepthAfter| offsets.
+         OffsetAndDefIndex* offsetStackAfter;
+ 
+         struct JumpInfo {
+             uint32_t from;
+@@ -365,48 +365,48 @@ class BytecodeParser
+               : from(from_),
+                 kind(kind_)
+             {}
+         };
+ 
+         // A list of offsets of the bytecode that jumps to this bytecode,
+         // exclusing previous bytecode.
+         Vector<JumpInfo, 0, LifoAllocPolicy<Fallible>> jumpOrigins;
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+         bool captureOffsetStack(LifoAlloc& alloc, const OffsetAndDefIndex* stack, uint32_t depth) {
+             stackDepth = depth;
+             offsetStack = alloc.newArray<OffsetAndDefIndex>(stackDepth);
+             if (!offsetStack)
+                 return false;
+             if (stackDepth) {
+                 for (uint32_t n = 0; n < stackDepth; n++)
+                     offsetStack[n] = stack[n];
+             }
+             return true;
+         }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+         bool captureOffsetStackAfter(LifoAlloc& alloc, const OffsetAndDefIndex* stack,
+                                      uint32_t depth) {
+             stackDepthAfter = depth;
+             offsetStackAfter = alloc.newArray<OffsetAndDefIndex>(stackDepthAfter);
+             if (!offsetStackAfter)
+                 return false;
+             if (stackDepthAfter) {
+                 for (uint32_t n = 0; n < stackDepthAfter; n++)
+                     offsetStackAfter[n] = stack[n];
+             }
+             return true;
+         }
+ 
+         bool addJump(uint32_t from, JumpKind kind) {
+             return jumpOrigins.append(JumpInfo(from, kind));
+         }
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+         // When control-flow merges, intersect the stacks, marking slots that
+         // are defined by different offsets and/or defIndices merged.
+         // This is sufficient for forward control-flow.  It doesn't grok loops
+         // -- for that you would have to iterate to a fixed point -- but there
+         // shouldn't be operands on the stack at a loop back-edge anyway.
+         void mergeOffsetStack(const OffsetAndDefIndex* stack, uint32_t depth) {
+             MOZ_ASSERT(depth == stackDepth);
+@@ -422,52 +422,52 @@ class BytecodeParser
+     };
+ 
+     JSContext* cx_;
+     LifoAllocScope allocScope_;
+     RootedScript script_;
+ 
+     Bytecode** codeArray_;
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     // Dedicated mode for stack dump.
+     // Capture stack after each opcode, and also enable special handling for
+     // some opcodes to make stack transition clearer.
+     bool isStackDump;
+-#endif /* DEBUG */
++#endif
+ 
+   public:
+     BytecodeParser(JSContext* cx, JSScript* script)
+       : cx_(cx),
+         allocScope_(&cx->tempLifoAlloc()),
+         script_(cx, script),
+         codeArray_(nullptr)
+ #ifdef DEBUG
+         ,
+         isStackDump(false)
+-#endif /* DEBUG */
++#endif
+     {}
+ 
+     bool parse();
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     bool isReachable(const jsbytecode* pc) { return maybeCode(pc); }
+-#endif /* DEBUG */
++#endif
+ 
+     uint32_t stackDepthAtPC(uint32_t offset) {
+         // Sometimes the code generator in debug mode asks about the stack depth
+         // of unreachable code (bug 932180 comment 22).  Assume that unreachable
+         // code has no operands on the stack.
+         return getCode(offset).stackDepth;
+     }
+     uint32_t stackDepthAtPC(const jsbytecode* pc) {
+         return stackDepthAtPC(script_->pcToOffset(pc));
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     uint32_t stackDepthAfterPC(uint32_t offset) {
+         return getCode(offset).stackDepthAfter;
+     }
+     uint32_t stackDepthAfterPC(const jsbytecode* pc) {
+         return stackDepthAfterPC(script_->pcToOffset(pc));
+     }
+ #endif
+ 
+@@ -484,17 +484,17 @@ class BytecodeParser
+         size_t offset = script_->pcToOffset(pc);
+         const OffsetAndDefIndex& offsetAndDefIndex = offsetForStackOperand(offset, operand);
+         if (offsetAndDefIndex.isSpecial())
+             return nullptr;
+         *defIndex = offsetAndDefIndex.defIndex();
+         return script_->offsetToPC(offsetAndDefIndex.offset());
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     const OffsetAndDefIndex& offsetForStackOperandAfterPC(uint32_t offset, int operand) {
+         Bytecode& code = getCode(offset);
+         if (operand < 0) {
+             operand += code.stackDepthAfter;
+             MOZ_ASSERT(operand >= 0);
+         }
+         MOZ_ASSERT(uint32_t(operand) < code.stackDepthAfter);
+         return code.offsetStackAfter[operand];
+@@ -510,17 +510,17 @@ class BytecodeParser
+         }
+ 
+         return true;
+     }
+ 
+     void setStackDump() {
+         isStackDump = true;
+     }
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+   private:
+     LifoAlloc& alloc() {
+         return allocScope_.alloc();
+     }
+ 
+     void reportOOM() {
+         allocScope_.releaseEarly();
+@@ -537,17 +537,17 @@ class BytecodeParser
+         return *codeArray_[offset];
+     }
+ 
+     Bytecode* maybeCode(uint32_t offset) {
+         MOZ_ASSERT(offset < script_->length());
+         return codeArray_[offset];
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     Bytecode* maybeCode(const jsbytecode* pc) { return maybeCode(script_->pcToOffset(pc)); }
+ #endif
+ 
+     uint32_t simulateOp(JSOp op, uint32_t offset, OffsetAndDefIndex* offsetStack,
+                         uint32_t stackDepth);
+ 
+     inline bool recordBytecode(uint32_t offset, const OffsetAndDefIndex* offsetStack,
+                                uint32_t stackDepth);
+@@ -966,17 +966,17 @@ BytecodeParser::parse()
+             if (!recordBytecode(successorOffset, offsetStack, stackDepth))
+                 return false;
+         }
+     }
+ 
+     return true;
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ bool
+ js::ReconstructStackDepth(JSContext* cx, JSScript* script, jsbytecode* pc, uint32_t* depth, bool* reachablePC)
+ {
+     BytecodeParser parser(cx, script);
+     if (!parser.parse())
+         return false;
+ 
+@@ -1144,17 +1144,21 @@ ToDisassemblySource(JSContext* cx, Handl
+         if (!copy) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+         bytes->initBytes(std::move(copy));
+         return true;
+     }
+ 
+-    if (JS::RuntimeHeapIsBusy() || !cx->isAllocAllowed()) {
++    if (JS::RuntimeHeapIsBusy()
++#ifdef DEBUG
++        || !cx->isAllocAllowed()
++#endif
++        ) {
+         UniqueChars source = JS_smprintf("<value>");
+         if (!source) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+         bytes->initBytes(std::move(source));
+         return true;
+     }
+@@ -1576,17 +1580,17 @@ Disassemble1(JSContext* cx, HandleScript
+ 
+ unsigned
+ js::Disassemble1(JSContext* cx, JS::Handle<JSScript*> script, jsbytecode* pc, unsigned loc,
+                  bool lines, Sprinter* sp)
+ {
+     return Disassemble1(cx, script, pc, loc, lines, nullptr, sp);
+ }
+ 
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ namespace {
+ /*
+  * The expression decompiler is invoked by error handling code to produce a
+  * string representation of the erroring expression. As it's only a debugging
+  * tool, it only supports basic expressions. For anything complicated, it simply
+  * puts "(intermediate value)" into the error result.
+  *
+@@ -1617,49 +1621,49 @@ namespace {
+  */
+ struct ExpressionDecompiler
+ {
+     JSContext* cx;
+     RootedScript script;
+     BytecodeParser parser;
+     Sprinter sprinter;
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     // Dedicated mode for stack dump.
+     // Generates an expression for stack dump, including internal state,
+     // and also disables special handling for self-hosted code.
+     bool isStackDump;
+-#endif /* DEBUG */
++#endif
+ 
+     ExpressionDecompiler(JSContext* cx, JSScript* script)
+         : cx(cx),
+           script(cx, script),
+           parser(cx, script),
+           sprinter(cx)
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+           ,
+           isStackDump(false)
+-#endif /* DEBUG */
++#endif
+     {}
+     bool init();
+     bool decompilePCForStackOperand(jsbytecode* pc, int i);
+     bool decompilePC(jsbytecode* pc, uint8_t defIndex);
+     bool decompilePC(const OffsetAndDefIndex& offsetAndDefIndex);
+     JSAtom* getArg(unsigned slot);
+     JSAtom* loadAtom(jsbytecode* pc);
+     bool quote(JSString* s, uint32_t quote);
+     bool write(const char* s);
+     bool write(JSString* str);
+     bool getOutput(char** out);
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void setStackDump() {
+         isStackDump = true;
+         parser.setStackDump();
+     }
+-#endif /* DEBUG */
++#endif
+ };
+ 
+ bool
+ ExpressionDecompiler::decompilePCForStackOperand(jsbytecode* pc, int i)
+ {
+     return decompilePC(parser.offsetForStackOperand(script->pcToOffset(pc), i));
+ }
+ 
+@@ -2165,17 +2169,17 @@ ExpressionDecompiler::getOutput(char** r
+         return false;
+     js_memcpy(*res, sprinter.stringAt(0), len);
+     (*res)[len] = 0;
+     return true;
+ }
+ 
+ }  // anonymous namespace
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ static bool
+ DecompileAtPCForStackDump(JSContext* cx, HandleScript script,
+                           const OffsetAndDefIndex& offsetAndDefIndex, Sprinter* sp)
+ {
+     ExpressionDecompiler ed(cx, script);
+     ed.setStackDump();
+     if (!ed.init())
+         return false;
+@@ -2186,17 +2190,17 @@ DecompileAtPCForStackDump(JSContext* cx,
+     char* result;
+     if (!ed.getOutput(&result))
+         return false;
+ 
+     bool ok = sp->put(result);
+     js_free(result);
+     return ok;
+ }
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ static bool
+ FindStartPC(JSContext* cx, const FrameIter& iter, int spindex, int skipStackHits, const Value& v,
+             jsbytecode** valuepc, uint8_t* defIndex)
+ {
+     jsbytecode* current = *valuepc;
+     *valuepc = nullptr;
+     *defIndex = 0;
+diff --git a/js/src/vm/BytecodeUtil.h b/js/src/vm/BytecodeUtil.h
+--- a/js/src/vm/BytecodeUtil.h
++++ b/js/src/vm/BytecodeUtil.h
+@@ -556,17 +556,17 @@ StackUses(jsbytecode* pc)
+ MOZ_ALWAYS_INLINE unsigned
+ StackDefs(jsbytecode* pc)
+ {
+     int ndefs = CodeSpec[*pc].ndefs;
+     MOZ_ASSERT(ndefs >= 0);
+     return ndefs;
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ /*
+  * Given bytecode address pc in script's main program code, compute the operand
+  * stack depth just before (JSOp) *pc executes.  If *pc is not reachable, return
+  * false.
+  */
+ extern bool
+ ReconstructStackDepth(JSContext* cx, JSScript* script, jsbytecode* pc, uint32_t* depth, bool* reachablePC);
+ #endif
+@@ -907,17 +907,17 @@ class PCCounts
+ };
+ 
+ static inline jsbytecode*
+ GetNextPc(jsbytecode* pc)
+ {
+     return pc + GetBytecodeLength(pc);
+ }
+ 
+-#if defined(DEBUG)
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ /*
+  * Disassemblers, for debugging only.
+  */
+ extern MOZ_MUST_USE bool
+ Disassemble(JSContext* cx, JS::Handle<JSScript*> script, bool lines, Sprinter* sp);
+ 
+ unsigned
+ Disassemble1(JSContext* cx, JS::Handle<JSScript*> script, jsbytecode* pc, unsigned loc,
+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
+@@ -3394,17 +3394,17 @@ GetObjectSlotNameFunctor::operator()(JS:
+         } else {
+             snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
+         }
+     }
+ }
+ 
+ /*** Debugging routines **************************************************************************/
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ /*
+  * Routines to print out values during debugging.  These are FRIEND_API to help
+  * the debugger find them and to support temporarily hacking js::Dump* calls
+  * into other code.
+  */
+ 
+ static void
+@@ -3445,25 +3445,23 @@ dumpValue(const Value& v, js::GenericPri
+                 (void*) obj);
+     } else if (v.isBoolean()) {
+         if (v.toBoolean())
+             out.put("true");
+         else
+             out.put("false");
+     } else if (v.isMagic()) {
+         out.put("<invalid");
+-#ifdef DEBUG
+         switch (v.whyMagic()) {
+           case JS_ELEMENTS_HOLE:     out.put(" elements hole");      break;
+           case JS_NO_ITER_VALUE:     out.put(" no iter value");      break;
+           case JS_GENERATOR_CLOSING: out.put(" generator closing");  break;
+           case JS_OPTIMIZED_OUT:     out.put(" optimized out");      break;
+           default:                   out.put(" ?!");                 break;
+         }
+-#endif
+         out.putChar('>');
+     } else {
+         out.put("unexpected value");
+     }
+ }
+ 
+ namespace js {
+ 
+@@ -3738,17 +3736,17 @@ js::DumpInterpreterFrame(JSContext* cx, 
+         out.putChar('\n');
+ 
+         out.printf("  envChain: (JSObject*) %p\n", (void*) i.environmentChain(cx));
+ 
+         out.putChar('\n');
+     }
+ }
+ 
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ namespace js {
+ 
+ // We don't want jsfriendapi.h to depend on GenericPrinter,
+ // so these functions are declared directly in the cpp.
+ 
+ JS_FRIEND_API(void)
+ DumpBacktrace(JSContext* cx, js::GenericPrinter& out);
+diff --git a/js/src/vm/JSObject.h b/js/src/vm/JSObject.h
+--- a/js/src/vm/JSObject.h
++++ b/js/src/vm/JSObject.h
+@@ -528,17 +528,17 @@ class JSObject : public js::gc::Cell
+     }
+ 
+     template <class T>
+     const T& as() const {
+         MOZ_ASSERT(this->is<T>());
+         return *static_cast<const T*>(this);
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dump(js::GenericPrinter& fp) const;
+     void dump() const;
+ #endif
+ 
+     // Maximum size in bytes of a JSObject.
+     static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
+ 
+   protected:
+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
+@@ -103,17 +103,17 @@ JS::ubi::Concrete<JSString>::size(mozill
+ 
+     size += str.sizeOfExcludingThis(mallocSizeOf);
+ 
+     return size;
+ }
+ 
+ const char16_t JS::ubi::Concrete<JSString>::concreteTypeName[] = u"JSString";
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ template <typename CharT>
+ /*static */ void
+ JSString::dumpChars(const CharT* s, size_t n, js::GenericPrinter& out)
+ {
+     if (n == SIZE_MAX) {
+         n = 0;
+         while (s[n])
+@@ -245,17 +245,17 @@ JSString::equals(const char* s)
+     if (!linear) {
+         // This is DEBUG-only code.
+         fprintf(stderr, "OOM in JSString::equals!\n");
+         return false;
+     }
+ 
+     return StringEqualsAscii(linear, s);
+ }
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ template <typename CharT>
+ static MOZ_ALWAYS_INLINE bool
+ AllocChars(JSString* str, size_t length, CharT** chars, size_t* capacity)
+ {
+     /*
+      * String length doesn't include the null char, so include it here before
+      * doubling. Adding the null char after doubling would interact poorly with
+@@ -392,17 +392,17 @@ JSRope::hash(uint32_t* outHash) const
+                 break;
+             str = nodeStack.popCopy();
+         }
+     }
+ 
+     return true;
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ JSRope::dumpRepresentation(js::GenericPrinter& out, int indent) const
+ {
+     dumpRepresentationHeader(out, "JSRope");
+     indent += 2;
+ 
+     out.printf("%*sleft:  ", indent, "");
+     leftChild()->dumpRepresentation(out, indent);
+@@ -815,17 +815,17 @@ JSFlatString*
+ JSDependentString::undepend(JSContext* cx)
+ {
+     MOZ_ASSERT(JSString::isDependent());
+     return hasLatin1Chars()
+            ? undependInternal<Latin1Char>(cx)
+            : undependInternal<char16_t>(cx);
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ JSDependentString::dumpRepresentation(js::GenericPrinter& out, int indent) const
+ {
+     dumpRepresentationHeader(out, "JSDependentString");
+     indent += 2;
+ 
+     if (mozilla::Maybe<size_t> offset = baseOffset())
+         out.printf("%*soffset: %zu\n", indent, "", *offset);
+@@ -1384,17 +1384,17 @@ JSExternalString::ensureFlat(JSContext* 
+     // resulting string will still be in an AllocKind::EXTERNAL_STRING arena,
+     // but will no longer be an external string.
+     setNonInlineChars<char16_t>(s);
+     d.u1.flags = INIT_FLAT_FLAGS;
+ 
+     return &this->asFlat();
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ JSAtom::dump(js::GenericPrinter& out)
+ {
+     out.printf("JSAtom* (%p) = ", (void*) this);
+     this->JSString::dump(out);
+ }
+ 
+ void
+@@ -1408,17 +1408,17 @@ void
+ JSExternalString::dumpRepresentation(js::GenericPrinter& out, int indent) const
+ {
+     dumpRepresentationHeader(out, "JSExternalString");
+     indent += 2;
+ 
+     out.printf("%*sfinalizer: ((JSStringFinalizer*) %p)\n", indent, "", externalFinalizer());
+     dumpRepresentationChars(out, indent);
+ }
+-#endif /* DEBUG */
++#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ JSLinearString*
+ js::NewDependentString(JSContext* cx, JSString* baseArg, size_t start, size_t length)
+ {
+     if (length == 0)
+         return cx->emptyString();
+ 
+     JSLinearString* base = baseArg->ensureLinear(cx);
+@@ -1771,17 +1771,17 @@ NewMaybeExternalString(JSContext* cx, co
+ 
+     *allocatedExternal = true;
+     cache.put(str);
+     return str;
+ }
+ 
+ } /* namespace js */
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ JSExtensibleString::dumpRepresentation(js::GenericPrinter& out, int indent) const
+ {
+     dumpRepresentationHeader(out, "JSExtensibleString");
+     indent += 2;
+ 
+     out.printf("%*scapacity: %zu\n", indent, "", capacity());
+     dumpRepresentationChars(out, indent);
+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
+@@ -598,17 +598,17 @@ class JSString : public js::gc::Cell
+             AllocKind tenuredKind = asTenured().getAllocKind();
+             MOZ_ASSERT(kind == tenuredKind ||
+                        (tenuredKind == AllocKind::EXTERNAL_STRING && kind == AllocKind::STRING));
+         }
+ #endif
+         return kind;
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dump(); // Debugger-friendly stderr dump.
+     void dump(js::GenericPrinter& out);
+     void dumpNoNewline(js::GenericPrinter& out);
+     void dumpCharsNoNewline(js::GenericPrinter& out);
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+     void dumpRepresentationHeader(js::GenericPrinter& out, const char* subclass) const;
+ 
+     template <typename CharT>
+@@ -713,17 +713,17 @@ class JSRope : public JSString
+ 
+     JSString* rightChild() const {
+         MOZ_ASSERT(isRope());
+         return d.s.u3.right;
+     }
+ 
+     void traceChildren(JSTracer* trc);
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ #endif
+ 
+   private:
+     // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
+     // to call the methods below.
+     friend class js::jit::MacroAssembler;
+ 
+@@ -809,17 +809,17 @@ class JSLinearString : public JSString
+     MOZ_ALWAYS_INLINE
+     char16_t latin1OrTwoByteChar(size_t index) const {
+         MOZ_ASSERT(JSString::isLinear());
+         MOZ_ASSERT(index < length());
+         JS::AutoCheckCannotGC nogc;
+         return hasLatin1Chars() ? latin1Chars(nogc)[index] : twoByteChars(nogc)[index];
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentationChars(js::GenericPrinter& out, int indent) const;
+ #endif
+ };
+ 
+ static_assert(sizeof(JSLinearString) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+ class JSDependentString : public JSLinearString
+@@ -851,17 +851,17 @@ class JSDependentString : public JSLinea
+         MOZ_ASSERT(offset < base()->length());
+         return mozilla::Some(offset);
+     }
+ 
+   public:
+     static inline JSLinearString* new_(JSContext* cx, JSLinearString* base,
+                                        size_t start, size_t length);
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ #endif
+ 
+   private:
+     // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
+     // to call the method below.
+     friend class js::jit::MacroAssembler;
+ 
+@@ -945,17 +945,17 @@ class JSFlatString : public JSLinearStri
+      * Once a JSFlatString sub-class has been added to the atom state, this
+      * operation changes the string to the JSAtom type, in place.
+      */
+     MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoAtom(js::HashNumber hash);
+     MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoPermanentAtom(js::HashNumber hash);
+ 
+     inline void finalize(js::FreeOp* fop);
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ #endif
+ };
+ 
+ static_assert(sizeof(JSFlatString) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+ class JSExtensibleString : public JSFlatString
+@@ -966,17 +966,17 @@ class JSExtensibleString : public JSFlat
+ 
+   public:
+     MOZ_ALWAYS_INLINE
+     size_t capacity() const {
+         MOZ_ASSERT(JSString::isExtensible());
+         return d.s.u3.capacity;
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ #endif
+ };
+ 
+ static_assert(sizeof(JSExtensibleString) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+ class JSInlineString : public JSFlatString
+@@ -994,17 +994,17 @@ class JSInlineString : public JSFlatStri
+         MOZ_ASSERT(JSString::isInline());
+         MOZ_ASSERT(hasTwoByteChars());
+         return d.inlineStorageTwoByte;
+     }
+ 
+     template<typename CharT>
+     static bool lengthFits(size_t length);
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ #endif
+ 
+   private:
+     // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
+     // to call the method below.
+     friend class js::jit::MacroAssembler;
+     static size_t offsetOfInlineStorage() {
+@@ -1121,17 +1121,17 @@ class JSExternalString : public JSLinear
+ 
+     /*
+      * Free the external chars and allocate a new buffer, converting this to a
+      * flat string (which still lives in an AllocKind::EXTERNAL_STRING
+      * arena).
+      */
+     JSFlatString* ensureFlat(JSContext* cx);
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ #endif
+ };
+ 
+ static_assert(sizeof(JSExternalString) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+ class JSUndependedString : public JSFlatString
+@@ -1180,17 +1180,17 @@ class JSAtom : public JSFlatString
+         MOZ_ASSERT(static_cast<JSString*>(this)->isAtom());
+         MOZ_ASSERT(!isPinned());
+         d.u1.flags |= PINNED_ATOM_BIT;
+     }
+ 
+     inline js::HashNumber hash() const;
+     inline void initHash(js::HashNumber hash);
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dump(js::GenericPrinter& out);
+     void dump();
+ #endif
+ };
+ 
+ static_assert(sizeof(JSAtom) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+diff --git a/js/src/vm/SymbolType.cpp b/js/src/vm/SymbolType.cpp
+--- a/js/src/vm/SymbolType.cpp
++++ b/js/src/vm/SymbolType.cpp
+@@ -89,17 +89,17 @@ Symbol::for_(JSContext* cx, HandleString
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+     }
+     cx->markAtom(sym);
+     return sym;
+ }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ Symbol::dump()
+ {
+     js::Fprinter out(stderr);
+     dump(out);
+ }
+ 
+ void
+@@ -119,17 +119,17 @@ Symbol::dump(js::GenericPrinter& out)
+         out.putChar(')');
+ 
+         if (code_ == SymbolCode::UniqueSymbol)
+             out.printf("@%p", (void*) this);
+     } else {
+         out.printf("<Invalid Symbol code=%u>", unsigned(code_));
+     }
+ }
+-#endif  // DEBUG
++#endif  // defined(DEBUG) || defined(JS_JITSPEW)
+ 
+ bool
+ js::SymbolDescriptiveString(JSContext* cx, Symbol* sym, MutableHandleValue result)
+ {
+     // steps 2-5
+     StringBuffer sb(cx);
+     if (!sb.append("Symbol("))
+         return false;
+diff --git a/js/src/vm/SymbolType.h b/js/src/vm/SymbolType.h
+--- a/js/src/vm/SymbolType.h
++++ b/js/src/vm/SymbolType.h
+@@ -92,17 +92,17 @@ class Symbol : public js::gc::TenuredCel
+         if (thing && !thing->isWellKnownSymbol())
+             thing->asTenured().writeBarrierPre(thing);
+     }
+ 
+     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+         return mallocSizeOf(this);
+     }
+ 
+-#ifdef DEBUG
++#if defined(DEBUG) || defined(JS_JITSPEW)
+     void dump(); // Debugger-friendly stderr dump.
+     void dump(js::GenericPrinter& out);
+ #endif
+ };
+ 
+ } /* namespace JS */
+ 
+ namespace js {

+ 169 - 0
frg/work-js/mozilla-release/patches/1471878-63a1.patch

@@ -0,0 +1,169 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1533177283 14400
+# Node ID ad5ea44b20539d35847c031bbaa16367a66343f9
+# Parent  27c4c00c21bb554628d3533e297d8361a799c102
+Bug 1471878 - Use alignas on gc::Cell instead of manual padding. r=jonco
+
+MozReview-Commit-ID: 8E7Os4Rsh5M
+
+diff --git a/js/src/gc/Cell.h b/js/src/gc/Cell.h
+--- a/js/src/gc/Cell.h
++++ b/js/src/gc/Cell.h
+@@ -44,17 +44,17 @@ namespace gc {
+ 
+ class Arena;
+ enum class AllocKind : uint8_t;
+ struct Chunk;
+ class StoreBuffer;
+ class TenuredCell;
+ 
+ // A GC cell is the base class for all GC things.
+-struct Cell
++struct alignas(gc::CellAlignBytes) Cell
+ {
+   public:
+     MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
+     MOZ_ALWAYS_INLINE const TenuredCell& asTenured() const;
+     MOZ_ALWAYS_INLINE TenuredCell& asTenured();
+ 
+     MOZ_ALWAYS_INLINE bool isMarkedAny() const;
+     MOZ_ALWAYS_INLINE bool isMarkedBlack() const;
+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
+@@ -996,18 +996,16 @@ class JSScript : public js::gc::TenuredC
+     uint32_t sourceEnd_ = 0;
+     uint32_t toStringStart_ = 0;
+     uint32_t toStringEnd_ = 0;
+ 
+ #ifdef MOZ_VTUNE
+     // Unique Method ID passed to the VTune profiler, or 0 if unset.
+     // Allows attribution of different jitcode to the same source script.
+     uint32_t vtuneMethodId_ = 0;
+-    // Extra padding to maintain JSScript as a multiple of gc::CellAlignBytes.
+-    uint32_t __vtune_unused_padding_;
+ #endif
+ 
+     // Number of times the script has been called or has had backedges taken.
+     // When running in ion, also increased for any inlined scripts. Reset if
+     // the script's JIT code is forcibly discarded.
+     mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount = {};
+ 
+     // 16-bit fields.
+@@ -1175,24 +1173,16 @@ class JSScript : public js::gc::TenuredC
+         bool isAsync_ : 1;
+ 
+         bool hasRest_ : 1;
+ 
+         // True if the debugger's onNewScript hook has not yet been called.
+         bool hideScriptFromDebugger_ : 1;
+     } bitFields_;
+ 
+-    // Add padding so JSScript is gc::Cell aligned. Make padding protected
+-    // instead of private to suppress -Wunused-private-field compiler warnings.
+-  protected:
+-#if JS_BITS_PER_WORD == 32
+-    // Currently padding is needed.
+-    uint32_t padding_;
+-#endif
+-
+     //
+     // End of fields.  Start methods.
+     //
+ 
+   private:
+     template <js::XDRMode mode>
+     friend
+     js::XDRResult
+@@ -2150,23 +2140,16 @@ class LazyScript : public gc::TenuredCel
+     // 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_;
+ 
+-    // Add padding so LazyScript is gc::Cell aligned. Make padding protected
+-    // instead of private to suppress -Wunused-private-field compiler warnings.
+-  protected:
+-#if JS_BITS_PER_WORD == 32
+-    uint32_t padding;
+-#endif
+-
+   private:
+     static const uint32_t NumClosedOverBindingsBits = 20;
+     static const uint32_t NumInnerFunctionsBits = 20;
+ 
+     struct PackedView {
+         uint32_t shouldDeclareArguments : 1;
+         uint32_t hasThisBinding : 1;
+         uint32_t isAsync : 1;
+diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
+--- a/js/src/vm/Shape.h
++++ b/js/src/vm/Shape.h
+@@ -495,21 +495,16 @@ class BaseShape : public gc::TenuredCell
+                                          * dictionary last properties. */
+ 
+     /* For owned BaseShapes, the canonical unowned BaseShape. */
+     GCPtrUnownedBaseShape unowned_;
+ 
+     /* For owned BaseShapes, the shape's shape table. */
+     ShapeTable*      table_;
+ 
+-#if JS_BITS_PER_WORD == 32
+-    // Ensure sizeof(BaseShape) is a multiple of gc::CellAlignBytes.
+-    uint32_t padding_;
+-#endif
+-
+     BaseShape(const BaseShape& base) = delete;
+     BaseShape& operator=(const BaseShape& other) = delete;
+ 
+   public:
+     void finalize(FreeOp* fop);
+ 
+     explicit inline BaseShape(const StackBaseShape& base);
+ 
+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
+@@ -1193,19 +1193,18 @@ class JSAtom : public JSFlatString
+ 
+ static_assert(sizeof(JSAtom) == sizeof(JSString),
+               "string subclasses must be binary-compatible with JSString");
+ 
+ namespace js {
+ 
+ class NormalAtom : public JSAtom
+ {
+-  protected: // Silence Clang unused-field warning.
++  protected:
+     HashNumber hash_;
+-    uint32_t padding_; // Ensure the size is a multiple of gc::CellAlignBytes.
+ 
+   public:
+     HashNumber hash() const {
+         return hash_;
+     }
+     void initHash(HashNumber hash) {
+         hash_ = hash;
+     }
+@@ -1215,17 +1214,16 @@ static_assert(sizeof(NormalAtom) == size
+               "NormalAtom must have size of a string + HashNumber, "
+               "aligned to gc::CellAlignBytes");
+ 
+ class FatInlineAtom : public JSAtom
+ {
+   protected: // Silence Clang unused-field warning.
+     char inlineStorage_[sizeof(JSFatInlineString) - sizeof(JSString)];
+     HashNumber hash_;
+-    uint32_t padding_; // Ensure the size is a multiple of gc::CellAlignBytes.
+ 
+   public:
+     HashNumber hash() const {
+         return hash_;
+     }
+     void initHash(HashNumber hash) {
+         hash_ = hash;
+     }

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

@@ -0,0 +1,799 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530202064 25200
+#      Thu Jun 28 09:07:44 2018 -0700
+# Node ID bd01847472fbc512fbf56b8e4748cf5fad6ee897
+# Parent  4a79f1f833ecbb7d5ca2ea6cde313b0dfdfcfaec
+Bug 1471931 - Part 1: Replace some js_malloc/js_calloc/js_realloc with their js_pod_malloc/js_pod_calloc/js_pod_realloc counterparts. r=sfink
+
+diff --git a/js/src/builtin/Profilers.cpp b/js/src/builtin/Profilers.cpp
+--- a/js/src/builtin/Profilers.cpp
++++ b/js/src/builtin/Profilers.cpp
+@@ -23,16 +23,17 @@
+ #endif
+ #endif
+ 
+ #ifdef XP_WIN
+ # include <process.h>
+ # define getpid _getpid
+ #endif
+ 
++#include "util/Text.h"
+ #include "vm/Probes.h"
+ 
+ #include "vm/JSContext-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::ArrayLength;
+ 
+@@ -542,20 +543,19 @@ bool js_StartPerf()
+         if (!args.append(defaultArgs, ArrayLength(defaultArgs)))
+             return false;
+ 
+         const char* flags = getenv("MOZ_PROFILE_PERF_FLAGS");
+         if (!flags) {
+             flags = "--call-graph";
+         }
+ 
+-        UniqueChars flags2((char*)js_malloc(strlen(flags) + 1));
++        UniqueChars flags2 = DuplicateString(flags);
+         if (!flags2)
+             return false;
+-        strcpy(flags2.get(), flags);
+ 
+         // Split |flags2| on spaces.
+         char* toksave;
+         char* tok = strtok_r(flags2.get(), " ", &toksave);
+         while (tok) {
+             if (!args.append(tok))
+                 return false;
+             tok = strtok_r(nullptr, " ", &toksave);
+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
+@@ -2952,17 +2952,17 @@ class CloneBufferObject : public NativeO
+         Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
+         MOZ_ASSERT(args.length() == 0);
+ 
+         JSStructuredCloneData* data;
+         if (!getData(cx, obj, &data))
+             return false;
+ 
+         size_t size = data->Size();
+-        UniqueChars buffer(static_cast<char*>(js_malloc(size)));
++        UniqueChars buffer(js_pod_malloc<char>(size));
+         if (!buffer) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+         auto iter = data->Start();
+         data->ReadBytes(iter, buffer.get(), size);
+         JSString* str = JS_NewStringCopyN(cx, buffer.get(), size);
+         if (!str)
+@@ -2982,17 +2982,17 @@ class CloneBufferObject : public NativeO
+         Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
+         MOZ_ASSERT(args.length() == 0);
+ 
+         JSStructuredCloneData* data;
+         if (!getData(cx, obj, &data))
+             return false;
+ 
+         size_t size = data->Size();
+-        UniqueChars buffer(static_cast<char*>(js_malloc(size)));
++        UniqueChars buffer(js_pod_malloc<char>(size));
+         if (!buffer) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+         auto iter = data->Start();
+         data->ReadBytes(iter, buffer.get(), size);
+         JSObject* arrayBuffer = JS_NewArrayBufferWithContents(cx, size, buffer.release());
+         if (!arrayBuffer)
+diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp
+--- a/js/src/jit/BaselineBailouts.cpp
++++ b/js/src/jit/BaselineBailouts.cpp
+@@ -113,17 +113,17 @@ struct BaselineStackBuilder
+ 
+     ~BaselineStackBuilder() {
+         js_free(buffer_);
+     }
+ 
+     MOZ_MUST_USE bool init() {
+         MOZ_ASSERT(!buffer_);
+         MOZ_ASSERT(bufferUsed_ == 0);
+-        buffer_ = reinterpret_cast<uint8_t*>(js_calloc(bufferTotal_));
++        buffer_ = js_pod_calloc<uint8_t>(bufferTotal_);
+         if (!buffer_)
+             return false;
+         bufferAvail_ = bufferTotal_ - HeaderSize();
+         bufferUsed_ = 0;
+ 
+         header_ = reinterpret_cast<BaselineBailoutInfo*>(buffer_);
+         header_->incomingStack = reinterpret_cast<uint8_t*>(frame_);
+         header_->copyStackTop = buffer_ + bufferTotal_;
+@@ -143,17 +143,17 @@ struct BaselineStackBuilder
+         return true;
+     }
+ 
+     MOZ_MUST_USE bool enlarge() {
+         MOZ_ASSERT(buffer_ != nullptr);
+         if (bufferTotal_ & mozilla::tl::MulOverflowMask<2>::value)
+             return false;
+         size_t newSize = bufferTotal_ * 2;
+-        uint8_t* newBuffer = reinterpret_cast<uint8_t*>(js_calloc(newSize));
++        uint8_t* newBuffer = js_pod_calloc<uint8_t>(newSize);
+         if (!newBuffer)
+             return false;
+         memcpy((newBuffer + newSize) - bufferUsed_, header_->copyStackBottom, bufferUsed_);
+         memcpy(newBuffer, header_, sizeof(BaselineBailoutInfo));
+         js_free(buffer_);
+         buffer_ = newBuffer;
+         bufferTotal_ = newSize;
+         bufferAvail_ = newSize - (HeaderSize() + bufferUsed_);
+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
+@@ -5342,17 +5342,17 @@ CodeGenerator::maybeCreateScriptCounts()
+             // with.
+             while (resume->caller())
+                 resume = resume->caller();
+             offset = script->pcToOffset(resume->pc());
+ 
+             if (block->entryResumePoint()->caller()) {
+                 // Get the filename and line number of the inner script.
+                 JSScript* innerScript = block->info().script();
+-                description = (char*) js_calloc(200);
++                description = js_pod_calloc<char>(200);
+                 if (description) {
+                     snprintf(description, 200, "%s:%u",
+                              innerScript->filename(), innerScript->lineno());
+                 }
+             }
+         }
+ 
+         if (!counts->block(i).init(block->id(), offset, description, block->numSuccessors()))
+diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
+--- a/js/src/jit/JitFrames.cpp
++++ b/js/src/jit/JitFrames.cpp
+@@ -1413,17 +1413,17 @@ GetPcScript(JSContext* cx, JSScript** sc
+     }
+ 
+     uint32_t hash;
+     if (retAddr) {
+         hash = PcScriptCache::Hash(retAddr);
+ 
+         // Lazily initialize the cache. The allocation may safely fail and will not GC.
+         if (MOZ_UNLIKELY(cx->ionPcScriptCache == nullptr)) {
+-            cx->ionPcScriptCache = (PcScriptCache*)js_malloc(sizeof(struct PcScriptCache));
++            cx->ionPcScriptCache = js_pod_malloc<PcScriptCache>();
+             if (cx->ionPcScriptCache)
+                 cx->ionPcScriptCache->clear(cx->runtime()->gc.gcNumber());
+         }
+ 
+         if (cx->ionPcScriptCache && cx->ionPcScriptCache->get(cx->runtime(), hash, retAddr, scriptRes, pcRes))
+             return;
+     }
+ 
+diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp
+--- a/js/src/jit/arm/Simulator-arm.cpp
++++ b/js/src/jit/arm/Simulator-arm.cpp
+@@ -637,23 +637,23 @@ ReadLine(const char* prompt)
+         if (len > 0 && line_buf[len - 1] == '\n') {
+             // Since we read a new line we are done reading the line. This will
+             // exit the loop after copying this buffer into the result.
+             keep_going = false;
+         }
+         if (!result) {
+             // Allocate the initial result and make room for the terminating
+             // '\0'.
+-            result = (char*)js_malloc(len + 1);
++            result = js_pod_malloc<char>(len + 1);
+             if (!result)
+                 return nullptr;
+         } else {
+             // Allocate a new result with enough room for the new addition.
+             int new_len = offset + len + 1;
+-            char* new_result = (char*)js_malloc(new_len);
++            char* new_result = js_pod_malloc<char>(new_len);
+             if (!new_result)
+                 return nullptr;
+             // Copy the existing input into the new array and set the new
+             // array as the result.
+             memcpy(new_result, result, offset * sizeof(char));
+             js_free(result);
+             result = new_result;
+         }
+@@ -1194,17 +1194,17 @@ Simulator::Simulator(JSContext* cx)
+     exclusiveMonitor_ = 0;
+ }
+ 
+ bool
+ Simulator::init()
+ {
+     // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
+     static const size_t stackSize = 2 * 1024*1024;
+-    stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
++    stack_ = js_pod_malloc<char>(stackSize);
+     if (!stack_)
+         return false;
+ 
+     // Leave a safety margin of 1MB to prevent overrunning the stack when
+     // pushing values (total stack size is 2MB).
+     stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
+ 
+     // The sp is initialized to point to the bottom (high address) of the
+@@ -1252,17 +1252,17 @@ class Redirection
+         for (; current != nullptr; current = current->next_) {
+             if (current->nativeFunction_ == nativeFunction) {
+                 MOZ_ASSERT(current->type() == type);
+                 return current;
+             }
+         }
+ 
+         AutoEnterOOMUnsafeRegion oomUnsafe;
+-        Redirection* redir = (Redirection*)js_malloc(sizeof(Redirection));
++        Redirection* redir = js_pod_malloc<Redirection>();
+         if (!redir)
+             oomUnsafe.crash("Simulator redirection");
+         new(redir) Redirection(nativeFunction, type);
+         return redir;
+     }
+ 
+     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
+         uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
+diff --git a/js/src/jit/arm64/vixl/Debugger-vixl.cpp b/js/src/jit/arm64/vixl/Debugger-vixl.cpp
+--- a/js/src/jit/arm64/vixl/Debugger-vixl.cpp
++++ b/js/src/jit/arm64/vixl/Debugger-vixl.cpp
+@@ -131,17 +131,17 @@ class FPRegisterToken : public ValueToke
+ 
+ 
+ // Non-register identifiers.
+ // Format: Alphanumeric string starting with a letter.
+ class IdentifierToken : public ValueToken<char*> {
+  public:
+   explicit IdentifierToken(const char* name) {
+     size_t size = strlen(name) + 1;
+-    value_ = (char*)js_malloc(size);
++    value_ = js_pod_malloc<char>(size);
+     strncpy(value_, name, size);
+   }
+   virtual ~IdentifierToken() { js_free(value_); }
+ 
+   virtual bool IsIdentifier() const override { return true; }
+   virtual bool CanAddressMemory() const override { return strcmp(value(), "pc") == 0; }
+   virtual uint8_t* ToAddress(Debugger* debugger) const override;
+   virtual void Print(FILE* out = stdout) const override;
+@@ -239,17 +239,17 @@ template<typename T> class Format : publ
+   char type_code_;
+ };
+ 
+ // Tokens which don't fit any of the above.
+ class UnknownToken : public Token {
+  public:
+   explicit UnknownToken(const char* arg) {
+     size_t size = strlen(arg) + 1;
+-    unknown_ = (char*)js_malloc(size);
++    unknown_ = js_pod_malloc<char>(size);
+     strncpy(unknown_, arg, size);
+   }
+   virtual ~UnknownToken() { js_free(unknown_); }
+   virtual uint8_t* ToAddress(Debugger* debugger) const override {
+     USE(debugger);
+     VIXL_ABORT();
+   }
+ 
+diff --git a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+--- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
++++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+@@ -119,17 +119,17 @@ void Simulator::init(Decoder* decoder, F
+     return;
+   }
+   set_coloured_trace(false);
+   trace_parameters_ = LOG_NONE;
+ 
+   ResetState();
+ 
+   // Allocate and set up the simulator stack.
+-  stack_ = (byte*)js_malloc(stack_size_);
++  stack_ = js_pod_malloc<byte>(stack_size_);
+   if (!stack_) {
+     oom_ = true;
+     return;
+   }
+   stack_limit_ = stack_ + stack_protection_size_;
+   // Configure the starting stack pointer.
+   //  - Find the top of the stack.
+   byte * tos = stack_ + stack_size_;
+@@ -387,17 +387,17 @@ class Redirection
+     for (; current != nullptr; current = current->next_) {
+       if (current->nativeFunction_ == nativeFunction) {
+         VIXL_ASSERT(current->type() == type);
+         return current;
+       }
+     }
+ 
+     js::AutoEnterOOMUnsafeRegion oomUnsafe;
+-    Redirection* redir = (Redirection*)js_malloc(sizeof(Redirection));
++    Redirection* redir = js_pod_malloc<Redirection>();
+     if (!redir)
+         oomUnsafe.crash("Simulator redirection");
+     new(redir) Redirection(nativeFunction, type);
+     return redir;
+   }
+ 
+   static const Redirection* FromSvcInstruction(const Instruction* svcInstruction) {
+     const uint8_t* addrOfSvc = reinterpret_cast<const uint8_t*>(svcInstruction);
+diff --git a/js/src/jit/mips32/Simulator-mips32.cpp b/js/src/jit/mips32/Simulator-mips32.cpp
+--- a/js/src/jit/mips32/Simulator-mips32.cpp
++++ b/js/src/jit/mips32/Simulator-mips32.cpp
+@@ -765,23 +765,23 @@ ReadLine(const char* prompt)
+         int len = strlen(lineBuf);
+         if (len > 0 && lineBuf[len - 1] == '\n') {
+             // Since we read a new line we are done reading the line. This
+             // will exit the loop after copying this buffer into the result.
+             keepGoing = false;
+         }
+         if (!result) {
+             // Allocate the initial result and make room for the terminating '\0'
+-            result = (char*)js_malloc(len + 1);
++            result = js_pod_malloc<char>(len + 1);
+             if (!result)
+                 return nullptr;
+         } else {
+             // Allocate a new result with enough room for the new addition.
+             int new_len = offset + len + 1;
+-            char* new_result = (char*)js_malloc(new_len);
++            char* new_result = js_pod_malloc<char>(new_len);
+             if (!new_result)
+                 return nullptr;
+             // Copy the existing input into the new array and set the new
+             // array as the result.
+             memcpy(new_result, result, offset * sizeof(char));
+             js_free(result);
+             result = new_result;
+         }
+@@ -1283,17 +1283,17 @@ Simulator::Simulator()
+     lastDebuggerInput_ = nullptr;
+ }
+ 
+ bool
+ Simulator::init()
+ {
+     // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
+     static const size_t stackSize = 2 * 1024 * 1024;
+-    stack_ = static_cast<char*>(js_malloc(stackSize));
++    stack_ = js_pod_malloc<char>(stackSize);
+     if (!stack_)
+         return false;
+ 
+     // Leave a safety margin of 1MB to prevent overrunning the stack when
+     // pushing values (total stack size is 2MB).
+     stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
+ 
+     // The sp is initialized to point to the bottom (high address) of the
+@@ -1342,17 +1342,17 @@ class Redirection
+         for (; current != nullptr; current = current->next_) {
+             if (current->nativeFunction_ == nativeFunction) {
+                 MOZ_ASSERT(current->type() == type);
+                 return current;
+             }
+         }
+ 
+         AutoEnterOOMUnsafeRegion oomUnsafe;
+-        Redirection* redir = (Redirection*)js_malloc(sizeof(Redirection));
++        Redirection* redir = js_pod_malloc<Redirection>();
+         if (!redir) {
+             oomUnsafe.crash("Simulator redirection");
+         }
+         new(redir) Redirection(nativeFunction, type);
+         return redir;
+     }
+ 
+     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
+diff --git a/js/src/jit/mips64/Simulator-mips64.cpp b/js/src/jit/mips64/Simulator-mips64.cpp
+--- a/js/src/jit/mips64/Simulator-mips64.cpp
++++ b/js/src/jit/mips64/Simulator-mips64.cpp
+@@ -783,23 +783,23 @@ ReadLine(const char* prompt)
+         int len = strlen(lineBuf);
+         if (len > 0 && lineBuf[len - 1] == '\n') {
+             // Since we read a new line we are done reading the line. This
+             // will exit the loop after copying this buffer into the result.
+             keepGoing = false;
+         }
+         if (!result) {
+             // Allocate the initial result and make room for the terminating '\0'
+-            result = (char*)js_malloc(len + 1);
++            result = js_pod_malloc<char>(len + 1);
+             if (!result)
+                 return nullptr;
+         } else {
+             // Allocate a new result with enough room for the new addition.
+             int new_len = offset + len + 1;
+-            char* new_result = (char*)js_malloc(new_len);
++            char* new_result = js_pod_malloc<char>(new_len);
+             if (!new_result)
+                 return nullptr;
+             // Copy the existing input into the new array and set the new
+             // array as the result.
+             memcpy(new_result, result, offset * sizeof(char));
+             js_free(result);
+             result = new_result;
+         }
+@@ -1291,17 +1291,17 @@ Simulator::Simulator()
+     lastDebuggerInput_ = nullptr;
+ }
+ 
+ bool
+ Simulator::init()
+ {
+     // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
+     static const size_t stackSize = 2 * 1024 * 1024;
+-    stack_ = static_cast<char*>(js_malloc(stackSize));
++    stack_ = js_pod_malloc<char>(stackSize);
+     if (!stack_)
+         return false;
+ 
+     // Leave a safety margin of 1MB to prevent overrunning the stack when
+     // pushing values (total stack size is 2MB).
+     stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
+ 
+     // The sp is initialized to point to the bottom (high address) of the
+@@ -1350,17 +1350,17 @@ class Redirection
+         for (; current != nullptr; current = current->next_) {
+             if (current->nativeFunction_ == nativeFunction) {
+                 MOZ_ASSERT(current->type() == type);
+                 return current;
+             }
+         }
+ 
+         AutoEnterOOMUnsafeRegion oomUnsafe;
+-        Redirection* redir = (Redirection*)js_malloc(sizeof(Redirection));
++        Redirection* redir = js_pod_malloc<Redirection>();
+         if (!redir) {
+             oomUnsafe.crash("Simulator redirection");
+         }
+         new(redir) Redirection(nativeFunction, type);
+         return redir;
+     }
+ 
+     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
+diff --git a/js/src/jit/shared/Disassembler-shared.cpp b/js/src/jit/shared/Disassembler-shared.cpp
+--- a/js/src/jit/shared/Disassembler-shared.cpp
++++ b/js/src/jit/shared/Disassembler-shared.cpp
+@@ -232,17 +232,17 @@ DisassemblerSpew::lookup(const Label* ke
+         ;
+     return p;
+ }
+ 
+ DisassemblerSpew::Node*
+ DisassemblerSpew::add(const Label* key, uint32_t value)
+ {
+     MOZ_ASSERT(!lookup(key));
+-    Node* node = (Node*)js_malloc(sizeof(Node));
++    Node* node = js_pod_malloc<Node>();
+     if (node) {
+         node->key = key;
+         node->value = value;
+         node->bound = false;
+         node->next = nodes_;
+         nodes_ = node;
+     }
+     return node;
+diff --git a/js/src/jsapi.h b/js/src/jsapi.h
+--- a/js/src/jsapi.h
++++ b/js/src/jsapi.h
+@@ -361,17 +361,17 @@ namespace JS {
+  *     must be kept alive until the JS compilation is complete.
+  *  3) Any code calling SourceBufferHolder::take() must guarantee to keep the
+  *     memory alive until JS compilation completes.  Normally only the JS
+  *     engine should be calling take().
+  *
+  * Example use:
+  *
+  *    size_t length = 512;
+- *    char16_t* chars = static_cast<char16_t*>(js_malloc(sizeof(char16_t) * length));
++ *    char16_t* chars = js_pod_malloc<char16_t>(length);
+  *    JS::SourceBufferHolder srcBuf(chars, length, JS::SourceBufferHolder::GiveOwnership);
+  *    JS::Compile(cx, options, srcBuf);
+  */
+ class MOZ_STACK_CLASS SourceBufferHolder final
+ {
+   public:
+     enum Ownership {
+       NoOwnership,
+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
+@@ -769,17 +769,17 @@ ReportSysError(JSContext* cx, const char
+ #else
+     const char* errstr = strerror_message(strerror_r(errno, buffer, sizeof(buffer)), buffer);
+ #endif
+ 
+     if (!errstr)
+         errstr = "unknown error";
+ 
+     size_t nbytes = strlen(prefix) + strlen(errstr) + 3;
+-    char* final = (char*) js_malloc(nbytes);
++    char* final = js_pod_malloc<char>(nbytes);
+     if (!final) {
+         JS_ReportOutOfMemory(cx);
+         return;
+     }
+ 
+     snprintf(final, nbytes, "%s: %s", prefix, errstr);
+     /*
+      * Use Latin1 variant here because the encoding of the return value of
+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
+@@ -2083,17 +2083,17 @@ js::shell::FileAsString(JSContext* cx, J
+     if (fseek(file, 0, SEEK_SET) != 0) {
+         pathname.clear();
+         if (!pathname.encodeUtf8(cx, pathnameStr))
+             return nullptr;
+         JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr());
+         return nullptr;
+     }
+ 
+-    UniqueChars buf(static_cast<char*>(js_malloc(len + 1)));
++    UniqueChars buf(js_pod_malloc<char>(len + 1));
+     if (!buf)
+         return nullptr;
+ 
+     size_t cc = fread(buf.get(), 1, len, file);
+     if (cc != len) {
+         if (ptrdiff_t(cc) < 0) {
+             ReportCantOpenErrorUnknownEncoding(cx, pathname.ptr());
+         } else {
+@@ -3649,17 +3649,17 @@ EvalInWorker(JSContext* cx, unsigned arg
+         if (!workerThreadsLock) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+     }
+ 
+     JSLinearString* str = &args[0].toString()->asLinear();
+ 
+-    char16_t* chars = (char16_t*) js_malloc(str->length() * sizeof(char16_t));
++    char16_t* chars = js_pod_malloc<char16_t>(str->length());
+     if (!chars) {
+         ReportOutOfMemory(cx);
+         return false;
+     }
+ 
+     CopyChars(chars, *str);
+ 
+     WorkerInput* input = js_new<WorkerInput>(JS_GetParentRuntime(cx), chars, str->length());
+diff --git a/js/src/util/DoubleToString.cpp b/js/src/util/DoubleToString.cpp
+--- a/js/src/util/DoubleToString.cpp
++++ b/js/src/util/DoubleToString.cpp
+@@ -302,17 +302,17 @@ js_dtobasestr(DtoaState* state, int base
+     char* q;
+     uint32_t digit;
+     U di;                /* d truncated to an integer */
+     U df;                /* The fractional part of d */
+ 
+     MOZ_ASSERT(base >= 2 && base <= 36);
+ 
+     dval(d) = dinput;
+-    buffer = (char*) js_malloc(DTOBASESTR_BUFFER_SIZE);
++    buffer = js_pod_malloc<char>(DTOBASESTR_BUFFER_SIZE);
+     if (!buffer)
+         return nullptr;
+     p = buffer;
+ 
+     if (dval(d) < 0.0) {
+         *p++ = '-';
+         dval(d) = -dval(d);
+     }
+diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp
+--- a/js/src/vm/BigIntType.cpp
++++ b/js/src/vm/BigIntType.cpp
+@@ -211,17 +211,17 @@ BigInt::numberValue(BigInt* x)
+ }
+ 
+ JSLinearString*
+ BigInt::toString(JSContext* cx, BigInt* x, uint8_t radix)
+ {
+     MOZ_ASSERT(2 <= radix && radix <= 36);
+     // We need two extra chars for '\0' and potentially '-'.
+     size_t strSize = mpz_sizeinbase(x->num_, 10) + 2;
+-    UniqueChars str(static_cast<char*>(js_malloc(strSize)));
++    UniqueChars str(js_pod_malloc<char>(strSize));
+     if (!str) {
+         ReportOutOfMemory(cx);
+         return nullptr;
+     }
+     mpz_get_str(str.get(), radix, x->num_);
+ 
+     return NewStringCopyZ<CanGC>(cx, str.get());
+ }
+diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp
+--- a/js/src/vm/Printer.cpp
++++ b/js/src/vm/Printer.cpp
+@@ -11,16 +11,17 @@
+ 
+ #include <ctype.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ 
+ #include "jsutil.h"
+ 
+ #include "ds/LifoAlloc.h"
++#include "util/Text.h"
+ #include "util/Windows.h"
+ #include "vm/JSContext.h"
+ 
+ using mozilla::PodCopy;
+ 
+ namespace
+ {
+ 
+@@ -119,17 +120,17 @@ Sprinter::~Sprinter()
+ #endif
+     js_free(base);
+ }
+ 
+ bool
+ Sprinter::init()
+ {
+     MOZ_ASSERT(!initialized);
+-    base = (char*) js_malloc(DefaultSize);
++    base = js_pod_malloc<char>(DefaultSize);
+     if (!base) {
+         reportOutOfMemory();
+         return false;
+     }
+ #ifdef DEBUG
+     initialized = true;
+ #endif
+     *base = 0;
+@@ -440,23 +441,21 @@ Fprinter::put(const char* s, size_t len)
+     MOZ_ASSERT(file_);
+     int i = fwrite(s, /*size=*/ 1, /*nitems=*/ len, file_);
+     if (size_t(i) != len) {
+         reportOutOfMemory();
+         return false;
+     }
+ #ifdef XP_WIN32
+     if ((file_ == stderr) && (IsDebuggerPresent())) {
+-        UniqueChars buf(static_cast<char*>(js_malloc(len + 1)));
++        UniqueChars buf = DuplicateString(s, len);
+         if (!buf) {
+             reportOutOfMemory();
+             return false;
+         }
+-        PodCopy(buf.get(), s, len);
+-        buf[len] = '\0';
+         OutputDebugStringA(buf.get());
+     }
+ #endif
+     return true;
+ }
+ 
+ LSprinter::LSprinter(LifoAlloc* lifoAlloc)
+   : alloc_(lifoAlloc),
+diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
+--- a/js/src/vm/StructuredClone.cpp
++++ b/js/src/vm/StructuredClone.cpp
+@@ -1182,17 +1182,17 @@ JSStructuredCloneWriter::writeBigInt(uin
+ {
+     bool signBit = bi->sign() < 1;
+     size_t length = BigInt::byteLength(bi);
+     // The length must fit in 31 bits to leave room for a sign bit.
+     if (length > size_t(INT32_MAX))
+         return false;
+     uint32_t lengthAndSign = length | (static_cast<uint32_t>(signBit) << 31);
+ 
+-    js::UniquePtr<uint8_t> buf(static_cast<uint8_t*>(js_malloc(length)));
++    js::UniquePtr<uint8_t> buf(js_pod_malloc<uint8_t>(length));
+     if (!buf)
+         return false;
+ 
+     BigInt::writeBytes(bi, RangedPtr<uint8_t>(buf.get(), length));
+     if (!out.writePair(tag, lengthAndSign))
+         return false;
+     return out.writeBytes(buf.get(), length);
+ }
+@@ -1962,17 +1962,17 @@ BigInt*
+ JSStructuredCloneReader::readBigInt(uint32_t data)
+ {
+     size_t nbytes = data & JS_BITMASK(31);
+     bool isNegative = data & (1 << 31);
+ 
+     if (nbytes == 0)
+         return BigInt::create(context());
+ 
+-    UniquePtr<uint8_t> buf(static_cast<uint8_t*>(js_malloc(nbytes)));
++    UniquePtr<uint8_t> buf(js_pod_malloc<uint8_t>(nbytes));
+     if (!buf)
+         return nullptr;
+     if (!in.readBytes(buf.get(), nbytes))
+         return nullptr;
+     return BigInt::createFromBytes(context(), isNegative ? -1 : 1, buf.get(), nbytes);
+ }
+ #endif
+ 
+diff --git a/js/src/vm/TraceLoggingGraph.cpp b/js/src/vm/TraceLoggingGraph.cpp
+--- a/js/src/vm/TraceLoggingGraph.cpp
++++ b/js/src/vm/TraceLoggingGraph.cpp
+@@ -49,18 +49,16 @@ TraceLoggerGraphState* traceLoggerGraphS
+ #define MAX_LOGGERS 999
+ 
+ // Return a filename relative to the output directory. %u and %d substitutions
+ // are allowed, with %u standing for a full 32-bit number and %d standing for
+ // an up to 3-digit number.
+ static js::UniqueChars
+ MOZ_FORMAT_PRINTF(1, 2)
+ AllocTraceLogFilename(const char* pattern, ...) {
+-    js::UniqueChars filename;
+-
+     va_list ap;
+ 
+     static const char* outdir = getenv("TLDIR") ? getenv("TLDIR") : DEFAULT_TRACE_LOG_DIR;
+     size_t len = strlen(outdir) + 1; // "+ 1" is for the '/'
+ 
+     for (const char* p = pattern; *p; p++) {
+         if (*p == '%') {
+             p++;
+@@ -72,17 +70,17 @@ AllocTraceLogFilename(const char* patter
+                 MOZ_CRASH("Invalid format");
+         } else {
+             len++;
+         }
+     }
+ 
+     len++; // For the terminating NUL.
+ 
+-    filename.reset((char*) js_malloc(len));
++    js::UniqueChars filename(js_pod_malloc<char>(len));
+     if (!filename)
+         return nullptr;
+     char* rest = filename.get() + sprintf(filename.get(), "%s/", outdir);
+ 
+     va_start(ap, pattern);
+     int ret = vsnprintf(rest, len, pattern, ap);
+     va_end(ap);
+     if (ret < 0)
+diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h
+--- a/js/src/vm/TraceLoggingTypes.h
++++ b/js/src/vm/TraceLoggingTypes.h
+@@ -165,17 +165,17 @@ class ContinuousSpace {
+      : data_(nullptr),
+        size_(0),
+        capacity_(0)
+     { }
+ 
+     bool init() {
+         capacity_ = 64;
+         size_ = 0;
+-        data_ = (T*) js_malloc(capacity_ * sizeof(T));
++        data_ = js_pod_malloc<T>(capacity_);
+         if (!data_)
+             return false;
+ 
+         return true;
+     }
+ 
+     ~ContinuousSpace()
+     {
+@@ -225,17 +225,17 @@ class ContinuousSpace {
+ 
+         // Limit the size of a continuous buffer.
+         if (size_ + count > maxSize())
+             return false;
+ 
+         uint32_t nCapacity = capacity_ * 2;
+         nCapacity = (nCapacity < maxSize()) ? nCapacity : maxSize();
+ 
+-        T* entries = (T*) js_realloc(data_, nCapacity * sizeof(T));
++        T* entries = js_pod_realloc<T>(data_, capacity_, nCapacity);
+         if (!entries)
+             return false;
+ 
+         data_ = entries;
+         capacity_ = nCapacity;
+ 
+         return true;
+     }

+ 1552 - 0
frg/work-js/mozilla-release/patches/1471931-2-63a1.patch

@@ -0,0 +1,1552 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530202625 25200
+#      Thu Jun 28 09:17:05 2018 -0700
+# Node ID 8b1fc57cce36f9a85a1d1c8534309a5e1936de24
+# Parent  bd01847472fbc512fbf56b8e4748cf5fad6ee897
+Bug 1471931 - Part 2: Replace manual memory management with UniquePtr in a few places. r=sfink
+
+diff --git a/js/src/builtin/Profilers.cpp b/js/src/builtin/Profilers.cpp
+--- a/js/src/builtin/Profilers.cpp
++++ b/js/src/builtin/Profilers.cpp
+@@ -23,16 +23,17 @@
+ #endif
+ #endif
+ 
+ #ifdef XP_WIN
+ # include <process.h>
+ # define getpid _getpid
+ #endif
+ 
++#include "js/Utility.h"
+ #include "util/Text.h"
+ #include "vm/Probes.h"
+ 
+ #include "vm/JSContext-inl.h"
+ 
+ using namespace js;
+ 
+ using mozilla::ArrayLength;
+@@ -184,134 +185,128 @@ JS_DumpProfile(const char* outfile, cons
+ #ifdef MOZ_CALLGRIND
+     ok = js_DumpCallgrind(outfile);
+ #endif
+     return ok;
+ }
+ 
+ #ifdef MOZ_PROFILING
+ 
+-struct RequiredStringArg {
+-    JSContext* mCx;
+-    char* mBytes;
+-    RequiredStringArg(JSContext* cx, const CallArgs& args, size_t argi, const char* caller)
+-        : mCx(cx), mBytes(nullptr)
+-    {
+-        if (args.length() <= argi) {
+-            JS_ReportErrorASCII(cx, "%s: not enough arguments", caller);
+-        } else if (!args[argi].isString()) {
+-            JS_ReportErrorASCII(cx, "%s: invalid arguments (string expected)", caller);
+-        } else {
+-            mBytes = JS_EncodeString(cx, args[argi].toString());
+-        }
++static UniqueChars
++RequiredStringArg(JSContext* cx, const CallArgs& args, size_t argi, const char* caller)
++{
++    if (args.length() <= argi) {
++        JS_ReportErrorASCII(cx, "%s: not enough arguments", caller);
++        return nullptr;
+     }
+-    operator void*() {
+-        return (void*) mBytes;
++
++    if (!args[argi].isString()) {
++        JS_ReportErrorASCII(cx, "%s: invalid arguments (string expected)", caller);
++        return nullptr;
+     }
+-    ~RequiredStringArg() {
+-        js_free(mBytes);
+-    }
+-};
++
++    return UniqueChars(JS_EncodeString(cx, args[argi].toString()));
++}
+ 
+ static bool
+ StartProfiling(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (args.length() == 0) {
+         args.rval().setBoolean(JS_StartProfiling(nullptr, getpid()));
+         return true;
+     }
+ 
+-    RequiredStringArg profileName(cx, args, 0, "startProfiling");
++    UniqueChars profileName = RequiredStringArg(cx, args, 0, "startProfiling");
+     if (!profileName)
+         return false;
+ 
+     if (args.length() == 1) {
+-        args.rval().setBoolean(JS_StartProfiling(profileName.mBytes, getpid()));
++        args.rval().setBoolean(JS_StartProfiling(profileName.get(), getpid()));
+         return true;
+     }
+ 
+     if (!args[1].isInt32()) {
+         JS_ReportErrorASCII(cx, "startProfiling: invalid arguments (int expected)");
+         return false;
+     }
+     pid_t pid = static_cast<pid_t>(args[1].toInt32());
+-    args.rval().setBoolean(JS_StartProfiling(profileName.mBytes, pid));
++    args.rval().setBoolean(JS_StartProfiling(profileName.get(), pid));
+     return true;
+ }
+ 
+ static bool
+ StopProfiling(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (args.length() == 0) {
+         args.rval().setBoolean(JS_StopProfiling(nullptr));
+         return true;
+     }
+ 
+-    RequiredStringArg profileName(cx, args, 0, "stopProfiling");
++    UniqueChars profileName = RequiredStringArg(cx, args, 0, "stopProfiling");
+     if (!profileName)
+         return false;
+-    args.rval().setBoolean(JS_StopProfiling(profileName.mBytes));
++    args.rval().setBoolean(JS_StopProfiling(profileName.get()));
+     return true;
+ }
+ 
+ static bool
+ PauseProfilers(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (args.length() == 0) {
+         args.rval().setBoolean(JS_PauseProfilers(nullptr));
+         return true;
+     }
+ 
+-    RequiredStringArg profileName(cx, args, 0, "pauseProfiling");
++    UniqueChars profileName = RequiredStringArg(cx, args, 0, "pauseProfiling");
+     if (!profileName)
+         return false;
+-    args.rval().setBoolean(JS_PauseProfilers(profileName.mBytes));
++    args.rval().setBoolean(JS_PauseProfilers(profileName.get()));
+     return true;
+ }
+ 
+ static bool
+ ResumeProfilers(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (args.length() == 0) {
+         args.rval().setBoolean(JS_ResumeProfilers(nullptr));
+         return true;
+     }
+ 
+-    RequiredStringArg profileName(cx, args, 0, "resumeProfiling");
++    UniqueChars profileName = RequiredStringArg(cx, args, 0, "resumeProfiling");
+     if (!profileName)
+         return false;
+-    args.rval().setBoolean(JS_ResumeProfilers(profileName.mBytes));
++    args.rval().setBoolean(JS_ResumeProfilers(profileName.get()));
+     return true;
+ }
+ 
+ /* Usage: DumpProfile([filename[, profileName]]) */
+ static bool
+ DumpProfile(JSContext* cx, unsigned argc, Value* vp)
+ {
+     bool ret;
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (args.length() == 0) {
+         ret = JS_DumpProfile(nullptr, nullptr);
+     } else {
+-        RequiredStringArg filename(cx, args, 0, "dumpProfile");
++        UniqueChars filename = RequiredStringArg(cx, args, 0, "dumpProfile");
+         if (!filename)
+             return false;
+ 
+         if (args.length() == 1) {
+-            ret = JS_DumpProfile(filename.mBytes, nullptr);
++            ret = JS_DumpProfile(filename.get(), nullptr);
+         } else {
+-            RequiredStringArg profileName(cx, args, 1, "dumpProfile");
++            UniqueChars profileName = RequiredStringArg(cx, args, 1, "dumpProfile");
+             if (!profileName)
+                 return false;
+ 
+-            ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
++            ret = JS_DumpProfile(filename.get(), profileName.get());
+         }
+     }
+ 
+     args.rval().setBoolean(ret);
+     return true;
+ }
+ 
+ static bool
+@@ -363,21 +358,21 @@ static bool
+ DumpCallgrind(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+     if (args.length() == 0) {
+         args.rval().setBoolean(js_DumpCallgrind(nullptr));
+         return true;
+     }
+ 
+-    RequiredStringArg outFile(cx, args, 0, "dumpCallgrind");
++    UniqueChars outFile = RequiredStringArg(cx, args, 0, "dumpCallgrind");
+     if (!outFile)
+         return false;
+ 
+-    args.rval().setBoolean(js_DumpCallgrind(outFile.mBytes));
++    args.rval().setBoolean(js_DumpCallgrind(outFile.get()));
+     return true;
+ }
+ #endif
+ 
+ static const JSFunctionSpec profiling_functions[] = {
+     JS_FN("startProfiling",  StartProfiling,      1,0),
+     JS_FN("stopProfiling",   StopProfiling,       1,0),
+     JS_FN("pauseProfilers",  PauseProfilers,      1,0),
+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
+@@ -3553,41 +3553,39 @@ js::str_fromCodePoint(JSContext* cx, uns
+     if (args.length() <= JSFatInlineString::MAX_LENGTH_TWO_BYTE / 2)
+         return str_fromCodePoint_few_args(cx, args);
+ 
+     // Steps 1-2 (omitted).
+ 
+     // Step 3.
+     static_assert(ARGS_LENGTH_MAX < std::numeric_limits<decltype(args.length())>::max() / 2,
+                   "|args.length() * 2 + 1| does not overflow");
+-    char16_t* elements = cx->pod_malloc<char16_t>(args.length() * 2 + 1);
++    auto elements = cx->make_pod_array<char16_t>(args.length() * 2 + 1);
+     if (!elements)
+         return false;
+ 
+     // Steps 4-5.
+     unsigned length = 0;
+     for (unsigned nextIndex = 0; nextIndex < args.length(); nextIndex++) {
+         // Steps 5.a-d.
+         uint32_t codePoint;
+-        if (!ToCodePoint(cx, args[nextIndex], &codePoint)) {
+-            js_free(elements);
++        if (!ToCodePoint(cx, args[nextIndex], &codePoint))
+             return false;
+-        }
+ 
+         // Step 5.e.
+-        unicode::UTF16Encode(codePoint, elements, &length);
++        unicode::UTF16Encode(codePoint, elements.get(), &length);
+     }
+     elements[length] = 0;
+ 
+     // Step 6.
+-    JSString* str = NewString<CanGC>(cx, elements, length);
+-    if (!str) {
+-        js_free(elements);
++    JSString* str = NewString<CanGC>(cx, elements.get(), length);
++    if (!str)
+         return false;
+-    }
++
++    mozilla::Unused << elements.release();
+ 
+     args.rval().setString(str);
+     return true;
+ }
+ 
+ static const JSFunctionSpec string_static_methods[] = {
+     JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
+     JS_INLINABLE_FN("fromCodePoint", js::str_fromCodePoint, 1, 0, StringFromCodePoint),
+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
+@@ -4342,28 +4342,26 @@ GetLcovInfo(JSContext* cx, unsigned argc
+             JS_ReportErrorASCII(cx, "Argument must be a global object");
+             return false;
+         }
+     } else {
+         global = JS::CurrentGlobalOrNull(cx);
+     }
+ 
+     size_t length = 0;
+-    char* content = nullptr;
++    UniqueChars content;
+     {
+         AutoRealm ar(cx, global);
+-        content = js::GetCodeCoverageSummary(cx, &length);
++        content.reset(js::GetCodeCoverageSummary(cx, &length));
+     }
+ 
+     if (!content)
+         return false;
+ 
+-    JSString* str = JS_NewStringCopyN(cx, content, length);
+-    js_free(content);
+-
++    JSString* str = JS_NewStringCopyN(cx, content.get(), length);
+     if (!str)
+         return false;
+ 
+     args.rval().setString(str);
+     return true;
+ }
+ 
+ #ifdef DEBUG
+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
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "ctypes/CTypes.h"
+ 
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/Sprintf.h"
+ #include "mozilla/TextUtils.h"
++#include "mozilla/Unused.h"
+ #include "mozilla/Vector.h"
+ #include "mozilla/WrappingOperations.h"
+ 
+ #if defined(XP_UNIX)
+ # include <errno.h>
+ #endif
+ #if defined(XP_WIN)
+ # include <float.h>
+@@ -7694,42 +7695,41 @@ CData::Create(JSContext* cx,
+   if (refObj)
+     JS_SetReservedSlot(dataObj, SLOT_REFERENT, ObjectValue(*refObj));
+ 
+   // Set our ownership flag.
+   JS_SetReservedSlot(dataObj, SLOT_OWNS, BooleanValue(ownResult));
+ 
+   // attach the buffer. since it might not be 2-byte aligned, we need to
+   // allocate an aligned space for it and store it there. :(
+-  char** buffer = cx->new_<char*>();
++  UniquePtr<char*, JS::FreePolicy> buffer(cx->new_<char*>());
+   if (!buffer)
+     return nullptr;
+ 
+   char* data;
+   if (!ownResult) {
+     data = static_cast<char*>(source);
+   } else {
+     // Initialize our own buffer.
+     size_t size = CType::GetSize(typeObj);
+     data = dataObj->zone()->pod_malloc<char>(size);
+     if (!data) {
+       // Report a catchable allocation error.
+       JS_ReportAllocationOverflow(cx);
+-      js_free(buffer);
+       return nullptr;
+     }
+ 
+     if (!source)
+       memset(data, 0, size);
+     else
+       memcpy(data, source, size);
+   }
+ 
+-  *buffer = data;
+-  JS_SetReservedSlot(dataObj, SLOT_DATA, PrivateValue(buffer));
++  *buffer.get() = data;
++  JS_SetReservedSlot(dataObj, SLOT_DATA, PrivateValue(buffer.release()));
+ 
+   // If this is an array, wrap it in a proxy so we can intercept element
+   // gets/sets.
+ 
+   if (CType::GetTypeCode(typeObj) != TYPE_array)
+       return dataObj;
+ 
+   RootedValue priv(cx, ObjectValue(*dataObj));
+@@ -8009,26 +8009,25 @@ ReadStringCommon(JSContext* cx, InflateU
+   case TYPE_uint8_t:
+   case TYPE_char:
+   case TYPE_signed_char:
+   case TYPE_unsigned_char: {
+     char* bytes = static_cast<char*>(data);
+     size_t length = strnlen(bytes, maxLength);
+ 
+     // Determine the length.
+-    char16_t* dst = inflateUTF8(cx, JS::UTF8Chars(bytes, length), &length).get();
++    UniqueTwoByteChars dst(inflateUTF8(cx, JS::UTF8Chars(bytes, length), &length).get());
+     if (!dst)
+       return false;
+ 
+-    result = JS_NewUCString(cx, dst, length);
+-    if (!result) {
+-      js_free(dst);
++    result = JS_NewUCString(cx, dst.get(), length);
++    if (!result)
+       return false;
+-    }
+-
++
++    mozilla::Unused << dst.release();
+     break;
+   }
+   case TYPE_int16_t:
+   case TYPE_uint16_t:
+   case TYPE_short:
+   case TYPE_unsigned_short:
+   case TYPE_char16_t: {
+     char16_t* chars = static_cast<char16_t*>(data);
+diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp
+--- a/js/src/jit/BaselineBailouts.cpp
++++ b/js/src/jit/BaselineBailouts.cpp
+@@ -13,16 +13,17 @@
+ #include "jit/BaselineIC.h"
+ #include "jit/BaselineJIT.h"
+ #include "jit/CompileInfo.h"
+ #include "jit/JitSpewer.h"
+ #include "jit/mips32/Simulator-mips32.h"
+ #include "jit/mips64/Simulator-mips64.h"
+ #include "jit/Recover.h"
+ #include "jit/RematerializedFrame.h"
++#include "js/Utility.h"
+ #include "vm/ArgumentsObject.h"
+ #include "vm/Debugger.h"
+ #include "vm/TraceLogging.h"
+ 
+ #include "jit/JitFrames-inl.h"
+ #include "vm/JSScript-inl.h"
+ 
+ using namespace js;
+@@ -1231,30 +1232,29 @@ InitFromBailout(JSContext* cx, size_t fr
+         }
+ 
+         if (cx->runtime()->geckoProfiler().enabled()) {
+             // Register bailout with profiler.
+             const char* filename = script->filename();
+             if (filename == nullptr)
+                 filename = "<unknown>";
+             unsigned len = strlen(filename) + 200;
+-            char* buf = js_pod_malloc<char>(len);
++            UniqueChars buf(js_pod_malloc<char>(len));
+             if (buf == nullptr) {
+                 ReportOutOfMemory(cx);
+                 return false;
+             }
+-            snprintf(buf, len, "%s %s %s on line %u of %s:%u",
++            snprintf(buf.get(), len, "%s %s %s on line %u of %s:%u",
+                      BailoutKindString(bailoutKind),
+                      resumeAfter ? "after" : "at",
+                      CodeName[op],
+                      PCToLineNumber(script, pc),
+                      filename,
+                      script->lineno());
+-            cx->runtime()->geckoProfiler().markEvent(buf);
+-            js_free(buf);
++            cx->runtime()->geckoProfiler().markEvent(buf.get());
+         }
+ 
+         return true;
+     }
+ 
+     // Write out descriptor of BaselineJS frame.
+     size_t baselineFrameDescr = MakeFrameDescriptor((uint32_t) builder.framePushed(),
+                                                     JitFrame_BaselineJS,
+diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp
+--- a/js/src/jit/arm/Simulator-arm.cpp
++++ b/js/src/jit/arm/Simulator-arm.cpp
+@@ -33,16 +33,17 @@
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/MathAlgorithms.h"
+ #include "mozilla/Unused.h"
+ 
+ #include "jit/arm/Assembler-arm.h"
+ #include "jit/arm/disasm/Constants-arm.h"
+ #include "jit/AtomicOperations.h"
++#include "js/Utility.h"
+ #include "threading/LockGuard.h"
+ #include "vm/Runtime.h"
+ #include "vm/SharedMem.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ extern "C" {
+ 
+@@ -615,61 +616,58 @@ ArmDebugger::redoBreakpoints()
+ {
+     if (sim_->break_pc_)
+         sim_->break_pc_->setInstructionBits(kBreakpointInstr);
+ }
+ 
+ static char*
+ ReadLine(const char* prompt)
+ {
+-    char* result = nullptr;
++    UniqueChars result;
+     char line_buf[256];
+     int offset = 0;
+     bool keep_going = true;
+     fprintf(stdout, "%s", prompt);
+     fflush(stdout);
+     while (keep_going) {
+         if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
+             // fgets got an error. Just give up.
+-            if (result)
+-                js_delete(result);
+             return nullptr;
+         }
+         int len = strlen(line_buf);
+         if (len > 0 && line_buf[len - 1] == '\n') {
+             // Since we read a new line we are done reading the line. This will
+             // exit the loop after copying this buffer into the result.
+             keep_going = false;
+         }
+         if (!result) {
+             // Allocate the initial result and make room for the terminating
+             // '\0'.
+-            result = js_pod_malloc<char>(len + 1);
++            result.reset(js_pod_malloc<char>(len + 1));
+             if (!result)
+                 return nullptr;
+         } else {
+             // Allocate a new result with enough room for the new addition.
+             int new_len = offset + len + 1;
+             char* new_result = js_pod_malloc<char>(new_len);
+             if (!new_result)
+                 return nullptr;
+             // Copy the existing input into the new array and set the new
+             // array as the result.
+-            memcpy(new_result, result, offset * sizeof(char));
+-            js_free(result);
+-            result = new_result;
++            memcpy(new_result, result.get(), offset * sizeof(char));
++            result.reset(new_result);
+         }
+         // Copy the newly read line into the result.
+-        memcpy(result + offset, line_buf, len * sizeof(char));
++        memcpy(result.get() + offset, line_buf, len * sizeof(char));
+         offset += len;
+     }
+ 
+     MOZ_ASSERT(result);
+     result[offset] = '\0';
+-    return result;
++    return result.release();
+ }
+ 
+ 
+ void
+ ArmDebugger::debug()
+ {
+     intptr_t last_pc = -1;
+     bool done = false;
+diff --git a/js/src/jit/mips32/Simulator-mips32.cpp b/js/src/jit/mips32/Simulator-mips32.cpp
+--- a/js/src/jit/mips32/Simulator-mips32.cpp
++++ b/js/src/jit/mips32/Simulator-mips32.cpp
+@@ -32,16 +32,17 @@
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/MathAlgorithms.h"
+ 
+ #include <float.h>
+ 
+ #include "jit/AtomicOperations.h"
+ #include "jit/mips32/Assembler-mips32.h"
++#include "js/Utility.h"
+ #include "vm/Runtime.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ #define I8(v)   static_cast<int8_t>(v)
+ #define I16(v)  static_cast<int16_t>(v)
+ #define U16(v)  static_cast<uint16_t>(v)
+ #define I32(v)  static_cast<int32_t>(v)
+@@ -744,60 +745,57 @@ MipsDebugger::printAllRegsIncludingFPU()
+         }
+     }
+ 
+ }
+ 
+ static char*
+ ReadLine(const char* prompt)
+ {
+-    char* result = nullptr;
++    UniqueChars result;
+     char lineBuf[256];
+     int offset = 0;
+     bool keepGoing = true;
+     fprintf(stdout, "%s", prompt);
+     fflush(stdout);
+     while (keepGoing) {
+         if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
+             // fgets got an error. Just give up.
+-            if (result)
+-                js_delete(result);
+             return nullptr;
+         }
+         int len = strlen(lineBuf);
+         if (len > 0 && lineBuf[len - 1] == '\n') {
+             // Since we read a new line we are done reading the line. This
+             // will exit the loop after copying this buffer into the result.
+             keepGoing = false;
+         }
+         if (!result) {
+             // Allocate the initial result and make room for the terminating '\0'
+-            result = js_pod_malloc<char>(len + 1);
++            result.reset(js_pod_malloc<char>(len + 1));
+             if (!result)
+                 return nullptr;
+         } else {
+             // Allocate a new result with enough room for the new addition.
+             int new_len = offset + len + 1;
+             char* new_result = js_pod_malloc<char>(new_len);
+             if (!new_result)
+                 return nullptr;
+             // Copy the existing input into the new array and set the new
+             // array as the result.
+-            memcpy(new_result, result, offset * sizeof(char));
+-            js_free(result);
+-            result = new_result;
++            memcpy(new_result, result.get(), offset * sizeof(char));
++            result.reset(new_result);
+         }
+         // Copy the newly read line into the result.
+-        memcpy(result + offset, lineBuf, len * sizeof(char));
++        memcpy(result.get() + offset, lineBuf, len * sizeof(char));
+         offset += len;
+     }
+ 
+     MOZ_ASSERT(result);
+     result[offset] = '\0';
+-    return result;
++    return result.release();
+ }
+ 
+ static void
+ DisassembleInstruction(uint32_t pc)
+ {
+     uint8_t* bytes = reinterpret_cast<uint8_t*>(pc);
+     char hexbytes[256];
+     sprintf(hexbytes, "0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3]);
+diff --git a/js/src/jit/mips64/Simulator-mips64.cpp b/js/src/jit/mips64/Simulator-mips64.cpp
+--- a/js/src/jit/mips64/Simulator-mips64.cpp
++++ b/js/src/jit/mips64/Simulator-mips64.cpp
+@@ -35,16 +35,17 @@
+ #include "mozilla/Likely.h"
+ #include "mozilla/MathAlgorithms.h"
+ 
+ #include <float.h>
+ #include <limits>
+ 
+ #include "jit/AtomicOperations.h"
+ #include "jit/mips64/Assembler-mips64.h"
++#include "js/Utility.h"
+ #include "threading/LockGuard.h"
+ #include "vm/Runtime.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ #define I8(v)   static_cast<int8_t>(v)
+ #define I16(v)  static_cast<int16_t>(v)
+ #define U16(v)  static_cast<uint16_t>(v)
+@@ -762,60 +763,57 @@ MipsDebugger::printAllRegsIncludingFPU()
+                getFPURegisterValueFloat(i),
+                getFPURegisterValueDouble(i));
+     }
+ }
+ 
+ static char*
+ ReadLine(const char* prompt)
+ {
+-    char* result = nullptr;
++    UniqueChars result;
+     char lineBuf[256];
+     int offset = 0;
+     bool keepGoing = true;
+     fprintf(stdout, "%s", prompt);
+     fflush(stdout);
+     while (keepGoing) {
+         if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
+             // fgets got an error. Just give up.
+-            if (result)
+-                js_delete(result);
+             return nullptr;
+         }
+         int len = strlen(lineBuf);
+         if (len > 0 && lineBuf[len - 1] == '\n') {
+             // Since we read a new line we are done reading the line. This
+             // will exit the loop after copying this buffer into the result.
+             keepGoing = false;
+         }
+         if (!result) {
+             // Allocate the initial result and make room for the terminating '\0'
+-            result = js_pod_malloc<char>(len + 1);
++            result.reset(js_pod_malloc<char>(len + 1));
+             if (!result)
+                 return nullptr;
+         } else {
+             // Allocate a new result with enough room for the new addition.
+             int new_len = offset + len + 1;
+             char* new_result = js_pod_malloc<char>(new_len);
+             if (!new_result)
+                 return nullptr;
+             // Copy the existing input into the new array and set the new
+             // array as the result.
+-            memcpy(new_result, result, offset * sizeof(char));
+-            js_free(result);
+-            result = new_result;
++            memcpy(new_result, result.get(), offset * sizeof(char));
++            result.reset(new_result);
+         }
+         // Copy the newly read line into the result.
+-        memcpy(result + offset, lineBuf, len * sizeof(char));
++        memcpy(result.get() + offset, lineBuf, len * sizeof(char));
+         offset += len;
+     }
+ 
+     MOZ_ASSERT(result);
+     result[offset] = '\0';
+-    return result;
++    return result.release();
+ }
+ 
+ static void
+ DisassembleInstruction(uint64_t pc)
+ {
+     uint8_t* bytes = reinterpret_cast<uint8_t*>(pc);
+     char hexbytes[256];
+     sprintf(hexbytes, "0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3]);
+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
+@@ -768,30 +768,21 @@ ReportSysError(JSContext* cx, const char
+     const char* errstr = buffer;
+ #else
+     const char* errstr = strerror_message(strerror_r(errno, buffer, sizeof(buffer)), buffer);
+ #endif
+ 
+     if (!errstr)
+         errstr = "unknown error";
+ 
+-    size_t nbytes = strlen(prefix) + strlen(errstr) + 3;
+-    char* final = js_pod_malloc<char>(nbytes);
+-    if (!final) {
+-        JS_ReportOutOfMemory(cx);
+-        return;
+-    }
+-
+-    snprintf(final, nbytes, "%s: %s", prefix, errstr);
+     /*
+      * Use Latin1 variant here because the encoding of the return value of
+      * strerror_s and strerror_r function can be non-UTF-8.
+      */
+-    JS_ReportErrorLatin1(cx, "%s", final);
+-    js_free(final);
++    JS_ReportErrorLatin1(cx, "%s: %s", prefix, errstr);
+ }
+ 
+ static bool
+ os_system(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+ 
+     if (args.length() == 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
+@@ -3557,35 +3557,32 @@ EnsureGeckoProfilingStackInstalled(JSCon
+ 
+     SetContextProfilingStack(cx, sc->geckoProfilingStack.get());
+     return true;
+ }
+ 
+ struct WorkerInput
+ {
+     JSRuntime* parentRuntime;
+-    char16_t* chars;
++    UniqueTwoByteChars chars;
+     size_t length;
+ 
+-    WorkerInput(JSRuntime* parentRuntime, char16_t* chars, size_t length)
+-      : parentRuntime(parentRuntime), chars(chars), length(length)
++    WorkerInput(JSRuntime* parentRuntime, UniqueTwoByteChars chars, size_t length)
++      : parentRuntime(parentRuntime), chars(std::move(chars)), length(length)
+     {}
+ 
+-    ~WorkerInput() {
+-        js_free(chars);
+-    }
++    ~WorkerInput() = default;
+ };
+ 
+ static void SetWorkerContextOptions(JSContext* cx);
+ static bool ShellBuildId(JS::BuildIdCharVector* buildId);
+ 
+ static void
+-WorkerMain(void* arg)
+-{
+-    WorkerInput* input = (WorkerInput*) arg;
++WorkerMain(WorkerInput* input)
++{
+     MOZ_ASSERT(input->parentRuntime);
+ 
+     JSContext* cx = JS_NewContext(8L * 1024L * 1024L, 2L * 1024L * 1024L, input->parentRuntime);
+     if (!cx)
+         return;
+ 
+     ShellContext* sc = js_new<ShellContext>(cx);
+     if (!sc)
+@@ -3630,17 +3627,17 @@ WorkerMain(void* arg)
+         JSAutoRealm ar(cx, global);
+ 
+         JS::CompileOptions options(cx);
+         options.setFileAndLine("<string>", 1)
+                .setIsRunOnce(true);
+ 
+         AutoReportException are(cx);
+         RootedScript script(cx);
+-        if (!JS::Compile(cx, options, input->chars, input->length, &script))
++        if (!JS::Compile(cx, options, input->chars.get(), input->length, &script))
+             break;
+         RootedValue result(cx);
+         JS_ExecuteScript(cx, script, &result);
+     } while (0);
+ 
+     KillWatchdog(cx);
+     JS_SetGrayGCRootsTracer(cx, nullptr, nullptr);
+ }
+@@ -3689,25 +3686,26 @@ EvalInWorker(JSContext* cx, unsigned arg
+         if (!workerThreadsLock) {
+             ReportOutOfMemory(cx);
+             return false;
+         }
+     }
+ 
+     JSLinearString* str = &args[0].toString()->asLinear();
+ 
+-    char16_t* chars = js_pod_malloc<char16_t>(str->length());
++    UniqueTwoByteChars chars(js_pod_malloc<char16_t>(str->length()));
+     if (!chars) {
+         ReportOutOfMemory(cx);
+         return false;
+     }
+ 
+-    CopyChars(chars, *str);
+-
+-    WorkerInput* input = js_new<WorkerInput>(JS_GetParentRuntime(cx), chars, str->length());
++    CopyChars(chars.get(), *str);
++
++    WorkerInput* input = js_new<WorkerInput>(JS_GetParentRuntime(cx), std::move(chars),
++                                             str->length());
+     if (!input) {
+         ReportOutOfMemory(cx);
+         return false;
+     }
+ 
+     Thread* thread;
+     {
+         AutoEnterOOMUnsafeRegion oomUnsafe;
+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
+@@ -1,9 +1,9 @@
+-	/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
++/* -*- 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/. */
+ 
+ /*
+  * JS bytecode descriptors, disassemblers, and (expression) decompilers.
+  */
+@@ -90,17 +90,17 @@ const char * const js::CodeName[] = {
+ #define OPNAME(op, val, name, ...)  name,
+     FOR_EACH_OPCODE(OPNAME)
+ #undef OPNAME
+ };
+ 
+ /************************************************************************/
+ 
+ static bool
+-DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res);
++DecompileArgumentFromStack(JSContext* cx, int formalIndex, UniqueChars* res);
+ 
+ size_t
+ js::GetVariableBytecodeLength(jsbytecode* pc)
+ {
+     JSOp op = JSOp(*pc);
+     MOZ_ASSERT(CodeSpec[op].length == -1);
+     switch (op) {
+       case JSOP_TABLESWITCH: {
+@@ -1647,17 +1647,17 @@ struct ExpressionDecompiler
+     bool decompilePCForStackOperand(jsbytecode* pc, int i);
+     bool decompilePC(jsbytecode* pc, uint8_t defIndex);
+     bool decompilePC(const OffsetAndDefIndex& offsetAndDefIndex);
+     JSAtom* getArg(unsigned slot);
+     JSAtom* loadAtom(jsbytecode* pc);
+     bool quote(JSString* s, uint32_t quote);
+     bool write(const char* s);
+     bool write(JSString* str);
+-    bool getOutput(char** out);
++    UniqueChars getOutput();
+ #if defined(DEBUG) || defined(JS_JITSPEW)
+     void setStackDump() {
+         isStackDump = true;
+         parser.setStackDump();
+     }
+ #endif
+ };
+ 
+@@ -1720,27 +1720,24 @@ ExpressionDecompiler::decompilePC(jsbyte
+         // unhelpful. Decompile the argument name instead.
+         if (script->selfHosted()
+ #ifdef DEBUG
+             // For stack dump, argument name is not necessary.
+             && !isStackDump
+ #endif /* DEBUG */
+             )
+         {
+-            char* result;
++            UniqueChars result;
+             if (!DecompileArgumentFromStack(cx, slot, &result))
+                 return false;
+ 
+             // Note that decompiling the argument in the parent frame might
+             // not succeed.
+-            if (result) {
+-		bool ok = write(result);
+-                js_free(result);
+-		return ok;
+-            }
++            if (result)
++                return write(result.get());
+         }
+ 
+         JSAtom* atom = getArg(slot);
+         if (!atom)
+             return false;
+         return write(atom);
+       }
+       case JSOP_GETLOCAL: {
+@@ -2155,26 +2152,26 @@ ExpressionDecompiler::getArg(unsigned sl
+             static const char destructuredParam[] = "(destructured parameter)";
+             return Atomize(cx, destructuredParam, strlen(destructuredParam));
+         }
+     }
+ 
+     MOZ_CRASH("No binding");
+ }
+ 
+-bool
+-ExpressionDecompiler::getOutput(char** res)
++UniqueChars
++ExpressionDecompiler::getOutput()
+ {
+     ptrdiff_t len = sprinter.stringEnd() - sprinter.stringAt(0);
+-    *res = cx->pod_malloc<char>(len + 1);
+-    if (!*res)
+-        return false;
+-    js_memcpy(*res, sprinter.stringAt(0), len);
+-    (*res)[len] = 0;
+-    return true;
++    auto res = cx->make_pod_array<char>(len + 1);
++    if (!res)
++        return nullptr;
++    js_memcpy(res.get(), sprinter.stringAt(0), len);
++    res[len] = 0;
++    return res;
+ }
+ 
+ }  // anonymous namespace
+ 
+ #if defined(DEBUG) || defined(JS_JITSPEW)
+ static bool
+ DecompileAtPCForStackDump(JSContext* cx, HandleScript script,
+                           const OffsetAndDefIndex& offsetAndDefIndex, Sprinter* sp)
+@@ -2182,23 +2179,21 @@ DecompileAtPCForStackDump(JSContext* cx,
+     ExpressionDecompiler ed(cx, script);
+     ed.setStackDump();
+     if (!ed.init())
+         return false;
+ 
+     if (!ed.decompilePC(offsetAndDefIndex))
+         return false;
+ 
+-    char* result;
+-    if (!ed.getOutput(&result))
++    UniqueChars result = ed.getOutput();
++    if (!result)
+         return false;
+ 
+-    bool ok = sp->put(result);
+-    js_free(result);
+-    return ok;
++    return sp->put(result.get());
+ }
+ #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
+ 
+ static bool
+ FindStartPC(JSContext* cx, const FrameIter& iter, int spindex, int skipStackHits, const Value& v,
+             jsbytecode** valuepc, uint8_t* defIndex)
+ {
+     jsbytecode* current = *valuepc;
+@@ -2255,17 +2250,18 @@ FindStartPC(JSContext* cx, const FrameIt
+         }
+     } else {
+         *valuepc = parser.pcForStackOperand(current, spindex, defIndex);
+     }
+     return true;
+ }
+ 
+ static bool
+-DecompileExpressionFromStack(JSContext* cx, int spindex, int skipStackHits, HandleValue v, char** res)
++DecompileExpressionFromStack(JSContext* cx, int spindex, int skipStackHits, HandleValue v,
++                             UniqueChars* res)
+ {
+     MOZ_ASSERT(spindex < 0 ||
+                spindex == JSDVG_IGNORE_STACK ||
+                spindex == JSDVG_SEARCH_STACK);
+ 
+     *res = nullptr;
+ 
+ #ifdef JS_MORE_DETERMINISTIC
+@@ -2298,47 +2294,45 @@ DecompileExpressionFromStack(JSContext* 
+         return true;
+ 
+     ExpressionDecompiler ed(cx, script);
+     if (!ed.init())
+         return false;
+     if (!ed.decompilePC(valuepc, defIndex))
+         return false;
+ 
+-    return ed.getOutput(res);
++    *res = ed.getOutput();
++    return *res != nullptr;
+ }
+ 
+ UniqueChars
+ js::DecompileValueGenerator(JSContext* cx, int spindex, HandleValue v,
+                             HandleString fallbackArg, int skipStackHits)
+ {
+     RootedString fallback(cx, fallbackArg);
+     {
+-        char* result;
++        UniqueChars result;
+         if (!DecompileExpressionFromStack(cx, spindex, skipStackHits, v, &result))
+             return nullptr;
+-        if (result) {
+-            if (strcmp(result, "(intermediate value)"))
+-                return UniqueChars(result);
+-            js_free(result);
+-        }
++        if (result && strcmp(result.get(), "(intermediate value)"))
++            return result;
+     }
+     if (!fallback) {
+         if (v.isUndefined())
+             return DuplicateString(cx, js_undefined_str); // Prevent users from seeing "(void 0)"
+         fallback = ValueToSource(cx, v);
+         if (!fallback)
+             return nullptr;
+     }
+ 
+     return UniqueChars(JS_EncodeString(cx, fallback));
+ }
+ 
+ static bool
+-DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res)
++DecompileArgumentFromStack(JSContext* cx, int formalIndex, UniqueChars* res)
+ {
+     MOZ_ASSERT(formalIndex >= 0);
+ 
+     *res = nullptr;
+ 
+ #ifdef JS_MORE_DETERMINISTIC
+     /* See note in DecompileExpressionFromStack. */
+     return true;
+@@ -2393,31 +2387,29 @@ DecompileArgumentFromStack(JSContext* cx
+         return true;
+ 
+     ExpressionDecompiler ed(cx, script);
+     if (!ed.init())
+         return false;
+     if (!ed.decompilePCForStackOperand(current, formalStackIndex))
+         return false;
+ 
+-    return ed.getOutput(res);
++    *res = ed.getOutput();
++    return *res != nullptr;
+ }
+ 
+ UniqueChars
+ js::DecompileArgument(JSContext* cx, int formalIndex, HandleValue v)
+ {
+     {
+-        char* result;
++        UniqueChars result;
+         if (!DecompileArgumentFromStack(cx, formalIndex, &result))
+             return nullptr;
+-        if (result) {
+-            if (strcmp(result, "(intermediate value)"))
+-                return UniqueChars(result);
+-            js_free(result);
+-        }
++        if (result && strcmp(result.get(), "(intermediate value)"))
++            return result;
+     }
+     if (v.isUndefined())
+         return DuplicateString(cx, js_undefined_str); // Prevent users from seeing "(void 0)"
+ 
+     RootedString fallback(cx, ValueToSource(cx, v));
+     if (!fallback)
+         return nullptr;
+ 
+@@ -2750,21 +2742,20 @@ GetPCCountJSON(JSContext* cx, const Scri
+ 
+         {
+             ExpressionDecompiler ed(cx, script);
+             if (!ed.init())
+                 return false;
+             // defIndex passed here is not used.
+             if (!ed.decompilePC(pc, /* defIndex = */ 0))
+                 return false;
+-            char* text;
+-            if (!ed.getOutput(&text))
++            UniqueChars text = ed.getOutput();
++            if (!text)
+                 return false;
+-            JSString* str = JS_NewStringCopyZ(cx, text);
+-            js_free(text);
++            JSString* str = NewLatin1StringZ(cx, std::move(text));
+             if (!AppendJSONProperty(buf, "text"))
+                 return false;
+             if (!str || !(str = StringToSource(cx, str)))
+                 return false;
+             if (!buf.append(str))
+                 return false;
+         }
+ 
+diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp
+--- a/js/src/vm/HelperThreads.cpp
++++ b/js/src/vm/HelperThreads.cpp
+@@ -450,21 +450,17 @@ ParseTask::finish(JSContext* cx)
+             return false;
+         if (!sso->source()->tryCompressOffThread(cx))
+             return false;
+     }
+ 
+     return true;
+ }
+ 
+-ParseTask::~ParseTask()
+-{
+-    for (size_t i = 0; i < errors.length(); i++)
+-        js_delete(errors[i]);
+-}
++ParseTask::~ParseTask() = default;
+ 
+ void
+ ParseTask::trace(JSTracer* trc)
+ {
+     if (parseGlobal->runtimeFromAnyThread() != trc->runtime())
+         return;
+ 
+     Zone* zone = MaybeForwarded(parseGlobal)->zoneFromAnyThread();
+@@ -2054,21 +2050,22 @@ js::CurrentHelperThread()
+ }
+ 
+ bool
+ JSContext::addPendingCompileError(js::CompileError** error)
+ {
+     auto errorPtr = make_unique<js::CompileError>();
+     if (!errorPtr)
+         return false;
+-    if (!helperThread()->parseTask()->errors.append(errorPtr.get())) {
++    ParseTask* parseTask = helperThread()->parseTask();
++    if (!parseTask->errors.append(std::move(errorPtr))) {
+         ReportOutOfMemory(this);
+         return false;
+     }
+-    *error = errorPtr.release();
++    *error = parseTask->errors.back().get();
+     return true;
+ }
+ 
+ void
+ JSContext::addPendingOverRecursed()
+ {
+     if (helperThread()->parseTask())
+         helperThread()->parseTask()->overRecursed = true;
+diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h
+--- a/js/src/vm/HelperThreads.h
++++ b/js/src/vm/HelperThreads.h
+@@ -687,17 +687,17 @@ struct ParseTask : public mozilla::Linke
+     // ParseTask.
+     GCVector<JSScript*, 1> scripts;
+ 
+     // Holds the ScriptSourceObjects generated for the script compilation.
+     GCVector<ScriptSourceObject*, 1> sourceObjects;
+ 
+     // Any errors or warnings produced during compilation. These are reported
+     // when finishing the script.
+-    Vector<CompileError*, 0, SystemAllocPolicy> errors;
++    Vector<UniquePtr<CompileError>, 0, SystemAllocPolicy> errors;
+     bool overRecursed;
+     bool outOfMemory;
+ 
+     ParseTask(ParseTaskKind kind, JSContext* cx,
+               JS::OffThreadCompileCallback callback, void* callbackData);
+     virtual ~ParseTask();
+ 
+     bool init(JSContext* cx, const ReadOnlyCompileOptions& options, JSObject* global);
+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
+@@ -740,33 +740,34 @@ js::XDRAtom(XDRState<mode>* xdr, Mutable
+         atom = AtomizeChars(cx, chars, length);
+ #else
+         /*
+          * We must copy chars to a temporary buffer to convert between little and
+          * big endian data.
+          */
+         char16_t* chars;
+         char16_t stackChars[256];
++        UniqueTwoByteChars heapChars;
+         if (length <= ArrayLength(stackChars)) {
+             chars = stackChars;
+         } else {
+             /*
+              * This is very uncommon. Don't use the tempLifoAlloc arena for this as
+              * most allocations here will be bigger than tempLifoAlloc's default
+              * chunk size.
+              */
+-            chars = cx->pod_malloc<char16_t>(length);
+-            if (!chars)
++            heapChars.reset(cx->pod_malloc<char16_t>(length));
++            if (!heapChars)
+                 return xdr->fail(JS::TranscodeResult_Throw);
++
++            chars = heapChars.get();
+         }
+ 
+         MOZ_TRY(xdr->codeChars(chars, length));
+         atom = AtomizeChars(cx, chars, length);
+-        if (chars != stackChars)
+-            js_free(chars);
+ #endif /* !MOZ_LITTLE_ENDIAN */
+     }
+ 
+     if (!atom)
+         return xdr->fail(JS::TranscodeResult_Throw);
+     atomp.set(atom);
+     return Ok();
+ }
+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
+@@ -317,17 +317,17 @@ JSRuntime::destroyRuntime()
+ #if !EXPOSE_INTL_API
+     FinishRuntimeNumberState(this);
+ #endif
+ 
+     gc.finish();
+ 
+     js_delete(defaultFreeOp_.ref());
+ 
+-    js_free(defaultLocale);
++    defaultLocale = nullptr;
+     js_delete(jitRuntime_.ref());
+ 
+ #ifdef DEBUG
+     initialized_ = false;
+ #endif
+ }
+ 
+ void
+@@ -527,56 +527,54 @@ JSContext::handleInterrupt()
+ }
+ 
+ bool
+ JSRuntime::setDefaultLocale(const char* locale)
+ {
+     if (!locale)
+         return false;
+ 
+-    char* newLocale = DuplicateString(mainContextFromOwnThread(), locale).release();
++    UniqueChars newLocale = DuplicateString(mainContextFromOwnThread(), locale);
+     if (!newLocale)
+         return false;
+ 
+-    resetDefaultLocale();
+-    defaultLocale = newLocale;
++    defaultLocale.ref() = std::move(newLocale);
+     return true;
+ }
+ 
+ void
+ JSRuntime::resetDefaultLocale()
+ {
+-    js_free(defaultLocale);
+     defaultLocale = nullptr;
+ }
+ 
+ const char*
+ JSRuntime::getDefaultLocale()
+ {
+-    if (defaultLocale)
+-        return defaultLocale;
++    if (defaultLocale.ref())
++        return defaultLocale.ref().get();
+ 
+     const char* locale = setlocale(LC_ALL, nullptr);
+ 
+     // convert to a well-formed BCP 47 language tag
+     if (!locale || !strcmp(locale, "C"))
+         locale = "und";
+ 
+-    char* lang = DuplicateString(mainContextFromOwnThread(), locale).release();
++    UniqueChars lang = DuplicateString(mainContextFromOwnThread(), locale);
+     if (!lang)
+         return nullptr;
+ 
+     char* p;
+-    if ((p = strchr(lang, '.')))
++    if ((p = strchr(lang.get(), '.')))
+         *p = '\0';
+-    while ((p = strchr(lang, '_')))
++    while ((p = strchr(lang.get(), '_')))
+         *p = '-';
+ 
+-    defaultLocale = lang;
+-    return defaultLocale;
++    defaultLocale.ref() = std::move(lang);
++    return defaultLocale.ref().get();
+ }
+ 
+ void
+ JSRuntime::traceSharedIntlData(JSTracer* trc)
+ {
+     sharedIntlData.ref().trace(trc);
+ }
+ 
+diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
+--- a/js/src/vm/Runtime.h
++++ b/js/src/vm/Runtime.h
+@@ -31,16 +31,17 @@
+ #include "irregexp/RegExpStack.h"
+ #include "js/Debug.h"
+ #include "js/GCVector.h"
+ #include "js/HashTable.h"
+ #ifdef DEBUG
+ # include "js/Proxy.h" // For AutoEnterPolicy
+ #endif
+ #include "js/UniquePtr.h"
++#include "js/Utility.h"
+ #include "js/Vector.h"
+ #include "threading/Thread.h"
+ #include "vm/Caches.h"
+ #include "vm/CodeCoverage.h"
+ #include "vm/CommonPropertyNames.h"
+ #include "vm/DateTime.h"
+ #include "vm/GeckoProfiler.h"
+ #include "vm/JSAtom.h"
+@@ -523,17 +524,17 @@ struct JSRuntime : public js::MallocProv
+     // off-thread context realms, so it isn't necessarily equal to the
+     // number of realms visited by RealmsIter.
+     js::MainThreadData<size_t> numRealms;
+ 
+     /* Locale-specific callbacks for string conversion. */
+     js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
+ 
+     /* Default locale for Internationalization API */
+-    js::MainThreadData<char*> defaultLocale;
++    js::MainThreadData<js::UniqueChars> defaultLocale;
+ 
+     /* If true, new scripts must be created with PC counter information. */
+     js::MainThreadOrIonCompileData<bool> profilingScripts;
+ 
+     /* Strong references on scripts held for PCCount profiling API. */
+     js::MainThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
+ 
+   private:
+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
+@@ -777,32 +777,31 @@ js::ConcatStrings<CanGC>(JSContext* cx, 
+ template JSString*
+ js::ConcatStrings<NoGC>(JSContext* cx, JSString* const& left, JSString* const& right);
+ 
+ template <typename CharT>
+ JSFlatString*
+ JSDependentString::undependInternal(JSContext* cx)
+ {
+     size_t n = length();
+-    CharT* s = cx->pod_malloc<CharT>(n + 1);
++    auto s = cx->make_pod_array<CharT>(n + 1);
+     if (!s)
+         return nullptr;
+ 
+     if (!isTenured()) {
+-        if (!cx->runtime()->gc.nursery().registerMallocedBuffer(s)) {
+-            js_free(s);
++        if (!cx->runtime()->gc.nursery().registerMallocedBuffer(s.get())) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+     }
+ 
+     AutoCheckCannotGC nogc;
+-    PodCopy(s, nonInlineChars<CharT>(nogc), n);
++    PodCopy(s.get(), nonInlineChars<CharT>(nogc), n);
+     s[n] = '\0';
+-    setNonInlineChars<CharT>(s);
++    setNonInlineChars<CharT>(s.release());
+ 
+     /*
+      * Transform *this into an undepended string so 'base' will remain rooted
+      * for the benefit of any other dependent string that depends on *this.
+      */
+     if (IsSame<CharT, Latin1Char>::value)
+         d.u1.flags = UNDEPENDED_FLAGS | LATIN1_CHARS_BIT;
+     else
+@@ -1353,42 +1352,41 @@ JSString::ensureFlat(JSContext* cx)
+ }
+ 
+ JSFlatString*
+ JSExternalString::ensureFlat(JSContext* cx)
+ {
+     MOZ_ASSERT(hasTwoByteChars());
+ 
+     size_t n = length();
+-    char16_t* s = cx->pod_malloc<char16_t>(n + 1);
++    auto s = cx->make_pod_array<char16_t>(n + 1);
+     if (!s)
+         return nullptr;
+ 
+     if (!isTenured()) {
+-        if (!cx->runtime()->gc.nursery().registerMallocedBuffer(s)) {
+-            js_free(s);
++        if (!cx->runtime()->gc.nursery().registerMallocedBuffer(s.get())) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+     }
+ 
+     // Copy the chars before finalizing the string.
+     {
+         AutoCheckCannotGC nogc;
+-        PodCopy(s, nonInlineChars<char16_t>(nogc), n);
++        PodCopy(s.get(), nonInlineChars<char16_t>(nogc), n);
+         s[n] = '\0';
+     }
+ 
+     // Release the external chars.
+     finalize(cx->runtime()->defaultFreeOp());
+ 
+     // Transform the string into a non-external, flat string. Note that the
+     // resulting string will still be in an AllocKind::EXTERNAL_STRING arena,
+     // but will no longer be an external string.
+-    setNonInlineChars<char16_t>(s);
++    setNonInlineChars<char16_t>(s.release());
+     d.u1.flags = INIT_FLAT_FLAGS;
+ 
+     return &this->asFlat();
+ }
+ 
+ #if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ JSAtom::dump(js::GenericPrinter& out)
+diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
+--- a/js/src/vm/StructuredClone.cpp
++++ b/js/src/vm/StructuredClone.cpp
+@@ -27,16 +27,17 @@
+  */
+ 
+ #include "js/StructuredClone.h"
+ 
+ #include "mozilla/CheckedInt.h"
+ #include "mozilla/EndianUtils.h"
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/RangedPtr.h"
++#include "mozilla/Unused.h"
+ 
+ #include <algorithm>
+ #include <utility>
+ 
+ #include "jsapi.h"
+ #include "jsdate.h"
+ 
+ #include "builtin/DataViewObject.h"
+@@ -1900,57 +1901,42 @@ JSStructuredCloneReader::checkDouble(dou
+     if (!JS::IsCanonicalized(d)) {
+         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                   "unrecognized NaN");
+         return false;
+     }
+     return true;
+ }
+ 
+-namespace {
+-
+ template <typename CharT>
+-class Chars {
+-    JSContext* cx;
+-    CharT* p;
+-  public:
+-    explicit Chars(JSContext* cx) : cx(cx), p(nullptr) {}
+-    ~Chars() { js_free(p); }
+-
+-    bool allocate(size_t len) {
+-        MOZ_ASSERT(!p);
+-        // We're going to null-terminate!
+-        p = cx->pod_malloc<CharT>(len + 1);
+-        if (p) {
+-            p[len] = CharT(0);
+-            return true;
+-        }
+-        return false;
+-    }
+-    CharT* get() { return p; }
+-    void forget() { p = nullptr; }
+-};
+-
+-} // anonymous namespace
++static UniquePtr<CharT[], JS::FreePolicy>
++AllocateChars(JSContext* cx, size_t len)
++{
++    // We're going to null-terminate!
++    auto p = cx->make_pod_array<CharT>(len + 1);
++    if (p)
++        p[len] = CharT(0);
++    return p;
++}
+ 
+ template <typename CharT>
+ JSString*
+ JSStructuredCloneReader::readStringImpl(uint32_t nchars)
+ {
+     if (nchars > JSString::MAX_LENGTH) {
+         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                   "string length");
+         return nullptr;
+     }
+-    Chars<CharT> chars(context());
+-    if (!chars.allocate(nchars) || !in.readChars(chars.get(), nchars))
++    UniquePtr<CharT[], JS::FreePolicy> chars = AllocateChars<CharT>(context(), nchars);
++    if (!chars || !in.readChars(chars.get(), nchars))
+         return nullptr;
+     JSString* str = NewString<CanGC>(context(), chars.get(), nchars);
+     if (str)
+-        chars.forget();
++        mozilla::Unused << chars.release();
+     return str;
+ }
+ 
+ JSString*
+ JSStructuredCloneReader::readString(uint32_t data)
+ {
+     uint32_t nchars = data & JS_BITMASK(31);
+     bool latin1 = data & (1 << 31);

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

@@ -0,0 +1,323 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530203162 25200
+#      Thu Jun 28 09:26:02 2018 -0700
+# Node ID d2861f3dcc589d186308e9a3339d7344773fdb3d
+# Parent  8b1fc57cce36f9a85a1d1c8534309a5e1936de24
+Bug 1471931 - Part 3: Switch to pod_calloc_with_extra, new_, make_pod_array, and make_zeroed_pod_array where possible. r=sfink
+
+diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp
+--- a/js/src/builtin/MapObject.cpp
++++ b/js/src/builtin/MapObject.cpp
+@@ -301,21 +301,20 @@ MapIteratorObject::objectMoved(JSObject*
+ 
+     Nursery& nursery = iter->runtimeFromMainThread()->gc.nursery();
+     if (!nursery.isInside(range)) {
+         nursery.removeMallocedBuffer(range);
+         return 0;
+     }
+ 
+     AutoEnterOOMUnsafeRegion oomUnsafe;
+-    auto newRange = iter->zone()->pod_malloc<ValueMap::Range>();
++    auto newRange = iter->zone()->new_<ValueMap::Range>(*range);
+     if (!newRange)
+         oomUnsafe.crash("MapIteratorObject failed to allocate Range data while tenuring.");
+ 
+-    new (newRange) ValueMap::Range(*range);
+     range->~Range();
+     iter->setReservedSlot(MapIteratorObject::RangeSlot, PrivateValue(newRange));
+     return sizeof(ValueMap::Range);
+ }
+ 
+ template <typename Range>
+ static void
+ DestroyRange(JSObject* iterator, Range* range)
+@@ -1156,21 +1155,20 @@ SetIteratorObject::objectMoved(JSObject*
+ 
+     Nursery& nursery = iter->runtimeFromMainThread()->gc.nursery();
+     if (!nursery.isInside(range)) {
+         nursery.removeMallocedBuffer(range);
+         return 0;
+     }
+ 
+     AutoEnterOOMUnsafeRegion oomUnsafe;
+-    auto newRange = iter->zone()->pod_malloc<ValueSet::Range>();
++    auto newRange = iter->zone()->new_<ValueSet::Range>(*range);
+     if (!newRange)
+         oomUnsafe.crash("SetIteratorObject failed to allocate Range data while tenuring.");
+ 
+-    new (newRange) ValueSet::Range(*range);
+     range->~Range();
+     iter->setReservedSlot(SetIteratorObject::RangeSlot, PrivateValue(newRange));
+     return sizeof(ValueSet::Range);
+ }
+ 
+ bool
+ SetIteratorObject::next(Handle<SetIteratorObject*> setIterator, HandleArrayObject resultObj,
+                         JSContext* cx)
+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
+@@ -1433,17 +1433,17 @@ NewExternalString(JSContext* cx, unsigne
+     if (args.length() != 1 || !args[0].isString()) {
+         JS_ReportErrorASCII(cx, "newExternalString takes exactly one string argument.");
+         return false;
+     }
+ 
+     RootedString str(cx, args[0].toString());
+     size_t len = str->length();
+ 
+-    UniqueTwoByteChars buf(cx->pod_malloc<char16_t>(len));
++    auto buf = cx->make_pod_array<char16_t>(len);
+     if (!buf)
+         return false;
+ 
+     if (!JS_CopyStringChars(cx, mozilla::Range<char16_t>(buf.get(), len), str))
+         return false;
+ 
+     JSString* res = JS_NewExternalString(cx, buf.get(), len, &ExternalStringFinalizer);
+     if (!res)
+@@ -1462,17 +1462,17 @@ NewMaybeExternalString(JSContext* cx, un
+     if (args.length() != 1 || !args[0].isString()) {
+         JS_ReportErrorASCII(cx, "newMaybeExternalString takes exactly one string argument.");
+         return false;
+     }
+ 
+     RootedString str(cx, args[0].toString());
+     size_t len = str->length();
+ 
+-    UniqueTwoByteChars buf(cx->pod_malloc<char16_t>(len));
++    auto buf = cx->make_pod_array<char16_t>(len);
+     if (!buf)
+         return false;
+ 
+     if (!JS_CopyStringChars(cx, mozilla::Range<char16_t>(buf.get(), len), str))
+         return false;
+ 
+     bool allocatedExternal;
+     JSString* res = JS_NewMaybeExternalString(cx, buf.get(), len, &ExternalStringFinalizer,
+diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp
+--- a/js/src/jit/RematerializedFrame.cpp
++++ b/js/src/jit/RematerializedFrame.cpp
+@@ -68,20 +68,17 @@ RematerializedFrame::New(JSContext* cx, 
+ 
+     // One Value slot is included in sizeof(RematerializedFrame), so we can
+     // reduce the extra slot count by one.  However, if there are zero slot
+     // allocations total, then reducing the slots by one will lead to
+     // the memory allocation being smaller  than sizeof(RematerializedFrame).
+     if (extraSlots > 0)
+         extraSlots -= 1;
+ 
+-    size_t numBytes = sizeof(RematerializedFrame) + (extraSlots * sizeof(Value));
+-    MOZ_ASSERT(numBytes >= sizeof(RematerializedFrame));
+-
+-    void* buf = cx->pod_calloc<uint8_t>(numBytes);
++    RematerializedFrame* buf = cx->pod_calloc_with_extra<RematerializedFrame, Value>(extraSlots);
+     if (!buf)
+         return nullptr;
+ 
+     return new (buf) RematerializedFrame(cx, top, iter.numActualArgs(), iter, fallback);
+ }
+ 
+ /* static */ bool
+ RematerializedFrame::RematerializeInlineFrames(JSContext* cx, uint8_t* top,
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -4356,17 +4356,17 @@ JS_PUBLIC_API(bool)
+ JS_BufferIsCompilableUnit(JSContext* cx, HandleObject obj, const char* utf8, size_t length)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+     assertSameCompartment(cx, obj);
+ 
+     cx->clearPendingException();
+ 
+-    UniquePtr<char16_t> chars
++    UniqueTwoByteChars chars
+         { JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get() };
+     if (!chars)
+         return true;
+ 
+     // Return true on any out-of-memory error or non-EOF-related syntax error, so our
+     // caller doesn't try to collect more buffered source.
+     bool result = true;
+ 
+diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
+--- a/js/src/jsnum.cpp
++++ b/js/src/jsnum.cpp
+@@ -81,17 +81,17 @@ EnsureDtoaState(JSContext* cx)
+  * Call js_strtod_harder to get the correct answer.
+  */
+ template <typename CharT>
+ static bool
+ ComputeAccurateDecimalInteger(JSContext* cx, const CharT* start, const CharT* end,
+                               double* dp)
+ {
+     size_t length = end - start;
+-    UniqueChars cstr(cx->pod_malloc<char>(length + 1));
++    auto cstr = cx->make_pod_array<char>(length + 1);
+     if (!cstr)
+         return false;
+ 
+     for (size_t i = 0; i < length; i++) {
+         char c = char(start[i]);
+         MOZ_ASSERT(IsAsciiAlphanumeric(c));
+         cstr[i] = c;
+     }
+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
+@@ -879,17 +879,17 @@ RunBinAST(JSContext* cx, const char* fil
+ static bool
+ InitModuleLoader(JSContext* cx)
+ {
+ 
+     // Decompress and evaluate the embedded module loader source to initialize
+     // the module loader for the current compartment.
+ 
+     uint32_t srcLen = moduleloader::GetRawScriptsSize();
+-    UniqueChars src(cx->pod_malloc<char>(srcLen));
++    auto src = cx->make_pod_array<char>(srcLen);
+     if (!src || !DecompressString(moduleloader::compressedSources, moduleloader::GetCompressedSize(),
+                                   reinterpret_cast<unsigned char*>(src.get()), srcLen))
+     {
+         return false;
+     }
+ 
+     CompileOptions options(cx);
+     options.setIntroductionType("shell module loader");
+@@ -5022,17 +5022,17 @@ EscapeForShell(JSContext* cx, AutoCStrin
+ 
+         size_t newLen = 3;  // quotes before and after and null-terminator
+         for (char* p = argv[i]; *p; p++) {
+             newLen++;
+             if (*p == '\"' || *p == '\\')
+                 newLen++;
+         }
+ 
+-        UniqueChars escaped(cx->pod_malloc<char>(newLen));
++        auto escaped = cx->make_pod_array<char>(newLen);
+         if (!escaped)
+             return false;
+ 
+         char* src = argv[i];
+         char* dst = escaped.get();
+         *dst++ = '\"';
+         while (*src) {
+             if (*src == '\"' || *src == '\\')
+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
+@@ -2132,17 +2132,17 @@ ScriptSource::performXDR(XDRState<mode>*
+         if (mode == XDR_ENCODE) {
+             CompressedLengthMatcher m;
+             compressedLength = data.match(m);
+         }
+         MOZ_TRY(xdr->codeUint32(&compressedLength));
+ 
+         size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
+         if (mode == XDR_DECODE) {
+-            UniqueChars bytes(xdr->cx()->template pod_malloc<char>(Max<size_t>(byteLen, 1)));
++            auto bytes = xdr->cx()->template make_pod_array<char>(Max<size_t>(byteLen, 1));
+             if (!bytes)
+                 return xdr->fail(JS::TranscodeResult_Throw);
+             MOZ_TRY(xdr->codeBytes(bytes.get(), byteLen));
+ 
+             if (compressedLength) {
+                 if (!setCompressedSource(xdr->cx(), std::move(bytes), byteLen, len))
+                     return xdr->fail(JS::TranscodeResult_Throw);
+             } else {
+diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
+--- a/js/src/vm/ObjectGroup.cpp
++++ b/js/src/vm/ObjectGroup.cpp
+@@ -1247,24 +1247,23 @@ ObjectGroup::newPlainObject(JSContext* c
+         // will try to use an unboxed layout for the group.
+         PreliminaryObjectArrayWithTemplate* preliminaryObjects =
+             cx->new_<PreliminaryObjectArrayWithTemplate>(obj->lastProperty());
+         if (!preliminaryObjects)
+             return nullptr;
+         group->setPreliminaryObjects(preliminaryObjects);
+         preliminaryObjects->registerNewObject(obj);
+ 
+-        UniquePtr<jsid[], JS::FreePolicy> ids(group->zone()->pod_calloc<jsid>(nproperties));
++        auto ids = group->zone()->make_zeroed_pod_array<jsid>(nproperties);
+         if (!ids) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+ 
+-        UniquePtr<TypeSet::Type[], JS::FreePolicy> types(
+-            group->zone()->pod_calloc<TypeSet::Type>(nproperties));
++        auto types = group->zone()->make_zeroed_pod_array<TypeSet::Type>(nproperties);
+         if (!types) {
+             ReportOutOfMemory(cx);
+             return nullptr;
+         }
+ 
+         for (size_t i = 0; i < nproperties; i++) {
+             ids[i] = properties[i].id;
+             types[i] = GetValueTypeForTable(obj->getSlot(i));
+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
+@@ -2950,17 +2950,17 @@ JSRuntime::initSelfHosting(JSContext* cx
+     FillSelfHostingCompileOptions(options);
+ 
+     RootedValue rv(cx);
+ 
+     uint32_t srcLen = GetRawScriptsSize();
+ 
+     const unsigned char* compressed = compressedSources;
+     uint32_t compressedLen = GetCompressedSize();
+-    UniqueChars src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
++    auto src = selfHostingGlobal_->zone()->make_pod_array<char>(srcLen);
+     if (!src || !DecompressString(compressed, compressedLen,
+                                   reinterpret_cast<unsigned char*>(src.get()), srcLen))
+     {
+         return false;
+     }
+ 
+     if (!Evaluate(cx, options, src.get(), srcLen, &rv))
+         return false;
+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
+@@ -1499,17 +1499,17 @@ static JSFlatString*
+ NewStringDeflated(JSContext* cx, const char16_t* s, size_t n)
+ {
+     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+         return str;
+ 
+     if (JSInlineString::lengthFits<Latin1Char>(n))
+         return NewInlineStringDeflated<allowGC>(cx, mozilla::Range<const char16_t>(s, n));
+ 
+-    UniquePtr<Latin1Char[], JS::FreePolicy> news(cx->pod_malloc<Latin1Char>(n + 1));
++    auto news = cx->make_pod_array<Latin1Char>(n + 1);
+     if (!news)
+         return nullptr;
+ 
+     for (size_t i = 0; i < n; i++) {
+         MOZ_ASSERT(s[i] <= JSString::MAX_LATIN1_CHAR);
+         news[i] = Latin1Char(s[i]);
+     }
+     news[n] = '\0';
+@@ -1601,17 +1601,17 @@ JSFlatString*
+ NewStringCopyNDontDeflate(JSContext* cx, const CharT* s, size_t n)
+ {
+     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+         return str;
+ 
+     if (JSInlineString::lengthFits<CharT>(n))
+         return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
+ 
+-    UniquePtr<CharT[], JS::FreePolicy> news(cx->pod_malloc<CharT>(n + 1));
++    auto news = cx->make_pod_array<CharT>(n + 1);
+     if (!news) {
+         if (!allowGC)
+             cx->recoverFromOutOfMemory();
+         return nullptr;
+     }
+ 
+     PodCopy(news.get(), s, n);
+     news[n] = 0;

+ 568 - 0
frg/work-js/mozilla-release/patches/1471931-4-63a1.patch

@@ -0,0 +1,568 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530203446 25200
+#      Thu Jun 28 09:30:46 2018 -0700
+# Node ID 4e320fc1cbb8c73e868b4bbbe6dee924eed384bc
+# Parent  70f2e5844cb9ab3a48b5759c6d460d098ea6c380
+Bug 1471931 - Part 4: Add NewString and NewStringDontDeflate functions which accept UniquePtr. r=sfink
+
+diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
+--- a/js/src/builtin/String.cpp
++++ b/js/src/builtin/String.cpp
+@@ -188,44 +188,34 @@ class MOZ_NON_PARAM InlineCharBuffer
+                        "expected only inline storage when length fits in inline string");
+ 
+             return NewStringCopyNDontDeflate<CanGC>(cx, inlineStorage, length);
+         }
+ 
+         MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
+ 
+         heapStorage.get()[length] = '\0'; // Null-terminate
+-        JSString* res = NewStringDontDeflate<CanGC>(cx, heapStorage.get(), length);
+-        if (!res)
+-            return nullptr;
+-
+-        mozilla::Unused << heapStorage.release();
+-        return res;
++        return NewStringDontDeflate<CanGC>(cx, std::move(heapStorage), length);
+     }
+ 
+     JSString* toString(JSContext* cx, size_t length)
+     {
+         MOZ_ASSERT(length == lastRequestedLength);
+ 
+         if (JSInlineString::lengthFits<CharT>(length)) {
+             MOZ_ASSERT(!heapStorage,
+                        "expected only inline storage when length fits in inline string");
+ 
+             return NewStringCopyN<CanGC>(cx, inlineStorage, length);
+         }
+ 
+         MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
+ 
+         heapStorage.get()[length] = '\0'; // Null-terminate
+-        JSString* res = NewString<CanGC>(cx, heapStorage.get(), length);
+-        if (!res)
+-            return nullptr;
+-
+-        mozilla::Unused << heapStorage.release();
+-        return res;
++        return NewString<CanGC>(cx, std::move(heapStorage), length);
+     }
+ };
+ 
+ /*
+  * Forward declarations for URI encode/decode and helper routines
+  */
+ static bool
+ str_decodeURI(JSContext* cx, unsigned argc, Value* vp);
+@@ -3826,22 +3816,20 @@ js::str_fromCodePoint(JSContext* cx, uns
+             return false;
+ 
+         // Step 5.e.
+         unicode::UTF16Encode(codePoint, elements.get(), &length);
+     }
+     elements[length] = 0;
+ 
+     // Step 6.
+-    JSString* str = NewString<CanGC>(cx, elements.get(), length);
++    JSString* str = NewString<CanGC>(cx, std::move(elements), length);
+     if (!str)
+         return false;
+ 
+-    mozilla::Unused << elements.release();
+-
+     args.rval().setString(str);
+     return true;
+ }
+ 
+ static const JSFunctionSpec string_static_methods[] = {
+     JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
+     JS_INLINABLE_FN("fromCodePoint", js::str_fromCodePoint, 1, 0, StringFromCodePoint),
+ 
+diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
+--- a/js/src/builtin/TestingFunctions.cpp
++++ b/js/src/builtin/TestingFunctions.cpp
+@@ -2462,21 +2462,20 @@ ReadGeckoProfilingStack(JSContext* cx, u
+ 
+             frameKind = NewStringCopyZ<CanGC>(cx, inlineFrame.kind);
+             if (!frameKind)
+                 return false;
+ 
+             if (!JS_DefineProperty(cx, inlineFrameInfo, "kind", frameKind, propAttrs))
+                 return false;
+ 
+-            size_t length = strlen(inlineFrame.label.get());
+-            auto label = reinterpret_cast<Latin1Char*>(inlineFrame.label.release());
+-            frameLabel = NewString<CanGC>(cx, label, length);
+-            if (!frameLabel)
++            frameLabel = NewLatin1StringZ(cx, std::move(inlineFrame.label));
++            if (!frameLabel) {
+                 return false;
++            }
+ 
+             if (!JS_DefineProperty(cx, inlineFrameInfo, "label", frameLabel, propAttrs))
+                 return false;
+ 
+             idx = INT_TO_JSID(inlineFrameNo);
+             if (!JS_DefinePropertyById(cx, inlineStack, idx, inlineFrameInfo, 0))
+                 return false;
+ 
+@@ -3667,20 +3666,20 @@ FindPath(JSContext* cx, unsigned argc, V
+         if (!cx->compartment()->wrap(cx, &wrapped))
+             return false;
+ 
+         if (!JS_DefineProperty(cx, obj, "node", wrapped, JSPROP_ENUMERATE))
+             return false;
+ 
+         heaptools::EdgeName edgeName = std::move(edges[i]);
+ 
+-        RootedString edgeStr(cx, NewString<CanGC>(cx, edgeName.get(), js_strlen(edgeName.get())));
++        size_t edgeNameLength = js_strlen(edgeName.get());
++        RootedString edgeStr(cx, NewString<CanGC>(cx, std::move(edgeName), edgeNameLength));
+         if (!edgeStr)
+             return false;
+-        mozilla::Unused << edgeName.release(); // edgeStr acquired ownership
+ 
+         if (!JS_DefineProperty(cx, obj, "edge", edgeStr, JSPROP_ENUMERATE))
+             return false;
+ 
+         result->setDenseElement(length - i - 1, ObjectValue(*obj));
+     }
+ 
+     args.rval().setObject(*result);
+diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
+--- a/js/src/jsapi.cpp
++++ b/js/src/jsapi.cpp
+@@ -5812,33 +5812,33 @@ JS_AtomizeAndPinStringN(JSContext* cx, c
+     return atom;
+ }
+ 
+ JS_PUBLIC_API(JSString*)
+ JS_NewLatin1String(JSContext* cx, JS::Latin1Char* chars, size_t length)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+-    return NewString<CanGC>(cx, chars, length);
++    return NewString(cx, chars, length);
+ }
+ 
+ JS_PUBLIC_API(JSString*)
+ JS_NewUCString(JSContext* cx, char16_t* chars, size_t length)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+-    return NewString<CanGC>(cx, chars, length);
++    return NewString(cx, chars, length);
+ }
+ 
+ JS_PUBLIC_API(JSString*)
+ JS_NewUCStringDontDeflate(JSContext* cx, char16_t* chars, size_t length)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+-    return NewStringDontDeflate<CanGC>(cx, chars, length);
++    return NewStringDontDeflate(cx, chars, length);
+ }
+ 
+ JS_PUBLIC_API(JSString*)
+ JS_NewUCStringCopyN(JSContext* cx, const char16_t* s, size_t n)
+ {
+     AssertHeapIsIdle();
+     CHECK_REQUEST(cx);
+     if (!n)
+diff --git a/js/src/util/StringBuffer.cpp b/js/src/util/StringBuffer.cpp
+--- a/js/src/util/StringBuffer.cpp
++++ b/js/src/util/StringBuffer.cpp
+@@ -79,27 +79,26 @@ FinishStringFlat(JSContext* cx, StringBu
+     size_t len = sb.length();
+     if (!sb.append('\0'))
+         return nullptr;
+ 
+     UniquePtr<CharT[], JS::FreePolicy> buf(ExtractWellSized<CharT>(cx, cb));
+     if (!buf)
+         return nullptr;
+ 
+-    JSFlatString* str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
++    JSFlatString* str = NewStringDontDeflate<CanGC>(cx, std::move(buf), len);
+     if (!str)
+         return nullptr;
+ 
+     /*
+      * The allocation was made on a TempAllocPolicy, so account for the string
+      * data on the string's zone.
+      */
+     cx->updateMallocCounter(sizeof(CharT) * len);
+ 
+-    mozilla::Unused << buf.release();
+     return str;
+ }
+ 
+ JSFlatString*
+ StringBuffer::finishString()
+ {
+     size_t len = length();
+     if (len == 0)
+diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp
+--- a/js/src/vm/JSCompartment.cpp
++++ b/js/src/vm/JSCompartment.cpp
+@@ -281,32 +281,24 @@ CopyStringPure(JSContext* cx, JSString* 
+                : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
+     }
+ 
+     if (str->hasLatin1Chars()) {
+         UniquePtr<Latin1Char[], JS::FreePolicy> copiedChars = str->asRope().copyLatin1CharsZ(cx);
+         if (!copiedChars)
+             return nullptr;
+ 
+-        auto* rawCopiedChars = copiedChars.release();
+-        auto* result = NewString<CanGC>(cx, rawCopiedChars, len);
+-        if (!result)
+-            js_free(rawCopiedChars);
+-        return result;
++        return NewString<CanGC>(cx, std::move(copiedChars), len);
+     }
+ 
+     UniqueTwoByteChars copiedChars = str->asRope().copyTwoByteCharsZ(cx);
+     if (!copiedChars)
+         return nullptr;
+ 
+-    auto* rawCopiedChars = copiedChars.release();
+-    auto* result = NewStringDontDeflate<CanGC>(cx, rawCopiedChars, len);
+-    if (!result)
+-        js_free(rawCopiedChars);
+-    return result;
++    return NewStringDontDeflate<CanGC>(cx, std::move(copiedChars), len);
+ }
+ 
+ bool
+ JSCompartment::wrap(JSContext* cx, MutableHandleString strp)
+ {
+     MOZ_ASSERT(cx->compartment() == this);
+ 
+     /* If the string is already in this compartment, we are done. */
+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
+@@ -36,16 +36,18 @@ using mozilla::IsSame;
+ using mozilla::PodCopy;
+ using mozilla::PodEqual;
+ using mozilla::RangedPtr;
+ using mozilla::RoundUpPow2;
+ using mozilla::Unused;
+ 
+ using JS::AutoCheckCannotGC;
+ 
++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())
+         return 0;
+ 
+     MOZ_ASSERT(isLinear());
+@@ -274,29 +276,29 @@ AllocChars(JSString* str, size_t length,
+     /* Like length, capacity does not include the null char, so take it out. */
+     *capacity = numChars - 1;
+ 
+     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
+     *chars = str->zone()->pod_malloc<CharT>(numChars);
+     return *chars != nullptr;
+ }
+ 
+-UniquePtr<Latin1Char[], JS::FreePolicy>
++UniqueLatin1Chars
+ JSRope::copyLatin1CharsZ(JSContext* maybecx) const
+ {
+     return copyCharsInternal<Latin1Char>(maybecx, true);
+ }
+ 
+ UniqueTwoByteChars
+ JSRope::copyTwoByteCharsZ(JSContext* maybecx) const
+ {
+     return copyCharsInternal<char16_t>(maybecx, true);
+ }
+ 
+-UniquePtr<Latin1Char[], JS::FreePolicy>
++UniqueLatin1Chars
+ JSRope::copyLatin1Chars(JSContext* maybecx) const
+ {
+     return copyCharsInternal<Latin1Char>(maybecx, false);
+ }
+ 
+ UniqueTwoByteChars
+ JSRope::copyTwoByteChars(JSContext* maybecx) const
+ {
+@@ -1524,80 +1526,120 @@ NewStringDeflated(JSContext* cx, const c
+ 
+ template <AllowGC allowGC>
+ static JSFlatString*
+ NewStringDeflated(JSContext* cx, const Latin1Char* s, size_t n)
+ {
+     MOZ_CRASH("Shouldn't be called for Latin1 chars");
+ }
+ 
+-template <AllowGC allowGC, typename CharT>
++template <typename CharT>
+ JSFlatString*
+ js::NewStringDontDeflate(JSContext* cx, CharT* chars, size_t length)
+ {
+     if (JSFlatString* str = TryEmptyOrStaticString(cx, chars, length)) {
+         // Free |chars| because we're taking possession of it, but it's no
+         // longer needed because we use the static string instead.
+         js_free(chars);
+         return str;
+     }
+ 
+     if (JSInlineString::lengthFits<CharT>(length)) {
+         JSInlineString* str =
+-            NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(chars, length));
++            NewInlineString<CanGC>(cx, mozilla::Range<const CharT>(chars, length));
+         if (!str)
+             return nullptr;
+ 
+         js_free(chars);
+         return str;
+     }
+ 
+-    return JSFlatString::new_<allowGC>(cx, chars, length);
++    return JSFlatString::new_<CanGC>(cx, chars, length);
+ }
+ 
+ template JSFlatString*
+-js::NewStringDontDeflate<CanGC>(JSContext* cx, char16_t* chars, size_t length);
+-
+-template JSFlatString*
+-js::NewStringDontDeflate<NoGC>(JSContext* cx, char16_t* chars, size_t length);
++js::NewStringDontDeflate(JSContext* cx, char16_t* chars, size_t length);
+ 
+ template JSFlatString*
+-js::NewStringDontDeflate<CanGC>(JSContext* cx, Latin1Char* chars, size_t length);
++js::NewStringDontDeflate(JSContext* cx, Latin1Char* chars, size_t length);
+ 
+-template JSFlatString*
+-js::NewStringDontDeflate<NoGC>(JSContext* cx, Latin1Char* chars, size_t length);
+-
+-template <AllowGC allowGC, typename CharT>
++template <typename CharT>
+ JSFlatString*
+ js::NewString(JSContext* cx, CharT* chars, size_t length)
+ {
+     if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(chars, length)) {
+-        JSFlatString* s = NewStringDeflated<allowGC>(cx, chars, length);
++        JSFlatString* s = NewStringDeflated<CanGC>(cx, chars, length);
+         if (!s)
+             return nullptr;
+ 
+         // Free |chars| because we're taking possession of it but not using it.
+         js_free(chars);
+         return s;
+     }
+ 
+-    return NewStringDontDeflate<allowGC>(cx, chars, length);
++    return NewStringDontDeflate(cx, chars, length);
++}
++
++template JSFlatString*
++js::NewString(JSContext* cx, char16_t* chars, size_t length);
++
++template JSFlatString*
++js::NewString(JSContext* cx, Latin1Char* chars, size_t length);
++
++template <AllowGC allowGC, typename CharT>
++JSFlatString*
++js::NewStringDontDeflate(JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length)
++{
++    if (JSFlatString* str = TryEmptyOrStaticString(cx, chars.get(), length))
++        return str;
++
++    if (JSInlineString::lengthFits<CharT>(length))
++        return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(chars.get(), length));
++
++    JSFlatString* str = JSFlatString::new_<allowGC>(cx, chars.get(), length);
++    if (!str)
++        return nullptr;
++
++    mozilla::Unused << chars.release();
++    return str;
+ }
+ 
+ template JSFlatString*
+-js::NewString<CanGC>(JSContext* cx, char16_t* chars, size_t length);
++js::NewStringDontDeflate<CanGC>(JSContext* cx, UniqueTwoByteChars chars, size_t length);
++
++template JSFlatString*
++js::NewStringDontDeflate<NoGC>(JSContext* cx, UniqueTwoByteChars chars, size_t length);
++
++template JSFlatString*
++js::NewStringDontDeflate<CanGC>(JSContext* cx, UniqueLatin1Chars chars, size_t length);
+ 
+ template JSFlatString*
+-js::NewString<NoGC>(JSContext* cx, char16_t* chars, size_t length);
++js::NewStringDontDeflate<NoGC>(JSContext* cx, UniqueLatin1Chars chars, size_t length);
++
++template <AllowGC allowGC, typename CharT>
++JSFlatString*
++js::NewString(JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length)
++{
++    if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(chars.get(), length))
++        return NewStringDeflated<allowGC>(cx, chars.get(), length);
++
++    return NewStringDontDeflate<allowGC>(cx, std::move(chars), length);
++}
+ 
+ template JSFlatString*
+-js::NewString<CanGC>(JSContext* cx, Latin1Char* chars, size_t length);
++js::NewString<CanGC>(JSContext* cx, UniqueTwoByteChars chars, size_t length);
+ 
+ template JSFlatString*
+-js::NewString<NoGC>(JSContext* cx, Latin1Char* chars, size_t length);
++js::NewString<NoGC>(JSContext* cx, UniqueTwoByteChars chars, size_t length);
++
++template JSFlatString*
++js::NewString<CanGC>(JSContext* cx, UniqueLatin1Chars chars, size_t length);
++
++template JSFlatString*
++js::NewString<NoGC>(JSContext* cx, UniqueLatin1Chars chars, size_t length);
+ 
+ namespace js {
+ 
+ template <AllowGC allowGC, typename CharT>
+ JSFlatString*
+ NewStringCopyNDontDeflate(JSContext* cx, const CharT* s, size_t n)
+ {
+     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+@@ -1634,22 +1676,19 @@ template JSFlatString*
+ NewStringCopyNDontDeflate<CanGC>(JSContext* cx, const Latin1Char* s, size_t n);
+ 
+ template JSFlatString*
+ NewStringCopyNDontDeflate<NoGC>(JSContext* cx, const Latin1Char* s, size_t n);
+ 
+ JSFlatString*
+ NewLatin1StringZ(JSContext* cx, UniqueChars chars)
+ {
+-    JSFlatString* str = NewString<CanGC>(cx, (Latin1Char*)chars.get(), strlen(chars.get()));
+-    if (!str)
+-        return nullptr;
+-
+-    mozilla::Unused << chars.release();
+-    return str;
++    size_t length = strlen(chars.get());
++    UniqueLatin1Chars latin1(reinterpret_cast<Latin1Char*>(chars.release()));
++    return NewString<CanGC>(cx, std::move(latin1), length);
+ }
+ 
+ template <AllowGC allowGC, typename CharT>
+ JSFlatString*
+ NewStringCopyN(JSContext* cx, const CharT* s, size_t n)
+ {
+     if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(s, n))
+         return NewStringDeflated<allowGC>(cx, s, n);
+@@ -1674,36 +1713,30 @@ JSFlatString*
+ NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8)
+ {
+     JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8);
+     if (encoding == JS::SmallestEncoding::ASCII)
+         return NewStringCopyN<allowGC>(cx, utf8.begin().get(), utf8.length());
+ 
+     size_t length;
+     if (encoding == JS::SmallestEncoding::Latin1) {
+-        Latin1Char* latin1 = UTF8CharsToNewLatin1CharsZ(cx, utf8, &length).get();
++        UniqueLatin1Chars latin1(UTF8CharsToNewLatin1CharsZ(cx, utf8, &length).get());
+         if (!latin1)
+             return nullptr;
+ 
+-        JSFlatString* result = NewString<allowGC>(cx, latin1, length);
+-        if (!result)
+-            js_free((void*)latin1);
+-        return result;
++        return NewString<allowGC>(cx, std::move(latin1), length);
+     }
+ 
+     MOZ_ASSERT(encoding == JS::SmallestEncoding::UTF16);
+ 
+-    char16_t* utf16 = UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get();
++    UniqueTwoByteChars utf16(UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get());
+     if (!utf16)
+         return nullptr;
+ 
+-    JSFlatString* result = NewString<allowGC>(cx, utf16, length);
+-    if (!result)
+-        js_free((void*)utf16);
+-    return result;
++    return NewString<allowGC>(cx, std::move(utf16), length);
+ }
+ 
+ template JSFlatString*
+ NewStringCopyUTF8N<CanGC>(JSContext* cx, const JS::UTF8Chars utf8);
+ 
+ MOZ_ALWAYS_INLINE JSString*
+ ExternalStringCache::lookup(const char16_t* chars, size_t len) const
+ {
+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
+@@ -1439,24 +1439,34 @@ StringToNewUTF8CharsZ(JSContext* maybecx
+         return nullptr;
+ 
+     return UniqueChars(linear->hasLatin1Chars()
+                        ? JS::CharsToNewUTF8CharsZ(maybecx, linear->latin1Range(nogc)).c_str()
+                        : JS::CharsToNewUTF8CharsZ(maybecx, linear->twoByteRange(nogc)).c_str());
+ }
+ 
+ /* GC-allocate a string descriptor for the given malloc-allocated chars. */
+-template <js::AllowGC allowGC, typename CharT>
++template <typename CharT>
+ extern JSFlatString*
+ NewString(JSContext* cx, CharT* chars, size_t length);
+ 
+ /* Like NewString, but doesn't try to deflate to Latin1. */
++template <typename CharT>
++extern JSFlatString*
++NewStringDontDeflate(JSContext* cx, CharT* chars, size_t length);
++
++/* GC-allocate a string descriptor for the given malloc-allocated chars. */
+ template <js::AllowGC allowGC, typename CharT>
+ extern JSFlatString*
+-NewStringDontDeflate(JSContext* cx, CharT* chars, size_t length);
++NewString(JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length);
++
++/* Like NewString, but doesn't try to deflate to Latin1. */
++template <js::AllowGC allowGC, typename CharT>
++extern JSFlatString*
++NewStringDontDeflate(JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length);
+ 
+ extern JSLinearString*
+ NewDependentString(JSContext* cx, JSString* base, size_t start, size_t length);
+ 
+ /* Take ownership of an array of Latin1Chars. */
+ extern JSFlatString*
+ NewLatin1StringZ(JSContext* cx, UniqueChars chars);
+ 
+diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
+--- a/js/src/vm/StructuredClone.cpp
++++ b/js/src/vm/StructuredClone.cpp
+@@ -1924,20 +1924,17 @@ JSStructuredCloneReader::readStringImpl(
+     if (nchars > JSString::MAX_LENGTH) {
+         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                   "string length");
+         return nullptr;
+     }
+     UniquePtr<CharT[], JS::FreePolicy> chars = AllocateChars<CharT>(context(), nchars);
+     if (!chars || !in.readChars(chars.get(), nchars))
+         return nullptr;
+-    JSString* str = NewString<CanGC>(context(), chars.get(), nchars);
+-    if (str)
+-        mozilla::Unused << chars.release();
+-    return str;
++    return NewString<CanGC>(context(), std::move(chars), nchars);
+ }
+ 
+ JSString*
+ JSStructuredCloneReader::readString(uint32_t data)
+ {
+     uint32_t nchars = data & JS_BITMASK(31);
+     bool latin1 = data & (1 << 31);
+     return latin1 ? readStringImpl<Latin1Char>(nchars) : readStringImpl<char16_t>(nchars);

+ 643 - 0
frg/work-js/mozilla-release/patches/1471931-5-63a1.patch

@@ -0,0 +1,643 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530264831 25200
+#      Fri Jun 29 02:33:51 2018 -0700
+# Node ID 266767b68e8c4552a2f7a602ca103883d45e91de
+# Parent  baec8372b08e26892bfcef5b29ed309f09a6f2cf
+Bug 1471931 - Part 5: Use MakeUnique in more places and replace manual js_delete with UniquePtr. r=sfink
+
+diff --git a/js/public/UbiNodeShortestPaths.h b/js/public/UbiNodeShortestPaths.h
+--- a/js/public/UbiNodeShortestPaths.h
++++ b/js/public/UbiNodeShortestPaths.h
+@@ -8,32 +8,33 @@
+ #define js_UbiNodeShortestPaths_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/Move.h"
+ 
+ #include "js/AllocPolicy.h"
+ #include "js/UbiNodeBreadthFirst.h"
++#include "js/UniquePtr.h"
+ #include "js/Vector.h"
+ 
+ namespace JS {
+ namespace ubi {
+ 
+ /**
+  * A back edge along a path in the heap graph.
+  */
+ struct JS_PUBLIC_API(BackEdge)
+ {
+   private:
+     Node predecessor_;
+     EdgeName name_;
+ 
+   public:
+-    using Ptr = mozilla::UniquePtr<BackEdge, JS::DeletePolicy<BackEdge>>;
++    using Ptr = js::UniquePtr<BackEdge>;
+ 
+     BackEdge() : predecessor_(), name_(nullptr) { }
+ 
+     MOZ_MUST_USE bool init(const Node& predecessor, Edge& edge) {
+         MOZ_ASSERT(!predecessor_);
+         MOZ_ASSERT(!name_);
+ 
+         predecessor_ = predecessor;
+@@ -142,17 +143,17 @@ struct JS_PUBLIC_API(ShortestPaths)
+             } else {
+                 auto ptr = shortestPaths.paths_.lookup(edge.referent);
+                 MOZ_ASSERT(ptr,
+                            "This isn't the first time we have seen the target node `edge.referent`. "
+                            "We should have inserted it into shortestPaths.paths_ the first time we "
+                            "saw it.");
+ 
+                 if (ptr->value().length() < shortestPaths.maxNumPaths_) {
+-                    BackEdge::Ptr thisBackEdge(js_new<BackEdge>());
++                    auto thisBackEdge = js::MakeUnique<BackEdge>();
+                     if (!thisBackEdge || !thisBackEdge->init(origin, edge))
+                         return false;
+                     ptr->value().infallibleAppend(std::move(thisBackEdge));
+                     totalPathsRecorded++;
+                 }
+             }
+ 
+             MOZ_ASSERT(totalPathsRecorded <= totalMaxPathsToRecord);
+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
+@@ -5321,17 +5321,17 @@ CodeGenerator::maybeCreateScriptCounts()
+     // currently incompatible with wasm codegen for two reasons: (1) wasm code
+     // must be serializable and script count codegen bakes in absolute
+     // addresses, (2) wasm code does not have a JSScript with which to associate
+     // code coverage data.
+     JSScript* script = gen->info().script();
+     if (!script)
+         return nullptr;
+ 
+-    UniquePtr<IonScriptCounts> counts(js_new<IonScriptCounts>());
++    auto counts = MakeUnique<IonScriptCounts>();
+     if (!counts || !counts->init(graph.numBlocks()))
+         return nullptr;
+ 
+     for (size_t i = 0; i < graph.numBlocks(); i++) {
+         MBasicBlock* block = graph.getBlock(i)->mir();
+ 
+         uint32_t offset = 0;
+         char* description = nullptr;
+diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
+--- a/js/src/jit/Ion.cpp
++++ b/js/src/jit/Ion.cpp
+@@ -1867,26 +1867,24 @@ GenerateLIR(MIRGenerator* mir)
+ }
+ 
+ CodeGenerator*
+ GenerateCode(MIRGenerator* mir, LIRGraph* lir)
+ {
+     TraceLoggerThread* logger = TraceLoggerForCurrentThread();
+     AutoTraceLog log(logger, TraceLogger_GenerateCode);
+ 
+-    CodeGenerator* codegen = js_new<CodeGenerator>(mir, lir);
++    auto codegen = MakeUnique<CodeGenerator>(mir, lir);
+     if (!codegen)
+         return nullptr;
+ 
+-    if (!codegen->generate()) {
+-        js_delete(codegen);
++    if (!codegen->generate())
+         return nullptr;
+-    }
+-
+-    return codegen;
++
++    return codegen.release();
+ }
+ 
+ CodeGenerator*
+ CompileBackEnd(MIRGenerator* mir)
+ {
+     // Everything in CompileBackEnd can potentially run on a helper thread.
+     AutoEnterIonCompilation enter(mir->safeForMinorGC());
+     AutoSpewEndFunction spewEndFunction(mir);
+diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp
+--- a/js/src/jit/arm/Simulator-arm.cpp
++++ b/js/src/jit/arm/Simulator-arm.cpp
+@@ -33,16 +33,17 @@
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/MathAlgorithms.h"
+ #include "mozilla/Unused.h"
+ 
+ #include "jit/arm/Assembler-arm.h"
+ #include "jit/arm/disasm/Constants-arm.h"
+ #include "jit/AtomicOperations.h"
++#include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ #include "threading/LockGuard.h"
+ #include "vm/Runtime.h"
+ #include "vm/SharedMem.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ extern "C" {
+@@ -410,33 +411,31 @@ mozilla::Atomic<size_t, mozilla::Release
+     SimulatorProcess::ICacheCheckingDisableCount(1); // Checking is disabled by default.
+ SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
+ 
+ int64_t Simulator::StopSimAt = -1L;
+ 
+ Simulator*
+ Simulator::Create(JSContext* cx)
+ {
+-    Simulator* sim = js_new<Simulator>(cx);
++    auto sim = MakeUnique<Simulator>(cx);
+     if (!sim)
+         return nullptr;
+ 
+-    if (!sim->init()) {
+-        js_delete(sim);
++    if (!sim->init())
+         return nullptr;
+-    }
+ 
+     char* stopAtStr = getenv("ARM_SIM_STOP_AT");
+     int64_t stopAt;
+     if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) {
+         fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt);
+         Simulator::StopSimAt = stopAt;
+     }
+ 
+-    return sim;
++    return sim.release();
+ }
+ 
+ void
+ Simulator::Destroy(Simulator* sim)
+ {
+     js_delete(sim);
+ }
+ 
+diff --git a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+--- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
++++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+@@ -24,16 +24,17 @@
+ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+ #include "mozilla/DebugOnly.h"
+ 
+ #include "jit/arm64/vixl/Debugger-vixl.h"
+ #include "jit/arm64/vixl/Simulator-vixl.h"
+ #include "jit/IonTypes.h"
++#include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ #include "threading/LockGuard.h"
+ #include "vm/Runtime.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmProcess.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ js::jit::SimulatorProcess* js::jit::SimulatorProcess::singleton_ = nullptr;
+@@ -163,29 +164,27 @@ Simulator* Simulator::Current() {
+ Simulator* Simulator::Create(JSContext* cx) {
+   Decoder *decoder = js_new<vixl::Decoder>();
+   if (!decoder)
+     return nullptr;
+ 
+   // FIXME: This just leaks the Decoder object for now, which is probably OK.
+   // FIXME: We should free it at some point.
+   // FIXME: Note that it can't be stored in the SimulatorRuntime due to lifetime conflicts.
+-  Simulator *sim;
++  js::UniquePtr<Simulator> sim;
+   if (getenv("USE_DEBUGGER") != nullptr)
+-    sim = js_new<Debugger>(cx, decoder, stdout);
++    sim.reset(js_new<Debugger>(cx, decoder, stdout));
+   else
+-    sim = js_new<Simulator>(cx, decoder, stdout);
++    sim.reset(js_new<Simulator>(cx, decoder, stdout));
+ 
+   // Check if Simulator:init ran out of memory.
+-  if (sim && sim->oom()) {
+-    js_delete(sim);
++  if (sim && sim->oom())
+     return nullptr;
+-  }
+ 
+-  return sim;
++  return sim.release();
+ }
+ 
+ 
+ void Simulator::Destroy(Simulator* sim) {
+   js_delete(sim);
+ }
+ 
+ 
+diff --git a/js/src/jit/mips32/Simulator-mips32.cpp b/js/src/jit/mips32/Simulator-mips32.cpp
+--- a/js/src/jit/mips32/Simulator-mips32.cpp
++++ b/js/src/jit/mips32/Simulator-mips32.cpp
+@@ -32,16 +32,17 @@
+ #include "mozilla/FloatingPoint.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/MathAlgorithms.h"
+ 
+ #include <float.h>
+ 
+ #include "jit/AtomicOperations.h"
+ #include "jit/mips32/Assembler-mips32.h"
++#include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ #include "vm/Runtime.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ #define I8(v)   static_cast<int8_t>(v)
+ #define I16(v)  static_cast<int16_t>(v)
+ #define U16(v)  static_cast<uint16_t>(v)
+@@ -519,33 +520,31 @@ mozilla::Atomic<size_t, mozilla::Release
+     SimulatorProcess::ICacheCheckingDisableCount(1); // Checking is disabled by default.
+ SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
+ 
+ int Simulator::StopSimAt = -1;
+ 
+ Simulator*
+ Simulator::Create(JSContext* cx)
+ {
+-    Simulator* sim = js_new<Simulator>();
++    auto sim = MakeUnique<Simulator>();
+     if (!sim)
+         return nullptr;
+ 
+-    if (!sim->init()) {
+-        js_delete(sim);
++    if (!sim->init())
+         return nullptr;
+-    }
+ 
+     char* stopAtStr = getenv("MIPS_SIM_STOP_AT");
+     int64_t stopAt;
+     if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) {
+         fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt);
+         Simulator::StopSimAt = stopAt;
+     }
+ 
+-    return sim;
++    return sim.release();
+ }
+ 
+ void
+ Simulator::Destroy(Simulator* sim)
+ {
+     js_delete(sim);
+ }
+ 
+diff --git a/js/src/jit/mips64/Simulator-mips64.cpp b/js/src/jit/mips64/Simulator-mips64.cpp
+--- a/js/src/jit/mips64/Simulator-mips64.cpp
++++ b/js/src/jit/mips64/Simulator-mips64.cpp
+@@ -35,16 +35,17 @@
+ #include "mozilla/Likely.h"
+ #include "mozilla/MathAlgorithms.h"
+ 
+ #include <float.h>
+ #include <limits>
+ 
+ #include "jit/AtomicOperations.h"
+ #include "jit/mips64/Assembler-mips64.h"
++#include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ #include "threading/LockGuard.h"
+ #include "vm/Runtime.h"
+ #include "wasm/WasmInstance.h"
+ #include "wasm/WasmSignalHandlers.h"
+ 
+ #define I8(v)   static_cast<int8_t>(v)
+ #define I16(v)  static_cast<int16_t>(v)
+@@ -554,33 +555,31 @@ mozilla::Atomic<size_t, mozilla::Release
+     SimulatorProcess::ICacheCheckingDisableCount(1);  // Checking is disabled by default.
+ SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
+ 
+ int64_t Simulator::StopSimAt = -1;
+ 
+ Simulator *
+ Simulator::Create(JSContext* cx)
+ {
+-    Simulator* sim = js_new<Simulator>();
++    auto sim = MakeUnique<Simulator>();
+     if (!sim)
+         return nullptr;
+ 
+-    if (!sim->init()) {
+-        js_delete(sim);
++    if (!sim->init())
+         return nullptr;
+-    }
+ 
+     int64_t stopAt;
+     char* stopAtStr = getenv("MIPS_SIM_STOP_AT");
+     if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) {
+         fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt);
+         Simulator::StopSimAt = stopAt;
+     }
+ 
+-    return sim;
++    return sim.release();
+ }
+ 
+ void
+ Simulator::Destroy(Simulator* sim)
+ {
+     js_delete(sim);
+ }
+ 
+diff --git a/js/src/vm/Caches.cpp b/js/src/vm/Caches.cpp
+--- a/js/src/vm/Caches.cpp
++++ b/js/src/vm/Caches.cpp
+@@ -12,17 +12,17 @@ using namespace js;
+ 
+ using mozilla::PodZero;
+ 
+ MathCache*
+ RuntimeCaches::createMathCache(JSContext* cx)
+ {
+     MOZ_ASSERT(!mathCache_);
+ 
+-    UniquePtr<MathCache> newMathCache(js_new<MathCache>());
++    auto newMathCache = MakeUnique<MathCache>();
+     if (!newMathCache) {
+         ReportOutOfMemory(cx);
+         return nullptr;
+     }
+ 
+     mathCache_ = std::move(newMathCache);
+     return mathCache_.get();
+ }
+diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp
+--- a/js/src/vm/Shape.cpp
++++ b/js/src/vm/Shape.cpp
+@@ -11,16 +11,17 @@
+ #include "mozilla/MathAlgorithms.h"
+ #include "mozilla/PodOperations.h"
+ 
+ #include "gc/FreeOp.h"
+ #include "gc/HashUtil.h"
+ #include "gc/Policy.h"
+ #include "gc/PublicIterators.h"
+ #include "js/HashTable.h"
++#include "js/UniquePtr.h"
+ #include "util/Text.h"
+ #include "vm/JSAtom.h"
+ #include "vm/JSContext.h"
+ #include "vm/JSObject.h"
+ 
+ #include "vm/Caches-inl.h"
+ #include "vm/JSCompartment-inl.h"
+ #include "vm/JSContext-inl.h"
+@@ -1605,25 +1606,23 @@ MOZ_ALWAYS_INLINE bool
+ ShapeHasher::match(const Key k, const Lookup& l)
+ {
+     return k->matches(l);
+ }
+ 
+ static KidsHash*
+ HashChildren(Shape* kid1, Shape* kid2)
+ {
+-    KidsHash* hash = js_new<KidsHash>();
+-    if (!hash || !hash->init(2)) {
+-        js_delete(hash);
++    auto hash = MakeUnique<KidsHash>();
++    if (!hash || !hash->init(2))
+         return nullptr;
+-    }
+ 
+     hash->putNewInfallible(StackShape(kid1), kid1);
+     hash->putNewInfallible(StackShape(kid2), kid2);
+-    return hash;
++    return hash.release();
+ }
+ 
+ bool
+ PropertyTree::insertChild(JSContext* cx, Shape* parent, Shape* child)
+ {
+     MOZ_ASSERT(!parent->inDictionary());
+     MOZ_ASSERT(!child->parent);
+     MOZ_ASSERT(!child->inDictionary());
+diff --git a/js/src/vm/SharedImmutableStringsCache.h b/js/src/vm/SharedImmutableStringsCache.h
+--- a/js/src/vm/SharedImmutableStringsCache.h
++++ b/js/src/vm/SharedImmutableStringsCache.h
+@@ -11,16 +11,17 @@
+ #include "mozilla/UniquePtr.h"
+ 
+ #include <cstring>
+ #include <new> // for placement new
+ 
+ #include "builtin/String.h"
+ 
+ #include "js/HashTable.h"
++#include "js/UniquePtr.h"
+ #include "js/Utility.h"
+ 
+ #include "threading/ExclusiveData.h"
+ 
+ #include "vm/MutexIDs.h"
+ 
+ namespace js {
+ 
+@@ -234,28 +235,28 @@ class SharedImmutableStringsCache
+         friend class SharedImmutableString;
+ 
+         OwnedChars chars_;
+         size_t length_;
+ 
+       public:
+         mutable size_t refcount;
+ 
+-        using Ptr = mozilla::UniquePtr<StringBox, JS::DeletePolicy<StringBox>>;
++        using Ptr = js::UniquePtr<StringBox>;
+ 
+         StringBox(OwnedChars&& chars, size_t length)
+           : chars_(std::move(chars))
+           , length_(length)
+           , refcount(0)
+         {
+             MOZ_ASSERT(chars_);
+         }
+ 
+         static Ptr Create(OwnedChars&& chars, size_t length) {
+-            return Ptr(js_new<StringBox>(std::move(chars), length));
++            return js::MakeUnique<StringBox>(std::move(chars), length);
+         }
+ 
+         StringBox(const StringBox&) = delete;
+         StringBox& operator=(const StringBox&) = delete;
+ 
+         ~StringBox() {
+             MOZ_RELEASE_ASSERT(refcount == 0,
+                                "There are `SharedImmutable[TwoByte]String`s outliving their "
+diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp
+--- a/js/src/vm/UbiNode.cpp
++++ b/js/src/vm/UbiNode.cpp
+@@ -328,24 +328,24 @@ template JS::Zone* TracerConcrete<JS::Sy
+ #ifdef ENABLE_BIGINT
+ template JS::Zone* TracerConcrete<BigInt>::zone() const;
+ #endif
+ template JS::Zone* TracerConcrete<JSString>::zone() const;
+ 
+ template<typename Referent>
+ UniquePtr<EdgeRange>
+ TracerConcrete<Referent>::edges(JSContext* cx, bool wantNames) const {
+-    UniquePtr<SimpleEdgeRange, JS::DeletePolicy<SimpleEdgeRange>> range(js_new<SimpleEdgeRange>());
++    auto range = js::MakeUnique<SimpleEdgeRange>();
+     if (!range)
+         return nullptr;
+ 
+     if (!range->init(cx->runtime(), ptr, JS::MapTypeToTraceKind<Referent>::kind, wantNames))
+         return nullptr;
+ 
+-    return UniquePtr<EdgeRange>(range.release());
++    return range;
+ }
+ 
+ template UniquePtr<EdgeRange> TracerConcrete<JSScript>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::LazyScript>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::Shape>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::BaseShape>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::RegExpShared>::edges(JSContext* cx, bool wantNames) const;
+@@ -551,13 +551,13 @@ RootList::addRoot(Node node, const char1
+     return edges.append(Edge(name.release(), node));
+ }
+ 
+ const char16_t Concrete<RootList>::concreteTypeName[] = u"JS::ubi::RootList";
+ 
+ UniquePtr<EdgeRange>
+ Concrete<RootList>::edges(JSContext* cx, bool wantNames) const {
+     MOZ_ASSERT_IF(wantNames, get().wantNames);
+-    return UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges));
++    return js::MakeUnique<PreComputedEdgeRange>(get().edges);
+ }
+ 
+ } // namespace ubi
+ } // 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
+@@ -433,17 +433,17 @@ class ByObjectClass : public CountType {
+ 
+ CountBasePtr
+ ByObjectClass::makeCount()
+ {
+     CountBasePtr otherCount(otherType->makeCount());
+     if (!otherCount)
+         return nullptr;
+ 
+-    UniquePtr<Count> count(js_new<Count>(*this, otherCount));
++    auto count = js::MakeUnique<Count>(*this, otherCount);
+     if (!count || !count->init())
+         return nullptr;
+ 
+     return CountBasePtr(count.release());
+ }
+ 
+ void
+ ByObjectClass::traceCount(CountBase& countBase, JSTracer* trc)
+@@ -527,17 +527,17 @@ class ByUbinodeType : public CountType {
+     void traceCount(CountBase& countBase, JSTracer* trc) override;
+     bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
+     bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
+ };
+ 
+ CountBasePtr
+ ByUbinodeType::makeCount()
+ {
+-    UniquePtr<Count> count(js_new<Count>(*this));
++    auto count = js::MakeUnique<Count>(*this);
+     if (!count || !count->init())
+         return nullptr;
+ 
+     return CountBasePtr(count.release());
+ }
+ 
+ void
+ ByUbinodeType::traceCount(CountBase& countBase, JSTracer* trc)
+@@ -674,17 +674,17 @@ class ByAllocationStack : public CountTy
+ 
+ CountBasePtr
+ ByAllocationStack::makeCount()
+ {
+     CountBasePtr noStackCount(noStackType->makeCount());
+     if (!noStackCount)
+         return nullptr;
+ 
+-    UniquePtr<Count> count(js_new<Count>(*this, noStackCount));
++    auto count = js::MakeUnique<Count>(*this, noStackCount);
+     if (!count || !count->init())
+         return nullptr;
+     return CountBasePtr(count.release());
+ }
+ 
+ void
+ ByAllocationStack::traceCount(CountBase& countBase, JSTracer* trc)
+ {
+@@ -850,17 +850,17 @@ ByFilename::makeCount()
+     CountBasePtr thenCount(thenType->makeCount());
+     if (!thenCount)
+         return nullptr;
+ 
+     CountBasePtr noFilenameCount(noFilenameType->makeCount());
+     if (!noFilenameCount)
+         return nullptr;
+ 
+-    UniquePtr<Count> count(js_new<Count>(*this, std::move(thenCount), std::move(noFilenameCount)));
++    auto count = js::MakeUnique<Count>(*this, std::move(thenCount), std::move(noFilenameCount));
+     if (!count || !count->init())
+         return nullptr;
+ 
+     return CountBasePtr(count.release());
+ }
+ 
+ void
+ ByFilename::traceCount(CountBase& countBase, JSTracer* trc)
+diff --git a/js/src/vm/UbiNodeShortestPaths.cpp b/js/src/vm/UbiNodeShortestPaths.cpp
+--- a/js/src/vm/UbiNodeShortestPaths.cpp
++++ b/js/src/vm/UbiNodeShortestPaths.cpp
+@@ -13,17 +13,17 @@
+ #include "util/Text.h"
+ 
+ namespace JS {
+ namespace ubi {
+ 
+ JS_PUBLIC_API(BackEdge::Ptr)
+ BackEdge::clone() const
+ {
+-    BackEdge::Ptr clone(js_new<BackEdge>());
++    auto clone = js::MakeUnique<BackEdge>();
+     if (!clone)
+         return nullptr;
+ 
+     clone->predecessor_ = predecessor();
+     if (name()) {
+         clone->name_ = js::DuplicateString(name().get());
+         if (!clone->name_)
+             return nullptr;
+diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
+--- a/js/src/wasm/WasmModule.cpp
++++ b/js/src/wasm/WasmModule.cpp
+@@ -206,17 +206,17 @@ Module::startTier2(const CompileArgs& ar
+     MOZ_ASSERT(!tiering_.lock()->active);
+ 
+     // If a Module initiates tier-2 compilation, we must ensure that eventually
+     // notifyCompilationListeners() is called. Since we must ensure
+     // Tier2GeneratorTaskImpl objects are destroyed *anyway*, we use
+     // ~Tier2GeneratorTaskImpl() to call notifyCompilationListeners() if it
+     // hasn't been already.
+ 
+-    UniqueTier2GeneratorTask task(js_new<Tier2GeneratorTaskImpl>(*this, args));
++    auto task = MakeUnique<Tier2GeneratorTaskImpl>(*this, args);
+     if (!task)
+         return;
+ 
+     tiering_.lock()->active = true;
+ 
+     StartOffThreadWasmTier2Generator(std::move(task));
+ }
+ 

+ 500 - 0
frg/work-js/mozilla-release/patches/1472211-1-63a1.patch

@@ -0,0 +1,500 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1533070478 25200
+# Node ID c7d750528120ec4998cecb466bbe20f744fd2323
+# Parent  96bc6ef6437bdc79794e8725b1ebbf66598901bd
+Bug 1472211 - Part 1: Reorder super-property evaluation order per latest spec change. r=arai, f=Waldo
+
+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
+@@ -4370,23 +4370,23 @@ BytecodeEmitter::emitPropOp(ParseNode* p
+ 
+     if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+-BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall)
++BytecodeEmitter::emitSuperGetProp(ParseNode* pn, bool isCall)
+ {
+     ParseNode* base = &pn->as<PropertyAccess>().expression();
+     if (!emitSuperPropLHS(base, isCall))
+         return false;
+ 
+-    if (!emitAtomOp(pn, op))
++    if (!emitAtomOp(pn, JSOP_GETPROP_SUPER))
+         return false;
+ 
+     if (isCall && !emit1(JSOP_SWAP))
+         return false;
+ 
+     return true;
+ }
+ 
+@@ -4524,62 +4524,52 @@ BytecodeEmitter::emitElemOperands(ParseN
+     } else if (opts == EmitElemOption::Call) {
+         if (!emit1(JSOP_DUP))
+             return false;
+     }
+ 
+     if (!emitTree(pn->pn_right))
+         return false;
+ 
+-    if (opts == EmitElemOption::Set) {
+-        if (!emit2(JSOP_PICK, 2))
+-            return false;
+-    } else if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
++    if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
+         if (!emit1(JSOP_TOID))
+             return false;
+     }
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
+ {
+     MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem) && pn->as<PropertyByValue>().isSuper());
+ 
+-    // The ordering here is somewhat screwy. We need to evaluate the propval
+-    // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
+-    // Since JSOP_THIS might throw in derived class constructors, we cannot
+-    // just push it earlier as the receiver. We have to swap it down instead.
+-
+-    if (!emitTree(pn->pn_right))
++    if (!emitGetThisForSuperBase(pn->pn_left))      // THIS
++        return false;
++
++    if (!emitTree(pn->pn_right))                    // THIS KEY
+         return false;
+ 
+     // We need to convert the key to an object id first, so that we do not do
+     // it inside both the GETELEM and the SETELEM.
+     if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
+-        if (!emit1(JSOP_TOID))
+-            return false;
+-    }
+-
+-    if (!emitGetThisForSuperBase(pn->pn_left))
+-        return false;
++        if (!emit1(JSOP_TOID))                      // THIS KEY
++            return false;
++    }
+ 
+     if (opts == EmitElemOption::Call) {
+-        if (!emit1(JSOP_SWAP))
+-            return false;
+-
+-        // We need another |this| on top, also
+-        if (!emitDupAt(1))
+-            return false;
+-    }
+-
+-    if (!emit1(JSOP_SUPERBASE))
+-        return false;
+-
+-    if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
++        // We need a second |this| that will be consumed during computation of
++        // the property value. (The original |this| is passed to the call.)
++        if (!emitDupAt(1))                          // THIS KEY THIS
++            return false;
++    } else {
++        if (!emit1(JSOP_SWAP))                      // KEY THIS
++            return false;
++    }
++
++    if (!emit1(JSOP_SUPERBASE))                     // THIS? KEY THIS SUPERBASE
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitElemOpBase(JSOp op)
+ {
+@@ -4588,40 +4578,37 @@ BytecodeEmitter::emitElemOpBase(JSOp op)
+ 
+     checkTypeSet(op);
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op)
+ {
+-    EmitElemOption opts = EmitElemOption::Get;
+-    if (op == JSOP_CALLELEM)
+-        opts = EmitElemOption::Call;
+-    else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
+-        opts = EmitElemOption::Set;
++    MOZ_ASSERT(op == JSOP_GETELEM ||
++               op == JSOP_CALLELEM ||
++               op == JSOP_DELELEM ||
++               op == JSOP_STRICTDELELEM);
++
++    EmitElemOption opts = op == JSOP_CALLELEM ? EmitElemOption::Call : EmitElemOption::Get;
+ 
+     return emitElemOperands(pn, opts) && emitElemOpBase(op);
+ }
+ 
+ bool
+-BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
+-{
+-    EmitElemOption opts = EmitElemOption::Get;
+-    if (isCall)
+-        opts = EmitElemOption::Call;
+-    else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
+-        opts = EmitElemOption::Set;
+-
+-    if (!emitSuperElemOperands(pn, opts))
+-        return false;
+-    if (!emitElemOpBase(op))
+-        return false;
+-
+-    if (isCall && !emit1(JSOP_SWAP))
++BytecodeEmitter::emitSuperGetElem(ParseNode* pn, bool isCall)
++{
++    EmitElemOption opts = isCall ? EmitElemOption::Call : EmitElemOption::Get;
++
++    if (!emitSuperElemOperands(pn, opts))           // THIS? KEY THIS SUPERBASE
++        return false;
++    if (!emitElemOpBase(JSOP_GETELEM_SUPER))        // THIS? VALUE
++        return false;
++
++    if (isCall && !emit1(JSOP_SWAP))                // VALUE THIS
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
+ {
+@@ -9078,56 +9065,74 @@ BytecodeEmitter::emitDeleteName(ParseNod
+ }
+ 
+ bool
+ BytecodeEmitter::emitDeleteProperty(ParseNode* node)
+ {
+     MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteProp));
+     MOZ_ASSERT(node->isArity(PN_UNARY));
+ 
+-    ParseNode* propExpr = node->pn_kid;
+-    MOZ_ASSERT(propExpr->isKind(ParseNodeKind::Dot));
+-
+-    if (propExpr->as<PropertyAccess>().isSuper()) {
+-        // Still have to calculate the base, even though we are are going
+-        // to throw unconditionally, as calculating the base could also
+-        // throw.
++    PropertyAccess* propExpr = &node->pn_kid->as<PropertyAccess>();
++
++    if (propExpr->isSuper()) {
++        // The expression |delete super.foo;| has to evaluate |super.foo|,
++        // which could throw if |this| hasn't yet been set by a |super(...)|
++        // call or the super-base is not an object, before throwing a
++        // ReferenceError for attempting to delete a super-reference.
++        if (!emitGetThisForSuperBase(&propExpr->expression()))
++            return false;
++
+         if (!emit1(JSOP_SUPERBASE))
+             return false;
+ 
+-        return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
++        // Unconditionally throw when attempting to delete a super-reference.
++        if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
++            return false;
++
++        // Another wrinkle: Balance the stack from the emitter's point of view.
++        // Execution will not reach here, as the last bytecode threw.
++        return emit1(JSOP_POP);
+     }
+ 
+     JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
+     return emitPropOp(propExpr, delOp);
+ }
+ 
+ bool
+ BytecodeEmitter::emitDeleteElement(ParseNode* node)
+ {
+     MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteElem));
+     MOZ_ASSERT(node->isArity(PN_UNARY));
+ 
+-    ParseNode* elemExpr = node->pn_kid;
+-    MOZ_ASSERT(elemExpr->isKind(ParseNodeKind::Elem));
+-
+-    if (elemExpr->as<PropertyByValue>().isSuper()) {
+-        // Still have to calculate everything, even though we're gonna throw
+-        // since it may have side effects
++    PropertyByValue* elemExpr = &node->pn_kid->as<PropertyByValue>();
++
++    if (elemExpr->isSuper()) {
++        // The expression |delete super[foo];| has to evaluate |super[foo]|,
++        // which could throw if |this| hasn't yet been set by a |super(...)|
++        // call, or trigger side-effects when evaluating ToPropertyKey(foo),
++        // or also throw when the super-base is not an object, before throwing
++        // a ReferenceError for attempting to delete a super-reference.
++        if (!emitGetThisForSuperBase(elemExpr->pn_left))
++            return false;
++
+         if (!emitTree(elemExpr->pn_right))
+             return false;
++        if (!emit1(JSOP_TOID))
++            return false;
+ 
+         if (!emit1(JSOP_SUPERBASE))
+             return false;
++
++        // Unconditionally throw when attempting to delete a super-reference.
+         if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
+             return false;
+ 
+         // Another wrinkle: Balance the stack from the emitter's point of view.
+         // Execution will not reach here, as the last bytecode threw.
+-        return emit1(JSOP_POP);
++        return emitPopN(2);
+     }
+ 
+     JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
+     return emitElemOp(elemExpr, delOp);
+ }
+ 
+ bool
+ BytecodeEmitter::emitDeleteExpression(ParseNode* node)
+@@ -9413,28 +9418,28 @@ BytecodeEmitter::emitCallee(ParseNode* c
+     switch (callee->getKind()) {
+       case ParseNodeKind::Name:
+         if (!emitGetName(callee, *callop))
+             return false;
+         break;
+       case ParseNodeKind::Dot:
+         MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
+         if (callee->as<PropertyAccess>().isSuper()) {
+-            if (!emitSuperPropOp(callee, JSOP_GETPROP_SUPER, /* isCall = */ *callop))
++            if (!emitSuperGetProp(callee, /* isCall = */ *callop))
+                 return false;
+         } else {
+             if (!emitPropOp(callee, *callop ? JSOP_CALLPROP : JSOP_GETPROP))
+                 return false;
+         }
+ 
+         break;
+       case ParseNodeKind::Elem:
+         MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
+         if (callee->as<PropertyByValue>().isSuper()) {
+-            if (!emitSuperElemOp(callee, JSOP_GETELEM_SUPER, /* isCall = */ *callop))
++            if (!emitSuperGetElem(callee, /* isCall = */ *callop))
+                 return false;
+         } else {
+             if (!emitElemOp(callee, *callop ? JSOP_CALLELEM : JSOP_GETELEM))
+                 return false;
+             if (*callop) {
+                 if (!emit1(JSOP_SWAP))
+                     return false;
+             }
+@@ -11135,27 +11140,27 @@ BytecodeEmitter::emitTree(ParseNode* pn,
+ 
+       case ParseNodeKind::DeleteExpr:
+         if (!emitDeleteExpression(pn))
+             return false;
+         break;
+ 
+       case ParseNodeKind::Dot:
+         if (pn->as<PropertyAccess>().isSuper()) {
+-            if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
++            if (!emitSuperGetProp(pn))
+                 return false;
+         } else {
+             if (!emitPropOp(pn, JSOP_GETPROP))
+                 return false;
+         }
+         break;
+ 
+       case ParseNodeKind::Elem:
+         if (pn->as<PropertyByValue>().isSuper()) {
+-            if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
++            if (!emitSuperGetElem(pn))
+                 return false;
+         } else {
+             if (!emitElemOp(pn, JSOP_GETELEM))
+                 return false;
+         }
+         break;
+ 
+       case ParseNodeKind::New:
+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
+@@ -716,17 +716,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
+                                        bool isGenerator);
+ 
+     MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
+ 
+     // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
+     // opcode onto the stack in the right order. In the case of SETELEM, the
+     // value to be assigned must already be pushed.
+-    enum class EmitElemOption { Get, Set, Call, IncDec, CompoundAssign, Ref };
++    enum class EmitElemOption { Get, Call, IncDec, CompoundAssign, Ref };
+     MOZ_MUST_USE bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
+ 
+     MOZ_MUST_USE bool emitElemOpBase(JSOp op);
+     MOZ_MUST_USE bool emitElemOp(ParseNode* pn, JSOp op);
+     MOZ_MUST_USE bool emitElemIncDec(ParseNode* pn);
+ 
+     MOZ_MUST_USE bool emitCatch(ParseNode* pn);
+     MOZ_MUST_USE bool emitIf(ParseNode* pn);
+@@ -889,20 +889,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+     // It will pop the iterator and I, then iterate over the iterator by calling
+     // |.next()| and put the results into the I-th element of array with
+     // incrementing I, then push the result I (it will be original I +
+     // iteration count). The stack after iteration will look like |ARRAY INDEX|.
+     MOZ_MUST_USE bool emitSpread(bool allowSelfHosted = false);
+ 
+     MOZ_MUST_USE bool emitClass(ParseNode* pn);
+     MOZ_MUST_USE bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false);
+-    MOZ_MUST_USE bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
++    MOZ_MUST_USE bool emitSuperGetProp(ParseNode* pn, bool isCall = false);
+     MOZ_MUST_USE bool emitSuperElemOperands(ParseNode* pn,
+                                             EmitElemOption opts = EmitElemOption::Get);
+-    MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
++    MOZ_MUST_USE bool emitSuperGetElem(ParseNode* pn, bool isCall = false);
+ 
+     MOZ_MUST_USE bool emitCallee(ParseNode* callee, ParseNode* call, bool* callop);
+ 
+     MOZ_MUST_USE bool emitPipeline(ParseNode* pn);
+ 
+     MOZ_MUST_USE bool emitExportDefault(ParseNode* pn);
+ };
+ 
+diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list
+--- a/js/src/tests/jstests.list
++++ b/js/src/tests/jstests.list
+@@ -441,16 +441,21 @@ skip script test262/built-ins/Function/p
+ skip script test262/built-ins/Function/prototype/toString/proxy-generator-function.js
+ 
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1462741
+ skip script test262/built-ins/Function/prototype/toString/well-known-intrinsic-object-functions.js
+ 
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1462745
+ skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js
+ 
++# Remove
++# -# https://bugzilla.mozilla.org/show_bug.cgi?id=1472211
++# -skip script test262/language/statements/class/super/in-constructor-superproperty-evaluation.js
++# -
++
+ 
+ ###########################################################
+ # Tests disabled due to issues in test262 importer script #
+ ###########################################################
+ 
+ # test262 importer merges all includes in a per directory shell.js file, breaking this harness test case.
+ skip script test262/harness/detachArrayBuffer.js
+ 
+diff --git a/js/src/tests/non262/class/superElemDelete.js b/js/src/tests/non262/class/superElemDelete.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/tests/non262/class/superElemDelete.js
+@@ -0,0 +1,68 @@
++// Make sure we get the proper side effects.
++// |delete super[expr]| applies ToPropertyKey on |expr| before throwing.
++
++class base {
++    constructor() { }
++}
++
++class derived extends base {
++    constructor() { super(); }
++    testDeleteElem() {
++        let sideEffect = 0;
++        let key = {
++            toString() {
++                sideEffect++;
++                return "";
++            }
++        };
++        assertThrowsInstanceOf(() => delete super[key], ReferenceError);
++        assertEq(sideEffect, 1);
++    }
++    testDeleteElemPropValFirst() {
++        // The deletion error is a reference error, but by munging the prototype
++        // chain, we can force a type error from JSOP_SUPERBASE.
++        let key = {
++            toString() {
++                Object.setPrototypeOf(derived.prototype, null);
++                return "";
++            }
++        };
++        delete super[key];
++    }
++}
++
++class derivedTestDeleteElem extends base {
++    constructor() {
++        let sideEffect = 0;
++        let key = {
++            toString() {
++                sideEffect++;
++                return "";
++            }
++        };
++
++        assertThrowsInstanceOf(() => delete super[key], ReferenceError);
++        assertEq(sideEffect, 0);
++
++        super();
++
++        assertThrowsInstanceOf(() => delete super[key], ReferenceError);
++        assertEq(sideEffect, 1);
++
++        Object.setPrototypeOf(derivedTestDeleteElem.prototype, null);
++
++        assertThrowsInstanceOf(() => delete super[key], TypeError);
++        assertEq(sideEffect, 2);
++
++        return {};
++    }
++}
++
++var d = new derived();
++d.testDeleteElem();
++assertThrowsInstanceOf(() => d.testDeleteElemPropValFirst(), TypeError);
++
++new derivedTestDeleteElem();
++
++if (typeof reportCompare === 'function')
++    reportCompare(0,0,"OK");
+diff --git a/js/src/tests/non262/class/superPropDelete.js b/js/src/tests/non262/class/superPropDelete.js
+--- a/js/src/tests/non262/class/superPropDelete.js
++++ b/js/src/tests/non262/class/superPropDelete.js
+@@ -37,10 +37,28 @@ assertEq(Object.prototype.toString, save
+ var thing2 = {
+     go() { delete super.prop; }
+ };
+ Object.setPrototypeOf(thing2, new Proxy({}, {
+     deleteProperty(x) { throw "FAIL"; }
+ }));
+ assertThrowsInstanceOf(() => thing2.go(), ReferenceError);
+ 
++class derivedTestDeleteProp extends base {
++    constructor() {
++        // The deletion error is a reference error, but by munging the prototype
++        // chain, we can force a type error from JSOP_SUPERBASE.
++        Object.setPrototypeOf(derivedTestDeleteProp.prototype, null);
++
++        assertThrowsInstanceOf(() => delete super.prop, ReferenceError);
++
++        super();
++
++        assertThrowsInstanceOf(() => delete super.prop, TypeError);
++
++        return {};
++    }
++}
++
++new derivedTestDeleteProp();
++
+ if (typeof reportCompare === 'function')
+     reportCompare(0,0,"OK");

+ 460 - 0
frg/work-js/mozilla-release/patches/1472211-2-63a1.patch

@@ -0,0 +1,460 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1533045247 25200
+# Node ID 12ca0190aa09804aa49fd9e74331458446268060
+# Parent  c7d750528120ec4998cecb466bbe20f744fd2323
+Bug 1472211 - Part 2: Reorder operands in Super-Elem bytecode operations. 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
+@@ -2120,37 +2120,34 @@ BytecodeEmitter::emitElemOperands(ParseN
+ bool
+ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
+ {
+     MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem) && pn->as<PropertyByValue>().isSuper());
+ 
+     if (!emitGetThisForSuperBase(pn->pn_left))      // THIS
+         return false;
+ 
+-    if (!emitTree(pn->pn_right))                    // THIS KEY
++    if (opts == EmitElemOption::Call) {
++        // We need a second |this| that will be consumed during computation of
++        // the property value. (The original |this| is passed to the call.)
++        if (!emit1(JSOP_DUP))                       // THIS THIS
++            return false;
++    }
++
++    if (!emitTree(pn->pn_right))                    // THIS? THIS KEY
+         return false;
+ 
+     // We need to convert the key to an object id first, so that we do not do
+     // it inside both the GETELEM and the SETELEM.
+     if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
+-        if (!emit1(JSOP_TOID))                      // THIS KEY
+-            return false;
+-    }
+-
+-    if (opts == EmitElemOption::Call) {
+-        // We need a second |this| that will be consumed during computation of
+-        // the property value. (The original |this| is passed to the call.)
+-        if (!emitDupAt(1))                          // THIS KEY THIS
+-            return false;
+-    } else {
+-        if (!emit1(JSOP_SWAP))                      // KEY THIS
+-            return false;
+-    }
+-
+-    if (!emit1(JSOP_SUPERBASE))                     // THIS? KEY THIS SUPERBASE
++        if (!emit1(JSOP_TOID))                      // THIS? THIS KEY
++            return false;
++    }
++
++    if (!emit1(JSOP_SUPERBASE))                     // THIS? THIS KEY SUPERBASE
+         return false;
+ 
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitElemOpBase(JSOp op)
+ {
+@@ -2174,17 +2171,17 @@ BytecodeEmitter::emitElemOp(ParseNode* p
+     return emitElemOperands(pn, opts) && emitElemOpBase(op);
+ }
+ 
+ bool
+ BytecodeEmitter::emitSuperGetElem(ParseNode* pn, bool isCall)
+ {
+     EmitElemOption opts = isCall ? EmitElemOption::Call : EmitElemOption::Get;
+ 
+-    if (!emitSuperElemOperands(pn, opts))           // THIS? KEY THIS SUPERBASE
++    if (!emitSuperElemOperands(pn, opts))           // THIS? THIS KEY SUPERBASE
+         return false;
+     if (!emitElemOpBase(JSOP_GETELEM_SUPER))        // THIS? VALUE
+         return false;
+ 
+     if (isCall && !emit1(JSOP_SWAP))                // VALUE THIS
+         return false;
+ 
+     return true;
+@@ -2210,54 +2207,43 @@ BytecodeEmitter::emitElemIncDec(ParseNod
+ 
+     bool post;
+     JSOp binop = GetIncDecInfo(pn->getKind(), &post);
+ 
+     JSOp getOp;
+     if (isSuper) {
+         // There's no such thing as JSOP_DUP3, so we have to be creative.
+         // Note that pushing things again is no fewer JSOps.
+-        if (!emitDupAt(2))                              // KEY THIS OBJ KEY
+-            return false;
+-        if (!emitDupAt(2))                              // KEY THIS OBJ KEY THIS
+-            return false;
+-        if (!emitDupAt(2))                              // KEY THIS OBJ KEY THIS OBJ
++        if (!emitDupAt(2))                              // THIS KEY OBJ THIS
++            return false;
++        if (!emitDupAt(2))                              // THIS KEY OBJ THIS KEY
++            return false;
++        if (!emitDupAt(2))                              // THIS KEY OBJ THIS KEY OBJ
+             return false;
+         getOp = JSOP_GETELEM_SUPER;
+     } else {
+                                                         // OBJ KEY
+         if (!emit1(JSOP_DUP2))                          // OBJ KEY OBJ KEY
+             return false;
+         getOp = JSOP_GETELEM;
+     }
+     if (!emitElemOpBase(getOp))                         // OBJ KEY V
+         return false;
+     if (!emit1(JSOP_POS))                               // OBJ KEY N
+         return false;
+-    if (post && !emit1(JSOP_DUP))                       // OBJ KEY N? N
+-        return false;
+-    if (!emit1(JSOP_ONE))                               // OBJ KEY N? N 1
+-        return false;
+-    if (!emit1(binop))                                  // OBJ KEY N? N+1
+-        return false;
+-
+     if (post) {
+-        if (isSuper) {
+-            // We have one more value to rotate around, because of |this|
+-            // on the stack
+-            if (!emit2(JSOP_PICK, 4))
+-                return false;
+-        }
+-        if (!emit2(JSOP_PICK, 3 + isSuper))             // KEY N N+1 OBJ
+-            return false;
+-        if (!emit2(JSOP_PICK, 3 + isSuper))             // N N+1 OBJ KEY
+-            return false;
+-        if (!emit2(JSOP_PICK, 2 + isSuper))             // N OBJ KEY N+1
+-            return false;
+-    }
++        if (!emit1(JSOP_DUP))                           // OBJ KEY N N
++            return false;
++        if (!emit2(JSOP_UNPICK, 3 + isSuper))           // N OBJ KEY N
++            return false;
++    }
++    if (!emit1(JSOP_ONE))                               // N? OBJ KEY N 1
++        return false;
++    if (!emit1(binop))                                  // N? OBJ KEY N+1
++        return false;
+ 
+     JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
+                          : (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
+     if (!emitElemOpBase(setOp))                         // N? N+1
+         return false;
+     if (post && !emit1(JSOP_POP))                       // RESULT
+         return false;
+ 
+@@ -6754,22 +6740,22 @@ BytecodeEmitter::emitSelfHostedGetProper
+     }
+ 
+     ParseNode* funNode = pn->pn_head;  // The getPropertySuper node.
+ 
+     ParseNode* objNode = funNode->pn_next;
+     ParseNode* idNode = objNode->pn_next;
+     ParseNode* receiverNode = idNode->pn_next;
+ 
++    if (!emitTree(receiverNode))
++        return false;
++
+     if (!emitTree(idNode))
+         return false;
+ 
+-    if (!emitTree(receiverNode))
+-        return false;
+-
+     if (!emitTree(objNode))
+         return false;
+ 
+     return emitElemOpBase(JSOP_GETELEM_SUPER);
+ }
+ 
+ bool
+ BytecodeEmitter::isRestParameter(ParseNode* pn)
+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
+@@ -2298,17 +2298,17 @@ BaselineCompiler::emit_JSOP_GETELEM()
+ 
+ bool
+ BaselineCompiler::emit_JSOP_GETELEM_SUPER()
+ {
+     // Store obj in the scratch slot.
+     storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
+     frame.pop();
+ 
+-    // Keep index and receiver in R0 and R1.
++    // Keep receiver and index in R0 and R1.
+     frame.popRegsAndSync(2);
+ 
+     // Keep obj on the stack.
+     frame.pushScratchValue();
+ 
+     ICGetElem_Fallback::Compiler stubCompiler(cx, /* hasReceiver = */ true);
+     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
+         return false;
+@@ -2351,31 +2351,31 @@ BaselineCompiler::emit_JSOP_STRICTSETELE
+     return emit_JSOP_SETELEM();
+ }
+ 
+ bool
+ BaselineCompiler::emit_JSOP_SETELEM_SUPER()
+ {
+     bool strict = IsCheckStrictOp(JSOp(*pc));
+ 
+-    // Incoming stack is |propval, receiver, obj, rval|. We need to shuffle
++    // Incoming stack is |receiver, propval, obj, rval|. We need to shuffle
+     // stack to leave rval when operation is complete.
+ 
+-    // Pop rval into R0, then load propval into R1 and replace with rval.
++    // Pop rval into R0, then load receiver into R1 and replace with rval.
+     frame.popRegsAndSync(1);
+     masm.loadValue(frame.addressOfStackValue(frame.peek(-3)), R1);
+     masm.storeValue(R0, frame.addressOfStackValue(frame.peek(-3)));
+ 
+     prepareVMCall();
+ 
+     pushArg(Imm32(strict));
+-    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R2);
+-    pushArg(R2); // receiver
++    pushArg(R1); // receiver
+     pushArg(R0); // rval
+-    pushArg(R1); // propval
++    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
++    pushArg(R0); // propval
+     masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+     pushArg(R0.scratchReg()); // obj
+ 
+     if (!callVM(SetObjectElementInfo))
+         return false;
+ 
+     frame.popn(2);
+     return true;
+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
+@@ -634,17 +634,17 @@ DoGetElemFallback(JSContext* cx, Baselin
+     if (!attached && !isTemporarilyUnoptimizable)
+         stub->noteUnoptimizableAccess();
+ 
+     return true;
+ }
+ 
+ static bool
+ DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_,
+-                       HandleValue lhs, HandleValue receiver, HandleValue rhs,
++                       HandleValue lhs, HandleValue rhs, HandleValue receiver,
+                        MutableHandleValue res)
+ {
+     // This fallback stub may trigger debug mode toggling.
+     DebugModeOSRVolatileStub<ICGetElem_Fallback*> stub(frame, stub_);
+ 
+     RootedScript script(cx, frame->script());
+     jsbytecode* pc = stub->icEntry()->pc(frame->script());
+     StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+@@ -729,27 +729,27 @@ ICGetElem_Fallback::Compiler::generateSt
+     MOZ_ASSERT(engine_ == Engine::Baseline);
+     MOZ_ASSERT(R0 == JSReturnOperand);
+ 
+     // Restore the tail call register.
+     EmitRestoreTailCallReg(masm);
+ 
+     // Super property getters use a |this| that differs from base object
+     if (hasReceiver_) {
+-        // State: index in R0, receiver in R1, obj on the stack
++        // State: receiver in R0, index in R1, obj on the stack
+ 
+         // Ensure stack is fully synced for the expression decompiler.
+-        // We need: index, receiver, obj
++        // We need: receiver, index, obj
+         masm.pushValue(R0);
+         masm.pushValue(R1);
+         masm.pushValue(Address(masm.getStackPointer(), sizeof(Value) * 2));
+ 
+         // Push arguments.
+-        masm.pushValue(R0); // Index
+-        masm.pushValue(R1); // Reciver
++        masm.pushValue(R0); // Receiver
++        masm.pushValue(R1); // Index
+         masm.pushValue(Address(masm.getStackPointer(), sizeof(Value) * 5)); // Obj
+         masm.push(ICStubReg);
+         pushStubPayload(masm, R0.scratchReg());
+ 
+         return tailCallVM(DoGetElemSuperFallbackInfo, masm);
+     }
+ 
+     // Ensure stack is fully synced for the expression decompiler.
+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
+@@ -9760,18 +9760,18 @@ IonBuilder::jsop_getprop_super(PropertyN
+     TemporaryTypeSet* types = bytecodeTypes(pc);
+     return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
+ }
+ 
+ AbortReasonOr<Ok>
+ IonBuilder::jsop_getelem_super()
+ {
+     MDefinition* obj = current->pop();
++    MDefinition* id = current->pop();
+     MDefinition* receiver = current->pop();
+-    MDefinition* id = current->pop();
+ 
+ #if defined(JS_CODEGEN_X86)
+     if (instrumentedProfiling())
+         return abort(AbortReason::Disable, "profiling functions with GETELEM_SUPER is disabled on x86");
+ #endif
+ 
+     auto* ins = MGetPropSuperCache::New(alloc(), obj, receiver, id);
+     current->add(ins);
+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
+@@ -1794,17 +1794,17 @@ ExpressionDecompiler::decompilePC(jsbyte
+                write("[") &&
+                decompilePCForStackOperand(pc, -1) &&
+                write("]") &&
+                (hasDelete ? write(")") : true);
+       }
+ 
+       case JSOP_GETELEM_SUPER:
+         return write("super[") &&
+-               decompilePCForStackOperand(pc, -3) &&
++               decompilePCForStackOperand(pc, -2) &&
+                write("]");
+       case JSOP_NULL:
+         return write(js_null_str);
+       case JSOP_TRUE:
+         return write(js_true_str);
+       case JSOP_FALSE:
+         return write(js_false_str);
+       case JSOP_ZERO:
+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
+@@ -3078,18 +3078,18 @@ CASE(JSOP_CALLELEM)
+ 
+     TypeScript::Monitor(cx, script, REGS.pc, res);
+     REGS.sp--;
+ }
+ END_CASE(JSOP_GETELEM)
+ 
+ CASE(JSOP_GETELEM_SUPER)
+ {
+-    ReservedRooted<Value> rval(&rootValue0, REGS.sp[-3]);
+-    ReservedRooted<Value> receiver(&rootValue1, REGS.sp[-2]);
++    ReservedRooted<Value> receiver(&rootValue1, REGS.sp[-3]);
++    ReservedRooted<Value> rval(&rootValue0, REGS.sp[-2]);
+     ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
+ 
+     MutableHandleValue res = REGS.stackHandleAt(-3);
+ 
+     // Since we have asserted that obj has to be an object, it cannot be
+     // either optimized arguments, or indeed any primitive. This simplifies
+     // our task some.
+     if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, rval, res))
+@@ -3121,18 +3121,18 @@ CASE(JSOP_STRICTSETELEM)
+ END_CASE(JSOP_SETELEM)
+ 
+ CASE(JSOP_SETELEM_SUPER)
+ CASE(JSOP_STRICTSETELEM_SUPER)
+ {
+     static_assert(JSOP_SETELEM_SUPER_LENGTH == JSOP_STRICTSETELEM_SUPER_LENGTH,
+                   "setelem-super and strictsetelem-super must be the same size");
+ 
+-    ReservedRooted<Value> index(&rootValue1, REGS.sp[-4]);
+-    ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
++    ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-4]);
++    ReservedRooted<Value> index(&rootValue1, REGS.sp[-3]);
+     ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-2].toObject());
+     HandleValue value = REGS.stackHandleAt(-1);
+ 
+     bool strict = JSOp(*REGS.pc) == JSOP_STRICTSETELEM_SUPER;
+     if (!SetObjectElement(cx, obj, index, value, receiver, strict))
+         goto error;
+     REGS.sp[-4] = value;
+     REGS.sp -= 3;
+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
+@@ -533,27 +533,27 @@ 1234567890123456789012345678901234567890
+      *   Category: Literals
+      *   Type: Object
+      *   Operands:
+      *   Stack: obj, propval => obj[propval]
+      */ \
+     macro(JSOP_GETELEM,   55, "getelem",    NULL,         1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+     /*
+      * Pops the top three values on the stack as 'val', 'propval' and 'obj',
+-     * sets 'propval' property of 'obj' as 'val', pushes 'obj' onto the
++     * sets 'propval' property of 'obj' as 'val', pushes 'val' onto the
+      * stack.
+      *   Category: Literals
+      *   Type: Object
+      *   Operands:
+      *   Stack: obj, propval, val => val
+      */ \
+     macro(JSOP_SETELEM,   56, "setelem",    NULL,         1,  3,  1, JOF_BYTE |JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+     /*
+      * Pops the top three values on the stack as 'val', 'propval' and 'obj',
+-     * sets 'propval' property of 'obj' as 'val', pushes 'obj' onto the
++     * sets 'propval' property of 'obj' as 'val', pushes 'val' onto the
+      * stack. Throws a TypeError if the set fails, per strict mode
+      * semantics.
+      *   Category: Literals
+      *   Type: Object
+      *   Operands:
+      *   Stack: obj, propval, val => val
+      */ \
+     macro(JSOP_STRICTSETELEM,   57, "strict-setelem",    NULL,         1,  3,  1, JOF_BYTE |JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT) \
+@@ -1276,17 +1276,17 @@ 1234567890123456789012345678901234567890
+      */ \
+     macro(JSOP_STRICTEVAL,       124, "strict-eval",       NULL,         3, -1,  1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT) \
+     /*
+      * LIKE JSOP_GETELEM but takes receiver on stack, and the propval is
+      * evaluated before the obj.
+      *   Category: Literals
+      *   Type: Object
+      *   Operands:
+-     *   Stack: propval, receiver, obj => obj[propval]
++     *   Stack: receiver, propval, obj => obj[propval]
+      */ \
+     macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+     macro(JSOP_UNUSED126, 126, "unused126", NULL, 5,  0,  1, JOF_UINT32) \
+     \
+     /*
+      * Defines the given function on the current scope.
+      *
+      * This is used for global scripts and also in some cases for function
+@@ -1634,26 +1634,26 @@ 1234567890123456789012345678901234567890
+      */                                                                 \
+     macro(JSOP_GIMPLICITTHIS, 157, "gimplicitthis", "",      5,  0,  1,  JOF_ATOM) \
+     /*
+      * LIKE JSOP_SETELEM, but takes receiver on the stack, and the propval is
+      * evaluated before the base.
+      *   Category: Literals
+      *   Type: Object
+      *   Operands:
+-     *   Stack: propval, receiver, obj, val => val
++     *   Stack: receiver, propval, obj, val => val
+      */ \
+     macro(JSOP_SETELEM_SUPER,   158, "setelem-super", NULL, 1,  4,  1, JOF_BYTE |JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+     /*
+      * LIKE JSOP_STRICTSETELEM, but takes receiver on the stack, and the
+      * propval is evaluated before the base.
+      *   Category: Literals
+      *   Type: Object
+      *   Operands:
+-     *   Stack: propval, receiver, obj, val => val
++     *   Stack: receiver, propval, obj, val => val
+      */ \
+     macro(JSOP_STRICTSETELEM_SUPER, 159, "strict-setelem-super", NULL, 1,  4, 1, JOF_BYTE |JOF_ELEM|JOF_PROPSET|JOF_DETECTING|JOF_CHECKSTRICT) \
+     \
+     /*
+      * Pushes a regular expression literal onto the stack.
+      * It requires special "clone on exec" handling.
+      *   Category: Literals
+      *   Type: RegExp
+

+ 51 - 0
frg/work-js/mozilla-release/patches/1472291-1-63a1.patch

@@ -0,0 +1,51 @@
+# HG changeset patch
+# User Logan Smyth <loganfsmyth@gmail.com>
+# Date 1530651136 25200
+# Node ID b4a8e7ca6bcdd112df1a1ffe7dc851e991d2fd53
+# Parent  a6dc6d6f4df1516707df4d06b01704ead35a1d5c
+Bug 1472291 - Fix two small typos. r=jorendorff
+
+MozReview-Commit-ID: GPC0WF4PLpx
+
+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
+@@ -1450,17 +1450,17 @@ 1234567890123456789012345678901234567890
+      *   Operands: uint8_t hops, uint24_t slot
+      *   Stack: v => v
+      */ \
+     macro(JSOP_INITALIASEDLEXICAL,  141, "initaliasedlexical",  NULL, 5,  1,  1, JOF_ENVCOORD|JOF_NAME|JOF_PROPINIT|JOF_DETECTING) \
+     /*
+      * Pushes a JS_UNINITIALIZED_LEXICAL value onto the stack, representing an
+      * uninitialized lexical binding.
+      *
+-     * This opcode is used with the JSOP_INITLET opcode.
++     * This opcode is used with the JSOP_INITLEXICAL opcode.
+      *   Category: Literals
+      *   Type: Constants
+      *   Operands:
+      *   Stack: => uninitialized
+      */ \
+     macro(JSOP_UNINITIALIZED, 142, "uninitialized", NULL, 1,  0,  1, JOF_BYTE) \
+     /* Pushes the value of the intrinsic onto the stack.
+      *
+@@ -2020,17 +2020,17 @@ 1234567890123456789012345678901234567890
+      *   Operands:
+      *   Stack: val => (typeof val)
+      */ \
+     macro(JSOP_TYPEOFEXPR,    196,"typeofexpr",  NULL,    1,  1,  1, JOF_BYTE|JOF_DETECTING) \
+     \
+     /* Lexical environment support. */ \
+     /*
+      * Replaces the current block on the env chain with a fresh block
+-     * that copies all the bindings in the bock.  This operation implements the
++     * that copies all the bindings in the block.  This operation implements the
+      * behavior of inducing a fresh lexical environment for every iteration of a
+      * for(let ...; ...; ...) loop, if any declarations induced by such a loop
+      * are captured within the loop.
+      *   Category: Variables and Scopes
+      *   Type: Block-local Scope
+      *   Operands:
+      *   Stack: =>
+      */ \
+

+ 454 - 0
frg/work-js/mozilla-release/patches/1472291-2-63a1.patch

@@ -0,0 +1,454 @@
+# HG changeset patch
+# User Logan Smyth <loganfsmyth@gmail.com>
+# Date 1530654332 25200
+# Node ID a1757187c5a9a6892bc28309567bceb5fdca3798
+# Parent  26a71aac5afc85de6ac7a8f0f602f35b659d5866
+Bug 1472291 - Ensure that if, switch, do-while, with, break, and continue statements have column offsets. r=jorendorff
+
+MozReview-Commit-ID: J1RL0xbW0qR
+
+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
+@@ -4735,16 +4735,20 @@ BytecodeEmitter::emitNumberOp(double dva
+  */
+ MOZ_NEVER_INLINE bool
+ BytecodeEmitter::emitSwitch(ParseNode* pn)
+ {
+     ParseNode* cases = pn->pn_right;
+     MOZ_ASSERT(cases->isKind(ParseNodeKind::LexicalScope) ||
+                cases->isKind(ParseNodeKind::StatementList));
+ 
++    // Ensure that the column of the switch statement is set properly.
++    if (!updateSourceCoordNotes(pn->pn_pos.begin))
++        return false;
++
+     // Emit code for the discriminant.
+     if (!emitTree(pn->pn_left))
+         return false;
+ 
+     // Enter the scope before pushing the switch BreakableControl since all
+     // breaks are under this scope.
+     Maybe<TDZCheckCache> tdzCache;
+     Maybe<EmitterScope> emitterScope;
+@@ -6994,16 +6998,21 @@ BytecodeEmitter::emitTry(ParseNode* pn)
+ }
+ 
+ bool
+ BytecodeEmitter::emitIf(ParseNode* pn)
+ {
+     IfEmitter ifThenElse(this);
+ 
+   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;
+@@ -7124,16 +7133,20 @@ BytecodeEmitter::emitLexicalScope(ParseN
+     }
+ 
+     return emitterScope.leave(this);
+ }
+ 
+ bool
+ BytecodeEmitter::emitWith(ParseNode* pn)
+ {
++    // Ensure that the column of the 'with' is set properly.
++    if (!updateSourceCoordNotes(pn->pn_pos.begin))
++        return false;
++
+     if (!emitTree(pn->pn_left))
+         return false;
+ 
+     EmitterScope emitterScope(this);
+     if (!emitterScope.enterWith(this))
+         return false;
+ 
+     if (!emitTree(pn->pn_right))
+@@ -8262,16 +8275,20 @@ BytecodeEmitter::emitAsyncWrapper(unsign
+             return false;
+     }
+     return true;
+ }
+ 
+ bool
+ BytecodeEmitter::emitDo(ParseNode* pn)
+ {
++    // Ensure that the column of the 'do' is set properly.
++    if (!updateSourceCoordNotes(pn->pn_pos.begin))
++        return false;
++
+     /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
+     unsigned noteIndex;
+     if (!newSrcNote(SRC_WHILE, &noteIndex))
+         return false;
+     if (!emit1(JSOP_NOP))
+         return false;
+ 
+     unsigned noteIndex2;
+@@ -10933,21 +10950,29 @@ BytecodeEmitter::emitTree(ParseNode* pn,
+         break;
+ 
+       case ParseNodeKind::For:
+         if (!emitFor(pn))
+             return false;
+         break;
+ 
+       case ParseNodeKind::Break:
++        // Ensure that the column of the 'break' is set properly.
++        if (!updateSourceCoordNotes(pn->pn_pos.begin))
++            return false;
++
+         if (!emitBreak(pn->as<BreakStatement>().label()))
+             return false;
+         break;
+ 
+       case ParseNodeKind::Continue:
++        // Ensure that the column of the 'continue' is set properly.
++        if (!updateSourceCoordNotes(pn->pn_pos.begin))
++            return false;
++
+         if (!emitContinue(pn->as<ContinueStatement>().label()))
+             return false;
+         break;
+ 
+       case ParseNodeKind::With:
+         if (!emitWith(pn))
+             return false;
+         break;
+diff --git a/js/src/jit-test/lib/assert-offset-columns.js b/js/src/jit-test/lib/assert-offset-columns.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/lib/assert-offset-columns.js
+@@ -0,0 +1,74 @@
++// Set breakpoints "everywhere" in a function, then call the function and check that
++// the breakpoints were added are at the expected columns, and the breakpoints
++// were executed in th expected order.
++//
++// `code` is a JS Script. The final line should define a function `f` to validate.
++// `expectedBpts` is a string of spaces and carets ('^'). Throws if we don't hit
++// breakpoints on exactly the columns indicated by the carets.
++// `expectedOrdering` is a string of integer indices for the offsets that are
++// executed, in the order that then are executed. Test code can also push
++// additional items into this string using items.push("!").
++function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) {
++    if (expectedOrdering === null) {
++        // The default ordering simply runs the breakpoints in order.
++        expectedOrdering = Array.from(expectedBpts.match(/\^/g), (_, i) => i).join(" ");
++    }
++
++    // Define the function `f` in a new global.
++    const global = newGlobal();
++
++    const lines = code.split(/\r?\n|\r]/g);
++    const initCode = lines.slice(0, -1).join("\n");
++    const execCode = lines[lines.length - 1];
++
++    // Treat everything but the last line as initialization code.
++    global.eval(initCode);
++
++    // Run the test code itself.
++    global.eval(execCode);
++
++    // Allow some tests to append to a log that will show up in expected ordering.
++    const hits = global.hits = [];
++    const bpts = new Set();
++
++    // Set breakpoints everywhere and call the function.
++    const dbg = new Debugger;
++    const script = dbg.addDebuggee(global).makeDebuggeeValue(global.f).script;
++    for (const offset of script.getAllColumnOffsets()) {
++        assertEq(offset.lineNumber, 1);
++        assertEq(offset.columnNumber < execCode.length, true);
++        bpts.add(offset.columnNumber);
++
++        script.setBreakpoint(offset.offset, {
++            hit(frame) {
++                hits.push(offset.columnNumber);
++            },
++        });
++    }
++    global.f(3);
++
++    const actualBpts = Array.from(execCode, (_, i) => {
++        return bpts.has(i) ? "^" : " ";
++    }).join("");
++
++    if (actualBpts.trimEnd() !== expectedBpts.trimEnd()) {
++        throw new Error(`Assertion failed:
++                     code: ${execCode}
++            expected bpts: ${expectedBpts}
++              actual bpts: ${actualBpts}\n`);
++    }
++
++    const indexLookup = new Map(
++        Array.from(bpts).sort().map((col, i) => [col, i]));
++    const actualOrdering = hits
++        .map(item => typeof item === "number" ? indexLookup.get(item) : item)
++        .join(" ");
++
++    if (actualOrdering.trimEnd() !== expectedOrdering.trimEnd()) {
++        throw new Error(`Assertion failed:
++                     code: ${execCode}
++                     bpts: ${expectedBpts}
++           expected order: ${expectedOrdering}
++             actual order: ${actualOrdering}\n`);
++    }
++}
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-01.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-01.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-01.js
++++ /dev/null
+@@ -1,19 +0,0 @@
+-// getColumnOffsets correctly places the various parts of a ForStatement.
+-
+-var global = newGlobal();
+-Debugger(global).onDebuggerStatement = function (frame) {
+-    var script = frame.eval("f").return.script;
+-    script.getAllColumnOffsets().forEach(function (offset) {
+-        script.setBreakpoint(offset.offset, {
+-            hit: function (frame) {
+-                assertEq(offset.lineNumber, 1);
+-                global.log += offset.columnNumber + " ";
+-            }
+-        });
+-    });
+-};
+-
+-global.log = '';
+-global.eval("function f(n) { for (var i = 0; i < n; ++i) log += '. '; log += '! '; } debugger;");
+-global.f(3);
+-assertEq(global.log, "25 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 70 ");
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-02.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-02.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-02.js
++++ /dev/null
+@@ -1,21 +0,0 @@
+-// getColumnOffsets correctly places multiple variable declarations.
+-
+-var global = newGlobal();
+-Debugger(global).onDebuggerStatement = function (frame) {
+-    var script = frame.eval("f").return.script;
+-    script.getAllColumnOffsets().forEach(function (offset) {
+-        script.setBreakpoint(offset.offset, {
+-            hit: function (frame) {
+-                assertEq(offset.lineNumber, 1);
+-                global.log += offset.columnNumber + " ";
+-            }
+-        });
+-    });
+-};
+-
+-global.log = '';
+-global.eval("function f(n){var w0,x1=3,y2=4,z3=9} debugger;");
+-global.f(3);
+-
+-// Should have hit each variable declared.
+-assertEq(global.log, "21 26 31 35 ");
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-03.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-03.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-03.js
++++ /dev/null
+@@ -1,20 +0,0 @@
+-// getColumnOffsets correctly places comma separated expressions.
+-
+-var global = newGlobal();
+-Debugger(global).onDebuggerStatement = function (frame) {
+-    var script = frame.eval("f").return.script;
+-    script.getAllColumnOffsets().forEach(function (offset) {
+-        script.setBreakpoint(offset.offset, {
+-            hit: function (frame) {
+-                assertEq(offset.lineNumber, 1);
+-                global.log += offset.columnNumber + " ";
+-            }
+-        });
+-    });
+-};
+-
+-global.log = '';
+-global.eval("function f(n){print(n),print(n),print(n)} debugger;");
+-global.f(3);
+-// Should hit each call that was separated by commas.
+-assertEq(global.log, "14 23 32 40 ");
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-04.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-04.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-04.js
++++ /dev/null
+@@ -1,20 +0,0 @@
+-// getColumnOffsets correctly places object properties.
+-
+-var global = newGlobal();
+-Debugger(global).onDebuggerStatement = function (frame) {
+-    var script = frame.eval("f").return.script;
+-    script.getAllColumnOffsets().forEach(function (offset) {
+-        script.setBreakpoint(offset.offset, {
+-            hit: function (frame) {
+-                assertEq(offset.lineNumber, 1);
+-                global.log += offset.columnNumber + " ";
+-            }
+-        });
+-    });
+-};
+-
+-global.log = '';
+-global.eval("function f(n){var o={a:1,b:2,c:3}} debugger;");
+-global.f(3);
+-// Should hit each property in the object.
+-assertEq(global.log, "18 21 25 29 33 ");
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-05.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-05.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-05.js
++++ /dev/null
+@@ -1,20 +0,0 @@
+-// getColumnOffsets correctly places array properties.
+-
+-var global = newGlobal();
+-Debugger(global).onDebuggerStatement = function (frame) {
+-    var script = frame.eval("f").return.script;
+-    script.getAllColumnOffsets().forEach(function (offset) {
+-        script.setBreakpoint(offset.offset, {
+-            hit: function (frame) {
+-                assertEq(offset.lineNumber, 1);
+-                global.log += offset.columnNumber + " ";
+-            }
+-        });
+-    });
+-};
+-
+-global.log = '';
+-global.eval("function f(n){var a=[1,2,n]} debugger;");
+-global.f(3);
+-// Should hit each item in the array.
+-assertEq(global.log, "18 21 23 25 27 ");
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-06.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-06.js
+deleted file mode 100644
+--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-06.js
++++ /dev/null
+@@ -1,28 +0,0 @@
+-// getColumnOffsets correctly places function calls.
+-
+-var global = newGlobal();
+-Debugger(global).onDebuggerStatement = function (frame) {
+-    var script = frame.eval("f").return.script;
+-    script.getAllColumnOffsets().forEach(function (offset) {
+-        script.setBreakpoint(offset.offset, {
+-            hit: function (frame) {
+-                assertEq(offset.lineNumber, 1);
+-                global.log += offset.columnNumber + " ";
+-            }
+-        });
+-    });
+-};
+-
+-global.log = "";
+-global.eval("function ppppp() { return 1; }");
+-//                     1         2         3         4
+-//           01234567890123456789012345678901234567890123456789
+-global.eval("function f(){ 1 && ppppp(ppppp()) && new Error() } debugger;");
+-global.f();
+-
+-// 14 - Enter the function body
+-// 25 - Inner print()
+-// 19 - Outer print()
+-// 37 - new Error()
+-// 49 - Exit the function body
+-assertEq(global.log, "14 25 19 37 49 ");
+diff --git a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets.js b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets.js
+@@ -0,0 +1,85 @@
++load(libdir + "assert-offset-columns.js");
++
++// getColumnOffsets correctly places the various parts of a ForStatement.
++assertOffsetColumns(
++    "function f(n) { for (var i = 0; i < n; ++i) hits.push('.'); hits.push('!'); }",
++    "                         ^      ^      ^    ^               ^               ^",
++    "0 1 3 . 2 1 3 . 2 1 3 . 2 1 4 ! 5",
++);
++
++// getColumnOffsets correctly places multiple variable declarations.
++assertOffsetColumns(
++    "function f(n){var w0,x1=3,y2=4,z3=9}",
++    "                     ^    ^    ^   ^",
++);
++
++// getColumnOffsets correctly places comma separated expressions.
++assertOffsetColumns(
++    "function f(n){print(n),print(n),print(n)}",
++    "              ^        ^        ^       ^",
++);
++
++// getColumnOffsets correctly places object properties.
++assertOffsetColumns(
++    // Should hit each property in the object.
++    "function f(n){var o={a:1,b:2,c:3}}",
++    "                  ^  ^   ^   ^   ^",
++);
++
++// getColumnOffsets correctly places array properties.
++assertOffsetColumns(
++    // Should hit each item in the array.
++    "function f(n){var a=[1,2,n]}",
++    "                  ^  ^ ^ ^ ^",
++);
++
++// getColumnOffsets correctly places function calls.
++assertOffsetColumns(
++    "function ppppp() { return 1; }\n" +
++    "function f(){ 1 && ppppp(ppppp()) && new Error() }",
++    "              ^    ^     ^           ^           ^",
++    "0 2 1 3 4",
++);
++
++// getColumnOffsets correctly places the various parts of a SwitchStatement.
++assertOffsetColumns(
++    "function f(n) { switch(n) { default: print(n); } }",
++    "                ^                    ^           ^",
++);
++
++// getColumnOffsets correctly places the various parts of a BreakStatement.
++assertOffsetColumns(
++    "function f(n) { do { print(n); break; } while(false); }",
++    "                ^    ^         ^                      ^",
++);
++
++// getColumnOffsets correctly places the various parts of a ContinueStatement.
++assertOffsetColumns(
++    "function f(n) { do { print(n); continue; } while(false); }",
++    "                ^    ^         ^                         ^",
++);
++
++// getColumnOffsets correctly places the various parts of a WithStatement.
++assertOffsetColumns(
++    "function f(n) { with({}) { print(n); } }",
++    "                ^          ^           ^",
++);
++
++// getColumnOffsets correctly places the various parts of a IfStatement.
++assertOffsetColumns(
++    "function f(n) { if (n == 3) print(n); }",
++    "                ^           ^         ^",
++);
++
++// getColumnOffsets correctly places the various parts of a IfStatement
++// with an if/else
++assertOffsetColumns(
++    "function f(n) { if (n == 2); else if (n === 3) print(n); }",
++    "                ^                 ^            ^         ^",
++);
++
++// getColumnOffsets correctly places the various parts of a DoWhileStatement.
++assertOffsetColumns(
++    "function f(n) { do { print(n); } while(false); }",
++    "                ^    ^                         ^",
++);

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

@@ -0,0 +1,33 @@
+# HG changeset patch
+# User Andre Bargull <andre.bargull@gmail.com>
+# Date 1530722689 25200
+# Node ID a5edd04dc60653208eb320899595725354f15591
+# Parent  cea2eefe9e5dc7e5bcf29bdf995cc1cb661e1311
+Bug 1472666: Fix UbiNode compilation for Clang 3.8 or older. r=Waldo
+
+diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp
+--- a/js/src/vm/UbiNode.cpp
++++ b/js/src/vm/UbiNode.cpp
+@@ -335,17 +335,20 @@ UniquePtr<EdgeRange>
+ TracerConcrete<Referent>::edges(JSContext* cx, bool wantNames) const {
+     auto range = js::MakeUnique<SimpleEdgeRange>();
+     if (!range)
+         return nullptr;
+ 
+     if (!range->init(cx->runtime(), ptr, JS::MapTypeToTraceKind<Referent>::kind, wantNames))
+         return nullptr;
+ 
+-    return range;
++    // Note: Clang 3.8 (or older) require an explicit construction of the
++    // target UniquePtr type. When we no longer require to support these Clang
++    // versions the return statement can be simplified to |return range;|.
++    return UniquePtr<EdgeRange>(range.release());
+ }
+ 
+ template UniquePtr<EdgeRange> TracerConcrete<JSScript>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::LazyScript>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::Shape>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::BaseShape>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext* cx, bool wantNames) const;
+ template UniquePtr<EdgeRange> TracerConcrete<js::RegExpShared>::edges(JSContext* cx, bool wantNames) const;
+

+ 99 - 0
frg/work-js/mozilla-release/patches/1472734-63a1.patch

@@ -0,0 +1,99 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1531388136 -3600
+# Node ID e72e7f5db9a668895f1081050e8ecb33a480de16
+# Parent  736469ed0fdd60b5d4448a968397be9e34498313
+Bug 1472734 - Allow ClearEdgesTracer when GC tracer is required to accomodate GCManagedDeletePolicy during sweeping r=sfink a=abillings
+
+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
+@@ -2,17 +2,16 @@
+  * 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 gc_DeletePolicy_h
+ #define gc_DeletePolicy_h
+ 
+-#include "gc/Barrier.h"
+ #include "js/TracingAPI.h"
+ #ifdef ENABLE_BIGINT
+ #include "vm/BigIntType.h"
+ #endif
+ 
+ namespace js {
+ namespace gc {
+ 
+@@ -69,23 +68,18 @@ IsClearEdgesTracer(JSTracer *trc)
+  * into the object and make it safe to delete.
+  */
+ template <typename T>
+ struct GCManagedDeletePolicy
+ {
+     void operator()(const T* constPtr) {
+         if (constPtr) {
+             auto ptr = const_cast<T*>(constPtr);
+-            if (JS::RuntimeHeapIsCollecting()) {
+-                MOZ_ASSERT(js::CurrentThreadIsGCSweeping());
+-                // Do not attempt to clear out storebuffer edges.
+-            } else {
+-                gc::ClearEdgesTracer trc;
+-                ptr->trace(&trc);
+-            }
++            gc::ClearEdgesTracer trc;
++            ptr->trace(&trc);
+             js_delete(ptr);
+         }
+     }
+ };
+ 
+ } // namespace js
+ 
+ #endif // gc_DeletePolicy_h
+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
+@@ -239,17 +239,20 @@ js::CheckTracedThing(JSTracer* trc, T* t
+ 
+     /*
+      * Do not check IsMarkingTracer directly -- it should only be used in paths
+      * where we cannot be the gray buffering tracer.
+      */
+     bool isGcMarkingTracer = trc->isMarkingTracer();
+ 
+     MOZ_ASSERT_IF(zone->requireGCTracer(),
+-                  isGcMarkingTracer || IsBufferGrayRootsTracer(trc) || IsUnmarkGrayTracer(trc));
++                  isGcMarkingTracer ||
++                  IsBufferGrayRootsTracer(trc) ||
++                  IsUnmarkGrayTracer(trc) ||
++                  IsClearEdgesTracer(trc));
+ 
+     if (isGcMarkingTracer) {
+         GCMarker* gcMarker = GCMarker::fromTracer(trc);
+         MOZ_ASSERT_IF(gcMarker->shouldCheckCompartments(),
+                       zone->isCollecting() || zone->isAtomsZone());
+ 
+         MOZ_ASSERT_IF(gcMarker->markColor() == MarkColor::Gray,
+                       !zone->isGCMarkingBlack() || zone->isAtomsZone());
+diff --git a/js/src/jit-test/tests/gc/bug-1472734.js b/js/src/jit-test/tests/gc/bug-1472734.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/gc/bug-1472734.js
+@@ -0,0 +1,14 @@
++if (!('oomTest' in this) || helperThreadCount() === 0)
++    quit();
++
++try {
++    oomTest(function() {
++      eval(`
++        function eval(source) {
++          offThreadCompileModule(source);
++          minorgc();
++        }
++        eval("");
++      `);
++    });
++} catch (exc) {}
+

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

@@ -0,0 +1,80 @@
+# HG changeset patch
+# User Ashley Hauck <khyperia@mozilla.com>
+# Date 1534871640 14400
+# Node ID c1e8bad5cea6ae5d0beccb7a242aff318c3a2eb3
+# Parent  827159ff7d580e165f32f4950acc2cd2da25decf
+Bug 1473228 - Add @@toStringTag in Intl.RelativeTimeFormat. r=jorendorff
+
+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
+@@ -62,16 +62,21 @@ static const JSFunctionSpec relativeTime
+ 
+ static const JSFunctionSpec relativeTimeFormat_methods[] = {
+     JS_SELF_HOSTED_FN("resolvedOptions", "Intl_RelativeTimeFormat_resolvedOptions", 0, 0),
+     JS_SELF_HOSTED_FN("format", "Intl_RelativeTimeFormat_format", 2, 0),
+     JS_FN(js_toSource_str, relativeTimeFormat_toSource, 0, 0),
+     JS_FS_END
+ };
+ 
++static const JSPropertySpec relativeTimeFormat_properties[] = {
++    JS_STRING_SYM_PS(toStringTag, "Intl.RelativeTimeFormat", JSPROP_READONLY),
++    JS_PS_END
++};
++
+ /**
+  * RelativeTimeFormat constructor.
+  * Spec: ECMAScript 402 API, RelativeTimeFormat, 1.1
+  */
+ static bool
+ RelativeTimeFormat(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+@@ -142,16 +147,19 @@ js::CreateRelativeTimeFormatPrototype(JS
+         return nullptr;
+ 
+     if (!JS_DefineFunctions(cx, ctor, relativeTimeFormat_static_methods))
+         return nullptr;
+ 
+     if (!JS_DefineFunctions(cx, proto, relativeTimeFormat_methods))
+         return nullptr;
+ 
++    if (!JS_DefineProperties(cx, proto, relativeTimeFormat_properties))
++        return nullptr;
++
+     RootedValue ctorValue(cx, ObjectValue(*ctor));
+     if (!DefineDataProperty(cx, Intl, cx->names().RelativeTimeFormat, ctorValue, 0))
+         return nullptr;
+ 
+     return proto;
+ }
+ 
+ /* static */ bool
+diff --git a/js/src/tests/jstests.list.1473228.later b/js/src/tests/jstests.list.1473228.later
+new file mode 100644
+--- /dev/null
++++ b/js/src/tests/jstests.list.1473228.later
+@@ -0,0 +1,23 @@
++--- jstests.list
+++++ jstests.list
++@@ -447,20 +447,16 @@ skip script test262/annexB/language/func
++ # https://bugzilla.mozilla.org/show_bug.cgi?id=1406171
++ skip script test262/built-ins/Reflect/ownKeys/return-on-corresponding-order-large-index.js
++ 
++ # https://bugzilla.mozilla.org/show_bug.cgi?id=1291407
++ skip script test262/intl402/ListFormat/prototype/toStringTag/toString.js
++ skip script test262/intl402/ListFormat/prototype/toStringTag/toStringTag.js
++ 
++ # https://bugzilla.mozilla.org/show_bug.cgi?id=1473228
++-skip script test262/intl402/RelativeTimeFormat/prototype/toStringTag/toString.js
++-skip script test262/intl402/RelativeTimeFormat/prototype/toStringTag/toStringTag.js
++-
++-# https://bugzilla.mozilla.org/show_bug.cgi?id=1473228
++ skip script test262/intl402/Segmenter/prototype/toStringTag/toString.js
++ skip script test262/intl402/Segmenter/prototype/toStringTag/toStringTag.js
++ 
++ # https://bugzilla.mozilla.org/show_bug.cgi?id=1473229
++ skip include test262/intl402/RelativeTimeFormat/prototype/formatToParts/jstests.list
++ 
++ # https://bugzilla.mozilla.org/show_bug.cgi?id=1483545
++ skip script test262/intl402/RelativeTimeFormat/prototype/format/en-us-numeric-always.js

+ 48 - 0
frg/work-js/mozilla-release/patches/1477621-0-63a1.patch

@@ -0,0 +1,48 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532505708 -32400
+#      Wed Jul 25 17:01:48 2018 +0900
+# Node ID 4f8e23bff248c7500302deb4b68804bbafbc462b
+# Parent  d8f622781168eed6fb5e1245a92af56936b0a7f0
+Bug 1477621 - Part 0: Remove unnecessary note from JSOP_DEFAULT. r=jandem
+
+diff --git a/js/src/frontend/SwitchEmitter.cpp b/js/src/frontend/SwitchEmitter.cpp
+--- a/js/src/frontend/SwitchEmitter.cpp
++++ b/js/src/frontend/SwitchEmitter.cpp
+@@ -219,29 +219,29 @@ SwitchEmitter::emitTable(const TableGene
+     return true;
+ }
+ 
+ bool
+ SwitchEmitter::emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault)
+ {
+     MOZ_ASSERT(kind_ == Kind::Cond);
+ 
+-    if (state_ == State::Case) {
+-        // Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE or
+-        // JSOP_DEFAULT for the benefit of IonBuilder.
+-        if (!bce_->setSrcNoteOffset(caseNoteIndex_, 0, bce_->offset() - lastCaseOffset_))
+-            return false;
+-    }
+-
+     if (isDefault) {
+         if (!bce_->emitJump(JSOP_DEFAULT, &condSwitchDefaultOffset_))
+             return false;
+         return true;
+     }
+ 
++    if (state_ == State::Case) {
++        // Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE for the
++        // benefit of IonBuilder.
++        if (!bce_->setSrcNoteOffset(caseNoteIndex_, 0, bce_->offset() - lastCaseOffset_))
++            return false;
++    }
++
+     if (!bce_->newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex_))
+         return false;
+ 
+     JumpList caseJump;
+     if (!bce_->emitJump(JSOP_CASE, &caseJump))
+         return false;
+     caseOffsets_[caseIndex] = caseJump.offset;
+     lastCaseOffset_ = caseJump.offset;

+ 320 - 0
frg/work-js/mozilla-release/patches/1477621-1-63a1.patch

@@ -0,0 +1,320 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532505708 -32400
+#      Wed Jul 25 17:01:48 2018 +0900
+# Node ID 5f7b22fe0124b332ea410e44b94afa11d29b254a
+# Parent  4f8e23bff248c7500302deb4b68804bbafbc462b
+Bug 1477621 - Part 1: Add source note field constants for switch. r=jandem
+
+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
+@@ -29,37 +29,73 @@ namespace js {
+  *              +---------+-----+           +---+-----------+
+  *
+  * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
+  * SRC_COLSPAN, SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
+  *
+  * NB: the js_SrcNoteSpec array in BytecodeEmitter.cpp is indexed by this
+  * enum, so its initializers need to match the order here.
+  */
++
++class SrcNote {
++  public:
++    // SRC_TABLESWITCH: Source note for JSOP_TABLESWITCH.
++    class TableSwitch {
++      public:
++        enum Fields {
++            // The offset of the end of switch (the first non-JumpTarget op
++            // after switch) from JSOP_TABLESWITCH.
++            EndOffset,
++            Count
++        };
++    };
++    // SRC_CONDSWITCH: Source note for JSOP_CONDSWITCH.
++    class CondSwitch {
++      public:
++        enum Fields {
++            // The offset of the end of switch (the first non-JumpTarget op
++            // after switch) from JSOP_CONDSWITCH.
++            EndOffset,
++
++            // The offset of JSOP_CASE for the first case from JSOP_CONDSWITCH.
++            FirstCaseOffset,
++            Count
++        };
++    };
++    // SRC_NEXTCASE: Source note for JSOP_CASE in a JSOP_CONDSWITCH.
++    class NextCase {
++      public:
++        enum Fields {
++            // Offset of the next JSOP_CASE from this JSOP_CASE.  This field is
++            // 0 if this is the last JSOP_CASE.
++            NextCaseOffset,
++            Count
++        };
++    };
++};
++
+ #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",         3)  /* JSOP_NOP or JSOP_POP in for(;;) loop head. */        \
+     M(SRC_WHILE,        "while",       1)  /* JSOP_GOTO to for or while loop condition from before \
+                                               loop, else JSOP_NOP at top of do-while loop. */      \
+     M(SRC_FOR_IN,       "for-in",      1)  /* JSOP_GOTO to for-in loop condition from before       \
+                                               loop. */                                             \
+     M(SRC_FOR_OF,       "for-of",      1)  /* JSOP_GOTO to for-of loop condition from before       \
+                                               loop. */                                             \
+     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", 1)  /* JSOP_TABLESWITCH; offset points to end of switch. */ \
+-    M(SRC_CONDSWITCH,   "condswitch",  2)  /* JSOP_CONDSWITCH; 1st offset points to end of switch, \
+-                                              2nd points to first JSOP_CASE. */                    \
+-    M(SRC_NEXTCASE,     "nextcase",    1)  /* Distance forward from one CASE in a CONDSWITCH to    \
+-                                              the next. */                                         \
++    M(SRC_TABLESWITCH,  "tableswitch", SrcNote::TableSwitch::Count) \
++    M(SRC_CONDSWITCH,   "condswitch",  SrcNote::CondSwitch::Count) \
++    M(SRC_NEXTCASE,     "nextcase",    SrcNote::NextCase::Count) \
+     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",         1)  /* JSOP_TRY, offset points to goto at the end of the    \
+                                               try block. */                                        \
+     /* All notes above here are "gettable".  See SN_IS_GETTABLE below. */                          \
+     M(SRC_COLSPAN,      "colspan",     1)  /* Number of columns this opcode spans. */              \
+     M(SRC_NEWLINE,      "newline",     0)  /* Bytecode follows a source newline. */                \
+diff --git a/js/src/frontend/SwitchEmitter.cpp b/js/src/frontend/SwitchEmitter.cpp
+--- a/js/src/frontend/SwitchEmitter.cpp
++++ b/js/src/frontend/SwitchEmitter.cpp
+@@ -228,18 +228,21 @@ SwitchEmitter::emitCaseOrDefaultJump(uin
+         if (!bce_->emitJump(JSOP_DEFAULT, &condSwitchDefaultOffset_))
+             return false;
+         return true;
+     }
+ 
+     if (state_ == State::Case) {
+         // Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE for the
+         // benefit of IonBuilder.
+-        if (!bce_->setSrcNoteOffset(caseNoteIndex_, 0, bce_->offset() - lastCaseOffset_))
++        if (!bce_->setSrcNoteOffset(caseNoteIndex_, SrcNote::NextCase::NextCaseOffset,
++                                    bce_->offset() - lastCaseOffset_))
++        {
+             return false;
++        }
+     }
+ 
+     if (!bce_->newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex_))
+         return false;
+ 
+     JumpList caseJump;
+     if (!bce_->emitJump(JSOP_CASE, &caseJump))
+         return false;
+@@ -387,18 +390,24 @@ SwitchEmitter::emitEnd()
+     } else {
+         // Fill in the default jump target.
+         pc = bce_->code(top_);
+         SET_JUMP_OFFSET(pc, defaultJumpTargetOffset_.offset - top_);
+         pc += JUMP_OFFSET_LEN;
+     }
+ 
+     // Set the SRC_SWITCH note's offset operand to tell end of switch.
+-    if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->lastNonJumpTargetOffset() - top_))
++    // This code is shared between table switch and cond switch.
++    static_assert(unsigned(SrcNote::TableSwitch::EndOffset) == unsigned(SrcNote::CondSwitch::EndOffset),
++                  "{TableSwitch,CondSwitch}::EndOffset should be same");
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::TableSwitch::EndOffset,
++                                bce_->lastNonJumpTargetOffset() - top_))
++    {
+         return false;
++    }
+ 
+     if (kind_ == Kind::Table) {
+         // Skip over the already-initialized switch bounds.
+         pc += 2 * JUMP_OFFSET_LEN;
+ 
+         // Fill in the jump table, if there is one.
+         for (uint32_t i = 0, length = caseOffsets_.length(); i < length; i++) {
+             ptrdiff_t off = caseOffsets_[i];
+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
+@@ -1113,33 +1113,33 @@ ControlFlowGenerator::processCondSwitch(
+     //  2/ Generate code for all cases (see processCondSwitchCase).
+     //  3/ Generate code for all bodies (see processCondSwitchBody).
+ 
+     MOZ_ASSERT(JSOp(*pc) == JSOP_CONDSWITCH);
+     jssrcnote* sn = GetSrcNote(gsn, script, pc);
+     MOZ_ASSERT(SN_TYPE(sn) == SRC_CONDSWITCH);
+ 
+     // Get the exit pc
+-    jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, 0);
+-    jsbytecode* firstCase = pc + GetSrcNoteOffset(sn, 1);
++    jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, SrcNote::CondSwitch::EndOffset);
++    jsbytecode* firstCase = pc + GetSrcNoteOffset(sn, SrcNote::CondSwitch::FirstCaseOffset);
+ 
+     // Iterate all cases in the conditional switch.
+     // - Stop at the default case. (always emitted after the last case)
+     // - Estimate the number of uniq bodies. This estimation might be off by 1
+     //   if the default body alias a case body.
+     jsbytecode* curCase = firstCase;
+     jsbytecode* lastTarget = GetJumpOffset(curCase) + curCase;
+     size_t nbBodies = 1; // default target and the first body.
+ 
+     MOZ_ASSERT(pc < curCase && curCase <= exitpc);
+     while (JSOp(*curCase) == JSOP_CASE) {
+         // Fetch the next case.
+         jssrcnote* caseSn = GetSrcNote(gsn, script, curCase);
+         MOZ_ASSERT(caseSn && SN_TYPE(caseSn) == SRC_NEXTCASE);
+-        ptrdiff_t off = GetSrcNoteOffset(caseSn, 0);
++        ptrdiff_t off = GetSrcNoteOffset(caseSn, SrcNote::NextCase::NextCaseOffset);
+         MOZ_ASSERT_IF(off == 0, JSOp(*GetNextPc(curCase)) == JSOP_JUMPTARGET);
+         curCase = off ? curCase + off : GetNextPc(GetNextPc(curCase));
+         MOZ_ASSERT(pc < curCase && curCase <= exitpc);
+ 
+         // Count non-aliased cases.
+         jsbytecode* curTarget = GetJumpOffset(curCase) + curCase;
+         if (lastTarget < curTarget)
+             nbBodies++;
+@@ -1162,17 +1162,17 @@ ControlFlowGenerator::processCondSwitch(
+             if (defaultTarget < curTarget)
+                 nbBodies++;
+             break;
+         }
+         if (lastTarget < curTarget)
+             defaultIdx++;
+ 
+         jssrcnote* caseSn = GetSrcNote(gsn, script, curCase);
+-        ptrdiff_t off = GetSrcNoteOffset(caseSn, 0);
++        ptrdiff_t off = GetSrcNoteOffset(caseSn, SrcNote::NextCase::NextCaseOffset);
+         curCase = off ? curCase + off : GetNextPc(GetNextPc(curCase));
+         lastTarget = curTarget;
+     }
+ 
+     // Allocate the current graph state.
+     CFGState state = CFGState::CondSwitch(alloc(), exitpc, defaultTarget);
+     if (!state.switch_.bodies || !state.switch_.bodies->init(alloc(), nbBodies))
+         return ControlStatus::Error;
+@@ -1218,17 +1218,17 @@ ControlFlowGenerator::processCondSwitchC
+     MOZ_ASSERT(JSOp(*pc) == JSOP_CASE);
+     FixedList<CFGBlock*>& bodies = *state.switch_.bodies;
+     uint32_t& currentIdx = state.switch_.currentIdx;
+ 
+     jsbytecode* lastTarget = currentIdx ? bodies[currentIdx - 1]->startPc() : nullptr;
+ 
+     // Fetch the following case in which we will continue.
+     jssrcnote* sn = GetSrcNote(gsn, script, pc);
+-    ptrdiff_t off = GetSrcNoteOffset(sn, 0);
++    ptrdiff_t off = GetSrcNoteOffset(sn, SrcNote::NextCase::NextCaseOffset);
+     MOZ_ASSERT_IF(off == 0, JSOp(*GetNextPc(pc)) == JSOP_JUMPTARGET);
+     jsbytecode* casePc = off ? pc + off : GetNextPc(GetNextPc(pc));
+     bool nextIsDefault = JSOp(*casePc) == JSOP_DEFAULT;
+     MOZ_ASSERT(JSOp(*casePc) == JSOP_CASE || nextIsDefault);
+ 
+     // Allocate the block of the matching case.
+     jsbytecode* bodyTarget = pc + GetJumpOffset(pc);
+     CFGBlock* bodyBlock = nullptr;
+@@ -1844,17 +1844,17 @@ ControlFlowGenerator::processTableSwitch
+     // 4: Offset of case low+1
+     // .: ...
+     // .: Offset of case high
+ 
+     MOZ_ASSERT(op == JSOP_TABLESWITCH);
+     MOZ_ASSERT(SN_TYPE(sn) == SRC_TABLESWITCH);
+ 
+     // Get the default and exit pc
+-    jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, 0);
++    jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset);
+     jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc);
+ 
+     MOZ_ASSERT(defaultpc > pc && defaultpc <= exitpc);
+ 
+     // Get the low and high from the tableswitch
+     jsbytecode* pc2 = pc;
+     pc2 += JUMP_OFFSET_LEN;
+     int low = GET_JUMP_OFFSET(pc2);
+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
+@@ -2752,36 +2752,51 @@ SrcNotes(JSContext* cx, HandleScript scr
+ 
+           case SRC_FOR_IN:
+           case SRC_FOR_OF:
+             if (!sp->jsprintf(" closingjump %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                 return false;
+             break;
+ 
+           case SRC_WHILE:
+-          case SRC_NEXTCASE:
+             if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                 return false;
+             break;
+ 
++          case SRC_NEXTCASE:
++            if (!sp->jsprintf(" next case offset %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::NextCase::NextCaseOffset))))
++            {
++                return false;
++            }
++            break;
++
+           case SRC_TABLESWITCH: {
+             mozilla::DebugOnly<JSOp> op = JSOp(script->code()[offset]);
+             MOZ_ASSERT(op == JSOP_TABLESWITCH);
+-            if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0))))
++            if (!sp->jsprintf(" end offset %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset))))
++            {
+                 return false;
++            }
+             UpdateSwitchTableBounds(cx, script, offset,
+                                     &switchTableStart, &switchTableEnd);
+             break;
+           }
+           case SRC_CONDSWITCH: {
+             mozilla::DebugOnly<JSOp> op = JSOp(script->code()[offset]);
+             MOZ_ASSERT(op == JSOP_CONDSWITCH);
+-            if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0))))
++            if (!sp->jsprintf(" end offset %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::CondSwitch::EndOffset))))
++            {
+                 return false;
+-            if (unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1)) {
++            }
++            if (unsigned caseOff =
++                unsigned(GetSrcNoteOffset(sn, SrcNote::CondSwitch::FirstCaseOffset)))
++            {
+                 if (!sp->jsprintf(" first case offset %u", caseOff))
+                     return false;
+             }
+             UpdateSwitchTableBounds(cx, script, offset,
+                                     &switchTableStart, &switchTableEnd);
+             break;
+           }
+ 
+diff --git a/js/src/vm/CodeCoverage.cpp b/js/src/vm/CodeCoverage.cpp
+--- a/js/src/vm/CodeCoverage.cpp
++++ b/js/src/vm/CodeCoverage.cpp
+@@ -195,17 +195,17 @@ LCovSource::writeScript(JSScript* script
+             size_t oldLine = lineno;
+             while (!SN_IS_TERMINATOR(sn) && snpc <= pc) {
+                 SrcNoteType type = SN_TYPE(sn);
+                 if (type == SRC_SETLINE)
+                     lineno = size_t(GetSrcNoteOffset(sn, 0));
+                 else if (type == SRC_NEWLINE)
+                     lineno++;
+                 else if (type == SRC_TABLESWITCH)
+-                    tableswitchExitOffset = GetSrcNoteOffset(sn, 0);
++                    tableswitchExitOffset = GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset);
+ 
+                 sn = SN_NEXT(sn);
+                 snpc += SN_DELTA(sn);
+             }
+ 
+             if ((oldLine != lineno || !firstLineHasBeenWritten) &&
+                 pc >= script->main() &&
+                 fallsthrough)

+ 154 - 0
frg/work-js/mozilla-release/patches/1477621-2-63a1.patch

@@ -0,0 +1,154 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532505709 -32400
+#      Wed Jul 25 17:01:49 2018 +0900
+# Node ID 7cabc189feb9c32b870183b8096ca8702f518f61
+# Parent  5f7b22fe0124b332ea410e44b94afa11d29b254a
+Bug 1477621 - Part 2: Add source note field constants for try. r=jandem
+
+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
+@@ -65,16 +65,26 @@ class SrcNote {
+       public:
+         enum Fields {
+             // Offset of the next JSOP_CASE from this JSOP_CASE.  This field is
+             // 0 if this is the last JSOP_CASE.
+             NextCaseOffset,
+             Count
+         };
+     };
++    // SRC_TRY: Source note for JSOP_TRY.
++    class Try {
++      public:
++        enum Fields {
++            // The offset of the JSOP_GOTO at the end of the try block from
++            // JSOP_TRY.
++            EndOfTryJumpOffset,
++            Count
++        };
++    };
+ };
+ 
+ #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",         3)  /* JSOP_NOP or JSOP_POP in for(;;) loop head. */        \
+@@ -89,18 +99,17 @@ class SrcNote {
+     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) \
+     M(SRC_NEXTCASE,     "nextcase",    SrcNote::NextCase::Count) \
+     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",         1)  /* JSOP_TRY, offset points to goto at the end of the    \
+-                                              try block. */                                        \
++    M(SRC_TRY,          "try",         SrcNote::Try::Count) \
+     /* All notes above here are "gettable".  See SN_IS_GETTABLE below. */                          \
+     M(SRC_COLSPAN,      "colspan",     1)  /* Number of columns this opcode spans. */              \
+     M(SRC_NEWLINE,      "newline",     0)  /* Bytecode follows a source newline. */                \
+     M(SRC_SETLINE,      "setline",     1)  /* A file-absolute source line number note. */          \
+     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. */
+diff --git a/js/src/frontend/TryEmitter.cpp b/js/src/frontend/TryEmitter.cpp
+--- a/js/src/frontend/TryEmitter.cpp
++++ b/js/src/frontend/TryEmitter.cpp
+@@ -76,18 +76,21 @@ TryEmitter::emitTryEnd()
+ 
+     // GOSUB to finally, if present.
+     if (hasFinally() && controlInfo_) {
+         if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
+             return false;
+     }
+ 
+     // Source note points to the jump at the end of the try block.
+-    if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
++    if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::Try::EndOfTryJumpOffset,
++                                bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
++    {
+         return false;
++    }
+ 
+     // Emit jump over catch and/or finally.
+     if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
+         return false;
+ 
+     if (!bce_->emitJumpTarget(&tryEnd_))
+         return false;
+ 
+diff --git a/js/src/jit/BytecodeAnalysis.cpp b/js/src/jit/BytecodeAnalysis.cpp
+--- a/js/src/jit/BytecodeAnalysis.cpp
++++ b/js/src/jit/BytecodeAnalysis.cpp
+@@ -128,17 +128,17 @@ BytecodeAnalysis::init(TempAllocator& al
+                 }
+             }
+ 
+             // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
+             // jump over the catch/finally blocks.
+             jssrcnote* sn = GetSrcNote(gsn, script_, pc);
+             MOZ_ASSERT(SN_TYPE(sn) == SRC_TRY);
+ 
+-            jsbytecode* endOfTry = pc + GetSrcNoteOffset(sn, 0);
++            jsbytecode* endOfTry = pc + GetSrcNoteOffset(sn, SrcNote::Try::EndOfTryJumpOffset);
+             MOZ_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
+ 
+             jsbytecode* afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
+             MOZ_ASSERT(afterTry > endOfTry);
+ 
+             // Ensure the code following the try-block is always marked as
+             // reachable, to simplify Ion's ControlFlowGenerator.
+             uint32_t afterTryOffset = script_->pcToOffset(afterTry);
+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
+@@ -541,17 +541,17 @@ ControlFlowGenerator::processTry()
+         checkedTryFinally_ = true;
+     }
+ 
+     jssrcnote* sn = GetSrcNote(gsn, script, pc);
+     MOZ_ASSERT(SN_TYPE(sn) == SRC_TRY);
+ 
+     // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
+     // jump over the catch block.
+-    jsbytecode* endpc = pc + GetSrcNoteOffset(sn, 0);
++    jsbytecode* endpc = pc + GetSrcNoteOffset(sn, SrcNote::Try::EndOfTryJumpOffset);
+     MOZ_ASSERT(JSOp(*endpc) == JSOP_GOTO);
+     MOZ_ASSERT(GetJumpOffset(endpc) > 0);
+ 
+     jsbytecode* afterTry = endpc + GetJumpOffset(endpc);
+ 
+     // If controlflow in the try body is terminated (by a return or throw
+     // statement), the code after the try-statement may still be reachable
+     // via the catch block (which we don't compile) and OSR can enter it.
+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
+@@ -2797,18 +2797,21 @@ SrcNotes(JSContext* cx, HandleScript scr
+             }
+             UpdateSwitchTableBounds(cx, script, offset,
+                                     &switchTableStart, &switchTableEnd);
+             break;
+           }
+ 
+           case SRC_TRY:
+             MOZ_ASSERT(JSOp(script->code()[offset]) == JSOP_TRY);
+-            if (!sp->jsprintf(" offset to jump %u", unsigned(GetSrcNoteOffset(sn, 0))))
++            if (!sp->jsprintf(" offset to jump %u",
++                              unsigned(GetSrcNoteOffset(sn, SrcNote::Try::EndOfTryJumpOffset))))
++            {
+                 return false;
++            }
+             break;
+ 
+           case SRC_CLASS_SPAN: {
+             unsigned startOffset = GetSrcNoteOffset(sn, 0);
+             unsigned endOffset = GetSrcNoteOffset(sn, 1);
+             if (!sp->jsprintf(" %u %u", startOffset, endOffset))
+                 return false;
+             break;

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

@@ -0,0 +1,124 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532505709 -32400
+#      Wed Jul 25 17:01:49 2018 +0900
+# Node ID d18e67f75339c713ce1aadc54631898b5af5df3d
+# Parent  7cabc189feb9c32b870183b8096ca8702f518f61
+Bug 1477621 - Part 3: Add source note field constants for colspan. r=jandem
+
+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
+@@ -75,16 +75,26 @@ class SrcNote {
+       public:
+         enum Fields {
+             // The offset of the JSOP_GOTO at the end of the try block from
+             // JSOP_TRY.
+             EndOfTryJumpOffset,
+             Count
+         };
+     };
++    // SRC_COLSPAN: Source note for arbitrary ops.
++    class ColSpan {
++      public:
++        enum Fields {
++            // The column span (the diff between the column corresponds to the
++            // current op and last known column).
++            Span,
++            Count
++        };
++    };
+ };
+ 
+ #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",         3)  /* JSOP_NOP or JSOP_POP in for(;;) loop head. */        \
+@@ -101,17 +111,17 @@ class SrcNote {
+     M(SRC_TABLESWITCH,  "tableswitch", SrcNote::TableSwitch::Count) \
+     M(SRC_CONDSWITCH,   "condswitch",  SrcNote::CondSwitch::Count) \
+     M(SRC_NEXTCASE,     "nextcase",    SrcNote::NextCase::Count) \
+     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",     1)  /* Number of columns this opcode spans. */              \
++    M(SRC_COLSPAN,      "colspan",     SrcNote::ColSpan::Count) \
+     M(SRC_NEWLINE,      "newline",     0)  /* Bytecode follows a source newline. */                \
+     M(SRC_SETLINE,      "setline",     1)  /* A file-absolute source line number note. */          \
+     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 {
+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
+@@ -2720,17 +2720,17 @@ SrcNotes(JSContext* cx, HandleScript scr
+           case SRC_BREAK:
+           case SRC_BREAK2LABEL:
+           case SRC_SWITCHBREAK:
+           case SRC_ASSIGNOP:
+           case SRC_XDELTA:
+             break;
+ 
+           case SRC_COLSPAN:
+-            colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
++            colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, SrcNote::ColSpan::Span));
+             if (!sp->jsprintf("%d", colspan))
+                 return false;
+             break;
+ 
+           case SRC_SETLINE:
+             lineno = GetSrcNoteOffset(sn, 0);
+             if (!sp->jsprintf(" lineno %u", lineno))
+                 return false;
+diff --git a/js/src/vm/BytecodeUtil-inl.h b/js/src/vm/BytecodeUtil-inl.h
+--- a/js/src/vm/BytecodeUtil-inl.h
++++ b/js/src/vm/BytecodeUtil-inl.h
+@@ -173,17 +173,18 @@ class BytecodeRangeWithPosition : privat
+   private:
+     void updatePosition() {
+         // Determine the current line number by reading all source notes up to
+         // and including the current offset.
+         jsbytecode *lastLinePC = nullptr;
+         while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) {
+             SrcNoteType type = SN_TYPE(sn);
+             if (type == SRC_COLSPAN) {
+-                ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
++                ptrdiff_t colspan =
++                    SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, SrcNote::ColSpan::Span));
+                 MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
+                 column += colspan;
+                 lastLinePC = snpc;
+             } else if (type == SRC_SETLINE) {
+                 lineno = size_t(GetSrcNoteOffset(sn, 0));
+                 column = 0;
+                 lastLinePC = snpc;
+             } else if (type == SRC_NEWLINE) {
+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
+@@ -3272,17 +3272,17 @@ js::PCToLineNumber(unsigned startLine, j
+         SrcNoteType type = SN_TYPE(sn);
+         if (type == SRC_SETLINE) {
+             lineno = unsigned(GetSrcNoteOffset(sn, 0));
+             column = 0;
+         } else if (type == SRC_NEWLINE) {
+             lineno++;
+             column = 0;
+         } else if (type == SRC_COLSPAN) {
+-            ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
++            ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, SrcNote::ColSpan::Span));
+             MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
+             column += colspan;
+         }
+     }
+ 
+     if (columnp)
+         *columnp = column;
+ 

+ 182 - 0
frg/work-js/mozilla-release/patches/1477621-4-63a1.patch

@@ -0,0 +1,182 @@
+# HG changeset patch
+# User Tooru Fujisawa <arai_a@mac.com>
+# Date 1532505709 -32400
+#      Wed Jul 25 17:01:49 2018 +0900
+# Node ID 9d328a1be52ce31ef56c4fe7e4155b4a6f2d35fc
+# Parent  d18e67f75339c713ce1aadc54631898b5af5df3d
+Bug 1477621 - Part 4: Add source note field constants for line. r=jandem
+
+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
+@@ -85,16 +85,25 @@ class SrcNote {
+       public:
+         enum Fields {
+             // The column span (the diff between the column corresponds to the
+             // current op and last known column).
+             Span,
+             Count
+         };
+     };
++    // SRC_SETLINE: Source note for arbitrary ops.
++    class SetLine {
++      public:
++        enum Fields {
++            // The file-absolute source line number of the current op.
++            Line,
++            Count
++        };
++    };
+ };
+ 
+ #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",         3)  /* JSOP_NOP or JSOP_POP in for(;;) loop head. */        \
+@@ -113,17 +122,17 @@ class SrcNote {
+     M(SRC_NEXTCASE,     "nextcase",    SrcNote::NextCase::Count) \
+     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",     1)  /* A file-absolute source line number note. */          \
++    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)
+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
+@@ -2726,17 +2726,17 @@ SrcNotes(JSContext* cx, HandleScript scr
+ 
+           case SRC_COLSPAN:
+             colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, SrcNote::ColSpan::Span));
+             if (!sp->jsprintf("%d", colspan))
+                 return false;
+             break;
+ 
+           case SRC_SETLINE:
+-            lineno = GetSrcNoteOffset(sn, 0);
++            lineno = GetSrcNoteOffset(sn, SrcNote::SetLine::Line);
+             if (!sp->jsprintf(" lineno %u", lineno))
+                 return false;
+             break;
+ 
+           case SRC_NEWLINE:
+             ++lineno;
+             break;
+ 
+diff --git a/js/src/vm/BytecodeUtil-inl.h b/js/src/vm/BytecodeUtil-inl.h
+--- a/js/src/vm/BytecodeUtil-inl.h
++++ b/js/src/vm/BytecodeUtil-inl.h
+@@ -179,17 +179,17 @@ class BytecodeRangeWithPosition : privat
+             SrcNoteType type = SN_TYPE(sn);
+             if (type == SRC_COLSPAN) {
+                 ptrdiff_t colspan =
+                     SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, SrcNote::ColSpan::Span));
+                 MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
+                 column += colspan;
+                 lastLinePC = snpc;
+             } else if (type == SRC_SETLINE) {
+-                lineno = size_t(GetSrcNoteOffset(sn, 0));
++                lineno = size_t(GetSrcNoteOffset(sn, SrcNote::SetLine::Line));
+                 column = 0;
+                 lastLinePC = snpc;
+             } else if (type == SRC_NEWLINE) {
+                 lineno++;
+                 column = 0;
+                 lastLinePC = snpc;
+             }
+ 
+diff --git a/js/src/vm/CodeCoverage.cpp b/js/src/vm/CodeCoverage.cpp
+--- a/js/src/vm/CodeCoverage.cpp
++++ b/js/src/vm/CodeCoverage.cpp
+@@ -191,17 +191,17 @@ LCovSource::writeScript(JSScript* script
+ 
+         // If we have additional source notes, walk all the source notes of the
+         // current pc.
+         if (snpc <= pc || !firstLineHasBeenWritten) {
+             size_t oldLine = lineno;
+             while (!SN_IS_TERMINATOR(sn) && snpc <= pc) {
+                 SrcNoteType type = SN_TYPE(sn);
+                 if (type == SRC_SETLINE)
+-                    lineno = size_t(GetSrcNoteOffset(sn, 0));
++                    lineno = size_t(GetSrcNoteOffset(sn, SrcNote::SetLine::Line));
+                 else if (type == SRC_NEWLINE)
+                     lineno++;
+                 else if (type == SRC_TABLESWITCH)
+                     tableswitchExitOffset = GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset);
+ 
+                 sn = SN_NEXT(sn);
+                 snpc += SN_DELTA(sn);
+             }
+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
+@@ -3266,17 +3266,17 @@ js::PCToLineNumber(unsigned startLine, j
+     ptrdiff_t target = pc - code;
+     for (jssrcnote* sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+         offset += SN_DELTA(sn);
+         if (offset > target)
+             break;
+ 
+         SrcNoteType type = SN_TYPE(sn);
+         if (type == SRC_SETLINE) {
+-            lineno = unsigned(GetSrcNoteOffset(sn, 0));
++            lineno = unsigned(GetSrcNoteOffset(sn, SrcNote::SetLine::Line));
+             column = 0;
+         } else if (type == SRC_NEWLINE) {
+             lineno++;
+             column = 0;
+         } else if (type == SRC_COLSPAN) {
+             ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, SrcNote::ColSpan::Span));
+             MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
+             column += colspan;
+@@ -3318,17 +3318,17 @@ js::LineNumberToPC(JSScript* script, uns
+             if (diff < bestdiff) {
+                 bestdiff = diff;
+                 best = offset;
+             }
+         }
+         offset += SN_DELTA(sn);
+         SrcNoteType type = SN_TYPE(sn);
+         if (type == SRC_SETLINE) {
+-            lineno = unsigned(GetSrcNoteOffset(sn, 0));
++            lineno = unsigned(GetSrcNoteOffset(sn, SrcNote::SetLine::Line));
+         } else if (type == SRC_NEWLINE) {
+             lineno++;
+         }
+     }
+     if (best >= 0)
+         offset = best;
+ out:
+     return script->offsetToPC(offset);
+@@ -3337,17 +3337,17 @@ out:
+ JS_FRIEND_API(unsigned)
+ js::GetScriptLineExtent(JSScript* script)
+ {
+     unsigned lineno = script->lineno();
+     unsigned maxLineNo = lineno;
+     for (jssrcnote* sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
+         SrcNoteType type = SN_TYPE(sn);
+         if (type == SRC_SETLINE)
+-            lineno = unsigned(GetSrcNoteOffset(sn, 0));
++            lineno = unsigned(GetSrcNoteOffset(sn, SrcNote::SetLine::Line));
+         else if (type == SRC_NEWLINE)
+             lineno++;
+ 
+         if (maxLineNo < lineno)
+             maxLineNo = lineno;
+     }
+ 
+     return 1 + maxLineNo - script->lineno();

+ 946 - 0
frg/work-js/mozilla-release/patches/1479900-1-63a1.patch

@@ -0,0 +1,946 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1533186313 14400
+# Node ID ebac10c8c8b9ab70465097b02de34eee86bf41be
+# Parent  044705c4d308da03fd8f89f42497ffd7b17614f1
+Bug 1479900 - Part 1: Use accessor methods for JSString::flags/length. r=sfink
+
+Add accessor methods so that underlying storage strategy can be changed
+later. This patch should not change current behaviour.
+
+MozReview-Commit-ID: IRA53TQShe6
+
+
+diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h
+--- a/js/public/HeapAPI.h
++++ b/js/public/HeapAPI.h
+@@ -209,33 +209,40 @@ struct String
+     static const uint32_t LINEAR_BIT       = JS_BIT(1);
+     static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
+     static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
+     static const uint32_t EXTERNAL_FLAGS   = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
+     static const uint32_t TYPE_FLAGS_MASK  = JS_BIT(6) - 1;
+     static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(5);
+     static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(5);
+ 
+-    uint32_t flags;
+-    uint32_t length;
++    uint32_t flags_;
++    uint32_t length_;
+     union {
+         const JS::Latin1Char* nonInlineCharsLatin1;
+         const char16_t* nonInlineCharsTwoByte;
+         JS::Latin1Char inlineStorageLatin1[1];
+         char16_t inlineStorageTwoByte[1];
+     };
+     const JSStringFinalizer* externalFinalizer;
+ 
++    inline uint32_t flags() const {
++        return flags_;
++    }
++    inline uint32_t length() const {
++        return length_;
++    }
++
+     static bool nurseryCellIsString(const js::gc::Cell* cell) {
+         MOZ_ASSERT(IsInsideNursery(cell));
+-        return reinterpret_cast<const String*>(cell)->flags & NON_ATOM_BIT;
++        return reinterpret_cast<const String*>(cell)->flags() & NON_ATOM_BIT;
+     }
+ 
+     static bool isPermanentAtom(const js::gc::Cell* cell) {
+-        uint32_t flags = reinterpret_cast<const String*>(cell)->flags;
++        uint32_t flags = reinterpret_cast<const String*>(cell)->flags();
+         return (flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
+     }
+ };
+ 
+ struct Symbol {
+     uint32_t code_;
+     static const uint32_t WellKnownAPILimit = 0x80000000;
+ 
+diff --git a/js/src/gc/Marking-inl.h b/js/src/gc/Marking-inl.h
+--- a/js/src/gc/Marking-inl.h
++++ b/js/src/gc/Marking-inl.h
+@@ -94,17 +94,17 @@ RelocationOverlay::forwardTo(Cell* cell)
+ {
+     MOZ_ASSERT(!isForwarded());
+     // The location of magic_ is important because it must never be valid to see
+     // the value Relocated there in a GC thing that has not been moved.
+     static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSObject, group_) + sizeof(uint32_t),
+                   "RelocationOverlay::magic_ is in the wrong location");
+     static_assert(offsetof(RelocationOverlay, magic_) == offsetof(js::Shape, base_) + sizeof(uint32_t),
+                   "RelocationOverlay::magic_ is in the wrong location");
+-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSString, d.u1.length),
++    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSString, d.u1.length_),
+                   "RelocationOverlay::magic_ is in the wrong location");
+     magic_ = Relocated;
+     newLocation_ = cell;
+ }
+ 
+ #ifdef JSGC_HASH_TABLE_CHECKS
+ 
+ template <typename T>
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -790,77 +790,77 @@ GetObjectSlot(JSObject* obj, size_t slot
+ {
+     MOZ_ASSERT(slot < GetObjectSlotSpan(obj));
+     return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot);
+ }
+ 
+ MOZ_ALWAYS_INLINE size_t
+ GetAtomLength(JSAtom* atom)
+ {
+-    return reinterpret_cast<JS::shadow::String*>(atom)->length;
++    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;
++    return reinterpret_cast<JS::shadow::String*>(s)->length();
+ }
+ 
+ MOZ_ALWAYS_INLINE size_t
+ GetFlatStringLength(JSFlatString* s)
+ {
+-    return reinterpret_cast<JS::shadow::String*>(s)->length;
++    return reinterpret_cast<JS::shadow::String*>(s)->length();
+ }
+ 
+ MOZ_ALWAYS_INLINE size_t
+ GetLinearStringLength(JSLinearString* s)
+ {
+-    return reinterpret_cast<JS::shadow::String*>(s)->length;
++    return reinterpret_cast<JS::shadow::String*>(s)->length();
+ }
+ 
+ MOZ_ALWAYS_INLINE bool
+ LinearStringHasLatin1Chars(JSLinearString* s)
+ {
+-    return reinterpret_cast<JS::shadow::String*>(s)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
++    return reinterpret_cast<JS::shadow::String*>(s)->flags() & JS::shadow::String::LATIN1_CHARS_BIT;
+ }
+ 
+ MOZ_ALWAYS_INLINE bool
+ AtomHasLatin1Chars(JSAtom* atom)
+ {
+-    return reinterpret_cast<JS::shadow::String*>(atom)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
++    return reinterpret_cast<JS::shadow::String*>(atom)->flags() & JS::shadow::String::LATIN1_CHARS_BIT;
+ }
+ 
+ MOZ_ALWAYS_INLINE bool
+ StringHasLatin1Chars(JSString* s)
+ {
+-    return reinterpret_cast<JS::shadow::String*>(s)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
++    return reinterpret_cast<JS::shadow::String*>(s)->flags() & JS::shadow::String::LATIN1_CHARS_BIT;
+ }
+ 
+ MOZ_ALWAYS_INLINE const JS::Latin1Char*
+ GetLatin1LinearStringChars(const JS::AutoRequireNoGC& nogc, JSLinearString* linear)
+ {
+     MOZ_ASSERT(LinearStringHasLatin1Chars(linear));
+ 
+     using JS::shadow::String;
+     String* s = reinterpret_cast<String*>(linear);
+-    if (s->flags & String::INLINE_CHARS_BIT)
++    if (s->flags() & String::INLINE_CHARS_BIT)
+         return s->inlineStorageLatin1;
+     return s->nonInlineCharsLatin1;
+ }
+ 
+ MOZ_ALWAYS_INLINE const char16_t*
+ GetTwoByteLinearStringChars(const JS::AutoRequireNoGC& nogc, JSLinearString* linear)
+ {
+     MOZ_ASSERT(!LinearStringHasLatin1Chars(linear));
+ 
+     using JS::shadow::String;
+     String* s = reinterpret_cast<String*>(linear);
+-    if (s->flags & String::INLINE_CHARS_BIT)
++    if (s->flags() & String::INLINE_CHARS_BIT)
+         return s->inlineStorageTwoByte;
+     return s->nonInlineCharsTwoByte;
+ }
+ 
+ MOZ_ALWAYS_INLINE JSLinearString*
+ AtomToLinearString(JSAtom* atom)
+ {
+     return reinterpret_cast<JSLinearString*>(atom);
+@@ -891,34 +891,34 @@ GetTwoByteAtomChars(const JS::AutoRequir
+ }
+ 
+ MOZ_ALWAYS_INLINE bool
+ IsExternalString(JSString* str, const JSStringFinalizer** fin, const char16_t** chars)
+ {
+     using JS::shadow::String;
+     String* s = reinterpret_cast<String*>(str);
+ 
+-    if ((s->flags & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS)
++    if ((s->flags() & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS)
+         return false;
+ 
+     MOZ_ASSERT(JS_IsExternalString(str));
+     *fin = s->externalFinalizer;
+     *chars = s->nonInlineCharsTwoByte;
+     return true;
+ }
+ 
+ JS_FRIEND_API(JSLinearString*)
+ StringToLinearStringSlow(JSContext* cx, JSString* str);
+ 
+ MOZ_ALWAYS_INLINE JSLinearString*
+ StringToLinearString(JSContext* cx, JSString* str)
+ {
+     using JS::shadow::String;
+     String* s = reinterpret_cast<String*>(str);
+-    if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT)))
++    if (MOZ_UNLIKELY(!(s->flags() & String::LINEAR_BIT)))
+         return StringToLinearStringSlow(cx, str);
+     return reinterpret_cast<JSLinearString*>(str);
+ }
+ 
+ template<typename CharType>
+ MOZ_ALWAYS_INLINE void
+ CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0);
+ 
+diff --git a/js/src/vm/StringType-inl.h b/js/src/vm/StringType-inl.h
+--- a/js/src/vm/StringType-inl.h
++++ b/js/src/vm/StringType-inl.h
+@@ -92,23 +92,37 @@ JSString::validateLength(JSContext* mayb
+     if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
+         js::ReportAllocationOverflow(maybecx);
+         return false;
+     }
+ 
+     return true;
+ }
+ 
++template<>
++MOZ_ALWAYS_INLINE const char16_t*
++JSString::nonInlineCharsRaw() const
++{
++    return d.s.u2.nonInlineCharsTwoByte;
++}
++
++template<>
++MOZ_ALWAYS_INLINE const JS::Latin1Char*
++JSString::nonInlineCharsRaw() const
++{
++    return d.s.u2.nonInlineCharsLatin1;
++}
++
+ MOZ_ALWAYS_INLINE void
+ JSRope::init(JSContext* cx, JSString* left, JSString* right, size_t length)
+ {
+-    d.u1.length = length;
+-    d.u1.flags = INIT_ROPE_FLAGS;
+     if (left->hasLatin1Chars() && right->hasLatin1Chars())
+-        d.u1.flags |= LATIN1_CHARS_BIT;
++        setLengthAndFlags(length, INIT_ROPE_FLAGS | LATIN1_CHARS_BIT);
++    else
++        setLengthAndFlags(length, INIT_ROPE_FLAGS);
+     d.s.u2.left = left;
+     d.s.u3.right = right;
+ 
+     // Post-barrier by inserting into the whole cell buffer if either
+     // this -> left or this -> right is a tenured -> nursery edge.
+     if (isTenured()) {
+         js::gc::StoreBuffer* sb = left->storeBuffer();
+         if (!sb)
+@@ -134,23 +148,22 @@ JSRope::new_(JSContext* cx,
+     return str;
+ }
+ 
+ MOZ_ALWAYS_INLINE void
+ JSDependentString::init(JSContext* cx, JSLinearString* base, size_t start,
+                         size_t length)
+ {
+     MOZ_ASSERT(start + length <= base->length());
+-    d.u1.length = length;
+     JS::AutoCheckCannotGC nogc;
+     if (base->hasLatin1Chars()) {
+-        d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
++        setLengthAndFlags(length, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
+         d.s.u2.nonInlineCharsLatin1 = base->latin1Chars(nogc) + start;
+     } else {
+-        d.u1.flags = DEPENDENT_FLAGS;
++        setLengthAndFlags(length, DEPENDENT_FLAGS);
+         d.s.u2.nonInlineCharsTwoByte = base->twoByteChars(nogc) + start;
+     }
+     d.s.u3.base = base;
+     if (isTenured() && !base->isTenured())
+         base->storeBuffer()->putWholeCell(this);
+ }
+ 
+ MOZ_ALWAYS_INLINE JSLinearString*
+@@ -201,26 +214,24 @@ JSDependentString::new_(JSContext* cx, J
+         return nullptr;
+     str->init(cx, base, start, length);
+     return str;
+ }
+ 
+ MOZ_ALWAYS_INLINE void
+ JSFlatString::init(const char16_t* chars, size_t length)
+ {
+-    d.u1.length = length;
+-    d.u1.flags = INIT_FLAT_FLAGS;
++    setLengthAndFlags(length, INIT_FLAT_FLAGS);
+     d.s.u2.nonInlineCharsTwoByte = chars;
+ }
+ 
+ MOZ_ALWAYS_INLINE void
+ JSFlatString::init(const JS::Latin1Char* chars, size_t length)
+ {
+-    d.u1.length = length;
+-    d.u1.flags = INIT_FLAT_FLAGS | LATIN1_CHARS_BIT;
++    setLengthAndFlags(length, INIT_FLAT_FLAGS | LATIN1_CHARS_BIT);
+     d.s.u2.nonInlineCharsLatin1 = chars;
+ }
+ 
+ template <js::AllowGC allowGC, typename CharT>
+ MOZ_ALWAYS_INLINE JSFlatString*
+ JSFlatString::new_(JSContext* cx, const CharT* chars, size_t length)
+ {
+     MOZ_ASSERT(chars[length] == CharT(0));
+@@ -289,58 +300,53 @@ JSFatInlineString::new_(JSContext* cx)
+     return js::Allocate<JSFatInlineString, allowGC>(cx, js::gc::DefaultHeap);
+ }
+ 
+ template<>
+ MOZ_ALWAYS_INLINE JS::Latin1Char*
+ JSThinInlineString::init<JS::Latin1Char>(size_t length)
+ {
+     MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
+-    d.u1.length = length;
+-    d.u1.flags = INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT;
++    setLengthAndFlags(length, INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT);
+     return d.inlineStorageLatin1;
+ }
+ 
+ template<>
+ MOZ_ALWAYS_INLINE char16_t*
+ JSThinInlineString::init<char16_t>(size_t length)
+ {
+     MOZ_ASSERT(lengthFits<char16_t>(length));
+-    d.u1.length = length;
+-    d.u1.flags = INIT_THIN_INLINE_FLAGS;
++    setLengthAndFlags(length, INIT_THIN_INLINE_FLAGS);
+     return d.inlineStorageTwoByte;
+ }
+ 
+ template<>
+ MOZ_ALWAYS_INLINE JS::Latin1Char*
+ JSFatInlineString::init<JS::Latin1Char>(size_t length)
+ {
+     MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
+-    d.u1.length = length;
+-    d.u1.flags = INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT;
++    setLengthAndFlags(length, INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT);
+     return d.inlineStorageLatin1;
+ }
+ 
+ template<>
+ MOZ_ALWAYS_INLINE char16_t*
+ JSFatInlineString::init<char16_t>(size_t length)
+ {
+     MOZ_ASSERT(lengthFits<char16_t>(length));
+-    d.u1.length = length;
+-    d.u1.flags = INIT_FAT_INLINE_FLAGS;
++    setLengthAndFlags(length, INIT_FAT_INLINE_FLAGS);
+     return d.inlineStorageTwoByte;
+ }
+ 
+ MOZ_ALWAYS_INLINE void
+ JSExternalString::init(const char16_t* chars, size_t length, const JSStringFinalizer* fin)
+ {
+     MOZ_ASSERT(fin);
+     MOZ_ASSERT(fin->finalize);
+-    d.u1.length = length;
+-    d.u1.flags = EXTERNAL_FLAGS;
++    setLengthAndFlags(length, EXTERNAL_FLAGS);
+     d.s.u2.nonInlineCharsTwoByte = chars;
+     d.s.u3.externalFinalizer = fin;
+ }
+ 
+ MOZ_ALWAYS_INLINE JSExternalString*
+ JSExternalString::new_(JSContext* cx, const char16_t* chars, size_t length,
+                        const JSStringFinalizer* fin)
+ {
+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
+@@ -207,17 +207,17 @@ JSString::dumpRepresentation(js::Generic
+     else if (isFlat())          asFlat()        .dumpRepresentation(out, indent);
+     else
+         MOZ_CRASH("Unexpected JSString representation");
+ }
+ 
+ void
+ JSString::dumpRepresentationHeader(js::GenericPrinter& out, const char* subclass) const
+ {
+-    uint32_t flags = d.u1.flags;
++    uint32_t flags = JSString::flags();
+     // Print the string's address as an actual C++ expression, to facilitate
+     // copy-and-paste into a debugger.
+     out.printf("((%s*) %p) length: %zu  flags: 0x%x", subclass, this, length(), flags);
+     if (flags & LINEAR_BIT)             out.put(" LINEAR");
+     if (flags & HAS_BASE_BIT)           out.put(" HAS_BASE");
+     if (flags & INLINE_CHARS_BIT)       out.put(" INLINE_CHARS");
+     if (flags & NON_ATOM_BIT)           out.put(" NON_ATOM");
+     else                                out.put(" (ATOM)");
+@@ -513,20 +513,18 @@ JSRope::flattenInternal(JSContext* maybe
+      * pointers in the JSDependentStrings are still valid.
+      */
+     const size_t wholeLength = length();
+     size_t wholeCapacity;
+     CharT* wholeChars;
+     JSString* str = this;
+     CharT* pos;
+ 
+-    /*
+-     * JSString::flattenData is a tagged pointer to the parent node.
+-     * The tag indicates what to do when we return to the parent.
+-     */
++    // JSString::setFlattenData() is used to store a tagged pointer to the
++    // parent node. The tag indicates what to do when we return to the parent.
+     static const uintptr_t Tag_Mask = 0x3;
+     static const uintptr_t Tag_FinishNode = 0x0;
+     static const uintptr_t Tag_VisitRightChild = 0x1;
+ 
+     AutoCheckCannotGC nogc;
+ 
+     gc::StoreBuffer* bufferIfNursery = storeBuffer();
+ 
+@@ -551,29 +549,30 @@ JSRope::flattenInternal(JSContext* maybe
+                 if (b == WithIncrementalBarrier) {
+                     JSString::writeBarrierPre(str->d.s.u2.left);
+                     JSString::writeBarrierPre(str->d.s.u3.right);
+                 }
+                 JSString* child = str->d.s.u2.left;
+                 // 'child' will be post-barriered during the later traversal.
+                 MOZ_ASSERT(child->isRope());
+                 str->setNonInlineChars(wholeChars);
+-                child->d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
++                child->setFlattenData(uintptr_t(str) | Tag_VisitRightChild);
+                 str = child;
+             }
+             if (b == WithIncrementalBarrier) {
+                 JSString::writeBarrierPre(str->d.s.u2.left);
+                 JSString::writeBarrierPre(str->d.s.u3.right);
+             }
+             str->setNonInlineChars(wholeChars);
+-            pos = wholeChars + left.d.u1.length;
++            uint32_t left_len = left.length();
++            pos = wholeChars + left_len;
+             if (IsSame<CharT, char16_t>::value)
+-                left.d.u1.flags = DEPENDENT_FLAGS;
++                left.setLengthAndFlags(left_len, DEPENDENT_FLAGS);
+             else
+-                left.d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
++                left.setLengthAndFlags(left_len, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
+             left.d.s.u3.base = (JSLinearString*)this;  /* will be true on exit */
+             Nursery& nursery = runtimeFromMainThread()->gc.nursery();
+             bool inTenured = !bufferIfNursery;
+             if (!inTenured && left.isTenured()) {
+                 // tenured leftmost child is giving its chars buffer to the
+                 // nursery-allocated root node.
+                 nursery.registerMallocedBuffer(wholeChars);
+                 // leftmost child -> root is a tenured -> nursery edge.
+@@ -609,54 +608,53 @@ JSRope::flattenInternal(JSContext* maybe
+             JSString::writeBarrierPre(str->d.s.u2.left);
+             JSString::writeBarrierPre(str->d.s.u3.right);
+         }
+ 
+         JSString& left = *str->d.s.u2.left;
+         str->setNonInlineChars(pos);
+         if (left.isRope()) {
+             /* Return to this node when 'left' done, then goto visit_right_child. */
+-            left.d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
++            left.setFlattenData(uintptr_t(str) | Tag_VisitRightChild);
+             str = &left;
+             goto first_visit_node;
+         }
+         CopyChars(pos, left.asLinear());
+         pos += left.length();
+     }
+     visit_right_child: {
+         JSString& right = *str->d.s.u3.right;
+         if (right.isRope()) {
+             /* Return to this node when 'right' done, then goto finish_node. */
+-            right.d.u1.flattenData = uintptr_t(str) | Tag_FinishNode;
++            right.setFlattenData(uintptr_t(str) | Tag_FinishNode);
+             str = &right;
+             goto first_visit_node;
+         }
+         CopyChars(pos, right.asLinear());
+         pos += right.length();
+     }
+ 
+     finish_node: {
+         if (str == this) {
+             MOZ_ASSERT(pos == wholeChars + wholeLength);
+             *pos = '\0';
+-            str->d.u1.length = wholeLength;
+             if (IsSame<CharT, char16_t>::value)
+-                str->d.u1.flags = EXTENSIBLE_FLAGS;
++                str->setLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS);
+             else
+-                str->d.u1.flags = EXTENSIBLE_FLAGS | LATIN1_CHARS_BIT;
++                str->setLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS | LATIN1_CHARS_BIT);
+             str->setNonInlineChars(wholeChars);
+             str->d.s.u3.capacity = wholeCapacity;
+             return &this->asFlat();
+         }
+-        uintptr_t flattenData = str->d.u1.flattenData;
++        uintptr_t flattenData;
++        uint32_t len = pos - str->nonInlineCharsRaw<CharT>();
+         if (IsSame<CharT, char16_t>::value)
+-            str->d.u1.flags = DEPENDENT_FLAGS;
++            flattenData = str->unsetFlattenData(len, DEPENDENT_FLAGS);
+         else
+-            str->d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
+-        str->d.u1.length = pos - str->asLinear().nonInlineChars<CharT>(nogc);
++            flattenData = str->unsetFlattenData(len, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
+         str->d.s.u3.base = (JSLinearString*)this;       /* will be true on exit */
+ 
+         // Every interior (rope) node in the rope's tree will be visited during
+         // the traversal and post-barriered here, so earlier additions of
+         // dependent.base -> root pointers are handled by this barrier as well.
+         //
+         // The only time post-barriers need do anything is when the root is in
+         // the nursery. Note that the root was a rope but will be an extensible
+@@ -801,19 +799,19 @@ JSDependentString::undependInternal(JSCo
+     s[n] = '\0';
+     setNonInlineChars<CharT>(s.release());
+ 
+     /*
+      * Transform *this into an undepended string so 'base' will remain rooted
+      * for the benefit of any other dependent string that depends on *this.
+      */
+     if (IsSame<CharT, Latin1Char>::value)
+-        d.u1.flags = UNDEPENDED_FLAGS | LATIN1_CHARS_BIT;
++        setLengthAndFlags(n, UNDEPENDED_FLAGS | LATIN1_CHARS_BIT);
+     else
+-        d.u1.flags = UNDEPENDED_FLAGS;
++        setLengthAndFlags(n, UNDEPENDED_FLAGS);
+ 
+     return &this->asFlat();
+ }
+ 
+ JSFlatString*
+ JSDependentString::undepend(JSContext* cx)
+ {
+     MOZ_ASSERT(JSString::isDependent());
+@@ -1378,18 +1376,18 @@ JSExternalString::ensureFlat(JSContext* 
+     }
+ 
+     // Release the external chars.
+     finalize(cx->runtime()->defaultFreeOp());
+ 
+     // Transform the string into a non-external, flat string. Note that the
+     // resulting string will still be in an AllocKind::EXTERNAL_STRING arena,
+     // but will no longer be an external string.
++    setLengthAndFlags(n, INIT_FLAT_FLAGS);
+     setNonInlineChars<char16_t>(s.release());
+-    d.u1.flags = INIT_FLAT_FLAGS;
+ 
+     return &this->asFlat();
+ }
+ 
+ #if defined(DEBUG) || defined(JS_JITSPEW)
+ void
+ JSAtom::dump(js::GenericPrinter& out)
+ {
+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
+@@ -162,20 +162,20 @@ class JSString : public js::gc::Cell
+     static const size_t NUM_INLINE_CHARS_LATIN1   = 2 * sizeof(void*) / sizeof(JS::Latin1Char);
+     static const size_t NUM_INLINE_CHARS_TWO_BYTE = 2 * sizeof(void*) / sizeof(char16_t);
+ 
+     /* Fields only apply to string types commented on the right. */
+     struct Data
+     {
+         union {
+             struct {
+-                uint32_t           flags;               /* JSString */
+-                uint32_t           length;              /* JSString */
++                uint32_t           flags_;              /* JSString */
++                uint32_t           length_;             /* JSString */
+             };
+-            uintptr_t              flattenData;         /* JSRope (temporary while flattening) */
++            uintptr_t              flattenData_;        /* JSRope (temporary while flattening) */
+         } u1;
+         union {
+             union {
+                 /* JS(Fat)InlineString */
+                 JS::Latin1Char     inlineStorageLatin1[NUM_INLINE_CHARS_LATIN1];
+                 char16_t           inlineStorageTwoByte[NUM_INLINE_CHARS_TWO_BYTE];
+             };
+             struct {
+@@ -312,19 +312,19 @@ class JSString : public js::gc::Cell
+                       "Inline Latin1 chars must fit in a JSString");
+         static_assert(sizeof(JSString) ==
+                       (offsetof(JSString, d.inlineStorageTwoByte) +
+                        NUM_INLINE_CHARS_TWO_BYTE * sizeof(char16_t)),
+                       "Inline char16_t chars must fit in a JSString");
+ 
+         /* Ensure js::shadow::String has the same layout. */
+         using JS::shadow::String;
+-        static_assert(offsetof(JSString, d.u1.length) == offsetof(String, length),
++        static_assert(offsetof(JSString, d.u1.length_) == offsetof(String, length_),
+                       "shadow::String length offset must match JSString");
+-        static_assert(offsetof(JSString, d.u1.flags) == offsetof(String, flags),
++        static_assert(offsetof(JSString, d.u1.flags_) == offsetof(String, flags_),
+                       "shadow::String flags offset must match JSString");
+         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(String, nonInlineCharsLatin1),
+                       "shadow::String nonInlineChars offset must match JSString");
+         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(String, nonInlineCharsTwoByte),
+                       "shadow::String nonInlineChars offset must match JSString");
+         static_assert(offsetof(JSString, d.s.u3.externalFinalizer) == offsetof(String, externalFinalizer),
+                       "shadow::String externalFinalizer offset must match JSString");
+         static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(String, inlineStorageLatin1),
+@@ -350,85 +350,127 @@ class JSString : public js::gc::Cell
+ 
+     friend class js::gc::RelocationOverlay;
+ 
+   protected:
+     template <typename CharT>
+     MOZ_ALWAYS_INLINE
+     void setNonInlineChars(const CharT* chars);
+ 
++    MOZ_ALWAYS_INLINE
++    uint32_t flags() const {
++        return d.u1.flags_;
++    }
++
+   public:
+-    /* All strings have length. */
++    MOZ_ALWAYS_INLINE
++    size_t length() const {
++        return d.u1.length_;
++    }
++
++  protected:
++    MOZ_ALWAYS_INLINE
++    void setFlagBit(uint32_t flags) {
++        d.u1.flags_ |= flags;
++    }
+ 
+     MOZ_ALWAYS_INLINE
+-    size_t length() const {
+-        return d.u1.length;
++    void clearFlagBit(uint32_t flags) {
++        d.u1.flags_ &= ~flags;
+     }
+ 
+     MOZ_ALWAYS_INLINE
++    void setLengthAndFlags(uint32_t len, uint32_t flags) {
++        d.u1.flags_ = flags;
++        d.u1.length_ = len;
++    }
++
++    // Flatten algorithm stores a temporary word by clobbering flags. This is
++    // not GC-safe and user must ensure JSString::flags are never checked
++    // (including by asserts) while this data is stored.
++    MOZ_ALWAYS_INLINE
++    void setFlattenData(uintptr_t data) {
++        d.u1.flattenData_ = data;
++    }
++
++    // To get back the data, values to safely re-initialize clobbered flags
++    // must be provided.
++    MOZ_ALWAYS_INLINE
++    uintptr_t unsetFlattenData(uint32_t len, uint32_t flags) {
++        uintptr_t data = d.u1.flattenData_;
++        setLengthAndFlags(len, flags);
++        return data;
++    }
++
++    // Get correct non-inline chars enum arm for given type
++    template <typename CharT> MOZ_ALWAYS_INLINE const CharT* nonInlineCharsRaw() const;
++
++  public:
++
++    MOZ_ALWAYS_INLINE
+     bool empty() const {
+-        return d.u1.length == 0;
++        return length() == 0;
+     }
+ 
+     inline bool getChar(JSContext* cx, size_t index, char16_t* code);
+ 
+     /* Strings have either Latin1 or TwoByte chars. */
+     bool hasLatin1Chars() const {
+-        return d.u1.flags & LATIN1_CHARS_BIT;
++        return flags() & LATIN1_CHARS_BIT;
+     }
+     bool hasTwoByteChars() const {
+-        return !(d.u1.flags & LATIN1_CHARS_BIT);
++        return !(flags() & LATIN1_CHARS_BIT);
+     }
+ 
+     /* Strings might contain cached indexes. */
+     bool hasIndexValue() const {
+-        return d.u1.flags & INDEX_VALUE_BIT;
++        return flags() & INDEX_VALUE_BIT;
+     }
+     uint32_t getIndexValue() const {
+         MOZ_ASSERT(hasIndexValue());
+         MOZ_ASSERT(isFlat());
+-        return d.u1.flags >> INDEX_VALUE_SHIFT;
++        return flags() >> INDEX_VALUE_SHIFT;
+     }
+ 
+     /* Fallible conversions to more-derived string types. */
+ 
+     inline JSLinearString* ensureLinear(JSContext* cx);
+     JSFlatString* ensureFlat(JSContext* cx);
+ 
+     static bool ensureLinear(JSContext* cx, JSString* str) {
+         return str->ensureLinear(cx) != nullptr;
+     }
+ 
+     /* Type query and debug-checked casts */
+ 
+     MOZ_ALWAYS_INLINE
+     bool isRope() const {
+-        return !(d.u1.flags & LINEAR_BIT);
++        return !(flags() & LINEAR_BIT);
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSRope& asRope() const {
+         MOZ_ASSERT(isRope());
+         return *(JSRope*)this;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isLinear() const {
+-        return d.u1.flags & LINEAR_BIT;
++        return flags() & LINEAR_BIT;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSLinearString& asLinear() const {
+         MOZ_ASSERT(JSString::isLinear());
+         return *(JSLinearString*)this;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isDependent() const {
+-        return (d.u1.flags & TYPE_FLAGS_MASK) == DEPENDENT_FLAGS;
++        return (flags() & TYPE_FLAGS_MASK) == DEPENDENT_FLAGS;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSDependentString& asDependent() const {
+         MOZ_ASSERT(isDependent());
+         return *(JSDependentString*)this;
+     }
+ 
+@@ -440,65 +482,65 @@ class JSString : public js::gc::Cell
+     MOZ_ALWAYS_INLINE
+     JSFlatString& asFlat() const {
+         MOZ_ASSERT(isFlat());
+         return *(JSFlatString*)this;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isExtensible() const {
+-        return (d.u1.flags & TYPE_FLAGS_MASK) == EXTENSIBLE_FLAGS;
++        return (flags() & TYPE_FLAGS_MASK) == EXTENSIBLE_FLAGS;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSExtensibleString& asExtensible() const {
+         MOZ_ASSERT(isExtensible());
+         return *(JSExtensibleString*)this;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isInline() const {
+-        return d.u1.flags & INLINE_CHARS_BIT;
++        return flags() & INLINE_CHARS_BIT;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSInlineString& asInline() const {
+         MOZ_ASSERT(isInline());
+         return *(JSInlineString*)this;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isFatInline() const {
+-        return (d.u1.flags & FAT_INLINE_MASK) == FAT_INLINE_MASK;
++        return (flags() & FAT_INLINE_MASK) == FAT_INLINE_MASK;
+     }
+ 
+     /* For hot code, prefer other type queries. */
+     bool isExternal() const {
+-        return (d.u1.flags & TYPE_FLAGS_MASK) == EXTERNAL_FLAGS;
++        return (flags() & TYPE_FLAGS_MASK) == EXTERNAL_FLAGS;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSExternalString& asExternal() const {
+         MOZ_ASSERT(isExternal());
+         return *(JSExternalString*)this;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isUndepended() const {
+-        return (d.u1.flags & TYPE_FLAGS_MASK) == UNDEPENDED_FLAGS;
++        return (flags() & TYPE_FLAGS_MASK) == UNDEPENDED_FLAGS;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isAtom() const {
+-        return !(d.u1.flags & NON_ATOM_BIT);
++        return !(flags() & NON_ATOM_BIT);
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isPermanentAtom() const {
+-        return (d.u1.flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
++        return (flags() & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSAtom& asAtom() const {
+         MOZ_ASSERT(isAtom());
+         return *(JSAtom*)this;
+     }
+ 
+@@ -512,17 +554,17 @@ class JSString : public js::gc::Cell
+ 
+     // Fills |array| with various strings that represent the different string
+     // kinds and character encodings.
+     static bool fillWithRepresentatives(JSContext* cx, js::HandleArrayObject array);
+ 
+     /* Only called by the GC for dependent or undepended strings. */
+ 
+     inline bool hasBase() const {
+-        return d.u1.flags & HAS_BASE_BIT;
++        return flags() & HAS_BASE_BIT;
+     }
+ 
+     inline JSLinearString* base() const;
+ 
+     void traceBase(JSTracer* trc);
+ 
+     /* Only called by the GC for strings with the AllocKind::STRING kind. */
+ 
+@@ -530,20 +572,20 @@ class JSString : public js::gc::Cell
+ 
+     /* Gets the number of bytes that the chars take on the heap. */
+ 
+     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+ 
+     /* Offsets for direct field from jit code. */
+ 
+     static size_t offsetOfLength() {
+-        return offsetof(JSString, d.u1.length);
++        return offsetof(JSString, d.u1.length_);
+     }
+     static size_t offsetOfFlags() {
+-        return offsetof(JSString, d.u1.flags);
++        return offsetof(JSString, d.u1.flags_);
+     }
+ 
+   private:
+     // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
+     // to call the method below.
+     friend class js::jit::MacroAssembler;
+     static size_t offsetOfNonInlineChars() {
+         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) ==
+@@ -926,17 +968,17 @@ class JSFlatString : public JSLinearStri
+ 
+         if (hasIndexValue() || index > UINT16_MAX)
+             return;
+ 
+         mozilla::DebugOnly<uint32_t> containedIndex;
+         MOZ_ASSERT(isIndexSlow(&containedIndex));
+         MOZ_ASSERT(index == containedIndex);
+ 
+-        d.u1.flags |= (index << INDEX_VALUE_SHIFT) | INDEX_VALUE_BIT;
++        setFlagBit((index << INDEX_VALUE_SHIFT) | INDEX_VALUE_BIT);
+     }
+ 
+     /*
+      * Returns a property name represented by this string, or null on failure.
+      * You must verify that this is not an index per isIndex before calling
+      * this method.
+      */
+     inline js::PropertyName* toPropertyName(JSContext* cx);
+@@ -1162,29 +1204,29 @@ class JSAtom : public JSFlatString
+     bool isPermanent() const {
+         return JSString::isPermanentAtom();
+     }
+ 
+     // Transform this atom into a permanent atom. This is only done during
+     // initialization of the runtime. Permanent atoms are always pinned.
+     MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
+         MOZ_ASSERT(static_cast<JSString*>(this)->isAtom());
+-        d.u1.flags |= PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT;
++        setFlagBit(PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT);
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     bool isPinned() const {
+-        return d.u1.flags & PINNED_ATOM_BIT;
++        return flags() & PINNED_ATOM_BIT;
+     }
+ 
+     // Mark the atom as pinned. For use by atomization only.
+     MOZ_ALWAYS_INLINE void setPinned() {
+         MOZ_ASSERT(static_cast<JSString*>(this)->isAtom());
+         MOZ_ASSERT(!isPinned());
+-        d.u1.flags |= PINNED_ATOM_BIT;
++        setFlagBit(PINNED_ATOM_BIT);
+     }
+ 
+     inline js::HashNumber hash() const;
+     inline void initHash(js::HashNumber hash);
+ 
+ #if defined(DEBUG) || defined(JS_JITSPEW)
+     void dump(js::GenericPrinter& out);
+     void dump();
+@@ -1252,28 +1294,28 @@ JSAtom::initHash(js::HashNumber hash)
+         return static_cast<js::FatInlineAtom*>(this)->initHash(hash);
+     return static_cast<js::NormalAtom*>(this)->initHash(hash);
+ }
+ 
+ MOZ_ALWAYS_INLINE JSAtom*
+ JSFlatString::morphAtomizedStringIntoAtom(js::HashNumber hash)
+ {
+     MOZ_ASSERT(!isAtom());
+-    d.u1.flags &= ~NON_ATOM_BIT;
++    clearFlagBit(NON_ATOM_BIT);
+     JSAtom* atom = &asAtom();
+     atom->initHash(hash);
+     return atom;
+ }
+ 
+ MOZ_ALWAYS_INLINE JSAtom*
+ JSFlatString::morphAtomizedStringIntoPermanentAtom(js::HashNumber hash)
+ {
+     MOZ_ASSERT(!isAtom());
+-    d.u1.flags |= PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT;
+-    d.u1.flags &= ~NON_ATOM_BIT;
++    setFlagBit(PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT);
++    clearFlagBit(NON_ATOM_BIT);
+     JSAtom* atom = &asAtom();
+     atom->initHash(hash);
+     return atom;
+ }
+ 
+ namespace js {
+ 
+ class StaticStrings
+

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

@@ -0,0 +1,1047 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1533234736 25200
+# Node ID 819b923159847ebf0227a910e966490f4f9dc177
+# Parent  4ed363b9ebbbf6384f1ea283cbabb132ed9762cb
+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
+field with the low bits reserved for the GC and uses these bits for
+relocation mechanism.
+
+- JSString now stores flags in a uintptr_t. On 32-bit platforms, a
+  second field is used to hold length.
+- Redefine JSString flag bit positions to avoid cell reserved bits.
+- Forwarded Cells are now indicated by a reserved flag instead of a
+  magic invalid-pointer-like value.
+- gc::RelocationOverlay now extends gc::Cell
+- Update js::Symbol, js::Scope and js::BigInt fields to be compatible.
+
+MozReview-Commit-ID: Cs5OavbHmqK
+
+diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h
+--- a/js/public/HeapAPI.h
++++ b/js/public/HeapAPI.h
+@@ -21,22 +21,16 @@ namespace js {
+ 
+ JS_FRIEND_API(bool)
+ CurrentThreadCanAccessZone(JS::Zone* zone);
+ 
+ namespace gc {
+ 
+ struct Cell;
+ 
+-/*
+- * The low bit is set so this should never equal a normal pointer, and the high
+- * bit is set so this should never equal the upper 32 bits of a 64-bit pointer.
+- */
+-const uint32_t Relocated = uintptr_t(0xbad0bad1);
+-
+ const size_t ArenaShift = 12;
+ const size_t ArenaSize = size_t(1) << ArenaShift;
+ const size_t ArenaMask = ArenaSize - 1;
+ 
+ #ifdef JS_GC_SMALL_CHUNK_SIZE
+ const size_t ChunkShift = 18;
+ #else
+ const size_t ChunkShift = 20;
+@@ -200,54 +194,57 @@ struct Zone
+ 
+     static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) {
+         return reinterpret_cast<JS::shadow::Zone*>(zone);
+     }
+ };
+ 
+ struct String
+ {
+-    static const uint32_t NON_ATOM_BIT     = JS_BIT(0);
+-    static const uint32_t LINEAR_BIT       = JS_BIT(1);
+-    static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
+-    static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
+-    static const uint32_t EXTERNAL_FLAGS   = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
+-    static const uint32_t TYPE_FLAGS_MASK  = JS_BIT(6) - 1;
+-    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(5);
+-    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(5);
++    static const uint32_t NON_ATOM_BIT     = JS_BIT(1);
++    static const uint32_t LINEAR_BIT       = JS_BIT(4);
++    static const uint32_t INLINE_CHARS_BIT = JS_BIT(6);
++    static const uint32_t LATIN1_CHARS_BIT = JS_BIT(9);
++    static const uint32_t EXTERNAL_FLAGS   = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(8);
++    static const uint32_t TYPE_FLAGS_MASK  = JS_BITMASK(9) - JS_BIT(2) - JS_BIT(0);
++    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(8);
++    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(8);
+ 
+-    uint32_t flags_;
++    uintptr_t flags_;
++  #if JS_BITS_PER_WORD == 32
+     uint32_t length_;
++  #endif
++
+     union {
+         const JS::Latin1Char* nonInlineCharsLatin1;
+         const char16_t* nonInlineCharsTwoByte;
+         JS::Latin1Char inlineStorageLatin1[1];
+         char16_t inlineStorageTwoByte[1];
+     };
+     const JSStringFinalizer* externalFinalizer;
+ 
+     inline uint32_t flags() const {
+-        return flags_;
++        return uint32_t(flags_);
+     }
+     inline uint32_t length() const {
++  #if JS_BITS_PER_WORD == 32
+         return length_;
+-    }
+-
+-    static bool nurseryCellIsString(const js::gc::Cell* cell) {
+-        MOZ_ASSERT(IsInsideNursery(cell));
+-        return reinterpret_cast<const String*>(cell)->flags() & NON_ATOM_BIT;
++  #else
++        return uint32_t(flags_ >> 32);
++  #endif
+     }
+ 
+     static bool isPermanentAtom(const js::gc::Cell* cell) {
+         uint32_t flags = reinterpret_cast<const String*>(cell)->flags();
+         return (flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
+     }
+ };
+ 
+ struct Symbol {
++    uintptr_t reserved_;
+     uint32_t code_;
+     static const uint32_t WellKnownAPILimit = 0x80000000;
+ 
+     static bool isWellKnownSymbol(const js::gc::Cell* cell) {
+         return reinterpret_cast<const Symbol*>(cell)->code_ < WellKnownAPILimit;
+     }
+ };
+ 
+diff --git a/js/src/gc/Cell.h b/js/src/gc/Cell.h
+--- a/js/src/gc/Cell.h
++++ b/js/src/gc/Cell.h
+@@ -43,20 +43,45 @@ TraceManuallyBarrieredGenericPointerEdge
+ namespace gc {
+ 
+ class Arena;
+ enum class AllocKind : uint8_t;
+ struct Chunk;
+ class StoreBuffer;
+ class TenuredCell;
+ 
+-// A GC cell is the base class for all GC things.
++// [SMDOC] GC Cell
++//
++// A GC cell is the base class for all GC things. All types allocated on the GC
++// heap extend either gc::Cell or gc::TenuredCell. If a type is always tenured,
++// prefer the TenuredCell class as base.
++//
++// The first word (a pointer or uintptr_t) of each Cell must reserve the low
++// Cell::ReservedBits bits for GC purposes. The remaining bits are available to
++// sub-classes and typically store a pointer to another gc::Cell.
++//
++// During moving GC operation a Cell may be marked as forwarded. This indicates
++// that a gc::RelocationOverlay is currently stored in the Cell's memory and
++// should be used to find the new location of the Cell.
+ struct alignas(gc::CellAlignBytes) Cell
+ {
+   public:
++    // The low bits of the first word of each Cell are reserved for GC flags.
++    static constexpr int ReservedBits = 2;
++    static constexpr uintptr_t RESERVED_MASK = JS_BITMASK(ReservedBits);
++
++    // Indicates if the cell is currently a RelocationOverlay
++    static constexpr uintptr_t FORWARD_BIT = JS_BIT(0);
++
++    // When a Cell is in the nursery, this will indicate if it is a JSString (1)
++    // or JSObject (0). When not in nursery, this bit is still reserved for
++    // JSString to use as JSString::NON_ATOM bit. This may be removed by Bug
++    // 1376646.
++    static constexpr uintptr_t JSSTRING_BIT = JS_BIT(1);
++
+     MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
+     MOZ_ALWAYS_INLINE const TenuredCell& asTenured() const;
+     MOZ_ALWAYS_INLINE TenuredCell& asTenured();
+ 
+     MOZ_ALWAYS_INLINE bool isMarkedAny() const;
+     MOZ_ALWAYS_INLINE bool isMarkedBlack() const;
+     MOZ_ALWAYS_INLINE bool isMarkedGray() const;
+ 
+@@ -72,16 +97,27 @@ struct alignas(gc::CellAlignBytes) Cell
+     // The StoreBuffer used to record incoming pointers from the tenured heap.
+     // This will return nullptr for a tenured cell.
+     inline StoreBuffer* storeBuffer() const;
+ 
+     inline JS::TraceKind getTraceKind() const;
+ 
+     static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
+ 
++    inline bool isForwarded() const {
++        uintptr_t firstWord = *reinterpret_cast<const uintptr_t*>(this);
++        return firstWord & FORWARD_BIT;
++    }
++
++    inline bool nurseryCellIsString() const {
++        MOZ_ASSERT(!isTenured());
++        uintptr_t firstWord = *reinterpret_cast<const uintptr_t*>(this);
++        return firstWord & JSSTRING_BIT;
++    }
++
+     template <class T>
+     inline bool is() const {
+         return getTraceKind() == JS::MapTypeToTraceKind<T>::kind;
+     }
+ 
+     template<class T>
+     inline T* as() {
+         // |this|-qualify the |is| call below to avoid compile errors with even
+@@ -250,17 +286,17 @@ Cell::storeBuffer() const
+     return chunk()->trailer.storeBuffer;
+ }
+ 
+ inline JS::TraceKind
+ Cell::getTraceKind() const
+ {
+     if (isTenured())
+         return asTenured().getTraceKind();
+-    if (JS::shadow::String::nurseryCellIsString(this))
++    if (nurseryCellIsString())
+         return JS::TraceKind::String;
+     return JS::TraceKind::Object;
+ }
+ 
+ /* static */ MOZ_ALWAYS_INLINE bool
+ Cell::needWriteBarrierPre(JS::Zone* zone) {
+     return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
+ }
+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
+@@ -216,16 +216,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/MacroAssembler.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"
+@@ -378,16 +379,27 @@ static const int IGC_MARK_SLICE_MULTIPLI
+ const AllocKind gc::slotsToThingKind[] = {
+     /*  0 */ AllocKind::OBJECT0,  AllocKind::OBJECT2,  AllocKind::OBJECT2,  AllocKind::OBJECT4,
+     /*  4 */ AllocKind::OBJECT4,  AllocKind::OBJECT8,  AllocKind::OBJECT8,  AllocKind::OBJECT8,
+     /*  8 */ AllocKind::OBJECT8,  AllocKind::OBJECT12, AllocKind::OBJECT12, AllocKind::OBJECT12,
+     /* 12 */ AllocKind::OBJECT12, AllocKind::OBJECT16, AllocKind::OBJECT16, AllocKind::OBJECT16,
+     /* 16 */ AllocKind::OBJECT16
+ };
+ 
++// Check that reserved bits of a Cell are compatible with our typical allocators
++// since most derived classes will store a pointer in the first word.
++static_assert(js::detail::LIFO_ALLOC_ALIGN > JS_BITMASK(Cell::ReservedBits),
++              "Cell::ReservedBits should support LifoAlloc");
++static_assert(CellAlignBytes > JS_BITMASK(Cell::ReservedBits),
++              "Cell::ReservedBits should support gc::Cell");
++static_assert(sizeof(uintptr_t) > JS_BITMASK(Cell::ReservedBits),
++              "Cell::ReservedBits should support small malloc / aligned globals");
++static_assert(js::jit::CodeAlignment > JS_BITMASK(Cell::ReservedBits),
++              "Cell::ReservedBits should support JIT code");
++
+ static_assert(mozilla::ArrayLength(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT,
+               "We have defined a slot count for each kind.");
+ 
+ #define CHECK_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+     static_assert(sizeof(sizedType) >= SortedArenaList::MinThingSize, \
+                   #sizedType " is smaller than SortedArenaList::MinThingSize!"); \
+     static_assert(sizeof(sizedType) >= sizeof(FreeSpan), \
+                   #sizedType " is smaller than FreeSpan"); \
+@@ -2416,17 +2428,17 @@ RelocateArena(Arena* arena, SliceBudget&
+     for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
+         RelocateCell(zone, i.getCell(), thingKind, thingSize);
+         sliceBudget.step();
+     }
+ 
+ #ifdef DEBUG
+     for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
+         TenuredCell* src = i.getCell();
+-        MOZ_ASSERT(RelocationOverlay::isCellForwarded(src));
++        MOZ_ASSERT(src->isForwarded());
+         TenuredCell* dest = Forwarded(src);
+         MOZ_ASSERT(src->isMarkedBlack() == dest->isMarkedBlack());
+         MOZ_ASSERT(src->isMarkedGray() == dest->isMarkedGray());
+     }
+ #endif
+ }
+ 
+ static inline bool
+@@ -8482,18 +8494,18 @@ js::gc::AssertGCThingHasType(js::gc::Cel
+     if (!cell) {
+         MOZ_ASSERT(kind == JS::TraceKind::Null);
+         return;
+     }
+ 
+     MOZ_ASSERT(IsCellPointerValid(cell));
+ 
+     if (IsInsideNursery(cell)) {
+-        MOZ_ASSERT(kind == (JSString::nurseryCellIsString(cell) ? JS::TraceKind::String
+-                                                                : JS::TraceKind::Object));
++        MOZ_ASSERT(kind == (cell->nurseryCellIsString() ? JS::TraceKind::String
++                                                        : JS::TraceKind::Object));
+         return;
+     }
+ 
+     MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured().getAllocKind()) == kind);
+ }
+ #endif
+ 
+ #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h
+--- a/js/src/gc/GCInternals.h
++++ b/js/src/gc/GCInternals.h
+@@ -120,17 +120,17 @@ struct MovingTracer : JS::CallbackTracer
+     void onShapeEdge(Shape** shapep) override;
+     void onStringEdge(JSString** stringp) override;
+     void onScriptEdge(JSScript** scriptp) override;
+     void onLazyScriptEdge(LazyScript** lazyp) override;
+     void onBaseShapeEdge(BaseShape** basep) override;
+     void onScopeEdge(Scope** basep) override;
+     void onRegExpSharedEdge(RegExpShared** sharedp) override;
+     void onChild(const JS::GCCellPtr& thing) override {
+-        MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
++        MOZ_ASSERT(!thing.asCell()->isForwarded());
+     }
+ 
+ #ifdef DEBUG
+     TracerKind getTracerKind() const override { return TracerKind::Moving; }
+ #endif
+ 
+   private:
+     template <typename T>
+diff --git a/js/src/gc/Marking-inl.h b/js/src/gc/Marking-inl.h
+--- a/js/src/gc/Marking-inl.h
++++ b/js/src/gc/Marking-inl.h
+@@ -35,23 +35,22 @@ struct MightBeForwarded
+                               mozilla::IsBaseOf<js::Scope, T>::value ||
+                               mozilla::IsBaseOf<js::RegExpShared, T>::value;
+ };
+ 
+ template <typename T>
+ inline bool
+ IsForwarded(const T* t)
+ {
+-    const RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
+     if (!MightBeForwarded<T>::value) {
+-        MOZ_ASSERT(!overlay->isForwarded());
++        MOZ_ASSERT(!t->isForwarded());
+         return false;
+     }
+ 
+-    return overlay->isForwarded();
++    return t->isForwarded();
+ }
+ 
+ struct IsForwardedFunctor : public BoolDefaultAdaptor<Value, false> {
+     template <typename T> bool operator()(const T* t) { return IsForwarded(t); }
+ };
+ 
+ inline bool
+ IsForwarded(const JS::Value& value)
+@@ -88,35 +87,33 @@ MaybeForwarded(T t)
+         t = Forwarded(t);
+     return t;
+ }
+ 
+ inline void
+ RelocationOverlay::forwardTo(Cell* cell)
+ {
+     MOZ_ASSERT(!isForwarded());
+-    // The location of magic_ is important because it must never be valid to see
+-    // the value Relocated there in a GC thing that has not been moved.
+-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSObject, group_) + sizeof(uint32_t),
+-                  "RelocationOverlay::magic_ is in the wrong location");
+-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(js::Shape, base_) + sizeof(uint32_t),
+-                  "RelocationOverlay::magic_ is in the wrong location");
+-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSString, d.u1.length_),
+-                  "RelocationOverlay::magic_ is in the wrong location");
+-    magic_ = Relocated;
+-    newLocation_ = cell;
++
++    // Preserve old flags because nursery may check them before checking
++    // if this is a forwarded Cell.
++    //
++    // This is pretty terrible and we should find a better way to implement
++    // Cell::getTrackKind() that doesn't rely on this behavior.
++    uintptr_t gcFlags = dataWithTag_ & Cell::RESERVED_MASK;
++    dataWithTag_ = uintptr_t(cell) | gcFlags | Cell::FORWARD_BIT;
+ }
+ 
+ #ifdef JSGC_HASH_TABLE_CHECKS
+ 
+ template <typename T>
+ inline bool
+ IsGCThingValidAfterMovingGC(T* t)
+ {
+-    return !IsInsideNursery(t) && !RelocationOverlay::isCellForwarded(t);
++    return !IsInsideNursery(t) && !t->isForwarded();
+ }
+ 
+ template <typename T>
+ inline void
+ CheckGCThingAfterMovingGC(T* t)
+ {
+     if (t)
+         MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t));
+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
+@@ -2821,17 +2821,17 @@ js::gc::StoreBuffer::CellPtrEdge::trace(
+ #endif
+ 
+     // Bug 1376646: Make separate store buffers for strings and objects, and
+     // only check IsInsideNursery once.
+ 
+     if (!IsInsideNursery(*edge))
+         return;
+ 
+-    if (JSString::nurseryCellIsString(*edge))
++    if ((*edge)->nurseryCellIsString())
+         mover.traverse(reinterpret_cast<JSString**>(edge));
+     else
+         mover.traverse(reinterpret_cast<JSObject**>(edge));
+ }
+ 
+ void
+ js::gc::StoreBuffer::ValueEdge::trace(TenuringTracer& mover) const
+ {
+diff --git a/js/src/gc/Nursery-inl.h b/js/src/gc/Nursery-inl.h
+--- a/js/src/gc/Nursery-inl.h
++++ b/js/src/gc/Nursery-inl.h
+@@ -23,21 +23,21 @@ bool
+ js::Nursery::isInside(const SharedMem<T>& p) const
+ {
+     return isInside(p.unwrap(/*safe - used for value in comparison above*/));
+ }
+ 
+ MOZ_ALWAYS_INLINE /* static */ bool
+ js::Nursery::getForwardedPointer(js::gc::Cell** ref)
+ {
+-    MOZ_ASSERT(ref);
+-    MOZ_ASSERT(IsInsideNursery(*ref));
+-    const gc::RelocationOverlay* overlay = reinterpret_cast<const gc::RelocationOverlay*>(*ref);
+-    if (!overlay->isForwarded())
++    js::gc::Cell* cell = (*ref);
++    MOZ_ASSERT(IsInsideNursery(cell));
++    if (!cell->isForwarded())
+         return false;
++    const gc::RelocationOverlay* overlay = gc::RelocationOverlay::fromCell(cell);
+     *ref = overlay->forwardingAddress();
+     return true;
+ }
+ 
+ inline void
+ js::Nursery::maybeSetForwardingPointer(JSTracer* trc, void* oldData, void* newData, bool direct)
+ {
+     if (trc->isTenuringTracer())
+diff --git a/js/src/gc/RelocationOverlay.h b/js/src/gc/RelocationOverlay.h
+--- a/js/src/gc/RelocationOverlay.h
++++ b/js/src/gc/RelocationOverlay.h
+@@ -11,81 +11,65 @@
+ #ifndef gc_RelocationOverlay_h
+ #define gc_RelocationOverlay_h
+ 
+ #include "mozilla/Assertions.h"
+ #include "mozilla/EndianUtils.h"
+ 
+ #include <stdint.h>
+ 
++#include "gc/Cell.h"
+ #include "js/HeapAPI.h"
+ #include "vm/JSObject.h"
+ #include "vm/Shape.h"
+ 
+ namespace js {
+ namespace gc {
+ 
+-struct Cell;
+-
+ /*
+  * This structure overlays a Cell that has been moved and provides a way to find
+  * its new location. It's used during generational and compacting GC.
+  */
+-class RelocationOverlay
++class RelocationOverlay : public Cell
+ {
+-    /* See comment in js/public/HeapAPI.h. */
+-    static const uint32_t Relocated = js::gc::Relocated;
+-
+-    /*
+-     * Keep the low 32 bits untouched. Use them to distinguish strings from
+-     * objects in the nursery.
+-     */
+-    uint32_t preserve_;
+-
+-    /* Set to Relocated when moved. */
+-    uint32_t magic_;
+-
+-    /* The location |this| was moved to. */
+-    Cell* newLocation_;
++    // First word of a Cell has additional requirements from GC. The GC flags
++    // determine if a Cell is a normal entry or is a RelocationOverlay.
++    //                3         0
++    //  -------------------------
++    //  | NewLocation | GCFlags |
++    //  -------------------------
++    uintptr_t dataWithTag_;
+ 
+     /* A list entry to track all relocated things. */
+     RelocationOverlay* next_;
+ 
+   public:
+     static const RelocationOverlay* fromCell(const Cell* cell) {
+-        return reinterpret_cast<const RelocationOverlay*>(cell);
++        return static_cast<const RelocationOverlay*>(cell);
+     }
+ 
+     static RelocationOverlay* fromCell(Cell* cell) {
+-        return reinterpret_cast<RelocationOverlay*>(cell);
+-    }
+-
+-    bool isForwarded() const {
+-        (void) preserve_; // Suppress warning
+-        return magic_ == Relocated;
++        return static_cast<RelocationOverlay*>(cell);
+     }
+ 
+     Cell* forwardingAddress() const {
+         MOZ_ASSERT(isForwarded());
+-        return newLocation_;
++        uintptr_t newLocation = dataWithTag_ & ~Cell::RESERVED_MASK;
++        return reinterpret_cast<Cell*>(newLocation);
+     }
+ 
+     void forwardTo(Cell* cell);
+ 
+     RelocationOverlay*& nextRef() {
+         MOZ_ASSERT(isForwarded());
+         return next_;
+     }
+ 
+     RelocationOverlay* next() const {
+         MOZ_ASSERT(isForwarded());
+         return next_;
+     }
+-
+-    static bool isCellForwarded(const Cell* cell) {
+-        return fromCell(cell)->isForwarded();
+-    }
+ };
+ 
+ } // namespace gc
+ } // namespace js
+ 
+ #endif /* gc_RelocationOverlay_h */
+diff --git a/js/src/gc/Verifier.cpp.1479900-2.later b/js/src/gc/Verifier.cpp.1479900-2.later
+new file mode 100644
+--- /dev/null
++++ b/js/src/gc/Verifier.cpp.1479900-2.later
+@@ -0,0 +1,22 @@
++--- Verifier.cpp
+++++ Verifier.cpp
++@@ -638,18 +638,17 @@ IsValidGCThingPointer(Cell* cell)
++ }
++ 
++ void
++ CheckHeapTracer::checkCell(Cell* cell)
++ {
++     // Moving
++     if (!IsValidGCThingPointer(cell) ||
++         ((gcType == GCType::Moving) && !IsGCThingValidAfterMovingGC(cell)) ||
++-        ((gcType == GCType::NonMoving) &&
++-            RelocationOverlay::isCellForwarded(cell)))
+++        ((gcType == GCType::NonMoving) && cell->isForwarded()))
++     {
++         failures++;
++         fprintf(stderr, "Bad pointer %p\n", cell);
++         dumpCellPath();
++     }
++ }
++ 
++ void
+diff --git a/js/src/vm/BigIntType.h b/js/src/vm/BigIntType.h
+--- a/js/src/vm/BigIntType.h
++++ b/js/src/vm/BigIntType.h
+@@ -33,23 +33,26 @@ namespace JS {
+ 
+ class BigInt final : public js::gc::TenuredCell
+ {
+     // StringToBigIntImpl modifies the num_ field of the res argument.
+     template <typename CharT>
+     friend bool js::StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
+                                        uint8_t radix, Handle<BigInt*> res);
+ 
++  protected:
++    // Reserved word for Cell GC invariants. This also ensures minimum
++    // structure size.
++    uintptr_t reserved_;
++
+   private:
+-    // The minimum allocation size is currently 16 bytes (see
+-    // SortedArenaList in gc/ArenaList.h).
+-    union {
+-        mpz_t num_;
+-        uint8_t unused_[js::gc::MinCellSize];
+-    };
++    mpz_t num_;
++
++  protected:
++    BigInt() : reserved_(0) { }
+ 
+   public:
+     // Allocate and initialize a BigInt value
+     static BigInt* create(JSContext* cx);
+ 
+     static BigInt* createFromDouble(JSContext* cx, double d);
+ 
+     static BigInt* createFromBoolean(JSContext* cx, bool b);
+diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h
+--- a/js/src/vm/Scope.h
++++ b/js/src/vm/Scope.h
+@@ -299,44 +299,34 @@ class WrappedPtrOperations<Scope*, Wrapp
+ 
+ //
+ // The base class of all Scopes.
+ //
+ class Scope : public js::gc::TenuredCell
+ {
+     friend class GCMarker;
+ 
+-    // The kind determines data_.
+-    //
+-    // The memory here must be fully initialized, since otherwise the magic_
+-    // value for gc::RelocationOverlay will land in the padding and may be
+-    // stale.
+-    union {
+-        ScopeKind kind_;
+-        uintptr_t paddedKind_;
+-    };
+-
+     // The enclosing scope or nullptr.
+     GCPtrScope enclosing_;
+ 
++    // The kind determines data_.
++    ScopeKind kind_;
++
+     // If there are any aliased bindings, the shape for the
+     // EnvironmentObject. Otherwise nullptr.
+     GCPtrShape environmentShape_;
+ 
+   protected:
+     uintptr_t data_;
+ 
+     Scope(ScopeKind kind, Scope* enclosing, Shape* environmentShape)
+       : enclosing_(enclosing),
++        kind_(kind),
+         environmentShape_(environmentShape),
+-        data_(0)
+-    {
+-        paddedKind_ = 0;
+-        kind_ = kind;
+-    }
++        data_(0) { }
+ 
+     static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
+                          HandleShape envShape);
+ 
+     template <typename T, typename D>
+     static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
+                          HandleShape envShape, mozilla::UniquePtr<T, D> data);
+ 
+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
+@@ -160,23 +160,31 @@ class JSString : public js::gc::Cell
+ {
+   protected:
+     static const size_t NUM_INLINE_CHARS_LATIN1   = 2 * sizeof(void*) / sizeof(JS::Latin1Char);
+     static const size_t NUM_INLINE_CHARS_TWO_BYTE = 2 * sizeof(void*) / sizeof(char16_t);
+ 
+     /* Fields only apply to string types commented on the right. */
+     struct Data
+     {
+-        union {
+-            struct {
+-                uint32_t           flags_;              /* JSString */
+-                uint32_t           length_;             /* JSString */
+-            };
+-            uintptr_t              flattenData_;        /* JSRope (temporary while flattening) */
+-        } u1;
++        // First word of a Cell has additional requirements from GC and normally
++        // would store a pointer. If a single word isn't large enough, the length
++        // is stored separately.
++        //          32      16       0
++        //  --------------------------
++        //  | Length | Index | Flags |
++        //  --------------------------
++        //
++        // NOTE: This is also used for temporary storage while linearizing a Rope.
++        uintptr_t flags_;                               /* JSString */
++
++#if JS_BITS_PER_WORD == 32
++        // Additional storage for length if |flags_| is too small to fit both.
++        uint32_t                   length_;             /* JSString */
++#endif
+         union {
+             union {
+                 /* JS(Fat)InlineString */
+                 JS::Latin1Char     inlineStorageLatin1[NUM_INLINE_CHARS_LATIN1];
+                 char16_t           inlineStorageTwoByte[NUM_INLINE_CHARS_TWO_BYTE];
+             };
+             struct {
+                 union {
+@@ -193,19 +201,21 @@ class JSString : public js::gc::Cell
+             } s;
+         };
+     } d;
+ 
+   public:
+     /* Flags exposed only for jits */
+ 
+     /*
+-     * The Flags Word
++     * Flag Encoding
+      *
+-     * The flags word stores both the string's type and its character encoding.
++     * The first word of a JSString stores flags, index, and (on some
++     * platforms) the length. The flags store both the string's type and its
++     * character encoding.
+      *
+      * If LATIN1_CHARS_BIT is set, the string's characters are stored as Latin1
+      * instead of TwoByte. This flag can also be set for ropes, if both the
+      * left and right nodes are Latin1. Flattening will result in a Latin1
+      * string in this case.
+      *
+      * The other flags store the string's type. Instead of using a dense index
+      * to represent the most-derived type, string types are encoded to allow
+@@ -247,56 +257,55 @@ class JSString : public js::gc::Cell
+      *   Bit 3: IsInline (Inline, FatInline)
+      *
+      *  "HasBase" here refers to the two string types that have a 'base' field:
+      *  JSDependentString and JSUndependedString.
+      *  A JSUndependedString is a JSDependentString which has been 'fixed' (by ensureFixed)
+      *  to be null-terminated.  In such cases, the string must keep marking its base since
+      *  there may be any number of *other* JSDependentStrings transitively depending on it.
+      *
+-     * The atom bit (NON_ATOM_BIT) is inverted so that objects and strings can
+-     * be differentiated in the nursery: atoms are never in the nursery, so
+-     * this bit is always 1 for a nursery string. For an object on a
+-     * little-endian architecture, this is the low-order bit of the ObjectGroup
+-     * pointer in a JSObject, which will always be zero. A 64-bit big-endian
+-     * architecture will need to do something else (the ObjectGroup* is in the
+-     * same place as a string's struct { uint32_t flags; uint32_t length; }).
++     * The atom bit (NON_ATOM_BIT) is inverted and stored in a Cell
++     * ReservedBit. Atoms are never stored in nursery, so the nursery can use
++     * this bit to distinguish between JSString (1) and JSObject (0).
+      *
+-     * If the INDEX_VALUE_BIT is set the upper 16 bits of the flag word hold the integer
+-     * index.
++     * If the INDEX_VALUE_BIT is set, flags will also hold an integer index.
+      */
+ 
+-    static const uint32_t NON_ATOM_BIT           = JS_BIT(0);
+-    static const uint32_t LINEAR_BIT             = JS_BIT(1);
+-    static const uint32_t HAS_BASE_BIT           = JS_BIT(2);
+-    static const uint32_t INLINE_CHARS_BIT       = JS_BIT(3);
++    // The low bits of flag word are reserved by GC.
++    static_assert(js::gc::Cell::ReservedBits <= 3,
++                  "JSString::flags must reserve enough bits for Cell");
++
++    static const uint32_t NON_ATOM_BIT           = js::gc::Cell::JSSTRING_BIT;
++    static const uint32_t LINEAR_BIT             = JS_BIT(4);
++    static const uint32_t HAS_BASE_BIT           = JS_BIT(5);
++    static const uint32_t INLINE_CHARS_BIT       = JS_BIT(6);
+ 
+     static const uint32_t DEPENDENT_FLAGS        = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT;
+-    static const uint32_t UNDEPENDED_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT | JS_BIT(4);
+-    static const uint32_t EXTENSIBLE_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(4);
+-    static const uint32_t EXTERNAL_FLAGS         = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(5);
++    static const uint32_t UNDEPENDED_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT | JS_BIT(7);
++    static const uint32_t EXTENSIBLE_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(7);
++    static const uint32_t EXTERNAL_FLAGS         = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(8);
+ 
+-    static const uint32_t FAT_INLINE_MASK        = INLINE_CHARS_BIT | JS_BIT(4);
+-    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(5);
+-    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(5);
++    static const uint32_t FAT_INLINE_MASK        = INLINE_CHARS_BIT | JS_BIT(7);
++    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(8);
++    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(8);
+ 
+     /* Initial flags for thin inline and fat inline strings. */
+     static const uint32_t INIT_THIN_INLINE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | INLINE_CHARS_BIT;
+     static const uint32_t INIT_FAT_INLINE_FLAGS  = NON_ATOM_BIT | LINEAR_BIT | FAT_INLINE_MASK;
+     static const uint32_t INIT_ROPE_FLAGS        = NON_ATOM_BIT;
+     static const uint32_t INIT_FLAT_FLAGS        = NON_ATOM_BIT | LINEAR_BIT;
+ 
+-    static const uint32_t TYPE_FLAGS_MASK        = JS_BIT(6) - 1;
++    static const uint32_t TYPE_FLAGS_MASK        = JS_BITMASK(9) - JS_BITMASK(3) + js::gc::Cell::JSSTRING_BIT;
+ 
+-    static const uint32_t LATIN1_CHARS_BIT       = JS_BIT(6);
++    static const uint32_t LATIN1_CHARS_BIT       = JS_BIT(9);
+ 
+-    static const uint32_t INDEX_VALUE_BIT        = JS_BIT(7);
++    static const uint32_t INDEX_VALUE_BIT        = JS_BIT(10);
+     static const uint32_t INDEX_VALUE_SHIFT      = 16;
+ 
+-    static const uint32_t PINNED_ATOM_BIT        = JS_BIT(8);
++    static const uint32_t PINNED_ATOM_BIT        = JS_BIT(11);
+ 
+     static const uint32_t MAX_LENGTH             = js::MaxStringLength;
+ 
+     static const JS::Latin1Char MAX_LATIN1_CHAR = 0xff;
+ 
+     /*
+      * Helper function to validate that a string of a given length is
+      * representable by a JSString. An allocation overflow is reported if false
+@@ -312,20 +321,22 @@ class JSString : public js::gc::Cell
+                       "Inline Latin1 chars must fit in a JSString");
+         static_assert(sizeof(JSString) ==
+                       (offsetof(JSString, d.inlineStorageTwoByte) +
+                        NUM_INLINE_CHARS_TWO_BYTE * sizeof(char16_t)),
+                       "Inline char16_t chars must fit in a JSString");
+ 
+         /* Ensure js::shadow::String has the same layout. */
+         using JS::shadow::String;
+-        static_assert(offsetof(JSString, d.u1.length_) == offsetof(String, length_),
++        static_assert(offsetof(JSString, d.flags_) == offsetof(String, flags_),
++                      "shadow::String flags offset must match JSString");
++#if JS_BITS_PER_WORD == 32
++        static_assert(offsetof(JSString, d.length_) == offsetof(String, length_),
+                       "shadow::String length offset must match JSString");
+-        static_assert(offsetof(JSString, d.u1.flags_) == offsetof(String, flags_),
+-                      "shadow::String flags offset must match JSString");
++#endif
+         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(String, nonInlineCharsLatin1),
+                       "shadow::String nonInlineChars offset must match JSString");
+         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(String, nonInlineCharsTwoByte),
+                       "shadow::String nonInlineChars offset must match JSString");
+         static_assert(offsetof(JSString, d.s.u3.externalFinalizer) == offsetof(String, externalFinalizer),
+                       "shadow::String externalFinalizer offset must match JSString");
+         static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(String, inlineStorageLatin1),
+                       "shadow::String inlineStorage offset must match JSString");
+@@ -352,55 +363,63 @@ class JSString : public js::gc::Cell
+ 
+   protected:
+     template <typename CharT>
+     MOZ_ALWAYS_INLINE
+     void setNonInlineChars(const CharT* chars);
+ 
+     MOZ_ALWAYS_INLINE
+     uint32_t flags() const {
+-        return d.u1.flags_;
++        return uint32_t(d.flags_);
+     }
+ 
+   public:
+     MOZ_ALWAYS_INLINE
+     size_t length() const {
+-        return d.u1.length_;
++#if JS_BITS_PER_WORD == 32
++        return d.length_;
++#else
++        return uint32_t(d.flags_ >> 32);
++#endif
+     }
+ 
+   protected:
+     MOZ_ALWAYS_INLINE
+     void setFlagBit(uint32_t flags) {
+-        d.u1.flags_ |= flags;
++        d.flags_ |= uintptr_t(flags);
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     void clearFlagBit(uint32_t flags) {
+-        d.u1.flags_ &= ~flags;
++        d.flags_ &= ~uintptr_t(flags);
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     void setLengthAndFlags(uint32_t len, uint32_t flags) {
+-        d.u1.flags_ = flags;
+-        d.u1.length_ = len;
++#if JS_BITS_PER_WORD == 32
++        d.flags_ = flags;
++        d.length_ = len;
++#else
++        d.flags_ = uint64_t(len) << 32 | uint64_t(flags);
++#endif
+     }
+ 
+     // Flatten algorithm stores a temporary word by clobbering flags. This is
+     // not GC-safe and user must ensure JSString::flags are never checked
+     // (including by asserts) while this data is stored.
+     MOZ_ALWAYS_INLINE
+     void setFlattenData(uintptr_t data) {
+-        d.u1.flattenData_ = data;
++        d.flags_ = data;
+     }
+ 
+     // To get back the data, values to safely re-initialize clobbered flags
+     // must be provided.
+     MOZ_ALWAYS_INLINE
+     uintptr_t unsetFlattenData(uint32_t len, uint32_t flags) {
+-        uintptr_t data = d.u1.flattenData_;
++        uintptr_t data = d.flags_;
+         setLengthAndFlags(len, flags);
+         return data;
+     }
+ 
+     // Get correct non-inline chars enum arm for given type
+     template <typename CharT> MOZ_ALWAYS_INLINE const CharT* nonInlineCharsRaw() const;
+ 
+   public:
+@@ -539,24 +558,16 @@ class JSString : public js::gc::Cell
+     }
+ 
+     MOZ_ALWAYS_INLINE
+     JSAtom& asAtom() const {
+         MOZ_ASSERT(isAtom());
+         return *(JSAtom*)this;
+     }
+ 
+-    // Used for distinguishing strings from objects in the nursery. The caller
+-    // must ensure that cell is in the nursery (and not forwarded).
+-    MOZ_ALWAYS_INLINE
+-    static bool nurseryCellIsString(js::gc::Cell* cell) {
+-        MOZ_ASSERT(!cell->isTenured());
+-        return !static_cast<JSString*>(cell)->isAtom();
+-    }
+-
+     // Fills |array| with various strings that represent the different string
+     // kinds and character encodings.
+     static bool fillWithRepresentatives(JSContext* cx, js::HandleArrayObject array);
+ 
+     /* Only called by the GC for dependent or undepended strings. */
+ 
+     inline bool hasBase() const {
+         return flags() & HAS_BASE_BIT;
+@@ -569,24 +580,40 @@ class JSString : public js::gc::Cell
+     /* Only called by the GC for strings with the AllocKind::STRING kind. */
+ 
+     inline void finalize(js::FreeOp* fop);
+ 
+     /* Gets the number of bytes that the chars take on the heap. */
+ 
+     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+ 
+-    /* Offsets for direct field from jit code. */
+-
+-    static size_t offsetOfLength() {
+-        return offsetof(JSString, d.u1.length_);
++    // Offsets for direct field from jit code. A number of places directly
++    // access 32-bit length and flags fields so do endian trickery here.
++#if JS_BITS_PER_WORD == 32
++    static constexpr size_t offsetOfFlags() {
++        return offsetof(JSString, d.flags_);
++    }
++    static constexpr size_t offsetOfLength() {
++        return offsetof(JSString, d.length_);
+     }
+-    static size_t offsetOfFlags() {
+-        return offsetof(JSString, d.u1.flags_);
++#elif defined(MOZ_LITTLE_ENDIAN)
++    static constexpr size_t offsetOfFlags() {
++        return offsetof(JSString, d.flags_);
++    }
++    static constexpr size_t offsetOfLength() {
++        return offsetof(JSString, d.flags_) + sizeof(uint32_t);
+     }
++#else
++    static constexpr size_t offsetOfFlags() {
++        return offsetof(JSString, d.flags_) + sizeof(uint32_t);
++    }
++    static constexpr size_t offsetOfLength() {
++        return offsetof(JSString, d.flags_);
++    }
++#endif
+ 
+   private:
+     // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
+     // to call the method below.
+     friend class js::jit::MacroAssembler;
+     static size_t offsetOfNonInlineChars() {
+         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) ==
+                       offsetof(JSString, d.s.u2.nonInlineCharsLatin1),
+diff --git a/js/src/vm/SymbolType.h b/js/src/vm/SymbolType.h
+--- a/js/src/vm/SymbolType.h
++++ b/js/src/vm/SymbolType.h
+@@ -27,46 +27,54 @@
+ namespace js {
+ class AutoLockForExclusiveAccess;
+ } // namespace js
+ 
+ namespace JS {
+ 
+ class Symbol : public js::gc::TenuredCell
+ {
++  protected:
++    // Reserved word for Cell GC invariants. This also ensures minimum
++    // structure size.
++    uintptr_t reserved_;
++
+   private:
+     SymbolCode code_;
+ 
+     // Each Symbol gets its own hash code so that we don't have to use
+     // addresses as hash codes (a security hazard).
+     js::HashNumber hash_;
+ 
+     JSAtom* description_;
+ 
+     // The minimum allocation size is sizeof(JSString): 16 bytes on 32-bit
+     // architectures and 24 bytes on 64-bit.  A size_t of padding makes Symbol
+     // the minimum size on both.
+     size_t unused_;
+ 
+     Symbol(SymbolCode code, js::HashNumber hash, JSAtom* desc)
+-        : code_(code), hash_(hash), description_(desc)
+-    {
+-        // Silence warnings about unused_ being... unused.
+-        (void)unused_;
+-        static_assert(uint32_t(SymbolCode::WellKnownAPILimit) == JS::shadow::Symbol::WellKnownAPILimit,
+-                      "JS::shadow::Symbol::WellKnownAPILimit must match SymbolCode::WellKnownAPILimit");
+-    }
++        : reserved_(0), code_(code), hash_(hash), description_(desc) { }
+ 
+     Symbol(const Symbol&) = delete;
+     void operator=(const Symbol&) = delete;
+ 
+     static Symbol*
+     newInternal(JSContext* cx, SymbolCode code, js::HashNumber hash,
+                 JSAtom* description, js::AutoLockForExclusiveAccess& lock);
+ 
++    static void staticAsserts() {
++        static_assert(uint32_t(SymbolCode::WellKnownAPILimit) == JS::shadow::Symbol::WellKnownAPILimit,
++                      "JS::shadow::Symbol::WellKnownAPILimit must match SymbolCode::WellKnownAPILimit");
++        static_assert(offsetof(Symbol, reserved_) == offsetof(JS::shadow::Symbol, reserved_),
++                      "JS::shadow::Symbol::reserved_ offset must match SymbolCode::reserved_");
++        static_assert(offsetof(Symbol, code_) == offsetof(JS::shadow::Symbol, code_),
++                      "JS::shadow::Symbol::code_ offset must match SymbolCode::code_");
++    }
++
+   public:
+     static Symbol* new_(JSContext* cx, SymbolCode code, JSString* description);
+     static Symbol* for_(JSContext* cx, js::HandleString description);
+ 
+     JSAtom* description() const { return description_; }
+     SymbolCode code() const { return code_; }
+     js::HashNumber hash() const { return hash_; }
+ 

+ 120 - 0
frg/work-js/mozilla-release/patches/1480521-BACKOUT-60.patch

@@ -0,0 +1,120 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1534945581 14400
+#      Wed Aug 22 09:46:21 2018 -0400
+# Node ID bf26310ec595095b8fcba50099456f29d5a2a76c
+# Parent  8041ae208e1d066e5235c2be603bfe4f0f31e267
+Bug 1480521 - Backport fixes from Bug 1479900. r=sfink, a=RyanVM
+
+MozReview-Commit-ID: 3bP92eIdNIw
+
+diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
+--- a/js/src/jsfriendapi.h
++++ b/js/src/jsfriendapi.h
+@@ -578,18 +578,17 @@ struct ObjectGroup {
+ struct BaseShape {
+     const js::Class* clasp_;
+     JSObject* parent;
+ };
+ 
+ class Shape {
+ public:
+     shadow::BaseShape* base;
+-    void*             _1;
+-    jsid              _2;
++    jsid              _1;
+     uint32_t          immutableFlags;
+ 
+     static const uint32_t FIXED_SLOTS_SHIFT = 24;
+     static const uint32_t FIXED_SLOTS_MASK = 0x1f << FIXED_SLOTS_SHIFT;
+ };
+ 
+ /**
+  * This layout is shared by all native objects. For non-native objects, the
+diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
+--- a/js/src/vm/Shape.h
++++ b/js/src/vm/Shape.h
+@@ -696,17 +696,16 @@ class Shape : public gc::TenuredCell
+     friend class TenuringTracer;
+     friend struct StackBaseShape;
+     friend struct StackShape;
+     friend class JS::ubi::Concrete<Shape>;
+     friend class js::gc::RelocationOverlay;
+ 
+   protected:
+     GCPtrBaseShape base_;
+-    GCPtrShape parent;
+     PreBarrieredId propid_;
+ 
+     // Flags that are not modified after the Shape is created. Off-thread Ion
+     // compilation can access the immutableFlags word, so we don't want any
+     // mutable state here to avoid (TSan) races.
+     enum ImmutableFlags : uint32_t
+     {
+         // Mask to get the index in object slots for isDataProperty() shapes.
+@@ -746,16 +745,17 @@ class Shape : public gc::TenuredCell
+         HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x10,
+         CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x20,
+     };
+ 
+     uint32_t            immutableFlags; /* immutable flags, see above */
+     uint8_t             attrs;          /* attributes, see jsapi.h JSPROP_* */
+     uint8_t             mutableFlags;   /* mutable flags, see below for defines */
+ 
++    GCPtrShape   parent;          /* parent node, reverse for..in order */
+     /* kids is valid when !inDictionary(), listp is valid when inDictionary(). */
+     union {
+         KidsPointer kids;         /* null, single child, or a tagged ptr
+                                      to many-kids data structure */
+         GCPtrShape* listp;        /* dictionary list starting at shape_
+                                      has a double-indirect back pointer,
+                                      either to the next shape's parent if not
+                                      last, else to obj->shape_ */
+@@ -1525,21 +1525,21 @@ class MutableWrappedPtrOperations<StackS
+     void setSlot(uint32_t slot) { ss().setSlot(slot); }
+     void setBase(UnownedBaseShape* base) { ss().base = base; }
+     void setAttrs(uint8_t attrs) { ss().attrs = attrs; }
+ };
+ 
+ inline
+ Shape::Shape(const StackShape& other, uint32_t nfixed)
+   : base_(other.base),
+-    parent(nullptr),
+     propid_(other.propid),
+     immutableFlags(other.immutableFlags),
+     attrs(other.attrs),
+-    mutableFlags(other.mutableFlags)
++    mutableFlags(other.mutableFlags),
++    parent(nullptr)
+ {
+     setNumFixedSlots(nfixed);
+ 
+ #ifdef DEBUG
+     gc::AllocKind allocKind = getAllocKind();
+     MOZ_ASSERT_IF(other.isAccessorShape(), allocKind == gc::AllocKind::ACCESSOR_SHAPE);
+     MOZ_ASSERT_IF(allocKind == gc::AllocKind::SHAPE, !other.isAccessorShape());
+ #endif
+@@ -1559,21 +1559,21 @@ class NurseryShapesRef : public gc::Buff
+   public:
+     explicit NurseryShapesRef(Zone* zone) : zone_(zone) {}
+     void trace(JSTracer* trc) override;
+ };
+ 
+ inline
+ Shape::Shape(UnownedBaseShape* base, uint32_t nfixed)
+   : base_(base),
+-    parent(nullptr),
+     propid_(JSID_EMPTY),
+     immutableFlags(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
+     attrs(0),
+-    mutableFlags(0)
++    mutableFlags(0),
++    parent(nullptr)
+ {
+     MOZ_ASSERT(base);
+     kids.setNull();
+ }
+ 
+ inline GetterOp
+ Shape::getter() const
+ {

+ 71 - 107
frg/work-js/mozilla-release/patches/1480720-63a1.patch

@@ -2,7 +2,7 @@
 # User Jon Coppeard <jcoppeard@mozilla.com>
 # Date 1533549268 -3600
 # Node ID 5f9c8d7612a7e44685a7c64815d86f5299f1b8b3
-# Parent  7e1f880b5f882732370ad70d02e7378b14b302f8
+# Parent  4200cf09bbcc542eaf84eb18087c42f461b91ef2
 Bug 1480720 - Factor out script fetch options from script load request classes r=baku
 
 diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp
@@ -69,7 +69,7 @@ diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp
 diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h
 --- a/dom/script/ModuleLoadRequest.h
 +++ b/dom/script/ModuleLoadRequest.h
-@@ -39,21 +39,19 @@ class ModuleLoadRequest final : public S
+@@ -40,21 +40,19 @@ class ModuleLoadRequest final : public S
    ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete;
  
  public:
@@ -95,7 +95,7 @@ diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h
 diff --git a/dom/script/ScriptLoadHandler.cpp b/dom/script/ScriptLoadHandler.cpp
 --- a/dom/script/ScriptLoadHandler.cpp
 +++ b/dom/script/ScriptLoadHandler.cpp
-@@ -218,17 +218,17 @@ ScriptLoadHandler::EnsureDecoder(nsIIncr
+@@ -202,17 +202,17 @@ ScriptLoadHandler::EnsureDecoder(nsIIncr
        return true;
      }
    }
@@ -114,24 +114,12 @@ diff --git a/dom/script/ScriptLoadHandler.cpp b/dom/script/ScriptLoadHandler.cpp
      NS_ASSERTION(i != mScriptLoader->mPreloads.NoIndex,
                   "Incorrect preload bookkeeping");
      hintCharset = mScriptLoader->mPreloads[i].mCharset;
-@@ -296,46 +296,46 @@ ScriptLoadHandler::EnsureKnownDataType(n
-   if (ScriptLoader::BinASTEncodingEnabled()) {
-     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(req);
-     if (httpChannel) {
-       nsAutoCString mimeType;
-       httpChannel->GetContentType(mimeType);
-       if (mimeType.LowerCaseEqualsASCII(APPLICATION_JAVASCRIPT_BINAST)) {
-         if (mRequest->ShouldAcceptBinASTEncoding()) {
-           mRequest->SetBinASTSource();
--          TRACE_FOR_TEST(mRequest->mElement, "scriptloader_load_source");
-+          TRACE_FOR_TEST(mRequest->Element(), "scriptloader_load_source");
-           return NS_OK;
-         } else {
-           return NS_ERROR_FAILURE;
-         }
-       }
-     }
-   }
+@@ -274,35 +274,35 @@ ScriptLoadHandler::EnsureKnownDataType(n
+ 
+   nsCOMPtr<nsIRequest> req;
+   nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
+   MOZ_ASSERT(req, "StreamLoader's request went away prematurely");
+   NS_ENSURE_SUCCESS(rv, rv);
  
    if (mRequest->IsLoadingSource()) {
      mRequest->SetTextSource();
@@ -169,7 +157,7 @@ diff --git a/dom/script/ScriptLoadHandler.cpp b/dom/script/ScriptLoadHandler.cpp
 diff --git a/dom/script/ScriptLoadRequest.cpp b/dom/script/ScriptLoadRequest.cpp
 --- a/dom/script/ScriptLoadRequest.cpp
 +++ b/dom/script/ScriptLoadRequest.cpp
-@@ -12,75 +12,98 @@
+@@ -12,74 +12,97 @@
  #include "nsICacheInfoChannel.h"
  #include "ScriptLoadRequest.h"
  #include "ScriptSettings.h"
@@ -261,7 +249,6 @@ diff --git a/dom/script/ScriptLoadRequest.cpp b/dom/script/ScriptLoadRequest.cpp
    , mIsTracking(false)
 +  , mFetchOptions(aFetchOptions)
    , mOffThreadToken(nullptr)
-   , mScriptTextLength(0)
    , mScriptBytecode()
    , mBytecodeOffset(0)
    , mURI(aURI)
@@ -379,7 +366,7 @@ diff --git a/dom/script/ScriptLoadRequest.h b/dom/script/ScriptLoadRequest.h
    {
      return mIsCanceled;
    }
-@@ -219,41 +244,68 @@ public:
+@@ -194,39 +219,67 @@ public:
    }
  
    virtual bool IsTopLevel() const
@@ -413,8 +400,6 @@ diff --git a/dom/script/ScriptLoadRequest.h b/dom/script/ScriptLoadRequest.h
 +    mFetchOptions->mElement = aElement;
 +  }
 +
-   bool ShouldAcceptBinASTEncoding() const;
- 
    void ClearScriptSource();
  
    void MaybeCancelOffThreadScript();
@@ -432,6 +417,7 @@ diff --git a/dom/script/ScriptLoadRequest.h b/dom/script/ScriptLoadRequest.h
    DataType mDataType;     // Does this contain Source or Bytecode?
 -  ScriptMode mScriptMode; // Whether this is a blocking, defer or async script.
 +  bool mScriptFromHead;   // Synchronous head script block loading of other non js/css content.
++
    bool mIsInline;         // Is the script inline or loaded?
    bool mHasSourceMapURL;  // Does the HTTP header have a source map url?
    bool mInDeferList;      // True if we live in mDeferRequests.
@@ -452,8 +438,8 @@ diff --git a/dom/script/ScriptLoadRequest.h b/dom/script/ScriptLoadRequest.h
    JS::Heap<JSScript*> mScript;
  
    // Holds script source data for non-inline scripts. Don't use nsString so we
-@@ -266,24 +318,21 @@ public:
-   size_t mScriptTextLength;
+@@ -235,24 +288,21 @@ public:
+   Maybe<Variant<Vector<char16_t>, Vector<uint8_t>>> mScriptData;
  
    // Holds the SRI serialized hash and the script bytecode for non-inline
    // scripts.
@@ -480,26 +466,7 @@ diff --git a/dom/script/ScriptLoadRequest.h b/dom/script/ScriptLoadRequest.h
 diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
 --- a/dom/script/ScriptLoader.cpp
 +++ b/dom/script/ScriptLoader.cpp
-@@ -211,17 +211,17 @@ CollectScriptTelemetry(ScriptLoadRequest
- 
-   // Report the type of source. This is used to monitor the status of the
-   // JavaScript Start-up Bytecode Cache, with the expectation of an almost zero
-   // source-fallback and alternate-data being roughtly equal to source loads.
-   if (aRequest->IsLoadingSource()) {
-     if (aRequest->mIsInline) {
-       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
-       nsAutoString inlineData;
--      aRequest->mElement->GetScriptText(inlineData);
-+      aRequest->Element()->GetScriptText(inlineData);
-     } else if (aRequest->IsTextSource()) {
-       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback);
-     }
-     // TODO: Add telemetry for BinAST encoded source.
-   } else {
-     MOZ_ASSERT(aRequest->IsLoading());
-     if (aRequest->IsTextSource()) {
-       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Source);
-@@ -865,17 +865,17 @@ public:
+@@ -817,17 +817,17 @@ public:
  
  void
  ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
@@ -518,7 +485,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
        MaybeMoveToLoadedList(aRequest);
        ProcessPendingRequests();
      }
-@@ -955,17 +955,17 @@ ScriptLoader::InstantiateModuleTree(Modu
+@@ -907,17 +907,17 @@ ScriptLoader::InstantiateModuleTree(Modu
    return true;
  }
  
@@ -537,7 +504,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    if (NS_FAILED(rv)) {
      return rv;
    }
-@@ -1006,60 +1006,60 @@ ScriptLoader::StartLoad(ScriptLoadReques
+@@ -958,60 +958,60 @@ ScriptLoader::StartLoad(ScriptLoadReques
        return NS_OK;
      }
    }
@@ -601,16 +568,16 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
 +      aRequest->TriggeringPrincipal(),
        securityFlags,
        contentPolicyType,
-       nullptr, // aPerformanceStorage
        loadGroup,
        prompter,
        nsIRequest::LOAD_NORMAL |
        nsIChannel::LOAD_CLASSIFY_URI);
  
-@@ -1129,17 +1129,17 @@ ScriptLoader::StartLoad(ScriptLoadReques
-     if (BinASTEncodingEnabled() && aRequest->ShouldAcceptBinASTEncoding()) {
-       acceptTypes = APPLICATION_JAVASCRIPT_BINAST ", */*";
-     }
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -1079,17 +1079,17 @@ ScriptLoader::StartLoad(ScriptLoadReques
+   if (httpChannel) {
+     // HTTP content negotation has little value in this context.
+     nsAutoCString acceptTypes("*/*");
      rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                         acceptTypes, false);
      MOZ_ASSERT(NS_SUCCEEDED(rv));
@@ -626,7 +593,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
        MOZ_ASSERT(NS_SUCCEEDED(rv));
      }
    }
-@@ -1221,30 +1221,31 @@ CSPAllowsInlineScript(nsIScriptElement* 
+@@ -1170,30 +1170,31 @@ CSPAllowsInlineScript(nsIScriptElement* 
                              &allowInlineScript);
    return allowInlineScript;
  }
@@ -662,7 +629,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    // We need a document to evaluate scripts.
    NS_ENSURE_TRUE(mDocument, false);
  
-@@ -1375,19 +1376,18 @@ ScriptLoader::ProcessExternalScript(nsIS
+@@ -1313,19 +1314,18 @@ ScriptLoader::ProcessExternalScript(nsIS
  
      nsCOMPtr<nsIPrincipal> principal = aElement->GetScriptURITriggeringPrincipal();
      if (!principal) {
@@ -683,7 +650,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
  
      LOG(("ScriptLoadRequest (%p): Created request for external script",
           request.get()));
-@@ -1516,25 +1516,25 @@ ScriptLoader::ProcessInlineScript(nsIScr
+@@ -1454,25 +1454,25 @@ ScriptLoader::ProcessInlineScript(nsIScr
    // Inline classic scripts ignore their CORS mode and are always CORS_NONE.
    CORSMode corsMode = CORS_NONE;
    if (aScriptKind == ScriptKind::eModule) {
@@ -703,7 +670,6 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    request->SetTextSource();
 -  TRACE_FOR_TEST_BOOL(request->mElement, "scriptloader_load_source");
 +  TRACE_FOR_TEST_BOOL(request->Element(), "scriptloader_load_source");
-   CollectScriptTelemetry(request);
  
    // Only the 'async' attribute is heeded on an inline module script and
    // inline classic scripts ignore both these attributes.
@@ -711,7 +677,8 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    MOZ_ASSERT_IF(!request->IsModuleRequest(), !aElement->GetScriptAsync());
    request->SetScriptMode(false, aElement->GetScriptAsync());
  
-@@ -1609,27 +1609,27 @@ ScriptLoader::LookupPreloadRequest(nsISc
+   LOG(("ScriptLoadRequest (%p): Created request for inline script",
+@@ -1546,27 +1546,27 @@ ScriptLoader::LookupPreloadRequest(nsISc
      mPreloads.IndexOf(aElement->GetScriptURI(), 0, PreloadURIComparator());
    if (i == nsTArray<PreloadInfo>::NoIndex) {
      return nullptr;
@@ -737,31 +704,31 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
        aScriptKind != request->mKind) {
      // Drop the preload.
      request->Cancel();
-     AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::RequestMismatch);
      return nullptr;
    }
  
    return request;
-@@ -1900,17 +1900,17 @@ SourceBufferHolder
- ScriptLoader::GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest)
+ }
+@@ -1811,17 +1811,17 @@ ScriptLoader::GetScriptSource(ScriptLoad
  {
    // Return a SourceBufferHolder object holding the script's source text.
-   // Ownership of the buffer is transferred to the resulting SourceBufferHolder.
+   // |inlineData| is used to hold the text for inline objects.
  
    // If there's no script text, we try to get it from the element
    if (aRequest->mIsInline) {
-     nsAutoString inlineData;
+     // XXX This is inefficient - GetText makes multiple
+     // copies.
 -    aRequest->mElement->GetScriptText(inlineData);
 +    aRequest->Element()->GetScriptText(inlineData);
- 
-     size_t nbytes = inlineData.Length() * sizeof(char16_t);
-     JS::UniqueTwoByteChars chars(static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
-     MOZ_RELEASE_ASSERT(chars);
-     memcpy(chars.get(), inlineData.get(), nbytes);
-     return SourceBufferHolder(std::move(chars), inlineData.Length());
+     return SourceBufferHolder(inlineData.get(),
+                               inlineData.Length(),
+                               SourceBufferHolder::NoOwnership);
    }
  
-@@ -1943,31 +1943,31 @@ ScriptLoader::ProcessRequest(ScriptLoadR
+   return SourceBufferHolder(aRequest->ScriptText().begin(),
+                             aRequest->ScriptText().length(),
+                             SourceBufferHolder::NoOwnership);
+@@ -1850,31 +1850,31 @@ ScriptLoader::ProcessRequest(ScriptLoadR
      if (!request->mModuleScript) {
        // There was an error fetching a module script.  Nothing to do here.
        LOG(("ScriptLoadRequest (%p):   Error loading request, firing error", aRequest));
@@ -797,11 +764,11 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
  
    {
      // Try to perform a microtask checkpoint
-@@ -2002,17 +2002,17 @@ ScriptLoader::ProcessRequest(ScriptLoadR
+@@ -1909,17 +1909,17 @@ ScriptLoader::ProcessRequest(ScriptLoadR
      nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
                                           scriptElem,
                                           NS_LITERAL_STRING("afterscriptexecute"),
-                                          CanBubble::eYes, Cancelable::eNo);
+                                          true, false);
    }
  
    FireScriptEvaluated(rv, aRequest);
@@ -816,7 +783,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    if (aRequest->mOffThreadToken) {
      // The request was parsed off-main-thread, but the result of the off
      // thread parse was not actually needed to process the request
-@@ -2036,31 +2036,31 @@ ScriptLoader::ProcessRequest(ScriptLoadR
+@@ -1943,31 +1943,31 @@ ScriptLoader::ProcessRequest(ScriptLoadR
  }
  
  void
@@ -850,7 +817,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
  
  already_AddRefed<nsIScriptGlobalObject>
  ScriptLoader::GetScriptGlobalObject()
-@@ -2121,18 +2121,18 @@ ScriptLoader::FillCompileOptionsForReque
+@@ -2028,18 +2028,18 @@ ScriptLoader::FillCompileOptionsForReque
      aOptions->setMutedErrors(!subsumes);
    }
  
@@ -871,7 +838,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    }
  
    return NS_OK;
-@@ -2235,17 +2235,17 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+@@ -2136,17 +2136,17 @@ ScriptLoader::EvaluateScript(ScriptLoadR
    using namespace mozilla::Telemetry;
    MOZ_ASSERT(aRequest->IsReadyToRun());
  
@@ -890,7 +857,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
  
    // Get the script-type to be used by this element.
    NS_ASSERTION(scriptContent, "no content - what is default script-type?");
-@@ -2296,17 +2296,17 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+@@ -2197,17 +2197,17 @@ ScriptLoader::EvaluateScript(ScriptLoadR
          JS_SetPendingException(cx, error);
          return NS_OK; // An error is reported by AutoEntryScript.
        }
@@ -909,7 +876,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
          JS::ExposeScriptToDebugger(cx, script);
        }
  
-@@ -2315,24 +2315,24 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+@@ -2216,24 +2216,24 @@ ScriptLoader::EvaluateScript(ScriptLoadR
        if (NS_FAILED(rv)) {
          LOG(("ScriptLoadRequest (%p):   evaluation failed", aRequest));
          rv = NS_OK; // An error is reported by AutoEntryScript.
@@ -936,7 +903,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
              LOG(("ScriptLoadRequest (%p): Decode Bytecode and Execute", aRequest));
              rv = exec.DecodeAndExec(options, aRequest->mScriptBytecode,
                                      aRequest->mBytecodeOffset);
-@@ -2343,17 +2343,17 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+@@ -2244,17 +2244,17 @@ ScriptLoader::EvaluateScript(ScriptLoadR
          } else {
            MOZ_ASSERT(aRequest->IsSource());
            JS::Rooted<JSScript*> script(cx);
@@ -951,12 +918,12 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
                // Off-main-thread parsing.
                LOG(("ScriptLoadRequest (%p): Join (off-thread parsing) and Execute",
                     aRequest));
-               if (aRequest->IsBinASTSource()) {
-                 rv = exec.DecodeBinASTJoinAndExec(&aRequest->mOffThreadToken, &script);
-               } else {
-                 MOZ_ASSERT(aRequest->IsTextSource());
-@@ -2380,23 +2380,23 @@ ScriptLoader::EvaluateScript(ScriptLoadR
-               }
+               MOZ_ASSERT(aRequest->IsTextSource());
+               rv = exec.JoinAndExec(&aRequest->mOffThreadToken, &script);
+             } else {
+               // Main thread parsing (inline and small scripts)
+@@ -2265,23 +2265,23 @@ ScriptLoader::EvaluateScript(ScriptLoadR
+               rv = exec.CompileAndExec(options, srcBuf, &script);
              }
            }
  
@@ -981,7 +948,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
  
      // Even if we are not saving the bytecode of the current script, we have
      // to trigger the encoding of the bytecode, as the current script can
-@@ -2507,17 +2507,17 @@ ScriptLoader::EncodeBytecode()
+@@ -2392,17 +2392,17 @@ ScriptLoader::EncodeBytecode()
  
  void
  ScriptLoader::EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest)
@@ -1000,7 +967,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
           aRequest));
      return;
    }
-@@ -2552,17 +2552,17 @@ ScriptLoader::EncodeRequestBytecode(JSCo
+@@ -2436,17 +2436,17 @@ ScriptLoader::EncodeRequestBytecode(JSCo
                       aRequest->mScriptBytecode.length(), &n);
    LOG(("ScriptLoadRequest (%p): Write bytecode cache (rv = %X, length = %u, written = %u)",
         aRequest, unsigned(rv), unsigned(aRequest->mScriptBytecode.length()), n));
@@ -1019,7 +986,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    // If the document went away prematurely, we still want to set this, in order
    // to avoid queuing more scripts.
    mGiveUpEncoding = true;
-@@ -2579,17 +2579,17 @@ ScriptLoader::GiveUpBytecodeEncoding()
+@@ -2463,17 +2463,17 @@ ScriptLoader::GiveUpBytecodeEncoding()
      if (context) {
        aes.emplace(globalObject, "give-up bytecode encoding", true);
      }
@@ -1038,7 +1005,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
      }
  
      request->mScriptBytecode.clearAndFree();
-@@ -2887,18 +2887,18 @@ ScriptLoader::VerifySRI(ScriptLoadReques
+@@ -2781,17 +2781,18 @@ ScriptLoader::VerifySRI(ScriptLoadReques
  
      if (loadInfo && loadInfo->GetEnforceSRI()) {
        MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
@@ -1048,18 +1015,17 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
        nsAutoCString violationURISpec;
        mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
 -      uint32_t lineNo = aRequest->mElement ? aRequest->mElement->GetScriptLineNumber() : 0;
--      uint32_t columnNo = aRequest->mElement ? aRequest->mElement->GetScriptColumnNumber() : 0;
 +      uint32_t lineNo = aRequest->Element() ? aRequest->Element()->GetScriptLineNumber() : 0;
-+      uint32_t columnNo = aRequest->Element() ? aRequest->Element()->GetScriptColumnNumber() : 0;
++//     uint32_t columnNo = aRequest->Element() ? aRequest->Element()->GetScriptColumnNumber() : 0;
        csp->LogViolationDetails(
          nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
-         nullptr, // triggering element
          NS_ConvertUTF8toUTF16(violationURISpec),
-         EmptyString(), lineNo, columnNo, EmptyString(), EmptyString());
+         EmptyString(), lineNo, EmptyString(), EmptyString());
        rv = NS_ERROR_SRI_CORRUPT;
      }
    }
-@@ -2953,17 +2953,17 @@ ScriptLoader::SaveSRIHash(ScriptLoadRequ
+ 
+@@ -2845,17 +2846,17 @@ ScriptLoader::SaveSRIHash(ScriptLoadRequ
  }
  
  void
@@ -1078,7 +1044,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    if (aResult == NS_ERROR_MALFORMED_URI) {
      message =
        isScript ? "ScriptSourceMalformed" : "ModuleSourceMalformed";
-@@ -2974,18 +2974,18 @@ ScriptLoader::ReportErrorToConsole(Scrip
+@@ -2866,17 +2867,18 @@ ScriptLoader::ReportErrorToConsole(Scrip
    } else {
      message =
        isScript ? "ScriptSourceLoadFailed" : "ModuleSourceLoadFailed";
@@ -1088,18 +1054,17 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    const char16_t* params[] = { url.get() };
  
 -  uint32_t lineNo = aRequest->mElement->GetScriptLineNumber();
--  uint32_t columnNo = aRequest->mElement->GetScriptColumnNumber();
 +  uint32_t lineNo = aRequest->Element()->GetScriptLineNumber();
-+  uint32_t columnNo = aRequest->Element()->GetScriptColumnNumber();
++//   uint32_t columnNo = aRequest->Element()->GetScriptColumnNumber();
  
    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                    NS_LITERAL_CSTRING("Script Loader"), mDocument,
                                    nsContentUtils::eDOM_PROPERTIES, message,
                                    params, ArrayLength(params), nullptr,
-                                   EmptyString(), lineNo, columnNo);
+                                   EmptyString(), lineNo);
  }
  
-@@ -2993,17 +2993,17 @@ void
+@@ -2884,17 +2886,17 @@ void
  ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult)
  {
    /*
@@ -1118,7 +1083,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
      SetModuleFetchFinishedAndResumeWaitingRequests(request, aResult);
    }
  
-@@ -3038,22 +3038,22 @@ ScriptLoader::HandleLoadError(ScriptLoad
+@@ -2929,22 +2931,22 @@ ScriptLoader::HandleLoadError(ScriptLoad
      MOZ_ASSERT(!modReq->isInList());
      modReq->Cancel();
      // A single error is fired for the top level module.
@@ -1144,7 +1109,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
        aRequest->Cancel();
      }
      if (aRequest->IsTopLevel()) {
-@@ -3066,23 +3066,23 @@ ScriptLoader::HandleLoadError(ScriptLoad
+@@ -2956,23 +2958,23 @@ ScriptLoader::HandleLoadError(ScriptLoad
      MOZ_ASSERT(aRequest->IsCanceled());
      MOZ_ASSERT(!aRequest->isInList());
    }
@@ -1170,7 +1135,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    if (mNumberOfProcessors > 0)
      return mNumberOfProcessors;
  
-@@ -3153,17 +3153,17 @@ ScriptLoader::PrepareLoadedRequest(Scrip
+@@ -3042,17 +3044,17 @@ ScriptLoader::PrepareLoadedRequest(Scrip
        aRequest->SetIsTracking();
      }
    }
@@ -1189,7 +1154,7 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
    // This assertion could fire errorously if we ran out of memory when
    // inserting the request in the array. However it's an unlikely case
    // so if you see this assertion it is likely something else that is
-@@ -3307,19 +3307,19 @@ ScriptLoader::PreloadURI(nsIURI* aURI,
+@@ -3198,19 +3200,19 @@ ScriptLoader::PreloadURI(nsIURI* aURI,
      return;
    }
  
@@ -1213,8 +1178,8 @@ diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
 diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h
 --- a/dom/script/ScriptLoader.h
 +++ b/dom/script/ScriptLoader.h
-@@ -344,16 +344,17 @@ public:
-   }
+@@ -346,16 +346,17 @@ public:
+   void ClearModuleMap();
  
  private:
    virtual ~ScriptLoader();
@@ -1231,4 +1196,3 @@ diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h
     * Unblocks the creator parser of the parser-blocking scripts.
     */
    void UnblockParser(ScriptLoadRequest* aParserBlockingRequest);
-

+ 24 - 116
frg/work-js/mozilla-release/patches/1484948-64a1.patch

@@ -2,13 +2,13 @@
 # User Jon Coppeard <jcoppeard@mozilla.com>
 # Date 1536339169 -3600
 # Node ID d1b2141b1c454f28b8d35164c958e9ddcc7058fe
-# Parent  293c4672dd15110112e96e277a30e3180133278d
+# Parent  1668b9d0af172e26e4d76e58e21d3a436cb3c714
 Bug 1484948 - Parse dynamic module import syntax but throw SyntaxError if used r=jorendorff
 
 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
-@@ -594,16 +594,19 @@ class NodeBuilder
+@@ -592,16 +592,19 @@ class NodeBuilder
      MOZ_MUST_USE bool thisExpression(TokenPos* pos, MutableHandleValue dst);
  
      MOZ_MUST_USE bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos,
@@ -28,7 +28,7 @@ diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
  
      MOZ_MUST_USE bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
                                            MutableHandleValue dst);
-@@ -1595,16 +1598,30 @@ NodeBuilder::metaProperty(HandleValue me
+@@ -1593,16 +1596,30 @@ NodeBuilder::metaProperty(HandleValue me
  
      return newNode(AST_METAPROPERTY, pos,
                     "meta", meta,
@@ -59,7 +59,7 @@ diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
  
      return newNode(AST_SUPER, pos, dst);
  }
-@@ -2945,16 +2962,31 @@ ASTSerializer::expression(ParseNode* pn,
+@@ -2942,16 +2959,31 @@ ASTSerializer::expression(ParseNode* pn,
              secondStr = cx->names().meta;
          }
  
@@ -94,7 +94,7 @@ diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
 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
-@@ -1212,16 +1212,21 @@ BytecodeEmitter::checkSideEffects(ParseN
+@@ -3680,16 +3680,21 @@ BytecodeEmitter::checkSideEffects(ParseN
          return true;
  
        // Likewise.
@@ -116,7 +116,7 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
        case ParseNodeKind::DoWhile:
        case ParseNodeKind::While:
        case ParseNodeKind::For:
-@@ -8303,16 +8308,20 @@ BytecodeEmitter::emitTree(ParseNode* pn,
+@@ -11270,16 +11275,20 @@ BytecodeEmitter::emitTree(ParseNode* pn,
              return false;
          break;
  
@@ -134,13 +134,13 @@ diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitt
              return false;
          break;
  
-       case ParseNodeKind::PropertyName:
        case ParseNodeKind::PosHolder:
-         MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder or ::Property");
+         MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder");
+ 
 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
-@@ -131,16 +131,17 @@ ContainsHoistedDeclaration(JSContext* cx
+@@ -133,16 +133,17 @@ ContainsHoistedDeclaration(JSContext* cx
        case ParseNodeKind::ImportSpecList:
        case ParseNodeKind::ImportSpec:
        case ParseNodeKind::ExportFrom:
@@ -158,7 +158,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
        case ParseNodeKind::DoWhile:
          return ContainsHoistedDeclaration(cx, node->pn_left, result);
  
-@@ -1750,16 +1751,21 @@ Fold(JSContext* cx, ParseNode** pnp, Per
+@@ -1725,16 +1726,21 @@ Fold(JSContext* cx, ParseNode** pnp, Per
  
        case ParseNodeKind::NewTarget:
        case ParseNodeKind::ImportMeta:
@@ -183,7 +183,7 @@ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.c
 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
-@@ -557,16 +557,20 @@ class FullParseHandler
+@@ -552,16 +552,20 @@ class FullParseHandler
      ParseNode* newExportBatchSpec(const TokenPos& pos) {
          return new_<NullaryNode>(ParseNodeKind::ExportBatchSpec, JSOP_NOP, pos);
      }
@@ -207,7 +207,7 @@ diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandl
 diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp
 --- a/js/src/frontend/NameFunctions.cpp
 +++ b/js/src/frontend/NameFunctions.cpp
-@@ -781,16 +781,22 @@ class NameResolver
+@@ -760,16 +760,22 @@ class NameResolver
                  MOZ_ASSERT(!item->pn_left->expr());
                  MOZ_ASSERT(item->pn_right->isKind(ParseNodeKind::Name));
                  MOZ_ASSERT(!item->pn_right->expr());
@@ -223,17 +223,17 @@ diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.c
 +            break;
 +
            case ParseNodeKind::Dot:
-             MOZ_ASSERT(cur->isArity(PN_BINARY));
+             MOZ_ASSERT(cur->isArity(PN_NAME));
  
              // Super prop nodes do not have a meaningful LHS
              if (cur->as<PropertyAccess>().isSuper())
                  break;
-             if (!resolve(cur->pn_left, prefix))
+             if (!resolve(cur->expr(), prefix))
                  return false;
 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
-@@ -131,16 +131,17 @@ class ObjectBox;
+@@ -128,16 +128,17 @@ class ObjectBox;
      F(ClassMethodList) \
      F(ClassNames) \
      F(NewTarget) \
@@ -254,7 +254,7 @@ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
 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
-@@ -5437,25 +5437,25 @@ template <class ParseHandler, typename C
+@@ -5335,25 +5335,25 @@ template <class ParseHandler, typename C
  inline typename ParseHandler::Node
  GeneralParser<ParseHandler, CharT>::importDeclaration()
  {
@@ -282,7 +282,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
  template<typename CharT>
  bool
  Parser<FullParseHandler, CharT>::checkExportedName(JSAtom* exportName)
-@@ -7806,17 +7806,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7705,17 +7705,17 @@ GeneralParser<ParseHandler, CharT>::stat
  
        // |class| is also forbidden by lookahead restriction.
        case TokenKind::Class:
@@ -301,7 +301,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
        // Miscellaneous error cases arguably better caught here than elsewhere.
  
        case TokenKind::Catch:
-@@ -7999,17 +7999,17 @@ GeneralParser<ParseHandler, CharT>::stat
+@@ -7898,17 +7898,17 @@ GeneralParser<ParseHandler, CharT>::stat
        //     LetOrConst BindingList[?In, ?Yield]
        case TokenKind::Const:
          // [In] is the default behavior, because for-loops specially parse
@@ -320,7 +320,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
        // Miscellaneous error cases arguably better caught here than elsewhere.
  
        case TokenKind::Catch:
-@@ -8836,17 +8836,17 @@ GeneralParser<ParseHandler, CharT>::memb
+@@ -8719,17 +8719,17 @@ GeneralParser<ParseHandler, CharT>::memb
      } else if (tt == TokenKind::Super) {
          Node thisName = newThisName();
          if (!thisName)
@@ -339,7 +339,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
              return null();
      }
  
-@@ -10019,51 +10019,58 @@ GeneralParser<ParseHandler, CharT>::tryN
+@@ -9900,51 +9900,58 @@ GeneralParser<ParseHandler, CharT>::tryN
          return false;
  
      newTarget = handler.newNewTarget(newHolder, targetHolder);
@@ -426,7 +426,7 @@ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
 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
-@@ -1040,17 +1040,17 @@ class MOZ_STACK_CLASS GeneralParser
+@@ -1023,17 +1023,17 @@ class MOZ_STACK_CLASS GeneralParser
      Node labeledItem(YieldHandling yieldHandling);
  
      Node ifStatement(YieldHandling yieldHandling);
@@ -445,7 +445,7 @@ diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
      Node exportFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
                                     FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
      Node exportVariableStatement(uint32_t begin);
-@@ -1140,17 +1140,17 @@ class MOZ_STACK_CLASS GeneralParser
+@@ -1123,17 +1123,17 @@ class MOZ_STACK_CLASS GeneralParser
      Node primaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
                       TokenKind tt, PossibleError* possibleError,
                       InvokedPrediction invoked = PredictUninvoked);
@@ -467,7 +467,7 @@ diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
 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
-@@ -297,16 +297,19 @@ class SyntaxParseHandler
+@@ -295,16 +295,19 @@ class SyntaxParseHandler
          return NodeGeneric;
      }
      Node newExportBatchSpec(const TokenPos& pos) {
@@ -599,7 +599,7 @@ diff --git a/js/src/js.msg b/js/src/js.msg
  MSG_DEF(JSMSG_LABEL_NOT_FOUND,         0, JSEXN_SYNTAXERR, "label not found")
  MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,   1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
  MSG_DEF(JSMSG_LEXICAL_DECL_LABEL,      1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
-@@ -601,16 +601,17 @@ MSG_DEF(JSMSG_REINIT_THIS,       0, JSEX
+@@ -592,16 +592,17 @@ MSG_DEF(JSMSG_REINIT_THIS,       0, JSEX
  MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT,        0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")
  MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT,   0, JSEXN_SYNTAXERR, "indirect export not found")
  MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "ambiguous indirect export")
@@ -638,95 +638,3 @@ diff --git a/js/src/jsast.tbl b/js/src/jsast.tbl
  ASTDEF(AST_IF_STMT,               "IfStatement",                    "ifStatement")
  ASTDEF(AST_SWITCH_STMT,           "SwitchStatement",                "switchStatement")
  ASTDEF(AST_WHILE_STMT,            "WhileStatement",                 "whileStatement")
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini
-@@ -1,4 +1,8 @@
- [dynamic-imports-fetch-error.sub.html]
-+  expected: ERROR
-   [import(): error cases occuring during fetching]
-     expected: FAIL
- 
-+  [import() must reject when there is a wrong MIME type]
-+    expected: FAIL
-+
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini
-@@ -1,4 +1,8 @@
- [dynamic-imports-script-error.html]
-+  expected: ERROR
-   [import(): error cases caused by the imported module script]
-     expected: FAIL
- 
-+  [import() must reject when there is a parse error]
-+    expected: FAIL
-+
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini
-@@ -1,4 +1,7 @@
- [dynamic-imports.html]
-   [Basic dynamic imports]
-     expected: FAIL
- 
-+  [Dynamic imports should resolve module.]
-+    expected: FAIL
-+
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini
-@@ -1,7 +1,10 @@
- [propagate-nonce-external-classic.html]
-   [Untitled]
-     expected: FAIL
- 
-   [propagate-nonce-external-classic]
-     expected: FAIL
- 
-+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
-+    expected: FAIL
-+
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini
-@@ -1,7 +1,10 @@
- [propagate-nonce-external-module.html]
-   [Untitled]
-     expected: FAIL
- 
-   [propagate-nonce-external-module]
-     expected: FAIL
- 
-+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
-+    expected: FAIL
-+
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini
-@@ -1,7 +1,10 @@
- [propagate-nonce-inline-classic.html]
-   [Untitled]
-     expected: FAIL
- 
-   [propagate-nonce-inline-classic]
-     expected: FAIL
- 
-+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
-+    expected: FAIL
-+
-diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini
---- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini
-+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini
-@@ -1,7 +1,10 @@
- [propagate-nonce-inline-module.html]
-   [Untitled]
-     expected: FAIL
- 
-   [propagate-nonce-inline-module]
-     expected: FAIL
- 
-+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
-+    expected: FAIL
-+
-

+ 3 - 3
frg/work-js/mozilla-release/patches/1486173-2-63a1.patch

@@ -2,7 +2,7 @@
 # User Robin Templeton <robin@igalia.com>
 # Date 1535132580 -10800
 # Node ID c62f40111003f108aa6bef93af6b289688ea1d97
-# Parent  24a3e06645b36a4c04d4450cd434fe61380761b1
+# Parent  9132f2609e20740d3d318384c132e5b6cdce825d
 bug 1486173 - Part 2: Add BigInt methods for equality comparison. r=jandem
 
 diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp
@@ -82,12 +82,12 @@ diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp
      MOZ_ASSERT(2 <= radix && radix <= 36);
      // We need two extra chars for '\0' and potentially '-'.
      size_t strSize = mpz_sizeinbase(x->num_, 10) + 2;
-     UniqueChars str(static_cast<char*>(js_malloc(strSize)));
+     UniqueChars str(js_pod_malloc<char>(strSize));
      if (!str) {
 diff --git a/js/src/vm/BigIntType.h b/js/src/vm/BigIntType.h
 --- a/js/src/vm/BigIntType.h
 +++ b/js/src/vm/BigIntType.h
-@@ -92,16 +92,20 @@ class BigInt final : public js::gc::Tenu
+@@ -95,16 +95,20 @@ class BigInt final : public js::gc::Tenu
      static bool div(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res);
      static bool mod(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res);
      static bool pow(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res);

+ 30 - 4
frg/work-js/mozilla-release/patches/1489698-6-65a1.patch

@@ -3,14 +3,14 @@
 # Date 1541023705 14400
 #      Wed Oct 31 18:08:25 2018 -0400
 # Node ID 93ecf65646b9f9112437eee8f571265d864ea3de
-# Parent  340e076fc0b425a37930050497101aa86003faa8
+# Parent  f0aa90015f79fe2e55128e91a6df7f618acbf3a4
 Bug 1489698 - Add moz.build for js/src/frontend. r=waldo,froydnj
 
 diff --git a/js/src/frontend/moz.build b/js/src/frontend/moz.build
 new file mode 100644
 --- /dev/null
 +++ b/js/src/frontend/moz.build
-@@ -0,0 +1,41 @@
+@@ -0,0 +1,54 @@
 +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 +# vim: set filetype=python:
 +# This Source Code Form is subject to the terms of the Mozilla Public
@@ -40,11 +40,24 @@ new file mode 100644
 +
 +UNIFIED_SOURCES += [
 +    'BytecodeCompiler.cpp',
++    'BytecodeControlStructures.cpp',
 +    'BytecodeEmitter.cpp',
++    'CForEmitter.cpp',
++    'DoWhileEmitter.cpp',
++    'EmitterScope.cpp',
 +    'FoldConstants.cpp',
++    'ForInEmitter.cpp',
++    'ForOfEmitter.cpp',
++    'ForOfLoopControl.cpp',
++    'IfEmitter.cpp',
++    'JumpList.cpp',
 +    'NameFunctions.cpp',
 +    'ParseNode.cpp',
++    'SwitchEmitter.cpp',
++    'TDZCheckCache.cpp',
 +    'TokenStream.cpp',
++    'TryEmitter.cpp',
++    'WhileEmitter.cpp',
 +]
 +
 +# Parser.cpp cannot be built in unified mode because of explicit
@@ -55,7 +68,7 @@ new file mode 100644
 diff --git a/js/src/moz.build b/js/src/moz.build
 --- a/js/src/moz.build
 +++ b/js/src/moz.build
-@@ -193,22 +193,16 @@ UNIFIED_SOURCES += [
+@@ -193,35 +193,16 @@ UNIFIED_SOURCES += [
      'builtin/TestingFunctions.cpp',
      'builtin/TypedObject.cpp',
      'builtin/WeakMapObject.cpp',
@@ -65,11 +78,24 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'ds/LifoAlloc.cpp',
      'ds/MemoryProtectionExceptionHandler.cpp',
 -    'frontend/BytecodeCompiler.cpp',
+-    'frontend/BytecodeControlStructures.cpp',
 -    'frontend/BytecodeEmitter.cpp',
+-    'frontend/CForEmitter.cpp',
+-    'frontend/DoWhileEmitter.cpp',
+-    'frontend/EmitterScope.cpp',
 -    'frontend/FoldConstants.cpp',
+-    'frontend/ForInEmitter.cpp',
+-    'frontend/ForOfEmitter.cpp',
+-    'frontend/ForOfLoopControl.cpp',
+-    'frontend/IfEmitter.cpp',
+-    'frontend/JumpList.cpp',
 -    'frontend/NameFunctions.cpp',
 -    'frontend/ParseNode.cpp',
+-    'frontend/SwitchEmitter.cpp',
+-    'frontend/TDZCheckCache.cpp',
 -    'frontend/TokenStream.cpp',
+-    'frontend/TryEmitter.cpp',
+-    'frontend/WhileEmitter.cpp',
      'gc/Allocator.cpp',
      'gc/AtomMarking.cpp',
      'gc/Barrier.cpp',
@@ -78,7 +104,7 @@ diff --git a/js/src/moz.build b/js/src/moz.build
      'gc/Marking.cpp',
      'gc/Memory.cpp',
      'gc/Nursery.cpp',
-@@ -432,25 +426,19 @@ if CONFIG['HAVE_LINUX_PERF_EVENT_H']:
+@@ -445,25 +426,19 @@ if CONFIG['HAVE_LINUX_PERF_EVENT_H']:
      ]
      if CONFIG['LINUX_HEADERS_INCLUDES']:
          SOURCES['perf/pm_linux.cpp'].flags += [CONFIG['LINUX_HEADERS_INCLUDES']]

+ 178 - 0
frg/work-js/mozilla-release/patches/1498980-64a1.patch

@@ -0,0 +1,178 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1539855213 -3600
+# Node ID 6b952be63f69e244ab688cdb7a84d121b009a162
+# Parent  8f74f5dbf5c0d12bebf84841b8553b179b7d04a0
+Bug 1498980 - Remove module environment from live debugger envionments after execution r=jorendorff
+
+diff --git a/js/src/jit-test/tests/modules/bug-1498980.js b/js/src/jit-test/tests/modules/bug-1498980.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/modules/bug-1498980.js
+@@ -0,0 +1,24 @@
++dbgGlobal = newGlobal();
++dbg = new dbgGlobal.Debugger;
++dbg.addDebuggee(this);
++
++function f() {
++    dbg.getNewestFrame().older.eval("");
++}
++
++function execModule(source) {
++    m = parseModule(source);
++    m.declarationInstantiation();
++    m.evaluation();
++}
++
++execModule("f();");
++gc();
++
++let caught;
++try {
++    execModule("throw 'foo'");
++} catch (e) {
++    caught = e;
++}
++assertEq(caught, 'foo');
+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
+@@ -2802,20 +2802,21 @@ DebugEnvironments::takeFrameSnapshot(JSC
+      * copy of the unaliased variables' values in an array for later debugger
+      * access via DebugEnvironmentProxy::handleUnaliasedAccess.
+      *
+      * Note: since it is simplest for this function to be infallible, failure
+      * in this code will be silently ignored. This does not break any
+      * invariants since DebugEnvironmentProxy::maybeSnapshot can already be nullptr.
+      */
+ 
++    JSScript* script = frame.script();
++
+     // Act like no snapshot was taken if we run OOM while taking the snapshot.
+     Rooted<GCVector<Value>> vec(cx, GCVector<Value>(cx));
+     if (debugEnv->environment().is<CallObject>()) {
+-        JSScript* script = frame.script();
+ 
+         FunctionScope* scope = &script->bodyScope()->as<FunctionScope>();
+         uint32_t frameSlotCount = scope->nextFrameSlot();
+         MOZ_ASSERT(frameSlotCount <= script->nfixed());
+ 
+         // For simplicity, copy all frame slots from 0 to the frameSlotCount,
+         // even if we don't need all of them (like in the case of a defaults
+         // parameter scope having frame slots).
+@@ -2843,32 +2844,38 @@ DebugEnvironments::takeFrameSnapshot(JSC
+     } else {
+         uint32_t frameSlotStart;
+         uint32_t frameSlotEnd;
+ 
+         if (debugEnv->environment().is<LexicalEnvironmentObject>()) {
+             LexicalScope* scope = &debugEnv->environment().as<LexicalEnvironmentObject>().scope();
+             frameSlotStart = scope->firstFrameSlot();
+             frameSlotEnd = scope->nextFrameSlot();
+-        } else {
++        } else if (debugEnv->environment().is<VarEnvironmentObject>()) {
+             VarEnvironmentObject* env = &debugEnv->environment().as<VarEnvironmentObject>();
+             if (frame.isFunctionFrame()) {
+                 VarScope* scope = &env->scope().as<VarScope>();
+                 frameSlotStart = scope->firstFrameSlot();
+                 frameSlotEnd = scope->nextFrameSlot();
+             } else {
+                 EvalScope* scope = &env->scope().as<EvalScope>();
+-                MOZ_ASSERT(scope == frame.script()->bodyScope());
++                MOZ_ASSERT(scope == script->bodyScope());
+                 frameSlotStart = 0;
+                 frameSlotEnd = scope->nextFrameSlot();
+             }
++        } else {
++            MOZ_ASSERT(&debugEnv->environment().as<ModuleEnvironmentObject>() ==
++                       script->module()->environment());
++            ModuleScope* scope = &script->bodyScope()->as<ModuleScope>();
++            frameSlotStart = 0;
++            frameSlotEnd = scope->nextFrameSlot();
+         }
+ 
+         uint32_t frameSlotCount = frameSlotEnd - frameSlotStart;
+-        MOZ_ASSERT(frameSlotCount <= frame.script()->nfixed());
++        MOZ_ASSERT(frameSlotCount <= script->nfixed());
+ 
+         if (!vec.resize(frameSlotCount)) {
+             cx->recoverFromOutOfMemory();
+             return;
+         }
+         for (uint32_t slot = frameSlotStart; slot < frameSlotCount; slot++) {
+             vec[slot - frameSlotStart].set(frame.unaliasedLocal(slot));
+         }
+@@ -3018,16 +3025,22 @@ DebugEnvironments::onPopWith(AbstractFra
+ {
+     Realm* realm = frame.realm();
+     if (DebugEnvironments* envs = realm->debugEnvs()) {
+         envs->liveEnvs.remove(&frame.environmentChain()->as<WithEnvironmentObject>());
+     }
+ }
+ 
+ void
++DebugEnvironments::onPopModule(JSContext* cx, const EnvironmentIter& ei)
++{
++    onPopGeneric<ModuleEnvironmentObject, ModuleScope>(cx, ei);
++}
++
++void
+ DebugEnvironments::onRealmUnsetIsDebuggee(Realm* realm)
+ {
+     if (DebugEnvironments* envs = realm->debugEnvs()) {
+         envs->proxiedEnvs.clear();
+         envs->missingEnvs.clear();
+         envs->liveEnvs.clear();
+     }
+ }
+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
+@@ -1049,16 +1049,17 @@ class DebugEnvironments
+     // In debug-mode, these must be called whenever exiting a scope that might
+     // have stack-allocated locals.
+     static void onPopCall(JSContext* cx, AbstractFramePtr frame);
+     static void onPopVar(JSContext* cx, const EnvironmentIter& ei);
+     static void onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
+     static void onPopLexical(JSContext* cx, const EnvironmentIter& ei);
+     static void onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
+     static void onPopWith(AbstractFramePtr frame);
++    static void onPopModule(JSContext* cx, const EnvironmentIter& ei);
+     static void onRealmUnsetIsDebuggee(Realm* realm);
+ };
+ 
+ }  /* namespace js */
+ 
+ template <>
+ inline bool
+ JSObject::is<js::EnvironmentObject>() const
+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
+@@ -1238,20 +1238,24 @@ PopEnvironment(JSContext* cx, Environmen
+       case ScopeKind::StrictEval:
+         if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
+             DebugEnvironments::onPopVar(cx, ei);
+         }
+         if (ei.scope().hasEnvironment()) {
+             ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
+         }
+         break;
++      case ScopeKind::Module:
++        if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
++            DebugEnvironments::onPopModule(cx, ei);
++        }
++        break;
+       case ScopeKind::Eval:
+       case ScopeKind::Global:
+       case ScopeKind::NonSyntactic:
+-      case ScopeKind::Module:
+         break;
+       case ScopeKind::WasmInstance:
+       case ScopeKind::WasmFunction:
+         MOZ_CRASH("wasm is not interpreted");
+         break;
+     }
+ }
+ 
+

+ 39 - 0
frg/work-js/mozilla-release/patches/1517546-67a1.patch

@@ -0,0 +1,39 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1551892824 0
+# Node ID 6ce854f480d62475419081de730a80166d4946f4
+# Parent  a8c07059ab926e6c1d7ee415d8406a9ff3331878
+Bug 1517546 - Enable dyanmic module import by default r=smaug
+
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
+--- a/modules/libpref/init/all.js
++++ b/modules/libpref/init/all.js
+@@ -1597,21 +1597,17 @@ pref("javascript.options.spectre.jit_to_
+ 
+ // Streams API
+ pref("javascript.options.streams", true);
+ 
+ // BigInt API
+ pref("javascript.options.bigint", false);
+ 
+ // Dynamic module import.
+-#ifdef NIGHTLY_BUILD
+ pref("javascript.options.dynamicImport", true);
+-#else
+-pref("javascript.options.dynamicImport", false);
+-#endif
+ 
+ // advanced prefs
+ pref("advanced.mailftp",                    false);
+ pref("image.animation_mode",                "normal");
+ 
+ // Same-origin policy for file URIs, "false" is traditional
+ pref("security.fileuri.strict_origin_policy", true);
+ 
+diff --git a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/__dir__.ini b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/__dir__.ini
+--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/__dir__.ini
++++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/__dir__.ini
+@@ -1,1 +1,1 @@
+-prefs: [javascript.options.dynamicImport:true, security.csp.experimentalEnabled:true]
++prefs: [security.csp.experimentalEnabled:true]
+

+ 6 - 6
frg/work-js/mozilla-release/patches/1522150-1-66a1.patch

@@ -2,7 +2,7 @@
 # User Randell Jesup <rjesup@jesup.org>
 # Date 1548523085 18000
 # Node ID 0f5c896960f5147c3600c847209fb786dc6c1481
-# Parent  61193547bd951c37b20dac413247966918ad082c
+# Parent  5cf6a22e0fb625a8bbe71a933642ce478d01d7db
 Bug 1522150: Rename EventPriority to EventQueuePriority to avoid name conflict with MacOS r=froyd
 
 diff --git a/xpcom/threads/AbstractEventQueue.h b/xpcom/threads/AbstractEventQueue.h
@@ -458,7 +458,7 @@ diff --git a/xpcom/threads/PrioritizedEventQueue.h b/xpcom/threads/PrioritizedEv
 diff --git a/xpcom/threads/SchedulerGroup.h b/xpcom/threads/SchedulerGroup.h
 --- a/xpcom/threads/SchedulerGroup.h
 +++ b/xpcom/threads/SchedulerGroup.h
-@@ -179,18 +179,17 @@ public:
+@@ -183,18 +183,17 @@ public:
        : mRunnable(aRunnable)
        , mEpochNumber(aEpoch)
      {
@@ -474,11 +474,11 @@ diff --git a/xpcom/threads/SchedulerGroup.h b/xpcom/threads/SchedulerGroup.h
    }
  
  protected:
-   static nsresult InternalUnlabeledDispatch(TaskCategory aCategory,
-                                             already_AddRefed<Runnable>&& aRunnable);
+   nsresult DispatchWithDocGroup(TaskCategory aCategory,
+                                 already_AddRefed<nsIRunnable>&& aRunnable,
+                                 dom::DocGroup* aDocGroup);
  
-   // Implementations are guaranteed that this method is called on the main
-@@ -219,16 +218,16 @@ protected:
+@@ -228,16 +227,16 @@ protected:
    bool mIsRunning;
  
    // Number of events that are currently enqueued for this SchedulerGroup

+ 33 - 0
frg/work-js/mozilla-release/patches/1522491-67a1.patch

@@ -0,0 +1,33 @@
+# HG changeset patch
+# User Jon Coppeard <jcoppeard@mozilla.com>
+# Date 1548672809 0
+# Node ID fb748cd921d184cc901c111639db1a19bd14bf26
+# Parent  231f059ad9d9b02edf6b7e90de29691f24e5d92a
+Bug 1522491 - Enable dynamic module import on nightly builds only r=smaug
+
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
+--- a/modules/libpref/init/all.js
++++ b/modules/libpref/init/all.js
+@@ -1601,17 +1601,21 @@ pref("javascript.options.spectre.jit_to_
+ 
+ // Streams API
+ pref("javascript.options.streams", true);
+ 
+ // BigInt API
+ pref("javascript.options.bigint", false);
+ 
+ // Dynamic module import.
++#ifdef NIGHTLY_BUILD
++pref("javascript.options.dynamicImport", true);
++#else
+ pref("javascript.options.dynamicImport", false);
++#endif
+ 
+ // advanced prefs
+ pref("advanced.mailftp",                    false);
+ pref("image.animation_mode",                "normal");
+ 
+ // Same-origin policy for file URIs, "false" is traditional
+ pref("security.fileuri.strict_origin_policy", true);
+ 
+

+ 5 - 5
frg/work-js/mozilla-release/patches/1533481-1-68a1.patch

@@ -3,7 +3,7 @@
 # Date 1554367911 -10800
 #      Thu Apr 04 11:51:51 2019 +0300
 # Node ID eaddff053db4dcbb5205e69bb8dbb78fc817c5ff
-# Parent  09305d5bbba39f88fe98aa442ae2a6536df0c6f5
+# Parent  7568ed7ca8d7b87d377467b038574e0e67d2c542
 Bug 1533481 - Part 1: Use ICU to retrieve the system default locale. r=jwalden!
 
 Summary:
@@ -68,14 +68,14 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
  #include "vm/JSScript.h"
  #include "vm/TraceLogging.h"
  #include "vm/TraceLoggingGraph.h"
-@@ -546,17 +549,23 @@ JSRuntime::resetDefaultLocale()
+@@ -544,17 +547,23 @@ JSRuntime::resetDefaultLocale()
  }
  
  const char*
  JSRuntime::getDefaultLocale()
  {
-     if (defaultLocale)
-         return defaultLocale;
+     if (defaultLocale.ref())
+         return defaultLocale.ref().get();
  
 +    // Use ICU if available to retrieve the default locale, this ensures ICU's
 +    // default locale matches our default locale.
@@ -89,6 +89,6 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
      if (!locale || !strcmp(locale, "C"))
          locale = "und";
  
-     char* lang = DuplicateString(mainContextFromOwnThread(), locale).release();
+     UniqueChars lang = DuplicateString(mainContextFromOwnThread(), locale);
      if (!lang)
          return nullptr;

+ 7 - 7
frg/work-js/mozilla-release/patches/1535226-68a1.patch

@@ -2,7 +2,7 @@
 # User Nicholas Nethercote <nnethercote@mozilla.com>
 # Date 1553131730 0
 # Node ID c36acc45cddcc9ddc89d4e84acf44c0c206eb341
-# Parent  4da7c303a5a64e4da1cc568cacc77390751b3ff7
+# Parent  8fcc8f2a51c3d471ae242647e40a07a356a57853
 Bug 1535226 - Remove uses of XP_WIN32 in Gecko. r=glandium
 
 The definitions can't be entirely removed yet because NSS still needs them.
@@ -189,7 +189,7 @@ diff --git a/js/src/old-configure.in b/js/src/old-configure.in
 diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp
 --- a/js/src/vm/Printer.cpp
 +++ b/js/src/vm/Printer.cpp
-@@ -438,17 +438,17 @@ bool
+@@ -439,17 +439,17 @@ bool
  Fprinter::put(const char* s, size_t len)
  {
      MOZ_ASSERT(file_);
@@ -201,13 +201,13 @@ diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp
 -#ifdef XP_WIN32
 +#ifdef XP_WIN
      if ((file_ == stderr) && (IsDebuggerPresent())) {
-         UniqueChars buf(static_cast<char*>(js_malloc(len + 1)));
+         UniqueChars buf = DuplicateString(s, len);
          if (!buf) {
              reportOutOfMemory();
              return false;
          }
-         PodCopy(buf.get(), s, len);
-         buf[len] = '\0';
+         OutputDebugStringA(buf.get());
+     }
 diff --git a/old-configure.in b/old-configure.in
 --- a/old-configure.in
 +++ b/old-configure.in
@@ -935,7 +935,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
  #endif
  
  #ifdef DEBUG
-@@ -1262,17 +1262,17 @@ nsXULAppInfo::RegisterAppMemory(uint64_t
+@@ -1251,17 +1251,17 @@ nsXULAppInfo::RegisterAppMemory(uint64_t
                                  uint64_t len)
  {
    return CrashReporter::RegisterAppMemory((void *)pointer, len);
@@ -954,7 +954,7 @@ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
  
  NS_IMETHODIMP
  nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
-@@ -5122,17 +5122,17 @@ SetupErrorHandling(const char* progname)
+@@ -5111,17 +5111,17 @@ SetupErrorHandling(const char* progname)
  
    HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
    SetProcessDEPPolicyFunc _SetProcessDEPPolicy =

+ 4 - 4
frg/work-js/mozilla-release/patches/1539462-1only-webide-71a1.patch

@@ -2,7 +2,7 @@
 # User Julian Descottes <jdescottes@mozilla.com>
 # Date 1569432298 0
 # Node ID eaa523b98e726c437fe96086f665495b61ed48e2
-# Parent  aba53d85cb3ab7827b0720eae771098415d30fc7
+# Parent  73d77e02b2bc0cfc84254a8dc636bb3e7ed2fbe5
 Bug 1539462 - Remove WebIDE r=ochameau,jryans,janerik,fluent-reviewers,flod
 
 Per deprecation roadmap on https://developer.mozilla.org/en-US/docs/Tools/Deprecated_tools#WebIDE_and_Connect_page
@@ -10380,7 +10380,7 @@ diff --git a/devtools/startup/locales/en-US/key-shortcuts.properties b/devtools/
 diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
 --- a/toolkit/components/telemetry/Histograms.json
 +++ b/toolkit/components/telemetry/Histograms.json
-@@ -6805,43 +6805,16 @@
+@@ -6795,43 +6795,16 @@
      "record_in_processes": ["main", "content"],
      "alert_emails": ["dev-developer-tools@lists.mozilla.org", "jan@mozilla.com"],
      "expires_in_version": "never",
@@ -10424,7 +10424,7 @@ diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/t
      "bug_numbers": [1247985],
      "description": "Number of times a custom developer tool has been opened.",
      "releaseChannelCollection": "opt-out"
-@@ -7064,143 +7037,24 @@
+@@ -7054,143 +7027,24 @@
      "record_in_processes": ["main", "content"],
      "alert_emails": ["dev-developer-tools@lists.mozilla.org", "jan@mozilla.com"],
      "expires_in_version": "55",
@@ -10653,7 +10653,6 @@ diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/co
 -    "DEVTOOLS_WEBIDE_IMPORT_PROJECT_COUNT",
 -    "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT",
 -    "DEVTOOLS_WEBIDE_OPENED_COUNT",
-     "DOM_SCRIPT_SRC_ENCODING",
      "ENABLE_PRIVILEGE_EVER_CALLED",
      "FENNEC_DISTRIBUTION_REFERRER_INVALID",
      "FENNEC_ORBOT_INSTALLED",
@@ -10661,3 +10660,4 @@ diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/co
      "FENNEC_SESSIONSTORE_ALL_FILES_DAMAGED",
      "FENNEC_SESSIONSTORE_DAMAGED_SESSION_FILE",
      "FENNEC_SESSIONSTORE_RESTORING_FROM_BACKUP",
+     "FENNEC_SYNC11_MIGRATIONS_COMPLETED",

+ 21 - 21
frg/work-js/mozilla-release/patches/1539780-70a1.patch

@@ -2,7 +2,7 @@
 # User Andre Bargull <andre.bargull@gmail.com>
 # Date 1565379799 0
 # Node ID 5967a3947ad0eeeecd97099e50655765259db28a
-# Parent  831c21bad2d5a6b30d7f7efc02b7982715ccdb8a
+# Parent  da79a196d9131098701c48b9cec76aa789b37675
 Bug 1539780: Remove "--with-intl-api=build" build config option. r=jwalden
 
 There are about the same number of occurrences of "ENABLE_INTL_API" and "EXPOSE_INTL_API"
@@ -133,7 +133,7 @@ diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js
 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
-@@ -1076,17 +1076,17 @@ js::intl_toLocaleLowerCase(JSContext* cx
+@@ -1066,17 +1066,17 @@ js::intl_toLocaleLowerCase(JSContext* cx
      JSString* result = NewStringCopyN<CanGC>(cx, chars.begin(), size);
      if (!result)
          return false;
@@ -152,7 +152,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  
  bool
  js::str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp)
-@@ -1117,17 +1117,17 @@ js::str_toLocaleLowerCase(JSContext* cx,
+@@ -1107,17 +1107,17 @@ js::str_toLocaleLowerCase(JSContext* cx,
      JSString* result = StringToLowerCase(cx, linear);
      if (!result)
          return false;
@@ -171,7 +171,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
      // special casing rules, so detect it inline.
      bool hasUpperCaseSpecialCasing = charCode == unicode::LATIN_SMALL_LETTER_SHARP_S;
      MOZ_ASSERT(hasUpperCaseSpecialCasing == unicode::ChangesWhenUpperCasedSpecialCasing(charCode));
-@@ -1474,17 +1474,17 @@ js::intl_toLocaleUpperCase(JSContext* cx
+@@ -1464,17 +1464,17 @@ js::intl_toLocaleUpperCase(JSContext* cx
      JSString* result = NewStringCopyN<CanGC>(cx, chars.begin(), size);
      if (!result)
          return false;
@@ -190,7 +190,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  
  bool
  js::str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
-@@ -1515,19 +1515,19 @@ js::str_toLocaleUpperCase(JSContext* cx,
+@@ -1505,19 +1505,19 @@ js::str_toLocaleUpperCase(JSContext* cx,
      JSString* result = StringToUpperCase(cx, linear);
      if (!result)
          return false;
@@ -213,7 +213,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  bool
  js::str_localeCompare(JSContext* cx, unsigned argc, Value* vp)
  {
-@@ -1552,19 +1552,19 @@ js::str_localeCompare(JSContext* cx, uns
+@@ -1542,19 +1542,19 @@ js::str_localeCompare(JSContext* cx, uns
      int32_t result;
      if (!CompareStrings(cx, str, thatStr, &result))
          return false;
@@ -236,7 +236,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  {
      CallArgs args = CallArgsFromVp(argc, vp);
  
-@@ -1679,17 +1679,17 @@ js::str_normalize(JSContext* cx, unsigne
+@@ -1669,17 +1669,17 @@ js::str_normalize(JSContext* cx, unsigne
      if (!ns)
          return false;
  
@@ -255,7 +255,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  
      RootedString str(cx);
      size_t i;
-@@ -3556,27 +3556,27 @@ static const JSFunctionSpec string_metho
+@@ -3546,27 +3546,27 @@ static const JSFunctionSpec string_metho
      JS_FN("includes",          str_includes,          1,0),
      JS_FN("indexOf",           str_indexOf,           1,0),
      JS_FN("lastIndexOf",       str_lastIndexOf,       1,0),
@@ -285,7 +285,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
      JS_SELF_HOSTED_FN("search", "String_search",      1,0),
      JS_SELF_HOSTED_FN("replace", "String_replace",    2,0),
      JS_SELF_HOSTED_FN("replaceAll", "String_replaceAll", 2, 0),
-@@ -3866,17 +3866,17 @@ static const JSFunctionSpec string_stati
+@@ -3852,17 +3852,17 @@ static const JSFunctionSpec string_stati
      JS_SELF_HOSTED_FN("lastIndexOf",     "String_static_lastIndexOf",   2,0),
      JS_SELF_HOSTED_FN("startsWith",      "String_static_startsWith",    2,0),
      JS_SELF_HOSTED_FN("endsWith",        "String_static_endsWith",      2,0),
@@ -463,7 +463,7 @@ diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js
 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
-@@ -259,17 +259,17 @@ GetBuildConfiguration(JSContext* cx, uns
+@@ -266,17 +266,17 @@ GetBuildConfiguration(JSContext* cx, uns
  #ifdef ENABLE_BINARYDATA
      value = BooleanValue(true);
  #else
@@ -526,7 +526,7 @@ diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js
 diff --git a/js/src/jsapi.h b/js/src/jsapi.h
 --- a/js/src/jsapi.h
 +++ b/js/src/jsapi.h
-@@ -4902,19 +4902,19 @@ JS_GetDefaultLocale(JSContext* cx);
+@@ -4903,19 +4903,19 @@ JS_GetDefaultLocale(JSContext* cx);
   */
  extern JS_PUBLIC_API(void)
  JS_ResetDefaultLocale(JSRuntime* rt);
@@ -612,7 +612,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
 diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
 --- a/js/src/jsnum.cpp
 +++ b/js/src/jsnum.cpp
-@@ -735,17 +735,17 @@ num_toString_impl(JSContext* cx, const C
+@@ -744,17 +744,17 @@ num_toString_impl(JSContext* cx, const C
  
  bool
  js::num_toString(JSContext* cx, unsigned argc, Value* vp)
@@ -631,7 +631,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      double d = Extract(args.thisv());
  
      RootedString str(cx, NumberToStringWithBase<CanGC>(cx, d, 10));
-@@ -868,17 +868,17 @@ num_toLocaleString_impl(JSContext* cx, c
+@@ -877,17 +877,17 @@ num_toLocaleString_impl(JSContext* cx, c
  }
  
  static bool
@@ -650,7 +650,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      args.rval().setNumber(Extract(args.thisv()));
      return true;
  }
-@@ -1087,17 +1087,17 @@ num_toPrecision(JSContext* cx, unsigned 
+@@ -1096,17 +1096,17 @@ num_toPrecision(JSContext* cx, unsigned 
  {
      CallArgs args = CallArgsFromVp(argc, vp);
      return CallNonGenericMethod<IsNumber, num_toPrecision_impl>(cx, args);
@@ -669,7 +669,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      JS_FN("toFixed",             num_toFixed,           1, 0),
      JS_FN("toExponential",       num_toExponential,     1, 0),
      JS_FN("toPrecision",         num_toPrecision,       1, 0),
-@@ -1118,20 +1118,20 @@ static const JSFunctionSpec number_stati
+@@ -1127,20 +1127,20 @@ static const JSFunctionSpec number_stati
      JS_SELF_HOSTED_FN("isSafeInteger", "Number_isSafeInteger", 1,0),
      JS_FS_END
  };
@@ -692,7 +692,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      struct lconv* locale = localeconv();
      thousandsSeparator = locale->thousands_sep;
      decimalPoint = locale->decimal_point;
-@@ -1167,21 +1167,21 @@ js::InitRuntimeNumberState(JSRuntime* rt
+@@ -1176,21 +1176,21 @@ js::InitRuntimeNumberState(JSRuntime* rt
      storage += thousandsSeparatorSize;
  
      js_memcpy(storage, decimalPoint, decimalPointSize);
@@ -865,13 +865,13 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
  
      js_delete(defaultFreeOp_.ref());
  
-     js_free(defaultLocale);
-@@ -546,17 +546,17 @@ JSRuntime::resetDefaultLocale()
+     defaultLocale = nullptr;
+@@ -549,17 +549,17 @@ JSRuntime::resetDefaultLocale()
  const char*
  JSRuntime::getDefaultLocale()
  {
-     if (defaultLocale)
-         return defaultLocale;
+     if (defaultLocale.ref())
+         return defaultLocale.ref().get();
  
      // Use ICU if available to retrieve the default locale, this ensures ICU's
      // default locale matches our default locale.
@@ -888,7 +888,7 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
 diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
 --- a/js/src/vm/Runtime.h
 +++ b/js/src/vm/Runtime.h
-@@ -647,17 +647,17 @@ struct JSRuntime : public js::MallocProv
+@@ -652,17 +652,17 @@ struct JSRuntime : public js::MallocProv
      js::WriteOnceData<js::FreeOp*> defaultFreeOp_;
  
    public:

+ 12 - 12
frg/work-js/mozilla-release/patches/1566141-7-72a1.patch

@@ -3,7 +3,7 @@
 # Date 1573577859 0
 #      Tue Nov 12 16:57:39 2019 +0000
 # Node ID ddc6fa7e24f2eb5e96e0e0215a943b06d4607b95
-# Parent  ee12ff8df27a5bcfaffc1e725991dde00eb8afba
+# Parent  248761481fd59a1f8e37663ddd1b4fb4ce3ee8be
 Bug 1566141 - implement nullish coalescence in ion monkey r=jandem
 
 Differential Revision: https://phabricator.services.mozilla.com/D51640
@@ -11,7 +11,7 @@ Differential Revision: https://phabricator.services.mozilla.com/D51640
 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
-@@ -12704,16 +12704,32 @@ CodeGenerator::visitIsObject(LIsObject* 
+@@ -12701,16 +12701,32 @@ CodeGenerator::visitIsObject(LIsObject* 
  
  void
  CodeGenerator::visitIsObjectAndBranch(LIsObjectAndBranch* ins)
@@ -47,7 +47,7 @@ diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
 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
-@@ -1796,16 +1796,17 @@ IonBuilder::inspectOpcode(JSOp op)
+@@ -1781,16 +1781,17 @@ IonBuilder::inspectOpcode(JSOp op)
          return Ok();
  
        case JSOP_IFNE:
@@ -65,7 +65,7 @@ diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
        case JSOP_CASE:
        case JSOP_DEFAULT:
          // Control flow opcodes should be handled in the ControlFlowGenerator.
-@@ -2952,25 +2953,35 @@ IonBuilder::jsop_dup2()
+@@ -2937,25 +2938,35 @@ IonBuilder::jsop_dup2()
      current->pushSlot(lhsSlot);
      current->pushSlot(rhsSlot);
      return Ok();
@@ -106,7 +106,7 @@ diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
 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
-@@ -312,19 +312,20 @@ ControlFlowGenerator::snoopControlFlow(J
+@@ -323,19 +323,20 @@ ControlFlowGenerator::snoopControlFlow(J
        case JSOP_IFNE:
          // We should never reach an IFNE, it's a stopAt point, which will
          // trigger closing the loop.
@@ -128,7 +128,7 @@ diff --git a/js/src/jit/IonControlFlow.cpp b/js/src/jit/IonControlFlow.cpp
          return processTry();
  
        case JSOP_THROWMSG:
-@@ -464,18 +465,18 @@ ControlFlowGenerator::processCfgEntry(CF
+@@ -475,18 +476,18 @@ ControlFlowGenerator::processCfgEntry(CF
          return processNextTableSwitchCase(state);
  
        case CFGState::COND_SWITCH_CASE:
@@ -149,7 +149,7 @@ diff --git a/js/src/jit/IonControlFlow.cpp b/js/src/jit/IonControlFlow.cpp
          return processTryEnd(state);
  
        default:
-@@ -1354,18 +1355,17 @@ ControlFlowGenerator::processCondSwitchB
+@@ -1370,18 +1371,17 @@ ControlFlowGenerator::processCondSwitchB
      if (currentIdx < bodies.length())
          state.stopAt = bodies[currentIdx]->startPc();
      else
@@ -169,7 +169,7 @@ diff --git a/js/src/jit/IonControlFlow.cpp b/js/src/jit/IonControlFlow.cpp
  
      // End the rhs.
      current->setStopIns(CFGGoto::New(alloc(), join));
-@@ -2043,21 +2043,20 @@ ControlFlowGenerator::CFGState::IfElse(j
+@@ -2022,21 +2022,20 @@ ControlFlowGenerator::CFGState::IfElse(j
                    : IF_ELSE_TRUE;
      state.stopAt = trueEnd;
      state.branch.falseEnd = falseEnd;
@@ -194,7 +194,7 @@ diff --git a/js/src/jit/IonControlFlow.cpp b/js/src/jit/IonControlFlow.cpp
  
  ControlFlowGenerator::CFGState
  ControlFlowGenerator::CFGState::TableSwitch(TempAllocator& alloc, jsbytecode* exitpc)
-@@ -2102,38 +2101,49 @@ ControlFlowGenerator::CFGState::Try(jsby
+@@ -2081,38 +2080,49 @@ ControlFlowGenerator::CFGState::Try(jsby
  {
      CFGState state;
      state.state = TRY;
@@ -374,12 +374,12 @@ diff --git a/js/src/jit/IonControlFlow.h b/js/src/jit/IonControlFlow.h
      };
  
      Vector<CFGState, 8, JitAllocPolicy> cfgStack_;
-@@ -877,18 +867,18 @@ class ControlFlowGenerator
+@@ -876,18 +866,18 @@ class ControlFlowGenerator
+     ControlStatus processThrow();
      ControlStatus processTableSwitch(JSOp op, jssrcnote* sn);
      ControlStatus processContinue(JSOp op);
      ControlStatus processBreak(JSOp op, jssrcnote* sn);
      ControlStatus processReturn(JSOp op);
-     ControlStatus maybeLoop(JSOp op, jssrcnote* sn);
      ControlStatus snoopControlFlow(JSOp op);
      ControlStatus processBrokenLoop(CFGState& state);
      ControlStatus finishLoop(CFGState& state, CFGBlock* successor);
@@ -498,7 +498,7 @@ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
 diff --git a/js/src/vm/BytecodeUtil-inl.h b/js/src/vm/BytecodeUtil-inl.h
 --- a/js/src/vm/BytecodeUtil-inl.h
 +++ b/js/src/vm/BytecodeUtil-inl.h
-@@ -18,16 +18,17 @@ GetDefCount(jsbytecode* pc)
+@@ -19,16 +19,17 @@ GetDefCount(jsbytecode* pc)
  {
      /*
       * Add an extra pushed value for OR/AND opcodes, so that they are included

+ 4 - 4
frg/work-js/mozilla-release/patches/1586358-71a1.patch

@@ -2,7 +2,7 @@
 # User Ricky Stewart <rstewart@mozilla.com>
 # Date 1570482919 0
 # Node ID fb7912816d3e5a8f8f5ec90d6e0f79565b669924
-# Parent  a45f6253e7d3d21fa86722370da111eebce479a6
+# Parent  815d73b0c1b64da5c3238e072b616806c026b789
 Bug 1586358 - Replace existing instances of GENERATED_FILES with references to the GeneratedFile template r=firefox-build-system-reviewers,mshal
 
 (Same content as bad revision https://phabricator.services.mozilla.com/D48230, but with a very small change to config/external/icu/data/moz.build to fix the build breakage.)
@@ -522,10 +522,10 @@ diff --git a/js/src/frontend/moz.build b/js/src/frontend/moz.build
  
  UNIFIED_SOURCES += [
      'BytecodeCompiler.cpp',
+     'BytecodeControlStructures.cpp',
      'BytecodeEmitter.cpp',
-     'FoldConstants.cpp',
-     'NameFunctions.cpp',
-     'ParseNode.cpp',
+     'CForEmitter.cpp',
+     'DoWhileEmitter.cpp',
 diff --git a/js/src/gc/moz.build b/js/src/gc/moz.build
 --- a/js/src/gc/moz.build
 +++ b/js/src/gc/moz.build

+ 25 - 25
frg/work-js/mozilla-release/patches/1590907-5-72a1.patch

@@ -2,7 +2,7 @@
 # User Philip Chimento <philip.chimento@gmail.com>
 # Date 1574753135 0
 # Node ID bfdd5f34f2f4a11b84742400bb3130192c89d4fb
-# Parent  04d286e61ecd393ce7bf5b0985e19b45f9fb3b30
+# Parent  f2ce73e28a6c9701727cc7dd5e05c59e354d5080
 Bug 1590907 - Make ENABLE_INTL_API and ENABLE_TYPED_OBJECTS into js-config macros. r=sfink,firefox-build-system-reviewers,mshal
 
 Whether ENABLE_INTL_API and ENABLE_TYPED_OBJECTS are defined, affects
@@ -229,7 +229,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  #include "vm/BytecodeUtil.h"
  #include "vm/GlobalObject.h"
  #include "vm/Interpreter.h"
-@@ -738,17 +738,17 @@ js::SubstringKernel(JSContext* cx, Handl
+@@ -728,17 +728,17 @@ js::SubstringKernel(JSContext* cx, Handl
  static char16_t
  Final_Sigma(const char16_t* chars, size_t length, size_t index)
  {
@@ -248,7 +248,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
      for (size_t i = index; i > 0; ) {
          char16_t c = chars[--i];
          uint32_t codePoint = c;
-@@ -1076,17 +1076,17 @@ js::intl_toLocaleLowerCase(JSContext* cx
+@@ -1066,17 +1066,17 @@ js::intl_toLocaleLowerCase(JSContext* cx
      JSString* result = NewStringCopyN<CanGC>(cx, chars.begin(), size);
      if (!result)
          return false;
@@ -267,7 +267,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  
  bool
  js::str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp)
-@@ -1117,17 +1117,17 @@ js::str_toLocaleLowerCase(JSContext* cx,
+@@ -1107,17 +1107,17 @@ js::str_toLocaleLowerCase(JSContext* cx,
      JSString* result = StringToLowerCase(cx, linear);
      if (!result)
          return false;
@@ -286,7 +286,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
      // special casing rules, so detect it inline.
      bool hasUpperCaseSpecialCasing = charCode == unicode::LATIN_SMALL_LETTER_SHARP_S;
      MOZ_ASSERT(hasUpperCaseSpecialCasing == unicode::ChangesWhenUpperCasedSpecialCasing(charCode));
-@@ -1474,17 +1474,17 @@ js::intl_toLocaleUpperCase(JSContext* cx
+@@ -1464,17 +1464,17 @@ js::intl_toLocaleUpperCase(JSContext* cx
      JSString* result = NewStringCopyN<CanGC>(cx, chars.begin(), size);
      if (!result)
          return false;
@@ -305,7 +305,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  
  bool
  js::str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
-@@ -1515,19 +1515,19 @@ js::str_toLocaleUpperCase(JSContext* cx,
+@@ -1505,19 +1505,19 @@ js::str_toLocaleUpperCase(JSContext* cx,
      JSString* result = StringToUpperCase(cx, linear);
      if (!result)
          return false;
@@ -328,7 +328,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  bool
  js::str_localeCompare(JSContext* cx, unsigned argc, Value* vp)
  {
-@@ -1552,19 +1552,19 @@ js::str_localeCompare(JSContext* cx, uns
+@@ -1542,19 +1542,19 @@ js::str_localeCompare(JSContext* cx, uns
      int32_t result;
      if (!CompareStrings(cx, str, thatStr, &result))
          return false;
@@ -351,7 +351,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  {
      CallArgs args = CallArgsFromVp(argc, vp);
  
-@@ -1679,17 +1679,17 @@ js::str_normalize(JSContext* cx, unsigne
+@@ -1669,17 +1669,17 @@ js::str_normalize(JSContext* cx, unsigne
      if (!ns)
          return false;
  
@@ -370,7 +370,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
  
      RootedString str(cx);
      size_t i;
-@@ -3556,27 +3556,27 @@ static const JSFunctionSpec string_metho
+@@ -3546,27 +3546,27 @@ static const JSFunctionSpec string_metho
      JS_FN("includes",          str_includes,          1,0),
      JS_FN("indexOf",           str_indexOf,           1,0),
      JS_FN("lastIndexOf",       str_lastIndexOf,       1,0),
@@ -400,7 +400,7 @@ diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp
      JS_SELF_HOSTED_FN("search", "String_search",      1,0),
      JS_SELF_HOSTED_FN("replace", "String_replace",    2,0),
      JS_SELF_HOSTED_FN("replaceAll", "String_replaceAll", 2, 0),
-@@ -3866,17 +3866,17 @@ static const JSFunctionSpec string_stati
+@@ -3852,17 +3852,17 @@ static const JSFunctionSpec string_stati
      JS_SELF_HOSTED_FN("lastIndexOf",     "String_static_lastIndexOf",   2,0),
      JS_SELF_HOSTED_FN("startsWith",      "String_static_startsWith",    2,0),
      JS_SELF_HOSTED_FN("endsWith",        "String_static_endsWith",      2,0),
@@ -578,7 +578,7 @@ diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js
 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
-@@ -259,17 +259,17 @@ GetBuildConfiguration(JSContext* cx, uns
+@@ -266,17 +266,17 @@ GetBuildConfiguration(JSContext* cx, uns
  #ifdef ENABLE_BINARYDATA
      value = BooleanValue(true);
  #else
@@ -799,7 +799,7 @@ new file mode 100644
 diff --git a/js/src/jsapi.h b/js/src/jsapi.h
 --- a/js/src/jsapi.h
 +++ b/js/src/jsapi.h
-@@ -4902,19 +4902,19 @@ JS_GetDefaultLocale(JSContext* cx);
+@@ -4903,19 +4903,19 @@ JS_GetDefaultLocale(JSContext* cx);
   */
  extern JS_PUBLIC_API(void)
  JS_ResetDefaultLocale(JSRuntime* rt);
@@ -961,7 +961,7 @@ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
 diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
 --- a/js/src/jsnum.cpp
 +++ b/js/src/jsnum.cpp
-@@ -735,17 +735,17 @@ num_toString_impl(JSContext* cx, const C
+@@ -744,17 +744,17 @@ num_toString_impl(JSContext* cx, const C
  
  bool
  js::num_toString(JSContext* cx, unsigned argc, Value* vp)
@@ -980,7 +980,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      double d = Extract(args.thisv());
  
      RootedString str(cx, NumberToStringWithBase<CanGC>(cx, d, 10));
-@@ -868,17 +868,17 @@ num_toLocaleString_impl(JSContext* cx, c
+@@ -877,17 +877,17 @@ num_toLocaleString_impl(JSContext* cx, c
  }
  
  static bool
@@ -999,7 +999,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      args.rval().setNumber(Extract(args.thisv()));
      return true;
  }
-@@ -1087,17 +1087,17 @@ num_toPrecision(JSContext* cx, unsigned 
+@@ -1096,17 +1096,17 @@ num_toPrecision(JSContext* cx, unsigned 
  {
      CallArgs args = CallArgsFromVp(argc, vp);
      return CallNonGenericMethod<IsNumber, num_toPrecision_impl>(cx, args);
@@ -1018,7 +1018,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      JS_FN("toFixed",             num_toFixed,           1, 0),
      JS_FN("toExponential",       num_toExponential,     1, 0),
      JS_FN("toPrecision",         num_toPrecision,       1, 0),
-@@ -1118,20 +1118,20 @@ static const JSFunctionSpec number_stati
+@@ -1127,20 +1127,20 @@ static const JSFunctionSpec number_stati
      JS_SELF_HOSTED_FN("isSafeInteger", "Number_isSafeInteger", 1,0),
      JS_FS_END
  };
@@ -1041,7 +1041,7 @@ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
      struct lconv* locale = localeconv();
      thousandsSeparator = locale->thousands_sep;
      decimalPoint = locale->decimal_point;
-@@ -1167,21 +1167,21 @@ js::InitRuntimeNumberState(JSRuntime* rt
+@@ -1176,21 +1176,21 @@ js::InitRuntimeNumberState(JSRuntime* rt
      storage += thousandsSeparatorSize;
  
      js_memcpy(storage, decimalPoint, decimalPointSize);
@@ -1090,7 +1090,7 @@ diff --git a/js/src/jsnum.h b/js/src/jsnum.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
-@@ -1092,17 +1092,17 @@ BindToAsyncStack(JSContext* cx, unsigned
+@@ -1094,17 +1094,17 @@ BindToAsyncStack(JSContext* cx, unsigned
          return false;
      SetFunctionNativeReserved(bound, 0, args[0]);
      SetFunctionNativeReserved(bound, 1, args[1]);
@@ -1109,7 +1109,7 @@ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
          JS_ReportErrorASCII(cx, "addIntlExtras must be passed an object");
          return false;
      }
-@@ -1119,17 +1119,17 @@ AddIntlExtras(JSContext* cx, unsigned ar
+@@ -1121,17 +1121,17 @@ AddIntlExtras(JSContext* cx, unsigned ar
          return false;
  
      if (!js::AddMozDateTimeFormatConstructor(cx, intl))
@@ -1128,7 +1128,7 @@ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
      // Eval.
      JS::CompileOptions options(cx);
      options.setIntroductionType("js shell interactive")
-@@ -7079,25 +7079,25 @@ static const JSFunctionSpecWithHelp shel
+@@ -7126,25 +7126,25 @@ static const JSFunctionSpecWithHelp shel
  "  cause:    A string, supplied as the async cause on the top frame of\n"
  "            captured async stacks.\n"
  "\n"
@@ -1655,13 +1655,13 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
  
      js_delete(defaultFreeOp_.ref());
  
-     js_free(defaultLocale);
-@@ -546,17 +546,17 @@ JSRuntime::resetDefaultLocale()
+     defaultLocale = nullptr;
+@@ -549,17 +549,17 @@ JSRuntime::resetDefaultLocale()
  const char*
  JSRuntime::getDefaultLocale()
  {
-     if (defaultLocale)
-         return defaultLocale;
+     if (defaultLocale.ref())
+         return defaultLocale.ref().get();
  
      // Use ICU if available to retrieve the default locale, this ensures ICU's
      // default locale matches our default locale.
@@ -1678,7 +1678,7 @@ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
 diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
 --- a/js/src/vm/Runtime.h
 +++ b/js/src/vm/Runtime.h
-@@ -647,17 +647,17 @@ struct JSRuntime : public js::MallocProv
+@@ -652,17 +652,17 @@ struct JSRuntime : public js::MallocProv
      js::WriteOnceData<js::FreeOp*> defaultFreeOp_;
  
    public:

+ 277 - 0
frg/work-js/mozilla-release/patches/1600664-73a1.patch

@@ -0,0 +1,277 @@
+# HG changeset patch
+# User Ricky Stewart <rstewart@mozilla.com>
+# Date 1575405515 0
+# Node ID d2f8a8875708e694346e9ec7b5d5d0761e3662ca
+# Parent  734a362bcfe442e4c11be040f160b88f0f934df4
+Bug 1600664 - Download the wasi sysroot during bootstrap for Linux r=firefox-build-system-reviewers,chmanchester
+
+Differential Revision: https://phabricator.services.mozilla.com/D55481
+
+diff --git a/python/mozboot/mozboot/archlinux.py b/python/mozboot/mozboot/archlinux.py
+--- a/python/mozboot/mozboot/archlinux.py
++++ b/python/mozboot/mozboot/archlinux.py
+@@ -12,28 +12,29 @@ import glob
+ 
+ from mozboot.base import BaseBootstrapper
+ from mozboot.linux_common import (
+     ClangStaticAnalysisInstall,
+     LucetcInstall,
+     NodeInstall,
+     SccacheInstall,
+     StyloInstall,
++    WasiSysrootInstall,
+ )
+ 
+ # NOTE: This script is intended to be run with a vanilla Python install.  We
+ # have to rely on the standard library instead of Python 2+3 helpers like
+ # the six module.
+ if sys.version_info < (3,):
+     input = raw_input  # noqa
+ 
+ 
+ class ArchlinuxBootstrapper(
+         NodeInstall, StyloInstall, SccacheInstall, ClangStaticAnalysisInstall,
+-        LucetcInstall, BaseBootstrapper):
++        LucetcInstall, WasiSysrootInstall, BaseBootstrapper):
+     '''Archlinux experimental bootstrapper.'''
+ 
+     SYSTEM_PACKAGES = [
+         'autoconf2.13',
+         'base-devel',
+         'nodejs',
+         'python2',
+         'python2-setuptools',
+diff --git a/python/mozboot/mozboot/base.py b/python/mozboot/mozboot/base.py
+--- a/python/mozboot/mozboot/base.py
++++ b/python/mozboot/mozboot/base.py
+@@ -296,16 +296,22 @@ class BaseBootstrapper(object):
+         pass
+ 
+     def ensure_lucetc_packages(self, state_dir, checkout_root):
+         '''
+         Install lucetc.
+         '''
+         pass
+ 
++    def ensure_wasi_sysroot_packages(self, state_dir, checkout_root):
++        '''
++        Install the wasi sysroot.
++        '''
++        pass
++
+     def ensure_node_packages(self, state_dir, checkout_root):
+         '''
+         Install any necessary packages needed to supply NodeJS'''
+         raise NotImplementedError(
+             '%s does not yet implement ensure_node_packages()'
+             % __name__)
+ 
+     def install_toolchain_static_analysis(self, state_dir, checkout_root, toolchain_job):
+diff --git a/python/mozboot/mozboot/bootstrap.py b/python/mozboot/mozboot/bootstrap.py
+--- a/python/mozboot/mozboot/bootstrap.py
++++ b/python/mozboot/mozboot/bootstrap.py
+@@ -349,16 +349,17 @@ class Bootstrapper(object):
+ 
+         self.instance.state_dir = state_dir
+         self.instance.ensure_node_packages(state_dir, checkout_root)
+         self.instance.ensure_stylo_packages(state_dir, checkout_root)
+         self.instance.ensure_clang_static_analysis_package(state_dir, checkout_root)
+         self.instance.ensure_nasm_packages(state_dir, checkout_root)
+         self.instance.ensure_sccache_packages(state_dir, checkout_root)
+         self.instance.ensure_lucetc_packages(state_dir, checkout_root)
++        self.instance.ensure_wasi_sysroot_packages(state_dir, checkout_root)
+ 
+     def bootstrap(self):
+         if self.choice is None:
+             # Like ['1. Firefox for Desktop', '2. Firefox for Android Artifact Mode', ...].
+             labels = ['%s. %s' % (i + 1, name) for (i, (name, _)) in enumerate(APPLICATIONS_LIST)]
+             prompt = APPLICATION_CHOICE % '\n'.join('  {}'.format(label) for label in labels)
+             prompt_choice = self.instance.prompt_int(prompt=prompt, low=1, high=len(APPLICATIONS))
+             name, application = APPLICATIONS_LIST[prompt_choice-1]
+diff --git a/python/mozboot/mozboot/centosfedora.py b/python/mozboot/mozboot/centosfedora.py
+--- a/python/mozboot/mozboot/centosfedora.py
++++ b/python/mozboot/mozboot/centosfedora.py
+@@ -9,22 +9,24 @@ import platform
+ from mozboot.base import BaseBootstrapper
+ from mozboot.linux_common import (
+     ClangStaticAnalysisInstall,
+     LucetcInstall,
+     NasmInstall,
+     NodeInstall,
+     SccacheInstall,
+     StyloInstall,
++    WasiSysrootInstall,
+ )
+ 
+ 
+-class CentOSFedoraBootstrapper(NasmInstall, NodeInstall, StyloInstall,
+-                               SccacheInstall, ClangStaticAnalysisInstall,
+-                               LucetcInstall, BaseBootstrapper):
++class CentOSFedoraBootstrapper(
++        NasmInstall, NodeInstall, StyloInstall, SccacheInstall,
++        ClangStaticAnalysisInstall, LucetcInstall, WasiSysrootInstall,
++        BaseBootstrapper):
+     def __init__(self, distro, version, dist_id, **kwargs):
+         BaseBootstrapper.__init__(self, **kwargs)
+ 
+         self.distro = distro
+         self.version = int(version.split('.')[0])
+         self.dist_id = dist_id
+ 
+         self.group_packages = []
+diff --git a/python/mozboot/mozboot/debian.py b/python/mozboot/mozboot/debian.py
+--- a/python/mozboot/mozboot/debian.py
++++ b/python/mozboot/mozboot/debian.py
+@@ -7,16 +7,17 @@ from __future__ import absolute_import, 
+ from mozboot.base import BaseBootstrapper
+ from mozboot.linux_common import (
+     ClangStaticAnalysisInstall,
+     LucetcInstall,
+     NasmInstall,
+     NodeInstall,
+     SccacheInstall,
+     StyloInstall,
++    WasiSysrootInstall,
+ )
+ 
+ 
+ MERCURIAL_INSTALL_PROMPT = '''
+ Mercurial releases a new version every 3 months and your distro's package
+ may become out of date. This may cause incompatibility with some
+ Mercurial extensions that rely on new Mercurial features. As a result,
+ you may not have an optimal version control experience.
+@@ -27,18 +28,19 @@ in files being placed in /usr/local/bin 
+ 
+ How would you like to continue?
+   1. Install a modern Mercurial via pip (recommended)
+   2. Install a legacy Mercurial via apt
+   3. Do not install Mercurial
+ Your choice: '''
+ 
+ 
+-class DebianBootstrapper(NasmInstall, NodeInstall, StyloInstall, ClangStaticAnalysisInstall,
+-                         SccacheInstall, LucetcInstall, BaseBootstrapper):
++class DebianBootstrapper(
++        NasmInstall, NodeInstall, StyloInstall, ClangStaticAnalysisInstall,
++        SccacheInstall, LucetcInstall, WasiSysrootInstall, BaseBootstrapper):
+     # These are common packages for all Debian-derived distros (such as
+     # Ubuntu).
+     COMMON_PACKAGES = [
+         'autoconf2.13',
+         'build-essential',
+         'nodejs',
+         'python-dev',
+         'python-pip',
+diff --git a/python/mozboot/mozboot/gentoo.py b/python/mozboot/mozboot/gentoo.py
+--- a/python/mozboot/mozboot/gentoo.py
++++ b/python/mozboot/mozboot/gentoo.py
+@@ -7,30 +7,31 @@ from __future__ import absolute_import, 
+ from mozboot.base import BaseBootstrapper
+ from mozboot.linux_common import (
+     ClangStaticAnalysisInstall,
+     LucetcInstall,
+     NasmInstall,
+     NodeInstall,
+     SccacheInstall,
+     StyloInstall,
++    WasiSysrootInstall,
+ )
+ 
+ try:
+     from urllib2 import urlopen
+ except ImportError:
+     from urllib.request import urlopen
+ 
+ import re
+ import subprocess
+ 
+ 
+ class GentooBootstrapper(
+         NasmInstall, NodeInstall, StyloInstall, ClangStaticAnalysisInstall,
+-        SccacheInstall, LucetcInstall, BaseBootstrapper):
++        SccacheInstall, LucetcInstall, WasiSysrootInstall, BaseBootstrapper):
+ 
+     def __init__(self, version, dist_id, **kwargs):
+         BaseBootstrapper.__init__(self, **kwargs)
+ 
+         self.version = version
+         self.dist_id = dist_id
+ 
+     def install_system_packages(self):
+diff --git a/python/mozboot/mozboot/linux_common.py b/python/mozboot/mozboot/linux_common.py
+--- a/python/mozboot/mozboot/linux_common.py
++++ b/python/mozboot/mozboot/linux_common.py
+@@ -31,16 +31,27 @@ class LucetcInstall(object):
+ 
+     def ensure_lucetc_packages(self, state_dir, checkout_root):
+         from mozboot import lucetc
+ 
+         self.install_toolchain_artifact(state_dir, checkout_root,
+                                         lucetc.LINUX_LUCETC)
+ 
+ 
++class WasiSysrootInstall(object):
++    def __init__(self, **kwargs):
++        pass
++
++    def ensure_wasi_sysroot_packages(self, state_dir, checkout_root):
++        from mozboot import wasi_sysroot
++
++        self.install_toolchain_artifact(state_dir, checkout_root,
++                                        wasi_sysroot.LINUX_WASI_SYSROOT)
++
++
+ class StyloInstall(object):
+     def __init__(self, **kwargs):
+         pass
+ 
+     def ensure_stylo_packages(self, state_dir, checkout_root):
+         from mozboot import stylo
+ 
+         if is_non_x86_64():
+diff --git a/python/mozboot/mozboot/solus.py b/python/mozboot/mozboot/solus.py
+--- a/python/mozboot/mozboot/solus.py
++++ b/python/mozboot/mozboot/solus.py
+@@ -9,28 +9,29 @@ import subprocess
+ 
+ from mozboot.base import BaseBootstrapper
+ from mozboot.linux_common import (
+     ClangStaticAnalysisInstall,
+     LucetcInstall,
+     NodeInstall,
+     SccacheInstall,
+     StyloInstall,
++    WasiSysrootInstall,
+ )
+ 
+ # NOTE: This script is intended to be run with a vanilla Python install.  We
+ # have to rely on the standard library instead of Python 2+3 helpers like
+ # the six module.
+ if sys.version_info < (3,):
+     input = raw_input  # noqa
+ 
+ 
+ class SolusBootstrapper(
+         NodeInstall, StyloInstall, SccacheInstall, ClangStaticAnalysisInstall,
+-        LucetcInstall, BaseBootstrapper):
++        LucetcInstall, WasiSysrootInstall, BaseBootstrapper):
+     '''Solus experimental bootstrapper.'''
+ 
+     SYSTEM_PACKAGES = [
+         'autoconf213',
+         'nodejs',
+         'python',
+         'python3',
+         'unzip',
+diff --git a/python/mozboot/mozboot/wasi_sysroot.py b/python/mozboot/mozboot/wasi_sysroot.py
+new file mode 100644
+--- /dev/null
++++ b/python/mozboot/mozboot/wasi_sysroot.py
+@@ -0,0 +1,7 @@
++# This Source Code Form is subject to the terms of the Mozilla Public
++# License, v. 2.0. If a copy of the MPL was not distributed with this
++# file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++from __future__ import absolute_import, print_function, unicode_literals
++
++LINUX_WASI_SYSROOT = 'wasi-sysroot'

+ 3 - 3
frg/work-js/mozilla-release/patches/1614518-1-75a1.patch

@@ -2,7 +2,7 @@
 # User Steve Fink <sfink@mozilla.com>
 # Date 1581441405 0
 # Node ID e5f9b1159797eb830acdb6f78be62b69ead5cb01
-# Parent  e0d333acf9dcb7ea5bca9b31c30c77a9e9e89654
+# Parent  74c227f2b061ef8df73efa121a42c2c0fe741d20
 Bug 1614518 - Remove code only present for python 2.6 compatibility. r=ahal
 
 Differential Revision: https://phabricator.services.mozilla.com/D62378
@@ -62,11 +62,11 @@ diff --git a/python/mozboot/mozboot/bootstrap.py b/python/mozboot/mozboot/bootst
  
    {statedir}
  
-@@ -338,25 +330,25 @@ class Bootstrapper(object):
-         self.instance.ensure_clang_static_analysis_package(state_dir, checkout_root)
+@@ -339,25 +331,25 @@ class Bootstrapper(object):
          self.instance.ensure_nasm_packages(state_dir, checkout_root)
          self.instance.ensure_sccache_packages(state_dir, checkout_root)
          self.instance.ensure_lucetc_packages(state_dir, checkout_root)
+         self.instance.ensure_wasi_sysroot_packages(state_dir, checkout_root)
  
      def bootstrap(self):
          if self.choice is None:

+ 3 - 3
frg/work-js/mozilla-release/patches/1614518-2-75a1.patch

@@ -2,7 +2,7 @@
 # User Steve Fink <sfink@mozilla.com>
 # Date 1582223590 0
 # Node ID 788e4b59e885b237c83bae1c9a1da6c74e827b41
-# Parent  cfcb7c3237e5a255aa813c37265f553f00141c06
+# Parent  e54e571d7b4e2b4fd717fc8ef947efc456507f72
 Bug 1614518 - Allow using internal name for selecting application to bootstrap. r=nalexander
 
 Differential Revision: https://phabricator.services.mozilla.com/D62379
@@ -10,11 +10,11 @@ Differential Revision: https://phabricator.services.mozilla.com/D62379
 diff --git a/python/mozboot/mozboot/bootstrap.py b/python/mozboot/mozboot/bootstrap.py
 --- a/python/mozboot/mozboot/bootstrap.py
 +++ b/python/mozboot/mozboot/bootstrap.py
-@@ -330,25 +330,27 @@ class Bootstrapper(object):
-         self.instance.ensure_clang_static_analysis_package(state_dir, checkout_root)
+@@ -331,25 +331,27 @@ class Bootstrapper(object):
          self.instance.ensure_nasm_packages(state_dir, checkout_root)
          self.instance.ensure_sccache_packages(state_dir, checkout_root)
          self.instance.ensure_lucetc_packages(state_dir, checkout_root)
+         self.instance.ensure_wasi_sysroot_packages(state_dir, checkout_root)
  
      def bootstrap(self):
          if self.choice is None:

+ 3 - 3
frg/work-js/mozilla-release/patches/1617095-75a1.patch

@@ -2,7 +2,7 @@
 # User Emilio Cobos Alvarez <emilio@crisal.io>
 # Date 1582294784 0
 # Node ID 05f206719d98841d8b637c66dbdddbe2eadb791e
-# Parent  5931bf1f0e6f702c86e8ba88dddc7188d10aae57
+# Parent  aff29da38bb25aa199c13ee4d98eea027578d4e3
 Bug 1617095 - Fix mach bootstrap interactive mode with python 3. r=froydnj
 
 Differential Revision: https://phabricator.services.mozilla.com/D63661
@@ -10,8 +10,8 @@ Differential Revision: https://phabricator.services.mozilla.com/D63661
 diff --git a/python/mozboot/mozboot/bootstrap.py b/python/mozboot/mozboot/bootstrap.py
 --- a/python/mozboot/mozboot/bootstrap.py
 +++ b/python/mozboot/mozboot/bootstrap.py
-@@ -333,17 +333,17 @@ class Bootstrapper(object):
-         self.instance.ensure_lucetc_packages(state_dir, checkout_root)
+@@ -334,17 +334,17 @@ class Bootstrapper(object):
+         self.instance.ensure_wasi_sysroot_packages(state_dir, checkout_root)
  
      def bootstrap(self):
          if self.choice is None:

+ 3 - 3
frg/work-js/mozilla-release/patches/1618620-6-75a1.patch

@@ -2,7 +2,7 @@
 # User Mike Shal <mshal@mozilla.com>
 # Date 1582849714 0
 # Node ID 0a6c791234214b03930c234970b23f55884c17dc
-# Parent  21d9f712ed46f78d411ee433b276bedc18c5d277
+# Parent  3659e4dc17d49f9a9ce8f71156e2f4623576eb2f
 Bug 1618620 - Convert GenerateReservedWords.py to py3; r=firefox-build-system-reviewers,rstewart
 
 Differential Revision: https://phabricator.services.mozilla.com/D64624
@@ -10,8 +10,8 @@ Differential Revision: https://phabricator.services.mozilla.com/D64624
 diff --git a/js/src/frontend/GenerateReservedWords.py b/js/src/frontend/GenerateReservedWords.py
 --- a/js/src/frontend/GenerateReservedWords.py
 +++ b/js/src/frontend/GenerateReservedWords.py
-@@ -118,17 +118,17 @@ def generate_letter_switch(opt, unproces
-     assert(unprocessed_columns != 0);
+@@ -126,17 +126,17 @@ def generate_letter_switch(opt, unproces
+     assert(unprocessed_columns != 0)
  
      optimal_column_index, use_if = optimal_switch_column(opt, reserved_word_list,
                                                           columns,

+ 2 - 2
frg/work-js/mozilla-release/patches/1621960-5-79a1.patch

@@ -2,7 +2,7 @@
 # User Mitchell Hentges <mhentges@mozilla.com>
 # Date 1591805408 0
 # Node ID 3b1827c74e34f1f0dfbf9ad174e2c8b84965c44d
-# Parent  bf9208be9350e8b4db63aea12b8aeb376480d1a3
+# Parent  90ef28b455884d06942f00bcdf7bd9b93e657bd2
 Bug 1621960: Change |mach python| default from Python 2 to Python 3 r=rstewart
 
 Depends on D77967
@@ -51,7 +51,7 @@ diff --git a/python/mach_commands.py b/python/mach_commands.py
 -            append_env[b'PYTHONPATH'] = os.pathsep.join(sys.path)
 +            append_env['PYTHONPATH'] = os.pathsep.join(sys.path)
          else:
-             self._activate_virtualenv()
+             self.activate_virtualenv()
              python_path = self.virtualenv_manager.python_path
  
          if exec_file:

+ 336 - 0
frg/work-js/mozilla-release/patches/1623024-1-79a1.patch

@@ -0,0 +1,336 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1592510690 0
+# Node ID ba8087e38e6c4c4dabe2db96aded343fb1a86fcf
+# Parent  3d655e90cabd2a1f135df997a8cd69e9a6258fa8
+Bug 1623024 - mozlint: Add pylint as new linter r=linter-reviewers,ahal
+
+Differential Revision: https://phabricator.services.mozilla.com/D79076
+
+diff --git a/docs/code-quality/index.rst b/docs/code-quality/index.rst
+new file mode 100644
+--- /dev/null
++++ b/docs/code-quality/index.rst
+@@ -0,0 +1,6 @@
++   * - pylint
++     -
++     - `bug 1623024 <https://bugzilla.mozilla.org/show_bug.cgi?id=1623024>`_
++     - :ref:`pylint`
++     - https://www.pylint.org/
++     * - Python 2/3 compatibility check
+diff --git a/docs/code-quality/lint/linters/pylint.rst b/docs/code-quality/lint/linters/pylint.rst
+new file mode 100644
+--- /dev/null
++++ b/docs/code-quality/lint/linters/pylint.rst
+@@ -0,0 +1,31 @@
++pylint
++======
++
++`pylint <https://www.pylint.org/>`__ is a popular linter for python developed by Logilab. It is now the default python
++linter in VS Code.
++
++Please note that we also have :ref:`Flake8` available as a linter.
++
++Run Locally
++-----------
++
++The mozlint integration of pylint can be run using mach:
++
++.. parsed-literal::
++
++    $ mach lint --linter pylint <file paths>
++
++
++
++Configuration
++-------------
++
++To enable pylint on new directory, add the path to the include
++section in the `pylint.yml <https://searchfox.org/mozilla-central/source/tools/lint/pylint.yml>`_ file.
++
++
++Sources
++-------
++
++* `Configuration (YAML) <https://searchfox.org/mozilla-central/source/tools/lint/pylint.yml>`_
++* `Source <https://searchfox.org/mozilla-central/source/tools/lint/python/pylint.py>`_
+diff --git a/tools/lint/pylint.yml b/tools/lint/pylint.yml
+new file mode 100644
+--- /dev/null
++++ b/tools/lint/pylint.yml
+@@ -0,0 +1,24 @@
++---
++pylint:
++    description: A second Python linter
++    include:
++        - configure.py
++        - client.py
++        - security/
++        - accessible/
++        - docs/
++        - dom/base/
++        - mozglue/
++    exclude:
++        - dom/bindings/Codegen.py
++        - dom/bindings/Configuration.py
++        - security/manager/tools/crtshToIdentifyingStruct/crtshToIdentifyingStruct.py
++        - security/manager/ssl/tests/unit/test_content_signing/pysign.py
++        - security/ct/tests/gtest/createSTHTestData.py
++    extensions: ['py']
++    support-files:
++        - '**/.pylint'
++        - 'tools/lint/python/pylint*'
++    type: external
++    payload: python.pylint:lint
++    setup: python.pylint:setup
+diff --git a/tools/lint/python/pylint.py b/tools/lint/python/pylint.py
+new file mode 100644
+--- /dev/null
++++ b/tools/lint/python/pylint.py
+@@ -0,0 +1,117 @@
++# 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/.
++
++import json
++import os
++
++import signal
++import re
++
++from mozprocess import ProcessHandler
++
++from mozlint import result
++from mozlint.pathutils import expand_exclusions
++from mozlint.util import pip
++
++here = os.path.abspath(os.path.dirname(__file__))
++PYLINT_REQUIREMENTS_PATH = os.path.join(here, 'pylint_requirements.txt')
++
++PYLINT_NOT_FOUND = """
++Could not find pylint! Install pylint and try again.
++
++    $ pip install -U --require-hashes -r {}
++""".strip().format(PYLINT_REQUIREMENTS_PATH)
++
++
++PYLINT_INSTALL_ERROR = """
++Unable to install correct version of pylint
++Try to install it manually with:
++    $ pip install -U --require-hashes -r {}
++""".strip().format(PYLINT_REQUIREMENTS_PATH)
++
++
++class PylintProcess(ProcessHandler):
++    def __init__(self, config, *args, **kwargs):
++        self.config = config
++        kwargs["stream"] = False
++        kwargs["universal_newlines"] = True
++        ProcessHandler.__init__(self, *args, **kwargs)
++
++    def run(self, *args, **kwargs):
++        orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
++        ProcessHandler.run(self, *args, **kwargs)
++        signal.signal(signal.SIGINT, orig)
++
++
++def setup(root, **lintargs):
++    if not pip.reinstall_program(PYLINT_REQUIREMENTS_PATH):
++        print(PYLINT_INSTALL_ERROR)
++        return 1
++
++
++def get_pylint_binary():
++    return "pylint"
++
++
++def run_process(config, cmd):
++    proc = PylintProcess(config, cmd)
++    proc.run()
++    try:
++        proc.wait()
++    except KeyboardInterrupt:
++        proc.kill()
++
++    return proc.output
++
++
++PYLINT_FORMAT_REGEX = re.compile(r'(.*):(.*): [(.*)] (.*)$')
++
++
++def parse_issues(log, config, issues_json, path):
++    results = []
++
++    try:
++        issues = json.loads(issues_json)
++    except json.decoder.JSONDecodeError:
++        log.debug("Could not parse the output:")
++        log.debug("pylint output: {}".format(issues_json))
++        return []
++
++    for issue in issues:
++        res = {
++            "path": issue["path"],
++            "level": issue["type"],
++            "lineno": issue["line"],
++            "column": issue["column"],
++            "message": issue["message"],
++            "rule": issue["message-id"],
++        }
++        results.append(result.from_config(config, **res))
++    return results
++
++
++def lint(paths, config, **lintargs):
++    log = lintargs['log']
++
++    binary = get_pylint_binary()
++
++    log = lintargs['log']
++    paths = list(expand_exclusions(paths, config, lintargs['root']))
++
++    cmd_args = [binary]
++    results = []
++
++    # list from https://code.visualstudio.com/docs/python/linting#_pylint
++    # And ignore a bit more elements
++    cmd_args += ["-fjson",
++                 "--disable=all",
++                 "--enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode",  # NOQA: E501
++                 "--disable=import-error,no-member"]
++
++    base_command = cmd_args + paths
++    log.debug("Command: {}".format(' '.join(cmd_args)))
++    output = " ".join(run_process(config, base_command))
++    results = parse_issues(log, config, str(output), [])
++
++    return results
+diff --git a/tools/lint/python/pylint_requirements.txt b/tools/lint/python/pylint_requirements.txt
+new file mode 100644
+--- /dev/null
++++ b/tools/lint/python/pylint_requirements.txt
+@@ -0,0 +1,61 @@
++pylint==2.5.3 \
++    --hash=sha256:7dd78437f2d8d019717dbf287772d0b2dbdfd13fc016aa7faa08d67bccc46adc \
++    --hash=sha256:d0ece7d223fe422088b0e8f13fa0a1e8eb745ebffcb8ed53d3e95394b6101a1c
++toml==0.10.1 \
++    --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \
++    --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88
++mccabe==0.6.1 \
++    --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \
++    --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f
++six==1.15.0 \
++    --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
++    --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced
++wrapt==1.12.1 \
++    --hash=sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7
++lazy-object-proxy==1.5.0 \
++    --hash=sha256:0aef3fa29f7d1194d6f8a99382b1b844e5a14d3bc1ef82c3b1c4fb7e7e2019bc \
++    --hash=sha256:159ae2bbb4dc3ba506aeba868d14e56a754c0be402d1f0d7fdb264e0bdf2b095 \
++    --hash=sha256:161a68a427022bf13e249458be2cb8da56b055988c584d372a917c665825ae9a \
++    --hash=sha256:2d58f0e6395bf41087a383a48b06b42165f3b699f1aa41ba201db84ab77be63d \
++    --hash=sha256:311c9d1840042fc8e2dd80fc80272a7ea73e7646745556153c9cda85a4628b18 \
++    --hash=sha256:35c3ad7b7f7d5d4a54a80f0ff5a41ab186237d6486843f8dde00c42cfab33905 \
++    --hash=sha256:459ef557e669d0046fe2b92eb4822c097c00b5ef9d11df0f9bd7d4267acdfc52 \
++    --hash=sha256:4a50513b6be001b9b7be2c435478fe9669249c77c241813907a44cda1fcd03f4 \
++    --hash=sha256:51035b175740c44707694c521560b55b66da9d5a7c545cf22582bc02deb61664 \
++    --hash=sha256:96f2cdb35bdfda10e075f12892a42cff5179bbda698992b845f36c5e92755d33 \
++    --hash=sha256:a0aed261060cd0372abf08d16399b1224dbb5b400312e6b00f2b23eabe1d4e96 \
++    --hash=sha256:a6052c4c7d95de2345d9c58fc0fe34fff6c27a8ed8550dafeb18ada84406cc99 \
++    --hash=sha256:cbf1354292a4f7abb6a0188f74f5e902e4510ebad105be1dbc4809d1ed92f77e \
++    --hash=sha256:da82b2372f5ded8806eaac95b19af89a7174efdb418d4e7beb0c6ab09cee7d95 \
++    --hash=sha256:dd89f466c930d7cfe84c94b5cbe862867c88b269f23e5aa61d40945e0d746f54 \
++    --hash=sha256:e3183fbeb452ec11670c2d9bfd08a57bc87e46856b24d1c335f995239bedd0e1 \
++    --hash=sha256:e9a571e7168076a0d5ecaabd91e9032e86d815cca3a4bf0dafead539ef071aa5 \
++    --hash=sha256:ec6aba217d0c4f71cbe48aea962a382dedcd111f47b55e8b58d4aaca519bd360
++astroid==2.4.2 \
++    --hash=sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703 \
++    --hash=sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386
++isort==4.3.21 \
++    --hash=sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1 \
++    --hash=sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd
++typed-ast==1.4.1 \
++    --hash=sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355 \
++    --hash=sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919 \
++    --hash=sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa \
++    --hash=sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652 \
++    --hash=sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75 \
++    --hash=sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01 \
++    --hash=sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d \
++    --hash=sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1 \
++    --hash=sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907 \
++    --hash=sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c \
++    --hash=sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3 \
++    --hash=sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b \
++    --hash=sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614 \
++    --hash=sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb \
++    --hash=sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b \
++    --hash=sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41 \
++    --hash=sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6 \
++    --hash=sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34 \
++    --hash=sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe \
++    --hash=sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4 \
++    --hash=sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7
+diff --git a/tools/lint/test/files/pylint/bad.py b/tools/lint/test/files/pylint/bad.py
+new file mode 100644
+--- /dev/null
++++ b/tools/lint/test/files/pylint/bad.py
+@@ -0,0 +1,5 @@
++def foo():
++    useless_var = 1
++    useless_var = true
++    return "true"
++    print("unreachable")
+\ No newline at end of file
+diff --git a/tools/lint/test/files/pylint/good.py b/tools/lint/test/files/pylint/good.py
+new file mode 100644
+--- /dev/null
++++ b/tools/lint/test/files/pylint/good.py
+@@ -0,0 +1,3 @@
++def foo():
++    a = 1 + 1
++    return a
+diff --git a/tools/lint/test/python.ini b/tools/lint/test/python.ini
+--- a/tools/lint/test/python.ini
++++ b/tools/lint/test/python.ini
+@@ -1,8 +1,11 @@
+ [DEFAULT]
+ subsuite=mozlint, os == "linux"
+ skip-if = python == 2
+ 
+ [test_eslint.py]
+ skip-if = os == "win"  # node not installed on worker
+ [test_flake8.py]
+ requirements = tools/lint/python/flake8_requirements.txt
++[test_pylint.py]
++skip-if = os == "win" || os == "mac"  # only installed on linux
++requirements = tools/lint/python/pylint_requirements.txt
+diff --git a/tools/lint/test/test_pylint.py b/tools/lint/test/test_pylint.py
+new file mode 100644
+--- /dev/null
++++ b/tools/lint/test/test_pylint.py
+@@ -0,0 +1,24 @@
++import mozunit
++
++LINTER = 'pylint'
++
++
++def test_lint_single_file(lint, paths):
++    results = lint(paths('bad.py'))
++    assert len(results) == 3
++    assert results[0].rule == 'E0602'
++    assert results[1].rule == 'W0101'
++    assert results[1].lineno == 5
++
++    # run lint again to make sure the previous results aren't counted twice
++    results = lint(paths('bad.py'))
++    assert len(results) == 3
++
++
++def test_lint_single_file_good(lint, paths):
++    results = lint(paths('good.py'))
++    assert len(results) == 0
++
++
++if __name__ == '__main__':
++    mozunit.main()

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