mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
Bug 926012 - Part 3: Convert wrappers to using dynamic prototype hooks. (r=bholley)
This commit is contained in:
parent
7f87debdf9
commit
46a65bdd10
@ -1011,11 +1011,7 @@ static JSObject*
|
||||
NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> parent, bool isChrome)
|
||||
{
|
||||
JSAutoCompartment ac(cx, parent);
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
if (!js::GetObjectProto(cx, parent, &proto))
|
||||
return nullptr;
|
||||
|
||||
JSObject *obj = js::Wrapper::New(cx, parent, proto, parent,
|
||||
JSObject *obj = js::Wrapper::New(cx, parent, parent,
|
||||
isChrome ? &nsChromeOuterWindowProxy::singleton
|
||||
: &nsOuterWindowProxy::singleton);
|
||||
|
||||
@ -2103,26 +2099,11 @@ nsGlobalWindow::CreateOuterObject(nsGlobalWindow* aNewInner)
|
||||
|
||||
js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
|
||||
|
||||
return SetOuterObject(cx, outer);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalWindow::SetOuterObject(JSContext* aCx, JS::Handle<JSObject*> aOuterObject)
|
||||
{
|
||||
JSAutoCompartment ac(aCx, aOuterObject);
|
||||
JSAutoCompartment ac(cx, outer);
|
||||
|
||||
// Inform the nsJSContext, which is the canonical holder of the outer.
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
mContext->SetWindowProxy(aOuterObject);
|
||||
|
||||
// Set up the prototype for the outer object.
|
||||
JS::Rooted<JSObject*> inner(aCx, JS_GetParent(aOuterObject));
|
||||
JS::Rooted<JSObject*> proto(aCx);
|
||||
if (!JS_GetPrototype(aCx, inner, &proto)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS_SetPrototype(aCx, aOuterObject, proto);
|
||||
|
||||
mContext->SetWindowProxy(outer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2457,8 +2438,9 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, mJSObject);
|
||||
rv = SetOuterObject(cx, obj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Inform the nsJSContext, which is the canonical holder of the outer.
|
||||
mContext->SetWindowProxy(obj);
|
||||
|
||||
NS_ASSERTION(!JS_IsExceptionPending(cx),
|
||||
"We might overwrite a pending exception!");
|
||||
|
@ -60,13 +60,12 @@ static JSObject *
|
||||
Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj,
|
||||
JS::HandleObject proto, JS::HandleObject parent, unsigned flags)
|
||||
{
|
||||
return js::Wrapper::New(cx, obj, proto, parent, &js::CrossCompartmentWrapper::singleton);
|
||||
return js::Wrapper::New(cx, obj, parent, &js::CrossCompartmentWrapper::singleton);
|
||||
}
|
||||
|
||||
BEGIN_TEST(testBug604087)
|
||||
{
|
||||
JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, global->getProto(), global,
|
||||
&OuterWrapper::singleton));
|
||||
JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, global, &OuterWrapper::singleton));
|
||||
JS::RootedObject compartment2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
JS::RootedObject compartment3(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
JS::RootedObject compartment4(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
@ -87,8 +86,7 @@ BEGIN_TEST(testBug604087)
|
||||
JS::RootedObject next(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, compartment2);
|
||||
next = js::Wrapper::New(cx, compartment2, compartment2->getProto(), compartment2,
|
||||
&OuterWrapper::singleton);
|
||||
next = js::Wrapper::New(cx, compartment2, compartment2, &OuterWrapper::singleton);
|
||||
CHECK(next);
|
||||
}
|
||||
|
||||
|
@ -516,6 +516,19 @@ DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandle
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DirectProxyHandler::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop)
|
||||
{
|
||||
RootedObject target(cx, proxy->as<ProxyObject>().target());
|
||||
return JSObject::getProto(cx, target, protop);
|
||||
}
|
||||
|
||||
bool
|
||||
DirectProxyHandler::setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp)
|
||||
{
|
||||
RootedObject target(cx, proxy->as<ProxyObject>().target());
|
||||
return JSObject::setProto(cx, target, proto, bp);
|
||||
}
|
||||
|
||||
bool
|
||||
DirectProxyHandler::objectClassIs(HandleObject proxy, ESClassValue classValue,
|
||||
|
@ -252,6 +252,8 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
|
||||
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
|
||||
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
|
||||
JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
|
||||
|
@ -39,7 +39,7 @@ Wrapper::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHan
|
||||
}
|
||||
|
||||
JSObject *
|
||||
Wrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, Wrapper *handler)
|
||||
Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler)
|
||||
{
|
||||
JS_ASSERT(parent);
|
||||
|
||||
@ -48,7 +48,7 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, Wr
|
||||
RootedValue priv(cx, ObjectValue(*obj));
|
||||
ProxyOptions options;
|
||||
options.setCallable(obj->isCallable());
|
||||
return NewProxyObject(cx, handler, priv, proto, parent, options);
|
||||
return NewProxyObject(cx, handler, priv, Proxy::LazyProto, parent, options);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -141,7 +141,8 @@ js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject
|
||||
{
|
||||
// Allow wrapping outer window proxies.
|
||||
JS_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
|
||||
return Wrapper::New(cx, obj, wrappedProto, parent, &CrossCompartmentWrapper::singleton);
|
||||
JS_ASSERT(wrappedProto == Proxy::LazyProto);
|
||||
return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
|
||||
}
|
||||
|
||||
ErrorCopier::~ErrorCopier()
|
||||
@ -578,11 +579,6 @@ bool
|
||||
CrossCompartmentWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper,
|
||||
MutableHandleObject protop)
|
||||
{
|
||||
if (!wrapper->getTaggedProto().isLazy()) {
|
||||
protop.set(wrapper->getTaggedProto().toObjectOrNull());
|
||||
return true;
|
||||
}
|
||||
|
||||
{
|
||||
RootedObject wrapped(cx, wrappedObject(wrapper));
|
||||
AutoCompartment call(cx, wrapped);
|
||||
@ -595,6 +591,17 @@ CrossCompartmentWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper,
|
||||
return cx->compartment()->wrap(cx, protop);
|
||||
}
|
||||
|
||||
bool
|
||||
CrossCompartmentWrapper::setPrototypeOf(JSContext *cx, HandleObject wrapper,
|
||||
HandleObject proto, bool *bp)
|
||||
{
|
||||
RootedObject protoCopy(cx, proto);
|
||||
PIERCE(cx, wrapper,
|
||||
cx->compartment()->wrap(cx, &protoCopy),
|
||||
Wrapper::setPrototypeOf(cx, wrapper, protoCopy, bp),
|
||||
NOTHING);
|
||||
}
|
||||
|
||||
CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
|
||||
|
||||
/* Security wrappers. */
|
||||
@ -646,6 +653,15 @@ SecurityWrapper<Base>::nativeCall(JSContext *cx, IsAcceptableThis test, NativeIm
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Base>
|
||||
bool
|
||||
SecurityWrapper<Base>::setPrototypeOf(JSContext *cx, HandleObject wrapper,
|
||||
HandleObject proto, bool *bp)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNWRAP_DENIED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// For security wrappers, we run the DefaultValue algorithm on the wrapper
|
||||
// itself, which means that the existing security policy on operations like
|
||||
// toString() will take effect and do the right thing here.
|
||||
|
@ -49,8 +49,7 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
||||
void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; }
|
||||
bool isSafeToUnwrap() { return mSafeToUnwrap; }
|
||||
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto,
|
||||
JSObject *parent, Wrapper *handler);
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler);
|
||||
|
||||
static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, Wrapper *handler);
|
||||
|
||||
@ -120,7 +119,10 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
|
||||
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
|
||||
virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
|
||||
MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
|
||||
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
|
||||
MutableHandleObject protop) MOZ_OVERRIDE;
|
||||
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
|
||||
static CrossCompartmentWrapper singleton;
|
||||
static CrossCompartmentWrapper singletonWithPrototype;
|
||||
@ -155,6 +157,9 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::HandleObject callable) MOZ_OVERRIDE;
|
||||
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) MOZ_OVERRIDE;
|
||||
|
@ -3743,6 +3743,34 @@ ThisFilename(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal class for testing hasPrototype easily.
|
||||
* Uses passed in prototype instead of target's.
|
||||
*/
|
||||
class WrapperWithProto : public Wrapper
|
||||
{
|
||||
public:
|
||||
explicit WrapperWithProto(unsigned flags)
|
||||
: Wrapper(flags, true)
|
||||
{ }
|
||||
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
|
||||
Wrapper *handler);
|
||||
};
|
||||
|
||||
/* static */ JSObject *
|
||||
WrapperWithProto::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
|
||||
Wrapper *handler)
|
||||
{
|
||||
JS_ASSERT(parent);
|
||||
AutoMarkInDeadZone amd(cx->zone());
|
||||
|
||||
RootedValue priv(cx, ObjectValue(*obj));
|
||||
ProxyOptions options;
|
||||
options.setCallable(obj->isCallable());
|
||||
return NewProxyObject(cx, handler, priv, proto, parent, options);
|
||||
}
|
||||
|
||||
static bool
|
||||
Wrap(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
@ -3753,10 +3781,7 @@ Wrap(JSContext *cx, unsigned argc, jsval *vp)
|
||||
}
|
||||
|
||||
RootedObject obj(cx, JSVAL_TO_OBJECT(v));
|
||||
RootedObject proto(cx);
|
||||
if (!JSObject::getProto(cx, obj, &proto))
|
||||
return false;
|
||||
JSObject *wrapped = Wrapper::New(cx, obj, proto, &obj->global(),
|
||||
JSObject *wrapped = Wrapper::New(cx, obj, &obj->global(),
|
||||
&Wrapper::singleton);
|
||||
if (!wrapped)
|
||||
return false;
|
||||
@ -3779,9 +3804,9 @@ WrapWithProto(JSContext *cx, unsigned argc, jsval *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *wrapped = Wrapper::New(cx, &obj.toObject(), proto.toObjectOrNull(),
|
||||
&obj.toObject().global(),
|
||||
&Wrapper::singletonWithPrototype);
|
||||
JSObject *wrapped = WrapperWithProto::New(cx, &obj.toObject(), proto.toObjectOrNull(),
|
||||
&obj.toObject().global(),
|
||||
&Wrapper::singletonWithPrototype);
|
||||
if (!wrapped)
|
||||
return false;
|
||||
|
||||
|
@ -91,4 +91,11 @@ WaiveXrayWrapper::nativeCall(JSContext *cx, JS::IsAcceptableThis test,
|
||||
WrapperFactory::WaiveXrayAndWrap(cx, args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
WaiveXrayWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper, MutableHandleObject protop)
|
||||
{
|
||||
return CrossCompartmentWrapper::getPrototypeOf(cx, wrapper, protop) &&
|
||||
(!protop || WrapperFactory::WaiveXrayAndWrap(cx, protop));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper {
|
||||
virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test,
|
||||
JS::NativeImpl impl, JS::CallArgs args) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool getPrototypeOf(JSContext *cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::MutableHandle<JSObject*> protop) MOZ_OVERRIDE;
|
||||
|
||||
static WaiveXrayWrapper singleton;
|
||||
};
|
||||
|
||||
|
@ -75,18 +75,8 @@ WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
|
||||
MOZ_ASSERT(!GetXrayWaiver(obj));
|
||||
XPCWrappedNativeScope *scope = GetObjectScope(obj);
|
||||
|
||||
// Get a waiver for the proto.
|
||||
RootedObject proto(cx);
|
||||
if (!js::GetObjectProto(cx, obj, &proto))
|
||||
return nullptr;
|
||||
if (proto && !(proto = WaiveXray(cx, proto)))
|
||||
return nullptr;
|
||||
|
||||
// Create the waiver.
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
if (!JS_WrapObject(cx, &proto))
|
||||
return nullptr;
|
||||
JSObject *waiver = Wrapper::New(cx, obj, proto,
|
||||
JSObject *waiver = Wrapper::New(cx, obj,
|
||||
JS_GetGlobalForObject(cx, obj),
|
||||
&XrayWaiver);
|
||||
if (!waiver)
|
||||
@ -409,10 +399,6 @@ WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
|
||||
XrayType xrayType = GetXrayType(obj);
|
||||
bool waiveXrayFlag = flags & WAIVE_XRAY_WRAPPER_FLAG;
|
||||
|
||||
// By default we use the wrapped proto of the underlying object as the
|
||||
// prototype for our wrapper, but we may select something different below.
|
||||
RootedObject proxyProto(cx, wrappedProto);
|
||||
|
||||
Wrapper *wrapper;
|
||||
CompartmentPrivate *targetdata = EnsureCompartmentPrivate(target);
|
||||
|
||||
@ -498,10 +484,10 @@ WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
|
||||
|
||||
DEBUG_CheckUnwrapSafety(obj, wrapper, origin, target);
|
||||
|
||||
if (existing && proxyProto == wrappedProto)
|
||||
if (existing)
|
||||
return Wrapper::Renew(cx, existing, obj, wrapper);
|
||||
|
||||
return Wrapper::New(cx, obj, proxyProto, parent, wrapper);
|
||||
return Wrapper::New(cx, obj, parent, wrapper);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -549,10 +535,22 @@ WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleValue vp)
|
||||
if (vp.isPrimitive())
|
||||
return JS_WrapValue(cx, vp);
|
||||
|
||||
JSObject *obj = js::UncheckedUnwrap(&vp.toObject());
|
||||
RootedObject obj(cx, &vp.toObject());
|
||||
if (!WaiveXrayAndWrap(cx, &obj))
|
||||
return false;
|
||||
|
||||
vp.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleObject argObj)
|
||||
{
|
||||
MOZ_ASSERT(argObj);
|
||||
RootedObject obj(cx, js::UncheckedUnwrap(argObj));
|
||||
MOZ_ASSERT(!js::IsInnerObject(obj));
|
||||
if (js::IsObjectInContextCompartment(obj, cx)) {
|
||||
vp.setObject(*obj);
|
||||
argObj.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -570,24 +568,23 @@ WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleValue vp)
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
vp.setObject(*obj);
|
||||
return JS_WrapValue(cx, vp);
|
||||
if (!JS_WrapObject(cx, &obj))
|
||||
return false;
|
||||
argObj.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
WrapperFactory::WrapSOWObject(JSContext *cx, JSObject *objArg)
|
||||
{
|
||||
RootedObject obj(cx, objArg);
|
||||
RootedObject proto(cx);
|
||||
|
||||
// If we're not allowing XBL scopes, that means we're running as a remote
|
||||
// XUL domain, in which we can't have SOWs. We should never be called in
|
||||
// that case.
|
||||
MOZ_ASSERT(xpc::AllowXBLScope(js::GetContextCompartment(cx)));
|
||||
if (!JS_GetPrototype(cx, obj, &proto))
|
||||
return nullptr;
|
||||
JSObject *wrapperObj =
|
||||
Wrapper::New(cx, obj, proto, JS_GetGlobalForObject(cx, obj),
|
||||
Wrapper::New(cx, obj, JS_GetGlobalForObject(cx, obj),
|
||||
&FilteringWrapper<SameCompartmentSecurityWrapper,
|
||||
Opaque>::singleton);
|
||||
return wrapperObj;
|
||||
@ -603,11 +600,8 @@ WrapperFactory::IsComponentsObject(JSObject *obj)
|
||||
JSObject *
|
||||
WrapperFactory::WrapComponentsObject(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
RootedObject proto(cx);
|
||||
if (!JS_GetPrototype(cx, obj, &proto))
|
||||
return nullptr;
|
||||
JSObject *wrapperObj =
|
||||
Wrapper::New(cx, obj, proto, JS_GetGlobalForObject(cx, obj),
|
||||
Wrapper::New(cx, obj, JS_GetGlobalForObject(cx, obj),
|
||||
&FilteringWrapper<SameCompartmentSecurityWrapper, ComponentsObjectPolicy>::singleton);
|
||||
|
||||
return wrapperObj;
|
||||
|
@ -64,6 +64,7 @@ class WrapperFactory {
|
||||
|
||||
// Wrap wrapped object into a waiver wrapper and then re-wrap it.
|
||||
static bool WaiveXrayAndWrap(JSContext *cx, JS::MutableHandleValue vp);
|
||||
static bool WaiveXrayAndWrap(JSContext *cx, JS::MutableHandleObject object);
|
||||
|
||||
// Wrap a (same compartment) object in a SOW.
|
||||
static JSObject *WrapSOWObject(JSContext *cx, JSObject *obj);
|
||||
|
@ -304,6 +304,7 @@ enum ExpandoSlots {
|
||||
JSSLOT_EXPANDO_NEXT = 0,
|
||||
JSSLOT_EXPANDO_ORIGIN,
|
||||
JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL,
|
||||
JSSLOT_EXPANDO_PROTOTYPE,
|
||||
JSSLOT_EXPANDO_COUNT
|
||||
};
|
||||
|
||||
@ -1792,6 +1793,56 @@ XrayWrapper<Base, Traits>::defaultValue(JSContext *cx, HandleObject wrapper,
|
||||
return js::DefaultValue(cx, wrapper, hint, vp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
bool
|
||||
XrayWrapper<Base, Traits>::getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
|
||||
JS::MutableHandleObject protop)
|
||||
{
|
||||
RootedObject target(cx, Traits::getTargetObject(wrapper));
|
||||
RootedObject expando(cx, Traits::singleton.getExpandoObject(cx, target, wrapper));
|
||||
|
||||
// We want to keep the Xray's prototype distinct from that of content, but only
|
||||
// if there's been a set. If there's not an expando, or the expando slot is |undefined|,
|
||||
// hand back content's proto, appropriately wrapped.
|
||||
//
|
||||
// NB: Our baseclass's getPrototypeOf() will appropriately wrap its return value, so there is
|
||||
// no need for us to.
|
||||
|
||||
if (!expando)
|
||||
return Base::getPrototypeOf(cx, wrapper, protop);
|
||||
|
||||
RootedValue v(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, expando);
|
||||
v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE);
|
||||
}
|
||||
|
||||
if (v.isUndefined())
|
||||
return Base::getPrototypeOf(cx, wrapper, protop);
|
||||
|
||||
protop.set(v.toObjectOrNull());
|
||||
return JS_WrapObject(cx, protop);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
bool
|
||||
XrayWrapper<Base, Traits>::setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
|
||||
JS::HandleObject proto, bool *bp)
|
||||
{
|
||||
RootedObject target(cx, Traits::getTargetObject(wrapper));
|
||||
RootedObject expando(cx, Traits::singleton.ensureExpandoObject(cx, wrapper, target));
|
||||
|
||||
// The expando lives in the target's compartment, so do our installation there.
|
||||
JSAutoCompartment ac(cx, target);
|
||||
|
||||
RootedValue v(cx, ObjectValue(*proto));
|
||||
if (!JS_WrapValue(cx, &v))
|
||||
return false;
|
||||
JS_SetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE, v);
|
||||
*bp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The Permissive / Security variants should be used depending on whether the
|
||||
|
@ -106,6 +106,11 @@ class XrayWrapper : public Base {
|
||||
JSType hint, JS::MutableHandleValue vp)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
|
||||
JS::MutableHandleObject protop) MOZ_OVERRIDE;
|
||||
virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
|
||||
JS::HandleObject proto, bool *bp) MOZ_OVERRIDE;
|
||||
|
||||
static XrayWrapper singleton;
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user