Bug 877762 - GC: Post-barrier cycle collector participants - 5 Convert JS::Value to use Heap<T> r=smaug
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 18 Jun 2013 11:00:37 +0100
changeset 146947 e71598bf972312dab776437686e41fcd4256f28d
parent 146946 8df6f75769f58b9539061c55a8efe8463578e6b1
child 146948 9fba4a49aa71ba00f5b557be53a4d30e634fc236
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs877762
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 877762 - GC: Post-barrier cycle collector participants - 5 Convert JS::Value to use Heap<T> r=smaug
content/base/src/nsXMLHttpRequest.cpp
content/base/src/nsXMLHttpRequest.h
content/events/src/nsDOMMessageEvent.h
content/xul/content/src/nsXULElement.cpp
dom/base/DOMRequest.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSTimeoutHandler.cpp
dom/future/Future.h
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBIndex.h
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBKeyRange.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBRequest.h
dom/indexedDB/Key.cpp
dom/indexedDB/Key.h
dom/indexedDB/KeyPath.cpp
dom/indexedDB/KeyPath.h
js/src/jsfriendapi.h
js/xpconnect/src/XPCJSRuntime.cpp
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -777,22 +777,24 @@ nsresult
 nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
 {
   if (!aCx) {
     return NS_ERROR_FAILURE;
   }
   RootJSResultObjects();
 
   // The Unicode converter has already zapped the BOM if there was one
+  JS::Rooted<JS::Value> value(aCx);
   if (!JS_ParseJSON(aCx,
                     static_cast<const jschar*>(mResponseText.get()), mResponseText.Length(),
-                    JS::MutableHandle<JS::Value>::fromMarkedLocation(&mResultJSON))) {
+                    &value)) {
     return NS_ERROR_FAILURE;
   }
 
+  mResultJSON = value;
   return NS_OK;
 }
 
 void
 nsXMLHttpRequest::CreatePartialBlob()
 {
   if (mDOMFile) {
     if (mLoadTotal == mLoadTransferred) {
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -652,21 +652,21 @@ protected:
    * @param aType The progress event type.
    * @param aFlag A XML_HTTP_REQUEST_* state flag defined in
    *              nsXMLHttpRequest.cpp.
    */
   void CloseRequestWithError(const nsAString& aType, const uint32_t aFlag);
 
   bool mFirstStartRequestSeen;
   bool mInLoadProgressEvent;
-  
+
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
-  
-  JS::Value mResultJSON;
+
+  JS::Heap<JS::Value> mResultJSON;
 
   js::ArrayBufferBuilder mArrayBufferBuilder;
   JSObject* mResultArrayBuffer;
 
   void ResetResponse();
 
   struct RequestHeader
   {
--- a/content/events/src/nsDOMMessageEvent.h
+++ b/content/events/src/nsDOMMessageEvent.h
@@ -60,15 +60,15 @@ public:
                         nsIDOMWindow* aSource,
                         mozilla::ErrorResult& aRv)
   {
     aRv = InitMessageEvent(aType, aCanBubble, aCancelable, aData,
                            aOrigin, aLastEventId, aSource);
   }
 
 private:
-  JS::Value mData;
+  JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
   nsCOMPtr<nsIDOMWindow> mSource;
 };
 
 #endif // nsDOMMessageEvent_h__
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2378,18 +2378,17 @@ nsXULPrototypeScript::Serialize(nsIObjec
 
     // Write basic prototype data
     nsresult rv;
     rv = aStream->Write32(mLineNo);
     if (NS_FAILED(rv)) return rv;
     rv = aStream->Write32(mLangVersion);
     if (NS_FAILED(rv)) return rv;
     // And delegate the writing to the nsIScriptContext
-    rv = context->Serialize(aStream,
-                            JS::Handle<JSScript*>::fromMarkedLocation(&mScriptObject));
+    rv = context->Serialize(aStream, mScriptObject);
     if (NS_FAILED(rv)) return rv;
 
     return NS_OK;
 }
 
 nsresult
 nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
                                          nsIScriptGlobalObject* aGlobal)
--- a/dom/base/DOMRequest.h
+++ b/dom/base/DOMRequest.h
@@ -17,17 +17,17 @@
 
 namespace mozilla {
 namespace dom {
 
 class DOMRequest : public nsDOMEventTargetHelper,
                    public nsIDOMDOMRequest
 {
 protected:
-  JS::Value mResult;
+  JS::Heap<JS::Value> mResult;
   nsRefPtr<DOMError> mError;
   bool mDone;
   bool mRooted;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMDOMREQUEST
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -3518,30 +3518,31 @@ public:
 
   // nsIJSArgArray
   nsresult GetArgs(uint32_t *argc, void **argv);
 
   void ReleaseJSObjects();
 
 protected:
   JSContext *mContext;
-  JS::Value *mArgv;
+  JS::Heap<JS::Value> *mArgv;
   uint32_t mArgc;
 };
 
 nsJSArgArray::nsJSArgArray(JSContext *aContext, uint32_t argc, JS::Value *argv,
                            nsresult *prv) :
     mContext(aContext),
     mArgv(nullptr),
     mArgc(argc)
 {
   // copy the array - we don't know its lifetime, and ours is tied to xpcom
-  // refcounting.  Alloc zero'd array so cleanup etc is safe.
+  // refcounting.
   if (argc) {
-    mArgv = (JS::Value *) PR_CALLOC(argc * sizeof(JS::Value));
+    static const fallible_t fallible = fallible_t();
+    mArgv = new (fallible) JS::Heap<JS::Value>[argc];
     if (!mArgv) {
       *prv = NS_ERROR_OUT_OF_MEMORY;
       return;
     }
   }
 
   // Callers are allowed to pass in a null argv even for argc > 0. They can
   // then use GetArgs to initialize the values.
@@ -3561,17 +3562,17 @@ nsJSArgArray::~nsJSArgArray()
 {
   ReleaseJSObjects();
 }
 
 void
 nsJSArgArray::ReleaseJSObjects()
 {
   if (mArgv) {
-    PR_DELETE(mArgv);
+    delete [] mArgv;
   }
   if (mArgc > 0) {
     mArgc = 0;
     NS_DROP_JS_OBJECTS(this, nsJSArgArray);
   }
 }
 
 // QueryInterface implementation for nsJSArgArray
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -62,17 +62,17 @@ public:
 
   void ReleaseJSObjects();
 
 private:
   // filename, line number and JS language version string of the
   // caller of setTimeout()
   nsCString mFileName;
   uint32_t mLineNo;
-  nsTArray<JS::Value> mArgs;
+  nsTArray<JS::Heap<JS::Value> > mArgs;
 
   // The JS expression to evaluate or function to call, if !mExpr
   JSFlatString *mExpr;
   nsRefPtr<Function> mFunction;
 };
 
 
 // nsJSScriptTimeoutHandler
@@ -294,17 +294,18 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
     mFunction = new Function(funobj);
 
     // Create our arg array.  argc is the number of arguments passed
     // to setTimeout or setInterval; the first two are our callback
     // and the delay, so only arguments after that need to go in our
     // array.
     // std::max(argc - 2, 0) wouldn't work right because argc is unsigned.
     uint32_t argCount = std::max(argc, 2u) - 2;
-    FallibleTArray<JS::Value> args;
+
+    FallibleTArray<JS::Heap<JS::Value> > args;
     if (!args.SetCapacity(argCount)) {
       // No need to drop here, since we already have a non-null mFunction
       return NS_ERROR_OUT_OF_MEMORY;
     }
     for (uint32_t idx = 0; idx < argCount; ++idx) {
       *args.AppendElement() = argv[idx + 2];
     }
     args.SwapElements(mArgs);
--- a/dom/future/Future.h
+++ b/dom/future/Future.h
@@ -102,17 +102,17 @@ private:
 
   nsRefPtr<nsPIDOMWindow> mWindow;
 
   nsRefPtr<FutureResolver> mResolver;
 
   nsTArray<nsRefPtr<FutureCallback> > mResolveCallbacks;
   nsTArray<nsRefPtr<FutureCallback> > mRejectCallbacks;
 
-  JS::Value mResult;
+  JS::Heap<JS::Value> mResult;
   FutureState mState;
   bool mTaskPending;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Future_h
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -539,17 +539,17 @@ IDBCursor::GetKey(JSContext* aCx,
   }
 
   if (!mHaveCachedKey) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
-    nsresult rv = mKey.ToJSVal(aCx, &mCachedKey);
+    nsresult rv = mKey.ToJSVal(aCx, mCachedKey);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mHaveCachedKey = true;
   }
 
   *aKey = mCachedKey;
   return NS_OK;
 }
@@ -573,17 +573,17 @@ IDBCursor::GetPrimaryKey(JSContext* aCx,
 
     JSAutoRequest ar(aCx);
 
     NS_ASSERTION(mType == OBJECTSTORE ? !mKey.IsUnset() :
                                         !mObjectKey.IsUnset(), "Bad key!");
 
     const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
 
-    nsresult rv = key.ToJSVal(aCx, &mCachedPrimaryKey);
+    nsresult rv = key.ToJSVal(aCx, mCachedPrimaryKey);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mHaveCachedPrimaryKey = true;
   }
 
   *aValue = mCachedPrimaryKey;
   return NS_OK;
 }
@@ -734,17 +734,17 @@ IDBCursor::Update(const jsval& aValue,
 
     rv = mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, getter_AddRefs(request));
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   else {
     JS::Rooted<JS::Value> keyVal(aCx);
-    rv = objectKey.ToJSVal(aCx, keyVal.address());
+    rv = objectKey.ToJSVal(aCx, &keyVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = mObjectStore->Put(aValue, keyVal, aCx, 1, getter_AddRefs(request));
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
@@ -805,17 +805,17 @@ IDBCursor::Delete(JSContext* aCx,
   }
 
   NS_ASSERTION(mObjectStore, "This cannot be null!");
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
 
   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
   JS::Rooted<JS::Value> key(aCx);
-  nsresult rv = objectKey.ToJSVal(aCx, key.address());
+  nsresult rv = objectKey.ToJSVal(aCx, &key);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIDBRequest> request;
   rv = mObjectStore->Delete(key, aCx, getter_AddRefs(request));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -171,19 +171,19 @@ protected:
   JSObject* mScriptOwner;
 
   Type mType;
   Direction mDirection;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
 
   // These are cycle-collected!
-  jsval mCachedKey;
-  jsval mCachedPrimaryKey;
-  jsval mCachedValue;
+  JS::Heap<JS::Value> mCachedKey;
+  JS::Heap<JS::Value> mCachedPrimaryKey;
+  JS::Heap<JS::Value> mCachedValue;
 
   Key mRangeKey;
 
   Key mKey;
   Key mObjectKey;
   StructuredCloneReadInfo mCloneReadInfo;
   Key mContinueToKey;
 
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -805,17 +805,17 @@ IDBIndex::GetKeyPath(JSContext* aCx,
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!JSVAL_IS_VOID(mCachedKeyPath)) {
     *aVal = mCachedKeyPath;
     return NS_OK;
   }
 
-  nsresult rv = GetKeyPath().ToJSVal(aCx, &mCachedKeyPath);
+  nsresult rv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
     NS_HOLD_JS_OBJECTS(this, IDBIndex);
     mRooted = true;
   }
 
   *aVal = mCachedKeyPath;
@@ -1175,17 +1175,22 @@ GetKeyHelper::DoDatabaseWork(mozIStorage
 
   return NS_OK;
 }
 
 nsresult
 GetKeyHelper::GetSuccessResult(JSContext* aCx,
                                jsval* aVal)
 {
-  return mKey.ToJSVal(aCx, aVal);
+  JS::Rooted<JS::Value> value(aCx);
+  nsresult rv = mKey.ToJSVal(aCx, &value);
+  if (NS_SUCCEEDED(rv)) {
+    *aVal = value;
+  }
+  return rv;
 }
 
 void
 GetKeyHelper::ReleaseMainThreadObjects()
 {
   mKeyRange = nullptr;
   IndexHelper::ReleaseMainThreadObjects();
 }
@@ -1503,17 +1508,17 @@ GetAllKeysHelper::GetSuccessResult(JSCon
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t index = 0, count = keys.Length(); index < count; index++) {
       const Key& key = keys[index];
       NS_ASSERTION(!key.IsUnset(), "Bad key!");
 
       JS::Rooted<JS::Value> value(aCx);
-      nsresult rv = key.ToJSVal(aCx, value.address());
+      nsresult rv = key.ToJSVal(aCx, &value);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to get jsval for key!");
         return rv;
       }
 
       if (!JS_SetElement(aCx, array, index, value.address())) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -152,17 +152,17 @@ private:
   IDBIndex();
   ~IDBIndex();
 
   nsRefPtr<IDBObjectStore> mObjectStore;
 
   int64_t mId;
   nsString mName;
   KeyPath mKeyPath;
-  JS::Value mCachedKeyPath;
+  JS::Heap<JS::Value> mCachedKeyPath;
 
   IndexedDBIndexChild* mActorChild;
   IndexedDBIndexParent* mActorParent;
 
   bool mUnique;
   bool mMultiEntry;
   bool mRooted;
 };
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -358,17 +358,17 @@ IDBKeyRange::GetLower(JSContext* aCx,
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveCachedLowerVal) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBKeyRange);
       mRooted = true;
     }
 
-    nsresult rv = Lower().ToJSVal(aCx, &mCachedLowerVal);
+    nsresult rv = Lower().ToJSVal(aCx, mCachedLowerVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mHaveCachedLowerVal = true;
   }
 
   *aLower = mCachedLowerVal;
   return NS_OK;
 }
@@ -380,17 +380,17 @@ IDBKeyRange::GetUpper(JSContext* aCx,
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveCachedUpperVal) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBKeyRange);
       mRooted = true;
     }
 
-    nsresult rv = Upper().ToJSVal(aCx, &mCachedUpperVal);
+    nsresult rv = Upper().ToJSVal(aCx, mCachedUpperVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mHaveCachedUpperVal = true;
   }
 
   *aUpper = mCachedUpperVal;
   return NS_OK;
 }
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -152,18 +152,18 @@ public:
 
   void DropJSObjects();
 
 private:
   ~IDBKeyRange();
 
   Key mLower;
   Key mUpper;
-  jsval mCachedLowerVal;
-  jsval mCachedUpperVal;
+  JS::Heap<JS::Value> mCachedLowerVal;
+  JS::Heap<JS::Value> mCachedUpperVal;
   bool mLowerOpen;
   bool mUpperOpen;
   bool mIsOnly;
   bool mHaveCachedLowerVal;
   bool mHaveCachedUpperVal;
   bool mRooted;
 };
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -2382,17 +2382,17 @@ IDBObjectStore::GetKeyPath(JSContext* aC
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!JSVAL_IS_VOID(mCachedKeyPath)) {
     *aVal = mCachedKeyPath;
     return NS_OK;
   }
 
-  nsresult rv = GetKeyPath().ToJSVal(aCx, &mCachedKeyPath);
+  nsresult rv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
     NS_HOLD_JS_OBJECTS(this, IDBObjectStore);
     mRooted = true;
   }
 
   *aVal = mCachedKeyPath;
@@ -3129,17 +3129,22 @@ AddHelper::DoDatabaseWork(mozIStorageCon
 nsresult
 AddHelper::GetSuccessResult(JSContext* aCx,
                             jsval* aVal)
 {
   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
 
   mCloneWriteInfo.mCloneBuffer.clear();
 
-  return mKey.ToJSVal(aCx, aVal);
+  JS::Rooted<JS::Value> value(aCx);
+  nsresult rv = mKey.ToJSVal(aCx, &value);
+  if (NS_SUCCEEDED(rv)) {
+    *aVal = value;
+  }
+  return rv;
 }
 
 void
 AddHelper::ReleaseMainThreadObjects()
 {
   IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo);
   ObjectStoreHelper::ReleaseMainThreadObjects();
 }
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -282,17 +282,17 @@ protected:
                  uint32_t aTag,
                  BlobOrFileData* aRetval);
 private:
   nsRefPtr<IDBTransaction> mTransaction;
 
   int64_t mId;
   nsString mName;
   KeyPath mKeyPath;
-  JS::Value mCachedKeyPath;
+  JS::Heap<JS::Value> mCachedKeyPath;
   bool mRooted;
   bool mAutoIncrement;
   nsCOMPtr<nsIAtom> mDatabaseId;
   nsRefPtr<ObjectStoreInfo> mInfo;
 
   nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes;
 
   IndexedDBObjectStoreChild* mActorChild;
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -115,23 +115,25 @@ IDBRequest::NotifyHelperCompleted(Helper
   }
 
   JS::Rooted<JSObject*> global(cx, GetParentObject());
   NS_ASSERTION(global, "This should never be null!");
 
   JSAutoCompartment ac(cx, global);
   AssertIsRooted();
 
-  rv = aHelper->GetSuccessResult(cx, &mResultVal);
+  JS::Rooted<JS::Value> value(cx);
+  rv = aHelper->GetSuccessResult(cx, value.address());
   if (NS_FAILED(rv)) {
     NS_WARNING("GetSuccessResult failed!");
   }
 
   if (NS_SUCCEEDED(rv)) {
     mError = nullptr;
+    mResultVal = value;
   }
   else {
     SetError(rv);
     mResultVal = JSVAL_VOID;
   }
 
   return rv;
 }
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -104,17 +104,17 @@ public:
 
 protected:
   IDBRequest();
   ~IDBRequest();
 
   nsCOMPtr<nsISupports> mSource;
   nsRefPtr<IDBTransaction> mTransaction;
 
-  jsval mResultVal;
+  JS::Heap<JS::Value> mResultVal;
   nsRefPtr<mozilla::dom::DOMError> mError;
   IndexedDBRequestParentBase* mActorParent;
   nsString mFilename;
 #ifdef MOZ_ENABLE_PROFILER_SPS
   uint64_t mSerialNumber;
 #endif
   nsresult mErrorCode;
   uint32_t mLineNo;
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -180,17 +180,17 @@ Key::EncodeJSValInternal(JSContext* aCx,
   }
 
   return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
 }
 
 // static
 nsresult
 Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
-                         JSContext* aCx, uint8_t aTypeOffset, jsval* aVal,
+                         JSContext* aCx, uint8_t aTypeOffset, JS::MutableHandle<JS::Value> aVal,
                          uint16_t aRecursionDepth)
 {
   NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
 
   if (*aPos - aTypeOffset >= eArray) {
     JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
     if (!array) {
       NS_WARNING("Failed to make array!");
@@ -203,52 +203,52 @@ Key::DecodeJSValInternal(const unsigned 
       ++aPos;
       aTypeOffset = 0;
     }
 
     uint32_t index = 0;
     while (aPos < aEnd && *aPos - aTypeOffset != eTerminator) {
       JS::Rooted<JS::Value> val(aCx);
       nsresult rv = DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset,
-                                        val.address(), aRecursionDepth + 1);
+                                        &val, aRecursionDepth + 1);
       NS_ENSURE_SUCCESS(rv, rv);
 
       aTypeOffset = 0;
 
       if (!JS_SetElement(aCx, array, index++, val.address())) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     NS_ASSERTION(aPos >= aEnd || (*aPos % eMaxType) == eTerminator,
                  "Should have found end-of-array marker");
     ++aPos;
 
-    *aVal = OBJECT_TO_JSVAL(array);
+    aVal.setObject(*array);
   }
   else if (*aPos - aTypeOffset == eString) {
     nsString key;
     DecodeString(aPos, aEnd, key);
-    if (!xpc::StringToJsval(aCx, key, aVal)) {
+    if (!xpc::StringToJsval(aCx, key, aVal.address())) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
   else if (*aPos - aTypeOffset == eDate) {
     double msec = static_cast<double>(DecodeNumber(aPos, aEnd));
     JSObject* date = JS_NewDateObjectMsec(aCx, msec);
     if (!date) {
       NS_WARNING("Failed to make date!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
-    *aVal = OBJECT_TO_JSVAL(date);
+    aVal.setObject(*date);
   }
   else if (*aPos - aTypeOffset == eFloat) {
-    *aVal = DOUBLE_TO_JSVAL(DecodeNumber(aPos, aEnd));
+    aVal.setDouble(DecodeNumber(aPos, aEnd));
   }
   else {
     NS_NOTREACHED("Unknown key type!");
   }
 
   return NS_OK;
 }
 
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -174,33 +174,44 @@ public:
       return rv;
     }
     TrimBuffer();
 
     return NS_OK;
   }
 
   nsresult ToJSVal(JSContext* aCx,
-                   jsval* aVal) const
+                   JS::MutableHandle<JS::Value> aVal) const
   {
     if (IsUnset()) {
-      *aVal = JSVAL_VOID;
+      aVal.set(JSVAL_VOID);
       return NS_OK;
     }
 
     const unsigned char* pos = BufferStart();
     nsresult rv = DecodeJSVal(pos, BufferEnd(), aCx, 0, aVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ASSERTION(pos >= BufferEnd(),
                  "Didn't consume whole buffer");
 
     return NS_OK;
   }
 
+  nsresult ToJSVal(JSContext* aCx,
+                   JS::Heap<JS::Value>& aVal) const
+  {
+    JS::Rooted<JS::Value> value(aCx);
+    nsresult rv = ToJSVal(aCx, &value);
+    if (NS_SUCCEEDED(rv)) {
+      aVal = value;
+    }
+    return rv;
+  }
+
   nsresult AppendItem(JSContext* aCx,
                       bool aFirstOfArray,
                       const jsval aVal)
   {
     nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
     if (NS_FAILED(rv)) {
       Unset();
       return rv;
@@ -299,17 +310,17 @@ private:
   }
   void EncodeString(const nsAString& aString, uint8_t aTypeOffset);
   void EncodeNumber(double aFloat, uint8_t aType);
 
   // Decoding functions. aPos points into mBuffer and is adjusted to point
   // past the consumed value.
   static inline nsresult DecodeJSVal(const unsigned char*& aPos,
                                      const unsigned char* aEnd, JSContext* aCx,
-                                     uint8_t aTypeOffset, jsval* aVal)
+                                     uint8_t aTypeOffset, JS::MutableHandle<JS::Value> aVal)
   {
     return DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset, aVal, 0);
   }
 
   static void DecodeString(const unsigned char*& aPos,
                            const unsigned char* aEnd,
                            nsString& aString);
   static double DecodeNumber(const unsigned char*& aPos,
@@ -319,14 +330,14 @@ private:
 
 private:
   nsresult EncodeJSValInternal(JSContext* aCx, const jsval aVal,
                                uint8_t aTypeOffset, uint16_t aRecursionDepth);
 
   static nsresult DecodeJSValInternal(const unsigned char*& aPos,
                                       const unsigned char* aEnd,
                                       JSContext* aCx, uint8_t aTypeOffset,
-                                      jsval* aVal, uint16_t aRecursionDepth);
+                                      JS::MutableHandle<JS::Value> aVal, uint16_t aRecursionDepth);
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif /* mozilla_dom_indexeddb_key_h__ */
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -452,17 +452,17 @@ KeyPath::DeserializeFromString(const nsA
 
   keyPath.SetType(STRING);
   keyPath.mStrings.AppendElement(aString);
 
   return keyPath;
 }
 
 nsresult
-KeyPath::ToJSVal(JSContext* aCx, JS::Value* aValue) const
+KeyPath::ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aValue) const
 {
   if (IsArray()) {
     uint32_t len = mStrings.Length();
     JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, len, nullptr));
     if (!array) {
       NS_WARNING("Failed to make array!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
@@ -474,32 +474,43 @@ KeyPath::ToJSVal(JSContext* aCx, JS::Val
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       if (!JS_SetElement(aCx, array, i, val.address())) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
-    *aValue = OBJECT_TO_JSVAL(array);
+    aValue.setObject(*array);
     return NS_OK;
   }
 
   if (IsString()) {
     nsString tmp(mStrings[0]);
-    if (!xpc::StringToJsval(aCx, tmp, aValue)) {
+    if (!xpc::StringToJsval(aCx, tmp, aValue.address())) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
     return NS_OK;
   }
 
-  *aValue = JSVAL_NULL;
+  aValue.setNull();
   return NS_OK;
 }
 
+nsresult
+KeyPath::ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aValue) const
+{
+  JS::Rooted<JS::Value> value(aCx);
+  nsresult rv = ToJSVal(aCx, &value);
+  if (NS_SUCCEEDED(rv)) {
+    aValue = value;
+  }
+  return rv;
+}
+
 bool
 KeyPath::IsAllowedForObjectStore(bool aAutoIncrement) const
 {
   // Any keypath that passed validation is allowed for non-autoIncrement
   // objectStores.
   if (!aAutoIncrement) {
     return true;
   }
--- a/dom/indexedDB/KeyPath.h
+++ b/dom/indexedDB/KeyPath.h
@@ -82,17 +82,18 @@ public:
   bool operator==(const KeyPath& aOther) const
   {
     return mType == aOther.mType && mStrings == aOther.mStrings;
   }
 
   void SerializeToString(nsAString& aString) const;
   static KeyPath DeserializeFromString(const nsAString& aString);
 
-  nsresult ToJSVal(JSContext* aCx, JS::Value* aValue) const;
+  nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aValue) const;
+  nsresult ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aValue) const;
 
   bool IsAllowedForObjectStore(bool aAutoIncrement) const;
 
   KeyPathType mType;
 
   nsTArray<nsString> mStrings;
 };
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -26,16 +26,21 @@
     ((uintptr_t)(sp) < (limit)+(tolerance))
 #else
 # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance)  \
     ((uintptr_t)(sp) > (limit)-(tolerance))
 #endif
 
 #define JS_CHECK_STACK_SIZE(limit, lval) JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, lval, 0)
 
+namespace JS {
+template <class T>
+class Heap;
+} /* namespace JS */
+
 extern JS_FRIEND_API(void)
 JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
 extern JS_FRIEND_API(JSString *)
 JS_GetAnonymousString(JSRuntime *rt);
 
 extern JS_FRIEND_API(JSObject *)
 JS_FindCompilationScope(JSContext *cx, JSObject *obj);
@@ -885,17 +890,17 @@ NukeCrossCompartmentWrappers(JSContext* 
  */
 
 struct ExpandoAndGeneration {
   ExpandoAndGeneration()
     : expando(UndefinedValue()),
       generation(0)
   {}
 
-  Value expando;
+  JS::Heap<JS::Value> expando;
   uint32_t generation;
 };
 
 typedef enum DOMProxyShadowsResult {
   ShadowCheckFailed,
   Shadows,
   DoesntShadow,
   DoesntShadowUnique
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -498,18 +498,18 @@ void XPCJSRuntime::TraceGrayJS(JSTracer*
     XPCJSRuntime* self = (XPCJSRuntime*)data;
 
     // Mark these roots as gray so the CC can walk them later.
     self->TraceXPConnectRoots(trc);
 }
 
 struct JsGcTracer : public TraceCallbacks
 {
-    virtual void Trace(JS::Value *p, const char *name, void *closure) const MOZ_OVERRIDE {
-        JS_CallValueTracer(static_cast<JSTracer*>(closure), p, name);
+    virtual void Trace(JS::Heap<JS::Value> *p, const char *name, void *closure) const MOZ_OVERRIDE {
+        JS_CallHeapValueTracer(static_cast<JSTracer*>(closure), p, name);
     }
     virtual void Trace(jsid *p, const char *name, void *closure) const MOZ_OVERRIDE {
         JS_CallIdTracer(static_cast<JSTracer*>(closure), p, name);
     }
     virtual void Trace(JSObject **p, const char *name, void *closure) const MOZ_OVERRIDE {
         JS_CallObjectTracer(static_cast<JSTracer*>(closure), p, name);
     }
     virtual void Trace(JSString **p, const char *name, void *closure) const MOZ_OVERRIDE {
--- a/xpcom/glue/nsCycleCollectionParticipant.cpp
+++ b/xpcom/glue/nsCycleCollectionParticipant.cpp
@@ -64,19 +64,19 @@ CycleCollectionNoteEdgeNameImpl(nsCycleC
   nsAutoCString arrayEdgeName(aName);
   if (aFlags & CycleCollectionEdgeNameArrayFlag) {
     arrayEdgeName.AppendLiteral("[i]");
   }
   aCallback.NoteNextEdgeName(arrayEdgeName.get());
 }
 
 void
-TraceCallbackFunc::Trace(JS::Value* p, const char* name, void* closure) const
+TraceCallbackFunc::Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const
 {
-  mCallback(JSVAL_TO_TRACEABLE(*p), name, closure);
+  mCallback(JSVAL_TO_TRACEABLE(p->get()), name, closure);
 }
 
 void
 TraceCallbackFunc::Trace(jsid* p, const char* name, void* closure) const
 {
   void *thing = JSID_TO_GCTHING(*p);
   if (thing) {
     mCallback(thing, name, closure);
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -57,17 +57,17 @@ template <class T> class Heap;
 
 /*
  * A struct defining pure virtual methods which are called when tracing cycle
  * collection paticipants.  The appropriate method is called depending on the
  * type of JS GC thing.
  */
 struct TraceCallbacks
 {
-    virtual void Trace(JS::Value* p, const char* name, void* closure) const = 0;
+    virtual void Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const = 0;
     virtual void Trace(jsid* p, const char* name, void* closure) const = 0;
     virtual void Trace(JSObject** p, const char* name, void* closure) const = 0;
     virtual void Trace(JSString** p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const = 0;
 
     void Trace(JSFlatString** p, const char* name, void* closure) const {
         Trace(reinterpret_cast<JSString**>(p), name, closure);
     }
@@ -78,17 +78,17 @@ struct TraceCallbacks
  * GC thing types encountered.
  */
 struct TraceCallbackFunc : public TraceCallbacks
 {
     typedef void (* Func)(void* p, const char* name, void* closure);
 
     explicit TraceCallbackFunc(Func cb) : mCallback(cb) {}
 
-    virtual void Trace(JS::Value* p, const char* name, void* closure) const MOZ_OVERRIDE;
+    virtual void Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(jsid* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JSObject** p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JSString** p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
 
   private:
     Func mCallback;
 };