Bug 1125505 - SetClassAndProto should only reshape the whole proto chain if the object is another object's proto. r=bhackett

This commit is contained in:
Jan de Mooij
2015-01-30 12:17:10 +01:00
parent 8355aa1b4b
commit dbb6e24e09
5 changed files with 65 additions and 20 deletions

View File

@@ -2704,25 +2704,24 @@ bool
js::SetClassAndProto(JSContext *cx, HandleObject obj,
const Class *clasp, Handle<js::TaggedProto> proto)
{
/*
* Regenerate shapes for all of the scopes along the old prototype chain,
* in case any entries were filled by looking up through obj. Stop when a
* non-native object is found, prototype lookups will not be cached across
* these.
*
* How this shape change is done is very delicate; the change can be made
* either by marking the object's prototype as uncacheable (such that the
* property cache and JIT'ed ICs cannot assume the shape determines the
* prototype) or by just generating a new shape for the object. Choosing
* the former is bad if the object is on the prototype chain of other
* objects, as the uncacheable prototype can inhibit iterator caches on
* those objects and slow down prototype accesses. Choosing the latter is
* bad if there are many similar objects to this one which will have their
* prototype mutated, as the generateOwnShape forces the object into
* dictionary mode and similar property lineages will be repeatedly cloned.
*
* :XXX: bug 707717 make this code less brittle.
*/
// Regenerate the object's shape. If the object is a proto (isDelegate()),
// we also need to regenerate shapes for all of the objects along the old
// prototype chain, in case any entries were filled by looking up through
// obj. Stop when a non-native object is found, prototype lookups will not
// be cached across these.
//
// How this shape change is done is very delicate; the change can be made
// either by marking the object's prototype as uncacheable (such that the
// JIT'ed ICs cannot assume the shape determines the prototype) or by just
// generating a new shape for the object. Choosing the former is bad if the
// object is on the prototype chain of other objects, as the uncacheable
// prototype can inhibit iterator caches on those objects and slow down
// prototype accesses. Choosing the latter is bad if there are many similar
// objects to this one which will have their prototype mutated, as the
// generateOwnShape forces the object into dictionary mode and similar
// property lineages will be repeatedly cloned.
//
// :XXX: bug 707717 make this code less brittle.
RootedObject oldproto(cx, obj);
while (oldproto && oldproto->isNative()) {
if (oldproto->hasSingletonType()) {
@@ -2732,9 +2731,18 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj,
if (!oldproto->setUncacheableProto(cx))
return false;
}
if (!obj->isDelegate()) {
// If |obj| is not a proto of another object, we don't need to
// reshape the whole proto chain.
MOZ_ASSERT(obj == oldproto);
break;
}
oldproto = oldproto->getProto();
}
if (proto.isObject() && !proto.toObject()->setDelegate(cx))
return false;
if (obj->hasSingletonType()) {
/*
* Just splice the prototype, but mark the properties as unknown for