Bug 754044 - Introduce sameCompartmentWrapObjectCallback. r=mrbkap

We leave it null for gecko for the time being to keep this patch small.
This commit is contained in:
Bobby Holley 2012-05-14 23:30:07 +02:00
parent 28257a13d5
commit 0ff9136104
6 changed files with 47 additions and 10 deletions

View File

@ -35,6 +35,13 @@ wrap(JSContext *cx, JSObject *toWrap, JSObject *target)
return wrapper;
}
static JSObject *
SameCompartmentWrap(JSContext *cx, JSObject *obj)
{
JS_GC(JS_GetRuntime(cx));
return obj;
}
static JSObject *
PreWrap(JSContext *cx, JSObject *scope, JSObject *obj, unsigned flags)
{
@ -78,7 +85,7 @@ BEGIN_TEST(testBug604087)
CHECK(next);
}
JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), Wrap, PreWrap);
JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), Wrap, SameCompartmentWrap, PreWrap);
CHECK(JS_TransplantObject(cx, outerObj, next));
return true;
}

View File

@ -792,6 +792,7 @@ JSRuntime::JSRuntime()
pendingProxyOperation(NULL),
trustedPrincipals_(NULL),
wrapObjectCallback(TransparentObjectWrapper),
sameCompartmentWrapObjectCallback(NULL),
preWrapObjectCallback(NULL),
preserveWrapperCallback(NULL),
#ifdef DEBUG
@ -1340,10 +1341,12 @@ JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback cal
JS_PUBLIC_API(JSWrapObjectCallback)
JS_SetWrapObjectCallbacks(JSRuntime *rt,
JSWrapObjectCallback callback,
JSSameCompartmentWrapObjectCallback sccallback,
JSPreWrapCallback precallback)
{
JSWrapObjectCallback old = rt->wrapObjectCallback;
rt->wrapObjectCallback = callback;
rt->sameCompartmentWrapObjectCallback = sccallback;
rt->preWrapObjectCallback = precallback;
return old;
}

View File

@ -1693,6 +1693,19 @@ typedef JSObject *
typedef JSObject *
(* JSPreWrapCallback)(JSContext *cx, JSObject *scope, JSObject *obj, unsigned flags);
/*
* Callback used when wrapping determines that the underlying object is already
* in the compartment for which it is being wrapped. This allows consumers to
* maintain same-compartment wrapping invariants.
*
* |obj| is guaranteed to be same-compartment as |cx|, but it may (or may not)
* be a security or cross-compartment wrapper. This is an unfortunate contract,
* but is important for to avoid unnecessarily recomputing every cross-
* compartment wrapper that gets passed to wrap.
*/
typedef JSObject *
(* JSSameCompartmentWrapObjectCallback)(JSContext *cx, JSObject *obj);
typedef void
(* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment);
@ -2783,6 +2796,7 @@ JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback cal
extern JS_PUBLIC_API(JSWrapObjectCallback)
JS_SetWrapObjectCallbacks(JSRuntime *rt,
JSWrapObjectCallback callback,
JSSameCompartmentWrapObjectCallback sccallback,
JSPreWrapCallback precallback);
extern JS_PUBLIC_API(JSCrossCompartmentCall *)

View File

@ -779,9 +779,10 @@ struct JSRuntime : js::RuntimeFriendFields
/* Tables of strings that are pre-allocated in the atomsCompartment. */
js::StaticStrings staticStrings;
JSWrapObjectCallback wrapObjectCallback;
JSPreWrapCallback preWrapObjectCallback;
js::PreserveWrapperCallback preserveWrapperCallback;
JSWrapObjectCallback wrapObjectCallback;
JSSameCompartmentWrapObjectCallback sameCompartmentWrapObjectCallback;
JSPreWrapCallback preWrapObjectCallback;
js::PreserveWrapperCallback preserveWrapperCallback;
js::ScriptFilenameTable scriptFilenameTable;

View File

@ -132,6 +132,19 @@ JSCompartment::setNeedsBarrier(bool needs)
needsBarrier_ = needs;
}
static bool
WrapForSameCompartment(JSContext *cx, JSObject *obj, Value *vp)
{
JS_ASSERT(cx->compartment == obj->compartment());
if (cx->runtime->sameCompartmentWrapObjectCallback) {
obj = cx->runtime->sameCompartmentWrapObjectCallback(cx, obj);
if (!obj)
return false;
}
vp->setObject(*obj);
return true;
}
bool
JSCompartment::wrap(JSContext *cx, Value *vp)
{
@ -179,9 +192,8 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isObject()) {
JSObject *obj = &vp->toObject();
/* If the object is already in this compartment, we are done. */
if (obj->compartment() == this)
return true;
return WrapForSameCompartment(cx, obj, vp);
/* Translate StopIteration singleton. */
if (obj->isStopIteration())
@ -190,9 +202,8 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
/* Unwrap the object, but don't unwrap outer windows. */
obj = UnwrapObject(&vp->toObject(), /* stopAtOuter = */ true, &flags);
vp->setObject(*obj);
if (obj->compartment() == this)
return true;
return WrapForSameCompartment(cx, obj, vp);
if (cx->runtime->preWrapObjectCallback) {
obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags);
@ -200,9 +211,9 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
return false;
}
vp->setObject(*obj);
if (obj->compartment() == this)
return true;
return WrapForSameCompartment(cx, obj, vp);
vp->setObject(*obj);
#ifdef DEBUG
{

View File

@ -1999,6 +1999,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
JS_SetWrapObjectCallbacks(mJSRuntime,
xpc::WrapperFactory::Rewrap,
NULL,
xpc::WrapperFactory::PrepareForWrapping);
js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
#ifdef MOZ_CRASHREPORTER