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 13921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
13932 // setPrototypeOf. | 13932 // setPrototypeOf. |
13933 if (from_javascript && object->map()->is_strong()) { | 13933 if (from_javascript && object->map()->is_strong()) { |
13934 RETURN_FAILURE(isolate, should_throw, | 13934 RETURN_FAILURE(isolate, should_throw, |
13935 NewTypeError(MessageTemplate::kStrongSetProto, object)); | 13935 NewTypeError(MessageTemplate::kStrongSetProto, object)); |
13936 } | 13936 } |
13937 Heap* heap = isolate->heap(); | 13937 Heap* heap = isolate->heap(); |
13938 // 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. |
13939 // SpiderMonkey behaves this way. | 13939 // SpiderMonkey behaves this way. |
13940 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true); | 13940 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true); |
13941 | 13941 |
13942 bool dictionary_elements_in_chain = | |
13943 object->map()->DictionaryElementsInPrototypeChainOnly(); | |
13944 | |
13945 bool all_extensible = object->map()->is_extensible(); | |
13946 Handle<JSObject> real_receiver = object; | |
13947 if (from_javascript) { | |
13948 // Find the first object in the chain whose prototype object is not | |
13949 // hidden. | |
13950 PrototypeIterator iter(isolate, real_receiver); | |
13951 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | |
13952 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); | |
Toon Verwaest
2015/10/22 13:21:07
This code is a bit overkill, since this is only re
| |
13953 iter.Advance(); | |
13954 all_extensible = all_extensible && real_receiver->map()->is_extensible(); | |
13955 } | |
13956 } | |
13957 Handle<Map> map(real_receiver->map()); | |
Toon Verwaest
2015/10/22 13:21:07
Slight overkill to allocate a handle to just deref
neis
2015/10/23 14:26:54
It's used again further down.
| |
13958 | |
13959 // Nothing to do if prototype is already set. | |
13960 if (map->prototype() == *value) return Just(true); | |
13961 | |
13942 // From 8.6.2 Object Internal Methods | 13962 // From 8.6.2 Object Internal Methods |
13943 // ... | 13963 // ... |
13944 // In addition, if [[Extensible]] is false the value of the [[Class]] and | 13964 // In addition, if [[Extensible]] is false the value of the [[Class]] and |
13945 // [[Prototype]] internal properties of the object may not be modified. | 13965 // [[Prototype]] internal properties of the object may not be modified. |
13946 // ... | 13966 // ... |
13947 // Implementation specific extensions that modify [[Class]], [[Prototype]] | 13967 // Implementation specific extensions that modify [[Class]], [[Prototype]] |
13948 // or [[Extensible]] must not violate the invariants defined in the preceding | 13968 // or [[Extensible]] must not violate the invariants defined in the preceding |
13949 // paragraph. | 13969 // paragraph. |
13950 if (!object->map()->is_extensible()) { | 13970 if (!all_extensible) { |
13951 RETURN_FAILURE(isolate, should_throw, | 13971 RETURN_FAILURE(isolate, should_throw, |
13952 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); | 13972 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); |
13953 // TODO(neis): Don't fail if new and old prototype happen to be the same. | |
13954 } | 13973 } |
13955 | 13974 |
13956 // Before we can set the prototype we need to be sure | 13975 // Before we can set the prototype we need to be sure prototype cycles are |
13957 // prototype cycles are prevented. | 13976 // prevented. It is sufficient to validate that the receiver is not in the |
13958 // It is sufficient to validate that the receiver is not in the new prototype | 13977 // new prototype chain. |
13959 // chain. | |
13960 for (PrototypeIterator iter(isolate, *value, | 13978 for (PrototypeIterator iter(isolate, *value, |
13961 PrototypeIterator::START_AT_RECEIVER); | 13979 PrototypeIterator::START_AT_RECEIVER); |
13962 !iter.IsAtEnd(); iter.Advance()) { | 13980 !iter.IsAtEnd(); iter.Advance()) { |
13963 if (iter.GetCurrent<JSReceiver>() == *object) { | 13981 if (iter.GetCurrent<JSReceiver>() == *object) { |
13964 // Cycle detected. | 13982 // Cycle detected. |
13965 RETURN_FAILURE(isolate, should_throw, | 13983 RETURN_FAILURE(isolate, should_throw, |
13966 NewTypeError(MessageTemplate::kCyclicProto)); | 13984 NewTypeError(MessageTemplate::kCyclicProto)); |
13967 } | 13985 } |
13968 } | 13986 } |
13969 | 13987 |
13970 bool dictionary_elements_in_chain = | |
13971 object->map()->DictionaryElementsInPrototypeChainOnly(); | |
13972 Handle<JSObject> real_receiver = object; | |
13973 | |
13974 if (from_javascript) { | |
13975 // Find the first object in the chain whose prototype object is not | |
13976 // hidden and set the new prototype on that object. | |
13977 PrototypeIterator iter(isolate, real_receiver); | |
13978 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | |
13979 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); | |
13980 iter.Advance(); | |
13981 if (!real_receiver->map()->is_extensible()) { | |
13982 RETURN_FAILURE( | |
13983 isolate, should_throw, | |
13984 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); | |
13985 } | |
13986 } | |
13987 } | |
13988 | |
13989 // Set the new prototype of the object. | 13988 // Set the new prototype of the object. |
13990 Handle<Map> map(real_receiver->map()); | |
13991 | |
13992 // Nothing to do if prototype is already set. | |
13993 if (map->prototype() == *value) return Just(true); | |
13994 | 13989 |
13995 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); | 13990 isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); |
13996 | 13991 |
13997 PrototypeOptimizationMode mode = | 13992 PrototypeOptimizationMode mode = |
13998 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; | 13993 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; |
13999 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); | 13994 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode); |
14000 DCHECK(new_map->prototype() == *value); | 13995 DCHECK(new_map->prototype() == *value); |
14001 JSObject::MigrateToMap(real_receiver, new_map); | 13996 JSObject::MigrateToMap(real_receiver, new_map); |
14002 | 13997 |
14003 if (from_javascript && !dictionary_elements_in_chain && | 13998 if (from_javascript && !dictionary_elements_in_chain && |
(...skipping 3806 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
17810 if (cell->value() != *new_value) { | 17805 if (cell->value() != *new_value) { |
17811 cell->set_value(*new_value); | 17806 cell->set_value(*new_value); |
17812 Isolate* isolate = cell->GetIsolate(); | 17807 Isolate* isolate = cell->GetIsolate(); |
17813 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17808 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
17814 isolate, DependentCode::kPropertyCellChangedGroup); | 17809 isolate, DependentCode::kPropertyCellChangedGroup); |
17815 } | 17810 } |
17816 } | 17811 } |
17817 | 17812 |
17818 } // namespace internal | 17813 } // namespace internal |
17819 } // namespace v8 | 17814 } // namespace v8 |
OLD | NEW |