mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
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:
parent
48e7932308
commit
4be2dab6bb
@ -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
|
||||
|
@ -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.
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__
|
||||
|
Loading…
Reference in New Issue
Block a user