Relanding bug 372769 with some cycle collection changes to fix leaks. r=mrbkap, sr=sicking, with r=sicking on the leak fixes.

This commit is contained in:
bzbarsky@mit.edu 2007-09-28 06:45:01 -07:00
Родитель 891792d05e
Коммит 8102578ca9
16 изменённых файлов: 374 добавлений и 144 удалений

Просмотреть файл

@ -111,6 +111,7 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../../xul/document/src \
-I$(srcdir)/../../events/src \
-I$(srcdir)/../../../layout/style \
-I$(srcdir)/../../../dom/src/base \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

Просмотреть файл

@ -102,27 +102,134 @@
#include "prprf.h"
#include "nsNodeUtils.h"
// Nasty hack. Maybe we could move some of the classinfo utility methods
// (e.g. WrapNative and ThrowJSException) over to nsContentUtils?
#include "nsDOMClassInfo.h"
#include "nsJSUtils.h"
// Helper classes
/***********************************************************************/
//
// The JS class for XBLBinding
//
PR_STATIC_CALLBACK(void)
JS_STATIC_DLL_CALLBACK(void)
XBLFinalize(JSContext *cx, JSObject *obj)
{
nsIXBLDocumentInfo* docInfo =
static_cast<nsIXBLDocumentInfo*>(::JS_GetPrivate(cx, obj));
NS_RELEASE(docInfo);
nsXBLJSClass* c = static_cast<nsXBLJSClass*>(::JS_GetClass(cx, obj));
c->Drop();
}
JS_STATIC_DLL_CALLBACK(JSBool)
XBLResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
// Note: if we get here, that means that the implementation for some binding
// was installed, which means that AllowScripts() tested true. Hence no need
// to do checks like that here.
// Default to not resolving things.
NS_ASSERTION(*objp, "Must have starting object");
JSObject* origObj = *objp;
*objp = NULL;
if (!JSVAL_IS_STRING(id)) {
return JS_TRUE;
}
nsDependentJSString fieldName(id);
jsval slotVal;
::JS_GetReservedSlot(cx, obj, 0, &slotVal);
NS_ASSERTION(!JSVAL_IS_VOID(slotVal), "How did that happen?");
nsXBLPrototypeBinding* protoBinding =
static_cast<nsXBLPrototypeBinding*>(JSVAL_TO_PRIVATE(slotVal));
NS_ASSERTION(protoBinding, "Must have prototype binding!");
nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
if (!field) {
return JS_TRUE;
}
// We have this field. Time to install it. Get our node.
JSClass* nodeClass = ::JS_GetClass(cx, origObj);
if (!nodeClass) {
return JS_FALSE;
}
if (~nodeClass->flags &
(JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
// Looks like whatever |origObj| is it's not our nsIContent. It might well
// be the proto our binding installed, however, so just baul out quietly.
// Do NOT throw an exception here.
// We could make this stricter by checking the class maybe, but whatever
return JS_TRUE;
}
nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
do_QueryInterface(static_cast<nsISupports*>(::JS_GetPrivate(cx, origObj)));
if (!xpcWrapper) {
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_UNEXPECTED);
return JS_FALSE;
}
nsCOMPtr<nsIContent> content = do_QueryWrappedNative(xpcWrapper);
if (!content) {
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_UNEXPECTED);
return JS_FALSE;
}
// This mirrors code in nsXBLProtoImpl::InstallImplementation
nsIDocument* doc = content->GetOwnerDoc();
if (!doc) {
return JS_TRUE;
}
nsIScriptGlobalObject* global = doc->GetScriptGlobalObject();
if (!global) {
return JS_TRUE;
}
nsCOMPtr<nsIScriptContext> context = global->GetContext();
if (!context) {
return JS_TRUE;
}
// Now we either resolve or fail
*objp = origObj;
nsresult rv = field->InstallField(context, origObj,
protoBinding->DocURI());
if (NS_FAILED(rv)) {
if (!::JS_IsExceptionPending(cx)) {
nsDOMClassInfo::ThrowJSException(cx, rv);
}
return JS_FALSE;
}
return JS_TRUE;
}
nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName)
{
memset(this, 0, sizeof(nsXBLJSClass));
next = prev = static_cast<JSCList*>(this);
name = ToNewCString(aClassName);
flags =
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
JSCLASS_NEW_RESOLVE | JSCLASS_NEW_RESOLVE_GETS_START |
// Our one reserved slot holds the relevant nsXBLPrototypeBinding
JSCLASS_HAS_RESERVED_SLOTS(1);
addProperty = delProperty = setProperty = getProperty = ::JS_PropertyStub;
enumerate = ::JS_EnumerateStub;
resolve = ::JS_ResolveStub;
resolve = (JSResolveOp)XBLResolve;
convert = ::JS_ConvertStub;
finalize = XBLFinalize;
}
@ -1034,6 +1141,7 @@ nsXBLBinding::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData)
nsresult
nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,
nsXBLPrototypeBinding* aProtoBinding,
void **aClassObject)
{
// First ensure our JS class is initialized.
@ -1139,6 +1247,20 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
return NS_ERROR_OUT_OF_MEMORY;
}
// Keep this proto binding alive while we're alive. Do this first so that
// we can guarantee that in XBLFinalize this will be non-null.
nsIXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
::JS_SetPrivate(cx, proto, docInfo);
NS_ADDREF(docInfo);
if (!::JS_SetReservedSlot(cx, proto, 0, PRIVATE_TO_JSVAL(aProtoBinding))) {
(nsXBLService::gClassTable)->Remove(&key);
// |c| will get dropped when |proto| is finalized
return NS_ERROR_OUT_OF_MEMORY;
}
*aClassObject = (void*)proto;
}
else {
@ -1155,63 +1277,6 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
return NS_OK;
}
nsresult
nsXBLBinding::InitClass(const nsCString& aClassName,
nsIScriptContext* aContext,
nsIDocument* aDocument, void** aScriptObject,
void** aClassObject)
{
*aClassObject = nsnull;
*aScriptObject = nsnull;
nsresult rv;
// Obtain the bound element's current script object.
JSContext* cx = (JSContext*)aContext->GetNativeContext();
nsIDocument *ownerDoc = mBoundElement->GetOwnerDoc();
nsIScriptGlobalObject *sgo;
if (!ownerDoc || !(sgo = ownerDoc->GetScriptGlobalObject())) {
NS_ERROR("Can't find global object for bound content!");
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
rv = nsContentUtils::XPConnect()->WrapNative(cx, sgo->GetGlobalJSObject(),
mBoundElement,
NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
JSObject* object = nsnull;
rv = wrapper->GetJSObject(&object);
NS_ENSURE_SUCCESS(rv, rv);
*aScriptObject = object;
// First ensure our JS class is initialized.
rv = DoInitJSClass(cx, sgo->GetGlobalJSObject(), object, aClassName,
aClassObject);
NS_ENSURE_SUCCESS(rv, rv);
// Root mBoundElement so that it doesn't lose it's binding
nsIDocument* doc = mBoundElement->GetOwnerDoc();
if (doc) {
nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper =
do_QueryInterface(wrapper);
if (native_wrapper) {
doc->AddReference(mBoundElement, native_wrapper);
}
}
return NS_OK;
}
PRBool
nsXBLBinding::AllowScripts()
{
@ -1344,6 +1409,20 @@ nsXBLBinding::GetFirstStyleBinding()
return mNextBinding ? mNextBinding->GetFirstStyleBinding() : nsnull;
}
PRBool
nsXBLBinding::ResolveAllFields(JSContext *cx, JSObject *obj) const
{
if (!mPrototypeBinding->ResolveAllFields(cx, obj)) {
return PR_FALSE;
}
if (mNextBinding) {
return mNextBinding->ResolveAllFields(cx, obj);
}
return PR_TRUE;
}
void
nsXBLBinding::MarkForDeath()
{

Просмотреть файл

@ -132,6 +132,10 @@ public:
nsXBLBinding* RootBinding();
nsXBLBinding* GetFirstStyleBinding();
// Resolve all the fields for this binding and all ancestor bindings on the
// object |obj|. False return means a JS exception was set.
PRBool ResolveAllFields(JSContext *cx, JSObject *obj) const;
// Get the list of insertion points for aParent. The nsInsertionPointList
// is owned by the binding, you should not delete it.
nsresult GetInsertionPointsFor(nsIContent* aParent,
@ -155,16 +159,11 @@ public:
static nsresult DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,
nsXBLPrototypeBinding* aProtoBinding,
void **aClassObject);
PRBool AllowScripts(); // XXX make const
// Internal member functions
protected:
nsresult InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
nsIDocument* aDocument, void** aScriptObject,
void** aClassObject);
// MEMBER VARIABLES
protected:
nsAutoRefCnt mRefCnt;

Просмотреть файл

@ -83,12 +83,13 @@ nsXBLContentSink::nsXBLContentSink()
: mState(eXBL_InDocument),
mSecondaryState(eXBL_None),
mDocInfo(nsnull),
mFoundFirstBinding(PR_FALSE),
mIsChromeOrResource(PR_FALSE),
mFoundFirstBinding(PR_FALSE),
mBinding(nsnull),
mHandler(nsnull),
mImplementation(nsnull),
mImplMember(nsnull),
mImplField(nsnull),
mProperty(nsnull),
mMethod(nsnull),
mField(nsnull)
@ -263,6 +264,18 @@ nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember)
mImplMember = aMember; // Adjust our pointer to point to the new last member in the chain.
}
void
nsXBLContentSink::AddField(nsXBLProtoImplField* aField)
{
// Add this field to our chain.
if (mImplField)
mImplField->SetNext(aField); // Already have a chain. Just append to the end.
else
mImplementation->SetFieldList(aField); // We're the first member in the chain.
mImplField = aField; // Adjust our pointer to point to the new last field in the chain.
}
NS_IMETHODIMP
nsXBLContentSink::HandleStartElement(const PRUnichar *aName,
const PRUnichar **aAtts,
@ -703,7 +716,8 @@ nsXBLContentSink::ConstructImplementation(const PRUnichar **aAtts)
{
mImplementation = nsnull;
mImplMember = nsnull;
mImplField = nsnull;
if (!mBinding)
return;
@ -777,7 +791,7 @@ nsXBLContentSink::ConstructField(const PRUnichar **aAtts, PRUint32 aLineNumber)
mField = new nsXBLProtoImplField(name, readonly);
if (mField) {
mField->SetLineNumber(aLineNumber);
AddMember(mField);
AddField(mField);
}
}
}

Просмотреть файл

@ -157,6 +157,7 @@ protected:
nsresult ReportUnexpectedElement(nsIAtom* aElementName, PRUint32 aLineNumber);
void AddMember(nsXBLProtoImplMember* aMember);
void AddField(nsXBLProtoImplField* aField);
XBLPrimaryState mState;
XBLSecondaryState mSecondaryState;
@ -168,6 +169,7 @@ protected:
nsXBLPrototypeHandler* mHandler; // current handler, owned by its PrototypeBinding
nsXBLProtoImpl* mImplementation;
nsXBLProtoImplMember* mImplMember;
nsXBLProtoImplField* mImplField;
nsXBLProtoImplProperty* mProperty;
nsXBLProtoImplMethod* mMethod;
nsXBLProtoImplField* mField;

Просмотреть файл

@ -409,6 +409,8 @@ nsXBLDocGlobalObject::GetPrincipal()
{
nsresult rv = NS_OK;
if (!mGlobalObjectOwner) {
// XXXbz this should really save the principal when
// ClearGlobalObjectOwner() happens.
return nsnull;
}
@ -442,8 +444,19 @@ TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
return kHashEnumerateNext;
}
static PRIntn PR_CALLBACK
UnlinkProtos(nsHashKey *aKey, void *aData, void* aClosure)
{
nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
proto->Unlink();
return kHashEnumerateNext;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
if (tmp->mBindingTable) {
tmp->mBindingTable->Enumerate(UnlinkProtos, nsnull);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObject)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

Просмотреть файл

@ -47,6 +47,7 @@
#include "nsIServiceManager.h"
#include "nsIXBLDocumentInfo.h"
#include "nsIDOMNode.h"
#include "nsXBLPrototypeBinding.h"
nsresult
nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement)
@ -55,7 +56,7 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIConten
// this prototype implementation as a guide. The prototype implementation is compiled lazily,
// so for the first bound element that needs a concrete implementation, we also build the
// prototype implementation.
if (!mMembers) // Constructor and destructor also live in mMembers
if (!mMembers && !mFields) // Constructor and destructor also live in mMembers
return NS_OK; // Nothing to do, so let's not waste time.
// If the way this gets the script context changes, fix
@ -214,6 +215,45 @@ nsXBLProtoImpl::Traverse(nsCycleCollectionTraversalCallback &cb) const
}
}
void
nsXBLProtoImpl::Unlink()
{
if (mClassObject) {
DestroyMembers(nsnull);
}
}
nsXBLProtoImplField*
nsXBLProtoImpl::FindField(const nsString& aFieldName) const
{
for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
if (aFieldName.Equals(f->GetName())) {
return f;
}
}
return nsnull;
}
PRBool
nsXBLProtoImpl::ResolveAllFields(JSContext *cx, JSObject *obj) const
{
for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
// Using OBJ_LOOKUP_PROPERTY is a pain, since what we have is a
// PRUnichar* for the property name. Let's just use the public API and
// all.
nsDependentString name(f->GetName());
jsval dummy;
if (!::JS_LookupUCProperty(cx, obj,
reinterpret_cast<const jschar*>(name.get()),
name.Length(), &dummy)) {
return PR_FALSE;
}
}
return PR_TRUE;
}
void
nsXBLProtoImpl::DestroyMembers(nsXBLProtoImplMember* aBrokenMember)
{

Просмотреть файл

@ -42,9 +42,11 @@
#include "nsMemory.h"
#include "nsXBLPrototypeHandler.h"
#include "nsXBLProtoImplMember.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLProtoImplField.h"
class nsIXPConnectJSObjectHolder;
class nsXBLPrototypeBinding;
class nsXBLProtoImplAnonymousMethod;
class nsXBLProtoImpl
{
@ -52,6 +54,7 @@ public:
nsXBLProtoImpl()
: mClassObject(nsnull),
mMembers(nsnull),
mFields(nsnull),
mConstructor(nsnull),
mDestructor(nsnull)
{
@ -64,7 +67,8 @@ public:
// clean them up automatically.
for (nsXBLProtoImplMember* curr = mMembers; curr; curr=curr->GetNext())
curr->Destroy(mClassObject != nsnull);
delete mMembers;
delete mMembers;
delete mFields;
}
nsresult InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement);
@ -74,9 +78,26 @@ public:
void** aTargetClassObject);
nsresult CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding);
void SetMemberList(nsXBLProtoImplMember* aMemberList) { delete mMembers; mMembers = aMemberList; }
void SetMemberList(nsXBLProtoImplMember* aMemberList)
{
delete mMembers;
mMembers = aMemberList;
}
void SetFieldList(nsXBLProtoImplField* aFieldList)
{
delete mFields;
mFields = aFieldList;
}
void Traverse(nsCycleCollectionTraversalCallback &cb) const;
void Unlink();
nsXBLProtoImplField* FindField(const nsString& aFieldName) const;
// Resolve all the fields for this implementation on the object |obj| False
// return means a JS exception was set.
PRBool ResolveAllFields(JSContext *cx, JSObject *obj) const;
protected:
// Function to call if compilation of a member fails. When this is called,
@ -93,6 +114,8 @@ protected:
// and methods for the binding.
nsXBLProtoImplMember* mMembers; // The members of an implementation are chained in this singly-linked list.
nsXBLProtoImplField* mFields; // Our fields
public:
nsXBLProtoImplAnonymousMethod* mConstructor; // Our class constructor.

Просмотреть файл

@ -46,14 +46,17 @@
#include "nsXBLProtoImplField.h"
#include "nsIScriptContext.h"
#include "nsContentUtils.h"
#include "nsIURI.h"
nsXBLProtoImplField::nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar* aReadOnly)
: nsXBLProtoImplMember(aName),
: mNext(nsnull),
mFieldText(nsnull),
mFieldTextLength(0),
mLineNumber(0)
{
MOZ_COUNT_CTOR(nsXBLProtoImplField);
mName = NS_strdup(aName); // XXXbz make more sense to use a stringbuffer?
mJSAttributes = JSPROP_ENUMERATE;
if (aReadOnly) {
nsAutoString readOnly; readOnly.Assign(*aReadOnly);
@ -67,11 +70,8 @@ nsXBLProtoImplField::~nsXBLProtoImplField()
MOZ_COUNT_DTOR(nsXBLProtoImplField);
if (mFieldText)
nsMemory::Free(mFieldText);
}
void
nsXBLProtoImplField::Destroy(PRBool aIsCompiled)
{
NS_Free(mName);
delete mNext;
}
void
@ -92,27 +92,15 @@ nsXBLProtoImplField::AppendFieldText(const nsAString& aText)
}
nsresult
nsXBLProtoImplField::InstallMember(nsIScriptContext* aContext,
nsIContent* aBoundElement,
void* aScriptObject,
void* aTargetClassObject,
const nsCString& aClassStr)
nsXBLProtoImplField::InstallField(nsIScriptContext* aContext,
JSObject* aBoundNode,
nsIURI* aBindingDocURI) const
{
if (mFieldTextLength == 0)
return NS_OK; // nothing to do.
NS_PRECONDITION(aBoundNode,
"uh-oh, bound node should NOT be null or bad things will "
"happen");
JSContext* cx = (JSContext*) aContext->GetNativeContext();
NS_ASSERTION(aScriptObject, "uh-oh, script Object should NOT be null or bad things will happen");
if (!aScriptObject)
return NS_ERROR_FAILURE;
nsCAutoString bindingURI(aClassStr);
PRInt32 hash = bindingURI.RFindChar('#');
if (hash != kNotFound)
bindingURI.Truncate(hash);
// compile the literal string
jsval result = JSVAL_NULL;
jsval result = JSVAL_VOID;
// EvaluateStringWithValue and JS_DefineUCProperty can both trigger GC, so
// protect |result| here.
@ -120,39 +108,40 @@ nsXBLProtoImplField::InstallMember(nsIScriptContext* aContext,
nsAutoGCRoot root(&result, &rv);
if (NS_FAILED(rv))
return rv;
PRBool undefined;
// XXX Need a URI here!
nsCOMPtr<nsIScriptContext> context = aContext;
rv = context->EvaluateStringWithValue(nsDependentString(mFieldText,
mFieldTextLength),
aScriptObject,
nsnull, bindingURI.get(),
mLineNumber, nsnull,
(void*) &result, &undefined);
if (NS_FAILED(rv))
return rv;
if (!undefined) {
// Define the evaluated result as a JS property
nsDependentString name(mName);
JSAutoRequest ar(cx);
if (!::JS_DefineUCProperty(cx, static_cast<JSObject *>(aScriptObject),
reinterpret_cast<const jschar*>(mName),
name.Length(), result, nsnull, nsnull, mJSAttributes))
return NS_ERROR_OUT_OF_MEMORY;
if (mFieldTextLength != 0) {
nsCAutoString uriSpec;
aBindingDocURI->GetSpec(uriSpec);
// compile the literal string
// XXX Could we produce a better principal here? Should be able
// to, really!
PRBool undefined;
nsCOMPtr<nsIScriptContext> context = aContext;
rv = context->EvaluateStringWithValue(nsDependentString(mFieldText,
mFieldTextLength),
aBoundNode,
nsnull, uriSpec.get(),
mLineNumber, nsnull,
(void*) &result, &undefined);
if (NS_FAILED(rv))
return rv;
if (undefined) {
result = JSVAL_VOID;
}
}
// Define the evaluated result as a JS property
nsDependentString name(mName);
JSContext* cx = (JSContext*) aContext->GetNativeContext();
JSAutoRequest ar(cx);
if (!::JS_DefineUCProperty(cx, aBoundNode,
reinterpret_cast<const jschar*>(mName),
name.Length(), result, nsnull, nsnull,
mJSAttributes)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult
nsXBLProtoImplField::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
void* aClassObject)
{
return NS_OK;
}
void
nsXBLProtoImplField::Traverse(nsCycleCollectionTraversalCallback &cb) const
{
}

Просмотреть файл

@ -46,30 +46,31 @@
#include "nsString.h"
#include "nsXBLProtoImplMember.h"
class nsXBLProtoImplField: public nsXBLProtoImplMember
class nsIURI;
class nsXBLProtoImplField
{
public:
nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar* aReadOnly);
virtual ~nsXBLProtoImplField();
virtual void Destroy(PRBool aIsCompiled);
~nsXBLProtoImplField();
void AppendFieldText(const nsAString& aText);
void SetLineNumber(PRUint32 aLineNumber) {
mLineNumber = aLineNumber;
}
virtual nsresult InstallMember(nsIScriptContext* aContext,
nsIContent* aBoundElement,
void* aScriptObject,
void* aTargetClassObject,
const nsCString& aClassStr);
virtual nsresult CompileMember(nsIScriptContext* aContext,
const nsCString& aClassStr,
void* aClassObject);
nsXBLProtoImplField* GetNext() const { return mNext; }
void SetNext(nsXBLProtoImplField* aNext) { mNext = aNext; }
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const;
nsresult InstallField(nsIScriptContext* aContext,
JSObject* aBoundNode, nsIURI*
aBindingDocURI) const;
const PRUnichar* GetName() const { return mName; }
protected:
nsXBLProtoImplField* mNext;
PRUnichar* mName;
PRUnichar* mFieldText;
PRUint32 mFieldTextLength;
PRUint32 mLineNumber;

Просмотреть файл

@ -365,6 +365,25 @@ nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
mInterfaceTable->Enumerate(TraverseBinding, &cb);
}
void
nsXBLPrototypeBinding::Unlink()
{
mBinding = nsnull;
if (mImplementation)
mImplementation->Unlink();
if (mResources)
NS_IF_RELEASE(mResources->mLoader);
// I'm not sure whether it would be safer to just nuke the tables or to
// traverse them with unlinking functions... or whether we even need to
// unlink them. I think we need to at least clean up mInsertionPointTable
// becase it can hold strong refs to nodes in the binding document.
delete mInsertionPointTable;
mInsertionPointTable = nsnull;
delete mInterfaceTable;
mInterfaceTable = nsnull;
}
void
nsXBLPrototypeBinding::Initialize()
{
@ -822,7 +841,7 @@ nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
*aClassObject = nsnull;
return nsXBLBinding::DoInitJSClass(aContext, aGlobal, aScriptObject,
aClassName, aClassObject);
aClassName, this, aClassObject);
}
nsIContent*

Просмотреть файл

@ -50,6 +50,7 @@
#include "nsHashtable.h"
#include "nsIXBLDocumentInfo.h"
#include "nsCOMArray.h"
#include "nsXBLProtoImpl.h"
class nsIAtom;
class nsIDocument;
@ -58,7 +59,7 @@ class nsISupportsArray;
class nsSupportsHashtable;
class nsIXBLService;
class nsFixedSizeAllocator;
class nsXBLProtoImpl;
class nsXBLProtoImplField;
class nsXBLBinding;
// *********************************************************************/
@ -94,6 +95,22 @@ public:
nsXBLProtoImplAnonymousMethod* GetDestructor();
nsresult SetDestructor(nsXBLProtoImplAnonymousMethod* aDestructor);
nsXBLProtoImplField* FindField(const nsString& aFieldName) const
{
return mImplementation ? mImplementation->FindField(aFieldName) : nsnull;
}
// Resolve all the fields for this binding on the object |obj|.
// False return means a JS exception was set.
PRBool ResolveAllFields(JSContext* cx, JSObject* obj) const
{
return !mImplementation || mImplementation->ResolveAllFields(cx, obj);
}
const nsCString& ClassName() const {
return mImplementation ? mImplementation->mClassName : EmptyCString();
}
nsresult InitClass(const nsCString& aClassName, JSContext * aContext,
JSObject * aGlobal, JSObject * aScriptObject,
void ** aClassObject);
@ -172,6 +189,7 @@ public:
nsIContent* aElement);
void Traverse(nsCycleCollectionTraversalCallback &cb) const;
void Unlink();
// Static members
static PRUint32 gRefCnt;

Просмотреть файл

@ -60,7 +60,9 @@
#include "nsContentUtils.h"
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLResourceLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXBLResourceLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLResourceLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mBoundElements)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLResourceLoader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mBoundElements)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

Просмотреть файл

@ -50,6 +50,7 @@ _TEST_FILES = \
test_bug296375.xul \
test_bug366770.html \
test_bug371724.xhtml \
test_bug372769.xhtml \
$(NULL)
libs:: $(_TEST_FILES)

Просмотреть файл

@ -477,7 +477,8 @@ static const char kDOMStringBundleURL[] =
// possible.
#define ELEMENT_SCRIPTABLE_FLAGS \
(NODE_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY)
((NODE_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY) | \
nsIXPCScriptable::WANT_ENUMERATE)
#define EXTERNAL_OBJ_SCRIPTABLE_FLAGS \
(ELEMENT_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \
@ -6940,6 +6941,32 @@ nsElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_OK;
}
NS_IMETHODIMP
nsElementSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRBool *_retval)
{
// Make sure to not call the superclass here!
nsCOMPtr<nsIContent> content(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
nsIDocument* doc = content->GetOwnerDoc();
if (!doc) {
// Nothing else to do here
return NS_OK;
}
nsXBLBinding* binding = doc->BindingManager()->GetBinding(content);
if (!binding) {
// Nothing else to do here
return NS_OK;
}
*_retval = binding->ResolveAllFields(cx, obj);
return NS_OK;
}
// Generic array scriptable helper.
NS_IMETHODIMP

Просмотреть файл

@ -563,6 +563,8 @@ protected:
public:
NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRBool *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{