Bug 821850 - Make DoInitJSClass unconditionally fill in aClassObject. r=bz

Right now, DoInitJSClass only returns non-null if the class object is new
(and thus needs to have members installed on it). The code then goes and
unconditionally tries to install the members, null-checking and aborting
each time.

Instead, let's use an explicit boolean and one early return. This lets us
get a reference to our JSClass no matter what, which we need.
This commit is contained in:
Bobby Holley 2013-02-08 14:24:20 +00:00
parent 9069c014a7
commit 225d119eed
8 changed files with 34 additions and 17 deletions

View File

@ -1352,7 +1352,7 @@ nsresult
nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,
nsXBLPrototypeBinding* aProtoBinding,
JSObject** aClassObject)
JSObject** aClassObject, bool* aNew)
{
// First ensure our JS class is initialized.
nsAutoCString className(aClassName);
@ -1408,6 +1408,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
if ((!::JS_LookupPropertyWithFlags(cx, global, className.get(), 0, &val)) ||
JSVAL_IS_PRIMITIVE(val)) {
// We need to initialize the class.
*aNew = true;
nsCStringKey key(xblKey);
if (!c) {
@ -1485,12 +1486,14 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
::JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
*aClassObject = proto;
}
else {
*aNew = false;
proto = JSVAL_TO_OBJECT(val);
}
*aClassObject = proto;
if (obj) {
// Set the prototype of our object to be the new class.
if (!::JS_SetPrototype(cx, obj, proto)) {

View File

@ -114,7 +114,7 @@ public:
static nsresult DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,
nsXBLPrototypeBinding* aProtoBinding,
JSObject** aClassObject);
JSObject** aClassObject, bool* aNew);
bool AllowScripts(); // XXX make const

View File

@ -68,10 +68,17 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
// not been built already.
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
JSObject* targetClassObject = nullptr;
bool targetObjectIsNew = false;
nsresult rv = InitTargetObjects(aPrototypeBinding, context,
aBinding->GetBoundElement(),
getter_AddRefs(holder), &targetClassObject);
getter_AddRefs(holder), &targetClassObject,
&targetObjectIsNew);
NS_ENSURE_SUCCESS(rv, rv); // kick out if we were unable to properly intialize our target objects
MOZ_ASSERT(targetClassObject);
// If the prototype already existed, we don't need to install anything. return early.
if (!targetObjectIsNew)
return NS_OK;
JSObject * targetScriptObject;
holder->GetJSObject(&targetScriptObject);
@ -95,7 +102,8 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
nsIScriptContext* aContext,
nsIContent* aBoundElement,
nsIXPConnectJSObjectHolder** aScriptObjectHolder,
JSObject** aTargetClassObject)
JSObject** aTargetClassObject,
bool* aTargetIsNew)
{
nsresult rv = NS_OK;
*aScriptObjectHolder = nullptr;
@ -132,7 +140,7 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
// between the object and its base class. We become the new base class of the object, and the
// object's old base class becomes the new class' base class.
rv = aBinding->InitClass(mClassName, jscontext, global, JSVAL_TO_OBJECT(v),
aTargetClassObject);
aTargetClassObject, aTargetIsNew);
if (NS_FAILED(rv)) {
return rv;
}
@ -163,14 +171,15 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding)
JSObject* classObject;
bool classObjectIsNew = false;
nsresult rv = aBinding->InitClass(mClassName, cx, global, global,
&classObject);
&classObject, &classObjectIsNew);
if (NS_FAILED(rv))
return rv;
MOZ_ASSERT(classObjectIsNew);
MOZ_ASSERT(classObject);
mClassObject = classObject;
if (!mClassObject)
return NS_ERROR_FAILURE;
AutoVersionChecker avc(cx);
@ -284,9 +293,12 @@ nsXBLProtoImpl::Read(nsIScriptContext* aContext,
JSObject *global = aGlobal->GetGlobalJSObject();
JSObject* classObject;
nsresult rv = aBinding->InitClass(mClassName, cx, global, global, &classObject);
bool classObjectIsNew = false;
nsresult rv = aBinding->InitClass(mClassName, cx, global, global, &classObject,
&classObjectIsNew);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(classObject, NS_ERROR_FAILURE);
MOZ_ASSERT(classObject);
MOZ_ASSERT(classObjectIsNew);
mClassObject = classObject;

View File

@ -41,7 +41,8 @@ public:
nsresult InitTargetObjects(nsXBLPrototypeBinding* aBinding, nsIScriptContext* aContext,
nsIContent* aBoundElement,
nsIXPConnectJSObjectHolder** aScriptObjectHolder,
JSObject** aTargetClassObject);
JSObject** aTargetClassObject,
bool* aTargetIsNew);
nsresult CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding);
void SetMemberList(nsXBLProtoImplMember* aMemberList)

View File

@ -115,7 +115,7 @@ nsXBLProtoImplMethod::InstallMember(nsIScriptContext* aContext,
JSObject* globalObject = sgo->GetGlobalJSObject();
// now we want to reevaluate our property using aContext and the script object for this window...
if (mJSMethodObject && aTargetClassObject) {
if (mJSMethodObject) {
nsDependentString name(mName);
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, globalObject);

View File

@ -158,7 +158,7 @@ nsXBLProtoImplProperty::InstallMember(nsIScriptContext* aContext,
JSObject * globalObject = sgo->GetGlobalJSObject();
// now we want to reevaluate our property using aContext and the script object for this window...
if ((mJSGetterObject || mJSSetterObject) && aTargetClassObject) {
if (mJSGetterObject || mJSSetterObject) {
JSObject * getter = nullptr;
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, globalObject);

View File

@ -841,14 +841,15 @@ nsresult
nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
JSContext * aContext, JSObject * aGlobal,
JSObject * aScriptObject,
JSObject** aClassObject)
JSObject** aClassObject,
bool* aNew)
{
NS_ENSURE_ARG_POINTER(aClassObject);
*aClassObject = nullptr;
return nsXBLBinding::DoInitJSClass(aContext, aGlobal, aScriptObject,
aClassName, this, aClassObject);
aClassName, this, aClassObject, aNew);
}
nsIContent*

View File

@ -121,7 +121,7 @@ public:
nsresult InitClass(const nsCString& aClassName, JSContext * aContext,
JSObject * aGlobal, JSObject * aScriptObject,
JSObject** aClassObject);
JSObject** aClassObject, bool* aNew);
nsresult ConstructInterfaceTable(const nsAString& aImpls);