Bug 761695 - Unify holder creation and access. r=peterv

With this patch, all holders are created lazily. There are two common accessors,
getHolder() and ensureHolder(). The former returns null if no holder exists, the
latter lazily creates the holder if it doesn't exist. It does this by calling into
a virtual trap on XrayTraits, which lets the appropriate Xray type do its thing.
This commit is contained in:
Bobby Holley 2012-10-05 18:59:23 +02:00
parent 05eeb2aa4e
commit 1a9081b1ce
3 changed files with 61 additions and 122 deletions

View File

@ -329,7 +329,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
JSCompartment *origin = js::GetObjectCompartment(obj);
JSCompartment *target = js::GetContextCompartment(cx);
bool usingXray = false;
// By default we use the wrapped proto of the underlying object as the
// prototype for our wrapper, but we may select something different below.
@ -354,7 +353,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
wrapper = &XrayProxy::singleton;
} else if (type == XrayForWrappedNative) {
typedef XrayWrapper<CrossCompartmentWrapper> Xray;
usingXray = true;
wrapper = &Xray::singleton;
} else {
wrapper = &CrossCompartmentWrapper::singleton;
@ -377,7 +375,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
(wn = GetWrappedNative(cx, obj)) &&
wn->HasProto() && wn->GetProto()->ClassIsDOMObject()) {
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
usingXray = true;
if (IsLocationObject(obj))
wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
else
@ -441,7 +438,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
OnlyIfSubjectIsSystem>::singleton;
} else if (IsLocationObject(obj)) {
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
usingXray = true;
wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
} else if (IsComponentsObject(obj)) {
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
@ -455,7 +451,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
wrapper = &XrayProxy::singleton;
} else {
typedef XrayWrapper<CrossCompartmentWrapper> Xray;
usingXray = true;
wrapper = &Xray::singleton;
}
} else {
@ -476,7 +471,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
CrossOriginAccessiblePropertiesOnly>::singleton;
} else {
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
usingXray = true;
// Location objects can become same origin after navigation, so we might
// have to grant transparent access later on.
@ -489,15 +483,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
}
}
JSObject *wrapperObj = Wrapper::New(cx, obj, proxyProto, parent, wrapper);
if (!wrapperObj || !usingXray)
return wrapperObj;
JSObject *xrayHolder = XrayUtils::createHolder(cx, wrapperObj);
if (!xrayHolder)
return nullptr;
js::SetProxyExtra(wrapperObj, 0, js::ObjectValue(*xrayHolder));
return wrapperObj;
return Wrapper::New(cx, obj, proxyProto, parent, wrapper);
}
JSObject *
@ -534,15 +520,7 @@ WrapperFactory::WrapLocationObject(JSContext *cx, JSObject *obj)
JSObject *proto;
if (!js::GetObjectProto(cx, obj, &proto))
return nullptr;
JSObject *wrapperObj = Wrapper::New(cx, obj, proto, js::GetObjectParent(obj),
&LW::singleton);
if (!wrapperObj)
return nullptr;
JSObject *xrayHolder = XrayUtils::createHolder(cx, wrapperObj);
if (!xrayHolder)
return nullptr;
js::SetProxyExtra(wrapperObj, 0, js::ObjectValue(*xrayHolder));
return wrapperObj;
return Wrapper::New(cx, obj, proto, js::GetObjectParent(obj), &LW::singleton);
}
// Call WaiveXrayAndWrap when you have a JS object that you don't want to be
@ -627,19 +605,7 @@ WrapperFactory::WrapForSameCompartmentXray(JSContext *cx, JSObject *obj)
// Make the Xray.
JSObject *parent = JS_GetGlobalForObject(cx, obj);
JSObject *wrapperObj = Wrapper::New(cx, obj, NULL, parent, wrapper);
if (!wrapperObj)
return NULL;
// Make the holder. Note that this is currently for WNs only until we fix
// bug 761704.
if (type == XrayForWrappedNative) {
JSObject *xrayHolder = XrayUtils::createHolder(cx, wrapperObj);
if (!xrayHolder)
return nullptr;
js::SetProxyExtra(wrapperObj, 0, js::ObjectValue(*xrayHolder));
}
return wrapperObj;
return Wrapper::New(cx, obj, NULL, parent, wrapper);
}

View File

@ -249,20 +249,6 @@ CloneExpandoChain(JSContext *cx, JSObject *dst, JSObject *src)
}
return true;
}
JSObject *
createHolder(JSContext *cx, JSObject *wrapper)
{
JSObject *global = JS_GetGlobalForObject(cx, wrapper);
JSObject *holder = JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr,
global);
if (!holder)
return nullptr;
js::SetReservedSlot(holder, JSSLOT_RESOLVING, PrivateValue(NULL));
return holder;
}
}
using namespace XrayUtils;
@ -346,6 +332,11 @@ public:
{
MOZ_NOT_REACHED("Call trap currently implemented only for XPCWNs");
}
JSObject* getHolder(JSObject *wrapper);
JSObject* ensureHolder(JSContext *cx, JSObject *wrapper);
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) = 0;
};
class XPCWrappedNativeXrayTraits : public XrayTraits
@ -365,11 +356,6 @@ public:
static bool construct(JSContext *cx, JSObject *wrapper, unsigned argc,
Value *argv, Value *rval);
static JSObject* getHolderObject(JSContext *cx, JSObject *wrapper)
{
return getHolderObject(wrapper);
}
static bool isResolving(JSContext *cx, JSObject *holder, jsid id);
static bool resolveDOMCollectionProperty(JSContext *cx, JSObject *wrapper, JSObject *holder,
@ -381,13 +367,9 @@ public:
typedef ResolvingId ResolvingIdImpl;
static XPCWrappedNativeXrayTraits singleton;
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
private:
static JSObject* getHolderObject(JSObject *wrapper)
{
return &js::GetProxyExtra(wrapper, 0).toObject();
}
static XPCWrappedNativeXrayTraits singleton;
};
class ProxyXrayTraits : public XrayTraits
@ -403,10 +385,6 @@ public:
static bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
static bool enumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags,
JS::AutoIdVector &props);
static JSObject* getHolderObject(JSContext *cx, JSObject *wrapper)
{
return getHolderObject(cx, wrapper, true);
}
static bool isResolving(JSContext *cx, JSObject *holder, jsid id)
{
@ -415,21 +393,9 @@ public:
typedef ResolvingIdDummy ResolvingIdImpl;
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
static ProxyXrayTraits singleton;
private:
static JSObject* getHolderObject(JSContext *cx, JSObject *wrapper,
bool createHolder)
{
if (!js::GetProxyExtra(wrapper, 0).isUndefined())
return &js::GetProxyExtra(wrapper, 0).toObject();
if (!createHolder)
return nullptr;
return createHolderObject(cx, wrapper);
}
static JSObject* createHolderObject(JSContext *cx, JSObject *wrapper);
};
class DOMXrayTraits : public XrayTraits
@ -445,10 +411,6 @@ public:
static bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
static bool enumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags,
JS::AutoIdVector &props);
static JSObject* getHolderObject(JSContext *cx, JSObject *wrapper)
{
return getHolderObject(cx, wrapper, true);
}
static bool isResolving(JSContext *cx, JSObject *holder, jsid id)
{
@ -457,21 +419,9 @@ public:
typedef ResolvingIdDummy ResolvingIdImpl;
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
static DOMXrayTraits singleton;
private:
static JSObject* getHolderObject(JSContext *cx, JSObject *wrapper,
bool createHolder)
{
if (!js::GetProxyExtra(wrapper, 0).isUndefined())
return &js::GetProxyExtra(wrapper, 0).toObject();
if (!createHolder)
return nullptr;
return createHolderObject(cx, wrapper);
}
static JSObject* createHolderObject(JSContext *cx, JSObject *wrapper);
};
XPCWrappedNativeXrayTraits XPCWrappedNativeXrayTraits::singleton;
@ -510,6 +460,26 @@ FindWrapper(JSContext *cx, JSObject *wrapper)
return wrapper;
}
JSObject*
XrayTraits::getHolder(JSObject *wrapper)
{
MOZ_ASSERT(WrapperFactory::IsXrayWrapper(wrapper));
js::Value v = js::GetProxyExtra(wrapper, 0);
return v.isObject() ? &v.toObject() : nullptr;
}
JSObject*
XrayTraits::ensureHolder(JSContext *cx, JSObject *wrapper)
{
JSObject *holder = getHolder(wrapper);
if (holder)
return holder;
holder = createHolder(cx, wrapper); // virtual trap.
if (holder)
js::SetProxyExtra(wrapper, 0, ObjectValue(*holder));
return holder;
}
bool
XPCWrappedNativeXrayTraits::isResolving(JSContext *cx, JSObject *holder,
jsid id)
@ -1000,7 +970,7 @@ bool
XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
PropertyDescriptor *desc)
{
JSObject *holder = getHolderObject(wrapper);
JSObject *holder = singleton.ensureHolder(cx, wrapper);
if (isResolving(cx, holder, id)) {
if (!(desc->attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
if (!desc->getter)
@ -1089,6 +1059,19 @@ XPCWrappedNativeXrayTraits::enumerateNames(JSContext *cx, JSObject *wrapper, uns
return true;
}
JSObject *
XPCWrappedNativeXrayTraits::createHolder(JSContext *cx, JSObject *wrapper)
{
JSObject *global = JS_GetGlobalForObject(cx, wrapper);
JSObject *holder = JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr,
global);
if (!holder)
return nullptr;
js::SetReservedSlot(holder, JSSLOT_RESOLVING, PrivateValue(NULL));
return holder;
}
bool
XPCWrappedNativeXrayTraits::call(JSContext *cx, JSObject *wrapper,
unsigned argc, Value *vp)
@ -1166,7 +1149,7 @@ bool
ProxyXrayTraits::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
PropertyDescriptor *desc)
{
JSObject *holder = getHolderObject(cx, wrapper);
JSObject *holder = singleton.ensureHolder(cx, wrapper);
if (!holder)
return false;
@ -1182,7 +1165,7 @@ ProxyXrayTraits::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
return false;
JSObject *holder;
if (*bp && (holder = getHolderObject(cx, wrapper, false)))
if (*bp && (holder = singleton.getHolder(wrapper)))
JS_DeletePropertyById(cx, holder, id);
return true;
@ -1203,14 +1186,10 @@ ProxyXrayTraits::enumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags
// XPCWrappedNativeXrayTraits. Instead, it's a funny hybrid of the 'expando' and
// 'holder' properties. However, we store it in the same slot. Exercise caution.
JSObject*
ProxyXrayTraits::createHolderObject(JSContext *cx, JSObject *wrapper)
ProxyXrayTraits::createHolder(JSContext *cx, JSObject *wrapper)
{
JSObject *obj = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
JS_GetGlobalForObject(cx, wrapper));
if (!obj)
return nullptr;
js::SetProxyExtra(wrapper, 0, ObjectValue(*obj));
return obj;
return JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
JS_GetGlobalForObject(cx, wrapper));
}
bool
@ -1254,7 +1233,7 @@ DOMXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWrapper, JSObjec
bool
DOMXrayTraits::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
{
JSObject *holder = getHolderObject(cx, wrapper);
JSObject *holder = singleton.ensureHolder(cx, wrapper);
if (!holder)
return false;
@ -1266,7 +1245,7 @@ bool
DOMXrayTraits::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
{
JSObject *holder;
if ((holder = getHolderObject(cx, wrapper, false)))
if ((holder = singleton.getHolder(wrapper)))
JS_DeletePropertyById(cx, holder, id);
return true;
@ -1297,14 +1276,10 @@ DOMXrayTraits::enumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags,
}
JSObject*
DOMXrayTraits::createHolderObject(JSContext *cx, JSObject *wrapper)
DOMXrayTraits::createHolder(JSContext *cx, JSObject *wrapper)
{
JSObject *obj = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
JS_GetGlobalForObject(cx, wrapper));
if (!obj)
return nullptr;
js::SetProxyExtra(wrapper, 0, ObjectValue(*obj));
return obj;
return JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
JS_GetGlobalForObject(cx, wrapper));
}
template <typename Base, typename Traits>
@ -1393,7 +1368,7 @@ bool
XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
bool set, js::PropertyDescriptor *desc)
{
JSObject *holder = Traits::getHolderObject(cx, wrapper);
JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
if (Traits::isResolving(cx, holder, id)) {
desc->obj = NULL;
return true;
@ -1493,7 +1468,7 @@ bool
XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
bool set, PropertyDescriptor *desc)
{
JSObject *holder = Traits::getHolderObject(cx, wrapper);
JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
if (Traits::isResolving(cx, holder, id)) {
desc->obj = NULL;
return true;
@ -1550,7 +1525,7 @@ XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, JSObject *wrapper, jsid
// If shadowing is forbidden, see if the id corresponds to an underlying
// native property.
if (WrapperFactory::IsShadowingForbidden(wrapper)) {
JSObject *holder = Traits::getHolderObject(cx, wrapper);
JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
js::PropertyDescriptor nativeProp;
if (!Traits::resolveNativeProperty(cx, wrapper, holder, id, false, &nativeProp))
return false;

View File

@ -30,8 +30,6 @@ extern JSClass HolderClass;
bool CloneExpandoChain(JSContext *cx, JSObject *src, JSObject *dst);
JSObject *createHolder(JSContext *cx, JSObject *wrapper);
bool
IsTransparent(JSContext *cx, JSObject *wrapper);