Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 707ace30cac4b67a04843afa564361de485ff8f7..2b321a1c58356332b01c5697ec5ca6e364e09510 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -7965,107 +7965,134 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, |
} |
-MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
- KeyCollectionType type, |
- KeyFilter filter, |
- GetKeysConversion getConversion, |
- Enumerability enum_policy) { |
- USE(ContainsOnlyValidKeys); |
- Isolate* isolate = object->GetIsolate(); |
- KeyAccumulator accumulator(isolate, filter); |
- Handle<JSFunction> arguments_function( |
- JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
- PrototypeIterator::WhereToEnd end = type == OWN_ONLY |
- ? PrototypeIterator::END_AT_NON_HIDDEN |
- : PrototypeIterator::END_AT_NULL; |
+static bool GetKeysFromJSObject(Isolate* isolate, Handle<JSReceiver> receiver, |
+ Handle<JSObject> object, KeyFilter filter, |
+ Enumerability enum_policy, |
+ KeyAccumulator* accumulator) { |
+ // Check access rights if required. |
+ if (object->IsAccessCheckNeeded() && |
+ !isolate->MayAccess(handle(isolate->context()), object)) { |
+ // TODO(jkummerow): Get whitelisted (all-can-read) keys. |
+ // It's probably best to implement a "GetKeysWithFailedAccessCheck" |
+ // helper, which will need to look at both interceptors and accessors. |
+ return false; |
+ } |
+ |
PropertyAttributes attr_filter = static_cast<PropertyAttributes>( |
(enum_policy == RESPECT_ENUMERABILITY ? DONT_ENUM : NONE) | |
PRIVATE_SYMBOL); |
- // Only collect keys if access is permitted. |
+ JSObject::CollectOwnElementKeys(object, accumulator, attr_filter); |
+ |
+ // Add the element keys from the interceptor. |
+ if (object->HasIndexedInterceptor()) { |
+ Handle<JSObject> result; |
+ if (JSObject::GetKeysForIndexedInterceptor(object, receiver) |
+ .ToHandle(&result)) { |
+ accumulator->AddElementKeysFromInterceptor(result); |
+ } |
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false); |
+ } |
+ |
+ if (filter == SKIP_SYMBOLS) { |
+ if (enum_policy == IGNORE_ENUMERABILITY) UNIMPLEMENTED(); |
+ |
+ // We can cache the computed property keys if access checks are |
+ // not needed and no interceptors are involved. |
+ // |
+ // We do not use the cache if the object has elements and |
+ // therefore it does not make sense to cache the property names |
+ // for arguments objects. Arguments objects will always have |
+ // elements. |
+ // Wrapped strings have elements, but don't have an elements |
+ // array or dictionary. So the fast inline test for whether to |
+ // use the cache says yes, so we should not create a cache. |
+ Handle<JSFunction> arguments_function( |
+ JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); |
+ bool cache_enum_length = |
+ ((object->map()->GetConstructor() != *arguments_function) && |
+ !object->IsJSValue() && !object->IsAccessCheckNeeded() && |
+ !object->HasNamedInterceptor() && !object->HasIndexedInterceptor()); |
+ // Compute the property keys and cache them if possible. |
+ Handle<FixedArray> enum_keys = |
+ JSObject::GetEnumPropertyKeys(object, cache_enum_length); |
+ accumulator->AddKeys(enum_keys); |
+ } else { |
+ DCHECK(filter == INCLUDE_SYMBOLS); |
+ object->CollectOwnPropertyNames(accumulator, attr_filter); |
+ } |
+ |
+ // Add the property keys from the interceptor. |
+ if (object->HasNamedInterceptor()) { |
+ Handle<JSObject> result; |
+ if (JSObject::GetKeysForNamedInterceptor(object, receiver) |
+ .ToHandle(&result)) { |
+ accumulator->AddKeys(result); |
+ } |
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false); |
+ } |
+ return true; |
+} |
+ |
+ |
+// Helper function for JSReceiver::GetKeys() below. Can be called recursively. |
+// Returns false iff an exception was thrown. |
+static bool GetKeys_Internal(Isolate* isolate, Handle<JSReceiver> receiver, |
+ Handle<JSReceiver> object, |
+ JSReceiver::KeyCollectionType type, |
+ KeyFilter filter, Enumerability enum_policy, |
+ KeyAccumulator* accumulator) { |
+ PrototypeIterator::WhereToEnd end = type == JSReceiver::OWN_ONLY |
+ ? PrototypeIterator::END_AT_NON_HIDDEN |
+ : PrototypeIterator::END_AT_NULL; |
for (PrototypeIterator iter(isolate, object, |
PrototypeIterator::START_AT_RECEIVER); |
!iter.IsAtEnd(end); iter.Advance()) { |
- accumulator.NextPrototype(); |
- if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
- Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); |
- Handle<Object> args[] = { proxy }; |
+ accumulator->NextPrototype(); |
+ Handle<JSReceiver> current = |
+ PrototypeIterator::GetCurrent<JSReceiver>(iter); |
+ bool result = false; |
+ if (current->IsJSProxy()) { |
+ Handle<Object> args[] = {current}; |
Handle<Object> names; |
- ASSIGN_RETURN_ON_EXCEPTION( |
- isolate, names, |
- Execution::Call(isolate, |
- isolate->proxy_enumerate(), |
- object, |
- arraysize(args), |
- args), |
- FixedArray); |
- accumulator.AddKeysFromProxy(Handle<JSObject>::cast(names)); |
- break; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, names, Execution::Call(isolate, isolate->proxy_enumerate(), |
+ current, arraysize(args), args), |
+ false); |
+ accumulator->AddKeysFromProxy(Handle<JSObject>::cast(names)); |
+ } else { |
+ DCHECK(current->IsJSObject()); |
+ result = GetKeysFromJSObject(isolate, receiver, |
+ Handle<JSObject>::cast(current), filter, |
+ enum_policy, accumulator); |
} |
- |
- Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
- |
- // Check access rights if required. |
- if (current->IsAccessCheckNeeded() && |
- !isolate->MayAccess(handle(isolate->context()), current)) { |
- if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
- isolate->ReportFailedAccessCheck(current); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); |
+ if (!result) { |
+ if (isolate->has_pending_exception()) { |
+ return false; |
} |
+ // If there was no exception, then "false" means "stop iterating". |
break; |
} |
+ } |
+ return true; |
+} |
- JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter); |
- |
- // Add the element keys from the interceptor. |
- if (current->HasIndexedInterceptor()) { |
- Handle<JSObject> result; |
- if (JSObject::GetKeysForIndexedInterceptor(current, object) |
- .ToHandle(&result)) { |
- accumulator.AddElementKeysFromInterceptor(result); |
- } |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); |
- } |
- |
- if (filter == SKIP_SYMBOLS) { |
- if (enum_policy == IGNORE_ENUMERABILITY) UNIMPLEMENTED(); |
- |
- // We can cache the computed property keys if access checks are |
- // not needed and no interceptors are involved. |
- // |
- // We do not use the cache if the object has elements and |
- // therefore it does not make sense to cache the property names |
- // for arguments objects. Arguments objects will always have |
- // elements. |
- // Wrapped strings have elements, but don't have an elements |
- // array or dictionary. So the fast inline test for whether to |
- // use the cache says yes, so we should not create a cache. |
- bool cache_enum_length = |
- ((current->map()->GetConstructor() != *arguments_function) && |
- !current->IsJSValue() && !current->IsAccessCheckNeeded() && |
- !current->HasNamedInterceptor() && |
- !current->HasIndexedInterceptor()); |
- // Compute the property keys and cache them if possible. |
- Handle<FixedArray> enum_keys = |
- JSObject::GetEnumPropertyKeys(current, cache_enum_length); |
- accumulator.AddKeys(enum_keys); |
- } else { |
- DCHECK(filter == INCLUDE_SYMBOLS); |
- current->CollectOwnPropertyNames(&accumulator, attr_filter); |
- } |
- // Add the property keys from the interceptor. |
- if (current->HasNamedInterceptor()) { |
- Handle<JSObject> result; |
- if (JSObject::GetKeysForNamedInterceptor(current, object) |
- .ToHandle(&result)) { |
- accumulator.AddKeys(result); |
- } |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); |
- } |
+MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
+ KeyCollectionType type, |
+ KeyFilter filter, |
+ GetKeysConversion keys_conversion, |
+ Enumerability enum_policy) { |
+ USE(ContainsOnlyValidKeys); |
+ Isolate* isolate = object->GetIsolate(); |
+ KeyAccumulator accumulator(isolate, filter); |
+ if (!GetKeys_Internal(isolate, object, object, type, filter, enum_policy, |
+ &accumulator)) { |
+ DCHECK(isolate->has_pending_exception()); |
+ return MaybeHandle<FixedArray>(); |
} |
- Handle<FixedArray> keys = accumulator.GetKeys(getConversion); |
+ Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion); |
DCHECK(ContainsOnlyValidKeys(keys)); |
return keys; |
} |