Merge m-c to b2g-i
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 30 Apr 2014 15:34:35 +0200
changeset 181460 9c6fa0d543cab98ba2258b370d90128a881506a4
parent 181459 69cef315933b73d9725f9c37e32a908b094389fa (current diff)
parent 181418 43ba36bc10f24577d29f2fe953ef543c9760f7ec (diff)
child 181461 5b6c7c930f2d8dac650150fed60db8add18e5156
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone32.0a1
Merge m-c to b2g-i
b2g/config/emulator/sources.xml
--- a/b2g/components/ActivitiesGlue.js
+++ b/b2g/components/ActivitiesGlue.js
@@ -43,32 +43,39 @@ ActivitiesDialog.prototype = {
 
     // Listen the resulting choice from the front-end. If there is no choice,
     // let's return -1, which means the user has cancelled the dialog.
     SystemAppProxy.addEventListener("mozContentEvent", function act_getChoice(evt) {
       if (evt.detail.id != id)
         return;
 
       SystemAppProxy.removeEventListener("mozContentEvent", act_getChoice);
-      activity.callback.handleEvent(evt.detail.value !== undefined
+      activity.callback.handleEvent(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY,
+                                    evt.detail.value !== undefined
                                       ? evt.detail.value
                                       : -1);
     });
 
     SystemAppProxy.dispatchEvent(detail);
   },
 
-  chooseActivity: function ap_chooseActivity(aName, aActivities, aCallback) {
+  chooseActivity: function ap_chooseActivity(aOptions, aActivities, aCallback) {
+    // B2G does not have an alternate activity system, make no choice and return.
+    if (aActivities.length === 0) {
+      aCallback(Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY, -1);
+      return;
+    }
+
     this.activities.push({
-      name: aName,
+      name: aOptions.name,
       list: aActivities,
       callback: aCallback
     });
     Services.tm.currentThread.dispatch(this, Ci.nsIEventTarget.DISPATCH_NORMAL);
   },
 
-  classID: Components.ID("{70a83123-7467-4389-a309-3e81c74ad002}"),
+  classID: Components.ID("{3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIActivityUIGlue, Ci.nsIRunnable])
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ActivitiesDialog]);
 
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -16,18 +16,18 @@ contract @mozilla.org/updates/update-pro
 #endif
 
 # DirectoryProvider.js
 component {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5} DirectoryProvider.js
 contract @mozilla.org/browser/directory-provider;1 {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}
 category xpcom-directory-providers browser-directory-provider @mozilla.org/browser/directory-provider;1
 
 # ActivitiesGlue.js
-component {70a83123-7467-4389-a309-3e81c74ad002} ActivitiesGlue.js
-contract @mozilla.org/dom/activities/ui-glue;1 {70a83123-7467-4389-a309-3e81c74ad002}
+component {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e} ActivitiesGlue.js
+contract @mozilla.org/dom/activities/ui-glue;1 {3a54788b-48cc-4ab4-93d6-0d6a8ef74f8e}
 
 # ProcessGlobal.js
 component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js
 contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28}
 category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1
 
 # ContentHandler.js
 component {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} ContentHandler.js
--- a/b2g/components/FxAccountsMgmtService.jsm
+++ b/b2g/components/FxAccountsMgmtService.jsm
@@ -81,16 +81,21 @@ this.FxAccountsMgmtService = {
     if (!msg.id) {
       return;
     }
 
     let data = msg.data;
     if (!data) {
       return;
     }
+    // Backwards compatibility: handle accountId coming from Gaia
+    if (data.accountId && typeof(data.email === "undefined")) {
+      data.email = data.accountId;
+      delete data.accountId;
+    }
 
     switch(data.method) {
       case "getAccounts":
         FxAccountsManager.getAccount().then(
           account => {
             // We only expose the email and verification status so far.
             self._onFulfill(msg.id, account);
           },
@@ -105,29 +110,29 @@ this.FxAccountsMgmtService = {
             self._onFulfill(msg.id);
           },
           reason => {
             self._onReject(msg.id, reason);
           }
         ).then(null, Components.utils.reportError);
         break;
       case "queryAccount":
-        FxAccountsManager.queryAccount(data.accountId).then(
+        FxAccountsManager.queryAccount(data.email).then(
           result => {
             self._onFulfill(msg.id, result);
           },
           reason => {
             self._onReject(msg.id, reason);
           }
         ).then(null, Components.utils.reportError);
         break;
       case "signIn":
       case "signUp":
       case "refreshAuthentication":
-        FxAccountsManager[data.method](data.accountId, data.password).then(
+        FxAccountsManager[data.method](data.email, data.password).then(
           user => {
             self._onFulfill(msg.id, user);
           },
           reason => {
             self._onReject(msg.id, reason);
           }
         ).then(null, Components.utils.reportError);
         break;
--- a/b2g/components/FxAccountsUIGlue.js
+++ b/b2g/components/FxAccountsUIGlue.js
@@ -59,19 +59,19 @@ FxAccountsUIGlue.prototype = {
 
     return deferred.promise;
   },
 
   signInFlow: function() {
     return this._contentRequest("openFlow");
   },
 
-  refreshAuthentication: function(aAccountId) {
+  refreshAuthentication: function(aEmail) {
     return this._contentRequest("refreshAuthentication", {
-      accountId: aAccountId
+      email: aEmail
     });
   },
 
   classID: Components.ID("{51875c14-91d7-4b8c-b65d-3549e101228c}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIFxAccountsUIGlue])
 };
 
--- a/b2g/components/test/unit/test_fxaccounts.js
+++ b/b2g/components/test/unit/test_fxaccounts.js
@@ -123,17 +123,17 @@ add_test(function test_invalidEmailCase_
         break;
 
       // Having initially signed in as "Greta.Garbo", getAccounts should show
       // us that the signed-in user has the properly-capitalized email,
       // "greta.garbo".
       case "getAccounts":
         Services.obs.removeObserver(onMessage, "mozFxAccountsChromeEvent");
 
-        do_check_eq(message.data.accountId, canonicalEmail);
+        do_check_eq(message.data.email, canonicalEmail);
 
         do_test_finished();
         server.stop(run_next_test);
         break;
 
       // We should not receive any other mozFxAccountsChromeEvent messages
       default:
         do_throw("wat!");
@@ -146,17 +146,17 @@ add_test(function test_invalidEmailCase_
   SystemAppProxy._sendCustomEvent = mockSendCustomEvent;
 
   // Trigger signIn using an email with incorrect capitalization
   FxAccountsMgmtService.handleEvent({
     detail: {
       id: "signIn",
       data: {
         method: "signIn",
-        accountId: clientEmail,
+        email: clientEmail,
         password: "123456",
       },
     },
   });
 });
 
 // End of tests
 // Utility functions follow
--- a/browser/base/content/test/general/browser_bug581947.js
+++ b/browser/base/content/test/general/browser_bug581947.js
@@ -1,15 +1,19 @@
-function check(aElementName, aBarred) {
+function check(aElementName, aBarred, aType) {
   let doc = gBrowser.contentDocument;
   let tooltip = document.getElementById("aHTMLTooltip");
   let content = doc.getElementById('content');
 
   let e = doc.createElement(aElementName);
   content.appendChild(e);
+  
+  if (aType) {
+    e.type = aType;
+  }
 
   ok(!tooltip.fillInPageTooltip(e),
      "No tooltip should be shown when the element is valid");
 
   e.setCustomValidity('foo');
   if (aBarred) {
     ok(!tooltip.fillInPageTooltip(e),
        "No tooltip should be shown when the element is barred from constraint validation");
@@ -54,27 +58,28 @@ function todo_check(aElementName, aBarre
 function test () {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     let testData = [
     /* element name, barred */
-      [ 'input',    false ],
-      [ 'textarea', false ],
-      [ 'button',   true ],
-      [ 'select',   false ],
-      [ 'output',   true ],
-      [ 'fieldset', true ],
-      [ 'object',   true ],
+      [ 'input',    false,  null],
+      [ 'textarea', false,  null],
+      [ 'button',   true,  'button'],
+      [ 'button',   false, 'submit'],
+      [ 'select',   false,  null],
+      [ 'output',   true,   null],
+      [ 'fieldset', true,   null],
+      [ 'object',   true,   null],
     ];
 
     for each (let data in testData) {
-      check(data[0], data[1]);
+      check(data[0], data[1], data[2]);
     }
 
     let todo_testData = [
       [ 'keygen', 'false' ],
     ];
 
     for each(let data in todo_testData) {
       todo_check(data[0], data[1]);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -12150,17 +12150,17 @@ nsIDocument::WrapObject(JSContext *aCx)
                                            false);
   if (NS_FAILED(rv)) {
     Throw(aCx, rv);
     return nullptr;
   }
 
   NS_NAMED_LITERAL_STRING(doc_str, "document");
 
-  if (!JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal), doc_str.get(),
+  if (!JS_DefineUCProperty(aCx, winVal.toObjectOrNull(), doc_str.get(),
                            doc_str.Length(), JS::ObjectValue(*obj),
                            JS_PropertyStub, JS_StrictPropertyStub,
                            JSPROP_READONLY | JSPROP_ENUMERATE)) {
     return nullptr;
   }
 
   return obj;
 }
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2445,18 +2445,18 @@ GetRequestBody(nsIVariant* aBody, nsIInp
       return GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
     }
 
     // ArrayBuffer?
     AutoSafeJSContext cx;
     JS::Rooted<JS::Value> realVal(cx);
 
     nsresult rv = aBody->GetAsJSVal(&realVal);
-    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal)) {
-      JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(realVal));
+    if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) {
+      JS::Rooted<JSObject*> obj(cx, realVal.toObjectOrNull());
       if (JS_IsArrayBufferObject(obj)) {
           ArrayBuffer buf(obj);
           return GetRequestBody(buf.Data(), buf.Length(), aResult,
                                 aContentLength, aContentType, aCharset);
       }
     }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -820,17 +820,17 @@ void
 CanvasRenderingContext2D::RemoveDemotableContext(CanvasRenderingContext2D* context)
 {
   std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(DemotableContexts().begin(), DemotableContexts().end(), context);
   if (iter != DemotableContexts().end())
     DemotableContexts().erase(iter);
 }
 
 bool
-CheckSizeForSkiaGL(IntSize size) {
+CanvasRenderingContext2D::CheckSizeForSkiaGL(IntSize size) {
   MOZ_ASSERT(NS_IsMainThread());
 
   int minsize = Preferences::GetInt("gfx.canvas.min-size-for-skia-gl", 128);
   if (size.width < minsize || size.height < minsize) {
     return false;
   }
 
   // Maximum pref allows 3 different options:
@@ -847,32 +847,57 @@ CheckSizeForSkiaGL(IntSize size) {
   // absolute max size threshold
   if (maxsize > 0) {
     return size.width <= maxsize && size.height <= maxsize;
   }
 
   // Cache the number of pixels on the primary screen
   static int32_t gScreenPixels = -1;
   if (gScreenPixels < 0) {
+    // Default to historical mobile screen size of 980x480.  In addition,
+    // allow skia use up to this size even if the screen is smaller.  A lot
+    // content expects this size to work well.
+    gScreenPixels = 980 * 480;
+
     nsCOMPtr<nsIScreenManager> screenManager =
       do_GetService("@mozilla.org/gfx/screenmanager;1");
     if (screenManager) {
       nsCOMPtr<nsIScreen> primaryScreen;
       screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
       if (primaryScreen) {
         int32_t x, y, width, height;
         primaryScreen->GetRect(&x, &y, &width, &height);
 
-        gScreenPixels = width * height;
+        gScreenPixels = std::max(gScreenPixels, width * height);
       }
     }
   }
 
+  // On high DPI devices the screen pixels may be scaled up.  Make
+  // sure to apply that scaling here as well if we are hooked up
+  // to a widget.
+  static double gDefaultScale = 0.0;
+  if (gDefaultScale < 1.0) {
+    nsIPresShell* ps = GetPresShell();
+    if (ps) {
+      nsIFrame* frame = ps->GetRootFrame();
+      if (frame) {
+        nsIWidget* widget = frame->GetNearestWidget();
+        if (widget) {
+          gDefaultScale = widget->GetDefaultScale().scale;
+        }
+      }
+    }
+  }
+
+  int32_t threshold = gDefaultScale > 0 ? ceil(gDefaultScale * gScreenPixels)
+                                        : gScreenPixels;
+
   // screen size acts as max threshold
-  return gScreenPixels < 0 || (size.width * size.height) <= gScreenPixels;
+  return threshold < 0 || (size.width * size.height) <= threshold;
 }
 
 void
 CanvasRenderingContext2D::EnsureTarget()
 {
   if (mTarget) {
     return;
   }
@@ -1330,17 +1355,17 @@ CanvasRenderingContext2D::GetMozCurrentT
 {
   if (!mTarget) {
     return MatrixToJSObject(cx, Matrix(), error);
   }
 
   Matrix ctm = mTarget->GetTransform();
 
   if (!ctm.Invert()) {
-    double NaN = JSVAL_TO_DOUBLE(JS_GetNaNValue(cx));
+    double NaN = JS_GetNaNValue(cx).toDouble();
     ctm = Matrix(NaN, NaN, NaN, NaN, NaN, NaN);
   }
 
   return MatrixToJSObject(cx, ctm, error);
 }
 
 //
 // colors
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -847,16 +847,18 @@ protected:
     */
   nsresult DrawOrMeasureText(const nsAString& text,
                              float x,
                              float y,
                              const Optional<double>& maxWidth,
                              TextDrawOperation op,
                              float* aWidth);
 
+  bool CheckSizeForSkiaGL(mozilla::gfx::IntSize size);
+
   // state stack handling
   class ContextState {
   public:
     ContextState() : textAlign(TextAlign::START),
                      textBaseline(TextBaseline::ALPHABETIC),
                      lineWidth(1.0f),
                      miterLimit(10.0f),
                      globalAlpha(1.0f),
--- a/content/canvas/src/CanvasUtils.cpp
+++ b/content/canvas/src/CanvasUtils.cpp
@@ -62,21 +62,21 @@ DoDrawImageSecurityCheck(dom::HTMLCanvas
     }
 
     aCanvasElement->SetWriteOnly();
 }
 
 bool
 CoerceDouble(JS::Value v, double* d)
 {
-    if (JSVAL_IS_DOUBLE(v)) {
-        *d = JSVAL_TO_DOUBLE(v);
-    } else if (JSVAL_IS_INT(v)) {
-        *d = double(JSVAL_TO_INT(v));
-    } else if (JSVAL_IS_VOID(v)) {
+    if (v.isDouble()) {
+        *d = v.toDouble();
+    } else if (v.isInt32()) {
+        *d = double(v.toInt32());
+    } else if (v.isUndefined()) {
         *d = 0.0;
     } else {
         return false;
     }
     return true;
 }
 
 } // namespace CanvasUtils
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -101,18 +101,18 @@ template<typename T>
 nsresult
 JSValToDashArray(JSContext* cx, const JS::Value& patternArray,
                  FallibleTArray<T>& dashes)
 {
     // The cap is pretty arbitrary.  16k should be enough for
     // anybody...
     static const uint32_t MAX_NUM_DASHES = 1 << 14;
 
-    if (!JSVAL_IS_PRIMITIVE(patternArray)) {
-        JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(patternArray));
+    if (!patternArray.isPrimitive()) {
+        JS::Rooted<JSObject*> obj(cx, patternArray.toObjectOrNull());
         uint32_t length;
         if (!JS_GetArrayLength(cx, obj, &length)) {
             // Not an array-like thing
             return NS_ERROR_INVALID_ARG;
         } else if (length > MAX_NUM_DASHES) {
             // Too many dashes in the pattern
             return NS_ERROR_ILLEGAL_VALUE;
         }
@@ -136,17 +136,17 @@ JSValToDashArray(JSContext* cx, const JS
                 return NS_ERROR_OUT_OF_MEMORY;
             }
         }
 
         if (dashes.Length() > 0 && !haveNonzeroElement) {
             // An all-zero pattern makes no sense.
             return NS_ERROR_ILLEGAL_VALUE;
         }
-    } else if (!(JSVAL_IS_VOID(patternArray) || JSVAL_IS_NULL(patternArray))) {
+    } else if (!(patternArray.isUndefined() || patternArray.isNull())) {
         // undefined and null mean "reset to no dash".  Any other
         // random garbage is a type error.
         return NS_ERROR_INVALID_ARG;
     }
 
     return NS_OK;
 }
 
--- a/content/html/content/src/HTMLButtonElement.cpp
+++ b/content/html/content/src/HTMLButtonElement.cpp
@@ -58,19 +58,16 @@ static const nsAttrValue::EnumTable* kBu
 HTMLButtonElement::HTMLButtonElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
                                      FromParser aFromParser)
   : nsGenericHTMLFormElementWithState(aNodeInfo),
     mType(kButtonDefaultType->value),
     mDisabledChanged(false),
     mInInternalActivate(false),
     mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT))
 {
-  // <button> is always barred from constraint validation.
-  SetBarredFromConstraintValidation(true);
-
   // Set up our default state: enabled
   AddStatesSilently(NS_EVENT_STATE_ENABLED);
 }
 
 HTMLButtonElement::~HTMLButtonElement()
 {
 }
 
@@ -87,21 +84,46 @@ NS_IMPL_RELEASE_INHERITED(HTMLButtonElem
 // QueryInterface implementation for HTMLButtonElement
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLButtonElement)
   NS_INTERFACE_TABLE_INHERITED(HTMLButtonElement,
                                nsIDOMHTMLButtonElement,
                                nsIConstraintValidation)
 NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
 
 // nsIConstraintValidation
-NS_IMPL_NSICONSTRAINTVALIDATION(HTMLButtonElement)
+NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLButtonElement)
+
+NS_IMETHODIMP
+HTMLButtonElement::SetCustomValidity(const nsAString& aError) 
+{
+  nsIConstraintValidation::SetCustomValidity(aError);
+  
+  UpdateState(true);
+
+  return NS_OK;
+}
+
+void
+HTMLButtonElement::UpdateBarredFromConstraintValidation()
+{
+  SetBarredFromConstraintValidation(mType == NS_FORM_BUTTON_BUTTON ||
+                                    mType == NS_FORM_BUTTON_RESET ||
+                                    IsDisabled());
+}
+
+void
+HTMLButtonElement::FieldSetDisabledChanged(bool aNotify)
+{
+  UpdateBarredFromConstraintValidation();
+
+  nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
+}
 
 // nsIDOMHTMLButtonElement
 
-
 NS_IMPL_ELEMENT_CLONE(HTMLButtonElement)
 
 
 // nsIDOMHTMLButtonElement
 
 NS_IMETHODIMP
 HTMLButtonElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
@@ -486,18 +508,21 @@ nsresult
 HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::type) {
       if (!aValue) {
         mType = kButtonDefaultType->value;
       }
+    }
 
-      UpdateState(aNotify);
+    if (aName == nsGkAtoms::type || aName == nsGkAtoms::disabled) {
+      UpdateBarredFromConstraintValidation();
+      UpdateState(aNotify); 
     }
   }
 
   return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
                                                          aValue, aNotify);
 }
 
 NS_IMETHODIMP
@@ -526,16 +551,30 @@ HTMLButtonElement::RestoreState(nsPresSt
 
   return false;
 }
 
 EventStates
 HTMLButtonElement::IntrinsicState() const
 {
   EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
+  
+  if (IsCandidateForConstraintValidation()) {
+    if (IsValid()) {
+      state |= NS_EVENT_STATE_VALID;
+      if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
+        state |= NS_EVENT_STATE_MOZ_UI_VALID;
+      }
+    } else {
+      state |= NS_EVENT_STATE_INVALID;
+      if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
+        state |= NS_EVENT_STATE_MOZ_UI_INVALID;
+      }
+    }
+  }
 
   if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
     state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
   }
 
   return state;
 }
 
--- a/content/html/content/src/HTMLButtonElement.h
+++ b/content/html/content/src/HTMLButtonElement.h
@@ -43,16 +43,18 @@ public:
   // overriden nsIFormControl methods
   NS_IMETHOD_(uint32_t) GetType() const { return mType; }
   NS_IMETHOD Reset() MOZ_OVERRIDE;
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission) MOZ_OVERRIDE;
   NS_IMETHOD SaveState() MOZ_OVERRIDE;
   bool RestoreState(nsPresState* aState) MOZ_OVERRIDE;
   virtual bool IsDisabledForEvents(uint32_t aMessage) MOZ_OVERRIDE;
 
+  virtual void FieldSetDisabledChanged(bool aNotify) MOZ_OVERRIDE; 
+
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
 
   // nsINode
   virtual nsresult Clone(nsINodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE;
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
@@ -60,16 +62,17 @@ public:
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) MOZ_OVERRIDE;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) MOZ_OVERRIDE;
   virtual void DoneCreatingElement() MOZ_OVERRIDE;
 
+  void UpdateBarredFromConstraintValidation();
   // Element
   EventStates IntrinsicState() const MOZ_OVERRIDE;
   /**
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify) MOZ_OVERRIDE;
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -6680,18 +6680,16 @@ HTMLInputElement::UpdateAllValidityState
 }
 
 void
 HTMLInputElement::UpdateBarredFromConstraintValidation()
 {
   SetBarredFromConstraintValidation(mType == NS_FORM_INPUT_HIDDEN ||
                                     mType == NS_FORM_INPUT_BUTTON ||
                                     mType == NS_FORM_INPUT_RESET ||
-                                    mType == NS_FORM_INPUT_SUBMIT ||
-                                    mType == NS_FORM_INPUT_IMAGE ||
                                     HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
                                     IsDisabled());
 }
 
 void
 HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
                                        ErrorResult& aRv)
 {
--- a/content/html/content/test/forms/test_pattern_attribute.html
+++ b/content/html/content/test/forms/test_pattern_attribute.html
@@ -250,18 +250,18 @@ function checkPatternValidity(element)
   checkValidPattern(element, true);
 }
 
 var input = document.getElementById('i');
 
 // |validTypes| are the types which accept @pattern
 // and |invalidTypes| are the ones which do not accept it.
 var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
-var barredTypes = Array('hidden', 'reset', 'button', 'submit', 'image');
-var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time', 'color');
+var barredTypes = Array('hidden', 'reset', 'button');
+var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time', 'color', 'submit', 'image');
 // TODO: 'datetime', 'month', 'week', and 'datetime-local'
 //       do not accept the @pattern too but are not implemented yet.
 
 for (type of validTypes) {
   input.type = type;
   completeValidityCheck(input, false);
   checkPatternValidity(input);
 }
--- a/content/html/content/test/forms/test_required_attribute.html
+++ b/content/html/content/test/forms/test_required_attribute.html
@@ -355,23 +355,23 @@ function checkInputRequiredValidityForFi
   checkSufferingFromBeingMissing(element, true);
 }
 
 checkTextareaRequiredValidity();
 
 // The require attribute behavior depend of the input type.
 // First of all, checks for types that make the element barred from
 // constraint validation.
-var typeBarredFromConstraintValidation = ["hidden", "button", "reset", "submit", "image"];
+var typeBarredFromConstraintValidation = ["hidden", "button", "reset"];
 for (type of typeBarredFromConstraintValidation) {
   checkInputRequiredNotApply(type, true);
 }
 
 // Then, checks for the types which do not use the required attribute.
-var typeRequireNotApply = ['range', 'color'];
+var typeRequireNotApply = ['range', 'color', 'submit', 'image'];
 for (type of typeRequireNotApply) {
   checkInputRequiredNotApply(type, false);
 }
 
 // Now, checking for all types which accept the required attribute.
 // TODO: check 'datetime', 'month', 'week' and 'datetime-local'
 //       when they will be implemented.
 var typeRequireApply = ["text", "password", "search", "tel", "email", "url",
--- a/content/html/content/test/forms/test_validation.html
+++ b/content/html/content/test/forms/test_validation.html
@@ -114,18 +114,18 @@ function checkDefaultPseudoClass()
        .getPropertyValue('background-color'), "rgb(0, 255, 0)",
      ":valid pseudo-class should apply");
 
   is(window.getComputedStyle(document.getElementById('t'), null)
        .getPropertyValue('background-color'), "rgb(0, 255, 0)",
      ":valid pseudo-class should apply");
 
   is(window.getComputedStyle(document.getElementById('b'), null)
-       .getPropertyValue('background-color'), "rgb(0, 0, 0)",
-     ":valid pseudo-class should not apply");
+       .getPropertyValue('background-color'), "rgb(0, 255, 0)",
+     ":valid pseudo-class should apply");
 }
 
 function checkSpecificWillValidate()
 {
   // fieldset, output, object, keygen (TODO) and select elements
   ok(!document.getElementById('f').willValidate, "Fielset element should be barred from constraint validation");
   ok(!document.getElementById('obj').willValidate, "Object element should be barred from constraint validation");
   todo(!document.getElementById('k').willValidate, "Keygen element should be barred from constraint validation");
@@ -142,23 +142,23 @@ function checkSpecificWillValidate()
   ok(!i.willValidate, "Reset button state input should be barred from constraint validation");
   is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
      "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
   i.type = "button";
   ok(!i.willValidate, "Button state input should be barred from constraint validation");
   is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
      "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
   i.type = "image";
-  ok(!i.willValidate, "Image state input should be barred from constraint validation");
+  ok(i.willValidate, "Image state input should not be barred from constraint validation");
   is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
-     "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
+     "rgb(0, 255, 0)", ":valid and :invalid should apply");
   i.type = "submit";
-  ok(!i.willValidate, "Submit state input should be barred from constraint validation");
+  ok(i.willValidate, "Submit state input should not be barred from constraint validation");
   is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
-     "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
+     "rgb(0, 255, 0)", ":valid and :invalid should apply");
   i.type = "number";
   ok(i.willValidate, "Number state input should not be barred from constraint validation");
   is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
      "rgb(0, 255, 0)", ":valid pseudo-class should apply");
   i.type = "";
   i.readOnly = 'true';
   ok(!i.willValidate, "Readonly input should be barred from constraint validation");
   is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
@@ -174,23 +174,23 @@ function checkSpecificWillValidate()
   ok(!b.willValidate, "Reset state button should be barred from constraint validation");
   is(window.getComputedStyle(b, null).getPropertyValue('background-color'),
      "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
   b.type = "button";
   ok(!b.willValidate, "Button state button should be barred from constraint validation");
   is(window.getComputedStyle(b, null).getPropertyValue('background-color'),
      "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
   b.type = "submit";
-  ok(!b.willValidate, "Submit state button should be barred from constraint validation");
+  ok(b.willValidate, "Submit state button should not be barred from constraint validation");
   is(window.getComputedStyle(b, null).getPropertyValue('background-color'),
-     "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
+     "rgb(0, 255, 0)", ":valid and :invalid should apply");
   b.type = "";
-  ok(!b.willValidate, "Default button element should be barred from constraint validation");
+  ok(b.willValidate, "Default button element should not be barred from constraint validation");
   is(window.getComputedStyle(b, null).getPropertyValue('background-color'),
-     "rgb(0, 0, 0)", ":valid pseudo-class should apply");
+     "rgb(0, 255, 0)", ":valid pseudo-class should apply");
 
   // textarea element
   t = document.getElementById('t');
   t.readOnly = true;
   ok(!t.willValidate, "Readonly textarea should be barred from constraint validation");
   is(window.getComputedStyle(t, null).getPropertyValue('background-color'),
      "rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
   t.removeAttribute('readOnly');
@@ -327,17 +327,17 @@ checkCommonWillValidate(document.getElem
 checkCommonWillValidate(document.getElementById('t'));
 checkCommonWillValidate(document.getElementById('o'));
 
 /* TODO: add "keygen" element */
 checkCustomError(document.getElementById('i'), false);
 checkCustomError(document.getElementById('s'), false);
 checkCustomError(document.getElementById('t'), false);
 checkCustomError(document.getElementById('o'), false);
-checkCustomError(document.getElementById('b'), true);
+checkCustomError(document.getElementById('b'), false);
 checkCustomError(document.getElementById('f'), true);
 checkCustomError(document.getElementById('obj'), true);
 
 // Not checking button, fieldset, object and keygen
 // because they are always barred from constraint validation.
 checkCheckValidity(document.getElementById('i'));
 checkCheckValidity(document.getElementById('s'));
 checkCheckValidity(document.getElementById('t'));
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -314,16 +314,17 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_bug874897.html]
 [test_bug883173.html]
 [test_bug895305.html]
 [test_bug895091.html]
 [test_bug919265.html]
 [test_bug957847.html]
 [test_chaining.html]
 skip-if = buildapp == 'b2g' # b2g(timed out) b2g-debug(timed out) b2g-desktop(timed out)
+[test_clone_media_element.html]
 [test_contentDuration1.html]
 [test_contentDuration2.html]
 [test_contentDuration3.html]
 [test_contentDuration4.html]
 [test_contentDuration5.html]
 [test_contentDuration6.html]
 [test_contentDuration7.html]
 [test_can_play_type.html]
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_clone_media_element.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test: cloned media element should continue to play to the end even after the source of the original element is cleared</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.requestLongerTimeout(2);
+// tests must run in sequence otherwise concurrent running test will also
+// update media cache which will hide the fact media cache not updated
+// after changes in media cache streams.
+PARALLEL_TESTS = 1;
+
+function startTest(test, token) {
+  manager.started(token);
+  info("Trying to load " + token);
+  var v = document.createElement('video');
+  v.preload = "metadata";
+  v.token = token;
+  v.src = test.name;
+
+  v.onloadedmetadata = function(evt) {
+    info(evt.target.token + " metadata loaded.");
+    evt.target.onloadedmetadata = null;
+    var clone = evt.target.cloneNode(false);
+    clone.token = evt.target.token;
+    clone.play();
+
+    clone.onloadstart = function(evt) {
+      info("cloned " + evt.target.token + " start loading.");
+      evt.target.onloadstart = null;
+      removeNodeAndSource(v);
+    }
+
+    clone.onended = function(evt) {
+      ok(true, "cloned " + evt.target.token + " ended.");
+      evt.target.onended = null;
+      removeNodeAndSource(evt.target);
+      manager.finished(evt.target.token);
+    }
+  }
+}
+
+var manager = new MediaTestManager;
+manager.runTests(gSmallTests.concat(gPlayedTests), startTest);
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/webm/EbmlComposer.cpp
+++ b/content/media/webm/EbmlComposer.cpp
@@ -83,17 +83,20 @@ void EbmlComposer::FinishCluster()
     // No completed cluster available.
     return;
   }
 
   MOZ_ASSERT(mClusterLengthLoc > 0);
   EbmlGlobal ebml;
   EbmlLoc ebmlLoc;
   ebmlLoc.offset = mClusterLengthLoc;
-  ebml.offset = mClusterBuffs[mClusterHeaderIndex].Length();
+  ebml.offset = 0;
+  for (uint32_t i = mClusterHeaderIndex; i < mClusterBuffs.Length(); i++) {
+    ebml.offset += mClusterBuffs[i].Length();
+  }
   ebml.buf = mClusterBuffs[mClusterHeaderIndex].Elements();
   Ebml_EndSubElement(&ebml, &ebmlLoc);
   // Move the mClusterBuffs data from mClusterHeaderIndex that we can skip
   // the metadata and the rest P-frames after ContainerWriter::FLUSH_NEEDED.
   for (uint32_t i = mClusterHeaderIndex; i < mClusterBuffs.Length(); i++) {
     mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
   }
 
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -1387,17 +1387,17 @@ nsXULTemplateBuilder::InitHTMLTemplateRo
     // point, but as this is XUL related it does not appear in the HTML spec.
     AutoEntryScript entryScript(innerWin, true);
     JSContext* jscontext = entryScript.cx();
 
     JS::Rooted<JS::Value> v(jscontext);
     rv = nsContentUtils::WrapNative(jscontext, mRoot, mRoot, &v);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JS::Rooted<JSObject*> jselement(jscontext, JSVAL_TO_OBJECT(v));
+    JS::Rooted<JSObject*> jselement(jscontext, v.toObjectOrNull());
 
     if (mDB) {
         // database
         JS::Rooted<JS::Value> jsdatabase(jscontext);
         rv = nsContentUtils::WrapNative(jscontext, mDB,
                                         &NS_GET_IID(nsIRDFCompositeDataSource),
                                         &jsdatabase);
         NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/activities/interfaces/nsIActivityUIGlue.idl
+++ b/dom/activities/interfaces/nsIActivityUIGlue.idl
@@ -1,25 +1,45 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, function, uuid(7a16feb4-5a78-4589-9174-b728f26942e2)]
+[scriptable, function, uuid(674b6e69-05f0-41da-aabd-4184ea85c9d8)]
 interface nsIActivityUIGlueCallback : nsISupports
 {
-    void handleEvent(in long choice);
+    /**
+     * The activity service should start the activity at the specified index.
+     */
+    const short WEBAPPS_ACTIVITY = 0;
+
+    /**
+     * The activity service should deliver the specified result to the MozActivity callback.
+     */
+    const short NATIVE_ACTIVITY  = 1;
+
+    /**
+      * Called if the user picked an activitiy to launch.
+      * @param resultType Inidcates that {@code result} is an index or a native activity result.
+      * @param result     If WEBAPPS_ACTIVITY, the index of the chosen activity. Send '-1' if no choice is made.
+                          If NATIVE_ACTIVITY, the return value to be sent to the MozActivity.
+      */
+    void handleEvent(in short resultType, in jsval result);
 };
 
 /**
   * To be implemented by @mozilla.org/dom/activities/ui-glue;1
   */
-[scriptable, uuid(8624ad73-937a-400f-9d93-39ab5449b867)]
+[scriptable, uuid(3caef69f-3569-4b19-bcea-1cfb0fee4466)]
 interface nsIActivityUIGlue : nsISupports
 {
     /**
-      * @param name        The name of the activity to handle (eg. "share", "pick").
+      * This method is called even if the size of {@code activities} is 0 so that the callee can
+      * decide whether or not to defer the request to an alternate activity system.
+      *
+      * @param options     The ActivityOptions object in the form of { name: "send", data: { ... } }
       * @param activities  A json blob which is an array of { "title":"...", "icon":"..." }.
-      * @param onresult    The callback to send the index of the choosen activity. Send -1 if no choice is made.
+      * @param callback    The callback to send the index of the choosen activity, or the result.
       */
-    void chooseActivity(in DOMString title, in jsval activities, in nsIActivityUIGlueCallback onresult);
+    void chooseActivity(in jsval options, in jsval activities,
+        in nsIActivityUIGlueCallback callback);
 };
--- a/dom/activities/src/ActivitiesService.jsm
+++ b/dom/activities/src/ActivitiesService.jsm
@@ -201,75 +201,89 @@ let Activities = {
     *   activity data as a payload.
     */
   startActivity: function activities_startActivity(aMsg) {
     debug("StartActivity: " + JSON.stringify(aMsg));
 
     let successCb = function successCb(aResults) {
       debug(JSON.stringify(aResults));
 
-      // We have no matching activity registered, let's fire an error.
-      if (aResults.options.length === 0) {
-        Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
-          "id": aMsg.id,
-          "error": "NO_PROVIDER"
-        });
-        delete Activities.callers[aMsg.id];
-        return;
-      }
+      function getActivityChoice(aResultType, aResult) {
+        switch(aResultType) {
+          case Ci.nsIActivityUIGlueCallback.NATIVE_ACTIVITY: {
+            Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
+              "id": aMsg.id,
+              "result": aResult
+            });
+            break;
+          }
+          case Ci.nsIActivityUIGlueCallback.WEBAPPS_ACTIVITY: {
+            debug("Activity choice: " + aResult);
 
-      function getActivityChoice(aChoice) {
-        debug("Activity choice: " + aChoice);
+            // We have no matching activity registered, let's fire an error.
+            // Don't do this check until we have passed to UIGlue so the glue can choose to launch
+            // its own activity if needed.
+            if (aResults.options.length === 0) {
+              Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
+                "id": aMsg.id,
+                "error": "NO_PROVIDER"
+              });
+              delete Activities.callers[aMsg.id];
+              return;
+            }
 
-        // The user has cancelled the choice, fire an error.
-        if (aChoice === -1) {
-          Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
-            "id": aMsg.id,
-            "error": "ActivityCanceled"
-          });
-          delete Activities.callers[aMsg.id];
-          return;
-        }
+            // The user has cancelled the choice, fire an error.
+            if (aResult === -1) {
+              Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
+                "id": aMsg.id,
+                "error": "ActivityCanceled"
+              });
+              delete Activities.callers[aMsg.id];
+              return;
+            }
 
-        let sysmm = Cc["@mozilla.org/system-message-internal;1"]
-                      .getService(Ci.nsISystemMessagesInternal);
-        if (!sysmm) {
-          // System message is not present, what should we do?
-          delete Activities.callers[aMsg.id];
-          return;
-        }
+            let sysmm = Cc["@mozilla.org/system-message-internal;1"]
+                          .getService(Ci.nsISystemMessagesInternal);
+            if (!sysmm) {
+              // System message is not present, what should we do?
+              delete Activities.callers[aMsg.id];
+              return;
+            }
 
-        debug("Sending system message...");
-        let result = aResults.options[aChoice];
-        sysmm.sendMessage("activity", {
-            "id": aMsg.id,
-            "payload": aMsg.options,
-            "target": result.description
-          },
-          Services.io.newURI(result.description.href, null, null),
-          Services.io.newURI(result.manifest, null, null),
-          {
-            "manifestURL": Activities.callers[aMsg.id].manifestURL,
-            "pageURL": Activities.callers[aMsg.id].pageURL
-          });
+            debug("Sending system message...");
+            let result = aResults.options[aResult];
+            sysmm.sendMessage("activity", {
+                "id": aMsg.id,
+                "payload": aMsg.options,
+                "target": result.description
+              },
+              Services.io.newURI(result.description.href, null, null),
+              Services.io.newURI(result.manifest, null, null),
+              {
+                "manifestURL": Activities.callers[aMsg.id].manifestURL,
+                "pageURL": Activities.callers[aMsg.id].pageURL
+              });
 
-        if (!result.description.returnValue) {
-          Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
-            "id": aMsg.id,
-            "result": null
-          });
-          // No need to notify observers, since we don't want the caller
-          // to be raised on the foreground that quick.
-          delete Activities.callers[aMsg.id];
+            if (!result.description.returnValue) {
+              Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
+                "id": aMsg.id,
+                "result": null
+              });
+              // No need to notify observers, since we don't want the caller
+              // to be raised on the foreground that quick.
+              delete Activities.callers[aMsg.id];
+            }
+            break;
+          }
         }
       };
 
       let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"]
                    .createInstance(Ci.nsIActivityUIGlue);
-      glue.chooseActivity(aResults.name, aResults.options, getActivityChoice);
+      glue.chooseActivity(aMsg.options, aResults.options, getActivityChoice);
     };
 
     let errorCb = function errorCb(aError) {
       // Something unexpected happened. Should we send an error back?
       debug("Error in startActivity: " + aError + "\n");
     };
 
     let matchFunc = function matchFunc(aResult) {
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -96,17 +96,17 @@ DOMRequest::GetError(nsISupports** aErro
 void
 DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult)
 {
   NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
   NS_ASSERTION(!mError, "mError shouldn't have been set!");
   NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
   mDone = true;
-  if (JSVAL_IS_GCTHING(aResult)) {
+  if (aResult.isGCThing()) {
     RootResultVal();
   }
   mResult = aResult;
 
   FireEvent(NS_LITERAL_STRING("success"), false, false);
 }
 
 void
--- a/dom/base/MessagePort.cpp
+++ b/dom/base/MessagePort.cpp
@@ -104,17 +104,17 @@ PostMessageReadStructuredClone(JSContext
 {
   if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
       JS::Rooted<JS::Value> val(cx);
       if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
-        return JSVAL_TO_OBJECT(val);
+        return val.toObjectOrNull();
       }
     }
   }
 
   const JSStructuredCloneCallbacks* runtimeCallbacks =
     js::GetContextStructuredCloneCallbacks(cx);
 
   if (runtimeCallbacks) {
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1423,17 +1423,17 @@ nsDOMClassInfo::ResolveConstructor(JSCon
   JS::Rooted<JSObject*> obj(cx, aObj);
   JS::Rooted<JSObject*> global(cx, ::JS_GetGlobalForObject(cx, obj));
 
   JS::Rooted<JS::Value> val(cx);
   if (!::JS_LookupProperty(cx, global, mData->mName, &val)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (!JSVAL_IS_PRIMITIVE(val)) {
+  if (!val.isPrimitive()) {
     // If val is not an (non-null) object there either is no
     // constructor for this class, or someone messed with
     // window.classname, just fall through and let the JS engine
     // return the Object constructor.
 
     if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, JS_PropertyStub,
                                  JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
       return NS_ERROR_UNEXPECTED;
@@ -2268,17 +2268,17 @@ nsDOMConstructor::Construct(nsIXPConnect
 nsresult
 nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper,
                               JSContext * cx, JS::Handle<JSObject*> obj,
                               const jsval &v, bool *bp, bool *_retval)
 
 {
   // No need to look these up in the hash.
   *bp = false;
-  if (JSVAL_IS_PRIMITIVE(v)) {
+  if (v.isPrimitive()) {
     return NS_OK;
   }
 
   JS::Rooted<JSObject*> dom_obj(cx, v.toObjectOrNull());
   NS_ASSERTION(dom_obj, "nsDOMConstructor::HasInstance couldn't get object");
 
   // This might not be the right object, if there are wrappers. Unwrap if we can.
   JSObject *wrapped_obj = js::CheckedUnwrap(dom_obj, /* stopAtOuter = */ false);
@@ -2300,17 +2300,17 @@ nsDOMConstructor::HasInstance(nsIXPConne
   if (!name_struct) {
     // This isn't a normal DOM object, see if this constructor lives on its
     // prototype chain.
     JS::Rooted<JS::Value> val(cx);
     if (!JS_GetProperty(cx, obj, "prototype", &val)) {
       return NS_ERROR_UNEXPECTED;
     }
 
-    if (JSVAL_IS_PRIMITIVE(val)) {
+    if (val.isPrimitive()) {
       return NS_OK;
     }
 
     JS::Rooted<JSObject*> dot_prototype(cx, val.toObjectOrNull());
 
     JS::Rooted<JSObject*> proto(cx, dom_obj);
     for (;;) {
       if (!JS_GetPrototype(cx, proto, &proto)) {
@@ -3029,17 +3029,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     JS::Rooted<JS::Value> prop_val(cx, JS::UndefinedValue()); // Property value.
 
     nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
     if (gpi) {
       rv = gpi->Init(aWin, &prop_val);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
+    if (prop_val.isPrimitive() && !prop_val.isNull()) {
       if (aWin->IsOuterWindow()) {
         nsGlobalWindow *inner = aWin->GetCurrentInnerWindowInternal();
         NS_ENSURE_TRUE(inner, NS_ERROR_UNEXPECTED);
       }
 
       rv = WrapNative(cx, native, true, &prop_val);
     }
 
@@ -3542,23 +3542,23 @@ nsGenericArraySH::GetLength(nsIXPConnect
 {
   *length = 0;
 
   JS::Rooted<JS::Value> lenval(cx);
   if (!JS_GetProperty(cx, obj, "length", &lenval)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (!JSVAL_IS_INT(lenval)) {
+  if (!lenval.isInt32()) {
     // This can apparently happen with some sparse array impls falling back
     // onto this code.
     return NS_OK;
   }
 
-  int32_t slen = JSVAL_TO_INT(lenval);
+  int32_t slen = lenval.toInt32();
   if (slen < 0) {
     return NS_OK;
   }
 
   *length = (uint32_t)slen;
 
   return NS_OK;
 }
@@ -3579,18 +3579,18 @@ nsGenericArraySH::Enumerate(nsIXPConnect
     return NS_OK;
   }
 
   sCurrentlyEnumerating = true;
 
   JS::Rooted<JS::Value> len_val(cx);
   bool ok = ::JS_GetProperty(cx, obj, "length", &len_val);
 
-  if (ok && JSVAL_IS_INT(len_val)) {
-    int32_t length = JSVAL_TO_INT(len_val);
+  if (ok && len_val.isInt32()) {
+    int32_t length = len_val.toInt32();
 
     for (int32_t i = 0; ok && i < length; ++i) {
       ok = ::JS_DefineElement(cx, obj, i, JSVAL_VOID, nullptr, nullptr,
                               JSPROP_ENUMERATE | JSPROP_SHARED);
     }
   }
 
   sCurrentlyEnumerating = false;
@@ -3839,18 +3839,17 @@ nsStorage2SH::NewEnumerate(nsIXPConnectW
     *statep = PRIVATE_TO_JSVAL(keys);
 
     if (idp) {
       *idp = INT_TO_JSID(keys->Length());
     }
     return NS_OK;
   }
 
-  nsTArray<nsString> *keys =
-    (nsTArray<nsString> *)JSVAL_TO_PRIVATE(*statep);
+  nsTArray<nsString> *keys = (nsTArray<nsString> *)statep->toPrivate();
 
   if (enum_op == JSENUMERATE_NEXT && keys->Length() != 0) {
     nsString& key = keys->ElementAt(0);
     JS::Rooted<JSString*> str(cx, JS_NewUCStringCopyN(cx, key.get(), key.Length()));
     NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
 
     JS::Rooted<jsid> id(cx);
     JS_StringToId(cx, str, &id);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2381,21 +2381,21 @@ NS_IMETHODIMP
 nsDOMWindowUtils::GetClassName(JS::Handle<JS::Value> aObject, JSContext* aCx,
                                char** aName)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // Our argument must be a non-null object.
-  if (JSVAL_IS_PRIMITIVE(aObject)) {
+  if (aObject.isPrimitive()) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
-  *aName = NS_strdup(JS_GetClass(JSVAL_TO_OBJECT(aObject))->name);
+  *aName = NS_strdup(JS_GetClass(aObject.toObjectOrNull())->name);
   NS_ABORT_IF_FALSE(*aName, "NS_strdup should be infallible.");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetVisitedDependentComputedStyle(
                     nsIDOMElement *aElement, const nsAString& aPseudoElement,
                     const nsAString& aPropertyName, nsAString& aResult)
@@ -3207,18 +3207,18 @@ nsDOMWindowUtils::GetBlob(JS::Handle<JS:
 NS_IMETHODIMP
 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
                             int64_t* aResult)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  if (!JSVAL_IS_PRIMITIVE(aFile)) {
-    JSObject* obj = JSVAL_TO_OBJECT(aFile);
+  if (!aFile.isPrimitive()) {
+    JSObject* obj = aFile.toObjectOrNull();
 
     file::FileHandle* fileHandle;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FileHandle, obj, fileHandle))) {
       *aResult = fileHandle->GetFileId();
       return NS_OK;
     }
 
     nsISupports* nativeObj =
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -180,17 +180,17 @@ public:
       NS_ASSERTION(IsEmpty(), "init() on initialized string");
       nsDependentString* base = this;
       new(base) nsDependentString(chars, length);
       return true;
   }
 
   bool init(JSContext* aContext, const JS::Value &v)
   {
-      return init(aContext, JSVAL_TO_STRING(v));
+      return init(aContext, v.toString());
   }
 
   void init(JSFlatString* fstr)
   {
       MOZ_ASSERT(IsEmpty(), "init() on initialized string");
       new(this) nsDependentJSString(fstr);
   }
 
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -347,17 +347,17 @@ InterfaceObjectToString(JSContext* cx, u
     return false;
   }
 
   JS::Value v = js::GetFunctionNativeReserved(callee,
                                               TOSTRING_CLASS_RESERVED_SLOT);
   const JSClass* clasp = static_cast<const JSClass*>(v.toPrivate());
 
   v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT);
-  JSString* jsname = static_cast<JSString*>(JSVAL_TO_STRING(v));
+  JSString* jsname = static_cast<JSString*>(v.toString());
   size_t length;
   const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length);
 
   if (js::GetObjectJSClass(&args.thisv().toObject()) != clasp) {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                          JSMSG_INCOMPATIBLE_PROTO,
                          NS_ConvertUTF16toUTF8(name).get(), "toString",
                          "object");
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -512,22 +512,22 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndex)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-  NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
+  NS_ASSERTION(tmp->mHaveCachedKey || tmp->mCachedKey.isUndefined(),
                "Should have a cached key");
   NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
-               JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
+               tmp->mCachedPrimaryKey.isUndefined(),
                "Should have a cached primary key");
-  NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
+  NS_ASSERTION(tmp->mHaveCachedValue || tmp->mCachedValue.isUndefined(),
                "Should have a cached value");
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -826,24 +826,24 @@ IDBIndex::WrapObject(JSContext* aCx)
   return IDBIndexBinding::Wrap(aCx, this);
 }
 
 JS::Value
 IDBIndex::GetKeyPath(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!JSVAL_IS_VOID(mCachedKeyPath)) {
+  if (!mCachedKeyPath.isUndefined()) {
     return mCachedKeyPath;
   }
 
   aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
   ENSURE_SUCCESS(aRv, JSVAL_VOID);
 
-  if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
+  if (mCachedKeyPath.isGCThing()) {
     mozilla::HoldJSObjects(this);
     mRooted = true;
   }
 
   return mCachedKeyPath;
 }
 
 already_AddRefed<IDBRequest>
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -832,17 +832,17 @@ public:
       JS::Rooted<JS::Value> wrappedBlob(aCx);
       rv = nsContentUtils::WrapNative(aCx, domBlob, &NS_GET_IID(nsIDOMBlob),
                                       &wrappedBlob);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to wrap native!");
         return nullptr;
       }
 
-      return JSVAL_TO_OBJECT(wrappedBlob);
+      return wrappedBlob.toObjectOrNull();
     }
 
     nsCOMPtr<nsIDOMFile> domFile;
     if (aFile.mFile) {
       if (!ResolveMysteryFile(aFile.mFile, aData.name, aData.type, aData.size,
                               aData.lastModifiedDate)) {
         return nullptr;
       }
@@ -857,17 +857,17 @@ public:
     JS::Rooted<JS::Value> wrappedFile(aCx);
     rv = nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile),
                                     &wrappedFile);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to wrap native!");
       return nullptr;
     }
 
-    return JSVAL_TO_OBJECT(wrappedFile);
+    return wrappedFile.toObjectOrNull();
   }
 };
 
 
 class CreateIndexDeserializationTraits
 {
 public:
   static JSObject* CreateAndWrapFileHandle(JSContext* aCx,
@@ -1832,17 +1832,17 @@ IDBObjectStore::GetAddInfo(JSContext* aC
                            StructuredCloneWriteInfo& aCloneWriteInfo,
                            Key& aKey,
                            nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
 {
   nsresult rv;
 
   // Return DATA_ERR if a key was passed in and this objectStore uses inline
   // keys.
-  if (!JSVAL_IS_VOID(aKeyVal) && HasValidKeyPath()) {
+  if (!aKeyVal.isUndefined() && HasValidKeyPath()) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   JSAutoRequest ar(aCx);
 
   if (!HasValidKeyPath()) {
     // Out-of-line keys must be passed in.
     rv = aKey.SetFromJSVal(aCx, aKeyVal);
@@ -2610,24 +2610,24 @@ IDBObjectStore::WrapObject(JSContext* aC
   return IDBObjectStoreBinding::Wrap(aCx, this);
 }
 
 JS::Value
 IDBObjectStore::GetKeyPath(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!JSVAL_IS_VOID(mCachedKeyPath)) {
+  if (!mCachedKeyPath.isUndefined()) {
     return mCachedKeyPath;
   }
 
   aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
   ENSURE_SUCCESS(aRv, JSVAL_VOID);
 
-  if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
+  if (mCachedKeyPath.isGCThing()) {
     mozilla::HoldJSObjects(this);
     mRooted = true;
   }
 
   return mCachedKeyPath;
 }
 
 already_AddRefed<DOMStringList>
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -164,17 +164,17 @@ IDBRequest::Reset()
   mError = nullptr;
 }
 
 nsresult
 IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
-  NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
+  NS_ASSERTION(mResultVal.isUndefined(), "Should be undefined!");
 
   mHaveResultOrErrorCode = true;
 
   nsresult rv = aHelper->GetResultCode();
 
   // If the request failed then set the error code and return.
   if (NS_FAILED(rv)) {
     SetError(rv);
@@ -220,17 +220,17 @@ IDBRequest::NotifyHelperCompleted(Helper
   return rv;
 }
 
 void
 IDBRequest::NotifyHelperSentResultsToChildProcess(nsresult aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
-  NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
+  NS_ASSERTION(mResultVal.isUndefined(), "Should be undefined!");
 
   // See if our window is still valid. If not then we're going to pretend that
   // we never completed.
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return;
   }
 
   mHaveResultOrErrorCode = true;
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -650,17 +650,17 @@ NS_IMPL_RELEASE_WITH_DESTROY(IndexedData
 NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIIndexedDatabaseManager,
                         nsIObserver)
 
 NS_IMETHODIMP
 IndexedDatabaseManager::InitWindowless(JS::Handle<JS::Value> aGlobal, JSContext* aCx)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
-  JS::Rooted<JSObject*> global(aCx, JSVAL_TO_OBJECT(aGlobal));
+  JS::Rooted<JSObject*> global(aCx, aGlobal.toObjectOrNull());
   if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
     NS_WARNING("Passed object is not a global object!");
     return NS_ERROR_FAILURE;
   }
 
   bool hasIndexedDB;
   if (!JS_HasProperty(aCx, global, IDB_STR, &hasIndexedDB)) {
     return NS_ERROR_FAILURE;
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -91,17 +91,17 @@ GetJSValFromKeyPathString(JSContext* aCx
   nsresult rv = NS_OK;
   *aKeyJSVal = aValue;
 
   KeyPathTokenizer tokenizer(aKeyPathString, '.');
 
   nsString targetObjectPropName;
   JS::Rooted<JSObject*> targetObject(aCx, nullptr);
   JS::Rooted<JSObject*> obj(aCx,
-    JSVAL_IS_PRIMITIVE(aValue) ? nullptr : JSVAL_TO_OBJECT(aValue));
+    aValue.isPrimitive() ? nullptr : aValue.toObjectOrNull());
 
   while (tokenizer.hasMoreTokens()) {
     const nsDependentSubstring& token = tokenizer.nextToken();
 
     NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
 
     const jschar* keyPathChars = token.BeginReading();
     const size_t keyPathLen = token.Length();
@@ -124,20 +124,20 @@ GetJSValFromKeyPathString(JSContext* aCx
         IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         // Treat explicitly undefined as an error.
         if (intermediate == JSVAL_VOID) {
           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
         }
         if (tokenizer.hasMoreTokens()) {
           // ...and walk to it if there are more steps...
-          if (JSVAL_IS_PRIMITIVE(intermediate)) {
+          if (intermediate.isPrimitive()) {
             return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
           }
-          obj = JSVAL_TO_OBJECT(intermediate);
+          obj = intermediate.toObjectOrNull();
         }
         else {
           // ...otherwise use it as key
           *aKeyJSVal = intermediate;
         }
       }
       else {
         // If the property doesn't exist, fall into below path of starting
@@ -267,17 +267,17 @@ KeyPath::Parse(JSContext* aCx, const JS:
   JS::Rooted<JS::Value> aValue(aCx, aValue_);
   KeyPath keyPath(0);
 
   aKeyPath->SetType(NONEXISTENT);
 
   // See if this is a JS array.
   if (JS_IsArrayObject(aCx, aValue)) {
 
-    JS::Rooted<JSObject*> obj(aCx, JSVAL_TO_OBJECT(aValue));
+    JS::Rooted<JSObject*> obj(aCx, aValue.toObjectOrNull());
 
     uint32_t length;
     if (!JS_GetArrayLength(aCx, obj, &length)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!length) {
       return NS_ERROR_FAILURE;
@@ -296,17 +296,17 @@ KeyPath::Parse(JSContext* aCx, const JS:
       }
 
       if (!keyPath.AppendStringWithValidation(aCx, str)) {
         return NS_ERROR_FAILURE;
       }
     }
   }
   // Otherwise convert it to a string.
-  else if (!JSVAL_IS_NULL(aValue) && !JSVAL_IS_VOID(aValue)) {
+  else if (!aValue.isNull() && !aValue.isUndefined()) {
     JSString* jsstr;
     nsDependentJSString str;
     if (!(jsstr = JS::ToString(aCx, aValue)) ||
         !str.init(aCx, jsstr)) {
       return NS_ERROR_FAILURE;
     }
 
     keyPath.SetType(STRING);
@@ -430,17 +430,17 @@ KeyPath::ExtractOrCreateKey(JSContext* a
                                           CreateProperties, aCallback,
                                           aClosure);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (NS_FAILED(aKey.AppendItem(aCx, false, value))) {
     NS_ASSERTION(aKey.IsUnset(), "Should be unset");
-    return JSVAL_IS_VOID(value) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    return value.isUndefined() ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   aKey.FinishArray();
 
   return NS_OK;
 }
 
 void
--- a/dom/indexedDB/ipc/IndexedDBParent.cpp
+++ b/dom/indexedDB/ipc/IndexedDBParent.cpp
@@ -406,17 +406,17 @@ IndexedDBDatabaseParent::HandleRequestEv
   }
 
   AutoSafeJSContext cx;
 
   ErrorResult error;
   JS::Rooted<JS::Value> result(cx, mOpenRequest->GetResult(cx, error));
   ENSURE_SUCCESS(error, error.ErrorCode());
 
-  MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(result));
+  MOZ_ASSERT(!result.isPrimitive());
 
   IDBDatabase *database;
   rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
   if (NS_FAILED(rv)) {
     NS_WARNING("Didn't get the object we expected!");
     return rv;
   }
 
--- a/dom/network/src/TCPSocketParent.cpp
+++ b/dom/network/src/TCPSocketParent.cpp
@@ -235,18 +235,18 @@ TCPSocketParent::SendEvent(const nsAStri
       data = SendableData(arr);
 
     } else {
       nsDependentJSString name;
 
       JS::Rooted<JS::Value> val(aCx);
       if (!JS_GetProperty(aCx, obj, "name", &val)) {
         NS_ERROR("No name property on supposed error object");
-      } else if (JSVAL_IS_STRING(val)) {
-        if (!name.init(aCx, JSVAL_TO_STRING(val))) {
+      } else if (val.isString()) {
+        if (!name.init(aCx, val.toString())) {
           NS_WARNING("couldn't initialize string");
         }
       }
 
       data = TCPError(name);
     }
   } else {
     NS_ERROR("Unexpected JS value encountered");
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -376,35 +376,35 @@ NPVariantToJSVal(NPP npp, JSContext *cx,
   return JSVAL_VOID;
 }
 
 bool
 JSValToNPVariant(NPP npp, JSContext *cx, JS::Value val, NPVariant *variant)
 {
   NS_ASSERTION(npp, "Must have an NPP to wrap a jsval!");
 
-  if (JSVAL_IS_PRIMITIVE(val)) {
+  if (val.isPrimitive()) {
     if (val == JSVAL_VOID) {
       VOID_TO_NPVARIANT(*variant);
-    } else if (JSVAL_IS_NULL(val)) {
+    } else if (val.isNull()) {
       NULL_TO_NPVARIANT(*variant);
-    } else if (JSVAL_IS_BOOLEAN(val)) {
-      BOOLEAN_TO_NPVARIANT(JSVAL_TO_BOOLEAN(val), *variant);
-    } else if (JSVAL_IS_INT(val)) {
-      INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant);
-    } else if (JSVAL_IS_DOUBLE(val)) {
-      double d = JSVAL_TO_DOUBLE(val);
+    } else if (val.isBoolean()) {
+      BOOLEAN_TO_NPVARIANT(val.toBoolean(), *variant);
+    } else if (val.isInt32()) {
+      INT32_TO_NPVARIANT(val.toInt32(), *variant);
+    } else if (val.isDouble()) {
+      double d = val.toDouble();
       int i;
       if (JS_DoubleIsInt32(d, &i)) {
         INT32_TO_NPVARIANT(i, *variant);
       } else {
         DOUBLE_TO_NPVARIANT(d, *variant);
       }
-    } else if (JSVAL_IS_STRING(val)) {
-      JSString *jsstr = JSVAL_TO_STRING(val);
+    } else if (val.isString()) {
+      JSString *jsstr = val.toString();
       size_t length;
       const jschar *chars = ::JS_GetStringCharsZAndLength(cx, jsstr, &length);
       if (!chars) {
           return false;
       }
 
       nsDependentString str(chars, length);
 
@@ -430,17 +430,17 @@ JSValToNPVariant(NPP npp, JSContext *cx,
   // transplanting the plugin objects, and just do a unwrap with security
   // checks if we encounter one of them as an argument. If the unwrap fails,
   // we run with the original wrapped object, since sometimes there are
   // legitimate cases where a security wrapper ends up here (for example,
   // Location objects, which are _always_ behind security wrappers).
   JS::Rooted<JSObject*> obj(cx, val.toObjectOrNull());
   obj = js::CheckedUnwrap(obj);
   if (!obj) {
-    obj = JSVAL_TO_OBJECT(val);
+    obj = val.toObjectOrNull();
   }
 
   NPObject *npobj = nsJSObjWrapper::GetNewOrUsed(npp, cx, obj);
   if (!npobj) {
     return false;
   }
 
   // Pass over ownership of npobj to *variant
@@ -588,18 +588,18 @@ nsJSObjWrapper::NP_HasMethod(NPObject *n
   pusher.Push(cx);
   JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   AutoJSExceptionReporter reporter(cx);
 
   JS::Rooted<JS::Value> v(cx);
   bool ok = GetProperty(cx, npjsobj->mJSObj, id, &v);
 
-  return ok && !JSVAL_IS_PRIMITIVE(v) &&
-    ::JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v));
+  return ok && !v.isPrimitive() &&
+    ::JS_ObjectIsFunction(cx, v.toObjectOrNull());
 }
 
 static bool
 doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args,
          uint32_t argCount, bool ctorCall, NPVariant *result)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
@@ -896,19 +896,19 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
       JS::Rooted<JSString*> str(cx, v.toString());
       str = JS_InternJSString(cx, str);
       if (!str) {
         PR_Free(*idarray);
         return false;
       }
       id = StringToNPIdentifier(cx, str);
     } else {
-      NS_ASSERTION(JSVAL_IS_INT(v),
+      NS_ASSERTION(v.isInt32(),
                    "The element in ida must be either string or int!\n");
-      id = IntToNPIdentifier(JSVAL_TO_INT(v));
+      id = IntToNPIdentifier(v.toInt32());
     }
 
     (*idarray)[i] = id;
   }
 
   return true;
 }
 
@@ -1347,17 +1347,17 @@ CallNPMethodInternal(JSContext *cx, JS::
 
       return false;
     }
   }
 
   NPVariant v;
   VOID_TO_NPVARIANT(v);
 
-  JSObject *funobj = JSVAL_TO_OBJECT(argv[-2]);
+  JSObject *funobj = argv[-2].toObjectOrNull();
   bool ok;
   const char *msg = "Error calling method on NPObject!";
 
   if (ctorCall) {
     // construct a new NPObject based on the NPClass in npobj. Fail if
     // no construct method is available.
 
     if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) &&
@@ -1493,28 +1493,28 @@ NPObjWrapper_newEnumerate(JSContext *cx,
     *statep = PRIVATE_TO_JSVAL(state);
     if (idp) {
       *idp = INT_TO_JSID(length);
     }
 
     break;
 
   case JSENUMERATE_NEXT:
-    state = (NPObjectEnumerateState *)JSVAL_TO_PRIVATE(*statep);
+    state = (NPObjectEnumerateState *)statep->toPrivate();
     enum_value = state->value;
     length = state->length;
     if (state->index != length) {
       *idp = NPIdentifierToJSId(enum_value[state->index++]);
       return true;
     }
 
     // FALL THROUGH
 
   case JSENUMERATE_DESTROY:
-    state = (NPObjectEnumerateState *)JSVAL_TO_PRIVATE(*statep);
+    state = (NPObjectEnumerateState *)statep->toPrivate();
     if (state->value)
       PR_Free(state->value);
     delete state;
     *statep = JSVAL_NULL;
 
     break;
   }
 
@@ -1589,20 +1589,20 @@ NPObjWrapper_Convert(JSContext *cx, JS::
   // specifically java.lang.Integer.  The Integer class has static valueOf
   // methods, none of which are nullary, so the JS-reflected method will behave
   // poorly when called with no arguments.  We work around this problem by
   // giving plugins a [[DefaultValue]] which uses only toString and not valueOf.
 
   JS::Rooted<JS::Value> v(cx, JSVAL_VOID);
   if (!JS_GetProperty(cx, obj, "toString", &v))
     return false;
-  if (!JSVAL_IS_PRIMITIVE(v) && JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(v))) {
+  if (!v.isPrimitive() && JS_ObjectIsCallable(cx, v.toObjectOrNull())) {
     if (!JS_CallFunctionValue(cx, obj, v, JS::HandleValueArray::empty(), vp))
       return false;
-    if (JSVAL_IS_PRIMITIVE(vp))
+    if (vp.isPrimitive())
       return true;
   }
 
   JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
                        JS_GetClass(obj)->name,
                        hint == JSTYPE_VOID
                        ? "primitive type"
                        : hint == JSTYPE_NUMBER
@@ -2093,17 +2093,17 @@ NPObjectMember_Trace(JSTracer *trc, JSOb
   NPObjectMemberPrivate *memberPrivate =
     (NPObjectMemberPrivate *)::JS_GetPrivate(obj);
   if (!memberPrivate)
     return;
 
   // Our NPIdentifier is not always interned, so we must root it explicitly.
   JS_CallHeapIdTracer(trc, &memberPrivate->methodName, "NPObjectMemberPrivate.methodName");
 
-  if (!JSVAL_IS_PRIMITIVE(memberPrivate->fieldValue)) {
+  if (!memberPrivate->fieldValue.isPrimitive()) {
     JS_CallHeapValueTracer(trc, &memberPrivate->fieldValue,
                            "NPObject Member => fieldValue");
   }
 
   // There's no strong reference from our private data to the
   // NPObject, so make sure to mark the NPObject wrapper to keep the
   // NPObject alive as long as this NPObjectMember is alive.
   if (memberPrivate->npobjWrapper) {
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -120,19 +120,19 @@ public:
   NS_DECL_ISUPPORTS
 
   AudioChannelVolInitCallback() {}
 
   NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
   {
     nsCOMPtr<nsIAudioManager> audioManager =
       do_GetService(NS_AUDIOMANAGER_CONTRACTID);
-    NS_ENSURE_TRUE(JSVAL_IS_INT(aResult), NS_OK);
+    NS_ENSURE_TRUE(aResult.isInt32(), NS_OK);
 
-    int32_t volIndex = JSVAL_TO_INT(aResult);
+    int32_t volIndex = aResult.toInt32();
     if (aName.EqualsLiteral("audio.volume.content")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Content,
                                           volIndex);
     } else if (aName.EqualsLiteral("audio.volume.notification")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Notification,
                                           volIndex);
     } else if (aName.EqualsLiteral("audio.volume.alarm")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Alarm,
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -38,18 +38,18 @@ class SettingsServiceCallback MOZ_FINAL 
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   SettingsServiceCallback() {}
 
   NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
   {
-    if (JSVAL_IS_INT(aResult)) {
-      int32_t mode = JSVAL_TO_INT(aResult);
+    if (aResult.isInt32()) {
+      int32_t mode = aResult.toInt32();
       SetAutoMounterMode(mode);
     }
     return NS_OK;
   }
 
   NS_IMETHOD HandleError(const nsAString& aName)
   {
     ERR("SettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get());
@@ -64,18 +64,18 @@ class CheckVolumeSettingsCallback MOZ_FI
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   CheckVolumeSettingsCallback(const nsACString& aVolumeName)
   : mVolumeName(aVolumeName) {}
 
   NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
   {
-    if (JSVAL_IS_BOOLEAN(aResult)) {
-      bool isSharingEnabled = JSVAL_TO_BOOLEAN(aResult);
+    if (aResult.isBoolean()) {
+      bool isSharingEnabled = aResult.toBoolean();
       SetAutoMounterSharingMode(mVolumeName, isSharingEnabled);
     }
     return NS_OK;
   }
 
   NS_IMETHOD HandleError(const nsAString& aName)
   {
     ERR("CheckVolumeSettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get());
--- a/dom/workers/ChromeWorkerScope.cpp
+++ b/dom/workers/ChromeWorkerScope.cpp
@@ -58,16 +58,16 @@ DefineChromeWorkerFunctions(JSContext* a
         !JS_GetProperty(aCx, aGlobal, "ctypes", &ctypes)) {
       return false;
     }
 
     static JSCTypesCallbacks callbacks = {
       UnicodeToNative
     };
 
-    JS_SetCTypesCallbacks(JSVAL_TO_OBJECT(ctypes), &callbacks);
+    JS_SetCTypesCallbacks(ctypes.toObjectOrNull(), &callbacks);
   }
 #endif // BUILD_CTYPES
 
   return true;
 }
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -1155,17 +1155,17 @@ EventRunnable::PreDispatch(JSContext* aC
     if (mResponseText.IsVoid()) {
       mResponse = JSVAL_NULL;
     }
   }
   else {
     JS::Rooted<JS::Value> response(aCx);
     mResponseResult = xhr->GetResponse(aCx, &response);
     if (NS_SUCCEEDED(mResponseResult)) {
-      if (JSVAL_IS_UNIVERSAL(response)) {
+      if (!response.isGCThing()) {
         mResponse = response;
       }
       else {
         // Anything subject to GC must be cloned.
         JSStructuredCloneCallbacks* callbacks =
           aWorkerPrivate->IsChromeWorker() ?
           ChromeWorkerStructuredCloneCallbacks(true) :
           WorkerStructuredCloneCallbacks(true);
@@ -1251,26 +1251,26 @@ EventRunnable::WorkerRun(JSContext* aCx,
 
   nsAutoPtr<XMLHttpRequest::StateData> state(new XMLHttpRequest::StateData());
   StateDataAutoRooter rooter(aCx, state);
 
   state->mResponseTextResult = mResponseTextResult;
   state->mResponseText = mResponseText;
 
   if (NS_SUCCEEDED(mResponseTextResult)) {
-    MOZ_ASSERT(JSVAL_IS_VOID(mResponse) || JSVAL_IS_NULL(mResponse));
+    MOZ_ASSERT(mResponse.isUndefined() || mResponse.isNull());
     state->mResponseResult = mResponseTextResult;
     state->mResponse = mResponse;
   }
   else {
     state->mResponseResult = mResponseResult;
 
     if (NS_SUCCEEDED(mResponseResult)) {
       if (mResponseBuffer.data()) {
-        MOZ_ASSERT(JSVAL_IS_VOID(mResponse));
+        MOZ_ASSERT(mResponse.isUndefined());
 
         JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer));
 
         JSStructuredCloneCallbacks* callbacks =
           aWorkerPrivate->IsChromeWorker() ?
           ChromeWorkerStructuredCloneCallbacks(false) :
           WorkerStructuredCloneCallbacks(false);
 
@@ -2253,17 +2253,17 @@ XMLHttpRequest::SetResponseType(XMLHttpR
 
   mResponseType = ConvertStringToResponseType(acceptedResponseTypeString);
 }
 
 jsval
 XMLHttpRequest::GetResponse(JSContext* /* unused */, ErrorResult& aRv)
 {
   if (NS_SUCCEEDED(mStateData.mResponseTextResult) &&
-      JSVAL_IS_VOID(mStateData.mResponse)) {
+      mStateData.mResponse.isUndefined()) {
     MOZ_ASSERT(mStateData.mResponseText.Length());
     MOZ_ASSERT(NS_SUCCEEDED(mStateData.mResponseResult));
 
     JSString* str =
       JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(),
                           mStateData.mResponseText.get(),
                           mStateData.mResponseText.Length());
     if (!str) {
@@ -2284,12 +2284,12 @@ XMLHttpRequest::GetResponseText(nsAStrin
   aRv = mStateData.mResponseTextResult;
   aResponseText = mStateData.mResponseText;
 }
 
 void
 XMLHttpRequest::UpdateState(const StateData& aStateData)
 {
   mStateData = aStateData;
-  if (JSVAL_IS_GCTHING(mStateData.mResponse)) {
+  if (mStateData.mResponse.isGCThing()) {
     mozilla::HoldJSObjects(this);
   }
 }
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -775,17 +775,17 @@ nsXBLBinding::ChangeDocument(nsIDocument
               static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(proto));
             if (!docInfo) {
               // Not the proto we seek
               continue;
             }
 
             JS::Value protoBinding = ::JS_GetReservedSlot(proto, 0);
 
-            if (JSVAL_TO_PRIVATE(protoBinding) != mPrototypeBinding) {
+            if (protoBinding.toPrivate() != mPrototypeBinding) {
               // Not the right binding
               continue;
             }
 
             // Alright!  This is the right prototype.  Pull it out of the
             // proto chain.
             JS::Rooted<JSObject*> grandProto(cx);
             if (!JS_GetPrototype(cx, proto, &grandProto)) {
--- a/gfx/skia/trunk/src/xml/SkJS.cpp
+++ b/gfx/skia/trunk/src/xml/SkJS.cpp
@@ -105,25 +105,25 @@ global_resolve(JSContext *cx, JSObject *
          * Do this expensive hack only for unoptimized Unix builds, which are
          * not used for benchmarking.
          */
         char *path, *comp, *full;
         const char *name;
         JSBool ok, found;
         JSFunction *fun;
 
-        if (!JSVAL_IS_STRING(id))
+        if (!id.isString())
             return JS_TRUE;
         path = getenv("PATH");
         if (!path)
             return JS_TRUE;
         path = JS_strdup(cx, path);
         if (!path)
             return JS_FALSE;
-        name = JS_GetStringBytes(JSVAL_TO_STRING(id));
+        name = JS_GetStringBytes(id.toString());
         ok = JS_TRUE;
         for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) {
             if (*comp != '\0') {
                 full = JS_smprintf("%s/%s", comp, name);
                 if (!full) {
                     JS_ReportOutOfMemory(cx);
                     ok = JS_FALSE;
                     break;
--- a/gfx/skia/trunk/src/xml/SkJSDisplayable.cpp
+++ b/gfx/skia/trunk/src/xml/SkJSDisplayable.cpp
@@ -213,24 +213,24 @@ static void GenerateTables() {
 
 void SkJSDisplayable::Destructor(JSContext *cx, JSObject *obj) {
     delete (SkJSDisplayable*) JS_GetPrivate(cx, obj);
 }
 
 JSBool SkJSDisplayable::GetProperty(JSContext *cx, JSObject *obj, jsval id,
                                  jsval *vp)
 {
-    if (JSVAL_IS_INT(id) == 0)
+    if (id.isInt32() == 0)
         return JS_TRUE;
     SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj);
     SkDisplayable* displayable = p->fDisplayable;
     SkDisplayTypes displayableType = displayable->getType();
     int members;
     const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members);
-    int idIndex = JSVAL_TO_INT(id);
+    int idIndex = id.toInt32();
     SkASSERT(idIndex >= 0 && idIndex < members);
     info = &info[idIndex];
     SkDisplayTypes infoType = (SkDisplayTypes) info->fType;
     SkScalar scalar = 0;
     S32 s32 = 0;
     SkString* string= NULL;
     JSString *str;
     if (infoType == SkType_MemberProperty) {
@@ -285,46 +285,46 @@ JSBool SkJSDisplayable::GetProperty(JSCo
             break;
         default:
             SkASSERT(0); // !!! unimplemented
     }
     return JS_TRUE;
 }
 
 JSBool SkJSDisplayable::SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
-    if (JSVAL_IS_INT(id) == 0)
+    if (id.isInt32() == 0)
         return JS_TRUE;
     SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj);
     SkDisplayable* displayable = p->fDisplayable;
     SkDisplayTypes displayableType = displayable->getType();
     int members;
     const SkMemberInfo* info = SkDisplayType::GetMembers(NULL /* fMaker */, displayableType, &members);
-    int idIndex = JSVAL_TO_INT(id);
+    int idIndex = id.toInt32();
     SkASSERT(idIndex >= 0 && idIndex < members);
     info = &info[idIndex];
     SkDisplayTypes infoType = info->getType();
     SkScalar scalar = 0;
     S32 s32 = 0;
     SkString string;
     JSString* str;
     jsval value = *vp;
     switch (infoType) {
         case SkType_Boolean:
-            s32 = JSVAL_TO_BOOLEAN(value);
+            s32 = value.toBoolean();
             break;
         case SkType_Color:
         case SkType_S32:
-            s32 = JSVAL_TO_INT(value);
+            s32 = value.toInt32();
             break;
         case SkType_Scalar:
-            if (JSVAL_IS_INT(value))
-                scalar = SkIntToScalar(JSVAL_TO_INT(value));
+            if (value.isInt32())
+                scalar = SkIntToScalar(value.toInt32());
             else {
-                SkASSERT(JSVAL_IS_DOUBLE(value));
-                scalar = (float) *(double*) JSVAL_TO_DOUBLE(value);
+                SkASSERT(value.isDouble());
+                scalar = (float) *(double*) value.toDouble();
             }
             break;
         case SkType_String:
             str = JS_ValueToString(cx, value);
             string.set(JS_GetStringBytes(str));
             break;
         default:
             SkASSERT(0); // !!! unimplemented
--- a/ipc/nfc/Nfc.cpp
+++ b/ipc/nfc/Nfc.cpp
@@ -85,26 +85,26 @@ PostToNFC(JSContext* aCx,
         return false;
     }
 
     JS::Value v = args[0];
 
     JSAutoByteString abs;
     void* data;
     size_t size;
-    if (JSVAL_IS_STRING(v)) {
+    if (v.isString()) {
         JS::Rooted<JSString*> str(aCx, v.toString());
         if (!abs.encodeUtf8(aCx, str)) {
             return false;
         }
 
         data = abs.ptr();
         size = abs.length();
-    } else if (!JSVAL_IS_PRIMITIVE(v)) {
-        JSObject* obj = JSVAL_TO_OBJECT(v);
+    } else if (!v.isPrimitive()) {
+        JSObject* obj = v.toObjectOrNull();
         if (!JS_IsTypedArrayObject(obj)) {
             JS_ReportError(aCx, "Object passed in wasn't a typed array");
             return false;
         }
 
         uint32_t type = JS_GetArrayBufferViewType(obj);
         if (type != js::ArrayBufferView::TYPE_INT8 &&
             type != js::ArrayBufferView::TYPE_UINT8 &&
--- a/ipc/ril/Ril.cpp
+++ b/ipc/ril/Ril.cpp
@@ -90,26 +90,26 @@ PostToRIL(JSContext *aCx,
     }
 
     int clientId = args[0].toInt32();
     JS::Value v = args[1];
 
     JSAutoByteString abs;
     void *data;
     size_t size;
-    if (JSVAL_IS_STRING(v)) {
+    if (v.isString()) {
         JS::Rooted<JSString*> str(aCx, v.toString());
         if (!abs.encodeUtf8(aCx, str)) {
             return false;
         }
 
         data = abs.ptr();
         size = abs.length();
-    } else if (!JSVAL_IS_PRIMITIVE(v)) {
-        JSObject *obj = JSVAL_TO_OBJECT(v);
+    } else if (!v.isPrimitive()) {
+        JSObject *obj = v.toObjectOrNull();
         if (!JS_IsTypedArrayObject(obj)) {
             JS_ReportError(aCx, "Object passed in wasn't a typed array");
             return false;
         }
 
         uint32_t type = JS_GetArrayBufferViewType(obj);
         if (type != js::ArrayBufferView::TYPE_INT8 &&
             type != js::ArrayBufferView::TYPE_UINT8 &&
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -205,17 +205,17 @@ JavaScriptShared::toVariant(JSContext *c
         nsDependentJSString dep;
         if (!dep.init(cx, from))
             return false;
         *to = dep;
         return true;
       }
 
       case JSTYPE_NUMBER:
-        if (JSVAL_IS_INT(from))
+        if (from.isInt32())
             *to = double(from.toInt32());
         else
             *to = from.toDouble();
         return true;
 
       case JSTYPE_BOOLEAN:
         *to = from.toBoolean();
         return true;
--- a/js/jsd/jsd_obj.cpp
+++ b/js/jsd/jsd_obj.cpp
@@ -217,17 +217,17 @@ jsd_GetJSDObjectForJSObject(JSDContext* 
     jsdobj = (JSDObject*) JS_HashTableLookup(jsdc->objectsTable, jsobj);
     JSD_UNLOCK_OBJECTS(jsdc);
     return jsdobj;
 }
 
 JSDObject*
 jsd_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return jsd_GetJSDObjectForJSObject(jsdc, JSVAL_TO_OBJECT(jsdval->val));
+    return jsd_GetJSDObjectForJSObject(jsdc, jsdval->val.toObjectOrNull());
 }
 
 JSDValue*
 jsd_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj)
 {
     return jsd_NewValue(jsdc, OBJECT_TO_JSVAL(jsdobj->obj));
 }
 
--- a/js/jsd/jsd_scpt.cpp
+++ b/js/jsd/jsd_scpt.cpp
@@ -701,17 +701,17 @@ static bool
 }
 
 
 JSTrapStatus
 jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval,
                 jsval closure)
 {
     JS::RootedScript script(cx, script_);
-    JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
+    JSDExecHook* jsdhook = (JSDExecHook*) closure.toPrivate();
     JSD_ExecutionHookProc hook;
     void* hookData;
     JSDContext*  jsdc;
 
     JSD_LOCK();
 
     if( nullptr == (jsdc = jsd_JSDContextForJSContext(cx)) ||
         ! _isActiveHook(jsdc, script, jsdhook) )
--- a/js/jsd/jsd_step.cpp
+++ b/js/jsd/jsd_step.cpp
@@ -94,17 +94,17 @@ bool
          */
         return hookresult;
     }
 
     if (before && isConstructing) {
         JS::RootedValue newObj(cx);
         if (!frame.getThisValue(cx, &newObj))
             return false;
-        jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), frame);
+        jsd_Constructing(jsdc, cx, newObj.toObjectOrNull(), frame);
     }
 
     jsscript = frame.script();
     if (jsscript)
     {
         JSD_LOCK_SCRIPTS(jsdc);
         jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, frame);
         JSD_UNLOCK_SCRIPTS(jsdc);
--- a/js/jsd/jsd_val.cpp
+++ b/js/jsd/jsd_val.cpp
@@ -19,17 +19,17 @@ using mozilla::AutoSafeJSContext;
 #ifdef DEBUG
 void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
 {
     MOZ_ASSERT(jsdval);
     MOZ_ASSERT(jsdval->nref > 0);
     if(!JS_CLIST_IS_EMPTY(&jsdval->props))
     {
         MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS));
-        MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val));
+        MOZ_ASSERT(!jsdval->val.isPrimitive());
     }
 
     if(jsdval->proto)
     {
         MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
         MOZ_ASSERT(jsdval->proto->nref > 0);
     }
     if(jsdval->parent)
@@ -55,173 +55,173 @@ void JSD_ASSERT_VALID_PROPERTY(JSDProper
         MOZ_ASSERT(jsdprop->alias->nref > 0);
 }
 #endif
 
 
 bool
 jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return !JSVAL_IS_PRIMITIVE(jsdval->val) || JSVAL_IS_NULL(jsdval->val);
+    return !jsdval->val.isPrimitive() || jsdval->val.isNull();
 }
 
 bool
 jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_NUMBER(jsdval->val);
+    return jsdval->val.isNumber();
 }
 
 bool
 jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_INT(jsdval->val);
+    return jsdval->val.isInt32();
 }
 
 bool
 jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_DOUBLE(jsdval->val);
+    return jsdval->val.isDouble();
 }
 
 bool
 jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_STRING(jsdval->val);
+    return jsdval->val.isString();
 }
 
 bool
 jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_BOOLEAN(jsdval->val);
+    return jsdval->val.isBoolean();
 }
 
 bool
 jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_NULL(jsdval->val);
+    return jsdval->val.isNull();
 }
 
 bool
 jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_VOID(jsdval->val);
+    return jsdval->val.isUndefined();
 }
 
 bool
 jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
 {
-    return JSVAL_IS_PRIMITIVE(jsdval->val);
+    return jsdval->val.isPrimitive();
 }
 
 bool
 jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx; // NB: Actually unused.
-    return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
-           JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(jsdval->val));
+    return !jsdval->val.isPrimitive() &&
+           JS_ObjectIsCallable(cx, jsdval->val.toObjectOrNull());
 }
 
 bool
 jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx;
     JS::RootedFunction fun(cx);
 
     if(jsd_IsValueFunction(jsdc, jsdval))
     {
-        JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val));
+        JSAutoCompartment ac(cx, jsdval->val.toObjectOrNull());
         AutoSaveExceptionState as(cx);
         bool ok = false;
         fun = JSD_GetValueFunction(jsdc, jsdval);
         if(fun)
             ok = JS_GetFunctionScript(cx, fun) ? false : true;
         MOZ_ASSERT(fun);
         return ok;
     }
-    return !JSVAL_IS_PRIMITIVE(jsdval->val);
+    return !jsdval->val.isPrimitive();
 }
 
 /***************************************************************************/
 
 bool
 jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
 {
     jsval val = jsdval->val;
-    if(!JSVAL_IS_BOOLEAN(val))
+    if(!val.isBoolean())
         return false;
-    return JSVAL_TO_BOOLEAN(val);
+    return val.toBoolean();
 }
 
 int32_t
 jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
 {
     jsval val = jsdval->val;
-    if(!JSVAL_IS_INT(val))
+    if(!val.isInt32())
         return 0;
-    return JSVAL_TO_INT(val);
+    return val.toInt32();
 }
 
 double
 jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
 {
-    if(!JSVAL_IS_DOUBLE(jsdval->val))
+    if(!jsdval->val.isDouble())
         return 0;
-    return JSVAL_TO_DOUBLE(jsdval->val);
+    return jsdval->val.toDouble();
 }
 
 JSString*
 jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx;
     JS::RootedValue stringval(cx);
     JS::RootedString string(cx);
     JS::RootedObject scopeObj(cx);
 
     if(jsdval->string)
         return jsdval->string;
 
     /* Reuse the string without copying or re-rooting it */
-    if(JSVAL_IS_STRING(jsdval->val)) {
-        jsdval->string = JSVAL_TO_STRING(jsdval->val);
+    if(jsdval->val.isString()) {
+        jsdval->string = jsdval->val.toString();
         return jsdval->string;
     }
 
     /* Objects call JS_ValueToString in their own compartment. */
-    scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob;
+    scopeObj = !jsdval->val.isPrimitive() ? jsdval->val.toObjectOrNull() : jsdc->glob;
     {
         JSAutoCompartment ac(cx, scopeObj);
         AutoSaveExceptionState as(cx);
         JS::RootedValue v(cx, jsdval->val);
         string = JS::ToString(cx, v);
     }
 
     JSAutoCompartment ac2(cx, jsdc->glob);
     if(string) {
         stringval = STRING_TO_JSVAL(string);
     }
     if(!string || !JS_WrapValue(cx, &stringval)) {
         return nullptr;
     }
 
-    jsdval->string = JSVAL_TO_STRING(stringval);
+    jsdval->string = stringval.toString();
     if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
         jsdval->string = nullptr;
 
     return jsdval->string;
 }
 
 JSString*
 jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx;
     JS::RootedFunction fun(cx);
 
     if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
     {
-        JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val));
+        JSAutoCompartment ac(cx, jsdval->val.toObjectOrNull());
         AutoSaveExceptionState as(cx);
         fun = JSD_GetValueFunction(jsdc, jsdval);
         if(!fun)
             return nullptr;
         jsdval->funName = JS_GetFunctionId(fun);
 
         /* For compatibility we return "anonymous", not an empty string here. */
         if (!jsdval->funName)
@@ -242,23 +242,23 @@ jsd_NewValue(JSDContext* jsdc, jsval val
 {
     JS::RootedValue val(jsdc->jsrt, value);
     AutoSafeJSContext cx;
     JSDValue* jsdval;
 
     if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
         return nullptr;
 
-    if(JSVAL_IS_GCTHING(val))
+    if(val.isGCThing())
     {
         bool ok;
         JSAutoCompartment ac(cx, jsdc->glob);
 
         ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
-        if(ok && JSVAL_IS_STRING(val)) {
+        if(ok && val.isString()) {
             if(!JS_WrapValue(cx, &val)) {
                 ok = false;
             }
         }
 
         if(!ok)
         {
             free(jsdval);
@@ -274,17 +274,17 @@ jsd_NewValue(JSDContext* jsdc, jsval val
 
 void
 jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
 {
     MOZ_ASSERT(jsdval->nref > 0);
     if(0 == --jsdval->nref)
     {
         jsd_RefreshValue(jsdc, jsdval);
-        if(JSVAL_IS_GCTHING(jsdval->val))
+        if(jsdval->val.isGCThing())
         {
             AutoSafeJSContext cx;
             JSAutoCompartment ac(cx, jsdc->glob);
             JS::RemoveValueRoot(cx, &jsdval->val);
         }
         free(jsdval);
     }
 }
@@ -357,22 +357,22 @@ static bool _buildProps(JSDContext* jsdc
 {
     AutoSafeJSContext cx;
     JS::RootedObject obj(cx);
     JSPropertyDescArray pda;
     unsigned i;
 
     MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
     MOZ_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
-    MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val));
+    MOZ_ASSERT(!jsdval->val.isPrimitive());
 
-    if(JSVAL_IS_PRIMITIVE(jsdval->val))
+    if(jsdval->val.isPrimitive())
         return false;
 
-    obj = JSVAL_TO_OBJECT(jsdval->val);
+    obj = jsdval->val.toObjectOrNull();
 
     JSAutoCompartment ac(cx, obj);
 
     if(!JS_GetPropertyDescArray(cx, obj, &pda))
     {
         return false;
     }
 
@@ -404,17 +404,17 @@ static bool _buildProps(JSDContext* jsdc
 
 void
 jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx;
     if(jsdval->string)
     {
         /* if the jsval is a string, then we didn't need to root the string */
-        if(!JSVAL_IS_STRING(jsdval->val))
+        if(!jsdval->val.isString())
         {
             JSAutoCompartment ac(cx, jsdc->glob);
             JS::RemoveStringRoot(cx, &jsdval->string);
         }
         jsdval->string = nullptr;
     }
 
     jsdval->funName = nullptr;
@@ -500,17 +500,17 @@ jsd_GetValueProperty(JSDContext* jsdc, J
         JSD_DropProperty(jsdc, jsdprop);
     }
     /* Not found in property list, look it up explicitly */
 
     nameval = STRING_TO_JSVAL(name);
     if(!JS_ValueToId(cx, nameval, &nameid))
         return nullptr;
 
-    if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
+    if(!(obj = jsdval->val.toObjectOrNull()))
         return nullptr;
 
     JS::Rooted<JSPropertyDescriptor> desc(cx);
     {
         JSAutoCompartment ac(cx, obj);
         JS::RootedId id(cx, nameid);
 
         if(!JS_WrapId(cx, &id))
@@ -562,20 +562,20 @@ jsd_GetValueProperty(JSDContext* jsdc, J
 JSFunction*
 jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx;
 
     JS::RootedObject obj(cx);
     JS::RootedFunction fun(cx);
 
-    if (JSVAL_IS_PRIMITIVE(jsdval->val))
+    if (jsdval->val.isPrimitive())
         return nullptr;
 
-    obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val));
+    obj = js::UncheckedUnwrap(jsdval->val.toObjectOrNull());
     JSAutoCompartment ac(cx, obj);
     JS::RootedValue funval(cx, JS::ObjectValue(*obj));
     fun = JS_ValueToFunction(cx, funval);
 
     return fun;
 }
 
 JSDValue*
@@ -583,19 +583,19 @@ jsd_GetValuePrototype(JSDContext* jsdc, 
 {
     AutoSafeJSContext cx;
     if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
     {
         JS::RootedObject obj(cx);
         JS::RootedObject proto(cx);
         MOZ_ASSERT(!jsdval->proto);
         SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
-        if(JSVAL_IS_PRIMITIVE(jsdval->val))
+        if(jsdval->val.isPrimitive())
             return nullptr;
-        obj = JSVAL_TO_OBJECT(jsdval->val);
+        obj = jsdval->val.toObjectOrNull();
         if(!JS_GetPrototype(cx, obj, &proto))
             return nullptr;
         if(!proto)
             return nullptr;
         jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
     }
     if(jsdval->proto)
         jsdval->proto->nref++;
@@ -607,19 +607,19 @@ jsd_GetValueParent(JSDContext* jsdc, JSD
 {
     if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
     {
         AutoSafeJSContext cx;
         JS::RootedObject obj(cx);
         JS::RootedObject parent(cx);
         MOZ_ASSERT(!jsdval->parent);
         SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
-        if(JSVAL_IS_PRIMITIVE(jsdval->val))
+        if(jsdval->val.isPrimitive())
             return nullptr;
-        obj = JSVAL_TO_OBJECT(jsdval->val);
+        obj = jsdval->val.toObjectOrNull();
         {
             JSAutoCompartment ac(cx, obj);
             parent = JS_GetParentOrScopeChain(cx, obj);
         }
         if(!parent)
             return nullptr;
         jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
     }
@@ -634,19 +634,19 @@ jsd_GetValueConstructor(JSDContext* jsdc
     if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
     {
         AutoSafeJSContext cx;
         JS::RootedObject obj(cx);
         JS::RootedObject proto(cx);
         JS::RootedObject ctor(cx);
         MOZ_ASSERT(!jsdval->ctor);
         SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
-        if(JSVAL_IS_PRIMITIVE(jsdval->val))
+        if(jsdval->val.isPrimitive())
             return nullptr;
-        obj = JSVAL_TO_OBJECT(jsdval->val);
+        obj = jsdval->val.toObjectOrNull();
         if(!JS_GetPrototype(cx, obj, &proto))
             return nullptr;
         if(!proto)
             return nullptr;
         {
             JSAutoCompartment ac(cx, obj);
             ctor = JS_GetConstructor(cx, proto);
         }
@@ -658,19 +658,19 @@ jsd_GetValueConstructor(JSDContext* jsdc
         jsdval->ctor->nref++;
     return jsdval->ctor;
 }
 
 const char*
 jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
 {
     jsval val = jsdval->val;
-    if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val))
+    if(!jsdval->className && !val.isPrimitive())
     {
-        JS::RootedObject obj(jsdc->jsrt, JSVAL_TO_OBJECT(val));
+        JS::RootedObject obj(jsdc->jsrt, val.toObjectOrNull());
         AutoSafeJSContext cx;
         JSAutoCompartment ac(cx, obj);
         jsdval->className = JS_GetDebugClassName(obj);
     }
     return jsdval->className;
 }
 
 JSDScript*
@@ -680,17 +680,17 @@ jsd_GetScriptForValue(JSDContext* jsdc, 
     JS::RootedValue val(cx, jsdval->val);
     JS::RootedScript script(cx);
     JSDScript* jsdscript;
 
     if (!jsd_IsValueFunction(jsdc, jsdval))
         return nullptr;
 
     {
-        JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(val));
+        JSAutoCompartment ac(cx, val.toObjectOrNull());
         AutoSaveExceptionState as(cx);
         JS::RootedFunction fun(cx, JSD_GetValueFunction(jsdc, jsdval));
         if (fun)
             script = JS_GetFunctionScript(cx, fun);
     }
 
     if (!script)
         return nullptr;
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -2153,31 +2153,31 @@ jsdValue::GetIsPrimitive (bool *_rval)
 }
 
 NS_IMETHODIMP
 jsdValue::GetJsType (uint32_t *_rval)
 {
     ASSERT_VALID_EPHEMERAL;
     JS::RootedValue val(JSD_GetJSRuntime(mCx), JSD_GetValueWrappedJSVal (mCx, mValue));
 
-    if (JSVAL_IS_NULL(val))
+    if (val.isNull())
         *_rval = TYPE_NULL;
-    else if (JSVAL_IS_BOOLEAN(val))
+    else if (val.isBoolean())
         *_rval = TYPE_BOOLEAN;
-    else if (JSVAL_IS_DOUBLE(val))
+    else if (val.isDouble())
         *_rval = TYPE_DOUBLE;
-    else if (JSVAL_IS_INT(val))
+    else if (val.isInt32())
         *_rval = TYPE_INT;
-    else if (JSVAL_IS_STRING(val))
+    else if (val.isString())
         *_rval = TYPE_STRING;
-    else if (JSVAL_IS_VOID(val))
+    else if (val.isUndefined())
         *_rval = TYPE_VOID;
     else if (JSD_IsValueFunction (mCx, mValue))
         *_rval = TYPE_FUNCTION;
-    else if (!JSVAL_IS_PRIMITIVE(val))
+    else if (!val.isPrimitive())
         *_rval = TYPE_OBJECT;
     else
         NS_ASSERTION (0, "Value has no discernible type.");
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -383,26 +383,26 @@ CallArgsFromSp(unsigned argc, Value *sp)
 
 /*
  * Macros to hide interpreter stack layout details from a JSNative using its
  * JS::Value *vp parameter.  DO NOT USE THESE!  Instead use JS::CallArgs and
  * friends, above.  These macros will be removed when we change JSNative to
  * take a const JS::CallArgs&.
  */
 
-#define JS_THIS_OBJECT(cx,vp)   (JSVAL_TO_OBJECT(JS_THIS(cx,vp)))
+#define JS_THIS_OBJECT(cx,vp)   (JS_THIS(cx,vp).toObjectOrNull())
 
 /*
  * Note: if this method returns null, an error has occurred and must be
  * propagated or caught.
  */
 MOZ_ALWAYS_INLINE JS::Value
 JS_THIS(JSContext *cx, JS::Value *vp)
 {
-    return JSVAL_IS_PRIMITIVE(vp[1]) ? JS_ComputeThis(cx, vp) : vp[1];
+    return vp[1].isPrimitive() ? JS_ComputeThis(cx, vp) : vp[1];
 }
 
 /*
  * |this| is passed to functions in ES5 without change.  Functions themselves
  * do any post-processing they desire to box |this|, compute the global object,
  * &c.  This macro retrieves a function's unboxed |this| value.
  *
  * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT,
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -580,17 +580,17 @@ JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 
 static inline bool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
 {
     return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
 }
 
 static inline bool
-JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b)
+JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b)
 {
     return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b));
 }
 
 static inline jsval_layout
 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
 {
     jsval_layout l;
@@ -816,17 +816,17 @@ JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l
 
 static inline bool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
 {
     return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
 }
 
 static inline bool
-JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b)
+JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b)
 {
     return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
 }
 
 static inline jsval_layout
 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
 {
     jsval_layout l;
@@ -909,21 +909,17 @@ CanonicalizeNaN(double d)
  *   creating and checking for magic values, it is possible to assert, at
  *   runtime, that only magic values with the expected reason flow through a
  *   particular value. For example, if cx->exception has a magic value, the
  *   reason must be JS_GENERATOR_CLOSING.
  *
  * - The JS::Value operations are preferred.  The JSVAL_* operations remain for
  *   compatibility; they may be removed at some point.  These operations mostly
  *   provide similar functionality.  But there are a few key differences.  One
- *   is that JS::Value gives null a separate type. Thus
- *
- *           JSVAL_IS_OBJECT(v) === v.isObjectOrNull()
- *       !JSVAL_IS_PRIMITIVE(v) === v.isObject()
- *
+ *   is that JS::Value gives null a separate type.
  *   Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
  *   Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
  *   JSObject&.)  A convenience member Value::setObjectOrNull is provided.
  *
  * - JSVAL_VOID is the same as the singleton value of the Undefined type.
  *
  * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
  *   32-bit user code should avoid copying jsval/JS::Value as much as possible,
@@ -1079,21 +1075,21 @@ class Value
         return JSVAL_IS_GCTHING_IMPL(data);
     }
 
     bool isBoolean() const {
         return JSVAL_IS_BOOLEAN_IMPL(data);
     }
 
     bool isTrue() const {
-        return JSVAL_IS_SPECIFIC_BOOLEAN(data, true);
+        return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, true);
     }
 
     bool isFalse() const {
-        return JSVAL_IS_SPECIFIC_BOOLEAN(data, false);
+        return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, false);
     }
 
     bool isMagic() const {
         return JSVAL_IS_MAGIC_IMPL(data);
     }
 
     bool isMagic(JSWhyMagic why) const {
         MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why);
@@ -1816,62 +1812,22 @@ static_assert(sizeof(LayoutAlignmentTest
  */
 typedef JS::Value jsval;
 
 static_assert(sizeof(jsval_layout) == sizeof(JS::Value),
               "jsval_layout and JS::Value must have identical layouts");
 
 /************************************************************************/
 
-static inline bool
-JSVAL_IS_NULL(jsval v)
-{
-    return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline bool
-JSVAL_IS_VOID(jsval v)
-{
-    return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline bool
-JSVAL_IS_INT(jsval v)
-{
-    return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline int32_t
-JSVAL_TO_INT(jsval v)
-{
-    MOZ_ASSERT(JSVAL_IS_INT(v));
-    return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v));
-}
-
 static inline JS_VALUE_CONSTEXPR jsval
 INT_TO_JSVAL(int32_t i)
 {
     return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i));
 }
 
-static inline bool
-JSVAL_IS_DOUBLE(jsval v)
-{
-    return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline double
-JSVAL_TO_DOUBLE(jsval v)
-{
-    jsval_layout l;
-    MOZ_ASSERT(JSVAL_IS_DOUBLE(v));
-    l = JSVAL_TO_IMPL(v);
-    return l.asDouble;
-}
-
 static inline JS_VALUE_CONSTEXPR jsval
 DOUBLE_TO_JSVAL(double d)
 {
     /*
      * This is a manually inlined version of:
      *    d = JS_CANONICALIZE_NAN(d);
      *    return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d));
      * because GCC from XCode 3.1.4 miscompiles the above code.
@@ -1893,109 +1849,44 @@ DOUBLE_TO_JSVAL(double d)
 static inline JS_VALUE_CONSTEXPR jsval
 UINT_TO_JSVAL(uint32_t i)
 {
     return (i <= JSVAL_INT_MAX
             ? INT_TO_JSVAL((int32_t)i)
             : DOUBLE_TO_JSVAL((double)i));
 }
 
-static inline bool
-JSVAL_IS_NUMBER(jsval v)
-{
-    return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline bool
-JSVAL_IS_STRING(jsval v)
-{
-    return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline JSString *
-JSVAL_TO_STRING(jsval v)
-{
-    MOZ_ASSERT(JSVAL_IS_STRING(v));
-    return JSVAL_TO_STRING_IMPL(JSVAL_TO_IMPL(v));
-}
-
 static inline jsval
 STRING_TO_JSVAL(JSString *str)
 {
     return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str));
 }
 
-static inline JSObject *
-JSVAL_TO_OBJECT(jsval v)
-{
-    MOZ_ASSERT(JSVAL_IS_OBJECT_OR_NULL_IMPL(JSVAL_TO_IMPL(v)));
-    return JSVAL_TO_OBJECT_IMPL(JSVAL_TO_IMPL(v));
-}
-
 static inline jsval
 OBJECT_TO_JSVAL(JSObject *obj)
 {
     if (obj)
         return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj));
     return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
 }
 
-static inline bool
-JSVAL_IS_BOOLEAN(jsval v)
-{
-    return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline bool
-JSVAL_TO_BOOLEAN(jsval v)
-{
-    MOZ_ASSERT(JSVAL_IS_BOOLEAN(v));
-    return JSVAL_TO_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
-}
-
 static inline jsval
 BOOLEAN_TO_JSVAL(bool b)
 {
     return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b));
 }
 
-static inline bool
-JSVAL_IS_PRIMITIVE(jsval v)
-{
-    return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline bool
-JSVAL_IS_GCTHING(jsval v)
-{
-    return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static inline void *
-JSVAL_TO_GCTHING(jsval v)
-{
-    MOZ_ASSERT(JSVAL_IS_GCTHING(v));
-    return JSVAL_TO_GCTHING_IMPL(JSVAL_TO_IMPL(v));
-}
-
 /* To be GC-safe, privates are tagged as doubles. */
 
 static inline jsval
 PRIVATE_TO_JSVAL(void *ptr)
 {
     return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr));
 }
 
-static inline void *
-JSVAL_TO_PRIVATE(jsval v)
-{
-    MOZ_ASSERT(JSVAL_IS_DOUBLE(v));
-    return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
-}
-
 // JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
 // constructing values from scratch (e.g. Int32Value(0)).  These constants are
 // stored in memory and initialized at startup, so testing against them and
 // using them requires memory loads and will be correspondingly slow.
 extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -186,40 +186,16 @@ TryEvalJSON(JSContext *cx, JSScript *cal
                 rval.set(tmp);
                 return EvalJSON_Success;
             }
         }
     }
     return EvalJSON_NotJSON;
 }
 
-static void
-MarkFunctionsWithinEvalScript(JSScript *script)
-{
-    // Mark top level functions in an eval script as being within an eval and,
-    // if applicable, inside a with statement.
-
-    if (!script->hasObjects())
-        return;
-
-    ObjectArray *objects = script->objects();
-    size_t start = script->innerObjectsStart();
-
-    for (size_t i = start; i < objects->length; i++) {
-        JSObject *obj = objects->vector[i];
-        if (obj->is<JSFunction>()) {
-            JSFunction *fun = &obj->as<JSFunction>();
-            if (fun->hasScript())
-                fun->nonLazyScript()->setDirectlyInsideEval();
-            else if (fun->isInterpretedLazy())
-                fun->lazyScript()->setDirectlyInsideEval();
-        }
-    }
-}
-
 // Define subset of ExecuteType so that casting performs the injection.
 enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL };
 
 // Common code implementing direct and indirect eval.
 //
 // Evaluate call.argv[2], if it is a string, in the context of the given calling
 // frame, with the provided scope chain, with the semantics of either a direct
 // or indirect eval (see ES5 10.4.2).  If this is an indirect eval, scopeobj
@@ -322,18 +298,16 @@ EvalKernel(JSContext *cx, const CallArgs
                .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
         SourceBufferHolder srcBuf(chars.get(), length, SourceBufferHolder::NoOwnership);
         JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
                                                      scopeobj, callerScript, options,
                                                      srcBuf, flatStr, staticLevel);
         if (!compiled)
             return false;
 
-        MarkFunctionsWithinEvalScript(compiled);
-
         esg.setNewScript(compiled);
     }
 
     return ExecuteKernel(cx, esg.script(), *scopeobj, thisv, ExecuteType(evalType),
                          NullFramePtr() /* evalInFrame */, args.rval().address());
 }
 
 bool
@@ -391,18 +365,16 @@ js::DirectEvalStringFromIon(JSContext *c
                .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
         SourceBufferHolder srcBuf(chars.get(), length, SourceBufferHolder::NoOwnership);
         JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
                                                      scopeobj, callerScript, options,
                                                      srcBuf, flatStr, staticLevel);
         if (!compiled)
             return false;
 
-        MarkFunctionsWithinEvalScript(compiled);
-
         esg.setNewScript(compiled);
     }
 
     // Primitive 'this' values should have been filtered out by Ion. If boxed,
     // the calling frame cannot be updated to store the new object.
     JS_ASSERT(thisValue.isObject() || thisValue.isUndefined() || thisValue.isNull());
 
     return ExecuteKernel(cx, esg.script(), *scopeobj, thisValue, ExecuteType(DIRECT_EVAL),
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -816,17 +816,17 @@ static ABICode
 GetABICode(JSObject* obj)
 {
   // make sure we have an object representing a CABI class,
   // and extract the enumerated class type from the reserved slot.
   if (JS_GetClass(obj) != &sCABIClass)
     return INVALID_ABI;
 
   jsval result = JS_GetReservedSlot(obj, SLOT_ABICODE);
-  return ABICode(JSVAL_TO_INT(result));
+  return ABICode(result.toInt32());
 }
 
 static const JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
 #define MSG_DEF(name, number, count, exception, format) \
   { format, count, exception } ,
 #include "ctypes/ctypes.msg"
 #undef MSG_DEF
 };
@@ -1281,39 +1281,39 @@ IsCTypesGlobal(HandleValue v)
 
 // Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'.
 JSCTypesCallbacks*
 GetCallbacks(JSObject* obj)
 {
   JS_ASSERT(IsCTypesGlobal(obj));
 
   jsval result = JS_GetReservedSlot(obj, SLOT_CALLBACKS);
-  if (JSVAL_IS_VOID(result))
+  if (result.isUndefined())
     return nullptr;
 
-  return static_cast<JSCTypesCallbacks*>(JSVAL_TO_PRIVATE(result));
+  return static_cast<JSCTypesCallbacks*>(result.toPrivate());
 }
 
 // Utility function to access a property of an object as an object
 // returns false and sets the error if the property does not exist
 // or is not an object
 static bool GetObjectProperty(JSContext *cx, HandleObject obj,
                               const char *property, MutableHandleObject result)
 {
   RootedValue val(cx);
   if (!JS_GetProperty(cx, obj, property, &val)) {
     return false;
   }
 
-  if (JSVAL_IS_PRIMITIVE(val)) {
+  if (val.isPrimitive()) {
     JS_ReportError(cx, "missing or non-object field");
     return false;
   }
 
-  result.set(JSVAL_TO_OBJECT(val));
+  result.set(val.toObjectOrNull());
   return true;
 }
 
 } /* namespace ctypes */
 } /* namespace js */
 
 using namespace js;
 using namespace js::ctypes;
@@ -1379,21 +1379,21 @@ namespace js {
 JS_FRIEND_API(size_t)
 SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject *obj)
 {
     if (!CData::IsCData(obj))
         return 0;
 
     size_t n = 0;
     jsval slot = JS_GetReservedSlot(obj, ctypes::SLOT_OWNS);
-    if (!JSVAL_IS_VOID(slot)) {
-        bool owns = JSVAL_TO_BOOLEAN(slot);
+    if (!slot.isUndefined()) {
+        bool owns = slot.toBoolean();
         slot = JS_GetReservedSlot(obj, ctypes::SLOT_DATA);
-        if (!JSVAL_IS_VOID(slot)) {
-            char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
+        if (!slot.isUndefined()) {
+            char** buffer = static_cast<char**>(slot.toPrivate());
             n += mallocSizeOf(buffer);
             if (owns)
                 n += mallocSizeOf(*buffer);
         }
     }
     return n;
 }
 
@@ -1570,27 +1570,27 @@ static MOZ_ALWAYS_INLINE bool IsNegative
   return IsNegativeImpl<Type, NumericLimits<Type>::is_signed>::Test(i);
 }
 
 // Implicitly convert val to bool, allowing bool, int, and double
 // arguments numerically equal to 0 or 1.
 static bool
 jsvalToBool(JSContext* cx, jsval val, bool* result)
 {
-  if (JSVAL_IS_BOOLEAN(val)) {
-    *result = JSVAL_TO_BOOLEAN(val);
+  if (val.isBoolean()) {
+    *result = val.toBoolean();
     return true;
   }
-  if (JSVAL_IS_INT(val)) {
-    int32_t i = JSVAL_TO_INT(val);
+  if (val.isInt32()) {
+    int32_t i = val.toInt32();
     *result = i != 0;
     return i == 0 || i == 1;
   }
-  if (JSVAL_IS_DOUBLE(val)) {
-    double d = JSVAL_TO_DOUBLE(val);
+  if (val.isDouble()) {
+    double d = val.toDouble();
     *result = d != 0;
     // Allow -0.
     return d == 1 || d == 0;
   }
   // Don't silently convert null to bool. It's probably a mistake.
   return false;
 }
 
@@ -1598,30 +1598,30 @@ jsvalToBool(JSContext* cx, jsval val, bo
 // Int64, UInt64, and CData integer types 't' where all values of 't' are
 // representable by IntegerType.
 template<class IntegerType>
 static bool
 jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
 {
   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
-  if (JSVAL_IS_INT(val)) {
+  if (val.isInt32()) {
     // Make sure the integer fits in the alotted precision, and has the right
     // sign.
-    int32_t i = JSVAL_TO_INT(val);
+    int32_t i = val.toInt32();
     return ConvertExact(i, result);
   }
-  if (JSVAL_IS_DOUBLE(val)) {
+  if (val.isDouble()) {
     // Don't silently lose bits here -- check that val really is an
     // integer value, and has the right sign.
-    double d = JSVAL_TO_DOUBLE(val);
+    double d = val.toDouble();
     return ConvertExact(d, result);
   }
-  if (!JSVAL_IS_PRIMITIVE(val)) {
-    JSObject* obj = JSVAL_TO_OBJECT(val);
+  if (val.isObject()) {
+    JSObject* obj = &val.toObject();
     if (CData::IsCData(obj)) {
       JSObject* typeObj = CData::GetCType(obj);
       void* data = CData::GetData(obj);
 
       // Check whether the source type is always representable, with exact
       // precision, by the target type. If it is, convert the value.
       switch (CType::GetTypeCode(typeObj)) {
 #define DEFINE_INT_TYPE(name, fromType, ffiType)                               \
@@ -1668,19 +1668,19 @@ jsvalToInteger(JSContext* cx, jsval val,
       if (!CDataFinalizer::GetValue(cx, obj, innerData.address())) {
         return false; // Nothing to convert
       }
       return jsvalToInteger(cx, innerData, result);
     }
 
     return false;
   }
-  if (JSVAL_IS_BOOLEAN(val)) {
+  if (val.isBoolean()) {
     // Implicitly promote boolean values to 0 or 1, like C.
-    *result = JSVAL_TO_BOOLEAN(val);
+    *result = val.toBoolean();
     JS_ASSERT(*result == 0 || *result == 1);
     return true;
   }
   // Don't silently convert null to an integer. It's probably a mistake.
   return false;
 }
 
 // Implicitly convert val to FloatType, allowing int, double,
@@ -1691,26 +1691,26 @@ static bool
 jsvalToFloat(JSContext *cx, jsval val, FloatType* result)
 {
   JS_STATIC_ASSERT(!NumericLimits<FloatType>::is_exact);
 
   // The following casts may silently throw away some bits, but there's
   // no good way around it. Sternly requiring that the 64-bit double
   // argument be exactly representable as a 32-bit float is
   // unrealistic: it would allow 1/2 to pass but not 1/3.
-  if (JSVAL_IS_INT(val)) {
-    *result = FloatType(JSVAL_TO_INT(val));
+  if (val.isInt32()) {
+    *result = FloatType(val.toInt32());
     return true;
   }
-  if (JSVAL_IS_DOUBLE(val)) {
-    *result = FloatType(JSVAL_TO_DOUBLE(val));
+  if (val.isDouble()) {
+    *result = FloatType(val.toDouble());
     return true;
   }
-  if (!JSVAL_IS_PRIMITIVE(val)) {
-    JSObject* obj = JSVAL_TO_OBJECT(val);
+  if (val.isObject()) {
+    JSObject* obj = &val.toObject();
     if (CData::IsCData(obj)) {
       JSObject* typeObj = CData::GetCType(obj);
       void* data = CData::GetData(obj);
 
       // Check whether the source type is always representable, with exact
       // precision, by the target type. If it is, convert the value.
       switch (CType::GetTypeCode(typeObj)) {
 #define DEFINE_FLOAT_TYPE(name, fromType, ffiType)                             \
@@ -1803,38 +1803,38 @@ template<class IntegerType>
 static bool
 jsvalToBigInteger(JSContext* cx,
                   jsval val,
                   bool allowString,
                   IntegerType* result)
 {
   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
-  if (JSVAL_IS_INT(val)) {
+  if (val.isInt32()) {
     // Make sure the integer fits in the alotted precision, and has the right
     // sign.
-    int32_t i = JSVAL_TO_INT(val);
+    int32_t i = val.toInt32();
     return ConvertExact(i, result);
   }
-  if (JSVAL_IS_DOUBLE(val)) {
+  if (val.isDouble()) {
     // Don't silently lose bits here -- check that val really is an
     // integer value, and has the right sign.
-    double d = JSVAL_TO_DOUBLE(val);
+    double d = val.toDouble();
     return ConvertExact(d, result);
   }
-  if (allowString && JSVAL_IS_STRING(val)) {
+  if (allowString && val.isString()) {
     // Allow conversion from base-10 or base-16 strings, provided the result
     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
     // to the JS array element operator, which will automatically call
     // toString() on the object for us.)
-    return StringToInteger(cx, JSVAL_TO_STRING(val), result);
-  }
-  if (!JSVAL_IS_PRIMITIVE(val)) {
+    return StringToInteger(cx, val.toString(), result);
+  }
+  if (val.isObject()) {
     // Allow conversion from an Int64 or UInt64 object directly.
-    JSObject* obj = JSVAL_TO_OBJECT(val);
+    JSObject* obj = &val.toObject();
 
     if (UInt64::IsUInt64(obj)) {
       // Make sure the integer fits in IntegerType.
       uint64_t i = Int64Base::GetInt(obj);
       return ConvertExact(i, result);
     }
 
     if (Int64::IsInt64(obj)) {
@@ -1939,25 +1939,25 @@ SizeTojsval(JSContext* cx, size_t size, 
 
 // Forcefully convert val to IntegerType when explicitly requested.
 template<class IntegerType>
 static bool
 jsvalToIntegerExplicit(jsval val, IntegerType* result)
 {
   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
-  if (JSVAL_IS_DOUBLE(val)) {
+  if (val.isDouble()) {
     // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
-    double d = JSVAL_TO_DOUBLE(val);
+    double d = val.toDouble();
     *result = mozilla::IsFinite(d) ? IntegerType(d) : 0;
     return true;
   }
-  if (!JSVAL_IS_PRIMITIVE(val)) {
+  if (val.isObject()) {
     // Convert Int64 and UInt64 values by C-style cast.
-    JSObject* obj = JSVAL_TO_OBJECT(val);
+    JSObject* obj = &val.toObject();
     if (Int64::IsInt64(obj)) {
       int64_t i = Int64Base::GetInt(obj);
       *result = IntegerType(i);
       return true;
     }
     if (UInt64::IsUInt64(obj)) {
       uint64_t i = Int64Base::GetInt(obj);
       *result = IntegerType(i);
@@ -1966,42 +1966,42 @@ jsvalToIntegerExplicit(jsval val, Intege
   }
   return false;
 }
 
 // Forcefully convert val to a pointer value when explicitly requested.
 static bool
 jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result)
 {
-  if (JSVAL_IS_INT(val)) {
+  if (val.isInt32()) {
     // int32_t always fits in intptr_t. If the integer is negative, cast through
     // an intptr_t intermediate to sign-extend.
-    int32_t i = JSVAL_TO_INT(val);
+    int32_t i = val.toInt32();
     *result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
     return true;
   }
-  if (JSVAL_IS_DOUBLE(val)) {
-    double d = JSVAL_TO_DOUBLE(val);
+  if (val.isDouble()) {
+    double d = val.toDouble();
     if (d < 0) {
       // Cast through an intptr_t intermediate to sign-extend.
       intptr_t i = Convert<intptr_t>(d);
       if (double(i) != d)
         return false;
 
       *result = uintptr_t(i);
       return true;
     }
 
     // Don't silently lose bits here -- check that val really is an
     // integer value, and has the right sign.
     *result = Convert<uintptr_t>(d);
     return double(*result) == d;
   }
-  if (!JSVAL_IS_PRIMITIVE(val)) {
-    JSObject* obj = JSVAL_TO_OBJECT(val);
+  if (val.isObject()) {
+    JSObject* obj = &val.toObject();
     if (Int64::IsInt64(obj)) {
       int64_t i = Int64Base::GetInt(obj);
       intptr_t p = intptr_t(i);
 
       // Make sure the integer fits in the alotted precision.
       if (int64_t(p) != i)
         return false;
       *result = uintptr_t(p);
@@ -2237,18 +2237,18 @@ ImplicitConvert(JSContext* cx,
   RootedObject targetType(cx, targetType_);
   JS_ASSERT(CType::IsSizeDefined(targetType));
 
   // First, check if val is either a CData object or a CDataFinalizer
   // of type targetType.
   JSObject* sourceData = nullptr;
   JSObject* sourceType = nullptr;
   RootedObject valObj(cx, nullptr);
-  if (!JSVAL_IS_PRIMITIVE(val)) {
-    valObj = JSVAL_TO_OBJECT(val);
+  if (val.isObject()) {
+    valObj = &val.toObject();
     if (CData::IsCData(valObj)) {
       sourceData = valObj;
       sourceType = CData::GetCType(sourceData);
 
       // If the types are equal, copy the buffer contained within the CData.
       // (Note that the buffers may overlap partially or completely.)
       if (CType::TypesEqual(sourceType, targetType)) {
         size_t size = CType::GetSize(sourceType);
@@ -2307,33 +2307,33 @@ ImplicitConvert(JSContext* cx,
     break;                                                                     \
   }
 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
 #define DEFINE_JSCHAR_TYPE(name, type, ffiType)                                \
   case TYPE_##name: {                                                          \
     /* Convert from a 1-character string, regardless of encoding, */           \
     /* or from an integer, provided the result fits in 'type'. */              \
     type result;                                                               \
-    if (JSVAL_IS_STRING(val)) {                                                \
-      JSString* str = JSVAL_TO_STRING(val);                                    \
+    if (val.isString()) {                                                \
+      JSString* str = val.toString();                                    \
       if (str->length() != 1)                                                  \
         return TypeError(cx, #name, val);                                      \
       const jschar *chars = str->getChars(cx);                                 \
       if (!chars)                                                              \
         return false;                                                          \
       result = chars[0];                                                       \
     } else if (!jsvalToInteger(cx, val, &result)) {                            \
       return TypeError(cx, #name, val);                                        \
     }                                                                          \
     *static_cast<type*>(buffer) = result;                                      \
     break;                                                                     \
   }
 #include "ctypes/typedefs.h"
   case TYPE_pointer: {
-    if (JSVAL_IS_NULL(val)) {
+    if (val.isNull()) {
       // Convert to a null pointer.
       *static_cast<void**>(buffer) = nullptr;
       break;
     }
 
     JS::Rooted<JSObject*> baseType(cx, PointerType::GetBaseType(targetType));
     if (sourceData) {
       // First, determine if the targetType is ctypes.void_t.ptr.
@@ -2351,21 +2351,21 @@ ImplicitConvert(JSContext* cx,
         // sourceType.elementType.ptr, just like C.
         JSObject* elementType = ArrayType::GetBaseType(sourceType);
         if (voidptrTarget || CType::TypesEqual(baseType, elementType)) {
           *static_cast<void**>(buffer) = sourceBuffer;
           break;
         }
       }
 
-    } else if (isArgument && JSVAL_IS_STRING(val)) {
+    } else if (isArgument && val.isString()) {
       // Convert the string for the ffi call. This requires allocating space
       // which the caller assumes ownership of.
       // TODO: Extend this so we can safely convert strings at other times also.
-      JSString* sourceString = JSVAL_TO_STRING(val);
+      JSString* sourceString = val.toString();
       size_t sourceLength = sourceString->length();
       const jschar* sourceChars = sourceString->getChars(cx);
       if (!sourceChars)
         return false;
 
       switch (CType::GetTypeCode(baseType)) {
       case TYPE_char:
       case TYPE_signed_char:
@@ -2404,44 +2404,44 @@ ImplicitConvert(JSContext* cx,
         memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar));
         (*jscharBuffer)[sourceLength] = 0;
         break;
       }
       default:
         return TypeError(cx, "string pointer", val);
       }
       break;
-    } else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayBufferObject(valObj)) {
+    } else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
       // Convert ArrayBuffer to pointer without any copy.
       // Just as with C arrays, we make no effort to
       // keep the ArrayBuffer alive.
       void* p = JS_GetStableArrayBufferData(cx, valObj);
       if (!p)
           return false;
       *static_cast<void**>(buffer) = p;
       break;
-    } if (!JSVAL_IS_PRIMITIVE(val) && JS_IsTypedArrayObject(valObj)) {
+    } if (val.isObject() && JS_IsTypedArrayObject(valObj)) {
       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
         return TypeError(cx, "typed array with the appropriate type", val);
       }
 
       // Convert TypedArray to pointer without any copy.
       // Just as with C arrays, we make no effort to
       // keep the TypedArray alive.
       *static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj);
       break;
     }
     return TypeError(cx, "pointer", val);
   }
   case TYPE_array: {
     RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
     size_t targetLength = ArrayType::GetLength(targetType);
 
-    if (JSVAL_IS_STRING(val)) {
-      JSString* sourceString = JSVAL_TO_STRING(val);
+    if (val.isString()) {
+      JSString* sourceString = val.toString();
       size_t sourceLength = sourceString->length();
       const jschar* sourceChars = sourceString->getChars(cx);
       if (!sourceChars)
         return false;
 
       switch (CType::GetTypeCode(baseType)) {
       case TYPE_char:
       case TYPE_signed_char:
@@ -2479,17 +2479,17 @@ ImplicitConvert(JSContext* cx,
           static_cast<jschar*>(buffer)[sourceLength] = 0;
 
         break;
       }
       default:
         return TypeError(cx, "array", val);
       }
 
-    } else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayObject(cx, valObj)) {
+    } else if (val.isObject() && JS_IsArrayObject(cx, valObj)) {
       // Convert each element of the array by calling ImplicitConvert.
       uint32_t sourceLength;
       if (!JS_GetArrayLength(cx, valObj, &sourceLength) ||
           targetLength != size_t(sourceLength)) {
         JS_ReportError(cx, "ArrayType length does not match source array length");
         return false;
       }
 
@@ -2509,31 +2509,29 @@ ImplicitConvert(JSContext* cx,
 
         char* data = intermediate.get() + elementSize * i;
         if (!ImplicitConvert(cx, item, baseType, data, false, nullptr))
           return false;
       }
 
       memcpy(buffer, intermediate.get(), arraySize);
 
-    } else if (!JSVAL_IS_PRIMITIVE(val) &&
-               JS_IsArrayBufferObject(valObj)) {
+    } else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
       // Check that array is consistent with type, then
       // copy the array.
       uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj);
       size_t elementSize = CType::GetSize(baseType);
       size_t arraySize = elementSize * targetLength;
       if (arraySize != size_t(sourceLength)) {
         JS_ReportError(cx, "ArrayType length does not match source ArrayBuffer length");
         return false;
       }
       memcpy(buffer, JS_GetArrayBufferData(valObj), sourceLength);
       break;
-    }  else if (!JSVAL_IS_PRIMITIVE(val) &&
-               JS_IsTypedArrayObject(valObj)) {
+    } else if (val.isObject() && JS_IsTypedArrayObject(valObj)) {
       // Check that array is consistent with type, then
       // copy the array.
       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
         return TypeError(cx, "typed array with the appropriate type", val);
       }
 
       uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
       size_t elementSize = CType::GetSize(baseType);
@@ -2547,17 +2545,17 @@ ImplicitConvert(JSContext* cx,
     } else {
       // Don't implicitly convert to string. Users can implicitly convert
       // with `String(x)` or `""+x`.
       return TypeError(cx, "array", val);
     }
     break;
   }
   case TYPE_struct: {
-    if (!JSVAL_IS_PRIMITIVE(val) && !sourceData) {
+    if (val.isObject() && !sourceData) {
       // Enumerate the properties of the object; if they match the struct
       // specification, convert the fields.
       RootedObject iter(cx, JS_NewPropertyIterator(cx, valObj));
       if (!iter)
         return false;
 
       // Convert into an intermediate, in case of failure.
       size_t structSize = CType::GetSize(targetType);
@@ -2646,18 +2644,18 @@ ExplicitConvert(JSContext* cx, HandleVal
     break;
   }
 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
   case TYPE_##name: {                                                          \
     /* Convert numeric values with a C-style cast, and */                      \
     /* allow conversion from a base-10 or base-16 string. */                   \
     type result;                                                               \
     if (!jsvalToIntegerExplicit(val, &result) &&                               \
-        (!JSVAL_IS_STRING(val) ||                                              \
-         !StringToInteger(cx, JSVAL_TO_STRING(val), &result)))                 \
+        (!val.isString() ||                                              \
+         !StringToInteger(cx, val.toString(), &result)))                 \
       return TypeError(cx, #name, val);                                        \
     *static_cast<type*>(buffer) = result;                                      \
     break;                                                                     \
   }
 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
 #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z)
 #include "ctypes/typedefs.h"
@@ -3287,44 +3285,44 @@ CType::DefineBuiltin(JSContext* cx,
   return typeObj;
 }
 
 void
 CType::Finalize(JSFreeOp *fop, JSObject* obj)
 {
   // Make sure our TypeCode slot is legit. If it's not, bail.
   jsval slot = JS_GetReservedSlot(obj, SLOT_TYPECODE);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
 
   // The contents of our slots depends on what kind of type we are.
-  switch (TypeCode(JSVAL_TO_INT(slot))) {
+  switch (TypeCode(slot.toInt32())) {
   case TYPE_function: {
     // Free the FunctionInfo.
     slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
-    if (!JSVAL_IS_VOID(slot))
-      FreeOp::get(fop)->delete_(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
+    if (!slot.isUndefined())
+      FreeOp::get(fop)->delete_(static_cast<FunctionInfo*>(slot.toPrivate()));
     break;
   }
 
   case TYPE_struct: {
     // Free the FieldInfoHash table.
     slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
-    if (!JSVAL_IS_VOID(slot)) {
-      void* info = JSVAL_TO_PRIVATE(slot);
+    if (!slot.isUndefined()) {
+      void* info = slot.toPrivate();
       FreeOp::get(fop)->delete_(static_cast<FieldInfoHash*>(info));
     }
   }
 
     // Fall through.
   case TYPE_array: {
     // Free the ffi_type info.
     slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
-    if (!JSVAL_IS_VOID(slot)) {
-      ffi_type* ffiType = static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
+    if (!slot.isUndefined()) {
+      ffi_type* ffiType = static_cast<ffi_type*>(slot.toPrivate());
       FreeOp::get(fop)->free_(ffiType->elements);
       FreeOp::get(fop)->delete_(ffiType);
     }
 
     break;
   }
   default:
     // Nothing to do here.
@@ -3332,45 +3330,44 @@ CType::Finalize(JSFreeOp *fop, JSObject*
   }
 }
 
 void
 CType::Trace(JSTracer* trc, JSObject* obj)
 {
   // Make sure our TypeCode slot is legit. If it's not, bail.
   jsval slot = obj->getSlot(SLOT_TYPECODE);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
 
   // The contents of our slots depends on what kind of type we are.
-  switch (TypeCode(JSVAL_TO_INT(slot))) {
+  switch (TypeCode(slot.toInt32())) {
   case TYPE_struct: {
     slot = obj->getReservedSlot(SLOT_FIELDINFO);
-    if (JSVAL_IS_VOID(slot))
+    if (slot.isUndefined())
       return;
 
-    FieldInfoHash* fields =
-      static_cast<FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
+    FieldInfoHash* fields = static_cast<FieldInfoHash*>(slot.toPrivate());
     for (FieldInfoHash::Enum e(*fields); !e.empty(); e.popFront()) {
       JSString *key = e.front().key();
       JS_CallStringTracer(trc, &key, "fieldName");
       if (key != e.front().key())
           e.rekeyFront(JS_ASSERT_STRING_IS_FLAT(key));
       JS_CallHeapObjectTracer(trc, &e.front().value().mType, "fieldType");
     }
 
     break;
   }
   case TYPE_function: {
     // Check if we have a FunctionInfo.
     slot = obj->getReservedSlot(SLOT_FNINFO);
-    if (JSVAL_IS_VOID(slot))
+    if (slot.isUndefined())
       return;
 
-    FunctionInfo* fninfo = static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
+    FunctionInfo* fninfo = static_cast<FunctionInfo*>(slot.toPrivate());
     JS_ASSERT(fninfo);
 
     // Identify our objects to the tracer.
     JS_CallHeapObjectTracer(trc, &fninfo->mABI, "abi");
     JS_CallHeapObjectTracer(trc, &fninfo->mReturnType, "returnType");
     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i)
       JS_CallHeapObjectTracer(trc, &fninfo->mArgTypes[i], "argType");
 
@@ -3395,17 +3392,17 @@ CType::IsCTypeProto(JSObject* obj)
 }
 
 TypeCode
 CType::GetTypeCode(JSObject* typeObj)
 {
   JS_ASSERT(IsCType(typeObj));
 
   jsval result = JS_GetReservedSlot(typeObj, SLOT_TYPECODE);
-  return TypeCode(JSVAL_TO_INT(result));
+  return TypeCode(result.toInt32());
 }
 
 bool
 CType::TypesEqual(JSObject* t1, JSObject* t2)
 {
   JS_ASSERT(IsCType(t1) && IsCType(t2));
 
   // Fast path: check for object equality.
@@ -3476,77 +3473,77 @@ bool
 CType::GetSafeSize(JSObject* obj, size_t* result)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
 
   // The "size" property can be an int, a double, or JSVAL_VOID
   // (for arrays of undefined length), and must always fit in a size_t.
-  if (JSVAL_IS_INT(size)) {
-    *result = JSVAL_TO_INT(size);
+  if (size.isInt32()) {
+    *result = size.toInt32();
     return true;
   }
-  if (JSVAL_IS_DOUBLE(size)) {
-    *result = Convert<size_t>(JSVAL_TO_DOUBLE(size));
+  if (size.isDouble()) {
+    *result = Convert<size_t>(size.toDouble());
     return true;
   }
 
-  JS_ASSERT(JSVAL_IS_VOID(size));
+  JS_ASSERT(size.isUndefined());
   return false;
 }
 
 size_t
 CType::GetSize(JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
 
-  JS_ASSERT(!JSVAL_IS_VOID(size));
+  JS_ASSERT(!size.isUndefined());
 
   // The "size" property can be an int, a double, or JSVAL_VOID
   // (for arrays of undefined length), and must always fit in a size_t.
   // For callers who know it can never be JSVAL_VOID, return a size_t directly.
-  if (JSVAL_IS_INT(size))
-    return JSVAL_TO_INT(size);
-  return Convert<size_t>(JSVAL_TO_DOUBLE(size));
+  if (size.isInt32())
+    return size.toInt32();
+  return Convert<size_t>(size.toDouble());
 }
 
 bool
 CType::IsSizeDefined(JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
 
   // The "size" property can be an int, a double, or JSVAL_VOID
   // (for arrays of undefined length), and must always fit in a size_t.
-  JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size));
-  return !JSVAL_IS_VOID(size);
+  JS_ASSERT(size.isInt32() || size.isDouble() || size.isUndefined());
+  return !size.isUndefined();
 }
 
 size_t
 CType::GetAlignment(JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_ALIGN);
-  return static_cast<size_t>(JSVAL_TO_INT(slot));
+  return static_cast<size_t>(slot.toInt32());
 }
 
 ffi_type*
 CType::GetFFIType(JSContext* cx, JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
 
-  if (!JSVAL_IS_VOID(slot)) {
-    return static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
+  if (!slot.isUndefined()) {
+    return static_cast<ffi_type*>(slot.toPrivate());
   }
 
   AutoPtr<ffi_type> result;
   switch (CType::GetTypeCode(obj)) {
   case TYPE_array:
     result = ArrayType::BuildFFIType(cx, obj);
     break;
 
@@ -3565,18 +3562,18 @@ CType::GetFFIType(JSContext* cx, JSObjec
 }
 
 JSString*
 CType::GetName(JSContext* cx, HandleObject obj)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval string = JS_GetReservedSlot(obj, SLOT_NAME);
-  if (!JSVAL_IS_VOID(string))
-    return JSVAL_TO_STRING(string);
+  if (!string.isUndefined())
+    return string.toString();
 
   // Build the type name lazily.
   JSString* name = BuildTypeName(cx, obj);
   if (!name)
     return nullptr;
   JS_SetReservedSlot(obj, SLOT_NAME, STRING_TO_JSVAL(name));
   return name;
 }
@@ -3606,18 +3603,18 @@ CType::GetProtoFromType(JSContext* cx, J
   RootedObject proto(cx);
   if (!JS_GetPrototype(cx, obj, &proto))
     return nullptr;
   JS_ASSERT(proto);
   JS_ASSERT(CType::IsCTypeProto(proto));
 
   // Get the requested ctypes.{Pointer,Array,Struct,Function}Type.prototype.
   jsval result = JS_GetReservedSlot(proto, slot);
-  JS_ASSERT(!JSVAL_IS_PRIMITIVE(result));
-  return JSVAL_TO_OBJECT(result);
+  JS_ASSERT(result.isObject());
+  return &result.toObject();
 }
 
 bool
 CType::IsCTypeOrProto(HandleValue v)
 {
   if (!v.isObject())
     return false;
   JSObject* obj = &v.toObject();
@@ -3774,17 +3771,17 @@ CType::HasInstance(JSContext* cx, Handle
   JS_ASSERT(CType::IsCType(obj));
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_PROTO);
   JS::Rooted<JSObject*> prototype(cx, &slot.toObject());
   JS_ASSERT(prototype);
   JS_ASSERT(CData::IsCDataProto(prototype));
 
   *bp = false;
-  if (JSVAL_IS_PRIMITIVE(v))
+  if (v.isPrimitive())
     return true;
 
   RootedObject proto(cx, &v.toObject());
   for (;;) {
     if (!JS_GetPrototype(cx, proto, &proto))
       return false;
     if (!proto)
       break;
@@ -3804,19 +3801,17 @@ CType::GetGlobalCTypes(JSContext* cx, JS
   RootedObject obj(cx, objArg);
   RootedObject objTypeProto(cx);
   if (!JS_GetPrototype(cx, obj, &objTypeProto))
     return nullptr;
   JS_ASSERT(objTypeProto);
   JS_ASSERT(CType::IsCTypeProto(objTypeProto));
 
   jsval valCTypes = JS_GetReservedSlot(objTypeProto, SLOT_CTYPES);
-  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
-
-  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
+  JS_ASSERT(valCTypes.isObject());
   return &valCTypes.toObject();
 }
 
 /*******************************************************************************
 ** ABI implementation
 *******************************************************************************/
 
 bool
@@ -3876,17 +3871,17 @@ PointerType::Create(JSContext* cx, unsig
   // Construct and return a new PointerType object.
   if (args.length() != 1) {
     JS_ReportError(cx, "PointerType takes one argument");
     return false;
   }
 
   jsval arg = args[0];
   RootedObject obj(cx);
-  if (JSVAL_IS_PRIMITIVE(arg) || !CType::IsCType(obj = &arg.toObject())) {
+  if (arg.isPrimitive() || !CType::IsCType(obj = &arg.toObject())) {
     JS_ReportError(cx, "first argument must be a CType");
     return false;
   }
 
   JSObject* result = CreateInternal(cx, obj);
   if (!result)
     return false;
 
@@ -3989,17 +3984,17 @@ PointerType::ConstructData(JSContext* cx
 
   // The second argument is an optional 'this' parameter with which to invoke
   // the given js function. Callers may leave this blank, or pass null if they
   // wish to pass the third argument.
   RootedObject thisObj(cx, nullptr);
   if (args.length() >= 2) {
     if (args[1].isNull()) {
       thisObj = nullptr;
-    } else if (!JSVAL_IS_PRIMITIVE(args[1])) {
+    } else if (args[1].isObject()) {
       thisObj = &args[1].toObject();
     } else if (!JS_ValueToObject(cx, args[1], &thisObj)) {
       return false;
     }
   }
 
   // The third argument is an optional error sentinel that js-ctypes will return
   // if an exception is raised while executing the closure. The type must match
@@ -4176,17 +4171,17 @@ ArrayType::Create(JSContext* cx, unsigne
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   // Construct and return a new ArrayType object.
   if (args.length() < 1 || args.length() > 2) {
     JS_ReportError(cx, "ArrayType takes one or two arguments");
     return false;
   }
 
-  if (JSVAL_IS_PRIMITIVE(args[0]) ||
+  if (args[0].isPrimitive() ||
       !CType::IsCType(&args[0].toObject())) {
     JS_ReportError(cx, "first argument must be a CType");
     return false;
   }
 
   // Convert the length argument to a size_t.
   size_t length = 0;
   if (args.length() == 2 && !jsvalToSize(cx, args[1], false, &length)) {
@@ -4290,17 +4285,17 @@ ArrayType::ConstructData(JSContext* cx,
 
     RootedObject baseType(cx, GetBaseType(obj));
 
     size_t length;
     if (jsvalToSize(cx, args[0], false, &length)) {
       // Have a length, rather than an object to initialize from.
       convertObject = false;
 
-    } else if (!JSVAL_IS_PRIMITIVE(args[0])) {
+    } else if (args[0].isObject()) {
       // We were given an object with a .length property.
       // This could be a JS array, or a CData array.
       RootedObject arg(cx, &args[0].toObject());
       RootedValue lengthVal(cx);
       if (!JS_GetProperty(cx, arg, "length", &lengthVal) ||
           !jsvalToSize(cx, lengthVal, false, &length)) {
         JS_ReportError(cx, "argument must be an array object or length");
         return false;
@@ -4361,17 +4356,17 @@ ArrayType::ConstructData(JSContext* cx,
 
 JSObject*
 ArrayType::GetBaseType(JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
 
   jsval type = JS_GetReservedSlot(obj, SLOT_ELEMENT_T);
-  JS_ASSERT(!JSVAL_IS_NULL(type));
+  JS_ASSERT(!type.isNull());
   return &type.toObject();
 }
 
 bool
 ArrayType::GetSafeLength(JSObject* obj, size_t* result)
 {
   JS_ASSERT(CType::IsCType(obj));
   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
@@ -4629,22 +4624,22 @@ ArrayType::AddressOfElement(JSContext* c
 ** StructType implementation
 *******************************************************************************/
 
 // For a struct field descriptor 'val' of the form { name : type }, extract
 // 'name' and 'type'.
 static JSFlatString*
 ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
 {
-  if (JSVAL_IS_PRIMITIVE(val)) {
+  if (val.isPrimitive()) {
     JS_ReportError(cx, "struct field descriptors require a valid name and type");
     return nullptr;
   }
 
-  RootedObject obj(cx, JSVAL_TO_OBJECT(val));
+  RootedObject obj(cx, val.toObjectOrNull());
   RootedObject iter(cx, JS_NewPropertyIterator(cx, obj));
   if (!iter)
     return nullptr;
 
   RootedId nameid(cx);
   if (!JS_NextProperty(cx, iter, nameid.address()))
     return nullptr;
   if (JSID_IS_VOID(nameid)) {
@@ -4732,22 +4727,22 @@ StructType::Create(JSContext* cx, unsign
 
   // Get ctypes.StructType.prototype from the ctypes.StructType constructor.
   RootedObject typeProto(cx, CType::GetProtoFromCtor(&args.callee(), SLOT_STRUCTPROTO));
 
   // Create a simple StructType with no defined fields. The result will be
   // non-instantiable as CData, will have no 'prototype' property, and will
   // have undefined size and alignment and no ffi_type.
   RootedObject result(cx, CType::Create(cx, typeProto, NullPtr(), TYPE_struct,
-                                        JSVAL_TO_STRING(name), JSVAL_VOID, JSVAL_VOID, nullptr));
+                                        name.toString(), JSVAL_VOID, JSVAL_VOID, nullptr));
   if (!result)
     return false;
 
   if (args.length() == 2) {
-    RootedObject arr(cx, JSVAL_IS_PRIMITIVE(args[1]) ? nullptr : &args[1].toObject());
+    RootedObject arr(cx, args[1].isPrimitive() ? nullptr : &args[1].toObject());
     if (!arr || !JS_IsArrayObject(cx, arr)) {
       JS_ReportError(cx, "second argument must be an array");
       return false;
     }
 
     // Define the struct fields.
     if (!DefineInternal(cx, result, arr))
       return false;
@@ -4994,21 +4989,21 @@ StructType::Define(JSContext* cx, unsign
   }
 
   if (args.length() != 1) {
     JS_ReportError(cx, "define takes one argument");
     return false;
   }
 
   jsval arg = args[0];
-  if (JSVAL_IS_PRIMITIVE(arg)) {
+  if (arg.isPrimitive()) {
     JS_ReportError(cx, "argument must be an array");
     return false;
   }
-  RootedObject arr(cx, JSVAL_TO_OBJECT(arg));
+  RootedObject arr(cx, arg.toObjectOrNull());
   if (!JS_IsArrayObject(cx, arr)) {
     JS_ReportError(cx, "argument must be an array");
     return false;
   }
 
   return DefineInternal(cx, obj, arr);
 }
 
@@ -5089,19 +5084,19 @@ StructType::ConstructData(JSContext* cx,
 
 const FieldInfoHash*
 StructType::GetFieldInfo(JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
-  JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
-
-  return static_cast<const FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
+  JS_ASSERT(!slot.isUndefined() && slot.toPrivate());
+
+  return static_cast<const FieldInfoHash*>(slot.toPrivate());
 }
 
 const FieldInfo*
 StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
 {
   JS_ASSERT(CType::IsCType(obj));
   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
 
@@ -5306,20 +5301,20 @@ struct AutoValue
   }
 
   void* mData;
 };
 
 static bool
 GetABI(JSContext* cx, jsval abiType, ffi_abi* result)
 {
-  if (JSVAL_IS_PRIMITIVE(abiType))
-    return false;
-
-  ABICode abi = GetABICode(JSVAL_TO_OBJECT(abiType));
+  if (abiType.isPrimitive())
+    return false;
+
+  ABICode abi = GetABICode(abiType.toObjectOrNull());
 
   // determine the ABI from the subset of those available on the
   // given platform. ABI_DEFAULT specifies the default
   // C calling convention (cdecl) on each platform.
   switch (abi) {
   case ABI_DEFAULT:
     *result = FFI_DEFAULT_ABI;
     return true;
@@ -5338,23 +5333,22 @@ GetABI(JSContext* cx, jsval abiType, ffi
     break;
   }
   return false;
 }
 
 static JSObject*
 PrepareType(JSContext* cx, jsval type)
 {
-  if (JSVAL_IS_PRIMITIVE(type) ||
-      !CType::IsCType(JSVAL_TO_OBJECT(type))) {
+  if (type.isPrimitive() || !CType::IsCType(type.toObjectOrNull())) {
     JS_ReportError(cx, "not a ctypes type");
     return nullptr;
   }
 
-  JSObject* result = JSVAL_TO_OBJECT(type);
+  JSObject* result = type.toObjectOrNull();
   TypeCode typeCode = CType::GetTypeCode(result);
 
   if (typeCode == TYPE_array) {
     // convert array argument types to pointers, just like C.
     // ImplicitConvert will do the same, when passing an array as data.
     RootedObject baseType(cx, ArrayType::GetBaseType(result));
     result = PointerType::CreateInternal(cx, baseType);
     if (!result)
@@ -5375,23 +5369,22 @@ PrepareType(JSContext* cx, jsval type)
   JS_ASSERT(CType::GetSize(result) != 0);
 
   return result;
 }
 
 static JSObject*
 PrepareReturnType(JSContext* cx, jsval type)
 {
-  if (JSVAL_IS_PRIMITIVE(type) ||
-      !CType::IsCType(JSVAL_TO_OBJECT(type))) {
+  if (type.isPrimitive() || !CType::IsCType(type.toObjectOrNull())) {
     JS_ReportError(cx, "not a ctypes type");
     return nullptr;
   }
 
-  JSObject* result = JSVAL_TO_OBJECT(type);
+  JSObject* result = type.toObjectOrNull();
   TypeCode typeCode = CType::GetTypeCode(result);
 
   // Arrays and functions can never be return types.
   if (typeCode == TYPE_array || typeCode == TYPE_function) {
     JS_ReportError(cx, "Return type cannot be an array or function");
     return nullptr;
   }
 
@@ -5405,19 +5398,19 @@ PrepareReturnType(JSContext* cx, jsval t
 
   return result;
 }
 
 static MOZ_ALWAYS_INLINE bool
 IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
 {
   *isEllipsis = false;
-  if (!JSVAL_IS_STRING(v))
+  if (!v.isString())
     return true;
-  JSString* str = JSVAL_TO_STRING(v);
+  JSString* str = v.toString();
   if (str->length() != 3)
     return true;
   const jschar* chars = str->getChars(cx);
   if (!chars)
     return false;
   jschar dot = '.';
   *isEllipsis = (chars[0] == dot &&
                  chars[1] == dot &&
@@ -5519,17 +5512,17 @@ NewFunctionInfo(JSContext* cx,
     return nullptr;
   }
 
   ffi_abi abi;
   if (!GetABI(cx, abiType, &abi)) {
     JS_ReportError(cx, "Invalid ABI specification");
     return nullptr;
   }
-  fninfo->mABI = JSVAL_TO_OBJECT(abiType);
+  fninfo->mABI = abiType.toObjectOrNull();
 
   // prepare the result type
   fninfo->mReturnType = PrepareReturnType(cx, returnType);
   if (!fninfo->mReturnType)
     return nullptr;
 
   // prepare the argument types
   if (!fninfo->mArgTypes.reserve(argLength) ||
@@ -5596,17 +5589,17 @@ FunctionType::Create(JSContext* cx, unsi
     return false;
   }
 
   AutoValueVector argTypes(cx);
   RootedObject arrayObj(cx, nullptr);
 
   if (args.length() == 3) {
     // Prepare an array of jsvals for the arguments.
-    if (!JSVAL_IS_PRIMITIVE(args[2]))
+    if (args[2].isObject())
       arrayObj = &args[2].toObject();
     if (!arrayObj || !JS_IsArrayObject(cx, arrayObj)) {
       JS_ReportError(cx, "third argument must be an array");
       return false;
     }
 
     uint32_t len;
     ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len));
@@ -5802,17 +5795,17 @@ FunctionType::Call(JSContext* cx,
       JS_ReportOutOfMemory(cx);
       return false;
     }
 
     RootedObject obj(cx);  // Could reuse obj instead of declaring a second
     RootedObject type(cx); // RootedObject, but readability would suffer.
 
     for (uint32_t i = argcFixed; i < args.length(); ++i) {
-      if (JSVAL_IS_PRIMITIVE(args[i]) ||
+      if (args[i].isPrimitive() ||
           !CData::IsCData(obj = &args[i].toObject())) {
         // Since we know nothing about the CTypes of the ... arguments,
         // they absolutely must be CData objects already.
         JS_ReportError(cx, "argument %d of type %s is not a CData object",
                        i, JS_GetTypeName(cx, JS_TypeOfValue(cx, args[i])));
         return false;
       }
       if (!(type = CData::GetCType(obj)) ||
@@ -5907,19 +5900,19 @@ FunctionType::Call(JSContext* cx,
 
 FunctionInfo*
 FunctionType::GetFunctionInfo(JSObject* obj)
 {
   JS_ASSERT(CType::IsCType(obj));
   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_function);
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
-  JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
-
-  return static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
+  JS_ASSERT(!slot.isUndefined() && slot.toPrivate());
+
+  return static_cast<FunctionInfo*>(slot.toPrivate());
 }
 
 bool
 FunctionType::IsFunctionType(HandleValue v)
 {
   if (!v.isObject())
     return false;
   JSObject* obj = &v.toObject();
@@ -6025,17 +6018,17 @@ CClosure::Create(JSContext* cx,
 
   // Get a JSContext for use with the closure.
   cinfo->cx = js::DefaultJSContext(JS_GetRuntime(cx));
 
   // Prepare the error sentinel value. It's important to do this now, because
   // we might be unable to convert the value to the proper type. If so, we want
   // the caller to know about it _now_, rather than some uncertain time in the
   // future when the error sentinel is actually needed.
-  if (!JSVAL_IS_VOID(errVal)) {
+  if (!errVal.isUndefined()) {
 
     // Make sure the callback returns something.
     if (CType::GetTypeCode(fninfo->mReturnType) == TYPE_void_t) {
       JS_ReportError(cx, "A void callback can't pass an error sentinel");
       return nullptr;
     }
 
     // With the exception of void, the FunctionType constructor ensures that
@@ -6087,38 +6080,38 @@ CClosure::Create(JSContext* cx,
   return result;
 }
 
 void
 CClosure::Trace(JSTracer* trc, JSObject* obj)
 {
   // Make sure our ClosureInfo slot is legit. If it's not, bail.
   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
 
-  ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
+  ClosureInfo* cinfo = static_cast<ClosureInfo*>(slot.toPrivate());
 
   // Identify our objects to the tracer. (There's no need to identify
   // 'closureObj', since that's us.)
   JS_CallHeapObjectTracer(trc, &cinfo->typeObj, "typeObj");
   JS_CallHeapObjectTracer(trc, &cinfo->jsfnObj, "jsfnObj");
   if (cinfo->thisObj)
     JS_CallHeapObjectTracer(trc, &cinfo->thisObj, "thisObj");
 }
 
 void
 CClosure::Finalize(JSFreeOp *fop, JSObject* obj)
 {
   // Make sure our ClosureInfo slot is legit. If it's not, bail.
   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
 
-  ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
+  ClosureInfo* cinfo = static_cast<ClosureInfo*>(slot.toPrivate());
   FreeOp::get(fop)->delete_(cinfo);
 }
 
 void
 CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
 {
   JS_ASSERT(cif);
   JS_ASSERT(result);
@@ -6290,19 +6283,19 @@ CData::Create(JSContext* cx,
   JS_ASSERT(typeObj);
   JS_ASSERT(CType::IsCType(typeObj));
   JS_ASSERT(CType::IsSizeDefined(typeObj));
   JS_ASSERT(ownResult || source);
   JS_ASSERT_IF(refObj && CData::IsCData(refObj), !ownResult);
 
   // Get the 'prototype' property from the type.
   jsval slot = JS_GetReservedSlot(typeObj, SLOT_PROTO);
-  JS_ASSERT(!JSVAL_IS_PRIMITIVE(slot));
-
-  RootedObject proto(cx, JSVAL_TO_OBJECT(slot));
+  JS_ASSERT(slot.isObject());
+
+  RootedObject proto(cx, &slot.toObject());
   RootedObject parent(cx, JS_GetParent(typeObj));
   JS_ASSERT(parent);
 
   RootedObject dataObj(cx, JS_NewObject(cx, &sCDataClass, proto, parent));
   if (!dataObj)
     return nullptr;
 
   // set the CData's associated type
@@ -6349,50 +6342,50 @@ CData::Create(JSContext* cx,
   return dataObj;
 }
 
 void
 CData::Finalize(JSFreeOp *fop, JSObject* obj)
 {
   // Delete our buffer, and the data it contains if we own it.
   jsval slot = JS_GetReservedSlot(obj, SLOT_OWNS);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
 
-  bool owns = JSVAL_TO_BOOLEAN(slot);
+  bool owns = slot.toBoolean();
 
   slot = JS_GetReservedSlot(obj, SLOT_DATA);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
-  char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
+  char** buffer = static_cast<char**>(slot.toPrivate());
 
   if (owns)
     FreeOp::get(fop)->free_(*buffer);
   FreeOp::get(fop)->delete_(buffer);
 }
 
 JSObject*
 CData::GetCType(JSObject* dataObj)
 {
   JS_ASSERT(CData::IsCData(dataObj));
 
   jsval slot = JS_GetReservedSlot(dataObj, SLOT_CTYPE);
-  JSObject* typeObj = JSVAL_TO_OBJECT(slot);
+  JSObject* typeObj = slot.toObjectOrNull();
   JS_ASSERT(CType::IsCType(typeObj));
   return typeObj;
 }
 
 void*
 CData::GetData(JSObject* dataObj)
 {
   JS_ASSERT(CData::IsCData(dataObj));
 
   jsval slot = JS_GetReservedSlot(dataObj, SLOT_DATA);
 
-  void** buffer = static_cast<void**>(JSVAL_TO_PRIVATE(slot));
+  void** buffer = static_cast<void**>(slot.toPrivate());
   JS_ASSERT(buffer);
   JS_ASSERT(*buffer);
   return *buffer;
 }
 
 bool
 CData::IsCData(JSObject* obj)
 {
@@ -6468,26 +6461,24 @@ bool
 CData::Cast(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 2) {
     JS_ReportError(cx, "cast takes two arguments");
     return false;
   }
 
-  if (JSVAL_IS_PRIMITIVE(args[0]) ||
-      !CData::IsCData(&args[0].toObject())) {
+  if (args[0].isPrimitive() || !CData::IsCData(&args[0].toObject())) {
     JS_ReportError(cx, "first argument must be a CData");
     return false;
   }
   RootedObject sourceData(cx, &args[0].toObject());
   JSObject* sourceType = CData::GetCType(sourceData);
 
-  if (JSVAL_IS_PRIMITIVE(args[1]) ||
-      !CType::IsCType(&args[1].toObject())) {
+  if (args[1].isPrimitive() || !CType::IsCType(&args[1].toObject())) {
     JS_ReportError(cx, "second argument must be a CType");
     return false;
   }
 
   RootedObject targetType(cx, &args[1].toObject());
   size_t targetSize;
   if (!CType::GetSafeSize(targetType, &targetSize) ||
       targetSize > CType::GetSize(sourceType)) {
@@ -6511,18 +6502,17 @@ bool
 CData::GetRuntime(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 1) {
     JS_ReportError(cx, "getRuntime takes one argument");
     return false;
   }
 
-  if (JSVAL_IS_PRIMITIVE(args[0]) ||
-      !CType::IsCType(&args[0].toObject())) {
+  if (args[0].isPrimitive() || !CType::IsCType(&args[0].toObject())) {
     JS_ReportError(cx, "first argument must be a CType");
     return false;
   }
 
   RootedObject targetType(cx, &args[0].toObject());
   size_t targetSize;
   if (!CType::GetSafeSize(targetType, &targetSize) ||
       targetSize != sizeof(void*)) {
@@ -6737,21 +6727,21 @@ CDataFinalizer::Methods::ToSource(JSCont
     JSString *srcValue = CData::GetSourceString(cx, objType, p->cargs);
     if (!srcValue) {
       return false;
     }
     AppendString(source, srcValue);
     AppendString(source, ", ");
     jsval valCodePtrType = JS_GetReservedSlot(objThis,
                                               SLOT_DATAFINALIZER_CODETYPE);
-    if (JSVAL_IS_PRIMITIVE(valCodePtrType)) {
+    if (valCodePtrType.isPrimitive()) {
       return false;
     }
 
-    RootedObject typeObj(cx, JSVAL_TO_OBJECT(valCodePtrType));
+    RootedObject typeObj(cx, valCodePtrType.toObjectOrNull());
     JSString *srcDispose = CData::GetSourceString(cx, typeObj, &(p->code));
     if (!srcDispose) {
       return false;
     }
 
     AppendString(source, srcDispose);
     AppendString(source, ")");
     strMessage = NewUCString(cx, source);
@@ -6808,21 +6798,21 @@ CDataFinalizer::IsCDataFinalizer(JSObjec
 
 JSObject *
 CDataFinalizer::GetCType(JSContext *cx, JSObject *obj)
 {
   MOZ_ASSERT(IsCDataFinalizer(obj));
 
   jsval valData = JS_GetReservedSlot(obj,
                                      SLOT_DATAFINALIZER_VALTYPE);
-  if (JSVAL_IS_VOID(valData)) {
+  if (valData.isUndefined()) {
     return nullptr;
   }
 
-  return JSVAL_TO_OBJECT(valData);
+  return valData.toObjectOrNull();
 }
 
 JSObject*
 CDataFinalizer::GetCData(JSContext *cx, JSObject *obj)
 {
   if (!obj) {
     JS_ReportError(cx, "No C data");
     return nullptr;
@@ -6830,21 +6820,21 @@ CDataFinalizer::GetCData(JSContext *cx, 
   if (CData::IsCData(obj)) {
     return obj;
   }
   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
     JS_ReportError(cx, "Not C data");
     return nullptr;
   }
   RootedValue val(cx);
-  if (!CDataFinalizer::GetValue(cx, obj, val.address()) || JSVAL_IS_PRIMITIVE(val)) {
+  if (!CDataFinalizer::GetValue(cx, obj, val.address()) || val.isPrimitive()) {
     JS_ReportError(cx, "Empty CDataFinalizer");
     return nullptr;
   }
-  return JSVAL_TO_OBJECT(val);
+  return val.toObjectOrNull();
 }
 
 bool
 CDataFinalizer::GetValue(JSContext *cx, JSObject *obj, jsval *aResult)
 {
   MOZ_ASSERT(IsCDataFinalizer(obj));
 
   CDataFinalizer::Private *p = (CDataFinalizer::Private *)
@@ -6988,17 +6978,17 @@ CDataFinalizer::Construct(JSContext* cx,
   if (!objResult) {
     return false;
   }
 
   // If our argument is a CData, it holds a type.
   // This is the type that we should capture, not that
   // of the function, which may be less precise.
   JSObject *objBestArgType = objArgType;
-  if (!JSVAL_IS_PRIMITIVE(valData)) {
+  if (valData.isObject()) {
     JSObject *objData = &valData.toObject();
     if (CData::IsCData(objData)) {
       objBestArgType = CData::GetCType(objData);
       size_t sizeBestArg;
       if (!CType::GetSafeSize(objBestArgType, &sizeBestArg)) {
         MOZ_ASSUME_UNREACHABLE("object with unknown size");
       }
       if (sizeBestArg != sizeArg) {
@@ -7168,24 +7158,24 @@ CDataFinalizer::Methods::Dispose(JSConte
     JS_GetPrivate(obj);
 
   if (!p) {
     JS_ReportError(cx, "dispose called on an empty CDataFinalizer.");
     return false;
   }
 
   jsval valType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_VALTYPE);
-  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valType));
+  JS_ASSERT(valType.isObject());
 
   JSObject *objCTypes = CType::GetGlobalCTypes(cx, &valType.toObject());
   if (!objCTypes)
     return false;
 
   jsval valCodePtrType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_CODETYPE);
-  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCodePtrType));
+  JS_ASSERT(valCodePtrType.isObject());
   JSObject *objCodePtrType = &valCodePtrType.toObject();
 
   JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType);
   JS_ASSERT(objCodeType);
   JS_ASSERT(CType::GetTypeCode(objCodeType) == TYPE_function);
 
   RootedObject resultType(cx, FunctionType::GetFunctionInfo(objCodeType)->mReturnType);
   RootedValue result(cx, JSVAL_VOID);
@@ -7301,28 +7291,28 @@ Int64Base::Construct(JSContext* cx,
 
   return result;
 }
 
 void
 Int64Base::Finalize(JSFreeOp *fop, JSObject* obj)
 {
   jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
-  if (JSVAL_IS_VOID(slot))
+  if (slot.isUndefined())
     return;
 
-  FreeOp::get(fop)->delete_(static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot)));
+  FreeOp::get(fop)->delete_(static_cast<uint64_t*>(slot.toPrivate()));
 }
 
 uint64_t
 Int64Base::GetInt(JSObject* obj) {
   JS_ASSERT(Int64::IsInt64(obj) || UInt64::IsUInt64(obj));
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
-  return *static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot));
+  return *static_cast<uint64_t*>(slot.toPrivate());
 }
 
 bool
 Int64Base::ToString(JSContext* cx,
                     JSObject* obj,
                     const CallArgs& args,
                     bool isUnsigned)
 {
@@ -7403,17 +7393,17 @@ Int64::Construct(JSContext* cx,
   int64_t i = 0;
   if (!jsvalToBigInteger(cx, args[0], true, &i))
     return TypeError(cx, "int64", args[0]);
 
   // Get ctypes.Int64.prototype from the 'prototype' property of the ctor.
   RootedValue slot(cx);
   RootedObject callee(cx, &args.callee());
   ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
-  RootedObject proto(cx, JSVAL_TO_OBJECT(slot));
+  RootedObject proto(cx, slot.toObjectOrNull());
   JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
 
   JSObject* result = Int64Base::Construct(cx, proto, i, false);
   if (!result)
     return false;
 
   args.rval().setObject(*result);
   return true;
@@ -7455,18 +7445,18 @@ Int64::ToSource(JSContext* cx, unsigned 
   return Int64Base::ToSource(cx, obj, args, false);
 }
 
 bool
 Int64::Compare(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 2 ||
-      JSVAL_IS_PRIMITIVE(args[0]) ||
-      JSVAL_IS_PRIMITIVE(args[1]) ||
+      args[0].isPrimitive() ||
+      args[1].isPrimitive() ||
       !Int64::IsInt64(&args[0].toObject()) ||
       !Int64::IsInt64(&args[1].toObject())) {
     JS_ReportError(cx, "compare takes two Int64 arguments");
     return false;
   }
 
   JSObject* obj1 = &args[0].toObject();
   JSObject* obj2 = &args[1].toObject();
@@ -7487,17 +7477,17 @@ Int64::Compare(JSContext* cx, unsigned a
 #define LO_MASK ((uint64_t(1) << 32) - 1)
 #define INT64_LO(i) ((i) & LO_MASK)
 #define INT64_HI(i) ((i) >> 32)
 
 bool
 Int64::Lo(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
+  if (args.length() != 1 || args[0].isPrimitive() ||
       !Int64::IsInt64(&args[0].toObject())) {
     JS_ReportError(cx, "lo takes one Int64 argument");
     return false;
   }
 
   JSObject* obj = &args[0].toObject();
   int64_t u = Int64Base::GetInt(obj);
   double d = uint32_t(INT64_LO(u));
@@ -7505,17 +7495,17 @@ Int64::Lo(JSContext* cx, unsigned argc, 
   args.rval().setNumber(d);
   return true;
 }
 
 bool
 Int64::Hi(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
+  if (args.length() != 1 || args[0].isPrimitive() ||
       !Int64::IsInt64(&args[0].toObject())) {
     JS_ReportError(cx, "hi takes one Int64 argument");
     return false;
   }
 
   JSObject* obj = &args[0].toObject();
   int64_t u = Int64Base::GetInt(obj);
   double d = int32_t(INT64_HI(u));
@@ -7625,18 +7615,18 @@ UInt64::ToSource(JSContext* cx, unsigned
   return Int64Base::ToSource(cx, obj, args, true);
 }
 
 bool
 UInt64::Compare(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 2 ||
-      JSVAL_IS_PRIMITIVE(args[0]) ||
-      JSVAL_IS_PRIMITIVE(args[1]) ||
+      args[0].isPrimitive() ||
+      args[1].isPrimitive() ||
       !UInt64::IsUInt64(&args[0].toObject()) ||
       !UInt64::IsUInt64(&args[1].toObject())) {
     JS_ReportError(cx, "compare takes two UInt64 arguments");
     return false;
   }
 
   JSObject* obj1 = &args[0].toObject();
   JSObject* obj2 = &args[1].toObject();
@@ -7653,17 +7643,17 @@ UInt64::Compare(JSContext* cx, unsigned 
 
   return true;
 }
 
 bool
 UInt64::Lo(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
+  if (args.length() != 1 || args[0].isPrimitive() ||
       !UInt64::IsUInt64(&args[0].toObject())) {
     JS_ReportError(cx, "lo takes one UInt64 argument");
     return false;
   }
 
   JSObject* obj = &args[0].toObject();
   uint64_t u = Int64Base::GetInt(obj);
   double d = uint32_t(INT64_LO(u));
@@ -7671,17 +7661,17 @@ UInt64::Lo(JSContext* cx, unsigned argc,
   args.rval().setDouble(d);
   return true;
 }
 
 bool
 UInt64::Hi(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
+  if (args.length() != 1 || args[0].isPrimitive() ||
       !UInt64::IsUInt64(&args[0].toObject())) {
     JS_ReportError(cx, "hi takes one UInt64 argument");
     return false;
   }
 
   JSObject* obj = &args[0].toObject();
   uint64_t u = Int64Base::GetInt(obj);
   double d = uint32_t(INT64_HI(u));
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -53,20 +53,19 @@ Library::Name(JSContext* cx, unsigned ar
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 1) {
     JS_ReportError(cx, "libraryName takes one argument");
     return false;
   }
 
   Value arg = args[0];
   JSString* str = nullptr;
-  if (JSVAL_IS_STRING(arg)) {
-    str = JSVAL_TO_STRING(arg);
-  }
-  else {
+  if (arg.isString()) {
+    str = arg.toString();
+  } else {
     JS_ReportError(cx, "name argument must be a string");
     return false;
   }
 
   AutoString resultString;
   AppendString(resultString, DLL_PREFIX);
   AppendString(resultString, str);
   AppendString(resultString, DLL_SUFFIX);
@@ -91,23 +90,23 @@ Library::Create(JSContext* cx, jsval pat
 
   // initialize the library
   JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(nullptr));
 
   // attach API functions
   if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions))
     return nullptr;
 
-  if (!JSVAL_IS_STRING(path)) {
+  if (!path.isString()) {
     JS_ReportError(cx, "open takes a string argument");
     return nullptr;
   }
 
   PRLibSpec libSpec;
-  RootedFlatString pathStr(cx, JS_FlattenString(cx, JSVAL_TO_STRING(path)));
+  RootedFlatString pathStr(cx, JS_FlattenString(cx, path.toString()));
   if (!pathStr)
     return nullptr;
 #ifdef XP_WIN
   // On Windows, converting to native charset may corrupt path string.
   // So, we have to use Unicode path directly.
   char16ptr_t pathChars = JS_GetFlatStringChars(pathStr);
   if (!pathChars)
     return nullptr;
@@ -174,17 +173,17 @@ Library::IsLibrary(JSObject* obj)
 }
 
 PRLibrary*
 Library::GetLibrary(JSObject* obj)
 {
   JS_ASSERT(IsLibrary(obj));
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_LIBRARY);
-  return static_cast<PRLibrary*>(JSVAL_TO_PRIVATE(slot));
+  return static_cast<PRLibrary*>(slot.toPrivate());
 }
 
 static void
 UnloadLibrary(JSObject* obj)
 {
   PRLibrary* library = Library::GetLibrary(obj);
   if (library)
     PR_UnloadLibrary(library);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -147,16 +147,40 @@ CanLazilyParse(ExclusiveContext *cx, con
     return options.canLazilyParse &&
         options.compileAndGo &&
         !cx->compartment()->options().discardSource() &&
         !options.sourceIsLazy &&
         !(cx->compartment()->debugMode() &&
           cx->compartment()->runtimeFromAnyThread()->debugHooks.newScriptHook);
 }
 
+static void
+MarkFunctionsWithinEvalScript(JSScript *script)
+{
+    // Mark top level functions in an eval script as being within an eval and,
+    // if applicable, inside a with statement.
+
+    if (!script->hasObjects())
+        return;
+
+    ObjectArray *objects = script->objects();
+    size_t start = script->innerObjectsStart();
+
+    for (size_t i = start; i < objects->length; i++) {
+        JSObject *obj = objects->vector[i];
+        if (obj->is<JSFunction>()) {
+            JSFunction *fun = &obj->as<JSFunction>();
+            if (fun->hasScript())
+                fun->nonLazyScript()->setDirectlyInsideEval();
+            else if (fun->isInterpretedLazy())
+                fun->lazyScript()->setDirectlyInsideEval();
+        }
+    }
+}
+
 void
 frontend::MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
                                  SourceBufferHolder &srcBuf)
 {
     JSSourceHandler listener = cx->runtime()->debugHooks.sourceHandler;
     void *listenerData = cx->runtime()->debugHooks.sourceHandlerData;
 
     if (listener) {
@@ -415,16 +439,22 @@ frontend::CompileScript(ExclusiveContext
     InternalHandle<Bindings*> bindings(script, &script->bindings);
     if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, nullptr,
                                             pc.ref().blockScopeDepth))
         return nullptr;
 
     if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
         return nullptr;
 
+    // Note that this marking must happen before we tell Debugger
+    // about the new script, in case Debugger delazifies the script's
+    // inner functions.
+    if (options.forEval)
+        MarkFunctionsWithinEvalScript(script);
+
     bce.tellDebuggerAboutCompiledScript(cx);
 
     if (sct && !extraSct && !sct->complete())
         return nullptr;
 
     return script;
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-error-scope-unwind-01.js
@@ -0,0 +1,32 @@
+// Tests that exception handling works with block scopes.
+
+var g = newGlobal();
+var dbg = new Debugger(g);
+var correct;
+dbg.onEnterFrame = function (f) {
+  if (f.callee && f.callee.name == "f") {
+    f.onPop = function() {
+      // The scope at the point of onPop is the outermost.
+      correct = (f.environment.getVariable("e") === undefined &&
+                 f.environment.getVariable("outer") === 43);
+    };
+  }
+};
+g.eval("" + function f() {
+  var outer = 43;
+  try {
+    eval("");
+    throw 42;
+  } catch (e) {
+    noSuchFn(e);
+  }
+});
+
+
+try {
+  g.eval("f();");
+} catch (e) {
+  // The above is expected to throw.
+}
+
+assertEq(correct, true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-error-scope-unwind-02.js
@@ -0,0 +1,35 @@
+// Tests that exception handling works with block scopes.
+
+var g = newGlobal();
+var dbg = new Debugger(g);
+var correct;
+dbg.onEnterFrame = function (f) {
+  if (f.callee && f.callee.name == "f") {
+    f.onPop = function() {
+      // The scope at the point of onPop is the outermost.
+      correct = (f.environment.getVariable("e") === undefined &&
+                 f.environment.getVariable("outer") === 43);
+    };
+  }
+};
+g.eval("" + function f() {
+  var outer = 43;
+  // Surround with a loop to insert a loop trynote.
+  for (;;) {
+    try {
+      eval("");
+      throw 42;
+    } catch (e) {
+      noSuchFn(e);
+    }
+  }
+});
+
+
+try {
+  g.eval("f();");
+} catch (e) {
+  // The above is expected to throw.
+}
+
+assertEq(correct, true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getChildScripts-05.js
@@ -0,0 +1,16 @@
+// Test that lazy inner functions inside eval are tagged properly so we don't
+// incorrectly do NAME -> GNAME optimization.
+
+var g = newGlobal();
+var dbg = new Debugger(g);
+dbg.onNewScript = function delazify(script, global) {
+  // Force delazification of inner functions.
+  script.getChildScripts();
+};
+
+g.eval("" + function f() {
+  var $;
+  eval('var obj={foo:1}; $=function() { assertEq(obj.foo, 1); }');
+  return $;
+});
+g.eval("f()();");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1001372.js
@@ -0,0 +1,21 @@
+var lfcode = new Array();
+lfcode.push = loadFile;
+lfcode.push("");
+lfcode.push("");
+lfcode.push("3");
+lfcode.push("");
+lfcode.push("");
+lfcode.push("");
+lfcode.push("");
+lfcode.push("4");
+lfcode.push("");
+lfcode.push("0");
+lfcode.push("gczeal(2);");
+lfcode.push("\
+    var g = newGlobal();\
+    g.parent = this;\
+    g.eval('new Debugger(parent).onExceptionUnwind = function() {};');\
+    ");
+function loadFile(lfVarx) {
+  evaluate(lfVarx);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1002797.js
@@ -0,0 +1,15 @@
+var lfcode = new Array();
+lfcode.push("");
+lfcode.push("0");
+lfcode.push("newGlobal(\"1\").eval(\"(new Debugger).addAllGlobalsAsDebuggees();\");\n");
+while (true) {
+    var file = lfcode.shift(); if (file == undefined) { break; }
+    loadFile(file)
+}
+function loadFile(lfVarx) {
+    try {
+      if (lfVarx.substr(-3) != ".js" && lfVarx.length != 1) {
+        evaluate(lfVarx); 
+      } else if (!isNaN(lfVarx)) {}
+    } catch (lfVare) {    }
+}
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -382,22 +382,22 @@ IsInlinableFallback(ICFallbackStub *icEn
     return icEntry->isCall_Fallback() || icEntry->isGetProp_Fallback() ||
            icEntry->isSetProp_Fallback();
 }
 
 static inline void*
 GetStubReturnAddress(JSContext *cx, jsbytecode *pc)
 {
     if (IsGetPropPC(pc))
-        return cx->compartment()->jitCompartment()->baselineGetPropReturnFromIonAddr();
+        return cx->compartment()->jitCompartment()->baselineGetPropReturnAddr();
     if (IsSetPropPC(pc))
-        return cx->compartment()->jitCompartment()->baselineSetPropReturnFromIonAddr();
+        return cx->compartment()->jitCompartment()->baselineSetPropReturnAddr();
     // This should be a call op of some kind, now.
     JS_ASSERT(IsCallPC(pc));
-    return cx->compartment()->jitCompartment()->baselineCallReturnFromIonAddr();
+    return cx->compartment()->jitCompartment()->baselineCallReturnAddr();
 }
 
 static inline jsbytecode *
 GetNextNonLoopEntryPc(jsbytecode *pc)
 {
     JSOp op = JSOp(*pc);
     if (op == JSOP_GOTO)
         return pc + GET_JUMP_OFFSET(pc);
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -16,39 +16,40 @@
 using namespace mozilla;
 using namespace js;
 using namespace js::jit;
 
 struct DebugModeOSREntry
 {
     JSScript *script;
     BaselineScript *oldBaselineScript;
+    ICStub *oldStub;
+    ICStub *newStub;
     BaselineDebugModeOSRInfo *recompInfo;
     uint32_t pcOffset;
     ICEntry::Kind frameKind;
 
-    // Used for sanity asserts in debug builds.
-    DebugOnly<ICStub *> stub;
-
     DebugModeOSREntry(JSScript *script)
       : script(script),
         oldBaselineScript(script->baselineScript()),
+        oldStub(nullptr),
+        newStub(nullptr),
         recompInfo(nullptr),
         pcOffset(uint32_t(-1)),
-        frameKind(ICEntry::Kind_NonOp),
-        stub(nullptr)
+        frameKind(ICEntry::Kind_NonOp)
     { }
 
     DebugModeOSREntry(JSScript *script, const ICEntry &icEntry)
       : script(script),
         oldBaselineScript(script->baselineScript()),
+        oldStub(nullptr),
+        newStub(nullptr),
         recompInfo(nullptr),
         pcOffset(icEntry.pcOffset()),
-        frameKind(icEntry.kind()),
-        stub(nullptr)
+        frameKind(icEntry.kind())
     {
 #ifdef DEBUG
         MOZ_ASSERT(pcOffset == icEntry.pcOffset());
         MOZ_ASSERT(frameKind == icEntry.kind());
 
         // Assert that if we have a NonOp ICEntry, that there are no unsynced
         // slots, since such a recompile could have only been triggered from
         // either an interrupt check or a debug trap handler.
@@ -66,20 +67,21 @@ struct DebugModeOSREntry
             MOZ_ASSERT(slotInfo.numUnsynced() == 0);
         }
 #endif
     }
 
     DebugModeOSREntry(DebugModeOSREntry &&other)
       : script(other.script),
         oldBaselineScript(other.oldBaselineScript),
+        oldStub(other.oldStub),
+        newStub(other.newStub),
         recompInfo(other.recompInfo ? other.takeRecompInfo() : nullptr),
         pcOffset(other.pcOffset),
-        frameKind(other.frameKind),
-        stub(other.stub)
+        frameKind(other.frameKind)
     { }
 
     ~DebugModeOSREntry() {
         // Note that this is nulled out when the recompInfo is taken by the
         // frame. The frame then has the responsibility of freeing the
         // recompInfo.
         js_delete(recompInfo);
     }
@@ -107,25 +109,30 @@ struct DebugModeOSREntry
         jsbytecode *pc = script->offsetToPC(pcOffset);
 
         // XXX: Work around compiler error disallowing using bitfields
         // with the template magic of new_.
         ICEntry::Kind kind = frameKind;
         recompInfo = cx->new_<BaselineDebugModeOSRInfo>(pc, kind);
         return !!recompInfo;
     }
+
+    ICFallbackStub *fallbackStub() const {
+        MOZ_ASSERT(oldStub);
+        return script->baselineScript()->icEntryFromPCOffset(pcOffset).fallbackStub();
+    }
 };
 
 typedef js::Vector<DebugModeOSREntry> DebugModeOSREntryVector;
 
 static bool
 CollectOnStackScripts(JSContext *cx, const JitActivationIterator &activation,
                       DebugModeOSREntryVector &entries)
 {
-    DebugOnly<ICStub *> prevFrameStubPtr = nullptr;
+    ICStub *prevFrameStubPtr = nullptr;
     bool needsRecompileHandler = false;
     for (JitFrameIterator iter(activation); !iter.done(); ++iter) {
         switch (iter.type()) {
           case JitFrame_BaselineJS: {
             JSScript *script = iter.script();
             uint8_t *retAddr = iter.returnAddressToFp();
             ICEntry &entry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
 
@@ -134,17 +141,17 @@ CollectOnStackScripts(JSContext *cx, con
 
             if (entries.back().needsRecompileInfo()) {
                 if (!entries.back().allocateRecompileInfo(cx))
                     return false;
 
                 needsRecompileHandler |= true;
             }
 
-            entries.back().stub = prevFrameStubPtr;
+            entries.back().oldStub = prevFrameStubPtr;
             prevFrameStubPtr = nullptr;
             break;
           }
 
           case JitFrame_BaselineStub:
             prevFrameStubPtr =
                 reinterpret_cast<IonBaselineStubFrameLayout *>(iter.fp())->maybeStubPtr();
             break;
@@ -170,32 +177,16 @@ CollectOnStackScripts(JSContext *cx, con
         JitRuntime *rt = cx->runtime()->jitRuntime();
         if (!rt->getBaselineDebugModeOSRHandlerAddress(cx, true))
             return false;
     }
 
     return true;
 }
 
-static inline uint8_t *
-GetStubReturnFromStubAddress(JSContext *cx, jsbytecode *pc)
-{
-    JitCompartment *comp = cx->compartment()->jitCompartment();
-    void *addr;
-    if (IsGetPropPC(pc)) {
-        addr = comp->baselineGetPropReturnFromStubAddr();
-    } else if (IsSetPropPC(pc)) {
-        addr = comp->baselineSetPropReturnFromStubAddr();
-    } else {
-        JS_ASSERT(IsCallPC(pc));
-        addr = comp->baselineCallReturnFromStubAddr();
-    }
-    return reinterpret_cast<uint8_t *>(addr);
-}
-
 static const char *
 ICEntryKindToString(ICEntry::Kind kind)
 {
     switch (kind) {
       case ICEntry::Kind_Op:
         return "IC";
       case ICEntry::Kind_NonOp:
         return "non-op IC";
@@ -219,25 +210,21 @@ SpewPatchBaselineFrame(uint8_t *oldRetur
     IonSpew(IonSpew_BaselineDebugModeOSR,
             "Patch return %#016llx -> %#016llx to BaselineJS (%s:%d) from %s at %s",
             uintptr_t(oldReturnAddress), uintptr_t(newReturnAddress),
             script->filename(), script->lineno(),
             ICEntryKindToString(frameKind), js_CodeName[(JSOp)*pc]);
 }
 
 static void
-SpewPatchStubFrame(uint8_t *oldReturnAddress, uint8_t *newReturnAddress,
-                   ICStub *oldStub, ICStub *newStub)
+SpewPatchStubFrame(ICStub *oldStub, ICStub *newStub)
 {
     IonSpew(IonSpew_BaselineDebugModeOSR,
-            "Patch return %#016llx -> %#016llx",
-            uintptr_t(oldReturnAddress), uintptr_t(newReturnAddress));
-    IonSpew(IonSpew_BaselineDebugModeOSR,
-            "Patch   stub %#016llx -> %#016llx to BaselineStub",
-            uintptr_t(oldStub), uintptr_t(newStub));
+            "Patch   stub %#016llx -> %#016llx to BaselineStub (%s)",
+            uintptr_t(oldStub), uintptr_t(newStub), ICStub::KindString(newStub->kind()));
 }
 
 static void
 PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &activation,
                                 DebugModeOSREntryVector &entries, size_t *start)
 {
     //
     // Recompile Patching Overview
@@ -261,51 +248,52 @@ PatchBaselineFramesForDebugMode(JSContex
     // state). Specifics on what need to be done are documented below.
     //
 
     IonCommonFrameLayout *prev = nullptr;
     size_t entryIndex = *start;
     DebugOnly<bool> expectedDebugMode = cx->compartment()->debugMode();
 
     for (JitFrameIterator iter(activation); !iter.done(); ++iter) {
+        DebugModeOSREntry &entry = entries[entryIndex];
         switch (iter.type()) {
           case JitFrame_BaselineJS: {
-            JSScript *script = entries[entryIndex].script;
-            uint32_t pcOffset = entries[entryIndex].pcOffset;
+            JSScript *script = entry.script;
+            uint32_t pcOffset = entry.pcOffset;
             jsbytecode *pc = script->offsetToPC(pcOffset);
 
             MOZ_ASSERT(script == iter.script());
             MOZ_ASSERT(pcOffset < script->length());
             MOZ_ASSERT(script->baselineScript()->debugMode() == expectedDebugMode);
 
             BaselineScript *bl = script->baselineScript();
-            ICEntry::Kind kind = entries[entryIndex].frameKind;
+            ICEntry::Kind kind = entry.frameKind;
 
             if (kind == ICEntry::Kind_Op) {
                 // Case A above.
                 //
                 // Patching this case needs to patch both the stub frame and
                 // the baseline frame. The stub frame is patched below. For
                 // the baseline frame here, we resume right after the IC
                 // returns.
                 //
-                // Since we're using the IC-specific k-fixer, we can resume
+                // Since we're using the same IC stub code, we can resume
                 // directly to the IC resume address.
                 uint8_t *retAddr = bl->returnAddressForIC(bl->icEntryFromPCOffset(pcOffset));
                 SpewPatchBaselineFrame(prev->returnAddress(), retAddr, script, kind, pc);
                 prev->setReturnAddress(retAddr);
                 entryIndex++;
                 break;
             }
 
             bool popFrameReg;
 
             // The RecompileInfo must already be allocated so that this
             // function may be infallible.
-            BaselineDebugModeOSRInfo *recompInfo = entries[entryIndex].takeRecompInfo();
+            BaselineDebugModeOSRInfo *recompInfo = entry.takeRecompInfo();
 
             switch (kind) {
               case ICEntry::Kind_CallVM:
                 // Case B above.
                 //
                 // Patching returns from an interrupt handler or the debugger
                 // statement handler is similar in that we can resume at the
                 // next op.
@@ -358,51 +346,43 @@ PatchBaselineFramesForDebugMode(JSContex
             prev->setReturnAddress(reinterpret_cast<uint8_t *>(handlerAddr));
             iter.baselineFrame()->setDebugModeOSRInfo(recompInfo);
 
             entryIndex++;
             break;
           }
 
           case JitFrame_BaselineStub: {
-            JSScript *script = entries[entryIndex].script;
+            JSScript *script = entry.script;
             IonBaselineStubFrameLayout *layout =
                 reinterpret_cast<IonBaselineStubFrameLayout *>(iter.fp());
             MOZ_ASSERT(script->baselineScript()->debugMode() == expectedDebugMode);
-            MOZ_ASSERT(layout->maybeStubPtr() == entries[entryIndex].stub);
+            MOZ_ASSERT(layout->maybeStubPtr() == entry.oldStub);
 
             // Patch baseline stub frames for case A above.
             //
-            // We need to patch the stub frame return address to go to the
-            // k-fixer that is at the end of fallback stubs of all such
-            // can-call ICs. These k-fixers share code with bailout-from-Ion
-            // fixers, but in this case we are returning from VM and not
-            // Ion. See e.g., JitCompartment::baselineCallReturnFromStubAddr()
+            // We need to patch the stub frame to point to an ICStub belonging
+            // to the recompiled baseline script. These stubs are allocated up
+            // front in CloneOldBaselineStub. They share the same JitCode as
+            // the old baseline script's stubs, so we don't need to patch the
+            // exit frame's return address.
             //
             // Subtlety here: the debug trap handler of case C above pushes a
             // stub frame with a null stub pointer. This handler will exist
             // across recompiling the script, so we don't patch anything for
             // such stub frames. We will return to that handler, which takes
             // care of cleaning up the stub frame.
             //
             // Note that for stub pointers that are already on the C stack
             // (i.e. fallback calls), we need to check for recompilation using
             // DebugModeOSRVolatileStub.
             if (layout->maybeStubPtr()) {
-                MOZ_ASSERT(layout->maybeStubPtr() == entries[entryIndex].stub);
-                uint32_t pcOffset = entries[entryIndex].pcOffset;
-                uint8_t *retAddr = GetStubReturnFromStubAddress(cx, script->offsetToPC(pcOffset));
-
-                // Get the fallback stub for the IC in the recompiled
-                // script. The fallback stub is guaranteed to exist.
-                ICEntry &entry = script->baselineScript()->icEntryFromPCOffset(pcOffset);
-                ICStub *newStub = entry.fallbackStub();
-                SpewPatchStubFrame(prev->returnAddress(), retAddr, layout->maybeStubPtr(), newStub);
-                prev->setReturnAddress(retAddr);
-                layout->setStubPtr(newStub);
+                MOZ_ASSERT(entry.newStub);
+                SpewPatchStubFrame(entry.oldStub, entry.newStub);
+                layout->setStubPtr(entry.newStub);
             }
 
             break;
           }
 
           case JitFrame_IonJS:
             // Nothing to patch.
             entryIndex++;
@@ -428,16 +408,18 @@ RecompileBaselineScriptForDebugMode(JSCo
     // been recompiled.
     bool expectedDebugMode = cx->compartment()->debugMode();
     if (oldBaselineScript->debugMode() == expectedDebugMode)
         return true;
 
     IonSpew(IonSpew_BaselineDebugModeOSR, "Recompiling (%s:%d) for debug mode %s",
             script->filename(), script->lineno(), expectedDebugMode ? "ON" : "OFF");
 
+    CancelOffThreadIonCompile(cx->compartment(), script);
+
     if (script->hasIonScript())
         Invalidate(cx, script, /* resetUses = */ false);
 
     script->setBaselineScript(cx, nullptr);
 
     MethodStatus status = BaselineCompile(cx, script);
     if (status != Method_Compiled) {
         // We will only fail to recompile for debug mode due to OOM. Restore
@@ -449,16 +431,111 @@ RecompileBaselineScriptForDebugMode(JSCo
     }
 
     // Don't destroy the old baseline script yet, since if we fail any of the
     // recompiles we need to rollback all the old baseline scripts.
     MOZ_ASSERT(script->baselineScript()->debugMode() == expectedDebugMode);
     return true;
 }
 
+#define PATCHABLE_ICSTUB_KIND_LIST(_)           \
+    _(Call_Scripted)                            \
+    _(Call_AnyScripted)                         \
+    _(Call_Native)                              \
+    _(Call_ScriptedApplyArray)                  \
+    _(Call_ScriptedApplyArguments)              \
+    _(Call_ScriptedFunCall)                     \
+    _(GetElem_NativePrototypeCallNative)        \
+    _(GetElem_NativePrototypeCallScripted)      \
+    _(GetProp_CallScripted)                     \
+    _(GetProp_CallNative)                       \
+    _(GetProp_CallNativePrototype)              \
+    _(GetProp_CallDOMProxyNative)               \
+    _(GetProp_CallDOMProxyWithGenerationNative) \
+    _(GetProp_DOMProxyShadowed)                 \
+    _(SetProp_CallScripted)                     \
+    _(SetProp_CallNative)
+
+#if JS_HAS_NO_SUCH_METHOD
+#define PATCHABLE_NSM_ICSTUB_KIND_LIST(_)       \
+    _(GetElem_Dense)                            \
+    _(GetElem_Arguments)                        \
+    _(GetProp_NativePrototype)                  \
+    _(GetProp_Native)
+#endif
+
+static bool
+CloneOldBaselineStub(JSContext *cx, DebugModeOSREntryVector &entries, size_t entryIndex)
+{
+    DebugModeOSREntry &entry = entries[entryIndex];
+    if (!entry.oldStub)
+        return true;
+
+    ICStub *oldStub = entry.oldStub;
+    MOZ_ASSERT(ICStub::CanMakeCalls(oldStub->kind()));
+
+    // Get the new fallback stub from the recompiled baseline script.
+    ICFallbackStub *fallbackStub = entry.fallbackStub();
+
+    // We don't need to clone fallback stubs, as they are guaranteed to
+    // exist. Furthermore, their JitCode is cached and should be the same even
+    // across the recompile.
+    if (oldStub->isFallback()) {
+        MOZ_ASSERT(oldStub->jitCode() == fallbackStub->jitCode());
+        entry.newStub = fallbackStub;
+        return true;
+    }
+
+    // Check if we have already cloned the stub on a younger frame.
+    for (size_t i = 0; i < entryIndex; i++) {
+        if (oldStub == entries[i].oldStub) {
+            MOZ_ASSERT(entries[i].newStub);
+            entry.newStub = entries[i].newStub;
+            return true;
+        }
+    }
+
+    // Some stubs are monitored, get the first stub in the monitor chain from
+    // the new fallback stub if so.
+    ICStub *firstMonitorStub;
+    if (fallbackStub->isMonitoredFallback()) {
+        ICMonitoredFallbackStub *monitored = fallbackStub->toMonitoredFallbackStub();
+        firstMonitorStub = monitored->fallbackMonitorStub()->firstMonitorStub();
+    } else {
+        firstMonitorStub = nullptr;
+    }
+    ICStubSpace *stubSpace = ICStubCompiler::StubSpaceForKind(oldStub->kind(), entry.script);
+
+    // Clone the existing stub into the recompiled IC.
+    //
+    // Note that since JitCode is a GC thing, cloning an ICStub with the same
+    // JitCode ensures it won't be collected.
+    switch (oldStub->kind()) {
+#define CASE_KIND(kindName)                                                  \
+      case ICStub::kindName:                                                 \
+        entry.newStub = IC##kindName::Clone(cx, stubSpace, firstMonitorStub, \
+                                            *oldStub->to##kindName());       \
+        break;
+        PATCHABLE_ICSTUB_KIND_LIST(CASE_KIND)
+#if JS_HAS_NO_SUCH_METHOD
+        PATCHABLE_NSM_ICSTUB_KIND_LIST(CASE_KIND)
+#endif
+#undef CASE_KIND
+
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad stub kind");
+    }
+
+    if (!entry.newStub)
+        return false;
+
+    fallbackStub->addNewStub(entry.newStub);
+    return true;
+}
+
 static void
 UndoRecompileBaselineScriptsForDebugMode(JSContext *cx,
                                          const DebugModeOSREntryVector &entries)
 {
     // In case of failure, roll back the entire set of active scripts so that
     // we don't have to patch return addresses on the stack.
     for (size_t i = 0; i < entries.length(); i++) {
         JSScript *script = entries[i].script;
@@ -492,17 +569,20 @@ jit::RecompileOnStackBaselineScriptsForD
         MinorGC(cx->runtime(), JS::gcreason::EVICT_NURSERY);
 #endif
 
     // Try to recompile all the scripts. If we encounter an error, we need to
     // roll back as if none of the compilations happened, so that we don't
     // crash.
     for (size_t i = 0; i < entries.length(); i++) {
         JSScript *script = entries[i].script;
-        if (!RecompileBaselineScriptForDebugMode(cx, script)) {
+
+        if (!RecompileBaselineScriptForDebugMode(cx, script) ||
+            !CloneOldBaselineStub(cx, entries, i))
+        {
             UndoRecompileBaselineScriptsForDebugMode(cx, entries);
             return false;
         }
     }
 
     // If all recompiles succeeded, destroy the old baseline scripts and patch
     // the live frames.
     //
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -58,35 +58,42 @@ class BaselineFrame
         // Frame has profiler entry pushed.
         HAS_PUSHED_SPS_FRAME = 1 << 8,
 
         // Frame has over-recursed on an early check.
         OVER_RECURSED    = 1 << 9,
 
         // Frame has a BaselineRecompileInfo stashed in the scratch value
         // slot. See PatchBaselineFramesForDebugMOde.
-        HAS_DEBUG_MODE_OSR_INFO = 1 << 10
+        HAS_DEBUG_MODE_OSR_INFO = 1 << 10,
+
+        // Frame has had its scope chain unwound to a pc during exception
+        // handling that is different from its current pc.
+        //
+        // This flag is intended for use in the DebugEpilogue. Once it is set,
+        // the only way to clear it is to pop the frame. Do *not* set this if
+        // we will resume execution on the frame, such as in a catch or
+        // finally block.
+        HAS_UNWOUND_SCOPE_OVERRIDE_PC = 1 << 11
     };
 
   protected: // Silence Clang warning about unused private fields.
     // We need to split the Value into 2 fields of 32 bits, otherwise the C++
     // compiler may add some padding between the fields.
     uint32_t loScratchValue_;
     uint32_t hiScratchValue_;
-    uint32_t loReturnValue_;        // If HAS_RVAL, the frame's return value.
+    uint32_t loReturnValue_;              // If HAS_RVAL, the frame's return value.
     uint32_t hiReturnValue_;
     uint32_t frameSize_;
-    JSObject *scopeChain_;          // Scope chain (always initialized).
-    JSScript *evalScript_;          // If isEvalFrame(), the current eval script.
-    ArgumentsObject *argsObj_;      // If HAS_ARGS_OBJ, the arguments object.
-    void *hookData_;                // If HAS_HOOK_DATA, debugger call hook data.
+    JSObject *scopeChain_;                // Scope chain (always initialized).
+    JSScript *evalScript_;                // If isEvalFrame(), the current eval script.
+    ArgumentsObject *argsObj_;            // If HAS_ARGS_OBJ, the arguments object.
+    void *hookData_;                      // If HAS_HOOK_DATA, debugger call hook data.
+    uint32_t unwoundScopeOverrideOffset_; // If HAS_UNWOUND_SCOPE_OVERRIDE_PC.
     uint32_t flags_;
-#if JS_BITS_PER_WORD == 32
-    uint32_t padding_;              // Pad to 8-byte alignment.
-#endif
 
   public:
     // Distance between the frame pointer and the frame header (return address).
     // This is the old frame pointer saved in the prologue.
     static const uint32_t FramePointerOffset = sizeof(void *);
 
     bool initForOsr(InterpreterFrame *fp, uint32_t numStackValues);
 
@@ -315,16 +322,32 @@ class BaselineFrame
 
     void setDebugModeOSRInfo(BaselineDebugModeOSRInfo *info) {
         flags_ |= HAS_DEBUG_MODE_OSR_INFO;
         *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_) = info;
     }
 
     void deleteDebugModeOSRInfo();
 
+    jsbytecode *unwoundScopeOverridePc() {
+        MOZ_ASSERT(flags_ & HAS_UNWOUND_SCOPE_OVERRIDE_PC);
+        return script()->offsetToPC(unwoundScopeOverrideOffset_);
+    }
+
+    jsbytecode *getUnwoundScopeOverridePc() {
+        if (flags_ & HAS_UNWOUND_SCOPE_OVERRIDE_PC)
+            return unwoundScopeOverridePc();
+        return nullptr;
+    }
+
+    void setUnwoundScopeOverridePc(jsbytecode *pc) {
+        flags_ |= HAS_UNWOUND_SCOPE_OVERRIDE_PC;
+        unwoundScopeOverrideOffset_ = script()->pcToOffset(pc);
+    }
+
     void trace(JSTracer *trc, JitFrameIterator &frame);
 
     bool isFunctionFrame() const {
         return CalleeTokenIsFunction(calleeToken());
     }
     bool isGlobalFrame() const {
         return !CalleeTokenIsFunction(calleeToken());
     }
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -666,30 +666,16 @@ ICStubCompiler::enterStubFrame(MacroAsse
 void
 ICStubCompiler::leaveStubFrame(MacroAssembler &masm, bool calledIntoIon)
 {
     JS_ASSERT(entersStubFrame_);
     EmitLeaveStubFrame(masm, calledIntoIon);
 }
 
 void
-ICStubCompiler::leaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon)
-{
-    JS_ASSERT(entersStubFrame_);
-    EmitLeaveStubFrameHead(masm, calledIntoIon);
-}
-
-void
-ICStubCompiler::leaveStubFrameCommonTail(MacroAssembler &masm)
-{
-    JS_ASSERT(entersStubFrame_);
-    EmitLeaveStubFrameCommonTail(masm);
-}
-
-void
 ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
 {
     // This should only be called from the following stubs.
     JS_ASSERT(kind == ICStub::Call_Scripted                             ||
               kind == ICStub::Call_AnyScripted                          ||
               kind == ICStub::Call_Native                               ||
               kind == ICStub::Call_ScriptedApplyArray                   ||
               kind == ICStub::Call_ScriptedApplyArguments               ||
@@ -6494,61 +6480,44 @@ ICGetProp_Fallback::Compiler::generateSt
     // Push arguments.
     masm.pushValue(R0);
     masm.push(BaselineStubReg);
     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
     if (!tailCallVM(DoGetPropFallbackInfo, masm))
         return false;
 
-    // What follows is bailout for inlined scripted getters or for on-stack
-    // debug mode recompile. The return address pointed to by the baseline
-    // stack points here.
-    //
+    // What follows is bailout for inlined scripted getters.
+    // The return address pointed to by the baseline stack points here.
+    returnOffset_ = masm.currentOffset();
+
     // Even though the fallback frame doesn't enter a stub frame, the CallScripted
     // frame that we are emulating does. Again, we lie.
 #ifdef DEBUG
     entersStubFrame_ = true;
 #endif
 
-    Label leaveStubCommon;
-
-    returnFromStubOffset_ = masm.currentOffset();
-    leaveStubFrameHead(masm, false);
-    masm.jump(&leaveStubCommon);
-
-    returnFromIonOffset_ = masm.currentOffset();
-    leaveStubFrameHead(masm, true);
-
-    masm.bind(&leaveStubCommon);
-    leaveStubFrameCommonTail(masm);
+    leaveStubFrame(masm, true);
 
     // When we get here, BaselineStubReg contains the ICGetProp_Fallback stub,
     // which we can't use to enter the TypeMonitor IC, because it's a MonitoredFallbackStub
     // instead of a MonitoredStub. So, we cheat.
     masm.loadPtr(Address(BaselineStubReg, ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
                  BaselineStubReg);
     EmitEnterTypeMonitorIC(masm, ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
 
     return true;
 }
 
 bool
 ICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code)
 {
-    JitCompartment *comp = cx->compartment()->jitCompartment();
-
-    CodeOffsetLabel fromIon(returnFromIonOffset_);
-    fromIon.fixup(&masm);
-    comp->initBaselineGetPropReturnFromIonAddr(code->raw() + fromIon.offset());
-
-    CodeOffsetLabel fromVM(returnFromStubOffset_);
-    fromVM.fixup(&masm);
-    comp->initBaselineGetPropReturnFromStubAddr(code->raw() + fromVM.offset());
-
+    CodeOffsetLabel offset(returnOffset_);
+    offset.fixup(&masm);
+    cx->compartment()->jitCompartment()->initBaselineGetPropReturnAddr(code->raw() + offset.offset());
     return true;
 }
 
 bool
 ICGetProp_ArrayLength::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
@@ -7439,58 +7408,41 @@ ICSetProp_Fallback::Compiler::generateSt
     masm.pushValue(R1);
     masm.pushValue(R0);
     masm.push(BaselineStubReg);
     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
     if (!tailCallVM(DoSetPropFallbackInfo, masm))
         return false;
 
-    // What follows is bailout debug mode recompile code for inlined scripted
-    // getters The return address pointed to by the baseline stack points
-    // here.
-    //
+    // What follows is bailout-only code for inlined script getters.
+    // The return address pointed to by the baseline stack points here.
+    returnOffset_ = masm.currentOffset();
+
     // Even though the fallback frame doesn't enter a stub frame, the CallScripted
     // frame that we are emulating does. Again, we lie.
 #ifdef DEBUG
     entersStubFrame_ = true;
 #endif
 
-    Label leaveStubCommon;
-
-    returnFromStubOffset_ = masm.currentOffset();
-    leaveStubFrameHead(masm, false);
-    masm.jump(&leaveStubCommon);
-
-    returnFromIonOffset_ = masm.currentOffset();
-    leaveStubFrameHead(masm, true);
-
-    masm.bind(&leaveStubCommon);
-    leaveStubFrameCommonTail(masm);
+    leaveStubFrame(masm, true);
 
     // Retrieve the stashed initial argument from the caller's frame before returning
     EmitUnstowICValues(masm, 1);
     EmitReturnFromIC(masm);
 
     return true;
 }
 
 bool
 ICSetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code)
 {
-    JitCompartment *comp = cx->compartment()->jitCompartment();
-
-    CodeOffsetLabel fromIon(returnFromIonOffset_);
-    fromIon.fixup(&masm);
-    comp->initBaselineSetPropReturnFromIonAddr(code->raw() + fromIon.offset());
-
-    CodeOffsetLabel fromVM(returnFromStubOffset_);
-    fromVM.fixup(&masm);
-    comp->initBaselineSetPropReturnFromStubAddr(code->raw() + fromVM.offset());
-
+    CodeOffsetLabel offset(returnOffset_);
+    offset.fixup(&masm);
+    cx->compartment()->jitCompartment()->initBaselineSetPropReturnAddr(code->raw() + offset.offset());
     return true;
 }
 
 bool
 ICSetProp_Native::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
 
@@ -8501,45 +8453,27 @@ ICCall_Fallback::Compiler::generateStubC
     masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
 
     if (!callVM(DoCallFallbackInfo, masm))
         return false;
 
     leaveStubFrame(masm);
     EmitReturnFromIC(masm);
 
-    // The following asmcode is only used either when an Ion inlined frame
-    // bails out into baseline jitcode or we need to do on-stack script
-    // replacement for debug mode recompile.
-    Label leaveStubCommon;
-    returnFromStubOffset_ = masm.currentOffset();
+    // The following asmcode is only used when an Ion inlined frame bails out
+    // into into baseline jitcode. The return address pushed onto the
+    // reconstructed baseline stack points here.
+    returnOffset_ = masm.currentOffset();
 
     // Load passed-in ThisV into R1 just in case it's needed.  Need to do this before
     // we leave the stub frame since that info will be lost.
     // Current stack:  [...., ThisV, ActualArgc, CalleeToken, Descriptor ]
     masm.loadValue(Address(BaselineStackReg, 3 * sizeof(size_t)), R1);
 
-    // Emit the coming-from-VM specific part of the stub-leaving code.
-    leaveStubFrameHead(masm, /* calledIntoIon = */ false);
-
-    // Jump to the common leave stub tail.
-    masm.jump(&leaveStubCommon);
-
-    // For Ion bailouts, the return address pushed onto the reconstructed
-    // baseline stack points here.
-    returnFromIonOffset_ = masm.currentOffset();
-
-    masm.loadValue(Address(BaselineStackReg, 3 * sizeof(size_t)), R1);
-
-    // Emit the coming-from-Ion specific part of the stub-leaving code.
-    leaveStubFrameHead(masm, /* calledIntoIon = */ true);
-
-    // Emit the common stub-leaving tail.
-    masm.bind(&leaveStubCommon);
-    leaveStubFrameCommonTail(masm);
+    leaveStubFrame(masm, true);
 
     // R1 and R0 are taken.
     regs = availableGeneralRegs(2);
     Register scratch = regs.takeAny();
 
     // If this is a |constructing| call, if the callee returns a non-object, we replace it with
     // the |this| object passed in.
     JS_ASSERT(JSReturnOperand == R0);
@@ -8564,26 +8498,19 @@ ICCall_Fallback::Compiler::generateStubC
     EmitEnterTypeMonitorIC(masm, ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
 
     return true;
 }
 
 bool
 ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code)
 {
-    JitCompartment *comp = cx->compartment()->jitCompartment();
-
-    CodeOffsetLabel fromIon(returnFromIonOffset_);
-    fromIon.fixup(&masm);
-    comp->initBaselineCallReturnFromIonAddr(code->raw() + fromIon.offset());
-
-    CodeOffsetLabel fromVM(returnFromStubOffset_);
-    fromVM.fixup(&masm);
-    comp->initBaselineCallReturnFromStubAddr(code->raw() + fromVM.offset());
-
+    CodeOffsetLabel offset(returnOffset_);
+    offset.fixup(&masm);
+    cx->compartment()->jitCompartment()->initBaselineCallReturnAddr(code->raw() + offset.offset());
     return true;
 }
 
 typedef bool (*CreateThisFn)(JSContext *cx, HandleObject callee, MutableHandleValue rval);
 static const VMFunction CreateThisInfoBaseline = FunctionInfo<CreateThisFn>(CreateThis);
 
 bool
 ICCallScriptedCompiler::generateStubCode(MacroAssembler &masm)
@@ -9915,29 +9842,72 @@ ICGetElemNativePrototypeCallStub::ICGetE
                                 AccessType acctype, bool needsAtomize, HandleFunction getter,
                                 uint32_t pcOffset, HandleObject holder, HandleShape holderShape)
   : ICGetElemNativeGetterStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize,
                               getter, pcOffset),
     holder_(holder),
     holderShape_(holderShape)
 {}
 
+/* static */ ICGetElem_NativePrototypeCallNative *
+ICGetElem_NativePrototypeCallNative::Clone(JSContext *cx, ICStubSpace *space,
+                                           ICStub *firstMonitorStub,
+                                           ICGetElem_NativePrototypeCallNative &other)
+{
+    RootedShape shape(cx, other.shape());
+    RootedPropertyName name(cx, other.name());
+    RootedFunction getter(cx, other.getter());
+    RootedObject holder(cx, other.holder());
+    RootedShape holderShape(cx, other.holderShape());
+    return New(space, other.jitCode(), firstMonitorStub, shape, name, other.accessType(),
+               other.needsAtomize(), getter, other.pcOffset_, holder, holderShape);
+}
+
+/* static */ ICGetElem_NativePrototypeCallScripted *
+ICGetElem_NativePrototypeCallScripted::Clone(JSContext *cx, ICStubSpace *space,
+                                             ICStub *firstMonitorStub,
+                                             ICGetElem_NativePrototypeCallScripted &other)
+{
+    RootedShape shape(cx, other.shape());
+    RootedPropertyName name(cx, other.name());
+    RootedFunction getter(cx, other.getter());
+    RootedObject holder(cx, other.holder());
+    RootedShape holderShape(cx, other.holderShape());
+    return New(space, other.jitCode(), firstMonitorStub, shape, name, other.accessType(),
+               other.needsAtomize(), getter, other.pcOffset_, holder, holderShape);
+}
+
 ICGetElem_Dense::ICGetElem_Dense(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape)
     : ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
       shape_(shape)
 { }
 
+/* static */ ICGetElem_Dense *
+ICGetElem_Dense::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                       ICGetElem_Dense &other)
+{
+    RootedShape shape(cx, other.shape_);
+    return New(space, other.jitCode(), firstMonitorStub, shape);
+}
+
 ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type)
   : ICStub(GetElem_TypedArray, stubCode),
     shape_(shape)
 {
     extra_ = uint16_t(type);
     JS_ASSERT(extra_ == type);
 }
 
+/* static */ ICGetElem_Arguments *
+ICGetElem_Arguments::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                           ICGetElem_Arguments &other)
+{
+    return New(space, other.jitCode(), firstMonitorStub, other.which());
+}
+
 ICSetElem_Dense::ICSetElem_Dense(JitCode *stubCode, HandleShape shape, HandleTypeObject type)
   : ICUpdatedStub(SetElem_Dense, stubCode),
     shape_(shape),
     type_(type)
 { }
 
 ICSetElem_DenseAdd::ICSetElem_DenseAdd(JitCode *stubCode, types::TypeObject *type,
                                        size_t protoChainDepth)
@@ -10006,24 +9976,43 @@ ICGetProp_Primitive::ICGetProp_Primitive
 ICGetPropNativeStub::ICGetPropNativeStub(ICStub::Kind kind, JitCode *stubCode,
                                          ICStub *firstMonitorStub,
                                          HandleShape shape, uint32_t offset)
   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
     shape_(shape),
     offset_(offset)
 { }
 
+/* static */ ICGetProp_Native *
+ICGetProp_Native::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                        ICGetProp_Native &other)
+{
+    RootedShape shape(cx, other.shape());
+    return New(space, other.jitCode(), firstMonitorStub, shape, other.offset());
+}
+
 ICGetProp_NativePrototype::ICGetProp_NativePrototype(JitCode *stubCode, ICStub *firstMonitorStub,
                                                      HandleShape shape, uint32_t offset,
                                                      HandleObject holder, HandleShape holderShape)
   : ICGetPropNativeStub(GetProp_NativePrototype, stubCode, firstMonitorStub, shape, offset),
     holder_(holder),
     holderShape_(holderShape)
 { }
 
+/* static */ ICGetProp_NativePrototype *
+ICGetProp_NativePrototype::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                 ICGetProp_NativePrototype &other)
+{
+    RootedShape shape(cx, other.shape());
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    return New(space, other.jitCode(), firstMonitorStub, shape, other.offset(),
+               holder, holderShape);
+}
+
 ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
                                          HandleObject holder, HandleShape holderShape, HandleFunction getter,
                                          uint32_t pcOffset)
   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
     holder_(holder),
     holderShape_(holderShape),
     getter_(getter),
     pcOffset_(pcOffset)
@@ -10039,16 +10028,51 @@ ICGetPropCallPrototypeGetter::ICGetPropC
                                                            HandleShape holderShape,
                                                            HandleFunction getter, uint32_t pcOffset)
   : ICGetPropCallGetter(kind, stubCode, firstMonitorStub, holder, holderShape, getter, pcOffset),
     receiverShape_(receiverShape)
 {
     JS_ASSERT(kind == ICStub::GetProp_CallScripted || kind == ICStub::GetProp_CallNativePrototype);
 }
 
+/* static */ ICGetProp_CallScripted *
+ICGetProp_CallScripted::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                              ICGetProp_CallScripted &other)
+{
+    RootedShape receiverShape(cx, other.receiverShape_);
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction getter(cx, other.getter_);
+    return New(space, other.jitCode(), firstMonitorStub, receiverShape, holder,
+               holderShape, getter, other.pcOffset_);
+}
+
+/* static */ ICGetProp_CallNative *
+ICGetProp_CallNative::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                            ICGetProp_CallNative &other)
+{
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction getter(cx, other.getter_);
+    return New(space, other.jitCode(), firstMonitorStub, holder, holderShape, getter,
+               other.pcOffset_);
+}
+
+/* static */ ICGetProp_CallNativePrototype *
+ICGetProp_CallNativePrototype::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                     ICGetProp_CallNativePrototype &other)
+{
+    RootedShape receiverShape(cx, other.receiverShape_);
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction getter(cx, other.getter_);
+    return New(space, other.jitCode(), firstMonitorStub, receiverShape, holder,
+               holderShape, getter, other.pcOffset_);
+}
+
 ICSetProp_Native::ICSetProp_Native(JitCode *stubCode, HandleTypeObject type, HandleShape shape,
                                    uint32_t offset)
   : ICUpdatedStub(SetProp_Native, stubCode),
     type_(type),
     shape_(shape),
     offset_(offset)
 { }
 
@@ -10115,25 +10139,64 @@ ICSetPropCallSetter::ICSetPropCallSetter
     holder_(holder),
     holderShape_(holderShape),
     setter_(setter),
     pcOffset_(pcOffset)
 {
     JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
 }
 
+/* static */ ICSetProp_CallScripted *
+ICSetProp_CallScripted::Clone(JSContext *cx, ICStubSpace *space, ICStub *,
+                              ICSetProp_CallScripted &other)
+{
+    RootedShape shape(cx, other.shape_);
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction setter(cx, other.setter_);
+    return New(space, other.jitCode(), shape, holder, holderShape, setter, other.pcOffset_);
+}
+
+/* static */ ICSetProp_CallNative *
+ICSetProp_CallNative::Clone(JSContext *cx, ICStubSpace *space, ICStub *,
+                            ICSetProp_CallNative &other)
+{
+    RootedShape shape(cx, other.shape_);
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction setter(cx, other.setter_);
+    return New(space, other.jitCode(), shape, holder, holderShape, setter, other.pcOffset_);
+}
+
 ICCall_Scripted::ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
                                  HandleScript calleeScript, HandleObject templateObject,
                                  uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
     calleeScript_(calleeScript),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 { }
 
+/* static */ ICCall_Scripted *
+ICCall_Scripted::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                       ICCall_Scripted &other)
+{
+    RootedScript calleeScript(cx, other.calleeScript_);
+    RootedObject templateObject(cx, other.templateObject_);
+    return New(space, other.jitCode(), firstMonitorStub, calleeScript, templateObject,
+               other.pcOffset_);
+}
+
+/* static */ ICCall_AnyScripted *
+ICCall_AnyScripted::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                          ICCall_AnyScripted &other)
+{
+    return New(space, other.jitCode(), firstMonitorStub, other.pcOffset_);
+}
+
 ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
                              HandleFunction callee, HandleObject templateObject,
                              uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
     callee_(callee),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 {
@@ -10141,16 +10204,48 @@ ICCall_Native::ICCall_Native(JitCode *st
     // The simulator requires VM calls to be redirected to a special swi
     // instruction to handle them. To make this work, we store the redirected
     // pointer in the stub.
     native_ = Simulator::RedirectNativeFunction(JS_FUNC_TO_DATA_PTR(void *, callee->native()),
                                                 Args_General3);
 #endif
 }
 
+/* static */ ICCall_Native *
+ICCall_Native::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                     ICCall_Native &other)
+{
+    RootedFunction callee(cx, other.callee_);
+    RootedObject templateObject(cx, other.templateObject_);
+    return New(space, other.jitCode(), firstMonitorStub, callee, templateObject,
+               other.pcOffset_);
+}
+
+/* static */ ICCall_ScriptedApplyArray *
+ICCall_ScriptedApplyArray::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                                 ICCall_ScriptedApplyArray &other)
+{
+    return New(space, other.jitCode(), firstMonitorStub, other.pcOffset_);
+}
+
+/* static */ ICCall_ScriptedApplyArguments *
+ICCall_ScriptedApplyArguments::Clone(JSContext *, ICStubSpace *space,
+                                     ICStub *firstMonitorStub,
+                                     ICCall_ScriptedApplyArguments &other)
+{
+    return New(space, other.jitCode(), firstMonitorStub, other.pcOffset_);
+}
+
+/* static */ ICCall_ScriptedFunCall *
+ICCall_ScriptedFunCall::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                              ICCall_ScriptedFunCall &other)
+{
+    return New(space, other.jitCode(), firstMonitorStub, other.pcOffset_);
+}
+
 ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, JitCode *stubCode,
                                                                  ICStub *firstMonitorStub,
                                                                  HandleShape shape,
                                                                  BaseProxyHandler *proxyHandler,
                                                                  HandleShape expandoShape,
                                                                  HandleObject holder,
                                                                  HandleShape holderShape,
                                                                  HandleFunction getter,
@@ -10179,29 +10274,67 @@ ICGetPropCallDOMProxyNativeCompiler::ICG
     getter_(cx, getter),
     pcOffset_(pcOffset)
 {
     JS_ASSERT(kind == ICStub::GetProp_CallDOMProxyNative ||
               kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
     JS_ASSERT(proxy_->handler()->family() == GetDOMProxyHandlerFamily());
 }
 
+/* static */ ICGetProp_CallDOMProxyNative *
+ICGetProp_CallDOMProxyNative::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                    ICGetProp_CallDOMProxyNative &other)
+{
+    RootedShape shape(cx, other.shape_);
+    RootedShape expandoShape(cx, other.expandoShape_);
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction getter(cx, other.getter_);
+    return New(space, other.jitCode(), firstMonitorStub, shape, other.proxyHandler_,
+               expandoShape, holder, holderShape, getter, other.pcOffset_);
+}
+
+/* static */ ICGetProp_CallDOMProxyWithGenerationNative *
+ICGetProp_CallDOMProxyWithGenerationNative::Clone(JSContext *cx, ICStubSpace *space,
+                                                  ICStub *firstMonitorStub,
+                                                  ICGetProp_CallDOMProxyWithGenerationNative &other)
+{
+    RootedShape shape(cx, other.shape_);
+    RootedShape expandoShape(cx, other.expandoShape_);
+    RootedObject holder(cx, other.holder_);
+    RootedShape holderShape(cx, other.holderShape_);
+    RootedFunction getter(cx, other.getter_);
+    return New(space, other.jitCode(), firstMonitorStub, shape, other.proxyHandler_,
+               other.expandoAndGeneration_, other.generation_,
+               expandoShape, holder, holderShape, getter, other.pcOffset_);
+}
+
 ICGetProp_DOMProxyShadowed::ICGetProp_DOMProxyShadowed(JitCode *stubCode,
                                                        ICStub *firstMonitorStub,
                                                        HandleShape shape,
                                                        BaseProxyHandler *proxyHandler,
                                                        HandlePropertyName name,
                                                        uint32_t pcOffset)
   : ICMonitoredStub(ICStub::GetProp_DOMProxyShadowed, stubCode, firstMonitorStub),
     shape_(shape),
     proxyHandler_(proxyHandler),
     name_(name),
     pcOffset_(pcOffset)
 { }
 
+/* static */ ICGetProp_DOMProxyShadowed *
+ICGetProp_DOMProxyShadowed::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                  ICGetProp_DOMProxyShadowed &other)
+{
+    RootedShape shape(cx, other.shape_);
+    RootedPropertyName name(cx, other.name_);
+    return New(space, other.jitCode(), firstMonitorStub, shape, other.proxyHandler_,
+               name, other.pcOffset_);
+}
+
 //
 // Rest_Fallback
 //
 
 static bool DoRestFallback(JSContext *cx, ICRest_Fallback *stub,
                            BaselineFrame *frame, MutableHandleValue res)
 {
     unsigned numFormals = frame->numFormalArgs() - 1;
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1087,18 +1087,16 @@ class ICStubCompiler
     // checked is already in R0.
     bool callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset);
 
     // A stub frame is used when a stub wants to call into the VM without
     // performing a tail call. This is required for the return address
     // to pc mapping to work.
     void enterStubFrame(MacroAssembler &masm, Register scratch);
     void leaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false);
-    void leaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false);
-    void leaveStubFrameCommonTail(MacroAssembler &masm);
 
     // Some stubs need to emit SPS profiler updates.  This emits the guarding
     // jitcode for those stubs.  If profiling is not enabled, jumps to the
     // given label.
     void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip);
 
     // Higher-level helper to emit an update to the profiler pseudo-stack.
     void emitProfilingUpdate(MacroAssembler &masm, Register pcIdx, Register scratch,
@@ -1142,21 +1140,25 @@ class ICStubCompiler
 #ifdef JSGC_GENERATIONAL
     inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
                                          Register scratch, GeneralRegisterSet saveRegs);
 #endif
 
   public:
     virtual ICStub *getStub(ICStubSpace *space) = 0;
 
-    ICStubSpace *getStubSpace(JSScript *script) {
+    static ICStubSpace *StubSpaceForKind(ICStub::Kind kind, JSScript *script) {
         if (ICStub::CanMakeCalls(kind))
             return script->baselineScript()->fallbackStubSpace();
         return script->zone()->jitZone()->optimizedStubSpace();
     }
+
+    ICStubSpace *getStubSpace(JSScript *script) {
+        return StubSpaceForKind(kind, script);
+    }
 };
 
 // Base class for stub compilers that can generate multiple stubcodes.
 // These compilers need access to the JSOp they are compiling for.
 class ICMultiStubCompiler : public ICStubCompiler
 {
   protected:
     JSOp op;
@@ -3155,27 +3157,31 @@ class ICGetElem_NativePrototypeCallNativ
                     HandleObject holder, HandleShape holderShape)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_NativePrototypeCallNative>(
                         code, firstMonitorStub, shape, name, acctype, needsAtomize, getter,
                         pcOffset, holder, holderShape);
     }
+
+    static ICGetElem_NativePrototypeCallNative *Clone(JSContext *cx, ICStubSpace *space,
+                                                      ICStub *firstMonitorStub,
+                                                      ICGetElem_NativePrototypeCallNative &other);
 };
 
 class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub
 {
     friend class ICStubSpace;
 
     ICGetElem_NativePrototypeCallScripted(JitCode *stubCode, ICStub *firstMonitorStub,
-                                        HandleShape shape, HandlePropertyName name,
-                                        AccessType acctype, bool needsAtomize,
-                                        HandleFunction getter, uint32_t pcOffset,
-                                        HandleObject holder, HandleShape holderShape)
+                                          HandleShape shape, HandlePropertyName name,
+                                          AccessType acctype, bool needsAtomize,
+                                          HandleFunction getter, uint32_t pcOffset,
+                                          HandleObject holder, HandleShape holderShape)
       : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallScripted,
                                          stubCode, firstMonitorStub, shape, name,
                                          acctype, needsAtomize, getter, pcOffset, holder,
                                          holderShape)
     {}
 
   public:
     static inline ICGetElem_NativePrototypeCallScripted *New(
@@ -3185,16 +3191,21 @@ class ICGetElem_NativePrototypeCallScrip
                     HandleObject holder, HandleShape holderShape)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_NativePrototypeCallScripted>(
                         code, firstMonitorStub, shape, name, acctype, needsAtomize, getter,
                         pcOffset, holder, holderShape);
     }
+
+    static ICGetElem_NativePrototypeCallScripted *
+    Clone(JSContext *cx, ICStubSpace *space,
+          ICStub *firstMonitorStub,
+          ICGetElem_NativePrototypeCallScripted &other);
 };
 
 // Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
 class ICGetElemNativeCompiler : public ICStubCompiler
 {
     bool isCallElem_;
     ICStub *firstMonitorStub_;
     HandleObject obj_;
@@ -3334,16 +3345,19 @@ class ICGetElem_Dense : public ICMonitor
     static inline ICGetElem_Dense *New(ICStubSpace *space, JitCode *code,
                                        ICStub *firstMonitorStub, HandleShape shape)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_Dense>(code, firstMonitorStub, shape);
     }
 
+    static ICGetElem_Dense *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                  ICGetElem_Dense &other);
+
     static size_t offsetOfShape() {
         return offsetof(ICGetElem_Dense, shape_);
     }
 
     HeapPtrShape &shape() {
         return shape_;
     }
 
@@ -3444,16 +3458,19 @@ class ICGetElem_Arguments : public ICMon
     static inline ICGetElem_Arguments *New(ICStubSpace *space, JitCode *code,
                                            ICStub *firstMonitorStub, Which which)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_Arguments>(code, firstMonitorStub, which);
     }
 
+    static ICGetElem_Arguments *Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                                      ICGetElem_Arguments &other);
+
     Which which() const {
         return static_cast<Which>(extra_);
     }
 
     class Compiler : public ICStubCompiler {
       ICStub *firstMonitorStub_;
       Which which_;
       bool isCallElem_;
@@ -4090,18 +4107,17 @@ class ICGetProp_Fallback : public ICMoni
         extra_ |= (1u << ACCESSED_GETTER_BIT);
     }
     bool hasAccessedGetter() const {
         return extra_ & (1u << ACCESSED_GETTER_BIT);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
-        uint32_t returnFromIonOffset_;
-        uint32_t returnFromStubOffset_;
+        uint32_t returnOffset_;
         bool generateStubCode(MacroAssembler &masm);
         bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::GetProp_Fallback)
         { }
 
@@ -4317,16 +4333,19 @@ class ICGetProp_Native : public ICGetPro
     static inline ICGetProp_Native *New(ICStubSpace *space, JitCode *code,
                                         ICStub *firstMonitorStub, HandleShape shape,
                                         uint32_t offset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_Native>(code, firstMonitorStub, shape, offset);
     }
+
+    static ICGetProp_Native *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                   ICGetProp_Native &other);
 };
 
 // Stub for accessing a property on a native object's prototype. Note that due to
 // the shape teleporting optimization, we only have to guard on the object's shape
 // and the holder's shape.
 class ICGetProp_NativePrototype : public ICGetPropNativeStub
 {
     friend class ICStubSpace;
@@ -4346,16 +4365,20 @@ class ICGetProp_NativePrototype : public
                                                  HandleShape holderShape)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_NativePrototype>(code, firstMonitorStub, shape, offset,
                                                           holder, holderShape);
     }
 
+    static ICGetProp_NativePrototype *Clone(JSContext *cx, ICStubSpace *space,
+                                            ICStub *firstMonitorStub,
+                                            ICGetProp_NativePrototype &other);
+
   public:
     HeapPtrObject &holder() {
         return holder_;
     }
     HeapPtrShape &holderShape() {
         return holderShape_;
     }
     static size_t offsetOfHolder() {
@@ -4549,16 +4572,19 @@ class ICGetProp_CallScripted : public IC
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_CallScripted>(code, firstMonitorStub,
                                                        receiverShape, holder, holderShape, getter,
                                                        pcOffset);
     }
 
+    static ICGetProp_CallScripted *Clone(JSContext *cx, ICStubSpace *space,
+                                         ICStub *firstMonitorStub, ICGetProp_CallScripted &other);
+
     class Compiler : public ICGetPropCallPrototypeGetter::Compiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
                  HandleObject holder, HandleFunction getter, uint32_t pcOffset)
           : ICGetPropCallPrototypeGetter::Compiler(cx, ICStub::GetProp_CallScripted,
@@ -4595,16 +4621,19 @@ class ICGetProp_CallNative : public ICGe
                                             uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_CallNative>(code, firstMonitorStub, obj, shape,
                                                      getter, pcOffset);
     }
 
+    static ICGetProp_CallNative *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                       ICGetProp_CallNative &other);
+
     class Compiler : public ICGetPropCallGetter::Compiler
     {
         bool inputDefinitelyObject_;
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(kind) |
@@ -4648,16 +4677,20 @@ class ICGetProp_CallNativePrototype : pu
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_CallNativePrototype>(code, firstMonitorStub,
                                                               receiverShape, holder, holderShape,
                                                               getter, pcOffset);
     }
 
+    static ICGetProp_CallNativePrototype *Clone(JSContext *cx, ICStubSpace *space,
+                                                ICStub *firstMonitorStub,
+                                                ICGetProp_CallNativePrototype &other);
+
     class Compiler : public ICGetPropCallPrototypeGetter::Compiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
                  HandleObject holder, HandleFunction getter, uint32_t pcOffset)
           : ICGetPropCallPrototypeGetter::Compiler(cx, ICStub::GetProp_CallNativePrototype,
@@ -4766,16 +4799,20 @@ class ICGetProp_CallDOMProxyNative : pub
             HandleFunction getter, uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_CallDOMProxyNative>(code, firstMonitorStub, shape,
                                                    proxyHandler, expandoShape, holder,
                                                    holderShape, getter, pcOffset);
     }
+
+    static ICGetProp_CallDOMProxyNative *Clone(JSContext *cx, ICStubSpace *space,
+                                               ICStub *firstMonitorStub,
+                                               ICGetProp_CallDOMProxyNative &other);
 };
 
 class ICGetProp_CallDOMProxyWithGenerationNative : public ICGetPropCallDOMProxyNativeStub
 {
   protected:
     ExpandoAndGeneration *expandoAndGeneration_;
     uint32_t generation_;
 
@@ -4804,16 +4841,20 @@ class ICGetProp_CallDOMProxyWithGenerati
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_CallDOMProxyWithGenerationNative>(code, firstMonitorStub,
                                                    shape, proxyHandler, expandoAndGeneration,
                                                    generation, expandoShape, holder, holderShape,
                                                    getter, pcOffset);
     }
 
+    static ICGetProp_CallDOMProxyWithGenerationNative *
+    Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+          ICGetProp_CallDOMProxyWithGenerationNative &other);
+
     void *expandoAndGeneration() const {
         return expandoAndGeneration_;
     }
     uint32_t generation() const {
         return generation_;
     }
 
     void setGeneration(uint32_t value) {
@@ -4868,16 +4909,20 @@ class ICGetProp_DOMProxyShadowed : publi
                                                   HandlePropertyName name, uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_DOMProxyShadowed>(code, firstMonitorStub, shape,
                                                            proxyHandler, name, pcOffset);
     }
 
+    static ICGetProp_DOMProxyShadowed *Clone(JSContext *cx, ICStubSpace *space,
+                                             ICStub *firstMonitorStub,
+                                             ICGetProp_DOMProxyShadowed &other);
+
     HeapPtrShape &shape() {
         return shape_;
     }
     HeapPtrPropertyName &name() {
         return name_;
     }
 
     static size_t offsetOfShape() {
@@ -4984,18 +5029,17 @@ class ICSetProp_Fallback : public ICFall
         extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
     bool hadUnoptimizableAccess() const {
         return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
-        uint32_t returnFromIonOffset_;
-        uint32_t returnFromStubOffset_;
+        uint32_t returnOffset_;
         bool generateStubCode(MacroAssembler &masm);
         bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::SetProp_Fallback)
         { }
 
@@ -5269,16 +5313,19 @@ class ICSetProp_CallScripted : public IC
                                               uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICSetProp_CallScripted>(code, shape, holder, holderShape, setter,
                                                        pcOffset);
     }
 
+    static ICSetProp_CallScripted *Clone(JSContext *cx, ICStubSpace *space, ICStub *,
+                                         ICSetProp_CallScripted &other);
+
     class Compiler : public ICSetPropCallSetter::Compiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
                  uint32_t pcOffset)
           : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallScripted,
@@ -5313,16 +5360,19 @@ class ICSetProp_CallNative : public ICSe
                                             uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICSetProp_CallNative>(code, shape, holder, holderShape, setter,
                                                      pcOffset);
     }
 
+    static ICSetProp_CallNative *Clone(JSContext *cx, ICStubSpace *space, ICStub *,
+                                       ICSetProp_CallNative &other);
+
     class Compiler : public ICSetPropCallSetter::Compiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
                  uint32_t pcOffset)
           : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallNative,
@@ -5409,18 +5459,17 @@ class ICCall_Fallback : public ICMonitor
         // Return hasStub(Call_AnyNative) after Call_AnyNative stub is added.
         return false;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         bool isConstructing_;
-        uint32_t returnFromIonOffset_;
-        uint32_t returnFromStubOffset_;
+        uint32_t returnOffset_;
         bool generateStubCode(MacroAssembler &masm);
         bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code);
 
       public:
         Compiler(JSContext *cx, bool isConstructing)
           : ICCallStubCompiler(cx, ICStub::Call_Fallback),
             isConstructing_(isConstructing)
         { }
@@ -5454,16 +5503,19 @@ class ICCall_Scripted : public ICMonitor
             uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_Scripted>(code, firstMonitorStub,
                                                 calleeScript, templateObject, pcOffset);
     }
 
+    static ICCall_Scripted *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                  ICCall_Scripted &other);
+
     HeapPtrScript &calleeScript() {
         return calleeScript_;
     }
     HeapPtrObject &templateObject() {
         return templateObject_;
     }
 
     static size_t offsetOfCalleeScript() {
@@ -5490,16 +5542,19 @@ class ICCall_AnyScripted : public ICMoni
     static inline ICCall_AnyScripted *New(ICStubSpace *space, JitCode *code,
                                           ICStub *firstMonitorStub, uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_AnyScripted>(code, firstMonitorStub, pcOffset);
     }
 
+    static ICCall_AnyScripted *Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                                     ICCall_AnyScripted &other);
+
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_AnyScripted, pcOffset_);
     }
 };
 
 // Compiler for Call_Scripted and Call_AnyScripted stubs.
 class ICCallScriptedCompiler : public ICCallStubCompiler {
   protected:
@@ -5569,16 +5624,19 @@ class ICCall_Native : public ICMonitored
                                      uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_Native>(code, firstMonitorStub,
                                               callee, templateObject, pcOffset);
     }
 
+    static ICCall_Native *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
+                                ICCall_Native &other);
+
     HeapPtrFunction &callee() {
         return callee_;
     }
     HeapPtrObject &templateObject() {
         return templateObject_;
     }
 
     static size_t offsetOfCallee() {
@@ -5648,16 +5706,20 @@ class ICCall_ScriptedApplyArray : public
     static inline ICCall_ScriptedApplyArray *New(ICStubSpace *space, JitCode *code,
                                                  ICStub *firstMonitorStub, uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_ScriptedApplyArray>(code, firstMonitorStub, pcOffset);
     }
 
+    static ICCall_ScriptedApplyArray *Clone(JSContext *, ICStubSpace *space,
+                                            ICStub *firstMonitorStub,
+                                            ICCall_ScriptedApplyArray &other);
+
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_ScriptedApplyArray, pcOffset_);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub *firstMonitorStub_;
@@ -5698,16 +5760,20 @@ class ICCall_ScriptedApplyArguments : pu
     static inline ICCall_ScriptedApplyArguments *New(ICStubSpace *space, JitCode *code,
                                                      ICStub *firstMonitorStub, uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_ScriptedApplyArguments>(code, firstMonitorStub, pcOffset);
     }
 
+    static ICCall_ScriptedApplyArguments *Clone(JSContext *, ICStubSpace *space,
+                                                ICStub *firstMonitorStub,
+                                                ICCall_ScriptedApplyArguments &other);
+
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_ScriptedApplyArguments, pcOffset_);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub *firstMonitorStub_;
@@ -5749,16 +5815,19 @@ class ICCall_ScriptedFunCall : public IC
     static inline ICCall_ScriptedFunCall *New(ICStubSpace *space, JitCode *code,
                                               ICStub *firstMonitorStub, uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_ScriptedFunCall>(code, firstMonitorStub, pcOffset);
     }
 
+    static ICCall_ScriptedFunCall *Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
+                                         ICCall_ScriptedFunCall &other);
+
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_ScriptedFunCall, pcOffset_);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub *firstMonitorStub_;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -453,22 +453,19 @@ jit::RequestInterruptForIonCode(JSRuntim
 
       default:
         MOZ_ASSUME_UNREACHABLE("Bad interrupt mode");
     }
 }
 
 JitCompartment::JitCompartment()
   : stubCodes_(nullptr),
-    baselineCallReturnFromIonAddr_(nullptr),
-    baselineGetPropReturnFromIonAddr_(nullptr),
-    baselineSetPropReturnFromIonAddr_(nullptr),
-    baselineCallReturnFromStubAddr_(nullptr),
-    baselineGetPropReturnFromStubAddr_(nullptr),
-    baselineSetPropReturnFromStubAddr_(nullptr),
+    baselineCallReturnAddr_(nullptr),
+    baselineGetPropReturnAddr_(nullptr),
+    baselineSetPropReturnAddr_(nullptr),
     stringConcatStub_(nullptr),
     parallelStringConcatStub_(nullptr),
     activeParallelEntryScripts_(nullptr)
 {
 }
 
 JitCompartment::~JitCompartment()
 {
@@ -621,29 +618,23 @@ JitCompartment::mark(JSTracer *trc, JSCo
 }
 
 void
 JitCompartment::sweep(FreeOp *fop)
 {
     stubCodes_->sweep(fop);
 
     // If the sweep removed the ICCall_Fallback stub, nullptr the baselineCallReturnAddr_ field.
-    if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::Call_Fallback))) {
-        baselineCallReturnFromIonAddr_ = nullptr;
-        baselineCallReturnFromStubAddr_ = nullptr;
-    }
+    if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::Call_Fallback)))
+        baselineCallReturnAddr_ = nullptr;
     // Similarly for the ICGetProp_Fallback stub.
-    if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::GetProp_Fallback))) {
-        baselineGetPropReturnFromIonAddr_ = nullptr;
-        baselineGetPropReturnFromStubAddr_ = nullptr;
-    }
-    if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::SetProp_Fallback))) {
-        baselineSetPropReturnFromIonAddr_ = nullptr;
-        baselineSetPropReturnFromStubAddr_ = nullptr;
-    }
+    if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::GetProp_Fallback)))
+        baselineGetPropReturnAddr_ = nullptr;
+    if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::SetProp_Fallback)))
+        baselineSetPropReturnAddr_ = nullptr;
 
     if (stringConcatStub_ && !IsJitCodeMarked(stringConcatStub_.unsafeGet()))
         stringConcatStub_ = nullptr;
 
     if (parallelStringConcatStub_ && !IsJitCodeMarked(parallelStringConcatStub_.unsafeGet()))
         parallelStringConcatStub_ = nullptr;
 
     if (activeParallelEntryScripts_) {
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -222,16 +222,23 @@ void
 JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
 {
     JS_ASSERT(isBaselineJS());
     JSScript *script = this->script();
     if (scriptRes)
         *scriptRes = script;
     uint8_t *retAddr = returnAddressToFp();
 
+    // If we have unwound the scope due to exception handling to a different
+    // pc, the frame should behave as if it were settled on that pc.
+    if (jsbytecode *overridePc = baselineFrame()->getUnwoundScopeOverridePc()) {
+        *pcRes = overridePc;
+        return;
+    }
+
     // If we are in the middle of a recompile handler, get the real return
     // address as stashed in the RecompileInfo.
     if (BaselineDebugModeOSRInfo *info = baselineFrame()->getDebugModeOSRInfo())
         retAddr = info->resumeAddr;
 
     if (pcRes) {
         // If the return address is into the prologue entry address or just
         // after the debug prologue, then assume start of script.
@@ -515,18 +522,29 @@ HandleExceptionBaseline(JSContext *cx, c
         // Skip if the try note's stack depth exceeds the frame's stack depth.
         // See the big comment in TryNoteIter::settle for more info.
         JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
         size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
         if (tn->stackDepth > stackDepth)
             continue;
 
         // Unwind scope chain (pop block objects).
-        if (cx->isExceptionPending())
-            UnwindScope(cx, si, script->main() + tn->start);
+        if (cx->isExceptionPending()) {
+            jsbytecode *unwindPc = script->main() + tn->start;
+            UnwindScope(cx, si, unwindPc);
+
+            // If we still need to call DebugEpilogue, we must remember the pc
+            // we unwound the scope chain to, as it will be out of sync with
+            // the frame's actual pc.
+            if (tn->kind != JSTRY_CATCH && tn->kind != JSTRY_FINALLY &&
+                cx->compartment()->debugMode() && !*calledDebugEpilogue)
+            {
+                frame.baselineFrame()->setUnwoundScopeOverridePc(unwindPc);
+            }
+        }
 
         // Compute base pointer and stack pointer.
         rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
         rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
             (script->nfixed() + tn->stackDepth) * sizeof(Value);
 
         switch (tn->kind) {
           case JSTRY_CATCH:
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -359,26 +359,19 @@ class JitCompartment
     friend class JitActivation;
 
     // Map ICStub keys to ICStub shared code objects.
     typedef WeakValueCache<uint32_t, ReadBarrieredJitCode> ICStubCodeMap;
     ICStubCodeMap *stubCodes_;
 
     // Keep track of offset into various baseline stubs' code at return
     // point from called script.
-    void *baselineCallReturnFromIonAddr_;
-    void *baselineGetPropReturnFromIonAddr_;
-    void *baselineSetPropReturnFromIonAddr_;
-
-    // Same as above, but is used for return from a baseline stub. This is
-    // used for recompiles of on-stack baseline scripts (e.g., for debug
-    // mode).
-    void *baselineCallReturnFromStubAddr_;
-    void *baselineGetPropReturnFromStubAddr_;
-    void *baselineSetPropReturnFromStubAddr_;
+    void *baselineCallReturnAddr_;
+    void *baselineGetPropReturnAddr_;
+    void *baselineSetPropReturnAddr_;
 
     // Stub to concatenate two strings inline. Note that it can't be
     // stored in JitRuntime because masm.newGCString bakes in zone-specific
     // pointers. This has to be a weak pointer to avoid keeping the whole
     // compartment alive.
     ReadBarrieredJitCode stringConcatStub_;
     ReadBarrieredJitCode parallelStringConcatStub_;
 
@@ -400,64 +393,39 @@ class JitCompartment
     bool putStubCode(uint32_t key, Handle<JitCode *> stubCode) {
         // Make sure to do a lookupForAdd(key) and then insert into that slot, because
         // that way if stubCode gets moved due to a GC caused by lookupForAdd, then
         // we still write the correct pointer.
         JS_ASSERT(!stubCodes_->has(key));
         ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
         return stubCodes_->add(p, key, stubCode.get());
     }
-    void initBaselineCallReturnFromIonAddr(void *addr) {
-        JS_ASSERT(baselineCallReturnFromIonAddr_ == nullptr);
-        baselineCallReturnFromIonAddr_ = addr;
-    }
-    void *baselineCallReturnFromIonAddr() {
-        JS_ASSERT(baselineCallReturnFromIonAddr_ != nullptr);
-        return baselineCallReturnFromIonAddr_;
-    }
-    void initBaselineGetPropReturnFromIonAddr(void *addr) {
-        JS_ASSERT(baselineGetPropReturnFromIonAddr_ == nullptr);
-        baselineGetPropReturnFromIonAddr_ = addr;
+    void initBaselineCallReturnAddr(void *addr) {
+        JS_ASSERT(baselineCallReturnAddr_ == nullptr);
+        baselineCallReturnAddr_ = addr;
     }
-    void *baselineGetPropReturnFromIonAddr() {
-        JS_ASSERT(baselineGetPropReturnFromIonAddr_ != nullptr);
-        return baselineGetPropReturnFromIonAddr_;
+    void *baselineCallReturnAddr() {
+        JS_ASSERT(baselineCallReturnAddr_ != nullptr);
+        return baselineCallReturnAddr_;
     }
-    void initBaselineSetPropReturnFromIonAddr(void *addr) {
-        JS_ASSERT(baselineSetPropReturnFromIonAddr_ == nullptr);
-        baselineSetPropReturnFromIonAddr_ = addr;
-    }
-    void *baselineSetPropReturnFromIonAddr() {
-        JS_ASSERT(baselineSetPropReturnFromIonAddr_ != nullptr);
-        return baselineSetPropReturnFromIonAddr_;
+    void initBaselineGetPropReturnAddr(void *addr) {
+        JS_ASSERT(baselineGetPropReturnAddr_ == nullptr);
+        baselineGetPropReturnAddr_ = addr;
     }
-
-    void initBaselineCallReturnFromStubAddr(void *addr) {
-        MOZ_ASSERT(baselineCallReturnFromStubAddr_ == nullptr);
-        baselineCallReturnFromStubAddr_ = addr;;
-    }
-    void *baselineCallReturnFromStubAddr() {
-        JS_ASSERT(baselineCallReturnFromStubAddr_ != nullptr);
-        return baselineCallReturnFromStubAddr_;
+    void *baselineGetPropReturnAddr() {
+        JS_ASSERT(baselineGetPropReturnAddr_ != nullptr);
+        return baselineGetPropReturnAddr_;
     }
-    void initBaselineGetPropReturnFromStubAddr(void *addr) {
-        JS_ASSERT(baselineGetPropReturnFromStubAddr_ == nullptr);
-        baselineGetPropReturnFromStubAddr_ = addr;
-    }
-    void *baselineGetPropReturnFromStubAddr() {
-        JS_ASSERT(baselineGetPropReturnFromStubAddr_ != nullptr);
-        return baselineGetPropReturnFromStubAddr_;
+    void initBaselineSetPropReturnAddr(void *addr) {
+        JS_ASSERT(baselineSetPropReturnAddr_ == nullptr);
+        baselineSetPropReturnAddr_ = addr;
     }
-    void initBaselineSetPropReturnFromStubAddr(void *addr) {
-        JS_ASSERT(baselineSetPropReturnFromStubAddr_ == nullptr);
-        baselineSetPropReturnFromStubAddr_ = addr;
-    }
-    void *baselineSetPropReturnFromStubAddr() {
-        JS_ASSERT(baselineSetPropReturnFromStubAddr_ != nullptr);
-        return baselineSetPropReturnFromStubAddr_;
+    void *baselineSetPropReturnAddr() {
+        JS_ASSERT(baselineSetPropReturnAddr_ != nullptr);
+        return baselineSetPropReturnAddr_;
     }
 
     bool notifyOfActiveParallelEntryScript(JSContext *cx, HandleScript script);
 
     void toggleBaselineStubBarriers(bool enabled);
 
     JSC::ExecutableAllocator *createIonAlloc();
 
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1898,17 +1898,17 @@ IonBuilder::inlineAssertFloat32(CallInfo
 {
     callInfo.setImplicitlyUsedUnchecked();
 
     MDefinition *secondArg = callInfo.getArg(1);
 
     JS_ASSERT(secondArg->type() == MIRType_Boolean);
     JS_ASSERT(secondArg->isConstant());
 
-    bool mustBeFloat32 = JSVAL_TO_BOOLEAN(secondArg->toConstant()->value());
+    bool mustBeFloat32 = secondArg->toConstant()->value().toBoolean();
     current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32));
 
     MConstant *undefined = MConstant::New(alloc(), UndefinedValue());
     current->add(undefined);
     current->push(undefined);
     return InliningStatus_Inlined;
 }
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -772,17 +772,19 @@ DebugPrologue(JSContext *cx, BaselineFra
     }
 }
 
 bool
 DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
 {
     // Unwind scope chain to stack depth 0.
     ScopeIter si(frame, pc, cx);
-    UnwindScope(cx, si, frame->script()->main());
+    jsbytecode *unwindPc = frame->script()->main();
+    UnwindScope(cx, si, unwindPc);
+    frame->setUnwoundScopeOverridePc(unwindPc);
 
     // If ScriptDebugEpilogue returns |true| we have to return the frame's
     // return value. If it returns |false|, the debugger threw an exception.
     // In both cases we have to pop debug scopes.
     ok = ScriptDebugEpilogue(cx, frame, pc, ok);
 
     if (frame->isNonEvalFunctionFrame()) {
         JS_ASSERT_IF(ok, frame->hasReturnValue());
--- a/js/src/jit/arm/BaselineHelpers-arm.h
+++ b/js/src/jit/arm/BaselineHelpers-arm.h
@@ -155,52 +155,41 @@ EmitEnterStubFrame(MacroAssembler &masm,
     masm.push(BaselineFrameReg);
     masm.mov(BaselineStackReg, BaselineFrameReg);
 
     // We pushed 4 words, so the stack is still aligned to 8 bytes.
     masm.checkStackAlignment();
 }
 
 inline void
-EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false)
+EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
 {
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
     // in that case we use the frame pointer.
     if (calledIntoIon) {
         masm.pop(ScratchRegister);
         masm.ma_lsr(Imm32(FRAMESIZE_SHIFT), ScratchRegister, ScratchRegister);
         masm.ma_add(ScratchRegister, BaselineStackReg);
     } else {
         masm.mov(BaselineFrameReg, BaselineStackReg);
     }
-}
 
-inline void
-EmitLeaveStubFrameCommonTail(MacroAssembler &masm)
-{
     masm.pop(BaselineFrameReg);
     masm.pop(BaselineStubReg);
 
     // Load the return address.
     masm.pop(BaselineTailCallReg);
 
     // Discard the frame descriptor.
     masm.pop(ScratchRegister);
 }
 
 inline void
-EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
-{
-    EmitLeaveStubFrameHead(masm, calledIntoIon);
-    EmitLeaveStubFrameCommonTail(masm);
-}
-
-inline void
 EmitStowICValues(MacroAssembler &masm, int values)
 {
     JS_ASSERT(values >= 0 && values <= 2);
     switch(values) {
       case 1:
         // Stow R0
         masm.pushValue(R0);
         break;
--- a/js/src/jit/x64/BaselineHelpers-x64.h
+++ b/js/src/jit/x64/BaselineHelpers-x64.h
@@ -136,53 +136,42 @@ EmitEnterStubFrame(MacroAssembler &masm,
 
     // Save old frame pointer, stack pointer and stub reg.
     masm.push(BaselineStubReg);
     masm.push(BaselineFrameReg);
     masm.mov(BaselineStackReg, BaselineFrameReg);
 }
 
 inline void
-EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false)
+EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
 {
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
     // in that case we use the frame pointer.
     if (calledIntoIon) {
         masm.pop(ScratchReg);
         masm.shrq(Imm32(FRAMESIZE_SHIFT), ScratchReg);
         masm.addq(ScratchReg, BaselineStackReg);
     } else {
         masm.mov(BaselineFrameReg, BaselineStackReg);
     }
-}
 
-inline void
-EmitLeaveStubFrameCommonTail(MacroAssembler &masm)
-{
     masm.pop(BaselineFrameReg);
     masm.pop(BaselineStubReg);
 
     // Pop return address.
     masm.pop(BaselineTailCallReg);
 
     // Overwrite frame descriptor with return address, so that the stack matches
     // the state before entering the stub frame.
     masm.storePtr(BaselineTailCallReg, Address(BaselineStackReg, 0));
 }
 
 inline void
-EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
-{
-    EmitLeaveStubFrameHead(masm, calledIntoIon);
-    EmitLeaveStubFrameCommonTail(masm);
-}
-
-inline void
 EmitStowICValues(MacroAssembler &masm, int values)
 {
     JS_ASSERT(values >= 0 && values <= 2);
     switch(values) {
       case 1:
         // Stow R0
         masm.pop(BaselineTailCallReg);
         masm.pushValue(R0);
--- a/js/src/jit/x86/BaselineHelpers-x86.h
+++ b/js/src/jit/x86/BaselineHelpers-x86.h
@@ -141,54 +141,43 @@ EmitEnterStubFrame(MacroAssembler &masm,
 
     // Save old frame pointer, stack pointer and stub reg.
     masm.push(BaselineStubReg);
     masm.push(BaselineFrameReg);
     masm.mov(BaselineStackReg, BaselineFrameReg);
 }
 
 inline void
-EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false)
+EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
 {
     // Ion frames do not save and restore the frame pointer. If we called
     // into Ion, we have to restore the stack pointer from the frame descriptor.
     // If we performed a VM call, the descriptor has been popped already so
     // in that case we use the frame pointer.
     if (calledIntoIon) {
         Register scratch = BaselineTailCallReg;
         masm.pop(scratch);
         masm.shrl(Imm32(FRAMESIZE_SHIFT), scratch);
         masm.addl(scratch, BaselineStackReg);
     } else {
         masm.mov(BaselineFrameReg, BaselineStackReg);
     }
-}
 
-inline void
-EmitLeaveStubFrameCommonTail(MacroAssembler &masm)
-{
     masm.pop(BaselineFrameReg);
     masm.pop(BaselineStubReg);
 
     // Pop return address.
     masm.pop(BaselineTailCallReg);
 
     // Overwrite frame descriptor with return address, so that the stack matches
     // the state before entering the stub frame.
     masm.storePtr(BaselineTailCallReg, Address(BaselineStackReg, 0));
 }
 
 inline void
-EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
-{
-    EmitLeaveStubFrameHead(masm, calledIntoIon);
-    EmitLeaveStubFrameCommonTail(masm);
-}
-
-inline void
 EmitStowICValues(MacroAssembler &masm, int values)
 {
     JS_ASSERT(values >= 0 && values <= 2);
     switch(values) {
       case 1:
         // Stow R0
         masm.pop(BaselineTailCallReg);
         masm.pushValue(R0);
--- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp
+++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp
@@ -48,17 +48,17 @@ BEGIN_TEST(testAddPropertyHook)
 
     CHECK(JS_DefineProperty(cx, global, "arr", arr, JSPROP_ENUMERATE,
                             JS_PropertyStub, JS_StrictPropertyStub));
 
     for (int i = 0; i < ExpectedCount; ++i) {
         obj = JS_NewObject(cx, &AddPropertyClass, JS::NullPtr(), JS::NullPtr());
         CHECK(obj);
         JS::RootedValue vobj(cx, OBJECT_TO_JSVAL(obj));
-        JS::RootedObject arrObj(cx, JSVAL_TO_OBJECT(arr));
+        JS::RootedObject arrObj(cx, arr.toObjectOrNull());
         CHECK(JS_DefineElement(cx, arrObj, i, vobj,
                                JS_PropertyStub, JS_StrictPropertyStub,
                                JSPROP_ENUMERATE));
     }
 
     // Now add a prop to each of the objects, but make sure to do
     // so at the same bytecode location so we can hit the propcache.
     EXEC("'use strict';                                     \n"
--- a/js/src/jsapi-tests/testArgumentsObject.cpp
+++ b/js/src/jsapi-tests/testArgumentsObject.cpp
@@ -78,17 +78,17 @@ static const size_t MAX_ELEMS = 6;
 
 template<size_t ArgCount> bool
 ExhaustiveTest(const char funcode[])
 {
     RootedValue v(cx);
     EVAL(funcode, &v);
 
     EVAL(CALL_CODES[ArgCount], &v);
-    Rooted<ArgumentsObject*> argsobj(cx, &JSVAL_TO_OBJECT(v)->as<ArgumentsObject>());
+    Rooted<ArgumentsObject*> argsobj(cx, &v.toObjectOrNull()->as<ArgumentsObject>());
 
     JS::AutoValueArray<MAX_ELEMS> elems(cx);
 
     for (size_t i = 0; i <= ArgCount; i++) {
         for (size_t j = 0; j <= ArgCount - i; j++) {
             ClearElements(elems);
             CHECK(argsobj->maybeGetElements(i, j, elems.begin()));
             for (size_t k = 0; k < j; k++)
--- a/js/src/jsapi-tests/testBindCallable.cpp
+++ b/js/src/jsapi-tests/testBindCallable.cpp
@@ -9,24 +9,24 @@ BEGIN_TEST(test_BindCallable)
   JS::RootedValue v(cx);
   EVAL("({ somename : 1717 })", &v);
   CHECK(v.isObject());
 
   JS::RootedValue func(cx);
   EVAL("(function() { return this.somename; })", &func);
   CHECK(func.isObject());
 
-  JS::RootedObject funcObj(cx, JSVAL_TO_OBJECT(func));
-  JS::RootedObject vObj(cx, JSVAL_TO_OBJECT(v));
+  JS::RootedObject funcObj(cx, func.toObjectOrNull());
+  JS::RootedObject vObj(cx, v.toObjectOrNull());
   JSObject* newCallable = JS_BindCallable(cx, funcObj, vObj);
   CHECK(newCallable);
 
   JS::RootedValue retval(cx);
   JS::RootedValue fun(cx, JS::ObjectValue(*newCallable));
   bool called = JS_CallFunctionValue(cx, JS::NullPtr(), fun, JS::HandleValueArray::empty(), &retval);
   CHECK(called);
 
-  CHECK(JSVAL_IS_INT(retval));
+  CHECK(retval.isInt32());
 
-  CHECK(JSVAL_TO_INT(retval) == 1717);
+  CHECK(retval.toInt32() == 1717);
   return true;
 }
 END_TEST(test_BindCallable)
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -93,17 +93,17 @@ BEGIN_TEST(testChromeBuffer)
                             "}                                          ";
         JS::CompileOptions options(cx);
         options.setFileAndLine("", 0);
         CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
                                        bytes, strlen(bytes), options));
 
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, v, &rval));
-        CHECK(JSVAL_TO_INT(rval) == 100);
+        CHECK(rval.toInt32() == 100);
     }
 
     /*
      * Check that content called from chrome in the reserved-buffer space
      * immediately ooms.
      */
     {
         {
@@ -134,17 +134,17 @@ BEGIN_TEST(testChromeBuffer)
         JS::CompileOptions options(cx);
         options.setFileAndLine("", 0);
         CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
                                        bytes, strlen(bytes), options));
 
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, v, &rval));
         bool match;
-        CHECK(JS_StringEqualsAscii(cx, JSVAL_TO_STRING(rval), "From trusted: InternalError: too much recursion", &match));
+        CHECK(JS_StringEqualsAscii(cx, rval.toString(), "From trusted: InternalError: too much recursion", &match));
         CHECK(match);
     }
 
     /*
      * Check that JS_SaveFrameChain called on the way from content to chrome
      * (say, as done by XPCJSContextSTack::Push) works.
      */
     {
@@ -171,17 +171,17 @@ BEGIN_TEST(testChromeBuffer)
         JS::CompileOptions options(cx);
         options.setFileAndLine("", 0);
         CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
                                        bytes, strlen(bytes), options));
 
         JS::RootedValue arg(cx, JS::ObjectValue(*callTrusted));
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, arg, &rval));
-        CHECK(JSVAL_TO_INT(rval) == 42);
+        CHECK(rval.toInt32() == 42);
     }
 
     return true;
 }
 virtual void uninit() {
     trusted_glob = nullptr;
     trusted_fun = nullptr;
     JS::RemoveObjectRoot(cx, &trusted_glob);
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ b/js/src/jsapi-tests/testConservativeGC.cpp
@@ -10,50 +10,50 @@
 #include "vm/String.h"
 
 BEGIN_TEST(testConservativeGC)
 {
     JS::RootedValue v2(cx);
     EVAL("({foo: 'bar'});", &v2);
     CHECK(v2.isObject());
     char objCopy[sizeof(JSObject)];
-    js_memcpy(&objCopy, JSVAL_TO_OBJECT(v2), sizeof(JSObject));
+    js_memcpy(&objCopy, v2.toObjectOrNull(), sizeof(JSObject));
 
     JS::RootedValue v3(cx);
     EVAL("String(Math.PI);", &v3);
-    CHECK(JSVAL_IS_STRING(v3));
+    CHECK(v3.isString());
     char strCopy[sizeof(JSString)];
-    js_memcpy(&strCopy, JSVAL_TO_STRING(v3), sizeof(JSString));
+    js_memcpy(&strCopy, v3.toString(), sizeof(JSString));
 
     JS::RootedValue tmp(cx);
     EVAL("({foo2: 'bar2'});", &tmp);
     CHECK(tmp.isObject());
-    JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(tmp));
+    JS::RootedObject obj2(cx, tmp.toObjectOrNull());
     char obj2Copy[sizeof(JSObject)];
     js_memcpy(&obj2Copy, obj2, sizeof(JSObject));
 
     EVAL("String(Math.sqrt(3));", &tmp);
-    CHECK(JSVAL_IS_STRING(tmp));
-    JS::RootedString str2(cx, JSVAL_TO_STRING(tmp));
+    CHECK(tmp.isString());
+    JS::RootedString str2(cx, tmp.toString());
     char str2Copy[sizeof(JSString)];
     js_memcpy(&str2Copy, str2, sizeof(JSString));
 
     tmp = JSVAL_NULL;
 
     JS_GC(rt);
 
     EVAL("var a = [];\n"
          "for (var i = 0; i != 10000; ++i) {\n"
          "a.push(i + 0.1, [1, 2], String(Math.sqrt(i)), {a: i});\n"
          "}", &tmp);
 
     JS_GC(rt);
 
-    checkObjectFields((JSObject *)objCopy, JSVAL_TO_OBJECT(v2));
-    CHECK(!memcmp(strCopy, JSVAL_TO_STRING(v3), sizeof(strCopy)));
+    checkObjectFields((JSObject *)objCopy, v2.toObjectOrNull());
+    CHECK(!memcmp(strCopy, v3.toString(), sizeof(strCopy)));
 
     checkObjectFields((JSObject *)obj2Copy, obj2);
     CHECK(!memcmp(str2Copy, str2, sizeof(str2Copy)));
 
     return true;
 }
 
 bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
--- a/js/src/jsapi-tests/testCustomIterator.cpp
+++ b/js/src/jsapi-tests/testCustomIterator.cpp
@@ -69,15 +69,15 @@ BEGIN_TEST(testCustomIterator_bug612523)
                        IterClassConstructor, 0, nullptr, nullptr, nullptr, nullptr));
 
     JS::RootedValue result(cx);
     EVAL("var o = new HasCustomIter(); \n"
          "var j = 0; \n"
          "for (var i in o) { ++j; }; \n"
          "j;", &result);
 
-    CHECK(JSVAL_IS_INT(result));
-    CHECK_EQUAL(JSVAL_TO_INT(result), 100);
+    CHECK(result.isInt32());
+    CHECK_EQUAL(result.toInt32(), 100);
     CHECK_EQUAL(iterCount, 101);
 
     return true;
 }
 END_TEST(testCustomIterator_bug612523)
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -43,17 +43,17 @@ END_TEST(testDebugger_bug519719)
 static void *
 nonStrictThisHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, bool before,
                   bool *ok, void *closure)
 {
     if (before) {
         bool *allWrapped = (bool *) closure;
         JS::RootedValue thisv(cx);
         frame.getThisValue(cx, &thisv);
-        *allWrapped = *allWrapped && !JSVAL_IS_PRIMITIVE(thisv);
+        *allWrapped = *allWrapped && !thisv.isPrimitive();
     }
     return nullptr;
 }
 
 BEGIN_TEST(testDebugger_getThisNonStrict)
 {
     bool allWrapped = true;
     CHECK(JS_SetDebugMode(cx, true));
@@ -82,17 +82,17 @@ END_TEST(testDebugger_getThisNonStrict)
 static void *
 strictThisHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, bool before,
                bool *ok, void *closure)
 {
     if (before) {
         bool *anyWrapped = (bool *) closure;
         JS::RootedValue thisv(cx);
         frame.getThisValue(cx, &thisv);
-        *anyWrapped = *anyWrapped || !JSVAL_IS_PRIMITIVE(thisv);
+        *anyWrapped = *anyWrapped || !thisv.isPrimitive();
     }
     return nullptr;
 }
 
 BEGIN_TEST(testDebugger_getThisStrict)
 {
     bool anyWrapped = false;
     CHECK(JS_SetDebugMode(cx, true));
--- a/js/src/jsapi-tests/testDeepFreeze.cpp
+++ b/js/src/jsapi-tests/testDeepFreeze.cpp
@@ -6,34 +6,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testDeepFreeze_bug535703)
 {
     JS::RootedValue v(cx);
     EVAL("var x = {}; x;", &v);
-    JS::RootedObject obj(cx, JSVAL_TO_OBJECT(v));
+    JS::RootedObject obj(cx, v.toObjectOrNull());
     CHECK(JS_DeepFreezeObject(cx, obj));  // don't crash
     EVAL("Object.isFrozen(x)", &v);
     CHECK_SAME(v, JSVAL_TRUE);
     return true;
 }
 END_TEST(testDeepFreeze_bug535703)
 
 BEGIN_TEST(testDeepFreeze_deep)
 {
     JS::RootedValue a(cx), o(cx);
     EXEC("var a = {}, o = a;\n"
          "for (var i = 0; i < 5000; i++)\n"
          "    a = {x: a, y: a};\n");
     EVAL("a", &a);
     EVAL("o", &o);
 
-    JS::RootedObject aobj(cx, JSVAL_TO_OBJECT(a));
+    JS::RootedObject aobj(cx, a.toObjectOrNull());
     CHECK(JS_DeepFreezeObject(cx, aobj));
 
     JS::RootedValue b(cx);
     EVAL("Object.isFrozen(a)", &b);
     CHECK_SAME(b, JSVAL_TRUE);
     EVAL("Object.isFrozen(o)", &b);
     CHECK_SAME(b, JSVAL_TRUE);
     return true;
@@ -42,17 +42,17 @@ END_TEST(testDeepFreeze_deep)
 
 BEGIN_TEST(testDeepFreeze_loop)
 {
     JS::RootedValue x(cx), y(cx);
     EXEC("var x = [], y = {x: x}; y.y = y; x.push(x, y);");
     EVAL("x", &x);
     EVAL("y", &y);
 
-    JS::RootedObject xobj(cx, JSVAL_TO_OBJECT(x));
+    JS::RootedObject xobj(cx, x.toObjectOrNull());
     CHECK(JS_DeepFreezeObject(cx, xobj));
 
     JS::RootedValue b(cx);
     EVAL("Object.isFrozen(x)", &b);
     CHECK_SAME(b, JSVAL_TRUE);
     EVAL("Object.isFrozen(y)", &b);
     CHECK_SAME(b, JSVAL_TRUE);
     return true;
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
+++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
@@ -27,17 +27,17 @@ BEGIN_TEST(testDefineGetterSetterNonEnum
     JS::RootedObject funGetObj(cx, JS_GetFunctionObject(funGet));
     JS::RootedValue vget(cx, OBJECT_TO_JSVAL(funGetObj));
 
     JSFunction *funSet = JS_NewFunction(cx, NativeGetterSetter, 1, 0, JS::NullPtr(), "set");
     CHECK(funSet);
     JS::RootedObject funSetObj(cx, JS_GetFunctionObject(funSet));
     JS::RootedValue vset(cx, OBJECT_TO_JSVAL(funSetObj));
 
-    JS::RootedObject vObject(cx, JSVAL_TO_OBJECT(vobj));
+    JS::RootedObject vObject(cx, vobj.toObjectOrNull());
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
                             JS::UndefinedHandleValue,
                             JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE,
                             JS_DATA_TO_FUNC_PTR(JSPropertyOp, (JSObject*) funGetObj),
                             JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, (JSObject*) funSetObj)));
 
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
                             JS::UndefinedHandleValue,
--- a/js/src/jsapi-tests/testDefineProperty.cpp
+++ b/js/src/jsapi-tests/testDefineProperty.cpp
@@ -10,14 +10,14 @@
 BEGIN_TEST(testDefineProperty_bug564344)
 {
     JS::RootedValue x(cx);
     EVAL("function f() {}\n"
          "var x = {p: f};\n"
          "x.p();  // brand x's scope\n"
          "x;", &x);
 
-    JS::RootedObject obj(cx, JSVAL_TO_OBJECT(x));
+    JS::RootedObject obj(cx, x.toObjectOrNull());
     for (int i = 0; i < 2; i++)
         CHECK(JS_DefineProperty(cx, obj, "q", JS::UndefinedHandleValue, JSPROP_SHARED));
     return true;
 }
 END_TEST(testDefineProperty_bug564344)
--- a/js/src/jsapi-tests/testFunctionProperties.cpp
+++ b/js/src/jsapi-tests/testFunctionProperties.cpp
@@ -7,17 +7,17 @@
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testFunctionProperties)
 {
     JS::RootedValue x(cx);
     EVAL("(function f() {})", &x);
 
-    JS::RootedObject obj(cx, JSVAL_TO_OBJECT(x));
+    JS::RootedObject obj(cx, x.toObjectOrNull());
 
     JS::RootedValue y(cx);
     CHECK(JS_GetProperty(cx, obj, "arguments", &y));
     CHECK_SAME(y, JSVAL_NULL);
 
     CHECK(JS_GetProperty(cx, obj, "caller", &y));
     CHECK_SAME(y, JSVAL_NULL);
 
--- a/js/src/jsapi-tests/testIntString.cpp
+++ b/js/src/jsapi-tests/testIntString.cpp
@@ -7,36 +7,36 @@
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testIntString_bug515273)
 {
     JS::RootedValue v(cx);
 
     EVAL("'1';", &v);
-    JSString *str = JSVAL_TO_STRING(v);
+    JSString *str = v.toString();
     CHECK(JS_StringHasBeenInterned(cx, str));
     CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1"));
 
     EVAL("'42';", &v);
-    str = JSVAL_TO_STRING(v);
+    str = v.toString();
     CHECK(JS_StringHasBeenInterned(cx, str));
     CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
 
     EVAL("'111';", &v);
-    str = JSVAL_TO_STRING(v);
+    str = v.toString();
     CHECK(JS_StringHasBeenInterned(cx, str));
     CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111"));
 
     /* Test other types of static strings. */
     EVAL("'a';", &v);
-    str = JSVAL_TO_STRING(v);
+    str = v.toString();
     CHECK(JS_StringHasBeenInterned(cx, str));
     CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a"));
 
     EVAL("'bc';", &v);
-    str = JSVAL_TO_STRING(v);
+    str = v.toString();
     CHECK(JS_StringHasBeenInterned(cx, str));
     CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
 
     return true;
 }
 END_TEST(testIntString_bug515273)
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -18,17 +18,17 @@ BEGIN_TEST(testLookup_bug522590)
     EXEC("function mkobj() { return {f: function () {return 2;}} }");
 
     // Calling mkobj() multiple times must create multiple functions in ES5.
     EVAL("mkobj().f !== mkobj().f", &x);
     CHECK_SAME(x, JSVAL_TRUE);
 
     // Now make x.f a method.
     EVAL("mkobj()", &x);
-    JS::RootedObject xobj(cx, JSVAL_TO_OBJECT(x));
+    JS::RootedObject xobj(cx, x.toObjectOrNull());
 
     // This lookup must not return an internal function object.
     JS::RootedValue r(cx);
     CHECK(JS_LookupProperty(cx, xobj, "f", &r));
     CHECK(r.isObject());
     JSObject *funobj = &r.toObject();
     CHECK(funobj->is<JSFunction>());
     CHECK(!js::IsInternalFunctionObject(funobj));
@@ -52,18 +52,18 @@ static const JSClass DocumentAllClass = 
 bool
 document_resolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                  JS::MutableHandleObject objp)
 {
     // If id is "all", resolve document.all=true.
     JS::RootedValue v(cx);
     if (!JS_IdToValue(cx, id, &v))
         return false;
-    if (JSVAL_IS_STRING(v)) {
-        JSString *str = JSVAL_TO_STRING(v);
+    if (v.isString()) {
+        JSString *str = v.toString();
         JSFlatString *flatStr = JS_FlattenString(cx, str);
         if (!flatStr)
             return false;
         if (JS_FlatStringEqualsAscii(flatStr, "all")) {
             JS::Rooted<JSObject*> docAll(cx,
                                          JS_NewObject(cx, &DocumentAllClass, JS::NullPtr(), JS::NullPtr()));
             if (!docAll)
                 return false;
--- a/js/src/jsapi-tests/testLooselyEqual.cpp
+++ b/js/src/jsapi-tests/testLooselyEqual.cpp
@@ -58,18 +58,18 @@ struct LooseEqualityData
         undef = JSVAL_VOID;
         null = JSVAL_NULL;
         obj = OBJECT_TO_JSVAL(JS::CurrentGlobalOrNull(cx));
         poszero = DOUBLE_TO_JSVAL(0.0);
         negzero = DOUBLE_TO_JSVAL(-0.0);
 #ifdef XP_WIN
 # define copysign _copysign
 #endif
-        JS_ASSERT(copysign(1.0, JSVAL_TO_DOUBLE(poszero)) == 1.0);
-        JS_ASSERT(copysign(1.0, JSVAL_TO_DOUBLE(negzero)) == -1.0);
+        JS_ASSERT(copysign(1.0, poszero.toDouble()) == 1.0);
+        JS_ASSERT(copysign(1.0, negzero.toDouble()) == -1.0);
 #ifdef XP_WIN
 # undef copysign
 #endif
     }
 };
 
 // 11.9.3 1a
 BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_undef_leq_undef)
--- a/js/src/jsapi-tests/testMappedArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp
@@ -123,17 +123,17 @@ bool TestCloneObject()
     JS::RootedObject obj1(cx, CreateNewObject(8, 12));
     CHECK(obj1);
     JSAutoStructuredCloneBuffer cloned_buffer;
     JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1));
     const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx);
     CHECK(cloned_buffer.write(cx, v1, callbacks, nullptr));
     JS::RootedValue v2(cx);
     CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr));
-    JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2));
+    JS::RootedObject obj2(cx, v2.toObjectOrNull());
     CHECK(VerifyObject(obj2, 8, 12, false));
 
     return true;
 }
 
 bool TestStealContents()
 {
     JS::RootedObject obj(cx, CreateNewObject(8, 12));
@@ -159,17 +159,17 @@ bool TestTransferObject()
     CHECK(obj);
     JS::RootedValue transferable(cx, OBJECT_TO_JSVAL(obj));
 
     JSAutoStructuredCloneBuffer cloned_buffer;
     const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx);
     CHECK(cloned_buffer.write(cx, v1, transferable, callbacks, nullptr));
     JS::RootedValue v2(cx);
     CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr));
-    JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2));
+    JS::RootedObject obj2(cx, v2.toObjectOrNull());
     CHECK(VerifyObject(obj2, 8, 12, true));
     CHECK(isNeutered(obj1));
 
     return true;
 }
 
 bool isNeutered(JS::HandleObject obj)
 {
--- a/js/src/jsapi-tests/testNewObject.cpp
+++ b/js/src/jsapi-tests/testNewObject.cpp
@@ -55,17 +55,17 @@ constructHook(JSContext *cx, unsigned ar
 BEGIN_TEST(testNewObject_1)
 {
     static const size_t N = 1000;
     JS::AutoValueVector argv(cx);
     CHECK(argv.resize(N));
 
     JS::RootedValue v(cx);
     EVAL("Array", &v);
-    JS::RootedObject Array(cx, JSVAL_TO_OBJECT(v));
+    JS::RootedObject Array(cx, v.toObjectOrNull());
 
     // With no arguments.
     JS::RootedObject obj(cx, JS_New(cx, Array, JS::HandleValueArray::empty()));
     CHECK(obj);
     JS::RootedValue rt(cx, JS::ObjectValue(*obj));
     CHECK(JS_IsArrayObject(cx, obj));
     uint32_t len;
     CHECK(JS_GetArrayLength(cx, obj, &len));
--- a/js/src/jsapi-tests/testParseJSON.cpp
+++ b/js/src/jsapi-tests/testParseJSON.cpp
@@ -98,41 +98,41 @@ BEGIN_TEST(testParseJSON_success)
     CHECK(TryParse(cx, "\"\\u000A\"", expected));
 
 
     // Arrays
     JS::RootedValue v(cx), v2(cx);
     JS::RootedObject obj(cx);
 
     CHECK(Parse(cx, "[]", &v));
-    CHECK(!JSVAL_IS_PRIMITIVE(v));
-    obj = JSVAL_TO_OBJECT(v);
+    CHECK(v.isObject());
+    obj = &v.toObject();
     CHECK(JS_IsArrayObject(cx, obj));
     CHECK(JS_GetProperty(cx, obj, "length", &v2));
     CHECK_SAME(v2, JSVAL_ZERO);
 
     CHECK(Parse(cx, "[1]", &v));
-    CHECK(!JSVAL_IS_PRIMITIVE(v));
-    obj = JSVAL_TO_OBJECT(v);
+    CHECK(v.isObject());
+    obj = &v.toObject();
     CHECK(JS_IsArrayObject(cx, obj));
     CHECK(JS_GetProperty(cx, obj, "0", &v2));
     CHECK_SAME(v2, JSVAL_ONE);
     CHECK(JS_GetProperty(cx, obj, "length", &v2));
     CHECK_SAME(v2, JSVAL_ONE);
 
 
     // Objects
     CHECK(Parse(cx, "{}", &v));
-    CHECK(!JSVAL_IS_PRIMITIVE(v));
-    obj = JSVAL_TO_OBJECT(v);
+    CHECK(v.isObject());
+    obj = &v.toObject();
     CHECK(!JS_IsArrayObject(cx, obj));
 
     CHECK(Parse(cx, "{ \"f\": 17 }", &v));
-    CHECK(!JSVAL_IS_PRIMITIVE(v));
-    obj = JSVAL_TO_OBJECT(v);
+    CHECK(v.isObject());
+    obj = &v.toObject();
     CHECK(!JS_IsArrayObject(cx, obj));
     CHECK(JS_GetProperty(cx, obj, "f", &v2));
     CHECK_SAME(v2, INT_TO_JSVAL(17));
 
     return true;
 }
 
 template<size_t N> static JSFlatString *
--- a/js/src/jsapi-tests/testRegExp.cpp
+++ b/js/src/jsapi-tests/testRegExp.cpp
@@ -4,53 +4,53 @@
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testObjectIsRegExp)
 {
     JS::RootedValue val(cx);
 
     EVAL("new Object", &val);
-    JS::RootedObject obj(cx, JSVAL_TO_OBJECT(val));
+    JS::RootedObject obj(cx, val.toObjectOrNull());
     CHECK(!JS_ObjectIsRegExp(cx, obj));
 
     EVAL("/foopy/", &val);
-    obj = JSVAL_TO_OBJECT(val);
+    obj = val.toObjectOrNull();
     CHECK(JS_ObjectIsRegExp(cx, obj));
 
     return true;
 }
 END_TEST(testObjectIsRegExp)
 
 BEGIN_TEST(testGetRegExpFlags)
 {
     JS::RootedValue val(cx);
     JS::RootedObject obj(cx);
 
     EVAL("/foopy/", &val);
-    obj = JSVAL_TO_OBJECT(val);
+    obj = val.toObjectOrNull();
     CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), 0);
 
     EVAL("/foopy/g", &val);
-    obj = JSVAL_TO_OBJECT(val);
+    obj = val.toObjectOrNull();
     CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), JSREG_GLOB);
 
     EVAL("/foopy/gi", &val);
-    obj = JSVAL_TO_OBJECT(val);
+    obj = val.toObjectOrNull();
     CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), (JSREG_FOLD | JSREG_GLOB));
 
     return true;
 }
 END_TEST(testGetRegExpFlags)
 
 BEGIN_TEST(testGetRegExpSource)
 {
     JS::RootedValue val(cx);
     JS::RootedObject obj(cx);
 
     EVAL("/foopy/", &val);
-    obj = JSVAL_TO_OBJECT(val);
+    obj = val.toObjectOrNull();
     JSString *source = JS_GetRegExpSource(cx, obj);
     CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(source), "foopy"));
 
     return true;
 }
 END_TEST(testGetRegExpSource)
--- a/js/src/jsapi-tests/testRegExpInstanceProperties.cpp
+++ b/js/src/jsapi-tests/testRegExpInstanceProperties.cpp
@@ -11,28 +11,28 @@
 #include "jsapi-tests/tests.h"
 #include "vm/Shape.h"
 
 BEGIN_TEST(testRegExpInstanceProperties)
 {
     jsval regexpProtoVal;
     EVAL("RegExp.prototype", &regexpProtoVal);
 
-    JSObject *regexpProto = JSVAL_TO_OBJECT(regexpProtoVal);
+    JSObject *regexpProto = regexpProtoVal.toObjectOrNull();
 
     if (!helper(regexpProto))
         return false;
 
     JS_GC(cx);
 
     CHECK_EQUAL(regexpProto->compartment()->initialRegExpShape, nullptr);
 
     jsval regexp;
     EVAL("/foopy/", &regexp);
-    JSObject *robj = JSVAL_TO_OBJECT(regexp);
+    JSObject *robj = regexp.toObjectOrNull();
 
     CHECK(robj->lastProperty());
     CHECK_EQUAL(robj->compartment()->initialRegExpShape, robj->lastProperty());
 
     return true;
 }
 
 /*
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -105,32 +105,32 @@ doResolve(JS::HandleObject obj, JS::Hand
             objp.set(nullptr);
             return true;
         }
     } else if (JS_FlatStringEqualsAscii(str, "y")) {
         if (obj == obj2) {
             CHECK_EQUAL(resolveEntryCount, 2);
             CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_NULL, nullptr, nullptr, 0));
             EVAL("obj1.x", &v);
-            CHECK(JSVAL_IS_VOID(v));
+            CHECK(v.isUndefined());
             EVAL("obj1.y", &v);
             CHECK_SAME(v, JSVAL_ZERO);
             objp.set(obj);
             return true;
         }
         if (obj == obj1) {
             CHECK_EQUAL(resolveEntryCount, 3);
             EVAL("obj1.x", &v);
-            CHECK(JSVAL_IS_VOID(v));
+            CHECK(v.isUndefined());
             EVAL("obj1.y", &v);
-            CHECK(JSVAL_IS_VOID(v));
+            CHECK(v.isUndefined());
             EVAL("obj2.y", &v);
-            CHECK(JSVAL_IS_NULL(v));
+            CHECK(v.isNull());
             EVAL("obj2.x", &v);
-            CHECK(JSVAL_IS_VOID(v));
+            CHECK(v.isUndefined());
             EVAL("obj1.y = 0", &v);
             CHECK_SAME(v, JSVAL_ZERO);
             objp.set(obj);
             return true;
         }
     }
     CHECK(false);
     return false;
--- a/js/src/jsapi-tests/testTrap.cpp
+++ b/js/src/jsapi-tests/testTrap.cpp
@@ -11,17 +11,17 @@
 static int emptyTrapCallCount = 0;
 
 static JSTrapStatus
 EmptyTrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
                  jsval closureArg)
 {
     JS::RootedValue closure(cx, closureArg);
     JS_GC(JS_GetRuntime(cx));
-    if (JSVAL_IS_STRING(closure))
+    if (closure.isString())
         ++emptyTrapCallCount;
     return JSTRAP_CONTINUE;
 }
 
 BEGIN_TEST(testTrap_gc)
 {
     static const char source[] =
 "var i = 0;\n"
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -132,33 +132,33 @@ TestArrayFromBuffer(JSContext *cx)
     // Make sure all 3 views reflect the same buffer at the expected locations
     JS::RootedValue v(cx, INT_TO_JSVAL(39));
     JS_SetElement(cx, array, 0, v);
     JS::RootedValue v2(cx);
     CHECK(JS_GetElement(cx, array, 0, &v2));
     CHECK_SAME(v, v2);
     CHECK(JS_GetElement(cx, shortArray, 0, &v2));
     CHECK_SAME(v, v2);
-    CHECK_EQUAL(long(JSVAL_TO_INT(v)), long(reinterpret_cast<Element*>(data)[0]));
+    CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[0]));
 
     v = INT_TO_JSVAL(40);
     JS_SetElement(cx, array, elts / 2, v);
     CHECK(JS_GetElement(cx, array, elts / 2, &v2));
     CHECK_SAME(v, v2);
     CHECK(JS_GetElement(cx, ofsArray, 0, &v2));
     CHECK_SAME(v, v2);
-    CHECK_EQUAL(long(JSVAL_TO_INT(v)), long(reinterpret_cast<Element*>(data)[elts / 2]));
+    CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts / 2]));
 
     v = INT_TO_JSVAL(41);
     JS_SetElement(cx, array, elts - 1, v);
     CHECK(JS_GetElement(cx, array, elts - 1, &v2));
     CHECK_SAME(v, v2);
     CHECK(JS_GetElement(cx, ofsArray, elts / 2 - 1, &v2));
     CHECK_SAME(v, v2);
-    CHECK_EQUAL(long(JSVAL_TO_INT(v)), long(reinterpret_cast<Element*>(data)[elts - 1]));
+    CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts - 1]));
 
     JS::RootedObject copy(cx, CreateFromArray(cx, array));
     CHECK(JS_GetElement(cx, array, 0, &v));
     CHECK(JS_GetElement(cx, copy, 0, &v2));
     CHECK_SAME(v, v2);
 
     /* The copy should not see changes in the original */
     v2 = INT_TO_JSVAL(42);
--- a/js/src/jsapi-tests/testValueABI.cpp
+++ b/js/src/jsapi-tests/testValueABI.cpp
@@ -33,17 +33,17 @@ BEGIN_TEST(testValueABI_retparam)
     jsval v = OBJECT_TO_JSVAL(obj);
     obj = nullptr;
     CHECK(C_ValueToObject(cx, v, obj.address()));
     bool equal;
     CHECK(JS_StrictlyEqual(cx, v, OBJECT_TO_JSVAL(obj), &equal));
     CHECK(equal);
 
     v = C_GetEmptyStringValue(cx);
-    CHECK(JSVAL_IS_STRING(v));
+    CHECK(v.isString());
 
     return true;
 }
 END_TEST(testValueABI_retparam)
 
 BEGIN_TEST(testValueABI_alignment)
 {
     typedef struct { char c; jsval v; } AlignTest;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5978,17 +5978,17 @@ JS_SaveExceptionState(JSContext *cx)
     JSExceptionState *state;
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     state = cx->pod_malloc<JSExceptionState>();
     if (state) {
         state->throwing =
             JS_GetPendingException(cx, MutableHandleValue::fromMarkedLocation(&state->exception));
-        if (state->throwing && JSVAL_IS_GCTHING(state->exception))
+        if (state->throwing && state->exception.isGCThing())
             AddValueRoot(cx, &state->exception, "JSExceptionState.exception");
     }
     return state;
 }
 
 JS_PUBLIC_API(void)
 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
 {
@@ -6004,17 +6004,17 @@ JS_RestoreExceptionState(JSContext *cx, 
 }
 
 JS_PUBLIC_API(void)
 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (state) {
-        if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
+        if (state->throwing && state->exception.isGCThing()) {
             assertSameCompartment(cx, state->exception);
             RemoveRoot(cx->runtime(), &state->exception);
         }
         js_free(state);
     }
 }
 
 JS_PUBLIC_API(JSErrorReport *)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -832,26 +832,16 @@ JS_StringHasBeenInterned(JSContext *cx, 
  * jsids by API clients.
  *
  * N.B. if a jsid is backed by a string which has not been interned, that
  * string must be appropriately rooted to avoid being collected by the GC.
  */
 JS_PUBLIC_API(jsid)
 INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str);
 
-/*
- * Returns true iff the given jsval is immune to GC and can be used across
- * multiple JSRuntimes without requiring any conversion API.
- */
-static MOZ_ALWAYS_INLINE bool
-JSVAL_IS_UNIVERSAL(jsval v)
-{
-    return !JSVAL_IS_GCTHING(v);
-}
-
 namespace JS {
 
 class AutoIdRooter : private AutoGCRooter
 {
   public:
     explicit AutoIdRooter(JSContext *cx, jsid aId = INT_TO_JSID(0)
                           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, ID), id_(aId)
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -84,17 +84,17 @@ js::GetLengthProperty(JSContext *cx, Han
  *
  * "Array objects give special treatment to a certain class of property names.
  * A property name P (in the form of a string value) is an array index if and
  * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
  * to 2^32-1."
  *
  * This means the largest allowed index is actually 2^32-2 (4294967294).
  *
- * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id)
+ * In our implementation, it would be sufficient to check for id.isInt32()
  * except that by using signed 31-bit integers we miss the top half of the
  * valid range. This function checks the string representation itself; note
  * that calling a standard conversion routine might allow strings such as
  * "08" or "4.0" as array indices, which they are not.
  *
  */
 JS_FRIEND_API(bool)
 js::StringIsArrayIndex(JSLinearString *str, uint32_t *indexp)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -539,20 +539,20 @@ js::ReportUsageError(JSContext *cx, Hand
     JS_ASSERT(!shape->configurable());
     JS_ASSERT(!shape->writable());
     JS_ASSERT(shape->hasDefaultGetter());
 
     RootedValue usage(cx);
     if (!JS_LookupProperty(cx, callee, "usage", &usage))
         return;
 
-    if (JSVAL_IS_VOID(usage)) {
+    if (usage.isUndefined()) {
         JS_ReportError(cx, "%s", msg);
     } else {
-        JSString *str = JSVAL_TO_STRING(usage);
+        JSString *str = usage.toString();
         JS::Anchor<JSString *> a_str(str);
         const jschar *chars = JS_GetStringCharsZ(cx, str);
         if (!chars)
             return;
         JS_ReportError(cx, "%s. Usage: %hs", msg, chars);
     }
 }
 
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -291,17 +291,17 @@ CallJSNativeConstructor(JSContext *cx, N
      *   could be any object.
      *
      * - (new Object(Object)) returns the callee.
      */
     JS_ASSERT_IF(native != ProxyObject::callableClass_.construct &&
                  native != js::CallOrConstructBoundFunction &&
                  native != js::IteratorConstructor &&
                  (!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
-                 !args.rval().isPrimitive() && callee != &args.rval().toObject());
+                 args.rval().isObject() && callee != &args.rval().toObject());
 
     return true;
 }
 
 MOZ_ALWAYS_INLINE bool
 CallJSPropertyOp(JSContext *cx, PropertyOp op, HandleObject receiver, HandleId id, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -750,20 +750,20 @@ js_ReportUncaughtException(JSContext *cx
 
     /*
      * Because ToString below could error and an exception object could become
      * unrooted, we must root exnObject.  Later, if exnObject is non-null, we
      * need to root other intermediates, so allocate an operand stack segment
      * to protect all of these values.
      */
     RootedObject exnObject(cx);
-    if (JSVAL_IS_PRIMITIVE(exn)) {
+    if (exn.isPrimitive()) {
         exnObject = nullptr;
     } else {
-        exnObject = JSVAL_TO_OBJECT(exn);
+        exnObject = exn.toObjectOrNull();
     }
 
     JS_ClearPendingException(cx);
     JSErrorReport *reportp = exnObject ? js_ErrorFromException(cx, exnObject)
                                        : nullptr;
 
     // Be careful not to invoke ToString if we've already successfully extracted
     // an error report, since the exception might be wrapped in a security
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -795,21 +795,21 @@ js_DumpScriptDepth(JSContext *cx, JSScri
 }
 
 static char *
 QuoteString(Sprinter *sp, JSString *str, uint32_t quote);
 
 static bool
 ToDisassemblySource(JSContext *cx, HandleValue v, JSAutoByteString *bytes)
 {
-    if (JSVAL_IS_STRING(v)) {
+    if (v.isString()) {
         Sprinter sprinter(cx);
         if (!sprinter.init())
             return false;
-        char *nbytes = QuoteString(&sprinter, JSVAL_TO_STRING(v), '"');
+        char *nbytes = QuoteString(&sprinter, v.toString(), '"');
         if (!nbytes)
             return false;
         nbytes = JS_sprintf_append(nullptr, "%s", nbytes);
         if (!nbytes)
             return false;
         bytes->initBytes(nbytes);
         return true;
     }
@@ -817,20 +817,20 @@ ToDisassemblySource(JSContext *cx, Handl
     if (cx->runtime()->isHeapBusy() || cx->runtime()->noGCOrAllocationCheck) {
         char *source = JS_sprintf_append(nullptr, "<value>");
         if (!source)
             return false;
         bytes->initBytes(source);
         return true;
     }
 
-    if (!JSVAL_IS_PRIMITIVE(v)) {
-        JSObject *obj = JSVAL_TO_OBJECT(v);
-        if (obj->is<StaticBlockObject>()) {
-            Rooted<StaticBlockObject*> block(cx, &obj->as<StaticBlockObject>());
+    if (v.isObject()) {
+        JSObject &obj = v.toObject();
+        if (obj.is<StaticBlockObject>()) {
+            Rooted<StaticBlockObject*> block(cx, &obj.as<StaticBlockObject>());
             char *source = JS_sprintf_append(nullptr, "depth %d {", block->localOffset());
             if (!source)
                 return false;
 
             Shape::Range<CanGC> r(cx, block->lastProperty());
 
             while (!r.empty()) {
                 Rooted<Shape*> shape(cx, &r.front());
@@ -853,26 +853,26 @@ ToDisassemblySource(JSContext *cx, Handl
 
             source = JS_sprintf_append(source, "}");
             if (!source)
                 return false;
             bytes->initBytes(source);
             return true;
         }
 
-        if (obj->is<JSFunction>()) {
-            RootedFunction fun(cx, &obj->as<JSFunction>());
+        if (obj.is<JSFunction>()) {
+            RootedFunction fun(cx, &obj.as<JSFunction>());
             JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
             if (!str)
                 return false;
             return bytes->encodeLatin1(cx, str);
         }
 
-        if (obj->is<RegExpObject>()) {
-            JSString *source = obj->as<RegExpObject>().toString(cx);
+        if (obj.is<RegExpObject>()) {
+            JSString *source = obj.as<RegExpObject>().toString(cx);
             if (!source)
                 return false;
             JS::Anchor<JSString *> anchor(source);
             return bytes->encodeLatin1(cx, source);
         }
     }
 
     return !!js_ValueToPrintable(cx, v, bytes, true);
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1132,17 +1132,17 @@ NormalizePropertyDescriptor(JSContext *c
 
     // Aux.3 steps 1-2 / Aux.4 steps 2-3
     AutoPropDescArrayRooter descs(cx);
     PropDesc *desc = descs.append();
     if (!desc || !desc->initialize(cx, vp.get()))
         return false;
     if (complete)
         desc->complete();
-    JS_ASSERT(!vp.isPrimitive()); // due to desc->initialize
+    JS_ASSERT(vp.isObject()); // due to desc->initialize
     RootedObject attributes(cx, &vp.toObject());
 
     /*
      * Aux.3 step 3 / Aux.4 step 4
      *
      * NOTE: Aux.4 step 4 actually specifies FromPropertyDescriptor here.
      * However, the way FromPropertyDescriptor is implemented (PropDesc::
      * makeObject) is actually closer to FromGenericPropertyDescriptor,
--- a/js/src/perf/jsperf.cpp
+++ b/js/src/perf/jsperf.cpp
@@ -257,21 +257,21 @@ RegisterPerfMeasurement(JSContext *cx, H
     }
 
     return prototype;
 }
 
 PerfMeasurement*
 ExtractPerfMeasurement(jsval wrapper)
 {
-    if (JSVAL_IS_PRIMITIVE(wrapper))
+    if (wrapper.isPrimitive())
         return 0;
 
     // This is what JS_GetInstancePrivate does internally.  We can't
     // call JS_anything from here, because we don't have a JSContext.
-    JSObject *obj = JSVAL_TO_OBJECT(wrapper);
+    JSObject *obj = wrapper.toObjectOrNull();
     if (obj->getClass() != js::Valueify(&pm_class))
         return 0;
 
     return (PerfMeasurement*) obj->getPrivate();
 }
 
 } // namespace JS
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -596,17 +596,17 @@ Process(JSContext *cx, JSObject *obj_, c
     }
 }
 
 static bool
 Version(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSVersion origVersion = JS_GetVersion(cx);
-    if (args.length() == 0 || JSVAL_IS_VOID(args[0])) {
+    if (args.length() == 0 || args[0].isUndefined()) {
         /* Get version. */
         args.rval().setInt32(origVersion);
     } else {
         /* Set version. */
         int32_t v = -1;
         if (args[0].isInt32()) {
             v = args[0].toInt32();
         } else if (args[0].isDouble()) {
@@ -1766,17 +1766,17 @@ static bool
 GetScriptAndPCArgs(JSContext *cx, unsigned argc, jsval *argv, MutableHandleScript scriptp,
                    int32_t *ip)
 {
     RootedScript script(cx, GetTopScript(cx));
     *ip = 0;
     if (argc != 0) {
         jsval v = argv[0];
         unsigned intarg = 0;
-        if (!JSVAL_IS_PRIMITIVE(v) &&
+        if (v.isObject() &&
             JS_GetClass(&v.toObject()) == Jsvalify(&JSFunction::class_)) {
             script = ValueToScript(cx, v);
             if (!script)
                 return false;
             intarg++;
         }
         if (argc > intarg) {
             if (!JS::ToInt32(cx, HandleValue::fromMarkedLocation(&argv[intarg]), ip))
@@ -1792,17 +1792,17 @@ GetScriptAndPCArgs(JSContext *cx, unsign
 
     return true;
 }
 
 static JSTrapStatus
 TrapHandler(JSContext *cx, JSScript *, jsbytecode *pc, jsval *rvalArg,
             jsval closure)
 {
-    RootedString str(cx, JSVAL_TO_STRING(closure));
+    RootedString str(cx, closure.toString());
     RootedValue rval(cx, *rvalArg);
 
     ScriptFrameIter iter(cx);
     JS_ASSERT(!iter.done());
 
     /* Debug-mode currently disables Ion compilation. */
     JSAbstractFramePtr frame(iter.abstractFramePtr().raw(), iter.pc());
     RootedScript script(cx, iter.script());
@@ -2564,17 +2564,17 @@ Clone(JSContext *cx, unsigned argc, jsva
 
     if (!args.length()) {
         JS_ReportError(cx, "Invalid arguments to clone");
         return false;
     }
 
     {
         Maybe<JSAutoCompartment> ac;
-        RootedObject obj(cx, JSVAL_IS_PRIMITIVE(args[0]) ? nullptr : &args[0].toObject());
+        RootedObject obj(cx, args[0].isPrimitive() ? nullptr : &args[0].toObject());
 
         if (obj && obj->is<CrossCompartmentWrapperObject>()) {
             obj = UncheckedUnwrap(obj);
             ac.construct(cx, obj);
             args[0].setObject(*obj);
         }
         if (obj && obj->is<JSFunction>()) {
             funobj = obj;
@@ -3066,17 +3066,17 @@ resolver_resolve(JSContext *cx, HandleOb
     Rooted<JSObject*> vobj(cx, &v.toObject());
     return CopyProperty(cx, obj, vobj, id, objp);
 }
 
 static bool
 resolver_enumerate(JSContext *cx, HandleObject obj)
 {
     jsval v = JS_GetReservedSlot(obj, 0);
-    RootedObject referent(cx, JSVAL_TO_OBJECT(v));
+    RootedObject referent(cx, v.toObjectOrNull());
 
     AutoIdArray ida(cx, JS_Enumerate(cx, referent));
     bool ok = !!ida;
     RootedObject ignore(cx);
     for (size_t i = 0; ok && i < ida.length(); i++) {
         Rooted<jsid> id(cx, ida[i]);
         ok = CopyProperty(cx, obj, referent, id, &ignore);
     }
@@ -3490,17 +3490,17 @@ Parent(JSContext *cx, unsigned argc, jsv
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "Wrong number of arguments");
         return false;
     }
 
     Value v = args[0];
-    if (JSVAL_IS_PRIMITIVE(v)) {
+    if (v.isPrimitive()) {
         JS_ReportError(cx, "Only objects have parents!");
         return false;
     }
 
     Rooted<JSObject*> parent(cx, JS_GetParent(&v.toObject()));
     args.rval().setObjectOrNull(parent);
 
     /* Outerize if necessary.  Embrace the ugliness! */
@@ -4191,22 +4191,22 @@ ThisFilename(JSContext *cx, unsigned arg
     return true;
 }
 
 static bool
 Wrap(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Value v = args.get(0);
-    if (JSVAL_IS_PRIMITIVE(v)) {
+    if (v.isPrimitive()) {
         args.rval().set(v);
         return true;
     }
 
-    RootedObject obj(cx, JSVAL_TO_OBJECT(v));
+    RootedObject obj(cx, v.toObjectOrNull());
     JSObject *wrapped = Wrapper::New(cx, obj, &obj->global(),
                                      &Wrapper::singleton);
     if (!wrapped)
         return false;
 
     args.rval().setObject(*wrapped);
     return true;
 }
@@ -4926,17 +4926,17 @@ static const JSFunctionSpecWithHelp fuzz
 #undef PROFILING_FUNCTION_COUNT
 #undef CALLGRIND_FUNCTION_COUNT
 #undef VTUNE_FUNCTION_COUNT
 #undef EXTERNAL_FUNCTION_COUNT
 
 static bool
 PrintHelpString(JSContext *cx, jsval v)
 {
-    JSString *str = JSVAL_TO_STRING(v);
+    JSString *str = v.toString();
     JS::Anchor<JSString *> a_str(str);
     const jschar *chars = JS_GetStringCharsZ(cx, str);
     if (!chars)
         return false;
 
     for (const jschar *p = chars; *p; p++)
         fprintf(gOutFile, "%c", char(*p));
 
@@ -4950,17 +4950,17 @@ PrintHelp(JSContext *cx, HandleObject ob
 {
     RootedValue usage(cx);
     if (!JS_LookupProperty(cx, obj, "usage", &usage))
         return false;
     RootedValue help(cx);
     if (!JS_LookupProperty(cx, obj, "help", &help))
         return false;
 
-    if (JSVAL_IS_VOID(usage) || JSVAL_IS_VOID(help))
+    if (usage.isUndefined() || help.isUndefined())
         return true;
 
     return PrintHelpString(cx, usage) && PrintHelpString(cx, help);
 }
 
 static bool
 Help(JSContext *cx, unsigned argc, jsval *vp)
 {
@@ -4974,21 +4974,21 @@ Help(JSContext *cx, unsigned argc, jsval
         if (!ida)
             return false;
 
         for (size_t i = 0; i < ida.length(); i++) {
             RootedValue v(cx);
             RootedId id(cx, ida[i]);
             if (!JS_LookupPropertyById(cx, global, id, &v))
                 return false;
-            if (JSVAL_IS_PRIMITIVE(v)) {
+            if (v.isPrimitive()) {
                 JS_ReportError(cx, "primitive arg");
                 return false;
             }
-            obj = JSVAL_TO_OBJECT(v);
+            obj = v.toObjectOrNull();
             if (!PrintHelp(cx, obj))
                 return false;
         }
     } else {
         for (unsigned i = 0; i < args.length(); i++) {
             if (args[i].isPrimitive()) {
                 JS_ReportError(cx, "primitive arg");
                 return false;
--- a/js/src/shell/jsheaptools.cpp
+++ b/js/src/shell/jsheaptools.cpp
@@ -427,17 +427,17 @@ ReferenceFinder::visit(void *cell, Path 
 
     HeapReverser::Map::Ptr p = reverser.map.lookup(cell);
     JS_ASSERT(p);
     HeapReverser::Node *node = &p->value();
 
     /* Is |cell| a representable cell, reached via a non-empty path? */
     if (path != nullptr) {
         jsval representation = representable(cell, node->kind);
-        if (!JSVAL_IS_VOID(representation))
+        if (!representation.isUndefined())
             return addReferrer(representation, path);
     }
 
     /*
      * If we've made a cycle, don't traverse further. We *do* want to include
      * paths from the target to itself, so we don't want to do this check until
      * after we've possibly reported this cell as a referrer.
      */
--- a/js/src/tests/js1_5/Regress/regress-355829-01.js
+++ b/js/src/tests/js1_5/Regress/regress-355829-01.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 355829;
-var summary = 'Do not assert: !argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0])';
+var summary = 'Do not assert: !argc || argv[0].isNull() || argv[0].isUndefined()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_5/Regress/regress-407024.js
+++ b/js/src/tests/js1_5/Regress/regress-407024.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 407024;
-var summary = 'Do not assert JSVAL_IS_NUMBER(pn3->pn_val) || JSVAL_IS_STRING(pn3->pn_val) || JSVAL_IS_BOOLEAN(pn3->pn_val)';
+var summary = 'Do not assert pn3->pn_val.isNumber() || pn3->pn_val.isString() || pn3->pn_val.isBoolean()';
 var actual = 'No Crash';
 var expect = 'No Crash';
 
 printBugNumber(BUGNUMBER);
 printStatus (summary);
 
 eval("function f(x) { switch (x) { case Array: return 1; }}");
 var result = f(Array);
--- a/js/src/tests/js1_5/Regress/regress-452573-01.js
+++ b/js/src/tests/js1_5/Regress/regress-452573-01.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 452573;
-var summary = 'Do not assert with JIT: JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed)';
+var summary = 'Do not assert with JIT: boxed.isUndefined() || boxed.isBoolean()';
 var actual = 'No Crash';
 var expect = 'No Crash';
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
 function test()
--- a/js/src/tests/js1_5/Regress/regress-453747.js
+++ b/js/src/tests/js1_5/Regress/regress-453747.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 453747;
-var summary = 'Do not assert with JIT: JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed)';
+var summary = 'Do not assert with JIT: boxed.isUndefined() || boxed.isBoolean()';
 var actual = 'No Crash';
 var expect = 'No Crash';
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
 function test()
--- a/js/src/tests/js1_5/Regress/regress-457065-03.js
+++ b/js/src/tests/js1_5/Regress/regress-457065-03.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 457065;
-var summary = 'Do not assert: !fp->callee || fp->thisp == JSVAL_TO_OBJECT(fp->argv[-1])';
+var summary = 'Do not assert: !fp->callee || fp->thisp == fp->argv[-1].toObjectOrNull()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_5/Regress/regress-459628.js
+++ b/js/src/tests/js1_5/Regress/regress-459628.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 459628;
-var summary = 'Do not assert: JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, map->freeslot))';
+var summary = 'Do not assert: STOBJ_GET_SLOT(obj, map->freeslot).isUndefined()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_5/extensions/regress-394967.js
+++ b/js/src/tests/js1_5/extensions/regress-394967.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 394967;
-var summary = 'Do not assert: !JSVAL_IS_PRIMITIVE(vp[1])';
+var summary = 'Do not assert: !vp[1].isPrimitive()';
 var actual = 'No Crash';
 var expect = 'No Crash';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_5/extensions/regress-469761.js
+++ b/js/src/tests/js1_5/extensions/regress-469761.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 469761;
-var summary = 'TM: Do not assert: JSVAL_IS_INT(STOBJ_GET_SLOT(callee_obj, JSSLOT_PRIVATE))';
+var summary = 'TM: Do not assert: STOBJ_GET_SLOT(callee_obj, JSSLOT_PRIVATE).isInt32()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_5/extensions/regress-472599.js
+++ b/js/src/tests/js1_5/extensions/regress-472599.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 472599;
-var summary = 'Do not assert: JSVAL_IS_INT(STOBJ_GET_SLOT(callee_obj, JSSLOT_PRIVATE))';
+var summary = 'Do not assert: STOBJ_GET_SLOT(callee_obj, JSSLOT_PRIVATE).isInt32()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_7/extensions/regress-469405-01.js
+++ b/js/src/tests/js1_7/extensions/regress-469405-01.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 469405;
-var summary = 'Do not assert: !JSVAL_IS_PRIMITIVE(regs.sp[-2])';
+var summary = 'Do not assert: !regs.sp[-2].isPrimitive()';
 var actual = '';
 var expect = '';
 
 printBugNumber(BUGNUMBER);
 printStatus (summary);
 
 try
 { 
--- a/js/src/tests/js1_7/extensions/regress-469405-02.js
+++ b/js/src/tests/js1_7/extensions/regress-469405-02.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 469405;
-var summary = 'Do not assert: !JSVAL_IS_PRIMITIVE(regs.sp[-2])';
+var summary = 'Do not assert: !regs.sp[-2].isPrimitive()';
 var actual = '';
 var expect = '';
 
 printBugNumber(BUGNUMBER);
 printStatus (summary);
 
 try
 { 
--- a/js/src/tests/js1_7/regress/regress-452960.js
+++ b/js/src/tests/js1_7/regress/regress-452960.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 452960;
-var summary = 'Do not assert with JIT: !JSVAL_IS_PRIMITIVE(v)';
+var summary = 'Do not assert with JIT: !v.isPrimitive()';
 var actual = 'No Crash';
 var expect = 'No Crash';
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
 function test()
--- a/js/src/tests/js1_8/regress/regress-457065-01.js
+++ b/js/src/tests/js1_8/regress/regress-457065-01.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 457065;
-var summary = 'Do not assert: !fp->callee || fp->thisp == JSVAL_TO_OBJECT(fp->argv[-1])';
+var summary = 'Do not assert: !fp->callee || fp->thisp == fp->argv[-1].toObjectOrNull()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_8/regress/regress-457065-02.js
+++ b/js/src/tests/js1_8/regress/regress-457065-02.js
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 457065;
-var summary = 'Do not assert: !fp->callee || fp->thisp == JSVAL_TO_OBJECT(fp->argv[-1])';
+var summary = 'Do not assert: !fp->callee || fp->thisp == fp->argv[-1].toObjectOrNull()';
 var actual = '';
 var expect = '';
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
--- a/js/src/tests/js1_8/regress/regress-477581.js
+++ b/js/src/tests/js1_8/regress/regress-477581.js
@@ -2,17 +2,17 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/licenses/publicdomain/
  * Contributor: Jason Orendorff
  */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 477581;
-var summary = 'Do not assert: !JSVAL_IS_PRIMITIVE(regs.sp[-2])';
+var summary = 'Do not assert: !regs.sp[-2].isPrimitive()';
 var actual = '';
 var expect = '';
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
 function test()
--- a/js/src/tests/js1_8_1/regress/regress-452498-119.js
+++ b/js/src/tests/js1_8_1/regress/regress-452498-119.js
@@ -26,17 +26,17 @@ function test()
 
 // =====
   function f() {
     var x;
     eval("for(let y in [false]) var x, x = 0");
   }
   f();
 
-// Assertion failure: !JSVAL_IS_PRIMITIVE(regs.sp[-2]), at ../jsinterp.cpp:3243
+// Assertion failure: !regs.sp[-2].isPrimitive(), at ../jsinterp.cpp:3243
 // Opt crash [@ JS_GetMethodById] near null
 // =====
   new Function("for(x1 in ((function (){ yield x } )())){var c, x = []} function x(){} ");
 
 // Assertion failure: pn_used, at ../jsparse.h:401
 // Opt crash [@ FindFunArgs] at null
 // =====
   uneval(new Function("[(x = x) for (c in []) if ([{} for (x in [])])]"))
--- a/js/src/tests/js1_8_1/regress/regress-452498-123.js
+++ b/js/src/tests/js1_8_1/regress/regress-452498-123.js
@@ -40,17 +40,17 @@ function test()
 // Assertion failure: dn->pn_defn, at ../jsemit.cpp:1873
 // =====
 
 
 // Requires -j:
 // =====
   (function(){ eval("for (x in ['', {}, '', {}]) { this; }" )})();
 
-// Assertion failure: fp->thisp == JSVAL_TO_OBJECT(fp->argv[-1]), at ../jstracer.cpp:4172
+// Assertion failure: fp->thisp == fp->argv[-1].toObjectOrNull(), at ../jstracer.cpp:4172
 // =====
   for each (let x in ['', '', '']) { (new function(){} )}
 
 // Assertion failure: scope->object == ctor, at ../jsbuiltins.cpp:236
 // Opt crash [@ js_FastNewObject] near null
 // =====
 
   reportCompare(expect, actual, summary);
--- a/js/src/tests/js1_8_5/regress/regress-477053.js
+++ b/js/src/tests/js1_8_5/regress/regress-477053.js
@@ -1,16 +1,16 @@
 /* -*- Mode: java; 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/. */
 
 
-var summary = 'Do not assert: JSVAL_IS_STRING(v)';
+var summary = 'Do not assert: v.isString()';
 var BUGNUMBER = 477053;
 var actual = '';
 var expect = '';
 
 printBugNumber(BUGNUMBER);
 
 try
 {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -488,17 +488,17 @@ js::Invoke(JSContext *cx, CallArgs args,
             jsbytecode *pc = iter.pc();
             if (UseNewType(cx, script, pc))
                 state.setUseNewType();
         }
     }
 
     bool ok = RunScript(cx, state);
 
-    JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
+    JS_ASSERT_IF(ok && construct, args.rval().isObject());
     return ok;
 }
 
 bool
 js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, const Value *argv,
            MutableHandleValue rval)
 {
     InvokeArgs args(cx);
@@ -1927,17 +1927,17 @@ END_CASE(JSOP_IN)
 
 CASE(JSOP_ITER)
 {
     JS_ASSERT(REGS.stackDepth() >= 1);
     uint8_t flags = GET_UINT8(REGS.pc);
     MutableHandleValue res = REGS.stackHandleAt(-1);
     if (!ValueToIterator(cx, flags, res))
         goto error;
-    JS_ASSERT(!res.isPrimitive());
+    JS_ASSERT(res.isObject());
 }
 END_CASE(JSOP_ITER)
 
 CASE(JSOP_MOREITER)
 {
     JS_ASSERT(REGS.stackDepth() >= 1);
     JS_ASSERT(REGS.sp[-1].isObject());
     PUSH_NULL();
--- a/js/src/vm/OldDebugAPI.cpp
+++ b/js/src/vm/OldDebugAPI.cpp
@@ -1018,17 +1018,17 @@ FormatFrame(JSContext *cx, const NonBuil
     RootedString funname(cx);
     if (fun)
         funname = fun->atom();
 
     RootedValue thisVal(cx);
     AutoPropertyDescArray thisProps(cx);
     if (iter.computeThis(cx)) {
         thisVal = iter.computedThisValue();
-        if (showThisProps && !thisVal.isPrimitive()) {
+        if (showThisProps && thisVal.isObject()) {
             RootedObject thisObj(cx, &thisVal.toObject());
             thisProps.fetch(thisObj);
         }
     }
 
     // print the frame number and function name
     if (funname) {
         JSAutoByteString funbytes;
--- a/js/src/vm/Probes.cpp
+++ b/js/src/vm/Probes.cpp
@@ -7,17 +7,17 @@
 #include "vm/Probes-inl.h"
 
 #include "jscntxt.h"
 
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "jsscriptinlines.h"
 #endif
 
-#define TYPEOF(cx,v)    (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
+#define TYPEOF(cx,v)    (v.isNull() ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
 
 using namespace js;
 
 const char probes::nullName[] = "(null)";
 const char probes::anonymousName[] = "(anonymous)";
 
 bool probes::ProfilingActive = true;
 
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -714,17 +714,17 @@ JSStructuredCloneWriter::~JSStructuredCl
     ClearStructuredClone(data, size, callbacks, closure);
 }
 
 bool
 JSStructuredCloneWriter::parseTransferable()
 {
     MOZ_ASSERT(transferableObjects.empty(), "parseTransferable called with stale data");
 
-    if (JSVAL_IS_NULL(transferable) || JSVAL_IS_VOID(transferable))
+    if (transferable.isNull() || transferable.isUndefined())
         return true;
 
     if (!transferable.isObject())
         return reportErrorTransferable();
 
     JSContext *cx = context();
     RootedObject array(cx, &transferable.toObject());
     if (!JS_IsArrayObject(cx, array))
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -466,17 +466,17 @@ mozJSComponentLoader::LoadModule(FileLoc
     if (!file_jsobj) {
         return nullptr;
     }
 
     JSCLAutoErrorReporterSetter aers(cx, xpc::SystemErrorReporter);
 
     RootedValue NSGetFactory_val(cx);
     if (!JS_GetProperty(cx, entryObj, "NSGetFactory", &NSGetFactory_val) ||
-        JSVAL_IS_VOID(NSGetFactory_val)) {
+        NSGetFactory_val.isUndefined()) {
         return nullptr;
     }
 
     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
         nsAutoCString spec;
         uri->GetSpec(spec);
         JS_ReportError(cx, "%s has NSGetFactory property that is not a function",
                        spec.get());
--- a/js/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/xpconnect/public/nsAutoJSValHolder.h
@@ -112,17 +112,17 @@ public:
   JS::Value get() const { return mVal; }
 
   nsAutoJSValHolder &operator=(JSObject* aOther) {
     return *this = OBJECT_TO_JSVAL(aOther);
   }
 
   nsAutoJSValHolder &operator=(JS::Value aOther) {
 #ifdef DEBUG
-    if (JSVAL_IS_GCTHING(aOther) && !JSVAL_IS_NULL(aOther)) {
+    if (aOther.isGCThing() && !aOther.isNull()) {
       MOZ_ASSERT(IsHeld(), "Not rooted!");
     }
 #endif
     mVal = aOther;
     return *this;
   }
 
 private:
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -254,17 +254,17 @@ nsXPCComponents_Interfaces::NewEnumerate
 
             *statep = JSVAL_ZERO;
             if (idp)
                 *idp = INT_TO_JSID(mInterfaces.Length());
             return NS_OK;
         }
         case JSENUMERATE_NEXT:
         {
-            uint32_t idx = JSVAL_TO_INT(*statep);
+            uint32_t idx = statep->toInt32();
             nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(idx);
             *statep = UINT_TO_JSVAL(idx + 1);
 
             if (interface) {
                 const char* name;
 
                 RootedId id(cx);
                 if (NS_SUCCEEDED(interface->GetNameShared(&name)) && name) {
@@ -502,17 +502,17 @@ nsXPCComponents_InterfacesByID::NewEnume
 
             *statep = JSVAL_ZERO;
             if (idp)
                 *idp = INT_TO_JSID(mInterfaces.Length());
             return NS_OK;
         }
         case JSENUMERATE_NEXT:
         {
-            uint32_t idx = JSVAL_TO_INT(*statep);
+            uint32_t idx = statep->toInt32();
             nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(idx);
             *statep = UINT_TO_JSVAL(idx + 1);
             if (interface) {
                 nsIID const *iid;
                 char idstr[NSID_LENGTH];
 
                 if (NS_SUCCEEDED(interface->GetIIDShared(&iid))) {
                     iid->ToProvidedString(idstr);
@@ -759,17 +759,17 @@ nsXPCComponents_Classes::NewEnumerate(ns
             if (idp)
                 *idp = INT_TO_JSID(0); // indicate that we don't know the count
             return NS_OK;
         }
         case JSENUMERATE_NEXT:
         {
             nsCOMPtr<nsISupports> isup;
             bool hasMore;
-            e = (nsISimpleEnumerator*) JSVAL_TO_PRIVATE(*statep);
+            e = (nsISimpleEnumerator*) statep->toPrivate();
 
             if (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore &&
                 NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) {
                 nsCOMPtr<nsISupportsCString> holder(do_QueryInterface(isup));
                 if (holder) {
                     nsAutoCString name;
                     if (NS_SUCCEEDED(holder->GetData(name))) {
                         RootedString idstr(cx, JS_NewStringCopyN(cx, name.get(), name.Length()));
@@ -781,17 +781,17 @@ nsXPCComponents_Classes::NewEnumerate(ns
                     }
                 }
             }
             // else... FALL THROUGH
         }
 
         case JSENUMERATE_DESTROY:
         default:
-            e = (nsISimpleEnumerator*) JSVAL_TO_PRIVATE(*statep);
+            e = (nsISimpleEnumerator*) statep->toPrivate();
             NS_IF_RELEASE(e);
             *statep = JSVAL_NULL;
             return NS_OK;
     }
 }
 
 /* bool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id, out JSObjectPtr objp); */
 NS_IMETHODIMP
@@ -999,17 +999,17 @@ nsXPCComponents_ClassesByID::NewEnumerat
             if (idp)
                 *idp = INT_TO_JSID(0); // indicate that we don't know the count
             return NS_OK;
         }
         case JSENUMERATE_NEXT:
         {
             nsCOMPtr<nsISupports> isup;
             bool hasMore;
-            e = (nsISimpleEnumerator*) JSVAL_TO_PRIVATE(*statep);
+            e = (nsISimpleEnumerator*) statep->toPrivate();
 
             if (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore &&
                 NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) {
                 nsCOMPtr<nsISupportsID> holder(do_QueryInterface(isup));
                 if (holder) {
                     char* name;
                     if (NS_SUCCEEDED(holder->ToString(&name)) && name) {
                         RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
@@ -1022,17 +1022,17 @@ nsXPCComponents_ClassesByID::NewEnumerat
                     }
                 }
             }
             // else... FALL THROUGH
         }
 
         case JSENUMERATE_DESTROY:
         default:
-            e = (nsISimpleEnumerator*) JSVAL_TO_PRIVATE(*statep);
+            e = (nsISimpleEnumerator*) statep->toPrivate();
             NS_IF_RELEASE(e);
             *statep = JSVAL_NULL;
             return NS_OK;
     }
 }
 
 static bool
 IsRegisteredCLSID(const char* str)
@@ -1259,31 +1259,31 @@ nsXPCComponents_Results::NewEnumerate(ns
             void** space = (void**) new char[sizeof(void*)];
             *space = nullptr;
             *statep = PRIVATE_TO_JSVAL(space);
             return NS_OK;
         }
         case JSENUMERATE_NEXT:
         {
             const char* name;
-            iter = (const void**) JSVAL_TO_PRIVATE(*statep);
+            iter = (const void**) statep->toPrivate();
             if (nsXPCException::IterateNSResults(nullptr, &name, nullptr, iter)) {
                 RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
                 JS::RootedId id(cx);
                 if (idstr && JS_StringToId(cx, idstr, &id)) {
                     *idp = id;
                     return NS_OK;
                 }
             }
             // else... FALL THROUGH
         }
 
         case JSENUMERATE_DESTROY:
         default:
-            iter = (const void**) JSVAL_TO_PRIVATE(*statep);
+            iter = (const void**) statep->toPrivate();
             delete [] (char*) iter;
             *statep = JSVAL_NULL;
             return NS_OK;
     }
 }
 
 
 /* bool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id, out JSObjectPtr objp); */
@@ -2464,17 +2464,17 @@ nsXPCComponents_Constructor::CallOrConst
         if (!str || !JS_StringToId(cx, str, &id))
             return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
 
         RootedValue val(cx);
         if (!JS_GetPropertyById(cx, classesObj, id, &val) || val.isPrimitive())
             return ThrowAndFail(NS_ERROR_XPC_BAD_CID, cx, _retval);
 
         nsCOMPtr<nsIXPConnectWrappedNative> wn;
-        if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, JSVAL_TO_OBJECT(val),
+        if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, val.toObjectOrNull(),
                                                       getter_AddRefs(wn))) || !wn ||
             !(cClassID = do_QueryWrappedNative(wn))) {
             return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
         }
     }
 
     nsCOMPtr<nsIXPCConstructor> ctor = new nsXPCConstructor(cClassID, cInterfaceID, cInitializer);
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder2;
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -468,38 +468,38 @@ XPCConvert::JSData2Native(void* d, Handl
             return false;
         }
         *((const nsID**)d) = pid;
         return true;
     }
 
     case nsXPTType::T_ASTRING:
     {
-        if (JSVAL_IS_VOID(s)) {
+        if (s.isUndefined()) {
             if (useAllocator)
                 *((const nsAString**)d) = &NullString();
             else
                 (**((nsAString**)d)).SetIsVoid(true);
             return true;
         }
         // Fall through to T_DOMSTRING case.
     }
     case nsXPTType::T_DOMSTRING:
     {
-        if (JSVAL_IS_NULL(s)) {
+        if (s.isNull()) {
             if (useAllocator)
                 *((const nsAString**)d) = &NullString();
             else
                 (**((nsAString**)d)).SetIsVoid(true);
             return true;
         }
         size_t length = 0;
         const char16_t* chars = nullptr;
         JSString* str = nullptr;
-        if (!JSVAL_IS_VOID(s)) {
+        if (!s.isUndefined()) {
             str = ToString(cx, s);
             if (!str)
                 return false;
 
             chars = useAllocator ? JS_GetStringCharsZAndLength(cx, str, &length)
                                  : JS_GetStringCharsAndLength(cx, str, &length);
             if (!chars)
                 return false;
@@ -538,17 +538,17 @@ XPCConvert::JSData2Native(void* d, Handl
         } else {
             ws->Assign(chars, length);
         }
         return true;
     }
 
     case nsXPTType::T_CHAR_STR:
     {
-        if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+        if (s.isUndefined() || s.isNull()) {
             *((char**)d) = nullptr;
             return true;
         }
 
         JSString* str = ToString(cx, s);
         if (!str) {
             return false;
         }
@@ -579,17 +579,17 @@ XPCConvert::JSData2Native(void* d, Handl
         return true;
     }
 
     case nsXPTType::T_WCHAR_STR:
     {
         const jschar* chars=nullptr;
         JSString* str;
 
-        if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+        if (s.isUndefined() || s.isNull()) {
             *((jschar**)d) = nullptr;
             return true;
         }
 
         if (!(str = ToString(cx, s))) {
             return false;
         }
         if (!(chars = JS_GetStringCharsZ(cx, str))) {
@@ -609,17 +609,17 @@ XPCConvert::JSData2Native(void* d, Handl
     }
 
     case nsXPTType::T_UTF8STRING:
     {
         const jschar* chars;
         size_t length;
         JSString* str;
 
-        if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
+        if (s.isNull() || s.isUndefined()) {
             if (useAllocator) {
                 *((const nsACString**)d) = &NullCString();
             } else {
                 nsCString* rs = *((nsCString**)d);
                 rs->SetIsVoid(true);
             }
             return true;
         }
@@ -653,17 +653,17 @@ XPCConvert::JSData2Native(void* d, Handl
             rs = *((nsCString**)d);
         }
         CopyUTF16toUTF8(Substring(chars, length), *rs);
         return true;
     }
 
     case nsXPTType::T_CSTRING:
     {
-        if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
+        if (s.isNull() || s.isUndefined()) {
             if (useAllocator) {
                 nsACString *rs = new nsCString();
                 if (!rs)
                     return false;
 
                 rs->SetIsVoid(true);
                 *((nsACString**)d) = rs;
             } else {
@@ -721,20 +721,19 @@ XPCConvert::JSData2Native(void* d, Handl
 
         if (iid->Equals(NS_GET_IID(nsIVariant))) {
             nsCOMPtr<nsIVariant> variant = XPCVariant::newVariant(cx, s);
             if (!variant)
                 return false;
 
             variant.forget(static_cast<nsISupports**>(d));
             return true;
-        } else if (iid->Equals(NS_GET_IID(nsIAtom)) &&
-                   JSVAL_IS_STRING(s)) {
+        } else if (iid->Equals(NS_GET_IID(nsIAtom)) && s.isString()) {
             // We're trying to pass a string as an nsIAtom.  Let's atomize!
-            JSString* str = JSVAL_TO_STRING(s);
+            JSString* str = s.toString();
             const char16_t* chars = JS_GetStringCharsZ(cx, str);
             if (!chars) {
                 if (pErr)
                     *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
                 return false;
             }
             uint32_t length = JS_GetStringLength(str);
             nsCOMPtr<nsIAtom> atom =
@@ -1118,19 +1117,19 @@ nsresult
 XPCConvert::JSValToXPCException(MutableHandleValue s,
                                 const char* ifaceName,
                                 const char* methodName,
                                 nsIException** exceptn)
 {
     AutoJSContext cx;
     AutoExceptionRestorer aer(cx, s);
 
-    if (!JSVAL_IS_PRIMITIVE(s)) {
+    if (!s.isPrimitive()) {
         // we have a JSObject
-        RootedObject obj(cx, JSVAL_TO_OBJECT(s));
+        RootedObject obj(cx, s.toObjectOrNull());
 
         if (!obj) {
             NS_ERROR("when is an object not an object?");
             return NS_ERROR_FAILURE;
         }
 
         // is this really a native xpcom object with a wrapper?
         JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
@@ -1206,36 +1205,36 @@ XPCConvert::JSValToXPCException(MutableH
                 return NS_ERROR_FAILURE;
 
             return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
                                       strBytes.ptr(), ifaceName, methodName,
                                       nullptr, exceptn, cx, s.address());
         }
     }
 
-    if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+    if (s.isUndefined() || s.isNull()) {
         return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
                                   nullptr, ifaceName, methodName, nullptr,
                                   exceptn, cx, s.address());
     }
 
-    if (JSVAL_IS_NUMBER(s)) {
+    if (s.isNumber()) {
         // lets see if it looks like an nsresult
         nsresult rv;
         double number;
         bool isResult = false;
 
-        if (JSVAL_IS_INT(s)) {
-            rv = (nsresult) JSVAL_TO_INT(s);
+        if (s.isInt32()) {
+            rv = (nsresult) s.toInt32();
             if (NS_FAILED(rv))
                 isResult = true;
             else
-                number = (double) JSVAL_TO_INT(s);
+                number = (double) s.toInt32();
         } else {
-            number = JSVAL_TO_DOUBLE(s);
+            number = s.toDouble();
             if (number > 0.0 &&
                 number < (double)0xffffffff &&
                 0.0 == fmod(number,1)) {
                 // Visual Studio 9 doesn't allow casting directly from a
                 // double to an enumeration type, contrary to 5.2.9(10) of
                 // C++11, so add an intermediate cast.
                 rv = (nsresult)(uint32_t) number;
                 if (NS_FAILED(rv))
@@ -1754,29 +1753,29 @@ XPCConvert::NativeStringWithSize2JS(Muta
 }
 
 // static
 bool
 XPCConvert::JSStringWithSize2Native(void* d, HandleValue s,
                                     uint32_t count, const nsXPTType& type,
                                     nsresult* pErr)
 {
-    NS_PRECONDITION(!JSVAL_IS_NULL(s), "bad param");
+    NS_PRECONDITION(!s.isNull(), "bad param");
     NS_PRECONDITION(d, "bad param");
 
     AutoJSContext cx;
     uint32_t len;
 
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
     switch (type.TagPart()) {
         case nsXPTType::T_PSTRING_SIZE_IS:
         {
-            if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+            if (s.isUndefined() || s.isNull()) {
                 if (0 != count) {
                     if (pErr)
                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
                     return false;
                 }
                 if (0 != count) {
                     len = (count + 1) * sizeof(char);
                     if (!(*((void**)d) = nsMemory::Alloc(len)))
@@ -1820,17 +1819,17 @@ XPCConvert::JSStringWithSize2Native(void
             return true;
         }
 
         case nsXPTType::T_PWSTRING_SIZE_IS:
         {
             const jschar* chars=nullptr;
             JSString* str;
 
-            if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
+            if (s.isUndefined() || s.isNull()) {
                 if (0 != count) {
                     if (pErr)
                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
                     return false;
                 }
 
                 if (0 != count) {
                     len = (count + 1) * sizeof(jschar);
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -639,18 +639,18 @@ nsJSCID::NewID(const char* str)
 static const nsID*
 GetIIDArg(uint32_t argc, const JS::Value& val, JSContext* cx)
 {
     const nsID* iid;
 
     // If an IID was passed in then use it
     if (argc) {
         JSObject* iidobj;
-        if (JSVAL_IS_PRIMITIVE(val) ||
-            !(iidobj = JSVAL_TO_OBJECT(val)) ||
+        if (val.isPrimitive() ||
+            !(iidobj = val.toObjectOrNull()) ||
             !(iid = xpc_JSObjectToID(cx, iidobj))) {
             return nullptr;
         }
     } else
         iid = &NS_GET_IID(nsISupports);
 
     return iid;
 }
--- a/js/xpconnect/src/XPCQuickStubs.h
+++ b/js/xpconnect/src/XPCQuickStubs.h
@@ -219,32 +219,32 @@ protected:
     bool mValid;
 
     /*
      * If null is returned, then we either failed or fully initialized
      * |this|; in either case the caller should return immediately
      * without doing anything else. Otherwise, the JSString* created
      * from |v| will be returned.  It'll be rooted, as needed, in
      * *pval.  nullBehavior and undefinedBehavior control what happens
-     * when |v| is JSVAL_IS_NULL and JSVAL_IS_VOID respectively.
+     * when v.isNull() and v.isUndefined() are respectively true.
      */
     template<class traits>
     JSString* InitOrStringify(JSContext* cx, JS::HandleValue v,
                               JS::MutableHandleValue pval,
                               bool notpassed,
                               StringificationBehavior nullBehavior,
                               StringificationBehavior undefinedBehavior) {
         JSString *s;
-        if (JSVAL_IS_STRING(v)) {
-            s = JSVAL_TO_STRING(v);
+        if (v.isString()) {
+            s = v.toString();
         } else {
             StringificationBehavior behavior = eStringify;
-            if (JSVAL_IS_NULL(v)) {
+            if (v.isNull()) {
                 behavior = nullBehavior;
-            } else if (JSVAL_IS_VOID(v)) {
+            } else if (v.isUndefined()) {
                 behavior = undefinedBehavior;
             }
 
             // If pval is null, that means the argument was optional and
             // not passed; turn those into void strings if they're
             // supposed to be stringified.
             if (behavior != eStringify || notpassed) {
                 // Here behavior == eStringify implies notpassed, so both eNull and
@@ -592,17 +592,17 @@ PropertyOpForwarder(JSContext *cx, unsig
 
     JS::RootedObject callee(cx, &args.callee());
     JS::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
     if (!obj)
         return false;
 
     JS::RootedValue v(cx, js::GetFunctionNativeReserved(callee, 0));
 
-    JSObject *ptrobj = JSVAL_TO_OBJECT(v);
+    JSObject *ptrobj = v.toObjectOrNull();
     Op *popp = static_cast<Op *>(JS_GetPrivate(ptrobj));
 
     v = js::GetFunctionNativeReserved(callee, 1);
 
     JS::RootedValue argval(cx, args.get(0));
     JS::RootedId id(cx);
     if (!JS_ValueToId(cx, v, &id))
         return false;
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -539,17 +539,17 @@ Parent(JSContext *cx, unsigned argc, jsv
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "Wrong number of arguments");
         return false;
     }
 
     Value v = args[0];
-    if (JSVAL_IS_PRIMITIVE(v)) {
+    if (v.isPrimitive()) {
         JS_ReportError(cx, "Only objects have parents!");
         return false;
     }
 
     args.rval().setObjectOrNull(JS_GetParent(&v.toObject()));
     return true;
 }
 
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -51,24 +51,24 @@ XPCVariant::XPCVariant(JSContext* cx, js
     } else
         mReturnRawObject = false;
 }
 
 XPCTraceableVariant::~XPCTraceableVariant()
 {
     jsval val = GetJSValPreserveColor();
 
-    MOZ_ASSERT(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked");
+    MOZ_ASSERT(val.isGCThing(), "Must be traceable or unlinked");
 
     // If val is JSVAL_STRING, we don't need to clean anything up; simply
     // removing the string from the root set is good.
-    if (!JSVAL_IS_STRING(val))
+    if (!val.isString())
         nsVariant::Cleanup(&mData);
 
-    if (!JSVAL_IS_NULL(val))
+    if (!val.isNull())
         RemoveFromRootSet();
 }
 
 void XPCTraceableVariant::TraceJS(JSTracer* trc)
 {
     MOZ_ASSERT(mJSVal.isMarkable());
     trc->setTracingDetails(GetTraceName, this, 0);
     JS_CallHeapValueTracer(trc, &mJSVal, "XPCTraceableVariant::mJSVal");
@@ -82,17 +82,17 @@ XPCTraceableVariant::GetTraceName(JSTrac
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant)
     JS::Value val = tmp->GetJSValPreserveColor();
     if (val.isObjectOrNull()) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal");
-        cb.NoteJSChild(JSVAL_TO_OBJECT(val));
+        cb.NoteJSChild(val.toObjectOrNull());
     }
 
     nsVariant::Traverse(tmp->mData, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
     JS::Value val = tmp->GetJSValPreserveColor();
 
@@ -379,17 +379,17 @@ XPCVariant::VariantDataToJS(nsIVariant* 
     if (NS_FAILED(variant->GetDataType(&type)))
         return false;
 
     AutoJSContext cx;
     RootedValue realVal(cx);
     nsresult rv = variant->GetAsJSVal(&realVal);
 
     if (NS_SUCCEEDED(rv) &&
-        (JSVAL_IS_PRIMITIVE(realVal) ||
+        (realVal.isPrimitive() ||
          type == nsIDataType::VTYPE_ARRAY ||
          type == nsIDataType::VTYPE_EMPTY_ARRAY ||
          type == nsIDataType::VTYPE_ID)) {
         if (!JS_WrapValue(cx, &realVal))
             return false;
         pJSVal.set(realVal);
         return true;
     }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -186,17 +186,17 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
 
     // XXX we should install an error reporter that will send reports to
     // the JS error console service.
     if (!scriptEval.StartEvaluating(jsobj))
         return nullptr;
 
     // check upfront for the existence of the function property
     HandleId funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
-    if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
+    if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || fun.isPrimitive())
         return nullptr;
 
     // Ensure that we are asking for a scriptable interface.
     // NB:  It's important for security that this check is here rather
     // than later, since it prevents untrusted objects from implementing
     // some interfaces in JS and aggregating a trusted object to
     // implement intentionally (for security) unscriptable interfaces.
     // We so often ask for nsISupports that we can short-circuit the test...
@@ -236,25 +236,25 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
                     Exception *e = nullptr;
                     UNWRAP_OBJECT(Exception, &jsexception.toObject(), e);
 
                     if (e &&
                         NS_SUCCEEDED(e->GetResult(&rv)) &&
                         rv == NS_NOINTERFACE) {
                         JS_ClearPendingException(cx);
                     }
-                } else if (JSVAL_IS_NUMBER(jsexception)) {
+                } else if (jsexception.isNumber()) {
                     // JS often throws an nsresult.
-                    if (JSVAL_IS_DOUBLE(jsexception))
+                    if (jsexception.isDouble())
                         // Visual Studio 9 doesn't allow casting directly from
                         // a double to an enumeration type, contrary to
                         // 5.2.9(10) of C++11, so add an intermediate cast.
-                        rv = (nsresult)(uint32_t)(JSVAL_TO_DOUBLE(jsexception));
+                        rv = (nsresult)(uint32_t)(jsexception.toDouble());
                     else
-                        rv = (nsresult)(JSVAL_TO_INT(jsexception));
+                        rv = (nsresult)(jsexception.toInt32());
 
                     if (rv == NS_NOINTERFACE)
                         JS_ClearPendingException(cx);
                 }
             }
 
             // Don't report if reporting was disabled by someone else.
             if (!ContextOptionsRef(cx).dontReportUncaught())
@@ -1079,17 +1079,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
                                 xpcObjectHelper helper(newThis);
                                 bool ok =
                                   XPCConvert::NativeInterface2JSObject(
                                       &v, nullptr, helper, nullptr,
                                       nullptr, false, nullptr);
                                 if (!ok) {
                                     goto pre_call_clean_up;
                                 }
-                                thisObj = JSVAL_TO_OBJECT(v);
+                                thisObj = v.toObjectOrNull();
                                 if (!JS_WrapObject(cx, &thisObj))
                                     goto pre_call_clean_up;
                             }
                         }
                     }
                 }
             }
         } else {
@@ -1260,17 +1260,17 @@ pre_call_clean_up:
 
     RootedValue rval(cx);
     if (XPT_MD_IS_GETTER(info->flags)) {
         success = JS_GetProperty(cx, obj, name, &rval);
     } else if (XPT_MD_IS_SETTER(info->flags)) {
         rval = *argv;
         success = JS_SetProperty(cx, obj, name, rval);
     } else {
-        if (!JSVAL_IS_PRIMITIVE(fval)) {
+        if (!fval.isPrimitive()) {
             AutoSaveContextOptions asco(cx);
             ContextOptionsRef(cx).setDontReportUncaught(true);
 
             success = JS_CallFunctionValue(cx, thisObj, fval, args, &rval);
         } else {
             // The property was not an object so can't be a function.
             // Let's build and 'throw' an exception.
 
--- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp
@@ -25,18 +25,18 @@ bool
 XPCNativeMember::GetCallInfo(JSObject* funobj,
                              XPCNativeInterface** pInterface,
                              XPCNativeMember**    pMember)
 {
     funobj = js::UncheckedUnwrap(funobj);
     jsval ifaceVal = js::GetFunctionNativeReserved(funobj, 0);
     jsval memberVal = js::GetFunctionNativeReserved(funobj, 1);
 
-    *pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal);
-    *pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal);
+    *pInterface = (XPCNativeInterface*) ifaceVal.toPrivate();
+    *pMember = (XPCNativeMember*) memberVal.toPrivate();
 
     return true;
 }
 
 bool
 XPCNativeMember::NewFunctionObject(XPCCallContext& ccx,
                                    XPCNativeInterface* iface, HandleObject parent,
                                    jsval* pval)
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -116,18 +116,18 @@ GetDoubleWrappedJSObject(XPCCallContext&
         if (mainObj) {
             RootedId id(ccx, ccx.GetRuntime()->
                             GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT));
 
             JSAutoCompartment ac(ccx, mainObj);
 
             RootedValue val(ccx);
             if (JS_GetPropertyById(ccx, mainObj, id, &val) &&
-                !JSVAL_IS_PRIMITIVE(val)) {
-                obj = JSVAL_TO_OBJECT(val);
+                !val.isPrimitive()) {
+                obj = val.toObjectOrNull();
             }
         }
     }
     return obj;
 }
 
 // This is the getter native function we use to handle 'wrappedJSObject' for
 // double wrapped JSObjects.
@@ -376,17 +376,17 @@ DefinePropertyIfFound(XPCCallContext& cc
                                      propFlags);
     }
 
     // else...
 
     MOZ_ASSERT(member->IsAttribute(), "way broken!");
 
     propFlags |= JSPROP_GETTER | JSPROP_SHARED;
-    JSObject* funobj = JSVAL_TO_OBJECT(funval);
+    JSObject* funobj = funval.toObjectOrNull();
     JSPropertyOp getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, funobj);
     JSStrictPropertyOp setter;
     if (member->IsWritableAttribute()) {
         propFlags |= JSPROP_SETTER;
         propFlags &= ~JSPROP_READONLY;
         setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, funobj);
     } else {
         setter = js_GetterOnlyPropertyStub;
@@ -482,17 +482,17 @@ XPC_WN_Shared_Convert(JSContext *cx, Han
             ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
             ccx.SetArgsAndResultPtr(0, nullptr, vp.address());
 
             XPCNativeMember* member = ccx.GetMember();
             if (member && member->IsMethod()) {
                 if (!XPCWrappedNative::CallMethod(ccx))
                     return false;
 
-                if (JSVAL_IS_PRIMITIVE(vp))
+                if (vp.isPrimitive())
                     return true;
             }
 
             // else...
             return ToStringGuts(ccx);
         }
         default:
             NS_ERROR("bad type in conversion");
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -826,21 +826,21 @@ NS_IMETHODIMP
 nsXPConnect::CreateSandbox(JSContext *cx, nsIPrincipal *principal,
                            nsIXPConnectJSObjectHolder **_retval)
 {
     *_retval = nullptr;
 
     RootedValue rval(cx);
     SandboxOptions options;
     nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
-    MOZ_ASSERT(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
+    MOZ_ASSERT(NS_FAILED(rv) || !rval.isPrimitive(),
                "Bad return value from xpc_CreateSandboxObject()!");
 
-    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) {
-        *_retval = XPCJSObjectHolder::newHolder(JSVAL_TO_OBJECT(rval));
+    if (NS_SUCCEEDED(rv) && !rval.isPrimitive()) {
+        *_retval = XPCJSObjectHolder::newHolder(rval.toObjectOrNull());
         NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY);
 
         NS_ADDREF(*_retval);
     }
 
     return rv;
 }
 
--- a/js/xpconnect/src/qsgen.py
+++ b/js/xpconnect/src/qsgen.py
@@ -558,17 +558,17 @@ def writeArgumentUnboxing(f, i, name, ty
             f.write("    %s *%s;\n" % (type.name, name))
             f.write("    xpc_qsSelfRef %sref;\n" % name)
             f.write("    rv = xpc_qsUnwrapArg<%s>("
                     "cx, %s, &%s, &%sref.ptr, %s);\n"
                     % (type.name, argVal, name, name, argPtr))
             f.write("    if (NS_FAILED(rv)) {\n")
             if isSetter:
                 assert(propIndex is not None)
-                f.write("        xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(vp[1]), (uint16_t)%s);\n" %
+                f.write("        xpc_qsThrowBadSetterValue(cx, rv, vp[1].toObjectOrNull(), (uint16_t)%s);\n" %
                         propIndex)
             else:
                 f.write("        xpc_qsThrowBadArg(cx, rv, vp, %d);\n" % i)
             f.write("        return false;\n"
                     "    }\n")
             return True
 
     warn("Unable to unbox argument of type %s (native type %s)" % (type.name, typeName))
@@ -981,17 +981,17 @@ def writeQuickStub(f, customMethodCalls,
     if canFail:
         # Check for errors.
         f.write("    if (NS_FAILED(rv))\n")
         if isMethod:
             f.write("        return xpc_qsThrowMethodFailed("
                     "cx, rv, vp);\n")
         else:
             f.write("        return xpc_qsThrowGetterSetterFailed(cx, rv, " +
-                    "JSVAL_TO_OBJECT(vp[1]), (uint16_t)%d);\n" %
+                    "vp[1].toObjectOrNull(), (uint16_t)%d);\n" %
                     stringtable.stringIndex(member.name))
 
     # Convert the return value.
     if isMethod or isGetter:
         writeResultConv(f, member.realtype, 'args.rval()', '*vp')
     else:
         f.write("    return true;\n")
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3169,17 +3169,17 @@ public:
     static already_AddRefed<XPCVariant> newVariant(JSContext* cx, jsval aJSVal);
 
     /**
      * This getter clears the gray bit before handing out the jsval if the jsval
      * represents a JSObject. That means that the object is guaranteed to be
      * kept alive past the next CC.
      */
     jsval GetJSVal() const {
-        if (!JSVAL_IS_PRIMITIVE(mJSVal))
+        if (!mJSVal.isPrimitive())
             JS::ExposeObjectToActiveJS(&mJSVal.toObject());
         return mJSVal;
     }
 
     /**
      * This getter does not change the color of the jsval (if it represents a
      * JSObject) meaning that the value returned is not guaranteed to be kept
      * alive past the next CC.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-button.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is of the button type, it is barred from constraint
+             validation and should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').setCustomValidity('foo'); document.documentElement.className='';">
+    <button class='notinvalid' id='b' type='button'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-disabled-fieldset-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notinvalid' id='b'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-disabled-fieldset-2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notinvalid' id='b'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-disabled-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <button style="background-color: green;" disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-disabled.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button is disabled, it is barred from constraint validation
+             and should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <button class='notinvalid' disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-dyn-disabled.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is disabled and invalid, it is barred from constraint
+             validation and should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      e.disabled = 'true';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='notinvalid' id='b'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-dyn-not-disabled.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is not disabled and invalid, it is candidate for
+             constraint validation and should be affected
+             by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      e.removeAttribute('disabled');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='invalid' id='b' disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-fieldset-legend-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <legend>
+        <button style="background-color: green;"></button>
+      </legend>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-fieldset-legend.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, but is in the first
+             legend, it is not barred from constraint validation and should be
+             affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <legend>
+        <button class='invalid' id='b'></button>
+      </legend>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset disabled>
+        <button style="background-color: green;"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-invalid/button/button-invalid.html
+++ b/layout/reftests/css-invalid/button/button-invalid.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
-  <!-- Test: if button has a custom error, it should not be affected by :invalid
+  <!-- Test: if button has a custom error, it should be affected by :invalid
              pseudo-class. -->
   <link rel='stylesheet' type='text/css' href='style.css'>
   <body onload="document.getElementById('b').setCustomValidity('foo'); document.documentElement.className='';">
-    <button class='notinvalid' id='b'></button>
+    <button class='invalid' id='b'></button>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-reset.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is of the reset type, it is barred from constraint
+             validation and should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').setCustomValidity('foo'); document.documentElement.className='';">
+    <button class='notinvalid' id='b' type='reset'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-type-barred.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if a button has is candidate for constraint validation then change
+             its type to be barred from constraint validation, it should not be
+             affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var b = document.getElementById('b');
+      b.setCustomValidity('foo');
+      b.type = 'button';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="document.getElementById('b').type='button'; document.documentElement.className='';">
+    <button class='notinvalid' type='submit' id='b'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-type-invalid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if a button has a custom error when barred from constraint
+             validation then move a type candidate for constraint validation,
+             it should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var b = document.getElementById('b');
+      b.setCustomValidity('foo');
+      b.type = 'submit';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='invalid' type='button' id='b'></button>
+  </body>
+</html>
--- a/layout/reftests/css-invalid/button/reftest.list
+++ b/layout/reftests/css-invalid/button/reftest.list
@@ -1,2 +1,12 @@
 == button-valid.html button-ref.html
 == button-invalid.html button-ref.html
+== button-disabled.html button-disabled-ref.html
+== button-dyn-disabled.html button-disabled-ref.html
+== button-dyn-not-disabled.html button-ref.html
+== button-button.html button-ref.html
+== button-reset.html button-ref.html
+== button-type-invalid.html button-ref.html
+== button-type-barred.html button-ref.html
+== button-disabled-fieldset-1.html button-fieldset-ref.html
+== button-disabled-fieldset-2.html button-fieldset-ref.html
+== button-fieldset-legend.html button-fieldset-legend-ref.html
--- a/layout/reftests/css-submit-invalid/button-submit/reftest.list
+++ b/layout/reftests/css-submit-invalid/button-submit/reftest.list
@@ -7,9 +7,10 @@
 == dynamic-invalid-not-barred.html invalid-ref.html
 == static-invalid-barred.html invalid-barred-ref.html
 == remove-invalid-element.html valid-ref-2.html
 == add-invalid-element.html invalid-ref-2.html
 == add-submit-control.html invalid-ref.html
 == remove-submit-control.html valid-ref-3.html
 == change-type-submit-control.html invalid-ref.html
 == change-type-not-submit-control.html valid-ref-4.html
+== self-invalid.html about:blank
 == remove-form.html invalid-ref-3.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-submit-invalid/button-submit/self-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <head>
+    <style>
+      :invalid { display: none; }
+    </style>
+  </head>
+  <script>
+    function onloadHandler()
+    {
+      document.getElementById('b').setCustomValidity('foo');
+      document.documentElement.className = '';
+    }
+  </script>
+  <body onload='onloadHandler();'>
+    <form>
+      <button id='b' type='submit'></button>
+    </form>
+  </body>
+</html>
--- a/layout/reftests/css-submit-invalid/input-image/reftest.list
+++ b/layout/reftests/css-submit-invalid/input-image/reftest.list
@@ -7,9 +7,10 @@ skip-if(B2G) == dynamic-invalid.html inv
 == dynamic-invalid-not-barred.html invalid-ref.html
 == static-invalid-barred.html invalid-barred-ref.html
 == remove-invalid-element.html valid-ref-2.html
 == add-invalid-element.html invalid-ref-2.html
 == add-submit-control.html invalid-ref.html
 == remove-submit-control.html valid-ref-3.html
 == change-type-submit-control.html invalid-ref.html
 == change-type-not-submit-control.html valid-ref-4.html
+== self-invalid.html about:blank
 == remove-form.html invalid-ref-3.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-submit-invalid/input-image/self-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <head>
+    <style>
+      :invalid { display: none; }
+    </style>
+  </head>
+  <script>
+    function onloadHandler()
+    {
+      document.getElementById('i').setCustomValidity('foo');
+      document.documentElement.className = '';
+    }
+  </script>
+  <body onload='onloadHandler();'>
+    <form>
+      <input id='i' type='image'>
+    </form>
+  </body>
+</html>
--- a/layout/reftests/css-submit-invalid/input-submit/reftest.list
+++ b/layout/reftests/css-submit-invalid/input-submit/reftest.list
@@ -7,9 +7,10 @@ skip-if(B2G) == dynamic-invalid.html inv
 == dynamic-invalid-not-barred.html invalid-ref.html
 == static-invalid-barred.html invalid-barred-ref.html
 == remove-invalid-element.html valid-ref-2.html
 == add-invalid-element.html invalid-ref-2.html
 == add-submit-control.html invalid-ref.html
 == remove-submit-control.html valid-ref-3.html
 == change-type-submit-control.html invalid-ref.html
 == change-type-not-submit-control.html valid-ref-4.html
+== self-invalid.html about:blank
 == remove-form.html invalid-ref-3.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-submit-invalid/input-submit/self-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <head>
+    <style>
+      :invalid { display: none; }
+    </style>
+  </head>
+  <script>
+    function onloadHandler()
+    {
+      document.getElementById('i').setCustomValidity('foo');
+      document.documentElement.className = '';
+    }
+  </script>
+  <body onload='onloadHandler();'>
+    <form>
+      <input id='i' type='submit'>
+    </form>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-button.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is of the button type, it is barred from constraint
+             validation and should not be affected by :-moz-ui-invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').setCustomValidity('foo'); document.documentElement.className='';">
+    <button class='notinvalid' id='b' type='button'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-disabled-fieldset-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :-moz-ui-invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notinvalid' id='b'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-disabled-fieldset-2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :-moz-ui-invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notinvalid' id='b'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-disabled-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <button style="background-color: green;" disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-disabled.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button is disabled, it is barred from constraint validation
+             and should not be affected by :-moz-ui-invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <button class='notinvalid' disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-dyn-disabled.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is disabled and invalid, it is barred from constraint
+             validation and should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      e.disabled = 'true';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='notinvalid' id='b'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-dyn-not-disabled.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is not disabled and invalid, it is candidate for
+             constraint validation and should be affected
+             by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      e.removeAttribute('disabled');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='invalid' id='b' disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-fieldset-legend-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <legend>
+        <button style="background-color: green;"></button>
+      </legend>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-fieldset-legend.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, but is in the first
+             legend, it is not barred from constraint validation and should be
+             affected by :-moz-ui-invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <legend>
+        <button class='invalid' id='b'></button>
+      </legend>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset disabled>
+        <button style="background-color: green;"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-ui-invalid/button/button-invalid.html
+++ b/layout/reftests/css-ui-invalid/button/button-invalid.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
-  <!-- Test: button element is never affected by :-moz-ui-invalid. -->
+  <!-- Test: if button has a custom error, it should not be affected by :valid
+             pseudo-class -->
   <link rel='stylesheet' type='text/css' href='style.css'>
   <body onload="document.getElementById('b').setCustomValidity('foo'); document.documentElement.className='';">
-    <button class='notinvalid' id='b'></button>
+    <button class='invalid' id='b'></button>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-novalidate.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').setCustomValidity('foo');
+                document.documentElement.className = '';">
+    <form novalidate>
+      <button id='b' class='notinvalid'></button>
+    </form>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-reset.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is of the reset type, it is barred from constraint
+             validation and should not be affected by :-moz-ui-invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').setCustomValidity('foo'); document.documentElement.className='';">
+    <button class='notinvalid' id='b' type='reset'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-type-barred.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if a button has is candidate for constraint validation then change
+             its type to be barred from constraint validation, it should not be
+             affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var b = document.getElementById('b');
+      b.setCustomValidity('foo');
+      b.type = 'button';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="document.getElementById('b').type='button'; document.documentElement.className='';">
+    <button class='notinvalid' type='submit' id='b'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-invalid/button/button-type-invalid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if a button has a custom error when barred from constraint
+             validation then move a type candidate for constraint validation,
+             it should not be affected by :invalid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var b = document.getElementById('b');
+      b.setCustomValidity('foo');
+      b.type = 'submit';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='invalid' type='button' id='b'></button>
+  </body>
+</html>
--- a/layout/reftests/css-ui-invalid/button/button-valid.html
+++ b/layout/reftests/css-ui-invalid/button/button-valid.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
 <html>
-  <!-- Test: button element is never affected by :-moz-ui-invalid. -->
+  <!-- Test: if button has no custom error and is not barred from constraint
+             validation, it should be affected by :invalid pseudo-class.  -->
   <link rel='stylesheet' type='text/css' href='style.css'>
   <body>
     <button class='notinvalid'</button>
   </body>
 </html>
--- a/layout/reftests/css-ui-invalid/button/reftest.list
+++ b/layout/reftests/css-ui-invalid/button/reftest.list
@@ -1,2 +1,13 @@
 == button-valid.html button-ref.html
 == button-invalid.html button-ref.html
+== button-disabled.html button-disabled-ref.html
+== button-dyn-disabled.html button-disabled-ref.html
+== button-dyn-not-disabled.html button-ref.html
+== button-button.html button-ref.html
+== button-reset.html button-ref.html
+== button-type-invalid.html button-ref.html
+== button-type-barred.html button-ref.html
+== button-disabled-fieldset-1.html button-fieldset-ref.html
+== button-disabled-fieldset-2.html button-fieldset-ref.html
+== button-fieldset-legend.html button-fieldset-legend-ref.html
+== button-novalidate.html button-ref.html
--- a/layout/reftests/css-ui-invalid/default-style/button-focus-ref.html
+++ b/layout/reftests/css-ui-invalid/default-style/button-focus-ref.html
@@ -1,7 +1,7 @@
 <!DOCTYPE>
 <html class="reftest-wait">
   <link rel='stylesheet' type='text/css' href='style.css'>
   <body onload="document.getElementsByTagName('button')[0].focus();">
-    <button class='barred-ref' onfocus="document.documentElement.className='';"></button>
+    <button class='invalid-ref' onfocus="document.documentElement.className='';"></button>
   </body>
 </html>
--- a/layout/reftests/css-ui-invalid/default-style/button-ref.html
+++ b/layout/reftests/css-ui-invalid/default-style/button-ref.html
@@ -1,7 +1,7 @@
 <!DOCTYPE>
 <html>
   <link rel='stylesheet' type='text/css' href='style.css'>
   <body>
-    <button class='barred-ref'></button>
+    <button class='invalid-ref'></button>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-button.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button is of the button type, it is barred from constraint
+             validation and should not be affected by :-moz-ui-valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <button class='notvalid' type='button'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-disabled-fieldset-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled>
+      <fieldset>
+        <button class='notvalid'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notvalid'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-disabled-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <button style="background-color: green;" disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-disabled.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button is disabled, it is barred from constraint validation
+             and should not be affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <button class='notvalid' disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-dyn-disabled.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is disabled, it is barred from constraint validation
+             and should not be affected by :-moz-ui-valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').disabled='true'; document.documentElement.className='';">
+    <button class='notvalid' id='b'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-dyn-not-disabled.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button is not disabled, it is candidate for constraint validation
+             and should be affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').removeAttribute('disabled'); document.documentElement.className='';">
+    <button class='valid' id='b' disabled></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-fieldset-legend-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <legend>
+        <button style="background-color: green;"></button>
+      </legend>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-fieldset-legend.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button has a disabled fieldset ancestor, but is in the first
+             legend, it is not barred from constraint validation and should be
+             affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled>
+      <legend>
+        <button class='valid'></button>
+      </legend>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset disabled>
+        <button style="background-color: green;"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-novalidate.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <form novalidate>
+      <button class='notvalid'></button>
+    </form>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-reset.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button is of the reset type, it is barred from constraint
+             validation and should not be affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <button class='notvalid' type='reset'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-type-barred.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if a button has is candidate for constraint validation then change
+             its type to be barred from constraint validation, it should not be
+             affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="document.getElementById('b').type='button'; document.documentElement.className='';">
+    <button class='notvalid' type='submit' id='b'></button>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui-valid/button/button-type-invalid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if a button has a custom error when barred from constraint
+             validation then move a type candidate for constraint validation,
+             it should not be affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var b = document.getElementById('b');
+      b.setCustomValidity('foo');
+      b.type = 'submit';
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <button class='notvalid' type='button' id='b'></button>
+  </body>
+</html>
--- a/layout/reftests/css-ui-valid/button/button-valid.html
+++ b/layout/reftests/css-ui-valid/button/button-valid.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
 <html>
-  <!-- Test: button element is never affected by :-moz-ui-valid. -->
+  <!-- Test: if button has no custom error and is not barred from constraint
+             validation, it should be affected by :valid pseudo-class  -->
   <link rel='stylesheet' type='text/css' href='style.css'>
   <body>
-    <button class='notvalid'></button>
+    <button class='valid'></button>
   </body>
 </html>
--- a/layout/reftests/css-ui-valid/button/reftest.list
+++ b/layout/reftests/css-ui-valid/button/reftest.list
@@ -1,2 +1,13 @@
 == button-valid.html button-ref.html
 == button-invalid.html button-ref.html
+== button-disabled.html button-disabled-ref.html
+== button-dyn-disabled.html button-disabled-ref.html
+== button-dyn-not-disabled.html button-ref.html
+== button-button.html button-ref.html
+== button-reset.html button-ref.html
+== button-type-invalid.html button-ref.html
+== button-type-barred.html button-ref.html
+== button-disabled-fieldset-1.html button-fieldset-ref.html
+== button-disabled-fieldset-2.html button-fieldset-ref.html
+== button-fieldset-legend.html button-fieldset-legend-ref.html
+== button-novalidate.html button-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/button/button-button.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button is of the button type, it is barred from constraint
+             validation and should not be affected by :valid pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>