runtime-forin.cc revision 342c50ce1624b485728b9a4fc41d8bbf37eb46cf
1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/runtime/runtime-utils.h" 6 7#include "src/arguments.h" 8#include "src/factory.h" 9#include "src/isolate-inl.h" 10#include "src/objects-inl.h" 11 12namespace v8 { 13namespace internal { 14 15namespace { 16 17// Returns either a FixedArray or, if the given {receiver} has an enum cache 18// that contains all enumerable properties of the {receiver} and its prototypes 19// have none, the map of the {receiver}. This is used to speed up the check for 20// deletions during a for-in. 21MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) { 22 Isolate* const isolate = receiver->GetIsolate(); 23 // Test if we have an enum cache for {receiver}. 24 if (!receiver->IsSimpleEnum()) { 25 Handle<FixedArray> keys; 26 ASSIGN_RETURN_ON_EXCEPTION( 27 isolate, keys, 28 JSReceiver::GetKeys(receiver, INCLUDE_PROTOS, ENUMERABLE_STRINGS), 29 HeapObject); 30 // Test again, since cache may have been built by GetKeys() calls above. 31 if (!receiver->IsSimpleEnum()) return keys; 32 } 33 return handle(receiver->map(), isolate); 34} 35 36 37MaybeHandle<Object> Filter(Handle<JSReceiver> receiver, Handle<Object> key) { 38 Isolate* const isolate = receiver->GetIsolate(); 39 // TODO(turbofan): Fast case for array indices. 40 Handle<Name> name; 41 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key), 42 Object); 43 Maybe<bool> result = JSReceiver::HasProperty(receiver, name); 44 MAYBE_RETURN_NULL(result); 45 if (result.FromJust()) return name; 46 return isolate->factory()->undefined_value(); 47} 48 49} // namespace 50 51 52RUNTIME_FUNCTION(Runtime_ForInEnumerate) { 53 HandleScope scope(isolate); 54 DCHECK_EQ(1, args.length()); 55 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 56 Handle<HeapObject> result; 57 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Enumerate(receiver)); 58 return *result; 59} 60 61 62RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) { 63 HandleScope scope(isolate); 64 DCHECK_EQ(1, args.length()); 65 Handle<JSReceiver> receiver = args.at<JSReceiver>(0); 66 Handle<Object> cache_type; 67 if (!Enumerate(receiver).ToHandle(&cache_type)) { 68 return MakeTriple(isolate->heap()->exception(), nullptr, nullptr); 69 } 70 Handle<FixedArray> cache_array; 71 int cache_length; 72 if (cache_type->IsMap()) { 73 Handle<Map> cache_map = Handle<Map>::cast(cache_type); 74 Handle<DescriptorArray> descriptors(cache_map->instance_descriptors(), 75 isolate); 76 cache_length = cache_map->EnumLength(); 77 if (cache_length && descriptors->HasEnumCache()) { 78 cache_array = handle(descriptors->GetEnumCache(), isolate); 79 } else { 80 cache_array = isolate->factory()->empty_fixed_array(); 81 cache_length = 0; 82 } 83 } else { 84 cache_array = Handle<FixedArray>::cast(cache_type); 85 cache_length = cache_array->length(); 86 cache_type = handle(Smi::FromInt(1), isolate); 87 } 88 return MakeTriple(*cache_type, *cache_array, Smi::FromInt(cache_length)); 89} 90 91 92RUNTIME_FUNCTION(Runtime_ForInDone) { 93 SealHandleScope scope(isolate); 94 DCHECK_EQ(2, args.length()); 95 CONVERT_SMI_ARG_CHECKED(index, 0); 96 CONVERT_SMI_ARG_CHECKED(length, 1); 97 DCHECK_LE(0, index); 98 DCHECK_LE(index, length); 99 return isolate->heap()->ToBoolean(index == length); 100} 101 102 103RUNTIME_FUNCTION(Runtime_ForInFilter) { 104 HandleScope scope(isolate); 105 DCHECK_EQ(2, args.length()); 106 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 107 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 108 Handle<Object> result; 109 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Filter(receiver, key)); 110 return *result; 111} 112 113 114RUNTIME_FUNCTION(Runtime_ForInNext) { 115 HandleScope scope(isolate); 116 DCHECK_EQ(4, args.length()); 117 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 118 CONVERT_ARG_HANDLE_CHECKED(FixedArray, cache_array, 1); 119 CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 2); 120 CONVERT_SMI_ARG_CHECKED(index, 3); 121 Handle<Object> key = handle(cache_array->get(index), isolate); 122 // Don't need filtering if expected map still matches that of the receiver. 123 if (receiver->map() == *cache_type) { 124 return *key; 125 } 126 Handle<Object> result; 127 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Filter(receiver, key)); 128 return *result; 129} 130 131 132RUNTIME_FUNCTION(Runtime_ForInStep) { 133 SealHandleScope scope(isolate); 134 DCHECK_EQ(1, args.length()); 135 CONVERT_SMI_ARG_CHECKED(index, 0); 136 DCHECK_LE(0, index); 137 DCHECK_LT(index, Smi::kMaxValue); 138 return Smi::FromInt(index + 1); 139} 140 141} // namespace internal 142} // namespace v8 143