Bug 684039: Don't use JSArenaPool in nsJSEnvironment. (r=mrbkap)
authorChris Leary <cdleary@mozilla.com>
Thu, 22 Sep 2011 15:13:36 -0700
changeset 78677 ebb656c6410ea49cb5f19e1071f2915e0b569976
parent 78676 c4b5ba89b4b7ae9a7d765ebbdd24b5b9ed15a1a2
child 78678 7f0922f6090db56e809391c2aa4bb3d67686fef3
push idunknown
push userunknown
push dateunknown
reviewersmrbkap
bugs684039
milestone9.0a1
Bug 684039: Don't use JSArenaPool in nsJSEnvironment. (r=mrbkap)
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -194,16 +194,43 @@ nsMemoryPressureObserver::Observe(nsISup
 {
   if (sGCOnMemoryPressure) {
     nsJSContext::GarbageCollectNow();
     nsJSContext::CycleCollectNow();
   }
   return NS_OK;
 }
 
+class nsRootedJSValueArray {
+public:
+  explicit nsRootedJSValueArray(JSContext *cx) : avr(cx, vals.Length(), vals.Elements()) {}
+
+  PRBool SetCapacity(JSContext *cx, size_t capacity) {
+    PRBool ok = vals.SetCapacity(capacity);
+    if (!ok)
+      return PR_FALSE;
+    // Values must be safe for the GC to inspect (they must not contain garbage).
+    memset(vals.Elements(), 0, vals.SizeOf());
+    resetRooter(cx);
+    return PR_TRUE;
+  }
+
+  jsval *Elements() {
+    return vals.Elements();
+  }
+
+private:
+  void resetRooter(JSContext *cx) {
+    avr.changeArray(vals.Elements(), vals.Length());
+  }
+
+  nsAutoTArray<jsval, 16> vals;
+  js::AutoArrayRooter avr;
+};
+
 /****************************************************************
  ************************** AutoFree ****************************
  ****************************************************************/
 
 class AutoFree {
 public:
   AutoFree(void *aPtr) : mPtr(aPtr) {
   }
@@ -213,25 +240,16 @@ public:
   }
   void Invalidate() {
     mPtr = 0;
   }
 private:
   void *mPtr;
 };
 
-class nsAutoPoolRelease {
-public:
-  nsAutoPoolRelease(JSArenaPool *p, void *m) : mPool(p), mMark(m) {}
-  ~nsAutoPoolRelease() { JS_ARENA_RELEASE(mPool, mMark); }
-private:
-  JSArenaPool *mPool;
-  void *mMark;
-};
-
 // A utility function for script languages to call.  Although it looks small,
 // the use of nsIDocShell and nsPresContext triggers a huge number of
 // dependencies that most languages would not otherwise need.
 // XXXmarkh - This function is mis-placed!
 PRBool
 NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
                      nsScriptErrorEvent *aErrorEvent,
                      nsEventStatus *aStatus)
@@ -1907,26 +1925,24 @@ nsJSContext::CallEventHandler(nsISupport
     JSAutoEnterCompartment ac;
     js::ForceFrame ff(mContext, funobj);
     if (!ac.enter(mContext, funobj) || !ff.enter() ||
         !JS_WrapObject(mContext, &target)) {
       sSecurityManager->PopContextPrincipal(mContext);
       return NS_ERROR_FAILURE;
     }
 
-    Maybe<nsAutoPoolRelease> poolRelease;
-    Maybe<js::AutoArrayRooter> tvr;
+    Maybe<nsRootedJSValueArray> tempStorage;
 
     // Use |target| as the scope for wrapping the arguments, since aScope is
     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
     // was OK because those typically have PreCreate methods that give them the
     // right scope anyway, and we want to make sure that the arguments end up
     // in the same scope as aTarget.
-    rv = ConvertSupportsTojsvals(aargv, target, &argc,
-                                 &argv, poolRelease, tvr);
+    rv = ConvertSupportsTojsvals(aargv, target, &argc, &argv, tempStorage);
     NS_ENSURE_SUCCESS(rv, rv);
 
     ++mExecuteDepth;
     PRBool ok = ::JS_CallFunctionValue(mContext, target,
                                        funval, argc, argv, &rval);
     --mExecuteDepth;
 
     if (!ok) {
@@ -2338,22 +2354,20 @@ nsJSContext::InitializeExternalClasses()
 nsresult
 nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArgs)
 {
   PRUint32  argc;
   jsval    *argv = nsnull;
 
   JSAutoRequest ar(mContext);
 
-  Maybe<nsAutoPoolRelease> poolRelease;
-  Maybe<js::AutoArrayRooter> tvr;
+  Maybe<nsRootedJSValueArray> tempStorage;
 
   nsresult rv;
-  rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
-                               &argv, poolRelease, tvr);
+  rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   jsval vargs;
 
   // got the arguments, now attach them.
 
   // window.dialogArguments is supposed to be an array if a JS array
   // was passed to showModalDialog(), deal with that here.
@@ -2379,18 +2393,17 @@ nsJSContext::SetProperty(void *aTarget, 
   return rv;
 }
 
 nsresult
 nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
                                      void *aScope,
                                      PRUint32 *aArgc,
                                      jsval **aArgv,
-                                     Maybe<nsAutoPoolRelease> &aPoolRelease,
-                                     Maybe<js::AutoArrayRooter> &aRooter)
+                                     Maybe<nsRootedJSValueArray> &aTempStorage)
 {
   nsresult rv = NS_OK;
 
   // If the array implements nsIJSArgArray, just grab the values directly.
   nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
   if (fastArray != nsnull)
     return fastArray->GetArgs(aArgc, reinterpret_cast<void **>(aArgv));
 
@@ -2415,26 +2428,21 @@ nsJSContext::ConvertSupportsTojsvals(nsI
     rv = argsArray->GetLength(&argCount);
     NS_ENSURE_SUCCESS(rv, rv);
     if (argCount == 0)
       return NS_OK;
   } else {
     argCount = 1; // the nsISupports which is not an array
   }
 
-  void *mark = JS_ARENA_MARK(&mContext->tempPool);
-  jsval *argv;
-  size_t nbytes = argCount * sizeof(jsval);
-  JS_ARENA_ALLOCATE_CAST(argv, jsval *, &mContext->tempPool, nbytes);
-  NS_ENSURE_TRUE(argv, NS_ERROR_OUT_OF_MEMORY);
-  memset(argv, 0, nbytes);  /* initialize so GC-able */
-
   // Use the caller's auto guards to release and unroot.
-  aPoolRelease.construct(&mContext->tempPool, mark);
-  aRooter.construct(mContext, argCount, argv);
+  aTempStorage.construct(mContext);
+  PRBool ok = aTempStorage.ref().SetCapacity(mContext, argCount);
+  NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
+  jsval *argv = aTempStorage.ref().Elements();
 
   if (argsArray) {
     for (argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
       nsCOMPtr<nsISupports> arg;
       jsval *thisval = argv + argCtr;
       argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
                                 getter_AddRefs(arg));
       if (!arg) {
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -43,17 +43,17 @@
 #include "jsapi.h"
 #include "nsIObserver.h"
 #include "nsIXPCScriptNotify.h"
 #include "prtime.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsScriptNameSpaceManager.h"
 
 class nsIXPConnectJSObjectHolder;
-class nsAutoPoolRelease;
+class nsRootedJSValueArray;
 namespace js {
 class AutoArrayRooter;
 }
 namespace mozilla {
 template <class> class Maybe;
 }
 
 class nsJSContext : public nsIScriptContext,
@@ -199,18 +199,17 @@ public:
 protected:
   nsresult InitializeExternalClasses();
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    void *aScope,
                                    PRUint32 *aArgc,
                                    jsval **aArgv,
-                                   mozilla::Maybe<nsAutoPoolRelease> &aPoolRelease,
-                                   mozilla::Maybe<js::AutoArrayRooter> &aRooter);
+                                   mozilla::Maybe<nsRootedJSValueArray> &aPoolRelease);
 
   nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
 
   // given an nsISupports object (presumably an event target or some other
   // DOM object), get (or create) the JSObject wrapping it.
   nsresult JSObjectFromInterface(nsISupports *aSup, void *aScript, 
                                  JSObject **aRet);