зеркало из https://github.com/mozilla/pjs.git
Make wrapper preservation (the mechanism that makes the GC use reachability information between certain C++ objects rather than rooting at language boundaries) use an interface (nsIDOMGCParticipant) to get reachability information. Preserve the wrappers for event handlers as long as what they are attached to is reachable (from C++ or JS) to avoid entraining event handler closures in cycles. b=241518 r=mrbkap sr=jst
This commit is contained in:
Родитель
e79a259e56
Коммит
3ceffc0fc4
|
@ -56,6 +56,7 @@ nsContentUtils.h \
|
|||
nsIDocument.h \
|
||||
nsIDocumentEncoder.h \
|
||||
nsIDocumentObserver.h \
|
||||
nsIDOMGCParticipant.h \
|
||||
nsINameSpaceManager.h \
|
||||
nsINodeInfo.h \
|
||||
nsIRangeUtils.h \
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsINodeInfo.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsPropertyTable.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
|
||||
class nsIAtom;
|
||||
class nsDOMAttributeMap;
|
||||
|
@ -52,7 +53,7 @@ class nsDOMAttributeMap;
|
|||
{0x4940cc50, 0x2ede, 0x4883, \
|
||||
{0x95, 0xf5, 0x53, 0xdb, 0x50, 0x50, 0x13, 0x3e}}
|
||||
|
||||
class nsIAttribute : public nsISupports
|
||||
class nsIAttribute : public nsIDOMGCParticipant
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IATTRIBUTE_IID)
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsPropertyTable.h"
|
||||
#include "nsCaseTreatment.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "nsINodeInfo.h"
|
||||
|
@ -67,15 +68,16 @@ class nsRuleWalker;
|
|||
class nsAttrValue;
|
||||
|
||||
// IID for the nsIContent interface
|
||||
#define NS_ICONTENT_IID \
|
||||
{ 0x5d098839, 0x389d, 0x41db, \
|
||||
{ 0x8f, 0x53, 0x59, 0x07, 0xbf, 0x90, 0x0d, 0x4e } }
|
||||
// ffc6f2b8-bcdc-4cf7-b72f-e843860f14a6
|
||||
#define NS_ICONTENT_IID \
|
||||
{ 0xffc6f2b8, 0xbcdc, 0x4cf7, \
|
||||
{ 0xb7, 0x2f, 0xe8, 0x43, 0x86, 0x0f, 0x14, 0xa6 } }
|
||||
|
||||
/**
|
||||
* A node of content in a document's content model. This interface
|
||||
* is supported by all content objects.
|
||||
*/
|
||||
class nsIContent : public nsISupports {
|
||||
class nsIContent : public nsIDOMGCParticipant {
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENT_IID)
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998-1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsIDOMGCParticipant_h_
|
||||
#define nsIDOMGCParticipant_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
// 0e2a5a8d-28fd-4a5c-8bf1-5b0067ff3286
|
||||
#define NS_IDOMGCPARTICIPANT_IID \
|
||||
{ 0x0e2a5a8d, 0x28fd, 0x4a5c, \
|
||||
{0x8b, 0xf1, 0x5b, 0x00, 0x67, 0xff, 0x32, 0x86} }
|
||||
|
||||
/**
|
||||
* DOM GC Participants are objects that expose information about
|
||||
* reachability in the native object graphs to help prevent script ->
|
||||
* native -> script cyclical reference from causing leaks due to the
|
||||
* creation of garbage collection roots and native/script boundaries.
|
||||
*/
|
||||
class nsIDOMGCParticipant : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMGCPARTICIPANT_IID)
|
||||
|
||||
/**
|
||||
* Get a reference node for what is known to be a strongly connected
|
||||
* component of nsIDOMGCParticipants. For example, DOM trees are
|
||||
* strongly connected, so can return the root node to greatly reduce
|
||||
* the number of nodes on which we need to run graph algorithms.
|
||||
*
|
||||
* Note that it's acceptable for nodes in a single strongly connected
|
||||
* component to return different values for GetSCCIndex, as long as
|
||||
* those two values claim that they're reachable from each other in
|
||||
* AppendReachableList.
|
||||
*/
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex() = 0;
|
||||
|
||||
/**
|
||||
* Append the list of nsIDOMGCPartipants reachable from this one via
|
||||
* C++ getters exposed to script that return a different result from
|
||||
* |GetSCCIndex|. The caller is responsible for taking the transitive
|
||||
* closure of |AppendReachableList|.
|
||||
*
|
||||
* This will only be called on objects that are returned by GetSCCIndex.
|
||||
*/
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMGCParticipant, NS_IDOMGCPARTICIPANT_IID)
|
||||
|
||||
#endif // !defined(nsIDOMGCParticipant_h_)
|
|
@ -37,7 +37,7 @@
|
|||
#ifndef nsIDocument_h___
|
||||
#define nsIDocument_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
#include "nsEvent.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
@ -92,9 +92,10 @@ class nsIVariant;
|
|||
class nsIDOMUserDataHandler;
|
||||
|
||||
// IID for the nsIDocument interface
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0xbcb48147, 0xed60, 0x490e, \
|
||||
{ 0xa2, 0x47, 0xe2, 0x35, 0x3c, 0xf7, 0xc8, 0x68 } }
|
||||
// a5d8343d-9b0a-40a8-a47e-893065749f0b
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0xa5d8343d, 0x9b0a, 0x40a8, \
|
||||
{ 0xa4, 0x7e, 0x89, 0x30, 0x65, 0x74, 0x9f, 0x0b } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
|
@ -103,7 +104,7 @@ class nsIDOMUserDataHandler;
|
|||
|
||||
// Document interface. This is implemented by all document objects in
|
||||
// Gecko.
|
||||
class nsIDocument : public nsISupports
|
||||
class nsIDocument : public nsIDOMGCParticipant
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
|
||||
|
|
|
@ -83,6 +83,7 @@ nsDOMAttribute::~nsDOMAttribute()
|
|||
NS_INTERFACE_MAP_BEGIN(nsDOMAttribute)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMAttr)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAttribute)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMAttr)
|
||||
|
@ -93,6 +94,22 @@ NS_INTERFACE_MAP_END
|
|||
NS_IMPL_ADDREF(nsDOMAttribute)
|
||||
NS_IMPL_RELEASE(nsDOMAttribute)
|
||||
|
||||
// nsIDOMGCParticipant methods
|
||||
nsIDOMGCParticipant*
|
||||
nsDOMAttribute::GetSCCIndex()
|
||||
{
|
||||
PRBool spec;
|
||||
if (NS_SUCCEEDED(GetSpecified(&spec)) && spec) {
|
||||
return GetContentInternal()->GetSCCIndex();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMAttribute::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap)
|
||||
{
|
||||
|
|
|
@ -80,6 +80,10 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIDOMGCParticipant interface methods
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
||||
|
||||
// nsIDOMNode interface
|
||||
NS_DECL_NSIDOMNODE
|
||||
|
||||
|
|
|
@ -797,6 +797,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocument)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentXBL)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
||||
|
@ -3324,6 +3325,23 @@ nsDocument::SetDir(const nsAString& aDirection)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIDOMGCParticipant methods
|
||||
//
|
||||
nsIDOMGCParticipant*
|
||||
nsDocument::GetSCCIndex()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
nsCOMPtr<nsIDOMGCParticipant> gcp = do_QueryInterface(mScriptGlobalObject);
|
||||
if (gcp)
|
||||
aArray.AppendObject(gcp);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// nsIDOMNode methods
|
||||
|
|
|
@ -557,6 +557,10 @@ public:
|
|||
nsresult GetRadioGroup(const nsAString& aName,
|
||||
nsRadioGroupStruct **aRadioGroup);
|
||||
|
||||
// nsIDOMGCParticipant interface methods
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
||||
|
||||
// nsIDOMNode
|
||||
NS_DECL_NSIDOMNODE
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ NS_IMPL_RELEASE(nsGenericDOMDataNode)
|
|||
|
||||
NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
|
||||
nsDOMEventRTTearoff::Create(this))
|
||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
|
||||
|
@ -632,6 +633,30 @@ nsGenericDOMDataNode::ToCString(nsAString& aBuf, PRInt32 aOffset,
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* See comment for nsGenericElement::GetSCCIndex
|
||||
*/
|
||||
nsIDOMGCParticipant*
|
||||
nsGenericDOMDataNode::GetSCCIndex()
|
||||
{
|
||||
// This is an optimized way of walking nsIDOMNode::GetParentNode to
|
||||
// the top of the tree.
|
||||
nsIDOMGCParticipant *result = GetCurrentDoc();
|
||||
if (!result) {
|
||||
nsIContent *top = this;
|
||||
while (top->GetParent())
|
||||
top = top->GetParent();
|
||||
result = top;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericDOMDataNode::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
|
|
|
@ -174,6 +174,10 @@ public:
|
|||
nsresult ReplaceData(PRUint32 aOffset, PRUint32 aCount,
|
||||
const nsAString& aArg);
|
||||
|
||||
// nsIDOMGCParticipant interface methods
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
||||
|
||||
// Implementation for nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
|
|
|
@ -1017,6 +1017,37 @@ nsGenericElement::InitHashes()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* During the Mark phase of the GC, we need to mark all of the preserved
|
||||
* wrappers that are reachable via DOM APIs. Since reachability for DOM
|
||||
* nodes is symmetric, if one DOM node is reachable from another via DOM
|
||||
* APIs, then they are in the same strongly connected component.
|
||||
* (Strongly connected components are never reachable from each other
|
||||
* via DOM APIs.) We can refer to each strongly connected component by
|
||||
* walking up to the top of the parent chain. This function finds that
|
||||
* root node for any DOM node.
|
||||
*/
|
||||
nsIDOMGCParticipant*
|
||||
nsGenericElement::GetSCCIndex()
|
||||
{
|
||||
// This is an optimized way of walking nsIDOMNode::GetParentNode to
|
||||
// the top of the tree.
|
||||
nsIDOMGCParticipant *result = GetCurrentDoc();
|
||||
if (!result) {
|
||||
nsIContent *top = this;
|
||||
while (top->GetParent())
|
||||
top = top->GetParent();
|
||||
result = top;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericElement::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericElement::GetNodeName(nsAString& aNodeName)
|
||||
{
|
||||
|
@ -3694,6 +3725,7 @@ nsGenericElement::RemoveChild(nsIDOMNode *aOldChild, nsIDOMNode **aReturn)
|
|||
|
||||
NS_INTERFACE_MAP_BEGIN(nsGenericElement)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
|
||||
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
|
||||
nsDOMEventRTTearoff::Create(this))
|
||||
|
|
|
@ -352,6 +352,10 @@ public:
|
|||
/** Free globals, to be called from module destructor */
|
||||
static void Shutdown();
|
||||
|
||||
// nsIDOMGCParticipant interface methods
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
||||
|
||||
// nsIContent interface methods
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
|
|
|
@ -419,14 +419,12 @@ GenericListenersHashEnum(nsHashKey *aKey, void *aData, void* closure)
|
|||
if (ls) {
|
||||
if (*scriptOnly) {
|
||||
if (ls->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) {
|
||||
NS_RELEASE(ls->mListener);
|
||||
//listeners->RemoveElement((void*)ls); we delete the entire array anyways, no need to RemoveElement
|
||||
PR_DELETE(ls);
|
||||
listeners->RemoveElement(ls);
|
||||
delete ls;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_IF_RELEASE(ls->mListener);
|
||||
PR_DELETE(ls);
|
||||
delete ls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -686,14 +684,12 @@ nsEventListenerManager::ReleaseListeners(nsVoidArray** aListeners,
|
|||
if (ls) {
|
||||
if (aScriptOnly) {
|
||||
if (ls->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) {
|
||||
NS_RELEASE(ls->mListener);
|
||||
//(*aListeners)->RemoveElement((void*)ls); We're going to delete the array anyways
|
||||
PR_DELETE(ls);
|
||||
(*aListeners)->RemoveElement(ls);
|
||||
delete ls;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_IF_RELEASE(ls->mListener);
|
||||
PR_DELETE(ls);
|
||||
delete ls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -765,7 +761,8 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
|
|||
|
||||
for (PRInt32 i=0; i<listeners->Count(); i++) {
|
||||
ls = (nsListenerStruct*)listeners->ElementAt(i);
|
||||
if (ls->mListener == aListener && ls->mFlags == aFlags &&
|
||||
nsRefPtr<nsIDOMEventListener> iListener = ls->mListener.Get();
|
||||
if (iListener == aListener && ls->mFlags == aFlags &&
|
||||
ls->mGroupFlags == group) {
|
||||
ls->mSubType |= aSubType;
|
||||
found = PR_TRUE;
|
||||
|
@ -774,17 +771,20 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
ls = PR_NEW(nsListenerStruct);
|
||||
if (ls) {
|
||||
ls->mListener = aListener;
|
||||
ls->mFlags = aFlags;
|
||||
ls->mSubType = aSubType;
|
||||
ls->mSubTypeCapture = NS_EVENT_BITS_NONE;
|
||||
ls->mHandlerIsString = 0;
|
||||
ls->mGroupFlags = group;
|
||||
listeners->AppendElement((void*)ls);
|
||||
NS_ADDREF(aListener);
|
||||
ls = new nsListenerStruct;
|
||||
if (!ls) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMGCParticipant> participant = do_QueryInterface(mTarget);
|
||||
NS_ASSERTION(participant, "must implement nsIDOMGCParticipant");
|
||||
ls->mListener.Set(aListener, participant);
|
||||
ls->mFlags = aFlags;
|
||||
ls->mSubType = aSubType;
|
||||
ls->mSubTypeCapture = NS_EVENT_BITS_NONE;
|
||||
ls->mHandlerIsString = 0;
|
||||
ls->mGroupFlags = group;
|
||||
listeners->AppendElement((void*)ls);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -809,13 +809,13 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
|
|||
|
||||
for (PRInt32 i=0; i<listeners->Count(); i++) {
|
||||
ls = (nsListenerStruct*)listeners->ElementAt(i);
|
||||
if (ls->mListener == aListener &&
|
||||
nsRefPtr<nsIDOMEventListener> iListener = ls->mListener.Get();
|
||||
if (iListener == aListener &&
|
||||
(ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) {
|
||||
ls->mSubType &= ~aSubType;
|
||||
if (ls->mSubType == NS_EVENT_BITS_NONE) {
|
||||
NS_RELEASE(ls->mListener);
|
||||
listeners->RemoveElement((void*)ls);
|
||||
PR_DELETE(ls);
|
||||
delete ls;
|
||||
listenerRemoved = PR_TRUE;
|
||||
}
|
||||
break;
|
||||
|
@ -1403,14 +1403,12 @@ nsEventListenerManager::RemoveScriptEventListener(nsIAtom *aName)
|
|||
if (ls) {
|
||||
ls->mSubType &= ~flags;
|
||||
if (ls->mSubType == NS_EVENT_BITS_NONE) {
|
||||
NS_RELEASE(ls->mListener);
|
||||
|
||||
//Get the listeners array so we can remove ourselves from it
|
||||
nsVoidArray* listeners;
|
||||
listeners = GetListenersByType(arrayType, nsnull, PR_FALSE);
|
||||
NS_ENSURE_TRUE(listeners, NS_ERROR_FAILURE);
|
||||
listeners->RemoveElement((void*)ls);
|
||||
PR_DELETE(ls);
|
||||
delete ls;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1634,6 +1632,7 @@ nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
|
|||
|
||||
nsresult
|
||||
nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
|
||||
nsIDOMEventListener* aListener,
|
||||
nsIDOMEvent* aDOMEvent,
|
||||
nsIDOMEventTarget* aCurrentTarget,
|
||||
PRUint32 aSubType,
|
||||
|
@ -1659,7 +1658,7 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
|
|||
}
|
||||
if (aListenerStruct->mHandlerIsString & aSubType) {
|
||||
|
||||
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListenerStruct->mListener);
|
||||
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListener);
|
||||
if (jslistener) {
|
||||
nsAutoString eventString;
|
||||
if (NS_SUCCEEDED(aDOMEvent->GetType(eventString))) {
|
||||
|
@ -1683,7 +1682,7 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
nsCOMPtr<nsIPrivateDOMEvent> aPrivDOMEvent(do_QueryInterface(aDOMEvent));
|
||||
aPrivDOMEvent->SetCurrentTarget(aCurrentTarget);
|
||||
result = aListenerStruct->mListener->HandleEvent(aDOMEvent);
|
||||
result = aListener->HandleEvent(aDOMEvent);
|
||||
aPrivDOMEvent->SetCurrentTarget(nsnull);
|
||||
}
|
||||
|
||||
|
@ -1772,19 +1771,23 @@ nsEventListenerManager::HandleEvent(nsPresContext* aPresContext,
|
|||
ls->mGroupFlags == currentGroup &&
|
||||
(NS_IS_TRUSTED_EVENT(aEvent) ||
|
||||
ls->mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED)) {
|
||||
// Try the type-specific listener interface
|
||||
PRBool hasInterface = PR_FALSE;
|
||||
if (typeData)
|
||||
DispatchToInterface(*aDOMEvent, ls->mListener,
|
||||
dispData->method, *typeData->iid,
|
||||
&hasInterface);
|
||||
nsRefPtr<nsIDOMEventListener> eventListener = ls->mListener.Get();
|
||||
NS_ASSERTION(eventListener, "listener wasn't preserved properly");
|
||||
if (eventListener) {
|
||||
// Try the type-specific listener interface
|
||||
PRBool hasInterface = PR_FALSE;
|
||||
if (typeData)
|
||||
DispatchToInterface(*aDOMEvent, eventListener,
|
||||
dispData->method, *typeData->iid,
|
||||
&hasInterface);
|
||||
|
||||
// If it doesn't implement that, call the generic HandleEvent()
|
||||
if (!hasInterface && (ls->mSubType == NS_EVENT_BITS_NONE ||
|
||||
ls->mSubType & dispData->bits)) {
|
||||
HandleEventSubType(ls, *aDOMEvent, aCurrentTarget,
|
||||
dispData ? dispData->bits : NS_EVENT_BITS_NONE,
|
||||
aFlags);
|
||||
// If it doesn't implement that, call the generic HandleEvent()
|
||||
if (!hasInterface && (ls->mSubType == NS_EVENT_BITS_NONE ||
|
||||
ls->mSubType & dispData->bits)) {
|
||||
HandleEventSubType(ls, eventListener, *aDOMEvent, aCurrentTarget,
|
||||
dispData ? dispData->bits : NS_EVENT_BITS_NONE,
|
||||
aFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,12 +45,22 @@
|
|||
#include "nsIDOM3EventTarget.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
class nsIDOMEvent;
|
||||
class nsIAtom;
|
||||
|
||||
typedef struct {
|
||||
nsIDOMEventListener* mListener;
|
||||
// The nsMarkedJSFunctionHolder does magic to avoid holding strong
|
||||
// references to listeners implemented in JS. Instead, it protects
|
||||
// them from garbage collection using nsDOMClassInfo::PreserveWrapper,
|
||||
// which protects the event listener from garbage collection as long
|
||||
// as it is still reachable from JS using C++ getters. (It exposes
|
||||
// reachability information to the JS GC instead of treating the C++
|
||||
// reachability information as own-in root-out, which creates roots
|
||||
// that cause reference cycles to entrain garbage.)
|
||||
nsMarkedJSFunctionHolder<nsIDOMEventListener> mListener;
|
||||
|
||||
PRUint16 mFlags;
|
||||
PRUint16 mGroupFlags;
|
||||
PRUint8 mSubType;
|
||||
|
@ -196,6 +206,7 @@ public:
|
|||
|
||||
protected:
|
||||
nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
|
||||
nsIDOMEventListener* aListener,
|
||||
nsIDOMEvent* aDOMEvent,
|
||||
nsIDOMEventTarget* aCurrentTarget,
|
||||
PRUint32 aSubType,
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
nsresult NS_DOMClassInfo_PreserveWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
|
||||
// Helper classes
|
||||
|
||||
|
@ -1164,7 +1164,7 @@ nsXBLBinding::InitClass(const nsCString& aClassName,
|
|||
do_QueryInterface(wrapper);
|
||||
|
||||
if (native_wrapper) {
|
||||
NS_DOMClassInfo_PreserveWrapper(native_wrapper);
|
||||
NS_DOMClassInfo_PreserveNodeWrapper(native_wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include "nsIXBLDocumentInfo.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
||||
nsresult NS_DOMClassInfo_PreserveWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
|
||||
nsresult
|
||||
nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement)
|
||||
|
@ -151,7 +151,7 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
|
|||
if (doc) {
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> nativeWrapper(do_QueryInterface(wrapper));
|
||||
if (nativeWrapper) {
|
||||
NS_DOMClassInfo_PreserveWrapper(nativeWrapper);
|
||||
NS_DOMClassInfo_PreserveNodeWrapper(nativeWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,9 @@ nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
|
|||
delete mHandler;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXBLWindowKeyHandler, nsIDOMKeyListener)
|
||||
NS_IMPL_ISUPPORTS2(nsXBLWindowKeyHandler,
|
||||
nsIDOMKeyListener,
|
||||
nsIDOMEventListener)
|
||||
|
||||
static void
|
||||
BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
|
||||
|
|
|
@ -41,14 +41,16 @@
|
|||
#define nsPIWindowRoot_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
|
||||
class nsIFocusController;
|
||||
|
||||
// {575CB0E1-E6C4-484a-99F8-C47B06C0E521}
|
||||
// a22236a5-db06-4653-94b6-c4b6068e053c
|
||||
#define NS_IWINDOWROOT_IID \
|
||||
{ 0x575cb0e1, 0xe6c4, 0x484a, { 0x99, 0xf8, 0xc4, 0x7b, 0x6, 0xc0, 0xe5, 0x21 } }
|
||||
{ 0xa22236a5, 0xdb06, 0x4653, \
|
||||
{ 0x94, 0xb6, 0xc4, 0xb6, 0x06, 0x8e, 0x05, 0x3c } }
|
||||
|
||||
class nsPIWindowRoot : public nsISupports {
|
||||
class nsPIWindowRoot : public nsIDOMGCParticipant {
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
|
||||
|
||||
|
|
|
@ -196,10 +196,6 @@ enum nsDOMClassInfoID {
|
|||
// DOM Traversal classes
|
||||
eDOMClassInfo_TreeWalker_id,
|
||||
|
||||
// We are now trying to preserve binary compat in classinfo. No
|
||||
// more putting things in those categories up there. New entries
|
||||
// are to be added right before eDOMClassInfoIDCount.
|
||||
|
||||
// Rect object used by getComputedStyle
|
||||
eDOMClassInfo_CSSRect_id,
|
||||
|
||||
|
@ -365,6 +361,13 @@ enum nsDOMClassInfoID {
|
|||
eDOMClassInfo_XPathNSResolver_id,
|
||||
eDOMClassInfo_XPathResult_id,
|
||||
|
||||
eDOMClassInfo_WindowRoot_id,
|
||||
|
||||
// We are now trying to preserve binary compat in classinfo. No more
|
||||
// putting things in those categories up there. New entries are to be
|
||||
// added here, which is the end of the things that are currently on by
|
||||
// default.
|
||||
|
||||
// Define this near the end so that enabling/disabling foreignobject doesn't
|
||||
// break binary compatibility
|
||||
#if defined(MOZ_SVG) && defined(MOZ_SVG_FOREIGNOBJECT)
|
||||
|
|
|
@ -420,6 +420,7 @@ static const char kDOMStringBundleURL[] =
|
|||
nsIXPCScriptable::WANT_ADDPROPERTY | \
|
||||
nsIXPCScriptable::WANT_DELPROPERTY | \
|
||||
nsIXPCScriptable::WANT_NEWENUMERATE | \
|
||||
nsIXPCScriptable::WANT_MARK | \
|
||||
nsIXPCScriptable::WANT_EQUALITY | \
|
||||
nsIXPCScriptable::WANT_OUTER_OBJECT | \
|
||||
nsIXPCScriptable::WANT_INNER_OBJECT | \
|
||||
|
@ -1081,6 +1082,12 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
NS_DEFINE_CLASSINFO_DATA(XPathResult, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
// We just want this to have classinfo so it gets mark callbacks for marking
|
||||
// event listeners.
|
||||
// We really don't want any of the default flags!
|
||||
NS_DEFINE_CLASSINFO_DATA(WindowRoot, nsEventReceiverSH,
|
||||
nsIXPCScriptable::WANT_MARK)
|
||||
|
||||
// Define MOZ_SVG_FOREIGNOBJECT here so that when it gets switched on,
|
||||
// we preserve binary compatibility. New classes should be added
|
||||
// at the end.
|
||||
|
@ -2952,6 +2959,11 @@ nsDOMClassInfo::Init()
|
|||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathResult)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
// We just want this to have classinfo so it gets mark callbacks for marking
|
||||
// event listeners.
|
||||
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(WindowRoot, nsISupports)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
#if defined(MOZ_SVG) && defined(MOZ_SVG_FOREIGNOBJECT)
|
||||
DOM_CLASSINFO_MAP_BEGIN(SVGForeignObjectElement, nsIDOMSVGForeignObjectElement)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGForeignObjectElement)
|
||||
|
@ -4865,105 +4877,23 @@ nsDOMClassInfo::InitDOMJSClass(JSContext *cx, JSObject *obj)
|
|||
#endif
|
||||
|
||||
/**
|
||||
* Every XPConnect wrapper that needs to be preserved (because it has JS
|
||||
* properties set on it) as long as the element it wraps is reachable
|
||||
* from script (via JS or via DOM APIs accessible from JS) gets an entry
|
||||
* in this table.
|
||||
* Every XPConnect wrapper that needs to be preserved (a wrapped native
|
||||
* with JS properties set on it or used by XBL or a wrapped JS event
|
||||
* handler function) as long as the element it wraps is reachable from
|
||||
* script (via JS or via DOM APIs accessible from JS) gets an entry in
|
||||
* this table.
|
||||
*/
|
||||
static PLDHashTable sPreservedWrapperTable;
|
||||
|
||||
struct PreservedWrapperEntry : public PLDHashEntryHdr {
|
||||
nsIDOMNode* key; // must be first to line up with PLDHashEntryStub
|
||||
nsIXPConnectWrappedNative *wrapper;
|
||||
void *key; // must be first to line up with PLDHashEntryStub
|
||||
nsIXPConnectJSObjectHolder* (*keyToWrapperFunc)(void* aKey);
|
||||
nsIDOMGCParticipant *participant;
|
||||
|
||||
// See |WrapperSCCEntry::first|. Valid only during mark phase of GC.
|
||||
PreservedWrapperEntry *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* During the Mark phase of the GC, we need to mark all of the preserved
|
||||
* wrappers that are reachable via DOM APIs. Since reachability for DOM
|
||||
* nodes is symmetric, if one DOM node is reachable from another via DOM
|
||||
* APIs, then they are in the same strongly connected component.
|
||||
* (Strongly connected components are never reachable from each other
|
||||
* via DOM APIs.) We can refer to each strongly connected component by
|
||||
* walking up to the top of the parent chain. This function finds that
|
||||
* root node for any DOM node.
|
||||
*/
|
||||
static nsIDOMNode *
|
||||
GetSCCRootFor(nsIDOMNode *aDOMNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> cur(aDOMNode), next;
|
||||
#ifdef DEBUG_NOISY_PRESERVE_WRAPPERS
|
||||
nsCOMArray<nsIDOMNode> stack;
|
||||
#endif
|
||||
PRUint16 nodeType;
|
||||
cur->GetNodeType(&nodeType);
|
||||
if (nodeType == nsIDOMNode::ATTRIBUTE_NODE) {
|
||||
nsCOMPtr<nsIDOMAttr> attr = do_QueryInterface(cur);
|
||||
nsCOMPtr<nsIDOMElement> owner;
|
||||
attr->GetOwnerElement(getter_AddRefs(owner));
|
||||
if (owner) {
|
||||
#ifdef DEBUG_NOISY_PRESERVE_WRAPPERS
|
||||
stack.AppendObject(cur);
|
||||
#endif
|
||||
cur = do_QueryInterface(owner);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
#ifdef DEBUG_NOISY_PRESERVE_WRAPPERS
|
||||
stack.AppendObject(cur);
|
||||
#endif
|
||||
cur->GetParentNode(getter_AddRefs(next));
|
||||
if (!next) {
|
||||
#ifdef DEBUG_NOISY_PRESERVE_WRAPPERS
|
||||
PRUint16 nodeType;
|
||||
cur->GetNodeType(&nodeType);
|
||||
if (nodeType != nsIDOMNode::DOCUMENT_NODE) {
|
||||
printf(" non-document root:");
|
||||
nsAutoString nodeName;
|
||||
for (PRInt32 i = stack.Count() - 1; i >= 0; --i) {
|
||||
stack[i]->GetNodeName(nodeName);
|
||||
stack[i]->GetNodeType(&nodeType);
|
||||
if (nodeType == nsIDOMNode::ATTRIBUTE_NODE) {
|
||||
nsAutoString nodeValue;
|
||||
stack[i]->GetNodeValue(nodeValue);
|
||||
printf(" > @%s=\"%s\"", NS_ConvertUTF16toUTF8(nodeName).get(),
|
||||
NS_ConvertUTF16toUTF8(nodeValue).get());
|
||||
} else {
|
||||
printf(" > %s", NS_ConvertUTF16toUTF8(nodeName).get());
|
||||
if (nodeType == nsIDOMNode::ELEMENT_NODE) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(stack[i]);
|
||||
PRInt32 j;
|
||||
for (j = 0, j_end = content->GetAttrCount(); j < j_end; ++j) {
|
||||
PRInt32 namespaceID;
|
||||
nsCOMPtr<nsIAtom> name, prefix;
|
||||
content->GetAttrNameAt(j, &namespaceID, getter_AddRefs(name),
|
||||
getter_AddRefs(prefix));
|
||||
nsAutoString val;
|
||||
nsCAutoString atomStr;
|
||||
content->GetAttr(namespaceID, name, val);
|
||||
printf("[");
|
||||
if (prefix) {
|
||||
prefix->ToUTF8String(atomStr);
|
||||
printf("%s:", atomStr.get());
|
||||
}
|
||||
name->ToUTF8String(atomStr);
|
||||
printf("%s=\"%s\"]", atomStr.get(),
|
||||
NS_ConvertUTF16toUTF8(val).get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
return cur;
|
||||
}
|
||||
next.swap(cur);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At the beginning of the mark phase of the GC, we sort all the
|
||||
* wrappers into their strongly connected components. We maintain this
|
||||
|
@ -4985,7 +4915,7 @@ static PLDHashTable sWrapperSCCTable;
|
|||
struct WrapperSCCEntry : public PLDHashEntryHdr {
|
||||
// This could probably be a weak pointer (which would avoid the
|
||||
// need for hash table ops), but it seems safer this way.
|
||||
nsCOMPtr<nsIDOMNode> key; // must be first to line up with PLDHashEntryStub
|
||||
nsCOMPtr<nsIDOMGCParticipant> key; // must be first to line up with PLDHashEntryStub
|
||||
|
||||
// Linked list of preserved wrappers in the strongly connected
|
||||
// component, to be traversed using |PreservedWrapperEntry::next|.
|
||||
|
@ -4993,7 +4923,7 @@ struct WrapperSCCEntry : public PLDHashEntryHdr {
|
|||
|
||||
PRBool marked;
|
||||
|
||||
WrapperSCCEntry(nsIDOMNode *aKey)
|
||||
WrapperSCCEntry(nsIDOMGCParticipant *aKey)
|
||||
: key(aKey), first(nsnull), marked(PR_FALSE) {}
|
||||
};
|
||||
|
||||
|
@ -5010,8 +4940,8 @@ WrapperSCCsInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|||
const void *key)
|
||||
{
|
||||
WrapperSCCEntry *entry = NS_STATIC_CAST(WrapperSCCEntry*, hdr);
|
||||
new (entry) WrapperSCCEntry(NS_STATIC_CAST(nsIDOMNode*,
|
||||
NS_CONST_CAST(void*, key)));
|
||||
new (entry) WrapperSCCEntry(NS_STATIC_CAST(nsIDOMGCParticipant*,
|
||||
NS_CONST_CAST(void*, key)));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -5030,14 +4960,16 @@ static const PLDHashTableOps sWrapperSCCTableOps = {
|
|||
|
||||
// static
|
||||
nsresult
|
||||
nsDOMClassInfo::PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
|
||||
nsDOMClassInfo::PreserveWrapper(void *aKey,
|
||||
nsIXPConnectJSObjectHolder* (*aKeyToWrapperFunc)(void* aKey),
|
||||
nsIDOMGCParticipant *aParticipant)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> node = do_QueryWrappedNative(aWrapper);
|
||||
if (!node) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsIDOMNode* nodePtr = node;
|
||||
|
||||
NS_PRECONDITION(aKey, "unexpected null pointer");
|
||||
NS_PRECONDITION(aKeyToWrapperFunc, "unexpected null pointer");
|
||||
NS_PRECONDITION(aParticipant, "unexpected null pointer");
|
||||
NS_ASSERTION(!sWrapperSCCTable.ops,
|
||||
"cannot change preserved wrapper table during mark phase");
|
||||
|
||||
if (!sPreservedWrapperTable.ops &&
|
||||
!PL_DHashTableInit(&sPreservedWrapperTable, PL_DHashGetStubOps(), nsnull,
|
||||
sizeof(PreservedWrapperEntry), 16)) {
|
||||
|
@ -5046,22 +4978,43 @@ nsDOMClassInfo::PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
|
|||
}
|
||||
|
||||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*,
|
||||
PL_DHashTableOperate(&sPreservedWrapperTable, nodePtr, PL_DHASH_ADD));
|
||||
PL_DHashTableOperate(&sPreservedWrapperTable, aKey, PL_DHASH_ADD));
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
entry->key = nodePtr;
|
||||
entry->wrapper = aWrapper;
|
||||
entry->key = aKey;
|
||||
entry->keyToWrapperFunc = aKeyToWrapperFunc;
|
||||
entry->participant = aParticipant;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsIXPConnectJSObjectHolder* IdentityKeyToWrapperFunc(void* aKey)
|
||||
{
|
||||
return NS_STATIC_CAST(nsIXPConnectJSObjectHolder*, aKey);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsDOMClassInfo::PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper)
|
||||
{
|
||||
nsCOMPtr<nsIDOMGCParticipant> participant =
|
||||
do_QueryInterface(aWrapper->Native());
|
||||
|
||||
return nsDOMClassInfo::PreserveWrapper(aWrapper, IdentityKeyToWrapperFunc,
|
||||
participant);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsDOMClassInfo::ReleaseWrapper(nsIDOMNode *aDOMNode)
|
||||
nsDOMClassInfo::ReleaseWrapper(void *aKey)
|
||||
{
|
||||
NS_PRECONDITION(aKey, "unexpected null pointer");
|
||||
NS_ASSERTION(!sWrapperSCCTable.ops,
|
||||
"cannot change preserved wrapper table during mark phase");
|
||||
|
||||
if (sPreservedWrapperTable.ops) {
|
||||
PL_DHashTableOperate(&sPreservedWrapperTable, aDOMNode, PL_DHASH_REMOVE);
|
||||
PL_DHashTableOperate(&sPreservedWrapperTable, aKey, PL_DHASH_REMOVE);
|
||||
if (sPreservedWrapperTable.entryCount == 0) {
|
||||
PL_DHashTableFinish(&sPreservedWrapperTable);
|
||||
sPreservedWrapperTable.ops = nsnull;
|
||||
|
@ -5081,8 +5034,10 @@ MarkAllWrappers(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|||
MarkAllWrappersData *data = NS_STATIC_CAST(MarkAllWrappersData*, arg);
|
||||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*, hdr);
|
||||
|
||||
nsIXPConnectJSObjectHolder *wrapper;
|
||||
JSObject *wrapper_obj;
|
||||
if (NS_SUCCEEDED(entry->wrapper->GetJSObject(&wrapper_obj)))
|
||||
if ((wrapper = entry->keyToWrapperFunc(entry->key)) &&
|
||||
NS_SUCCEEDED(wrapper->GetJSObject(&wrapper_obj)))
|
||||
JS_MarkGCThing(data->cx, wrapper_obj,
|
||||
"nsDOMClassInfo::sPreservedWrapperTable_OOM", data->arg);
|
||||
|
||||
|
@ -5091,7 +5046,7 @@ MarkAllWrappers(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|||
|
||||
// static
|
||||
void
|
||||
nsDOMClassInfo::MarkReachablePreservedWrappers(nsIDOMNode *aDOMNode,
|
||||
nsDOMClassInfo::MarkReachablePreservedWrappers(nsIDOMGCParticipant *aParticipant,
|
||||
JSContext *cx, void *arg)
|
||||
{
|
||||
// Magic value indicating we've hit out-of-memory earlier in this GC.
|
||||
|
@ -5118,25 +5073,40 @@ nsDOMClassInfo::MarkReachablePreservedWrappers(nsIDOMNode *aDOMNode,
|
|||
return;
|
||||
}
|
||||
|
||||
nsIDOMGCParticipant *SCCIndex = aParticipant->GetSCCIndex();
|
||||
WrapperSCCEntry *entry = NS_STATIC_CAST(WrapperSCCEntry*,
|
||||
PL_DHashTableOperate(&sWrapperSCCTable, GetSCCRootFor(aDOMNode),
|
||||
PL_DHASH_LOOKUP));
|
||||
PL_DHashTableOperate(&sWrapperSCCTable, SCCIndex, PL_DHASH_LOOKUP));
|
||||
if (!PL_DHASH_ENTRY_IS_BUSY(entry) || entry->marked)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
||||
{
|
||||
nsAutoString nodeName;
|
||||
entry->key->GetNodeName(nodeName);
|
||||
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(entry->key);
|
||||
if (node)
|
||||
node->GetNodeName(nodeName);
|
||||
else
|
||||
nodeName.AssignLiteral("##not-node##");
|
||||
printf(" marking entries for SCC root %p \"%s\"\n",
|
||||
entry->key.get(), NS_ConvertUTF16toUTF8(nodeName).get());
|
||||
NS_STATIC_CAST(void*, entry->key.get()),
|
||||
NS_ConvertUTF16toUTF8(nodeName).get());
|
||||
}
|
||||
#endif
|
||||
entry->marked = PR_TRUE;
|
||||
|
||||
// Do the reachable list first to encourage shorter call stacks
|
||||
// (perhaps slightly less recursion through JS marking).
|
||||
nsCOMArray<nsIDOMGCParticipant> reachable;
|
||||
SCCIndex->AppendReachableList(reachable);
|
||||
for (PRInt32 i = 0, i_end = reachable.Count(); i < i_end; ++i) {
|
||||
MarkReachablePreservedWrappers(reachable[i], cx, arg);
|
||||
}
|
||||
|
||||
for (PreservedWrapperEntry *pwe = entry->first; pwe; pwe = pwe->next) {
|
||||
nsIXPConnectJSObjectHolder *wrapper;
|
||||
JSObject *wrapper_obj;
|
||||
if (NS_SUCCEEDED(pwe->wrapper->GetJSObject(&wrapper_obj)))
|
||||
if ((wrapper = pwe->keyToWrapperFunc(pwe->key)) &&
|
||||
NS_SUCCEEDED(wrapper->GetJSObject(&wrapper_obj)))
|
||||
::JS_MarkGCThing(cx, wrapper_obj,
|
||||
"nsDOMClassInfo::sPreservedWrapperTable", arg);
|
||||
}
|
||||
|
@ -5149,7 +5119,7 @@ ClassifyWrapper(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|||
PreservedWrapperEntry *entry = NS_STATIC_CAST(PreservedWrapperEntry*, hdr);
|
||||
|
||||
WrapperSCCEntry *SCCEntry = NS_STATIC_CAST(WrapperSCCEntry*,
|
||||
PL_DHashTableOperate(&sWrapperSCCTable, GetSCCRootFor(entry->key),
|
||||
PL_DHashTableOperate(&sWrapperSCCTable, entry->participant->GetSCCIndex(),
|
||||
PL_DHASH_ADD));
|
||||
if (!SCCEntry) {
|
||||
*NS_STATIC_CAST(PRBool*, arg) = PR_TRUE;
|
||||
|
@ -5159,9 +5129,14 @@ ClassifyWrapper(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
||||
if (!SCCEntry->first) {
|
||||
nsAutoString nodeName;
|
||||
SCCEntry->key->GetNodeName(nodeName);
|
||||
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(SCCEntry->key);
|
||||
if (node)
|
||||
node->GetNodeName(nodeName);
|
||||
else
|
||||
nodeName.AssignLiteral("##not-node##");
|
||||
printf(" new SCC root %p \"%s\"\n",
|
||||
SCCEntry->key.get(), NS_ConvertUTF16toUTF8(nodeName).get());
|
||||
NS_STATIC_CAST(void*, SCCEntry->key.get()),
|
||||
NS_ConvertUTF16toUTF8(nodeName).get());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -5178,7 +5153,7 @@ nsDOMClassInfo::BeginGCMark()
|
|||
NS_PRECONDITION(!sWrapperSCCTable.ops, "table already initialized");
|
||||
|
||||
#ifdef DEBUG_PRESERVE_WRAPPERS
|
||||
printf("\nClassifying preserved wrappers into SCCs:\n");
|
||||
printf("Classifying preserved wrappers into SCCs:\n");
|
||||
#endif
|
||||
|
||||
if (!PL_DHashTableInit(&sWrapperSCCTable, &sWrapperSCCTableOps, nsnull,
|
||||
|
@ -5213,11 +5188,11 @@ nsDOMClassInfo::EndGCMark()
|
|||
}
|
||||
}
|
||||
|
||||
// hack to give XBL access to nsDOMClassInfo::PreserveWrapper
|
||||
// hack to give XBL access to nsDOMClassInfo::PreserveNodeWrapper
|
||||
nsresult
|
||||
NS_DOMClassInfo_PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
|
||||
NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper)
|
||||
{
|
||||
return nsDOMClassInfo::PreserveWrapper(aWrapper);
|
||||
return nsDOMClassInfo::PreserveNodeWrapper(aWrapper);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -6007,7 +5982,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
|
||||
if (id == sDocument_id) {
|
||||
nsCOMPtr<nsIDOMDocument> document;
|
||||
nsresult rv = win->GetDocument(getter_AddRefs(document));
|
||||
rv = win->GetDocument(getter_AddRefs(document));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
jsval v;
|
||||
|
@ -6151,7 +6126,7 @@ nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
|
||||
sgo->OnFinalize(obj);
|
||||
|
||||
return NS_OK;
|
||||
return nsEventReceiverSH::Finalize(wrapper, cx, obj);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -6431,37 +6406,12 @@ nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
{
|
||||
// This can fail on out-of-memory, which should end up throwing a JS
|
||||
// exception.
|
||||
nsresult rv = nsDOMClassInfo::PreserveWrapper(wrapper);
|
||||
nsresult rv = nsDOMClassInfo::PreserveNodeWrapper(wrapper);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNodeSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj)
|
||||
{
|
||||
nsISupports *native = wrapper->Native();
|
||||
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(native));
|
||||
|
||||
nsDOMClassInfo::ReleaseWrapper(node);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNodeSH::Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, void *arg, PRUint32 *_retval)
|
||||
{
|
||||
nsISupports *native = wrapper->Native();
|
||||
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(native));
|
||||
|
||||
nsDOMClassInfo::MarkReachablePreservedWrappers(node, cx, arg);
|
||||
|
||||
*_retval = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNodeSH::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
|
@ -6587,7 +6537,6 @@ nsEventReceiverSH::AddEventListenerHelper(JSContext *cx, JSObject *obj,
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMNSEventTarget> eventTarget(do_QueryWrappedNative(wrapper,
|
||||
&rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -6604,7 +6553,6 @@ nsEventReceiverSH::AddEventListenerHelper(JSContext *cx, JSObject *obj,
|
|||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget(do_QueryWrappedNative(wrapper,
|
||||
&rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -6732,13 +6680,27 @@ nsEventReceiverSH::AddProperty(nsIXPConnectWrappedNative *wrapper,
|
|||
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
|
||||
}
|
||||
|
||||
/*
|
||||
NS_IMETHODIMP
|
||||
nsEventReceiverSH::OnFinalize(...)
|
||||
nsEventReceiverSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj)
|
||||
{
|
||||
clear event handlers in mListener...
|
||||
// XXX clear event handlers in mListener...
|
||||
|
||||
nsDOMClassInfo::ReleaseWrapper(wrapper);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventReceiverSH::Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, void *arg, PRUint32 *_retval)
|
||||
{
|
||||
nsCOMPtr<nsIDOMGCParticipant> participant(do_QueryWrappedNative(wrapper));
|
||||
|
||||
nsDOMClassInfo::MarkReachablePreservedWrappers(participant, cx, arg);
|
||||
|
||||
*_retval = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// Element helper
|
||||
|
@ -7411,8 +7373,8 @@ nsDocumentSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
jsval winVal;
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult rv = WrapNative(cx, obj, win, NS_GET_IID(nsIDOMWindow), &winVal,
|
||||
getter_AddRefs(holder));
|
||||
rv = WrapNative(cx, obj, win, NS_GET_IID(nsIDOMWindow), &winVal,
|
||||
getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_NAMED_LITERAL_STRING(doc_str, "document");
|
||||
|
|
|
@ -53,6 +53,7 @@ class nsIForm;
|
|||
class nsIDOMNode;
|
||||
class nsIDOMNodeList;
|
||||
class nsIDOMDocument;
|
||||
class nsIDOMGCParticipant;
|
||||
class nsIHTMLDocument;
|
||||
class nsGlobalWindow;
|
||||
|
||||
|
@ -174,22 +175,34 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* Note that the XPConnect wrapper should be preserved. This will only
|
||||
* preserve aWrapper if its native QIs to nsIDOMNode; otherwise it'll just
|
||||
* return NS_OK.
|
||||
* Note that the XPConnect wrapper should be protected from garbage
|
||||
* collection as long as the GC participant is reachable.
|
||||
*
|
||||
* A preservation with a given key overwrites any previous
|
||||
* preservation with that key.
|
||||
*/
|
||||
static nsresult PreserveWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
static nsresult PreserveWrapper(void* aKey,
|
||||
nsIXPConnectJSObjectHolder* (*aKeyToWrapperFunc)(void* aKey),
|
||||
nsIDOMGCParticipant *aParticipant);
|
||||
|
||||
|
||||
/**
|
||||
* Undoes the effects of any prior |PreserveWrapper| calls on
|
||||
* |aDOMNode|.
|
||||
* Easier way to call the above just for DOM nodes (and better, since
|
||||
* we get the performance benefits of having the same identity function).
|
||||
* The call to |PreserveWrapper| is made with |aKey| == |aWrapper|.
|
||||
*/
|
||||
static void ReleaseWrapper(nsIDOMNode *aDOMNode);
|
||||
static nsresult PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
|
||||
/**
|
||||
* Undoes the effects of any prior |PreserveWrapper| calls made with
|
||||
* |aKey|.
|
||||
*/
|
||||
static void ReleaseWrapper(void* aKey);
|
||||
|
||||
/**
|
||||
* Mark all preserved wrappers reachable from |aDOMNode| via DOM APIs.
|
||||
*/
|
||||
static void MarkReachablePreservedWrappers(nsIDOMNode *aDOMNode,
|
||||
static void MarkReachablePreservedWrappers(nsIDOMGCParticipant *aParticipant,
|
||||
JSContext *cx, void *arg);
|
||||
|
||||
/**
|
||||
|
@ -401,6 +414,10 @@ public:
|
|||
PRBool *_retval);
|
||||
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsval id, jsval *vp, PRBool *_retval);
|
||||
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj);
|
||||
NS_IMETHOD Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, void *arg, PRUint32 *_retval);
|
||||
};
|
||||
|
||||
|
||||
|
@ -541,10 +558,6 @@ public:
|
|||
JSObject *globalObj, JSObject **parentObj);
|
||||
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsval id, jsval *vp, PRBool *_retval);
|
||||
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj);
|
||||
NS_IMETHOD Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, void *arg, PRUint32 *_retval);
|
||||
NS_IMETHOD GetFlags(PRUint32 *aFlags);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
|
|
|
@ -488,6 +488,7 @@ NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
||||
|
@ -5163,6 +5164,8 @@ nsGlobalWindow::GetListenerManager(nsIEventListenerManager **aResult)
|
|||
|
||||
mListenerManager = do_CreateInstance(kEventListenerManagerCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mListenerManager->SetListenerTarget(
|
||||
NS_STATIC_CAST(nsIDOMEventReceiver*, this));
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = mListenerManager);
|
||||
|
@ -5187,6 +5190,37 @@ nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindow::nsIDOMGCParticipant
|
||||
//*****************************************************************************
|
||||
|
||||
nsIDOMGCParticipant*
|
||||
nsGlobalWindow::GetSCCIndex()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
static void AppendToReachableList(nsISupports *aObject,
|
||||
nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
nsCOMPtr<nsIDOMGCParticipant> p = do_QueryInterface(aObject);
|
||||
if (p)
|
||||
aArray.AppendObject(p);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
AppendToReachableList(mChromeEventHandler, aArray);
|
||||
AppendToReachableList(mDocument, aArray);
|
||||
// XXXldb Do we want this to go both ways?
|
||||
if (IsOuterWindow()) {
|
||||
AppendToReachableList(mInnerWindow, aArray);
|
||||
} else {
|
||||
AppendToReachableList(mOuterWindow, aArray);
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindow::nsPIDOMWindow
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
#include "nsSize.h"
|
||||
#include "mozFlushType.h"
|
||||
#include "prclist.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
|
||||
#define DEFAULT_HOME_PAGE "www.mozilla.org"
|
||||
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
|
||||
|
@ -134,6 +135,7 @@ class nsGlobalWindow : public nsPIDOMWindow,
|
|||
public nsIDOMJSWindow,
|
||||
public nsIScriptObjectPrincipal,
|
||||
public nsIDOMEventReceiver,
|
||||
public nsIDOMGCParticipant,
|
||||
public nsIDOM3EventTarget,
|
||||
public nsIDOMNSEventTarget,
|
||||
public nsIDOMViewCSS,
|
||||
|
@ -193,6 +195,10 @@ public:
|
|||
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
|
||||
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
|
||||
|
||||
// nsIDOMGCParticipant
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
||||
|
||||
// nsPIDOMWindow
|
||||
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
|
||||
virtual NS_HIDDEN_(nsresult) GetObjectProperty(const PRUnichar* aProperty,
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include "nsIAtom.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "jscntxt.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
|
||||
// For locale aware string methods
|
||||
#include "plstr.h"
|
||||
|
@ -87,6 +88,7 @@
|
|||
#include "nsILocaleService.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#include "jsgc.h" // for WAY_TOO_MUCH_GC, if defined for GC debugging
|
||||
|
@ -2145,12 +2147,10 @@ nsJSContext::ScriptExecuted()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_DOMClassInfo_PreserveWrapper(nsIXPConnectWrappedNative *aWrapper);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJSContext::PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
|
||||
{
|
||||
return NS_DOMClassInfo_PreserveWrapper(aWrapper);
|
||||
return nsDOMClassInfo::PreserveNodeWrapper(aWrapper);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Vidur Apparao <vidur@netscape.com>
|
||||
* L. David Baron <dbaron@mozillafoundation.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -54,6 +55,9 @@
|
|||
#include "nsIXPConnect.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsIDOMGCParticipant.h"
|
||||
#include "nsIWeakReference.h"
|
||||
|
||||
|
||||
JSBool
|
||||
|
@ -212,3 +216,94 @@ nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
|
|||
return GetScriptContextFromJSContext(aContext);
|
||||
}
|
||||
|
||||
#define MARKED_OBJECT_BIT (PRWord(1<<0))
|
||||
|
||||
void
|
||||
nsMarkedJSFunctionHolder_base::Set(nsISupports *aPotentialFunction,
|
||||
nsIDOMGCParticipant *aParticipant)
|
||||
{
|
||||
if (PRWord(mObject) & MARKED_OBJECT_BIT) {
|
||||
nsDOMClassInfo::ReleaseWrapper(this);
|
||||
}
|
||||
nsISupports *oldVal = (nsISupports*)(PRWord(mObject) & ~MARKED_OBJECT_BIT);
|
||||
if (!TryMarkedSet(aPotentialFunction, aParticipant)) {
|
||||
NS_ASSERTION((PRWord(aPotentialFunction) & MARKED_OBJECT_BIT) == 0,
|
||||
"low bit set");
|
||||
NS_IF_ADDREF(aPotentialFunction);
|
||||
mObject = aPotentialFunction;
|
||||
}
|
||||
NS_IF_RELEASE(oldVal);
|
||||
}
|
||||
|
||||
static nsIXPConnectJSObjectHolder* HolderToWrappedJS(void *aKey)
|
||||
{
|
||||
nsMarkedJSFunctionHolder_base *holder = NS_STATIC_CAST(
|
||||
nsMarkedJSFunctionHolder_base*, aKey);
|
||||
|
||||
NS_ASSERTION(PRWord(holder->mObject) & MARKED_OBJECT_BIT,
|
||||
"yikes, not a marked object");
|
||||
|
||||
nsIWeakReference* weakRef =
|
||||
(nsIWeakReference*)(PRWord(holder->mObject) & ~MARKED_OBJECT_BIT);
|
||||
|
||||
// This entire interface is a hack to avoid reference counting, so
|
||||
// this actually doesn't do any reference counting, and we don't leak
|
||||
// anything. This is needed so we don't add and remove GC roots in
|
||||
// the middle of GC.
|
||||
nsWeakRefToIXPConnectWrappedJS *result;
|
||||
if (NS_FAILED(CallQueryReferent(weakRef, &result)))
|
||||
result = nsnull;
|
||||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsMarkedJSFunctionHolder_base::TryMarkedSet(nsISupports *aPotentialFunction,
|
||||
nsIDOMGCParticipant *aParticipant)
|
||||
{
|
||||
NS_ENSURE_TRUE(aParticipant, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS =
|
||||
do_QueryInterface(aPotentialFunction);
|
||||
if (!wrappedJS) // a non-JS implementation
|
||||
return PR_FALSE;
|
||||
|
||||
nsresult rv =
|
||||
nsDOMClassInfo::PreserveWrapper(this, HolderToWrappedJS, aParticipant);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
nsIWeakReference* weakRef; // [STRONG]
|
||||
wrappedJS->GetWeakReference(&weakRef);
|
||||
NS_ENSURE_TRUE(weakRef, PR_FALSE);
|
||||
|
||||
NS_ASSERTION((PRWord(weakRef) & MARKED_OBJECT_BIT) == 0, "low bit set");
|
||||
mObject = (nsISupports*)(PRWord(weakRef) | MARKED_OBJECT_BIT);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
nsMarkedJSFunctionHolder_base::Get(REFNSIID aIID)
|
||||
{
|
||||
nsISupports *result;
|
||||
if (PRWord(mObject) & MARKED_OBJECT_BIT) {
|
||||
nsIWeakReference* weakRef =
|
||||
(nsIWeakReference*)(PRWord(mObject) & ~MARKED_OBJECT_BIT);
|
||||
nsresult rv =
|
||||
weakRef->QueryReferent(aIID, NS_REINTERPRET_CAST(void**, &result));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_NOTREACHED("GC preservation didn't work");
|
||||
result = nsnull;
|
||||
}
|
||||
} else {
|
||||
NS_IF_ADDREF(result = mObject);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsMarkedJSFunctionHolder_base::~nsMarkedJSFunctionHolder_base()
|
||||
{
|
||||
if (PRWord(mObject) & MARKED_OBJECT_BIT) {
|
||||
nsDOMClassInfo::ReleaseWrapper(this);
|
||||
}
|
||||
nsISupports *obj = (nsISupports*)(PRWord(mObject) & ~MARKED_OBJECT_BIT);
|
||||
NS_IF_RELEASE(obj);
|
||||
}
|
||||
|
|
|
@ -48,10 +48,13 @@
|
|||
#include "nsISupports.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIDOMEventListener;
|
||||
class nsIScriptContext;
|
||||
class nsIScriptGlobalObject;
|
||||
class nsIDOMGCParticipant;
|
||||
class nsIXPConnectJSObjectHolder;
|
||||
|
||||
class nsJSUtils
|
||||
{
|
||||
|
@ -102,4 +105,44 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* nsMarkedJSFunctionHolder<T> is used to store objects of XPCOM
|
||||
* interface T.
|
||||
*
|
||||
* If the object stored is an XPConnect wrapped JS object and the
|
||||
* wrapper can be preserved through nsDOMClassInfo, the holder will hold
|
||||
* a weak reference and preserve the object from garbage collection as
|
||||
* long as the garbage collector can reach |aParticipant|; once both
|
||||
* |aParticipant| and the object are unreachable it will be garbage
|
||||
* collected and the holder will hold null.
|
||||
*
|
||||
* Otherwise, it holds a strong reference.
|
||||
*/
|
||||
|
||||
class nsMarkedJSFunctionHolder_base
|
||||
{
|
||||
public:
|
||||
void Set(nsISupports *aPotentialFunction, nsIDOMGCParticipant *aParticipant);
|
||||
already_AddRefed<nsISupports> Get(REFNSIID aIID);
|
||||
|
||||
nsMarkedJSFunctionHolder_base() : mObject(nsnull) {}
|
||||
~nsMarkedJSFunctionHolder_base();
|
||||
|
||||
PRBool TryMarkedSet(nsISupports *aPotentialFunction, nsIDOMGCParticipant *aParticipant);
|
||||
|
||||
nsISupports *mObject;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class nsMarkedJSFunctionHolder : protected nsMarkedJSFunctionHolder_base
|
||||
{
|
||||
public:
|
||||
void Set(T *aPotentialFunction, nsIDOMGCParticipant *aParticipant) {
|
||||
nsMarkedJSFunctionHolder_base::Set(aPotentialFunction, aParticipant);
|
||||
}
|
||||
already_AddRefed<T> Get() {
|
||||
return already_AddRefed<T>(NS_STATIC_CAST(T*, nsMarkedJSFunctionHolder_base::Get(NS_GET_IID(T)).get()));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* nsJSUtils_h__ */
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsFocusController.h"
|
||||
#include "nsString.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
static NS_DEFINE_CID(kEventListenerManagerCID, NS_EVENTLISTENERMANAGER_CID);
|
||||
|
||||
|
@ -63,21 +64,30 @@ nsWindowRoot::nsWindowRoot(nsIDOMWindow* aWindow)
|
|||
nsFocusController::Create(getter_AddRefs(mFocusController));
|
||||
|
||||
nsCOMPtr<nsIDOMFocusListener> focusListener(do_QueryInterface(mFocusController));
|
||||
++mRefCnt;
|
||||
AddEventListener(NS_LITERAL_STRING("focus"), focusListener, PR_TRUE);
|
||||
AddEventListener(NS_LITERAL_STRING("blur"), focusListener, PR_TRUE);
|
||||
--mRefCnt;
|
||||
}
|
||||
|
||||
nsWindowRoot::~nsWindowRoot()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS6(nsWindowRoot,
|
||||
nsIDOMEventReceiver,
|
||||
nsIChromeEventHandler,
|
||||
nsPIWindowRoot,
|
||||
nsIDOMEventTarget,
|
||||
nsIDOM3EventTarget,
|
||||
nsIDOMNSEventTarget)
|
||||
NS_INTERFACE_MAP_BEGIN(nsWindowRoot)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventReceiver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WindowRoot) // XXX right name?
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsWindowRoot)
|
||||
NS_IMPL_RELEASE(nsWindowRoot)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowRoot::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture)
|
||||
|
@ -202,6 +212,8 @@ nsWindowRoot::GetListenerManager(nsIEventListenerManager** aResult)
|
|||
nsresult rv;
|
||||
mListenerManager = do_CreateInstance(kEventListenerManagerCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mListenerManager->SetListenerTarget(
|
||||
NS_STATIC_CAST(nsIDOMEventReceiver*, this));
|
||||
}
|
||||
|
||||
*aResult = mListenerManager;
|
||||
|
@ -283,6 +295,17 @@ nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, nsEvent* aEvent,
|
|||
return ret;
|
||||
}
|
||||
|
||||
nsIDOMGCParticipant*
|
||||
nsWindowRoot::GetSCCIndex()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowRoot::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowRoot::GetFocusController(nsIFocusController** aResult)
|
||||
{
|
||||
|
|
|
@ -80,6 +80,10 @@ public:
|
|||
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
|
||||
NS_IMETHOD GetSystemEventGroup(nsIDOMEventGroup** aGroup);
|
||||
|
||||
// nsIDOMGCParticipant
|
||||
virtual nsIDOMGCParticipant* GetSCCIndex();
|
||||
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
|
||||
|
||||
// nsPIWindowRoot
|
||||
NS_IMETHOD GetFocusController(nsIFocusController** aResult);
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "nsIInterfaceInfoManager.idl"
|
||||
#include "nsIExceptionService.idl"
|
||||
#include "nsIVariant.idl"
|
||||
#include "nsIWeakReference.idl"
|
||||
|
||||
%{ C++
|
||||
#include "jspubtd.h"
|
||||
|
@ -232,7 +233,7 @@ do_QueryWrappedNative(nsIXPConnectWrappedNative *aWrappedNative,
|
|||
|
||||
%}
|
||||
|
||||
[uuid(BED52030-BCA6-11d2-BA79-00805F8A5DD7)]
|
||||
[uuid(a052e197-7ba4-494e-b735-8786ac091164)]
|
||||
interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
|
||||
{
|
||||
/* attribute 'JSObject' inherited from nsIXPConnectJSObjectHolder */
|
||||
|
@ -243,6 +244,27 @@ interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
|
|||
|
||||
void aggregatedQueryInterface(in nsIIDRef uuid,
|
||||
[iid_is(uuid),retval] out nsQIResult result);
|
||||
|
||||
/* This method has the same signature and the same semantics as the
|
||||
* one method on nsISupportsWeakReference. However, it exists here
|
||||
* so that callers who need to manage JS garbage collection for
|
||||
* wrapped objects themselves can get a weak reference to the
|
||||
* wrapped JS object: in other words, it's for callers who know
|
||||
* that they're dealing with a wrapper, and want a weak reference to
|
||||
* the wrapper rather than the wrapped object.
|
||||
*/
|
||||
nsIWeakReference GetWeakReference();
|
||||
};
|
||||
|
||||
/**
|
||||
* This interface is a complete hack. It is used by the DOM code to
|
||||
* call QueryReferent on a weak reference to a wrapped JS object without
|
||||
* causing reference counting, which would add and remove GC roots
|
||||
* (which can't be done in the middle of GC).
|
||||
*/
|
||||
[uuid(3f32871c-d014-4f91-b358-3ece74cbebaa)]
|
||||
interface nsWeakRefToIXPConnectWrappedJS : nsIXPConnectWrappedJS
|
||||
{
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
|
|
@ -2201,7 +2201,7 @@ private:
|
|||
// interface on the single underlying (possibly aggregate) JSObject.
|
||||
|
||||
class nsXPCWrappedJS : public nsXPTCStubBase,
|
||||
public nsIXPConnectWrappedJS,
|
||||
public nsWeakRefToIXPConnectWrappedJS,
|
||||
public nsSupportsWeakReference,
|
||||
public nsIPropertyBag
|
||||
{
|
||||
|
@ -2209,7 +2209,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
|
||||
NS_DECL_NSIXPCONNECTWRAPPEDJS
|
||||
NS_DECL_NSISUPPORTSWEAKREFERENCE
|
||||
//NS_DECL_NSISUPPORTSWEAKREFERENCE // methods also on nsIXPConnectWrappedJS
|
||||
NS_DECL_NSIPROPERTYBAG
|
||||
|
||||
// Note that both nsXPTCStubBase and nsIXPConnectWrappedJS declare
|
||||
|
|
|
@ -88,6 +88,13 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// This interface is a hack that says "don't AddRef me".
|
||||
if(aIID.Equals(NS_GET_IID(nsWeakRefToIXPConnectWrappedJS)))
|
||||
{
|
||||
*aInstancePtr = NS_STATIC_CAST(nsWeakRefToIXPConnectWrappedJS*, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsISupports* outer = GetAggregatedNativeObject();
|
||||
if(outer)
|
||||
return outer->QueryInterface(aIID, aInstancePtr);
|
||||
|
@ -189,10 +196,7 @@ do_decrement:
|
|||
NS_IMETHODIMP
|
||||
nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
|
||||
{
|
||||
if(mRoot != this)
|
||||
return mRoot->GetWeakReference(aInstancePtr);
|
||||
|
||||
return nsSupportsWeakReference::GetWeakReference(aInstancePtr);
|
||||
return mRoot->nsSupportsWeakReference::GetWeakReference(aInstancePtr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -247,6 +247,10 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
|
|||
AUTO_MARK_JSVAL(ccx, fun);
|
||||
|
||||
// Ensure that we are asking for a scriptable interface.
|
||||
// NB: It's important for security that this check is here rather
|
||||
// than later, since it prevents untrusted objects from implementing
|
||||
// some interfaces in JS and aggregating a trusted object to
|
||||
// implement intentionally (for security) unscriptable interfaces.
|
||||
// We so often ask for nsISupports that we can short-circuit the test...
|
||||
if(!aIID.Equals(NS_GET_IID(nsISupports)))
|
||||
{
|
||||
|
|
|
@ -3315,7 +3315,9 @@ NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocumen
|
|||
}
|
||||
|
||||
//nsDocViewerFocusListener
|
||||
NS_IMPL_ISUPPORTS1(nsDocViewerFocusListener, nsIDOMFocusListener)
|
||||
NS_IMPL_ISUPPORTS2(nsDocViewerFocusListener,
|
||||
nsIDOMFocusListener,
|
||||
nsIDOMEventListener)
|
||||
|
||||
nsDocViewerFocusListener::nsDocViewerFocusListener()
|
||||
:mDocViewer(nsnull)
|
||||
|
|
Загрузка…
Ссылка в новой задаче