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