зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
4c190491d0
Коммит
83c22ded1b
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче