Fix for bug 415028 (Startup assertions and crash compiling proto properties with gczeal == 2). r/sr=bz.

This commit is contained in:
peterv@propagandism.org 2008-02-12 08:02:41 -08:00
Родитель e4f9cdb8e2
Коммит 5675270420
7 изменённых файлов: 79 добавлений и 115 удалений

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

@ -192,7 +192,7 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding)
curr = curr->GetNext()) { curr = curr->GetNext()) {
nsresult rv = curr->CompileMember(context, mClassName, mClassObject); nsresult rv = curr->CompileMember(context, mClassName, mClassObject);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
DestroyMembers(curr); DestroyMembers();
return rv; return rv;
} }
} }
@ -219,7 +219,7 @@ void
nsXBLProtoImpl::UnlinkJSObjects() nsXBLProtoImpl::UnlinkJSObjects()
{ {
if (mClassObject) { if (mClassObject) {
DestroyMembers(nsnull); DestroyMembers();
} }
} }
@ -272,18 +272,10 @@ nsXBLProtoImpl::UndefineFields(JSContext *cx, JSObject *obj) const
} }
void void
nsXBLProtoImpl::DestroyMembers(nsXBLProtoImplMember* aBrokenMember) nsXBLProtoImpl::DestroyMembers()
{ {
NS_ASSERTION(mClassObject, "This should never be called when there is no class object"); NS_ASSERTION(mClassObject, "This should never be called when there is no class object");
PRBool compiled = PR_TRUE;
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
if (curr == aBrokenMember) {
compiled = PR_FALSE;
}
curr->Destroy(compiled);
}
// Now clear out mMembers so we don't try to call Destroy() on them again
delete mMembers; delete mMembers;
mMembers = nsnull; mMembers = nsnull;
mConstructor = nsnull; mConstructor = nsnull;

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

@ -65,8 +65,6 @@ public:
MOZ_COUNT_DTOR(nsXBLProtoImpl); MOZ_COUNT_DTOR(nsXBLProtoImpl);
// Note: the constructor and destructor are in mMembers, so we'll // Note: the constructor and destructor are in mMembers, so we'll
// clean them up automatically. // clean them up automatically.
for (nsXBLProtoImplMember* curr = mMembers; curr; curr=curr->GetNext())
curr->Destroy(mClassObject != nsnull);
delete mMembers; delete mMembers;
delete mFields; delete mFields;
} }
@ -108,11 +106,7 @@ public:
} }
protected: protected:
// Function to call if compilation of a member fails. When this is called, void DestroyMembers();
// all members before aBrokenMember are compiled, compilation of
// aBrokenMember failed, and members after aBrokenMember are uncompiled.
// This function assumes that aBrokenMember is _not_ compiled.
void DestroyMembers(nsXBLProtoImplMember* aBrokenMember);
public: public:
nsCString mClassName; // The name of the class. nsCString mClassName; // The name of the class.

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

@ -100,7 +100,6 @@ class nsXBLProtoImplMember
public: public:
nsXBLProtoImplMember(const PRUnichar* aName) :mNext(nsnull) { mName = ToNewUnicode(nsDependentString(aName)); } nsXBLProtoImplMember(const PRUnichar* aName) :mNext(nsnull) { mName = ToNewUnicode(nsDependentString(aName)); }
virtual ~nsXBLProtoImplMember() { nsMemory::Free(mName); delete mNext; } virtual ~nsXBLProtoImplMember() { nsMemory::Free(mName); delete mNext; }
virtual void Destroy(PRBool aIsCompiled)=0;
nsXBLProtoImplMember* GetNext() { return mNext; } nsXBLProtoImplMember* GetNext() { return mNext; }
void SetNext(nsXBLProtoImplMember* aNext) { mNext = aNext; } void SetNext(nsXBLProtoImplMember* aNext) { mNext = aNext; }

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

@ -53,10 +53,7 @@
nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) : nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
nsXBLProtoImplMember(aName), nsXBLProtoImplMember(aName),
mUncompiledMethod(nsnull) mUncompiledMethod(BIT_UNCOMPILED)
#ifdef DEBUG
, mIsCompiled(PR_FALSE)
#endif
{ {
MOZ_COUNT_CTOR(nsXBLProtoImplMethod); MOZ_COUNT_CTOR(nsXBLProtoImplMethod);
} }
@ -64,62 +61,61 @@ nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
nsXBLProtoImplMethod::~nsXBLProtoImplMethod() nsXBLProtoImplMethod::~nsXBLProtoImplMethod()
{ {
MOZ_COUNT_DTOR(nsXBLProtoImplMethod); MOZ_COUNT_DTOR(nsXBLProtoImplMethod);
}
void if (!IsCompiled()) {
nsXBLProtoImplMethod::Destroy(PRBool aIsCompiled) delete GetUncompiledMethod();
{
NS_PRECONDITION(aIsCompiled == mIsCompiled,
"Incorrect aIsCompiled in nsXBLProtoImplMethod::Destroy");
if (aIsCompiled) {
mJSMethodObject = nsnull;
}
else {
delete mUncompiledMethod;
mUncompiledMethod = nsnull;
} }
} }
void void
nsXBLProtoImplMethod::AppendBodyText(const nsAString& aText) nsXBLProtoImplMethod::AppendBodyText(const nsAString& aText)
{ {
NS_PRECONDITION(!mIsCompiled, NS_PRECONDITION(!IsCompiled(),
"Must not be compiled when accessing uncompiled method"); "Must not be compiled when accessing uncompiled method");
if (!mUncompiledMethod) {
mUncompiledMethod = new nsXBLUncompiledMethod(); nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
if (!mUncompiledMethod) if (!uncompiledMethod) {
uncompiledMethod = new nsXBLUncompiledMethod();
if (!uncompiledMethod)
return; return;
SetUncompiledMethod(uncompiledMethod);
} }
mUncompiledMethod->AppendBodyText(aText); uncompiledMethod->AppendBodyText(aText);
} }
void void
nsXBLProtoImplMethod::AddParameter(const nsAString& aText) nsXBLProtoImplMethod::AddParameter(const nsAString& aText)
{ {
NS_PRECONDITION(!mIsCompiled, NS_PRECONDITION(!IsCompiled(),
"Must not be compiled when accessing uncompiled method"); "Must not be compiled when accessing uncompiled method");
if (!mUncompiledMethod) {
mUncompiledMethod = new nsXBLUncompiledMethod(); nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
if (!mUncompiledMethod) if (!uncompiledMethod) {
uncompiledMethod = new nsXBLUncompiledMethod();
if (!uncompiledMethod)
return; return;
SetUncompiledMethod(uncompiledMethod);
} }
mUncompiledMethod->AddParameter(aText); uncompiledMethod->AddParameter(aText);
} }
void void
nsXBLProtoImplMethod::SetLineNumber(PRUint32 aLineNumber) nsXBLProtoImplMethod::SetLineNumber(PRUint32 aLineNumber)
{ {
NS_PRECONDITION(!mIsCompiled, NS_PRECONDITION(!IsCompiled(),
"Must not be compiled when accessing uncompiled method"); "Must not be compiled when accessing uncompiled method");
if (!mUncompiledMethod) {
mUncompiledMethod = new nsXBLUncompiledMethod(); nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
if (!mUncompiledMethod) if (!uncompiledMethod) {
uncompiledMethod = new nsXBLUncompiledMethod();
if (!uncompiledMethod)
return; return;
SetUncompiledMethod(uncompiledMethod);
} }
mUncompiledMethod->SetLineNumber(aLineNumber); uncompiledMethod->SetLineNumber(aLineNumber);
} }
nsresult nsresult
@ -129,7 +125,7 @@ nsXBLProtoImplMethod::InstallMember(nsIScriptContext* aContext,
void* aTargetClassObject, void* aTargetClassObject,
const nsCString& aClassStr) const nsCString& aClassStr)
{ {
NS_PRECONDITION(mIsCompiled, NS_PRECONDITION(IsCompiled(),
"Should not be installing an uncompiled method"); "Should not be installing an uncompiled method");
JSContext* cx = (JSContext*) aContext->GetNativeContext(); JSContext* cx = (JSContext*) aContext->GetNativeContext();
@ -177,36 +173,34 @@ nsresult
nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr, nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
void* aClassObject) void* aClassObject)
{ {
NS_PRECONDITION(!mIsCompiled, NS_PRECONDITION(!IsCompiled(),
"Trying to compile an already-compiled method"); "Trying to compile an already-compiled method");
NS_PRECONDITION(aClassObject, NS_PRECONDITION(aClassObject,
"Must have class object to compile"); "Must have class object to compile");
#ifdef DEBUG nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
// We have some "ok" early returns after which we consider ourselves compiled
mIsCompiled = PR_TRUE; // No parameters or body was supplied, so don't install method.
#endif if (!uncompiledMethod) {
// Early return after which we consider ourselves compiled.
// No parameters or body was supplied, so don't install method. mJSMethodObject = nsnull;
if (!mUncompiledMethod)
return NS_OK;
// Don't install method if no name was supplied.
if (!mName) {
delete mUncompiledMethod;
mUncompiledMethod = nsnull;
return NS_OK; return NS_OK;
} }
#ifdef DEBUG // Don't install method if no name was supplied.
// OK, now we have some error early returns that mean we're not if (!mName) {
// really compiled... delete uncompiledMethod;
mIsCompiled = PR_FALSE;
#endif // Early return after which we consider ourselves compiled.
mJSMethodObject = nsnull;
return NS_OK;
}
// We have a method. // We have a method.
// Allocate an array for our arguments. // Allocate an array for our arguments.
PRInt32 paramCount = mUncompiledMethod->GetParameterCount(); PRInt32 paramCount = uncompiledMethod->GetParameterCount();
char** args = nsnull; char** args = nsnull;
if (paramCount > 0) { if (paramCount > 0) {
args = new char*[paramCount]; args = new char*[paramCount];
@ -216,7 +210,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
// Add our parameters to our args array. // Add our parameters to our args array.
PRInt32 argPos = 0; PRInt32 argPos = 0;
for (nsXBLParameter* curr = mUncompiledMethod->mParameters; for (nsXBLParameter* curr = uncompiledMethod->mParameters;
curr; curr;
curr = curr->mNext) { curr = curr->mNext) {
args[argPos] = curr->mName; args[argPos] = curr->mName;
@ -225,7 +219,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
// Get the body // Get the body
nsDependentString body; nsDependentString body;
PRUnichar *bodyText = mUncompiledMethod->mBodyText.GetText(); PRUnichar *bodyText = uncompiledMethod->mBodyText.GetText();
if (bodyText) if (bodyText)
body.Rebind(bodyText); body.Rebind(bodyText);
@ -245,39 +239,27 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
(const char**)args, (const char**)args,
body, body,
functionUri.get(), functionUri.get(),
mUncompiledMethod->mBodyText.GetLineNumber(), uncompiledMethod->mBodyText.GetLineNumber(),
PR_TRUE, PR_TRUE,
(void **) &methodObject); (void **) &methodObject);
// Destroy our uncompiled method and delete our arg list. // Destroy our uncompiled method and delete our arg list.
delete mUncompiledMethod; delete uncompiledMethod;
delete [] args; delete [] args;
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mUncompiledMethod = nsnull; SetUncompiledMethod(nsnull);
return rv; return rv;
} }
mJSMethodObject = methodObject; mJSMethodObject = methodObject;
if (methodObject) { return NS_OK;
// Root the compiled prototype script object.
if (NS_FAILED(rv)) {
mJSMethodObject = nsnull;
}
}
#ifdef DEBUG
mIsCompiled = NS_SUCCEEDED(rv);
#endif
return rv;
} }
void void
nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const
{ {
NS_ASSERTION(mIsCompiled, "Shouldn't traverse uncompiled method"); if (IsCompiled() && mJSMethodObject) {
if (mJSMethodObject) {
aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject, aClosure); aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject, aClosure);
} }
} }
@ -285,7 +267,7 @@ nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const
nsresult nsresult
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement) nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{ {
NS_PRECONDITION(mIsCompiled, "Can't execute uncompiled method"); NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
if (!mJSMethodObject) { if (!mJSMethodObject) {
// Nothing to do here // Nothing to do here

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

@ -113,7 +113,6 @@ class nsXBLProtoImplMethod: public nsXBLProtoImplMember
public: public:
nsXBLProtoImplMethod(const PRUnichar* aName); nsXBLProtoImplMethod(const PRUnichar* aName);
virtual ~nsXBLProtoImplMethod(); virtual ~nsXBLProtoImplMethod();
virtual void Destroy(PRBool aIsCompiled);
void AppendBodyText(const nsAString& aBody); void AppendBodyText(const nsAString& aBody);
void AddParameter(const nsAString& aName); void AddParameter(const nsAString& aName);
@ -131,10 +130,26 @@ public:
virtual void Trace(TraceCallback aCallback, void *aClosure) const; virtual void Trace(TraceCallback aCallback, void *aClosure) const;
PRBool IsCompiled() const
{
return !(mUncompiledMethod & BIT_UNCOMPILED);
}
void SetUncompiledMethod(nsXBLUncompiledMethod* aUncompiledMethod)
{
mUncompiledMethod = PRUptrdiff(aUncompiledMethod) | BIT_UNCOMPILED;
}
nsXBLUncompiledMethod* GetUncompiledMethod() const
{
PRUptrdiff unmasked = mUncompiledMethod & ~BIT_UNCOMPILED;
return reinterpret_cast<nsXBLUncompiledMethod*>(unmasked);
}
protected: protected:
enum { BIT_UNCOMPILED = 1 << 0 };
union { union {
nsXBLUncompiledMethod* mUncompiledMethod; // An object that represents the method before being compiled. PRUptrdiff mUncompiledMethod; // An object that represents the method before being compiled.
JSObject * mJSMethodObject; // The JS object for the method (after compilation) JSObject* mJSMethodObject; // The JS object for the method (after compilation)
}; };
#ifdef DEBUG #ifdef DEBUG

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

@ -78,29 +78,14 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
nsXBLProtoImplProperty::~nsXBLProtoImplProperty() nsXBLProtoImplProperty::~nsXBLProtoImplProperty()
{ {
MOZ_COUNT_DTOR(nsXBLProtoImplProperty); MOZ_COUNT_DTOR(nsXBLProtoImplProperty);
}
void if (!(mJSAttributes & JSPROP_GETTER)) {
nsXBLProtoImplProperty::Destroy(PRBool aIsCompiled)
{
NS_PRECONDITION(aIsCompiled == mIsCompiled,
"Incorrect aIsCompiled in nsXBLProtoImplProperty::Destroy");
if ((mJSAttributes & JSPROP_GETTER) && mJSGetterObject) {
mJSGetterObject = nsnull;
}
else {
delete mGetterText; delete mGetterText;
} }
if ((mJSAttributes & JSPROP_SETTER) && mJSSetterObject) { if (!(mJSAttributes & JSPROP_SETTER)) {
mJSSetterObject = nsnull;
}
else {
delete mSetterText; delete mSetterText;
} }
mGetterText = mSetterText = nsnull;
} }
void void
@ -341,13 +326,11 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
void void
nsXBLProtoImplProperty::Trace(TraceCallback aCallback, void *aClosure) const nsXBLProtoImplProperty::Trace(TraceCallback aCallback, void *aClosure) const
{ {
NS_ASSERTION(mIsCompiled, "Shouldn't traverse uncompiled method"); if (mJSAttributes & JSPROP_GETTER) {
if ((mJSAttributes & JSPROP_GETTER) && mJSGetterObject) {
aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject, aClosure); aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject, aClosure);
} }
if ((mJSAttributes & JSPROP_SETTER) && mJSSetterObject) { if (mJSAttributes & JSPROP_SETTER) {
aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject, aClosure); aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject, aClosure);
} }
} }

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

@ -55,7 +55,6 @@ public:
const PRUnichar* aReadOnly); const PRUnichar* aReadOnly);
virtual ~nsXBLProtoImplProperty(); virtual ~nsXBLProtoImplProperty();
virtual void Destroy(PRBool aIsCompiled);
void AppendGetterText(const nsAString& aGetter); void AppendGetterText(const nsAString& aGetter);
void AppendSetterText(const nsAString& aSetter); void AppendSetterText(const nsAString& aSetter);