Bug 1254968 - Add support for running JS builtins' constructors over Xray wrappers without unwrapping the newTarget. r=bholley,f=bz

This commit is contained in:
Till Schneidereit 2016-02-10 23:09:13 +01:00
parent f8c3aa8993
commit dc24ad50e8
3 changed files with 56 additions and 12 deletions

View File

@ -665,7 +665,19 @@ struct JSClass {
// SetNewObjectMetadata itself
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*)
#define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
// Bit 5 is unused.
#define JSCLASS_HAS_XRAYED_CONSTRUCTOR (1<<5) // if wrapped by an xray
// wrapper, the builtin
// class's constructor won't
// be unwrapped and invoked.
// Instead, the constructor is
// resolved in the caller's
// compartment and invoked
// with a wrapped newTarget.
// The constructor has to
// detect and handle this
// situation.
// See PromiseConstructor for
// details.
#define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act
// like the value undefined,
// in some contexts

View File

@ -911,6 +911,48 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags
clasp->spec.prototypeProperties(), flags, props);
}
bool
JSXrayTraits::construct(JSContext* cx, HandleObject wrapper,
const JS::CallArgs& args, const js::Wrapper& baseInstance)
{
JSXrayTraits& self = JSXrayTraits::singleton;
JS::RootedObject holder(cx, self.ensureHolder(cx, wrapper));
if (self.getProtoKey(holder) == JSProto_Function) {
JSProtoKey standardConstructor = constructorFor(holder);
if (standardConstructor == JSProto_Null)
return baseInstance.construct(cx, wrapper, args);
const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
MOZ_ASSERT(clasp);
if (!(clasp->flags & JSCLASS_HAS_XRAYED_CONSTRUCTOR))
return baseInstance.construct(cx, wrapper, args);
// If the JSCLASS_HAS_XRAYED_CONSTRUCTOR flag is set on the Class,
// we don't use the constructor at hand. Instead, we retrieve the
// equivalent standard constructor in the xray compartment and run
// it in that compartment. The newTarget isn't unwrapped, and the
// constructor has to be able to detect and handle this situation.
// See the comments in js/public/Class.h and PromiseConstructor for
// details and an example.
RootedObject ctor(cx);
if (!JS_GetClassObject(cx, standardConstructor, &ctor))
return false;
RootedValue ctorVal(cx, ObjectValue(*ctor));
HandleValueArray vals(args);
RootedObject result(cx);
if (!JS::Construct(cx, ctorVal, wrapper, vals, &result))
return false;
AssertSameCompartment(cx, result);
args.rval().setObject(*result);
return true;
}
JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
js::ReportIsNotFunction(cx, v);
return false;
}
JSObject*
JSXrayTraits::createHolder(JSContext* cx, JSObject* wrapper)
{

View File

@ -251,17 +251,7 @@ public:
}
static bool construct(JSContext* cx, JS::HandleObject wrapper,
const JS::CallArgs& args, const js::Wrapper& baseInstance)
{
JSXrayTraits& self = JSXrayTraits::singleton;
JS::RootedObject holder(cx, self.ensureHolder(cx, wrapper));
if (self.getProtoKey(holder) == JSProto_Function)
return baseInstance.construct(cx, wrapper, args);
JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
js::ReportIsNotFunction(cx, v);
return false;
}
const JS::CallArgs& args, const js::Wrapper& baseInstance);
bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
JS::HandleObject target,