Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/objects.h" | 5 #include "src/objects.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <iomanip> | 8 #include <iomanip> |
| 9 #include <sstream> | 9 #include <sstream> |
| 10 | 10 |
| (...skipping 7947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7958 if (length == 0) { | 7958 if (length == 0) { |
| 7959 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 7959 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
| 7960 } | 7960 } |
| 7961 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 7961 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| 7962 dictionary->CopyEnumKeysTo(*storage); | 7962 dictionary->CopyEnumKeysTo(*storage); |
| 7963 return storage; | 7963 return storage; |
| 7964 } | 7964 } |
| 7965 } | 7965 } |
| 7966 | 7966 |
| 7967 | 7967 |
| 7968 static bool GetKeysFromJSObject(Isolate* isolate, Handle<JSReceiver> receiver, | |
| 7969 Handle<JSObject> object, KeyFilter filter, | |
| 7970 Enumerability enum_policy, | |
| 7971 KeyAccumulator* accumulator) { | |
| 7972 // Check access rights if required. | |
| 7973 if (object->IsAccessCheckNeeded() && | |
| 7974 !isolate->MayAccess(handle(isolate->context()), object)) { | |
| 7975 // TODO(jkummerow): Get whitelisted (all-can-read) keys. | |
| 7976 // It's probably best to implement a "GetKeysWithFailedAccessCheck" | |
| 7977 // helper, which will need to look at both interceptors and accessors. | |
| 7978 return false; | |
| 7979 } | |
| 7980 | |
| 7981 PropertyAttributes attr_filter = static_cast<PropertyAttributes>( | |
| 7982 (enum_policy == RESPECT_ENUMERABILITY ? DONT_ENUM : NONE) | | |
| 7983 PRIVATE_SYMBOL); | |
| 7984 | |
| 7985 JSObject::CollectOwnElementKeys(object, accumulator, attr_filter); | |
| 7986 | |
| 7987 // Add the element keys from the interceptor. | |
| 7988 if (object->HasIndexedInterceptor()) { | |
| 7989 Handle<JSObject> result; | |
| 7990 if (JSObject::GetKeysForIndexedInterceptor(object, receiver) | |
| 7991 .ToHandle(&result)) { | |
| 7992 accumulator->AddElementKeysFromInterceptor(result); | |
| 7993 } | |
| 7994 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false); | |
| 7995 } | |
| 7996 | |
| 7997 if (filter == SKIP_SYMBOLS) { | |
| 7998 if (enum_policy == IGNORE_ENUMERABILITY) UNIMPLEMENTED(); | |
| 7999 | |
| 8000 // We can cache the computed property keys if access checks are | |
| 8001 // not needed and no interceptors are involved. | |
| 8002 // | |
| 8003 // We do not use the cache if the object has elements and | |
| 8004 // therefore it does not make sense to cache the property names | |
| 8005 // for arguments objects. Arguments objects will always have | |
| 8006 // elements. | |
| 8007 // Wrapped strings have elements, but don't have an elements | |
| 8008 // array or dictionary. So the fast inline test for whether to | |
| 8009 // use the cache says yes, so we should not create a cache. | |
| 8010 Handle<JSFunction> arguments_function( | |
| 8011 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | |
| 8012 bool cache_enum_length = | |
| 8013 ((object->map()->GetConstructor() != *arguments_function) && | |
| 8014 !object->IsJSValue() && !object->IsAccessCheckNeeded() && | |
| 8015 !object->HasNamedInterceptor() && !object->HasIndexedInterceptor()); | |
| 8016 // Compute the property keys and cache them if possible. | |
| 8017 Handle<FixedArray> enum_keys = | |
| 8018 JSObject::GetEnumPropertyKeys(object, cache_enum_length); | |
| 8019 accumulator->AddKeys(enum_keys); | |
| 8020 } else { | |
| 8021 DCHECK(filter == INCLUDE_SYMBOLS); | |
| 8022 object->CollectOwnPropertyNames(accumulator, attr_filter); | |
| 8023 } | |
| 8024 | |
| 8025 // Add the property keys from the interceptor. | |
| 8026 if (object->HasNamedInterceptor()) { | |
| 8027 Handle<JSObject> result; | |
| 8028 if (JSObject::GetKeysForNamedInterceptor(object, receiver) | |
| 8029 .ToHandle(&result)) { | |
| 8030 accumulator->AddKeys(result); | |
| 8031 } | |
| 8032 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false); | |
| 8033 } | |
| 8034 return true; | |
| 8035 } | |
| 8036 | |
| 8037 | |
| 8038 static bool GetKeysFromJSProxy(Isolate* isolate, Handle<JSReceiver> receiver, | |
| 8039 Handle<JSProxy> proxy, KeyFilter filter, | |
| 8040 Enumerability enum_policy, | |
| 8041 KeyAccumulator* accumulator) { | |
| 8042 Handle<Object> args[] = {proxy}; | |
| 8043 Handle<Object> names; | |
| 8044 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 8045 isolate, names, Execution::Call(isolate, isolate->proxy_enumerate(), | |
| 8046 proxy, arraysize(args), args), | |
| 8047 false); | |
| 8048 accumulator->AddKeysFromProxy(Handle<JSObject>::cast(names)); | |
| 8049 return true; | |
| 8050 } | |
| 8051 | |
| 8052 | |
| 8053 // Returns false if an exception was thrown, or if prototype iteration | |
| 8054 // should not continue. | |
| 8055 static bool GetKeysFromJSReceiver(Isolate* isolate, Handle<JSReceiver> receiver, | |
|
Jakob Kummerow
2015/11/25 11:33:47
We'll need this entry point so that the new GetKey
| |
| 8056 Handle<JSReceiver> object, KeyFilter filter, | |
| 8057 Enumerability enum_policy, | |
| 8058 KeyAccumulator* accumulator) { | |
| 8059 if (object->IsJSProxy()) { | |
| 8060 return GetKeysFromJSProxy(isolate, receiver, Handle<JSProxy>::cast(object), | |
| 8061 filter, enum_policy, accumulator); | |
| 8062 } | |
| 8063 return GetKeysFromJSObject(isolate, receiver, Handle<JSObject>::cast(object), | |
| 8064 filter, enum_policy, accumulator); | |
| 8065 } | |
| 8066 | |
| 8067 | |
| 7968 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, | 8068 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
| 7969 KeyCollectionType type, | 8069 KeyCollectionType type, |
| 7970 KeyFilter filter, | 8070 KeyFilter filter, |
| 7971 GetKeysConversion getConversion, | 8071 GetKeysConversion keys_conversion, |
| 7972 Enumerability enum_policy) { | 8072 Enumerability enum_policy) { |
| 7973 USE(ContainsOnlyValidKeys); | 8073 USE(ContainsOnlyValidKeys); |
| 7974 Isolate* isolate = object->GetIsolate(); | 8074 Isolate* isolate = object->GetIsolate(); |
| 7975 KeyAccumulator accumulator(isolate, filter); | 8075 KeyAccumulator accumulator(isolate, filter); |
| 7976 Handle<JSFunction> arguments_function( | |
| 7977 JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor())); | |
| 7978 PrototypeIterator::WhereToEnd end = type == OWN_ONLY | 8076 PrototypeIterator::WhereToEnd end = type == OWN_ONLY |
| 7979 ? PrototypeIterator::END_AT_NON_HIDDEN | 8077 ? PrototypeIterator::END_AT_NON_HIDDEN |
| 7980 : PrototypeIterator::END_AT_NULL; | 8078 : PrototypeIterator::END_AT_NULL; |
| 7981 PropertyAttributes attr_filter = static_cast<PropertyAttributes>( | |
| 7982 (enum_policy == RESPECT_ENUMERABILITY ? DONT_ENUM : NONE) | | |
| 7983 PRIVATE_SYMBOL); | |
| 7984 | |
| 7985 // Only collect keys if access is permitted. | |
| 7986 for (PrototypeIterator iter(isolate, object, | 8079 for (PrototypeIterator iter(isolate, object, |
| 7987 PrototypeIterator::START_AT_RECEIVER); | 8080 PrototypeIterator::START_AT_RECEIVER); |
| 7988 !iter.IsAtEnd(end); iter.Advance()) { | 8081 !iter.IsAtEnd(end); iter.Advance()) { |
| 7989 accumulator.NextPrototype(); | 8082 accumulator.NextPrototype(); |
| 7990 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 8083 if (!GetKeysFromJSReceiver(isolate, object, |
| 7991 Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter); | 8084 PrototypeIterator::GetCurrent<JSReceiver>(iter), |
| 7992 Handle<Object> args[] = { proxy }; | 8085 filter, enum_policy, &accumulator)) { |
| 7993 Handle<Object> names; | 8086 if (isolate->has_pending_exception()) { |
| 7994 ASSIGN_RETURN_ON_EXCEPTION( | 8087 return MaybeHandle<FixedArray>(); |
| 7995 isolate, names, | 8088 } |
| 7996 Execution::Call(isolate, | 8089 // If there was no exception, then "false" means "stop iterating". |
| 7997 isolate->proxy_enumerate(), | |
| 7998 object, | |
| 7999 arraysize(args), | |
| 8000 args), | |
| 8001 FixedArray); | |
| 8002 accumulator.AddKeysFromProxy(Handle<JSObject>::cast(names)); | |
| 8003 break; | 8090 break; |
| 8004 } | 8091 } |
| 8005 | |
| 8006 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); | |
| 8007 | |
| 8008 // Check access rights if required. | |
| 8009 if (current->IsAccessCheckNeeded() && | |
| 8010 !isolate->MayAccess(handle(isolate->context()), current)) { | |
| 8011 if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | |
|
Jakob Kummerow
2015/11/25 11:33:47
I've dropped this condition as discussed, because
| |
| 8012 isolate->ReportFailedAccessCheck(current); | |
| 8013 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | |
| 8014 } | |
| 8015 break; | |
| 8016 } | |
| 8017 | |
| 8018 JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter); | |
| 8019 | |
| 8020 // Add the element keys from the interceptor. | |
| 8021 if (current->HasIndexedInterceptor()) { | |
| 8022 Handle<JSObject> result; | |
| 8023 if (JSObject::GetKeysForIndexedInterceptor(current, object) | |
| 8024 .ToHandle(&result)) { | |
| 8025 accumulator.AddElementKeysFromInterceptor(result); | |
| 8026 } | |
| 8027 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | |
| 8028 } | |
| 8029 | |
| 8030 if (filter == SKIP_SYMBOLS) { | |
| 8031 if (enum_policy == IGNORE_ENUMERABILITY) UNIMPLEMENTED(); | |
| 8032 | |
| 8033 // We can cache the computed property keys if access checks are | |
| 8034 // not needed and no interceptors are involved. | |
| 8035 // | |
| 8036 // We do not use the cache if the object has elements and | |
| 8037 // therefore it does not make sense to cache the property names | |
| 8038 // for arguments objects. Arguments objects will always have | |
| 8039 // elements. | |
| 8040 // Wrapped strings have elements, but don't have an elements | |
| 8041 // array or dictionary. So the fast inline test for whether to | |
| 8042 // use the cache says yes, so we should not create a cache. | |
| 8043 bool cache_enum_length = | |
| 8044 ((current->map()->GetConstructor() != *arguments_function) && | |
| 8045 !current->IsJSValue() && !current->IsAccessCheckNeeded() && | |
| 8046 !current->HasNamedInterceptor() && | |
| 8047 !current->HasIndexedInterceptor()); | |
| 8048 // Compute the property keys and cache them if possible. | |
| 8049 Handle<FixedArray> enum_keys = | |
| 8050 JSObject::GetEnumPropertyKeys(current, cache_enum_length); | |
| 8051 accumulator.AddKeys(enum_keys); | |
| 8052 } else { | |
| 8053 DCHECK(filter == INCLUDE_SYMBOLS); | |
| 8054 current->CollectOwnPropertyNames(&accumulator, attr_filter); | |
| 8055 } | |
| 8056 | |
| 8057 // Add the property keys from the interceptor. | |
| 8058 if (current->HasNamedInterceptor()) { | |
| 8059 Handle<JSObject> result; | |
| 8060 if (JSObject::GetKeysForNamedInterceptor(current, object) | |
| 8061 .ToHandle(&result)) { | |
| 8062 accumulator.AddKeys(result); | |
| 8063 } | |
| 8064 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | |
| 8065 } | |
| 8066 } | 8092 } |
| 8067 | 8093 |
| 8068 Handle<FixedArray> keys = accumulator.GetKeys(getConversion); | 8094 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion); |
| 8069 DCHECK(ContainsOnlyValidKeys(keys)); | 8095 DCHECK(ContainsOnlyValidKeys(keys)); |
| 8070 return keys; | 8096 return keys; |
| 8071 } | 8097 } |
| 8072 | 8098 |
| 8073 | 8099 |
| 8074 bool Map::DictionaryElementsInPrototypeChainOnly() { | 8100 bool Map::DictionaryElementsInPrototypeChainOnly() { |
| 8075 if (IsDictionaryElementsKind(elements_kind())) { | 8101 if (IsDictionaryElementsKind(elements_kind())) { |
| 8076 return false; | 8102 return false; |
| 8077 } | 8103 } |
| 8078 | 8104 |
| (...skipping 10469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 18548 if (cell->value() != *new_value) { | 18574 if (cell->value() != *new_value) { |
| 18549 cell->set_value(*new_value); | 18575 cell->set_value(*new_value); |
| 18550 Isolate* isolate = cell->GetIsolate(); | 18576 Isolate* isolate = cell->GetIsolate(); |
| 18551 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 18577 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
| 18552 isolate, DependentCode::kPropertyCellChangedGroup); | 18578 isolate, DependentCode::kPropertyCellChangedGroup); |
| 18553 } | 18579 } |
| 18554 } | 18580 } |
| 18555 | 18581 |
| 18556 } // namespace internal | 18582 } // namespace internal |
| 18557 } // namespace v8 | 18583 } // namespace v8 |
| OLD | NEW |