зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1525674 part 1 - Change the enumerate proxy trap to return the jsid vector instead of an iterator. r=bzbarsky,evilpie
In vm/Iteration.cpp this inlines some functions because there's a single caller now. Follow-up patches will do additional cleanup/optimization. Differential Revision: https://phabricator.services.mozilla.com/D18926 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8e4b95eae3
Коммит
13c7bd6d2c
|
@ -435,38 +435,20 @@ bool MaybeCrossOriginObject<Base>::defineProperty(
|
|||
}
|
||||
|
||||
template <typename Base>
|
||||
JSObject* MaybeCrossOriginObject<Base>::enumerate(
|
||||
JSContext* cx, JS::Handle<JSObject*> proxy) const {
|
||||
// We need to be a little careful here. We want to get our list of property
|
||||
// keys in whatever Realm we're in right now (which might be different from
|
||||
// the Realm of "proxy"), and invoke our ownPropertyKeys which will return the
|
||||
// right list. In particular we do NOT want to invoke
|
||||
// ForwardingProxyHandler::enumerate here, because that will get the keys from
|
||||
// our target, which may produce the wrong list.
|
||||
//
|
||||
// Once we have the list, we want to create the iterator object targeting the
|
||||
// representation of "proxy" in our current Realm, since that's what the
|
||||
// caller is working with.
|
||||
//
|
||||
// We could handle parts of this this by overriding enumerate() in
|
||||
// CrossOriginObjectWrapper, but we'd still need special-case code here, so
|
||||
// let's just do all the work here.
|
||||
//
|
||||
// BaseProxyHandler::enumerate would do the right thing if we passed the right
|
||||
// object to it, but it would assert that we've entered the policy of the
|
||||
// proxy we passed it, which may be a CCW, not us, and the policy we actually
|
||||
// entered is ours. So we basically reimplemnt it, but without that assert.
|
||||
bool MaybeCrossOriginObject<Base>::enumerate(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector& props) const {
|
||||
// Just get the property keys from ourselves, in whatever Realm we happen to
|
||||
// be in. It's important to not enter the Realm of "proxy" here, because that
|
||||
// would affect the list of keys we claim to have. We wrap the proxy in the
|
||||
// current compartment just to be safe; it doesn't affect behavior as far as
|
||||
// CrossOriginObjectWrapper and MaybeCrossOriginObject are concerned.
|
||||
JS::Rooted<JSObject*> self(cx, proxy);
|
||||
if (!MaybeWrapObject(cx, &self)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
js::AutoIdVector props(cx);
|
||||
if (!js::GetPropertyKeys(cx, self, 0, &props)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return js::EnumeratedIdVectorToIterator(cx, self, props);
|
||||
return js::GetPropertyKeys(cx, self, 0, &props);
|
||||
}
|
||||
|
||||
// Force instantiations of the out-of-line template methods we need.
|
||||
|
|
|
@ -315,7 +315,8 @@ class MaybeCrossOriginObject : public Base,
|
|||
/**
|
||||
* Spidermonkey-internal hook for enumerating objects.
|
||||
*/
|
||||
JSObject* enumerate(JSContext* cx, JS::Handle<JSObject*> proxy) const final;
|
||||
bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector& props) const final;
|
||||
|
||||
/**
|
||||
* Spidermonkey-internal hook used by Object.prototype.toString. Subclasses
|
||||
|
|
|
@ -89,7 +89,8 @@ class CPOWProxyHandler : public BaseProxyHandler {
|
|||
AutoIdVector& props) const override;
|
||||
virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const override;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool isExtensible(JSContext* cx, HandleObject proxy,
|
||||
|
@ -247,11 +248,11 @@ bool WrapperOwner::delete_(JSContext* cx, HandleObject proxy, HandleId id,
|
|||
return ok(cx, status, result);
|
||||
}
|
||||
|
||||
JSObject* CPOWProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const {
|
||||
// Using a CPOW for the Iterator would slow down for .. in performance,
|
||||
// instead call the base hook, that will use our implementation of
|
||||
bool CPOWProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const {
|
||||
// Call the base hook. That will use our implementation of
|
||||
// getOwnEnumerablePropertyKeys and follow the proto chain.
|
||||
return BaseProxyHandler::enumerate(cx, proxy);
|
||||
return BaseProxyHandler::enumerate(cx, proxy, props);
|
||||
}
|
||||
|
||||
bool CPOWProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
|
|
|
@ -337,7 +337,8 @@ class JS_FRIEND_API BaseProxyHandler {
|
|||
const CallArgs& args) const;
|
||||
|
||||
/* SpiderMonkey extensions. */
|
||||
virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const;
|
||||
virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
bool* bp) const;
|
||||
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
|
||||
|
|
|
@ -55,7 +55,8 @@ class JS_FRIEND_API ForwardingProxyHandler : public BaseProxyHandler {
|
|||
AutoIdVector& props) const override;
|
||||
virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const override;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool getPrototype(JSContext* cx, HandleObject proxy,
|
||||
MutableHandleObject protop) const override;
|
||||
virtual bool setPrototype(JSContext* cx, HandleObject proxy,
|
||||
|
@ -193,8 +194,8 @@ class JS_FRIEND_API CrossCompartmentWrapper : public Wrapper {
|
|||
AutoIdVector& props) const override;
|
||||
virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx,
|
||||
HandleObject wrapper) const override;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool getPrototype(JSContext* cx, HandleObject proxy,
|
||||
MutableHandleObject protop) const override;
|
||||
virtual bool setPrototype(JSContext* cx, HandleObject proxy,
|
||||
|
@ -264,8 +265,8 @@ class JS_FRIEND_API OpaqueCrossCompartmentWrapper
|
|||
AutoIdVector& props) const override;
|
||||
virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx,
|
||||
HandleObject wrapper) const override;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
|
||||
MutableHandleObject protop) const override;
|
||||
virtual bool setPrototype(JSContext* cx, HandleObject wrapper,
|
||||
|
|
|
@ -38,7 +38,8 @@ struct ProxyTraps {
|
|||
bool (*delete_)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::ObjectOpResult& result);
|
||||
|
||||
JSObject* (*enumerate)(JSContext* cx, JS::HandleObject proxy);
|
||||
bool (*enumerate)(JSContext* cx, JS::HandleObject proxy,
|
||||
JS::AutoIdVector& props);
|
||||
|
||||
bool (*getPrototypeIfOrdinary)(JSContext* cx, JS::HandleObject proxy,
|
||||
bool* isOrdinary,
|
||||
|
@ -99,10 +100,10 @@ static int HandlerFamily;
|
|||
#define DEFER_TO_TRAP_OR_BASE_CLASS(_base) \
|
||||
\
|
||||
/* Standard internal methods. */ \
|
||||
virtual JSObject* enumerate(JSContext* cx, JS::HandleObject proxy) \
|
||||
const override { \
|
||||
return mTraps.enumerate ? mTraps.enumerate(cx, proxy) \
|
||||
: _base::enumerate(cx, proxy); \
|
||||
virtual bool enumerate(JSContext* cx, JS::HandleObject proxy, \
|
||||
JS::AutoIdVector& props) const override { \
|
||||
return mTraps.enumerate ? mTraps.enumerate(cx, proxy, props) \
|
||||
: _base::enumerate(cx, proxy, props); \
|
||||
} \
|
||||
\
|
||||
virtual bool has(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, \
|
||||
|
|
|
@ -2795,12 +2795,6 @@ extern JS_FRIEND_API void LogDtor(void* self, const char* type, uint32_t sz);
|
|||
*/
|
||||
extern JS_FRIEND_API uint64_t GetGCHeapUsageForObjectZone(JSObject* obj);
|
||||
|
||||
/**
|
||||
* Create an iterator for the given list of props and the given object
|
||||
* being iterated.
|
||||
*/
|
||||
extern JS_FRIEND_API JSObject* EnumeratedIdVectorToIterator(
|
||||
JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& props);
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsfriendapi_h */
|
||||
|
|
|
@ -268,17 +268,14 @@ bool BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
JSObject* BaseProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const {
|
||||
bool BaseProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const {
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
|
||||
|
||||
// GetPropertyKeys will invoke getOwnEnumerablePropertyKeys along the proto
|
||||
// chain for us.
|
||||
AutoIdVector props(cx);
|
||||
if (!GetPropertyKeys(cx, proxy, 0, &props)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return EnumeratedIdVectorToIterator(cx, proxy, props);
|
||||
MOZ_ASSERT(props.empty());
|
||||
return GetPropertyKeys(cx, proxy, 0, &props);
|
||||
}
|
||||
|
||||
bool BaseProxyHandler::call(JSContext* cx, HandleObject proxy,
|
||||
|
|
|
@ -211,68 +211,10 @@ bool CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(
|
|||
MarkAtoms(cx, props));
|
||||
}
|
||||
|
||||
/*
|
||||
* We can reify non-escaping iterator objects instead of having to wrap them.
|
||||
* This allows fast iteration over objects across a compartment boundary.
|
||||
*/
|
||||
static bool CanReify(HandleObject obj) {
|
||||
return obj->is<PropertyIteratorObject>();
|
||||
}
|
||||
|
||||
static JSObject* Reify(JSContext* cx, JS::Compartment* origin,
|
||||
HandleObject iter) {
|
||||
// Ensure iterator gets closed.
|
||||
auto autoCloseIterator = mozilla::MakeScopeExit([=] { CloseIterator(iter); });
|
||||
|
||||
NativeIterator* ni = iter->as<PropertyIteratorObject>().getNativeIterator();
|
||||
RootedObject obj(cx, ni->objectBeingIterated());
|
||||
|
||||
// Wrap iteratee.
|
||||
if (!origin->wrap(cx, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Wrap the elements in the iterator's snapshot.
|
||||
size_t length = ni->numKeys();
|
||||
AutoIdVector keys(cx);
|
||||
if (length > 0) {
|
||||
if (!keys.reserve(length)) {
|
||||
return nullptr;
|
||||
}
|
||||
RootedId id(cx);
|
||||
RootedValue v(cx);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
v.setString(ni->propertiesBegin()[i]);
|
||||
if (!ValueToId<CanGC>(cx, v, &id)) {
|
||||
return nullptr;
|
||||
}
|
||||
cx->markId(id);
|
||||
keys.infallibleAppend(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Return iterator in current compartment.
|
||||
return EnumeratedIdVectorToIterator(cx, obj, keys);
|
||||
}
|
||||
|
||||
JSObject* CrossCompartmentWrapper::enumerate(JSContext* cx,
|
||||
HandleObject wrapper) const {
|
||||
RootedObject res(cx);
|
||||
{
|
||||
AutoRealm call(cx, wrappedObject(wrapper));
|
||||
res = Wrapper::enumerate(cx, wrapper);
|
||||
if (!res) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanReify(res)) {
|
||||
return Reify(cx, cx->compartment(), res);
|
||||
}
|
||||
if (!cx->compartment()->wrap(cx, &res)) {
|
||||
return nullptr;
|
||||
}
|
||||
return res;
|
||||
bool CrossCompartmentWrapper::enumerate(JSContext* cx, HandleObject wrapper,
|
||||
AutoIdVector& props) const {
|
||||
PIERCE(cx, wrapper, NOTHING, Wrapper::enumerate(cx, wrapper, props),
|
||||
MarkAtoms(cx, props));
|
||||
}
|
||||
|
||||
bool CrossCompartmentWrapper::call(JSContext* cx, HandleObject wrapper,
|
||||
|
|
|
@ -35,9 +35,9 @@ bool OpaqueCrossCompartmentWrapper::delete_(JSContext* cx, HandleObject wrapper,
|
|||
return result.succeed();
|
||||
}
|
||||
|
||||
JSObject* OpaqueCrossCompartmentWrapper::enumerate(JSContext* cx,
|
||||
HandleObject wrapper) const {
|
||||
return BaseProxyHandler::enumerate(cx, wrapper);
|
||||
bool OpaqueCrossCompartmentWrapper::enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const {
|
||||
return BaseProxyHandler::enumerate(cx, proxy, props);
|
||||
}
|
||||
|
||||
bool OpaqueCrossCompartmentWrapper::getPrototype(
|
||||
|
|
|
@ -441,49 +441,45 @@ bool Proxy::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
|
|||
return handler->getOwnEnumerablePropertyKeys(cx, proxy, props);
|
||||
}
|
||||
|
||||
JSObject* Proxy::enumerate(JSContext* cx, HandleObject proxy) {
|
||||
bool Proxy::enumerate(JSContext* cx, HandleObject proxy, AutoIdVector& props) {
|
||||
if (!CheckRecursionLimit(cx)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
|
||||
if (handler->hasPrototype()) {
|
||||
AutoIdVector props(cx);
|
||||
if (!Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototype(cx, proxy, &proto)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
if (!proto) {
|
||||
return EnumeratedIdVectorToIterator(cx, proxy, props);
|
||||
return true;
|
||||
}
|
||||
|
||||
cx->check(proxy, proto);
|
||||
|
||||
AutoIdVector protoProps(cx);
|
||||
if (!GetPropertyKeys(cx, proto, 0, &protoProps)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
if (!AppendUnique(cx, props, protoProps)) {
|
||||
return nullptr;
|
||||
}
|
||||
return EnumeratedIdVectorToIterator(cx, proxy, props);
|
||||
return AppendUnique(cx, props, protoProps);
|
||||
}
|
||||
|
||||
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
|
||||
BaseProxyHandler::ENUMERATE, true);
|
||||
|
||||
// If the policy denies access but wants us to return true, we need
|
||||
// to hand a valid (empty) iterator object to the caller.
|
||||
// to return an empty |props| list.
|
||||
if (!policy.allowed()) {
|
||||
if (!policy.returnValue()) {
|
||||
return nullptr;
|
||||
MOZ_ASSERT(props.empty());
|
||||
return policy.returnValue();
|
||||
}
|
||||
return NewEmptyPropertyIterator(cx);
|
||||
}
|
||||
return handler->enumerate(cx, proxy);
|
||||
|
||||
return handler->enumerate(cx, proxy, props);
|
||||
}
|
||||
|
||||
bool Proxy::call(JSContext* cx, HandleObject proxy, const CallArgs& args) {
|
||||
|
|
|
@ -36,7 +36,7 @@ class Proxy {
|
|||
AutoIdVector& props);
|
||||
static bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
ObjectOpResult& result);
|
||||
static JSObject* enumerate(JSContext* cx, HandleObject proxy);
|
||||
static bool enumerate(JSContext* cx, HandleObject proxy, AutoIdVector& props);
|
||||
static bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible);
|
||||
static bool preventExtensions(JSContext* cx, HandleObject proxy,
|
||||
ObjectOpResult& result);
|
||||
|
|
|
@ -75,13 +75,13 @@ bool ForwardingProxyHandler::delete_(JSContext* cx, HandleObject proxy,
|
|||
return DeleteProperty(cx, target, id, result);
|
||||
}
|
||||
|
||||
JSObject* ForwardingProxyHandler::enumerate(JSContext* cx,
|
||||
HandleObject proxy) const {
|
||||
bool ForwardingProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const {
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
|
||||
MOZ_ASSERT(
|
||||
!hasPrototype()); // Should never be called if there's a prototype.
|
||||
RootedObject target(cx, proxy->as<ProxyObject>().target());
|
||||
return GetIterator(cx, target);
|
||||
return EnumerateProperties(cx, target, props);
|
||||
}
|
||||
|
||||
bool ForwardingProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
|
||||
|
|
|
@ -794,32 +794,6 @@ NativeIterator::NativeIterator(JSContext* cx,
|
|||
MOZ_ASSERT(!*hadError);
|
||||
}
|
||||
|
||||
static inline PropertyIteratorObject* VectorToKeyIterator(JSContext* cx,
|
||||
HandleObject obj,
|
||||
AutoIdVector& props,
|
||||
uint32_t numGuards) {
|
||||
MOZ_ASSERT(cx->compartment() == obj->compartment(),
|
||||
"We may end up allocating shapes in the wrong zone!");
|
||||
if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
|
||||
|
||||
return CreatePropertyIterator(cx, obj, props, numGuards, 0);
|
||||
}
|
||||
|
||||
JS_FRIEND_API JSObject* js::EnumeratedIdVectorToIterator(JSContext* cx,
|
||||
HandleObject obj,
|
||||
AutoIdVector& props) {
|
||||
return VectorToKeyIterator(cx, obj, props, 0);
|
||||
}
|
||||
|
||||
// Mainly used for .. in over null/undefined
|
||||
JSObject* js::NewEmptyPropertyIterator(JSContext* cx) {
|
||||
AutoIdVector props(cx); // Empty
|
||||
return CreatePropertyIterator(cx, nullptr, props, 0, 0);
|
||||
}
|
||||
|
||||
/* static */ bool IteratorHashPolicy::match(PropertyIteratorObject* obj,
|
||||
const Lookup& lookup) {
|
||||
NativeIterator* ni = obj->getNativeIterator();
|
||||
|
@ -944,7 +918,22 @@ static MOZ_MUST_USE bool StoreInIteratorCache(JSContext* cx, JSObject* obj,
|
|||
return true;
|
||||
}
|
||||
|
||||
JSObject* js::GetIterator(JSContext* cx, HandleObject obj) {
|
||||
bool js::EnumerateProperties(JSContext* cx, HandleObject obj,
|
||||
AutoIdVector& props) {
|
||||
MOZ_ASSERT(props.empty());
|
||||
|
||||
if (MOZ_UNLIKELY(obj->is<ProxyObject>())) {
|
||||
return Proxy::enumerate(cx, obj, props);
|
||||
}
|
||||
|
||||
return Snapshot(cx, obj, 0, &props);
|
||||
}
|
||||
|
||||
static JSObject* GetIterator(JSContext* cx, HandleObject obj) {
|
||||
MOZ_ASSERT(!obj->is<PropertyIteratorObject>());
|
||||
MOZ_ASSERT(cx->compartment() == obj->compartment(),
|
||||
"We may end up allocating shapes in the wrong zone!");
|
||||
|
||||
uint32_t numGuards = 0;
|
||||
if (PropertyIteratorObject* iterobj =
|
||||
LookupInIteratorCache(cx, obj, &numGuards)) {
|
||||
|
@ -958,23 +947,22 @@ JSObject* js::GetIterator(JSContext* cx, HandleObject obj) {
|
|||
numGuards = 0;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!obj->is<PropertyIteratorObject>());
|
||||
|
||||
if (MOZ_UNLIKELY(obj->is<ProxyObject>())) {
|
||||
return Proxy::enumerate(cx, obj);
|
||||
}
|
||||
|
||||
AutoIdVector keys(cx);
|
||||
if (!Snapshot(cx, obj, 0, &keys)) {
|
||||
if (!EnumerateProperties(cx, obj, keys)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* res = VectorToKeyIterator(cx, obj, keys, numGuards);
|
||||
if (!res) {
|
||||
if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
|
||||
|
||||
PropertyIteratorObject* iterobj =
|
||||
CreatePropertyIterator(cx, obj, keys, numGuards, 0);
|
||||
if (!iterobj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PropertyIteratorObject* iterobj = &res->as<PropertyIteratorObject>();
|
||||
cx->check(iterobj);
|
||||
|
||||
// Cache the iterator object.
|
||||
|
@ -1272,7 +1260,8 @@ JSObject* js::ValueToIterator(JSContext* cx, HandleValue vp) {
|
|||
* that |for (var p in <null or undefined>) <loop>;| never executes
|
||||
* <loop>, per ES5 12.6.4.
|
||||
*/
|
||||
return NewEmptyPropertyIterator(cx);
|
||||
AutoIdVector props(cx); // Empty
|
||||
return CreatePropertyIterator(cx, nullptr, props, 0, 0);
|
||||
} else {
|
||||
obj = ToObject(cx, vp);
|
||||
if (!obj) {
|
||||
|
@ -1512,35 +1501,13 @@ bool js::SuppressDeletedElement(JSContext* cx, HandleObject obj,
|
|||
|
||||
bool js::IteratorMore(JSContext* cx, HandleObject iterobj,
|
||||
MutableHandleValue rval) {
|
||||
// Fast path for native iterators.
|
||||
if (MOZ_LIKELY(iterobj->is<PropertyIteratorObject>())) {
|
||||
NativeIterator* ni =
|
||||
iterobj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
|
||||
rval.set(ni->nextIteratedValueAndAdvance());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (JS_IsDeadWrapper(iterobj)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsWrapper(iterobj));
|
||||
|
||||
RootedObject obj(cx, CheckedUnwrap(iterobj));
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(obj->is<PropertyIteratorObject>());
|
||||
{
|
||||
AutoRealm ar(cx, obj);
|
||||
NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
rval.set(ni->nextIteratedValueAndAdvance());
|
||||
}
|
||||
return cx->compartment()->wrap(cx, rval);
|
||||
}
|
||||
|
||||
static const JSFunctionSpec iterator_proto_methods[] = {
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0), JS_FS_END};
|
||||
|
||||
|
|
|
@ -365,12 +365,11 @@ class RegExpStringIteratorObject : public NativeObject {
|
|||
RegExpStringIteratorObject* NewRegExpStringIteratorObject(
|
||||
JSContext* cx, NewObjectKind newKind = GenericObject);
|
||||
|
||||
JSObject* GetIterator(JSContext* cx, HandleObject obj);
|
||||
MOZ_MUST_USE bool EnumerateProperties(JSContext* cx, HandleObject obj,
|
||||
AutoIdVector& props);
|
||||
|
||||
PropertyIteratorObject* LookupInIteratorCache(JSContext* cx, HandleObject obj);
|
||||
|
||||
JSObject* NewEmptyPropertyIterator(JSContext* cx);
|
||||
|
||||
JSObject* ValueToIterator(JSContext* cx, HandleValue vp);
|
||||
|
||||
void CloseIterator(JSObject* obj);
|
||||
|
|
|
@ -518,8 +518,8 @@ class SandboxProxyHandler : public js::Wrapper {
|
|||
virtual bool getOwnEnumerablePropertyKeys(
|
||||
JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector& props) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy) const override;
|
||||
virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector& props) const override;
|
||||
|
||||
private:
|
||||
// Implements the custom getPropertyDescriptor behavior. If the getOwn
|
||||
|
@ -799,9 +799,9 @@ bool SandboxProxyHandler::getOwnEnumerablePropertyKeys(
|
|||
return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
|
||||
}
|
||||
|
||||
JSObject* SandboxProxyHandler::enumerate(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy) const {
|
||||
return BaseProxyHandler::enumerate(cx, proxy);
|
||||
bool SandboxProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector& props) const {
|
||||
return BaseProxyHandler::enumerate(cx, proxy, props);
|
||||
}
|
||||
|
||||
bool xpc::GlobalProperties::Parse(JSContext* cx, JS::HandleObject obj) {
|
||||
|
|
|
@ -162,14 +162,13 @@ bool FilteringWrapper<Base, Policy>::getOwnEnumerablePropertyKeys(
|
|||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
JSObject* FilteringWrapper<Base, Policy>::enumerate(
|
||||
JSContext* cx, HandleObject wrapper) const {
|
||||
bool FilteringWrapper<Base, Policy>::enumerate(JSContext* cx,
|
||||
HandleObject wrapper,
|
||||
JS::AutoIdVector& props) const {
|
||||
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
|
||||
// We refuse to trigger the enumerate hook across chrome wrappers because
|
||||
// we don't know how to censor custom iterator objects. Instead we trigger
|
||||
// the default proxy enumerate trap, which will use js::GetPropertyKeys
|
||||
// for the list of (censored) ids.
|
||||
return js::BaseProxyHandler::enumerate(cx, wrapper);
|
||||
// Trigger the default proxy enumerate trap, which will use
|
||||
// js::GetPropertyKeys for the list of (censored) ids.
|
||||
return js::BaseProxyHandler::enumerate(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
|
|
|
@ -32,8 +32,8 @@ class FilteringWrapper : public Base {
|
|||
virtual bool getOwnEnumerablePropertyKeys(
|
||||
JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::AutoIdVector& props) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx,
|
||||
JS::Handle<JSObject*> wrapper) const override;
|
||||
virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::AutoIdVector& props) const override;
|
||||
|
||||
virtual bool call(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
const JS::CallArgs& args) const override;
|
||||
|
|
|
@ -48,17 +48,6 @@ bool WaiveXrayWrapper::get(JSContext* cx, HandleObject wrapper,
|
|||
WrapperFactory::WaiveXrayAndWrap(cx, vp);
|
||||
}
|
||||
|
||||
JSObject* WaiveXrayWrapper::enumerate(JSContext* cx, HandleObject proxy) const {
|
||||
RootedObject obj(cx, CrossCompartmentWrapper::enumerate(cx, proxy));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!WrapperFactory::WaiveXrayAndWrap(cx, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool WaiveXrayWrapper::call(JSContext* cx, HandleObject wrapper,
|
||||
const JS::CallArgs& args) const {
|
||||
return CrossCompartmentWrapper::call(cx, wrapper, args) &&
|
||||
|
|
|
@ -34,8 +34,6 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper {
|
|||
virtual bool construct(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
const JS::CallArgs& args) const override;
|
||||
|
||||
virtual JSObject* enumerate(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy) const override;
|
||||
virtual bool nativeCall(JSContext* cx, JS::IsAcceptableThis test,
|
||||
JS::NativeImpl impl,
|
||||
const JS::CallArgs& args) const override;
|
||||
|
|
|
@ -2126,10 +2126,9 @@ bool XrayWrapper<Base, Traits>::getOwnEnumerablePropertyKeys(
|
|||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
JSObject* XrayWrapper<Base, Traits>::enumerate(JSContext* cx,
|
||||
HandleObject wrapper) const {
|
||||
bool XrayWrapper<Base, Traits>::enumerate(JSContext* cx, HandleObject wrapper,
|
||||
JS::AutoIdVector& props) const {
|
||||
MOZ_CRASH("Shouldn't be called: we return true for hasPrototype()");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
|
|
|
@ -390,8 +390,8 @@ class XrayWrapper : public Base {
|
|||
virtual bool delete_(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<jsid> id,
|
||||
JS::ObjectOpResult& result) const override;
|
||||
virtual JSObject* enumerate(JSContext* cx,
|
||||
JS::Handle<JSObject*> wrapper) const override;
|
||||
virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::AutoIdVector& props) const override;
|
||||
virtual bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
|
||||
JS::MutableHandleObject protop) const override;
|
||||
virtual bool setPrototype(JSContext* cx, JS::HandleObject wrapper,
|
||||
|
|
Загрузка…
Ссылка в новой задаче