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 6704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6715 | 6715 |
6716 return context->extension_object()->ReferencesObject(obj); | 6716 return context->extension_object()->ReferencesObject(obj); |
6717 } | 6717 } |
6718 } | 6718 } |
6719 | 6719 |
6720 // No references to object. | 6720 // No references to object. |
6721 return false; | 6721 return false; |
6722 } | 6722 } |
6723 | 6723 |
6724 | 6724 |
6725 #define RETURN_FAILURE(isolate, should_throw, call) \ | |
6726 do { \ | |
6727 if ((should_throw) == DONT_THROW) { \ | |
6728 return Just(false); \ | |
6729 } else { \ | |
6730 isolate->Throw(*isolate->factory()->call); \ | |
6731 return Nothing<bool>(); \ | |
6732 } \ | |
6733 } while (false) | |
6734 | |
6735 | |
6736 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, | 6725 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, |
6737 ShouldThrow should_throw) { | 6726 ShouldThrow should_throw) { |
6738 if (!object->IsJSObject()) return Just(false); | 6727 if (!object->IsJSObject()) return Just(false); |
6739 // TODO(neis): Deal with proxies. | 6728 // TODO(neis): Deal with proxies. |
6740 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), | 6729 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), |
6741 should_throw); | 6730 should_throw); |
6742 } | 6731 } |
6743 | 6732 |
6744 | 6733 |
6745 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, | 6734 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, |
(...skipping 7125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13871 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype); | 13860 Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype); |
13872 if (new_map.is_null()) { | 13861 if (new_map.is_null()) { |
13873 new_map = Copy(map, "TransitionToPrototype"); | 13862 new_map = Copy(map, "TransitionToPrototype"); |
13874 TransitionArray::PutPrototypeTransition(map, prototype, new_map); | 13863 TransitionArray::PutPrototypeTransition(map, prototype, new_map); |
13875 Map::SetPrototype(new_map, prototype, mode); | 13864 Map::SetPrototype(new_map, prototype, mode); |
13876 } | 13865 } |
13877 return new_map; | 13866 return new_map; |
13878 } | 13867 } |
13879 | 13868 |
13880 | 13869 |
13881 MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, | 13870 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object, |
13882 Handle<Object> value, | 13871 Handle<Object> value, bool from_javascript, |
13883 bool from_javascript) { | 13872 ShouldThrow should_throw) { |
| 13873 if (!object->IsJSObject()) return Just(false); |
| 13874 // TODO(neis): Deal with proxies. |
| 13875 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value, |
| 13876 from_javascript, should_throw); |
| 13877 } |
| 13878 |
| 13879 |
| 13880 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, |
| 13881 Handle<Object> value, bool from_javascript, |
| 13882 ShouldThrow should_throw) { |
13884 Isolate* isolate = object->GetIsolate(); | 13883 Isolate* isolate = object->GetIsolate(); |
13885 | 13884 |
13886 const bool observed = from_javascript && object->map()->is_observed(); | 13885 const bool observed = from_javascript && object->map()->is_observed(); |
13887 Handle<Object> old_value; | 13886 Handle<Object> old_value; |
13888 if (observed) { | 13887 if (observed) { |
13889 old_value = Object::GetPrototype(isolate, object); | 13888 old_value = Object::GetPrototype(isolate, object); |
13890 } | 13889 } |
13891 | 13890 |
13892 Handle<Object> result; | 13891 Maybe<bool> result = |
13893 ASSIGN_RETURN_ON_EXCEPTION( | 13892 SetPrototypeUnobserved(object, value, from_javascript, should_throw); |
13894 isolate, result, SetPrototypeUnobserved(object, value, from_javascript), | 13893 MAYBE_RETURN(result, Nothing<bool>()); |
13895 Object); | |
13896 | 13894 |
13897 if (observed) { | 13895 if (result.FromJust() && observed) { |
13898 Handle<Object> new_value = Object::GetPrototype(isolate, object); | 13896 Handle<Object> new_value = Object::GetPrototype(isolate, object); |
13899 if (!new_value->SameValue(*old_value)) { | 13897 if (!new_value->SameValue(*old_value)) { |
13900 RETURN_ON_EXCEPTION(isolate, | 13898 RETURN_ON_EXCEPTION_VALUE( |
13901 JSObject::EnqueueChangeRecord( | 13899 isolate, JSObject::EnqueueChangeRecord( |
13902 object, "setPrototype", | 13900 object, "setPrototype", |
13903 isolate->factory()->proto_string(), old_value), | 13901 isolate->factory()->proto_string(), old_value), |
13904 Object); | 13902 Nothing<bool>()); |
13905 } | 13903 } |
13906 } | 13904 } |
13907 | 13905 |
13908 return result; | 13906 return result; |
13909 } | 13907 } |
13910 | 13908 |
13911 | 13909 |
13912 MaybeHandle<Object> JSObject::SetPrototypeUnobserved(Handle<JSObject> object, | 13910 Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object, |
13913 Handle<Object> value, | 13911 Handle<Object> value, |
13914 bool from_javascript) { | 13912 bool from_javascript, |
| 13913 ShouldThrow should_throw) { |
13915 #ifdef DEBUG | 13914 #ifdef DEBUG |
13916 int size = object->Size(); | 13915 int size = object->Size(); |
13917 #endif | 13916 #endif |
13918 | 13917 |
13919 Isolate* isolate = object->GetIsolate(); | 13918 Isolate* isolate = object->GetIsolate(); |
13920 | 13919 |
13921 if (from_javascript) { | 13920 if (from_javascript) { |
13922 if (object->IsAccessCheckNeeded() && | 13921 if (object->IsAccessCheckNeeded() && |
13923 !isolate->MayAccess(handle(isolate->context()), object)) { | 13922 !isolate->MayAccess(handle(isolate->context()), object)) { |
13924 isolate->ReportFailedAccessCheck(object); | 13923 isolate->ReportFailedAccessCheck(object); |
13925 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 13924 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); |
13926 return isolate->factory()->undefined_value(); | 13925 UNREACHABLE(); |
13927 } | 13926 } |
13928 } else { | 13927 } else { |
13929 DCHECK(!object->IsAccessCheckNeeded()); | 13928 DCHECK(!object->IsAccessCheckNeeded()); |
13930 } | 13929 } |
13931 | 13930 |
13932 // Strong objects may not have their prototype set via __proto__ or | 13931 // Strong objects may not have their prototype set via __proto__ or |
13933 // setPrototypeOf. | 13932 // setPrototypeOf. |
13934 if (from_javascript && object->map()->is_strong()) { | 13933 if (from_javascript && object->map()->is_strong()) { |
13935 THROW_NEW_ERROR(isolate, | 13934 RETURN_FAILURE(isolate, should_throw, |
13936 NewTypeError(MessageTemplate::kStrongSetProto, object), | 13935 NewTypeError(MessageTemplate::kStrongSetProto, object)); |
13937 Object); | |
13938 } | 13936 } |
13939 Heap* heap = isolate->heap(); | 13937 Heap* heap = isolate->heap(); |
13940 // Silently ignore the change if value is not a JSObject or null. | 13938 // Silently ignore the change if value is not a JSObject or null. |
13941 // SpiderMonkey behaves this way. | 13939 // SpiderMonkey behaves this way. |
13942 if (!value->IsJSReceiver() && !value->IsNull()) return value; | 13940 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true); |
13943 | 13941 |
13944 // From 8.6.2 Object Internal Methods | 13942 // From 8.6.2 Object Internal Methods |
13945 // ... | 13943 // ... |
13946 // In addition, if [[Extensible]] is false the value of the [[Class]] and | 13944 // In addition, if [[Extensible]] is false the value of the [[Class]] and |
13947 // [[Prototype]] internal properties of the object may not be modified. | 13945 // [[Prototype]] internal properties of the object may not be modified. |
13948 // ... | 13946 // ... |
13949 // Implementation specific extensions that modify [[Class]], [[Prototype]] | 13947 // Implementation specific extensions that modify [[Class]], [[Prototype]] |
13950 // or [[Extensible]] must not violate the invariants defined in the preceding | 13948 // or [[Extensible]] must not violate the invariants defined in the preceding |
13951 // paragraph. | 13949 // paragraph. |
13952 if (!object->map()->is_extensible()) { | 13950 if (!object->map()->is_extensible()) { |
13953 THROW_NEW_ERROR(isolate, | 13951 RETURN_FAILURE(isolate, should_throw, |
13954 NewTypeError(MessageTemplate::kNonExtensibleProto, object), | 13952 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); |
13955 Object); | 13953 // TODO(neis): Don't fail if new and old prototype happen to be the same. |
13956 } | 13954 } |
13957 | 13955 |
13958 // Before we can set the prototype we need to be sure | 13956 // Before we can set the prototype we need to be sure |
13959 // prototype cycles are prevented. | 13957 // prototype cycles are prevented. |
13960 // It is sufficient to validate that the receiver is not in the new prototype | 13958 // It is sufficient to validate that the receiver is not in the new prototype |
13961 // chain. | 13959 // chain. |
13962 for (PrototypeIterator iter(isolate, *value, | 13960 for (PrototypeIterator iter(isolate, *value, |
13963 PrototypeIterator::START_AT_RECEIVER); | 13961 PrototypeIterator::START_AT_RECEIVER); |
13964 !iter.IsAtEnd(); iter.Advance()) { | 13962 !iter.IsAtEnd(); iter.Advance()) { |
13965 if (iter.GetCurrent<JSReceiver>() == *object) { | 13963 if (iter.GetCurrent<JSReceiver>() == *object) { |
13966 // Cycle detected. | 13964 // Cycle detected. |
13967 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kCyclicProto), | 13965 RETURN_FAILURE(isolate, should_throw, |
13968 Object); | 13966 NewTypeError(MessageTemplate::kCyclicProto)); |
13969 } | 13967 } |
13970 } | 13968 } |
13971 | 13969 |
13972 bool dictionary_elements_in_chain = | 13970 bool dictionary_elements_in_chain = |
13973 object->map()->DictionaryElementsInPrototypeChainOnly(); | 13971 object->map()->DictionaryElementsInPrototypeChainOnly(); |
13974 Handle<JSObject> real_receiver = object; | 13972 Handle<JSObject> real_receiver = object; |
13975 | 13973 |
13976 if (from_javascript) { | 13974 if (from_javascript) { |
13977 // Find the first object in the chain whose prototype object is not | 13975 // Find the first object in the chain whose prototype object is not |
13978 // hidden and set the new prototype on that object. | 13976 // hidden and set the new prototype on that object. |
13979 PrototypeIterator iter(isolate, real_receiver); | 13977 PrototypeIterator iter(isolate, real_receiver); |
13980 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | 13978 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
13981 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); | 13979 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); |
13982 iter.Advance(); | 13980 iter.Advance(); |
13983 if (!real_receiver->map()->is_extensible()) { | 13981 if (!real_receiver->map()->is_extensible()) { |
13984 THROW_NEW_ERROR( | 13982 RETURN_FAILURE( |
13985 isolate, NewTypeError(MessageTemplate::kNonExtensibleProto, object), | 13983 isolate, should_throw, |
13986 Object); | 13984 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); |
13987 } | 13985 } |
13988 } | 13986 } |
13989 } | 13987 } |
13990 | 13988 |
13991 // Set the new prototype of the object. | 13989 // Set the new prototype of the object. |
13992 Handle<Map> map(real_receiver->map()); | 13990 Handle<Map> map(real_receiver->map()); |
13993 | 13991 |
13994 // Nothing to do if prototype is already set. | 13992 // Nothing to do if prototype is already set. |
13995 if (map->prototype() == *value) return value; | 13993 if (map->prototype() == *value) return Just(true); |
13996 | 13994 |
13997 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); | 13995 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); |
13998 | 13996 |
13999 PrototypeOptimizationMode mode = | 13997 PrototypeOptimizationMode mode = |
14000 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; | 13998 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; |
14001 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); | 13999 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); |
14002 DCHECK(new_map->prototype() == *value); | 14000 DCHECK(new_map->prototype() == *value); |
14003 JSObject::MigrateToMap(real_receiver, new_map); | 14001 JSObject::MigrateToMap(real_receiver, new_map); |
14004 | 14002 |
14005 if (from_javascript && !dictionary_elements_in_chain && | 14003 if (from_javascript && !dictionary_elements_in_chain && |
14006 new_map->DictionaryElementsInPrototypeChainOnly()) { | 14004 new_map->DictionaryElementsInPrototypeChainOnly()) { |
14007 // If the prototype chain didn't previously have element callbacks, then | 14005 // If the prototype chain didn't previously have element callbacks, then |
14008 // KeyedStoreICs need to be cleared to ensure any that involve this | 14006 // KeyedStoreICs need to be cleared to ensure any that involve this |
14009 // map go generic. | 14007 // map go generic. |
14010 object->GetHeap()->ClearAllKeyedStoreICs(); | 14008 object->GetHeap()->ClearAllKeyedStoreICs(); |
14011 } | 14009 } |
14012 | 14010 |
14013 heap->ClearInstanceofCache(); | 14011 heap->ClearInstanceofCache(); |
14014 DCHECK(size == object->Size()); | 14012 DCHECK(size == object->Size()); |
14015 return value; | 14013 return Just(true); |
14016 } | 14014 } |
14017 | 14015 |
14018 | 14016 |
14019 void JSObject::EnsureCanContainElements(Handle<JSObject> object, | 14017 void JSObject::EnsureCanContainElements(Handle<JSObject> object, |
14020 Arguments* args, | 14018 Arguments* args, |
14021 uint32_t first_arg, | 14019 uint32_t first_arg, |
14022 uint32_t arg_count, | 14020 uint32_t arg_count, |
14023 EnsureElementsMode mode) { | 14021 EnsureElementsMode mode) { |
14024 // Elements in |Arguments| are ordered backwards (because they're on the | 14022 // Elements in |Arguments| are ordered backwards (because they're on the |
14025 // stack), but the method that's called here iterates over them in forward | 14023 // stack), but the method that's called here iterates over them in forward |
(...skipping 3786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17812 if (cell->value() != *new_value) { | 17810 if (cell->value() != *new_value) { |
17813 cell->set_value(*new_value); | 17811 cell->set_value(*new_value); |
17814 Isolate* isolate = cell->GetIsolate(); | 17812 Isolate* isolate = cell->GetIsolate(); |
17815 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17813 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
17816 isolate, DependentCode::kPropertyCellChangedGroup); | 17814 isolate, DependentCode::kPropertyCellChangedGroup); |
17817 } | 17815 } |
17818 } | 17816 } |
17819 | 17817 |
17820 } // namespace internal | 17818 } // namespace internal |
17821 } // namespace v8 | 17819 } // namespace v8 |
OLD | NEW |