Get new object empty shapes with a common hash table, bug 701509.

This commit is contained in:
Brian Hackett 2011-11-10 17:50:05 -08:00
Родитель 135431de6e
Коммит 83d4c45568
22 изменённых файлов: 292 добавлений и 391 удалений

Просмотреть файл

@ -1372,9 +1372,8 @@ JSObject::makeDenseArraySlow(JSContext *cx)
/* Create a native scope. */ /* Create a native scope. */
gc::AllocKind kind = getAllocKind(); gc::AllocKind kind = getAllocKind();
Shape *shape = GetInitialShapeForObject(cx, &SlowArrayClass, Shape *shape = EmptyShape::lookupInitialShape(cx, &SlowArrayClass, getProto(),
oldShape->getObjectParent(), oldShape->getObjectParent(), kind);
getProto()->getNewType(cx), kind);
if (!shape) if (!shape)
return false; return false;
setLastPropertyInfallible(shape); setLastPropertyInfallible(shape);
@ -3892,7 +3891,8 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto)
if (!type) if (!type)
return NULL; return NULL;
Shape *shape = GetInitialShapeForObject(cx, &ArrayClass, proto->getParent(), type, kind); Shape *shape = EmptyShape::lookupInitialShape(cx, &ArrayClass, proto,
proto->getParent(), kind);
if (!shape) if (!shape)
return NULL; return NULL;

Просмотреть файл

@ -469,6 +469,7 @@ JSCompartment::sweep(JSContext *cx, bool releaseTypes)
/* Remove dead references held weakly by the compartment. */ /* Remove dead references held weakly by the compartment. */
sweepBaseShapeTable(cx); sweepBaseShapeTable(cx);
sweepInitialShapeTable(cx);
sweepNewTypeObjectTable(cx, newTypeObjects); sweepNewTypeObjectTable(cx, newTypeObjects);
sweepNewTypeObjectTable(cx, lazyTypeObjects); sweepNewTypeObjectTable(cx, lazyTypeObjects);

Просмотреть файл

@ -46,6 +46,7 @@
#include "jsgc.h" #include "jsgc.h"
#include "jsgcstats.h" #include "jsgcstats.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsscope.h"
#include "vm/GlobalObject.h" #include "vm/GlobalObject.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -474,54 +475,18 @@ struct JS_FRIEND_API(JSCompartment) {
jsrefcount liveDictModeNodes; jsrefcount liveDictModeNodes;
#endif #endif
/* /* Set of all unowned base shapes in the compartment. */
* Set of all unowned base shapes in the compartment, with optional initial js::BaseShapeSet baseShapes;
* shape for objects with the base shape. The initial shape is filled in
* several circumstances:
*
* - For non-native classes and classes without class prototypes (scope
* chain classes, arguments, and iterators), the initial shape is set to
* an empty shape for the class/parent.
*
* - For the String and RegExp classes, the initial shape is preloaded with
* non-configurable properties of the objects mapping the class's various
* fixed slots.
*/
struct BaseShapeEntry {
js::UnownedBaseShape *base;
js::ShapeKindArray *shapes;
typedef const js::BaseShape *Lookup;
static inline js::HashNumber hash(const js::BaseShape *base);
static inline bool match(const BaseShapeEntry &key, const js::BaseShape *lookup);
};
typedef js::HashSet<BaseShapeEntry, BaseShapeEntry, js::SystemAllocPolicy> BaseShapeSet;
BaseShapeSet baseShapes;
void sweepBaseShapeTable(JSContext *cx); void sweepBaseShapeTable(JSContext *cx);
/* /* Set of initial shapes in the compartment. */
* Set of all type objects in the compartment which are the default 'new' js::InitialShapeSet initialShapes;
* or the lazy types of some (possibly NULL) prototype. void sweepInitialShapeTable(JSContext *cx);
*/
struct NewTypeObjectEntry { /* Set of default 'new' or lazy types in the compartment. */
typedef JSObject *Lookup; js::types::TypeObjectSet newTypeObjects;
js::types::TypeObjectSet lazyTypeObjects;
static inline js::HashNumber hash(JSObject *base); void sweepNewTypeObjectTable(JSContext *cx, js::types::TypeObjectSet &table);
static inline bool match(js::types::TypeObject *key, JSObject *lookup);
};
typedef js::HashSet<js::types::TypeObject *, NewTypeObjectEntry, js::SystemAllocPolicy> NewTypeObjectSet;
NewTypeObjectSet newTypeObjects;
NewTypeObjectSet lazyTypeObjects;
void sweepNewTypeObjectTable(JSContext *cx, NewTypeObjectSet &table);
js::types::TypeObject *emptyTypeObject; js::types::TypeObject *emptyTypeObject;
@ -530,6 +495,7 @@ struct JS_FRIEND_API(JSCompartment) {
js::types::TypeObject *getLazyType(JSContext *cx, JSObject *proto); js::types::TypeObject *getLazyType(JSContext *cx, JSObject *proto);
/* Cache to speed up object creation. */
js::NewObjectCache newObjectCache; js::NewObjectCache newObjectCache;
private: private:

Просмотреть файл

@ -139,8 +139,9 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
bool strict = callee.toFunction()->inStrictMode(); bool strict = callee.toFunction()->inStrictMode();
Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass; Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
Shape *emptyArgumentsShape = BaseShape::lookupInitialShape(cx, clasp, proto->getParent(), Shape *emptyArgumentsShape =
FINALIZE_OBJECT4); EmptyShape::lookupInitialShape(cx, clasp, proto,
proto->getParent(), FINALIZE_OBJECT4);
if (!emptyArgumentsShape) if (!emptyArgumentsShape)
return NULL; return NULL;
@ -707,8 +708,8 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
return NULL; return NULL;
JSObject *parent = fp->scopeChain().getGlobal(); JSObject *parent = fp->scopeChain().getGlobal();
Shape *emptyDeclEnvShape = BaseShape::lookupInitialShape(cx, &DeclEnvClass, parent, Shape *emptyDeclEnvShape = EmptyShape::lookupInitialShape(cx, &DeclEnvClass, NULL,
FINALIZE_OBJECT2); parent, FINALIZE_OBJECT2);
if (!emptyDeclEnvShape) if (!emptyDeclEnvShape)
return NULL; return NULL;

Просмотреть файл

@ -874,14 +874,6 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
} }
} }
if (type->emptyShapes) {
for (unsigned i = 0; i < ShapeKindArray::SHAPE_COUNT; i++) {
Shape *shape = type->emptyShapes->getIndex(i);
if (shape)
PushMarkStack(gcmarker, shape);
}
}
if (type->proto) if (type->proto)
PushMarkStack(gcmarker, type->proto); PushMarkStack(gcmarker, type->proto);
@ -914,14 +906,6 @@ MarkChildren(JSTracer *trc, types::TypeObject *type)
} }
} }
if (type->emptyShapes) {
for (unsigned i = 0; i < ShapeKindArray::SHAPE_COUNT; i++) {
Shape *shape = type->emptyShapes->getIndex(i);
if (shape)
MarkShape(trc, shape, "empty_shape");
}
}
if (type->proto) if (type->proto)
MarkObject(trc, *type->proto, "type_proto"); MarkObject(trc, *type->proto, "type_proto");

Просмотреть файл

@ -5703,13 +5703,13 @@ JSObject::makeLazyType(JSContext *cx)
} }
/* static */ inline HashNumber /* static */ inline HashNumber
JSCompartment::NewTypeObjectEntry::hash(JSObject *proto) TypeObjectEntry::hash(JSObject *proto)
{ {
return PointerHasher<JSObject *, 3>::hash(proto); return PointerHasher<JSObject *, 3>::hash(proto);
} }
/* static */ inline bool /* static */ inline bool
JSCompartment::NewTypeObjectEntry::match(TypeObject *key, JSObject *lookup) TypeObjectEntry::match(TypeObject *key, JSObject *lookup)
{ {
return key->proto == lookup; return key->proto == lookup;
} }
@ -5718,12 +5718,12 @@ JSCompartment::NewTypeObjectEntry::match(TypeObject *key, JSObject *lookup)
bool bool
JSObject::hasNewType(TypeObject *type) JSObject::hasNewType(TypeObject *type)
{ {
JSCompartment::NewTypeObjectSet &table = compartment()->newTypeObjects; TypeObjectSet &table = compartment()->newTypeObjects;
if (!table.initialized()) if (!table.initialized())
return false; return false;
JSCompartment::NewTypeObjectSet::Ptr p = table.lookup(this); TypeObjectSet::Ptr p = table.lookup(this);
return p && *p == type; return p && *p == type;
} }
#endif /* DEBUG */ #endif /* DEBUG */
@ -5739,9 +5739,9 @@ JSObject::setNewTypeUnknown(JSContext *cx)
* not have the SETS_MARKED_UNKNOWN bit set, so may require a type set * not have the SETS_MARKED_UNKNOWN bit set, so may require a type set
* crawl if prototypes of the object change dynamically in the future. * crawl if prototypes of the object change dynamically in the future.
*/ */
JSCompartment::NewTypeObjectSet &table = compartment()->newTypeObjects; TypeObjectSet &table = compartment()->newTypeObjects;
if (table.initialized()) { if (table.initialized()) {
JSCompartment::NewTypeObjectSet::Ptr p = table.lookup(this); TypeObjectSet::Ptr p = table.lookup(this);
if (p) if (p)
MarkTypeObjectUnknownProperties(cx, *p); MarkTypeObjectUnknownProperties(cx, *p);
} }
@ -5755,12 +5755,12 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun)
if (!setDelegate(cx)) if (!setDelegate(cx))
return NULL; return NULL;
JSCompartment::NewTypeObjectSet &table = cx->compartment->newTypeObjects; TypeObjectSet &table = cx->compartment->newTypeObjects;
if (!table.initialized() && !table.init()) if (!table.initialized() && !table.init())
return NULL; return NULL;
JSCompartment::NewTypeObjectSet::AddPtr p = table.lookupForAdd(this); TypeObjectSet::AddPtr p = table.lookupForAdd(this);
if (p) { if (p) {
TypeObject *type = *p; TypeObject *type = *p;
@ -5833,12 +5833,12 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun)
TypeObject * TypeObject *
JSCompartment::getLazyType(JSContext *cx, JSObject *proto) JSCompartment::getLazyType(JSContext *cx, JSObject *proto)
{ {
JSCompartment::NewTypeObjectSet &table = cx->compartment->lazyTypeObjects; TypeObjectSet &table = cx->compartment->lazyTypeObjects;
if (!table.initialized() && !table.init()) if (!table.initialized() && !table.init())
return NULL; return NULL;
JSCompartment::NewTypeObjectSet::AddPtr p = table.lookupForAdd(proto); TypeObjectSet::AddPtr p = table.lookupForAdd(proto);
if (p) { if (p) {
TypeObject *type = *p; TypeObject *type = *p;
JS_ASSERT(type->lazy()); JS_ASSERT(type->lazy());
@ -5931,7 +5931,6 @@ TypeObject::sweep(JSContext *cx)
contribution = 0; contribution = 0;
if (singleton) { if (singleton) {
JS_ASSERT(!emptyShapes);
JS_ASSERT(!newScript); JS_ASSERT(!newScript);
/* /*
@ -5944,8 +5943,6 @@ TypeObject::sweep(JSContext *cx)
} }
if (!isMarked()) { if (!isMarked()) {
if (emptyShapes)
Foreground::free_(emptyShapes);
if (newScript) if (newScript)
Foreground::free_(newScript); Foreground::free_(newScript);
return; return;
@ -6113,10 +6110,10 @@ TypeCompartment::sweep(JSContext *cx)
} }
void void
JSCompartment::sweepNewTypeObjectTable(JSContext *cx, NewTypeObjectSet &table) JSCompartment::sweepNewTypeObjectTable(JSContext *cx, TypeObjectSet &table)
{ {
if (table.initialized()) { if (table.initialized()) {
for (NewTypeObjectSet::Enum e(table); !e.empty(); e.popFront()) { for (TypeObjectSet::Enum e(table); !e.empty(); e.popFront()) {
TypeObject *type = e.front(); TypeObject *type = e.front();
if (!type->isMarked()) if (!type->isMarked())
e.removeFront(); e.removeFront();
@ -6328,7 +6325,7 @@ JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats, J
* every GC. The type object is normally destroyed too, but we don't * every GC. The type object is normally destroyed too, but we don't
* charge this to 'temporary' as this is not for GC heap values. * charge this to 'temporary' as this is not for GC heap values.
*/ */
JS_ASSERT(!object->newScript && !object->emptyShapes); JS_ASSERT(!object->newScript);
return; return;
} }
@ -6347,11 +6344,6 @@ JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats, J
} }
} }
if (object->emptyShapes) {
size_t usable = usf(object->emptyShapes);
stats->emptyShapes += usable ? usable : sizeof(ShapeKindArray);
}
/* /*
* This counts memory that is in the temp pool but gets attributed * This counts memory that is in the temp pool but gets attributed
* elsewhere. See JS_GetTypeInferenceMemoryStats for more details. * elsewhere. See JS_GetTypeInferenceMemoryStats for more details.

Просмотреть файл

@ -730,19 +730,9 @@ struct TypeObject : gc::Cell
static const size_t LAZY_SINGLETON = 1; static const size_t LAZY_SINGLETON = 1;
bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; } bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; }
/* Lazily filled array of empty shapes for each size of objects with this type. */
js::ShapeKindArray *emptyShapes;
/* Flags for this object. */ /* Flags for this object. */
TypeObjectFlags flags; TypeObjectFlags flags;
/*
* If non-NULL, objects of this type have always been constructed using
* 'new' on the specified script, which adds some number of properties to
* the object in a definite order before the object escapes.
*/
TypeNewScript *newScript;
/* /*
* Estimate of the contribution of this object to the type sets it appears in. * Estimate of the contribution of this object to the type sets it appears in.
* This is the sum of the sizes of those sets at the point when the object * This is the sum of the sizes of those sets at the point when the object
@ -757,6 +747,13 @@ struct TypeObject : gc::Cell
uint32 contribution; uint32 contribution;
static const uint32 CONTRIBUTION_LIMIT = 2000; static const uint32 CONTRIBUTION_LIMIT = 2000;
/*
* If non-NULL, objects of this type have always been constructed using
* 'new' on the specified script, which adds some number of properties to
* the object in a definite order before the object escapes.
*/
TypeNewScript *newScript;
/* /*
* Properties of this object. This may contain JSID_VOID, representing the * Properties of this object. This may contain JSID_VOID, representing the
* types of all integer indexes of the object, and/or JSID_EMPTY, holding * types of all integer indexes of the object, and/or JSID_EMPTY, holding
@ -792,6 +789,10 @@ struct TypeObject : gc::Cell
/* If this is an interpreted function, the function object. */ /* If this is an interpreted function, the function object. */
JSFunction *interpretedFunction; JSFunction *interpretedFunction;
#if JS_BITS_PER_WORD == 32
void *padding;
#endif
inline TypeObject(JSObject *proto, bool isFunction, bool unknown); inline TypeObject(JSObject *proto, bool isFunction, bool unknown);
bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); } bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
@ -811,14 +812,6 @@ struct TypeObject : gc::Cell
return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES); return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
} }
/*
* Return an immutable, shareable, empty shape for objects with this type
* and the specified class, and finalize kind (fixed slot count). Objects
* created with this shape have the same class and parent as the type's
* prototype.
*/
inline js::EmptyShape *getEmptyShape(JSContext *cx, 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
* a script accesses explicitly. 'assign' indicates whether this is for an * a script accesses explicitly. 'assign' indicates whether this is for an
@ -882,6 +875,19 @@ struct TypeObject : gc::Cell
} }
}; };
/*
* Entries for the per-compartment set of type objects which are the default
* 'new' or the lazy types of some prototype.
*/
struct TypeObjectEntry
{
typedef JSObject *Lookup;
static inline HashNumber hash(JSObject *base);
static inline bool match(TypeObject *key, JSObject *lookup);
};
typedef HashSet<TypeObject *, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
/* /*
* Call to mark a script's arguments as having been created, recompile any * Call to mark a script's arguments as having been created, recompile any
* dependencies and walk the stack if necessary to fix any lazy arguments. * dependencies and walk the stack if necessary to fix any lazy arguments.

Просмотреть файл

@ -413,8 +413,8 @@ NewIteratorObject(JSContext *cx, uintN flags)
if (!type) if (!type)
return NULL; return NULL;
Shape *emptyEnumeratorShape = BaseShape::lookupInitialShape(cx, &IteratorClass, NULL, Shape *emptyEnumeratorShape = EmptyShape::lookupInitialShape(cx, &IteratorClass, NULL, NULL,
FINALIZE_OBJECT2); FINALIZE_OBJECT2);
if (!emptyEnumeratorShape) if (!emptyEnumeratorShape)
return NULL; return NULL;

Просмотреть файл

@ -2917,7 +2917,7 @@ NewObject(JSContext *cx, Class *clasp, types::TypeObject *type, JSObject *parent
JS_ASSERT_IF(clasp == &FunctionClass, JS_ASSERT_IF(clasp == &FunctionClass,
kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind); kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
Shape *shape = GetInitialShapeForObject(cx, clasp, parent, type, kind); Shape *shape = EmptyShape::lookupInitialShape(cx, clasp, type->proto, parent, kind);
if (!shape) if (!shape)
return NULL; return NULL;
@ -3593,9 +3593,9 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp()); StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
Shape *emptyWithShape = BaseShape::lookupInitialShape(cx, &WithClass, Shape *emptyWithShape = EmptyShape::lookupInitialShape(cx, &WithClass, proto,
parent->getGlobal(), parent->getGlobal(),
FINALIZE_OBJECT4); FINALIZE_OBJECT4);
if (!emptyWithShape) if (!emptyWithShape)
return NULL; return NULL;
@ -3627,8 +3627,8 @@ js_NewBlockObject(JSContext *cx)
if (!type) if (!type)
return NULL; return NULL;
Shape *emptyBlockShape = BaseShape::lookupInitialShape(cx, &BlockClass, NULL, Shape *emptyBlockShape = EmptyShape::lookupInitialShape(cx, &BlockClass, NULL, NULL,
FINALIZE_OBJECT4); FINALIZE_OBJECT4);
if (!emptyBlockShape) if (!emptyBlockShape)
return NULL; return NULL;
@ -3957,8 +3957,9 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
if (!a->generateOwnShape(cx)) if (!a->generateOwnShape(cx))
return false; return false;
} else { } else {
reserved.newbshape = BaseShape::lookupInitialShape(cx, a->getClass(), a->getParent(), reserved.newbshape = EmptyShape::lookupInitialShape(cx, a->getClass(),
b->getAllocKind()); a->getProto(), a->getParent(),
b->getAllocKind());
if (!reserved.newbshape) if (!reserved.newbshape)
return false; return false;
} }
@ -3966,8 +3967,9 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
if (!b->generateOwnShape(cx)) if (!b->generateOwnShape(cx))
return false; return false;
} else { } else {
reserved.newashape = BaseShape::lookupInitialShape(cx, b->getClass(), b->getParent(), reserved.newashape = EmptyShape::lookupInitialShape(cx, b->getClass(),
a->getAllocKind()); b->getProto(), b->getParent(),
a->getAllocKind());
if (!reserved.newashape) if (!reserved.newashape)
return false; return false;
} }
@ -5310,7 +5312,7 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
return true; return true;
} }
const Shape * Shape *
js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
PropertyOp getter, StrictPropertyOp setter, uint32 slot, PropertyOp getter, StrictPropertyOp setter, uint32 slot,
uintN attrs, uintN flags, intN shortid) uintN attrs, uintN flags, intN shortid)
@ -5331,9 +5333,9 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid); return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
} }
const Shape * Shape *
js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
const Shape *shape, uintN attrs, uintN mask, Shape *shape, uintN attrs, uintN mask,
PropertyOp getter, StrictPropertyOp setter) PropertyOp getter, StrictPropertyOp setter)
{ {
/* /*
@ -5409,7 +5411,7 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
* update the attributes and property ops. A getter or setter is really * update the attributes and property ops. A getter or setter is really
* only half of a property. * only half of a property.
*/ */
const Shape *shape = NULL; Shape *shape = NULL;
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
JSObject *pobj; JSObject *pobj;
JSProperty *prop; JSProperty *prop;
@ -5426,7 +5428,7 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
return NULL; return NULL;
if (prop && pobj == obj) { if (prop && pobj == obj) {
shape = (const Shape *) prop; shape = (Shape *) prop;
if (shape->isAccessorDescriptor()) { if (shape->isAccessorDescriptor()) {
shape = obj->changeProperty(cx, shape, attrs, shape = obj->changeProperty(cx, shape, attrs,
JSPROP_GETTER | JSPROP_SETTER, JSPROP_GETTER | JSPROP_SETTER,

Просмотреть файл

@ -596,7 +596,7 @@ struct JSObject : js::gc::Cell
public: public:
inline bool nativeEmpty() const; inline bool nativeEmpty() const;
const js::Shape *methodShapeChange(JSContext *cx, const js::Shape &shape); js::Shape *methodShapeChange(JSContext *cx, const js::Shape &shape);
bool protoShapeChange(JSContext *cx); bool protoShapeChange(JSContext *cx);
bool shadowingShapeChange(JSContext *cx, const js::Shape &shape); bool shadowingShapeChange(JSContext *cx, const js::Shape &shape);
@ -605,7 +605,7 @@ struct JSObject : js::gc::Cell
* Defined in jsobjinlines.h, but not declared inline per standard style in * Defined in jsobjinlines.h, but not declared inline per standard style in
* order to avoid gcc warnings. * order to avoid gcc warnings.
*/ */
const js::Shape *methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp); js::Shape *methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp);
/* Whether method shapes can be added to this object. */ /* Whether method shapes can be added to this object. */
inline bool canHaveMethodBarrier() const; inline bool canHaveMethodBarrier() const;
@ -1212,11 +1212,11 @@ struct JSObject : js::gc::Cell
* 1. getter and setter must be normalized based on flags (see jsscope.cpp). * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
* 2. !isExtensible() checking must be done by callers. * 2. !isExtensible() checking must be done by callers.
*/ */
const js::Shape *addPropertyInternal(JSContext *cx, jsid id, js::Shape *addPropertyInternal(JSContext *cx, jsid id,
JSPropertyOp getter, JSStrictPropertyOp setter, JSPropertyOp getter, JSStrictPropertyOp setter,
uint32 slot, uintN attrs, uint32 slot, uintN attrs,
uintN flags, intN shortid, uintN flags, intN shortid,
js::Shape **spp, bool allowDictionary); js::Shape **spp, bool allowDictionary);
bool toDictionaryMode(JSContext *cx); bool toDictionaryMode(JSContext *cx);
@ -1229,26 +1229,26 @@ struct JSObject : js::gc::Cell
public: public:
/* Add a property whose id is not yet in this scope. */ /* Add a property whose id is not yet in this scope. */
const js::Shape *addProperty(JSContext *cx, jsid id, js::Shape *addProperty(JSContext *cx, jsid id,
JSPropertyOp getter, JSStrictPropertyOp setter, JSPropertyOp getter, JSStrictPropertyOp setter,
uint32 slot, uintN attrs, uint32 slot, uintN attrs,
uintN flags, intN shortid, bool allowDictionary = true); uintN flags, intN shortid, bool allowDictionary = true);
/* Add a data property whose id is not yet in this scope. */ /* Add a data property whose id is not yet in this scope. */
const js::Shape *addDataProperty(JSContext *cx, jsid id, uint32 slot, uintN attrs) { js::Shape *addDataProperty(JSContext *cx, jsid id, uint32 slot, uintN attrs) {
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
return addProperty(cx, id, NULL, NULL, slot, attrs, 0, 0); return addProperty(cx, id, NULL, NULL, slot, attrs, 0, 0);
} }
/* Add or overwrite a property for id in this scope. */ /* Add or overwrite a property for id in this scope. */
const js::Shape *putProperty(JSContext *cx, jsid id, js::Shape *putProperty(JSContext *cx, jsid id,
JSPropertyOp getter, JSStrictPropertyOp setter, JSPropertyOp getter, JSStrictPropertyOp setter,
uint32 slot, uintN attrs, uint32 slot, uintN attrs,
uintN flags, intN shortid); uintN flags, intN shortid);
/* Change the given property into a sibling with the same id in this scope. */ /* Change the given property into a sibling with the same id in this scope. */
const js::Shape *changeProperty(JSContext *cx, const js::Shape *shape, uintN attrs, uintN mask, js::Shape *changeProperty(JSContext *cx, js::Shape *shape, uintN attrs, uintN mask,
JSPropertyOp getter, JSStrictPropertyOp setter); JSPropertyOp getter, JSStrictPropertyOp setter);
/* Remove the property named by id from this object. */ /* Remove the property named by id from this object. */
bool removeProperty(JSContext *cx, jsid id); bool removeProperty(JSContext *cx, jsid id);
@ -1691,7 +1691,7 @@ js_CheckForStringIndex(jsid id);
* Find or create a property named by id in obj's scope, with the given getter * Find or create a property named by id in obj's scope, with the given getter
* and setter, slot, attributes, and other members. * and setter, slot, attributes, and other members.
*/ */
extern const js::Shape * extern js::Shape *
js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
JSPropertyOp getter, JSStrictPropertyOp setter, uint32 slot, JSPropertyOp getter, JSStrictPropertyOp setter, uint32 slot,
uintN attrs, uintN flags, intN shortid); uintN attrs, uintN flags, intN shortid);
@ -1701,9 +1701,9 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
* it into a potentially new js::Shape. Return a pointer to the changed * it into a potentially new js::Shape. Return a pointer to the changed
* or identical property. * or identical property.
*/ */
extern const js::Shape * extern js::Shape *
js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
const js::Shape *shape, uintN attrs, uintN mask, js::Shape *shape, uintN attrs, uintN mask,
JSPropertyOp getter, JSStrictPropertyOp setter); JSPropertyOp getter, JSStrictPropertyOp setter);
extern JSBool extern JSBool

Просмотреть файл

@ -330,7 +330,7 @@ JSObject::setStaticBlockScopeChain(JSObject *obj)
* Property read barrier for deferred cloning of compiler-created function * Property read barrier for deferred cloning of compiler-created function
* objects optimized as typically non-escaping, ad-hoc methods in obj. * objects optimized as typically non-escaping, ad-hoc methods in obj.
*/ */
inline const js::Shape * inline js::Shape *
JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp) JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp)
{ {
JS_ASSERT(nativeContains(cx, shape)); JS_ASSERT(nativeContains(cx, shape));
@ -355,7 +355,7 @@ JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp
* watchpoint on the property is not triggered. * watchpoint on the property is not triggered.
*/ */
uint32 slot = shape.slot(); uint32 slot = shape.slot();
const js::Shape *newshape = methodShapeChange(cx, shape); js::Shape *newshape = methodShapeChange(cx, shape);
if (!newshape) if (!newshape)
return NULL; return NULL;
JS_ASSERT(!newshape->isMethod()); JS_ASSERT(!newshape->isMethod());
@ -1611,29 +1611,6 @@ JSObject *
NewReshapedObject(JSContext *cx, js::types::TypeObject *type, JSObject *parent, NewReshapedObject(JSContext *cx, js::types::TypeObject *type, JSObject *parent,
gc::AllocKind kind, const Shape *shape); gc::AllocKind kind, const Shape *shape);
inline Shape *
GetInitialShapeForObject(JSContext* cx, Class *clasp, JSObject *parent,
types::TypeObject *type, gc::AllocKind kind)
{
if (clasp->isNative()) {
/* Share empty shapes on the type only if the object is similar to the proto. */
if (type->proto &&
clasp == type->proto->getClass() &&
parent == type->proto->getParent()) {
return type->getEmptyShape(cx, kind);
}
return EmptyShape::create(cx, clasp, parent, gc::GetGCKindSlots(kind, clasp));
}
Shape *empty = BaseShape::lookupInitialShape(cx, clasp, parent, kind);
if (!empty)
return NULL;
JS_ASSERT(empty->isEmptyShape());
return empty;
}
/* /*
* As for gc::GetGCObjectKind, where numSlots is a guess at the final size of * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
* the object, zero if the final size is unknown. This should only be used for * the object, zero if the final size is unknown. This should only be used for

Просмотреть файл

@ -589,7 +589,7 @@ JSObject::checkShapeConsistency()
# define CHECK_SHAPE_CONSISTENCY(obj) ((void)0) # define CHECK_SHAPE_CONSISTENCY(obj) ((void)0)
#endif #endif
const Shape * Shape *
JSObject::addProperty(JSContext *cx, jsid id, JSObject::addProperty(JSContext *cx, jsid id,
PropertyOp getter, StrictPropertyOp setter, PropertyOp getter, StrictPropertyOp setter,
uint32 slot, uintN attrs, uint32 slot, uintN attrs,
@ -610,7 +610,7 @@ JSObject::addProperty(JSContext *cx, jsid id,
return addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp, allowDictionary); return addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp, allowDictionary);
} }
const Shape * Shape *
JSObject::addPropertyInternal(JSContext *cx, jsid id, JSObject::addPropertyInternal(JSContext *cx, jsid id,
PropertyOp getter, StrictPropertyOp setter, PropertyOp getter, StrictPropertyOp setter,
uint32 slot, uintN attrs, uint32 slot, uintN attrs,
@ -705,7 +705,7 @@ CheckCanChangeAttrs(JSContext *cx, JSObject *obj, const Shape *shape, uintN *att
return true; return true;
} }
const Shape * Shape *
JSObject::putProperty(JSContext *cx, jsid id, JSObject::putProperty(JSContext *cx, jsid id,
PropertyOp getter, StrictPropertyOp setter, PropertyOp getter, StrictPropertyOp setter,
uint32 slot, uintN attrs, uint32 slot, uintN attrs,
@ -866,8 +866,8 @@ JSObject::putProperty(JSContext *cx, jsid id,
return shape; return shape;
} }
const Shape * Shape *
JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN mask, JSObject::changeProperty(JSContext *cx, Shape *shape, uintN attrs, uintN mask,
PropertyOp getter, StrictPropertyOp setter) PropertyOp getter, StrictPropertyOp setter)
{ {
JS_ASSERT(nativeContains(cx, *shape)); JS_ASSERT(nativeContains(cx, *shape));
@ -902,8 +902,8 @@ JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN m
* removeProperty because it will free an allocated shape->slot, and * removeProperty because it will free an allocated shape->slot, and
* putProperty won't re-allocate it. * putProperty won't re-allocate it.
*/ */
const Shape *newShape = putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(), Shape *newShape = putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(),
attrs, shape->flags, shape->maybeShortid()); attrs, shape->flags, shape->maybeShortid());
CHECK_SHAPE_CONSISTENCY(this); CHECK_SHAPE_CONSISTENCY(this);
return newShape; return newShape;
@ -1087,7 +1087,7 @@ JSObject::generateOwnShape(JSContext *cx, Shape *newShape)
return true; return true;
} }
const Shape * Shape *
JSObject::methodShapeChange(JSContext *cx, const Shape &shape) JSObject::methodShapeChange(JSContext *cx, const Shape &shape)
{ {
JS_ASSERT(shape.isMethod()); JS_ASSERT(shape.isMethod());
@ -1111,7 +1111,7 @@ JSObject::methodShapeChange(JSContext *cx, const Shape &shape)
* method memoized in the property tree to a plain old function-valued * method memoized in the property tree to a plain old function-valued
* property. * property.
*/ */
const Shape *result = Shape *result =
putProperty(cx, shape.propid(), NULL, NULL, shape.slot(), putProperty(cx, shape.propid(), NULL, NULL, shape.slot(),
shape.attrs, shape.attrs,
shape.getFlags() & ~Shape::METHOD, shape.getFlags() & ~Shape::METHOD,
@ -1223,7 +1223,7 @@ Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, Shape **listp)
} }
/* static */ inline HashNumber /* static */ inline HashNumber
JSCompartment::BaseShapeEntry::hash(const js::BaseShape *base) BaseShapeEntry::hash(const js::BaseShape *base)
{ {
JS_ASSERT(!base->isOwned()); JS_ASSERT(!base->isOwned());
@ -1238,10 +1238,9 @@ JSCompartment::BaseShapeEntry::hash(const js::BaseShape *base)
} }
/* static */ inline bool /* static */ inline bool
JSCompartment::BaseShapeEntry::match(const BaseShapeEntry &entry, const BaseShape *lookup) BaseShapeEntry::match(UnownedBaseShape *key, const BaseShape *lookup)
{ {
BaseShape *key = entry.base; JS_ASSERT(!lookup->isOwned());
JS_ASSERT(!key->isOwned() && !lookup->isOwned());
return key->flags == lookup->flags return key->flags == lookup->flags
&& key->clasp == lookup->clasp && key->clasp == lookup->clasp
@ -1250,83 +1249,29 @@ JSCompartment::BaseShapeEntry::match(const BaseShapeEntry &entry, const BaseShap
&& key->setterObj == lookup->setterObj; && key->setterObj == lookup->setterObj;
} }
static inline JSCompartment::BaseShapeEntry *
LookupBaseShape(JSContext *cx, const BaseShape &base)
{
JSCompartment::BaseShapeSet &table = cx->compartment->baseShapes;
if (!table.initialized() && !table.init())
return false;
JSCompartment::BaseShapeSet::AddPtr p = table.lookupForAdd(&base);
if (p)
return &const_cast<JSCompartment::BaseShapeEntry &>(*p);
BaseShape *nbase = js_NewGCBaseShape(cx);
if (!nbase)
return false;
new (nbase) BaseShape(base);
JSCompartment::BaseShapeEntry entry;
entry.base = static_cast<UnownedBaseShape *>(nbase);
entry.shapes = NULL;
if (!table.relookupOrAdd(p, &base, entry))
return NULL;
return &const_cast<JSCompartment::BaseShapeEntry &>(*p);
}
/* static */ UnownedBaseShape * /* static */ UnownedBaseShape *
BaseShape::lookup(JSContext *cx, const BaseShape &base) BaseShape::lookup(JSContext *cx, const BaseShape &base)
{ {
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, base); BaseShapeSet &table = cx->compartment->baseShapes;
return entry ? entry->base : NULL;
}
/* static */ Shape * if (!table.initialized() && !table.init())
BaseShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
AllocKind kind, uint32 objectFlags, Shape *initial)
{
BaseShape base(clasp, parent, objectFlags);
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, base);
if (!entry)
return NULL; return NULL;
/* BaseShapeSet::AddPtr p = table.lookupForAdd(&base);
* Hold a reference on the entry's base shape, which will keep the entry if (p)
* from being swept during a GC under newShape below. return *p;
*/
BaseShape *nbase = entry->base;
if (!entry->shapes) { BaseShape *nbase_ = js_NewGCBaseShape(cx);
entry->shapes = cx->new_<ShapeKindArray>(); if (!nbase_)
if (!entry->shapes)
return NULL;
}
Shape *&shape = entry->shapes->get(kind);
if (shape)
return shape;
if (initial) {
shape = initial;
return initial;
}
shape = JS_PROPERTY_TREE(cx).newShape(cx);
if (!shape)
return NULL; return NULL;
return new (shape) EmptyShape(nbase, gc::GetGCKindSlots(kind, clasp)); new (nbase_) BaseShape(base);
}
/* static */ void UnownedBaseShape *nbase = static_cast<UnownedBaseShape *>(nbase_);
BaseShape::insertInitialShape(JSContext *cx, AllocKind kind, const Shape *initial)
{ if (!table.relookupOrAdd(p, &base, nbase))
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, *initial->base()); return NULL;
JS_ASSERT(entry && entry->base == initial->base() && entry->shapes);
entry->shapes->get(kind) = const_cast<Shape *>(initial); return nbase;
} }
void void
@ -1334,19 +1279,9 @@ JSCompartment::sweepBaseShapeTable(JSContext *cx)
{ {
if (baseShapes.initialized()) { if (baseShapes.initialized()) {
for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) { for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
JSCompartment::BaseShapeEntry &entry = UnownedBaseShape *base = e.front();
const_cast<JSCompartment::BaseShapeEntry &>(e.front()); if (!base->isMarked())
if (!entry.base->isMarked()) {
if (entry.shapes)
cx->delete_(entry.shapes);
e.removeFront(); e.removeFront();
} else if (entry.shapes) {
for (size_t i = 0; i < ShapeKindArray::SHAPE_COUNT; i++) {
Shape *&shape = entry.shapes->getIndex(i);
if (shape && !shape->isMarked())
shape = NULL;
}
}
} }
} }
} }
@ -1387,3 +1322,82 @@ Bindings::setParent(JSContext *cx, JSObject *obj)
return false; return false;
return Shape::setObjectParent(cx, obj, &lastBinding); return Shape::setObjectParent(cx, obj, &lastBinding);
} }
/* static */ inline HashNumber
InitialShapeEntry::hash(const Lookup &lookup)
{
JSDHashNumber hash = jsuword(lookup.clasp) >> 3;
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsuword(lookup.proto) >> 3);
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsuword(lookup.parent) >> 3);
return hash + lookup.nfixed;
}
/* static */ inline bool
InitialShapeEntry::match(const InitialShapeEntry &key, const Lookup &lookup)
{
return lookup.clasp == key.shape->getObjectClass()
&& lookup.proto == key.proto
&& lookup.parent == key.shape->getObjectParent()
&& lookup.nfixed == key.shape->numFixedSlots();
}
/* static */ Shape *
EmptyShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent,
AllocKind kind, uint32 objectFlags)
{
InitialShapeSet &table = cx->compartment->initialShapes;
if (!table.initialized() && !table.init())
return NULL;
size_t nfixed = GetGCKindSlots(kind, clasp);
InitialShapeEntry::Lookup lookup(clasp, proto, parent, nfixed);
InitialShapeSet::AddPtr p = table.lookupForAdd(lookup);
if (p)
return p->shape;
BaseShape base(clasp, parent, objectFlags);
BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase)
return NULL;
Shape *shape = JS_PROPERTY_TREE(cx).newShape(cx);
if (!shape)
return NULL;
new (shape) EmptyShape(nbase, nfixed);
InitialShapeEntry entry;
entry.shape = shape;
entry.proto = proto;
if (!table.relookupOrAdd(p, lookup, entry))
return NULL;
return shape;
}
/* static */ void
EmptyShape::insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto)
{
InitialShapeEntry::Lookup lookup(shape->getObjectClass(), proto, shape->getObjectParent(),
shape->numFixedSlots());
InitialShapeSet::Ptr p = cx->compartment->initialShapes.lookup(lookup);
JS_ASSERT(p);
InitialShapeEntry &entry = const_cast<InitialShapeEntry &>(*p);
entry.shape = shape;
}
void
JSCompartment::sweepInitialShapeTable(JSContext *cx)
{
if (initialShapes.initialized()) {
for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
const InitialShapeEntry &entry = e.front();
if (!entry.shape->isMarked() || (entry.proto && !entry.proto->isMarked()))
e.removeFront();
}
}
}

Просмотреть файл

@ -51,7 +51,6 @@
#include "jstypes.h" #include "jstypes.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jscompartment.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsprvtd.h" #include "jsprvtd.h"
#include "jspubtd.h" #include "jspubtd.h"
@ -346,7 +345,7 @@ class BaseShape : public js::gc::Cell
{ {
public: public:
friend struct Shape; friend struct Shape;
friend struct JSCompartment::BaseShapeEntry; friend struct BaseShapeEntry;
enum Flag { enum Flag {
/* Owned by the referring shape. */ /* Owned by the referring shape. */
@ -459,18 +458,6 @@ class BaseShape : public js::gc::Cell
/* Lookup base shapes from the compartment's baseShapes table. */ /* Lookup base shapes from the compartment's baseShapes table. */
static UnownedBaseShape *lookup(JSContext *cx, const BaseShape &base); static UnownedBaseShape *lookup(JSContext *cx, const BaseShape &base);
/*
* Lookup a base shape from the baseShapes table, returning any associated
* initial shape and, constructing one (or reusing the 'shape' parameter)
* if none was found.
*/
static Shape *lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
gc::AllocKind kind, uint32 objectFlags = 0,
Shape *initial = NULL);
/* Reinsert a possibly modified initial shape to the baseShapes table. */
static void insertInitialShape(JSContext *cx, gc::AllocKind kind, const Shape *initial);
/* Get the canonical base shape. */ /* Get the canonical base shape. */
inline UnownedBaseShape *unowned(); inline UnownedBaseShape *unowned();
@ -511,6 +498,16 @@ BaseShape::baseUnowned()
JS_ASSERT(isOwned() && unowned_); return unowned_; JS_ASSERT(isOwned() && unowned_); return unowned_;
} }
/* Entries for the per-compartment baseShapes set of unowned base shapes. */
struct BaseShapeEntry
{
typedef const BaseShape *Lookup;
static inline HashNumber hash(const BaseShape *base);
static inline bool match(UnownedBaseShape *key, const BaseShape *lookup);
};
typedef HashSet<UnownedBaseShape *, BaseShapeEntry, SystemAllocPolicy> BaseShapeSet;
struct Shape : public js::gc::Cell struct Shape : public js::gc::Cell
{ {
friend struct ::JSObject; friend struct ::JSObject;
@ -958,46 +955,51 @@ struct EmptyShape : public js::Shape
{ {
EmptyShape(BaseShape *base, uint32 nfixed); EmptyShape(BaseShape *base, uint32 nfixed);
static EmptyShape *create(JSContext *cx, js::Class *clasp, JSObject *parent, uint32 nfixed) { /*
BaseShape lookup(clasp, parent, 0); * Lookup an initial shape matching the given parameters, creating an empty
BaseShape *base = BaseShape::lookup(cx, lookup); * shape if none was found.
if (!base) */
return NULL; static Shape *lookupInitialShape(JSContext *cx, Class *clasp, JSObject *proto,
JSObject *parent, gc::AllocKind kind, uint32 objectFlags = 0);
js::Shape *eprop = JS_PROPERTY_TREE(cx).newShape(cx); /* Reinsert an alternate initial shape to the baseShapes table. */
if (!eprop) static void insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto);
return NULL;
return new (eprop) EmptyShape(base, nfixed);
}
}; };
/* Heap-allocated array of shapes for each object allocation size. */ /*
class ShapeKindArray * Entries for the per-compartment initialShapes set indexing initial shapes
* for objects in the compartment and the associated types.
*/
struct InitialShapeEntry
{ {
public: /*
static const uint32 SHAPE_COUNT = * Initial shape to give to the object. This is an empty shape, except for
((js::gc::FINALIZE_OBJECT_LAST - js::gc::FINALIZE_OBJECT0) / 2) + 1; * certain classes (e.g. String, RegExp) which may add certain baked-in
* properties.
*/
js::Shape *shape;
ShapeKindArray() { PodZero(this); } /*
* Matching prototype for the entry. The shape of an object determines its
* prototype, but the prototype cannot be determined from the shape itself.
*/
JSObject *proto;
Shape *&get(gc::AllocKind kind) { /* State used to determine a match on an initial shape. */
JS_ASSERT(kind >= gc::FINALIZE_OBJECT0 && kind <= gc::FINALIZE_OBJECT_LAST); struct Lookup {
int i = (kind - gc::FINALIZE_OBJECT0) / 2; Class *clasp;
return shapes[i]; JSObject *proto;
} JSObject *parent;
size_t nfixed;
Lookup(Class *clasp, JSObject *proto, JSObject *parent, size_t nfixed)
: clasp(clasp), proto(proto), parent(parent), nfixed(nfixed)
{}
};
Shape *&getIndex(size_t i) { static inline HashNumber hash(const Lookup &lookup);
JS_ASSERT(i < SHAPE_COUNT); static inline bool match(const InitialShapeEntry &key, const Lookup &lookup);
return shapes[i];
}
private:
Shape *shapes[SHAPE_COUNT];
void staticAsserts() {
JS_STATIC_ASSERT(gc::FINALIZE_OBJECT0 % 2 == 0);
}
}; };
typedef HashSet<InitialShapeEntry, InitialShapeEntry, SystemAllocPolicy> InitialShapeSet;
} /* namespace js */ } /* namespace js */

Просмотреть файл

@ -57,33 +57,6 @@
#include "jsgcinlines.h" #include "jsgcinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
inline js::EmptyShape *
js::types::TypeObject::getEmptyShape(JSContext *cx, gc::AllocKind kind)
{
JS_ASSERT(!singleton);
/*
* 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
* their types differ.
*/
JS_ASSERT(proto->hasNewType(this));
if (!emptyShapes) {
emptyShapes = cx->new_<ShapeKindArray>();
if (!emptyShapes)
return NULL;
}
Shape *&empty = emptyShapes->get(kind);
if (!empty) {
empty = EmptyShape::create(cx, proto->getClass(), proto->getParent(),
gc::GetGCKindSlots(kind, proto->getClass()));
}
return static_cast<EmptyShape *>(empty);
}
inline bool inline bool
JSObject::updateFlags(JSContext *cx, jsid id, bool isDefinitelyAtom) JSObject::updateFlags(JSContext *cx, jsid id, bool isDefinitelyAtom)
{ {
@ -107,38 +80,6 @@ JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom)
namespace js { namespace js {
inline bool
StringObject::init(JSContext *cx, JSString *str)
{
JS_ASSERT(nativeEmpty());
JS_ASSERT(gc::GetGCKindSlots(getAllocKind()) == 2);
if (isDelegate()) {
if (!assignInitialShape(cx))
return false;
} else {
const js::Shape *shape =
BaseShape::lookupInitialShape(cx, getClass(), getParent(),
gc::FINALIZE_OBJECT2, 0,
lastProperty());
if (!shape)
return false;
if (shape != lastProperty()) {
setLastPropertyInfallible(shape);
} else {
shape = assignInitialShape(cx);
if (!shape)
return false;
BaseShape::insertInitialShape(cx, gc::FINALIZE_OBJECT2, shape);
}
}
JS_ASSERT(!nativeEmpty());
JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT);
setStringThis(str);
return true;
}
inline void inline void
BaseShape::adoptUnowned(UnownedBaseShape *other) BaseShape::adoptUnowned(UnownedBaseShape *other)
{ {

Просмотреть файл

@ -93,8 +93,8 @@ Bindings::ensureShape(JSContext *cx)
gc::AllocKind kind = gc::FINALIZE_OBJECT4; gc::AllocKind kind = gc::FINALIZE_OBJECT4;
JS_ASSERT(gc::GetGCKindSlots(kind) == CallObject::RESERVED_SLOTS + 1); JS_ASSERT(gc::GetGCKindSlots(kind) == CallObject::RESERVED_SLOTS + 1);
lastBinding = BaseShape::lookupInitialShape(cx, &CallClass, NULL, kind, lastBinding = EmptyShape::lookupInitialShape(cx, &CallClass, NULL, NULL, kind,
BaseShape::VAROBJ); BaseShape::VAROBJ);
if (!lastBinding) if (!lastBinding)
return false; return false;
} }

Просмотреть файл

@ -3001,7 +3001,7 @@ static JSFunctionSpec string_static_methods[] = {
JS_FS_END JS_FS_END
}; };
const Shape * Shape *
StringObject::assignInitialShape(JSContext *cx) StringObject::assignInitialShape(JSContext *cx)
{ {
JS_ASSERT(nativeEmpty()); JS_ASSERT(nativeEmpty());

Просмотреть файл

@ -222,8 +222,9 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes)
JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass); JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
js::Shape *empty = BaseShape::lookupInitialShape(cx, &ArrayBufferClass, obj->getParent(), js::Shape *empty = EmptyShape::lookupInitialShape(cx, &ArrayBufferClass,
gc::FINALIZE_OBJECT16); obj->getProto(), obj->getParent(),
gc::FINALIZE_OBJECT16);
if (!empty) if (!empty)
return false; return false;
obj->setLastPropertyInfallible(empty); obj->setLastPropertyInfallible(empty);
@ -1381,9 +1382,10 @@ class TypedArrayTemplate
JS_ASSERT(obj->getClass() == slowClass()); JS_ASSERT(obj->getClass() == slowClass());
js::Shape *empty = BaseShape::lookupInitialShape(cx, fastClass(), obj->getParent(), js::Shape *empty = EmptyShape::lookupInitialShape(cx, fastClass(),
gc::FINALIZE_OBJECT8, obj->getProto(), obj->getParent(),
BaseShape::NOT_EXTENSIBLE); gc::FINALIZE_OBJECT8,
BaseShape::NOT_EXTENSIBLE);
if (!empty) if (!empty)
return false; return false;
obj->setLastPropertyInfallible(empty); obj->setLastPropertyInfallible(empty);

Просмотреть файл

@ -151,19 +151,10 @@ RegExpObject::init(JSContext *cx, JSLinearString *source, RegExpFlag flags)
if (!assignInitialShape(cx)) if (!assignInitialShape(cx))
return false; return false;
} else { } else {
const js::Shape *shape = Shape *shape = assignInitialShape(cx);
js::BaseShape::lookupInitialShape(cx, getClass(), getParent(),
js::gc::FINALIZE_OBJECT8, 0,
lastProperty());
if (!shape) if (!shape)
return false; return false;
if (shape == lastProperty()) { EmptyShape::insertInitialShape(cx, shape, getProto());
shape = assignInitialShape(cx);
if (!shape)
return false;
js::BaseShape::insertInitialShape(cx, js::gc::FINALIZE_OBJECT8, shape);
}
setLastPropertyInfallible(shape);
} }
JS_ASSERT(!nativeEmpty()); JS_ASSERT(!nativeEmpty());
} }

Просмотреть файл

@ -252,7 +252,7 @@ RegExpObject::execute(JSContext *cx, const jschar *chars, size_t length, size_t
return getPrivate()->execute(cx, chars, length, lastIndex, allocScope, output); return getPrivate()->execute(cx, chars, length, lastIndex, allocScope, output);
} }
const Shape * Shape *
RegExpObject::assignInitialShape(JSContext *cx) RegExpObject::assignInitialShape(JSContext *cx)
{ {
JS_ASSERT(isRegExp()); JS_ASSERT(isRegExp());

Просмотреть файл

@ -187,7 +187,7 @@ class RegExpObject : public ::JSObject
* encoding their initial properties. Return the shape after * encoding their initial properties. Return the shape after
* changing this regular expression object's last property to it. * changing this regular expression object's last property to it.
*/ */
const Shape *assignInitialShape(JSContext *cx); Shape *assignInitialShape(JSContext *cx);
RegExpObject(); RegExpObject();
RegExpObject &operator=(const RegExpObject &reo); RegExpObject &operator=(const RegExpObject &reo);

Просмотреть файл

@ -52,6 +52,28 @@ JSObject::asString()
namespace js { namespace js {
inline bool
StringObject::init(JSContext *cx, JSString *str)
{
JS_ASSERT(nativeEmpty());
JS_ASSERT(gc::GetGCKindSlots(getAllocKind()) == 2);
if (isDelegate()) {
if (!assignInitialShape(cx))
return false;
} else {
Shape *shape = assignInitialShape(cx);
if (!shape)
return false;
EmptyShape::insertInitialShape(cx, shape, getProto());
}
JS_ASSERT(!nativeEmpty());
JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT);
setStringThis(str);
return true;
}
inline StringObject * inline StringObject *
StringObject::create(JSContext *cx, JSString *str) StringObject::create(JSContext *cx, JSString *str)
{ {

Просмотреть файл

@ -92,7 +92,7 @@ class StringObject : public ::JSObject
* encodes the initial length property. Return the shape after changing * encodes the initial length property. Return the shape after changing
* this String object's last property to it. * this String object's last property to it.
*/ */
const js::Shape *assignInitialShape(JSContext *cx); Shape *assignInitialShape(JSContext *cx);
private: private:
StringObject(); StringObject();