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 id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersmrbkap, blocker
bugs633879
milestone2.0b12pre
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)) {