mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Bug 949220 - Make |NewProxyObject| return only non-singletons, and add |NewSingletonProxyObject| for the singleton case. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D70502 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
5c128af468
commit
5f081085e8
@ -225,16 +225,16 @@ static const DOMIfaceAndProtoJSClass WindowNamedPropertiesClass = {
|
||||
// static
|
||||
JSObject* WindowNamedPropertiesHandler::Create(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aProto) {
|
||||
js::ProxyOptions options;
|
||||
options.setClass(&WindowNamedPropertiesClass.mBase);
|
||||
|
||||
// Note: since the scope polluter proxy lives on the window's prototype
|
||||
// chain, it needs a singleton type to avoid polluting type information
|
||||
// for properties on the window.
|
||||
js::ProxyOptions options;
|
||||
options.setSingleton(true);
|
||||
options.setClass(&WindowNamedPropertiesClass.mBase);
|
||||
|
||||
JS::Rooted<JSObject*> gsp(aCx);
|
||||
gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, aProto, options);
|
||||
JS::Rooted<JSObject*> gsp(
|
||||
aCx, js::NewSingletonProxyObject(
|
||||
aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, aProto, options));
|
||||
if (!gsp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1297,12 +1297,11 @@ static JSObject* NewOuterWindowProxy(JSContext* cx,
|
||||
|
||||
js::WrapperOptions options;
|
||||
options.setClass(&OuterWindowProxyClass);
|
||||
options.setSingleton(true);
|
||||
JSObject* obj =
|
||||
js::Wrapper::New(cx, global,
|
||||
isChrome ? &nsChromeOuterWindowProxy::singleton
|
||||
: &nsOuterWindowProxy::singleton,
|
||||
options);
|
||||
js::Wrapper::NewSingleton(cx, global,
|
||||
isChrome ? &nsChromeOuterWindowProxy::singleton
|
||||
: &nsOuterWindowProxy::singleton,
|
||||
options);
|
||||
MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
|
||||
return obj;
|
||||
}
|
||||
|
@ -555,19 +555,11 @@ inline bool IsScriptedProxy(const JSObject* obj) {
|
||||
class MOZ_STACK_CLASS ProxyOptions {
|
||||
protected:
|
||||
/* protected constructor for subclass */
|
||||
explicit ProxyOptions(bool singletonArg, bool lazyProtoArg = false)
|
||||
: singleton_(singletonArg),
|
||||
lazyProto_(lazyProtoArg),
|
||||
clasp_(&ProxyClass) {}
|
||||
explicit ProxyOptions(bool lazyProtoArg)
|
||||
: lazyProto_(lazyProtoArg), clasp_(&ProxyClass) {}
|
||||
|
||||
public:
|
||||
ProxyOptions() : singleton_(false), lazyProto_(false), clasp_(&ProxyClass) {}
|
||||
|
||||
bool singleton() const { return singleton_; }
|
||||
ProxyOptions& setSingleton(bool flag) {
|
||||
singleton_ = flag;
|
||||
return *this;
|
||||
}
|
||||
ProxyOptions() : ProxyOptions(false) {}
|
||||
|
||||
bool lazyProto() const { return lazyProto_; }
|
||||
ProxyOptions& setLazyProto(bool flag) {
|
||||
@ -582,7 +574,6 @@ class MOZ_STACK_CLASS ProxyOptions {
|
||||
}
|
||||
|
||||
private:
|
||||
bool singleton_;
|
||||
bool lazyProto_;
|
||||
const JSClass* clasp_;
|
||||
};
|
||||
@ -591,6 +582,10 @@ JS_FRIEND_API JSObject* NewProxyObject(
|
||||
JSContext* cx, const BaseProxyHandler* handler, HandleValue priv,
|
||||
JSObject* proto, const ProxyOptions& options = ProxyOptions());
|
||||
|
||||
JS_FRIEND_API JSObject* NewSingletonProxyObject(
|
||||
JSContext* cx, const BaseProxyHandler* handler, HandleValue priv,
|
||||
JSObject* proto, const ProxyOptions& options = ProxyOptions());
|
||||
|
||||
JSObject* RenewProxyObject(JSContext* cx, JSObject* obj,
|
||||
BaseProxyHandler* handler, const Value& priv);
|
||||
|
||||
|
@ -151,6 +151,10 @@ class JS_FRIEND_API Wrapper : public ForwardingProxyHandler {
|
||||
static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
|
||||
const WrapperOptions& options = WrapperOptions());
|
||||
|
||||
static JSObject* NewSingleton(
|
||||
JSContext* cx, JSObject* obj, const Wrapper* handler,
|
||||
const WrapperOptions& options = WrapperOptions());
|
||||
|
||||
static JSObject* Renew(JSObject* existing, JSObject* obj,
|
||||
const Wrapper* handler);
|
||||
|
||||
|
@ -300,7 +300,12 @@ extern "C" {
|
||||
aObj: JS::HandleObject,
|
||||
aHandler: *const ::libc::c_void,
|
||||
aClass: *const JSClass,
|
||||
aSingleton: bool,
|
||||
) -> *mut JSObject;
|
||||
pub fn WrapperNewSingleton(
|
||||
aCx: *mut JSContext,
|
||||
aObj: JS::HandleObject,
|
||||
aHandler: *const ::libc::c_void,
|
||||
aClass: *const JSClass,
|
||||
) -> *mut JSObject;
|
||||
pub fn NewWindowProxy(
|
||||
aCx: *mut JSContext,
|
||||
|
@ -454,16 +454,24 @@ JSObject* NewProxyObject(JSContext* aCx, const void* aHandler,
|
||||
}
|
||||
|
||||
JSObject* WrapperNew(JSContext* aCx, JS::HandleObject aObj,
|
||||
const void* aHandler, const JSClass* aClass,
|
||||
bool aSingleton) {
|
||||
const void* aHandler, const JSClass* aClass) {
|
||||
js::WrapperOptions options;
|
||||
if (aClass) {
|
||||
options.setClass(aClass);
|
||||
}
|
||||
options.setSingleton(aSingleton);
|
||||
return js::Wrapper::New(aCx, aObj, (const js::Wrapper*)aHandler, options);
|
||||
}
|
||||
|
||||
JSObject* WrapperNewSingleton(JSContext* aCx, JS::HandleObject aObj,
|
||||
const void* aHandler, const JSClass* aClass) {
|
||||
js::WrapperOptions options;
|
||||
if (aClass) {
|
||||
options.setClass(aClass);
|
||||
}
|
||||
return js::Wrapper::NewSingleton(aCx, aObj, (const js::Wrapper*)aHandler,
|
||||
options);
|
||||
}
|
||||
|
||||
const JSClass WindowProxyClass = PROXY_CLASS_DEF(
|
||||
"Proxy", JSCLASS_HAS_RESERVED_SLOTS(1)); /* additional class flags */
|
||||
|
||||
@ -479,7 +487,7 @@ void SetProxyReservedSlot(JSObject* obj, uint32_t slot, const JS::Value* val) {
|
||||
|
||||
JSObject* NewWindowProxy(JSContext* aCx, JS::HandleObject aObj,
|
||||
const void* aHandler) {
|
||||
return WrapperNew(aCx, aObj, aHandler, &WindowProxyClass, true);
|
||||
return WrapperNewSingleton(aCx, aObj, aHandler, &WindowProxyClass);
|
||||
}
|
||||
|
||||
JS::Value GetProxyPrivate(JSObject* obj) { return js::GetProxyPrivate(obj); }
|
||||
|
@ -385,10 +385,9 @@ ModuleNamespaceObject* ModuleNamespaceObject::create(
|
||||
RootedValue priv(cx, ObjectValue(*module));
|
||||
ProxyOptions options;
|
||||
options.setLazyProto(true);
|
||||
options.setSingleton(true);
|
||||
Rooted<UniquePtr<IndirectBindingMap>> rootedBindings(cx, std::move(bindings));
|
||||
RootedObject object(
|
||||
cx, NewProxyObject(cx, &proxyHandler, priv, nullptr, options));
|
||||
cx, NewSingletonProxyObject(cx, &proxyHandler, priv, nullptr, options));
|
||||
if (!object) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -45,9 +45,9 @@ BEGIN_TEST(testBug604087) {
|
||||
|
||||
js::WrapperOptions options;
|
||||
options.setClass(&OuterWrapperClass);
|
||||
options.setSingleton(true);
|
||||
JS::RootedObject outerObj(
|
||||
cx, js::Wrapper::New(cx, global, &js::Wrapper::singleton, options));
|
||||
cx,
|
||||
js::Wrapper::NewSingleton(cx, global, &js::Wrapper::singleton, options));
|
||||
JS::RealmOptions globalOptions;
|
||||
JS::RootedObject compartment2(
|
||||
cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
|
||||
@ -78,7 +78,8 @@ BEGIN_TEST(testBug604087) {
|
||||
JS::RootedObject next(cx);
|
||||
{
|
||||
JSAutoRealm ar(cx, compartment2);
|
||||
next = js::Wrapper::New(cx, compartment2, &js::Wrapper::singleton, options);
|
||||
next = js::Wrapper::NewSingleton(cx, compartment2, &js::Wrapper::singleton,
|
||||
options);
|
||||
CHECK(next);
|
||||
}
|
||||
|
||||
|
@ -792,7 +792,32 @@ JS_FRIEND_API JSObject* js::NewProxyObject(JSContext* cx,
|
||||
proto_ = TaggedProto::LazyProto;
|
||||
}
|
||||
|
||||
return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), options);
|
||||
return ProxyObject::New(cx, handler, priv, TaggedProto(proto_),
|
||||
options.clasp());
|
||||
}
|
||||
|
||||
JS_FRIEND_API JSObject* js::NewSingletonProxyObject(
|
||||
JSContext* cx, const BaseProxyHandler* handler, HandleValue priv,
|
||||
JSObject* proto_, const ProxyOptions& options) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
|
||||
// This can be called from the compartment wrap hooks while in a realm with a
|
||||
// gray global. Trigger the read barrier on the global to ensure this is
|
||||
// unmarked.
|
||||
cx->realm()->maybeGlobal();
|
||||
|
||||
if (proto_ != TaggedProto::LazyProto) {
|
||||
cx->check(proto_); // |priv| might be cross-compartment.
|
||||
}
|
||||
|
||||
if (options.lazyProto()) {
|
||||
MOZ_ASSERT(!proto_);
|
||||
proto_ = TaggedProto::LazyProto;
|
||||
}
|
||||
|
||||
return ProxyObject::NewSingleton(cx, handler, priv, TaggedProto(proto_),
|
||||
options.clasp());
|
||||
}
|
||||
|
||||
void ProxyObject::renew(const BaseProxyHandler* handler, const Value& priv) {
|
||||
|
@ -282,6 +282,19 @@ JSObject* Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler,
|
||||
return NewProxyObject(cx, handler, priv, options.proto(), options);
|
||||
}
|
||||
|
||||
JSObject* Wrapper::NewSingleton(JSContext* cx, JSObject* obj,
|
||||
const Wrapper* handler,
|
||||
const WrapperOptions& options) {
|
||||
// If this is a cross-compartment wrapper allocate it in the compartment's
|
||||
// first global. See Compartment::globalForNewCCW.
|
||||
mozilla::Maybe<AutoRealm> ar;
|
||||
if (handler->isCrossCompartmentWrapper()) {
|
||||
ar.emplace(cx, &cx->compartment()->globalForNewCCW());
|
||||
}
|
||||
RootedValue priv(cx, ObjectValue(*obj));
|
||||
return NewSingletonProxyObject(cx, handler, priv, options.proto(), options);
|
||||
}
|
||||
|
||||
JSObject* Wrapper::Renew(JSObject* existing, JSObject* obj,
|
||||
const Wrapper* handler) {
|
||||
existing->as<ProxyObject>().renew(handler, ObjectValue(*obj));
|
||||
|
@ -562,11 +562,10 @@ JSObject* NewShellWindowProxy(JSContext* cx, JS::HandleObject global) {
|
||||
|
||||
js::WrapperOptions options;
|
||||
options.setClass(&ShellWindowProxyClass);
|
||||
options.setSingleton(true);
|
||||
|
||||
JSAutoRealm ar(cx, global);
|
||||
JSObject* obj =
|
||||
js::Wrapper::New(cx, global, &js::Wrapper::singleton, options);
|
||||
js::Wrapper::NewSingleton(cx, global, &js::Wrapper::singleton, options);
|
||||
MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
|
||||
return obj;
|
||||
}
|
||||
|
@ -1378,9 +1378,6 @@ JSObject* js::CloneObject(JSContext* cx, HandleObject obj,
|
||||
obj->as<NativeObject>().getPrivate());
|
||||
}
|
||||
} else {
|
||||
ProxyOptions options;
|
||||
options.setClass(obj->getClass());
|
||||
|
||||
auto* handler = GetProxyHandler(obj);
|
||||
|
||||
// Same as above, require tenure allocation of the clone. This means for
|
||||
@ -1391,7 +1388,8 @@ JSObject* js::CloneObject(JSContext* cx, HandleObject obj,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
clone = ProxyObject::New(cx, handler, JS::NullHandleValue, proto, options);
|
||||
clone = ProxyObject::New(cx, handler, JS::NullHandleValue, proto,
|
||||
obj->getClass());
|
||||
if (!clone) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -45,14 +45,29 @@ static gc::AllocKind GetProxyGCObjectKind(const JSClass* clasp,
|
||||
return kind;
|
||||
}
|
||||
|
||||
void ProxyObject::init(const BaseProxyHandler* handler, HandleValue priv,
|
||||
JSContext* cx) {
|
||||
setInlineValueArray();
|
||||
|
||||
detail::ProxyValueArray* values = detail::GetProxyDataLayout(this)->values();
|
||||
values->init(numReservedSlots());
|
||||
|
||||
data.handler = handler;
|
||||
|
||||
if (IsCrossCompartmentWrapper(this)) {
|
||||
MOZ_ASSERT(cx->global() == &cx->compartment()->globalForNewCCW());
|
||||
setCrossCompartmentPrivate(priv);
|
||||
} else {
|
||||
setSameCompartmentPrivate(priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
|
||||
HandleValue priv, TaggedProto proto_,
|
||||
const ProxyOptions& options) {
|
||||
const JSClass* clasp) {
|
||||
Rooted<TaggedProto> proto(cx, proto_);
|
||||
|
||||
const JSClass* clasp = options.clasp();
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(isValidProxyClass(clasp));
|
||||
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
|
||||
@ -71,7 +86,7 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
|
||||
* because we want to be able to keep track of them in typesets in useful
|
||||
* ways.
|
||||
*/
|
||||
if (proto.isObject() && !options.singleton() && !clasp->isDOMClass()) {
|
||||
if (proto.isObject() && !clasp->isDOMClass()) {
|
||||
ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
|
||||
RootedObject protoObj(cx, proto.toObject());
|
||||
if (!JSObject::setNewGroupUnknown(cx, realm, clasp, protoObj)) {
|
||||
@ -82,12 +97,8 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
|
||||
// Ensure that the wrapper has the same lifetime assumptions as the
|
||||
// wrappee. Prefer to allocate in the nursery, when possible.
|
||||
NewObjectKind newKind = NurseryAllocatedProxy;
|
||||
if (options.singleton()) {
|
||||
MOZ_ASSERT(priv.isNull() ||
|
||||
(priv.isGCThing() && priv.toGCThing()->isTenured()));
|
||||
newKind = SingletonObject;
|
||||
} else if ((priv.isGCThing() && priv.toGCThing()->isTenured()) ||
|
||||
!handler->canNurseryAllocate()) {
|
||||
if ((priv.isGCThing() && priv.toGCThing()->isTenured()) ||
|
||||
!handler->canNurseryAllocate()) {
|
||||
newKind = TenuredObject;
|
||||
}
|
||||
|
||||
@ -100,28 +111,9 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
|
||||
JS_TRY_VAR_OR_RETURN_NULL(cx, proxy,
|
||||
create(cx, clasp, proto, allocKind, newKind));
|
||||
|
||||
proxy->setInlineValueArray();
|
||||
proxy->init(handler, priv, cx);
|
||||
|
||||
detail::ProxyValueArray* values = detail::GetProxyDataLayout(proxy)->values();
|
||||
values->init(proxy->numReservedSlots());
|
||||
|
||||
proxy->data.handler = handler;
|
||||
if (IsCrossCompartmentWrapper(proxy)) {
|
||||
MOZ_ASSERT(cx->global() == &cx->compartment()->globalForNewCCW());
|
||||
proxy->setCrossCompartmentPrivate(priv);
|
||||
} else {
|
||||
proxy->setSameCompartmentPrivate(priv);
|
||||
}
|
||||
|
||||
if (newKind == SingletonObject) {
|
||||
Rooted<ProxyObject*> rootedProxy(cx, proxy);
|
||||
if (!JSObject::setSingleton(cx, rootedProxy)) {
|
||||
return nullptr;
|
||||
}
|
||||
return rootedProxy;
|
||||
}
|
||||
|
||||
/* Don't track types of properties of non-DOM and non-singleton proxies. */
|
||||
// Don't track types of properties of non-DOM and non-singleton proxies.
|
||||
if (!clasp->isDOMClass()) {
|
||||
MarkObjectGroupUnknownProperties(cx, proxy->group());
|
||||
}
|
||||
@ -129,6 +121,43 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/* static */
|
||||
ProxyObject* ProxyObject::NewSingleton(JSContext* cx,
|
||||
const BaseProxyHandler* handler,
|
||||
HandleValue priv, TaggedProto proto_,
|
||||
const JSClass* clasp) {
|
||||
Rooted<TaggedProto> proto(cx, proto_);
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(isValidProxyClass(clasp));
|
||||
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
|
||||
MOZ_ASSERT_IF(proto.isObject(),
|
||||
cx->compartment() == proto.toObject()->compartment());
|
||||
MOZ_ASSERT(clasp->hasFinalize());
|
||||
if (priv.isGCThing()) {
|
||||
JS::AssertCellIsNotGray(priv.toGCThing());
|
||||
}
|
||||
#endif
|
||||
|
||||
gc::AllocKind allocKind = GetProxyGCObjectKind(clasp, handler, priv);
|
||||
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
// Note: this will initialize the object's |data| to strange values, but we
|
||||
// will immediately overwrite those below.
|
||||
ProxyObject* proxy;
|
||||
JS_TRY_VAR_OR_RETURN_NULL(
|
||||
cx, proxy, create(cx, clasp, proto, allocKind, SingletonObject));
|
||||
|
||||
proxy->init(handler, priv, cx);
|
||||
|
||||
Rooted<ProxyObject*> rootedProxy(cx, proxy);
|
||||
if (!JSObject::setSingleton(cx, rootedProxy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rootedProxy;
|
||||
}
|
||||
|
||||
gc::AllocKind ProxyObject::allocKindForTenure() const {
|
||||
MOZ_ASSERT(usingInlineValueArray());
|
||||
Value priv = private_();
|
||||
|
@ -46,7 +46,14 @@ class ProxyObject : public JSObject {
|
||||
public:
|
||||
static ProxyObject* New(JSContext* cx, const BaseProxyHandler* handler,
|
||||
HandleValue priv, TaggedProto proto_,
|
||||
const ProxyOptions& options);
|
||||
const JSClass* clasp);
|
||||
|
||||
static ProxyObject* NewSingleton(JSContext* cx,
|
||||
const BaseProxyHandler* handler,
|
||||
HandleValue priv, TaggedProto proto_,
|
||||
const JSClass* clasp);
|
||||
|
||||
void init(const BaseProxyHandler* handler, HandleValue priv, JSContext* cx);
|
||||
|
||||
// Proxies usually store their ProxyValueArray inline in the object.
|
||||
// There's one unfortunate exception: when a proxy is swapped with another
|
||||
@ -62,6 +69,7 @@ class ProxyObject : public JSObject {
|
||||
&reinterpret_cast<detail::ProxyValueArray*>(inlineDataStart())
|
||||
->reservedSlots;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool initExternalValueArrayAfterSwap(JSContext* cx,
|
||||
HandleValueVector values);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user