Bug 633879 - Stop wrappers from holding old scopes alive. r=mrbkap@gmail.com,jst@mozilla.com, a=blocker
authorAndreas Gal <gal@uci.edu>
Mon, 14 Feb 2011 14:19:36 -0800
changeset 62531 9e7a0e7f1f61c632741acae675226efc0dee3484
parent 62530 ef4948301ae0b819dc05d9af240348481f39af53
child 62532 0fd8793db7f37dbf6ed7e5936b311f91e4db8745
push id18769
push userjst@mozilla.com
push dateMon, 14 Feb 2011 22:19:58 +0000
treeherdermozilla-central@9e7a0e7f1f61 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap, blocker
bugs633879
milestone2.0b12pre
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 633879 - Stop wrappers from holding old scopes alive. r=mrbkap@gmail.com,jst@mozilla.com, a=blocker
js/src/jscompartment.cpp
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/shell/js.cpp
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -40,16 +40,17 @@
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jstracer.h"
+#include "jswrapper.h"
 #include "assembler/wtf/Platform.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
 
 #include "jsgcinlines.h"
 
 using namespace js;
@@ -165,16 +166,22 @@ JSCompartment::arenaListsAreEmpty()
 {
   for (unsigned i = 0; i < FINALIZE_LIMIT; i++) {
        if (!arenas[i].isEmpty())
            return false;
   }
   return true;
 }
 
+static bool
+IsCrossCompartmentWrapper(JSObject *wrapper)
+{
+    return !!(JSWrapper::wrapperHandler(wrapper)->flags() & JSWrapper::CROSS_COMPARTMENT);
+}
+
 bool
 JSCompartment::wrap(JSContext *cx, Value *vp)
 {
     JS_ASSERT(cx->compartment == this);
 
     uintN flags = 0;
 
     JS_CHECK_RECURSION(cx, return false);
@@ -265,18 +272,26 @@ JSCompartment::wrap(JSContext *cx, Value
             JS_ASSERT(outer && outer == obj);
         }
 #endif
     }
 
     /* If we already have a wrapper for this value, use it. */
     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) {
         *vp = p->value;
-        if (vp->isObject())
-            vp->toObject().setParent(global);
+        if (vp->isObject()) {
+            JSObject *obj = &vp->toObject();
+            JS_ASSERT(IsCrossCompartmentWrapper(obj));
+            if (obj->getParent() != global) {
+                do {
+                    obj->setParent(global);
+                    obj = obj->getProto();
+                } while (obj && IsCrossCompartmentWrapper(obj));
+            }
+        }
         return true;
     }
 
     if (vp->isString()) {
         Value orig = *vp;
         JSString *str = vp->toString();
         const jschar *chars = str->getChars(cx);
         if (!chars)
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -412,22 +412,16 @@ JSCrossCompartmentWrapper::JSCrossCompar
   : JSWrapper(CROSS_COMPARTMENT | flags)
 {
 }
 
 JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper()
 {
 }
 
-bool
-JSCrossCompartmentWrapper::isCrossCompartmentWrapper(JSObject *obj)
-{
-    return obj->isProxy() && obj->getProxyHandler() == &JSCrossCompartmentWrapper::singleton;
-}
-
 #define PIERCE(cx, wrapper, mode, pre, op, post)            \
     JS_BEGIN_MACRO                                          \
         AutoCompartment call(cx, wrappedObject(wrapper));   \
         if (!call.enter())                                  \
             return false;                                   \
         bool ok = (pre) && (op);                            \
         call.leave();                                       \
         return ok && (post);                                \
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -146,18 +146,16 @@ class JS_FRIEND_API(JSCrossCompartmentWr
     /* Spidermonkey extensions. */
     virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *vp);
     virtual bool construct(JSContext *cx, JSObject *wrapper,
                            uintN argc, js::Value *argv, js::Value *rval);
     virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const js::Value *vp, bool *bp);
     virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper);
     virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
 
-    static bool isCrossCompartmentWrapper(JSObject *obj);
-
     static JSCrossCompartmentWrapper singleton;
 };
 
 namespace js {
 
 class AutoCompartment
 {
   public:
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3447,18 +3447,20 @@ EvalInContext(JSContext *cx, uintN argc,
 
     *vp = OBJECT_TO_JSVAL(sobj);
     if (srclen == 0)
         return true;
 
     JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
     {
         JSAutoEnterCompartment ac;
-        if (JSCrossCompartmentWrapper::isCrossCompartmentWrapper(sobj)) {
-            sobj = sobj->unwrap();
+        uintN flags;
+        JSObject *unwrapped = sobj->unwrap(&flags);
+        if (flags & JSWrapper::CROSS_COMPARTMENT) {
+            sobj = unwrapped;
             if (!ac.enter(cx, sobj))
                 return false;
         }
 
         OBJ_TO_INNER_OBJECT(cx, sobj);
         if (!sobj)
             return false;
         if (!(sobj->getClass()->flags & JSCLASS_IS_GLOBAL)) {