Bug 1156077 - Remove the non-standard Proxy getPropertyDescriptor trap. r=bzbarsky,jorendorff

I am bit surprised myself, but just removing the getPropertyDescriptor trap seems to mostly work.
The only real special case here is the XPC Sandbox, which I changed to keep using its getPropertyDescriptorImpl.

testSetPropertyIgnoringNamedGetter.cpp didn't even really need its getPropertyDescriptor implementation.

Differential Revision: https://phabricator.services.mozilla.com/D17386

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tom Schuster 2019-01-25 16:41:34 +00:00
Родитель 9abcc24777
Коммит 35523d50cc
23 изменённых файлов: 22 добавлений и 268 удалений

Просмотреть файл

@ -457,19 +457,6 @@ class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
JS::ObjectOpResult& result) const override;
// SpiderMonkey extensions
/**
* Non-standard method we want to get rid of.
*
* "proxy" is the WindowProxy object involved. It may not be same-compartment
* with cx.
*
* The only reason we implement this is because js::Wrapper does and we want
* different behavior from the js::Wrapper implementation.
*/
bool getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
/**
* Implementation of SpiderMonkey extension which just checks whether this
* object has the property. Basically Object.getOwnPropertyDescriptor(obj,
@ -566,43 +553,6 @@ void nsOuterWindowProxy::finalize(JSFreeOp* fop, JSObject* proxy) const {
}
}
bool nsOuterWindowProxy::getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const {
// In the same-origin case the only thing we can do differently from
// js::Wrapper is shadow stuff with our indexed properties, so we can just try
// getOwnPropertyDescriptor and if that gives us nothing call on through to
// js::Wrapper.
//
// In the cross-origin case, we can only have own properties, so don't even
// need to worry about the js::Proxy bit.
desc.object().set(nullptr);
if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
return false;
}
if (desc.object()) {
return true;
}
if (!IsPlatformObjectSameOrigin(cx, proxy)) {
return true;
}
// When forwarding to js::Wrapper, we should just enter the Realm of proxy
// for now. That's what js::Wrapper expects, and since we're same-origin
// anyway this is not changing any security behavior.
{
JSAutoRealm ar(cx, proxy);
JS_MarkCrossZoneId(cx, id);
if (!js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc)) {
return false;
}
}
return JS_WrapPropertyDescriptor(cx, desc);
}
/**
* IsNonConfigurableReadonlyPrimitiveGlobalProp returns true for
* property names that fit the following criteria:

Просмотреть файл

@ -184,11 +184,10 @@ class JS_FRIEND_API BaseProxyHandler {
* treatment from the JS engine:
*
* - When mHasPrototype is true, the engine never calls these methods:
* getPropertyDescriptor, has, set, enumerate, iterate. Instead, for
* these operations, it calls the "own" methods like
* getOwnPropertyDescriptor, hasOwn, defineProperty,
* getOwnEnumerablePropertyKeys, etc., and consults the prototype chain
* if needed.
* has, set, enumerate, iterate. Instead, for these operations,
* it calls the "own" methods like getOwnPropertyDescriptor, hasOwn,
* defineProperty, getOwnEnumerablePropertyKeys, etc.,
* and consults the prototype chain if needed.
*
* - When mHasPrototype is true, the engine calls handler->get() only if
* handler->hasOwn() says an own property exists on the proxy. If not,
@ -307,7 +306,9 @@ class JS_FRIEND_API BaseProxyHandler {
* These standard internal methods are implemented, as a convenience, so
* that ProxyHandler subclasses don't have to provide every single method.
*
* The base-class implementations work by calling getPropertyDescriptor().
* The base-class implementations work by calling getOwnPropertyDescriptor()
* and going up the [[Prototype]] chain if necessary. The algorithm for this
* follows what is defined for Ordinary Objects in the ES spec.
* They do not follow any standard. When in doubt, override them.
*/
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
@ -337,9 +338,6 @@ class JS_FRIEND_API BaseProxyHandler {
/* SpiderMonkey extensions. */
virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const;
virtual bool getPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const;
virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
bool* bp) const;
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,

Просмотреть файл

@ -83,9 +83,6 @@ class JS_FRIEND_API ForwardingProxyHandler : public BaseProxyHandler {
const CallArgs& args) const override;
/* SpiderMonkey extensions. */
virtual bool getPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override;
virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
bool* bp) const override;
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
@ -215,9 +212,6 @@ class JS_FRIEND_API CrossCompartmentWrapper : public Wrapper {
const CallArgs& args) const override;
/* SpiderMonkey extensions. */
virtual bool getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override;
virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
bool* bp) const override;
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
@ -288,9 +282,6 @@ class JS_FRIEND_API OpaqueCrossCompartmentWrapper
const CallArgs& args) const override;
/* SpiderMonkey extensions. */
virtual bool getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override;
virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
bool* bp) const override;
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,

Просмотреть файл

@ -82,12 +82,6 @@ pub struct ProxyTraps {
proxy: JS::HandleObject,
args: *const JS::CallArgs)
-> bool>,
pub getPropertyDescriptor:
::std::option::Option<unsafe extern "C" fn(cx: *mut JSContext,
proxy: JS::HandleObject,
id: JS::HandleId,
desc: JS::MutableHandle<JS::PropertyDescriptor>)
-> bool>,
pub hasOwn: ::std::option::Option<unsafe extern "C" fn(cx: *mut JSContext,
proxy: JS::HandleObject,
id: JS::HandleId,

Просмотреть файл

@ -63,9 +63,6 @@ struct ProxyTraps {
bool (*construct)(JSContext* cx, JS::HandleObject proxy,
const JS::CallArgs& args);
bool (*getPropertyDescriptor)(JSContext* cx, JS::HandleObject proxy,
JS::HandleId id,
JS::MutableHandle<JS::PropertyDescriptor> desc);
bool (*hasOwn)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
bool* bp);
bool (*getOwnEnumerablePropertyKeys)(JSContext* cx, JS::HandleObject proxy,
@ -267,14 +264,6 @@ class WrapperProxyHandler : public js::Wrapper {
? mTraps.isExtensible(cx, proxy, succeeded)
: js::Wrapper::isExtensible(cx, proxy, succeeded);
}
virtual bool getPropertyDescriptor(
JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override {
return mTraps.getPropertyDescriptor
? mTraps.getPropertyDescriptor(cx, proxy, id, desc)
: js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
}
};
class RustJSPrincipal : public JSPrincipals {
@ -356,12 +345,6 @@ class ForwardingProxyHandler : public js::BaseProxyHandler {
bool* succeeded) const override {
return mTraps.isExtensible(cx, proxy, succeeded);
}
virtual bool getPropertyDescriptor(
JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override {
return mTraps.getPropertyDescriptor(cx, proxy, id, desc);
}
};
extern "C" {

Просмотреть файл

@ -15,49 +15,29 @@ class CustomProxyHandler : public Wrapper {
public:
CustomProxyHandler() : Wrapper(0) {}
bool getPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override {
return impl(cx, proxy, id, desc, false);
}
bool getOwnPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override {
return impl(cx, proxy, id, desc, true);
if (JSID_IS_STRING(id) &&
JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "phantom")) {
desc.object().set(proxy);
desc.attributesRef() = JSPROP_ENUMERATE;
desc.value().setInt32(42);
return true;
}
return Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
}
bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const override {
Rooted<PropertyDescriptor> desc(cx);
if (!Wrapper::getPropertyDescriptor(cx, proxy, id, &desc)) {
if (!Wrapper::getOwnPropertyDescriptor(cx, proxy, id, &desc)) {
return false;
}
return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc,
result);
}
private:
bool impl(JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc, bool ownOnly) const {
if (JSID_IS_STRING(id)) {
bool match;
if (!JS_StringEqualsAscii(cx, JSID_TO_STRING(id), "phantom", &match)) {
return false;
}
if (match) {
desc.object().set(proxy);
desc.attributesRef() = JSPROP_ENUMERATE;
desc.value().setInt32(42);
return true;
}
}
if (ownOnly) {
return Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
}
return Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
}
};
const CustomProxyHandler customProxyHandler;

Просмотреть файл

@ -56,29 +56,6 @@ bool BaseProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id,
return true;
}
bool BaseProxyHandler::getPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {
assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
return false;
}
if (desc.object()) {
return true;
}
RootedObject proto(cx);
if (!GetPrototype(cx, proxy, &proto)) {
return false;
}
if (!proto) {
MOZ_ASSERT(!desc.object());
return true;
}
return GetPropertyDescriptor(cx, proto, id, desc);
}
bool BaseProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
bool* bp) const {
assertEnteredPolicy(cx, proxy, id, GET);

Просмотреть файл

@ -43,14 +43,6 @@ static bool MarkAtoms(JSContext* cx, const AutoIdVector& ids) {
return true;
}
bool CrossCompartmentWrapper::getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {
PIERCE(cx, wrapper, MarkAtoms(cx, id),
Wrapper::getPropertyDescriptor(cx, wrapper, id, desc),
cx->compartment()->wrap(cx, desc));
}
bool CrossCompartmentWrapper::getOwnPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {

Просмотреть файл

@ -49,9 +49,7 @@ class DeadObjectProxy : public BaseProxyHandler {
const CallArgs& args) const override;
/* SpiderMonkey extensions. */
// BaseProxyHandler::getPropertyDescriptor will throw by calling
// getOwnPropertyDescriptor. BaseProxyHandler::enumerate will throw by calling
// ownKeys.
// BaseProxyHandler::enumerate will throw by calling ownKeys.
virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
const CallArgs& args) const override;
virtual bool hasInstance(JSContext* cx, HandleObject proxy,

Просмотреть файл

@ -111,12 +111,6 @@ bool OpaqueCrossCompartmentWrapper::construct(JSContext* cx,
return false;
}
bool OpaqueCrossCompartmentWrapper::getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {
return BaseProxyHandler::getPropertyDescriptor(cx, wrapper, id, desc);
}
bool OpaqueCrossCompartmentWrapper::hasOwn(JSContext* cx, HandleObject wrapper,
HandleId id, bool* bp) const {
return BaseProxyHandler::hasOwn(cx, wrapper, id, bp);

Просмотреть файл

@ -73,31 +73,6 @@ JS_FRIEND_API void js::assertEnteredPolicy(JSContext* cx, JSObject* proxy,
}
#endif
bool Proxy::getPropertyDescriptor(JSContext* cx, HandleObject proxy,
HandleId id,
MutableHandle<PropertyDescriptor> desc) {
if (!CheckRecursionLimit(cx)) {
return false;
}
const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
desc.object().set(
nullptr); // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id,
BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true);
if (!policy.allowed()) {
return policy.returnValue();
}
// Special case. See the comment on BaseProxyHandler::mHasPrototype.
if (handler->hasPrototype()) {
return handler->BaseProxyHandler::getPropertyDescriptor(cx, proxy, id,
desc);
}
return handler->getPropertyDescriptor(cx, proxy, id, desc);
}
bool Proxy::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy,
HandleId id,
MutableHandle<PropertyDescriptor> desc) {

Просмотреть файл

@ -65,9 +65,6 @@ class Proxy {
const CallArgs& args);
/* SpiderMonkey extensions. */
static bool getPropertyDescriptor(JSContext* cx, HandleObject proxy,
HandleId id,
MutableHandle<JS::PropertyDescriptor> desc);
static bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
static bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
AutoIdVector& props);

Просмотреть файл

@ -187,16 +187,6 @@ bool ForwardingProxyHandler::construct(JSContext* cx, HandleObject proxy,
return true;
}
bool ForwardingProxyHandler::getPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {
assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
MOZ_ASSERT(
!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyDescriptor(cx, target, id, desc);
}
bool ForwardingProxyHandler::hasOwn(JSContext* cx, HandleObject proxy,
HandleId id, bool* bp) const {
assertEnteredPolicy(cx, proxy, id, GET);

Просмотреть файл

@ -171,7 +171,6 @@
"getOwnPropertyDescriptor") \
MACRO(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
MACRO(getPrefix, getPrefix, "get ") \
MACRO(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
MACRO(getPropertySuper, getPropertySuper, "getPropertySuper") \
MACRO(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \
MACRO(GetTypeError, GetTypeError, "GetTypeError") \

Просмотреть файл

@ -1947,12 +1947,6 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler {
return true;
}
bool getPropertyDescriptor(
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override {
return getOwnPropertyDescriptor(cx, proxy, id, desc);
}
bool getMissingArgumentsPropertyDescriptor(
JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
EnvironmentObject& env, MutableHandle<PropertyDescriptor> desc) const {

Просмотреть файл

@ -3046,14 +3046,6 @@ bool js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
RootedObject pobj(cx);
for (pobj = obj; pobj;) {
if (pobj->is<ProxyObject>()) {
bool ok = Proxy::getPropertyDescriptor(cx, pobj, id, desc);
if (ok) {
desc.assertCompleteIfFound();
}
return ok;
}
if (!GetOwnPropertyDescriptor(cx, pobj, id, desc)) {
return false;
}

Просмотреть файл

@ -507,9 +507,6 @@ class SandboxProxyHandler : public js::Wrapper {
JS::Handle<JS::Value> receiver,
JS::ObjectOpResult& result) const override;
virtual bool getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
virtual bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool* bp) const override;
virtual bool getOwnEnumerablePropertyKeys(
@ -723,12 +720,6 @@ bool SandboxProxyHandler::getPropertyDescriptorImpl(
return true;
}
bool SandboxProxyHandler::getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<PropertyDescriptor> desc) const {
return getPropertyDescriptorImpl(cx, proxy, id, /* getOwn = */ false, desc);
}
bool SandboxProxyHandler::getOwnPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<PropertyDescriptor> desc) const {
@ -742,10 +733,9 @@ bool SandboxProxyHandler::getOwnPropertyDescriptor(
bool SandboxProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool* bp) const {
// This uses getPropertyDescriptor for backward compatibility with
// the old BaseProxyHandler::has implementation.
// This uses JS_GetPropertyDescriptorById for backward compatibility.
Rooted<PropertyDescriptor> desc(cx);
if (!getPropertyDescriptor(cx, proxy, id, &desc)) {
if (!getPropertyDescriptorImpl(cx, proxy, id, /* getOwn = */ false, &desc)) {
return false;
}
@ -761,10 +751,9 @@ bool SandboxProxyHandler::get(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<JS::Value> receiver,
JS::Handle<jsid> id,
JS::MutableHandle<Value> vp) const {
// This uses getPropertyDescriptor for backward compatibility with
// the old BaseProxyHandler::get implementation.
// This uses JS_GetPropertyDescriptorById for backward compatibility.
Rooted<PropertyDescriptor> desc(cx);
if (!getPropertyDescriptor(cx, proxy, id, &desc)) {
if (!getPropertyDescriptorImpl(cx, proxy, id, /* getOwn = */ false, &desc)) {
return false;
}
desc.assertCompleteIfFound();

Просмотреть файл

@ -132,19 +132,6 @@ static bool FilterPropertyDescriptor(JSContext* cx, HandleObject wrapper,
return true;
}
template <typename Base, typename Policy>
bool FilteringWrapper<Base, Policy>::getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {
assertEnteredPolicy(cx, wrapper, id,
BaseProxyHandler::GET | BaseProxyHandler::SET |
BaseProxyHandler::GET_PROPERTY_DESCRIPTOR);
if (!Base::getPropertyDescriptor(cx, wrapper, id, desc)) {
return false;
}
return FilterPropertyDescriptor<Policy>(cx, wrapper, id, desc);
}
template <typename Base, typename Policy>
bool FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,

Просмотреть файл

@ -29,9 +29,6 @@ class FilteringWrapper : public Base {
virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::AutoIdVector& props) const override;
virtual bool getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
virtual bool getOwnEnumerablePropertyKeys(
JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::AutoIdVector& props) const override;

Просмотреть файл

@ -32,15 +32,6 @@ static bool WaiveAccessors(JSContext* cx,
return true;
}
bool WaiveXrayWrapper::getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {
return CrossCompartmentWrapper::getPropertyDescriptor(cx, wrapper, id,
desc) &&
WrapperFactory::WaiveXrayAndWrap(cx, desc.value()) &&
WaiveAccessors(cx, desc);
}
bool WaiveXrayWrapper::getOwnPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const {

Просмотреть файл

@ -41,9 +41,6 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper {
const JS::CallArgs& args) const override;
virtual bool hasInstance(JSContext* cx, JS::HandleObject wrapper,
JS::MutableHandleValue v, bool* bp) const override;
virtual bool getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
static const WaiveXrayWrapper singleton;
};

Просмотреть файл

@ -1870,14 +1870,6 @@ bool XrayWrapper<Base, Traits>::isExtensible(JSContext* cx,
return true;
}
template <typename Base, typename Traits>
bool XrayWrapper<Base, Traits>::getPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,
JS::MutableHandle<PropertyDescriptor> desc) const {
MOZ_CRASH("Shouldn't be called: we return true for hasPrototype()");
return false;
}
template <typename Base, typename Traits>
bool XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(
JSContext* cx, HandleObject wrapper, HandleId id,

Просмотреть файл

@ -421,9 +421,6 @@ class XrayWrapper : public Base {
const JS::CallArgs& args) const override;
/* SpiderMonkey extensions. */
virtual bool getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
virtual bool hasOwn(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id, bool* bp) const override;
virtual bool getOwnEnumerablePropertyKeys(