Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(792)

Unified Diff: src/objects.cc

Issue 1423603002: Fix corner-case behavior of JSObject::SetPrototype. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/mjsunit/harmony/reflect-set-prototype-of.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « no previous file | test/mjsunit/harmony/reflect-set-prototype-of.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698