Bug 616992 - Give nsDOMConstructors a precreate hook so that we don't accidentally create more than one wrapper object for them. r=jst@mozilla.com, gal@uci.edu, a=blocker
authorBlake Kaplan <mrbkap@gmail.com>
Tue, 11 Jan 2011 12:15:52 -0800
changeset 60315 14752eafce65b2c01f7ca246b56fbd846d233217
parent 60314 08babae55fb42852772e6ac0b383d58b283e3a73
child 60316 635f0075c1840533991994bcdfe381dea43648f5
push idunknown
push userunknown
push dateunknown
reviewersjst, blocker
bugs616992
milestone2.0b10pre
Bug 616992 - Give nsDOMConstructors a precreate hook so that we don't accidentally create more than one wrapper object for them. r=jst@mozilla.com, gal@uci.edu, a=blocker
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
js/src/xpconnect/tests/chrome/Makefile.in
js/src/xpconnect/tests/chrome/test_bug616992.xul
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -665,20 +665,22 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(History, nsHistorySH,
                            ARRAY_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_PRECREATE)
   NS_DEFINE_CLASSINFO_DATA(Screen, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DOMPrototype, nsDOMConstructorSH,
                            DOM_BASE_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_PRECREATE |
                            nsIXPCScriptable::WANT_HASINSTANCE |
                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
   NS_DEFINE_CLASSINFO_DATA(DOMConstructor, nsDOMConstructorSH,
                            DOM_BASE_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_PRECREATE |
                            nsIXPCScriptable::WANT_HASINSTANCE |
                            nsIXPCScriptable::WANT_CALL |
                            nsIXPCScriptable::WANT_CONSTRUCT |
                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
 
   // Core classes
   NS_DEFINE_CLASSINFO_DATA(XMLDocument, nsDocumentSH,
                            DOCUMENT_SCRIPTABLE_FLAGS)
@@ -5730,27 +5732,29 @@ public:
                          const nsDOMClassInfoData* aData,
                          const nsGlobalNameStruct* aNameStruct,
                          nsPIDOMWindow* aOwner,
                          nsDOMConstructor** aResult);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMDOMCONSTRUCTOR
 
+  nsresult PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj);
+
   nsresult Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                      JSObject *obj, PRUint32 argc, jsval *argv,
                      jsval *vp, PRBool *_retval);
 
   nsresult HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                        JSObject *obj, const jsval &val, PRBool *bp,
                        PRBool *_retval);
 
   nsresult Install(JSContext *cx, JSObject *target, jsval thisAsVal)
   {
-    JSBool ok =
+    JSBool ok = JS_WrapValue(cx, &thisAsVal) &&
       ::JS_DefineUCProperty(cx, target,
                             reinterpret_cast<const jschar *>(mClassName),
                             nsCRT::strlen(mClassName), thisAsVal, nsnull,
                             nsnull, JSPROP_PERMANENT);
 
     return ok ? NS_OK : NS_ERROR_UNEXPECTED;
   }
 
@@ -5871,16 +5875,30 @@ NS_INTERFACE_MAP_BEGIN(nsDOMConstructor)
     if (!foundInterface) {
       *aInstancePtr = nsnull;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   } else
 NS_INTERFACE_MAP_END
 
 nsresult
+nsDOMConstructor::PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj)
+{
+  nsCOMPtr<nsPIDOMWindow> owner(do_QueryReferent(mWeakOwner));
+  if (!owner) {
+    // Can't do anything.
+    return NS_OK;
+  }
+
+  nsGlobalWindow *win = static_cast<nsGlobalWindow *>(owner.get());
+  *parentObj = win->FastGetGlobalJSObject();
+  return NS_OK;
+}
+
+nsresult
 nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                             JSObject * obj, PRUint32 argc, jsval * argv,
                             jsval * vp, PRBool *_retval)
 {
   JSObject* class_obj = JSVAL_TO_OBJECT(argv[-2]);
   if (!class_obj) {
     NS_ERROR("nsDOMConstructor::Construct couldn't get constructor object.");
     return NS_ERROR_UNEXPECTED;
@@ -6150,16 +6168,22 @@ ResolvePrototype(nsIXPConnect *aXPConnec
     primary_iid = ci_data->mProtoChainInterface;
   }
 
   nsCOMPtr<nsIInterfaceInfo> if_info;
   nsCOMPtr<nsIInterfaceInfo> parent;
   const char *class_parent_name = nsnull;
 
   if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
+    JSAutoEnterCompartment ac;
+
+    if (!ac.enter(cx, class_obj)) {
+      return NS_ERROR_FAILURE;
+    }
+
     rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Special case for |Node|, which needs constants from Node3
     // too for forwards compatibility.
     if (primary_iid->Equals(NS_GET_IID(nsIDOMNode))) {
       rv = DefineInterfaceConstants(cx, class_obj,
                                     &NS_GET_IID(nsIDOM3Node));
@@ -6275,16 +6299,21 @@ ResolvePrototype(nsIXPConnect *aXPConnec
       dot_prototype = ::JS_NewObject(cx, &sDOMConstructorProtoClass, proto,
                                      winobj);
       NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY);
     }
   }
 
   v = OBJECT_TO_JSVAL(dot_prototype);
 
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, class_obj)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
   // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
   if (!JS_WrapValue(cx, &v) ||
       !JS_DefineProperty(cx, class_obj, "prototype", v, nsnull, nsnull,
                          JSPROP_PERMANENT | JSPROP_READONLY)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   *did_resolve = PR_TRUE;
@@ -10602,16 +10631,33 @@ nsEventListenerThisTranslator::Translate
   event->GetCurrentTarget(getter_AddRefs(target));
 
   *_retval = target.forget().get();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMConstructorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
+                              JSObject *globalObj, JSObject **parentObj)
+{
+  nsDOMConstructor *wrapped = static_cast<nsDOMConstructor *>(nativeObj);
+
+#ifdef DEBUG
+  {
+    nsCOMPtr<nsIDOMDOMConstructor> is_constructor =
+      do_QueryInterface(nativeObj);
+    NS_ASSERTION(is_constructor, "How did we not get a constructor?");
+  }
+#endif
+
+  return wrapped->PreCreate(cx, globalObj, parentObj);
+}
+
+NS_IMETHODIMP
 nsDOMConstructorSH::Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, PRUint32 argc, jsval *argv, jsval *vp,
                          PRBool *_retval)
 {
   nsDOMConstructor *wrapped =
     static_cast<nsDOMConstructor *>(wrapper->Native());
 
 #ifdef DEBUG
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -1697,16 +1697,18 @@ public:
 class nsDOMConstructorSH : public nsDOMGenericSH
 {
 protected:
   nsDOMConstructorSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
   {
   }
 
 public:
+  NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
+                       JSObject *globalObj, JSObject **parentObj);
   NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto)
   {
     return NS_OK;
   }
   NS_IMETHOD Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                   JSObject *obj, PRUint32 argc, jsval *argv, jsval *vp,
                   PRBool *_retval);
 
--- a/js/src/xpconnect/tests/chrome/Makefile.in
+++ b/js/src/xpconnect/tests/chrome/Makefile.in
@@ -55,16 +55,17 @@ include $(topsrcdir)/config/rules.mk
 		test_wrappers.xul \
 		test_bug484459.xul \
 		test_cows.xul \
 		test_bug517163.xul \
 		test_bug571849.xul \
 		test_bug601803.xul \
 		test_bug610390.xul \
 		test_bug614757.xul \
+		test_bug616992.xul \
 		$(NULL)
 
 # Disabled until this test gets updated to test the new proxy based
 # wrappers.
 #		test_wrappers-2.xul \
 
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/js/src/xpconnect/tests/chrome/test_bug616992.xul
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=616992
+-->
+<window title="Mozilla Bug 601803"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=616992"
+     target="_blank">Mozilla Bug 616992</a>
+
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+
+  /** Test for Bug 616992 **/
+
+  const Cu = Components.utils;
+  var sandbox = new Cu.Sandbox(window);
+  sandbox.w = window;
+  var actual = Cu.evalInSandbox("Object.keys(w.NodeFilter)", sandbox).sort().toString();
+  var expected = Object.keys(NodeFilter).sort().toString();
+  is(actual, expected, "interface constants are visible inside sandboxes");
+
+  ]]></script>
+  </body>
+</window>