Bug 612267 - window.__proto__ doesn't correspond to Window.prototype. r=jst
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 10 Dec 2010 16:05:20 -0800
changeset 59873 b445e3e2dff0b4d51063d589faeb2136f98c60bb
parent 59253 c86a79eb18b95217369d7dc02e0ce3c79a6fdb68
child 59874 ddcee925424589d422427669e969fa48f40f9a78
push id17820
push usercleary@mozilla.com
push dateTue, 04 Jan 2011 21:40:57 +0000
treeherdermozilla-central@969691cfe40e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs612267
milestone2.0b8pre
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 612267 - window.__proto__ doesn't correspond to Window.prototype. r=jst
dom/base/nsJSEnvironment.cpp
dom/tests/mochitest/bugs/Makefile.in
dom/tests/mochitest/bugs/test_bug612267.html
js/src/xpconnect/src/nsXPConnect.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2543,47 +2543,24 @@ nsJSContext::CreateNativeGlobalForInner(
 
 nsresult
 nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal)
 {
   NS_ENSURE_ARG(aNewInner);
   JSObject *newInnerJSObject = (JSObject *)aNewInner->GetScriptGlobal(JAVASCRIPT);
   JSObject *outerGlobal = (JSObject *)aOuterGlobal;
 
-  // Make the inner and outer window both share the same
-  // prototype. The prototype we share is the outer window's
-  // prototype, this way XPConnect can still find the wrapper to
-  // use when making a call like alert() (w/o qualifying it with
-  // "window."). XPConnect looks up the wrapper based on the
-  // function object's parent, which is the object the function
-  // was called on, and when calling alert() we'll be calling the
-  // alert() function from the outer window's prototype off of the
-  // inner window. In this case XPConnect is able to find the
-  // outer (through the JSExtendedClass hook outerObject), so this
-  // prototype sharing works.
-
   // Now that we're connecting the outer global to the inner one,
   // we must have transplanted it. The JS engine tries to maintain
   // the global object's compartment as its default compartment,
   // so update that now since it might have changed.
   JS_SetGlobalObject(mContext, outerGlobal);
-
-  // We do *not* want to use anything else out of the outer
-  // object's prototype chain than the first prototype, which is
-  // the XPConnect prototype. The rest we want from the inner
-  // window's prototype, i.e. the global scope polluter and
-  // Object.prototype. This way the outer also gets the benefits
-  // of the global scope polluter, and the inner window's
-  // Object.prototype.
-  JSObject *proto = JS_GetPrototype(mContext, outerGlobal);
-  JSObject *innerProto = JS_GetPrototype(mContext, newInnerJSObject);
-  JSObject *innerProtoProto = JS_GetPrototype(mContext, innerProto);
-
-  JS_SetPrototype(mContext, newInnerJSObject, proto);
-  JS_SetPrototype(mContext, proto, innerProtoProto);
+  NS_ASSERTION(JS_GetPrototype(mContext, outerGlobal) ==
+               JS_GetPrototype(mContext, newInnerJSObject),
+               "outer and inner globals should have the same prototype");
 
   return NS_OK;
 }
 
 void *
 nsJSContext::GetNativeContext()
 {
   return mContext;
@@ -2621,45 +2598,46 @@ nsJSContext::CreateOuterObject(nsIScript
 
     // Always enable E4X for XUL and other chrome content -- there is no
     // need to preserve the <!-- script hiding hack from JS-in-HTML daze
     // (introduced in 1995 for graceful script degradation in Netscape 1,
     // Mosaic, and other pre-JS browsers).
     JS_SetOptions(mContext, JS_GetOptions(mContext) | JSOPTION_XML);
   }
 
-  nsIXPConnect *xpc = nsContentUtils::XPConnect();
-  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-
-  nsresult rv = xpc->WrapNative(mContext, aCurrentInner->GetGlobalJSObject(),
-                                aCurrentInner, NS_GET_IID(nsISupports),
-                                getter_AddRefs(holder));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(holder));
-  NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
-
-  wrapper->RefreshPrototype();
-
   JSObject *outer =
     NS_NewOuterWindowProxy(mContext, aCurrentInner->GetGlobalJSObject());
   if (!outer) {
     return NS_ERROR_FAILURE;
   }
 
   return SetOuterObject(outer);
 }
 
 nsresult
 nsJSContext::SetOuterObject(void *aOuterObject)
 {
   JSObject *outer = static_cast<JSObject *>(aOuterObject);
 
   // Force our context's global object to be the outer.
   JS_SetGlobalObject(mContext, outer);
+
+  // NB: JS_SetGlobalObject sets mContext->compartment.
+  JSObject *inner = JS_GetParent(mContext, outer);
+
+  nsIXPConnect *xpc = nsContentUtils::XPConnect();
+  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
+  nsresult rv = xpc->GetWrappedNativeOfJSObject(mContext, inner,
+                                                getter_AddRefs(wrapper));
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
+
+  wrapper->RefreshPrototype();
+  JS_SetPrototype(mContext, outer, JS_GetPrototype(mContext, inner));
+
   return NS_OK;
 }
 
 nsresult
 nsJSContext::InitOuterWindow()
 {
   JSObject *global = JS_GetGlobalObject(mContext);
   OBJ_TO_INNER_OBJECT(mContext, global);
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -121,12 +121,13 @@ include $(topsrcdir)/config/rules.mk
 		test_DOMWindowCreated_chromeonly.html \
 		test_bug581072.html \
 		test_bug583225.html \
 		test_bug585240.html \
 		test_bug585819.html \
 		test_bug369306.html \
 		test_bug61098.html \
 		test_bug597809.html \
+		test_bug612267.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug612267.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=612267
+-->
+<head>
+  <title>Test for Bug 393974</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=612267">Mozilla Bug 612267</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+Window.prototype.test = 'PASS';
+is(window.test, 'PASS', "setting Window.prototype affects window.__proto__");
+is(test, 'PASS', "setting Window.prototype affects the inner window lookup for sure");
+
+</script>
+</pre>
+</body>
+</html>
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1143,17 +1143,17 @@ nsXPConnect::InitClassesWithNewWrappedGl
     XPCWrappedNative* wrapper =
         reinterpret_cast<XPCWrappedNative*>(holder.get());
     XPCWrappedNativeScope* scope = wrapper->GetScope();
 
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     // Note: This call cooperates with a call to wrapper->RefreshPrototype()
-    // in nsJSEnvironment::CreateOuterObject in order to ensure that the
+    // in nsJSEnvironment::SetOuterObject in order to ensure that the
     // prototype defines its constructor on the right global object.
     if(wrapper->GetProto()->GetScriptableInfo())
         scope->RemoveWrappedNativeProtos();
 
     NS_ASSERTION(scope->GetGlobalJSObject() == tempGlobal, "stealing scope!");
 
     scope->SetGlobal(ccx, globalJSObj);