Bug 877762 - GC: Post-barrier cycle collector participants - 8 Convert JS::Object to use Heap<T> (XBL) r=bz r=sfink

This commit is contained in:
Jon Coppeard 2013-06-18 11:00:38 +01:00
parent 586c7b4514
commit 6e32864304
5 changed files with 250 additions and 122 deletions

View File

@ -0,0 +1,145 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXBLMaybeCompiled_h__
#define nsXBLMaybeCompiled_h__
#include "js/RootingAPI.h"
/*
* A union containing either a pointer representing uncompiled source or a
* JSObject* representing the compiled result. The class is templated on the
* source object type.
*
* The purpose of abstracting this as a separate class is to allow it to be
* wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
* pointer, when present.
*/
template <class UncompiledT>
class nsXBLMaybeCompiled
{
public:
nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {}
nsXBLMaybeCompiled(UncompiledT* uncompiled)
: mUncompiled(reinterpret_cast<uintptr_t>(uncompiled) | BIT_UNCOMPILED) {}
nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {}
bool IsCompiled() const
{
return !(mUncompiled & BIT_UNCOMPILED);
}
UncompiledT* GetUncompiled() const
{
MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled");
uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED;
return reinterpret_cast<UncompiledT*>(unmasked);
}
JSObject* GetJSFunction() const
{
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
return mCompiled;
}
private:
JSObject*& UnsafeGetJSFunction()
{
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
return mCompiled;
}
enum { BIT_UNCOMPILED = 1 << 0 };
union
{
// An pointer that represents the function before being compiled, with
// BIT_UNCOMPILED set.
uintptr_t mUncompiled;
// The JS object for the compiled result.
JSObject* mCompiled;
};
friend class js::RootMethods<nsXBLMaybeCompiled<UncompiledT> >;
};
/* Add support for JS::Heap<nsXBLMaybeCompiled>. */
namespace js {
template <class UncompiledT>
struct RootMethods<nsXBLMaybeCompiled<UncompiledT> > : public RootMethods<JSObject *>
{
typedef struct RootMethods<JSObject *> Base;
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function)
{
return function.IsCompiled() && Base::poisoned(function.GetJSFunction());
}
static bool needsPostBarrier(nsXBLMaybeCompiled<UncompiledT> function)
{
return function.IsCompiled() && Base::needsPostBarrier(function.GetJSFunction());
}
#ifdef JSGC_GENERATIONAL
static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp)
{
Base::postBarrier(&functionp->UnsafeGetJSFunction());
}
static void relocate(nsXBLMaybeCompiled<UncompiledT>* functionp)
{
Base::relocate(&functionp->UnsafeGetJSFunction());
}
#endif
};
template <class UncompiledT>
class HeapBase<nsXBLMaybeCompiled<UncompiledT> >
{
const JS::Heap<nsXBLMaybeCompiled<UncompiledT> >& wrapper() const {
return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT> >*>(this);
}
JS::Heap<nsXBLMaybeCompiled<UncompiledT> >& wrapper() {
return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT> >*>(this);
}
const nsXBLMaybeCompiled<UncompiledT>* extract() const {
return wrapper().address();
}
nsXBLMaybeCompiled<UncompiledT>* extract() {
return wrapper().unsafeGet();
}
public:
bool IsCompiled() const { return extract()->IsCompiled(); }
UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); }
JSObject* GetJSFunction() const { return extract()->GetJSFunction(); }
void SetUncompiled(UncompiledT* source) {
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(source));
}
void SetJSFunction(JSObject* function) {
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(function));
}
JS::Heap<JSObject*>& AsHeapObject()
{
MOZ_ASSERT(extract()->IsCompiled());
return *reinterpret_cast<JS::Heap<JSObject*>*>(this);
}
};
} /* namespace js */
#endif // nsXBLMaybeCompiled_h__

View File

@ -24,8 +24,8 @@
using namespace mozilla;
nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
nsXBLProtoImplMember(aName),
mUncompiledMethod(BIT_UNCOMPILED)
nsXBLProtoImplMember(aName),
mMethod()
{
MOZ_COUNT_CTOR(nsXBLProtoImplMethod);
}
@ -108,12 +108,13 @@ nsXBLProtoImplMethod::InstallMember(JSContext* aCx,
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
// now we want to reevaluate our property using aContext and the script object for this window...
if (mJSMethodObject) {
JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
if (jsMethodObject) {
nsDependentString name(mName);
// First, make the function in the compartment of the scope object.
JSAutoCompartment ac(aCx, scopeObject);
JS::Rooted<JSObject*> method(aCx, ::JS_CloneFunctionObject(aCx, mJSMethodObject, scopeObject));
JS::Rooted<JSObject*> method(aCx, ::JS_CloneFunctionObject(aCx, jsMethodObject, scopeObject));
if (!method) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -149,7 +150,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
// No parameters or body was supplied, so don't install method.
if (!uncompiledMethod) {
// Early return after which we consider ourselves compiled.
mJSMethodObject = nullptr;
SetCompiledMethod(nullptr);
return NS_OK;
}
@ -159,7 +160,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
delete uncompiledMethod;
// Early return after which we consider ourselves compiled.
mJSMethodObject = nullptr;
SetCompiledMethod(nullptr);
return NS_OK;
}
@ -219,7 +220,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
return rv;
}
mJSMethodObject = methodObject;
SetCompiledMethod(methodObject);
return NS_OK;
}
@ -227,8 +228,8 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
void
nsXBLProtoImplMethod::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
{
if (IsCompiled() && mJSMethodObject) {
aCallbacks.Trace(&mJSMethodObject, "mJSMethodObject", aClosure);
if (IsCompiled() && GetCompiledMethod()) {
aCallbacks.Trace(&mMethod.AsHeapObject(), "mMethod", aClosure);
}
}
@ -243,11 +244,7 @@ nsXBLProtoImplMethod::Read(nsIScriptContext* aContext,
return rv;
}
mJSMethodObject = methodObject;
#ifdef DEBUG
mIsCompiled = true;
#endif
SetCompiledMethod(methodObject);
return NS_OK;
}
@ -256,15 +253,15 @@ nsresult
nsXBLProtoImplMethod::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream)
{
if (mJSMethodObject) {
MOZ_ASSERT(IsCompiled());
if (GetCompiledMethod()) {
nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
return XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
return XBL_SerializeFunction(aContext, aStream, mMethod.AsHeapObject());
}
return NS_OK;
@ -275,7 +272,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{
NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
if (!mJSMethodObject) {
if (!GetCompiledMethod()) {
// Nothing to do here
return NS_OK;
}
@ -327,7 +324,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
// Clone the function object, using thisObject as the parent so "this" is in
// the scope chain of the resulting function (for backwards compat to the
// days when this was an event handler).
JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject));
JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, GetCompiledMethod(), thisObject));
if (!method)
return NS_ERROR_OUT_OF_MEMORY;
@ -364,12 +361,12 @@ nsXBLProtoImplAnonymousMethod::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
XBLBindingSerializeDetails aType)
{
if (mJSMethodObject) {
MOZ_ASSERT(IsCompiled());
if (GetCompiledMethod()) {
nsresult rv = aStream->Write8(aType);
NS_ENSURE_SUCCESS(rv, rv);
rv = XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
rv = XBL_SerializeFunction(aContext, aStream, mMethod.AsHeapObject());
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -11,6 +11,7 @@
#include "nsString.h"
#include "jsapi.h"
#include "nsString.h"
#include "nsXBLMaybeCompiled.h"
#include "nsXBLProtoImplMember.h"
#include "nsXBLSerialize.h"
@ -102,29 +103,31 @@ public:
bool IsCompiled() const
{
return !(mUncompiledMethod & BIT_UNCOMPILED);
return mMethod.IsCompiled();
}
void SetUncompiledMethod(nsXBLUncompiledMethod* aUncompiledMethod)
{
mUncompiledMethod = uintptr_t(aUncompiledMethod) | BIT_UNCOMPILED;
mMethod.SetUncompiled(aUncompiledMethod);
}
nsXBLUncompiledMethod* GetUncompiledMethod() const
{
uintptr_t unmasked = mUncompiledMethod & ~BIT_UNCOMPILED;
return reinterpret_cast<nsXBLUncompiledMethod*>(unmasked);
return mMethod.GetUncompiled();
}
protected:
enum { BIT_UNCOMPILED = 1 << 0 };
void SetCompiledMethod(JSObject* aCompiledMethod)
{
mMethod.SetJSFunction(aCompiledMethod);
}
union {
uintptr_t mUncompiledMethod; // An object that represents the method before being compiled.
JSObject* mJSMethodObject; // The JS object for the method (after compilation)
};
JSObject* GetCompiledMethod() const
{
return mMethod.GetJSFunction();
}
#ifdef DEBUG
bool mIsCompiled;
#endif
JS::Heap<nsXBLMaybeCompiled<nsXBLUncompiledMethod> > mMethod;
};
class nsXBLProtoImplAnonymousMethod : public nsXBLProtoImplMethod {

View File

@ -27,8 +27,6 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
const PRUnichar* aReadOnly,
uint32_t aLineNumber) :
nsXBLProtoImplMember(aName),
mGetterText(nullptr),
mSetterText(nullptr),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
, mIsCompiled(false)
@ -55,8 +53,6 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
const bool aIsReadOnly)
: nsXBLProtoImplMember(aName),
mGetterText(nullptr),
mSetterText(nullptr),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
, mIsCompiled(false)
@ -72,12 +68,20 @@ nsXBLProtoImplProperty::~nsXBLProtoImplProperty()
{
MOZ_COUNT_DTOR(nsXBLProtoImplProperty);
if (!(mJSAttributes & JSPROP_GETTER)) {
delete mGetterText;
if (!mGetter.IsCompiled()) {
delete mGetter.GetUncompiled();
}
if (!(mJSAttributes & JSPROP_SETTER)) {
delete mSetterText;
if (!mSetter.IsCompiled()) {
delete mSetter.GetUncompiled();
}
}
void nsXBLProtoImplProperty::EnsureUncompiledText(PropertyOp& aPropertyOp)
{
if (!aPropertyOp.GetUncompiled()) {
nsXBLTextWithLineNumber* text = new nsXBLTextWithLineNumber();
aPropertyOp.SetUncompiled(text);
}
}
@ -86,13 +90,8 @@ nsXBLProtoImplProperty::AppendGetterText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing getter text");
if (!mGetterText) {
mGetterText = new nsXBLTextWithLineNumber();
if (!mGetterText)
return;
}
mGetterText->AppendText(aText);
EnsureUncompiledText(mGetter);
mGetter.GetUncompiled()->AppendText(aText);
}
void
@ -100,13 +99,8 @@ nsXBLProtoImplProperty::AppendSetterText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing setter text");
if (!mSetterText) {
mSetterText = new nsXBLTextWithLineNumber();
if (!mSetterText)
return;
}
mSetterText->AppendText(aText);
EnsureUncompiledText(mSetter);
mSetter.GetUncompiled()->AppendText(aText);
}
void
@ -114,13 +108,8 @@ nsXBLProtoImplProperty::SetGetterLineNumber(uint32_t aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing getter text");
if (!mGetterText) {
mGetterText = new nsXBLTextWithLineNumber();
if (!mGetterText)
return;
}
mGetterText->SetLineNumber(aLineNumber);
EnsureUncompiledText(mGetter);
mGetter.GetUncompiled()->SetLineNumber(aLineNumber);
}
void
@ -128,13 +117,8 @@ nsXBLProtoImplProperty::SetSetterLineNumber(uint32_t aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing setter text");
if (!mSetterText) {
mSetterText = new nsXBLTextWithLineNumber();
if (!mSetterText)
return;
}
mSetterText->SetLineNumber(aLineNumber);
EnsureUncompiledText(mSetter);
mSetter.GetUncompiled()->SetLineNumber(aLineNumber);
}
const char* gPropertyArgs[] = { "val" };
@ -145,25 +129,26 @@ nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
{
NS_PRECONDITION(mIsCompiled,
"Should not be installing an uncompiled property");
MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
JS::Rooted<JSObject*> scopeObject(aCx, xpc::GetXBLScope(aCx, globalObject));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
// now we want to reevaluate our property using aContext and the script object for this window...
if (mJSGetterObject || mJSSetterObject) {
if (mGetter.GetJSFunction() || mSetter.GetJSFunction()) {
// First, enter the compartment of the scope object and clone the functions.
JSAutoCompartment ac(aCx, scopeObject);
JS::Rooted<JSObject*> getter(aCx, nullptr);
if (mJSGetterObject) {
if (!(getter = ::JS_CloneFunctionObject(aCx, mJSGetterObject, scopeObject)))
if (mGetter.GetJSFunction()) {
if (!(getter = ::JS_CloneFunctionObject(aCx, mGetter.GetJSFunction(), scopeObject)))
return NS_ERROR_OUT_OF_MEMORY;
}
JS::Rooted<JSObject*> setter(aCx, nullptr);
if (mJSSetterObject) {
if (!(setter = ::JS_CloneFunctionObject(aCx, mJSSetterObject, scopeObject)))
if (mSetter.GetJSFunction()) {
if (!(setter = ::JS_CloneFunctionObject(aCx, mSetter.GetJSFunction(), scopeObject)))
return NS_ERROR_OUT_OF_MEMORY;
}
@ -192,6 +177,7 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
"Trying to compile an already-compiled property");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
MOZ_ASSERT(!mGetter.IsCompiled() && !mSetter.IsCompiled());
if (!mName)
return NS_ERROR_FAILURE; // Without a valid name, we can't install the member.
@ -200,7 +186,7 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
nsresult rv = NS_OK;
nsAutoCString functionUri;
if (mGetterText || mSetterText) {
if (mGetter.GetUncompiled() || mSetter.GetUncompiled()) {
functionUri = aClassStr;
int32_t hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
@ -209,13 +195,14 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
}
bool deletedGetter = false;
if (mGetterText && mGetterText->GetText()) {
nsDependentString getter(mGetterText->GetText());
nsXBLTextWithLineNumber *getterText = mGetter.GetUncompiled();
if (getterText && getterText->GetText()) {
nsDependentString getter(getterText->GetText());
if (!getter.IsEmpty()) {
AutoPushJSContext cx(aContext->GetNativeContext());
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), mGetterText->GetLineNumber())
options.setFileAndLine(functionUri.get(), getterText->GetLineNumber())
.setVersion(JSVERSION_LATEST);
nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
JS::RootedObject rootedNull(cx, nullptr); // See bug 781070.
@ -223,17 +210,16 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
rv = nsJSUtils::CompileFunction(cx, rootedNull, options, name, 0, nullptr,
getter, getterObject.address());
// Make sure we free mGetterText here before setting mJSGetterObject, since
// that'll overwrite mGetterText
delete mGetterText;
delete getterText;
deletedGetter = true;
mJSGetterObject = getterObject;
mGetter.SetJSFunction(getterObject);
if (mJSGetterObject && NS_SUCCEEDED(rv)) {
if (mGetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
}
if (NS_FAILED(rv)) {
mJSGetterObject = nullptr;
mGetter.SetJSFunction(nullptr);
mJSAttributes &= ~JSPROP_GETTER;
/*chaining to return failure*/
}
@ -241,8 +227,8 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
} // if getter is not empty
if (!deletedGetter) { // Empty getter
delete mGetterText;
mJSGetterObject = nullptr;
delete getterText;
mGetter.SetJSFunction(nullptr);
}
if (NS_FAILED(rv)) {
@ -256,13 +242,14 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
}
bool deletedSetter = false;
if (mSetterText && mSetterText->GetText()) {
nsDependentString setter(mSetterText->GetText());
nsXBLTextWithLineNumber *setterText = mSetter.GetUncompiled();
if (setterText && setterText->GetText()) {
nsDependentString setter(setterText->GetText());
if (!setter.IsEmpty()) {
AutoPushJSContext cx(aContext->GetNativeContext());
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), mSetterText->GetLineNumber())
options.setFileAndLine(functionUri.get(), setterText->GetLineNumber())
.setVersion(JSVERSION_LATEST);
nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
JS::RootedObject rootedNull(cx, nullptr); // See bug 781070.
@ -270,17 +257,15 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
rv = nsJSUtils::CompileFunction(cx, rootedNull, options, name, 1,
gPropertyArgs, setter, setterObject.address());
// Make sure we free mSetterText here before setting mJSGetterObject, since
// that'll overwrite mSetterText
delete mSetterText;
delete setterText;
deletedSetter = true;
mJSSetterObject = setterObject;
mSetter.SetJSFunction(setterObject);
if (mJSSetterObject && NS_SUCCEEDED(rv)) {
if (mSetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
}
if (NS_FAILED(rv)) {
mJSSetterObject = nullptr;
mSetter.SetJSFunction(nullptr);
mJSAttributes &= ~JSPROP_SETTER;
/*chaining to return failure*/
}
@ -288,8 +273,8 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
} // if setter wasn't empty....
if (!deletedSetter) { // Empty setter
delete mSetterText;
mJSSetterObject = nullptr;
delete setterText;
mSetter.SetJSFunction(nullptr);
}
#ifdef DEBUG
@ -303,11 +288,11 @@ void
nsXBLProtoImplProperty::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
{
if (mJSAttributes & JSPROP_GETTER) {
aCallbacks.Trace(&mJSGetterObject, "mJSGetterObject", aClosure);
aCallbacks.Trace(&mGetter.AsHeapObject(), "mGetter", aClosure);
}
if (mJSAttributes & JSPROP_SETTER) {
aCallbacks.Trace(&mJSSetterObject, "mJSSetterObject", aClosure);
aCallbacks.Trace(&mSetter.AsHeapObject(), "mSetter", aClosure);
}
}
@ -316,27 +301,30 @@ nsXBLProtoImplProperty::Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream,
XBLBindingSerializeDetails aType)
{
MOZ_ASSERT(!mIsCompiled);
MOZ_ASSERT(!mGetter.GetUncompiled() && !mSetter.GetUncompiled());
JSContext *cx = aContext->GetNativeContext();
JS::Rooted<JSObject*> getterObject(cx);
if (aType == XBLBinding_Serialize_GetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
JS::Rooted<JSObject*> getterObject(cx);
nsresult rv = XBL_DeserializeFunction(aContext, aStream, &getterObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSGetterObject = getterObject;
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
}
mGetter.SetJSFunction(getterObject);
JS::Rooted<JSObject*> setterObject(cx);
if (aType == XBLBinding_Serialize_SetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
JS::Rooted<JSObject*> setterObject(cx);
nsresult rv = XBL_DeserializeFunction(aContext, aStream, &setterObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSSetterObject = setterObject;
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
}
mSetter.SetJSFunction(setterObject);
#ifdef DEBUG
mIsCompiled = true;
@ -370,14 +358,12 @@ nsXBLProtoImplProperty::Write(nsIScriptContext* aContext,
NS_ENSURE_SUCCESS(rv, rv);
if (mJSAttributes & JSPROP_GETTER) {
rv = XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSGetterObject));
rv = XBL_SerializeFunction(aContext, aStream, mGetter.AsHeapObject());
NS_ENSURE_SUCCESS(rv, rv);
}
if (mJSAttributes & JSPROP_SETTER) {
rv = XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSSetterObject));
rv = XBL_SerializeFunction(aContext, aStream, mSetter.AsHeapObject());
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -12,6 +12,7 @@
#include "jsapi.h"
#include "nsString.h"
#include "nsXBLSerialize.h"
#include "nsXBLMaybeCompiled.h"
#include "nsXBLProtoImplMember.h"
class nsXBLProtoImplProperty: public nsXBLProtoImplMember
@ -48,21 +49,17 @@ public:
nsIObjectOutputStream* aStream) MOZ_OVERRIDE;
protected:
union {
// The raw text for the getter (prior to compilation).
nsXBLTextWithLineNumber* mGetterText;
// The JS object for the getter (after compilation)
JSObject * mJSGetterObject;
};
typedef JS::Heap<nsXBLMaybeCompiled<nsXBLTextWithLineNumber> > PropertyOp;
union {
// The raw text for the setter (prior to compilation).
nsXBLTextWithLineNumber* mSetterText;
// The JS object for the setter (after compilation)
JSObject * mJSSetterObject;
};
void EnsureUncompiledText(PropertyOp& aPropertyOp);
// The raw text for the getter, or the JS object (after compilation).
PropertyOp mGetter;
// The raw text for the setter, or the JS object (after compilation).
PropertyOp mSetter;
unsigned mJSAttributes; // A flag for all our JS properties (getter/setter/readonly/shared/enum)
unsigned mJSAttributes; // A flag for all our JS properties (getter/setter/readonly/shared/enum)
#ifdef DEBUG
bool mIsCompiled;