Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 5382b411e6bb563a58139215f85900b7446f34f1..14e5d3e69f876f2616b60f2ac28af73a1c4d1d79 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -13939,6 +13939,26 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object, |
| // SpiderMonkey behaves this way. |
| if (!value->IsJSReceiver() && !value->IsNull()) return Just(true); |
| + bool dictionary_elements_in_chain = |
| + object->map()->DictionaryElementsInPrototypeChainOnly(); |
| + |
| + bool all_extensible = object->map()->is_extensible(); |
| + Handle<JSObject> real_receiver = object; |
| + if (from_javascript) { |
| + // Find the first object in the chain whose prototype object is not |
| + // hidden. |
| + PrototypeIterator iter(isolate, real_receiver); |
| + while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
| + 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
|
| + iter.Advance(); |
| + all_extensible = all_extensible && real_receiver->map()->is_extensible(); |
| + } |
| + } |
| + 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.
|
| + |
| + // Nothing to do if prototype is already set. |
| + if (map->prototype() == *value) return Just(true); |
| + |
| // From 8.6.2 Object Internal Methods |
| // ... |
| // In addition, if [[Extensible]] is false the value of the [[Class]] and |
| @@ -13947,16 +13967,14 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object, |
| // Implementation specific extensions that modify [[Class]], [[Prototype]] |
| // or [[Extensible]] must not violate the invariants defined in the preceding |
| // paragraph. |
| - if (!object->map()->is_extensible()) { |
| + if (!all_extensible) { |
| RETURN_FAILURE(isolate, should_throw, |
| NewTypeError(MessageTemplate::kNonExtensibleProto, object)); |
| - // TODO(neis): Don't fail if new and old prototype happen to be the same. |
| } |
| - // Before we can set the prototype we need to be sure |
| - // prototype cycles are prevented. |
| - // It is sufficient to validate that the receiver is not in the new prototype |
| - // chain. |
| + // Before we can set the prototype we need to be sure prototype cycles are |
| + // prevented. It is sufficient to validate that the receiver is not in the |
| + // new prototype chain. |
| for (PrototypeIterator iter(isolate, *value, |
| PrototypeIterator::START_AT_RECEIVER); |
| !iter.IsAtEnd(); iter.Advance()) { |
| @@ -13967,30 +13985,7 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object, |
| } |
| } |
| - bool dictionary_elements_in_chain = |
| - object->map()->DictionaryElementsInPrototypeChainOnly(); |
| - Handle<JSObject> real_receiver = object; |
| - |
| - if (from_javascript) { |
| - // Find the first object in the chain whose prototype object is not |
| - // hidden and set the new prototype on that object. |
| - PrototypeIterator iter(isolate, real_receiver); |
| - while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
| - real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); |
| - iter.Advance(); |
| - if (!real_receiver->map()->is_extensible()) { |
| - RETURN_FAILURE( |
| - isolate, should_throw, |
| - NewTypeError(MessageTemplate::kNonExtensibleProto, object)); |
| - } |
| - } |
| - } |
| - |
| // Set the new prototype of the object. |
| - Handle<Map> map(real_receiver->map()); |
| - |
| - // Nothing to do if prototype is already set. |
| - if (map->prototype() == *value) return Just(true); |
| isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); |