зеркало из https://github.com/mozilla/pjs.git
Get new object empty shapes with a common hash table, bug 701509.
This commit is contained in:
Родитель
135431de6e
Коммит
83d4c45568
|
@ -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();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче