author | Peter Van der Beken <peterv@propagandism.org> |
Sat, 09 Nov 2013 11:20:22 +0100 | |
changeset 177572 | f1e4f0f82a9a1572479ee08ed873cc61baeca0da |
parent 177571 | 33f98fa5c415b985750ee7084808a75cca514bd7 |
child 177573 | 39b430a304cabc4b4700ea00d95ac8c859ca19aa |
push id | 26556 |
push user | ryanvm@gmail.com |
push date | Tue, 08 Apr 2014 22:16:57 +0000 |
treeherder | mozilla-central@5811efc11011 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz |
bugs | 990158 |
milestone | 31.0a1 |
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
|
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -177,17 +177,16 @@ using namespace mozilla::dom; static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS // are defined in nsIDOMClassInfo.h. #define WINDOW_SCRIPTABLE_FLAGS \ (nsIXPCScriptable::WANT_PRECREATE | \ nsIXPCScriptable::WANT_POSTCREATE | \ - nsIXPCScriptable::WANT_FINALIZE | \ nsIXPCScriptable::WANT_ENUMERATE | \ nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ nsIXPCScriptable::IS_GLOBAL_OBJECT | \ nsIXPCScriptable::WANT_OUTER_OBJECT) #define ARRAY_SCRIPTABLE_FLAGS \ (DOM_DEFAULT_SCRIPTABLE_FLAGS | \ nsIXPCScriptable::WANT_GETPROPERTY | \ @@ -1850,17 +1849,17 @@ NS_IMETHODIMP nsWindowSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj) { JS::Rooted<JSObject*> window(cx, obj); #ifdef DEBUG nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper)); - NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == nullptr, + NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == obj, "Multiple wrappers created for global object!"); #endif const NativeProperties* windowProperties = WindowBinding::sNativePropertyHooks->mNativeProperties.regular; const NativeProperties* eventTargetProperties = EventTargetBinding::sNativePropertyHooks->mNativeProperties.regular; @@ -3395,36 +3394,16 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp return NS_OK; } return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval); } NS_IMETHODIMP -nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop, - JSObject *obj) -{ - // Since this call is virtual, the exact rooting hazard static analysis is - // not able to determine that it happens during finalization and should be - // ignored. Moreover, the analysis cannot discover and validate the - // potential targets of the virtual call to OnFinalize below because of the - // indirection through nsCOMMPtr. Thus, we annotate the analysis here so - // that it does not report OnFinalize as GCing with |obj| on stack. - JS::AutoAssertNoGC nogc; - - nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper)); - NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED); - - sgo->OnFinalize(obj); - - return NS_OK; -} - -NS_IMETHODIMP nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval) { nsGlobalWindow *origWin = nsGlobalWindow::FromWrapper(wrapper); nsGlobalWindow *win = origWin->GetOuterWindowInternal(); if (!win) { // If we no longer have an outer window. No code should ever be
--- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -265,18 +265,16 @@ public: NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto) MOZ_OVERRIDE; NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj) MOZ_OVERRIDE; NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, bool *_retval) MOZ_OVERRIDE; NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, uint32_t flags, JSObject **objp, bool *_retval) MOZ_OVERRIDE; - NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop, - JSObject *obj) MOZ_OVERRIDE; NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval) MOZ_OVERRIDE; static bool GlobalScopePolluterNewResolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, unsigned flags, JS::MutableHandle<JSObject*> objp); static bool GlobalScopePolluterGetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1366,17 +1366,16 @@ nsGlobalWindow::ShutDown() // static void nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow) { if (aWindow->mCachedXBLPrototypeHandlers && aWindow->mCachedXBLPrototypeHandlers->Count() > 0) { aWindow->mCachedXBLPrototypeHandlers->Clear(); - mozilla::DropJSObjects(aWindow); } } void nsGlobalWindow::MaybeForgiveSpamCount() { if (IsOuterWindow() && IsPopupSpamWindow()) @@ -1612,27 +1611,21 @@ nsGlobalWindow::FreeInnerObjects() mGamepads.Clear(); #endif } //***************************************************************************** // nsGlobalWindow::nsISupports //***************************************************************************** -#define OUTER_WINDOW_ONLY \ - if (IsOuterWindow()) { - -#define END_OUTER_WINDOW_ONLY \ - foundInterface = 0; \ - } else - DOMCI_DATA(Window, nsGlobalWindow) // QueryInterface implementation for nsGlobalWindow NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY // Make sure this matches the cast in nsGlobalWindow::FromWrapper() NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget) NS_INTERFACE_MAP_ENTRY(nsIDOMWindow) #ifdef MOZ_B2G NS_INTERFACE_MAP_ENTRY(nsIDOMWindowB2G) #endif // MOZ_B2G #ifdef MOZ_WEBSPEECH NS_INTERFACE_MAP_ENTRY(nsISpeechSynthesisGetter) @@ -1655,19 +1648,16 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget) NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance) NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver) NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window) - OUTER_WINDOW_ONLY - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - END_OUTER_WINDOW_ONLY NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow) static PLDHashOperator MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure) @@ -1765,16 +1755,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) nsGlobalWindow::CleanupCachedXBLHandlers(tmp); NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext) NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers) @@ -1825,16 +1816,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar) NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar) NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto) NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole) NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END #ifdef DEBUG void nsGlobalWindow::RiskyUnlink() { NS_CYCLE_COLLECTION_INNERNAME.Unlink(this); } @@ -1854,16 +1846,17 @@ TraceXBLHandlers(nsXBLPrototypeHandler* return PL_DHASH_NEXT; } NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow) if (tmp->mCachedXBLPrototypeHandlers) { TraceData data = { aCallbacks, aClosure }; tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data); } + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_END bool nsGlobalWindow::IsBlackForCC(bool aTracingNeeded) { if (!nsCCUncollectableMarker::sGeneration) { return false; } @@ -1899,22 +1892,22 @@ nsresult nsGlobalWindow::EnsureScriptEnvironment() { nsGlobalWindow* outer = GetOuterWindowInternal(); if (!outer) { NS_WARNING("No outer window available!"); return NS_ERROR_FAILURE; } - if (outer->mJSObject) { + if (outer->GetWrapperPreserveColor()) { return NS_OK; } NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(), - "mJSObject is null, but we have an inner window?"); + "No cached wrapper, but we have an inner window?"); // If this window is a [i]frame, don't bother GC'ing when the frame's context // is destroyed since a GC will happen when the frameset or host document is // destroyed anyway. nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer); NS_ASSERTION(!outer->mContext, "Will overwrite mContext!"); @@ -1939,19 +1932,17 @@ JSObject * nsGlobalWindow::GetGlobalJSObject() { return FastGetGlobalJSObject(); } void nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc) { - if (mJSObject) { - JS_CallTenuredObjectTracer(aTrc, &mJSObject, "active window global"); - } + TraceWrapper(aTrc, "active window global"); } bool nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument) { // We reuse the inner window when: // a. We are currently at our original document. // b. At least one of the following conditions are true: @@ -2124,17 +2115,17 @@ WindowStateHolder::WindowStateHolder(nsG NS_PRECONDITION(aWindow, "null window"); NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window"); mInnerWindowHolder = aHolder; aWindow->SuspendTimeouts(); // When a global goes into the bfcache, we disable script. - xpc::Scriptability::Get(aWindow->mJSObject).SetDocShellAllowsScript(false); + xpc::Scriptability::Get(aWindow->GetWrapperPreserveColor()).SetDocShellAllowsScript(false); } WindowStateHolder::~WindowStateHolder() { if (mInnerWindow) { // This window was left in the bfcache and is now going away. We need to // free it up. // Note that FreeInnerObjects may already have been called on the @@ -2162,17 +2153,16 @@ TreatAsRemoteXUL(nsIPrincipal* aPrincipa * Return the native global and an nsISupports 'holder' that can be used * to manage the lifetime of it. */ static nsresult CreateNativeGlobalForInner(JSContext* aCx, nsGlobalWindow* aNewInner, nsIURI* aURI, nsIPrincipal* aPrincipal, - JS::TenuredHeap<JSObject*>& aNativeGlobal, nsIXPConnectJSObjectHolder** aHolder) { MOZ_ASSERT(aCx); MOZ_ASSERT(aNewInner); MOZ_ASSERT(aNewInner->IsInnerWindow()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aHolder); @@ -2190,30 +2180,25 @@ CreateNativeGlobalForInner(JSContext* aC nsIXPConnect* xpc = nsContentUtils::XPConnect(); // Determine if we need the Components object. bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) || TreatAsRemoteXUL(aPrincipal); uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT; flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK; - nsRefPtr<nsIXPConnectJSObjectHolder> jsholder; nsresult rv = xpc->InitClassesWithNewWrappedGlobal( aCx, ToSupports(aNewInner), - aPrincipal, flags, options, getter_AddRefs(jsholder)); + aPrincipal, flags, options, aHolder); NS_ENSURE_SUCCESS(rv, rv); - MOZ_ASSERT(jsholder); - aNativeGlobal = jsholder->GetJSObject(); - jsholder.forget(aHolder); - // Set the location information for the new global, so that tools like // about:memory may use that information - MOZ_ASSERT(aNativeGlobal.getPtr()); - xpc::SetLocationForGlobal(aNativeGlobal, aURI); + MOZ_ASSERT(aNewInner->GetWrapperPreserveColor()); + xpc::SetLocationForGlobal(aNewInner->GetWrapperPreserveColor(), aURI); return NS_OK; } nsresult nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsISupports* aState, bool aForceReuseInnerWindow) @@ -2333,66 +2318,66 @@ nsGlobalWindow::SetNewDocument(nsIDocume // Check if we're near the stack limit before we get anywhere near the // transplanting code. JS_CHECK_RECURSION(cx, return NS_ERROR_FAILURE); nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState); NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?"); + JS::Rooted<JSObject*> newInnerGlobal(cx); if (reUseInnerWindow) { // We're reusing the current inner window. NS_ASSERTION(!currentInner->IsFrozen(), "We should never be reusing a shared inner window"); newInnerWindow = currentInner; + newInnerGlobal = currentInner->GetWrapperPreserveColor(); if (aDocument != oldDoc) { - JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject); - JS::ExposeObjectToActiveJS(obj); + JS::ExposeObjectToActiveJS(newInnerGlobal); } // We're reusing the inner window, but this still counts as a navigation, // so all expandos and such defined on the outer window should go away. Force // all Xray wrappers to be recomputed. - JS::ExposeObjectToActiveJS(mJSObject); - JS::Rooted<JSObject*> rootedObject(cx, mJSObject); + JS::Rooted<JSObject*> rootedObject(cx, GetWrapperPreserveColor()); + JS::ExposeObjectToActiveJS(rootedObject); if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) { return NS_ERROR_FAILURE; } // Inner windows are only reused for same-origin principals, but the principals // don't necessarily match exactly. Update the principal on the compartment to // match the new document. // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here // because we haven't yet set its mDoc to aDocument. - JSCompartment *compartment = js::GetObjectCompartment(currentInner->mJSObject); + JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal); #ifdef DEBUG bool sameOrigin = false; nsIPrincipal *existing = nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment)); aDocument->NodePrincipal()->Equals(existing, &sameOrigin); MOZ_ASSERT(sameOrigin); #endif JS_SetCompartmentPrincipals(compartment, nsJSPrincipals::get(aDocument->NodePrincipal())); } else { if (aState) { newInnerWindow = wsh->GetInnerWindow(); + newInnerGlobal = newInnerWindow->GetWrapperPreserveColor(); mInnerWindowHolder = wsh->GetInnerWindowHolder(); - - NS_ASSERTION(newInnerWindow, "Got a state without inner window"); - } else if (thisChrome) { - newInnerWindow = new nsGlobalChromeWindow(this); - } else if (mIsModalContentWindow) { - newInnerWindow = new nsGlobalModalWindow(this); } else { - newInnerWindow = new nsGlobalWindow(this); - } - - if (!aState) { + if (thisChrome) { + newInnerWindow = new nsGlobalChromeWindow(this); + } else if (mIsModalContentWindow) { + newInnerWindow = new nsGlobalModalWindow(this); + } else { + newInnerWindow = new nsGlobalWindow(this); + } + // Freeze the outer window and null out the inner window so // that initializing classes on the new inner doesn't end up // reaching into the old inner window for classes etc. // // [This happens with Object.prototype when XPConnect creates // a temporary global while initializing classes; the reason // being that xpconnect creates the temp global w/o a parent // and proto, which makes the JS engine look up classes in @@ -2402,29 +2387,30 @@ nsGlobalWindow::SetNewDocument(nsIDocume Freeze(); mCreatingInnerWindow = true; // Every script context we are initialized with must create a // new global. rv = CreateNativeGlobalForInner(cx, newInnerWindow, aDocument->GetDocumentURI(), aDocument->NodePrincipal(), - newInnerWindow->mJSObject, getter_AddRefs(mInnerWindowHolder)); - NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerWindow->mJSObject && mInnerWindowHolder, - "Failed to get script global and holder"); + newInnerGlobal = mInnerWindowHolder->GetJSObject(); + NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal && + newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal, + "Failed to get script global"); mCreatingInnerWindow = false; createdInnerWindow = true; Thaw(); NS_ENSURE_SUCCESS(rv, rv); } - if (currentInner && currentInner->mJSObject) { + if (currentInner && currentInner->GetWrapperPreserveColor()) { if (oldDoc == aDocument) { // Move the navigator from the old inner window to the new one since // this is a document.write. This is safe from a same-origin point of // view because document.write can only be used by the same origin. newInnerWindow->mNavigator = currentInner->mNavigator; currentInner->mNavigator = nullptr; if (newInnerWindow->mNavigator) { newInnerWindow->mNavigator->SetWindow(newInnerWindow); @@ -2446,122 +2432,114 @@ nsGlobalWindow::SetNewDocument(nsIDocume // held in the bfcache. if (!currentInner->IsFrozen()) { currentInner->FreeInnerObjects(); } } mInnerWindow = newInnerWindow; - if (!mJSObject) { - JS::Rooted<JSObject*> global(cx, newInnerWindow->FastGetGlobalJSObject()); - JS::Rooted<JSObject*> outer(cx, NewOuterWindowProxy(cx, global, thisChrome)); + if (!GetWrapperPreserveColor()) { + JS::Rooted<JSObject*> outer(cx, + NewOuterWindowProxy(cx, newInnerGlobal, thisChrome)); NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE); js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this))); + js::SetProxyExtra(outer, 1, JS::ObjectValue(*newInnerGlobal)); // Inform the nsJSContext, which is the canonical holder of the outer. mContext->SetWindowProxy(outer); mContext->DidInitializeContext(); - mJSObject = mContext->GetWindowProxy(); - SetWrapper(mJSObject); + SetWrapper(mContext->GetWindowProxy()); } else { - JS::ExposeObjectToActiveJS(newInnerWindow->mJSObject); - JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject); + JS::ExposeObjectToActiveJS(newInnerGlobal); JS::Rooted<JSObject*> outerObject(cx, - NewOuterWindowProxy(cx, global, thisChrome)); + NewOuterWindowProxy(cx, newInnerGlobal, thisChrome)); if (!outerObject) { NS_ERROR("out of memory"); return NS_ERROR_FAILURE; } - js::SetProxyExtra(mJSObject, 0, js::PrivateValue(nullptr)); - - JS::Rooted<JSObject*> obj(cx, mJSObject); + JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor()); + + js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr)); + outerObject = xpc::TransplantObject(cx, obj, outerObject); if (!outerObject) { NS_ERROR("unable to transplant wrappers, probably OOM"); return NS_ERROR_FAILURE; } js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this))); - mJSObject = outerObject; - SetWrapper(mJSObject); + SetWrapper(outerObject); { - JSAutoCompartment ac(cx, mJSObject); - - JS::Rooted<JSObject*> obj(cx, mJSObject); - JS::Rooted<JSObject*> newParent(cx, newInnerWindow->mJSObject); - JS_SetParent(cx, obj, newParent); + JSAutoCompartment ac(cx, outerObject); + + JS_SetParent(cx, outerObject, newInnerGlobal); // Inform the nsJSContext, which is the canonical holder of the outer. - mContext->SetWindowProxy(obj); + mContext->SetWindowProxy(outerObject); NS_ASSERTION(!JS_IsExceptionPending(cx), "We might overwrite a pending exception!"); - XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj); + XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject); if (scope->mWaiverWrapperMap) { - scope->mWaiverWrapperMap->Reparent(cx, newParent); + scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal); } } } // Enter the new global's compartment. - JSAutoCompartment ac(cx, mJSObject); + JSAutoCompartment ac(cx, GetWrapperPreserveColor()); // Set scriptability based on the state of the docshell. bool allow = GetDocShell()->GetCanExecuteScripts(); - xpc::Scriptability::Get(mJSObject).SetDocShellAllowsScript(allow); + xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow); // If we created a new inner window above, we need to do the last little bit // of initialization now that the dust has settled. if (createdInnerWindow) { nsIXPConnect *xpc = nsContentUtils::XPConnect(); nsCOMPtr<nsIXPConnectWrappedNative> wrapper; - nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject, + nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal, getter_AddRefs(wrapper)); NS_ENSURE_SUCCESS(rv, rv); NS_ABORT_IF_FALSE(wrapper, "bad wrapper"); rv = wrapper->FinishInitForWrappedGlobal(); NS_ENSURE_SUCCESS(rv, rv); } if (!aState) { - if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window", - OBJECT_TO_JSVAL(mJSObject), + if (!JS_DefineProperty(cx, newInnerGlobal, "window", + OBJECT_TO_JSVAL(GetWrapperPreserveColor()), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) { NS_ERROR("can't create the 'window' property"); return NS_ERROR_FAILURE; } } } - JSAutoCompartment ac(cx, mJSObject); + JSAutoCompartment ac(cx, GetWrapperPreserveColor()); if (!aState && !reUseInnerWindow) { // Loading a new page and creating a new inner window, *not* // restoring from session history. // Now that both the the inner and outer windows are initialized // let the script context do its magic to hook them together. + MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor()); #ifdef DEBUG - JS::Rooted<JSObject*> newInnerJSObject(cx, - newInnerWindow->FastGetGlobalJSObject()); -#endif - - MOZ_ASSERT(mContext->GetWindowProxy() == mJSObject); -#ifdef DEBUG - JS::Rooted<JSObject*> rootedJSObject(cx, mJSObject); + JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor()); JS::Rooted<JSObject*> proto1(cx), proto2(cx); JS_GetPrototype(cx, rootedJSObject, &proto1); - JS_GetPrototype(cx, newInnerJSObject, &proto2); + JS_GetPrototype(cx, newInnerGlobal, &proto2); NS_ASSERTION(proto1 == proto2, "outer and inner globals should have the same prototype"); #endif nsCOMPtr<Element> frame = GetFrameElementInternal(); if (frame) { nsPIDOMWindow* parentWindow = frame->OwnerDoc()->GetWindow(); if (parentWindow && parentWindow->TimeoutSuspendCount()) { @@ -2580,34 +2558,34 @@ nsGlobalWindow::SetNewDocument(nsIDocume if (newInnerWindow->mDoc != aDocument) { newInnerWindow->mDoc = aDocument; // We're reusing the inner window for a new document. In this // case we don't clear the inner window's scope, but we must // make sure the cached document property gets updated. // XXXmarkh - tell other languages about this? - JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject); + JS::Rooted<JSObject*> obj(cx, currentInner->GetWrapperPreserveColor()); ::JS_DeleteProperty(cx, obj, "document"); } } else { newInnerWindow->InnerSetNewDocument(aDocument); // Initialize DOM classes etc on the inner window. - JS::Rooted<JSObject*> obj(cx, newInnerWindow->mJSObject); + JS::Rooted<JSObject*> obj(cx, newInnerGlobal); rv = mContext->InitClasses(obj); NS_ENSURE_SUCCESS(rv, rv); } // If the document comes from a JAR, check if the channel was determined // to be unsafe. If so, permanently disable script on the compartment by // calling Block() and throwing away the key. nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel()); if (jarChannel && jarChannel->GetIsUnsafe()) { - xpc::Scriptability::Get(newInnerWindow->mJSObject).Block(); + xpc::Scriptability::Get(newInnerGlobal).Block(); } if (mArguments) { newInnerWindow->DefineArgumentsProperty(mArguments); mArguments = nullptr; } // Give the new inner window our chrome event handler (since it @@ -2616,17 +2594,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume } mContext->GC(JS::gcreason::SET_NEW_DOCUMENT); mContext->DidInitializeContext(); // We wait to fire the debugger hook until the window is all set up and hooked // up with the outer. See bug 969156. if (createdInnerWindow) { - JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject); + JS::Rooted<JSObject*> global(cx, newInnerWindow->GetWrapper()); JS_FireOnNewGlobalObject(cx, global); } if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) { // We should probably notify. However if this is the, arguably bad, // situation when we're creating a temporary non-chrome-about-blank // document in a chrome docshell, don't notify just yet. Instead wait // until we have a real chrome doc. @@ -2785,18 +2763,17 @@ nsGlobalWindow::SetDocShell(nsIDocShell* void nsGlobalWindow::DetachFromDocShell() { NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!"); // DetachFromDocShell means the window is being torn down. Drop our // reference to the script context, allowing it to be deleted // later. Meanwhile, keep our weak reference to the script object - // (mJSObject) so that it can be retrieved later (until it is - // finalized by the JS GC). + // so that it can be retrieved later (until it is finalized by the JS GC). NS_ASSERTION(mTimeouts.isEmpty(), "Uh, outer window holds timeouts!"); // Call FreeInnerObjects on all inner windows, not just the current // one, since some could be held by WindowStateHolder objects that // are GC-owned. for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this); inner != this; @@ -3210,29 +3187,21 @@ nsGlobalWindow::DispatchDOMEvent(WidgetE nsEventStatus* aEventStatus) { return EventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this), aEvent, aDOMEvent, aPresContext, aEventStatus); } void -nsGlobalWindow::OnFinalize(JSObject* aObject) -{ - if (aObject == mJSObject) { - mJSObject = nullptr; - } -} - -void nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject) { MOZ_ASSERT(IsOuterWindow()); - if (aObject == mJSObject) { - mJSObject.setToCrashOnTouch(); + if (aObject == GetWrapperPreserveColor()) { + PoisonWrapper(); } } nsresult nsGlobalWindow::SetArguments(nsIArray *aArguments) { MOZ_ASSERT(IsOuterWindow()); nsresult rv; @@ -3270,17 +3239,17 @@ nsresult nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments) { MOZ_ASSERT(!mIsModalContentWindow); // Handled separately. nsIScriptContext *ctx = GetOuterWindowInternal()->mContext; NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED); AutoPushJSContext cx(ctx->GetNativeContext()); NS_ENSURE_TRUE(cx, NS_ERROR_NOT_INITIALIZED); - JS::Rooted<JSObject*> obj(cx, mJSObject); + JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor()); return GetContextInternal()->SetProperty(obj, "arguments", aArguments); } //***************************************************************************** // nsGlobalWindow::nsIScriptObjectPrincipal //***************************************************************************** nsIPrincipal* @@ -4410,18 +4379,18 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* // expandos on Xrays as needed. JS::Rooted<JSObject*> otherObj(cx, glob->GetGlobalJSObject()); if (!otherObj) { aError.Throw(NS_ERROR_UNEXPECTED); return; } - JS::Rooted<JSObject*> thisObj(cx, mJSObject); - if (!mJSObject) { + JS::Rooted<JSObject*> thisObj(cx, GetWrapperPreserveColor()); + if (!thisObj) { aError.Throw(NS_ERROR_UNEXPECTED); return; } if (!JS_WrapObject(cx, &otherObj) || !JS_WrapObject(cx, &thisObj) || !JS_DefineProperty(cx, thisObj, "opener", JS::ObjectValue(*otherObj), JS_PropertyStub, JS_StrictPropertyStub, @@ -5095,18 +5064,18 @@ nsGlobalWindow::RequestAnimationFrame(co { FORWARD_TO_INNER_OR_THROW(RequestAnimationFrame, (aCallback, aError), aError, 0); if (!mDoc) { return 0; } - if (mJSObject) { - js::NotifyAnimationActivity(mJSObject); + if (GetWrapperPreserveColor()) { + js::NotifyAnimationActivity(GetWrapperPreserveColor()); } int32_t handle; aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle); return handle; } NS_IMETHODIMP @@ -5657,17 +5626,17 @@ nsGlobalWindow::DispatchResizeEvent(cons ErrorResult res; nsRefPtr<Event> domEvent = mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res); if (res.Failed()) { return false; } AutoSafeJSContext cx; - JSAutoCompartment ac(cx, mJSObject); + JSAutoCompartment ac(cx, GetWrapperPreserveColor()); DOMWindowResizeEventDetail detail; detail.mWidth = aSize.width; detail.mHeight = aSize.height; JS::Rooted<JS::Value> detailValue(cx); if (!detail.ToObject(cx, &detailValue)) { return false; } @@ -5694,17 +5663,17 @@ nsGlobalWindow::DispatchResizeEvent(cons return defaultActionEnabled; } void nsGlobalWindow::RefreshCompartmentPrincipal() { FORWARD_TO_INNER(RefreshCompartmentPrincipal, (), /* void */ ); - JS_SetCompartmentPrincipals(js::GetObjectCompartment(mJSObject), + JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()), nsJSPrincipals::get(mDoc->NodePrincipal())); } static already_AddRefed<nsIDocShellTreeItem> GetCallerDocShellTreeItem() { JSContext *cx = nsContentUtils::GetCurrentJSContext(); nsCOMPtr<nsIDocShellTreeItem> callerItem; @@ -8652,20 +8621,17 @@ nsGlobalWindow::GetCachedXBLPrototypeHan } void nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey, JS::Handle<JSObject*> aHandler) { if (!mCachedXBLPrototypeHandlers) { mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>(); - } - - if (!mCachedXBLPrototypeHandlers->Count()) { - mozilla::HoldJSObjects(this); + PreserveWrapper(ToSupports(this)); } mCachedXBLPrototypeHandlers->Put(aKey, aHandler); } /** * GetScriptableFrameElement is called when script reads * nsIGlobalWindow::frameElement. @@ -12537,17 +12503,17 @@ nsGlobalWindow::EnsureSizeUpToDate() } } already_AddRefed<nsISupports> nsGlobalWindow::SaveWindowState() { NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state"); - if (!mContext || !mJSObject) { + if (!mContext || !GetWrapperPreserveColor()) { // The window may be getting torn down; don't bother saving state. return nullptr; } nsGlobalWindow *inner = GetCurrentInnerWindowInternal(); NS_ASSERTION(inner, "No inner window to save"); // Don't do anything else to this inner window! After this point, all @@ -12567,17 +12533,17 @@ nsGlobalWindow::SaveWindowState() return state.forget(); } nsresult nsGlobalWindow::RestoreWindowState(nsISupports *aState) { NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window"); - if (!mContext || !mJSObject) { + if (!mContext || !GetWrapperPreserveColor()) { // The window may be getting torn down; don't bother restoring state. return NS_OK; } nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState); NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE); #ifdef DEBUG_PAGE_CACHE @@ -13547,34 +13513,34 @@ nsGlobalWindow::GetConsole(JSContext* aC JS::MutableHandle<JS::Value> aConsole) { ErrorResult rv; nsRefPtr<Console> console = GetConsole(rv); if (rv.Failed()) { return rv.ErrorCode(); } - JS::Rooted<JSObject*> thisObj(aCx, mJSObject); - if (!mJSObject) { + JS::Rooted<JSObject*> thisObj(aCx, GetWrapper()); + if (!thisObj) { return NS_ERROR_UNEXPECTED; } if (!JS_WrapObject(aCx, &thisObj) || !WrapNewBindingObject(aCx, thisObj, console, aConsole)) { return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue) { - JS::Rooted<JSObject*> thisObj(aCx, mJSObject); - if (!mJSObject) { + JS::Rooted<JSObject*> thisObj(aCx, GetWrapper()); + if (!thisObj) { return NS_ERROR_UNEXPECTED; } if (!JS_WrapObject(aCx, &thisObj) || !JS_DefineProperty(aCx, thisObj, "console", aValue, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE;
--- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -353,26 +353,26 @@ public: } // nsIGlobalJSObjectHolder virtual JSObject *GetGlobalJSObject(); // nsIScriptGlobalObject JSObject *FastGetGlobalJSObject() const { - return mJSObject; + return GetWrapperPreserveColor(); } + void TraceGlobalJSObject(JSTracer* aTrc); virtual nsresult EnsureScriptEnvironment(); virtual nsIScriptContext *GetScriptContext(); void PoisonOuterWindowProxy(JSObject *aObject); - virtual void OnFinalize(JSObject* aObject); virtual bool IsBlackForCC(bool aTracingNeeded = true); // nsIScriptObjectPrincipal virtual nsIPrincipal* GetPrincipal(); // nsIDOMWindow NS_DECL_NSIDOMWINDOW @@ -1501,19 +1501,16 @@ protected: uint32_t mTimeoutPublicIdCounter; uint32_t mTimeoutFiringDepth; nsRefPtr<nsLocation> mLocation; nsRefPtr<nsHistory> mHistory; // These member variables are used on both inner and the outer windows. nsCOMPtr<nsIPrincipal> mDocumentPrincipal; - // The JS global object. Global objects are always allocated tenured. - JS::TenuredHeap<JSObject*> mJSObject; - typedef nsCOMArray<nsIDOMStorageEvent> nsDOMStorageEventArray; nsDOMStorageEventArray mPendingStorageEvents; uint32_t mTimeoutsSuspendDepth; // the method that was used to focus mFocusedNode uint32_t mFocusMethod;
--- a/dom/base/nsIScriptGlobalObject.h +++ b/dom/base/nsIScriptGlobalObject.h @@ -28,18 +28,18 @@ struct ErrorEventInit; // aStatus will be filled in with the status. bool NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal, const mozilla::dom::ErrorEventInit &aErrorEvent, nsEventStatus *aStatus); #define NS_ISCRIPTGLOBALOBJECT_IID \ -{ 0x6995e1ff, 0x9fc5, 0x44a7, \ - { 0xbd, 0x7c, 0xe7, 0xcd, 0x44, 0x47, 0x22, 0x87 } } +{ 0x876f83bd, 0x6314, 0x460a, \ + { 0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1 } } /** * The global object which keeps a script context for each supported script * language. This often used to store per-window global state. * This is a heavyweight interface implemented only by DOM globals, and * it might go away some time in the future. */ @@ -63,25 +63,16 @@ public: */ virtual nsIScriptContext *GetScriptContext() = 0; nsIScriptContext* GetContext() { return GetScriptContext(); } /** - * Called when the global script for a language is finalized, typically as - * part of its GC process. By the time this call is made, the - * nsIScriptContext for the language has probably already been removed. - * After this call, the passed object is dead - which should generally be the - * same object the global is using for a global for that language. - */ - virtual void OnFinalize(JSObject* aObject) = 0; - - /** * Handle a script error. Generally called by a script context. */ virtual nsresult HandleScriptError( const mozilla::dom::ErrorEventInit &aErrorEventInit, nsEventStatus *aEventStatus) { NS_ENSURE_STATE(NS_HandleScriptError(this, aErrorEventInit, aEventStatus)); return NS_OK; }
--- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -6,18 +6,18 @@ #ifndef nsWrapperCache_h___ #define nsWrapperCache_h___ #include "nsCycleCollectionParticipant.h" #include "mozilla/Assertions.h" #include "js/Id.h" // must come before js/RootingAPI.h #include "js/Value.h" // must come before js/RootingAPI.h #include "js/RootingAPI.h" +#include "js/Tracer.h" -struct JSTracer; class XPCWrappedNativeScope; #define NS_WRAPPERCACHE_IID \ { 0x6f3179a1, 0x36f7, 0x4a5c, \ { 0x8c, 0xf1, 0xad, 0xc8, 0x7c, 0xde, 0x3e, 0x87 } } /** * Class to store the wrapper for an object. This can only be used with objects @@ -217,16 +217,31 @@ public: #ifdef DEBUG // Make sure the cycle collector will be able to traverse to the wrapper. CheckCCWrapperTraversal(aScriptObjectHolder, aTracer); #endif } void ReleaseWrapper(void* aScriptObjectHolder); +protected: + void TraceWrapper(JSTracer* aTrc, const char* name) + { + if (mWrapper) { + JS_CallHeapObjectTracer(aTrc, &mWrapper, name); + } + } + + void PoisonWrapper() + { + if (mWrapper) { + mWrapper.setToCrashOnTouch(); + } + } + private: JSObject *GetWrapperJSObject() const { return mWrapper; } void SetWrapperJSObject(JSObject* aWrapper) {
--- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -20,20 +20,16 @@ #include "nsCOMPtr.h" #include "nsTArray.h" #include "nsAutoPtr.h" // for nsRefPtr member variables #include "mozilla/dom/DOMString.h" #include "mozilla/dom/OwningNonNull.h" class nsWrapperCache; -// nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't -// try to use it without fixing that first. -class nsGlobalWindow; - namespace mozilla { namespace dom { // Struct that serves as a base class for all dictionaries. Particularly useful // so we can use IsBaseOf to detect dictionary template arguments. struct DictionaryBase { protected: @@ -438,22 +434,16 @@ public: inline nsWrapperCache* GetWrapperCache(nsWrapperCache* cache) { return cache; } inline nsWrapperCache* -GetWrapperCache(nsGlobalWindow*) -{ - return nullptr; -} - -inline nsWrapperCache* GetWrapperCache(void* p) { return nullptr; } // Helper template for smart pointers to resolve ambiguity between // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&). template <template <typename> class SmartPtr, typename T>
--- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -240,16 +240,28 @@ class Heap : public js::HeapBase<T> } else if (js::GCMethods<T>::needsPostBarrier(ptr)) { relocate(); /* Called before overwriting ptr. */ ptr = newPtr; } else { ptr = newPtr; } } + /* + * Set the pointer to a value which will cause a crash if it is + * dereferenced. + */ + void setToCrashOnTouch() { + ptr = reinterpret_cast<T>(crashOnTouchPointer); + } + + bool isSetToCrashOnTouch() { + return ptr == crashOnTouchPointer; + } + private: void init(T newPtr) { MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr)); ptr = newPtr; if (js::GCMethods<T>::needsPostBarrier(ptr)) post(); } @@ -261,16 +273,20 @@ class Heap : public js::HeapBase<T> } void relocate() { #ifdef JSGC_GENERATIONAL js::GCMethods<T>::relocate(&ptr); #endif } + enum { + crashOnTouchPointer = 1 + }; + T ptr; }; #ifdef JS_DEBUG /* * For generational GC, assert that an object is in the tenured generation as * opposed to being in the nursery. */ @@ -358,33 +374,20 @@ class TenuredHeap : public js::HeapBase< return *this; } TenuredHeap<T> &operator=(const TenuredHeap<T>& other) { bits = other.bits; return *this; } - /* - * Set the pointer to a value which will cause a crash if it is - * dereferenced. - */ - void setToCrashOnTouch() { - bits = (bits & flagsMask) | crashOnTouchPointer; - } - - bool isSetToCrashOnTouch() { - return (bits & ~flagsMask) == crashOnTouchPointer; - } - private: enum { maskBits = 3, flagsMask = (1 << maskBits) - 1, - crashOnTouchPointer = 1 << maskBits }; uintptr_t bits; }; /* * Reference to a T that has been rooted elsewhere. This is most useful * as a parameter type, which guarantees that the T lvalue is properly
--- a/js/xpconnect/src/XPCQuickStubs.h +++ b/js/xpconnect/src/XPCQuickStubs.h @@ -501,22 +501,16 @@ castNativeArgFromWrapper(JSContext *cx, } inline nsWrapperCache* xpc_qsGetWrapperCache(nsWrapperCache *cache) { return cache; } -// nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't -// try to use it without fixing that first. -class nsGlobalWindow; -inline nsWrapperCache* -xpc_qsGetWrapperCache(nsGlobalWindow *not_allowed); - inline nsWrapperCache* xpc_qsGetWrapperCache(void *p) { return nullptr; } /** Convert an XPCOM pointer to jsval. Return true on success. * aIdentity is a performance optimization. Set it to true,
--- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -19,16 +19,17 @@ #include "nsWrapperCache.h" #include "nsStringGlue.h" #include "nsTArray.h" #include "mozilla/dom/JSSlots.h" #include "nsMathUtils.h" #include "nsStringBuffer.h" #include "mozilla/dom/BindingDeclarations.h" +class nsGlobalWindow; class nsIPrincipal; class nsScriptNameSpaceManager; class nsIGlobalObject; class nsIMemoryReporterCallback; #ifndef BAD_TLS_INDEX #define BAD_TLS_INDEX ((uint32_t) -1) #endif
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -43,16 +43,17 @@ namespace test { class AFakePCObserver; #endif } #ifdef USE_FAKE_MEDIA_STREAMS class Fake_DOMMediaStream; #endif +class nsGlobalWindow; class nsIDOMMediaStream; class nsDOMDataChannel; namespace mozilla { class DataChannel; class DtlsIdentity; class NrIceCtx; class NrIceMediaStream;