Bug 593147 - TM: global Object created in _newJSDContext needs a compartment. r=gal.
authorJason Orendorff <jorendorff@mozilla.com>
Tue, 14 Sep 2010 16:24:59 -0700
changeset 54154 35e5647f070a56000dc6b1c6835c4c843e966f6a
parent 54153 84b4d4856e1eaab0ccc7ba6184a977ab44ef5ab5
child 54156 219353d3eb4ce7a23855442c7ee881b464f6bc79
push id15788
push userrsayre@mozilla.com
push dateThu, 16 Sep 2010 16:26:06 +0000
treeherdermozilla-central@f1f07a0a036b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgal
bugs593147
milestone2.0b6pre
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 593147 - TM: global Object created in _newJSDContext needs a compartment. r=gal.
js/jsd/jsd.h
js/jsd/jsd_high.c
js/jsd/jsdebug.c
js/jsd/jsdebug.h
js/src/jsapi.cpp
js/src/jsapi.h
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -335,17 +335,19 @@ extern void JSD_ASSERT_VALID_OBJECT(JSDO
 #endif
 
 /***************************************************************************/
 /* higher level functions */
 
 extern JSDContext*
 jsd_DebuggerOnForUser(JSRuntime*         jsrt,
                       JSD_UserCallbacks* callbacks,
-                      void*              user);
+                      void*              user,
+                      JSObject*          scopeobj);
+
 extern JSDContext*
 jsd_DebuggerOn(void);
 
 extern void
 jsd_DebuggerOff(JSDContext* jsdc);
 
 extern void
 jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff);
--- a/js/jsd/jsd_high.c
+++ b/js/jsd/jsd_high.c
@@ -81,19 +81,21 @@ static JSBool
 {
     return !callbacks ||
            (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
 }    
 
 static JSDContext*
 _newJSDContext(JSRuntime*         jsrt, 
                JSD_UserCallbacks* callbacks, 
-               void*              user)
+               void*              user,
+               JSObject*          scopeobj)
 {
     JSDContext* jsdc = NULL;
+    JSCompartment *compartment;
 
     if( ! jsrt )
         return NULL;
 
     if( ! _validateUserCallbacks(callbacks) )
         return NULL;
 
     jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
@@ -132,17 +134,21 @@ static JSDContext*
         goto label_newJSDContext_failure;
 
     jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256);
     if( ! jsdc->dumbContext )
         goto label_newJSDContext_failure;
 
     JS_BeginRequest(jsdc->dumbContext);
 
+    if( scopeobj )
+        compartment = js_SwitchToObjectCompartment(jsdc->dumbContext, scopeobj);
     jsdc->glob = JS_NewGlobalObject(jsdc->dumbContext, &global_class);
+    if( scopeobj )
+        js_SwitchToCompartment(jsdc->dumbContext, compartment);
     if( ! jsdc->glob )
         goto label_newJSDContext_failure;
 
     if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
         goto label_newJSDContext_failure;
 
     JS_EndRequest(jsdc->dumbContext);
 
@@ -189,22 +195,23 @@ static void
     jsdc->dumbContext = NULL;
 }
 
 /***************************************************************************/
 
 JSDContext*
 jsd_DebuggerOnForUser(JSRuntime*         jsrt, 
                       JSD_UserCallbacks* callbacks, 
-                      void*              user)
+                      void*              user,
+                      JSObject*          scopeobj)
 {
     JSDContext* jsdc;
     JSContext* iter = NULL;
 
-    jsdc = _newJSDContext(jsrt, callbacks, user);
+    jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
     if( ! jsdc )
         return NULL;
 
     /*
      * Set hooks here.  The new/destroy script hooks are on even when
      * the debugger is paused.  The destroy hook so we'll clean up
      * internal data structures when scripts are destroyed, and the
      * newscript hook for backwards compatibility for now.  We'd like
@@ -221,17 +228,17 @@ jsd_DebuggerOnForUser(JSRuntime*        
     return jsdc;
 }
 
 JSDContext*
 jsd_DebuggerOn(void)
 {
     JS_ASSERT(_jsrt);
     JS_ASSERT(_validateUserCallbacks(&_callbacks));
-    return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user);
+    return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, NULL);
 }
 
 void
 jsd_DebuggerOff(JSDContext* jsdc)
 {
     jsd_DebuggerPause(jsdc, JS_TRUE);
     /* clear hooks here */
     JS_SetNewScriptHookProc(jsdc->jsrt, NULL, NULL);
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -44,17 +44,17 @@
 /***************************************************************************/
 /* High Level calls */
 
 JSD_PUBLIC_API(JSDContext*)
 JSD_DebuggerOnForUser(JSRuntime*         jsrt,
                       JSD_UserCallbacks* callbacks,
                       void*              user)
 {
-    return jsd_DebuggerOnForUser(jsrt, callbacks, user);
+    return jsd_DebuggerOnForUser(jsrt, callbacks, user, NULL);
 }
 
 JSD_PUBLIC_API(JSDContext*)
 JSD_DebuggerOn(void)
 {
     return jsd_DebuggerOn();
 }
 
--- a/js/jsd/jsdebug.h
+++ b/js/jsd/jsdebug.h
@@ -138,16 +138,26 @@ JSD_DebuggerOn(void);
 * Startup JSD on a particular JSRuntime with (optional) callbacks
 */
 extern JSD_PUBLIC_API(JSDContext*)
 JSD_DebuggerOnForUser(JSRuntime*         jsrt,
                       JSD_UserCallbacks* callbacks,
                       void*              user);
 
 /*
+ * Startup JSD in an application that uses compartments. Debugger
+ * objects will be allocated in the same compartment as scopeobj.
+ */
+extern JSD_PUBLIC_API(JSDContext*)
+JSD_DebuggerOnForUserWithCompartment(JSRuntime*         jsrt,
+                                     JSD_UserCallbacks* callbacks,
+                                     void*              user,
+                                     JSObject*          scopeobj);
+
+/*
 * Shutdown JSD for this JSDContext
 */
 extern JSD_PUBLIC_API(void)
 JSD_DebuggerOff(JSDContext* jsdc);
 
 /*
  * Pause JSD for this JSDContext
  */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1180,32 +1180,30 @@ JSAutoCrossCompartmentCall::enter(JSCont
 {
     JS_ASSERT(!call);
     if (cx->compartment == target->getCompartment(cx))
         return true;
     call = JS_EnterCrossCompartmentCall(cx, target);
     return call != NULL;
 }
 
-JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx,
-                                               JSCompartment *newCompartment)
-  : cx(cx), compartment(cx->compartment)
-{
-    cx->compartment = newCompartment;
-}
-
-JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx, JSObject *target)
-  : cx(cx), compartment(cx->compartment)
-{
-    cx->compartment = target->getCompartment(cx);
-}
-
-JSAutoEnterCompartment::~JSAutoEnterCompartment()
-{
+JS_FRIEND_API(JSCompartment *)
+js_SwitchToCompartment(JSContext *cx, JSCompartment *compartment)
+{
+    JSCompartment *c = cx->compartment;
     cx->compartment = compartment;
+    return c;
+}
+
+JS_FRIEND_API(JSCompartment *)
+js_SwitchToObjectCompartment(JSContext *cx, JSObject *obj)
+{
+    JSCompartment *c = cx->compartment;
+    cx->compartment = obj->getCompartment(cx);
+    return c;
 }
 
 JS_PUBLIC_API(void *)
 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
 {
     CHECK_REQUEST(cx);
     void *old = compartment->data;
     compartment->data = data;
@@ -1240,17 +1238,18 @@ JS_GetGlobalObject(JSContext *cx)
 }
 
 JS_PUBLIC_API(void)
 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
 {
     CHECK_REQUEST(cx);
 
     cx->globalObject = obj;
-    cx->compartment = obj ? obj->getCompartment(cx) : cx->runtime->defaultCompartment;
+    if (!cx->maybefp())
+        cx->compartment = obj ? obj->getCompartment(cx) : cx->runtime->defaultCompartment;
 }
 
 class AutoResolvingEntry {
 public:
     AutoResolvingEntry() : entry(NULL) {}
 
     /*
      * Returns false on error. But N.B. if obj[id] was already being resolved,
@@ -1329,20 +1328,24 @@ js_InitFunctionAndObjectClasses(JSContex
     return fun_proto;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
 {
     CHECK_REQUEST(cx);
 
-    if (cx->globalObject)
-        assertSameCompartment(cx, obj);
-    else
+    /*
+     * JS_SetGlobalObject might or might not change cx's compartment, so call
+     * it before assertSameCompartment. (The API contract is that *after* this,
+     * cx and obj must be in the same compartment.)
+     */
+    if (!cx->globalObject)
         JS_SetGlobalObject(cx, obj);
+    assertSameCompartment(cx, obj);
 
     /* Define a top-level property 'undefined' with the undefined value. */
     JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
     if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
                              PropertyStub, PropertyStub,
                              JSPROP_PERMANENT | JSPROP_READONLY)) {
         return JS_FALSE;
     }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -952,16 +952,22 @@ extern JS_PUBLIC_API(void *)
 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment);
 
 extern JS_PUBLIC_API(JSBool)
 JS_RewrapObject(JSContext *cx, JSObject **objp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_RewrapValue(JSContext *cx, jsval *p);
 
+extern JS_FRIEND_API(JSCompartment *)
+js_SwitchToCompartment(JSContext *cx, JSCompartment *compartment);
+
+extern JS_FRIEND_API(JSCompartment *)
+js_SwitchToObjectCompartment(JSContext *cx, JSObject *obj);
+
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
 class JS_PUBLIC_API(JSAutoCrossCompartmentCall)
 {
     JSCrossCompartmentCall *call;
   public:
     JSAutoCrossCompartmentCall() : call(NULL) {}
@@ -977,24 +983,30 @@ class JS_PUBLIC_API(JSAutoCrossCompartme
 
     void swap(JSAutoCrossCompartmentCall &other) {
         JSCrossCompartmentCall *tmp = call;
         call = other.call;
         other.call = tmp;
     }
 };
 
-class JS_FRIEND_API(JSAutoEnterCompartment)
+class JSAutoEnterCompartment
 {
     JSContext *cx;
     JSCompartment *compartment;
   public:
-    JSAutoEnterCompartment(JSContext *cx, JSCompartment *newCompartment);
-    JSAutoEnterCompartment(JSContext *cx, JSObject *target);
-    ~JSAutoEnterCompartment();
+    JSAutoEnterCompartment(JSContext *cx, JSCompartment *newCompartment) : cx(cx) {
+        compartment = js_SwitchToCompartment(cx, newCompartment);
+    }
+    JSAutoEnterCompartment(JSContext *cx, JSObject *target) : cx(cx) {
+        compartment = js_SwitchToObjectCompartment(cx, target);
+    }
+    ~JSAutoEnterCompartment() {
+        js_SwitchToCompartment(cx, compartment);
+    }
 };
 
 JS_BEGIN_EXTERN_C
 #endif
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalObject(JSContext *cx);