Add some debug members to XBL to catch cases where things are treated as

compiled when they're not and vice versa.  Bug 280089, r+sr=bryner
This commit is contained in:
bzbarsky%mit.edu 2005-02-06 20:34:15 +00:00
parent 48e7932308
commit 4be2dab6bb
6 changed files with 94 additions and 11 deletions

View File

@ -187,6 +187,12 @@ nsXBLProtoImpl::DestroyMembers(nsXBLProtoImplMember* aBrokenMember)
}
curr->Destroy(compiled);
}
// Now clear out mMembers so we don't try to call Destroy() on them again
delete mMembers;
mMembers = nsnull;
mConstructor = nsnull;
mDestructor = nsnull;
}
nsresult

View File

@ -84,11 +84,14 @@ protected:
public:
nsCString mClassName; // The name of the class.
protected:
void* mClassObject; // The class object for the binding. We'll use this to pre-compile properties
// and methods for the binding.
nsXBLProtoImplMember* mMembers; // The members of an implementation are chained in this singly-linked list.
public:
nsXBLProtoImplAnonymousMethod* mConstructor; // Our class constructor.
nsXBLProtoImplAnonymousMethod* mDestructor; // Our class destructor.
};

View File

@ -55,6 +55,9 @@ MOZ_DECL_CTOR_COUNTER(nsXBLProtoImplMethod)
nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
nsXBLProtoImplMember(aName),
mUncompiledMethod(nsnull)
#ifdef DEBUG
, mIsCompiled(PR_FALSE)
#endif
{
MOZ_COUNT_CTOR(nsXBLProtoImplMethod);
}
@ -67,6 +70,8 @@ nsXBLProtoImplMethod::~nsXBLProtoImplMethod()
void
nsXBLProtoImplMethod::Destroy(PRBool aIsCompiled)
{
NS_PRECONDITION(aIsCompiled == mIsCompiled,
"Incorrect aIsCompiled in nsXBLProtoImplMethod::Destroy");
if (aIsCompiled) {
if (mJSMethodObject)
RemoveJSGCRoot(&mJSMethodObject);
@ -81,6 +86,8 @@ nsXBLProtoImplMethod::Destroy(PRBool aIsCompiled)
void
nsXBLProtoImplMethod::AppendBodyText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing uncompiled method");
if (!mUncompiledMethod) {
mUncompiledMethod = new nsXBLUncompiledMethod();
if (!mUncompiledMethod)
@ -93,6 +100,8 @@ nsXBLProtoImplMethod::AppendBodyText(const nsAString& aText)
void
nsXBLProtoImplMethod::AddParameter(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing uncompiled method");
if (!mUncompiledMethod) {
mUncompiledMethod = new nsXBLUncompiledMethod();
if (!mUncompiledMethod)
@ -105,6 +114,8 @@ nsXBLProtoImplMethod::AddParameter(const nsAString& aText)
void
nsXBLProtoImplMethod::SetLineNumber(PRUint32 aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing uncompiled method");
if (!mUncompiledMethod) {
mUncompiledMethod = new nsXBLUncompiledMethod();
if (!mUncompiledMethod)
@ -121,6 +132,8 @@ nsXBLProtoImplMethod::InstallMember(nsIScriptContext* aContext,
void* aTargetClassObject,
const nsCString& aClassStr)
{
NS_PRECONDITION(mIsCompiled,
"Should not be installing an uncompiled method");
JSContext* cx = (JSContext*) aContext->GetNativeContext();
JSObject * scriptObject = (JSObject *) aScriptObject;
NS_ASSERTION(scriptObject, "uh-oh, script Object should NOT be null or bad things will happen");
@ -147,9 +160,16 @@ nsresult
nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
void* aClassObject)
{
if (!aClassObject)
return NS_OK; // Nothing to do.
NS_PRECONDITION(!mIsCompiled,
"Trying to compile an already-compiled method");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
#ifdef DEBUG
// We have some "ok" early returns after which we consider ourselves compiled
mIsCompiled = PR_TRUE;
#endif
// No parameters or body was supplied, so don't install method.
if (!mUncompiledMethod)
return NS_OK;
@ -168,6 +188,12 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
return NS_OK;
}
#ifdef DEBUG
// OK, now we have some error early returns that mean we're not
// really compiled...
mIsCompiled = PR_FALSE;
#endif
// We have a method.
// Allocate an array for our arguments.
PRInt32 paramCount = mUncompiledMethod->GetParameterCount();
@ -221,16 +247,25 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
// Root the compiled prototype script object.
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
aContext->GetNativeContext());
if (!cx) return NS_ERROR_UNEXPECTED;
AddJSGCRoot(&mJSMethodObject, "nsXBLProtoImplMethod::mJSMethodObject");
rv = cx ?
AddJSGCRoot(&mJSMethodObject, "nsXBLProtoImplMethod::mJSMethodObject") :
NS_ERROR_UNEXPECTED;
if (NS_FAILED(rv)) {
mJSMethodObject = nsnull;
}
}
return NS_OK;
#ifdef DEBUG
mIsCompiled = NS_SUCCEEDED(rv);
#endif
return rv;
}
nsresult
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{
NS_PRECONDITION(mIsCompiled, "Can't execute uncompiled method");
if (!mJSMethodObject) {
// Nothing to do here
return NS_OK;

View File

@ -138,6 +138,10 @@ protected:
nsXBLUncompiledMethod* mUncompiledMethod; // An object that represents the method before being compiled.
JSObject * mJSMethodObject; // The JS object for the method (after compilation)
};
#ifdef DEBUG
PRBool mIsCompiled;
#endif
};
class nsXBLProtoImplAnonymousMethod : public nsXBLProtoImplMethod {

View File

@ -56,6 +56,9 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
mGetterText(nsnull),
mSetterText(nsnull),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
, mIsCompiled(PR_FALSE)
#endif
{
MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
@ -79,6 +82,8 @@ nsXBLProtoImplProperty::~nsXBLProtoImplProperty()
void
nsXBLProtoImplProperty::Destroy(PRBool aIsCompiled)
{
NS_PRECONDITION(aIsCompiled == mIsCompiled,
"Incorrect aIsCompiled in nsXBLProtoImplProperty::Destroy");
if (aIsCompiled) {
if (mJSGetterObject)
RemoveJSGCRoot(&mJSGetterObject);
@ -96,6 +101,8 @@ nsXBLProtoImplProperty::Destroy(PRBool aIsCompiled)
void
nsXBLProtoImplProperty::AppendGetterText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing getter text");
if (!mGetterText) {
mGetterText = new nsXBLTextWithLineNumber();
if (!mGetterText)
@ -108,6 +115,8 @@ nsXBLProtoImplProperty::AppendGetterText(const nsAString& aText)
void
nsXBLProtoImplProperty::AppendSetterText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing setter text");
if (!mSetterText) {
mSetterText = new nsXBLTextWithLineNumber();
if (!mSetterText)
@ -118,7 +127,10 @@ nsXBLProtoImplProperty::AppendSetterText(const nsAString& aText)
}
void
nsXBLProtoImplProperty::SetGetterLineNumber(PRUint32 aLineNumber) {
nsXBLProtoImplProperty::SetGetterLineNumber(PRUint32 aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing getter text");
if (!mGetterText) {
mGetterText = new nsXBLTextWithLineNumber();
if (!mGetterText)
@ -129,7 +141,10 @@ nsXBLProtoImplProperty::SetGetterLineNumber(PRUint32 aLineNumber) {
}
void
nsXBLProtoImplProperty::SetSetterLineNumber(PRUint32 aLineNumber) {
nsXBLProtoImplProperty::SetSetterLineNumber(PRUint32 aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing setter text");
if (!mSetterText) {
mSetterText = new nsXBLTextWithLineNumber();
if (!mSetterText)
@ -148,6 +163,8 @@ nsXBLProtoImplProperty::InstallMember(nsIScriptContext* aContext,
void* aTargetClassObject,
const nsCString& aClassStr)
{
NS_PRECONDITION(mIsCompiled,
"Should not be installing an uncompiled property");
JSContext* cx = (JSContext*) aContext->GetNativeContext();
JSObject * scriptObject = (JSObject *) aScriptObject;
NS_ASSERTION(scriptObject, "uh-oh, script Object should NOT be null or bad things will happen");
@ -183,8 +200,10 @@ nsresult
nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
void* aClassObject)
{
if (!aClassObject)
return NS_OK; // Nothing to do.
NS_PRECONDITION(!mIsCompiled,
"Trying to compile an already-compiled property");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
if (!mName)
return NS_ERROR_FAILURE; // Without a valid name, we can't install the member.
@ -246,7 +265,15 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
mJSGetterObject = nsnull;
}
nsresult rvG=rv;
if (NS_FAILED(rv)) {
// We failed to compile our getter. So either we've set it to null, or
// it's still set to the text object. In either case, it's safe to return
// the error here, since then we'll be cleaned up as uncompiled and that
// will be ok. Going on and compiling the setter and _then_ returning an
// error, on the other hand, will try to clean up a compiled setter as
// uncompiled and crash.
return rv;
}
PRBool deletedSetter = PR_FALSE;
if (mSetterText) {
@ -292,6 +319,10 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
delete mSetterText;
mJSSetterObject = nsnull;
}
#ifdef DEBUG
mIsCompiled = NS_SUCCEEDED(rv);
#endif
return NS_SUCCEEDED(rv) ? rvG : rv;
return rv;
}

View File

@ -88,6 +88,10 @@ protected:
};
uintN mJSAttributes; // A flag for all our JS properties (getter/setter/readonly/shared/enum)
#ifdef DEBUG
PRBool mIsCompiled;
#endif
};
#endif // nsXBLProtoImplProperty_h__