Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 3f028c62824a35653bdc4ef03b265f6eedd4413e..4876568ea474017d8a1decfa18489ac856468f90 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -8101,29 +8101,83 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, |
} |
+enum IndexedOrNamed { kIndexed, kNamed }; |
+ |
+ |
+// Returns false iff there was an exception. |
+template <class Callback, IndexedOrNamed type> |
+static bool GetKeysFromInterceptor(Isolate* isolate, |
+ Handle<JSReceiver> receiver, |
+ Handle<JSObject> object, |
+ PropertyFilter filter, |
+ KeyAccumulator* accumulator) { |
+ if (type == kIndexed) { |
+ if (!object->HasIndexedInterceptor()) return true; |
+ } else { |
+ if (!object->HasNamedInterceptor()) return true; |
+ } |
+ Handle<InterceptorInfo> interceptor(type == kIndexed |
+ ? object->GetIndexedInterceptor() |
+ : object->GetNamedInterceptor(), |
+ isolate); |
+ if ((filter & ONLY_ALL_CAN_READ) && !interceptor->all_can_read()) { |
+ return true; |
+ } |
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, |
+ *object); |
+ v8::Local<v8::Object> result; |
+ if (!interceptor->enumerator()->IsUndefined()) { |
+ Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator()); |
+ const char* log_tag = type == kIndexed ? "interceptor-indexed-enum" |
+ : "interceptor-named-enum"; |
+ LOG(isolate, ApiObjectAccess(log_tag, *object)); |
+ result = args.Call(enum_fun); |
+ } |
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false); |
+ if (result.IsEmpty()) return true; |
+ DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() || |
+ (v8::Utils::OpenHandle(*result)->IsJSObject() && |
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)) |
+ ->HasSloppyArgumentsElements())); |
+ // The accumulator takes care of string/symbol filtering. |
+ if (type == kIndexed) { |
+ accumulator->AddElementKeysFromInterceptor( |
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*result))); |
+ } else { |
+ accumulator->AddKeys( |
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*result))); |
+ } |
+ return true; |
+} |
+ |
+ |
static bool GetKeysFromJSObject(Isolate* isolate, Handle<JSReceiver> receiver, |
Handle<JSObject> object, PropertyFilter filter, |
+ JSReceiver::KeyCollectionType type, |
KeyAccumulator* accumulator) { |
accumulator->NextPrototype(); |
+ bool keep_going = true; |
// 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; |
+ // The cross-origin spec says that [[Enumerate]] shall return an empty |
+ // iterator when it doesn't have access... |
+ if (type == JSReceiver::INCLUDE_PROTOS) { |
+ return false; |
+ } |
+ // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. |
+ DCHECK(type == JSReceiver::OWN_ONLY); |
+ filter = static_cast<PropertyFilter>(filter | ONLY_ALL_CAN_READ); |
+ keep_going = false; |
} |
JSObject::CollectOwnElementKeys(object, accumulator, 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 (!GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>( |
+ isolate, receiver, object, filter, accumulator)) { |
+ DCHECK(isolate->has_pending_exception()); |
+ return false; |
} |
if (filter == ENUMERABLE_STRINGS) { |
@@ -8152,15 +8206,13 @@ static bool GetKeysFromJSObject(Isolate* isolate, Handle<JSReceiver> receiver, |
} |
// 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); |
+ if (!GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback, |
+ kNamed>(isolate, receiver, object, filter, |
+ accumulator)) { |
+ DCHECK(isolate->has_pending_exception()); |
+ return false; |
} |
- return true; |
+ return keep_going; |
} |
@@ -8194,7 +8246,7 @@ static bool GetKeys_Internal(Isolate* isolate, Handle<JSReceiver> receiver, |
DCHECK(current->IsJSObject()); |
result = GetKeysFromJSObject(isolate, receiver, |
Handle<JSObject>::cast(current), filter, |
- accumulator); |
+ type, accumulator); |
} |
if (!result) { |
if (isolate->has_pending_exception()) { |
@@ -15596,6 +15648,7 @@ MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it, |
// Compute the property keys from the interceptor. |
+// TODO(jkummerow): Deprecated. |
MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor( |
Handle<JSObject> object, Handle<JSReceiver> receiver) { |
Isolate* isolate = receiver->GetIsolate(); |
@@ -15621,6 +15674,7 @@ MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor( |
// Compute the element keys from the interceptor. |
+// TODO(jkummerow): Deprecated. |
MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor( |
Handle<JSObject> object, Handle<JSReceiver> receiver) { |
Isolate* isolate = receiver->GetIsolate(); |
@@ -15837,7 +15891,14 @@ void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys, |
int real_size = map()->NumberOfOwnDescriptors(); |
Handle<DescriptorArray> descs(map()->instance_descriptors()); |
for (int i = 0; i < real_size; i++) { |
- if ((descs->GetDetails(i).attributes() & filter) != 0) continue; |
+ PropertyDetails details = descs->GetDetails(i); |
+ if ((details.attributes() & filter) != 0) continue; |
+ if (filter & ONLY_ALL_CAN_READ) { |
+ if (details.kind() != kAccessor) continue; |
+ Object* accessors = descs->GetValue(i); |
+ if (!accessors->IsAccessorInfo()) continue; |
+ if (!AccessorInfo::cast(accessors)->all_can_read()) continue; |
+ } |
Name* key = descs->GetKey(i); |
if (key->FilterKey(filter)) continue; |
keys->AddKey(key); |
@@ -15873,6 +15934,7 @@ int JSObject::NumberOfEnumElements() { |
void JSObject::CollectOwnElementKeys(Handle<JSObject> object, |
KeyAccumulator* keys, |
PropertyFilter filter) { |
+ if (filter & SKIP_STRINGS) return; |
uint32_t string_keys = 0; |
// If this is a String wrapper, add the string indices first, |
@@ -15880,7 +15942,7 @@ void JSObject::CollectOwnElementKeys(Handle<JSObject> object, |
// and ascending order is required by ECMA-262, 6th, 9.1.12. |
if (object->IsJSValue()) { |
Object* val = JSValue::cast(*object)->value(); |
- if (val->IsString()) { |
+ if (val->IsString() && (filter & ONLY_ALL_CAN_READ) == 0) { |
String* str = String::cast(val); |
string_keys = str->length(); |
for (uint32_t i = 0; i < string_keys; i++) { |
@@ -17836,8 +17898,13 @@ void Dictionary<Derived, Shape, Key>::CollectKeysTo( |
if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue; |
if (raw_dict->IsDeleted(i)) continue; |
PropertyDetails details = raw_dict->DetailsAt(i); |
- PropertyAttributes attr = details.attributes(); |
- if ((attr & filter) != 0) continue; |
+ if ((details.attributes() & filter) != 0) continue; |
+ if (filter & ONLY_ALL_CAN_READ) { |
+ if (details.kind() != kAccessor) continue; |
+ Object* accessors = raw_dict->ValueAt(i); |
+ if (!accessors->IsAccessorInfo()) continue; |
+ if (!AccessorInfo::cast(accessors)->all_can_read()) continue; |
+ } |
array->set(array_size++, Smi::FromInt(i)); |
} |