Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 4c8723cdd44f3b07b3e91935e232eb7fc3e36f57..23360fefc41a2123e5ed1dde78529eafdf45b5ff 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -5753,6 +5753,19 @@ RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) { |
} |
+// Find the length of the prototype chain that is to be handled as one. If a |
+// prototype object is hidden it is to be viewed as part of the the object it |
+// is prototype for. |
+static int OwnPrototypeChainLength(JSObject* obj) { |
+ int count = 1; |
+ for (PrototypeIterator iter(obj->GetIsolate(), obj); |
+ !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) { |
+ count++; |
+ } |
+ return count; |
+} |
+ |
+ |
// Return the names of the own named properties. |
// args[0]: object |
// args[1]: PropertyAttributes as int |
@@ -5766,12 +5779,30 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { |
CONVERT_SMI_ARG_CHECKED(filter_value, 1); |
PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value); |
+ // Skip the global proxy as it has no properties and always delegates to the |
+ // real global object. |
+ if (obj->IsJSGlobalProxy()) { |
+ // Only collect names if access is permitted. |
+ if (obj->IsAccessCheckNeeded() && |
+ !isolate->MayNamedAccess( |
+ obj, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { |
+ isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS); |
+ RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); |
+ return *isolate->factory()->NewJSArray(0); |
+ } |
+ PrototypeIterator iter(isolate, obj); |
+ obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
+ } |
+ |
+ // Find the number of objects making up this. |
+ int length = OwnPrototypeChainLength(*obj); |
+ |
// Find the number of own properties for each of the objects. |
+ ScopedVector<int> own_property_count(length); |
int total_property_count = 0; |
{ |
PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); |
- for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); |
- iter.Advance()) { |
+ for (int i = 0; i < length; i++) { |
DCHECK(!iter.IsAtEnd()); |
Handle<JSObject> jsproto = |
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
@@ -5786,7 +5817,9 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { |
} |
int n; |
n = jsproto->NumberOfOwnProperties(filter); |
+ own_property_count[i] = n; |
total_property_count += n; |
+ iter.Advance(); |
} |
} |
@@ -5799,18 +5832,17 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { |
int hidden_strings = 0; |
{ |
PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); |
- for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); |
- iter.Advance()) { |
+ for (int i = 0; i < length; i++) { |
+ DCHECK(!iter.IsAtEnd()); |
Handle<JSObject> jsproto = |
Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
- int own_property_count = |
- jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); |
- if (!jsproto.is_identical_to(obj)) { |
+ jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); |
+ if (i > 0) { |
// Names from hidden prototypes may already have been added |
// for inherited function template instances. Count the duplicates |
// and stub them out; the final copy pass at the end ignores holes. |
- for (int j = next_copy_index; j < next_copy_index + own_property_count; |
- j++) { |
+ for (int j = next_copy_index; |
+ j < next_copy_index + own_property_count[i]; j++) { |
Object* name_from_hidden_proto = names->get(j); |
for (int k = 0; k < next_copy_index; k++) { |
if (names->get(k) != isolate->heap()->hidden_string()) { |
@@ -5824,12 +5856,13 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { |
} |
} |
} |
- next_copy_index += own_property_count; |
+ next_copy_index += own_property_count[i]; |
// Hidden properties only show up if the filter does not skip strings. |
if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) { |
hidden_strings++; |
} |
+ iter.Advance(); |
} |
} |