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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user