Bug 648801 (new DOM list bindings) - Cache prototypes and pick up function value from the proto slot instead of caching it locally. r=bz/jst/mrbkap.

--HG--
extra : rebase_source : 56a04a93973f479998d40eb22b015e940419c5e5
This commit is contained in:
Andreas Gal 2011-05-24 12:45:39 +02:00
Родитель cb2f52409d
Коммит 7d5b52f0f1
20 изменённых файлов: 234 добавлений и 120 удалений

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

@ -497,9 +497,9 @@ nsContentList::~nsContentList()
}
JSObject*
nsContentList::WrapObject(JSContext *cx)
nsContentList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope)
{
return xpc::dom::NodeListBase::create(cx,
return xpc::dom::NodeListBase::create(cx, scope,
static_cast<nsIHTMLCollection*>(this),
this);
}

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

@ -277,7 +277,7 @@ public:
virtual ~nsContentList();
// nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx);
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope);
// nsIDOMHTMLCollection
NS_DECL_NSIDOMHTMLCOLLECTION

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

@ -1531,9 +1531,9 @@ NS_INTERFACE_TABLE_HEAD(nsChildContentList)
NS_INTERFACE_MAP_END
JSObject*
nsChildContentList::WrapObject(JSContext *cx)
nsChildContentList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope)
{
return xpc::dom::NodeListBase::create(cx, this);
return xpc::dom::NodeListBase::create(cx, scope, this);
}
NS_IMETHODIMP

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

@ -106,7 +106,7 @@ public:
NS_DECL_ISUPPORTS
// nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx);
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope);
// nsIDOMNodeList interface
NS_DECL_NSIDOMNODELIST

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

@ -183,12 +183,13 @@ nsXBLDocGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id)
JSClass nsXBLDocGlobalObject::gSharedGlobalClass = {
"nsXBLPrototypeScript compilation scope",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS,
XPCONNECT_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub,
nsXBLDocGlobalObject_getProperty, nsXBLDocGlobalObject_setProperty,
JS_EnumerateStub, nsXBLDocGlobalObject_resolve,
JS_ConvertStub, nsXBLDocGlobalObject_finalize,
NULL, nsXBLDocGlobalObject_checkAccess
NULL, nsXBLDocGlobalObject_checkAccess, NULL, NULL, NULL, NULL,
TraceXPCGlobal
};
//----------------------------------------------------------------------

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

@ -143,10 +143,11 @@ nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id)
JSClass nsXULPDGlobalObject::gSharedGlobalClass = {
"nsXULPrototypeScript compilation scope",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS,
XPCONNECT_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, nsXULPDGlobalObject_resolve, JS_ConvertStub,
nsXULPDGlobalObject_finalize
nsXULPDGlobalObject_finalize, NULL, NULL, NULL, NULL, NULL, NULL,
TraceXPCGlobal
};

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

@ -44,6 +44,7 @@
struct JSObject;
struct JSContext;
class nsContentUtils;
class XPCWrappedNativeScope;
typedef PRUptrdiff PtrBits;
@ -126,11 +127,10 @@ public:
}
/**
* Wrap the object corresponding to this wrappe cache; this can return null
* if the object doesn't know how to wrap itself. If non-null is returned,
* the object has already been stored in the wrapper cache.
* Wrap the object corresponding to this wrapper cache. If non-null is
* returned, the object has already been stored in the wrapper cache.
*/
virtual JSObject* WrapObject(JSContext *cx) {
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope) {
return nsnull;
}

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

@ -3046,6 +3046,8 @@ struct JSClass {
#define JSCLASS_FREEZE_PROTO (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5))
#define JSCLASS_FREEZE_CTOR (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
#define JSCLASS_XPCONNECT_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
/* Global flags. */
#define JSGLOBAL_FLAGS_CLEARED 0x1
@ -3061,8 +3063,13 @@ struct JSClass {
* prevously allowed, but is now an ES5 violation and thus unsupported.
*/
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 8)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT))
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \
(((clasp)->flags & JSCLASS_IS_GLOBAL) \
&& JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
/* Fast access to the original value of each standard class's prototype. */
#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 8)

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

@ -933,8 +933,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
: NULL;
JS_ASSERT_IF(globalObj, globalObj->isNative());
JS_ASSERT_IF(globalObj, (globalObj->getClass()->flags & JSCLASS_GLOBAL_FLAGS) ==
JSCLASS_GLOBAL_FLAGS);
JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass()));
/* Null script early in case of error, to reduce our code footprint. */
script = NULL;

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

@ -44,6 +44,7 @@
#include "nsIDOMNode.h"
#include "nsDOMClassInfo.h"
#include "nsGlobalWindow.h"
extern XPCNativeInterface* interfaces[];
@ -55,16 +56,18 @@ namespace dom {
int NodeListBase::NodeListFamily;
JSObject *
NodeListBase::create(JSContext *cx, nsINodeList *aNodeList)
NodeListBase::create(JSContext *cx, XPCWrappedNativeScope *scope,
nsINodeList *aNodeList)
{
return NodeList<nsINodeList>::create(cx, aNodeList, aNodeList);
return NodeList<nsINodeList>::create(cx, scope, aNodeList, aNodeList);
}
JSObject *
NodeListBase::create(JSContext *cx, nsIHTMLCollection *aHTMLCollection,
NodeListBase::create(JSContext *cx, XPCWrappedNativeScope *scope,
nsIHTMLCollection *aHTMLCollection,
nsWrapperCache *aWrapperCache)
{
return NodeList<nsIHTMLCollection>::create(cx, aHTMLCollection,
return NodeList<nsIHTMLCollection>::create(cx, scope, aHTMLCollection,
aWrapperCache);
}
@ -77,7 +80,7 @@ template<class T>
NodeList<T> NodeList<T>::instance;
template<>
Class NodeList<nsINodeList>::NodeListProtoClass = {
Class NodeList<nsINodeList>::sProtoClass = {
"NodeList",
0,
JS_PropertyStub, /* addProperty */
@ -90,7 +93,16 @@ Class NodeList<nsINodeList>::NodeListProtoClass = {
};
template<>
Class NodeList<nsIHTMLCollection>::NodeListProtoClass = {
JSBool
NodeList<nsINodeList>::namedItem(JSContext *cx, uintN argc, jsval *vp);
template<>
NodeList<nsINodeList>::Methods NodeList<nsINodeList>::sProtoMethods[] = {
{ nsDOMClassInfo::sItem_id, &item, 1 }
};
template<>
Class NodeList<nsIHTMLCollection>::sProtoClass = {
"HTMLCollection",
0,
JS_PropertyStub, /* addProperty */
@ -102,6 +114,16 @@ Class NodeList<nsIHTMLCollection>::NodeListProtoClass = {
JS_ConvertStub
};
template<>
JSBool
NodeList<nsIHTMLCollection>::namedItem(JSContext *cx, uintN argc, jsval *vp);
template<>
NodeList<nsIHTMLCollection>::Methods NodeList<nsIHTMLCollection>::sProtoMethods[] = {
{ nsDOMClassInfo::sItem_id, &item, 1 },
{ nsDOMClassInfo::sNamedItem_id, &namedItem, 1 }
};
template<class T>
T*
NodeList<T>::getNodeList(JSObject *obj)
@ -126,22 +148,6 @@ NodeList<T>::setProtoShape(JSObject *obj, uint32 shape)
js::SetProxyExtra(obj, 0, PrivateUint32Value(shape));
}
template<class T>
JSObject *
NodeList<T>::getItemFunction(JSObject *obj)
{
JS_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == &NodeList<T>::instance);
return &js::GetProxyExtra(obj, 1).toObject();
}
template<class T>
void
NodeList<T>::setItemFunction(JSObject *obj, JSObject *funobj)
{
JS_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == &NodeList<T>::instance);
js::SetProxyExtra(obj, 1, ObjectValue(*funobj));
}
template<class T>
bool
NodeList<T>::instanceIsNodeListObject(JSContext *cx, JSObject *obj)
@ -220,63 +226,56 @@ NodeList<nsIHTMLCollection>::namedItem(JSContext *cx, uintN argc, jsval *vp)
template<class T>
JSObject *
NodeList<T>::getPrototypeShared(JSContext *cx)
NodeList<T>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
{
JSObject *proto = JS_NewObject(cx, Jsvalify(&NodeListProtoClass), NULL, NULL);
nsDataHashtable<nsIDHashKey, JSObject*> &cache =
scope->GetCachedDOMPrototypes();
JSObject *proto;
if (cache.IsInitialized()) {
if (cache.Get(NS_GET_TEMPLATE_IID(T), &proto))
return proto;
}
else if (!cache.Init()) {
return NULL;
}
proto = JS_NewObject(cx, Jsvalify(&sProtoClass), NULL, NULL);
if (!proto)
return NULL;
JSAutoEnterCompartment ac;
if (!ac.enter(cx, proto))
return NULL;
if (!JS_DefinePropertyById(cx, proto, nsDOMClassInfo::sLength_id, JSVAL_VOID,
length_getter, NULL,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_SHARED))
return NULL;
JSFunction *fun = JS_NewFunctionById(cx, item, 1, 0, js::GetObjectParent(proto),
nsDOMClassInfo::sItem_id);
if (!fun)
return NULL;
JSObject *funobj = JS_GetFunctionObject(fun);
if (!JS_DefinePropertyById(cx, proto, nsDOMClassInfo::sItem_id, OBJECT_TO_JSVAL(funobj),
NULL, NULL, JSPROP_ENUMERATE))
return NULL;
return proto;
}
template<>
JSObject *
NodeList<nsINodeList>::getPrototype(JSContext *cx)
{
// FIXME: This should be cached, not recreated every time.
return getPrototypeShared(cx);
}
for (size_t n = 0; n < NS_ARRAY_LENGTH(sProtoMethods); ++n) {
jsid id = sProtoMethods[n].id;
JSFunction *fun = JS_NewFunctionById(cx, sProtoMethods[n].native, sProtoMethods[n].nargs,
0, js::GetObjectParent(proto), id);
if (!fun)
return NULL;
JSObject *funobj = JS_GetFunctionObject(fun);
if (!JS_DefinePropertyById(cx, proto, id, OBJECT_TO_JSVAL(funobj),
NULL, NULL, JSPROP_ENUMERATE))
return NULL;
}
template<>
JSObject *
NodeList<nsIHTMLCollection>::getPrototype(JSContext *cx)
{
// FIXME: This should be cached, not recreated every time.
JSObject *proto = getPrototypeShared(cx);
if (!proto)
if (!cache.Put(NS_GET_TEMPLATE_IID(T), proto))
return NULL;
JSFunction *fun = JS_NewFunctionById(cx, item, 1, 0, js::GetObjectParent(proto),
nsDOMClassInfo::sNamedItem_id);
if (!fun)
return NULL;
JSObject *funobj = JS_GetFunctionObject(fun);
if (!JS_DefinePropertyById(cx, proto, nsDOMClassInfo::sNamedItem_id,
OBJECT_TO_JSVAL(funobj),
NULL, NULL, JSPROP_ENUMERATE))
return NULL;
return proto;
}
template<class T>
JSObject *
NodeList<T>::create(JSContext *cx, T *aNodeList, nsWrapperCache* aWrapperCache)
NodeList<T>::create(JSContext *cx, XPCWrappedNativeScope *scope, T *aNodeList,
nsWrapperCache* aWrapperCache)
{
JSObject *proto = getPrototype(cx);
JSObject *proto = getPrototype(cx, scope);
if (!proto)
return NULL;
JSObject *obj = NewProxyObject(cx, &NodeList<T>::instance,
@ -414,21 +413,26 @@ NodeList<T>::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
template<class T>
bool
NodeList<T>::cacheItemAndLength(JSContext *cx, JSObject *proxy, JSObject *proto)
NodeList<T>::cacheProtoShape(JSContext *cx, JSObject *proxy, JSObject *proto)
{
JSPropertyDescriptor desc;
if (!JS_GetPropertyDescriptorById(cx, proto, nsDOMClassInfo::sLength_id, JSRESOLVE_QUALIFIED, &desc))
return false;
if (desc.obj != proto || desc.getter != length_getter)
return true; // don't cache
if (!JS_GetPropertyDescriptorById(cx, proto, nsDOMClassInfo::sItem_id, JSRESOLVE_QUALIFIED, &desc))
return false;
if (desc.obj != proto || desc.getter || JSVAL_IS_PRIMITIVE(desc.value) ||
!JS_IsNativeFunction(JSVAL_TO_OBJECT(desc.value), item)) {
return true; // don't cache
for (size_t n = 0; n < NS_ARRAY_LENGTH(sProtoMethods); ++n) {
jsid id = sProtoMethods[n].id;
if (!JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc))
return false;
if (desc.obj != proto || desc.getter || JSVAL_IS_PRIMITIVE(desc.value) ||
n >= js::GetNumSlots(proto) || js::GetSlot(proto, n) != desc.value ||
!JS_IsNativeFunction(JSVAL_TO_OBJECT(desc.value), sProtoMethods[n].native)) {
return true; // don't cache
}
}
setProtoShape(proxy, js::GetObjectShape(proto));
setItemFunction(proxy, JSVAL_TO_OBJECT(desc.value));
return true;
}
@ -438,7 +442,7 @@ NodeList<T>::checkForCacheHit(JSContext *cx, JSObject *proxy, JSObject *receiver
jsid id, Value *vp, bool *hitp)
{
if (getProtoShape(proxy) != js::GetObjectShape(proto)) {
if (!cacheItemAndLength(cx, proxy, proto))
if (!cacheProtoShape(cx, proxy, proto))
return false;
if (getProtoShape(proxy) != js::GetObjectShape(proto)) {
*hitp = false;
@ -463,25 +467,23 @@ NodeList<T>::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Va
}
JSObject *proto = js::GetObjectProto(proxy);
if (id == nsDOMClassInfo::sLength_id) {
bool hit;
if (!checkForCacheHit(cx, proxy, receiver, proto, id, vp, &hit))
return false;
if (hit) {
bool hit;
if (!checkForCacheHit(cx, proxy, receiver, proto, id, vp, &hit))
return false;
if (hit) {
if (id == nsDOMClassInfo::sLength_id) {
PRUint32 length;
getNodeList(proxy)->GetLength(&length);
JS_ASSERT(int32(length) >= 0);
vp->setInt32(length);
return true;
}
}
else if (id == nsDOMClassInfo::sItem_id) {
bool hit;
if (!checkForCacheHit(cx, proxy, receiver, proto, id, vp, &hit))
return false;
if (hit) {
vp->setObject(*getItemFunction(proxy));
return true;
for (size_t n = 0; n < NS_ARRAY_LENGTH(sProtoMethods); ++n) {
if (id == sProtoMethods[n].id) {
*vp = js::GetSlot(proto, n);
JS_ASSERT(JS_IsNativeFunction(&vp->toObject(), sProtoMethods[n].native));
return true;
}
}
}
@ -517,7 +519,7 @@ template<class T>
bool
NodeList<T>::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
{
*bp = vp->isObject() && js::GetObjectClass(&vp->toObject()) == &NodeListProtoClass;
*bp = vp->isObject() && js::GetObjectClass(&vp->toObject()) == &sProtoClass;
return true;
}

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

@ -55,8 +55,10 @@ public:
static void* ProxyFamily() { return &NodeListFamily; }
static JSObject *create(JSContext *cx, nsINodeList *aNodeList);
static JSObject *create(JSContext *cx, nsIHTMLCollection *aHTMLCollection,
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope,
nsINodeList *aNodeList);
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope,
nsIHTMLCollection *aHTMLCollection,
nsWrapperCache *aWrapperCache);
private:
static int NodeListFamily;
@ -69,31 +71,29 @@ template<class T>
class NodeList : public NodeListBase {
static NodeList instance;
static js::Class NodeListProtoClass;
static js::Class sProtoClass;
struct Methods {
jsid &id;
JSNative native;
uintN nargs;
};
static Methods sProtoMethods[];
static bool instanceIsNodeListObject(JSContext *cx, JSObject *obj);
// Prototype-creation code that's the same (modulo templating) for
// all specializations.
static JSObject *getPrototypeShared(JSContext *cx);
// Specialization-specific prototype setup.
static JSObject *getPrototype(JSContext *cx);
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope);
static T *getNodeList(JSObject *obj);
static uint32 getProtoShape(JSObject *obj);
static void setProtoShape(JSObject *obj, uint32 shape);
static JSObject *getItemFunction(JSObject *obj);
static void setItemFunction(JSObject *obj, JSObject *funobj);
static JSBool length_getter(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
static JSBool item(JSContext *cx, uintN argc, jsval *vp);
static JSBool namedItem(JSContext *cx, uintN argc, jsval *vp);
static bool cacheItemAndLength(JSContext *cx, JSObject *proxy, JSObject *proto);
static bool cacheProtoShape(JSContext *cx, JSObject *proxy, JSObject *proto);
static bool checkForCacheHit(JSContext *cx, JSObject *proxy, JSObject *receiver, JSObject *proto,
jsid id, js::Value *vp, bool *hitp);
public:
@ -123,7 +123,8 @@ class NodeList : public NodeListBase {
JSString *obj_toString(JSContext *cx, JSObject *proxy);
void finalize(JSContext *cx, JSObject *proxy);
static JSObject *create(JSContext *cx, T *, nsWrapperCache* aWrapperCache);
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, T *,
nsWrapperCache* aWrapperCache);
static bool objIsNodeList(JSObject *obj) {
return js::IsProxy(obj) && js::GetProxyHandler(obj) == &instance;

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

@ -1070,6 +1070,40 @@ CreateNewCompartment(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
return true;
}
#ifdef DEBUG
struct VerifyTraceXPCGlobalCalledTracer
{
JSTracer base;
bool ok;
};
static void
VerifyTraceXPCGlobalCalled(JSTracer *trc, void *thing, JSGCTraceKind kind)
{
// We don't do anything here, we only want to verify that TraceXPCGlobal
// was called.
}
#endif
void
TraceXPCGlobal(JSTracer *trc, JSObject *obj)
{
#ifdef DEBUG
if(trc->callback == VerifyTraceXPCGlobalCalled)
{
// We don't do anything here, we only want to verify that TraceXPCGlobal
// was called.
reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = JS_TRUE;
return;
}
#endif
XPCWrappedNativeScope *scope =
XPCWrappedNativeScope::GetNativeScope(trc->context, obj);
if(scope)
scope->TraceDOMPrototypes(trc);
}
nsresult
xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
nsIPrincipal *principal, nsISupports *ptr,
@ -1105,6 +1139,17 @@ xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
*global = tempGlobal;
}
#ifdef DEBUG
if(clasp->flags & JSCLASS_XPCONNECT_GLOBAL)
{
VerifyTraceXPCGlobalCalledTracer trc;
JS_TRACER_INIT(&trc.base, cx, VerifyTraceXPCGlobalCalled);
trc.ok = JS_FALSE;
JS_TraceChildren(&trc.base, *global, JSTRACE_OBJECT);
NS_ABORT_IF_FALSE(trc.ok, "Trace hook needs to call TraceXPCGlobal if JSCLASS_XPCONNECT_GLOBAL is set.");
}
#endif
return NS_OK;
}

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

@ -3103,10 +3103,10 @@ sandbox_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
static JSClass SandboxClass = {
"Sandbox",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS,
XPCONNECT_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
sandbox_enumerate, sandbox_resolve, sandbox_convert, sandbox_finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
NULL, NULL, NULL, NULL, NULL, NULL, TraceXPCGlobal
};
static JSFunctionSpec SandboxFunctions[] = {

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

@ -1169,7 +1169,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
return JS_FALSE;
if(!flat) {
flat = cache->WrapObject(lccx.GetJSContext());
flat = cache->WrapObject(lccx.GetJSContext(), xpcscope);
if (!flat) {
flat = ConstructProxyObject(ccx, aHelper, xpcscope);
}

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

@ -1600,6 +1600,23 @@ public:
XPCContext *GetContext() { return mContext; }
void SetContext(XPCContext *xpcc) { mContext = nsnull; }
nsDataHashtable<nsIDHashKey, JSObject*>& GetCachedDOMPrototypes()
{
return mCachedDOMPrototypes;
}
static XPCWrappedNativeScope *GetNativeScope(JSContext *cx, JSObject *obj)
{
JS_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL);
jsval vp;
JS_ALWAYS_TRUE(JS_GetReservedSlot(cx, obj, JSCLASS_GLOBAL_SLOT_COUNT,
&vp));
return JSVAL_IS_VOID(vp) ? nsnull :
static_cast<XPCWrappedNativeScope*>(JSVAL_TO_PRIVATE(vp));
}
void TraceDOMPrototypes(JSTracer *trc);
protected:
XPCWrappedNativeScope(XPCCallContext& ccx, JSObject* aGlobal);
virtual ~XPCWrappedNativeScope();
@ -1639,6 +1656,8 @@ private:
// How do we deal? Do we need to? I suspect this isn't worth worrying
// about, since all of our scope objects are verified as not doing that.
nsIScriptObjectPrincipal* mScriptObjectPrincipal;
nsDataHashtable<nsIDHashKey, JSObject*> mCachedDOMPrototypes;
};
JSObject* xpc_CloneJSFunction(XPCCallContext &ccx, JSObject *funobj,
@ -2666,6 +2685,9 @@ public:
JSObject* wrapper = GetWrapperPreserveColor();
if(wrapper)
JS_CALL_OBJECT_TRACER(trc, wrapper, "XPCWrappedNative::mWrapper");
if(mScriptableInfo &&
(mScriptableInfo->GetJSClass()->flags & JSCLASS_XPCONNECT_GLOBAL))
GetScope()->TraceDOMPrototypes(trc);
}
inline void AutoTrace(JSTracer* trc)

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

@ -68,6 +68,13 @@ xpc_CreateMTGlobalObject(JSContext *cx, JSClass *clasp,
nsISupports *ptr, JSObject **global,
JSCompartment **compartment);
#define XPCONNECT_GLOBAL_FLAGS \
JSCLASS_XPCONNECT_GLOBAL | JSCLASS_HAS_PRIVATE | \
JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(1)
void
TraceXPCGlobal(JSTracer *trc, JSObject *obj);
// XXX where should this live?
NS_EXPORT_(void)
xpc_LocalizeContext(JSContext *cx);

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

@ -212,7 +212,7 @@ SafeFinalize(JSContext* cx, JSObject* obj)
static JSClass global_class = {
"global_for_XPCJSContextStack_SafeJSContext",
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS,
XPCONNECT_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize,
JSCLASS_NO_OPTIONAL_MEMBERS

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

@ -1146,7 +1146,7 @@ XPCWrappedNative::Init(XPCCallContext& ccx,
// JS class without the proper global flags. Notice that here and fix
// the problem.
if(!(jsclazz->flags & JSCLASS_IS_GLOBAL))
jsclazz->flags |= JSCLASS_GLOBAL_FLAGS;
jsclazz->flags |= XPCONNECT_GLOBAL_FLAGS;
}
else
NS_ASSERTION(!(jsclazz->flags & JSCLASS_IS_GLOBAL),

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

@ -1473,7 +1473,7 @@ XPCNativeScriptableShared::PopulateJSClass(JSBool isGlobal)
JSCLASS_NEW_RESOLVE;
if(isGlobal)
mJSClass.base.flags |= JSCLASS_GLOBAL_FLAGS;
mJSClass.base.flags |= XPCONNECT_GLOBAL_FLAGS;
JSPropertyOp addProperty;
if(mFlags.WantAddProperty())

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

@ -129,6 +129,10 @@ XPCWrappedNativeScope::GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal)
// called by nsXPConnect::InitClasses.
scope->SetGlobal(ccx, aGlobal);
}
if(js::GetObjectClass(aGlobal)->flags & JSCLASS_XPCONNECT_GLOBAL)
JS_ALWAYS_TRUE(JS_SetReservedSlot(ccx, aGlobal,
JSCLASS_GLOBAL_SLOT_COUNT,
PRIVATE_TO_JSVAL(scope)));
return scope;
}
@ -449,6 +453,8 @@ XPCWrappedNativeScope::FinishedMarkPhaseOfGC(JSContext* cx, XPCJSRuntime* rt)
{
cur->mGlobalJSObject = nsnull;
cur->mScriptObjectPrincipal = nsnull;
if(cur->GetCachedDOMPrototypes().IsInitialized())
cur->GetCachedDOMPrototypes().Clear();
// Move this scope from the live list to the dying list.
if(prev)
prev->mNext = next;
@ -803,6 +809,13 @@ XPCWrappedNativeScope::FindInJSObjectScope(JSContext* cx, JSObject* obj,
obj = JS_GetGlobalForObject(cx, obj);
if(js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL)
{
scope = XPCWrappedNativeScope::GetNativeScope(cx, obj);
if(scope)
return scope;
}
if(!runtime)
{
runtime = nsXPConnect::GetRuntimeInstance();
@ -907,6 +920,22 @@ XPCWrappedNativeScope::RemoveWrappedNativeProtos()
GetRuntime()->GetDetachedWrappedNativeProtoMap());
}
static PLDHashOperator
TraceDOMPrototype(const nsID& aKey, JSObject* aData, void* aClosure)
{
JSTracer *trc = static_cast<JSTracer*>(aClosure);
JS_CALL_OBJECT_TRACER(trc, aData, "DOM prototype");
return PL_DHASH_NEXT;
}
void
XPCWrappedNativeScope::TraceDOMPrototypes(JSTracer *trc)
{
if(mCachedDOMPrototypes.IsInitialized()) {
mCachedDOMPrototypes.EnumerateRead(TraceDOMPrototype, trc);
}
}
/***************************************************************************/
// static