| 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;
|
| }
|
|
|
|
|
|
|