Index: src/runtime/runtime-forin.cc |
diff --git a/src/runtime/runtime-forin.cc b/src/runtime/runtime-forin.cc |
index e6c9cca20f341349774da3a12e72eb41b7c438de..57a05f6f3b6a84d48bf0c9cd38d470c54ede9e57 100644 |
--- a/src/runtime/runtime-forin.cc |
+++ b/src/runtime/runtime-forin.cc |
@@ -12,32 +12,70 @@ |
namespace v8 { |
namespace internal { |
-RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) { |
+namespace { |
+ |
+// Returns either a FixedArray or, if the given {receiver} has an enum cache |
+// that contains all enumerable properties of the {receiver} and its prototypes |
+// have none, the map of the {receiver}. This is used to speed up the check for |
+// deletions during a for-in. |
+MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) { |
+ Isolate* const isolate = receiver->GetIsolate(); |
+ // Test if we have an enum cache for {receiver}. |
+ if (!receiver->IsSimpleEnum()) { |
+ Handle<FixedArray> keys; |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, keys, JSReceiver::GetKeys(receiver, JSReceiver::INCLUDE_PROTOS, |
+ ENUMERABLE_STRINGS), |
+ HeapObject); |
+ // Test again, since cache may have been built by GetKeys() calls above. |
+ if (!receiver->IsSimpleEnum()) return keys; |
+ } |
+ return handle(receiver->map(), isolate); |
+} |
+ |
+ |
+MaybeHandle<Object> Filter(Handle<JSReceiver> receiver, Handle<Object> key) { |
+ Isolate* const isolate = receiver->GetIsolate(); |
+ // TODO(turbofan): Fast case for array indices. |
+ Handle<Name> name; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key), |
+ Object); |
+ Maybe<bool> result = JSReceiver::HasProperty(receiver, name); |
+ MAYBE_RETURN_NULL(result); |
+ if (result.FromJust()) return name; |
+ return isolate->factory()->undefined_value(); |
+} |
+ |
+} // namespace |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_ForInEnumerate) { |
HandleScope scope(isolate); |
DCHECK_EQ(1, args.length()); |
+ CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
+ Handle<HeapObject> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Enumerate(receiver)); |
+ return *result; |
+} |
- if (!args[0]->IsJSReceiver()) { |
- return MakeTriple(isolate->ThrowIllegalOperation(), nullptr, nullptr); |
- } |
- Handle<JSReceiver> receiver = args.at<JSReceiver>(0); |
- Object* property_names = Runtime_GetPropertyNamesFast( |
- 1, Handle<Object>::cast(receiver).location(), isolate); |
- if (isolate->has_pending_exception()) { |
- return MakeTriple(property_names, nullptr, nullptr); |
+RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) { |
+ HandleScope scope(isolate); |
+ DCHECK_EQ(1, args.length()); |
+ Handle<JSReceiver> receiver = args.at<JSReceiver>(0); |
+ Handle<Object> cache_type; |
+ if (!Enumerate(receiver).ToHandle(&cache_type)) { |
+ return MakeTriple(isolate->heap()->exception(), nullptr, nullptr); |
} |
- |
- Handle<Object> cache_type(property_names, isolate); |
Handle<FixedArray> cache_array; |
int cache_length; |
- |
if (cache_type->IsMap()) { |
- Handle<Map> cache_type_map = Handle<Map>::cast(cache_type); |
- int const enum_length = cache_type_map->EnumLength(); |
- DescriptorArray* descriptors = cache_type_map->instance_descriptors(); |
- if (enum_length && descriptors->HasEnumCache()) { |
+ Handle<Map> cache_map = Handle<Map>::cast(cache_type); |
+ Handle<DescriptorArray> descriptors(cache_map->instance_descriptors(), |
+ isolate); |
+ cache_length = cache_map->EnumLength(); |
+ if (cache_length && descriptors->HasEnumCache()) { |
cache_array = handle(descriptors->GetEnumCache(), isolate); |
- cache_length = enum_length; |
} else { |
cache_array = isolate->factory()->empty_fixed_array(); |
cache_length = 0; |
@@ -45,10 +83,8 @@ RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) { |
} else { |
cache_array = Handle<FixedArray>::cast(cache_type); |
cache_length = cache_array->length(); |
- // Cache type of SMI one entails slow check. |
- cache_type = Handle<Object>(Smi::FromInt(1), isolate); |
+ cache_type = handle(Smi::FromInt(1), isolate); |
} |
- |
return MakeTriple(*cache_type, *cache_array, Smi::FromInt(cache_length)); |
} |
@@ -69,15 +105,9 @@ RUNTIME_FUNCTION(Runtime_ForInFilter) { |
DCHECK_EQ(2, args.length()); |
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
- // TODO(turbofan): Fast case for array indices. |
- Handle<Name> name; |
- if (!Object::ToName(isolate, key).ToHandle(&name)) { |
- return isolate->heap()->exception(); |
- } |
- Maybe<bool> result = JSReceiver::HasProperty(receiver, name); |
- if (!result.IsJust()) return isolate->heap()->exception(); |
- if (result.FromJust()) return *name; |
- return isolate->heap()->undefined_value(); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Filter(receiver, key)); |
+ return *result; |
} |
@@ -89,20 +119,13 @@ RUNTIME_FUNCTION(Runtime_ForInNext) { |
CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 2); |
CONVERT_SMI_ARG_CHECKED(index, 3); |
Handle<Object> key = handle(cache_array->get(index), isolate); |
- // Don't need filtering if expected map still matches that of the receiver, |
- // and neither for proxies. |
- if (receiver->map() == *cache_type || *cache_type == Smi::FromInt(0)) { |
+ // Don't need filtering if expected map still matches that of the receiver. |
+ if (receiver->map() == *cache_type) { |
return *key; |
} |
- // TODO(turbofan): Fast case for array indices. |
- Handle<Name> name; |
- if (!Object::ToName(isolate, key).ToHandle(&name)) { |
- return isolate->heap()->exception(); |
- } |
- Maybe<bool> result = JSReceiver::HasProperty(receiver, name); |
- if (!result.IsJust()) return isolate->heap()->exception(); |
- if (result.FromJust()) return *name; |
- return isolate->heap()->undefined_value(); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Filter(receiver, key)); |
+ return *result; |
} |