зеркало из https://github.com/mozilla/gecko-dev.git
Bug 907937 - Move object wrapping into the object-overloaded wrap() function. r=billm
There are a couple of changes to the wrap code, so it probably needs to be looked over.
This commit is contained in:
Родитель
9aeaa42d0b
Коммит
dd996d1173
|
@ -1106,9 +1106,13 @@ JS_WrapObject(JSContext *cx, JSObject **objp)
|
|||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
if (*objp)
|
||||
JS::ExposeGCThingToActiveJS(*objp, JSTRACE_OBJECT);
|
||||
return cx->compartment()->wrap(cx, objp);
|
||||
RootedObject obj(cx, *objp);
|
||||
if (obj)
|
||||
JS::ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
|
||||
if (!cx->compartment()->wrap(cx, &obj))
|
||||
return false;
|
||||
*objp = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
|
|
@ -175,18 +175,18 @@ JSCompartment::ensureIonCompartmentExists(JSContext *cx)
|
|||
#endif
|
||||
|
||||
static bool
|
||||
WrapForSameCompartment(JSContext *cx, HandleObject obj, MutableHandleValue vp)
|
||||
WrapForSameCompartment(JSContext *cx, MutableHandleObject obj)
|
||||
{
|
||||
JS_ASSERT(cx->compartment() == obj->compartment());
|
||||
if (!cx->runtime()->sameCompartmentWrapObjectCallback) {
|
||||
vp.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *wrapped = cx->runtime()->sameCompartmentWrapObjectCallback(cx, obj);
|
||||
RootedObject wrapped(cx);
|
||||
wrapped = cx->runtime()->sameCompartmentWrapObjectCallback(cx, obj);
|
||||
if (!wrapped)
|
||||
return false;
|
||||
vp.setObject(*wrapped);
|
||||
obj.set(wrapped);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -205,19 +205,7 @@ JSCompartment::putWrapper(const CrossCompartmentKey &wrapped, const js::Value &w
|
|||
bool
|
||||
JSCompartment::wrap(JSContext *cx, MutableHandleValue vp, HandleObject existingArg)
|
||||
{
|
||||
JSRuntime *rt = runtimeFromMainThread();
|
||||
|
||||
JS_ASSERT(cx->compartment() == this);
|
||||
JS_ASSERT(!rt->isAtomsCompartment(this));
|
||||
JS_ASSERT_IF(existingArg, existingArg->compartment() == cx->compartment());
|
||||
JS_ASSERT_IF(existingArg, vp.isObject());
|
||||
JS_ASSERT_IF(existingArg, IsDeadProxyObject(existingArg));
|
||||
|
||||
unsigned flags = 0;
|
||||
|
||||
JS_CHECK_CHROME_RECURSION(cx, return false);
|
||||
|
||||
AutoDisableProxyCheck adpc(rt);
|
||||
|
||||
/* Only GC things have to be wrapped or copied. */
|
||||
if (!vp.isMarkable())
|
||||
|
@ -234,95 +222,19 @@ JSCompartment::wrap(JSContext *cx, MutableHandleValue vp, HandleObject existingA
|
|||
|
||||
/* All that's left are objects. */
|
||||
MOZ_ASSERT(vp.isObject());
|
||||
|
||||
/*
|
||||
* Wrappers should really be parented to the wrapped parent of the wrapped
|
||||
* object, but in that case a wrapped global object would have a NULL
|
||||
* parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
|
||||
* we parent all wrappers to the global object in their home compartment.
|
||||
* This loses us some transparency, and is generally very cheesy.
|
||||
*/
|
||||
HandleObject global = cx->global();
|
||||
JS_ASSERT(global);
|
||||
|
||||
/* Unwrap incoming objects. */
|
||||
RootedObject obj(cx, &vp.toObject());
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return WrapForSameCompartment(cx, obj, vp);
|
||||
|
||||
/* Translate StopIteration singleton. */
|
||||
if (obj->is<StopIterationObject>())
|
||||
return js_FindClassObject(cx, JSProto_StopIteration, vp);
|
||||
|
||||
/* Unwrap the object, but don't unwrap outer windows. */
|
||||
obj = UncheckedUnwrap(obj, /* stopAtOuter = */ true, &flags);
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return WrapForSameCompartment(cx, obj, vp);
|
||||
|
||||
if (cx->runtime()->preWrapObjectCallback) {
|
||||
obj = cx->runtime()->preWrapObjectCallback(cx, global, obj, flags);
|
||||
if (!obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return WrapForSameCompartment(cx, obj, vp);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
JSObject *outer = GetOuterObject(cx, obj);
|
||||
JS_ASSERT(outer && outer == obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
RootedValue key(cx, ObjectValue(*obj));
|
||||
|
||||
/* If we already have a wrapper for this value, use it. */
|
||||
if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) {
|
||||
vp.set(p->value);
|
||||
DebugOnly<JSObject *> cachedWrapper = &vp.toObject();
|
||||
JS_ASSERT(cachedWrapper->is<CrossCompartmentWrapperObject>());
|
||||
JS_ASSERT(cachedWrapper->getParent() == global);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedObject proto(cx, Proxy::LazyProto);
|
||||
RootedObject existing(cx, existingArg);
|
||||
if (existing) {
|
||||
/* Is it possible to reuse |existing|? */
|
||||
if (!existing->getTaggedProto().isLazy() ||
|
||||
// Note: don't use is<ObjectProxyObject>() here -- it also matches subclasses!
|
||||
existing->getClass() != &ObjectProxyObject::class_ ||
|
||||
existing->getParent() != global ||
|
||||
obj->isCallable())
|
||||
{
|
||||
existing = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We hand in the original wrapped object into the wrap hook to allow
|
||||
* the wrap hook to reason over what wrappers are currently applied
|
||||
* to the object.
|
||||
*/
|
||||
RootedObject wrapper(cx);
|
||||
wrapper = cx->runtime()->wrapObjectCallback(cx, existing, obj, proto, global, flags);
|
||||
if (!wrapper)
|
||||
if (!wrap(cx, &obj, existingArg))
|
||||
return false;
|
||||
|
||||
// We maintain the invariant that the key in the cross-compartment wrapper
|
||||
// map is always directly wrapped by the value.
|
||||
JS_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject());
|
||||
|
||||
vp.setObject(*wrapper);
|
||||
return putWrapper(key, vp);
|
||||
vp.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::wrap(JSContext *cx, JSString **strp)
|
||||
{
|
||||
JS_ASSERT(!cx->runtime()->isAtomsCompartment(this));
|
||||
JS_ASSERT(cx->compartment() == this);
|
||||
|
||||
/* If the string is already in this compartment, we are done. */
|
||||
JSString *str = *strp;
|
||||
if (str->zone() == zone())
|
||||
|
@ -379,16 +291,102 @@ JSCompartment::wrap(JSContext *cx, HeapPtrString *strp)
|
|||
}
|
||||
|
||||
bool
|
||||
JSCompartment::wrap(JSContext *cx, JSObject **objp, JSObject *existingArg)
|
||||
JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existingArg)
|
||||
{
|
||||
if (!*objp)
|
||||
JS_ASSERT(!cx->runtime()->isAtomsCompartment(this));
|
||||
JS_ASSERT(cx->compartment() == this);
|
||||
JS_ASSERT_IF(existingArg, existingArg->compartment() == cx->compartment());
|
||||
JS_ASSERT_IF(existingArg, IsDeadProxyObject(existingArg));
|
||||
|
||||
if (!obj)
|
||||
return true;
|
||||
RootedValue value(cx, ObjectValue(**objp));
|
||||
AutoDisableProxyCheck adpc(cx->runtime());
|
||||
|
||||
/*
|
||||
* Wrappers should really be parented to the wrapped parent of the wrapped
|
||||
* object, but in that case a wrapped global object would have a NULL
|
||||
* parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
|
||||
* we parent all wrappers to the global object in their home compartment.
|
||||
* This loses us some transparency, and is generally very cheesy.
|
||||
*/
|
||||
HandleObject global = cx->global();
|
||||
JS_ASSERT(global);
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return WrapForSameCompartment(cx, obj);
|
||||
|
||||
/* Translate StopIteration singleton. */
|
||||
if (obj->is<StopIterationObject>()) {
|
||||
RootedValue v(cx);
|
||||
if (!js_FindClassObject(cx, JSProto_StopIteration, &v))
|
||||
return false;
|
||||
obj.set(&v.toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Unwrap the object, but don't unwrap outer windows. */
|
||||
unsigned flags = 0;
|
||||
obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true, &flags));
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return WrapForSameCompartment(cx, obj);
|
||||
|
||||
/* Invoke the prewrap callback. We're a bit worried about infinite
|
||||
* recursion here, so we do a check - see bug 809295. */
|
||||
JS_CHECK_CHROME_RECURSION(cx, return false);
|
||||
if (cx->runtime()->preWrapObjectCallback) {
|
||||
obj.set(cx->runtime()->preWrapObjectCallback(cx, global, obj, flags));
|
||||
if (!obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return WrapForSameCompartment(cx, obj);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
JSObject *outer = GetOuterObject(cx, obj);
|
||||
JS_ASSERT(outer && outer == obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we already have a wrapper for this value, use it. */
|
||||
RootedValue key(cx, ObjectValue(*obj));
|
||||
if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) {
|
||||
obj.set(&p->value.get().toObject());
|
||||
JS_ASSERT(obj->is<CrossCompartmentWrapperObject>());
|
||||
JS_ASSERT(obj->getParent() == global);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedObject proto(cx, Proxy::LazyProto);
|
||||
RootedObject existing(cx, existingArg);
|
||||
if (!wrap(cx, &value, existing))
|
||||
if (existing) {
|
||||
/* Is it possible to reuse |existing|? */
|
||||
if (!existing->getTaggedProto().isLazy() ||
|
||||
// Note: don't use is<ObjectProxyObject>() here -- it also matches subclasses!
|
||||
existing->getClass() != &ObjectProxyObject::class_ ||
|
||||
existing->getParent() != global ||
|
||||
obj->isCallable())
|
||||
{
|
||||
existing = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We hand in the original wrapped object into the wrap hook to allow
|
||||
* the wrap hook to reason over what wrappers are currently applied
|
||||
* to the object.
|
||||
*/
|
||||
obj.set(cx->runtime()->wrapObjectCallback(cx, existing, obj, proto, global, flags));
|
||||
if (!obj)
|
||||
return false;
|
||||
*objp = &value.get().toObject();
|
||||
return true;
|
||||
|
||||
// We maintain the invariant that the key in the cross-compartment wrapper
|
||||
// map is always directly wrapped by the value.
|
||||
JS_ASSERT(Wrapper::wrappedObject(obj) == &key.get().toObject());
|
||||
|
||||
return putWrapper(key, ObjectValue(*obj));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -431,7 +429,7 @@ JSCompartment::wrap(JSContext *cx, StrictPropertyOp *propp)
|
|||
bool
|
||||
JSCompartment::wrap(JSContext *cx, MutableHandle<PropertyDescriptor> desc)
|
||||
{
|
||||
if (!wrap(cx, desc.object().address()))
|
||||
if (!wrap(cx, desc.object()))
|
||||
return false;
|
||||
|
||||
if (desc.hasGetterObject()) {
|
||||
|
|
|
@ -284,7 +284,8 @@ struct JSCompartment
|
|||
bool wrap(JSContext *cx, JS::MutableHandleValue vp, JS::HandleObject existing = js::NullPtr());
|
||||
bool wrap(JSContext *cx, JSString **strp);
|
||||
bool wrap(JSContext *cx, js::HeapPtrString *strp);
|
||||
bool wrap(JSContext *cx, JSObject **objp, JSObject *existing = NULL);
|
||||
bool wrap(JSContext *cx, JS::MutableHandleObject obj,
|
||||
JS::HandleObject existingArg = js::NullPtr());
|
||||
bool wrapId(JSContext *cx, jsid *idp);
|
||||
bool wrap(JSContext *cx, js::PropertyOp *op);
|
||||
bool wrap(JSContext *cx, js::StrictPropertyOp *op);
|
||||
|
|
|
@ -293,7 +293,7 @@ CrossCompartmentWrapper::get(JSContext *cx, HandleObject wrapper, HandleObject r
|
|||
RootedId idCopy(cx, id);
|
||||
{
|
||||
AutoCompartment call(cx, wrappedObject(wrapper));
|
||||
if (!cx->compartment()->wrap(cx, receiverCopy.address()) ||
|
||||
if (!cx->compartment()->wrap(cx, &receiverCopy) ||
|
||||
!cx->compartment()->wrapId(cx, idCopy.address()))
|
||||
{
|
||||
return false;
|
||||
|
@ -312,7 +312,7 @@ CrossCompartmentWrapper::set(JSContext *cx, HandleObject wrapper, HandleObject r
|
|||
RootedObject receiverCopy(cx, receiver);
|
||||
RootedId idCopy(cx, id);
|
||||
PIERCE(cx, wrapper,
|
||||
cx->compartment()->wrap(cx, receiverCopy.address()) &&
|
||||
cx->compartment()->wrap(cx, &receiverCopy) &&
|
||||
cx->compartment()->wrapId(cx, idCopy.address()) &&
|
||||
cx->compartment()->wrap(cx, vp),
|
||||
Wrapper::set(cx, wrapper, receiverCopy, idCopy, strict, vp),
|
||||
|
@ -364,7 +364,7 @@ Reify(JSContext *cx, JSCompartment *origin, MutableHandleValue vp)
|
|||
|
||||
/* Wrap the iteratee. */
|
||||
RootedObject obj(cx, ni->obj);
|
||||
if (!origin->wrap(cx, obj.address()))
|
||||
if (!origin->wrap(cx, &obj))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -575,7 +575,7 @@ CrossCompartmentWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper,
|
|||
protop->setDelegate(cx);
|
||||
}
|
||||
|
||||
return cx->compartment()->wrap(cx, protop.address());
|
||||
return cx->compartment()->wrap(cx, protop);
|
||||
}
|
||||
|
||||
CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
|
||||
|
@ -933,7 +933,7 @@ js::RemapWrapper(JSContext *cx, JSObject *wobjArg, JSObject *newTargetArg)
|
|||
// the choice to reuse |wobj| or not.
|
||||
RootedObject tobj(cx, newTarget);
|
||||
AutoCompartment ac(cx, wobj);
|
||||
if (!wcompartment->wrap(cx, tobj.address(), wobj))
|
||||
if (!wcompartment->wrap(cx, &tobj, wobj))
|
||||
MOZ_CRASH();
|
||||
|
||||
// If wrap() reused |wobj|, it will have overwritten it and returned with
|
||||
|
|
|
@ -2519,7 +2519,7 @@ NewSandbox(JSContext *cx, bool lazy)
|
|||
|
||||
JS_FireOnNewGlobalObject(cx, obj);
|
||||
|
||||
if (!cx->compartment()->wrap(cx, obj.address()))
|
||||
if (!cx->compartment()->wrap(cx, &obj))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -859,7 +859,7 @@ CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects)
|
|||
if (srcObj->is<JSFunction>()) {
|
||||
if (srcObj->as<JSFunction>().isWrappable()) {
|
||||
clone = srcObj;
|
||||
if (!cx->compartment()->wrap(cx, clone.address()))
|
||||
if (!cx->compartment()->wrap(cx, &clone))
|
||||
return NULL;
|
||||
} else {
|
||||
RootedFunction fun(cx, &srcObj->as<JSFunction>());
|
||||
|
|
Загрузка…
Ссылка в новой задаче