merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 31 Oct 2014 14:07:48 +0100
changeset 237572 6bd2071b373f808c04a37fb29c5ea9e5ed89def9
parent 237533 4750a2124fa5bc021368605a7cd92b596a5466dd (current diff)
parent 237571 a37fedd51b7d388a8401467c3fbb020cd8c2b2a1 (diff)
child 237590 21fbf1e350900f5f7b9705535ac25e211fea5242
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
6bd2071b373f / 36.0a1 / 20141031061804 / files
nightly linux64
6bd2071b373f / 36.0a1 / 20141031061804 / files
nightly mac
6bd2071b373f / 36.0a1 / 20141031061804 / files
nightly win32
6bd2071b373f / 36.0a1 / 20141031061804 / files
nightly win64
6bd2071b373f / 36.0a1 / 20141031061804 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccessibleWrap.h"
 
 #include "Accessible-inl.h"
 #include "ApplicationAccessibleWrap.h"
 #include "InterfaceInitFuncs.h"
 #include "nsAccUtils.h"
+#include "mozilla/a11y/PDocAccessible.h"
 #include "ProxyAccessible.h"
 #include "RootAccessible.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "prprf.h"
 #include "nsStateMap.h"
@@ -766,17 +767,37 @@ GetAttributeSet(Accessible* aAccessible)
 
   return nullptr;
 }
 
 AtkAttributeSet *
 getAttributesCB(AtkObject *aAtkObj)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
-  return accWrap ? GetAttributeSet(accWrap) : nullptr;
+  if (accWrap)
+    return GetAttributeSet(accWrap);
+
+  ProxyAccessible* proxy = GetProxy(aAtkObj);
+  if (!proxy)
+    return nullptr;
+
+  nsAutoTArray<Attribute, 10> attrs;
+  proxy->Attributes(&attrs);
+  if (attrs.IsEmpty())
+    return nullptr;
+
+  AtkAttributeSet* objAttributeSet = nullptr;
+  for (uint32_t i = 0; i < attrs.Length(); i++) {
+    AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+    objAttr->name = g_strdup(attrs[i].Name().get());
+    objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(attrs[i].Value()).get());
+    objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
+  }
+
+  return objAttributeSet;
 }
 
 const gchar*
 GetLocaleCB(AtkObject* aAtkObj)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
   if (!accWrap)
     return nullptr;
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -44,8 +44,10 @@ LOCAL_INCLUDES += [
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_ENABLE_GTK']:
     CFLAGS += CONFIG['TK_CFLAGS']
     CXXFLAGS += CONFIG['TK_CFLAGS']
 
 if CONFIG['MOZ_ENABLE_DBUS']:
     CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
+
+    include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -3,16 +3,19 @@
 /* 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 "DocAccessibleChild.h"
 
 #include "Accessible-inl.h"
 
+#include "nsIPersistentProperties2.h"
+#include "nsISimpleEnumerator.h"
+
 namespace mozilla {
 namespace a11y {
 
 void
 SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
 {
   uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
   uint32_t role = aRoot->Role();
@@ -71,10 +74,48 @@ DocAccessibleChild::RecvDescription(cons
 {
   Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
   if (!acc)
     return true;
 
   acc->Description(*aDesc);
   return true;
 }
+
+bool
+DocAccessibleChild::RecvAttributes(const uint64_t& aID, nsTArray<Attribute>* aAttributes)
+{
+  Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
+  if (!acc)
+    return true;
+
+  nsCOMPtr<nsIPersistentProperties> props = acc->Attributes();
+  if (!props)
+    return true;
+
+  nsCOMPtr<nsISimpleEnumerator> propEnum;
+  nsresult rv = props->Enumerate(getter_AddRefs(propEnum));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  bool hasMore;
+  while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> sup;
+    rv = propEnum->GetNext(getter_AddRefs(sup));
+    NS_ENSURE_SUCCESS(rv, false);
+
+    nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
+    NS_ENSURE_TRUE(propElem, false);
+
+    nsAutoCString name;
+    rv = propElem->GetKey(name);
+    NS_ENSURE_SUCCESS(rv, false);
+
+    nsAutoString value;
+    rv = propElem->GetValue(value);
+    NS_ENSURE_SUCCESS(rv, false);
+
+    aAttributes->AppendElement(Attribute(name, value));
+    }
+
+  return true;
 }
 }
+}
--- a/accessible/ipc/DocAccessibleChild.h
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -43,16 +43,18 @@ public:
    */
   virtual bool RecvName(const uint64_t& aID, nsString* aName) MOZ_OVERRIDE;
 
   /*
    * Get the description for the accessible with given id.
    */
   virtual bool RecvDescription(const uint64_t& aID, nsString* aDesc) MOZ_OVERRIDE;
 
+  virtual bool RecvAttributes(const uint64_t& aID, nsTArray<Attribute> *aAttributes) MOZ_OVERRIDE;
+
 private:
   DocAccessible* mDoc;
 };
 
 }
 }
 
 #endif
--- a/accessible/ipc/PDocAccessible.ipdl
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -18,16 +18,22 @@ struct AccessibleData
 
 struct ShowEventData
 {
   uint64_t ID;
   uint32_t Idx;
   AccessibleData[] NewTree;
 };
 
+struct Attribute
+{
+  nsCString Name;
+  nsString Value;
+};
+
 prio(normal upto high) sync protocol PDocAccessible
 {
   manager PContent;
 
 parent:
   __delete__();
 
   /*
@@ -37,12 +43,13 @@ parent:
   Event(uint32_t type);
   ShowEvent(ShowEventData data);
   HideEvent(uint64_t aRootID);
 
 child:
   prio(high) sync State(uint64_t aID) returns(uint64_t states);
   prio(high) sync Name(uint64_t aID) returns(nsString name);
   prio(high) sync Description(uint64_t aID) returns(nsString desc);
+  prio(high) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
 };
 
 }
 }
--- a/accessible/ipc/ProxyAccessible.cpp
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -54,10 +54,16 @@ ProxyAccessible::Name(nsString& aName) c
   unused << mDoc->SendName(mID, &aName);
 }
 
 void
 ProxyAccessible::Description(nsString& aDesc) const
 {
   unused << mDoc->SendDescription(mID, &aDesc);
 }
+
+void
+ProxyAccessible::Attributes(nsTArray<Attribute> *aAttrs) const
+{
+  unused << mDoc->SendAttributes(mID, aAttrs);
 }
 }
+}
--- a/accessible/ipc/ProxyAccessible.h
+++ b/accessible/ipc/ProxyAccessible.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/a11y/Role.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace a11y {
 
+class Attribute;
 class DocAccessibleParent;
 
 class ProxyAccessible
 {
 public:
 
   ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
                   DocAccessibleParent* aDoc, role aRole) :
@@ -64,16 +65,21 @@ public:
   void Name(nsString& aName) const;
 
   /**
    * Set aDesc to the description of the proxied accessible.
    */
   void Description(nsString& aDesc) const;
 
   /**
+   * Get the set of attributes on the proxied accessible.
+   */
+  void Attributes(nsTArray<Attribute> *aAttrs) const;
+
+  /**
    * Allow the platform to store a pointers worth of data on us.
    */
   uintptr_t GetWrapper() const { return mWrapper; }
   void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
 
   /*
    * Return the ID of the accessible being proxied.
    */
--- a/addon-sdk/source/lib/sdk/util/iteration.js
+++ b/addon-sdk/source/lib/sdk/util/iteration.js
@@ -2,30 +2,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "experimental"
 };
 
-// This is known as @@iterator in the ES6 spec.  Until it is bound to
-// some well-known name, find the @@iterator object by expecting it as
-// the first property accessed on a for-of iterable.
-const iteratorSymbol = (function() {
-  try {
-    for (var _ of Proxy.create({get: function(_, name) { throw name; } }))
-      break;
-  } catch (name) {
-    return name;
-  }
-  throw new TypeError;
-})();
-
-exports.iteratorSymbol = iteratorSymbol;
+// This is known as @@iterator in the ES6 spec. In builds that have ES6
+// Symbols, use Symbol.iterator; otherwise use the legacy method name,
+// "@@iterator".
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+exports.iteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
 
 // An adaptor that, given an object that is iterable with for-of, is
 // suitable for being bound to __iterator__ in order to make the object
 // iterable in the same way via for-in.
 function forInIterator() {
     for (let item of this)
         yield item;
 }
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -46,16 +46,23 @@ const kPrefWebIDEInNavbar            = "
  * of providing onViewShowing and onViewHiding event handlers.
  */
 const kSubviewEvents = [
   "ViewShowing",
   "ViewHiding"
 ];
 
 /**
+ * The method name to use for ES6 iteration. If Symbols are enabled in
+ * this build, use Symbol.iterator; otherwise "@@iterator".
+ */
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const kIteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+
+/**
  * The current version. We can use this to auto-add new default widgets as necessary.
  * (would be const but isn't because of testing purposes)
  */
 let kVersion = 1;
 
 /**
  * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed
  * on their IDs.
@@ -2674,17 +2681,17 @@ this.CustomizableUI = {
 
 
   /**
    * An iteratable property of windows managed by CustomizableUI.
    * Note that this can *only* be used as an iterator. ie:
    *     for (let window of CustomizableUI.windows) { ... }
    */
   windows: {
-    "@@iterator": function*() {
+    *[kIteratorSymbol]() {
       for (let [window,] of gBuildWindows)
         yield window;
     }
   },
 
   /**
    * Add a listener object that will get fired for various events regarding
    * customization.
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -3255,20 +3255,25 @@ LineResults.prototype = {
   line: 0,
   _sourceResults: null,
   _store: null,
   _target: null
 };
 
 /**
  * A generator-iterator over the global, source or line results.
+ *
+ * The method name depends on whether symbols are enabled in
+ * this build. If so, use Symbol.iterator; otherwise "@@iterator".
  */
-GlobalResults.prototype["@@iterator"] =
-SourceResults.prototype["@@iterator"] =
-LineResults.prototype["@@iterator"] = function*() {
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+GlobalResults.prototype[ITERATOR_SYMBOL] =
+SourceResults.prototype[ITERATOR_SYMBOL] =
+LineResults.prototype[ITERATOR_SYMBOL] = function*() {
   yield* this._store;
 };
 
 /**
  * Gets the item associated with the specified element.
  *
  * @param nsIDOMNode aElement
  *        The element used to identify the item.
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -21,16 +21,23 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
                                   "resource:///modules/CustomizableUI.jsm");
 
 const EventEmitter = devtools.require("devtools/toolkit/event-emitter");
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
 const MAX_ORDINAL = 99;
 
 /**
+ * The method name to use for ES6 iteration. If symbols are enabled in this
+ * build, use Symbol.iterator; otherwise "@@iterator".
+ */
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+
+/**
  * DevTools is a class that represents a set of developer tools, it holds a
  * set of tools and keeps track of open toolboxes in the browser.
  */
 this.DevTools = function DevTools() {
   this._tools = new Map();     // Map<toolId, tool>
   this._themes = new Map();    // Map<themeId, theme>
   this._toolboxes = new Map(); // Map<target, toolbox>
 
@@ -481,17 +488,17 @@ DevTools.prototype = {
     // Cleaning down the toolboxes: i.e.
     //   for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
     // Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
   },
 
   /**
    * Iterator that yields each of the toolboxes.
    */
-  '@@iterator': function*() {
+  *[ITERATOR_SYMBOL]() {
     for (let toolbox of this._toolboxes) {
       yield toolbox;
     }
   }
 };
 
 /**
  * gDevTools is a singleton that controls the Firefox Developer Tools.
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -13,16 +13,23 @@ const LAZY_EMPTY_DELAY = 150; // ms
 const LAZY_EXPAND_DELAY = 50; // ms
 const SCROLL_PAGE_SIZE_DEFAULT = 0;
 const APPEND_PAGE_SIZE_DEFAULT = 500;
 const PAGE_SIZE_SCROLL_HEIGHT_RATIO = 100;
 const PAGE_SIZE_MAX_JUMPS = 30;
 const SEARCH_ACTION_MAX_DELAY = 300; // ms
 const ITEM_FLASH_DURATION = 300 // ms
 
+/**
+ * The method name to use for ES6 iteration. If symbols are enabled in
+ * this build, use Symbol.iterator; otherwise "@@iterator".
+ */
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 
@@ -3051,20 +3058,20 @@ Property.prototype = Heritage.extend(Var
     this._absoluteName = this.ownerView.absoluteName + "[\"" + this._nameString + "\"]";
     return this._absoluteName;
   }
 });
 
 /**
  * A generator-iterator over the VariablesView, Scopes, Variables and Properties.
  */
-VariablesView.prototype["@@iterator"] =
-Scope.prototype["@@iterator"] =
-Variable.prototype["@@iterator"] =
-Property.prototype["@@iterator"] = function*() {
+VariablesView.prototype[ITERATOR_SYMBOL] =
+Scope.prototype[ITERATOR_SYMBOL] =
+Variable.prototype[ITERATOR_SYMBOL] =
+Property.prototype[ITERATOR_SYMBOL] = function*() {
   yield* this._store;
 };
 
 /**
  * Forget everything recorded about added scopes, variables or properties.
  * @see VariablesView.commitHierarchy
  */
 VariablesView.prototype.clearHierarchy = function() {
--- a/browser/devtools/shared/widgets/ViewHelpers.jsm
+++ b/browser/devtools/shared/widgets/ViewHelpers.jsm
@@ -8,16 +8,23 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const PANE_APPEARANCE_DELAY = 50;
 const PAGE_SIZE_ITEM_COUNT_RATIO = 5;
 const WIDGET_FOCUSABLE_NODES = new Set(["vbox", "hbox"]);
 
+/**
+ * The method name to use for ES6 iteration. If symbols are enabled in
+ * this build, use Symbol.iterator; otherwise "@@iterator".
+ */
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
 
 this.EXPORTED_SYMBOLS = [
   "Heritage", "ViewHelpers", "WidgetMethods",
   "setNamedTimeout", "clearNamedTimeout",
@@ -1724,12 +1731,12 @@ this.WidgetMethods = {
   _headerText: "",
   _preferredValue: "",
   _cachedCommandDispatcher: null
 };
 
 /**
  * A generator-iterator over all the items in this container.
  */
-Item.prototype["@@iterator"] =
-WidgetMethods["@@iterator"] = function*() {
+Item.prototype[ITERATOR_SYMBOL] =
+WidgetMethods[ITERATOR_SYMBOL] = function*() {
   yield* this._itemsByElement.values();
 };
--- a/configure.in
+++ b/configure.in
@@ -6554,16 +6554,19 @@ dnl ====================================
 if test -n "$gonkdir"; then
     MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
 fi
 
 case "$OS_TARGET:$NIGHTLY_BUILD" in
 WINNT:1)
     MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
     ;;
+Darwin:1)
+    MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
+    ;;
 *)
     MOZ_ARG_ENABLE_BOOL(content-sandbox,
     [  --enable-content-sandbox        Enable sandboxing support for content-processes],
         MOZ_CONTENT_SANDBOX=1,
         MOZ_CONTENT_SANDBOX=)
     ;;
 esac
 
--- a/dom/base/nsCSPContext.cpp
+++ b/dom/base/nsCSPContext.cpp
@@ -810,16 +810,17 @@ class CSPReportSenderRunnable MOZ_FINAL 
       , mReportOnlyFlag(aReportOnlyFlag)
       , mViolatedDirective(aViolatedDirective)
       , mSourceFile(aSourceFile)
       , mScriptSample(aScriptSample)
       , mLineNum(aLineNum)
       , mInnerWindowID(aInnerWindowID)
       , mCSPContext(aCSPContext)
     {
+      NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
       // the observer subject is an nsISupports: either an nsISupportsCString
       // from the arg passed in directly, or if that's empty, it's the blocked
       // source.
       if (aObserverSubject.IsEmpty()) {
         mObserverSubject = aBlockedContentSource;
       } else {
         nsCOMPtr<nsISupportsCString> supportscstr =
           do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
--- a/dom/base/nsCSPUtils.cpp
+++ b/dom/base/nsCSPUtils.cpp
@@ -922,26 +922,44 @@ nsCSPPolicy::directiveExists(enum CSPDir
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->equals(aDir)) {
       return true;
     }
   }
   return false;
 }
 
+/*
+ * Use this function only after ::allows() returned 'false'. Most and
+ * foremost it's used to get the violated directive before sending reports.
+ * The parameter outDirective is the equivalent of 'outViolatedDirective'
+ * for the ::permits() function family.
+ */
 void
 nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
                                               nsAString& outDirective) const
 {
+  nsCSPDirective* defaultDir = nullptr;
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->restrictsContentType(aContentType)) {
       mDirectives[i]->toString(outDirective);
       return;
     }
+    if (mDirectives[i]->isDefaultDirective()) {
+      defaultDir = mDirectives[i];
+    }
   }
+  // if we haven't found a matching directive yet,
+  // the contentType must be restricted by the default directive
+  if (defaultDir) {
+    defaultDir->toString(outDirective);
+    return;
+  }
+  NS_ASSERTION(false, "Can not query directive string for contentType!");
+  outDirective.AppendASCII("couldNotQueryViolatedDirective");
 }
 
 void
 nsCSPPolicy::getDirectiveStringForBaseURI(nsAString& outDirective) const
 {
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->equals(CSP_BASE_URI)) {
       mDirectives[i]->toString(outDirective);
--- a/dom/base/test/chrome/cpows_parent.xul
+++ b/dom/base/test/chrome/cpows_parent.xul
@@ -53,19 +53,24 @@
         ok(Components.utils.isCrossProcessWrapper(data), "got a CPOW");
         ok(Components.utils.isCrossProcessWrapper(document), "got a CPOW");
       }
       ok(data.i === 5, "integer property");
       ok(data.b === true, "boolean property");
       ok(data.s === "hello", "string property");
       ok(data.x.i === 10, "nested property");
       ok(data.f() === 99, "function call");
+      is(Object.getOwnPropertyDescriptor(data, "doesn't exist"), undefined,
+         "getOwnPropertyDescriptor returns undefined for non-existant properties");
+      ok(Object.getOwnPropertyDescriptor(data, "i").value, 5,
+         "getOwnPropertyDescriptor.value works");
       let obj = new data.ctor();
       ok(obj.a === 3, "constructor call");
       ok(document.title === "Hello, Kitty", "document node");
+      is(typeof document.cookie, "string", "can get document.cookie");
 
       data.i = 6;
       data.b = false;
       data.s = "bye";
       data.x = null;
       ok(data.i === 6, "integer property");
       ok(data.b === false, "boolean property");
       ok(data.s === "bye", "string property");
--- a/dom/base/test/csp/test_csp_report.html
+++ b/dom/base/test/csp/test_csp_report.html
@@ -14,30 +14,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 
 <iframe style="width:200px;height:200px;" id='cspframe'></iframe>
 <script class="testbody" type="text/javascript">
 
 /*
  * Description of the test:
  * We try to load an inline-src using a policy that constrains
- * all scripts from running (script-src 'none'). We verify that
+ * all scripts from running (default-src 'none'). We verify that
  * the generated csp-report contains the expceted values. If any
  * of the JSON is not formatted properly (e.g. not properly escaped)
  * then JSON.parse will fail, which allows to pinpoint such errors
  * in the catch block, and the test will fail. Since we use an
  * observer, we can set the actual report-uri to a foo value.
  */
 
 const testfile = "tests/dom/base/test/csp/file_csp_report.html";
 const reportURI = "http://mochi.test:8888/foo.sjs";
-const policy = "script-src 'none'; report-uri " + reportURI;
+const policy = "default-src 'none'; report-uri " + reportURI;
 const docUri = "http://mochi.test:8888/tests/dom/base/test/csp/file_csp_testserver.sjs" +
                "?file=tests/dom/base/test/csp/file_csp_report.html" +
-               "&csp=script-src%20%27none%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
+               "&csp=default-src%20%27none%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
 
 window.checkResults = function(reportObj) {
   var cspReport = reportObj["csp-report"];
 
   // The following uris' fragments should be stripped before reporting:
   //    * document-uri
   //    * blocked-uri
   //    * source-file
@@ -45,19 +45,19 @@ window.checkResults = function(reportObj
   is(cspReport["document-uri"], docUri, "Incorrect document-uri");
 
   // we can not test for the whole referrer since it includes platform specific information
   ok(cspReport["referrer"].startsWith("http://mochi.test:8888/tests/dom/base/test/csp/test_csp_report.html"),
      "Incorrect referrer");
 
   is(cspReport["blocked-uri"], "self", "Incorrect blocked-uri");
 
-  is(cspReport["violated-directive"], "script-src 'none'", "Incorrect violated-directive");
+  is(cspReport["violated-directive"], "default-src 'none'", "Incorrect violated-directive");
 
-  is(cspReport["original-policy"], "script-src 'none'; report-uri http://mochi.test:8888/foo.sjs",
+  is(cspReport["original-policy"], "default-src 'none'; report-uri http://mochi.test:8888/foo.sjs",
      "Incorrect original-policy");
 
   is(cspReport["source-file"], docUri, "Incorrect source-file");
 
   is(cspReport["script-sample"], "\n    var foo = \"propEscFoo\";\n    var bar...",
      "Incorrect script-sample");
 
   is(cspReport["line-number"], "7", "Incorrect line-number");
--- a/dom/base/test/test_window_define_symbol.html
+++ b/dom/base/test/test_window_define_symbol.html
@@ -11,15 +11,19 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1082672">Mozilla Bug 1082672</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
-var sym = Symbol("ponies");
-Object.defineProperty(window, sym, {configurable: true, value: 3});
-is(window[sym], 3);
+if (typeof Symbol === "function") {
+  var sym = Symbol("ponies");
+  Object.defineProperty(window, sym, {configurable: true, value: 3});
+  is(window[sym], 3);
+} else {
+  ok(true, "no Symbols in this build");
+}
 </script>
 </pre>
 </body>
 </html>
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2009,37 +2009,38 @@ class PropertyDefiner:
     def getControllingCondition(interfaceMember, descriptor):
         return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember,
                                                              "Pref"),
                                PropertyDefiner.getStringAttr(interfaceMember,
                                                              "Func"),
                                getAvailableInTestFunc(interfaceMember),
                                descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
 
-    def generatePrefableArray(self, array, name, specTemplate, specTerminator,
+    def generatePrefableArray(self, array, name, specFormatter, specTerminator,
                               specType, getCondition, getDataTuple, doIdArrays):
         """
         This method generates our various arrays.
 
         array is an array of interface members as passed to generateArray
 
         name is the name as passed to generateArray
 
-        specTemplate is a template for each entry of the spec array
+        specFormatter is a function that takes a single argument, a tuple,
+          and returns a string, a spec array entry
 
         specTerminator is a terminator for the spec array (inserted every time
           our controlling pref changes and at the end of the array)
 
         specType is the actual typename of our spec
 
         getCondition is a callback function that takes an array entry and
           returns the corresponding MemberCondition.
 
         getDataTuple is a callback function that takes an array entry and
-          returns a tuple suitable for substitution into specTemplate.
+          returns a tuple suitable to be passed to specFormatter.
         """
 
         # We want to generate a single list of specs, but with specTerminator
         # inserted at every point where the pref name controlling the member
         # changes.  That will make sure the order of the properties as exposed
         # on the interface and interface prototype objects does not change when
         # pref control is added to members while still allowing us to define all
         # the members in the smallest number of JSAPI calls.
@@ -2072,17 +2073,17 @@ class PropertyDefiner:
             curCondition = getCondition(member, self.descriptor)
             if lastCondition != curCondition:
                 # Terminate previous list
                 specs.append(specTerminator)
                 # And switch to our new pref
                 switchToCondition(self, curCondition)
                 lastCondition = curCondition
             # And the actual spec
-            specs.append(specTemplate % getDataTuple(member))
+            specs.append(specFormatter(getDataTuple(member)))
         specs.append(specTerminator)
         prefableSpecs.append("  { false, nullptr }")
 
         specType = "const " + specType
         arrays = fill(
             """
             static ${specType} ${name}_specs[] = {
             ${specs}
@@ -2349,19 +2350,25 @@ class MethodDefiner(PropertyDefiner):
                     if m.get("returnsPromise", False):
                         jitinfo = "&%s_methodinfo" % accessor
                         accessor = "StaticMethodPromiseWrapper"
                     else:
                         jitinfo = "nullptr"
 
             return (m["name"], accessor, jitinfo, m["length"], flags(m), selfHostedName)
 
+        def formatSpec(fields):
+            if fields[0].startswith("@@"):
+                fields = (fields[0][2:],) + fields[1:]
+                return '  JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
+            return '  JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
+
         return self.generatePrefableArray(
             array, name,
-            '  JS_FNSPEC("%s", %s, %s, %s, %s, %s)',
+            formatSpec,
             '  JS_FS_END',
             'JSFunctionSpec',
             condition, specData, doIdArrays)
 
 
 def IsCrossOriginWritable(attr, descriptor):
     """
     Return whether the IDLAttribute in question is cross-origin writable on the
@@ -2455,17 +2462,17 @@ class AttrDefiner(PropertyDefiner):
                    (accessor, jitinfo)
 
         def specData(attr):
             return (attr.identifier.name, flags(attr), getter(attr),
                     setter(attr))
 
         return self.generatePrefableArray(
             array, name,
-            '  { "%s", %s, %s, %s}',
+            lambda fields: '  { "%s", %s, %s, %s}' % fields,
             '  JS_PS_END',
             'JSPropertySpec',
             PropertyDefiner.getControllingCondition, specData, doIdArrays)
 
 
 class ConstDefiner(PropertyDefiner):
     """
     A class for definining constants on the interface object
@@ -2483,17 +2490,17 @@ class ConstDefiner(PropertyDefiner):
             return ""
 
         def specData(const):
             return (const.identifier.name,
                     convertConstIDLValueToJSVal(const.value))
 
         return self.generatePrefableArray(
             array, name,
-            '  { "%s", %s }',
+            lambda fields: '  { "%s", %s }' % fields,
             '  { 0, JS::UndefinedValue() }',
             'ConstantSpec',
             PropertyDefiner.getControllingCondition, specData, doIdArrays)
 
 
 class PropertyArrays():
     def __init__(self, descriptor):
         self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
--- a/dom/bindings/test/test_sequence_detection.html
+++ b/dom/bindings/test/test_sequence_detection.html
@@ -11,28 +11,19 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript">
 
   /** Test for Bug 1066432 **/
   SimpleTest.waitForExplicitFinish();
   SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
     var testInterfaceJS = new TestInterfaceJS();
     ok(testInterfaceJS, "got a TestInterfaceJS object");
 
-    var nonIterableObject = { "@@iterator": 5 };
-    if (typeof Symbol === "function") {
-      // Make this test fail if Symbol.iterator is correctly implemented.
-      // This is here to make sure this test is updated when bug 918828 lands,
-      // at which point the correct code will be:
-      //   var JS_HAS_SYMBOLS = typeof Symbol === "function";
-      //   var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
-      //   var nonIterableObject = { [std_iterator]: 5};
-      // Otherwise, fixing bug 918828 would cause this test to silently stop
-      // testing what it's supposed to be testing.
-      nonIterableObject[Symbol.iterator] = Array.prototype[Symbol.iterator];
-    }
+    var JS_HAS_SYMBOLS = typeof Symbol === "function";
+    var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+    var nonIterableObject = {[std_iterator]: 5};
 
     try {
       testInterfaceJS.testSequenceOverload(nonIterableObject);
       ok(false, "Should have thrown in the overload case");  // see long comment above!
     } catch (e) {
       ise(e.name, "TypeError", "Should get a TypeError for the overload case");
       ok(e.message.contains("not iterable"),
          "Should have a message about being non-iterable in the overload case");
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -439,17 +439,17 @@ HTMLTextAreaElement::GetAttributeChangeH
     NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
   }
   return retval;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTextAreaElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
-  static const MappedAttributeEntry attributes[] {
+  static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::wrap },
     { nullptr }
   };
 
   static const MappedAttributeEntry* const map[] = {
     attributes,
     sDivAlignAttributeMap,
     sCommonAttributeMap,
--- a/dom/html/test/test_formelements.html
+++ b/dom/html/test/test_formelements.html
@@ -27,27 +27,33 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 772869 **/
 var x = $("f").elements;
 x.something = "another";
 names = [];
 for (var name in x) {
   names.push(name);
 }
-is(names.length, 10, "Should have 10 enumerated names");
+var JS_HAS_SYMBOLS = typeof Symbol === "function";
+is(names.length, JS_HAS_SYMBOLS ? 9 : 10,
+   "Should have 9 enumerated names (or 10 with '@@iterator')");
 is(names[0], "0", "Enum entry 1");
 is(names[1], "1", "Enum entry 2");
 is(names[2], "2", "Enum entry 3");
 is(names[3], "3", "Enum entry 4");
 is(names[4], "4", "Enum entry 5");
 is(names[5], "something", "Enum entry 6");
 is(names[6], "namedItem", "Enum entry 7");
 is(names[7], "item", "Enum entry 8");
-is(names[8], "@@iterator", "Enum entry 9");
-is(names[9], "length", "Enum entry 10");
+if (JS_HAS_SYMBOLS) {
+  is(names[8], "length", "Enum entry 9");
+} else {
+  is(names[8], "@@iterator", "Enum entry 9");
+  is(names[9], "length", "Enum entry 10");
+}
 
 names = Object.getOwnPropertyNames(x);
 is(names.length, 10, "Should have 10 items");
 // Now sort entries 5 through 8, for comparison purposes.  We don't sort the
 // whole array, because we want to make sure the ordering between the parts
 // is correct
 temp = names.slice(5, 9);
 temp.sort();
--- a/dom/html/test/test_htmlcollection.html
+++ b/dom/html/test/test_htmlcollection.html
@@ -23,26 +23,32 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 772869 **/
 var x = document.getElementsByClassName("foo");
 x.something = "another";
 var names = [];
 for (var name in x) {
   names.push(name);
 }
-is(names.length, 9, "Should have 9 enumerated names");
+var JS_HAS_SYMBOLS = typeof Symbol === "function";
+is(names.length, JS_HAS_SYMBOLS ? 8 : 9,
+   "Should have 8 enumerated names (or 9 with '@@iterator')");
 is(names[0], "0", "Enum entry 1")
 is(names[1], "1", "Enum entry 2")
 is(names[2], "2", "Enum entry 3")
 is(names[3], "3", "Enum entry 4")
 is(names[4], "something", "Enum entry 5")
 is(names[5], "item", "Enum entry 6")
 is(names[6], "namedItem", "Enum entry 7")
-is(names[7], "@@iterator", "Enum entry 8")
-is(names[8], "length", "Enum entry 9")
+if (JS_HAS_SYMBOLS) {
+  is(names[7], "length", "Enum entry 8");
+} else {
+  is(names[7], "@@iterator", "Enum entry 8");
+  is(names[8], "length", "Enum entry 9");
+}
 
 names = Object.getOwnPropertyNames(x);
 is(names.length, 9, "Should have 9 items");
 is(names[0], "0", "Entry 1")
 is(names[1], "1", "Entry 2")
 is(names[2], "2", "Entry 3")
 is(names[3], "3", "Entry 4")
 is(names[4], "x", "Entry 5")
--- a/dom/html/test/test_named_options.html
+++ b/dom/html/test/test_named_options.html
@@ -37,26 +37,30 @@ is(names[5], "y", "Entry 6")
 is(names[6], "z", "Entry 7")
 is(names[7], "w", "Entry 8")
 is(names[8], "loopy", "Entry 9")
 
 var names2 = [];
 for (var name in opt) {
   names2.push(name);
 }
-is(names2.length, 12, "Should have twelve enumerated names");
+var JS_HAS_SYMBOLS = typeof Symbol === "function";
+is(names2.length, JS_HAS_SYMBOLS ? 11 : 12,
+   "Should have eleven enumerated names (or twelve with '@@iterator')");
 is(names2[0], "0", "Enum entry 1")
 is(names2[1], "1", "Enum entry 2")
 is(names2[2], "2", "Enum entry 3")
 is(names2[3], "3", "Enum entry 4")
 is(names2[4], "loopy", "Enum entry 5")
 is(names2[5], "add", "Enum entrry 6")
 is(names2[6], "remove", "Enum entry 7")
 is(names2[7], "length", "Enum entry 8")
 is(names2[8], "selectedIndex", "Enum entry 9")
 is(names2[9], "item", "Enum entry 10")
 is(names2[10], "namedItem", "Enum entry 11")
-is(names2[11], "@@iterator", "Enum entry 12")
+if (!JS_HAS_SYMBOLS) {
+  is(names2[11], "@@iterator", "Enum entry 12");
+}
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/html/test/test_rowscollection.html
+++ b/dom/html/test/test_rowscollection.html
@@ -33,28 +33,34 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 772869 **/
 var x = $("f").rows;
 x.something = "another";
 var names = [];
 for (var name in x) {
   names.push(name);
 }
-is(names.length, 11, "Should have 11 enumerated names");
+var JS_HAS_SYMBOLS = typeof Symbol === "function";
+is(names.length, JS_HAS_SYMBOLS ? 10 : 11,
+   "Should have 10 enumerated names (or 11 with '@@iterator')");
 is(names[0], "0", "Enum entry 1")
 is(names[1], "1", "Enum entry 2")
 is(names[2], "2", "Enum entry 3")
 is(names[3], "3", "Enum entry 4")
 is(names[4], "4", "Enum entry 5")
 is(names[5], "5", "Enum entry 6")
 is(names[6], "something", "Enum entry 7")
 is(names[7], "item", "Enum entry 8")
 is(names[8], "namedItem", "Enum entry 9")
-is(names[9], "@@iterator", "Enum entry 10")
-is(names[10], "length", "Enum entry 11")
+if (JS_HAS_SYMBOLS) {
+  is(names[9], "length", "Enum entry 10");
+} else {
+  is(names[9], "@@iterator", "Enum entry 10");
+  is(names[10], "length", "Enum entry 11");
+}
 
 names = Object.getOwnPropertyNames(x);
 is(names.length, 11, "Should have 11 items");
 is(names[0], "0", "Entry 1")
 is(names[1], "1", "Entry 2")
 is(names[2], "2", "Entry 3")
 is(names[3], "3", "Entry 4")
 is(names[4], "4", "Entry 5")
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -2201,16 +2201,24 @@ SetDefaultPragmas(mozIStorageConnection*
     // trigger.
     "PRAGMA recursive_triggers = ON;";
 
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(query));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  if (IndexedDatabaseManager::FullSynchronous()) {
+    rv = aConnection->ExecuteSimpleSQL(
+                             NS_LITERAL_CSTRING("PRAGMA synchronous = FULL;"));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
   return NS_OK;
 }
 
 nsresult
 CreateDatabaseConnection(nsIFile* aDBFile,
                          nsIFile* aFMDirectory,
                          const nsAString& aName,
                          PersistenceType aPersistenceType,
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -207,16 +207,17 @@ IndexedDatabaseManager::IndexedDatabaseM
 }
 
 IndexedDatabaseManager::~IndexedDatabaseManager()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 bool IndexedDatabaseManager::sIsMainProcess = false;
+bool IndexedDatabaseManager::sFullSynchronousMode = false;
 mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
 
 // static
 IndexedDatabaseManager*
 IndexedDatabaseManager::GetOrCreate()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -294,16 +295,24 @@ IndexedDatabaseManager::Init()
     nsresult rv =
       obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   Preferences::RegisterCallbackAndCall(TestingPrefChangedCallback,
                                        kTestingPref);
 
+  // By default IndexedDB uses SQLite with PRAGMA synchronous = NORMAL. This
+  // guarantees (unlike synchronous = OFF) atomicity and consistency, but not
+  // necessarily durability in situations such as power loss. This preference
+  // allows enabling PRAGMA synchronous = FULL on SQLite, which does guarantee
+  // durability, but with an extra fsync() and the corresponding performance
+  // hit.
+  sFullSynchronousMode = Preferences::GetBool("dom.indexedDB.fullSynchronous");
+
   return NS_OK;
 }
 
 void
 IndexedDatabaseManager::Destroy()
 {
   // Setting the closed flag prevents the service from being recreated.
   // Don't set it though if there's no real instance created.
@@ -497,16 +506,26 @@ bool
 IndexedDatabaseManager::InTestingMode()
 {
   MOZ_ASSERT(gDBManager,
              "InTestingMode() called before indexedDB has been initialized!");
 
   return gTestingMode;
 }
 
+// static
+bool
+IndexedDatabaseManager::FullSynchronous()
+{
+  MOZ_ASSERT(gDBManager,
+             "FullSynchronous() called before indexedDB has been initialized!");
+
+  return sFullSynchronousMode;
+}
+
 already_AddRefed<FileManager>
 IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
                                        const nsACString& aOrigin,
                                        const nsAString& aDatabaseName)
 {
   AssertIsOnIOThread();
 
   FileManagerInfo* info;
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -75,16 +75,19 @@ public:
   {
     return !!sLowDiskSpaceMode;
   }
 #endif
 
   static bool
   InTestingMode();
 
+  static bool
+  FullSynchronous();
+
   already_AddRefed<FileManager>
   GetFileManager(PersistenceType aPersistenceType,
                  const nsACString& aOrigin,
                  const nsAString& aDatabaseName);
 
   void
   AddFileManager(FileManager* aFileManager);
 
@@ -157,16 +160,17 @@ private:
   nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos;
 
   // Lock protecting FileManager.mFileInfos and FileImplBase.mFileInfos
   // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
   // and FileInfo.mSliceRefCnt
   mozilla::Mutex mFileMutex;
 
   static bool sIsMainProcess;
+  static bool sFullSynchronousMode;
   static mozilla::Atomic<bool> sLowDiskSpaceMode;
 };
 
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_indexeddb_indexeddatabasemanager_h__
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -45,17 +45,17 @@
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #if defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #include "nsDirectoryServiceDefs.h"
-#elif defined(XP_LINUX)
+#elif defined(XP_LINUX) || defined(XP_MACOSX)
 #include "mozilla/Sandbox.h"
 #endif
 #endif
 
 #include "mozilla/unused.h"
 
 #include "mozInlineSpellChecker.h"
 #include "nsIConsoleListener.h"
@@ -547,16 +547,86 @@ ContentChild::~ContentChild()
 {
 }
 
 NS_INTERFACE_MAP_BEGIN(ContentChild)
   NS_INTERFACE_MAP_ENTRY(nsIContentChild)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+static bool
+GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
+{
+  nsAutoCString appPath;
+  nsAutoCString appBinaryPath(
+    (CommandLine::ForCurrentProcess()->argv()[0]).c_str());
+
+  nsAutoCString::const_iterator start, end;
+  appBinaryPath.BeginReading(start);
+  appBinaryPath.EndReading(end);
+  if (RFindInReadable(NS_LITERAL_CSTRING(".app/Contents/MacOS/"), start, end)) {
+    end = start;
+    ++end; ++end; ++end; ++end;
+    appBinaryPath.BeginReading(start);
+    appPath.Assign(Substring(start, end));
+  } else {
+    return false;
+  }
+
+  nsCOMPtr<nsIFile> app, appBinary;
+  nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appPath),
+                                true, getter_AddRefs(app));
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appBinaryPath),
+                       true, getter_AddRefs(appBinary));
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+
+  bool isLink;
+  app->IsSymlink(&isLink);
+  if (isLink) {
+    app->GetNativeTarget(aAppPath);
+  } else {
+    app->GetNativePath(aAppPath);
+  }
+  appBinary->IsSymlink(&isLink);
+  if (isLink) {
+    appBinary->GetNativeTarget(aAppBinaryPath);
+  } else {
+    appBinary->GetNativePath(aAppBinaryPath);
+  }
+
+  return true;
+}
+
+void
+ContentChild::OnChannelConnected(int32_t aPid)
+{
+  nsAutoCString appPath, appBinaryPath;
+  if (!GetAppPaths(appPath, appBinaryPath)) {
+    MOZ_CRASH("Error resolving child process path");
+  }
+
+  MacSandboxInfo info;
+  info.type = MacSandboxType_Content;
+  info.appPath.Assign(appPath);
+  info.appBinaryPath.Assign(appBinaryPath);
+
+  nsAutoCString err;
+  if (!mozilla::StartMacSandbox(info, err)) {
+    NS_WARNING(err.get());
+    MOZ_CRASH("sandbox_init() failed");
+  }
+}
+#endif
+
 bool
 ContentChild::Init(MessageLoop* aIOLoop,
                    base::ProcessHandle aParentHandle,
                    IPC::Channel* aChannel)
 {
 #ifdef MOZ_WIDGET_GTK
     // sigh
     gtk_init(nullptr, nullptr);
@@ -581,17 +651,19 @@ ContentChild::Init(MessageLoop* aIOLoop,
     // Once we start sending IPC messages, we need the thread manager to be
     // initialized so we can deal with the responses. Do that here before we
     // try to construct the crash reporter.
     nsresult rv = nsThreadManager::get()->Init();
     if (NS_WARN_IF(NS_FAILED(rv))) {
         return false;
     }
 
-    Open(aChannel, aParentHandle, aIOLoop);
+    if (!Open(aChannel, aParentHandle, aIOLoop)) {
+      return false;
+    }
     sSingleton = this;
 
     // Make sure there's an nsAutoScriptBlocker on the stack when dispatching
     // urgent messages.
     GetIPCChannel()->BlockScripts();
 
 #ifdef MOZ_X11
     // Send the parent our X socket to act as a proxy reference for our X
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -69,16 +69,20 @@ public:
         nsCString version;
         nsCString buildID;
         nsCString name;
         nsCString UAName;
         nsCString ID;
         nsCString vendor;
     };
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+    void OnChannelConnected(int32_t aPid);
+#endif
+
     bool Init(MessageLoop* aIOLoop,
               base::ProcessHandle aParentHandle,
               IPC::Channel* aChannel);
     void InitProcessAttributes();
     void InitXPCOM();
 
     static ContentChild* GetSingleton() {
         return sSingleton;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -64,17 +64,17 @@ struct NativeKeyBinding
 };
 
 union MaybeNativeKeyBinding
 {
   NativeKeyBinding;
   void_t;
 };
 
-prio(normal upto high) intr protocol PBrowser
+prio(normal upto urgent) intr protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDocumentRenderer;
     manages PContentPermissionRequest;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
@@ -136,102 +136,106 @@ parent:
      * Notifies chrome that there is a focus change involving an editable
      * object (input, textarea, document, contentEditable. etc.)
      *
      *  focus        PR_TRUE if editable object is receiving focus
      *               PR_FALSE if losing focus
      *  preference   Native widget preference for IME updates
      *  seqno        Current seqno value on the chrome side
      */
-    sync NotifyIMEFocus(bool focus)
+    prio(urgent) sync NotifyIMEFocus(bool focus)
       returns (nsIMEUpdatePreference preference, uint32_t seqno);
 
     /**
      * Notifies chrome that there has been a change in text content
      * One call can encompass both a delete and an insert operation
      * Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
      *
      *  offset       Starting offset of the change
      *  end          Ending offset of the range deleted
      *  newEnd       New ending offset after insertion
      *  causedByComposition true if the change is caused by composition
      *
      *  for insertion, offset == end
      *  for deletion, offset == newEnd
      */
-    NotifyIMETextChange(uint32_t offset, uint32_t end, uint32_t newEnd,
-                        bool causedByComposition);
+    prio(urgent) async NotifyIMETextChange(uint32_t offset, uint32_t end,
+                                           uint32_t newEnd,
+                                           bool causedByComposition);
 
     /**
      * Notifies chrome that there is a IME compostion rect updated
      *
      *  offset       The starting offset of this rect
      *  rect         The rect of first character of selected IME composition
      *  caretOffset  The offset of caret position
      *  caretRect    The rect of IME caret
      */
-    NotifyIMESelectedCompositionRect(uint32_t offset, nsIntRect[] rect,
-                                     uint32_t caretOffset, nsIntRect caretRect);
+    prio(urgent) async NotifyIMESelectedCompositionRect(uint32_t offset,
+                                                        nsIntRect[] rect,
+                                                        uint32_t caretOffset,
+                                                        nsIntRect caretRect);
 
     /**
      * Notifies chrome that there has been a change in selection
      * Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
      *
      *  seqno        Current seqno value on the content side
      *  anchor       Offset where the selection started
      *  focus        Offset where the caret is
      *  causedByComposition true if the change is caused by composition
      */
-    NotifyIMESelection(uint32_t seqno, uint32_t anchor, uint32_t focus,
-                       bool causedByComposition);
+    prio(urgent) async NotifyIMESelection(uint32_t seqno, uint32_t anchor,
+                                          uint32_t focus, bool causedByComposition);
 
     /**
      * Notifies chrome to refresh its text cache 
      *
      *  text         The entire content of the text field
      */
-    NotifyIMETextHint(nsString text);
+    prio(urgent) async NotifyIMETextHint(nsString text);
 
     /**
      * Notifies IME of mouse button event on a character in focused editor.
      *
      * Returns true if the mouse button event is consumd by IME.
      */
-    sync NotifyIMEMouseButtonEvent(IMENotification notification)
+    prio(urgent) sync NotifyIMEMouseButtonEvent(IMENotification notification)
       returns (bool consumedByIME);
 
     /**
      * Instructs chrome to end any pending composition
      *
      *  cancel       PR_TRUE if composition should be cancelled
      *  composition  Text to commit before ending the composition
      *
      *  if cancel is PR_TRUE,
      *    widget should return empty string for composition
      *  if cancel is PR_FALSE,
      *    widget should return the current composition text
      */
-    sync EndIMEComposition(bool cancel) returns (nsString composition);
+    prio(urgent) sync EndIMEComposition(bool cancel) returns (nsString composition);
 
     /**
      * Request that the parent process move focus to the browser's frame. If
      * canRaise is true, the window can be raised if it is inactive.
      */
     RequestFocus(bool canRaise);
 
-    sync GetInputContext() returns (int32_t IMEEnabled, int32_t IMEOpen,
-                                    intptr_t NativeIMEContext);
+    prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
+                                                 int32_t IMEOpen,
+                                                 intptr_t NativeIMEContext);
 
-    SetInputContext(int32_t IMEEnabled,
-                    int32_t IMEOpen,
-                    nsString type,
-                    nsString inputmode,
-                    nsString actionHint,
-                    int32_t cause,
-                    int32_t focusChange);
+    prio(urgent) async SetInputContext(int32_t IMEEnabled,
+                                       int32_t IMEOpen,
+                                       nsString type,
+                                       nsString inputmode,
+                                       nsString actionHint,
+                                       int32_t cause,
+                                       int32_t focusChange);
 
     sync IsParentWindowMainWidgetVisible() returns (bool visible);
 
     /**
      * Gets the DPI of the screen corresponding to this browser.
      */
     sync GetDPI() returns (float value);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -325,17 +325,17 @@ struct ClipboardCapabilities {
   bool supportsFindClipboard;
 };
 
 union MaybeFileDesc {
     FileDescriptor;
     void_t;
 };
 
-prio(normal upto high) intr protocol PContent
+prio(normal upto urgent) intr protocol PContent
 {
     parent spawns PPluginModule;
 
     parent opens PCompositor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     child opens PBackground;
 
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -23,17 +23,17 @@ namespace dom {
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
  * child will allocate the PContentBridgeParent, and the newly opened child will
  * allocate the PContentBridgeChild.  This protocol allows these processes to
  * share PBrowsers and send messages to each other.
  */
-prio(normal upto high) intr protocol PContentBridge
+prio(normal upto urgent) intr protocol PContentBridge
 {
     bridges PContent, PContent;
 
     manages PBlob;
     manages PBrowser;
     manages PJavaScript;
 
 parent:
--- a/dom/network/UDPSocketChild.cpp
+++ b/dom/network/UDPSocketChild.cpp
@@ -23,16 +23,17 @@ UDPSocketChildBase::~UDPSocketChildBase(
 {
 }
 
 void
 UDPSocketChildBase::ReleaseIPDLReference()
 {
   MOZ_ASSERT(mIPCOpen);
   mIPCOpen = false;
+  mSocket = nullptr;
   this->Release();
 }
 
 void
 UDPSocketChildBase::AddIPDLReference()
 {
   MOZ_ASSERT(!mIPCOpen);
   mIPCOpen = true;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -238,16 +238,24 @@ static bool UnloadPluginsASAP()
 {
   return (Preferences::GetUint(kPrefUnloadPluginTimeoutSecs, kDefaultPluginUnloadingTimeout) == 0);
 }
 
 nsPluginHost::nsPluginHost()
   // No need to initialize members to nullptr, false etc because this class
   // has a zeroing operator new.
 {
+  // Bump the pluginchanged epoch on startup. This insures content gets a
+  // good plugin list the first time it requests it. Normally we'd just
+  // init this to 1, but due to the unique nature of our ctor we need to do
+  // this manually.
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    IncrementChromeEpoch();
+  }
+
   // check to see if pref is set at startup to let plugins take over in
   // full page mode for certain image mime types that we handle internally
   mOverrideInternalTypes =
     Preferences::GetBool("plugin.override_internal_types", false);
 
   mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
   mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
 
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -687,33 +687,16 @@ MessageChannel::Send(Message* aMsg, Mess
 
     if (!SendAndWait(aMsg, aReply))
         return false;
 
     NS_ABORT_IF_FALSE(aReply->is_sync(), "reply is not sync");
     return true;
 }
 
-struct AutoDeferMessages
-{
-    typedef IPC::Message Message;
-
-    std::deque<Message>& mQueue;
-    mozilla::Vector<Message> mDeferred;
-
-    AutoDeferMessages(std::deque<Message>& queue) : mQueue(queue) {}
-    ~AutoDeferMessages() {
-        mQueue.insert(mQueue.begin(), mDeferred.begin(), mDeferred.end());
-    }
-
-    void Defer(Message aMsg) {
-        mDeferred.append(aMsg);
-    }
-};
-
 bool
 MessageChannel::SendAndWait(Message* aMsg, Message* aReply)
 {
     mMonitor->AssertCurrentThreadOwns();
 
     nsAutoPtr<Message> msg(aMsg);
 
     if (!Connected()) {
@@ -723,26 +706,38 @@ MessageChannel::SendAndWait(Message* aMs
 
     msg->set_seqno(NextSeqno());
 
     DebugOnly<int32_t> replySeqno = msg->seqno();
     DebugOnly<msgid_t> replyType = msg->type() + 1;
 
     mLink->SendMessage(msg.forget());
 
-    AutoDeferMessages defer(mPending);
+    while (true) {
+        // Loop until there aren't any more priority messages to process.
+        for (;;) {
+            mozilla::Vector<Message> toProcess;
 
-    while (true) {
-        while (!mPending.empty()) {
-            Message msg = mPending.front();
-            mPending.pop_front();
-            if (ShouldDeferMessage(msg))
-                defer.Defer(msg);
-            else
-                ProcessPendingRequest(msg);
+            for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
+                Message &msg = *it;
+                if (!ShouldDeferMessage(msg)) {
+                    toProcess.append(msg);
+                    it = mPending.erase(it);
+                    continue;
+                }
+                it++;
+            }
+
+            if (toProcess.empty())
+                break;
+
+            // Processing these messages could result in more messages, so we
+            // loop around to check for more afterwards.
+            for (auto it = toProcess.begin(); it != toProcess.end(); it++)
+                ProcessPendingRequest(*it);
         }
 
         // See if we've received a reply.
         if (mRecvd) {
             MOZ_ASSERT(mRecvd->is_reply(), "expected reply");
 
             if (mRecvd->is_reply_error()) {
                 mRecvd = nullptr;
@@ -855,17 +850,17 @@ MessageChannel::Call(Message* aMsg, Mess
             // won't break the inner while loop again until something new
             // happens.
             continue;
         }
 
         // If the message is not Interrupt, we can dispatch it as normal.
         if (!recvd.is_interrupt()) {
             {
-                AutoEnterTransaction transaction(this, &recvd);
+                AutoEnterTransaction transaction(this, recvd);
                 MonitorAutoUnlock unlock(*mMonitor);
                 CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
                 DispatchMessage(recvd);
             }
             if (!Connected()) {
                 ReportConnectionError("MessageChannel::DispatchMessage");
                 return false;
             }
@@ -942,17 +937,17 @@ MessageChannel::InterruptEventOccurred()
     return (!Connected() ||
             !mPending.empty() ||
             (!mOutOfTurnReplies.empty() &&
              mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
              mOutOfTurnReplies.end()));
 }
 
 bool
-MessageChannel::ProcessPendingRequest(Message aUrgent)
+MessageChannel::ProcessPendingRequest(const Message &aUrgent)
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
     // Note that it is possible we could have sent a sync message at
     // the same time the parent process sent an urgent message, and
     // therefore mPendingUrgentRequest is set *and* mRecvd is set as
     // well, because the link thread received both before the worker
@@ -960,17 +955,17 @@ MessageChannel::ProcessPendingRequest(Me
     //
     // In this case, we process the urgent message first, but we need
     // to save the reply.
     nsAutoPtr<Message> savedReply(mRecvd.forget());
 
     {
         // In order to send the parent RPC messages and guarantee it will
         // wake up, we must re-use its transaction.
-        AutoEnterTransaction transaction(this, &aUrgent);
+        AutoEnterTransaction transaction(this, aUrgent);
 
         MonitorAutoUnlock unlock(*mMonitor);
         DispatchMessage(aUrgent);
     }
     if (!Connected()) {
         ReportConnectionError("MessageChannel::ProcessPendingRequest");
         return false;
     }
@@ -1024,17 +1019,17 @@ MessageChannel::OnMaybeDequeueOne()
         // Interrupt call sent before entering that loop.
         mOutOfTurnReplies[recvd.seqno()] = recvd;
         return false;
     }
 
     {
         // We should not be in a transaction yet if we're not blocked.
         MOZ_ASSERT(mCurrentTransaction == 0);
-        AutoEnterTransaction transaction(this, &recvd);
+        AutoEnterTransaction transaction(this, recvd);
 
         MonitorAutoUnlock unlock(*mMonitor);
 
         CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
         DispatchMessage(recvd);
     }
     return true;
 }
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -40,17 +40,16 @@ class RefCountedMonitor : public Monitor
   private:
     ~RefCountedMonitor() {}
 };
 
 class MessageChannel : HasResultCodes
 {
     friend class ProcessLink;
     friend class ThreadLink;
-    friend class AutoEnterRPCTransaction;
 
     class CxxStackFrame;
     class InterruptFrame;
 
     typedef mozilla::Monitor Monitor;
 
   public:
     static const int32_t kNoTimeout;
@@ -223,17 +222,17 @@ class MessageChannel : HasResultCodes
     // soon as a reply has been received, or an error has occurred.
     //
     // Note that while the child is blocked waiting for a sync reply, it can wake
     // up to process urgent calls from the parent.
     bool SendAndWait(Message* aMsg, Message* aReply);
 
     bool InterruptEventOccurred();
 
-    bool ProcessPendingRequest(Message aUrgent);
+    bool ProcessPendingRequest(const Message &aUrgent);
 
     void MaybeUndeferIncall();
     void EnqueuePendingMessages();
 
     // Executed on the worker thread. Dequeues one pending message.
     bool OnMaybeDequeueOne();
     bool DequeueOne(Message *recvd);
 
@@ -505,28 +504,28 @@ class MessageChannel : HasResultCodes
        explicit AutoEnterTransaction(MessageChannel *aChan)
         : mChan(aChan),
           mOldTransaction(mChan->mCurrentTransaction)
        {
            mChan->mMonitor->AssertCurrentThreadOwns();
            if (mChan->mCurrentTransaction == 0)
                mChan->mCurrentTransaction = mChan->NextSeqno();
        }
-       explicit AutoEnterTransaction(MessageChannel *aChan, Message *message)
+       explicit AutoEnterTransaction(MessageChannel *aChan, const Message &aMessage)
         : mChan(aChan),
           mOldTransaction(mChan->mCurrentTransaction)
        {
            mChan->mMonitor->AssertCurrentThreadOwns();
 
-           if (!message->is_sync())
+           if (!aMessage.is_sync())
                return;
 
-           MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != message->transaction_id(),
-                         !mOldTransaction || message->priority() > mChan->AwaitingSyncReplyPriority());
-           mChan->mCurrentTransaction = message->transaction_id();
+           MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != aMessage.transaction_id(),
+                         !mOldTransaction || aMessage.priority() > mChan->AwaitingSyncReplyPriority());
+           mChan->mCurrentTransaction = aMessage.transaction_id();
        }
        ~AutoEnterTransaction() {
            mChan->mMonitor->AssertCurrentThreadOwns();
            mChan->mCurrentTransaction = mOldTransaction;
        }
 
       private:
        MessageChannel *mChan;
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -673,17 +673,17 @@ function ArrayFrom(arrayLike, mapfn=unde
     var mapping = (mapfn !== undefined);
     if (mapping && !IsCallable(mapfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
 
     // All elements defined by this algorithm have the same attrs:
     var attrs = ATTR_CONFIGURABLE | ATTR_ENUMERABLE | ATTR_WRITABLE;
 
     // Steps 6-8.
-    var usingIterator = items["@@iterator"];
+    var usingIterator = items[std_iterator];
     if (usingIterator !== undefined) {
         // Steps 8.a-c.
         var A = IsConstructor(C) ? new C() : [];
 
         // Steps 8.d-e.
         var iterator = callFunction(usingIterator, items);
 
         // Step 8.f.
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -873,17 +873,17 @@ const Class MapIteratorObject::class_ = 
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     MapIteratorObject::finalize
 };
 
 const JSFunctionSpec MapIteratorObject::methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
 
 inline ValueMap::Range *
 MapIteratorObject::range()
 {
     return static_cast<ValueMap::Range *>(getSlot(RangeSlot).toPrivate());
@@ -1071,18 +1071,24 @@ MapObject::initClass(JSContext *cx, JSOb
     if (proto) {
         // Define the "entries" method.
         JSFunction *fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
         if (!fun)
             return nullptr;
 
         // Define its alias.
         RootedValue funval(cx, ObjectValue(*fun));
+#if JS_HAS_SYMBOLS
+        RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+        if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
+            return nullptr;
+#else
         if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
             return nullptr;
+#endif
     }
     return proto;
 }
 
 template <class Range>
 static void
 MarkKey(Range &r, const HashableValue &key, JSTracer *trc)
 {
@@ -1523,17 +1529,17 @@ const Class SetIteratorObject::class_ = 
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     SetIteratorObject::finalize
 };
 
 const JSFunctionSpec SetIteratorObject::methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
 
 inline ValueSet::Range *
 SetIteratorObject::range()
 {
     return static_cast<ValueSet::Range *>(getSlot(RangeSlot).toPrivate());
@@ -1697,18 +1703,25 @@ SetObject::initClass(JSContext *cx, JSOb
         JSFunction *fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
         if (!fun)
             return nullptr;
 
         // Define its aliases.
         RootedValue funval(cx, ObjectValue(*fun));
         if (!JS_DefineProperty(cx, proto, "keys", funval, 0))
             return nullptr;
+
+#if JS_HAS_SYMBOLS
+        RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+        if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
+            return nullptr;
+#else
         if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
             return nullptr;
+#endif
     }
     return proto;
 }
 
 
 bool
 SetObject::keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys)
 {
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -26,17 +26,16 @@
 #include "SelfHostingDefines.h"
 
 // All C++-implemented standard builtins library functions used in self-hosted
 // code are installed via the std_functions JSFunctionSpec[] in
 // SelfHosting.cpp.
 //
 // The few items below here are either self-hosted or installing them under a
 // std_Foo name would require ugly contortions, so they just get aliased here.
-var std_iterator = '@@iterator'; // FIXME: Change to be a symbol.
 var std_Array_indexOf = ArrayIndexOf;
 // WeakMap is a bare constructor without properties or methods.
 var std_WeakMap = WeakMap;
 // StopIteration is a bare constructor without properties or methods.
 var std_StopIteration = StopIteration;
 
 
 /********** List specification type **********/
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2483,21 +2483,16 @@ EmitElemOperands(ExclusiveContext *cx, P
 }
 
 static inline bool
 EmitElemOpBase(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
 {
     if (Emit1(cx, bce, op) < 0)
         return false;
     CheckTypeSet(cx, bce, op);
-
-    if (op == JSOP_CALLELEM) {
-        if (Emit1(cx, bce, JSOP_SWAP) < 0)
-            return false;
-    }
     return true;
 }
 
 static bool
 EmitElemOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
 {
     return EmitElemOperands(cx, pn, op, bce) && EmitElemOpBase(cx, bce, op);
 }
@@ -4725,19 +4720,26 @@ EmitWith(ExclusiveContext *cx, BytecodeE
  * It will replace that stack value with the corresponding iterator
  */
 static bool
 EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
 {
     // Convert iterable to iterator.
     if (Emit1(cx, bce, JSOP_DUP) < 0)                          // OBJ OBJ
         return false;
-    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ @@ITERATOR
-        return false;
-    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
+#ifdef JS_HAS_SYMBOLS
+    if (Emit2(cx, bce, JSOP_SYMBOL, jsbytecode(JS::SymbolCode::iterator)) < 0) // OBJ OBJ @@ITERATOR
+        return false;
+    if (!EmitElemOpBase(cx, bce, JSOP_CALLELEM))               // OBJ ITERFN
+        return false;
+#else
+    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce))  // OBJ ITERFN
+        return false;
+#endif
+    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // ITERFN OBJ
         return false;
     if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
     return true;
 }
 
 static bool
@@ -5593,27 +5595,18 @@ EmitYield(ExclusiveContext *cx, Bytecode
 static bool
 EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, ParseNode *gen)
 {
     MOZ_ASSERT(bce->sc->isFunctionBox());
     MOZ_ASSERT(bce->sc->asFunctionBox()->isStarGenerator());
 
     if (!EmitTree(cx, bce, iter))                                // ITERABLE
         return false;
-
-    // Convert iterable to iterator.
-    if (Emit1(cx, bce, JSOP_DUP) < 0)                            // ITERABLE ITERABLE
-        return false;
-    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // ITERABLE @@ITERATOR
-        return false;
-    if (Emit1(cx, bce, JSOP_SWAP) < 0)                           // @@ITERATOR ITERABLE
-        return false;
-    if (EmitCall(cx, bce, JSOP_CALL, 0, iter) < 0)               // ITER
-        return false;
-    CheckTypeSet(cx, bce, JSOP_CALL);
+    if (!EmitIterator(cx, bce))                                  // ITER
+        return false;
 
     // Initial send value is undefined.
     if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                      // ITER RECEIVED
         return false;
 
     int depth = bce->stackDepth;
     MOZ_ASSERT(depth >= 2);
 
@@ -6047,16 +6040,20 @@ EmitCallOrNew(ExclusiveContext *cx, Byte
         break;
       case PNK_DOT:
         if (!EmitPropOp(cx, pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP, bce))
             return false;
         break;
       case PNK_ELEM:
         if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, bce))
             return false;
+        if (callop) {
+            if (Emit1(cx, bce, JSOP_SWAP) < 0)
+                return false;
+        }
         break;
       case PNK_FUNCTION:
         /*
          * Top level lambdas which are immediately invoked should be
          * treated as only running once. Every time they execute we will
          * create new types and scripts for their contents, to increase
          * the quality of type information within them and enable more
          * backend optimizations. Note that this does not depend on the
--- a/js/src/jit-test/lib/iteration.js
+++ b/js/src/jit-test/lib/iteration.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 load(libdir + "asserts.js");
 
-// FIXME: Import from std::iteration.
-const std_iterator = '@@iterator';
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : '@@iterator';
 
 if (typeof assertIteratorResult === 'undefined') {
     var assertIteratorResult = function assertIteratorResult(result, value, done) {
         assertEq(typeof result, "object");
         var expectedProps = ['done', 'value'];
         var actualProps = Object.getOwnPropertyNames(result);
         actualProps.sort(), expectedProps.sort();
         assertDeepEq(actualProps, expectedProps);
--- a/js/src/jit-test/tests/arguments/destructuring-exprbody.js
+++ b/js/src/jit-test/tests/arguments/destructuring-exprbody.js
@@ -1,7 +1,8 @@
 // See bug 763313
+load(libdir + "iteration.js");
 function f([a]) a
 var i = 0;
-var o = {'@@iterator': function () { i++; return {
+var o = {[std_iterator]: function () { i++; return {
   next: function () { i++; return {value: 42, done: false}; }}}};
 assertEq(f(o), 42);
 assertEq(i, 2);
--- a/js/src/jit-test/tests/basic/expression-autopsy.js
+++ b/js/src/jit-test/tests/basic/expression-autopsy.js
@@ -1,9 +1,10 @@
 load(libdir + "asserts.js");
+load(libdir + "iteration.js");
 
 function check_one(expected, f, err) {
     var failed = true;
     try {
         f();
         failed = false;
     } catch (ex) {
         var s = ex.toString();
@@ -104,13 +105,16 @@ for (let tok of ["|", "^", "&", "==", "!
 check("o[!(o)]");
 check("o[~(o)]");
 check("o[+ (o)]");
 check("o[- (o)]");
 
 // A few one off tests
 check_one("6", (function () { 6() }), " is not a function");
 check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
-check_one("(intermediate value)['@@iterator'](...).next(...).value", function () { var [{ x }] = [null, {}]; }, " is null");
-check_one("(intermediate value)['@@iterator'](...).next(...).value", function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
+var ITERATOR = JS_HAS_SYMBOLS ? "Symbol.iterator" : "'@@iterator'";
+check_one(`(intermediate value)[${ITERATOR}](...).next(...).value`,
+          function () { var [{ x }] = [null, {}]; }, " is null");
+check_one(`(intermediate value)[${ITERATOR}](...).next(...).value`,
+          function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
 
 // Check fallback behavior
 assertThrowsInstanceOf(function () { for (let x of undefined) {} }, TypeError);
--- a/js/src/jit-test/tests/collections/WeakSet-error.js
+++ b/js/src/jit-test/tests/collections/WeakSet-error.js
@@ -1,21 +1,22 @@
 load(libdir + "asserts.js");
+load(libdir + "iteration.js");
 
 function testMethod(name) {
     var method = WeakSet.prototype[name];
 
     assertThrowsInstanceOf(function() { method.call(1); }, TypeError);
     assertThrowsInstanceOf(function() { method.call({}); }, TypeError);
     assertThrowsInstanceOf(function() { method.call(new WeakMap); }, TypeError);
     assertThrowsInstanceOf(function() { method.call(WeakSet.prototype); }, TypeError);
 }
 
 testMethod("has");
 testMethod("add");
 testMethod("delete");
 testMethod("clear");
 
 assertThrowsInstanceOf(function() { var ws = new WeakSet(); ws.add(1); }, TypeError);
-assertThrowsInstanceOf(function() { new WeakSet({"@@iterator": 2}) }, TypeError);
-assertEq(typeof []["@@iterator"], "function"); // Make sure we fail when @@iterator is removed
+assertThrowsInstanceOf(function() { new WeakSet({[std_iterator]: 2}) }, TypeError);
+assertEq(typeof [][std_iterator], "function");
 
 assertThrowsInstanceOf(function() { WeakSet(); }, TypeError);
--- a/js/src/jit-test/tests/collections/iterator-proto-surfaces.js
+++ b/js/src/jit-test/tests/collections/iterator-proto-surfaces.js
@@ -2,17 +2,18 @@
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 function test(constructor) {
     var proto = Object.getPrototypeOf(constructor()[std_iterator]());
     var names = Object.getOwnPropertyNames(proto);
     names.sort();
-    assertDeepEq(names, [std_iterator, 'next']);
+    assertDeepEq(names, JS_HAS_SYMBOLS ? ['next'] : ['@@iterator', 'next']);
+    assertEq(proto.hasOwnProperty(std_iterator), true);
 
     var desc = Object.getOwnPropertyDescriptor(proto, 'next');
     assertEq(desc.configurable, true);
     assertEq(desc.enumerable, false);
     assertEq(desc.writable, true);
 
     assertEq(proto[std_iterator](), proto);
     assertIteratorDone(proto, undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/array-jit.js
@@ -0,0 +1,6 @@
+var arr = [1, 2, 3];
+var y = 0;
+for (var i = 0; i < 10; i++)
+    for (var x of arr)
+        y += x;
+assertEq(y, 60);
--- a/js/src/jit-test/tests/for-of/next-3.js
+++ b/js/src/jit-test/tests/for-of/next-3.js
@@ -3,11 +3,11 @@
 // compartment's .next method.
 
 // FIXME: 'next' should work cross-realm.  Bug 924059.
 
 load(libdir + "asserts.js");
 load(libdir + "iteration.js");
 
 var g = newGlobal();
-g.eval("var it = [1, 2]['" + std_iterator + "']();");
+g.eval(`var it = [1, 2][${uneval(std_iterator)}]();`);
 assertIteratorNext(g.it, 1);
 assertThrowsInstanceOf([][std_iterator]().next.bind(g.it), TypeError)
--- a/js/src/jit-test/tests/for-of/semantics-08.js
+++ b/js/src/jit-test/tests/for-of/semantics-08.js
@@ -1,9 +1,12 @@
 // Results from another compartment are correctly interpreted by for-of.
 
 load(libdir + "iteration.js");
 
 var g = newGlobal();
-var it = g.eval("({ '" + std_iterator + "': function () { return this; }, " +
-                "next: function () { return { done: true } } });");
-for (x of it)
+g.eval(`
+    var obj = {};
+    obj[${uneval(std_iterator)}] = function () { return this; };
+    obj.next = function () { return { done: true }; };
+`);
+for (x of g.obj)
     throw 'FAIL';
--- a/js/src/jit-test/tests/for-of/string-iterator-surfaces.js
+++ b/js/src/jit-test/tests/for-of/string-iterator-surfaces.js
@@ -52,17 +52,19 @@ assertBuiltinFunction(String.prototype, 
 // Test StringIterator.prototype surface
 var iter = ""[std_iterator]();
 var iterProto = Object.getPrototypeOf(iter);
 
 // StringIterator.prototype inherits from Object.prototype
 assertEq(Object.getPrototypeOf(iterProto), Object.prototype);
 
 // Own properties for StringIterator.prototype: "next" and @@iterator
-arraysEqual(Object.getOwnPropertyNames(iterProto).sort(), ["next", std_iterator].sort());
+arraysEqual(Object.getOwnPropertyNames(iterProto).sort(),
+            JS_HAS_SYMBOLS ? ["next"] : ["@@iterator", "next"]);
+assertEq(iterProto.hasOwnProperty(std_iterator), true);
 
 // StringIterator.prototype[@@iterator] is a built-in function
 assertBuiltinFunction(iterProto, std_iterator, 0);
 
 // StringIterator.prototype.next is a built-in function
 assertBuiltinFunction(iterProto, "next", 0);
 
 // StringIterator.prototype[@@iterator] is generic and returns |this|
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/symbol/toNumber-2.js
@@ -0,0 +1,14 @@
+// |jit-test| error: ReferenceError
+function eq(e, a) {
+    passed = (a == e);
+}
+function f(e, a) {
+    fail();
+    eq(e, a);
+}
+try {
+    f();
+} catch (exc1) {}
+eq(.1, .1);
+var sym = Symbol("method");
+evaluate("f(test, sym, 0)", {compileAndGo: true});
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1254,16 +1254,25 @@ BaselineCompiler::emit_JSOP_DOUBLE()
 
 bool
 BaselineCompiler::emit_JSOP_STRING()
 {
     frame.push(StringValue(script->getAtom(pc)));
     return true;
 }
 
+bool
+BaselineCompiler::emit_JSOP_SYMBOL()
+{
+    unsigned which = GET_UINT8(pc);
+    JS::Symbol *sym = cx->runtime()->wellKnownSymbols->get(which);
+    frame.push(SymbolValue(sym));
+    return true;
+}
+
 typedef NativeObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleNativeObject, NewObjectKind);
 static const VMFunction DeepCloneObjectLiteralInfo =
     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
 
 bool
 BaselineCompiler::emit_JSOP_OBJECT()
 {
     if (JS::CompartmentOptionsRef(cx).cloneSingletons()) {
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -56,16 +56,17 @@ namespace jit {
     _(JSOP_ZERO)               \
     _(JSOP_ONE)                \
     _(JSOP_INT8)               \
     _(JSOP_INT32)              \
     _(JSOP_UINT16)             \
     _(JSOP_UINT24)             \
     _(JSOP_DOUBLE)             \
     _(JSOP_STRING)             \
+    _(JSOP_SYMBOL)             \
     _(JSOP_OBJECT)             \
     _(JSOP_CALLSITEOBJ)        \
     _(JSOP_REGEXP)             \
     _(JSOP_LAMBDA)             \
     _(JSOP_LAMBDA_ARROW)       \
     _(JSOP_BITOR)              \
     _(JSOP_BITXOR)             \
     _(JSOP_BITAND)             \
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3412,18 +3412,18 @@ IsCacheableGetPropReadSlot(JSObject *obj
 
     if (!shape->hasSlot() || !shape->hasDefaultGetter())
         return false;
 
     return true;
 }
 
 static bool
-IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted,
-                       bool isDOMProxy=false)
+IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape,
+                       bool *isScripted, bool *isTemporarilyUnoptimizable, bool isDOMProxy=false)
 {
     MOZ_ASSERT(isScripted);
 
     if (!shape || !IsCacheableProtoChain(obj, holder, isDOMProxy))
         return false;
 
     if (shape->hasSlot() || shape->hasDefaultGetter())
         return false;
@@ -3434,27 +3434,31 @@ IsCacheableGetPropCall(JSContext *cx, JS
     if (!shape->getterValue().isObject() || !shape->getterObject()->is<JSFunction>())
         return false;
 
     JSFunction *func = &shape->getterObject()->as<JSFunction>();
 
 #ifdef JSGC_GENERATIONAL
     // Information from get prop call ICs may be used directly from Ion code,
     // and should not be nursery allocated.
-    if (IsInsideNursery(holder) || IsInsideNursery(func))
-        return false;
+    if (IsInsideNursery(holder) || IsInsideNursery(func)) {
+        *isTemporarilyUnoptimizable = true;
+        return false;
+    }
 #endif
 
     if (func->isNative()) {
         *isScripted = false;
         return true;
     }
 
-    if (!func->hasJITCode())
-        return false;
+    if (!func->hasJITCode()) {
+        *isTemporarilyUnoptimizable = true;
+        return false;
+    }
 
     *isScripted = true;
     return true;
 }
 
 static bool
 IsCacheableSetPropWriteSlot(JSObject *obj, Shape *oldShape, JSObject *holder, Shape *shape)
 {
@@ -3528,17 +3532,18 @@ IsCacheableSetPropAddSlot(JSContext *cx,
     if (obj->as<NativeObject>().numDynamicSlots() != oldSlots)
         return false;
 
     *protoChainDepth = chainDepth;
     return true;
 }
 
 static bool
-IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, Shape* oldShape, bool *isScripted)
+IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape,
+                       Shape* oldShape, bool *isScripted, bool *isTemporarilyUnoptimizable)
 {
     MOZ_ASSERT(isScripted);
 
     // Currently we only optimize setter calls for setters bound on prototypes.
     if (obj == holder)
         return false;
 
     if (obj->lastProperty() != oldShape) {
@@ -3560,27 +3565,31 @@ IsCacheableSetPropCall(JSContext *cx, JS
     if (!shape->setterValue().isObject() || !shape->setterObject()->is<JSFunction>())
         return false;
 
     JSFunction *func = &shape->setterObject()->as<JSFunction>();
 
 #ifdef JSGC_GENERATIONAL
     // Information from set prop call ICs may be used directly from Ion code,
     // and should not be nursery allocated.
-    if (IsInsideNursery(holder) || IsInsideNursery(func))
-        return false;
+    if (IsInsideNursery(holder) || IsInsideNursery(func)) {
+        *isTemporarilyUnoptimizable = true;
+        return false;
+    }
 #endif
 
     if (func->isNative()) {
         *isScripted = false;
         return true;
     }
 
-    if (!func->hasJITCode())
-        return false;
+    if (!func->hasJITCode()) {
+        *isTemporarilyUnoptimizable = true;
+        return false;
+    }
 
     *isScripted = true;
     return true;
 }
 
 static bool
 LookupNoSuchMethodHandler(JSContext *cx, HandleObject obj, HandleValue id,
                           MutableHandleValue result)
@@ -3812,17 +3821,19 @@ static bool TryAttachNativeGetElemStub(J
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         return true;
     }
 
     bool getterIsScripted = false;
-    if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
+    bool isTemporarilyUnoptimizable = false;
+    if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted,
+                               &isTemporarilyUnoptimizable, /*isDOMProxy=*/false)) {
         RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
 
 #if JS_HAS_NO_SUCH_METHOD
         // It's unlikely that a getter function will be used in callelem locations.
         // Just don't attach stubs in that case to avoid issues with __noSuchMethod__ handling.
         if (isCallElem)
             return true;
 #endif
@@ -4058,16 +4069,19 @@ DoGetElemFallback(JSContext *cx, Baselin
         // But for now we just bail.
         return true;
     }
 
     // Try to attach an optimized stub.
     if (!TryAttachGetElemStub(cx, frame->script(), pc, stub, lhs, rhs, res))
         return false;
 
+    // If we ever add a way to note unoptimizable accesses here, propagate the
+    // isTemporarilyUnoptimizable state from TryAttachNativeGetElemStub to here.
+
     return true;
 }
 
 typedef bool (*DoGetElemFallbackFn)(JSContext *, BaselineFrame *, ICGetElem_Fallback *,
                                     HandleValue, HandleValue, MutableHandleValue);
 static const VMFunction DoGetElemFallbackInfo =
     FunctionInfo<DoGetElemFallbackFn>(DoGetElemFallback, PopValues(2));
 
@@ -5835,17 +5849,19 @@ TryAttachGlobalNameStub(JSContext *cx, H
         stub->addNewStub(newStub);
         return true;
     }
 
     // Try to add a getter stub. We don't handle scripted getters yet; if this
     // changes we need to make sure IonBuilder::getPropTryCommonGetter (which
     // requires a Baseline stub) handles non-outerized this objects correctly.
     bool isScripted;
-    if (IsCacheableGetPropCall(cx, global, current, shape, &isScripted) && !isScripted)
+    bool isTemporarilyUnoptimizable = false;
+    if (IsCacheableGetPropCall(cx, global, current, shape, &isScripted, &isTemporarilyUnoptimizable) &&
+        !isScripted)
     {
         ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
         RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
         ICStub *newStub;
         if (current == global) {
             JitSpew(JitSpew_BaselineIC, "  Generating GetName(GlobalName/NativeGetter) stub");
             if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNative,
                                                global, JS::NullPtr(), getter)) {
@@ -6015,16 +6031,19 @@ DoGetNameFallback(JSContext *cx, Baselin
     if (js_CodeSpec[*pc].format & JOF_GNAME) {
         if (!TryAttachGlobalNameStub(cx, script, pc, stub, scopeChain.as<GlobalObject>(), name))
             return false;
     } else {
         if (!TryAttachScopeNameStub(cx, script, stub, scopeChain, name))
             return false;
     }
 
+    // If we ever add a way to note unoptimizable accesses here, propagate the
+    // isTemporarilyUnoptimizable state from TryAttachGlobalNameStub to here.
+
     return true;
 }
 
 typedef bool (*DoGetNameFallbackFn)(JSContext *, BaselineFrame *, ICGetName_Fallback *,
                                     HandleObject, MutableHandleValue);
 static const VMFunction DoGetNameFallbackInfo = FunctionInfo<DoGetNameFallbackFn>(DoGetNameFallback);
 
 bool
@@ -6391,19 +6410,21 @@ StripPreliminaryObjectStubs(JSContext *c
             iter.unlink(cx);
     }
 }
 
 static bool
 TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
                            ICGetProp_Fallback *stub, HandlePropertyName name,
                            HandleValue val, HandleShape oldShape,
-                           HandleValue res, bool *attached)
+                           HandleValue res, bool *attached,
+                           bool *isTemporarilyUnoptimizable)
 {
     MOZ_ASSERT(!*attached);
+    MOZ_ASSERT(!*isTemporarilyUnoptimizable);
 
     if (!val.isObject())
         return true;
 
     RootedObject obj(cx, &val.toObject());
 
     if (oldShape != obj->lastProperty()) {
         // No point attaching anything, since we know the shape guard will fail
@@ -6454,17 +6475,18 @@ TryAttachNativeGetPropStub(JSContext *cx
             StripPreliminaryObjectStubs(cx, stub);
 
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
-    bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted, isDOMProxy);
+    bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted,
+                                                isTemporarilyUnoptimizable, isDOMProxy);
 
     // Try handling scripted getters.
     if (cacheableCall && isScripted && !isDOMProxy) {
 #if JS_HAS_NO_SUCH_METHOD
         // It's hard to keep the original object alive through a call, and it's unlikely
         // that a getter will be used to generate functions for calling in CALLPROP locations.
         // Just don't attach stubs in that case.
         if (isCallProp)
@@ -6761,33 +6783,38 @@ DoGetPropFallback(JSContext *cx, Baselin
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         return true;
     }
 
     bool attached = false;
+    // There are some reasons we can fail to attach a stub that are temporary.
+    // We want to avoid calling noteUnoptimizableAccess() if the reason we
+    // failed to attach a stub is one of those temporary reasons, since we might
+    // end up attaching a stub for the exact same access later.
+    bool isTemporarilyUnoptimizable = false;
 
     if (op == JSOP_LENGTH) {
         if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
             return false;
         if (attached)
             return true;
     }
 
     if (!TryAttachMagicArgumentsGetPropStub(cx, frame->script(), stub, name, val, res, &attached))
         return false;
     if (attached)
         return true;
 
     RootedScript script(cx, frame->script());
 
     if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, oldShape,
-                                    res, &attached))
+                                    res, &attached, &isTemporarilyUnoptimizable))
         return false;
     if (attached)
         return true;
 
     if (val.isString() || val.isNumber() || val.isBoolean()) {
         if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
             return false;
         if (attached)
@@ -6798,17 +6825,18 @@ DoGetPropFallback(JSContext *cx, Baselin
         // Try attaching property-not-found optimized stub for undefined results.
         if (!TryAttachNativeDoesNotExistStub(cx, script, pc, stub, name, val, &attached))
             return false;
         if (attached)
             return true;
     }
 
     MOZ_ASSERT(!attached);
-    stub->noteUnoptimizableAccess();
+    if (!isTemporarilyUnoptimizable)
+        stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoGetPropFallbackFn)(JSContext *, BaselineFrame *, ICGetProp_Fallback *,
                                     MutableHandleValue, MutableHandleValue);
 static const VMFunction DoGetPropFallbackInfo =
     FunctionInfo<DoGetPropFallbackFn>(DoGetPropFallback, PopValues(1));
@@ -7694,19 +7722,21 @@ BaselineScript::noteAccessedGetter(uint3
 //
 // SetProp_Fallback
 //
 
 // Attach an optimized stub for a SETPROP/SETGNAME/SETNAME op.
 static bool
 TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetProp_Fallback *stub,
                      HandleObject obj, HandleShape oldShape, HandleTypeObject oldType, uint32_t oldSlots,
-                     HandlePropertyName name, HandleId id, HandleValue rhs, bool *attached)
+                     HandlePropertyName name, HandleId id, HandleValue rhs, bool *attached,
+                     bool *isTemporarilyUnoptimizable)
 {
     MOZ_ASSERT(!*attached);
+    MOZ_ASSERT(!*isTemporarilyUnoptimizable);
 
     if (!obj->isNative() || obj->watched())
         return true;
 
     RootedShape shape(cx);
     RootedObject holder(cx);
     if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape))
         return false;
@@ -7775,17 +7805,18 @@ TryAttachSetPropStub(JSContext *cx, Hand
             StripPreliminaryObjectStubs(cx, stub);
 
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
-    bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, oldShape, &isScripted);
+    bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, oldShape,
+                                                &isScripted, isTemporarilyUnoptimizable);
 
     // Try handling scripted setters.
     if (cacheableCall && isScripted) {
         RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
         MOZ_ASSERT(obj != holder);
         MOZ_ASSERT(callee->hasScript());
 
         if (UpdateExistingSetPropCallStubs(stub, ICStub::SetProp_CallScripted,
@@ -7901,26 +7932,32 @@ DoSetPropFallback(JSContext *cx, Baselin
         return true;
 
     if (stub->numOptimizedStubs() >= ICSetProp_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with generic setprop stub.
         return true;
     }
 
     bool attached = false;
+    // There are some reasons we can fail to attach a stub that are temporary.
+    // We want to avoid calling noteUnoptimizableAccess() if the reason we
+    // failed to attach a stub is one of those temporary reasons, since we might
+    // end up attaching a stub for the exact same access later.
+    bool isTemporarilyUnoptimizable = false;
     if (!TryAttachSetPropStub(cx, script, pc, stub, obj, oldShape, oldType, oldSlots,
-                              name, id, rhs, &attached))
+                              name, id, rhs, &attached, &isTemporarilyUnoptimizable))
     {
         return false;
     }
     if (attached)
         return true;
 
     MOZ_ASSERT(!attached);
-    stub->noteUnoptimizableAccess();
+    if (!isTemporarilyUnoptimizable)
+        stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoSetPropFallbackFn)(JSContext *, BaselineFrame *, ICSetProp_Fallback *,
                                     HandleValue, HandleValue, MutableHandleValue);
 static const VMFunction DoSetPropFallbackInfo =
     FunctionInfo<DoSetPropFallbackFn>(DoSetPropFallback, PopValues(2));
--- a/js/src/jsapi-tests/testForOfIterator.cpp
+++ b/js/src/jsapi-tests/testForOfIterator.cpp
@@ -3,46 +3,42 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 
 #ifdef JS_HAS_SYMBOLS
-#define IF_JS_HAS_SYMBOLS(x) x
+#define STD_ITERATOR "Symbol.iterator"
 #else
-#define IF_JS_HAS_SYMBOLS(x)
+#define STD_ITERATOR "'@@iterator'"
 #endif
 
 BEGIN_TEST(testForOfIterator_basicNonIterable)
 {
     JS::RootedValue v(cx);
     // Hack to make it simple to produce an object that has a property
     // named Symbol.iterator.
-    EVAL("var obj = {'@@iterator': 5"
-         IF_JS_HAS_SYMBOLS(", [Symbol.iterator]: Array.prototype[Symbol.iterator]")
-         "}; obj;", &v);
+    EVAL("({[" STD_ITERATOR "]: 5})", &v);
     JS::ForOfIterator iter(cx);
     bool ok = iter.init(v);
     CHECK(!ok);
     JS_ClearPendingException(cx);
     return true;
 }
 END_TEST(testForOfIterator_basicNonIterable)
 
 BEGIN_TEST(testForOfIterator_bug515273_part1)
 {
     JS::RootedValue v(cx);
 
     // Hack to make it simple to produce an object that has a property
     // named Symbol.iterator.
-    EVAL("var obj = {'@@iterator': 5"
-         IF_JS_HAS_SYMBOLS(", [Symbol.iterator]: Array.prototype[Symbol.iterator]")
-         "}; obj;", &v);
+    EVAL("({[" STD_ITERATOR "]: 5})", &v);
 
     JS::ForOfIterator iter(cx);
     bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
     CHECK(!ok);
     JS_ClearPendingException(cx);
     return true;
 }
 END_TEST(testForOfIterator_bug515273_part1)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5587,17 +5587,17 @@ JS_PUBLIC_API(JS::SymbolCode)
 JS::GetSymbolCode(Handle<Symbol*> symbol)
 {
     return symbol->code();
 }
 
 JS_PUBLIC_API(JS::Symbol *)
 JS::GetWellKnownSymbol(JSContext *cx, JS::SymbolCode which)
 {
-    return cx->runtime()->wellKnownSymbols->get(uint32_t(which));
+    return cx->wellKnownSymbols().get(uint32_t(which));
 }
 
 static bool
 PropertySpecNameIsDigits(const char *s) {
     if (JS::PropertySpecNameIsSymbol(s))
         return false;
     if (!*s)
         return false;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2556,34 +2556,42 @@ struct JSFunctionSpec {
  * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays
  * homage to the old JSNative/JSFastNative split) simply adds the flag
  * JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of
  * JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. Finally
  * JS_FNSPEC has slots for all the fields.
  *
  * The _SYM variants allow defining a function with a symbol key rather than a
  * string key. For example, use JS_SYM_FN(iterator, ...) to define an
- * @@iterator method.
+ * @@iterator method. (In builds without ES6 symbols, it defines a method with
+ * the string id "@@iterator".)
  */
 #define JS_FS(name,call,nargs,flags)                                          \
     JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
 #define JS_FN(name,call,nargs,flags)                                          \
     JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
 #define JS_SYM_FN(name,call,nargs,flags)                                      \
     JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
 #define JS_FNINFO(name,call,info,nargs,flags)                                 \
     JS_FNSPEC(name, call, info, nargs, flags, nullptr)
 #define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags)                    \
     JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
 #define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags)           \
     JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
+
+#ifdef JS_HAS_SYMBOLS
 #define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName)       \
     JS_FNSPEC(reinterpret_cast<const char *>(                                 \
                   uint32_t(::JS::SymbolCode::symbol) + 1),                    \
               call, info, nargs, flags, selfHostedName)
+#else
+#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName)       \
+    JS_FNSPEC("@@" #symbol, call, info, nargs, flags, selfHostedName)
+#endif
+
 #define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName)                  \
     {name, {call, info}, nargs, flags, selfHostedName}
 
 extern JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, JS::HandleObject obj, JS::HandleObject parent_proto,
              const JSClass *clasp, JSNative constructor, unsigned nargs,
              const JSPropertySpec *ps, const JSFunctionSpec *fs,
              const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3169,17 +3169,17 @@ static const JSFunctionSpec array_method
 
     /* ES6 additions */
     JS_SELF_HOSTED_FN("find",        "ArrayFind",        1,0),
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
     JS_SELF_HOSTED_FN("copyWithin",  "ArrayCopyWithin",  3,0),
 
     JS_SELF_HOSTED_FN("fill",        "ArrayFill",        3,0),
 
-    JS_SELF_HOSTED_FN("@@iterator",  "ArrayValues",      0,0),
+    JS_SELF_HOSTED_SYM_FN(iterator,  "ArrayValues",      0,0),
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -151,17 +151,17 @@ JSRuntime::initializeAtoms(JSContext *cx
 
     emptyString = commonNames->empty;
 
     // Create the well-known symbols.
     wellKnownSymbols = cx->new_<WellKnownSymbols>();
     if (!wellKnownSymbols)
         return false;
 
-    ImmutablePropertyNamePtr *descriptions = &commonNames->Symbol_iterator;
+    ImmutablePropertyNamePtr *descriptions = commonNames->wellKnownSymbolDescriptions();
     ImmutableSymbolPtr *symbols = reinterpret_cast<ImmutableSymbolPtr *>(wellKnownSymbols);
     for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
         JS::Symbol *symbol = JS::Symbol::new_(cx, JS::SymbolCode(i), descriptions[i]);
         if (!symbol) {
             js_ReportOutOfMemory(cx);
             return false;
         }
         symbols[i].init(symbol);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -881,17 +881,17 @@ iterator_next_impl(JSContext *cx, CallAr
 static bool
 iterator_next(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsIterator, iterator_next_impl>(cx, args);
 }
 
 static const JSFunctionSpec iterator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "LegacyIteratorShim", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "LegacyIteratorShim", 0, 0),
     JS_FN("next",      iterator_next,       0, 0),
     JS_FS_END
 };
 
 static JSObject *
 iterator_iteratorObject(JSContext *cx, HandleObject obj, bool keysonly)
 {
     return obj;
@@ -960,17 +960,17 @@ const Class ArrayIteratorObject::class_ 
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr                  /* finalize    */
 };
 
 static const JSFunctionSpec array_iterator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "ArrayIteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "ArrayIteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "ArrayIteratorNext", 0, 0),
     JS_FS_END
 };
 
 static const Class StringIteratorPrototypeClass = {
     "String Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub,         /* addProperty */
@@ -999,17 +999,17 @@ const Class StringIteratorObject::class_
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr                  /* finalize    */
 };
 
 static const JSFunctionSpec string_iterator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "StringIteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "StringIteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "StringIteratorNext", 0, 0),
     JS_FS_END
 };
 
 bool
 js::ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp)
 {
     /* JSITER_KEYVALUE must always come with JSITER_FOREACH */
@@ -1364,18 +1364,24 @@ ForOfIterator::init(HandleValue iterable
 
     // The iterator is the result of calling obj[@@iterator]().
     InvokeArgs args(cx);
     if (!args.init(0))
         return false;
     args.setThis(ObjectValue(*iterableObj));
 
     RootedValue callee(cx);
+#ifdef JS_HAS_SYMBOLS
+    RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+    if (!JSObject::getGeneric(cx, iterableObj, iterableObj, iteratorId, &callee))
+        return false;
+#else
     if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
         return false;
+#endif
 
     // If obj[@@iterator] is undefined and we were asked to allow non-iterables,
     // bail out now without setting iterator.  This will make valueIsIterable(),
     // which our caller should check, return false.
     if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
         return true;
 
     // Throw if obj[@@iterator] isn't callable.
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1587,16 +1587,23 @@ ExpressionDecompiler::decompilePC(jsbyte
       case JSOP_ONE:
       case JSOP_INT8:
       case JSOP_UINT16:
       case JSOP_UINT24:
       case JSOP_INT32:
         return sprinter.printf("%d", GetBytecodeInteger(pc)) >= 0;
       case JSOP_STRING:
         return quote(loadAtom(pc), '"');
+      case JSOP_SYMBOL: {
+        unsigned i = uint8_t(pc[1]);
+        MOZ_ASSERT(i < JS::WellKnownSymbolLimit);
+        if (i < JS::WellKnownSymbolLimit)
+            return write(cx->names().wellKnownSymbolDescriptions()[i]);
+        break;
+      }
       case JSOP_UNDEFINED:
         return write(js_undefined_str);
       case JSOP_THIS:
         // |this| could convert to a very long object initialiser, so cite it by
         // its keyword name.
         return write(js_this_str);
       case JSOP_CALL:
       case JSOP_FUNCALL:
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4199,17 +4199,17 @@ static const JSFunctionSpec string_metho
     JS_SELF_HOSTED_FN("blink",    "String_blink",      0,0),
     JS_SELF_HOSTED_FN("sup",      "String_sup",        0,0),
     JS_SELF_HOSTED_FN("sub",      "String_sub",        0,0),
     JS_SELF_HOSTED_FN("anchor",   "String_anchor",     1,0),
     JS_SELF_HOSTED_FN("link",     "String_link",       1,0),
     JS_SELF_HOSTED_FN("fontcolor","String_fontcolor",  1,0),
     JS_SELF_HOSTED_FN("fontsize", "String_fontsize",   1,0),
 
-    JS_SELF_HOSTED_FN("@@iterator", "String_iterator", 0,0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "String_iterator", 0,0),
     JS_FS_END
 };
 
 // ES6 rev 27 (2014 Aug 24) 21.1.1
 bool
 js_String(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/tests/ecma_6/Array/for_of_2.js
+++ b/js/src/tests/ecma_6/Array/for_of_2.js
@@ -20,17 +20,17 @@ function TestChangeArrayIteratorNext() {
     var GET_COUNT = 0;
     function getter() {
         GET_COUNT++;
         if (GET_COUNT == MID)
             iterProto.next = NewNext;
         return M2;
     }
 
-    var iter = ([])['@@iterator']();
+    var iter = ([])[std_iterator]();
     var iterProto = Object.getPrototypeOf(iter);
     var OldNext = iterProto.next;
     var NewNext = function () {
         return OldNext.apply(this, arguments);
     };
 
     var TRUE_SUM = 0;
     var N = 100;
--- a/js/src/tests/ecma_6/Array/for_of_3.js
+++ b/js/src/tests/ecma_6/Array/for_of_3.js
@@ -22,17 +22,17 @@ function TestIncreaseArrayLength() {
         GET_COUNT++;
         if (GET_COUNT == MID) {
             ARR_SUM += arr.length;
             arr.push(arr.length);
         }
         return M2;
     }
 
-    var iter = ([])['@@iterator']();
+    var iter = ([])[std_iterator]();
     var iterProto = Object.getPrototypeOf(iter);
     var OldNext = iterProto.next;
     var NewNext = function () {
         return OldNext.apply(this, arguments);
     };
 
     var TRUE_SUM = 0;
     var N = 100;
--- a/js/src/tests/ecma_6/Array/for_of_4.js
+++ b/js/src/tests/ecma_6/Array/for_of_4.js
@@ -21,17 +21,17 @@ function TestDecreaseArrayLength() {
     function getter() {
         GET_COUNT++;
         if (GET_COUNT == MID) {
             arr.length = 0;
         }
         return M2;
     }
 
-    var iter = ([])['@@iterator']();
+    var iter = ([])[std_iterator]();
     var iterProto = Object.getPrototypeOf(iter);
     var OldNext = iterProto.next;
     var NewNext = function () {
         return OldNext.apply(this, arguments);
     };
 
     var TRUE_SUM = 0;
     var N = 100;
--- a/js/src/tests/ecma_6/Array/from_errors.js
+++ b/js/src/tests/ecma_6/Array/from_errors.js
@@ -129,17 +129,17 @@ var exc = {surprise: "ponies"};
 assertThrowsValue(() => Array.from.call(C, arrayish, () => { throw exc; }), exc);
 assertEq(log, "lC0");
 assertEq(obj instanceof C, true);
 
 // It's a TypeError if the iterator's .next() method returns a primitive.
 for (var primitive of [undefined, null, 17]) {
     assertThrowsInstanceOf(
         () => Array.from({
-            "@@iterator": () => {
-                next: () => primitive
+            [std_iterator]() {
+                return {next() { return primitive; }};
             }
         }),
         TypeError);
 }
 
 if (typeof reportCompare === 'function')
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Array/from_iterable.js
+++ b/js/src/tests/ecma_6/Array/from_iterable.js
@@ -3,17 +3,17 @@
 
 // Array.from works on arguments objects.
 (function () {
     assertDeepEq(Array.from(arguments), ["arg0", "arg1", undefined]);
 })("arg0", "arg1", undefined);
 
 // If an object has both .length and [@@iterator] properties, [@@iterator] is used.
 var a = ['a', 'e', 'i', 'o', 'u'];
-a["@@iterator"] = function* () {
+a[std_iterator] = function* () {
     for (var i = 5; i--; )
         yield this[i];
 };
 
 var log = '';
 function f(x) {
     log += x;
     return x + x;
--- a/js/src/tests/ecma_6/Array/from_proxy.js
+++ b/js/src/tests/ecma_6/Array/from_proxy.js
@@ -1,52 +1,54 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/licenses/publicdomain/ */
 
 // Two tests involving Array.from and a Proxy.
 var log = [];
 function LoggingProxy(target) {
     var h = {
         defineProperty: function (t, id) {
-            log.push("define " + id);
+            log.push("define", id);
             return undefined;
         },
         has: function (t, id) {
-            log.push("has " + id);
+            log.push("has", id);
             return id in t;
         },
         get: function (t, id) {
-            log.push("get " + id);
+            log.push("get", id);
             return t[id];
         },
         set: function (t, id, v) {
-            log.push("set " + id);
+            log.push("set", id);
             t[id] = v;
         }
     };
     return new Proxy(target || [], h);
 }
 
 // When the new object created by Array.from is a Proxy,
 // Array.from calls handler.defineProperty to create new elements
 // but handler.set to set the length.
 LoggingProxy.from = Array.from;
 LoggingProxy.from([3, 4, 5]);
-assertDeepEq(log, ["define 0", "define 1", "define 2", "set length"]);
+assertDeepEq(log, ["define", "0", "define", "1", "define", "2", "set", "length"]);
 
 // When the argument passed to Array.from is a Proxy, Array.from
 // calls handler.get on it.
 log = [];
 assertDeepEq(Array.from(new LoggingProxy([3, 4, 5])), [3, 4, 5]);
-assertDeepEq(log, ["get @@iterator",
-                   "get length", "get 0", "get length", "get 1", "get length", "get 2",
-                   "get length"]);
+assertDeepEq(log, ["get", std_iterator,
+                   "get", "length", "get", "0",
+                   "get", "length", "get", "1",
+                   "get", "length", "get", "2",
+                   "get", "length"]);
 
 // Array-like iteration only gets the length once.
 log = [];
 var arr = [5, 6, 7];
-arr["@@iterator"] = undefined;
+arr[std_iterator] = undefined;
 assertDeepEq(Array.from(new LoggingProxy(arr)), [5, 6, 7]);
-assertDeepEq(log, ["get @@iterator",
-                   "get length", "get 0", "get 1", "get 2"]);
+assertDeepEq(log, ["get", std_iterator,
+                   "get", "length", "get", "0", "get", "1", "get", "2"]);
 
 if (typeof reportCompare === 'function')
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Array/from_string.js
+++ b/js/src/tests/ecma_6/Array/from_string.js
@@ -6,18 +6,18 @@ assertDeepEq(Array.from("test string"),
              ['t', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g']);
 
 // Array.from on a string handles surrogate pairs correctly.
 var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF
 assertDeepEq(Array.from(gclef), [gclef]);
 assertDeepEq(Array.from(gclef + " G"), [gclef, " ", "G"]);
 
 // Array.from on a string calls the @@iterator method.
-String.prototype["@@iterator"] = function* () { yield 1; yield 2; };
+String.prototype[std_iterator] = function* () { yield 1; yield 2; };
 assertDeepEq(Array.from("anything"), [1, 2]);
 
 // If the iterator method is deleted, Strings are still arraylike.
-delete String.prototype["@@iterator"];
+delete String.prototype[std_iterator];
 assertDeepEq(Array.from("works"), ['w', 'o', 'r', 'k', 's']);
 assertDeepEq(Array.from(gclef), ['\uD834', '\uDD1E']);
 
 if (typeof reportCompare === 'function')
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Generators/runtime.js
+++ b/js/src/tests/ecma_6/Generators/runtime.js
@@ -12,18 +12,16 @@ function assertSyntaxError(str) {
 }
 
 
 function f() { }
 function* g() { yield 1; }
 var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
 var GeneratorFunction = GeneratorFunctionPrototype.constructor;
 var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
-// FIXME: This should be a symbol.
-var std_iterator = "@@iterator";
 
 
 // A generator function should have the same set of properties as any
 // other function.
 function TestGeneratorFunctionInstance() {
     var f_own_property_names = Object.getOwnPropertyNames(f);
     var g_own_property_names = Object.getOwnPropertyNames(g);
 
@@ -61,17 +59,19 @@ TestGeneratorFunctionPrototype();
 // Functions that we associate with generator objects are actually defined by
 // a common prototype.
 function TestGeneratorObjectPrototype() {
     assertEq(Object.getPrototypeOf(GeneratorObjectPrototype),
                Object.prototype);
     assertEq(Object.getPrototypeOf((function*(){yield 1}).prototype),
                GeneratorObjectPrototype);
 
-    var expected_property_names = ["next", "throw", "constructor", std_iterator];
+    var expected_property_names = ["next", "throw", "constructor"];
+    if (!JS_HAS_SYMBOLS)
+        expected_property_names.push(std_iterator);
     var found_property_names =
         Object.getOwnPropertyNames(GeneratorObjectPrototype);
 
     expected_property_names.sort();
     found_property_names.sort();
 
     assertDeepEq(found_property_names, expected_property_names);
 }
--- a/js/src/tests/ecma_6/Symbol/property-reflection.js
+++ b/js/src/tests/ecma_6/Symbol/property-reflection.js
@@ -61,20 +61,18 @@ if (typeof Symbol === "function") {
     desc = Object.getOwnPropertyDescriptor(n, s2);
     assertDeepEq(desc, descs[s2]);
     assertEq(desc.value, descs[s2].value);
 
     // Object.prototype.hasOwnProperty
     assertEq(descs.hasOwnProperty(s1), true);
     assertEq(descs.hasOwnProperty(s2), true);
     assertEq(descs.hasOwnProperty(s3), false);
-    assertEq([].hasOwnProperty(Symbol.iterator), false);
-    if (!("@@iterator" in []))
-        throw new Error("Congratulations on implementing Symbol.iterator! Please update this test.");
-    assertEq(Array.prototype.hasOwnProperty(Symbol.iterator), false);  // should be true
+    assertEq([].hasOwnProperty(std_iterator), false);
+    assertEq(Array.prototype.hasOwnProperty(std_iterator), true);
 
     // Object.prototype.propertyIsEnumerable
     assertEq(n.propertyIsEnumerable(s1), true);
     assertEq(n.propertyIsEnumerable(s2), false);
     assertEq(n.propertyIsEnumerable(s3), false);  // no such property
     assertEq(D.prototype.propertyIsEnumerable(s3), true);
     assertEq(descs.propertyIsEnumerable(s3), false); // inherited properties are not considered
 
--- a/js/src/tests/js1_8/regress/regress-469625-03.js
+++ b/js/src/tests/js1_8/regress/regress-469625-03.js
@@ -21,17 +21,18 @@ function test()
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
   function f(x) {
     var [a, b, [c0, c1]] = [x, x, x];
   }
 
-  expect = 'TypeError: (intermediate value)[\'@@iterator\'](...).next(...).value is null';
+  var ITERATOR = JS_HAS_SYMBOLS ? "Symbol.iterator" : "'@@iterator'";
+  expect = `TypeError: (intermediate value)[${ITERATOR}](...).next(...).value is null`;
   actual = 'No Error';
   try
   {
     f(null);
   }
   catch(ex)
   {
     actual = ex + '';
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/decompile-for-of.js
@@ -0,0 +1,28 @@
+// The decompiler can handle the implicit call to @@iterator in a for-of loop.
+
+var x;
+function check(code) {
+    var s = "no exception thrown";
+    try {
+        eval(code);
+    } catch (exc) {
+        s = exc.message;
+    }
+
+    var ITERATOR = JS_HAS_SYMBOLS ? "Symbol.iterator" : "'@@iterator'";
+    assertEq(s, `x[${ITERATOR}] is not a function`);
+}
+
+x = {};
+check("for (var v of x) throw fit;");
+check("[...x]");
+check("Math.hypot(...x)");
+
+x[std_iterator] = "potato";
+check("for (var v of x) throw fit;");
+
+x[std_iterator] = {};
+check("for (var v of x) throw fit;");
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0, "ok");
--- a/js/src/tests/shell.js
+++ b/js/src/tests/shell.js
@@ -871,8 +871,11 @@ function GetContext() {
   return Packages.com.netscape.javascript.Context.getCurrentContext();
 }
 function OptLevel( i ) {
   i = Number(i);
   var cx = GetContext();
   cx.setOptimizationLevel(i);
 }
 /* end of Rhino functions */
+
+var JS_HAS_SYMBOLS = typeof Symbol === "function";
+var std_iterator = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -242,26 +242,26 @@ const Class StarGeneratorObject::class_ 
     nullptr,                 /* finalize    */
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     nullptr,                 /* trace       */
 };
 
 static const JSFunctionSpec star_generator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0),
     JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0),
     JS_FS_END
 };
 
 #define JSPROP_ROPERM   (JSPROP_READONLY | JSPROP_PERMANENT)
 
 static const JSFunctionSpec legacy_generator_methods[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "LegacyGeneratorIteratorShim", 0, 0),
     // "send" is an alias for "next".
     JS_SELF_HOSTED_FN("next", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
     JS_SELF_HOSTED_FN("send", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
     JS_SELF_HOSTED_FN("throw", "LegacyGeneratorThrow", 1, JSPROP_ROPERM),
     JS_SELF_HOSTED_FN("close", "LegacyGeneratorClose", 0, JSPROP_ROPERM),
     JS_FS_END
 };
 
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -319,24 +319,38 @@ InitBareBuiltinCtor(JSContext *cx, Handl
  * The self-hosting global only gets a small subset of all standard classes.
  * Even those are only created as bare constructors without any properties
  * or functions.
  */
 /* static */ bool
 GlobalObject::initSelfHostingBuiltins(JSContext *cx, Handle<GlobalObject*> global,
                                       const JSFunctionSpec *builtins)
 {
-    /* Define a top-level property 'undefined' with the undefined value. */
+    // Define a top-level property 'undefined' with the undefined value.
     if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
                                   JS_PropertyStub, JS_StrictPropertyStub,
                                   JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return false;
     }
 
+    // Define a top-level property 'std_iterator' with the name of the method
+    // used by for-of loops to create an iterator.
+    RootedValue std_iterator(cx);
+#ifdef JS_HAS_SYMBOLS
+    std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
+#else
+    std_iterator.setString(cx->names().std_iterator);
+#endif
+    if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
+                           JSPROP_PERMANENT | JSPROP_READONLY))
+    {
+        return false;
+    }
+
     return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
            InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
            InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
            InitBareBuiltinCtor(cx, global, JSProto_Uint32Array) &&
            InitBareWeakMapCtor(cx, global) &&
            initStopIterationClass(cx, global) &&
            InitSelfHostingCollectionIteratorFunctions(cx, global) &&
            JS_DefineFunctions(cx, global, builtins);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1119,16 +1119,17 @@ HandleError(JSContext *cx, InterpreterRe
 #define REGS                     (activation.regs())
 #define PUSH_COPY(v)             do { *REGS.sp++ = (v); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_COPY_SKIP_CHECK(v)  *REGS.sp++ = (v)
 #define PUSH_NULL()              REGS.sp++->setNull()
 #define PUSH_UNDEFINED()         REGS.sp++->setUndefined()
 #define PUSH_BOOLEAN(b)          REGS.sp++->setBoolean(b)
 #define PUSH_DOUBLE(d)           REGS.sp++->setDouble(d)
 #define PUSH_INT32(i)            REGS.sp++->setInt32(i)
+#define PUSH_SYMBOL(s)           REGS.sp++->setSymbol(s)
 #define PUSH_STRING(s)           do { REGS.sp++->setString(s); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_OBJECT(obj)         do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
 #define PUSH_HOLE()              REGS.sp++->setMagic(JS_ELEMENTS_HOLE)
 #define PUSH_UNINITIALIZED()     REGS.sp++->setMagic(JS_UNINITIALIZED_LEXICAL)
 #define POP_COPY_TO(v)           (v) = *--REGS.sp
 #define POP_RETURN_VALUE()       REGS.fp()->setReturnValue(*--REGS.sp)
 
@@ -1596,17 +1597,16 @@ CASE(EnableInterruptsPseudoOpcode)
     /* Commence executing the actual opcode. */
     SANITY_CHECKS();
     DISPATCH_TO(op);
 }
 
 /* Various 1-byte no-ops. */
 CASE(JSOP_NOP)
 CASE(JSOP_UNUSED2)
-CASE(JSOP_UNUSED45)
 CASE(JSOP_UNUSED46)
 CASE(JSOP_UNUSED47)
 CASE(JSOP_UNUSED48)
 CASE(JSOP_UNUSED49)
 CASE(JSOP_UNUSED50)
 CASE(JSOP_UNUSED51)
 CASE(JSOP_UNUSED52)
 CASE(JSOP_UNUSED57)
@@ -2701,16 +2701,20 @@ CASE(JSOP_TOSTRING)
         JSString *operString = ToString<CanGC>(cx, oper);
         if (!operString)
             goto error;
         oper.setString(operString);
     }
 }
 END_CASE(JSOP_TOSTRING)
 
+CASE(JSOP_SYMBOL)
+    PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
+END_CASE(JSOP_SYMBOL)
+
 CASE(JSOP_OBJECT)
 {
     RootedNativeObject &ref = rootNativeObject0;
     ref = script->getObject(REGS.pc);
     if (JS::CompartmentOptionsRef(cx).cloneSingletons()) {
         JSObject *obj = js::DeepCloneObjectLiteral(cx, ref, js::MaybeSingletonObject);
         if (!obj)
             goto error;
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -411,17 +411,25 @@ 1234567890123456789012345678901234567890
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands: uint24_t n
      *   Stack: v[n], v[n-1], ..., v[1], v[0] =>
      *          v[n], v[n-1], ..., v[1], v[0], v[n]
      */ \
     macro(JSOP_DUPAT,     44, "dupat",      NULL,         4,  0,  1,  JOF_UINT24) \
     \
-    macro(JSOP_UNUSED45,  45, "unused45",   NULL,         1,  0,  0,  JOF_BYTE) \
+    /*
+     * Push a well-known symbol onto the operand stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: uint8_t n, the JS::SymbolCode of the symbol to use
+     *   Stack: => symbol
+     */ \
+    macro(JSOP_SYMBOL,    45, "symbol",     NULL,         2,  0,  1,  JOF_UINT8) \
+    \
     macro(JSOP_UNUSED46,  46, "unused46",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED47,  47, "unused47",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED48,  48, "unused48",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED49,  49, "unused49",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED50,  50, "unused50",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED51,  51, "unused51",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED52,  52, "unused52",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
--- a/js/src/vm/PIC.cpp
+++ b/js/src/vm/PIC.cpp
@@ -13,16 +13,22 @@
 #include "vm/SelfHosting.h"
 
 #include "jsobjinlines.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
+#ifdef JS_HAS_SYMBOLS
+#define STD_ITERATOR_ID  SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)
+#else
+#define STD_ITERATOR_ID  ::js::NameToId(cx->names().std_iterator)
+#endif
+
 bool
 js::ForOfPIC::Chain::initialize(JSContext *cx)
 {
     MOZ_ASSERT(!initialized_);
 
     // Get the canonical Array.prototype
     RootedNativeObject arrayProto(cx, GlobalObject::getOrCreateArrayPrototype(cx, cx->global()));
     if (!arrayProto)
@@ -39,18 +45,18 @@ js::ForOfPIC::Chain::initialize(JSContex
     initialized_ = true;
     arrayProto_ = arrayProto;
     arrayIteratorProto_ = arrayIteratorProto;
 
     // Shortcut returns below means Array for-of will never be optimizable,
     // do set disabled_ now, and clear it later when we succeed.
     disabled_ = true;
 
-    // Look up '@@iterator' on Array.prototype, ensure it's a slotful shape.
-    Shape *iterShape = arrayProto->lookup(cx, cx->names().std_iterator);
+    // Look up Array.prototype[@@iterator], ensure it's a slotful shape.
+    Shape *iterShape = arrayProto->lookup(cx, STD_ITERATOR_ID);
     if (!iterShape || !iterShape->hasSlot() || !iterShape->hasDefaultGetter())
         return true;
 
     // Get the referred value, and ensure it holds the canonical ArrayValues function.
     Value iterator = arrayProto->getSlot(iterShape->slot());
     JSFunction *iterFun;
     if (!IsFunctionObject(iterator, &iterFun))
         return true;
@@ -138,18 +144,18 @@ js::ForOfPIC::Chain::tryOptimizeArray(JS
     // churn on these.
     if (numStubs() >= MAX_STUBS)
         eraseChain();
 
     // Ensure array's prototype is the actual Array.prototype
     if (!isOptimizableArray(array))
         return true;
 
-    // Ensure array doesn't define '@@iterator' directly.
-    if (array->lookup(cx, cx->names().std_iterator))
+    // Ensure array doesn't define @@iterator directly.
+    if (array->lookup(cx, STD_ITERATOR_ID))
         return true;
 
     // Good to optimize now, create stub to add.
     RootedShape shape(cx, array->lastProperty());
     stub = cx->new_<Stub>(shape);
     if (!stub)
         return false;
 
@@ -192,17 +198,17 @@ js::ForOfPIC::Chain::isOptimizableArray(
 
 bool
 js::ForOfPIC::Chain::isArrayStateStillSane()
 {
     // Ensure that canonical Array.prototype has matching shape.
     if (arrayProto_->lastProperty() != arrayProtoShape_)
         return false;
 
-    // Ensure that Array.prototype['@@iterator'] contains the
+    // Ensure that Array.prototype[@@iterator] contains the
     // canonical iterator function.
     if (arrayProto_->getSlot(arrayProtoIteratorSlot_) != canonicalIteratorFunc_)
         return false;
 
     // Chain to isArrayNextStillSane.
     return isArrayNextStillSane();
 }
 
--- a/js/src/vm/PIC.h
+++ b/js/src/vm/PIC.h
@@ -125,17 +125,17 @@ struct ForOfPIC
     ForOfPIC() MOZ_DELETE;
     ForOfPIC(const ForOfPIC &other) MOZ_DELETE;
 
     typedef PICStub<ForOfPIC> BaseStub;
     typedef PICChain<ForOfPIC> BaseChain;
 
     /*
      * A ForOfPIC has only one kind of stub for now: one that holds the shape
-     * of an array object that does not override its '@@iterator' property.
+     * of an array object that does not override its @@iterator property.
      */
     class Stub : public BaseStub
     {
       private:
         // Shape of matching array object.
         Shape *shape_;
 
       public:
@@ -159,35 +159,35 @@ struct ForOfPIC
      *
      *  Array.prototype's shape (arrayProtoShape_)
      *      To ensure that Array.prototype has not been modified.
      *
      *  ArrayIterator.prototype (arrayIteratorProto_)
      *  ArrayIterator.prototype's shape (arrayIteratorProtoShape_)
      *      To ensure that an ArrayIterator.prototype has not been modified.
      *
-     *  Array.prototype's slot number for '@@iterator' (arrayProtoIteratorSlot_)
-     *  Array.prototype's canonical value for '@@iterator' (canonicalIteratorFunc_)
+     *  Array.prototype's slot number for @@iterator (arrayProtoIteratorSlot_)
+     *  Array.prototype's canonical value for @@iterator (canonicalIteratorFunc_)
      *      To quickly retreive and ensure that the iterator constructor
      *      stored in the slot has not changed.
      *
      *  ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_)
      *  ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_)
      *      To quickly retreive and ensure that the 'next' method for ArrayIterator
      *      objects has not changed.
      */
     class Chain : public BaseChain
     {
       private:
         // Pointer to canonical Array.prototype and ArrayIterator.prototype
         HeapPtrNativeObject arrayProto_;
         HeapPtrNativeObject arrayIteratorProto_;
 
         // Shape of matching Array.prototype object, and slot containing
-        // the '@@iterator' for it, and the canonical value.
+        // the @@iterator for it, and the canonical value.
         HeapPtrShape arrayProtoShape_;
         uint32_t arrayProtoIteratorSlot_;
         HeapValue canonicalIteratorFunc_;
 
         // Shape of matching ArrayIteratorProto, and slot containing
         // the 'next' property, and the canonical value.
         HeapPtrShape arrayIteratorProtoShape_;
         uint32_t arrayIteratorProtoNextSlot_;
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -401,16 +401,20 @@ struct RuntimeSizes;
 struct JSAtomState
 {
 #define PROPERTYNAME_FIELD(idpart, id, text) js::ImmutablePropertyNamePtr id;
     FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
 #undef PROPERTYNAME_FIELD
 #define PROPERTYNAME_FIELD(name, code, init, clasp) js::ImmutablePropertyNamePtr name;
     JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
 #undef PROPERTYNAME_FIELD
+
+    js::ImmutablePropertyNamePtr *wellKnownSymbolDescriptions() {
+        return &Symbol_iterator;
+    }
 };
 
 namespace js {
 
 /*
  * Storage for well-known symbols. It's a separate struct from the Runtime so
  * that it can be shared across multiple runtimes. As in JSAtomState, each
  * field is a smart pointer that's immutable once initialized.
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1496,16 +1496,22 @@ CloneValue(JSContext *cx, HandleValue se
     } else if (selfHostedValue.isString()) {
         if (!selfHostedValue.toString()->isFlat())
             MOZ_CRASH();
         JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
         JSString *clone = CloneString(cx, selfHostedString);
         if (!clone)
             return false;
         vp.setString(clone);
+    } else if (selfHostedValue.isSymbol()) {
+        // Well-known symbols are shared.
+        JS::Symbol *sym = selfHostedValue.toSymbol();
+        MOZ_ASSERT(sym->isWellKnownSymbol());
+        MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
+        vp.set(selfHostedValue);
     } else {
         MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
     }
     return true;
 }
 
 bool
 JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, HandlePropertyName name,
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -755,17 +755,17 @@ TypedArrayObject::subarray(JSContext *cx
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<TypedArrayObject::is,
                                 TypedArrayMethods<TypedArrayObject>::subarray>(cx, args);
 }
 
 /* static */ const JSFunctionSpec
 TypedArrayObject::protoFunctions[] = {
-    JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0, 0),
+    JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0),                          \
     JS_FN("subarray", TypedArrayObject::subarray, 2, 0),
     JS_FN("set", TypedArrayObject::set, 2, 0),
     JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0),
     JS_FS_END
 };
 
 /* static */ const JSFunctionSpec
 TypedArrayObject::staticFunctions[] = {
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -22,18 +22,31 @@ namespace js {
  * deserialization if there is a mismatch between the current and saved
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
+ *
+ * === GREETINGS, FELLOW SUBTRAHEND INCREMENTER! ===
+ * For the time being, please increment the subtrahend by 2 each time it
+ * changes, because we have two flavors of bytecode: with JSOP_SYMBOL (in
+ * Nightly) and without (all others).  FIXME: Bug 1066322 - Enable ES6 symbols
+ * in all builds.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 188);
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 190;
+static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above");
+static const uint32_t XDR_BYTECODE_VERSION =
+    uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND
+#ifdef JS_HAS_SYMBOLS
+                                                           + 1
+#endif
+                                                              ));
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext *cx)
       : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
 
     JSContext *cx() const {
         return context;
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -141,16 +141,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   // prototype, so that we make sure to audit any new ones to make sure they're
   // Xray-safe.
   //
   // DO NOT CHANGE WTIHOUT REVIEW FROM AN XPCONNECT PEER.
   var version = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).version;
   var isNightlyBuild = version.endsWith("a1");
   var isReleaseBuild = !version.contains("a");
   const jsHasSymbols = typeof Symbol === "function";
+  const kIteratorSymbol = jsHasSymbols ? Symbol.iterator : "@@iterator";
   var gPrototypeProperties = {};
   gPrototypeProperties['Date'] =
     ["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear",
     "getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay",
     "getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds",
     "getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", "setTime",
     "setYear", "setFullYear", "setUTCFullYear", "setMonth", "setUTCMonth",
     "setDate", "setUTCDate", "setHours", "setUTCHours", "setMinutes",
@@ -163,26 +164,26 @@ https://bugzilla.mozilla.org/show_bug.cg
                                       the JS engine filters it out of getOwnPropertyNames */
     ["constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch",
      "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
      "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__"];
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
-      "findIndex", "copyWithin", "fill", "@@iterator", "entries", "keys", "constructor"];
+      "findIndex", "copyWithin", "fill", kIteratorSymbol, "entries", "keys", "constructor"];
   if (isNightlyBuild) {
     let pjsMethods = ['mapPar', 'reducePar', 'scanPar', 'scatterPar', 'filterPar'];
     gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
   }
   for (var c of typedArrayClasses) {
     gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"];
   }
   gPrototypeProperties['TypedArray'] =
-    ["length", "buffer", "byteLength", "byteOffset", "@@iterator", "subarray",
+    ["length", "buffer", "byteLength", "byteOffset", kIteratorSymbol, "subarray",
      "set", "copyWithin"];
 
   for (var c of errorObjectClasses) {
       gPrototypeProperties[c] = ["constructor", "name",
                                  // We don't actually resolve these empty data properties
                                  // onto the Xray prototypes, but we list them here to make
                                  // the test happy.
                                  "lineNumber", "columnNumber", "fileName", "message", "stack"];
@@ -495,20 +496,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   function testTypedArrays() {
     // We don't invoke testXray with %TypedArray%, because that function isn't
     // set up to deal with "anonymous" dependent classes (that is, classes not
     // visible as a global property, which %TypedArray% is not), and fixing it
     // up is more trouble than it's worth.
 
     var typedArrayProto = Object.getPrototypeOf(Int8Array.prototype);
 
-  gPrototypeProperties['TypedArray'] =
-    ["length", "buffer", "byteLength", "byteOffset", "@@iterator", "subarray",
-     "set", "copyWithin"];
-
     var desiredInheritedProps = Object.getOwnPropertyNames(typedArrayProto).sort();
     var inheritedProps =
       filterOut(desiredInheritedProps, ["BYTES_PER_ELEMENT", "constructor"]);
 
     var inheritedCallables =
       inheritedProps.filter(name => (propertyIsGetter(typedArrayProto, name) ||
                                      typeof typedArrayProto[name] === "function") &&
                                     name !== "constructor");
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -247,34 +247,24 @@ nsPresContext::nsPresContext(nsIDocument
   PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
   if (log && log->level >= PR_LOG_WARNING) {
     mTextPerf = new gfxTextPerfMetrics();
   }
 
   PR_INIT_CLIST(&mDOMMediaQueryLists);
 }
 
-nsPresContext::~nsPresContext()
+void
+nsPresContext::Destroy()
 {
-  NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
-  SetShell(nullptr);
-
-  NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
-                    "must not have media query lists left");
-
-  // Disconnect the refresh driver *after* the transition manager, which
-  // needs it.
-  if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
-    mRefreshDriver->Disconnect();
-  }
-
   if (mEventManager) {
     // unclear if these are needed, but can't hurt
     mEventManager->NotifyDestroyPresContext(this);
     mEventManager->SetPresContext(nullptr);
+    mEventManager = nullptr;
   }
 
   if (mPrefChangedTimer)
   {
     mPrefChangedTimer->Cancel();
     mPrefChangedTimer = nullptr;
   }
 
@@ -316,16 +306,34 @@ nsPresContext::~nsPresContext()
                                   "layout.css.devPixelsPerPx",
                                   this);
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "nglayout.debug.paint_flashing",
                                   this);
   Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
                                   "nglayout.debug.paint_flashing_chrome",
                                   this);
+
+  // Disconnect the refresh driver *after* the transition manager, which
+  // needs it.
+  if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
+    mRefreshDriver->Disconnect();
+    mRefreshDriver = nullptr;
+  }
+}
+
+nsPresContext::~nsPresContext()
+{
+  NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
+  SetShell(nullptr);
+
+  NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
+                    "must not have media query lists left");
+
+  Destroy();
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
    NS_INTERFACE_MAP_ENTRY(nsISupports)
    NS_INTERFACE_MAP_ENTRY(nsIObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
@@ -363,44 +371,33 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLangService); // a service
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrintSettings);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrefChangedTimer);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
-  if (tmp->mEventManager) {
-    // unclear if these are needed, but can't hurt
-    tmp->mEventManager->NotifyDestroyPresContext(tmp);
-    tmp->mEventManager->SetPresContext(nullptr);
-    tmp->mEventManager = nullptr;
-  }
-
   // We own only the items in mDOMMediaQueryLists that have listeners;
   // this reference is managed by their AddListener and RemoveListener
   // methods.
   for (PRCList *l = PR_LIST_HEAD(&tmp->mDOMMediaQueryLists);
        l != &tmp->mDOMMediaQueryLists; ) {
     PRCList *next = PR_NEXT_LINK(l);
     MediaQueryList *mql = static_cast<MediaQueryList*>(l);
     mql->RemoveAllListeners();
     l = next;
   }
 
   // NS_RELEASE(tmp->mLanguage); // an atom
-
   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
-  if (tmp->mPrefChangedTimer)
-  {
-    tmp->mPrefChangedTimer->Cancel();
-    tmp->mPrefChangedTimer = nullptr;
-  }
+
+  tmp->Destroy();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
  _pref.Assign(_s0); \
  _pref.Append(_s1);
 
 static const char* const kGenericFont[] = {
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1167,16 +1167,19 @@ public:
   // Controls for whether debug information about restyling in this
   // document should be output.
   bool RestyleLoggingEnabled() const { return mRestyleLoggingEnabled; }
   void StartRestyleLogging() { mRestyleLoggingEnabled = true; }
   void StopRestyleLogging() { mRestyleLoggingEnabled = false; }
 #endif
 
 protected:
+  // May be called multiple times (unlink, destructor)
+  void Destroy();
+
   void InvalidatePaintedLayers();
   void AppUnitsPerDevPixelChanged();
 
   void HandleRebuildUserFontSet() {
     mPostedFlushUserFontSet = false;
     FlushUserFontSet();
   }
 
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -2951,21 +2951,21 @@ protected:
 uint32_t
 PropertyProvider::ComputeJustifiableCharacters(int32_t aOffset, int32_t aLength)
 {
   // Scan non-skipped characters and count justifiable chars.
   nsSkipCharsRunIterator
     run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength);
   run.SetOriginalOffset(aOffset);
   uint32_t justifiableChars = 0;
-  bool isCJK = IsChineseOrJapanese(mFrame);
+  bool isCJ = IsChineseOrJapanese(mFrame);
   while (run.NextRun()) {
     for (int32_t i = 0; i < run.GetRunLength(); ++i) {
       justifiableChars +=
-        IsJustifiableCharacter(mFrag, run.GetOriginalOffset() + i, isCJK);
+        IsJustifiableCharacter(mFrag, run.GetOriginalOffset() + i, isCJ);
     }
   }
   return justifiableChars;
 }
 
 /**
  * Finds the offset of the first character of the cluster containing aPos
  */
@@ -3078,28 +3078,28 @@ PropertyProvider::GetSpacingInternal(uin
     }
   }
 
   // Now add in justification spacing
   if (mJustificationSpacing) {
     gfxFloat halfJustificationSpace = mJustificationSpacing/2;
     // Scan non-skipped characters and adjust justifiable chars, adding
     // justification space on either side of the cluster
-    bool isCJK = IsChineseOrJapanese(mFrame);
+    bool isCJ = IsChineseOrJapanese(mFrame);
     gfxSkipCharsIterator justificationStart(mStart), justificationEnd(mStart);
     FindJustificationRange(&justificationStart, &justificationEnd);
 
     nsSkipCharsRunIterator
       run(start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
     while (run.NextRun()) {
       gfxSkipCharsIterator iter = run.GetPos();
       int32_t runOriginalOffset = run.GetOriginalOffset();
       for (int32_t i = 0; i < run.GetRunLength(); ++i) {
         int32_t iterOriginalOffset = runOriginalOffset + i;
-        if (IsJustifiableCharacter(mFrag, iterOriginalOffset, isCJK)) {
+        if (IsJustifiableCharacter(mFrag, iterOriginalOffset, isCJ)) {
           iter.SetOriginalOffset(iterOriginalOffset);
           FindClusterStart(mTextRun, runOriginalOffset, &iter);
           uint32_t clusterFirstChar = iter.GetSkippedOffset();
           FindClusterEnd(mTextRun, runOriginalOffset + run.GetRunLength(), &iter);
           uint32_t clusterLastChar = iter.GetSkippedOffset();
           // Only apply justification to characters before justificationEnd
           if (clusterFirstChar >= justificationStart.GetSkippedOffset() &&
               clusterLastChar < justificationEnd.GetSkippedOffset()) {
@@ -8473,23 +8473,23 @@ nsTextFrame::TrimTrailingWhiteSpace(nsRe
     }
   }
 
   if (!result.mLastCharIsJustifiable &&
       (GetStateBits() & TEXT_JUSTIFICATION_ENABLED)) {
     // Check if any character in the last cluster is justifiable
     PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength,
                               nullptr, 0, nsTextFrame::eInflated);
-    bool isCJK = IsChineseOrJapanese(this);
+    bool isCJ = IsChineseOrJapanese(this);
     gfxSkipCharsIterator justificationStart(start), justificationEnd(trimmedEndIter);
     provider.FindJustificationRange(&justificationStart, &justificationEnd);
 
     for (int32_t i = justificationEnd.GetOriginalOffset();
          i < trimmed.GetEnd(); ++i) {
-      if (IsJustifiableCharacter(frag, i, isCJK)) {
+      if (IsJustifiableCharacter(frag, i, isCJ)) {
         result.mLastCharIsJustifiable = true;
       }
     }
   }
 
   gfxFloat advanceDelta;
   mTextRun->SetLineBreaks(trimmedStart, trimmedEnd - trimmedStart,
                           (GetStateBits() & TEXT_START_OF_LINE) != 0, true,
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -143,10 +143,10 @@ fuzzy-if(d2d,47,400) == linear-onestoppo
 == radial-onestopposition-1c.html radial-onestopposition-1-ref.html
 == repeating-linear-onestopposition-1.html orange-square.html
 == repeating-radial-onestopposition-1a.html orange-square.html
 == repeating-radial-onestopposition-1b.html orange-square.html
 == repeating-radial-onestopposition-1c.html orange-square.html
 == bug-916535-background-repeat-linear.html bug-916535-background-repeat-linear-ref.html
 fuzzy(1,800000) == large-gradient-1.html large-gradient-1-ref.html
 == large-gradient-2.html large-gradient-2-ref.html
-fuzzy(1,800000) == large-gradient-3.html large-gradient-3-ref.html
-== large-gradient-4.html large-gradient-4-ref.html
+fails-if(browserIsRemote&&!B2G) fuzzy(1,800000) == large-gradient-3.html large-gradient-3-ref.html
+fails-if(browserIsRemote&&!B2G) == large-gradient-4.html large-gradient-4-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -243,20 +243,20 @@ skip-if(B2G) include native-theme/reftes
 include ../../netwerk/test/reftest/reftest.list
 
 include outline/reftest.list
 
 # object/
 include object/reftest.list
 
 # ogg-video/
-include ogg-video/reftest.list
+skip-if(!B2G&&browserIsRemote) include ogg-video/reftest.list
 
 # webm-video/
-include webm-video/reftest.list
+skip-if(!B2G&&browserIsRemote) include webm-video/reftest.list
 
 # parser/
 include ../../parser/htmlparser/tests/reftest/reftest.list
 
 # percent-overflow-sizing/
 include percent-overflow-sizing/reftest.list
 
 # pixel-rounding/
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -32,16 +32,17 @@ support-files =
   xbl_bindings.xml
 generated-files = css_properties.js
 
 [test_acid3_test46.html]
 [test_all_shorthand.html]
 [test_animations.html]
 skip-if = toolkit == 'android'
 [test_animations_omta.html]
+skip-if = buildapp == 'mulet'
 [test_animations_omta_start.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1041017
 [test_animations_pausing.html]
 [test_any_dynamic.html]
 [test_at_rule_parse_serialize.html]
 [test_bug73586.html]
 [test_bug74880.html]
 [test_bug98997.html]
--- a/netwerk/cookie/PCookieService.ipdl
+++ b/netwerk/cookie/PCookieService.ipdl
@@ -22,17 +22,17 @@ namespace net {
  * all cookie operations. Lower-level programmatic operations (i.e. those
  * provided by the nsICookieManager and nsICookieManager2 interfaces) are not
  * currently implemented and requesting these interfaces in the child will fail.
  *
  * @see nsICookieService
  * @see nsICookiePermission
  */
 
-sync protocol PCookieService
+prio(normal upto urgent) sync protocol PCookieService
 {
   manager PNecko;
 
 parent:
 
   /*
    * Get the complete cookie string associated with the URI. This is a sync
    * call in order to avoid race conditions -- for instance, an HTTP response
@@ -55,20 +55,20 @@ parent:
    *        being set on.
    *
    * @see nsICookieService.getCookieString
    * @see nsICookieService.getCookieStringFromHttp
    * @see mozIThirdPartyUtil.isThirdPartyChannel
    *
    * @return the resulting cookie string.
    */
-  sync GetCookieString(URIParams host,
-                       bool isForeign,
-                       bool fromHttp,
-                       SerializedLoadContext loadContext)
+  prio(urgent) sync GetCookieString(URIParams host,
+                                    bool isForeign,
+                                    bool fromHttp,
+                                    SerializedLoadContext loadContext)
        returns (nsCString result);
 
   /*
    * Set a cookie string.
    *
    * @param host
    *        Same as the 'aURI' argument to nsICookieService.setCookieString.
    * @param isForeign
@@ -90,21 +90,21 @@ parent:
    * @param loadContext
    *        The loadContext from the HTTP channel or document that the cookie is
    *        being set on.
    *
    * @see nsICookieService.setCookieString
    * @see nsICookieService.setCookieStringFromHttp
    * @see mozIThirdPartyUtil.isThirdPartyChannel
    */
-  SetCookieString(URIParams host,
-                  bool isForeign,
-                  nsCString cookieString,
-                  nsCString serverTime,
-                  bool fromHttp,
-                  SerializedLoadContext loadContext);
+  prio(urgent) async SetCookieString(URIParams host,
+                                     bool isForeign,
+                                     nsCString cookieString,
+                                     nsCString serverTime,
+                                     bool fromHttp,
+                                     SerializedLoadContext loadContext);
 
   __delete__();
 };
 
 }
 }
 
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -30,17 +30,17 @@ include PBrowserOrId;
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
-sync protocol PNecko
+prio(normal upto urgent) sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
   manages PWebSocket;
   manages PTCPSocket;
@@ -50,17 +50,17 @@ sync protocol PNecko
   manages PRemoteOpenFile;
   manages PRtspController;
   manages PRtspChannel;
   manages PChannelDiverter;
 
 parent:
   __delete__();
 
-  PCookieService();
+  prio(urgent) async PCookieService();
   PHttpChannel(PBrowserOrId browser,
                SerializedLoadContext loadContext,
                HttpChannelCreationArgs args);
   PWyciwygChannel();
   PFTPChannel(PBrowserOrId browser, SerializedLoadContext loadContext,
               FTPChannelCreationArgs args);
 
   PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext);
--- a/security/manager/ssl/public/nsICertOverrideService.idl
+++ b/security/manager/ssl/public/nsICertOverrideService.idl
@@ -13,17 +13,17 @@ interface nsIX509Cert;
 #define NS_CERTOVERRIDE_CONTRACTID "@mozilla.org/security/certoverride;1"
 %}
 
 /**
  * This represents the global list of triples
  *   {host:port, cert-fingerprint, allowed-overrides} 
  * that the user wants to accept without further warnings. 
  */
-[scriptable, uuid(31738d2a-77d3-4359-84c9-4be2f38fb8c5)]
+[scriptable, uuid(be019e47-22fc-4355-9f16-9ab047d6742d)]
 interface nsICertOverrideService : nsISupports {
 
   /**
    *  Override Untrusted
    */
   const short ERROR_UNTRUSTED = 1;
 
   /**
@@ -104,25 +104,16 @@ interface nsICertOverrideService : nsISu
    *               If it is -1, then it is internaly treated as 443.
    *               If it is 0 and aHostName is "all:temporary-certificates",
    *               then all temporary certificates should be cleared.
    */
   void clearValidityOverride(in ACString aHostName,
                              in int32_t aPort);
 
   /**
-   *  Obtain the full list of hostname:port for which overrides are known.
-   *
-   *  @param aCount The number of host:port entries returned
-   *  @param aHostsWithPortsArray The array of host:port entries returned
-   */
-  void getAllOverrideHostsWithPorts(out uint32_t aCount, 
-                                    [array, size_is(aCount)] out wstring aHostsWithPortsArray);
-
-  /**
    *  Is the given cert used in rules?
    *
    *  @param aCert The cert we're looking for
    *  @return how many override entries are currently on file
    *          for the given certificate
    */
   uint32_t isCertUsedForOverrides(in nsIX509Cert aCert,
                                   in boolean aCheckTemporaries,
--- a/security/manager/ssl/src/nsCertOverrideService.cpp
+++ b/security/manager/ssl/src/nsCertOverrideService.cpp
@@ -1,39 +1,34 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCertOverrideService.h"
 
-#include "pkix/pkixtypes.h"
-#include "nsIX509Cert.h"
 #include "NSSCertDBTrustDomain.h"
-#include "nsNSSCertificate.h"
-#include "nsNSSCertHelper.h"
+#include "ScopedNSSTypes.h"
+#include "SharedSSLState.h"
+#include "mozilla/Telemetry.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "nsCRT.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsStreamUtils.h"
-#include "nsNetUtil.h"
 #include "nsILineInputStream.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsISupportsPrimitives.h"
+#include "nsIX509Cert.h"
+#include "nsNSSCertHelper.h"
+#include "nsNSSCertificate.h"
+#include "nsNSSComponent.h"
+#include "nsNetUtil.h"
 #include "nsPromiseFlatString.h"
-#include "nsThreadUtils.h"
+#include "nsStreamUtils.h"
 #include "nsStringBuffer.h"
-#include "ScopedNSSTypes.h"
-#include "SharedSSLState.h"
-
-#include "nspr.h"
-#include "pk11pub.h"
-#include "certdb.h"
-#include "sechash.h"
+#include "nsThreadUtils.h"
 #include "ssl.h" // For SSL_ClearSessionCache
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 static const char kCertOverrideFileName[] = "cert_override.txt";
 
 void
@@ -101,28 +96,21 @@ nsCertOverrideService::~nsCertOverrideSe
 nsresult
 nsCertOverrideService::Init()
 {
   if (!NS_IsMainThread()) {
     NS_NOTREACHED("nsCertOverrideService initialized off main thread");
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
+  // Note that the names of these variables would seem to indicate that at one
+  // point another hash algorithm was used and is still supported for backwards
+  // compatibility. This is not the case. It has always been SHA256.
   mOidTagForStoringNewHashes = SEC_OID_SHA256;
-
-  SECOidData *od = SECOID_FindOIDByTag(mOidTagForStoringNewHashes);
-  if (!od)
-    return NS_ERROR_FAILURE;
-
-  char *dotted_oid = CERT_GetOidString(&od->oid);
-  if (!dotted_oid)
-    return NS_ERROR_FAILURE;
-
-  mDottedOidForStoringNewHashes = dotted_oid;
-  PR_smprintf_free(dotted_oid);
+  mDottedOidForStoringNewHashes.Assign("OID.2.16.840.1.101.3.4.2.1");
 
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
 
   // If we cannot add ourselves as a profile change observer, then we will not
   // attempt to read/write any settings file. Otherwise, we would end up
   // reading/writing the wrong settings file after a profile change.
   if (observerService) {
@@ -167,17 +155,17 @@ nsCertOverrideService::Observe(nsISuppor
 
     nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
     if (NS_SUCCEEDED(rv)) {
       mSettingsFile->AppendNative(NS_LITERAL_CSTRING(kCertOverrideFileName));
     } else {
       mSettingsFile = nullptr;
     }
     Read();
-
+    CountPermanentOverrideTelemetry();
   }
 
   return NS_OK;
 }
 
 void
 nsCertOverrideService::RemoveAllFromMemory()
 {
@@ -393,52 +381,16 @@ GetCertFingerprintByOidTag(nsIX509Cert *
 
   ScopedCERTCertificate nsscert(aCert->GetCert());
   if (!nsscert) {
     return NS_ERROR_FAILURE;
   }
   return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
 }
 
-static nsresult
-GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
-                                    const nsCString &dottedOid, 
-                                    nsCString &fp)
-{
-  SECItem oid;
-  oid.data = nullptr;
-  oid.len = 0;
-  SECStatus srv = SEC_StringToOID(nullptr, &oid, 
-                    dottedOid.get(), dottedOid.Length());
-  if (srv != SECSuccess)
-    return NS_ERROR_FAILURE;
-
-  SECOidTag oid_tag = SECOID_FindOIDTag(&oid);
-  SECITEM_FreeItem(&oid, false);
-
-  if (oid_tag == SEC_OID_UNKNOWN)
-    return NS_ERROR_FAILURE;
-
-  return GetCertFingerprintByOidTag(nsscert, oid_tag, fp);
-}
-
-static nsresult
-GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
-                                    const nsCString &dottedOid,
-                                    nsCString &fp)
-{
-
-  ScopedCERTCertificate nsscert(aCert->GetCert());
-  if (!nsscert) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
-}
-
 NS_IMETHODIMP
 nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
                                                 int32_t aPort,
                                                 nsIX509Cert* aCert,
                                                 uint32_t aOverrideBits,
                                                 bool aTemporary)
 {
   NS_ENSURE_ARG_POINTER(aCert);
@@ -541,24 +493,27 @@ nsCertOverrideService::HasMatchingOverri
   }
 
   *aOverrideBits = settings.mOverrideBits;
   *aIsTemporary = settings.mIsTemporary;
 
   nsAutoCString fpStr;
   nsresult rv;
 
+  // This code was originally written in a way that suggested that other hash
+  // algorithms are supported for backwards compatibility. However, this was
+  // always unnecessary, because only SHA256 has ever been used here.
   if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
     rv = GetCertFingerprintByOidTag(aCert, mOidTagForStoringNewHashes, fpStr);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  } else {
+    return NS_ERROR_UNEXPECTED;
   }
-  else {
-    rv = GetCertFingerprintByDottedOidString(aCert, settings.mFingerprintAlgOID, fpStr);
-  }
-  if (NS_FAILED(rv))
-    return rv;
 
   *_retval = settings.mFingerprint.Equals(fpStr);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertOverrideService::GetValidityOverride(const nsACString & aHostName, int32_t aPort,
                                            nsACString & aHashAlg, 
@@ -644,25 +599,47 @@ nsCertOverrideService::ClearValidityOver
   }
   nsAutoCString hostPort;
   GetHostWithPort(aHostName, aPort, hostPort);
   {
     ReentrantMonitorAutoEnter lock(monitor);
     mSettingsTable.RemoveEntry(hostPort.get());
     Write();
   }
-  SSL_ClearSessionCache();
+
+  if (EnsureNSSInitialized(nssEnsure)) {
+    SSL_ClearSessionCache();
+  } else {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsCertOverrideService::GetAllOverrideHostsWithPorts(uint32_t *aCount, 
-                                                        char16_t ***aHostsWithPortsArray)
+static PLDHashOperator
+CountPermanentEntriesCallback(nsCertOverrideEntry* aEntry, void* aArg)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  uint32_t* overrideCount = reinterpret_cast<uint32_t*>(aArg);
+  if (aEntry && !aEntry->mSettings.mIsTemporary) {
+    *overrideCount = *overrideCount + 1;
+    return PL_DHASH_NEXT;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
+void
+nsCertOverrideService::CountPermanentOverrideTelemetry()
+{
+  ReentrantMonitorAutoEnter lock(monitor);
+  uint32_t overrideCount = 0;
+  mSettingsTable.EnumerateEntries(CountPermanentEntriesCallback,
+                                  &overrideCount);
+  Telemetry::Accumulate(Telemetry::SSL_PERMANENT_CERT_ERROR_OVERRIDES,
+                        overrideCount);
 }
 
 static bool
 matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
 {
   char *dbkey = nullptr;
   nsresult rv = cert->GetDbKey(&dbkey);
   if (NS_FAILED(rv) || !dbkey)
@@ -733,25 +710,21 @@ FindMatchingCertCallback(nsCertOverrideE
     if ((settings.mIsTemporary && !cai->aCheckTemporaries)
         ||
         (!settings.mIsTemporary && !cai->aCheckPermanents)) {
       still_ok = false;
     }
 
     if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
       nsAutoCString cert_fingerprint;
-      nsresult rv;
+      nsresult rv = NS_ERROR_UNEXPECTED;
       if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
         rv = GetCertFingerprintByOidTag(cai->cert,
                cai->mOidTagForStoringNewHashes, cert_fingerprint);
       }
-      else {
-        rv = GetCertFingerprintByDottedOidString(cai->cert,
-               settings.mFingerprintAlgOID, cert_fingerprint);
-      }
       if (NS_SUCCEEDED(rv) &&
           settings.mFingerprint.Equals(cert_fingerprint)) {
         cai->counter++;
       }
     }
   }
 
   return PL_DHASH_NEXT;
@@ -803,25 +776,21 @@ EnumerateCertOverridesCallback(nsCertOve
     const nsCertOverride &settings = aEntry->mSettings;
 
     if (!capac->cert) {
       (*capac->enumerator)(settings, capac->userdata);
     }
     else {
       if (matchesDBKey(capac->cert, settings.mDBKey.get())) {
         nsAutoCString cert_fingerprint;
-        nsresult rv;
+        nsresult rv = NS_ERROR_UNEXPECTED;
         if (settings.mFingerprintAlgOID.Equals(capac->mDottedOidForStoringNewHashes)) {
           rv = GetCertFingerprintByOidTag(capac->cert,
                  capac->mOidTagForStoringNewHashes, cert_fingerprint);
         }
-        else {
-          rv = GetCertFingerprintByDottedOidString(capac->cert,
-                 settings.mFingerprintAlgOID, cert_fingerprint);
-        }
         if (NS_SUCCEEDED(rv) &&
             settings.mFingerprint.Equals(cert_fingerprint)) {
           (*capac->enumerator)(settings, capac->userdata);
         }
       }
     }
   }
 
@@ -855,9 +824,8 @@ nsCertOverrideService::GetHostWithPort(c
     aPort = 443;
   }
   if (!hostPort.IsEmpty()) {
     hostPort.Append(':');
     hostPort.AppendInt(aPort);
   }
   _retval.Assign(hostPort);
 }
-
--- a/security/manager/ssl/src/nsCertOverrideService.h
+++ b/security/manager/ssl/src/nsCertOverrideService.h
@@ -160,16 +160,18 @@ protected:
 
     mozilla::ReentrantMonitor monitor;
     nsCOMPtr<nsIFile> mSettingsFile;
     nsTHashtable<nsCertOverrideEntry> mSettingsTable;
 
     SECOidTag mOidTagForStoringNewHashes;
     nsCString mDottedOidForStoringNewHashes;
 
+    void CountPermanentOverrideTelemetry();
+
     void RemoveAllFromMemory();
     nsresult Read();
     nsresult Write();
     nsresult AddEntryToList(const nsACString &host, int32_t port,
                             nsIX509Cert *aCert,
                             const bool aIsTemporary,
                             const nsACString &algo_oid, 
                             const nsACString &fingerprint,
--- a/security/manager/ssl/src/nsNSSModule.cpp
+++ b/security/manager/ssl/src/nsNSSModule.cpp
@@ -194,24 +194,24 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEn
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCertPicker)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsNTLMAuthModule, InitTest)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHash)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHMAC)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsStreamCipher)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObject)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
-NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsCertOverrideService, Init)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, TransportSecurityInfo)
 
 typedef mozilla::psm::NSSErrorsService NSSErrorsService;
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NSSErrorsService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSVersion)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCertOverrideService, Init)
 
 NS_DEFINE_NAMED_CID(NS_NSSCOMPONENT_CID);
 NS_DEFINE_NAMED_CID(NS_SSLSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_STARTTLSSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_SDR_CID);
 NS_DEFINE_NAMED_CID(NS_PK11TOKENDB_CID);
 NS_DEFINE_NAMED_CID(NS_PKCS11MODULEDB_CID);
 NS_DEFINE_NAMED_CID(NS_PSMCONTENTLISTEN_CID);
--- a/security/manager/tools/PreloadedHPKPins.json
+++ b/security/manager/tools/PreloadedHPKPins.json
@@ -184,24 +184,16 @@
         "Verisign Class 3 Public Primary Certification Authority - G2",
         "Verisign Class 3 Public Primary Certification Authority - G3",
         "VeriSign Class 3 Public Primary Certification Authority - G4",
         "VeriSign Class 3 Public Primary Certification Authority - G5",
         "Verisign Class 4 Public Primary Certification Authority - G3",
         "VeriSign Universal Root Certification Authority",
         "XRamp Global CA Root"
       ]
-    },
-    {
-      "name": "facebook",
-      "sha256_hashes": [
-        "Verisign Class 3 Public Primary Certification Authority - G3",
-        "DigiCert High Assurance EV Root CA",
-        "DigiCert ECC Secure Server CA"
-      ]
     }
   ],
 
   "entries": [
     // Only domains that are operationally crucial to Firefox can have per-host
     // telemetry reporting (the "id") field
     { "name": "addons.mozilla.org", "include_subdomains": true,
       "pins": "mozilla", "test_mode": false, "id": 1 },
@@ -229,19 +221,16 @@
       "include_subdomains": false, "pins": "mozilla_test",
       "test_mode": false, "id": 0 },
     { "name": "test-mode.pinning.example.com", "include_subdomains": true,
       "pins": "mozilla_test", "test_mode": true },
     // Expand twitter's pinset to include all of *.twitter.com and use
     // twitterCDN. More specific rules take precedence because we search for
     // exact domain name first.
     { "name": "twitter.com", "include_subdomains": true,
-      "pins": "twitterCDN", "test_mode": false },
-    // Facebook (not pinned by Chrome)
-    { "name": "facebook.com", "include_subdomains": true,
-      "pins": "facebook", "test_mode": true }
+      "pins": "twitterCDN", "test_mode": false }
   ],
 
   "extra_certificates": [
      // DigiCert ECC Secure Server CA (for Facebook)
      "MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBTZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6gLGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/AbuiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/63qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoBUEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQdEa8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc="
   ]
 }
--- a/security/sandbox/mac/Sandbox.h
+++ b/security/sandbox/mac/Sandbox.h
@@ -6,16 +6,17 @@
 #ifndef mozilla_Sandbox_h
 #define mozilla_Sandbox_h
 
 #include "nsString.h"
 
 enum MacSandboxType {
   MacSandboxType_Default = 0,
   MacSandboxType_Plugin,
+  MacSandboxType_Content,
   MacSandboxType_Invalid
 };
 
 enum MacSandboxPluginType {
   MacSandboxPluginType_Default = 0,
   MacSandboxPluginType_GMPlugin_Default,  // Any Gecko Media Plugin
   MacSandboxPluginType_GMPlugin_OpenH264, // Gecko Media Plugin, OpenH264
   MacSandboxPluginType_GMPlugin_EME,      // Gecko Media Plugin, EME
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -11,17 +11,17 @@
 // some/all of the Macs in Mozilla's build system.  For the time being (until
 // this problem is resolved), we refer directly to what we need from it,
 // rather than including it here.
 extern "C" int sandbox_init(const char *profile, uint64_t flags, char **errorbuf);
 extern "C" void sandbox_free_error(char *errorbuf);
 
 namespace mozilla {
 
-static const char rules[] =
+static const char pluginSandboxRules[] =
   "(version 1)\n"
   "(deny default)\n"
   "(allow signal (target self))\n"
   "(allow sysctl-read)\n"
   // Needed only on OS X 10.6
   "%s(allow file-read-data (literal \"%s\"))\n"
   "(allow mach-lookup\n"
   "    (global-name \"com.apple.cfprefsd.agent\")\n"
@@ -33,38 +33,46 @@ static const char rules[] =
   "    (regex #\"^/etc$\")\n"
   "    (regex #\"^/dev/u?random$\")\n"
   "    (regex #\"^/(private/)?var($|/)\")\n"
   "    (literal \"/usr/share/icu/icudt51l.dat\")\n"
   "    (literal \"%s\")\n"
   "    (literal \"%s\")\n"
   "    (literal \"%s\"))\n";
 
+static const char contentSandboxRules[] =
+  "(version 1)\n"
+  "(allow default)\n";
+
 bool StartMacSandbox(MacSandboxInfo aInfo, nsCString &aErrorMessage)
 {
-  if (aInfo.type != MacSandboxType_Plugin) {
+  nsAutoCString profile;
+  if (aInfo.type == MacSandboxType_Plugin) {
+    if (nsCocoaFeatures::OnLionOrLater()) {
+      profile.AppendPrintf(pluginSandboxRules, ";",
+                           aInfo.pluginInfo.pluginPath.get(),
+                           aInfo.pluginInfo.pluginBinaryPath.get(),
+                           aInfo.appPath.get(),
+                           aInfo.appBinaryPath.get());
+    } else {
+      profile.AppendPrintf(pluginSandboxRules, "",
+                           aInfo.pluginInfo.pluginPath.get(),
+                           aInfo.pluginInfo.pluginBinaryPath.get(),
+                           aInfo.appPath.get(),
+                           aInfo.appBinaryPath.get());
+    }
+  }
+  else if (aInfo.type == MacSandboxType_Content) {
+    profile.AppendPrintf(contentSandboxRules);
+  }
+  else {
     aErrorMessage.AppendPrintf("Unexpected sandbox type %u", aInfo.type);
     return false;
   }
 
-  nsAutoCString profile;
-  if (nsCocoaFeatures::OnLionOrLater()) {
-    profile.AppendPrintf(rules, ";",
-                         aInfo.pluginInfo.pluginPath.get(),
-                         aInfo.pluginInfo.pluginBinaryPath.get(),
-                         aInfo.appPath.get(),
-                         aInfo.appBinaryPath.get());
-  } else {
-    profile.AppendPrintf(rules, "",
-                         aInfo.pluginInfo.pluginPath.get(),
-                         aInfo.pluginInfo.pluginBinaryPath.get(),
-                         aInfo.appPath.get(),
-                         aInfo.appBinaryPath.get());
-  }
-
   char *errorbuf = NULL;
   if (sandbox_init(profile.get(), 0, &errorbuf)) {
     if (errorbuf) {
       aErrorMessage.AppendPrintf("sandbox_init() failed with error \"%s\"",
                                  errorbuf);
       printf("profile: %s\n", profile.get());
       sandbox_free_error(errorbuf);
     }
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/machformatter.py
@@ -39,16 +39,17 @@ class MachFormatter(base.BaseFormatter):
         self.start_time = start_time
         self.write_interval = write_interval
         self.write_times = write_times
         self.status_buffer = {}
         self.has_unexpected = {}
         self.last_time = None
         self.terminal = terminal
         self.verbose = False
+        self._known_pids = set()
 
         self.summary_values = {"tests": 0,
                                "subtests": 0,
                                "expected": 0,
                                "unexpected": defaultdict(int),
                                "skipped": 0}
         self.summary_unexpected = []
 
@@ -258,19 +259,24 @@ class MachFormatter(base.BaseFormatter):
         if "expected" in data:
             self.summary_values["unexpected"][data["status"]] += 1
         elif data["status"] == "SKIP":
             self.summary_values["skipped"] += 1
         else:
             self.summary_values["expected"] += 1
 
     def process_output(self, data):
-        return '"%s" (pid:%s command:%s)' % (data["data"],
-                                             data["process"],
-                                             data.get("command", ""))
+        rv = []
+
+        if "command" in data and data["process"] not in self._known_pids:
+            self._known_pids.add(data["process"])
+            rv.append('(pid:%s) Full command: %s' % (data["process"], data["command"]))
+
+        rv.append('(pid:%s) "%s"' % (data["process"], data["data"]))
+        return "\n".join(rv)
 
     def crash(self, data):
         test = self._get_test_id(data)
 
         if data.get("stackwalk_returncode", 0) != 0 and not data.get("stackwalk_stderr"):
             success = True
         else:
             success = False
--- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.forms.html.ini
+++ b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.forms.html.ini
@@ -1,8 +1,5 @@
 [document.forms.html]
   type: testharness
   [document.forms]
     expected: FAIL
 
-  [document.forms iteration]
-    expected: FAIL
-
--- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm
+++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm
@@ -704,17 +704,18 @@ RemoteBrowserElementInterposition.getter
   // and immediately set contentWindow.location.
   if (!target.contentWindowAsCPOW) {
     return makeDummyContentWindow(target);
   }
   return target.contentWindowAsCPOW;
 };
 
 let DummyContentDocument = {
-  readyState: "loading"
+  readyState: "loading",
+  location: { href: "about:blank" }
 };
 
 RemoteBrowserElementInterposition.getters.contentDocument = function(addon, target) {
   // If we don't have a CPOW yet, just return something we can use to
   // examine readyState. This is useful for tests that create a new
   // tab and then immediately start polling readyState.
   if (!target.contentDocumentAsCPOW) {
     return DummyContentDocument;
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -6473,16 +6473,24 @@
     "description": "For non-stapling cases, is OCSP fetching a possibility? (0=yes, 1=no because missing/invalid OCSP URI, 2=no because fetching disabled, 3=no because both)"
   },
   "SSL_CERT_ERROR_OVERRIDES": {
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 24,
     "description": "Was a certificate error overridden on this handshake? What was it? (0=unknown error (indicating bug), 1=no, >1=a specific error)"
   },
+  "SSL_PERMANENT_CERT_ERROR_OVERRIDES": {
+    "alert_emails": ["seceng@mozilla.org"],
+    "expires_in_version": "42",
+    "kind": "exponential",
+    "high": 1024,
+    "n_buckets": 10,
+    "description": "How many permanent certificate overrides a user has stored."
+  },
   "TELEMETRY_TEST_EXPIRED": {
     "expires_in_version": "4.0a1",
     "kind": "flag",
     "description": "a testing histogram; not meant to be touched"
   },
   "CERT_OCSP_ENABLED": {
     "expires_in_version": "never",
     "kind": "boolean",
--- a/toolkit/modules/Promise-backend.js
+++ b/toolkit/modules/Promise-backend.js
@@ -32,16 +32,19 @@ const STATUS_REJECTED = 2;
 // This N_INTERNALS name allow internal properties of the Promise to be
 // accessed only by this module, while still being visible on the object
 // manually when using a debugger.  This doesn't strictly guarantee that the
 // properties are inaccessible by other code, but provide enough protection to
 // avoid using them by mistake.
 const salt = Math.floor(Math.random() * 100);
 const N_INTERNALS = "{private:internals:" + salt + "}";
 
+const JS_HAS_SYMBOLS = typeof Symbol === "function";
+const ITERATOR_SYMBOL = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
+
 /////// Warn-upon-finalization mechanism
 //
 // One of the difficult problems with promises is locating uncaught
 // rejections. We adopt the following strategy: if a promise is rejected
 // at the time of its garbage-collection *and* if the promise is at the
 // end of a promise chain (i.e. |thatPromise.then| has never been
 // called), then we print a warning.
 //
@@ -506,17 +509,17 @@ Promise.reject = function (aReason)
  *         that is rejected when any of the values are rejected. Its
  *         resolution value will be an array of all resolved values in the
  *         given order, or undefined if aValues is an empty array. The reject
  *         reason will be forwarded from the first promise in the list of
  *         given promises to be rejected.
  */
 Promise.all = function (aValues)
 {
-  if (aValues == null || typeof(aValues["@@iterator"]) != "function") {
+  if (aValues == null || typeof(aValues[ITERATOR_SYMBOL]) != "function") {
     throw new Error("Promise.all() expects an iterable.");
   }
 
   return new Promise((resolve, reject) => {
     let values = Array.isArray(aValues) ? aValues : [...aValues];
     let countdown = values.length;
     let resolutionValues = new Array(countdown);
 
@@ -557,17 +560,17 @@ Promise.all = function (aValues)
  *        be resolved or rejected as to the given value or reason.
  *
  * @return A new promise that is fulfilled when any values are resolved or
  *         rejected. Its resolution value will be forwarded from the resolution
  *         value or rejection reason.
  */
 Promise.race = function (aValues)
 {
-  if (aValues == null || typeof(aValues["@@iterator"]) != "function") {
+  if (aValues == null || typeof(aValues[ITERATOR_SYMBOL]) != "function") {
     throw new Error("Promise.race() expects an iterable.");
   }
 
   return new Promise((resolve, reject) => {
     for (let value of aValues) {
       Promise.resolve(value).then(resolve, reject);
     }
   });