mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
Move JSObject::newType to a hashtable, bug 684410.
This commit is contained in:
parent
d0e05ed02f
commit
226f6d2a95
@ -50,7 +50,7 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
|
||||
/* Ignore fields which are unstable across GCs. */
|
||||
CHECK(savedCopy->lastProp == obj->lastProp);
|
||||
CHECK(savedCopy->flags == obj->flags);
|
||||
CHECK(savedCopy->newType == obj->newType);
|
||||
CHECK(savedCopy->initializedLength == obj->initializedLength);
|
||||
CHECK(savedCopy->getProto() == obj->getProto());
|
||||
CHECK(savedCopy->parent == obj->parent);
|
||||
CHECK(savedCopy->privateData == obj->privateData);
|
||||
|
@ -1333,7 +1333,6 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
|
||||
/* The initialized length is used iff this is a dense array. */
|
||||
initializedLength = 0;
|
||||
JS_ASSERT(newType == NULL);
|
||||
|
||||
/*
|
||||
* Begin with the length property to share more of the property tree.
|
||||
@ -2681,7 +2680,7 @@ TryReuseArrayType(JSObject *obj, JSObject *nobj)
|
||||
* and has the same prototype.
|
||||
*/
|
||||
JS_ASSERT(nobj->isDenseArray());
|
||||
JS_ASSERT(nobj->type() == nobj->getProto()->newType);
|
||||
JS_ASSERT(nobj->getProto()->hasNewType(nobj->type()));
|
||||
|
||||
if (obj->isArray() && !obj->hasSingletonType() && obj->getProto() == nobj->getProto())
|
||||
nobj->setType(obj->type());
|
||||
|
@ -95,6 +95,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
emptyDeclEnvShape(NULL),
|
||||
emptyEnumeratorShape(NULL),
|
||||
emptyWithShape(NULL),
|
||||
emptyTypeObject(NULL),
|
||||
initialRegExpShape(NULL),
|
||||
initialStringShape(NULL),
|
||||
debugModeBits(rt->debugMode ? DebugFromC : 0),
|
||||
@ -493,10 +494,10 @@ JSCompartment::markTypes(JSTracer *trc)
|
||||
|
||||
template <class T>
|
||||
void
|
||||
CheckWeakShape(JSContext *cx, T *&shape)
|
||||
CheckWeakReference(JSContext *cx, T *&ptr)
|
||||
{
|
||||
if (shape && IsAboutToBeFinalized(cx, shape))
|
||||
shape = NULL;
|
||||
if (ptr && IsAboutToBeFinalized(cx, ptr))
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@ -513,20 +514,23 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove dead empty shapes. */
|
||||
CheckWeakShape(cx, emptyStrictArgumentsShape);
|
||||
CheckWeakShape(cx, emptyNormalArgumentsShape);
|
||||
CheckWeakShape(cx, emptyBlockShape);
|
||||
CheckWeakShape(cx, emptyCallShape);
|
||||
CheckWeakShape(cx, emptyDeclEnvShape);
|
||||
CheckWeakShape(cx, emptyEnumeratorShape);
|
||||
CheckWeakShape(cx, emptyWithShape);
|
||||
/* Remove dead references held weakly by the compartment. */
|
||||
|
||||
CheckWeakShape(cx, initialRegExpShape);
|
||||
CheckWeakShape(cx, initialStringShape);
|
||||
CheckWeakReference(cx, emptyStrictArgumentsShape);
|
||||
CheckWeakReference(cx, emptyNormalArgumentsShape);
|
||||
CheckWeakReference(cx, emptyBlockShape);
|
||||
CheckWeakReference(cx, emptyCallShape);
|
||||
CheckWeakReference(cx, emptyDeclEnvShape);
|
||||
CheckWeakReference(cx, emptyEnumeratorShape);
|
||||
CheckWeakReference(cx, emptyWithShape);
|
||||
|
||||
CheckWeakReference(cx, initialRegExpShape);
|
||||
CheckWeakReference(cx, initialStringShape);
|
||||
|
||||
/* Remove dead base shapes */
|
||||
sweepBaseShapeTable(cx);
|
||||
sweepNewTypeObjectTable(cx);
|
||||
|
||||
CheckWeakReference(cx, emptyTypeObject);
|
||||
|
||||
sweepBreakpoints(cx);
|
||||
|
||||
|
@ -506,6 +506,29 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
|
||||
void sweepBaseShapeTable(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Set of all type objects in the compartment which are the default 'new'
|
||||
* types of some (possibly NULL) prototype.
|
||||
*/
|
||||
|
||||
struct NewTypeObjectEntry {
|
||||
typedef JSObject *Lookup;
|
||||
|
||||
static inline js::HashNumber hash(JSObject *base);
|
||||
static inline bool match(js::types::TypeObject *key, JSObject *lookup);
|
||||
};
|
||||
|
||||
typedef js::HashSet<js::types::TypeObject *, NewTypeObjectEntry, js::SystemAllocPolicy> NewTypeObjectSet;
|
||||
|
||||
NewTypeObjectSet newTypeObjects;
|
||||
|
||||
void sweepNewTypeObjectTable(JSContext *cx);
|
||||
|
||||
js::types::TypeObject *emptyTypeObject;
|
||||
|
||||
/* Get the default 'new' type for objects with a NULL prototype. */
|
||||
inline js::types::TypeObject *getEmptyType(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Initial shapes given to RegExp and String objects, encoding the initial
|
||||
* sets of built-in instance properties and the fixed slots where they must
|
||||
|
@ -761,10 +761,14 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
|
||||
if (!envobj)
|
||||
return NULL;
|
||||
|
||||
types::TypeObject *type = cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
|
||||
if (!emptyDeclEnvShape)
|
||||
return NULL;
|
||||
envobj->init(cx, &emptyTypeObject, &fp->scopeChain(), fp, false);
|
||||
envobj->init(cx, type, &fp->scopeChain(), fp, false);
|
||||
envobj->setMap(emptyDeclEnvShape);
|
||||
|
||||
return envobj;
|
||||
@ -1568,7 +1572,8 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
|
||||
if (!fun)
|
||||
return false;
|
||||
fun->clearParent();
|
||||
fun->clearType();
|
||||
if (!fun->clearType(cx))
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoObjectRooter tvr(cx, fun);
|
||||
|
@ -227,8 +227,6 @@ MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name)
|
||||
JS_ASSERT(trc);
|
||||
JS_ASSERT(type);
|
||||
JS_SET_TRACING_NAME(trc, name);
|
||||
if (type == &types::emptyTypeObject)
|
||||
return;
|
||||
Mark(trc, type);
|
||||
|
||||
/*
|
||||
@ -713,8 +711,7 @@ ScanObject(GCMarker *gcmarker, JSObject *obj)
|
||||
return;
|
||||
|
||||
types::TypeObject *type = obj->typeFromGC();
|
||||
if (type != &types::emptyTypeObject)
|
||||
PushMarkStack(gcmarker, type);
|
||||
PushMarkStack(gcmarker, type);
|
||||
|
||||
if (JSObject *parent = obj->getParent())
|
||||
PushMarkStack(gcmarker, parent);
|
||||
@ -733,13 +730,8 @@ ScanObject(GCMarker *gcmarker, JSObject *obj)
|
||||
clasp->trace(gcmarker, obj);
|
||||
}
|
||||
} else {
|
||||
if (obj->newType)
|
||||
PushMarkStack(gcmarker, obj->newType);
|
||||
clasp->trace(gcmarker, obj);
|
||||
}
|
||||
} else {
|
||||
if (obj->newType)
|
||||
PushMarkStack(gcmarker, obj->newType);
|
||||
}
|
||||
|
||||
js::Shape *shape = obj->lastProp;
|
||||
@ -795,8 +787,6 @@ MarkChildren(JSTracer *trc, JSObject *obj)
|
||||
MarkTypeObject(trc, obj->typeFromGC(), "type");
|
||||
|
||||
/* Trace universal (ops-independent) members. */
|
||||
if (!obj->isDenseArray() && obj->newType)
|
||||
MarkTypeObject(trc, obj->newType, "new_type");
|
||||
if (JSObject *parent = obj->getParent())
|
||||
MarkObject(trc, *parent, "parent");
|
||||
|
||||
|
@ -1886,8 +1886,6 @@ TypeSet::hasGlobalObject(JSContext *cx, JSObject *global)
|
||||
// TypeCompartment
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
TypeObject types::emptyTypeObject(NULL, false, true);
|
||||
|
||||
void
|
||||
TypeCompartment::init(JSContext *cx)
|
||||
{
|
||||
@ -2402,7 +2400,6 @@ GetValueTypeForTable(JSContext *cx, const Value &v)
|
||||
{
|
||||
Type type = GetValueType(cx, v);
|
||||
JS_ASSERT(!type.isSingleObject());
|
||||
JS_ASSERT_IF(type.isTypeObject(), type.typeObject() != &emptyTypeObject);
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -5575,7 +5572,7 @@ JSObject::splicePrototype(JSContext *cx, JSObject *proto)
|
||||
}
|
||||
|
||||
if (!cx->typeInferenceEnabled()) {
|
||||
TypeObject *type = proto ? proto->getNewType(cx) : &emptyTypeObject;
|
||||
TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return false;
|
||||
type_ = type;
|
||||
@ -5662,21 +5659,75 @@ JSObject::makeLazyType(JSContext *cx)
|
||||
flags &= ~LAZY_TYPE;
|
||||
}
|
||||
|
||||
void
|
||||
JSObject::makeNewType(JSContext *cx, JSFunction *fun, bool unknown)
|
||||
/* static */ inline HashNumber
|
||||
JSCompartment::NewTypeObjectEntry::hash(JSObject *proto)
|
||||
{
|
||||
JS_ASSERT(!newType);
|
||||
return PointerHasher<JSObject *, 3>::hash(proto);
|
||||
}
|
||||
|
||||
/* static */ inline bool
|
||||
JSCompartment::NewTypeObjectEntry::match(TypeObject *key, JSObject *lookup)
|
||||
{
|
||||
return key->proto == lookup;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
JSObject::hasNewType(TypeObject *type)
|
||||
{
|
||||
JSCompartment::NewTypeObjectSet &table = compartment()->newTypeObjects;
|
||||
|
||||
if (!table.initialized())
|
||||
return false;
|
||||
|
||||
JSCompartment::NewTypeObjectSet::AddPtr p = table.lookupForAdd(this);
|
||||
return p && *p == type;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
TypeObject *
|
||||
JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown)
|
||||
{
|
||||
JSCompartment::NewTypeObjectSet &table = cx->compartment->newTypeObjects;
|
||||
|
||||
if (!table.initialized() && !table.init())
|
||||
return NULL;
|
||||
|
||||
JSCompartment::NewTypeObjectSet::AddPtr p = table.lookupForAdd(this);
|
||||
if (p) {
|
||||
TypeObject *type = *p;
|
||||
|
||||
/*
|
||||
* If set, the type's newScript indicates the script used to create
|
||||
* all objects in existence which have this type. If there are objects
|
||||
* in existence which are not created by calling 'new' on newScript,
|
||||
* we must clear the new script information from the type and will not
|
||||
* be able to assume any definite properties for instances of the type.
|
||||
* This case is rare, but can happen if, for example, two scripted
|
||||
* functions have the same value for their 'prototype' property, or if
|
||||
* Object.create is called with a prototype object that is also the
|
||||
* 'prototype' property of some scripted function.
|
||||
*/
|
||||
if (type->newScript && type->newScript->fun != fun)
|
||||
type->clearNewScript(cx);
|
||||
if (markUnknown && cx->typeInferenceEnabled() && !type->unknownProperties())
|
||||
type->markUnknown(cx);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
|
||||
JSProto_Object, this, unknown);
|
||||
JSProto_Object, this, markUnknown);
|
||||
if (!type)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
if (!table.relookupOrAdd(p, this, type))
|
||||
return NULL;
|
||||
|
||||
newType = type;
|
||||
setDelegate();
|
||||
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return;
|
||||
return type;
|
||||
|
||||
AutoEnterTypeInference enter(cx);
|
||||
|
||||
@ -5710,6 +5761,8 @@ JSObject::makeNewType(JSContext *cx, JSFunction *fun, bool unknown)
|
||||
*/
|
||||
if (type->unknownProperties())
|
||||
type->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -5761,15 +5814,6 @@ TypeSet::sweep(JSContext *cx, JSCompartment *compartment)
|
||||
flags &= ~TYPE_FLAG_PROPAGATED_PROPERTY;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::revertLazyType()
|
||||
{
|
||||
JS_ASSERT(hasSingletonType() && !hasLazyType());
|
||||
JS_ASSERT_IF(type_->proto, type_->proto->newType);
|
||||
flags |= LAZY_TYPE;
|
||||
type_ = (type_->proto) ? type_->proto->newType : &emptyTypeObject;
|
||||
}
|
||||
|
||||
inline void
|
||||
TypeObject::clearProperties()
|
||||
{
|
||||
@ -5803,19 +5847,6 @@ TypeObject::sweep(JSContext *cx)
|
||||
*/
|
||||
clearProperties();
|
||||
|
||||
if (!isMarked()) {
|
||||
/*
|
||||
* Singleton objects do not hold strong references on their types.
|
||||
* When removing the type, however, we need to fixup the singleton
|
||||
* so that it has a lazy type again. The generic 'new' type for the
|
||||
* proto must be live, since the type's prototype and its 'new'
|
||||
* type are both strong references.
|
||||
*/
|
||||
JS_ASSERT_IF(singleton->isMarked() && proto,
|
||||
proto->isMarked() && proto->newType->isMarked());
|
||||
singleton->revertLazyType();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5905,9 +5936,6 @@ struct SweepTypeObjectOp
|
||||
void
|
||||
SweepTypeObjects(JSContext *cx, JSCompartment *compartment)
|
||||
{
|
||||
JS_ASSERT(!emptyTypeObject.emptyShapes);
|
||||
JS_ASSERT(!emptyTypeObject.newScript);
|
||||
|
||||
SweepTypeObjectOp op(cx);
|
||||
gc::ForEachArenaAndCell(compartment, gc::FINALIZE_TYPE_OBJECT, gc::EmptyArenaOp, op);
|
||||
}
|
||||
@ -5991,6 +6019,18 @@ TypeCompartment::sweep(JSContext *cx)
|
||||
pendingCapacity = 0;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::sweepNewTypeObjectTable(JSContext *cx)
|
||||
{
|
||||
if (newTypeObjects.initialized()) {
|
||||
for (NewTypeObjectSet::Enum e(newTypeObjects); !e.empty(); e.popFront()) {
|
||||
TypeObject *type = e.front();
|
||||
if (!type->isMarked())
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypeCompartment::~TypeCompartment()
|
||||
{
|
||||
if (pendingArray)
|
||||
|
@ -872,9 +872,6 @@ struct TypeObject : gc::Cell
|
||||
}
|
||||
};
|
||||
|
||||
/* Global singleton for the generic type of objects with no prototype. */
|
||||
extern TypeObject emptyTypeObject;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -1312,4 +1312,12 @@ js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32 offset, uint32
|
||||
pushed->addType(cx, type);
|
||||
}
|
||||
|
||||
inline js::types::TypeObject *
|
||||
JSCompartment::getEmptyType(JSContext *cx)
|
||||
{
|
||||
if (!emptyTypeObject)
|
||||
emptyTypeObject = types.newTypeObject(cx, NULL, JSProto_Object, NULL, true);
|
||||
return emptyTypeObject;
|
||||
}
|
||||
|
||||
#endif // jsinferinlines_h___
|
||||
|
@ -409,10 +409,15 @@ NewIteratorObject(JSContext *cx, uintN flags)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
types::TypeObject *type = cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx);
|
||||
if (!emptyEnumeratorShape)
|
||||
return NULL;
|
||||
obj->init(cx, &types::emptyTypeObject, NULL, NULL, false);
|
||||
|
||||
obj->init(cx, type, NULL, NULL, false);
|
||||
obj->setMap(emptyEnumeratorShape);
|
||||
return obj;
|
||||
}
|
||||
|
@ -3510,10 +3510,15 @@ js_NewBlockObject(JSContext *cx)
|
||||
if (!blockObj)
|
||||
return NULL;
|
||||
|
||||
types::TypeObject *type = cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx);
|
||||
if (!emptyBlockShape)
|
||||
return NULL;
|
||||
blockObj->init(cx, &emptyTypeObject, NULL, NULL, false);
|
||||
|
||||
blockObj->init(cx, type, NULL, NULL, false);
|
||||
blockObj->setMap(emptyBlockShape);
|
||||
|
||||
return blockObj;
|
||||
@ -3881,10 +3886,6 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
||||
JS_ASSERT(!a->isDenseArray() && !b->isDenseArray());
|
||||
JS_ASSERT(!a->isArrayBuffer() && !b->isArrayBuffer());
|
||||
|
||||
/* New types for a JSObject need to be stable when trading guts. */
|
||||
TypeObject *newTypeA = a->newType;
|
||||
TypeObject *newTypeB = b->newType;
|
||||
|
||||
/* Trade the guts of the objects. */
|
||||
const size_t size = a->structSize();
|
||||
if (size == b->structSize()) {
|
||||
@ -3945,9 +3946,6 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
||||
reserved.newaslots = NULL;
|
||||
reserved.newbslots = NULL;
|
||||
}
|
||||
|
||||
a->newType = newTypeA;
|
||||
b->newType = newTypeB;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4739,7 +4737,7 @@ SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
|
||||
|
||||
TypeObject *type = proto
|
||||
? proto->getNewType(cx, NULL, /* markUnknown = */ true)
|
||||
: &emptyTypeObject;
|
||||
: cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
|
@ -478,13 +478,8 @@ struct JSObject : js::gc::Cell {
|
||||
|
||||
uint32 flags; /* flags */
|
||||
|
||||
union {
|
||||
/* If prototype, type of values using this as their prototype. */
|
||||
js::types::TypeObject *newType;
|
||||
|
||||
/* If dense array, the initialized length (see jsarray.cpp). */
|
||||
jsuword initializedLength;
|
||||
};
|
||||
/* If dense array, the initialized length (see jsarray.cpp). */
|
||||
jsuword initializedLength;
|
||||
|
||||
JS_FRIEND_API(size_t) sizeOfSlotsArray(JSUsableSizeFun usf);
|
||||
|
||||
@ -783,9 +778,6 @@ struct JSObject : js::gc::Cell {
|
||||
*/
|
||||
inline bool setSingletonType(JSContext *cx);
|
||||
|
||||
/* Called from GC, reverts a singleton object to having a lazy type. */
|
||||
inline void revertLazyType();
|
||||
|
||||
inline js::types::TypeObject *getType(JSContext *cx);
|
||||
|
||||
js::types::TypeObject *type() const {
|
||||
@ -800,14 +792,15 @@ struct JSObject : js::gc::Cell {
|
||||
|
||||
static inline size_t offsetOfType() { return offsetof(JSObject, type_); }
|
||||
|
||||
inline void clearType();
|
||||
inline bool clearType(JSContext *cx);
|
||||
inline void setType(js::types::TypeObject *newType);
|
||||
|
||||
inline js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
|
||||
bool markUnknown = false);
|
||||
private:
|
||||
void makeNewType(JSContext *cx, JSFunction *fun, bool markUnknown);
|
||||
public:
|
||||
js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
|
||||
bool markUnknown = false);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool hasNewType(js::types::TypeObject *newType);
|
||||
#endif
|
||||
|
||||
/* Set a new prototype for an object with a singleton type. */
|
||||
bool splicePrototype(JSContext *cx, JSObject *proto);
|
||||
|
@ -311,7 +311,11 @@ JSObject::finalize(JSContext *cx, bool background)
|
||||
inline bool
|
||||
JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent)
|
||||
{
|
||||
init(cx, &js::types::emptyTypeObject, parent, NULL, false);
|
||||
js::types::TypeObject *type = cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
init(cx, type, parent, NULL, false);
|
||||
setMap(bindings.lastShape());
|
||||
|
||||
JS_ASSERT(isCall());
|
||||
@ -853,38 +857,17 @@ JSObject::getType(JSContext *cx)
|
||||
return type_;
|
||||
}
|
||||
|
||||
inline js::types::TypeObject *
|
||||
JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown)
|
||||
{
|
||||
if (isDenseArray() && !makeDenseArraySlow(cx))
|
||||
return NULL;
|
||||
if (newType) {
|
||||
/*
|
||||
* If set, the newType's newScript indicates the script used to create
|
||||
* all objects in existence which have this type. If there are objects
|
||||
* in existence which are not created by calling 'new' on newScript,
|
||||
* we must clear the new script information from the type and will not
|
||||
* be able to assume any definite properties for instances of the type.
|
||||
* This case is rare, but can happen if, for example, two scripted
|
||||
* functions have the same value for their 'prototype' property, or if
|
||||
* Object.create is called with a prototype object that is also the
|
||||
* 'prototype' property of some scripted function.
|
||||
*/
|
||||
if (newType->newScript && newType->newScript->fun != fun)
|
||||
newType->clearNewScript(cx);
|
||||
if (markUnknown && cx->typeInferenceEnabled() && !newType->unknownProperties())
|
||||
newType->markUnknown(cx);
|
||||
} else {
|
||||
makeNewType(cx, fun, markUnknown);
|
||||
}
|
||||
return newType;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::clearType()
|
||||
inline bool
|
||||
JSObject::clearType(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!hasSingletonType());
|
||||
type_ = &js::types::emptyTypeObject;
|
||||
|
||||
js::types::TypeObject *type = cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
type_ = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -969,8 +952,7 @@ JSObject::init(JSContext *cx, js::types::TypeObject *type,
|
||||
js::ClearValueRange(fixedSlots(), capacity, denseArray);
|
||||
}
|
||||
|
||||
newType = NULL;
|
||||
JS_ASSERT(initializedLength == 0);
|
||||
initializedLength = 0;
|
||||
|
||||
setType(type);
|
||||
setParent(parent);
|
||||
@ -1612,7 +1594,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
types::TypeObject *type = proto ? proto->getNewType(cx) : &js::types::emptyTypeObject;
|
||||
types::TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
@ -1712,7 +1694,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
|
||||
{
|
||||
JS_ASSERT(type == type->proto->newType);
|
||||
JS_ASSERT(type->proto->hasNewType(type));
|
||||
|
||||
if (CanBeFinalizedInBackground(kind, &ObjectClass))
|
||||
kind = GetBackgroundAllocKind(kind);
|
||||
|
@ -1947,7 +1947,8 @@ Parser::newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
|
||||
parent, atom);
|
||||
if (fun && !tc->compileAndGo()) {
|
||||
fun->clearParent();
|
||||
fun->clearType();
|
||||
if (!fun->clearType(context))
|
||||
return NULL;
|
||||
}
|
||||
return fun;
|
||||
}
|
||||
@ -8884,7 +8885,8 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
||||
return NULL;
|
||||
if (!tc->compileAndGo()) {
|
||||
obj->clearParent();
|
||||
obj->clearType();
|
||||
if (!obj->clearType(context))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pn->pn_objbox = tc->parser->newObjectBox(obj);
|
||||
|
@ -469,7 +469,8 @@ js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp)
|
||||
if (!obj)
|
||||
return false;
|
||||
obj->clearParent();
|
||||
obj->clearType();
|
||||
if (!obj->clearType(xdr->cx))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* initRegExp can GC before storing re in the private field of the
|
||||
|
@ -68,7 +68,7 @@ js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
|
||||
* Objects with a common prototype use the same shape lineage, even if
|
||||
* their prototypes differ.
|
||||
*/
|
||||
JS_ASSERT(this == proto->newType);
|
||||
JS_ASSERT(proto->hasNewType(this));
|
||||
|
||||
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
|
||||
int i = kind - js::gc::FINALIZE_OBJECT0;
|
||||
|
@ -1394,7 +1394,8 @@ js_NewScriptObject(JSContext *cx, JSScript *script)
|
||||
* Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent
|
||||
* for security checks, then we can clear the parent, too.
|
||||
*/
|
||||
obj->clearType();
|
||||
if (!obj->clearType(cx))
|
||||
return NULL;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -7424,7 +7424,8 @@ GlobalObject::getFunctionNamespace(JSContext *cx, Value *vp)
|
||||
* names, its prefix and uri references are copied to the QName.
|
||||
* The parent remains set and links back to global.
|
||||
*/
|
||||
obj->clearType();
|
||||
if (!obj->clearType(cx))
|
||||
return false;
|
||||
|
||||
v.setObject(*obj);
|
||||
}
|
||||
|
@ -1285,20 +1285,19 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
|
||||
* as for dense arrays we will need to get the address of the fixed
|
||||
* slots first.
|
||||
*/
|
||||
JS_ASSERT(!templateObject->initializedLength);
|
||||
if (templateObject->isDenseArray()) {
|
||||
JS_ASSERT(!templateObject->initializedLength);
|
||||
addPtr(Imm32(-thingSize + sizeof(JSObject)), result);
|
||||
storePtr(result, Address(result, -(int)sizeof(JSObject) + JSObject::offsetOfSlots()));
|
||||
addPtr(Imm32(-(int)sizeof(JSObject)), result);
|
||||
} else {
|
||||
JS_ASSERT(!templateObject->newType);
|
||||
addPtr(Imm32(-thingSize), result);
|
||||
storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
|
||||
}
|
||||
|
||||
storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp)));
|
||||
store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
|
||||
storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType)));
|
||||
storePtr(ImmPtr((void *) templateObject->initializedLength), Address(result, offsetof(JSObject, initializedLength)));
|
||||
storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));
|
||||
storePtr(ImmPtr(templateObject->privateData), Address(result, offsetof(JSObject, privateData)));
|
||||
storePtr(ImmPtr((void *) templateObject->capacity), Address(result, offsetof(JSObject, capacity)));
|
||||
|
Loading…
Reference in New Issue
Block a user