Empty shapes attached to type objects must have the same class as the prototype, bug 698150.

This commit is contained in:
Brian Hackett 2011-11-09 13:08:23 -08:00
parent da034e0aac
commit 2c2283ba38
5 changed files with 12 additions and 50 deletions

View File

@ -814,10 +814,10 @@ struct TypeObject : gc::Cell
/* /*
* Return an immutable, shareable, empty shape for objects with this type * Return an immutable, shareable, empty shape for objects with this type
* and the specified class, and finalize kind (fixed slot count). Objects * and the specified class, and finalize kind (fixed slot count). Objects
* created with this shape have the same parent as the type's prototype. * created with this shape have the same class and parent as the type's
* prototype.
*/ */
inline bool canProvideEmptyShape(js::Class *clasp); inline js::EmptyShape *getEmptyShape(JSContext *cx, gc::AllocKind kind);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind);
/* /*
* Get or create a property of this object. Only call this for properties which * Get or create a property of this object. Only call this for properties which

View File

@ -4419,10 +4419,6 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx)) if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx))
return NULL; return NULL;
TypeObject *type = proto->getNewType(cx);
if (!type || !type->getEmptyShape(cx, proto->getClass(), FINALIZE_OBJECT0))
return NULL;
/* After this point, control must exit via label bad or out. */ /* After this point, control must exit via label bad or out. */
JSObject *ctor; JSObject *ctor;
bool named = false; bool named = false;

View File

@ -1585,8 +1585,11 @@ GetInitialShapeForObject(JSContext* cx, Class *clasp, JSObject *parent,
{ {
if (clasp->isNative()) { if (clasp->isNative()) {
/* Share empty shapes on the type only if the object is similar to the proto. */ /* Share empty shapes on the type only if the object is similar to the proto. */
if (type->canProvideEmptyShape(clasp) && parent == type->proto->getParent()) if (type->proto &&
return type->getEmptyShape(cx, clasp, kind); clasp == type->proto->getClass() &&
parent == type->proto->getParent()) {
return type->getEmptyShape(cx, kind);
}
return EmptyShape::create(cx, clasp, parent, gc::GetGCKindSlots(kind, clasp)); return EmptyShape::create(cx, clasp, parent, gc::GetGCKindSlots(kind, clasp));
} }

View File

@ -58,14 +58,14 @@
#include "jsobjinlines.h" #include "jsobjinlines.h"
inline js::EmptyShape * inline js::EmptyShape *
js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind) js::types::TypeObject::getEmptyShape(JSContext *cx, gc::AllocKind kind)
{ {
JS_ASSERT(!singleton); JS_ASSERT(!singleton);
/* /*
* Empty shapes can only be on the default 'new' type for a prototype. * Empty shapes can only be on the default 'new' type for a prototype.
* Objects with a common prototype use the same shape lineage, even if * Objects with a common prototype use the same shape lineage, even if
* their prototypes differ. * their types differ.
*/ */
JS_ASSERT(proto->hasNewType(this)); JS_ASSERT(proto->hasNewType(this));
@ -73,38 +73,17 @@ js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp, gc::Alloc
emptyShapes = cx->new_<ShapeKindArray>(); emptyShapes = cx->new_<ShapeKindArray>();
if (!emptyShapes) if (!emptyShapes)
return NULL; return NULL;
/*
* Always fill in the first empty shape, so canProvideEmptyShape works.
* Other empty shapes are filled in lazily.
*/
Shape *first = EmptyShape::create(cx, aclasp, proto->getParent(), 0);
if (!first) {
cx->delete_(emptyShapes);
emptyShapes = NULL;
return NULL;
} }
emptyShapes->get(gc::FINALIZE_OBJECT0) = first;
}
JS_ASSERT(aclasp == emptyShapes->get(gc::FINALIZE_OBJECT0)->getObjectClass());
Shape *&empty = emptyShapes->get(kind); Shape *&empty = emptyShapes->get(kind);
if (!empty) { if (!empty) {
empty = EmptyShape::create(cx, aclasp, proto->getParent(), empty = EmptyShape::create(cx, proto->getClass(), proto->getParent(),
gc::GetGCKindSlots(kind, aclasp)); gc::GetGCKindSlots(kind, proto->getClass()));
} }
return static_cast<EmptyShape *>(empty); return static_cast<EmptyShape *>(empty);
} }
inline bool
js::types::TypeObject::canProvideEmptyShape(js::Class *aclasp)
{
return proto && !singleton &&
(!emptyShapes || emptyShapes->get(gc::FINALIZE_OBJECT0)->getObjectClass() == aclasp);
}
inline bool inline bool
JSObject::updateFlags(JSContext *cx, jsid id, bool isDefinitelyAtom) JSObject::updateFlags(JSContext *cx, jsid id, bool isDefinitelyAtom)
{ {

View File

@ -107,10 +107,6 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
if (!objectProto->setNewTypeUnknown(cx)) if (!objectProto->setNewTypeUnknown(cx))
return NULL; return NULL;
types::TypeObject *objectType = objectProto->getNewType(cx);
if (!objectType || !objectType->getEmptyShape(cx, &ObjectClass, gc::FINALIZE_OBJECT0))
return NULL;
/* Create |Function.prototype| next so we can create other functions. */ /* Create |Function.prototype| next so we can create other functions. */
JSFunction *functionProto; JSFunction *functionProto;
{ {
@ -144,10 +140,6 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
if (!proto->setNewTypeUnknown(cx)) if (!proto->setNewTypeUnknown(cx))
return NULL; return NULL;
types::TypeObject *functionType = proto->getNewType(cx);
if (!functionType || !functionType->getEmptyShape(cx, &FunctionClass, gc::FINALIZE_OBJECT0))
return NULL;
} }
/* Create the Object function now that we have a [[Prototype]] for it. */ /* Create the Object function now that we have a [[Prototype]] for it. */
@ -382,14 +374,6 @@ CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &glo
if (!blankProto || !blankProto->setSingletonType(cx)) if (!blankProto || !blankProto->setSingletonType(cx))
return NULL; return NULL;
/*
* Supply the created prototype object with an empty shape for the benefit
* of callers of JSObject::initSharingEmptyShape.
*/
types::TypeObject *type = blankProto->getNewType(cx);
if (!type || !type->getEmptyShape(cx, clasp, gc::FINALIZE_OBJECT0))
return NULL;
return blankProto; return blankProto;
} }