Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 06 Sep 2013 20:55:41 -0400
changeset 158941 3697f962bb7b6f395ca47eca4396921861633118
parent 158911 ba0ecbba9addbfc268fc05ccebe211b01d6e182c (current diff)
parent 158940 8cad45f03f6aefd3cf27fe2c955fd6826bd867f8 (diff)
child 158942 096801f3b9735c495d7401a82081c79f9dc585c7
child 158952 bc76d8a21d903debe30ddb58761c500515af5b65
child 158985 e2bf999b88570725efd0736a5ed57c4e74974fd0
child 158989 a67532a34e35d9d9edab54db9b0f760a94c1fb5f
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.0a1
first release with
nightly linux32
3697f962bb7b / 26.0a1 / 20130907030204 / files
nightly linux64
3697f962bb7b / 26.0a1 / 20130907030204 / files
nightly mac
3697f962bb7b / 26.0a1 / 20130907030204 / files
nightly win32
3697f962bb7b / 26.0a1 / 20130907030204 / files
nightly win64
3697f962bb7b / 26.0a1 / 20130907030204 / 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 inbound to m-c.
dom/ipc/ContentParent.cpp
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -483,19 +483,16 @@ private:
 
     nsresult
     InitPolicies();
 
     nsresult
     InitDomainPolicy(JSContext* cx, const char* aPolicyName,
                      DomainPolicy* aDomainPolicy);
 
-    // JS strings we need to clean up on shutdown
-    static jsid sEnabledID;
-
     inline void
     ScriptSecurityPrefChanged();
 
     nsObjectHashtable* mOriginToPolicyMap;
     DomainPolicy* mDefaultPolicy;
     nsObjectHashtable* mCapabilities;
 
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -72,16 +72,28 @@ using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr;
 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
 bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
 
+// Lazily initialized. Use the getter below.
+static jsid sEnabledID = JSID_VOID;
+static jsid
+EnabledID()
+{
+    if (sEnabledID != JSID_VOID)
+        return sEnabledID;
+    AutoSafeJSContext cx;
+    sEnabledID = INTERNED_STRING_TO_JSID(cx, JS_InternString(cx, "enabled"));
+    return sEnabledID;
+}
+
 bool
 nsScriptSecurityManager::SubjectIsPrivileged()
 {
     JSContext *cx = GetCurrentJSContext();
     if (cx && xpc::IsUniversalXPConnectEnabled(cx))
         return true;
     bool isSystem = false;
     return NS_SUCCEEDED(SubjectPrincipalIsSystem(&isSystem)) && isSystem;
@@ -1441,17 +1453,17 @@ nsScriptSecurityManager::CheckLoadURIWit
             return NS_OK;
         }
 
         // Now check capability policies
         static const char loadURIPrefGroup[] = "checkloaduri";
         ClassInfoData nameData(nullptr, loadURIPrefGroup);
 
         SecurityLevel secLevel;
-        rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
+        rv = LookupPolicy(aPrincipal, nameData, EnabledID(),
                           nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
                           nullptr, &secLevel);
         if (NS_SUCCEEDED(rv) && secLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
         {
             // OK for this site!
             return NS_OK;
         }
 
@@ -1728,17 +1740,17 @@ nsScriptSecurityManager::CanExecuteScrip
     if (!*result)
         return NS_OK; // Do not run scripts
 
     //-- Check for a per-site policy
     static const char jsPrefGroupName[] = "javascript";
     ClassInfoData nameData(nullptr, jsPrefGroupName);
 
     SecurityLevel secLevel;
-    rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
+    rv = LookupPolicy(aPrincipal, nameData, EnabledID(),
                       nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
                       nullptr, &secLevel);
     if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
     {
         *result = false;
         return rv;
     }
 
@@ -2325,24 +2337,16 @@ nsScriptSecurityManager::nsScriptSecurit
 {
     static_assert(sizeof(intptr_t) == sizeof(void*),
                   "intptr_t and void* have different lengths on this platform. "
                   "This may cause a security failure with the SecurityLevel union.");
 }
 
 nsresult nsScriptSecurityManager::Init()
 {
-    JSContext* cx = GetSafeJSContext();
-    if (!cx) return NS_ERROR_FAILURE;   // this can happen of xpt loading fails
-    
-    ::JS_BeginRequest(cx);
-    if (sEnabledID == JSID_VOID)
-        sEnabledID = INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "enabled"));
-    ::JS_EndRequest(cx);
-
     InitPrefs();
 
     nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIStringBundleService> bundleService =
         mozilla::services::GetStringBundleService();
     if (!bundleService)
@@ -2373,18 +2377,16 @@ nsresult nsScriptSecurityManager::Init()
 
     JS_SetTrustedPrincipals(sRuntime, system);
 
     return NS_OK;
 }
 
 static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
 
-jsid nsScriptSecurityManager::sEnabledID   = JSID_VOID;
-
 nsScriptSecurityManager::~nsScriptSecurityManager(void)
 {
     Preferences::RemoveObservers(this, kObservedPrefs);
     delete mOriginToPolicyMap;
     if(mDefaultPolicy)
         mDefaultPolicy->Drop();
     delete mCapabilities;
 }
--- a/content/base/public/nsHostObjectProtocolHandler.h
+++ b/content/base/public/nsHostObjectProtocolHandler.h
@@ -4,26 +4,26 @@
 
 #ifndef nsHostObjectProtocolHandler_h
 #define nsHostObjectProtocolHandler_h
 
 #include "mozilla/Attributes.h"
 #include "nsIProtocolHandler.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
+#include "nsIInputStream.h"
 
 #define BLOBURI_SCHEME "blob"
 #define MEDIASTREAMURI_SCHEME "mediastream"
 #define MEDIASOURCEURI_SCHEME "mediasource"
 #define FONTTABLEURI_SCHEME "moz-fonttable"
 
 class nsIDOMBlob;
 class nsIDOMMediaStream;
 class nsIPrincipal;
-class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 class MediaSource;
 }
 }
 
 class nsHostObjectProtocolHandler : public nsIProtocolHandler
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -62,16 +62,17 @@
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/Attributes.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsFormData.h"
 #include "nsStreamListenerWrapper.h"
+#include "xpcjsid.h"
 
 #include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Maximum size that we'll grow an ArrayBuffer instead of doubling,
 // once doubling reaches this threshold
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -43,16 +43,17 @@
 
 class AsyncVerifyRedirectCallbackForwarder;
 class BlobSet;
 class nsDOMFile;
 class nsFormData;
 class nsIJARChannel;
 class nsILoadGroup;
 class nsIUnicodeDecoder;
+class nsIJSID;
 
 namespace mozilla {
 
 // A helper for building up an ArrayBuffer object's data
 // before creating the ArrayBuffer itself.  Will do doubling
 // based reallocation, up to an optional maximum growth given.
 //
 // When all the data has been appended, call getArrayBuffer,
--- a/content/canvas/test/webgl/non-conf-tests/Makefile.in
+++ b/content/canvas/test/webgl/non-conf-tests/Makefile.in
@@ -1,8 +1,9 @@
 #
 # 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/.
 
 MOCHITEST_FILES = \
   test_webgl_conformance.html \
+  test_webgl_request_mismatch.html \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/non-conf-tests/test_webgl_request_mismatch.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<title>WebGL test: Mismatched 'webgl' and 'experimental-webgl' context requests</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<body>
+<canvas id="c1"></canvas>
+<canvas id="c2"></canvas>
+<canvas id="c3"></canvas>
+<canvas id="c4"></canvas>
+<script>
+
+function testContextRetrieval(canvasId, creationId, requestId) {
+  var canvas = document.getElementById(canvasId);
+  ok(canvas, 'Invalid `canvasId`: ' + canvasId);
+
+  var createdGL = canvas.getContext(creationId);
+  if (!createdGL)
+    return; // No WebGL on this machine?
+
+  var requestedGL = canvas.getContext(requestId);
+  if (creationId == requestId) {
+    ok(requestedGL, 'Request for \'' + requestId + '\' on from \'' + creationId + '\' should succeed.');
+    ok(requestedGL == createdGL, 'Request for \'' + requestId + '\' on from \'' + creationId + '\' should match.');
+  } else {
+    ok(!requestedGL, 'Request for \'' + requestId + '\' on from \'' + creationId + '\' should fail.');
+  }
+}
+
+testContextRetrieval('c1', 'experimental-webgl', 'webgl');
+testContextRetrieval('c2', 'webgl', 'experimental-webgl');
+testContextRetrieval('c3', 'experimental-webgl', 'experimental-webgl');
+testContextRetrieval('c4', 'webgl', 'webgl');
+
+</script>
+
--- a/content/html/content/src/HTMLAudioElement.cpp
+++ b/content/html/content/src/HTMLAudioElement.cpp
@@ -13,16 +13,17 @@
 #include "nsIDocument.h"
 #include "jsfriendapi.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "AudioSampleFormat.h"
 #include "AudioChannelCommon.h"
 #include <algorithm>
 #include "mozilla/Preferences.h"
+#include "nsComponentManagerUtils.h"
 
 static bool
 IsAudioAPIEnabled()
 {
   return mozilla::Preferences::GetBool("media.audio_data.enabled", true);
 }
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -666,16 +666,24 @@ nsresult
 HTMLCanvasElement::GetContext(const nsAString& aContextId,
                               nsISupports** aContext)
 {
   ErrorResult rv;
   *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).get();
   return rv.ErrorCode();
 }
 
+static bool
+IsContextIdWebGL(const nsAString& str)
+{
+  return str.EqualsLiteral("webgl") ||
+         str.EqualsLiteral("experimental-webgl") ||
+         str.EqualsLiteral("moz-webgl");
+}
+
 already_AddRefed<nsISupports>
 HTMLCanvasElement::GetContext(JSContext* aCx,
                               const nsAString& aContextId,
                               JS::Handle<JS::Value> aContextOptions,
                               ErrorResult& rv)
 {
   if (mCurrentContextId.IsEmpty()) {
     rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
@@ -697,16 +705,30 @@ HTMLCanvasElement::GetContext(JSContext*
     if (rv.Failed()) {
       rv = NS_OK; // See bug 645792
       return nullptr;
     }
     mCurrentContextId.Assign(aContextId);
   }
 
   if (!mCurrentContextId.Equals(aContextId)) {
+    if (IsContextIdWebGL(aContextId) &&
+        IsContextIdWebGL(mCurrentContextId))
+    {
+      // Warn when we get a request for a webgl context with an id that differs
+      // from the id it was created with.
+      nsCString creationId = NS_LossyConvertUTF16toASCII(mCurrentContextId);
+      nsCString requestId = NS_LossyConvertUTF16toASCII(aContextId);
+      JS_ReportWarning(aCx, "WebGL: Retrieving a WebGL context from a canvas "
+                            "via a request id ('%s') different from the id used "
+                            "to create the context ('%s') is not allowed.",
+                            requestId.get(),
+                            creationId.get());
+    }
+    
     //XXX eventually allow for more than one active context on a given canvas
     return nullptr;
   }
 
   nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
   return context.forget();
 }
 
--- a/content/media/WebVTTLoadListener.cpp
+++ b/content/media/WebVTTLoadListener.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "WebVTTLoadListener.h"
 #include "mozilla/dom/TextTrackCue.h"
 #include "mozilla/dom/HTMLTrackElement.h"
+#include "nsIInputStream.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_1(WebVTTLoadListener, mElement)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebVTTLoadListener)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -6,16 +6,17 @@
 
 #include "MediaSource.h"
 
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "MediaSourceInputAdapter.h"
 #include "SourceBuffer.h"
 #include "SourceBufferList.h"
 #include "nsContentTypeParser.h"
+#include "nsIInputStream.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gMediaSourceLog;
 #define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
 #else
 #define LOG(type, msg)
 #endif
 
--- a/content/media/mediasource/MediaSource.h
+++ b/content/media/mediasource/MediaSource.h
@@ -13,16 +13,18 @@
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TypedArray.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsWrapperCache.h"
 #include "nscore.h"
 
+class nsIInputStream;
+
 namespace mozilla {
 namespace dom {
 
 class HTMLMediaElement;
 class MediaSourceInputAdapter;
 class SourceBufferList;
 class SourceBuffer;
 class TimeRanges;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -185,16 +185,17 @@
 #include "nsIDOMCameraManager.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 #include "nsIDOMLockedFile.h"
 #include "nsDebug.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Likely.h"
 #include "WindowNamedPropertiesHandler.h"
+#include "nsIInterfaceInfoManager.h"
 
 #ifdef MOZ_TIME_MANAGER
 #include "TimeManager.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::workers::ResolveWorkerClasses;
--- a/dom/base/nsDOMException.cpp
+++ b/dom/base/nsDOMException.cpp
@@ -10,16 +10,17 @@
 #include "nsCRTGlue.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsError.h"
 #include "nsIDOMDOMException.h"
 #include "nsIDocument.h"
 #include "nsString.h"
 #include "prprf.h"
+#include "nsIException.h"
 
 using namespace mozilla;
 
 enum DOM4ErrorTypeCodeMap {
   /* DOM4 errors from http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */
   IndexSizeError             = nsIDOMDOMException::INDEX_SIZE_ERR,
   HierarchyRequestError      = nsIDOMDOMException::HIERARCHY_REQUEST_ERR,
   WrongDocumentError         = nsIDOMDOMException::WRONG_DOCUMENT_ERR,
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -44,16 +44,17 @@
 #include "nsIInlineEventHandlers.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIIdleObserver.h"
 #include "nsIDocument.h"
 #include "nsIDOMTouchEvent.h"
 
 #include "mozilla/dom/EventTarget.h"
 #include "Units.h"
+#include "nsComponentManagerUtils.h"
 
 #ifdef MOZ_B2G
 #include "nsIDOMWindowB2G.h"
 #endif // MOZ_B2G
 
 #ifdef MOZ_WEBSPEECH
 #include "nsISpeechSynthesisGetter.h"
 #endif // MOZ_WEBSPEECH
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -50,16 +50,17 @@
 #include "nsIObjectOutputStream.h"
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
 #include "StructuredCloneTags.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
+#include "nsAXPCNativeCallContext.h"
 
 #include "nsJSPrincipals.h"
 
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
 #undef check
 #endif
 #include "AccessCheck.h"
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -12,16 +12,17 @@
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsGlobalWindow.h"
 #include "nsIContentSecurityPolicy.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 #include "mozilla/dom/FunctionBinding.h"
+#include "nsAXPCNativeCallContext.h"
 
 static const char kSetIntervalStr[] = "setInterval";
 static const char kSetTimeoutStr[] = "setTimeout";
 
 using namespace mozilla::dom;
 
 // Our JS nsIScriptTimeoutHandler implementation.
 class nsJSScriptTimeoutHandler MOZ_FINAL : public nsIScriptTimeoutHandler
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -23,16 +23,17 @@
 #include "mozilla/Likely.h"
 #include "mozilla/Util.h"
 #include "nsCycleCollector.h"
 #include "nsIXPConnect.h"
 #include "nsThreadUtils.h" // Hacky work around for some bindings needing NS_IsMainThread.
 #include "nsTraceRefcnt.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
+#include "nsIVariant.h"
 
 #include "nsWrapperCacheInlines.h"
 
 class nsPIDOMWindow;
 
 extern nsresult
 xpc_qsUnwrapArgImpl(JSContext* cx, jsval v, const nsIID& iid, void** ppArg,
                     nsISupports** ppArgRef, jsval* vp);
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -18,16 +18,18 @@
 
 #define DEVICESTORAGE_PICTURES   "pictures"
 #define DEVICESTORAGE_VIDEOS     "videos"
 #define DEVICESTORAGE_MUSIC      "music"
 #define DEVICESTORAGE_APPS       "apps"
 #define DEVICESTORAGE_SDCARD     "sdcard"
 #define DEVICESTORAGE_CRASHES    "crashes"
 
+class nsIInputStream;
+
 namespace mozilla {
 namespace dom {
 class DeviceStorageEnumerationParameters;
 class DOMCursor;
 class DOMRequest;
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -12,28 +12,28 @@
 #include "mozilla/Attributes.h"
 #include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
+#include "nsIInputStream.h"
 
 #define BEGIN_INDEXEDDB_NAMESPACE \
   namespace mozilla { namespace dom { namespace indexedDB {
 
 #define END_INDEXEDDB_NAMESPACE \
   } /* namespace indexedDB */ } /* namepsace dom */ } /* namespace mozilla */
 
 #define USING_INDEXEDDB_NAMESPACE \
   using namespace mozilla::dom::indexedDB;
 
 class nsIDOMBlob;
-class nsIInputStream;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class FileInfo;
 class IDBDatabase;
 class IDBTransaction;
 
 template <class T>
--- a/dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
+++ b/dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
@@ -3,31 +3,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIDOMGeoPositionCallback;
 interface nsIDOMGeoPositionErrorCallback;
 
 %{C++
-#include "DictionaryHelpers.h"
+namespace mozilla {
+namespace dom {
+class PositionOptions;
+}
+}
 %}
 
-dictionary GeoPositionOptions
-{
-  boolean enableHighAccuracy;
-  long timeout;
-  long maximumAge;
-};
-
-[ptr] native NamespacedGeoPositionOptions(mozilla::idl::GeoPositionOptions);
+[ptr] native NamespacedPositionOptions(mozilla::dom::PositionOptions);
 
 [builtinclass, uuid(1bc7d103-c7ae-4467-881c-21a8dfa17938)]
 interface nsIDOMGeoGeolocation : nsISupports
 {
   int32_t watchPosition(in nsIDOMGeoPositionCallback callback,
                         in nsIDOMGeoPositionErrorCallback errorCallback,
-                        in NamespacedGeoPositionOptions options);
+                        in NamespacedPositionOptions options);
   void getCurrentPosition(in nsIDOMGeoPositionCallback callback,
                           in nsIDOMGeoPositionErrorCallback errorCallback,
-                          in NamespacedGeoPositionOptions options);
+                          in NamespacedPositionOptions options);
   void clearWatch(in long watchId);
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/PFMRadioParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
+#include "mozilla/dom/GeolocationBinding.h"
 #include "SmsParent.h"
 #include "mozilla/Hal.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/net/NeckoParent.h"
@@ -143,17 +144,16 @@ static const char* sClipboardTextFlavors
 using base::ChildPrivileges;
 using base::KillProcess;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::dom::power;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::hal;
-using namespace mozilla::idl;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 
 namespace mozilla {
 namespace dom {
 
@@ -2616,18 +2616,18 @@ ContentParent::RecvFilePathUpdateNotify(
 static int32_t
 AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy)
 {
   nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
   if (!geo) {
     return -1;
   }
 
-  GeoPositionOptions* options = new GeoPositionOptions();
-  options->enableHighAccuracy = highAccuracy;
+  PositionOptions* options = new PositionOptions();
+  options->mEnableHighAccuracy = highAccuracy;
   int32_t retval = 1;
   geo->WatchPosition(watcher, nullptr, options, &retval);
   return retval;
 }
 
 bool
 ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
                                           const bool& aHighAccuracy)
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -66,56 +66,55 @@ class nsGeolocationRequest
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIGEOLOCATIONUPDATE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
 
   nsGeolocationRequest(Geolocation* aLocator,
                        const GeoPositionCallback& aCallback,
                        const GeoPositionErrorCallback& aErrorCallback,
-                       idl::GeoPositionOptions* aOptions,
+                       PositionOptions* aOptions,
                        bool aWatchPositionRequest = false,
                        int32_t aWatchId = 0);
   void Shutdown();
 
   void SendLocation(nsIDOMGeoPosition* location);
-  bool WantsHighAccuracy() {return mOptions && mOptions->enableHighAccuracy;}
+  bool WantsHighAccuracy() {return mOptions && mOptions->mEnableHighAccuracy;}
   void SetTimeoutTimer();
   nsIPrincipal* GetPrincipal();
 
   ~nsGeolocationRequest();
 
   virtual bool Recv__delete__(const bool& allow) MOZ_OVERRIDE;
   virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
 
   bool IsWatch() { return mIsWatchPositionRequest; }
   int32_t WatchId() { return mWatchId; }
  private:
   bool mIsWatchPositionRequest;
 
   nsCOMPtr<nsITimer> mTimeoutTimer;
   GeoPositionCallback mCallback;
   GeoPositionErrorCallback mErrorCallback;
-  nsAutoPtr<idl::GeoPositionOptions> mOptions;
+  nsAutoPtr<PositionOptions> mOptions;
 
   nsRefPtr<Geolocation> mLocator;
 
   int32_t mWatchId;
   bool mShutdown;
 };
 
-static idl::GeoPositionOptions*
-GeoPositionOptionsFromPositionOptions(const PositionOptions& aOptions)
+static PositionOptions*
+CreatePositionOptionsCopy(const PositionOptions& aOptions)
 {
-  nsAutoPtr<idl::GeoPositionOptions> geoOptions(
-    new idl::GeoPositionOptions());
+  nsAutoPtr<PositionOptions> geoOptions(new PositionOptions());
 
-  geoOptions->enableHighAccuracy = aOptions.mEnableHighAccuracy;
-  geoOptions->maximumAge = aOptions.mMaximumAge;
-  geoOptions->timeout = aOptions.mTimeout;
+  geoOptions->mEnableHighAccuracy = aOptions.mEnableHighAccuracy;
+  geoOptions->mMaximumAge = aOptions.mMaximumAge;
+  geoOptions->mTimeout = aOptions.mTimeout;
 
   return geoOptions.forget();
 }
 
 class GeolocationSettingsCallback : public nsISettingsServiceCallback
 {
 public:
   NS_DECL_ISUPPORTS
@@ -331,17 +330,17 @@ PositionError::NotifyCallback(const GeoP
 }
 ////////////////////////////////////////////////////
 // nsGeolocationRequest
 ////////////////////////////////////////////////////
 
 nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
                                            const GeoPositionCallback& aCallback,
                                            const GeoPositionErrorCallback& aErrorCallback,
-                                           idl::GeoPositionOptions* aOptions,
+                                           PositionOptions* aOptions,
                                            bool aWatchPositionRequest,
                                            int32_t aWatchId)
   : mIsWatchPositionRequest(aWatchPositionRequest),
     mCallback(aCallback),
     mErrorCallback(aErrorCallback),
     mOptions(aOptions),
     mLocator(aLocator),
     mWatchId(aWatchId),
@@ -455,21 +454,21 @@ nsGeolocationRequest::Allow()
   //
   // either:
   // a) the user has specified a maximumAge which allows us to return a cached value,
   // -or-
   // b) the cached position time is some reasonable value to return to the user (<30s)
 
   uint32_t maximumAge = 30 * PR_MSEC_PER_SEC;
   if (mOptions) {
-    if (mOptions->maximumAge >= 0) {
-      maximumAge = mOptions->maximumAge;
+    if (mOptions->mMaximumAge >= 0) {
+      maximumAge = mOptions->mMaximumAge;
     }
   }
-  gs->SetHigherAccuracy(mOptions && mOptions->enableHighAccuracy);
+  gs->SetHigherAccuracy(mOptions && mOptions->mEnableHighAccuracy);
 
   bool canUseCache = lastPosition && maximumAge > 0 &&
     (PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
     PRTime(cachedPositionTime));
 
   if (canUseCache) {
     // okay, we can return a cached position
     // getCurrentPosition requests serviced by the cache
@@ -492,17 +491,17 @@ void
 nsGeolocationRequest::SetTimeoutTimer()
 {
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
     mTimeoutTimer = nullptr;
   }
 
   int32_t timeout;
-  if (mOptions && (timeout = mOptions->timeout) != 0) {
+  if (mOptions && (timeout = mOptions->mTimeout) != 0) {
 
     if (timeout < 0) {
       timeout = 0;
     } else if (timeout < 10) {
       timeout = 10;
     }
 
     mTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1");
@@ -595,17 +594,17 @@ nsGeolocationRequest::Shutdown()
 
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
     mTimeoutTimer = nullptr;
   }
 
   // This should happen last, to ensure that this request isn't taken into consideration
   // when deciding whether existing requests still require high accuracy.
-  if (mOptions && mOptions->enableHighAccuracy) {
+  if (mOptions && mOptions->mEnableHighAccuracy) {
     nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
     if (gs) {
       gs->SetHigherAccuracy(false);
     }
   }
 }
 
 bool nsGeolocationRequest::Recv__delete__(const bool& allow)
@@ -1195,44 +1194,43 @@ void
 Geolocation::GetCurrentPosition(PositionCallback& aCallback,
                                 PositionErrorCallback* aErrorCallback,
                                 const PositionOptions& aOptions,
                                 ErrorResult& aRv)
 {
   GeoPositionCallback successCallback(&aCallback);
   GeoPositionErrorCallback errorCallback(aErrorCallback);
 
-  nsresult rv =
-    GetCurrentPosition(successCallback, errorCallback,
-                       GeoPositionOptionsFromPositionOptions(aOptions));
+  nsresult rv = GetCurrentPosition(successCallback, errorCallback,
+                                   CreatePositionOptionsCopy(aOptions));
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 
   return;
 }
 
 NS_IMETHODIMP
 Geolocation::GetCurrentPosition(nsIDOMGeoPositionCallback* aCallback,
                                 nsIDOMGeoPositionErrorCallback* aErrorCallback,
-                                idl::GeoPositionOptions* aOptions)
+                                PositionOptions* aOptions)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
 
   GeoPositionCallback successCallback(aCallback);
   GeoPositionErrorCallback errorCallback(aErrorCallback);
 
   return GetCurrentPosition(successCallback, errorCallback, aOptions);
 }
 
 nsresult
 Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
                                 GeoPositionErrorCallback& errorCallback,
-                                idl::GeoPositionOptions *options)
+                                PositionOptions *options)
 {
   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
                                                                     callback,
                                                                     errorCallback,
@@ -1284,45 +1282,44 @@ Geolocation::WatchPosition(PositionCallb
                            PositionErrorCallback* aErrorCallback,
                            const PositionOptions& aOptions,
                            ErrorResult& aRv)
 {
   int32_t ret;
   GeoPositionCallback successCallback(&aCallback);
   GeoPositionErrorCallback errorCallback(aErrorCallback);
 
-  nsresult rv =
-    WatchPosition(successCallback, errorCallback,
-                  GeoPositionOptionsFromPositionOptions(aOptions), &ret);
+  nsresult rv = WatchPosition(successCallback, errorCallback,
+                              CreatePositionOptionsCopy(aOptions), &ret);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 
   return ret;
 }
 
 NS_IMETHODIMP
 Geolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
                            nsIDOMGeoPositionErrorCallback *aErrorCallback,
-                           idl::GeoPositionOptions *aOptions,
+                           PositionOptions *aOptions,
                            int32_t* aRv)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
 
   GeoPositionCallback successCallback(aCallback);
   GeoPositionErrorCallback errorCallback(aErrorCallback);
 
   return WatchPosition(successCallback, errorCallback, aOptions, aRv);
 }
 
 nsresult
 Geolocation::WatchPosition(GeoPositionCallback& aCallback,
                            GeoPositionErrorCallback& aErrorCallback,
-                           idl::GeoPositionOptions* aOptions,
+                           PositionOptions* aOptions,
                            int32_t* aRv)
 {
   if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // The watch ID:
   *aRv = mLastWatchId++;
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -171,18 +171,18 @@ public:
 
   // Notification from the service:
   void ServiceReady();
 
 private:
 
   ~Geolocation();
 
-  nsresult GetCurrentPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, mozilla::idl::GeoPositionOptions* aOptions);
-  nsresult WatchPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, mozilla::idl::GeoPositionOptions* aOptions, int32_t* aRv);
+  nsresult GetCurrentPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, PositionOptions* aOptions);
+  nsresult WatchPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, PositionOptions* aOptions, int32_t* aRv);
 
   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
 
   // Methods for the service when it's ready to process requests:
   nsresult GetCurrentPositionReady(nsGeolocationRequest* aRequest);
   nsresult WatchPositionReady(nsGeolocationRequest* aRequest);
 
   // Two callback arrays.  The first |mPendingCallbacks| holds objects for only
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -25,16 +25,17 @@
 #include "Exceptions.h"
 #include "File.h"
 #include "RuntimeService.h"
 #include "WorkerPrivate.h"
 #include "XMLHttpRequestUpload.h"
 
 #include "DOMBindingInlines.h"
 #include "mozilla/Attributes.h"
+#include "nsComponentManagerUtils.h"
 
 using namespace mozilla;
 
 using namespace mozilla::dom;
 USING_WORKERS_NAMESPACE
 
 using mozilla::dom::workers::exceptions::ThrowDOMExceptionForNSResult;
 
--- a/embedding/components/find/src/nsWebBrowserFind.cpp
+++ b/embedding/components/find/src/nsWebBrowserFind.cpp
@@ -33,16 +33,17 @@
 #include "nsIServiceManager.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsFind.h"
 #include "nsError.h"
 #include "nsFocusManager.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/Element.h"
+#include "nsISimpleEnumerator.h"
 
 #if DEBUG
 #include "nsIWebNavigation.h"
 #include "nsXPIDLString.h"
 #endif
 
 #if defined(XP_MACOSX) && !defined(__LP64__)
 #include "nsAutoPtr.h"
--- a/js/jsd/jsd_val.cpp
+++ b/js/jsd/jsd_val.cpp
@@ -472,20 +472,17 @@ JSDProperty*
 jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr)
 {
     JS::RootedString name(jsdc->jsrt, nameStr);
     AutoSafeJSContext cx;
     JSAutoCompartment acBase(cx, jsdc->glob);
     JSDProperty* jsdprop;
     JSDProperty* iter = NULL;
     JS::RootedObject obj(cx);
-    unsigned  attrs = 0;
     bool found;
-    const jschar * nameChars;
-    size_t nameLen;
     JS::RootedValue val(cx), nameval(cx);
     JS::RootedId nameid(cx);
     JS::RootedValue propId(cx);
     JS::RootedValue propValue(cx);
     JS::RootedValue propAlias(cx);
     uint8_t propFlags;
 
     if(!jsd_IsValueObject(jsdc, jsdval))
@@ -499,34 +496,38 @@ jsd_GetValueProperty(JSDContext* jsdc, J
             int result;
             if (JS_CompareStrings(cx, propName, name, &result) && !result)
                 return jsdprop;
         }
         JSD_DropProperty(jsdc, jsdprop);
     }
     /* Not found in property list, look it up explicitly */
 
+    nameval = STRING_TO_JSVAL(name);
+    if(!JS_ValueToId(cx, nameval, nameid.address()))
+        return NULL;
+
     if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
         return NULL;
 
-    if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
-        return NULL;
-
+    JS::Rooted<JSPropertyDescriptor> desc(cx);
     {
         JSAutoCompartment ac(cx, obj);
+        JS::RootedId id(cx, nameid);
 
-        JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
-        if (!found)
-        {
+        if(!JS_WrapId(cx, id.address()))
             return NULL;
-        }
+        if(!JS_GetOwnPropertyDescriptorById(cx, obj, id, 0, &desc))
+            return NULL;
+        if(!desc.object())
+            return NULL;
 
         JS_ClearPendingException(cx);
 
-        if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
+        if(!JS_GetPropertyById(cx, obj, id, &val))
         {
             if (JS_IsExceptionPending(cx))
             {
                 if (!JS_GetPendingException(cx, propValue.address()))
                 {
                     return NULL;
                 }
                 propFlags = JSPD_EXCEPTION;
@@ -538,26 +539,23 @@ jsd_GetValueProperty(JSDContext* jsdc, J
             }
         }
         else
         {
             propValue = val;
         }
     }
 
-    nameval = STRING_TO_JSVAL(name);
-    if (!JS_ValueToId(cx, nameval, nameid.address()) ||
-        !JS_IdToValue(cx, nameid, propId.address())) {
+    if (!JS_IdToValue(cx, nameid, propId.address()))
         return NULL;
-    }
 
     propAlias = JSVAL_NULL;
-    propFlags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
-        | (attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0
-        | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
+    propFlags |= desc.isEnumerable() ? JSPD_ENUMERATE : 0
+        | desc.isReadonly() ? JSPD_READONLY  : 0
+        | desc.isPermanent() ? JSPD_PERMANENT : 0;
 
     return _newProperty(jsdc, propId, propValue, propAlias, propFlags, JSDPD_HINTED);
 }
 
 /*
  * Retrieve a JSFunction* from a JSDValue*. This differs from
  * JS_ValueToFunction by fully unwrapping the object first.
  */
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -368,20 +368,16 @@ typedef bool
 (* StrictSpecialIdOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
                       JS::MutableHandleValue vp, bool strict);
 typedef bool
 (* GenericAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
 typedef bool
 (* PropertyAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
                          unsigned *attrsp);
 typedef bool
-(* ElementAttributesOp)(JSContext *cx, JS::HandleObject obj, uint32_t index, unsigned *attrsp);
-typedef bool
-(* SpecialAttributesOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, unsigned *attrsp);
-typedef bool
 (* DeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
                      bool *succeeded);
 typedef bool
 (* DeleteElementOp)(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded);
 typedef bool
 (* DeleteSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, bool *succeeded);
 
 
@@ -463,35 +459,28 @@ struct ObjectOps
     ElementIdOp         getElement;
     ElementIfPresentOp  getElementIfPresent; /* can be null */
     SpecialIdOp         getSpecial;
     StrictGenericIdOp   setGeneric;
     StrictPropertyIdOp  setProperty;
     StrictElementIdOp   setElement;
     StrictSpecialIdOp   setSpecial;
     GenericAttributesOp getGenericAttributes;
-    PropertyAttributesOp getPropertyAttributes;
-    ElementAttributesOp getElementAttributes;
-    SpecialAttributesOp getSpecialAttributes;
     GenericAttributesOp setGenericAttributes;
-    PropertyAttributesOp setPropertyAttributes;
-    ElementAttributesOp setElementAttributes;
-    SpecialAttributesOp setSpecialAttributes;
     DeletePropertyOp    deleteProperty;
     DeleteElementOp     deleteElement;
     DeleteSpecialOp     deleteSpecial;
 
     JSNewEnumerateOp    enumerate;
     ObjectOp            thisObject;
 };
 
 #define JS_NULL_OBJECT_OPS                                                    \
     {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,   \
-     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,        \
-     NULL,NULL,NULL}
+     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
 
 } // namespace js
 
 // Classes, objects, and properties.
 
 typedef void (*JSClassInternal)();
 
 struct JSClass {
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1659,23 +1659,17 @@ Class BinaryBlock::class_ = {
         BinaryBlock::obj_getElement,
         BinaryBlock::obj_getElementIfPresent,
         BinaryBlock::obj_getSpecial,
         BinaryBlock::obj_setGeneric,
         BinaryBlock::obj_setProperty,
         BinaryBlock::obj_setElement,
         BinaryBlock::obj_setSpecial,
         BinaryBlock::obj_getGenericAttributes,
-        BinaryBlock::obj_getPropertyAttributes,
-        BinaryBlock::obj_getElementAttributes,
-        BinaryBlock::obj_getSpecialAttributes,
         BinaryBlock::obj_setGenericAttributes,
-        BinaryBlock::obj_setPropertyAttributes,
-        BinaryBlock::obj_setElementAttributes,
-        BinaryBlock::obj_setSpecialAttributes,
         BinaryBlock::obj_deleteProperty,
         BinaryBlock::obj_deleteElement,
         BinaryBlock::obj_deleteSpecial,
         BinaryBlock::obj_enumerate,
         NULL, /* thisObject */
     }
 };
 
@@ -2199,43 +2193,16 @@ BinaryBlock::obj_getGenericAttributes(JS
     if (!proto) {
         *attrsp = 0;
         return true;
     }
 
     return JSObject::getGenericAttributes(cx, proto, id, attrsp);
 }
 
-bool
-BinaryBlock::obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
-                                        HandlePropertyName name,
-                                        unsigned *attrsp)
-{
-    RootedId id(cx, NameToId(name));
-    return obj_getGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
-BinaryBlock::obj_getElementAttributes(JSContext *cx, HandleObject obj,
-                                       uint32_t index, unsigned *attrsp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return obj_getGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
-BinaryBlock::obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
-                                       HandleSpecialId sid, unsigned *attrsp)
-{
-    RootedId id(cx, SPECIALID_TO_JSID(sid));
-    return obj_getGenericAttributes(cx, obj, id, attrsp);
-}
-
 static bool
 IsOwnId(JSContext *cx, HandleObject obj, HandleId id)
 {
     uint32_t index;
     RootedObject type(cx, GetType(obj));
     TypeRepresentation *typeRepr = typeRepresentation(type);
 
     switch (typeRepr->kind()) {
@@ -2266,43 +2233,16 @@ BinaryBlock::obj_setGenericAttributes(JS
         *attrsp = 0;
         return true;
     }
 
     return JSObject::setGenericAttributes(cx, proto, id, attrsp);
 }
 
 bool
-BinaryBlock::obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
-                                        HandlePropertyName name,
-                                        unsigned *attrsp)
-{
-    RootedId id(cx, NameToId(name));
-    return obj_setGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
-BinaryBlock::obj_setElementAttributes(JSContext *cx, HandleObject obj,
-                                       uint32_t index, unsigned *attrsp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return obj_setGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
-BinaryBlock::obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
-                                      HandleSpecialId sid, unsigned *attrsp)
-{
-    RootedId id(cx, SPECIALID_TO_JSID(sid));
-    return obj_setGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
 BinaryBlock::obj_deleteProperty(JSContext *cx, HandleObject obj,
                                 HandlePropertyName name, bool *succeeded)
 {
     Rooted<jsid> id(cx, NameToId(name));
     if (IsOwnId(cx, obj, id))
         return ReportPropertyError(cx, JSMSG_CANT_DELETE, id);
 
     RootedObject proto(cx, obj->getProto());
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -176,31 +176,18 @@ class BinaryBlock
                                   MutableHandleValue vp, bool strict);
     static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
                                  MutableHandleValue vp, bool strict);
     static bool obj_setSpecial(JSContext *cx, HandleObject obj,
                                  HandleSpecialId sid, MutableHandleValue vp, bool strict);
 
     static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
                                            HandleId id, unsigned *attrsp);
-    static bool obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
-                                            HandlePropertyName name, unsigned *attrsp);
-    static bool obj_getElementAttributes(JSContext *cx, HandleObject obj,
-                                           uint32_t index, unsigned *attrsp);
-    static bool obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
-                                           HandleSpecialId sid, unsigned *attrsp);
-
     static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                            HandleId id, unsigned *attrsp);
-    static bool obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
-                                            HandlePropertyName name, unsigned *attrsp);
-    static bool obj_setElementAttributes(JSContext *cx, HandleObject obj,
-                                           uint32_t index, unsigned *attrsp);
-    static bool obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
-                                           HandleSpecialId sid, unsigned *attrsp);
 
     static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                      bool *succeeded);
     static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
                                     bool *succeeded);
     static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                                     bool *succeeded);
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1647,16 +1647,21 @@ IonCompile(JSContext *cx, JSScript *scri
 
     JS_ASSERT(!GetIonScript(builder->script(), executionMode));
     JS_ASSERT(CanIonCompile(builder->script(), executionMode));
 
     RootedScript builderScript(cx, builder->script());
     IonSpewNewFunction(graph, builderScript);
 
     if (!builder->build()) {
+        if (cx->isExceptionPending()) {
+            IonSpew(IonSpew_Abort, "Builder raised exception.");
+            return AbortReason_Error;
+        }
+
         IonSpew(IonSpew_Abort, "Builder failed to build.");
         return builder->abortReason();
     }
     builder->clearForBackEnd();
 
     // If possible, compile the script off thread.
     if (OffThreadCompilationAvailable(cx)) {
         SetIonScript(builder->script(), executionMode, ION_COMPILING_SCRIPT);
@@ -1827,16 +1832,19 @@ Compile(JSContext *cx, HandleScript scri
     if (executionMode == SequentialExecution) {
         // Use getUseCount instead of incUseCount to avoid bumping the
         // use count twice.
         if (script->getUseCount() < js_IonOptions.usesBeforeCompile)
             return Method_Skipped;
     }
 
     AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode);
+    if (reason == AbortReason_Error)
+        return Method_Error;
+
     if (reason == AbortReason_Disable)
         return Method_CantCompile;
 
     // Compilation succeeded or we invalidated right away or an inlining/alloc abort
     return HasIonScript(script, executionMode) ? Method_Compiled : Method_Skipped;
 }
 
 } // namespace jit
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -250,16 +250,17 @@ enum MethodStatus
     Method_Skipped,
     Method_Compiled
 };
 
 enum AbortReason {
     AbortReason_Alloc,
     AbortReason_Inlining,
     AbortReason_Disable,
+    AbortReason_Error,
     AbortReason_NoAbort
 };
 
 // An Ion context is needed to enter into either an Ion method or an instance
 // of the Ion compiler. It points to a temporary allocator and the active
 // JSContext, either of which may be NULL, and the active compartment, which
 // will not be NULL.
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3767,24 +3767,33 @@ IonBuilder::inlineScriptedCall(CallInfo 
                                                  this->info().executionMode());
     if (!info)
         return false;
 
     MIRGraphExits saveExits;
     AutoAccumulateExits aae(graph(), saveExits);
 
     // Build the graph.
+    JS_ASSERT(!cx->isExceptionPending());
     IonBuilder inlineBuilder(cx, &temp(), &graph(), &inspector, info, NULL,
                              inliningDepth_ + 1, loopDepth_);
     if (!inlineBuilder.buildInline(this, outerResumePoint, callInfo)) {
         JS_ASSERT(calleeScript->hasAnalysis());
+        if (cx->isExceptionPending()) {
+            IonSpew(IonSpew_Abort, "Inline builder raised exception.");
+            abortReason_ = AbortReason_Error;
+            return false;
+        }
 
         // Inlining the callee failed. Disable inlining the function
-        if (inlineBuilder.abortReason_ == AbortReason_Disable)
+        if (inlineBuilder.abortReason_ == AbortReason_Disable) {
+            // Only mark callee as un-inlineable only if the inlining was aborted
+            // for a non-exception reason.
             calleeScript->analysis()->setIonUninlineable();
+        }
 
         abortReason_ = AbortReason_Inlining;
         return false;
     }
 
     // Create return block.
     jsbytecode *postCall = GetNextPc(pc);
     MBasicBlock *returnBlock = newBlock(NULL, postCall);
@@ -5560,19 +5569,30 @@ IonBuilder::jsop_initprop(HandleProperty
     if (!CanEffectlesslyCallLookupGenericOnObject(cx, templateObject, id))
         return abort("INITPROP template object is special");
 
     bool res = LookupPropertyWithFlags(cx, templateObject, id,
                                        0, &holder, &shape);
     if (!res)
         return false;
 
-    if (!shape || holder != templateObject ||
-        PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value))
+    if (!shape || holder != templateObject) {
+        // JSOP_NEWINIT becomes an MNewObject without preconfigured properties.
+        MInitProp *init = MInitProp::New(obj, name, value);
+        current->add(init);
+        return resumeAfter(init);
+    }
+
+    bool writeNeedsBarrier = false;
+    if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value, /* canModify = */ true,
+                                       &writeNeedsBarrier))
     {
+        return false;
+    }
+    if (writeNeedsBarrier) {
         // JSOP_NEWINIT becomes an MNewObject without preconfigured properties.
         MInitProp *init = MInitProp::New(obj, name, value);
         current->add(init);
         return resumeAfter(init);
     }
 
     if (NeedsPostBarrier(info(), value))
         current->add(MPostWriteBarrier::New(obj, value));
@@ -6262,17 +6282,22 @@ IonBuilder::getStaticName(HandleObject s
     if (propertyTypes && propertyTypes->isOwnProperty(cx, staticType, true)) {
         // The property has been reconfigured as non-configurable, non-enumerable
         // or non-writable.
         *psucceeded = false;
         return true;
     }
 
     types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
-    bool barrier = PropertyReadNeedsTypeBarrier(cx, staticType, name, types);
+    bool barrier;
+    if (!PropertyReadNeedsTypeBarrier(cx, staticType, name, types, /* updateObserved = */ true,
+                                      &barrier))
+    {
+        return false;
+    }
 
     // If the property is permanent, a shape guard isn't necessary.
 
     JSObject *singleton = types->getSingleton();
 
     JSValueType knownType = types->getKnownTypeTag();
     if (!barrier) {
         if (singleton) {
@@ -6786,17 +6811,19 @@ IonBuilder::getElemTryCache(bool *emitte
     // of this getelem.
     bool nonNativeGetElement = inspector->hasSeenNonNativeGetElement(pc);
     if (index->mightBeType(MIRType_Int32) && nonNativeGetElement)
         return true;
 
     // Emit GetElementCache.
 
     types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
-    bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types);
+    bool barrier;
+    if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, types, &barrier))
+        return false;
 
     // Always add a barrier if the index might be a string, so that the cache
     // can attach stubs for particular properties.
     if (index->mightBeType(MIRType_String))
         barrier = true;
 
     // See note about always needing a barrier in jsop_getprop.
     if (needsToMonitorMissingProperties(types))
@@ -6830,20 +6857,24 @@ bool
 IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
 {
     types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
 
     if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String) && types->noConstraints()) {
         // Indexed call on an element of an array. Populate the observed types
         // with any objects that could be in the array, to avoid extraneous
         // type barriers.
-        AddObjectsForPropertyRead(cx, obj, NULL, types);
-    }
-
-    bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types);
+        if (!AddObjectsForPropertyRead(cx, obj, NULL, types))
+            return false;
+    }
+
+    bool barrier;
+    if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, types, &barrier))
+        return false;
+
     bool needsHoleCheck = !ElementAccessIsPacked(cx, obj);
 
     // Reads which are on holes in the object do not have to bail out if
     // undefined values have been observed at this access site and the access
     // cannot hit another indexed property on the object or its prototypes.
     bool readOutOfBounds =
         types->hasType(types::Type::UndefinedType()) &&
         !ElementAccessHasExtraIndexedProperty(cx, obj);
@@ -7198,17 +7229,23 @@ IonBuilder::setElemTryTyped(bool *emitte
 bool
 IonBuilder::setElemTryDense(bool *emitted, MDefinition *object,
                             MDefinition *index, MDefinition *value)
 {
     JS_ASSERT(*emitted == false);
 
     if (!ElementAccessIsDenseNative(object, index))
         return true;
-    if (PropertyWriteNeedsTypeBarrier(cx, current, &object, NULL, &value))
+    bool needsBarrier;
+    if (!PropertyWriteNeedsTypeBarrier(cx, current, &object, NULL, &value, /* canModify = */ true,
+                                       &needsBarrier))
+    {
+        return false;
+    }
+    if (needsBarrier)
         return true;
     if (!object->resultTypeSet())
         return true;
 
     types::StackTypeSet::DoubleConversion conversion =
         object->resultTypeSet()->convertDoubleElements(cx);
 
     // If AmbiguousDoubleConversion, only handle int32 values for now.
@@ -7258,17 +7295,24 @@ IonBuilder::setElemTryCache(bool *emitte
 
     // TODO: Bug 876650: remove this check:
     // Temporary disable the cache if non dense native,
     // untill the cache supports more ics
     SetElemICInspector icInspect(inspector->setElemICInspector(pc));
     if (!icInspect.sawDenseWrite())
         return true;
 
-    if (PropertyWriteNeedsTypeBarrier(cx, current, &object, NULL, &value))
+    bool needsBarrier;
+    if (PropertyWriteNeedsTypeBarrier(cx, current, &object, NULL, &value, /* canModify = */ true,
+                                      &needsBarrier))
+    {
+        return false;
+    }
+
+    if (needsBarrier)
         return true;
 
     // Emit SetElementCache.
     MInstruction *ins = MSetElementCache::New(object, index, value, script()->strict);
     current->add(ins);
     current->push(value);
 
     if (!resumeAfter(ins))
@@ -7278,17 +7322,20 @@ IonBuilder::setElemTryCache(bool *emitte
     return true;
 }
 
 bool
 IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
                                SetElemSafety safety,
                                MDefinition *obj, MDefinition *id, MDefinition *value)
 {
-    MIRType elementType = DenseNativeElementType(cx, obj);
+    MIRType elementType;
+    if (!DenseNativeElementType(cx, obj, &elementType))
+        return false;
+
     bool packed = ElementAccessIsPacked(cx, obj);
 
     // Writes which are on holes in the object do not have to bail out if they
     // cannot hit another indexed property on the object or its prototypes.
     bool writeOutOfBounds = !ElementAccessHasExtraIndexedProperty(cx, obj);
 
     if (NeedsPostBarrier(info(), value))
         current->add(MPostWriteBarrier::New(obj, value));
@@ -8095,17 +8142,19 @@ IonBuilder::jsop_getprop(HandlePropertyN
     bool emitted = false;
 
     types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
 
     // Try to optimize arguments.length.
     if (!getPropTryArgumentsLength(&emitted) || emitted)
         return emitted;
 
-    bool barrier = PropertyReadNeedsTypeBarrier(cx, current->peek(-1), name, types);
+    bool barrier;
+    if (!PropertyReadNeedsTypeBarrier(cx, current->peek(-1), name, types, &barrier))
+        return false;
 
     // Try to hardcode known constants.
     if (!getPropTryConstant(&emitted, id, types) || emitted)
         return emitted;
 
     // Except when loading constants above, always use a call if we are doing
     // the definite properties analysis and not actually emitting code, to
     // simplify later analysis.
@@ -8400,17 +8449,21 @@ IonBuilder::getPropTryCache(bool *emitte
     //
     // In parallel execution, idempotency of caches is ignored, since we
     // repeat the entire ForkJoin workload if we bail out. Note that it's
     // overly restrictive to mark everything as idempotent, because we can
     // treat non-idempotent caches in parallel as repeatable.
     if (obj->type() == MIRType_Object && !invalidatedIdempotentCache() &&
         info().executionMode() != ParallelExecution)
     {
-        if (PropertyReadIsIdempotent(cx, obj, name))
+        bool idempotent;
+        if (!PropertyReadIsIdempotent(cx, obj, name, &idempotent))
+            return false;
+
+        if (idempotent)
             load->setIdempotent();
     }
 
     if (JSOp(*pc) == JSOP_CALLPROP) {
         if (!annotateGetPropertyCache(cx, obj, load, obj->resultTypeSet(), types))
             return false;
     }
 
@@ -8475,17 +8528,22 @@ IonBuilder::jsop_setprop(HandlePropertyN
     if (NeedsPostBarrier(info(), value))
         current->add(MPostWriteBarrier::New(obj, value));
 
     // Try to inline a common property setter, or make a call.
     if (!setPropTryCommonSetter(&emitted, obj, name, id, value) || emitted)
         return emitted;
 
     types::StackTypeSet *objTypes = obj->resultTypeSet();
-    bool barrier = PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value);
+    bool barrier;
+    if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value,
+                                       /* canModify = */ true, &barrier))
+    {
+        return false;
+    }
 
     // Try to emit store from definite slots.
     if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
         return emitted;
 
     // Try to emit a monomorphic/polymorphic store based on baseline caches.
     if (!setPropTryInlineAccess(&emitted, obj, name, id, value, barrier, objTypes) || emitted)
         return emitted;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -318,17 +318,20 @@ IonBuilder::inlineArrayPopShift(CallInfo
         return InliningStatus_NotInlined;
 
     callInfo.unwrapArgs();
 
     types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
     bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
     bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
 
-    bool barrier = PropertyReadNeedsTypeBarrier(cx, callInfo.thisArg(), NULL, returnTypes);
+    bool barrier;
+    if (!PropertyReadNeedsTypeBarrier(cx, callInfo.thisArg(), NULL, returnTypes, &barrier))
+        return InliningStatus_Error;
+
     if (barrier)
         returnType = MIRType_Value;
 
     MArrayPopShift *ins = MArrayPopShift::New(callInfo.thisArg(), mode,
                                               needsHoleCheck, maybeUndefined);
     current->add(ins);
     current->push(ins);
     ins->setResultType(returnType);
@@ -345,17 +348,23 @@ IonBuilder::inlineArrayPopShift(CallInfo
 IonBuilder::InliningStatus
 IonBuilder::inlineArrayPush(CallInfo &callInfo)
 {
     if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     MDefinition *obj = callInfo.thisArg();
     MDefinition *value = callInfo.getArg(0);
-    if (PropertyWriteNeedsTypeBarrier(cx, current, &obj, NULL, &value, /* canModify = */ false))
+    bool writeNeedsBarrier;
+    if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, NULL, &value, /* canModify = */ false,
+                                       &writeNeedsBarrier))
+    {
+        return InliningStatus_Error;
+    }
+    if (writeNeedsBarrier)
         return InliningStatus_NotInlined;
     JS_ASSERT(obj == callInfo.thisArg() && value == callInfo.getArg(0));
 
     if (getInlineReturnType() != MIRType_Int32)
         return InliningStatus_NotInlined;
     if (callInfo.thisArg()->type() != MIRType_Object)
         return InliningStatus_NotInlined;
 
@@ -997,22 +1006,32 @@ IonBuilder::inlineUnsafePutElements(Call
         uint32_t arri = base + 0;
         uint32_t idxi = base + 1;
         uint32_t elemi = base + 2;
 
         MDefinition *obj = callInfo.getArg(arri);
         MDefinition *id = callInfo.getArg(idxi);
         MDefinition *elem = callInfo.getArg(elemi);
 
+        bool isDenseNative = ElementAccessIsDenseNative(obj, id);
+
+        bool writeNeedsBarrier = false;
+        if (isDenseNative) {
+            if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, NULL, &elem,
+                                               /* canModify = */ false,
+                                               &writeNeedsBarrier))
+            {
+                return InliningStatus_Error;
+            }
+        }
+
         // We can only inline setelem on dense arrays that do not need type
         // barriers and on typed arrays.
         ScalarTypeRepresentation::Type arrayType;
-        if ((!ElementAccessIsDenseNative(obj, id) ||
-             PropertyWriteNeedsTypeBarrier(cx, current, &obj, NULL,
-                                           &elem, /* canModify = */ false)) &&
+        if ((!isDenseNative || writeNeedsBarrier) &&
             !ElementAccessIsTypedArray(obj, id, &arrayType))
         {
             return InliningStatus_NotInlined;
         }
     }
 
     callInfo.unwrapArgs();
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2525,58 +2525,71 @@ jit::ElementAccessHasExtraIndexedPropert
     types::StackTypeSet *types = obj->resultTypeSet();
 
     if (!types || types->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW))
         return true;
 
     return types::TypeCanHaveExtraIndexedProperties(cx, types);
 }
 
-MIRType
-jit::DenseNativeElementType(JSContext *cx, MDefinition *obj)
+bool
+jit::DenseNativeElementType(JSContext *cx, MDefinition *obj, MIRType *result)
 {
+    JS_ASSERT(result);
+    *result = MIRType_None;
+
     types::StackTypeSet *types = obj->resultTypeSet();
     MIRType elementType = MIRType_None;
     unsigned count = types->getObjectCount();
 
     for (unsigned i = 0; i < count; i++) {
-        if (types::TypeObject *object = types->getTypeOrSingleObject(cx, i)) {
-            if (object->unknownProperties())
-                return MIRType_None;
-
-            types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID, false);
-            if (!elementTypes)
-                return MIRType_None;
-
-            MIRType type = MIRTypeFromValueType(elementTypes->getKnownTypeTag(cx));
-            if (type == MIRType_None)
-                return MIRType_None;
-
-            if (elementType == MIRType_None)
-                elementType = type;
-            else if (elementType != type)
-                return MIRType_None;
-        }
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
+        if (!object)
+            continue;
+
+        if (object->unknownProperties())
+            return true;
+
+        types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID, false);
+        if (!elementTypes)
+            return true;
+
+        MIRType type = MIRTypeFromValueType(elementTypes->getKnownTypeTag(cx));
+        if (type == MIRType_None)
+            return true;
+
+        if (elementType == MIRType_None)
+            elementType = type;
+        else if (elementType != type)
+            return true;
     }
 
-    return elementType;
+    *result = elementType;
+    return true;
 }
 
 bool
 jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
-                                  types::StackTypeSet *observed, bool updateObserved)
+                                  types::StackTypeSet *observed, bool updateObserved, bool *result)
 {
     // If the object being read from has types for the property which haven't
     // been observed at this access site, the read could produce a new type and
     // a barrier is needed. Note that this only covers reads from properties
     // which are accounted for by type information, i.e. native data properties
     // and elements.
-
-    if (object->unknownProperties())
+    JS_ASSERT(result);
+    *result = false;
+
+    if (object->unknownProperties()) {
+        *result = true;
         return true;
+    }
 
     jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
 
     // If this access has never executed, try to add types to the observed set
     // according to any property which exists on the object or its prototype.
     if (updateObserved && observed->empty() && observed->noConstraints() && !JSID_IS_VOID(id)) {
         JSObject *obj = object->singleton ? object->singleton : object->proto;
 
@@ -2591,151 +2604,186 @@ jit::PropertyReadNeedsTypeBarrier(JSCont
                 observed->addType(cx, types::GetValueType(v));
             }
 
             obj = obj->getProto();
         }
     }
 
     types::HeapTypeSet *property = object->getProperty(cx, id, false);
-    if (!property)
+    if (!property) {
+        *result = true;
         return true;
+    }
 
     // We need to consider possible types for the property both as an 'own'
     // property on the object and as inherited from any prototype. Type sets
     // for a property do not, however, reflect inherited types until a
     // getFromPrototypes() call has been performed.
     if (!property->hasPropagatedProperty())
         object->getFromPrototypes(cx, id, property);
 
-    if (!TypeSetIncludes(observed, MIRType_Value, property))
+    if (!TypeSetIncludes(observed, MIRType_Value, property)) {
+        *result = true;
         return true;
+    }
 
     // Type information for singleton objects is not required to reflect the
     // initial 'undefined' value for native properties, in particular global
     // variables declared with 'var'. Until the property is assigned a value
     // other than undefined, a barrier is required.
     if (name && object->singleton && object->singleton->isNative()) {
         Shape *shape = object->singleton->nativeLookup(cx, name);
         if (shape &&
             shape->hasDefaultGetter() &&
             object->singleton->nativeGetSlot(shape->slot()).isUndefined())
         {
+            *result = true;
             return true;
         }
     }
 
     property->addFreeze(cx);
-    return false;
+    *result = false;
+    return true;
 }
 
 bool
 jit::PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
-                                  types::StackTypeSet *observed)
+                                  types::StackTypeSet *observed, bool *result)
 {
+    JS_ASSERT(result);
+    *result = false;
+
     if (observed->unknown())
-        return false;
+        return true;
 
     types::TypeSet *types = obj->resultTypeSet();
-    if (!types || types->unknownObject())
+    if (!types || types->unknownObject()) {
+        *result = true;
         return true;
+    }
 
     bool updateObserved = types->getObjectCount() == 1;
     for (size_t i = 0; i < types->getObjectCount(); i++) {
-        types::TypeObject *object = types->getTypeOrSingleObject(cx, i);
-        if (object && PropertyReadNeedsTypeBarrier(cx, object, name, observed, updateObserved))
-            return true;
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
+        if (object) {
+            if (!PropertyReadNeedsTypeBarrier(cx, object, name, observed, updateObserved, result))
+                return false;
+
+            if (*result)
+                return true;
+        }
     }
 
-    return false;
+    *result = false;
+    return true;
 }
 
 bool
-jit::PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name)
+jit::PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name, bool *result)
 {
+    JS_ASSERT(result);
+    *result = false;
     // Determine if reading a property from obj is likely to be idempotent.
 
     jsid id = types::IdToTypeId(NameToId(name));
 
     types::TypeSet *types = obj->resultTypeSet();
     if (!types || types->unknownObject())
-        return false;
+        return true;
 
     for (size_t i = 0; i < types->getObjectCount(); i++) {
-        if (types::TypeObject *object = types->getTypeOrSingleObject(cx, i)) {
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
+        if (object) {
             if (object->unknownProperties())
-                return false;
+                return true;
 
             // Check if the property has been reconfigured or is a getter.
             types::HeapTypeSet *property = object->getProperty(cx, id, false);
             if (!property || property->isOwnProperty(cx, object, true))
-                return false;
+                return true;
         }
     }
 
+    *result = true;
     return true;
 }
 
-void
+bool
 jit::AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *name,
                                types::StackTypeSet *observed)
 {
     // Add objects to observed which *could* be observed by reading name from obj,
     // to hopefully avoid unnecessary type barriers and code invalidations.
 
     JS_ASSERT(observed->noConstraints());
 
     types::StackTypeSet *types = obj->resultTypeSet();
     if (!types || types->unknownObject()) {
         observed->addType(cx, types::Type::AnyObjectType());
-        return;
+        return true;
     }
 
     jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
 
     for (size_t i = 0; i < types->getObjectCount(); i++) {
-        types::TypeObject *object = types->getTypeOrSingleObject(cx, i);
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
         if (!object)
             continue;
 
         if (object->unknownProperties()) {
             observed->addType(cx, types::Type::AnyObjectType());
-            return;
+            return true;
         }
 
         types::HeapTypeSet *property = object->getProperty(cx, id, false);
         if (property->unknownObject()) {
             observed->addType(cx, types::Type::AnyObjectType());
-            return;
+            return true;
         }
 
         for (size_t i = 0; i < property->getObjectCount(); i++) {
             if (types::TypeObject *object = property->getTypeObject(i))
                 observed->addType(cx, types::Type::ObjectType(object));
             else if (JSObject *object = property->getSingleObject(i))
                 observed->addType(cx, types::Type::ObjectType(object));
         }
     }
+
+    return true;
 }
 
 static bool
 TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeSet *objTypes,
                           jsid id, MDefinition **pvalue)
 {
     // Return whether pvalue was modified to include a type barrier ensuring
     // that writing the value to objTypes/id will not require changing type
     // information.
 
     // All objects in the set must have the same types for id. Otherwise, we
     // could bail out without subsequently triggering a type change that
     // invalidates the compiled code.
     types::HeapTypeSet *aggregateProperty = NULL;
 
     for (size_t i = 0; i < objTypes->getObjectCount(); i++) {
-        types::TypeObject *object = objTypes->getTypeOrSingleObject(cx, i);
+        types::TypeObject *object;
+        if (!objTypes->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
         if (!object)
             continue;
 
         if (object->unknownProperties())
             return false;
 
         types::HeapTypeSet *property = object->getProperty(cx, id, false);
         if (!property)
@@ -2803,83 +2851,103 @@ AddTypeGuard(MBasicBlock *current, MDefi
     // For now, never move type object guards.
     guard->setNotMovable();
 
     return guard;
 }
 
 bool
 jit::PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinition **pobj,
-                                   PropertyName *name, MDefinition **pvalue, bool canModify)
+                                   PropertyName *name, MDefinition **pvalue, bool canModify,
+                                   bool *result)
 {
+    JS_ASSERT(result);
+    *result = false;
+
     // If any value being written is not reflected in the type information for
     // objects which obj could represent, a type barrier is needed when writing
     // the value. As for propertyReadNeedsTypeBarrier, this only applies for
     // properties that are accounted for by type information, i.e. normal data
     // properties and elements.
 
     types::StackTypeSet *types = (*pobj)->resultTypeSet();
-    if (!types || types->unknownObject())
+    if (!types || types->unknownObject()) {
+        *result = true;
         return true;
+    }
 
     jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
 
     // If all of the objects being written to have property types which already
     // reflect the value, no barrier at all is needed. Additionally, if all
     // objects being written to have the same types for the property, and those
     // types do *not* reflect the value, add a type barrier for the value.
 
     bool success = true;
     for (size_t i = 0; i < types->getObjectCount(); i++) {
-        types::TypeObject *object = types->getTypeOrSingleObject(cx, i);
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
         if (!object || object->unknownProperties())
             continue;
 
         types::HeapTypeSet *property = object->getProperty(cx, id, false);
         if (!property) {
             success = false;
             break;
         }
         if (!TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
             // Either pobj or pvalue needs to be modified to filter out the
             // types which the value could have but are not in the property,
             // or a VM call is required. A VM call is always required if pobj
             // and pvalue cannot be modified.
-            if (!canModify)
+            if (!canModify) {
+                *result = true;
                 return true;
+            }
             success = TryAddTypeBarrierForWrite(cx, current, types, id, pvalue);
             break;
         }
     }
 
     if (success)
-        return false;
+        return true;
 
     // If all of the objects except one have property types which reflect the
     // value, and the remaining object has no types at all for the property,
     // add a guard that the object does not have that remaining object's type.
 
-    if (types->getObjectCount() <= 1)
+    if (types->getObjectCount() <= 1) {
+        *result = true;
         return true;
+    }
 
     types::TypeObject *excluded = NULL;
     for (size_t i = 0; i < types->getObjectCount(); i++) {
-        types::TypeObject *object = types->getTypeOrSingleObject(cx, i);
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
         if (!object || object->unknownProperties())
             continue;
 
         types::HeapTypeSet *property = object->getProperty(cx, id, false);
-        if (!property)
+        if (!property) {
+            *result = true;
             return true;
+        }
 
         if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
             continue;
 
-        if (!property->empty() || excluded)
+        if (!property->empty() || excluded) {
+            *result = true;
             return true;
+        }
         excluded = object;
     }
 
     JS_ASSERT(excluded);
 
     *pobj = AddTypeGuard(current, *pobj, excluded, /* bailOnEquality = */ true);
-    return false;
+    return true;
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8505,24 +8505,24 @@ typedef Vector<MDefinition *, 8, IonAllo
 
 // Helper functions used to decide how to build MIR.
 
 bool ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id);
 bool ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
                                ScalarTypeRepresentation::Type *arrayType);
 bool ElementAccessIsPacked(JSContext *cx, MDefinition *obj);
 bool ElementAccessHasExtraIndexedProperty(JSContext *cx, MDefinition *obj);
-MIRType DenseNativeElementType(JSContext *cx, MDefinition *obj);
+bool DenseNativeElementType(JSContext *cx, MDefinition *obj, MIRType *result);
 bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
-                                  types::StackTypeSet *observed, bool updateObserved = true);
+                                  types::StackTypeSet *observed, bool updateObserved, bool *result);
 bool PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
-                                  types::StackTypeSet *observed);
-bool PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name);
-void AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *name,
+                                  types::StackTypeSet *observed, bool *result);
+bool PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name, bool *result);
+bool AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *name,
                                types::StackTypeSet *observed);
 bool PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinition **pobj,
                                    PropertyName *name, MDefinition **pvalue,
-                                   bool canModify = true);
+                                   bool canModify, bool *result);
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_MIR_h */
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
+++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
@@ -40,20 +40,19 @@ BEGIN_TEST(testDefineGetterSetterNonEnum
                             JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE));
 
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
                             JSVAL_VOID,
                             JS_DATA_TO_FUNC_PTR(JSPropertyOp, (JSObject*) funGetObj),
                             JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, (JSObject*) funSetObj),
                             JSPROP_GETTER | JSPROP_SETTER | JSPROP_PERMANENT));
 
-    bool found = false;
-    unsigned attrs = 0;
-    CHECK(JS_GetPropertyAttributes(cx, vObject, PROPERTY_NAME, &attrs, &found));
-    CHECK(found);
-    CHECK(attrs & JSPROP_GETTER);
-    CHECK(attrs & JSPROP_SETTER);
-    CHECK(attrs & JSPROP_PERMANENT);
-    CHECK(!(attrs & JSPROP_ENUMERATE));
+    JS::Rooted<JSPropertyDescriptor> desc(cx);
+    CHECK(JS_GetOwnPropertyDescriptor(cx, vObject, PROPERTY_NAME, 0, &desc));
+    CHECK(desc.object());
+    CHECK(desc.hasGetterObject());
+    CHECK(desc.hasSetterObject());
+    CHECK(desc.isPermanent());
+    CHECK(!desc.isEnumerable());
 
     return true;
 }
 END_TEST(testDefineGetterSetterNonEnumerable)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3629,136 +3629,52 @@ GetPropertyDescriptorById(JSContext *cx,
         JS_ASSERT(desc.getter() == NULL);
         JS_ASSERT(desc.setter() == NULL);
         JS_ASSERT(desc.value().isUndefined());
     }
     return true;
 }
 
 JS_PUBLIC_API(bool)
+JS_GetOwnPropertyDescriptorById(JSContext *cx, JSObject *objArg, jsid idArg, unsigned flags,
+                                MutableHandle<JSPropertyDescriptor> desc)
+{
+    RootedObject obj(cx, objArg);
+    RootedId id(cx, idArg);
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+
+    return GetPropertyDescriptorById(cx, obj, id, flags, true, desc);
+}
+
+JS_PUBLIC_API(bool)
+JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *objArg, const char *name, unsigned flags,
+                            MutableHandle<JSPropertyDescriptor> desc)
+{
+    RootedObject obj(cx, objArg);
+    JSAtom *atom = Atomize(cx, name, strlen(name));
+    return atom && JS_GetOwnPropertyDescriptorById(cx, obj, AtomToId(atom), flags, desc);
+}
+
+JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *objArg, jsid idArg, unsigned flags,
                              MutableHandle<JSPropertyDescriptor> desc)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
     return GetPropertyDescriptorById(cx, obj, id, flags, false, desc);
 }
 
 JS_PUBLIC_API(bool)
-JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *objArg, jsid idArg,
-                                       unsigned *attrsp, bool *foundp,
-                                       JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
-{
-    RootedObject obj(cx, objArg);
-    RootedId id(cx, idArg);
-    Rooted<PropertyDescriptor> desc(cx);
-    if (!GetPropertyDescriptorById(cx, obj, id, 0, false, &desc))
-        return false;
-
-    *attrsp = desc.attributes();
-    *foundp = !!desc.object();
-    if (getterp)
-        *getterp = desc.getter();
-    if (setterp)
-        *setterp = desc.setter();
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_GetPropertyAttributes(JSContext *cx, JSObject *objArg, const char *name,
-                         unsigned *attrsp, bool *foundp)
-{
-    RootedObject obj(cx, objArg);
-    JSAtom *atom = Atomize(cx, name, strlen(name));
-    return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
-                                                          attrsp, foundp, NULL, NULL);
-}
-
-JS_PUBLIC_API(bool)
-JS_GetUCPropertyAttributes(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
-                           unsigned *attrsp, bool *foundp)
-{
-    RootedObject obj(cx, objArg);
-    JSAtom *atom = AtomizeChars<CanGC>(cx, name, AUTO_NAMELEN(name, namelen));
-    return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
-                                                          attrsp, foundp, NULL, NULL);
-}
-
-JS_PUBLIC_API(bool)
-JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *objArg, const char *name,
-                                   unsigned *attrsp, bool *foundp,
-                                   JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
+JS_GetPropertyDescriptor(JSContext *cx, JSObject *objArg, const char *name, unsigned flags,
+                         MutableHandle<JSPropertyDescriptor> desc)
 {
     RootedObject obj(cx, objArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
-    return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
-                                                          attrsp, foundp, getterp, setterp);
-}
-
-JS_PUBLIC_API(bool)
-JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *objArg,
-                                     const jschar *name, size_t namelen,
-                                     unsigned *attrsp, bool *foundp,
-                                     JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
-{
-    RootedObject obj(cx, objArg);
-    JSAtom *atom = AtomizeChars<CanGC>(cx, name, AUTO_NAMELEN(name, namelen));
-    return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
-                                                          attrsp, foundp, getterp, setterp);
-}
-
-JS_PUBLIC_API(bool)
-JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *objArg, jsid idArg, MutableHandleValue vp)
-{
-    RootedObject obj(cx, objArg);
-    RootedId id(cx, idArg);
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-
-    return GetOwnPropertyDescriptor(cx, obj, id, vp);
-}
-
-static bool
-SetPropertyAttributesById(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, bool *foundp)
-{
-    RootedObject obj2(cx);
-    RootedShape shape(cx);
-
-    if (!LookupPropertyById(cx, obj, id, 0, &obj2, &shape))
-        return false;
-    if (!shape || obj != obj2) {
-        *foundp = false;
-        return true;
-    }
-    bool ok = obj->isNative()
-                ? JSObject::changePropertyAttributes(cx, obj, shape, attrs)
-                : JSObject::setGenericAttributes(cx, obj, id, &attrs);
-    if (ok)
-        *foundp = true;
-    return ok;
-}
-
-JS_PUBLIC_API(bool)
-JS_SetPropertyAttributes(JSContext *cx, JSObject *objArg, const char *name,
-                         unsigned attrs, bool *foundp)
-{
-    RootedObject obj(cx, objArg);
-    JSAtom *atom = Atomize(cx, name, strlen(name));
-    RootedId id(cx, AtomToId(atom));
-    return atom && SetPropertyAttributesById(cx, obj, id, attrs, foundp);
-}
-
-JS_PUBLIC_API(bool)
-JS_SetUCPropertyAttributes(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
-                           unsigned attrs, bool *foundp)
-{
-    RootedObject obj(cx, objArg);
-    JSAtom *atom = AtomizeChars<CanGC>(cx, name, AUTO_NAMELEN(name, namelen));
-    RootedId id(cx, AtomToId(atom));
-    return atom && SetPropertyAttributesById(cx, obj, id, attrs, foundp);
+    return atom && JS_GetPropertyDescriptorById(cx, obj, AtomToId(atom), flags, desc);
 }
 
 JS_PUBLIC_API(bool)
 JS_GetPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, MutableHandleValue vp)
 {
     return JS_ForwardGetPropertyTo(cx, objArg, idArg, objArg, vp);
 }
 
@@ -6659,9 +6575,8 @@ JS_PreventExtensions(JSContext *cx, JS::
 {
     bool extensible;
     if (!JSObject::isExtensible(cx, obj, &extensible))
         return false;
     if (!extensible)
         return true;
     return JSObject::preventExtensions(cx, obj);
 }
-
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2786,55 +2786,16 @@ JS_DefineProperty(JSContext *cx, JSObjec
 
 extern JS_PUBLIC_API(bool)
 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
                       JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 extern JS_PUBLIC_API(bool)
 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, bool *bp);
 
-/*
- * Determine the attributes (JSPROP_* flags) of a property on a given object.
- *
- * If the object does not have a property by that name, *foundp will be
- * false and the value of *attrsp is undefined.
- */
-extern JS_PUBLIC_API(bool)
-JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
-                         unsigned *attrsp, bool *foundp);
-
-/*
- * The same, but if the property is native, return its getter and setter via
- * *getterp and *setterp, respectively (and only if the out parameter pointer
- * is not null).
- */
-extern JS_PUBLIC_API(bool)
-JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
-                                   const char *name,
-                                   unsigned *attrsp, bool *foundp,
-                                   JSPropertyOp *getterp,
-                                   JSStrictPropertyOp *setterp);
-
-extern JS_PUBLIC_API(bool)
-JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj,
-                                       jsid id,
-                                       unsigned *attrsp, bool *foundp,
-                                       JSPropertyOp *getterp,
-                                       JSStrictPropertyOp *setterp);
-
-/*
- * Set the attributes of a property on a given object.
- *
- * If the object does not have a property by that name, *foundp will be
- * false and nothing will be altered.
- */
-extern JS_PUBLIC_API(bool)
-JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
-                         unsigned attrs, bool *foundp);
-
 extern JS_PUBLIC_API(bool)
 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
                             int8_t tinyid, jsval value,
                             JSPropertyOp getter, JSStrictPropertyOp setter,
                             unsigned attrs);
 
 extern JS_PUBLIC_API(bool)
 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name,
@@ -3008,27 +2969,36 @@ class MutableHandleBase<JSPropertyDescri
     }
     JSPropertyDescriptor *extractMutable() {
         return static_cast<JS::MutableHandle<JSPropertyDescriptor>*>(this)->address();
     }
 };
 
 } /* namespace js */
 
+extern JS_PUBLIC_API(bool)
+JS_GetOwnPropertyDescriptorById(JSContext *cx, JSObject *objArg, jsid id, unsigned flags,
+                                JS::MutableHandle<JSPropertyDescriptor> desc);
+
+extern JS_PUBLIC_API(bool)
+JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *objArg, const char *name, unsigned flags,
+                            JS::MutableHandle<JSPropertyDescriptor> desc);
+
 /*
- * Like JS_GetPropertyAttrsGetterAndSetterById but will return a property on
- * an object on the prototype chain (returned in objp). If data->obj is null,
+ * Like JS_GetOwnPropertyDescriptorById but will return a property on
+ * an object on the prototype chain (returned in desc->obj). If desc->obj is null,
  * then this property was not found on the prototype chain.
  */
 extern JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
                              JS::MutableHandle<JSPropertyDescriptor> desc);
 
 extern JS_PUBLIC_API(bool)
-JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, JS::MutableHandle<JS::Value> vp);
+JS_GetPropertyDescriptor(JSContext *cx, JSObject *obj, const char *name, unsigned flags,
+                         JS::MutableHandle<JSPropertyDescriptor> desc);
 
 extern JS_PUBLIC_API(bool)
 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, JS::MutableHandle<JS::Value> vp);
 
 extern JS_PUBLIC_API(bool)
 JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def,
                       JS::MutableHandle<JS::Value> vp);
 
@@ -3062,51 +3032,16 @@ extern JS_PUBLIC_API(bool)
 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, bool *succeeded);
 
 extern JS_PUBLIC_API(bool)
 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
                     const jschar *name, size_t namelen, jsval value,
                     JSPropertyOp getter, JSStrictPropertyOp setter,
                     unsigned attrs);
 
-/*
- * Determine the attributes (JSPROP_* flags) of a property on a given object.
- *
- * If the object does not have a property by that name, *foundp will be
- * false and the value of *attrsp is undefined.
- */
-extern JS_PUBLIC_API(bool)
-JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
-                           const jschar *name, size_t namelen,
-                           unsigned *attrsp, bool *foundp);
-
-/*
- * The same, but if the property is native, return its getter and setter via
- * *getterp and *setterp, respectively (and only if the out parameter pointer
- * is not null).
- */
-extern JS_PUBLIC_API(bool)
-JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
-                                     const jschar *name, size_t namelen,
-                                     unsigned *attrsp, bool *foundp,
-                                     JSPropertyOp *getterp,
-                                     JSStrictPropertyOp *setterp);
-
-/*
- * Set the attributes of a property on a given object.
- *
- * If the object does not have a property by that name, *foundp will be
- * false and nothing will be altered.
- */
-extern JS_PUBLIC_API(bool)
-JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
-                           const jschar *name, size_t namelen,
-                           unsigned attrs, bool *foundp);
-
-
 extern JS_PUBLIC_API(bool)
 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
                               const jschar *name, size_t namelen,
                               int8_t tinyid, jsval value,
                               JSPropertyOp getter, JSStrictPropertyOp setter,
                               unsigned attrs);
 
 extern JS_PUBLIC_API(bool)
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -506,17 +506,17 @@ class TypeSet
      * Iterate through the objects in this set. getObjectCount overapproximates
      * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
      * may return NULL.
      */
     inline unsigned getObjectCount() const;
     inline TypeObjectKey *getObject(unsigned i) const;
     inline JSObject *getSingleObject(unsigned i) const;
     inline TypeObject *getTypeObject(unsigned i) const;
-    inline TypeObject *getTypeOrSingleObject(JSContext *cx, unsigned i) const;
+    inline bool getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **obj) const;
 
     void setOwnProperty(bool configurable) {
         flags |= TYPE_FLAG_OWN_PROPERTY;
         if (configurable)
             flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
     }
     void setDefinite(unsigned slot) {
         JS_ASSERT(slot <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT));
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1402,30 +1402,38 @@ TypeSet::getSingleObject(unsigned i) con
 
 inline TypeObject *
 TypeSet::getTypeObject(unsigned i) const
 {
     TypeObjectKey *key = getObject(i);
     return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL;
 }
 
-inline TypeObject *
-TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i) const
+inline bool
+TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **result) const
 {
+    JS_ASSERT(result);
     JS_ASSERT(cx->compartment()->activeAnalysis);
+
+    *result = NULL;
+
     TypeObject *type = getTypeObject(i);
     if (!type) {
         JSObject *singleton = getSingleObject(i);
         if (!singleton)
-            return NULL;
+            return true;
+
         type = singleton->uninlinedGetType(cx);
-        if (!type)
+        if (!type) {
             cx->compartment()->types.setPendingNukeTypes(cx);
+            return false;
+        }
     }
-    return type;
+    *result = type;
+    return true;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeCallsite
 /////////////////////////////////////////////////////////////////////
 
 inline
 TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -4771,34 +4771,16 @@ baseops::GetAttributes(JSContext *cx, Ha
     if (!nobj->isNative())
         return JSObject::getGenericAttributes(cx, nobj, id, attrsp);
 
     *attrsp = GetShapeAttributes(shape);
     return true;
 }
 
 bool
-baseops::GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
-{
-    RootedObject nobj(cx);
-    RootedShape shape(cx);
-    if (!baseops::LookupElement(cx, obj, index, &nobj, &shape))
-        return false;
-    if (!shape) {
-        *attrsp = 0;
-        return true;
-    }
-    if (!nobj->isNative())
-        return JSObject::getElementAttributes(cx, nobj, index, attrsp);
-
-    *attrsp = GetShapeAttributes(shape);
-    return true;
-}
-
-bool
 baseops::SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!baseops::LookupProperty<CanGC>(cx, obj, id, &nobj, &shape))
         return false;
     if (!shape)
         return true;
@@ -4808,36 +4790,16 @@ baseops::SetAttributes(JSContext *cx, Ha
         shape = obj->nativeLookup(cx, id);
     }
     return nobj->isNative()
            ? JSObject::changePropertyAttributes(cx, nobj, shape, *attrsp)
            : JSObject::setGenericAttributes(cx, nobj, id, attrsp);
 }
 
 bool
-baseops::SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
-{
-    RootedObject nobj(cx);
-    RootedShape shape(cx);
-    if (!baseops::LookupElement(cx, obj, index, &nobj, &shape))
-        return false;
-    if (!shape)
-        return true;
-    if (nobj->isNative() && IsImplicitDenseElement(shape)) {
-        if (!JSObject::sparsifyDenseElement(cx, obj, index))
-            return false;
-        jsid id = INT_TO_JSID(index);
-        shape = obj->nativeLookup(cx, HandleId::fromMarkedLocation(&id)); // not a gcthing
-    }
-    return nobj->isNative()
-           ? JSObject::changePropertyAttributes(cx, nobj, shape, *attrsp)
-           : JSObject::setElementAttributes(cx, nobj, index, attrsp);
-}
-
-bool
 baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
 {
     RootedObject proto(cx);
     RootedShape shape(cx);
     if (!baseops::LookupProperty<CanGC>(cx, obj, id, &proto, &shape))
         return false;
     if (!shape || proto != obj) {
         /*
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -139,22 +139,16 @@ TypeOf(JSContext *cx, HandleObject obj);
 
 extern bool
 GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
 
 extern bool
 SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
 
 extern bool
-GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp);
-
-extern bool
-SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp);
-
-extern bool
 DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, bool *succeeded);
 
 extern bool
 DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded);
 
 extern bool
 DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, bool *succeeded);
 
@@ -876,41 +870,18 @@ class JSObject : public js::ObjectImpl
 
     static bool getGenericAttributes(JSContext *cx, js::HandleObject obj,
                                      js::HandleId id, unsigned *attrsp)
     {
         js::GenericAttributesOp op = obj->getOps()->getGenericAttributes;
         return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp);
     }
 
-    static bool getPropertyAttributes(JSContext *cx, js::HandleObject obj,
-                                      js::PropertyName *name, unsigned *attrsp)
-    {
-        JS::RootedId id(cx, js::NameToId(name));
-        return getGenericAttributes(cx, obj, id, attrsp);
-    }
-
-    static inline bool getElementAttributes(JSContext *cx, js::HandleObject obj,
-                                            uint32_t index, unsigned *attrsp);
-
-    static bool getSpecialAttributes(JSContext *cx, js::HandleObject obj,
-                                     js::SpecialId sid, unsigned *attrsp)
-    {
-        JS::RootedId id(cx, SPECIALID_TO_JSID(sid));
-        return getGenericAttributes(cx, obj, id, attrsp);
-    }
-
     static inline bool setGenericAttributes(JSContext *cx, js::HandleObject obj,
                                             js::HandleId id, unsigned *attrsp);
-    static inline bool setPropertyAttributes(JSContext *cx, js::HandleObject obj,
-                                             js::PropertyName *name, unsigned *attrsp);
-    static inline bool setElementAttributes(JSContext *cx, js::HandleObject obj,
-                                            uint32_t index, unsigned *attrsp);
-    static inline bool setSpecialAttributes(JSContext *cx, js::HandleObject obj,
-                                            js::SpecialId sid, unsigned *attrsp);
 
     static inline bool deleteProperty(JSContext *cx, js::HandleObject obj,
                                       js::HandlePropertyName name,
                                       bool *succeeded);
     static inline bool deleteElement(JSContext *cx, js::HandleObject obj,
                                      uint32_t index, bool *succeeded);
     static inline bool deleteSpecial(JSContext *cx, js::HandleObject obj,
                                      js::HandleSpecialId sid, bool *succeeded);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -27,40 +27,16 @@ JSObject::setGenericAttributes(JSContext
                                js::HandleId id, unsigned *attrsp)
 {
     js::types::MarkTypePropertyConfigured(cx, obj, id);
     js::GenericAttributesOp op = obj->getOps()->setGenericAttributes;
     return (op ? op : js::baseops::SetAttributes)(cx, obj, id, attrsp);
 }
 
 /* static */ inline bool
-JSObject::setPropertyAttributes(JSContext *cx, js::HandleObject obj,
-                                js::PropertyName *name, unsigned *attrsp)
-{
-    JS::RootedId id(cx, js::NameToId(name));
-    return setGenericAttributes(cx, obj, id, attrsp);
-}
-
-/* static */ inline bool
-JSObject::setElementAttributes(JSContext *cx, js::HandleObject obj,
-                               uint32_t index, unsigned *attrsp)
-{
-    js::ElementAttributesOp op = obj->getOps()->setElementAttributes;
-    return (op ? op : js::baseops::SetElementAttributes)(cx, obj, index, attrsp);
-}
-
-/* static */ inline bool
-JSObject::setSpecialAttributes(JSContext *cx, js::HandleObject obj,
-                               js::SpecialId sid, unsigned *attrsp)
-{
-    JS::RootedId id(cx, SPECIALID_TO_JSID(sid));
-    return setGenericAttributes(cx, obj, id, attrsp);
-}
-
-/* static */ inline bool
 JSObject::changePropertyAttributes(JSContext *cx, js::HandleObject obj,
                                    js::HandleShape shape, unsigned attrs)
 {
     return !!changeProperty(cx, obj, shape, attrs, 0, shape->getter(), shape->setter());
 }
 
 /* static */ inline bool
 JSObject::deleteProperty(JSContext *cx, js::HandleObject obj, js::HandlePropertyName name,
@@ -742,26 +718,16 @@ JSObject::getElementIfPresent(JSContext 
         *present = false;
         return true;
     }
 
     *present = true;
     return getGeneric(cx, obj, receiver, id, vp);
 }
 
-/* static */ inline bool
-JSObject::getElementAttributes(JSContext *cx, js::HandleObject obj,
-                               uint32_t index, unsigned *attrsp)
-{
-    JS::RootedId id(cx);
-    if (!js::IndexToId(cx, index, &id))
-        return false;
-    return getGenericAttributes(cx, obj, id, attrsp);
-}
-
 inline js::GlobalObject &
 JSObject::global() const
 {
 #ifdef DEBUG
     JSObject *obj = const_cast<JSObject *>(this);
     while (JSObject *parent = obj->getParent())
         obj = parent;
 #endif
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2888,73 +2888,27 @@ proxy_GetGenericAttributes(JSContext *cx
     Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc, 0))
         return false;
     *attrsp = desc.attributes();
     return true;
 }
 
 static bool
-proxy_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
-}
-
-static bool
-proxy_GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
-}
-
-static bool
-proxy_GetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
-}
-
-static bool
 proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
     Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
     desc.setAttributes(*attrsp & (~JSPROP_SHORTID));
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
 
 static bool
-proxy_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
-}
-
-static bool
-proxy_SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
-}
-
-static bool
-proxy_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
-}
-
-static bool
 proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
 {
     bool deleted;
     if (!Proxy::delete_(cx, obj, id, &deleted))
         return false;
     *succeeded = deleted;
     return js_SuppressDeletedProperty(cx, obj, id);
 }
@@ -3098,23 +3052,17 @@ Class js::ObjectProxyObject::class_ = {
         proxy_GetElement,
         proxy_GetElementIfPresent,
         proxy_GetSpecial,
         proxy_SetGeneric,
         proxy_SetProperty,
         proxy_SetElement,
         proxy_SetSpecial,
         proxy_GetGenericAttributes,
-        proxy_GetPropertyAttributes,
-        proxy_GetElementAttributes,
-        proxy_GetSpecialAttributes,
         proxy_SetGenericAttributes,
-        proxy_SetPropertyAttributes,
-        proxy_SetElementAttributes,
-        proxy_SetSpecialAttributes,
         proxy_DeleteProperty,
         proxy_DeleteElement,
         proxy_DeleteSpecial,
         NULL,                /* enumerate       */
         NULL,                /* thisObject      */
     }
 };
 
@@ -3157,23 +3105,17 @@ Class js::OuterWindowProxyObject::class_
         proxy_GetElement,
         proxy_GetElementIfPresent,
         proxy_GetSpecial,
         proxy_SetGeneric,
         proxy_SetProperty,
         proxy_SetElement,
         proxy_SetSpecial,
         proxy_GetGenericAttributes,
-        proxy_GetPropertyAttributes,
-        proxy_GetElementAttributes,
-        proxy_GetSpecialAttributes,
         proxy_SetGenericAttributes,
-        proxy_SetPropertyAttributes,
-        proxy_SetElementAttributes,
-        proxy_SetSpecialAttributes,
         proxy_DeleteProperty,
         proxy_DeleteElement,
         proxy_DeleteSpecial,
         NULL,                /* enumerate       */
         NULL,                /* thisObject      */
     }
 };
 
@@ -3228,23 +3170,17 @@ Class js::FunctionProxyObject::class_ = 
         proxy_GetElement,
         proxy_GetElementIfPresent,
         proxy_GetSpecial,
         proxy_SetGeneric,
         proxy_SetProperty,
         proxy_SetElement,
         proxy_SetSpecial,
         proxy_GetGenericAttributes,
-        proxy_GetPropertyAttributes,
-        proxy_GetElementAttributes,
-        proxy_GetSpecialAttributes,
         proxy_SetGenericAttributes,
-        proxy_SetPropertyAttributes,
-        proxy_SetElementAttributes,
-        proxy_SetSpecialAttributes,
         proxy_DeleteProperty,
         proxy_DeleteElement,
         proxy_DeleteSpecial,
         NULL,                /* enumerate       */
         NULL,                /* thisObject      */
     }
 };
 
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -270,37 +270,37 @@ DefVarOrConstOperation(JSContext *cx, Ha
 
     /* Steps 8c, 8d. */
     if (!prop || (obj2 != varobj && varobj->is<GlobalObject>())) {
         RootedValue value(cx, UndefinedValue());
         if (!JSObject::defineProperty(cx, varobj, dn, value, JS_PropertyStub,
                                       JS_StrictPropertyStub, attrs)) {
             return false;
         }
-    } else {
+    } else if (attrs & JSPROP_READONLY) {
         /*
          * Extension: ordinarily we'd be done here -- but for |const|.  If we
          * see a redeclaration that's |const|, we consider it a conflict.
          */
         unsigned oldAttrs;
-        if (!JSObject::getPropertyAttributes(cx, varobj, dn, &oldAttrs))
+        RootedId id(cx, NameToId(dn));
+        if (!JSObject::getGenericAttributes(cx, varobj, id, &oldAttrs))
             return false;
-        if (attrs & JSPROP_READONLY) {
-            JSAutoByteString bytes;
-            if (AtomToPrintableString(cx, dn, &bytes)) {
-                JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
-                                                             js_GetErrorMessage,
-                                                             NULL, JSMSG_REDECLARED_VAR,
-                                                             (oldAttrs & JSPROP_READONLY)
-                                                             ? "const"
-                                                             : "var",
-                                                             bytes.ptr()));
-            }
-            return false;
+
+        JSAutoByteString bytes;
+        if (AtomToPrintableString(cx, dn, &bytes)) {
+            JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
+                                                         js_GetErrorMessage,
+                                                         NULL, JSMSG_REDECLARED_VAR,
+                                                         (oldAttrs & JSPROP_READONLY)
+                                                         ? "const"
+                                                         : "var",
+                                                         bytes.ptr()));
         }
+        return false;
     }
 
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
 NegOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue val,
              MutableHandleValue res)
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -507,65 +507,23 @@ with_SetSpecial(JSContext *cx, HandleObj
 static bool
 with_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject actual(cx, &obj->as<WithObject>().object());
     return JSObject::getGenericAttributes(cx, actual, id, attrsp);
 }
 
 static bool
-with_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<WithObject>().object());
-    return JSObject::getPropertyAttributes(cx, actual, name, attrsp);
-}
-
-static bool
-with_GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<WithObject>().object());
-    return JSObject::getElementAttributes(cx, actual, index, attrsp);
-}
-
-static bool
-with_GetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<WithObject>().object());
-    return JSObject::getSpecialAttributes(cx, actual, sid, attrsp);
-}
-
-static bool
 with_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject actual(cx, &obj->as<WithObject>().object());
     return JSObject::setGenericAttributes(cx, actual, id, attrsp);
 }
 
 static bool
-with_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<WithObject>().object());
-    return JSObject::setPropertyAttributes(cx, actual, name, attrsp);
-}
-
-static bool
-with_SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<WithObject>().object());
-    return JSObject::setElementAttributes(cx, actual, index, attrsp);
-}
-
-static bool
-with_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<WithObject>().object());
-    return JSObject::setSpecialAttributes(cx, actual, sid, attrsp);
-}
-
-static bool
 with_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                     bool *succeeded)
 {
     RootedObject actual(cx, &obj->as<WithObject>().object());
     return JSObject::deleteProperty(cx, actual, name, succeeded);
 }
 
 static bool
@@ -630,23 +588,17 @@ Class WithObject::class_ = {
         with_GetElement,
         NULL,             /* getElementIfPresent */
         with_GetSpecial,
         with_SetGeneric,
         with_SetProperty,
         with_SetElement,
         with_SetSpecial,
         with_GetGenericAttributes,
-        with_GetPropertyAttributes,
-        with_GetElementAttributes,
-        with_GetSpecialAttributes,
         with_SetGenericAttributes,
-        with_SetPropertyAttributes,
-        with_SetElementAttributes,
-        with_SetSpecialAttributes,
         with_DeleteProperty,
         with_DeleteElement,
         with_DeleteSpecial,
         with_Enumerate,
         with_ThisObject,
     }
 };
 
@@ -1403,17 +1355,17 @@ class DebugScopeProxy : public BaseProxy
             desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
             desc.value().set(v);
             desc.setShortId(0);
             desc.setGetter(NULL);
             desc.setSetter(NULL);
             return true;
         }
 
-        return JS_GetPropertyDescriptorById(cx, scope, id, 0, desc);
+        return JS_GetOwnPropertyDescriptorById(cx, scope, id, flags, desc);
     }
 
     bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,  HandleId id,
              MutableHandleValue vp) MOZ_OVERRIDE
     {
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1016,78 +1016,26 @@ ArrayBufferObject::obj_getGenericAttribu
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
     return baseops::GetAttributes(cx, delegate, id, attrsp);
 }
 
 bool
-ArrayBufferObject::obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
-                                             HandlePropertyName name, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return obj_getGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_getElementAttributes(JSContext *cx, HandleObject obj,
-                                            uint32_t index, unsigned *attrsp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::GetElementAttributes(cx, delegate, index, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
-                                            HandleSpecialId sid, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_getGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
 ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                             HandleId id, unsigned *attrsp)
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
     return baseops::SetAttributes(cx, delegate, id, attrsp);
 }
 
 bool
-ArrayBufferObject::obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
-                                             HandlePropertyName name, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return obj_setGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_setElementAttributes(JSContext *cx, HandleObject obj,
-                                            uint32_t index, unsigned *attrsp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::SetElementAttributes(cx, delegate, index, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
-                                            HandleSpecialId sid, unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_setGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
 ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                       bool *succeeded)
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
     return baseops::DeleteProperty(cx, delegate, name, succeeded);
 }
@@ -1227,71 +1175,23 @@ bool
 TypedArrayObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,
                                            unsigned *attrsp)
 {
     *attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE;
     return true;
 }
 
 bool
-TypedArrayObject::obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
-                                            HandlePropertyName name, unsigned *attrsp)
-{
-    *attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE;
-    return true;
-}
-
-bool
-TypedArrayObject::obj_getElementAttributes(JSContext *cx, HandleObject obj, uint32_t index,
-                                           unsigned *attrsp)
-{
-    *attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE;
-    return true;
-}
-
-bool
-TypedArrayObject::obj_getSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                           unsigned *attrsp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_getGenericAttributes(cx, obj, id, attrsp);
-}
-
-bool
 TypedArrayObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,
                                            unsigned *attrsp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
     return false;
 }
 
-bool
-TypedArrayObject::obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
-                                            HandlePropertyName name, unsigned *attrsp)
-{
-    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
-    return false;
-}
-
-bool
-TypedArrayObject::obj_setElementAttributes(JSContext *cx, HandleObject obj, uint32_t index,
-                                           unsigned *attrsp)
-{
-    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
-    return false;
-}
-
-bool
-TypedArrayObject::obj_setSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                           unsigned *attrsp)
-{
-    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
-    return false;
-}
-
 /* static */ int
 TypedArrayObject::lengthOffset()
 {
     return JSObject::getFixedSlotOffset(LENGTH_SLOT);
 }
 
 /* static */ int
 TypedArrayObject::dataOffset()
@@ -3489,23 +3389,17 @@ Class ArrayBufferObject::class_ = {
         ArrayBufferObject::obj_getElement,
         ArrayBufferObject::obj_getElementIfPresent,
         ArrayBufferObject::obj_getSpecial,
         ArrayBufferObject::obj_setGeneric,
         ArrayBufferObject::obj_setProperty,
         ArrayBufferObject::obj_setElement,
         ArrayBufferObject::obj_setSpecial,
         ArrayBufferObject::obj_getGenericAttributes,
-        ArrayBufferObject::obj_getPropertyAttributes,
-        ArrayBufferObject::obj_getElementAttributes,
-        ArrayBufferObject::obj_getSpecialAttributes,
         ArrayBufferObject::obj_setGenericAttributes,
-        ArrayBufferObject::obj_setPropertyAttributes,
-        ArrayBufferObject::obj_setElementAttributes,
-        ArrayBufferObject::obj_setSpecialAttributes,
         ArrayBufferObject::obj_deleteProperty,
         ArrayBufferObject::obj_deleteElement,
         ArrayBufferObject::obj_deleteSpecial,
         ArrayBufferObject::obj_enumerate,
         NULL,       /* thisObject      */
     }
 };
 
@@ -3657,23 +3551,17 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Flo
         _typedArray##Object::obj_getElement,                                   \
         _typedArray##Object::obj_getElementIfPresent,                          \
         _typedArray##Object::obj_getSpecial,                                   \
         _typedArray##Object::obj_setGeneric,                                   \
         _typedArray##Object::obj_setProperty,                                  \
         _typedArray##Object::obj_setElement,                                   \
         _typedArray##Object::obj_setSpecial,                                   \
         _typedArray##Object::obj_getGenericAttributes,                         \
-        _typedArray##Object::obj_getPropertyAttributes,                        \
-        _typedArray##Object::obj_getElementAttributes,                         \
-        _typedArray##Object::obj_getSpecialAttributes,                         \
         _typedArray##Object::obj_setGenericAttributes,                         \
-        _typedArray##Object::obj_setPropertyAttributes,                        \
-        _typedArray##Object::obj_setElementAttributes,                         \
-        _typedArray##Object::obj_setSpecialAttributes,                         \
         _typedArray##Object::obj_deleteProperty,                               \
         _typedArray##Object::obj_deleteElement,                                \
         _typedArray##Object::obj_deleteSpecial,                                \
         _typedArray##Object::obj_enumerate,                                    \
         NULL,                /* thisObject  */                                 \
     }                                                                          \
 }
 
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -119,31 +119,18 @@ class ArrayBufferObject : public JSObjec
                                 MutableHandleValue vp, bool strict);
     static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
                                MutableHandleValue vp, bool strict);
     static bool obj_setSpecial(JSContext *cx, HandleObject obj,
                                HandleSpecialId sid, MutableHandleValue vp, bool strict);
 
     static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
                                          HandleId id, unsigned *attrsp);
-    static bool obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
-                                          HandlePropertyName name, unsigned *attrsp);
-    static bool obj_getElementAttributes(JSContext *cx, HandleObject obj,
-                                         uint32_t index, unsigned *attrsp);
-    static bool obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
-                                         HandleSpecialId sid, unsigned *attrsp);
-
     static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                          HandleId id, unsigned *attrsp);
-    static bool obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
-                                          HandlePropertyName name, unsigned *attrsp);
-    static bool obj_setElementAttributes(JSContext *cx, HandleObject obj,
-                                         uint32_t index, unsigned *attrsp);
-    static bool obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
-                                         HandleSpecialId sid, unsigned *attrsp);
 
     static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                    bool *succeeded);
     static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
                                   bool *succeeded);
     static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                                   bool *succeeded);
 
@@ -290,31 +277,18 @@ class TypedArrayObject : public ArrayBuf
                                    MutableHandleObject objp, MutableHandleShape propp);
     static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
                                   MutableHandleObject objp, MutableHandleShape propp);
     static bool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
                                   MutableHandleObject objp, MutableHandleShape propp);
 
     static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
                                          HandleId id, unsigned *attrsp);
-    static bool obj_getPropertyAttributes(JSContext *cx, HandleObject obj,
-                                          HandlePropertyName name, unsigned *attrsp);
-    static bool obj_getElementAttributes(JSContext *cx, HandleObject obj,
-                                         uint32_t index, unsigned *attrsp);
-    static bool obj_getSpecialAttributes(JSContext *cx, HandleObject obj,
-                                         HandleSpecialId sid, unsigned *attrsp);
-
     static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                          HandleId id, unsigned *attrsp);
-    static bool obj_setPropertyAttributes(JSContext *cx, HandleObject obj,
-                                          HandlePropertyName name, unsigned *attrsp);
-    static bool obj_setElementAttributes(JSContext *cx, HandleObject obj,
-                                         uint32_t index, unsigned *attrsp);
-    static bool obj_setSpecialAttributes(JSContext *cx, HandleObject obj,
-                                         HandleSpecialId sid, unsigned *attrsp);
 
     static Value bufferValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTEOFFSET_SLOT);
     }
     static Value byteLengthValue(TypedArrayObject *tarr) {
--- a/js/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/xpconnect/idl/nsIXPCScriptable.idl
@@ -1,16 +1,17 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIXPConnect.idl"
+#include "nsIClassInfo.idl"
 
 %{C++
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 %}
 
 /**
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -2,36 +2,25 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* The core XPConnect public interfaces. */
 
 #include "nsISupports.idl"
-#include "nsIClassInfo.idl"
-#include "xpccomponents.idl"
-#include "xpcjsid.idl"
-#include "xpcexception.idl"
-#include "nsIInterfaceInfo.idl"
-#include "nsIInterfaceInfoManager.idl"
-#include "nsIExceptionService.idl"
-#include "nsIVariant.idl"
-#include "nsIObjectOutputStream.idl"
-#include "nsIObjectInputStream.idl"
 
 %{ C++
 #include "jspubtd.h"
 #include "js/TypeDecls.h"
-#include "xptinfo.h"
-#include "nsAXPCNativeCallContext.h"
 
 struct JSFreeOp;
 
 class nsWrapperCache;
+class nsAXPCNativeCallContext;
 %}
 
 /***************************************************************************/
 
 // NB: jsval and jsid are declared in nsrootidl.idl
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSClassPtr(JSClass);
@@ -53,16 +42,21 @@ class nsWrapperCache;
 
 // forward declarations...
 interface nsIXPCScriptable;
 interface nsIXPConnect;
 interface nsIXPConnectWrappedNative;
 interface nsIInterfaceInfo;
 interface nsIXPCSecurityManager;
 interface nsIPrincipal;
+interface nsIClassInfo;
+interface nsIVariant;
+interface nsIStackFrame;
+interface nsIObjectInputStream;
+interface nsIObjectOutputStream;
 
 /***************************************************************************/
 [uuid(909e8641-7c54-4dff-9b94-ba631f057b33)]
 interface nsIXPConnectJSObjectHolder : nsISupports
 {
     [notxpcom, nostdcall] JSObjectPtr GetJSObject();
 };
 
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1671,16 +1671,21 @@ main(int argc, char **argv, char **envp)
         ProcessArgsForCompartment(cx, argv, argc);
 
         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
         if (!xpc) {
             printf("failed to get nsXPConnect service!\n");
             return 1;
         }
 
+        // Force the SafeJSContext to be created. This is a workaround for our
+        // implicit dependency on keeping at least one JSContext alive until the
+        // end of shutdown. This can go away when we get bug 905926 landed.
+        xpc->GetSafeJSContext();
+
         nsCOMPtr<nsIPrincipal> systemprincipal;
         // Fetch the system principal and store it away in a global, to use for
         // script compilation in Load() and ProcessFile() (including interactive
         // eval loop)
         {
 
             nsCOMPtr<nsIScriptSecurityManager> securityManager =
                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1165,24 +1165,23 @@ XPCConvert::JSValToXPCException(MutableH
                 JSString* str;
                 if (nullptr != (str = JS_ValueToString(cx, s)))
                     message.encodeLatin1(cx, str);
                 return JSErrorToXPCException(message.ptr(), ifaceName,
                                              methodName, report, exceptn);
             }
 
 
-            unsigned ignored;
             bool found;
 
             // heuristic to see if it might be usable as an xpcexception
-            if (!JS_GetPropertyAttributes(cx, obj, "message", &ignored, &found))
-               return NS_ERROR_FAILURE;
+            if (!JS_HasProperty(cx, obj, "message", &found))
+                return NS_ERROR_FAILURE;
 
-            if (found && !JS_GetPropertyAttributes(cx, obj, "result", &ignored, &found))
+            if (found && !JS_HasProperty(cx, obj, "result", &found))
                 return NS_ERROR_FAILURE;
 
             if (found) {
                 // lets try to build a wrapper around the JSObject
                 nsXPCWrappedJS* jswrapper;
                 nsresult rv =
                     nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsIException),
                                                  nullptr, &jswrapper);
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -120,17 +120,17 @@ SafeFinalize(JSFreeOp *fop, JSObject* ob
 {
     SandboxPrivate* sop =
         static_cast<SandboxPrivate*>(xpc_GetJSPrivate(obj));
     sop->ForgetGlobalObject();
     NS_IF_RELEASE(sop);
     DestroyProtoAndIfaceCache(obj);
 }
 
-static JSClass global_class = {
+JSClass xpc::SafeJSContextGlobalClass = {
     "global_for_XPCJSContextStack_SafeJSContext",
     XPCONNECT_GLOBAL_FLAGS,
     JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize,
     NULL, NULL, NULL, NULL, TraceXPCGlobal
 };
 
 JSContext*
@@ -156,17 +156,17 @@ XPCJSContextStack::GetSafeJSContext()
         MOZ_CRASH();
     JSAutoRequest req(mSafeJSContext);
 
     JS::RootedObject glob(mSafeJSContext);
     JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);
 
     JS::CompartmentOptions options;
     options.setZone(JS::SystemZone);
-    glob = xpc::CreateGlobalObject(mSafeJSContext, &global_class, principal, options);
+    glob = xpc::CreateGlobalObject(mSafeJSContext, &SafeJSContextGlobalClass, principal, options);
     if (!glob)
         MOZ_CRASH();
 
     // Make sure the context is associated with a proper compartment
     // and not the default compartment.
     js::SetDefaultObjectForContext(mSafeJSContext, glob);
 
     // Note: make sure to set the private before calling
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -730,23 +730,17 @@ XPCWrappedNativeJSClass XPC_WN_NoHelper_
         nullptr, // getElement
         nullptr, // getElementIfPresent
         nullptr, // getSpecial
         nullptr, // setGeneric
         nullptr, // setProperty
         nullptr, // setElement
         nullptr, // setSpecial
         nullptr, // getGenericAttributes
-        nullptr, // getAttributes
-        nullptr, // getElementAttributes
-        nullptr, // getSpecialAttributes
         nullptr, // setGenericAttributes
-        nullptr, // setAttributes
-        nullptr, // setElementAttributes
-        nullptr, // setSpecialAttributes
         nullptr, // deleteProperty
         nullptr, // deleteElement
         nullptr, // deleteSpecial
         XPC_WN_JSOp_Enumerate,
         XPC_WN_JSOp_ThisObject,
     }
   },
   0 // interfacesBitmap
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -13,16 +13,17 @@
 #include "nsPrincipal.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 
 #include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace xpc;
+using namespace JS;
 
 /***************************************************************************/
 
 #ifdef XPC_TRACK_SCOPE_STATS
 static int DEBUG_TotalScopeCount;
 static int DEBUG_TotalLiveScopeCount;
 static int DEBUG_TotalMaxScopeCount;
 static int DEBUG_TotalScopeTraversalCount;
@@ -92,27 +93,34 @@ XPCWrappedNativeScope::GetNewOrUsed(JSCo
     XPCWrappedNativeScope* scope = GetObjectScope(aGlobal);
     if (!scope) {
         scope = new XPCWrappedNativeScope(cx, aGlobal);
     }
     return scope;
 }
 
 static bool
-RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal)
+RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal)
 {
-  // We end up getting called during SSM bootstrapping to create the
-  // SafeJSContext. In that case, nsContentUtils isn't ready for us.
-  //
-  // Also check for random JSD scopes that don't have a principal.
-  if (!nsContentUtils::IsInitialized() || !aPrincipal)
+  // Check for random JSD scopes that don't have a principal.
+  if (!aPrincipal)
+      return false;
+
+  // The SafeJSContext is lazily created, and tends to be created at really
+  // weird times, at least for xpcshell (often very early in startup or late
+  // in shutdown). Its scope isn't system principal, so if we proceeded we'd
+  // end up calling into AllowXULXBLForPrincipal, which depends on all kinds
+  // of persistent storage and permission machinery that may or not be running.
+  // We know the answer to the question here, so just short-circuit.
+  if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass)
       return false;
 
   // AllowXULXBLForPrincipal will return true for system principal, but we
   // don't want that here.
+  MOZ_ASSERT(nsContentUtils::IsInitialized());
   if (nsContentUtils::IsSystemPrincipal(aPrincipal))
       return false;
 
   // If this domain isn't whitelisted, we're done.
   if (!nsContentUtils::AllowXULXBLForPrincipal(aPrincipal))
       return false;
 
   // Check the pref to determine how we should behave.
@@ -156,17 +164,17 @@ XPCWrappedNativeScope::XPCWrappedNativeS
     // Attach ourselves to the compartment private.
     CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal);
     priv->scope = this;
 
     // Determine whether we would allow an XBL scope in this situation.
     // In addition to being pref-controlled, we also disable XBL scopes for
     // remote XUL domains, _except_ if we have an additional pref override set.
     nsIPrincipal *principal = GetPrincipal();
-    mAllowXBLScope = !RemoteXULForbidsXBLScope(principal);
+    mAllowXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal);
 
     // Determine whether to use an XBL scope.
     mUseXBLScope = mAllowXBLScope;
     if (mUseXBLScope) {
       js::Class *clasp = js::GetObjectClass(mGlobalJSObject);
       mUseXBLScope = !strcmp(clasp->name, "Window") ||
                      !strcmp(clasp->name, "ChromeWindow") ||
                      !strcmp(clasp->name, "ModalContentWindow");
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -1,15 +1,14 @@
 # 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/.
 
 # Dictionary interface name, interface file name
 dictionaries = [
-     [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
      [ 'CameraSize', 'nsIDOMCameraManager.idl' ],
      [ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
      [ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
      [ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
      [ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ],
      [ 'SmsThreadListItem', 'nsIMobileMessageCallback.idl' ],
      [ 'MmsAttachment', 'nsIDOMMozMmsMessage.idl' ]
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -48,16 +48,18 @@
 
 #include "nsWrapperCacheInlines.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollector.h"
 #include "nsDOMMutationObserver.h"
 #include "nsICycleCollectorListener.h"
 #include "nsThread.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace xpc;
 using namespace JS;
 
 NS_IMPL_ISUPPORTS5(nsXPConnect,
                    nsIXPConnect,
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -92,17 +92,16 @@
 #include <string.h>
 
 #include "xpcpublic.h"
 #include "pldhash.h"
 #include "nscore.h"
 #include "nsXPCOM.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
-#include "mozilla/CycleCollectedJSRuntime.h"
 #include "nsDebug.h"
 #include "nsISupports.h"
 #include "nsIServiceManager.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsISupportsPrimitives.h"
 #include "nsMemory.h"
@@ -155,16 +154,17 @@
 #include "nsIScriptObjectPrincipal.h"
 #include "nsISecurityCheckedComponent.h"
 #include "xpcObjectHelper.h"
 #include "nsIThreadInternal.h"
 
 #include "SandboxPrivate.h"
 #include "BackstagePass.h"
 #include "nsCxPusher.h"
+#include "nsAXPCNativeCallContext.h"
 
 #ifdef XP_WIN
 // Nasty MS defines
 #ifdef GetClassInfo
 #undef GetClassInfo
 #endif
 #ifdef GetClassName
 #undef GetClassName
@@ -1198,23 +1198,17 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
         nullptr, /* getElement    */                                          \
         nullptr, /* getElementIfPresent */                                    \
         nullptr, /* getSpecial    */                                          \
         nullptr, /* setGeneric    */                                          \
         nullptr, /* setProperty    */                                         \
         nullptr, /* setElement    */                                          \
         nullptr, /* setSpecial    */                                          \
         nullptr, /* getGenericAttributes  */                                  \
-        nullptr, /* getAttributes  */                                         \
-        nullptr, /* getElementAttributes  */                                  \
-        nullptr, /* getSpecialAttributes  */                                  \
         nullptr, /* setGenericAttributes  */                                  \
-        nullptr, /* setAttributes  */                                         \
-        nullptr, /* setElementAttributes  */                                  \
-        nullptr, /* setSpecialAttributes  */                                  \
         nullptr, /* deleteProperty */                                         \
         nullptr, /* deleteElement */                                          \
         nullptr, /* deleteSpecial */                                          \
         XPC_WN_JSOp_Enumerate,                                                \
         XPC_WN_JSOp_ThisObject,                                               \
     }
 
 #define XPC_WN_NoCall_ObjectOps                                               \
@@ -1232,23 +1226,17 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
         nullptr, /* getElement    */                                          \
         nullptr, /* getElementIfPresent */                                    \
         nullptr, /* getSpecial    */                                          \
         nullptr, /* setGeneric    */                                          \
         nullptr, /* setProperty    */                                         \
         nullptr, /* setElement    */                                          \
         nullptr, /* setSpecial    */                                          \
         nullptr, /* getGenericAttributes  */                                  \
-        nullptr, /* getAttributes  */                                         \
-        nullptr, /* getElementAttributes  */                                  \
-        nullptr, /* getSpecialAttributes  */                                  \
         nullptr, /* setGenericAttributes  */                                  \
-        nullptr, /* setAttributes  */                                         \
-        nullptr, /* setElementAttributes  */                                  \
-        nullptr, /* setSpecialAttributes  */                                  \
         nullptr, /* deleteProperty */                                         \
         nullptr, /* deleteElement */                                          \
         nullptr, /* deleteSpecial */                                          \
         XPC_WN_JSOp_Enumerate,                                                \
         XPC_WN_JSOp_ThisObject,                                               \
     }
 
 // Maybe this macro should check for class->enumerate ==
@@ -3864,16 +3852,18 @@ inline XPCWrappedNativeScope*
 GetObjectScope(JSObject *obj)
 {
     return EnsureCompartmentPrivate(obj)->scope;
 }
 
 extern bool gDebugMode;
 extern bool gDesiredDebugMode;
 
+extern JSClass SafeJSContextGlobalClass;
+
 JSObject* NewOutObject(JSContext* cx, JSObject* scope);
 bool IsOutObject(JSContext* cx, JSObject* obj);
 
 nsresult HasInstance(JSContext *cx, JS::HandleObject objArg, const nsID *iid, bool *bp);
 
 } // namespace xpc
 
 /***************************************************************************/
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1163,17 +1163,16 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
     // images to refresh, and then we refresh each image in that array.
     nsCOMArray<imgIContainer> imagesToRefresh(mRequests.Count());
     mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator,
                                &imagesToRefresh);
 
     for (uint32_t i = 0; i < imagesToRefresh.Length(); i++) {
       imagesToRefresh[i]->RequestRefresh(aNowTime);
     }
-    imagesToRefresh.Clear();
   }
 
   for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
     mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
   }
   mPresShellsToInvalidateIfHidden.Clear();
 
   if (mViewManagerFlushIsPending) {
--- a/layout/reftests/position-sticky/reftest.list
+++ b/layout/reftests/position-sticky/reftest.list
@@ -1,14 +1,14 @@
 test-pref(layout.css.sticky.enabled,false) == pref-1.html pref-1-disabled-ref.html
 test-pref(layout.css.sticky.enabled,true) == pref-1.html pref-1-enabled-ref.html
 default-preferences pref(layout.css.sticky.enabled,true)
 
 == top-1.html top-1-ref.html
-fuzzy-if(Android,4,914) == top-2.html top-2-ref.html
+fuzzy-if(Android,6,914) == top-2.html top-2-ref.html
 fuzzy-if(Android,4,2729) == top-3.html top-3-ref.html
 == top-4.html top-4-ref.html
 == top-5.html top-5-ref.html
 == top-6.html top-6-ref.html
 == bottom-1.html bottom-1-ref.html
 == bottom-2a.html bottom-2-ref.html
 == bottom-2b.html bottom-2-ref.html
 == bottom-2c.html bottom-2-ref.html
--- a/layout/style/nsCSSStyleSheet.cpp
+++ b/layout/style/nsCSSStyleSheet.cpp
@@ -35,16 +35,17 @@
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozAutoDocUpdate.h"
 #include "nsRuleNode.h"
 #include "nsMediaFeatures.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/CSSStyleSheetBinding.h"
+#include "nsComponentManagerUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 
 // -------------------------------
 // Style Rule List for the DOM
 //
--- a/layout/xul/base/src/nsBoxObject.cpp
+++ b/layout/xul/base/src/nsBoxObject.cpp
@@ -18,16 +18,17 @@
 #include "nsIDOMXULElement.h"
 #else
 #include "nsIDOMElement.h"
 #endif
 #include "nsLayoutUtils.h"
 #include "nsISupportsPrimitives.h"
 #include "nsSupportsPrimitives.h"
 #include "mozilla/dom/Element.h"
+#include "nsComponentManagerUtils.h"
 
 using namespace mozilla::dom;
 
 // Implementation /////////////////////////////////////////////////////////////////
 
 // Static member variable initialization
 
 // Implement our nsISupports methods
--- a/layout/xul/tree/nsTreeSelection.cpp
+++ b/layout/xul/tree/nsTreeSelection.cpp
@@ -13,16 +13,17 @@
 #include "nsDOMClassInfoID.h"
 #include "nsIContent.h"
 #include "nsGUIEvent.h"
 #include "nsINameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsAsyncDOMEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsAutoPtr.h"
+#include "nsComponentManagerUtils.h"
 
 // A helper class for managing our ranges of selection.
 struct nsTreeRange
 {
   nsTreeSelection* mSelection;
 
   nsTreeRange* mPrev;
   nsTreeRange* mNext;
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -64,21 +64,23 @@ typedef enum {
 
 using namespace CSF;
 
 VcmSIPCCBinding * VcmSIPCCBinding::gSelf = NULL;
 int VcmSIPCCBinding::gAudioCodecMask = 0;
 int VcmSIPCCBinding::gVideoCodecMask = 0;
 nsIThread *VcmSIPCCBinding::gMainThread = NULL;
 
-static mozilla::RefPtr<TransportFlow> vcmCreateTransportFlow(sipcc::PeerConnectionImpl *pc,
-                                                             int level, bool rtcp,
-                                                             const char *fingerprint_alg,
-                                                             const char *fingerprint
-                                                             );
+static mozilla::RefPtr<TransportFlow> vcmCreateTransportFlow(
+    sipcc::PeerConnectionImpl *pc,
+    int level,
+    bool rtcp,
+    sdp_setup_type_e setup_type,
+    const char *fingerprint_alg,
+    const char *fingerprint);
 
 // Convenience macro to acquire PC
 
 #define ENSURE_PC(pc, errval) \
   do { \
     if (!pc.impl()) {                                                 \
       CSFLogDebug(logTag, "%s: couldn't acquire peerconnection %s", __FUNCTION__, peerconnection); \
       return errval; \
@@ -1344,16 +1346,17 @@ int vcmRxStart(cc_mcapid_t mcap_id,
  *  @param[in]   stream_id    - stream id of the given media type.
  *  @param[in]   level        - the m-line index
  *  @param[in]   pc_stream_id - the media stream index (from PC.addStream())
  *  @param[in]   pc_track_id  - the track within the media stream
  *  @param[in]   call_handle  - call handle
  *  @param[in]   peerconnection - the peerconnection in use
  *  @param[in]   num_payloads   - number of negotiated payloads
  *  @param[in]   payloads       - negotiated codec details list
+ *  @param[in]   setup          - whether playing client or server role
  *  @param[in]   fingerprint_alg - the DTLS fingerprint algorithm
  *  @param[in]   fingerprint  - the DTLS fingerprint
  *  @param[in]   attrs        - media attributes
  *
  *  Returns: zero(0) for success; otherwise, ERROR for failure
  */
 
 static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
@@ -1361,29 +1364,30 @@ static int vcmRxStartICE_m(cc_mcapid_t m
         cc_streamid_t stream_id,
         int level,
         int pc_stream_id,
         int pc_track_id,
         cc_call_handle_t  call_handle,
         const char *peerconnection,
         int num_payloads,
         const vcm_payload_info_t* payloads,
+        sdp_setup_type_e setup_type,
         const char *fingerprint_alg,
         const char *fingerprint,
         vcm_mediaAttrs_t *attrs)
 {
   CSFLogDebug( logTag, "%s(%s)", __FUNCTION__, peerconnection);
 
   // Find the PC.
   sipcc::PeerConnectionWrapper pc(peerconnection);
   ENSURE_PC(pc, VCM_ERROR);
 
   // Datachannel will use this though not for RTP
   mozilla::RefPtr<TransportFlow> rtp_flow =
-    vcmCreateTransportFlow(pc.impl(), level, false,
+    vcmCreateTransportFlow(pc.impl(), level, false, setup_type,
                            fingerprint_alg, fingerprint);
   if (!rtp_flow) {
     CSFLogError( logTag, "Could not create RTP flow");
     return VCM_ERROR;
   }
 
   if (CC_IS_DATACHANNEL(mcap_id)) {
     // That's all we need for DataChannels - a flow registered
@@ -1402,17 +1406,17 @@ static int vcmRxStartICE_m(cc_mcapid_t m
   if (!stream) {
     // This should never happen
     PR_ASSERT(PR_FALSE);
     return VCM_ERROR;
   }
 
   mozilla::RefPtr<TransportFlow> rtcp_flow = nullptr;
   if(!attrs->rtcp_mux) {
-    rtcp_flow = vcmCreateTransportFlow(pc.impl(), level, true,
+    rtcp_flow = vcmCreateTransportFlow(pc.impl(), level, true, setup_type,
                                        fingerprint_alg, fingerprint);
     if (!rtcp_flow) {
       CSFLogError( logTag, "Could not create RTCP flow");
       return VCM_ERROR;
     }
   }
 
   if (CC_IS_AUDIO(mcap_id)) {
@@ -1530,16 +1534,17 @@ static int vcmRxStartICE_m(cc_mcapid_t m
  *  @param[in]   stream_id    - stream id of the given media type.
  *  @param[in]   level        - the m-line index
  *  @param[in]   pc_stream_id - the media stream index (from PC.addStream())
  *  @param[i]n   pc_track_id  - the track within the media stream
  *  @param[in]   call_handle  - call handle
  *  @param[in]  peerconnection - the peerconnection in use
  *  @param[in]  num_payloads   - number of negotiated payloads
  *  @param[in]  payloads       - negotiated codec details list
+ *  @param[in]   setup_type    - whether playing client or server role
  *  @param[in]   fingerprint_alg - the DTLS fingerprint algorithm
  *  @param[in]   fingerprint  - the DTLS fingerprint
  *  @param[in]   attrs        - media attributes
  *
  *  Returns: zero(0) for success; otherwise, ERROR for failure
  */
 
 int vcmRxStartICE(cc_mcapid_t mcap_id,
@@ -1547,16 +1552,17 @@ int vcmRxStartICE(cc_mcapid_t mcap_id,
                   cc_streamid_t stream_id,
                   int level,
                   int pc_stream_id,
                   int pc_track_id,
                   cc_call_handle_t  call_handle,
                   const char *peerconnection,
                   int num_payloads,
                   const vcm_payload_info_t* payloads,
+                  sdp_setup_type_e setup_type,
                   const char *fingerprint_alg,
                   const char *fingerprint,
                   vcm_mediaAttrs_t *attrs)
 {
   int ret;
 
   mozilla::SyncRunnable::DispatchToThread(VcmSIPCCBinding::getMainThread(),
       WrapRunnableNMRet(&vcmRxStartICE_m,
@@ -1565,16 +1571,17 @@ int vcmRxStartICE(cc_mcapid_t mcap_id,
                         stream_id,
                         level,
                         pc_stream_id,
                         pc_track_id,
                         call_handle,
                         peerconnection,
                         num_payloads,
                         payloads,
+                        setup_type,
                         fingerprint_alg,
                         fingerprint,
                         attrs,
                         &ret));
 
   return ret;
 }
 
@@ -2004,16 +2011,17 @@ int vcmTxStart(cc_mcapid_t mcap_id,
  *  @param[in]   stream_id    - stream id of the given media type.
  *  @param[in]   level        - the m-line index
  *  @param[in]   pc_stream_id - the media stream index (from PC.addStream())
  *  @param[i]n   pc_track_id  - the track within the media stream
  *  @param[in]   call_handle  - call handle
  *  @param[in]   peerconnection - the peerconnection in use
  *  @param[in]   payload      - payload information
  *  @param[in]   tos          - bit marking
+ *  @param[in]   setup_type   - whether playing the client or server role
  *  @param[in]   fingerprint_alg - the DTLS fingerprint algorithm
  *  @param[in]   fingerprint  - the DTLS fingerprint
  *  @param[in]   attrs        - media attributes
  *
  *  Returns: zero(0) for success; otherwise, ERROR for failure
  *
  */
 #define EXTRACT_DYNAMIC_PAYLOAD_TYPE(PTYPE) ((PTYPE)>>16)
@@ -2023,39 +2031,40 @@ static int vcmTxStartICE_m(cc_mcapid_t m
         cc_streamid_t stream_id,
         int level,
         int pc_stream_id,
         int pc_track_id,
         cc_call_handle_t  call_handle,
         const char *peerconnection,
         const vcm_payload_info_t *payload,
         short tos,
+        sdp_setup_type_e setup_type,
         const char *fingerprint_alg,
         const char *fingerprint,
         vcm_mediaAttrs_t *attrs)
 {
   CSFLogDebug( logTag, "%s(%s)", __FUNCTION__, peerconnection);
 
   // Find the PC and get the stream
   sipcc::PeerConnectionWrapper pc(peerconnection);
   ENSURE_PC(pc, VCM_ERROR);
   nsRefPtr<sipcc::LocalSourceStreamInfo> stream = pc.impl()->media()->
     GetLocalStream(pc_stream_id);
 
   // Create the transport flows
   mozilla::RefPtr<TransportFlow> rtp_flow =
-      vcmCreateTransportFlow(pc.impl(), level, false,
+      vcmCreateTransportFlow(pc.impl(), level, false, setup_type,
                              fingerprint_alg, fingerprint);
   if (!rtp_flow) {
       CSFLogError( logTag, "Could not create RTP flow");
       return VCM_ERROR;
   }
   mozilla::RefPtr<TransportFlow> rtcp_flow = nullptr;
   if(!attrs->rtcp_mux) {
-    rtcp_flow = vcmCreateTransportFlow(pc.impl(), level, true,
+    rtcp_flow = vcmCreateTransportFlow(pc.impl(), level, true, setup_type,
                                        fingerprint_alg, fingerprint);
     if (!rtcp_flow) {
       CSFLogError( logTag, "Could not create RTCP flow");
       return VCM_ERROR;
     }
   }
 
   if (CC_IS_AUDIO(mcap_id)) {
@@ -2161,16 +2170,17 @@ static int vcmTxStartICE_m(cc_mcapid_t m
  *  @param[in]   stream_id    - stream id of the given media type.
  *  @param[in]   level        - the m-line index
  *  @param[in]   pc_stream_id - the media stream index (from PC.addStream())
  *  @param[i]n   pc_track_id  - the track within the media stream
  *  @param[in]   call_handle  - call handle
  *  @param[in]  peerconnection - the peerconnection in use
  *  @param[in]   payload      - payload type
  *  @param[in]   tos          - bit marking
+ *  @param[in]   setup_type   - whether playing client or server role.
  *  @param[in]   fingerprint_alg - the DTLS fingerprint algorithm
  *  @param[in]   fingerprint  - the DTLS fingerprint
  *  @param[in]   attrs        - media attributes
  *
  *  Returns: zero(0) for success; otherwise, ERROR for failure
  *
  */
 #define EXTRACT_DYNAMIC_PAYLOAD_TYPE(PTYPE) ((PTYPE)>>16)
@@ -2180,16 +2190,17 @@ int vcmTxStartICE(cc_mcapid_t mcap_id,
                   cc_streamid_t stream_id,
                   int level,
                   int pc_stream_id,
                   int pc_track_id,
                   cc_call_handle_t  call_handle,
                   const char *peerconnection,
                   const vcm_payload_info_t *payload,
                   short tos,
+                  sdp_setup_type_e setup_type,
                   const char *fingerprint_alg,
                   const char *fingerprint,
                   vcm_mediaAttrs_t *attrs)
 {
   int ret;
 
   mozilla::SyncRunnable::DispatchToThread(VcmSIPCCBinding::getMainThread(),
       WrapRunnableNMRet(&vcmTxStartICE_m,
@@ -2198,16 +2209,17 @@ int vcmTxStartICE(cc_mcapid_t mcap_id,
                         stream_id,
                         level,
                         pc_stream_id,
                         pc_track_id,
                         call_handle,
                         peerconnection,
                         payload,
                         tos,
+                        setup_type,
                         fingerprint_alg,
                         fingerprint,
                         attrs,
                         &ret));
 
   return ret;
 }
 
@@ -2695,18 +2707,18 @@ int vcmGetILBCMode()
 {
     return 0;
 }
 
 } // extern "C"
 
 static mozilla::RefPtr<TransportFlow>
 vcmCreateTransportFlow(sipcc::PeerConnectionImpl *pc, int level, bool rtcp,
-                       const char *fingerprint_alg,
-                       const char *fingerprint) {
+  sdp_setup_type_e setup_type, const char *fingerprint_alg,
+  const char *fingerprint) {
 
   // TODO(ekr@rtfm.com): Check that if the flow already exists the digest
   // is the same. The only way that can happen is if
   //
   // (a) We have an error or
   // (b) The other side bundled but had mismatched digests for each line
   //
   // Not clear that either of these cases matters.
@@ -2738,23 +2750,24 @@ vcmCreateTransportFlow(sipcc::PeerConnec
     //   setup attribute value of setup:active or setup:passive.  Note that
     //   if the answerer uses setup:passive, then the DTLS handshake will
     //   not begin until the answerer is received, which adds additional
     //   latency. setup:active allows the answer and the DTLS handshake to
     //   occur in parallel.  Thus, setup:active is RECOMMENDED.  Whichever
     //   party is active MUST initiate a DTLS handshake by sending a
     //   ClientHello over each flow (host/port quartet).
     //
-    // Currently we just hardwire the roles to be that the offerer is the
-    // server, which is what you would expect from the "recommended"
-    // behavior above.
-    //
-    // TODO(ekr@rtfm.com): implement the actpass logic above.
-    dtls->SetRole(pc->GetRole() == sipcc::PeerConnectionImpl::kRoleOfferer ?
-                  TransportLayerDtls::SERVER : TransportLayerDtls::CLIENT);
+
+    // setup_type should at this point be either PASSIVE or ACTIVE
+    // other a=setup values should have been negotiated out.
+    MOZ_ASSERT(setup_type == SDP_SETUP_PASSIVE ||
+               setup_type == SDP_SETUP_ACTIVE);
+    dtls->SetRole(
+      setup_type == SDP_SETUP_PASSIVE ?
+      TransportLayerDtls::SERVER : TransportLayerDtls::CLIENT);
     mozilla::RefPtr<DtlsIdentity> pcid = pc->GetIdentity();
     if (!pcid) {
       return nullptr;
     }
     dtls->SetIdentity(pcid);
 
     unsigned char remote_digest[TransportLayerDtls::kMaxDigestLength];
     size_t digest_len;
@@ -2854,9 +2867,57 @@ int vcmOnSdpParseError(const char *peerc
   if (!NS_SUCCEEDED(rv)) {
     CSFLogError( logTag, "%s(): Could not dispatch to main thread", __FUNCTION__);
     return VCM_ERROR;
   }
 
   return 0;
 }
 
-
+/**
+ * vcmDisableRtcpComponent_m
+ *
+ * If we are doing rtcp-mux we need to disable component number 2 in the ICE
+ * layer.  Otherwise we will wait for it to connect when it is unused
+ */
+static int vcmDisableRtcpComponent_m(const char *peerconnection, int level) {
+#ifdef MOZILLA_INTERNAL_API
+  MOZ_ASSERT(NS_IsMainThread());
+#endif
+  MOZ_ASSERT(level > 0);
+
+  sipcc::PeerConnectionWrapper pc(peerconnection);
+  ENSURE_PC(pc, VCM_ERROR);
+
+  CSFLogDebug( logTag, "%s: disabling rtcp component %d", __FUNCTION__, level);
+  mozilla::RefPtr<NrIceMediaStream> stream = pc.impl()->media()->
+    ice_media_stream(level-1);
+  MOZ_ASSERT(stream);
+  if (!stream) {
+    return VCM_ERROR;
+  }
+
+  // The second component is for RTCP
+  nsresult res = stream->DisableComponent(2);
+  MOZ_ASSERT(NS_SUCCEEDED(res));
+  if (!NS_SUCCEEDED(res)) {
+    return VCM_ERROR;
+  }
+
+  return 0;
+}
+
+/**
+ * vcmDisableRtcpComponent
+ *
+ * If we are doing rtcp-mux we need to disable component number 2 in the ICE
+ * layer.  Otherwise we will wait for it to connect when it is unused
+ */
+int vcmDisableRtcpComponent(const char *peerconnection, int level) {
+  int ret;
+  mozilla::SyncRunnable::DispatchToThread(VcmSIPCCBinding::getMainThread(),
+      WrapRunnableNMRet(&vcmDisableRtcpComponent_m,
+                        peerconnection,
+                        level,
+                        &ret));
+  return ret;
+}
+
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -330,17 +330,16 @@ private:
   nsRefPtr<RemoteSourceStreamInfo> mRemoteStream;
 };
 
 NS_IMPL_ISUPPORTS1(PeerConnectionImpl, IPeerConnection)
 
 PeerConnectionImpl::PeerConnectionImpl()
 : mTimeCard(PR_LOG_TEST(signalingLogInfo(),PR_LOG_ERROR) ?
             create_timecard() : nullptr)
-  , mRole(kRoleUnknown)
   , mCall(NULL)
   , mReadyState(kNew)
   , mSignalingState(kSignalingStable)
   , mIceState(kIceGathering)
   , mPCObserver(NULL)
   , mWindow(NULL)
   , mIdentity(NULL)
   , mSTSThread(NULL)
@@ -1017,18 +1016,16 @@ NS_IMETHODIMP
 PeerConnectionImpl::CreateOffer(MediaConstraints& constraints)
 {
   PC_AUTO_ENTER_API_CALL(true);
 
   Timecard *tc = mTimeCard;
   mTimeCard = nullptr;
   STAMP_TIMECARD(tc, "Create Offer");
 
-  mRole = kRoleOfferer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
-
   cc_media_constraints_t* cc_constraints = nullptr;
   constraints.buildArray(&cc_constraints);
 
   mCall->createOffer(cc_constraints, tc);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1049,18 +1046,16 @@ NS_IMETHODIMP
 PeerConnectionImpl::CreateAnswer(MediaConstraints& constraints)
 {
   PC_AUTO_ENTER_API_CALL(true);
 
   Timecard *tc = mTimeCard;
   mTimeCard = nullptr;
   STAMP_TIMECARD(tc, "Create Answer");
 
-  mRole = kRoleAnswerer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
-
   cc_media_constraints_t* cc_constraints = nullptr;
   constraints.buildArray(&cc_constraints);
 
   mCall->createAnswer(cc_constraints, tc);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -160,22 +160,16 @@ public:
   enum IceState {
     kIceGathering,
     kIceWaiting,
     kIceChecking,
     kIceConnected,
     kIceFailed
   };
 
-  enum Role {
-    kRoleUnknown,
-    kRoleOfferer,
-    kRoleAnswerer
-  };
-
   enum Error {
     kNoError                          = 0,
     kInvalidConstraintsType           = 1,
     kInvalidCandidateType             = 2,
     kInvalidMediastreamTrack          = 3,
     kInvalidState                     = 4,
     kInvalidSessionDescription        = 5,
     kIncompatibleSessionDescription   = 6,
@@ -190,21 +184,16 @@ public:
   static PeerConnectionImpl* CreatePeerConnection();
   static nsresult ConvertRTCConfiguration(const JS::Value& aSrc,
     IceConfiguration *aDst, JSContext* aCx);
   static nsresult ConvertConstraints(
     const JS::Value& aConstraints, MediaConstraints* aObj, JSContext* aCx);
   static already_AddRefed<DOMMediaStream> MakeMediaStream(nsPIDOMWindow* aWindow,
                                                           uint32_t aHint);
 
-  Role GetRole() const {
-    PC_AUTO_ENTER_API_CALL_NO_CHECK();
-    return mRole;
-  }
-
   nsresult CreateRemoteSourceStreamInfo(nsRefPtr<RemoteSourceStreamInfo>* aInfo);
 
   // Implementation of the only observer we need
   virtual void onCallEvent(
     ccapi_call_event_e aCallEvent,
     CSF::CC_CallInfoPtr aInfo
   );
 
@@ -334,19 +323,16 @@ private:
   // ICE callbacks run on the right thread.
   nsresult IceStateChange_m(IceState aState);
 
   // Timecard used to measure processing time. This should be the first class
   // attribute so that we accurately measure the time required to instantiate
   // any other attributes of this class.
   Timecard *mTimeCard;
 
-  // The role we are adopting
-  Role mRole;
-
   // The call
   CSF::CC_CallPtr mCall;
   ReadyState mReadyState;
   SignalingState mSignalingState;
 
   // ICE State
   IceState mIceState;
 
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -523,16 +523,19 @@ gsmsdp_init_media (fsmdef_media_t *media
 
     media->hold  = FSM_HOLD_NONE;
     media->flags = 0;                    /* clear all flags      */
     media->cap_index = CC_MAX_MEDIA_CAP; /* max is invalid value */
     media->video = NULL;
     media->candidate_ct = 0;
     media->rtcp_mux = FALSE;
 
+    /* ACTPASS is the value we put in every offer */
+    media->setup = SDP_SETUP_ACTPASS;
+
     media->local_datachannel_port = 0;
     media->remote_datachannel_port = 0;
     media->datachannel_streams = WEBRTC_DATACHANNEL_STREAMS_DEFAULT;
     sstrncpy(media->datachannel_protocol, WEBRTC_DATA_CHANNEL_PROT, SDP_MAX_STRING_LEN);
 
     media->payloads = NULL;
     media->num_payloads = 0;
 }
@@ -1817,16 +1820,81 @@ gsmsdp_set_rtcp_mux_attribute (sdp_attr_
 
     result = sdp_attr_set_rtcp_mux_attribute(sdp_p, level, 0, sdp_attr, a_instance, rtcp_mux);
     if (result != SDP_SUCCESS) {
         GSM_ERR_MSG("Failed to set attribute");
     }
 }
 
 /*
+ * gsmsdp_set_setup_attribute
+ *
+ * Description:
+ *
+ * Adds a setup attribute to the specified SDP.
+ *
+ * Parameters:
+ *
+ * level        - The media level of the SDP where the media attribute exists.
+ * sdp_p        - Pointer to the SDP to set the ice candidate attribute against.
+ * setup_type   - Value for the a=setup line
+ */
+static void
+gsmsdp_set_setup_attribute(uint16_t level,
+  void *sdp_p, sdp_setup_type_e setup_type) {
+    uint16_t a_instance = 0;
+    sdp_result_e result;
+
+    result = sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_SETUP, &a_instance);
+    if (result != SDP_SUCCESS) {
+        GSM_ERR_MSG("Failed to add attribute");
+        return;
+    }
+
+    result = sdp_attr_set_setup_attribute(sdp_p, level, 0,
+      a_instance, setup_type);
+    if (result != SDP_SUCCESS) {
+        GSM_ERR_MSG("Failed to set attribute");
+    }
+}
+
+/*
+ * gsmsdp_set_connection_attribute
+ *
+ * Description:
+ *
+ * Adds a connection attribute to the specified SDP.
+ *
+ * Parameters:
+ *
+ * level        - The media level of the SDP where the media attribute exists.
+ * sdp_p        - Pointer to the SDP to set the ice candidate attribute against.
+ * connection_type - Value for the a=connection line
+ */
+static void
+gsmsdp_set_connection_attribute(uint16_t level,
+  void *sdp_p, sdp_connection_type_e connection_type) {
+    uint16_t a_instance = 0;
+    sdp_result_e result;
+
+    result = sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_CONNECTION,
+      &a_instance);
+    if (result != SDP_SUCCESS) {
+        GSM_ERR_MSG("Failed to add attribute");
+        return;
+    }
+
+    result = sdp_attr_set_connection_attribute(sdp_p, level, 0,
+      a_instance, connection_type);
+    if (result != SDP_SUCCESS) {
+        GSM_ERR_MSG("Failed to set attribute");
+    }
+}
+
+/*
  * gsmsdp_set_dtls_fingerprint_attribute
  *
  * Description:
  *
  * Adds an dtls fingerprint attribute attributes to the specified SDP.
  *
  * Parameters:
  *
@@ -4636,16 +4704,17 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
     char           *session_pwd;
     cc_action_data_t  data;
     int             j=0;
     int             rtcpmux = 0;
     tinybool        rtcp_mux = FALSE;
     sdp_result_e    sdp_res;
     boolean         created_media_stream = FALSE;
     int             lsm_rc;
+    sdp_setup_type_e remote_setup_type;
 
     config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
 
     num_m_lines = sdp_get_num_media_lines(sdp_p->dest_sdp);
     if (num_m_lines == 0) {
         GSM_DEBUG(DEB_L_C_F_PREFIX"no media lines found.",
                   DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
         return CC_CAUSE_NO_MEDIA;
@@ -4934,16 +5003,50 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
               }
             }
 
             if (!unsupported_line) {
 
               if (sdpmode) {
                   int j;
 
+                  /* Find the remote a=setup value */
+                  sdp_res = sdp_attr_get_setup_attribute(
+                      sdp_p->dest_sdp, i, 0, 1, &remote_setup_type);
+
+
+                  /* setup attribute
+                     We are setting our local SDP to be ACTIVE if the value
+                     in the remote SDP is missing, PASSIVE or ACTPASS.
+                     If the remote value is ACTIVE, then we will respond
+                     with PASSIVE.
+                     If the remote value is HOLDCONN we will respond with
+                     HOLDCONN and set the direction to INACTIVE
+                     The DTLS role will then be set when the TransportFlow
+                     is created */
+                  media->setup = SDP_SETUP_ACTIVE;
+
+                  if (sdp_res == SDP_SUCCESS) {
+                      if (remote_setup_type == SDP_SETUP_ACTIVE) {
+                          media->setup = SDP_SETUP_PASSIVE;
+                      } else if (remote_setup_type == SDP_SETUP_HOLDCONN) {
+                          media->setup = SDP_SETUP_HOLDCONN;
+                          media->direction = SDP_DIRECTION_INACTIVE;
+                      }
+                  }
+
+                  gsmsdp_set_setup_attribute(media->level, dcb_p->sdp->src_sdp,
+                    media->setup);
+
+                  /* TODO(ehugg) we are not yet supporting existing connections
+                     See bug 857115.  We currently always respond with
+                     connection:new */
+                  gsmsdp_set_connection_attribute(media->level,
+                    dcb_p->sdp->src_sdp, SDP_CONNECTION_NEW);
+
                   /* Set ICE */
                   for (j=0; j<media->candidate_ct; j++) {
                     gsmsdp_set_ice_attribute (SDP_ATTR_ICE_CANDIDATE, media->level,
                                               sdp_p->src_sdp, media->candidatesp[j]);
                   }
 
                   /* Set RTCPMux if we have it turned on in our config
                      and the other side requests it */
@@ -5451,16 +5554,23 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb
           /* Add supported rtcp-fb types */
           if (media_cap->type == SDP_MEDIA_VIDEO) {
               gsmsdp_add_rtcp_fb (level, dcb_p->sdp->src_sdp, RTP_VP8,
                   SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
                   SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
                   SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR));
           }
 
+          /* setup and connection attributes */
+          gsmsdp_set_setup_attribute(level, dcb_p->sdp->src_sdp, media->setup);
+
+          /* This is a new media line so we should send connection:new */
+          gsmsdp_set_connection_attribute(level, dcb_p->sdp->src_sdp,
+            SDP_CONNECTION_NEW);
+
           /*
            * wait until here to set ICE candidates as SDP is now initialized
            */
           for (i=0; i<media->candidate_ct; i++) {
             gsmsdp_set_ice_attribute (SDP_ATTR_ICE_CANDIDATE, level, dcb_p->sdp->src_sdp, media->candidatesp[i]);
           }
 
           config_get_value(CFGID_RTCPMUX, &rtcpmux, sizeof(rtcpmux));
@@ -6829,16 +6939,27 @@ gsmsdp_install_peer_ice_attributes(fsm_f
             return (CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED);
     }
 
     /* Now process all the media lines */
     GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
       if (!GSMSDP_MEDIA_ENABLED(media))
         continue;
 
+      /* If we are muxing, disable the second
+         component of the ICE stream */
+      if (media->rtcp_mux) {
+        vcm_res = vcmDisableRtcpComponent(dcb_p->peerconnection,
+          media->level);
+
+        if (vcm_res) {
+          return (CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED);
+        }
+      }
+
       sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, media->level, 0,
         SDP_ATTR_ICE_UFRAG, 1, &ufrag);
       if (sdp_res != SDP_SUCCESS)
         ufrag = NULL;
 
       sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, media->level, 0,
         SDP_ATTR_ICE_PWD, 1, &pwd);
       if (sdp_res != SDP_SUCCESS)
--- a/media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
@@ -203,16 +203,21 @@ typedef struct fsmdef_media_t_ {
     int candidate_ct;
 
     /*
      * rtcp-mux indicates media stream is muxed for RTP and RTCP
      */
     boolean        rtcp_mux;
 
     /*
+     * The value of the a=setup line
+     */
+    sdp_setup_type_e setup;
+
+    /*
      * port number used in m= data channel line
      */
     uint16_t       local_datachannel_port;
     uint16_t       remote_datachannel_port;
 
     /*
      * Data Channel properties
      */
--- a/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
@@ -1001,16 +1001,17 @@ lsm_rx_start (lsm_lcb_t *lcb, const char
                     ret_val = vcmRxStartICE(media->cap_index, group_id, media->refid,
                     media->level,
                     pc_stream_id,
                     pc_track_id,
                     lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
                     dcb->peerconnection,
                     media->num_payloads,
                     media->payloads,
+                    media->setup,
                     FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media),
                     FSM_NEGOTIATED_CRYPTO_DIGEST(media),
                     &attrs);
                 } else if (!sdpmode) {
                     if (media->payloads == NULL) {
                         LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
                         return;
                     }
@@ -1271,16 +1272,17 @@ lsm_tx_start (lsm_lcb_t *lcb, const char
                   /* TODO(emannion): his perhaps needs some error checking for validity.
                      See gsmsdp_get_media_cap_entry_by_index. */
                   dcb->media_cap_tbl->cap[media->cap_index].pc_stream,
                   dcb->media_cap_tbl->cap[media->cap_index].pc_track,
                   lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
                   dcb->peerconnection,
                   media->payloads,
                   (short)dscp,
+                  media->setup,
                   FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media),
                   FSM_NEGOTIATED_CRYPTO_DIGEST(media),
                   &attrs) == -1)
               {
                 LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStartICE failed",
                   DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
                 dcb->dsp_out_of_resources = TRUE;
                 return;
--- a/media/webrtc/signaling/src/sipcc/core/includes/config.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/config.h
@@ -174,17 +174,17 @@ static const unsigned char gCallWaiting 
 static const int gDeviceSecurityMode = 1;
 static const int gCcm2_sip_port = 5060;
 static const int gCcm3_sip_port = 5060;
 static const boolean gCcm1_isvalid = TRUE;
 static const int gDscpCallControl = 1;
 static const int gSpeakerEnabled = 1;
 static const char gExternalNumberMask[] = "";
 static const char gVersion[] = "0.1";
-static const boolean gRTCPMUX = FALSE;
+static const boolean gRTCPMUX = TRUE;
 static boolean gRTPSAVPF = TRUE;           /* TRUE = RTP/SAVPF , FALSE = RTP/SAVP */
 static const boolean gMAXAVBITRATE = FALSE;      /* Following six are OPUS fmtp options */
 static const boolean gMAXCODEDAUDIOBW = FALSE;
 static const boolean gUSEDTX = FALSE;
 static const boolean gSTEREO = FALSE;
 static const boolean gUSEINBANDFEC = FALSE;
 static const boolean gCBR = FALSE;
 static const boolean gMAXPTIME = FALSE;
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
@@ -514,16 +514,24 @@ typedef enum {
     SDP_RTCP_FB_CCM_FIR = 0,
     SDP_RTCP_FB_CCM_TMMBR,
     SDP_RTCP_FB_CCM_TSTR,
     SDP_RTCP_FB_CCM_VBCM,
     SDP_MAX_RTCP_FB_CCM,
     SDP_RTCP_FB_CCM_UNKNOWN
 } sdp_rtcp_fb_ccm_type_e;
 
+typedef enum {
+    SDP_CONNECTION_NOT_FOUND = -1,
+    SDP_CONNECTION_NEW = 0,
+    SDP_CONNECTION_EXISTING,
+    SDP_MAX_CONNECTION,
+    SDP_CONNECTION_UNKNOWN
+} sdp_connection_type_e;
+
 #define SDP_RTCP_FB_NACK_TO_BITMAP(type) (1 << (type))
 #define SDP_RTCP_FB_ACK_TO_BITMAP(type)  (1 << (SDP_MAX_RTCP_FB_NACK + (type)))
 #define SDP_RTCP_FB_CCM_TO_BITMAP(type)  (1 << (SDP_MAX_RTCP_FB_NACK + \
                                                 SDP_MAX_RTCP_FB_ACK + (type)))
 
 /*
  * sdp_srtp_fec_order_t
  *  This type defines the order in which to perform FEC
@@ -1012,16 +1020,18 @@ typedef struct sdp_attr {
         sdp_rtr_t             rtr;
         sdp_comediadir_t      comediadir;
         sdp_srtp_crypto_context_t srtp_context;
         sdp_mptime_t          mptime;
         sdp_stream_data_t     stream_data;
         char                  unknown[SDP_MAX_STRING_LEN+1];
         sdp_source_filter_t   source_filter;
         sdp_fmtp_fb_t         rtcp_fb;
+        sdp_setup_type_e      setup;
+        sdp_connection_type_e connection;
     } attr;
     struct sdp_attr          *next_p;
 } sdp_attr_t;
 
 typedef struct sdp_srtp_crypto_suite_list_ {
     sdp_srtp_crypto_suite_t crypto_suite_val;
     char * crypto_suite_str;
     unsigned char key_size_bytes;
@@ -2064,16 +2074,33 @@ sdp_result_e
 sdp_attr_get_rtcp_mux_attribute (void *sdp_ptr, u16 level,
                                   u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
                                   tinybool *rtcp_mux);
 
 sdp_result_e
 sdp_attr_set_rtcp_mux_attribute(void *sdp_ptr, u16 level,
                               u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const tinybool rtcp_mux);
 
+
+sdp_result_e
+sdp_attr_get_setup_attribute (void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_setup_type_e *setup_type);
+
+sdp_result_e
+sdp_attr_set_setup_attribute(void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_setup_type_e setup_type);
+
+sdp_result_e
+sdp_attr_get_connection_attribute (void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_connection_type_e *connection_type);
+
+sdp_result_e
+sdp_attr_set_connection_attribute(void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_connection_type_e connection_type);
+
 sdp_result_e
 sdp_attr_get_dtls_fingerprint_attribute (void *sdp_ptr, u16 level,
                                   u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
                                   char **out);
 
 sdp_result_e
 sdp_attr_set_dtls_fingerprint_attribute(void *sdp_ptr, u16 level,
                               u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const char *dtls_fingerprint);
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
@@ -4981,8 +4981,132 @@ sdp_result_e sdp_parse_attr_rtcp_fb (sdp
 
     /* Just store the rest of the line in "extra" -- this will return
        a failure result if there is no more text, but that's fine. */
     ptr = sdp_getnextstrtok(ptr, rtcp_fb_p->extra,
                             sizeof(rtcp_fb_p->extra), "\r\n", &result);
 
     return SDP_SUCCESS;
 }
+
+sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
+                                  sdp_attr_t *attr_p,
+                                  flex_string *fs)
+{
+    switch (attr_p->attr.setup) {
+    case SDP_SETUP_ACTIVE:
+    case SDP_SETUP_PASSIVE:
+    case SDP_SETUP_ACTPASS:
+    case SDP_SETUP_HOLDCONN:
+        flex_string_sprintf(fs, "a=%s:%s\r\n",
+            sdp_attr[attr_p->type].name,
+            sdp_setup_type_val[attr_p->attr.setup].name);
+        break;
+    default:
+        CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
+                    sdp_p->debug_str, attr_p->attr.setup);
+        return SDP_FAILURE;
+    }
+
+    return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
+                                   sdp_attr_t *attr_p,
+                                   const char *ptr)
+{
+    int i = find_token_enum("setup attribute", sdp_p, &ptr,
+        sdp_setup_type_val,
+        SDP_MAX_SETUP, SDP_SETUP_UNKNOWN);
+
+    if (i < 0) {
+        sdp_parse_error(sdp_p->peerconnection,
+          "%s Warning: could not parse setup attribute",
+          sdp_p->debug_str);
+        sdp_p->conf_p->num_invalid_param++;
+        return SDP_INVALID_PARAMETER;
+    }
+
+    attr_p->attr.setup = (sdp_setup_type_e) i;
+
+    switch (attr_p->attr.setup) {
+    case SDP_SETUP_ACTIVE:
+    case SDP_SETUP_PASSIVE:
+    case SDP_SETUP_ACTPASS:
+    case SDP_SETUP_HOLDCONN:
+        /* All these values are OK */
+        break;
+    case SDP_SETUP_UNKNOWN:
+        sdp_parse_error(sdp_p->peerconnection,
+            "%s Warning: Unknown setup attribute",
+            sdp_p->debug_str);
+        return SDP_INVALID_PARAMETER;
+        break;
+    default:
+        /* This is an internal error, not a parsing error */
+        CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
+                    sdp_p->debug_str, attr_p->attr.setup);
+        return SDP_FAILURE;
+        break;
+    }
+
+    return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
+                                       sdp_attr_t *attr_p,
+                                       flex_string *fs)
+{
+    switch (attr_p->attr.connection) {
+    case SDP_CONNECTION_NEW:
+    case SDP_CONNECTION_EXISTING:
+        flex_string_sprintf(fs, "a=%s:%s\r\n",
+            sdp_attr[attr_p->type].name,
+            sdp_connection_type_val[attr_p->attr.connection].name);
+        break;
+    default:
+        CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
+                    sdp_p->debug_str, attr_p->attr.connection);
+        return SDP_FAILURE;
+    }
+
+    return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
+                                       sdp_attr_t *attr_p,
+                                       const char *ptr)
+{
+    int i = find_token_enum("connection attribute", sdp_p, &ptr,
+        sdp_connection_type_val,
+        SDP_MAX_CONNECTION, SDP_CONNECTION_UNKNOWN);
+
+    if (i < 0) {
+        sdp_parse_error(sdp_p->peerconnection,
+          "%s Warning: could not parse connection attribute",
+          sdp_p->debug_str);
+        sdp_p->conf_p->num_invalid_param++;
+        return SDP_INVALID_PARAMETER;
+    }
+
+    attr_p->attr.connection = (sdp_connection_type_e) i;
+
+    switch (attr_p->attr.connection) {
+    case SDP_CONNECTION_NEW:
+    case SDP_CONNECTION_EXISTING:
+        /* All these values are OK */
+        break;
+    case SDP_CONNECTION_UNKNOWN:
+        sdp_parse_error(sdp_p->peerconnection,
+            "%s Warning: Unknown connection attribute",
+            sdp_p->debug_str);
+        return SDP_INVALID_PARAMETER;
+        break;
+    default:
+        /* This is an internal error, not a parsing error */
+        CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
+                    sdp_p->debug_str, attr_p->attr.connection);
+        return SDP_FAILURE;
+        break;
+    }
+
+    return SDP_SUCCESS;
+}
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c
@@ -4079,16 +4079,173 @@ sdp_result_e sdp_attr_set_rtcp_mux_attri
         sdp_p->conf_p->num_invalid_param++;
         return (SDP_INVALID_PARAMETER);
     }
 
     attr_p->attr.boolean_val = rtcp_mux;
     return (SDP_SUCCESS);
 }
 
+
+/* Function:    sdp_attr_get_setup_attribute
+ * Description: Returns the value of a setup attribute at a given level
+ *
+ * Parameters:  sdp_ptr     The SDP handle returned by sdp_init_description.
+ *              level       The level to check for the attribute.
+ *              cap_num     The capability number associated with the
+ *                          attribute if any.  If none, should be zero.
+ *              inst_num    The attribute instance number to check.
+ *              setup_type  Returns sdp_setup_type_e enum
+ * Returns:
+ *              SDP_SUCCESS           Attribute param was set successfully.
+ *              SDP_INVALID_SDP_PTR   SDP pointer invalid
+ *              SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_setup_attribute (void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_setup_type_e *setup_type)
+{
+    sdp_t       *sdp_p = (sdp_t *)sdp_ptr;
+    sdp_attr_t  *attr_p;
+
+    if (!sdp_verify_sdp_ptr(sdp_p)) {
+        return SDP_INVALID_SDP_PTR;
+    }
+
+    attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SETUP, inst_num);
+    if (!attr_p) {
+        if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+            CSFLogError(logTag,
+                "%s setup attribute, level %u instance %u not found.",
+                sdp_p->debug_str, level, inst_num);
+        }
+        sdp_p->conf_p->num_invalid_param++;
+        return SDP_INVALID_PARAMETER;
+    }
+
+    *setup_type = attr_p->attr.setup;
+    return SDP_SUCCESS;
+}
+
+/* Function:    sdp_attr_set_setup_attribute
+ * Description: Sets the value of a setup attribute parameter
+ *
+ * Parameters:  sdp_ptr        The SDP handle returned by sdp_init_description.
+ *              level          The level to set the attribute.
+ *              cap_num        The capability number associated with the
+ *                             attribute if any.  If none, should be zero.
+ *              inst_num       The attribute instance number to check.
+ *              setup_type     setup attribute value to set
+ * Returns:     SDP_SUCCESS            Attribute param was set successfully.
+ *              SDP_INVALID_SDP_PTR    SDP ptr invalid
+ *              SDP_INVALID_PARAMETER  Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_setup_attribute(void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_setup_type_e setup_type)
+{
+    sdp_t       *sdp_p = (sdp_t *)sdp_ptr;
+    sdp_attr_t  *attr_p;
+
+    if (!sdp_verify_sdp_ptr(sdp_p)) {
+        return SDP_INVALID_SDP_PTR;
+    }
+
+    attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SETUP, inst_num);
+    if (!attr_p) {
+        if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+            CSFLogError(logTag, "%s setup attribute, level %u instance %u "
+                      "not found.", sdp_p->debug_str, level, inst_num);
+        }
+        sdp_p->conf_p->num_invalid_param++;
+        return SDP_INVALID_PARAMETER;
+    }
+
+    attr_p->attr.setup = setup_type;
+    return SDP_SUCCESS;
+}
+
+/* Function:    sdp_attr_get_connection_attribute
+ * Description: Returns the value of a connection attribute at a given level
+ *
+ * Parameters:  sdp_ptr     The SDP handle returned by sdp_init_description.
+ *              level       The level to check for the attribute.
+ *              cap_num     The capability number associated with the
+ *                          attribute if any.  If none, should be zero.
+ *              inst_num    The attribute instance number to check.
+ *              connection_type  Returns sdp_connection_type_e enum
+ * Returns:
+ *              SDP_SUCCESS           Attribute param was set successfully.
+ *              SDP_INVALID_SDP_PTR   SDP pointer invalid
+ *              SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_connection_attribute (void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_connection_type_e *connection_type)
+{
+    sdp_t       *sdp_p = (sdp_t *)sdp_ptr;
+    sdp_attr_t  *attr_p;
+
+    if (!sdp_verify_sdp_ptr(sdp_p)) {
+        return SDP_INVALID_SDP_PTR;
+    }
+
+    attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_CONNECTION,
+        inst_num);
+    if (!attr_p) {
+        if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+            CSFLogError(logTag,
+                "%s setup attribute, level %u instance %u not found.",
+                sdp_p->debug_str, level, inst_num);
+        }
+        sdp_p->conf_p->num_invalid_param++;
+        return SDP_INVALID_PARAMETER;
+    }
+
+    *connection_type = attr_p->attr.connection;
+    return SDP_SUCCESS;
+}
+
+/* Function:    sdp_attr_set_connection_attribute
+ * Description: Sets the value of a connection attribute parameter
+ *
+ * Parameters:  sdp_ptr        The SDP handle returned by sdp_init_description.
+ *              level          The level to set the attribute.
+ *              cap_num        The capability number associated with the
+ *                             attribute if any.  If none, should be zero.
+ *              inst_num       The attribute instance number to check.
+ *              connection_type     connection attribute value to set
+ * Returns:     SDP_SUCCESS            Attribute param was set successfully.
+ *              SDP_INVALID_SDP_PTR    SDP ptr invalid
+ *              SDP_INVALID_PARAMETER  Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_connection_attribute(void *sdp_ptr, u16 level,
+    u8 cap_num, u16 inst_num, sdp_connection_type_e connection_type)
+{
+    sdp_t       *sdp_p = (sdp_t *)sdp_ptr;
+    sdp_attr_t  *attr_p;
+
+    if (!sdp_verify_sdp_ptr(sdp_p)) {
+        return SDP_INVALID_SDP_PTR;
+    }
+
+    attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_CONNECTION,
+        inst_num);
+    if (!attr_p) {
+        if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+            CSFLogError(logTag, "%s connection attribute, level %u instance %u "
+                      "not found.", sdp_p->debug_str, level, inst_num);
+        }
+        sdp_p->conf_p->num_invalid_param++;
+        return SDP_INVALID_PARAMETER;
+    }
+
+    attr_p->attr.connection = connection_type;
+    return SDP_SUCCESS;
+}
+
 /* Function:    sdp_attr_get_dtls_fingerprint_attribute
  * Description: Returns the value of dtls fingerprint attribute at a given level
  *
  * Parameters:  sdp_ptr     The SDP handle returned by sdp_init_description.
  *              level       The level to check for the attribute.
  *              cap_num     The capability number associated with the
  *                          attribute if any.  If none, should be zero.
  *              inst_num    The attribute instance number to check.
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_main.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_main.c
@@ -164,17 +164,21 @@ const sdp_attrarray_t sdp_attr[SDP_MAX_A
       sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr},
     {"rtcp-mux", sizeof("rtcp-mux"),
       sdp_parse_attr_rtcp_mux_attr, sdp_build_attr_rtcp_mux_attr},
     {"fingerprint", sizeof("fingerprint"),
       sdp_parse_attr_fingerprint_attr, sdp_build_attr_simple_string},
     {"maxptime", sizeof("maxptime"),
       sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32},
     {"rtcp-fb", sizeof("rtcp-fb"),
-      sdp_parse_attr_rtcp_fb, sdp_build_attr_rtcp_fb}
+      sdp_parse_attr_rtcp_fb, sdp_build_attr_rtcp_fb},
+    {"setup", sizeof("setup"),
+      sdp_parse_attr_setup, sdp_build_attr_setup},
+    {"connection", sizeof("connection"),
+      sdp_parse_attr_connection, sdp_build_attr_connection},
 };
 
 /* Note: These *must* be in the same order as the enum types. */
 const sdp_namearray_t sdp_media[SDP_MAX_MEDIA_TYPES] =
 {
     {"audio",        sizeof("audio")},
     {"video",        sizeof("video")},
     {"application",  sizeof("application")},
@@ -478,16 +482,31 @@ const sdp_namearray_t sdp_rtcp_fb_ack_ty
 const sdp_namearray_t sdp_rtcp_fb_ccm_type_val[SDP_MAX_RTCP_FB_CCM] =
 {
     SDP_NAME("fir"),
     SDP_NAME("tmmbr"),
     SDP_NAME("tstr"),
     SDP_NAME("vbcm")
 };
 
+/* Maintain the same order as defined in typedef sdp_setup_type_e */
+const sdp_namearray_t sdp_setup_type_val[SDP_MAX_SETUP] =
+{
+    SDP_NAME("active"),
+    SDP_NAME("passive"),
+    SDP_NAME("actpass"),
+    SDP_NAME("holdconn")
+};
+
+/* Maintain the same order as defined in typedef sdp_connection_type_e */
+const sdp_namearray_t sdp_connection_type_val[SDP_MAX_CONNECTION] =
+{
+    SDP_NAME("new"),
+    SDP_NAME("existing")
+};
 
 /*  Maintain same order as defined in typedef sdp_srtp_crypto_suite_t */
 const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] =
 {
   {SDP_SRTP_UNKNOWN_CRYPTO_SUITE, UNKNOWN_CRYPTO_SUITE, 0, 0},
   {SDP_SRTP_AES_CM_128_HMAC_SHA1_32, AES_CM_128_HMAC_SHA1_32,
       SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES,
       SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES},
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_private.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_private.h
@@ -32,16 +32,18 @@ extern const sdp_namearray_t sdp_srtp_co
 extern const sdp_namearray_t sdp_bw_modifier_val[];
 extern const sdp_namearray_t sdp_group_attr_val[];
 extern const sdp_namearray_t sdp_src_filter_mode_val[];
 extern const sdp_namearray_t sdp_rtcp_unicast_mode_val[];
 extern const sdp_namearray_t sdp_rtcp_fb_type_val[];
 extern const sdp_namearray_t sdp_rtcp_fb_nack_type_val[];
 extern const sdp_namearray_t sdp_rtcp_fb_ack_type_val[];
 extern const sdp_namearray_t sdp_rtcp_fb_ccm_type_val[];
+extern const sdp_namearray_t sdp_setup_type_val[];
+extern const sdp_namearray_t sdp_connection_type_val[];
 
 
 extern const  sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[];
 /* Function Prototypes */
 
 /* sdp_access.c */
 extern sdp_mca_t *sdp_find_media_level(sdp_t *sdp_p, u16 level);
 extern sdp_bw_data_t* sdp_find_bw_line (void *sdp_ptr, u16 level, u16 inst_num);
@@ -144,16 +146,28 @@ extern sdp_result_e sdp_build_attr_srtpc
                                                sdp_attr_t *attr_p,
                                                flex_string *fs);
 extern sdp_result_e sdp_parse_attr_rtcp_fb(sdp_t *sdp_p,
                                            sdp_attr_t *attr_p,
                                            const char *ptr);
 extern sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p,
                                            sdp_attr_t *attr_p,
                                            flex_string *fs);
+extern sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
+                                         sdp_attr_t *attr_p,
+                                         const char *ptr);
+extern sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
+                                         sdp_attr_t *attr_p,
+                                         flex_string *fs);
+extern sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
+                                              sdp_attr_t *attr_p,
+                                              const char *ptr);
+extern sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
+                                              sdp_attr_t *attr_p,
+                                              flex_string *fs);
 extern sdp_result_e sdp_parse_attr_mptime(
     sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
 extern sdp_result_e sdp_build_attr_mptime(
     sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
 
 extern sdp_result_e sdp_parse_attr_x_sidin(
     sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
 extern sdp_result_e sdp_build_attr_x_sidin(
--- a/media/webrtc/signaling/src/sipcc/include/ccsdp.h
+++ b/media/webrtc/signaling/src/sipcc/include/ccsdp.h
@@ -237,20 +237,33 @@ typedef enum {
     SDP_ATTR_FRAMERATE,
     SDP_ATTR_ICE_CANDIDATE,
     SDP_ATTR_ICE_UFRAG,
     SDP_ATTR_ICE_PWD,
     SDP_ATTR_RTCP_MUX,
     SDP_ATTR_DTLS_FINGERPRINT,
     SDP_ATTR_MAXPTIME,
     SDP_ATTR_RTCP_FB,  /* RFC 4585 */
+    SDP_ATTR_SETUP,
+    SDP_ATTR_CONNECTION,
     SDP_MAX_ATTR_TYPES,
     SDP_ATTR_INVALID
 } sdp_attr_e;
 
+/* This is here so that it can be used in the VcmSIPCCBinding interface */
+typedef enum {
+    SDP_SETUP_NOT_FOUND = -1,
+    SDP_SETUP_ACTIVE = 0,
+    SDP_SETUP_PASSIVE,
+    SDP_SETUP_ACTPASS,
+    SDP_SETUP_HOLDCONN,
+    SDP_MAX_SETUP,
+    SDP_SETUP_UNKNOWN
+} sdp_setup_type_e;
+
 /**
  * Gets the value of the fmtp attribute- parameter-sets parameter for H.264 codec
  *
  * @param[in]  sdp_handle     The SDP handle
  * @param[in]  level       The level to check for the attribute.
  * @param[in]  cap_num     The capability number associated with the attribute if any.  If none, should be zero.
  * @param[in]  inst_num    The attribute instance number to check.
  *
--- a/media/webrtc/signaling/src/sipcc/include/vcm.h
+++ b/media/webrtc/signaling/src/sipcc/include/vcm.h
@@ -580,16 +580,17 @@ int vcmRxStart(cc_mcapid_t mcap_id,
  *  @param[in]   stream_id    - stream id of the given media type.
  *  @param[in]   level        - the m-line index
  *  @param[in]   pc_stream_id - the media stream index (from PC.addStream())
  *  @param[in]   pc_track_id  - the track within the media stream
  *  @param[in]   call_handle  - call handle
  *  @param[in]   peerconnection - the peerconnection in use
  *  @param[in]   num_payloads  - number of codecs negotiated
  *  @param[in]   payloads      - list of negotiated codec details
+ *  @param[in]   setup_t       - whether playing client or server role
  *  @param[in]   fingerprint_alg - the DTLS fingerprint algorithm
  *  @param[in]   fingerprint  - the DTLS fingerprint
  *  @param[in]   attrs        - media attributes
  *
  *  Returns: zero(0) for success; otherwise, ERROR for failure
  *
  */
 
@@ -598,16 +599,17 @@ int vcmRxStartICE(cc_mcapid_t mcap_id,
         cc_streamid_t stream_id,
         int level,
         int pc_stream_id,
         int pc_track_id,
         cc_call_handle_t  call_handle,
         const char *peerconnection,
         int num_payloads,
         const vcm_payload_info_t* payloads,
+        sdp_setup_type_e setup_type,
         const char *fingerprint_alg,
         const char *fingerprint,
         vcm_mediaAttrs_t *attrs);
 
 /**
  *  start tx stream
  *  Note: For video calls, for a given call handle there will be
  *        two media lines and the corresponding group_id/stream_id pair.
@@ -658,16 +660,17 @@ int vcmTxStart(cc_mcapid_t mcap_id,
  *  @param[in]   stream_id    - stream id of the given media type.
  *  @param[in]   level        - the m-line index
  *  @param[in]   pc_stream_id - the media stream index (from PC.addStream())
  *  @param[in]   pc_track_id  - the track within the media stream
  *  @param[in]   call_handle  - call handle
  *  @param[in]   peerconnection - the peerconnection in use
  *  @param[in]   payload      - payload information
  *  @param[in]   tos          - bit marking
+ *  @param[in]   setup_type   - whether playing client or server role
  *  @param[in]   fingerprint_alg - the DTLS fingerprint algorithm
  *  @param[in]   fingerprint  - the DTLS fingerprint
  *  @param[in]   attrs        - media attributes
  *
  *  Returns: zero(0) for success; otherwise, ERROR for failure
  *
  */
 
@@ -676,16 +679,17 @@ int vcmTxStart(cc_mcapid_t mcap_id,
         cc_streamid_t stream_id,
         int level,
         int pc_stream_id,
         int pc_track_id,
         cc_call_handle_t  call_handle,
         const char *peerconnection,
         const vcm_payload_info_t *payload,
         short tos,
+        sdp_setup_type_e setup_type,
         const char *fingerprint_alg,
         const char *fingerprint,
         vcm_mediaAttrs_t *attrs);
 
 
   short vcmGetDtlsIdentity(const char *peerconnection,
         char *digest_alg,
         size_t max_digest_alg_len,
@@ -1030,16 +1034,24 @@ int vcmGetILBCMode();
  * vcmOnSdpParseError
  *
  * This method is called for each parsing error of SDP.  It does not necessarily
  * mean the SDP read was fatal and can be called many times for the same SDP.
  *
  */
 int vcmOnSdpParseError(const char *peercconnection, const char *message);
 
+/**
+ * vcmDisableRtcpComponent
+ *
+ * If we are doing rtcp-mux we need to disable component number 2 in the ICE
+ * layer.  Otherwise we will wait for it to connect when it is unused
+ */
+int vcmDisableRtcpComponent(const char *peerconnection, int level);
+
 //Using C++ for gips. This is the end of extern "C" above.
 #ifdef __cplusplus
 }
 #endif
 
 
 
 
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -32,17 +32,17 @@
 #include "nricectx.h"
 #include "mozilla/SyncRunnable.h"
 
 #include "mtransport_test_utils.h"
 MtransportTestUtils *test_utils;
 nsCOMPtr<nsIThread> gThread;
 
 static int kDefaultTimeout = 5000;
-static bool fRtcpMux = false;
+static bool fRtcpMux = true;
 
 static std::string callerName = "caller";
 static std::string calleeName = "callee";
 
 namespace test {
 
 std::string indent(const std::string &s, int width = 4) {
   std::string prefix;
@@ -2467,16 +2467,362 @@ TEST_F(SignalingTest, FullCallAudioNoMux
   a2_.CheckMediaPipeline(0, 1, 0);
 
   // Now check video mux.
   a2_.CheckMediaPipeline(0, 2, fRtcpMux ?
     PIPELINE_RTCP_MUX | PIPELINE_VIDEO :
     PIPELINE_VIDEO);
 }
 
+// In this test we will change the offer SDP's a=setup value
+// from actpass to passive.  This will make the answer do active.
+TEST_F(SignalingTest, AudioCallForceDtlsRoles)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give actpass
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=setup:actpass");
+  ASSERT_NE(match, std::string::npos);
+  // Now replace the actpass with passive so that the answer will
+  // return active
+  offer.replace(match, strlen("\r\na=setup:actpass"),
+    "\r\na=setup:passive");
+  std::cout << "Modified SDP " << std::endl
+            << indent(offer) << std::endl;
+
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=setup:active
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=setup:active");
+  ASSERT_NE(match, std::string::npos);
+
+  // This should setup the DTLS with the same roles
+  // as the regular tests above.
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), false);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_.GetPacketsSent(0) >= 40 &&
+                   a2_.GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+// In this test we will change the offer SDP's a=setup value
+// from actpass to active.  This will make the answer do passive
+TEST_F(SignalingTest, AudioCallReverseDtlsRoles)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give actpass
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=setup:actpass");
+  ASSERT_NE(match, std::string::npos);
+  // Now replace the actpass with active so that the answer will
+  // return passive
+  offer.replace(match, strlen("\r\na=setup:actpass"),
+    "\r\na=setup:active");
+  std::cout << "Modified SDP " << std::endl
+            << indent(offer) << std::endl;
+
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=setup:passive
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=setup:passive");
+  ASSERT_NE(match, std::string::npos);
+
+  // This should setup the DTLS with the opposite roles
+  // than the regular tests above.
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), false);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_.GetPacketsSent(0) >= 40 &&
+                   a2_.GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+// In this test we will change the answer SDP's a=setup value
+// from active to passive.  This will make both sides do
+// active and should not connect.
+TEST_F(SignalingTest, AudioCallMismatchDtlsRoles)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give actpass
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=setup:actpass");
+  ASSERT_NE(match, std::string::npos);
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=setup:active
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=setup:active");
+  ASSERT_NE(match, std::string::npos);
+
+  // Now replace the active with passive so that the offerer will
+  // also do active.
+  answer.replace(match, strlen("\r\na=setup:active"),
+    "\r\na=setup:passive");
+  std::cout << "Modified SDP " << std::endl
+            << indent(answer) << std::endl;
+
+  // This should setup the DTLS with both sides playing active
+  a2_.SetLocal(TestObserver::ANSWER, answer.c_str(), false);
+  a1_.SetRemote(TestObserver::ANSWER, answer.c_str(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Not using ASSERT_TRUE_WAIT here because we expect failure
+  PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  // In this case we should receive nothing.
+  ASSERT_EQ(a2_.GetPacketsReceived(0), 0);
+}
+
+// In this test we will change the offer SDP's a=setup value
+// from actpass to garbage.  It should ignore the garbage value
+// and respond with setup:active
+TEST_F(SignalingTest, AudioCallGarbageSetup)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give actpass
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=setup:actpass");
+  ASSERT_NE(match, std::string::npos);
+  // Now replace the actpass with a garbage value
+  offer.replace(match, strlen("\r\na=setup:actpass"),
+    "\r\na=setup:G4rb4g3V4lu3");
+  std::cout << "Modified SDP " << std::endl
+            << indent(offer) << std::endl;
+
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=setup:active
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=setup:active");
+  ASSERT_NE(match, std::string::npos);
+
+  // This should setup the DTLS with the same roles
+  // as the regular tests above.
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), false);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_.GetPacketsSent(0) >= 40 &&
+                   a2_.GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+// In this test we will change the offer SDP's a=connection value
+// from new to garbage.  It should ignore the garbage value
+// and respond with connection:new
+TEST_F(SignalingTest, AudioCallGarbageConnection)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give connection:new
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=connection:new");
+  ASSERT_NE(match, std::string::npos);
+  // Now replace the 'new' with a garbage value
+  offer.replace(match, strlen("\r\na=connection:new"),
+    "\r\na=connection:G4rb4g3V4lu3");
+  std::cout << "Modified SDP " << std::endl
+            << indent(offer) << std::endl;
+
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=connection:new
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=connection:new");
+  ASSERT_NE(match, std::string::npos);
+
+  // This should setup the DTLS with the same roles
+  // as the regular tests above.
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), false);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_.GetPacketsSent(0) >= 40 &&
+                   a2_.GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+// In this test we will change the offer SDP to remove the
+// a=setup and a=connection lines.  Answer should respond with
+// a=setup:active and a=connection:new
+TEST_F(SignalingTest, AudioCallOfferNoSetupOrConnection)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give setup:actpass and connection:new
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=setup:actpass");
+  ASSERT_NE(match, std::string::npos);
+  // Remove the a=setup line
+  offer.replace(match, strlen("\r\na=setup:actpass"), "");
+  match = offer.find("\r\na=connection:new");
+  ASSERT_NE(match, std::string::npos);
+  // Remove the a=connection line
+  offer.replace(match, strlen("\r\na=connection:new"), "");
+  std::cout << "Modified SDP " << std::endl
+            << indent(offer) << std::endl;
+
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=setup:active and a=connection:new
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=setup:active");
+  ASSERT_NE(match, std::string::npos);
+  match = answer.find("\r\na=connection:new");
+  ASSERT_NE(match, std::string::npos);
+
+  // This should setup the DTLS with the same roles
+  // as the regular tests above.
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), false);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_.GetPacketsSent(0) >= 40 &&
+                   a2_.GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
+// In this test we will change the answer SDP to remove the
+// a=setup and a=connection lines.  ICE should still connect
+// since active will be assumed.
+TEST_F(SignalingTest, AudioCallAnswerNoSetupOrConnection)
+{
+  sipcc::MediaConstraints constraints;
+  size_t match;
+
+  a1_.CreateOffer(constraints, OFFER_AUDIO, SHOULD_SENDRECV_AUDIO);
+
+  // By default the offer should give setup:actpass and connection:new
+  std::string offer(a1_.offer());
+  match = offer.find("\r\na=setup:actpass");
+  ASSERT_NE(match, std::string::npos);
+  match = offer.find("\r\na=connection:new");
+  ASSERT_NE(match, std::string::npos);
+
+  a1_.SetLocal(TestObserver::OFFER, offer.c_str(), false);
+  a2_.SetRemote(TestObserver::OFFER, offer.c_str(), false);
+  a2_.CreateAnswer(constraints, offer.c_str(), OFFER_AUDIO | ANSWER_AUDIO);
+
+  // Now the answer should contain a=setup:active and a=connection:new
+  std::string answer(a2_.answer());
+  match = answer.find("\r\na=setup:active");
+  ASSERT_NE(match, std::string::npos);
+  // Remove the a=setup line
+  answer.replace(match, strlen("\r\na=setup:active"), "");
+  match = answer.find("\r\na=connection:new");
+  ASSERT_NE(match, std::string::npos);
+  // Remove the a=connection line
+  answer.replace(match, strlen("\r\na=connection:new"), "");
+  std::cout << "Modified SDP " << std::endl
+            << indent(answer) << std::endl;
+
+  // This should setup the DTLS with the same roles
+  // as the regular tests above.
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), false);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), false);
+
+  ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_.GetPacketsSent(0) >= 40 &&
+                   a2_.GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_.CloseSendStreams();
+  a2_.CloseReceiveStreams();
+
+  ASSERT_GE(a1_.GetPacketsSent(0), 40);
+  ASSERT_GE(a2_.GetPacketsReceived(0), 40);
+}
+
 } // End namespace test.
 
 bool is_color_terminal(const char *terminal) {
   if (!terminal) {
     return false;
   }
   const char *color_terms[] = {
     "xterm",
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -63,42 +63,42 @@ class RefCounted
   protected:
     RefCounted() : refCnt(0) { }
     ~RefCounted() {
       MOZ_ASSERT(refCnt == detail::DEAD);
     }
 
   public:
     // Compatibility with nsRefPtr.
-    void AddRef() {
+    void AddRef() const {
       MOZ_ASSERT(refCnt >= 0);
       ++refCnt;
     }
 
-    void Release() {
+    void Release() const {
       MOZ_ASSERT(refCnt > 0);
       if (0 == --refCnt) {
 #ifdef DEBUG
         refCnt = detail::DEAD;
 #endif
-        delete static_cast<T*>(this);
+        delete static_cast<const T*>(this);
       }
     }
 
     // Compatibility with wtf::RefPtr.
     void ref() { AddRef(); }
     void deref() { Release(); }
     int refCount() const { return refCnt; }
     bool hasOneRef() const {
       MOZ_ASSERT(refCnt > 0);
       return refCnt == 1;
     }
 
   private:
-    typename Conditional<Atomicity == AtomicRefCount, Atomic<int>, int>::Type refCnt;
+    mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<int>, int>::Type refCnt;
 };
 
 }
 
 template<typename T>
 class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
 {
   public:
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -2342,17 +2342,20 @@ abstract public class GeckoApp
         CellLocation cl = tm.getCellLocation();
         String mcc = "", mnc = "";
         if (cl instanceof GsmCellLocation) {
             JSONObject obj = new JSONObject();
             GsmCellLocation gcl = (GsmCellLocation)cl;
             try {
                 obj.put("lac", gcl.getLac());
                 obj.put("cid", gcl.getCid());
-                obj.put("psc", gcl.getPsc());
+
+                int psc = (Build.VERSION.SDK_INT >= 9) ? gcl.getPsc() : -1;
+                obj.put("psc", psc);
+
                 switch(tm.getNetworkType()) {
                 case TelephonyManager.NETWORK_TYPE_GPRS:
                 case TelephonyManager.NETWORK_TYPE_EDGE:
                     obj.put("radio", "gsm");
                     break;
                 case TelephonyManager.NETWORK_TYPE_UMTS:
                 case TelephonyManager.NETWORK_TYPE_HSDPA:
                 case TelephonyManager.NETWORK_TYPE_HSUPA:
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -65,17 +65,17 @@ IsSignalHandlingBroken();
  * RefCounted<LibHandle>::Release to support some reentrancy. See further
  * below.
  */
 class LibHandle;
 
 namespace mozilla {
 namespace detail {
 
-template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release();
+template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const;
 
 template <> inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted()
 {
   MOZ_ASSERT(refCnt == 0x7fffdead);
 }
 
 } /* namespace detail */
 } /* namespace mozilla */
@@ -210,30 +210,30 @@ private:
  * to 1 on normal builds, and 0x7fffdead on debug builds so that the LibHandle
  * can still be referenced while the destructor is executing. The refCnt is
  * allowed to grow > 0x7fffdead, but not to decrease under that value, which
  * would mean too many Releases from within the destructor.
  */
 namespace mozilla {
 namespace detail {
 
-template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() {
+template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const {
 #ifdef DEBUG
   if (refCnt > 0x7fff0000)
     MOZ_ASSERT(refCnt > 0x7fffdead);
 #endif
   MOZ_ASSERT(refCnt > 0);
   if (refCnt > 0) {
     if (0 == --refCnt) {
 #ifdef DEBUG
       refCnt = 0x7fffdead;
 #else
       refCnt = 1;
 #endif
-      delete static_cast<LibHandle*>(this);
+      delete static_cast<const LibHandle*>(this);
     }
   }
 }
 
 } /* namespace detail */
 } /* namespace mozilla */
 
 /**
--- a/toolkit/content/widgets/remote-browser.xml
+++ b/toolkit/content/widgets/remote-browser.xml
@@ -33,33 +33,34 @@
 
       <field name="_remoteWebNavigation">null</field>
 
       <property name="webNavigation" readonly="true">
         <getter>
           <![CDATA[
             if (!this._remoteWebNavigation) {
               let jsm = "resource://gre/modules/RemoteWebNavigation.jsm";
-              let RemoteWebNavigation = Components.utils.import(jsm, {}).RemoteWebNavigation;
+              let RemoteWebNavigation = Cu.import(jsm, {}).RemoteWebNavigation;
               this._remoteWebNavigation = new RemoteWebNavigation(this);
             }
             return this._remoteWebNavigation;
           ]]>
         </getter>
       </property>
 
       <field name="_remoteWebProgress">null</field>
 
       <property name="webProgress" readonly="true">
       	<getter>
       	  <![CDATA[
             if (!this._remoteWebProgress) {
               let jsm = "resource://gre/modules/RemoteWebProgress.jsm";
-              let RemoteWebProgress = Components.utils.import(jsm, {}).RemoteWebProgress;
-              this._remoteWebProgress = new RemoteWebProgress(this);
+              let RemoteWebProgressManager = Cu.import(jsm, {}).RemoteWebProgressManager;
+              this._remoteWebProgress = new RemoteWebProgressManager(this)
+                                         .topLevelWebProgress;
             }
             return this._remoteWebProgress;
       	  ]]>
       	</getter>
       </property>
 
       <field name="_documentURI">null</field>
 
@@ -102,18 +103,16 @@
           this.messageManager.loadFrameScript("chrome://global/content/browser-child.js", true);
 
           if (this.hasAttribute("selectpopup")) {
             this.messageManager.addMessageListener("Forms:ShowDropDown", this);
             this.messageManager.addMessageListener("Forms:HideDropDown", this);
             this.messageManager.loadFrameScript("chrome://global/content/select-child.js", true);
           }
 
-          this.webProgress._init();
-
           let jsm = "resource://gre/modules/RemoteController.jsm";
           let RemoteController = Components.utils.import(jsm, {}).RemoteController;
           this._controller = new RemoteController(this);
           this.controllers.appendController(this._controller);
 
           jsm = "resource://gre/modules/RemoteAddonsParent.jsm";
           let RemoteAddonsParent = Components.utils.import(jsm, {}).RemoteAddonsParent;
           RemoteAddonsParent.init();
--- a/toolkit/modules/RemoteSecurityUI.jsm
+++ b/toolkit/modules/RemoteSecurityUI.jsm
@@ -8,41 +8,27 @@ this.EXPORTED_SYMBOLS = ["RemoteSecurity
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function RemoteSecurityUI()
 {
+    this._SSLStatus = null;
     this._state = 0;
-    this._SSLStatus = null;
 }
 
 RemoteSecurityUI.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISSLStatusProvider, Ci.nsISecureBrowserUI]),
 
+  // nsISSLStatusProvider
+  get SSLStatus() { return this._SSLStatus; },
+
   // nsISecureBrowserUI
   get state() { return this._state; },
   get tooltipText() { return ""; },
 
-  // nsISSLStatusProvider
-  get SSLStatus() { return this._SSLStatus; },
-
-  _update: function (state, status) {
-      let deserialized = null;
-      if (status) {
-        let helper = Cc["@mozilla.org/network/serialization-helper;1"]
-                      .getService(Components.interfaces.nsISerializationHelper);
-
-        deserialized = helper.deserializeObject(status)
-        deserialized.QueryInterface(Ci.nsISSLStatus);
-      }
-
-      // We must check the Extended Validation (EV) state here, on the chrome
-      // process, because NSS is needed for that determination.
-      if (deserialized && deserialized.isExtendedValidation)
-        state |= Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
-
-      this._state = state;
-      this._SSLStatus = deserialized;
+  _update: function (aStatus, aState) {
+    this._SSLStatus = aStatus;
+    this._state = aState;
   }
 };
--- a/toolkit/modules/RemoteWebProgress.jsm
+++ b/toolkit/modules/RemoteWebProgress.jsm
@@ -1,14 +1,14 @@
 // -*- Mode: javascript; tab-width: 8; 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/.
 
-this.EXPORTED_SYMBOLS = ["RemoteWebProgress"];
+this.EXPORTED_SYMBOLS = ["RemoteWebProgressManager"];
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function newURI(spec)
@@ -23,129 +23,159 @@ function RemoteWebProgressRequest(spec)
 }
 
 RemoteWebProgressRequest.prototype = {
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannel]),
 
   get URI() { return this.uri.clone(); }
 };
 
-function RemoteWebProgress(browser)
-{
-  this._browser = browser;
+function RemoteWebProgress(aManager, aIsTopLevel) {
+  this._manager = aManager;
+
   this._isLoadingDocument = false;
   this._DOMWindow = null;
-  this._isTopLevel = null;
+  this._isTopLevel = aIsTopLevel;
   this._loadType = 0;
-  this._progressListeners = [];
 }
 
 RemoteWebProgress.prototype = {
   NOTIFY_STATE_REQUEST:  0x00000001,
   NOTIFY_STATE_DOCUMENT: 0x00000002,
   NOTIFY_STATE_NETWORK:  0x00000004,
   NOTIFY_STATE_WINDOW:   0x00000008,
   NOTIFY_STATE_ALL:      0x0000000f,
   NOTIFY_PROGRESS:       0x00000010,
   NOTIFY_STATUS:         0x00000020,
   NOTIFY_SECURITY:       0x00000040,
   NOTIFY_LOCATION:       0x00000080,
   NOTIFY_REFRESH:        0x00000100,
   NOTIFY_ALL:            0x000001ff,
 
-  _init: function WP_Init() {
-    this._browser.messageManager.addMessageListener("Content:StateChange", this);
-    this._browser.messageManager.addMessageListener("Content:LocationChange", this);
-    this._browser.messageManager.addMessageListener("Content:SecurityChange", this);
-    this._browser.messageManager.addMessageListener("Content:StatusChange", this);
-  },
-
-  _destroy: function WP_Destroy() {
-    this._browser = null;
-  },
-
   get isLoadingDocument() { return this._isLoadingDocument },
   get DOMWindow() { return this._DOMWindow; },
   get DOMWindowID() { return 0; },
-  get isTopLevel() {
-    // When this object is accessed directly, it's usually obtained
-    // through browser.webProgress and thus represents the top-level
-    // document.
-    // However, during message handling it temporarily represents
-    // the webProgress that generated the notification, which may or
-    // may not be a toplevel frame.
-    return this._isTopLevel === null ? true : this._isTopLevel;
-  },
+  get isTopLevel() { return this._isTopLevel },
   get loadType() { return this._loadType; },
 
-  addProgressListener: function WP_AddProgressListener (aListener) {
+  addProgressListener: function (aListener) {
+    this._manager.addProgressListener(aListener);
+  },
+
+  removeProgressListener: function (aListener) {
+    this._manager.removeProgressListener(aListener);
+  }
+};
+
+function RemoteWebProgressManager (aBrowser) {
+  this._browser = aBrowser;
+  this._topLevelWebProgress = new RemoteWebProgress(this, true);
+  this._progressListeners = [];
+
+  this._browser.messageManager.addMessageListener("Content:StateChange", this);
+  this._browser.messageManager.addMessageListener("Content:LocationChange", this);
+  this._browser.messageManager.addMessageListener("Content:SecurityChange", this);
+  this._browser.messageManager.addMessageListener("Content:StatusChange", this);
+}
+
+RemoteWebProgressManager.prototype = {
+  get topLevelWebProgress() {
+    return this._topLevelWebProgress;
+  },
+
+  addProgressListener: function (aListener) {
     let listener = aListener.QueryInterface(Ci.nsIWebProgressListener);
     this._progressListeners.push(listener);
   },
 
-  removeProgressListener: function WP_RemoveProgressListener (aListener) {
+  removeProgressListener: function (aListener) {
     this._progressListeners =
-      this._progressListeners.filter(function (l) l != aListener);
+      this._progressListeners.filter(l => l != aListener);
   },
 
-  _uriSpec: function (spec) {
-    if (!spec)
-      return null;
-    return new RemoteWebProgressRequest(spec);
+  _fixSSLStatusAndState: function (aStatus, aState) {
+    let deserialized = null;
+    if (aStatus) {
+      let helper = Cc["@mozilla.org/network/serialization-helper;1"]
+                    .getService(Components.interfaces.nsISerializationHelper);
+
+      deserialized = helper.deserializeObject(aStatus)
+      deserialized.QueryInterface(Ci.nsISSLStatus);
+    }
+
+    // We must check the Extended Validation (EV) state here, on the chrome
+    // process, because NSS is needed for that determination.
+    if (deserialized && deserialized.isExtendedValidation)
+      aState |= Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
+
+    return [deserialized, aState];
   },
 
-  receiveMessage: function WP_ReceiveMessage(aMessage) {
-    this._isLoadingDocument = aMessage.json.isLoadingDocument;
-    this._DOMWindow = aMessage.objects.DOMWindow;
-    this._isTopLevel = aMessage.json.isTopLevel;
-    this._loadType = aMessage.json.loadType;
+  receiveMessage: function (aMessage) {
+    let json = aMessage.json;
+    let objects = aMessage.objects;
+
+    // The top-level WebProgress is always the same, but because we don't
+    // really have a concept of subframes/content we always creat a new object
+    // for those.
+    let webProgress = json.isTopLevel ? this._topLevelWebProgress
+                                      : new RemoteWebProgress(this, false);
 
-    this._browser._contentWindow = aMessage.objects.contentWindow;
+    // The WebProgressRequest object however is always dynamic.
+    let request = json.requestURI ? new RemoteWebProgressRequest(json.requestURI)
+                                  : null;
 
-    let req = this._uriSpec(aMessage.json.requestURI);
+    // Update the actual WebProgress fields.
+    webProgress._isLoadingDocument = json.isLoadingDocument;
+    webProgress._DOMWindow = objects.DOMWindow;
+    webProgress._loadType = json.loadType;
+
+    if (json.isTopLevel)
+      this._browser._contentWindow = objects.contentWindow;
+
     switch (aMessage.name) {
     case "Content:StateChange":
-      for each (let p in this._progressListeners) {
-        p.onStateChange(this, req, aMessage.json.stateFlags, aMessage.json.status);
+      for (let p of this._progressListeners) {
+        p.onStateChange(webProgress, request, json.stateFlags, json.status);
       }
       break;
 
     case "Content:LocationChange":
-      let location = newURI(aMessage.json.location);
+      let location = newURI(json.location);
 
-      if (aMessage.json.isTopLevel) {
+      if (json.isTopLevel) {
         this._browser.webNavigation._currentURI = location;
-        this._browser.webNavigation.canGoBack = aMessage.json.canGoBack;
-        this._browser.webNavigation.canGoForward = aMessage.json.canGoForward;
-        this._browser._characterSet = aMessage.json.charset;
-        this._browser._documentURI = newURI(aMessage.json.documentURI);
+        this._browser.webNavigation.canGoBack = json.canGoBack;
+        this._browser.webNavigation.canGoForward = json.canGoForward;
+        this._browser._characterSet = json.charset;
+        this._browser._documentURI = newURI(json.documentURI);
         this._browser._imageDocument = null;
       }
 
-      for each (let p in this._progressListeners) {
-        p.onLocationChange(this, req, location);
+      for (let p of this._progressListeners) {
+        p.onLocationChange(webProgress, request, location);
       }
       break;
 
     case "Content:SecurityChange":
-      // Invoking this getter triggers the generation of the underlying object,
-      // which we need to access with ._securityUI, because .securityUI returns
-      // a wrapper that makes _update inaccessible.
-      void this._browser.securityUI;
-      this._browser._securityUI._update(aMessage.json.state, aMessage.json.status);
+      let [status, state] = this._fixSSLStatusAndState(json.status, json.state);
 
-      // The state passed might not be correct due to checks performed
-      // on the chrome side. _update fixes that.
-      for each (let p in this._progressListeners) {
-        p.onSecurityChange(this, req, this._browser.securityUI.state);
+      if (json.isTopLevel) {
+        // Invoking this getter triggers the generation of the underlying object,
+        // which we need to access with ._securityUI, because .securityUI returns
+        // a wrapper that makes _update inaccessible.
+        void this._browser.securityUI;
+        this._browser._securityUI._update(status, state);
+      }
+
+      for (let p of this._progressListeners) {
+        p.onSecurityChange(webProgress, request, state);
       }
       break;
 
     case "Content:StatusChange":
-      for each (let p in this._progressListeners) {
-        p.onStatusChange(this, req, aMessage.json.status, aMessage.json.message);
+      for (let p of this._progressListeners) {
+        p.onStatusChange(webProgress, request, json.status, json.message);
       }
       break;
     }
-
-    this._isTopLevel = null;
   }
 };
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -100,17 +100,16 @@
 
 /* This must occur *after* base/process_util.h to avoid typedefs conflicts. */
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Util.h"
 
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollectionNoteRootCallback.h"
-#include "nsBaseHashtable.h"
 #include "nsHashKeys.h"
 #include "nsDeque.h"
 #include "nsCycleCollector.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "prprf.h"
 #include "plstr.h"
 #include "nsPrintfCString.h"
@@ -836,17 +835,17 @@ public:
         // We also don't measure the things pointed to by mEntries[] because
         // those pointers are non-owning.
 
         return n;
     }
 };
 
 static bool
-AddPurpleRoot(GCGraphBuilder &builder, void *root, nsCycleCollectionParticipant *cp);
+AddPurpleRoot(GCGraphBuilder &aBuilder, void *aRoot, nsCycleCollectionParticipant *aParti);
 
 struct SelectPointersVisitor
 {
     SelectPointersVisitor(GCGraphBuilder &aBuilder)
         : mBuilder(aBuilder)
     {}
 
     void
@@ -888,16 +887,17 @@ enum ccType {
 // Top level structure for the cycle collector.
 ////////////////////////////////////////////////////////////////////////
 
 class nsCycleCollector
 {
     friend class GCGraphBuilder;
 
     bool mCollectionInProgress;
+    // mScanInProgress should be false when we're collecting white objects.
     bool mScanInProgress;
     nsCycleCollectorResults *mResults;
     TimeStamp mCollectionStart;
 
     CycleCollectedJSRuntime *mJSRuntime;
 
     GCGraph mGraph;
 
@@ -931,26 +931,27 @@ public:
     inline CycleCollectedJSRuntime*
     JSRuntime() const
     {
         return mJSRuntime;
     }
 
     void SetBeforeUnlinkCallback(CC_BeforeUnlinkCallback aBeforeUnlinkCB)
     {
+        CheckThreadSafety();
         mBeforeUnlinkCB = aBeforeUnlinkCB;
     }
 
     void SetForgetSkippableCallback(CC_ForgetSkippableCallback aForgetSkippableCB)
     {
+        CheckThreadSafety();
         mForgetSkippableCB = aForgetSkippableCB;
     }
 
-    void SelectPurple(GCGraphBuilder &builder);
-    void MarkRoots(GCGraphBuilder &builder);
+    void MarkRoots(GCGraphBuilder &aBuilder);
     void ScanRoots();
     void ScanWeakMaps();
 
     void ForgetSkippable(bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing);
 
     // returns whether anything was collected
     bool CollectWhite(nsICycleCollectorListener *aListener);
 
@@ -973,17 +974,17 @@ public:
     // Prepare for and cleanup after one or more collection(s).
     bool PrepareForCollection(nsCycleCollectorResults *aResults,
                               nsTArray<PtrInfo*> *aWhiteNodes);
     void FixGrayBits(bool aForceGC);
     bool ShouldMergeZones(ccType aCCType);
     void CleanupAfterCollection();
 
     // Start and finish an individual collection.
-    bool BeginCollection(ccType aCCType, nsICycleCollectorListener *aListener);
+    void BeginCollection(ccType aCCType, nsICycleCollectorListener *aListener);
     bool FinishCollection(nsICycleCollectorListener *aListener);
 
     bool FreeSnowWhite(bool aUntilNoSWInPurpleBuffer);
 
     uint32_t SuspectedCount();
     void Shutdown();
 
     void ClearGraph()
@@ -1558,17 +1559,16 @@ private:
 
 public:
     GCGraphBuilder(nsCycleCollector *aCollector,
                    GCGraph &aGraph,
                    CycleCollectedJSRuntime *aJSRuntime,
                    nsICycleCollectorListener *aListener,
                    bool aMergeZones);
     ~GCGraphBuilder();
-    bool Initialized();
 
     bool WantAllTraces() const
     {
         return nsCycleCollectionNoteRootCallback::WantAllTraces();
     }
 
     uint32_t Count() const { return mPtrToNodeMap.entryCount; }
 
@@ -1652,18 +1652,17 @@ GCGraphBuilder::GCGraphBuilder(nsCycleCo
       mJSParticipant(nullptr),
       mJSZoneParticipant(nullptr),
       mListener(aListener),
       mMergeZones(aMergeZones),
       mRanOutOfMemory(false)
 {
     if (!PL_DHashTableInit(&mPtrToNodeMap, &PtrNodeOps, nullptr,
                            sizeof(PtrToNodeEntry), 32768)) {
-        mPtrToNodeMap.ops = nullptr;
-        mRanOutOfMemory = true;
+        MOZ_CRASH();
     }
 
     if (aJSRuntime) {
         mJSParticipant = aJSRuntime->GCThingParticipant();
         mJSZoneParticipant = aJSRuntime->ZoneParticipant();
     }
 
     uint32_t flags = 0;
@@ -1686,22 +1685,16 @@ GCGraphBuilder::GCGraphBuilder(nsCycleCo
 }
 
 GCGraphBuilder::~GCGraphBuilder()
 {
     if (mPtrToNodeMap.ops)
         PL_DHashTableFinish(&mPtrToNodeMap);
 }
 
-bool
-GCGraphBuilder::Initialized()
-{
-    return !!mPtrToNodeMap.ops;
-}
-
 PtrInfo*
 GCGraphBuilder::AddNode(void *s, nsCycleCollectionParticipant *aParticipant)
 {
     PtrToNodeEntry *e = static_cast<PtrToNodeEntry*>(PL_DHashTableOperate(&mPtrToNodeMap, s, PL_DHASH_ADD));
     if (!e) {
         mRanOutOfMemory = true;
         return nullptr;
     }
@@ -1891,22 +1884,22 @@ GCGraphBuilder::NoteWeakMapping(void *ma
 
     if (mListener) {
         mListener->NoteWeakMapEntry((uint64_t)map, (uint64_t)key,
                                     (uint64_t)kdelegate, (uint64_t)val);
     }
 }
 
 static bool
-AddPurpleRoot(GCGraphBuilder &builder, void *root, nsCycleCollectionParticipant *cp)
+AddPurpleRoot(GCGraphBuilder &aBuilder, void *aRoot, nsCycleCollectionParticipant *aParti)
 {
-    CanonicalizeParticipant(&root, &cp);
-
-    if (builder.WantAllTraces() || !cp->CanSkipInCC(root)) {
-        PtrInfo *pinfo = builder.AddNode(root, cp);
+    CanonicalizeParticipant(&aRoot, &aParti);
+
+    if (aBuilder.WantAllTraces() || !aParti->CanSkipInCC(aRoot)) {
+        PtrInfo *pinfo = aBuilder.AddNode(aRoot, aParti);
         if (!pinfo) {
             return false;
         }
     }
 
     return true;
 }
 
@@ -2015,17 +2008,17 @@ public:
             CanonicalizeParticipant(&o, &cp);
             SnowWhiteObject swo = { o, cp, aEntry->mRefCnt };
             if (mObjects.AppendElement(swo)) {
                 aBuffer.Remove(aEntry);
             }
         }
     }
 
-    bool HasSnowWhiteObjects()
+    bool HasSnowWhiteObjects() const
     {
       return mObjects.Length() > 0;
     }
 private:
     FallibleTArray<SnowWhiteObject> mObjects;
 };
 
 class RemoveSkippableVisitor : public SnowWhiteKiller
@@ -2094,64 +2087,63 @@ nsPurpleBuffer::RemoveSkippable(nsCycleC
     RemoveSkippableVisitor visitor(aCollector, Count(), aRemoveChildlessNodes,
                                    aAsyncSnowWhiteFreeing, aCb);
     VisitEntries(visitor);
 }
 
 bool
 nsCycleCollector::FreeSnowWhite(bool aUntilNoSWInPurpleBuffer)
 {
+    CheckThreadSafety();
+
     bool hadSnowWhiteObjects = false;
     do {
         SnowWhiteKiller visitor(mPurpleBuf.Count());
         mPurpleBuf.VisitEntries(visitor);
         hadSnowWhiteObjects = hadSnowWhiteObjects ||
                               visitor.HasSnowWhiteObjects();
         if (!visitor.HasSnowWhiteObjects()) {
             break;
         }
     } while (aUntilNoSWInPurpleBuffer);
     return hadSnowWhiteObjects;
 }
 
 void
-nsCycleCollector::SelectPurple(GCGraphBuilder &builder)
-{
-    mPurpleBuf.SelectPointers(builder);
-}
-
-void
 nsCycleCollector::ForgetSkippable(bool aRemoveChildlessNodes,
                                   bool aAsyncSnowWhiteFreeing)
 {
+    CheckThreadSafety();
     if (mJSRuntime) {
         mJSRuntime->PrepareForForgetSkippable();
     }
     mPurpleBuf.RemoveSkippable(this, aRemoveChildlessNodes,
                                aAsyncSnowWhiteFreeing, mForgetSkippableCB);
 }
 
 MOZ_NEVER_INLINE void
-nsCycleCollector::MarkRoots(GCGraphBuilder &builder)
+nsCycleCollector::MarkRoots(GCGraphBuilder &aBuilder)
 {
-    mGraph.mRootCount = builder.Count();
+    mGraph.mRootCount = aBuilder.Count();
 
     // read the PtrInfo out of the graph that we are building
     NodePool::Enumerator queue(mGraph.mNodes);
     while (!queue.IsDone()) {
         PtrInfo *pi = queue.GetNext();
         CC_AbortIfNull(pi);
-        builder.Traverse(pi);
-        if (queue.AtBlockEnd())
-            builder.SetLastChild();
+        aBuilder.Traverse(pi);
+        if (queue.AtBlockEnd()) {
+            aBuilder.SetLastChild();
+        }
     }
-    if (mGraph.mRootCount > 0)
-        builder.SetLastChild();
-
-    if (builder.RanOutOfMemory()) {
+    if (mGraph.mRootCount > 0) {
+        aBuilder.SetLastChild();
+    }
+
+    if (aBuilder.RanOutOfMemory()) {
         NS_ASSERTION(false,
                      "Ran out of memory while building cycle collector graph");
         Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_OOM, true);
     }
 }
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -2591,20 +2583,16 @@ nsCycleCollector::FixGrayBits(bool aForc
         Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_NEED_GC, needGC);
         if (!needGC)
             return;
         if (mResults)
             mResults->mForcedGC = true;
     }
 
     TimeLog timeLog;
-
-    // mJSRuntime->Collect() must be called from the main thread,
-    // because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN)
-    // which returns false if not in the main thread.
     mJSRuntime->Collect(aForceGC ? JS::gcreason::SHUTDOWN_CC : JS::gcreason::CC_FORCED);
     timeLog.Checkpoint("GC()");
 }
 
 bool
 nsCycleCollector::PrepareForCollection(nsCycleCollectorResults *aResults,
                                        nsTArray<PtrInfo*> *aWhiteNodes)
 {
@@ -2680,19 +2668,20 @@ nsCycleCollector::ShutdownCollect(nsICyc
     for (uint32_t i = 0; i < DEFAULT_SHUTDOWN_COLLECTIONS; ++i) {
         NS_ASSERTION(i < NORMAL_SHUTDOWN_COLLECTIONS, "Extra shutdown CC");
 
         // Synchronous cycle collection. Always force a JS GC beforehand.
         FixGrayBits(true);
         if (aListener && NS_FAILED(aListener->Begin()))
             aListener = nullptr;
         FreeSnowWhite(true);
-        if (!(BeginCollection(ShutdownCC, aListener) &&
-              FinishCollection(aListener)))
+        BeginCollection(ShutdownCC, aListener);
+        if (!FinishCollection(aListener)) {
             break;
+        }
     }
 
     CleanupAfterCollection();
 }
 
 void
 nsCycleCollector::Collect(ccType aCCType,
                           nsCycleCollectorResults *aResults,
@@ -2715,20 +2704,17 @@ nsCycleCollector::Collect(ccType aCCType
     }
 
     FreeSnowWhite(true);
 
     if (aListener && NS_FAILED(aListener->Begin())) {
         aListener = nullptr;
     }
 
-    if (!BeginCollection(aCCType, aListener)) {
-        return;
-    }
-
+    BeginCollection(aCCType, aListener);
     FinishCollection(aListener);
     CleanupAfterCollection();
 }
 
 // Don't merge too many times in a row, and do at least a minimum
 // number of unmerged CCs in a row.
 static const uint32_t kMinConsecutiveUnmerged = 3;
 static const uint32_t kMaxConsecutiveMerged = 3;
@@ -2758,45 +2744,39 @@ nsCycleCollector::ShouldMergeZones(ccTyp
         mMergedInARow++;
         return true;
     } else {
         mMergedInARow = 0;
         return false;
     }
 }
 
-bool
+void
 nsCycleCollector::BeginCollection(ccType aCCType,
                                   nsICycleCollectorListener *aListener)
 {
     // aListener should be Begin()'d before this
     TimeLog timeLog;
 
     bool mergeZones = ShouldMergeZones(aCCType);
     if (mResults) {
         mResults->mMergedZones = mergeZones;
     }
 
     GCGraphBuilder builder(this, mGraph, mJSRuntime, aListener,
                            mergeZones);
-    if (!builder.Initialized()) {
-        NS_ASSERTION(false, "Failed to initialize GCGraphBuilder, will probably leak.");
-        Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_OOM, true);
-        return false;
-    }
 
     if (mJSRuntime) {
         mJSRuntime->BeginCycleCollection(builder);
         timeLog.Checkpoint("mJSRuntime->BeginCycleCollection()");
     }
 
     mScanInProgress = true;
-    SelectPurple(builder);
-
-    timeLog.Checkpoint("SelectPurple()");
+    mPurpleBuf.SelectPointers(builder);
+    timeLog.Checkpoint("SelectPointers()");
 
     if (builder.Count() > 0) {
         // The main Bacon & Rajan collection algorithm.
 
         MarkRoots(builder);
         timeLog.Checkpoint("MarkRoots()");
 
         ScanRoots();
@@ -2816,18 +2796,16 @@ nsCycleCollector::BeginCollection(ccType
                     aListener->DescribeRoot((uint64_t)pi->mPointer,
                                             pi->mInternalRefs);
                 }
             }
         }
     } else {
         mScanInProgress = false;
     }
-
-    return true;
 }
 
 bool
 nsCycleCollector::FinishCollection(nsICycleCollectorListener *aListener)
 {
     TimeLog timeLog;
     bool collected = CollectWhite(aListener);
     timeLog.Checkpoint("CollectWhite()");
@@ -2837,22 +2815,25 @@ nsCycleCollector::FinishCollection(nsICy
     timeLog.Checkpoint("ClearGraph()");
 
     return collected;
 }
 
 uint32_t
 nsCycleCollector::SuspectedCount()
 {
+    CheckThreadSafety();
     return mPurpleBuf.Count();
 }
 
 void
 nsCycleCollector::Shutdown()
 {
+    CheckThreadSafety();
+
     // Always delete snow white objects.
     FreeSnowWhite(true);
 
 #ifndef DEBUG
     if (PR_GetEnv("XPCOM_CC_RUN_DURING_SHUTDOWN"))
 #endif
     {
         nsCOMPtr<nsCycleCollectorLogger> listener;
@@ -3209,17 +3190,16 @@ nsCycleCollector_collect(bool aManuallyT
 void
 nsCycleCollector_shutdown()
 {
     CollectorData *data = sCollectorData.get();
 
     if (data) {
         MOZ_ASSERT(data->mCollector);
         PROFILER_LABEL("CC", "nsCycleCollector_shutdown");
-        data->mCollector->CheckThreadSafety();
         data->mCollector->Shutdown();
         delete data->mCollector;
         data->mCollector = nullptr;
         if (!data->mRuntime) {
           delete data;
           sCollectorData.set(nullptr);
         }
     }