Bug 947014 - Allow callers of Wrapper::New to specify a prototype. (r=bholley)

This commit is contained in:
Eric Faust 2014-01-29 17:20:16 -08:00
parent e131d468b7
commit 232ac6947a
4 changed files with 40 additions and 38 deletions

View File

@ -448,12 +448,6 @@ class MOZ_STACK_CLASS ProxyOptions {
const Class *clasp_;
};
class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
public:
WrapperOptions() : ProxyOptions(false, nullptr)
{}
};
JS_FRIEND_API(JSObject *)
NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv,
JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions());

View File

@ -53,7 +53,7 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler,
opts.ref().selectDefaultClass(obj->isCallable());
options = opts.addr();
}
return NewProxyObject(cx, handler, priv, TaggedProto::LazyProto, parent, *options);
return NewProxyObject(cx, handler, priv, options->proto(), parent, *options);
}
JSObject *
@ -142,6 +142,7 @@ Wrapper::~Wrapper()
Wrapper Wrapper::singleton((unsigned)0);
Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
JSObject *Wrapper::defaultProto = TaggedProto::LazyProto;
/* Compartments. */

View File

@ -15,6 +15,37 @@ namespace js {
class DummyFrameGuard;
/*
* Helper for Wrapper::New default options.
*
* Callers of Wrapper::New() who wish to specify a prototype for the created
* Wrapper, *MUST* construct a WrapperOptions with a JSContext.
*/
class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
public:
WrapperOptions() : ProxyOptions(false, nullptr),
proto_()
{}
WrapperOptions(JSContext *cx) : ProxyOptions(false, nullptr),
proto_()
{
proto_.construct(cx);
}
JSObject *proto() const {
return proto_.empty() ? Wrapper::defaultProto : proto_.ref();
}
WrapperOptions &setProto(JSObject *protoArg) {
JS_ASSERT(!proto_.empty());
proto_.ref() = protoArg;
return *this;
}
private:
mozilla::Maybe<JS::RootedObject> proto_;
};
/*
* A wrapper is a proxy with a target object to which it generally forwards
* operations, but may restrict access to certain operations or instrument
@ -60,6 +91,8 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
static Wrapper singleton;
static Wrapper singletonWithPrototype;
static JSObject *defaultProto;
};
/* Base class for all cross compartment wrapper handlers. */

View File

@ -3764,34 +3764,6 @@ 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.selectDefaultClass(obj->isCallable());
return NewProxyObject(cx, handler, priv, proto, parent, options);
}
static bool
Wrap(JSContext *cx, unsigned argc, jsval *vp)
{
@ -3825,9 +3797,11 @@ WrapWithProto(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
JSObject *wrapped = WrapperWithProto::New(cx, &obj.toObject(), proto.toObjectOrNull(),
&obj.toObject().global(),
&Wrapper::singletonWithPrototype);
WrapperOptions options(cx);
options.setProto(proto.toObjectOrNull());
options.selectDefaultClass(obj.toObject().isCallable());
JSObject *wrapped = Wrapper::New(cx, &obj.toObject(), &obj.toObject().global(),
&Wrapper::singletonWithPrototype, &options);
if (!wrapped)
return false;