mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
586c7b4514
commit
6e32864304
145
content/xbl/src/nsXBLMaybeCompiled.h
Normal file
145
content/xbl/src/nsXBLMaybeCompiled.h
Normal 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__
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user