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/execution/arguments-inl.h" 8#include "src/execution/isolate-inl.h" 9#include "src/heap/factory.h" 10#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop. 11#include "src/logging/counters.h" 12#include "src/objects/elements.h" 13#include "src/objects/keys.h" 14#include "src/objects/module.h" 15#include "src/objects/objects-inl.h" 16 17namespace v8 { 18namespace internal { 19 20namespace { 21 22// Returns either a FixedArray or, if the given {receiver} has an enum cache 23// that contains all enumerable properties of the {receiver} and its prototypes 24// have none, the map of the {receiver}. This is used to speed up the check for 25// deletions during a for-in. 26MaybeHandle<HeapObject> Enumerate(Isolate* isolate, 27 Handle<JSReceiver> receiver) { 28 JSObject::MakePrototypesFast(receiver, kStartAtReceiver, isolate); 29 FastKeyAccumulator accumulator(isolate, receiver, 30 KeyCollectionMode::kIncludePrototypes, 31 ENUMERABLE_STRINGS, true); 32 // Test if we have an enum cache for {receiver}. 33 if (!accumulator.is_receiver_simple_enum()) { 34 Handle<FixedArray> keys; 35 ASSIGN_RETURN_ON_EXCEPTION( 36 isolate, keys, 37 accumulator.GetKeys(accumulator.may_have_elements() 38 ? GetKeysConversion::kConvertToString 39 : GetKeysConversion::kNoNumbers), 40 HeapObject); 41 // Test again, since cache may have been built by GetKeys() calls above. 42 if (!accumulator.is_receiver_simple_enum()) return keys; 43 } 44 DCHECK(!receiver->IsJSModuleNamespace()); 45 return handle(receiver->map(), isolate); 46} 47 48// This is a slight modification of JSReceiver::HasProperty, dealing with 49// the oddities of JSProxy and JSModuleNamespace in for-in filter. 50MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate, 51 Handle<JSReceiver> receiver, 52 Handle<Object> key) { 53 bool success = false; 54 Maybe<PropertyAttributes> result = Just(ABSENT); 55 PropertyKey lookup_key(isolate, key, &success); 56 if (!success) return isolate->factory()->undefined_value(); 57 LookupIterator it(isolate, receiver, lookup_key); 58 for (; it.IsFound(); it.Next()) { 59 switch (it.state()) { 60 case LookupIterator::NOT_FOUND: 61 case LookupIterator::TRANSITION: 62 UNREACHABLE(); 63 case LookupIterator::JSPROXY: { 64 // For proxies we have to invoke the [[GetOwnProperty]] trap. 65 result = JSProxy::GetPropertyAttributes(&it); 66 if (result.IsNothing()) return MaybeHandle<Object>(); 67 if (result.FromJust() == ABSENT) { 68 // Continue lookup on the proxy's prototype. 69 Handle<JSProxy> proxy = it.GetHolder<JSProxy>(); 70 Handle<Object> prototype; 71 ASSIGN_RETURN_ON_EXCEPTION(isolate, prototype, 72 JSProxy::GetPrototype(proxy), Object); 73 if (prototype->IsNull(isolate)) { 74 return isolate->factory()->undefined_value(); 75 } 76 // We already have a stack-check in JSProxy::GetPrototype. 77 return HasEnumerableProperty( 78 isolate, Handle<JSReceiver>::cast(prototype), key); 79 } else if (result.FromJust() & DONT_ENUM) { 80 return isolate->factory()->undefined_value(); 81 } else { 82 return it.GetName(); 83 } 84 } 85 case LookupIterator::INTERCEPTOR: { 86 result = JSObject::GetPropertyAttributesWithInterceptor(&it); 87 if (result.IsNothing()) return MaybeHandle<Object>(); 88 if (result.FromJust() != ABSENT) return it.GetName(); 89 continue; 90 } 91 case LookupIterator::ACCESS_CHECK: { 92 if (it.HasAccess()) continue; 93 result = JSObject::GetPropertyAttributesWithFailedAccessCheck(&it); 94 if (result.IsNothing()) return MaybeHandle<Object>(); 95 if (result.FromJust() != ABSENT) return it.GetName(); 96 return isolate->factory()->undefined_value(); 97 } 98 case LookupIterator::INTEGER_INDEXED_EXOTIC: 99 // TypedArray out-of-bounds access. 100 return isolate->factory()->undefined_value(); 101 case LookupIterator::ACCESSOR: { 102 if (it.GetHolder<Object>()->IsJSModuleNamespace()) { 103 result = JSModuleNamespace::GetPropertyAttributes(&it); 104 if (result.IsNothing()) return MaybeHandle<Object>(); 105 DCHECK_EQ(0, result.FromJust() & DONT_ENUM); 106 } 107 return it.GetName(); 108 } 109 case LookupIterator::DATA: 110 return it.GetName(); 111 } 112 } 113 return isolate->factory()->undefined_value(); 114} 115 116} // namespace 117 118 119RUNTIME_FUNCTION(Runtime_ForInEnumerate) { 120 HandleScope scope(isolate); 121 DCHECK_EQ(1, args.length()); 122 Handle<JSReceiver> receiver = args.at<JSReceiver>(0); 123 RETURN_RESULT_OR_FAILURE(isolate, Enumerate(isolate, receiver)); 124} 125 126 127RUNTIME_FUNCTION(Runtime_ForInHasProperty) { 128 HandleScope scope(isolate); 129 DCHECK_EQ(2, args.length()); 130 Handle<JSReceiver> receiver = args.at<JSReceiver>(0); 131 Handle<Object> key = args.at(1); 132 Handle<Object> result; 133 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 134 isolate, result, HasEnumerableProperty(isolate, receiver, key)); 135 return isolate->heap()->ToBoolean(!result->IsUndefined(isolate)); 136} 137 138} // namespace internal 139} // namespace v8 140