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