Move rarely set object flags to BaseShape, bug 694561.

This commit is contained in:
Brian Hackett 2011-10-14 13:51:21 -07:00
Родитель 52d3c3bbb6
Коммит dd1be81b31
25 изменённых файлов: 308 добавлений и 260 удалений

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

@ -3163,7 +3163,6 @@ JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
if (obj) { if (obj) {
if (clasp->ext.equality) if (clasp->ext.equality)
MarkTypeObjectFlags(cx, obj, OBJECT_FLAG_SPECIAL_EQUALITY); MarkTypeObjectFlags(cx, obj, OBJECT_FLAG_SPECIAL_EQUALITY);
obj->syncSpecialEquality();
MarkTypeObjectUnknownProperties(cx, obj->type()); MarkTypeObjectUnknownProperties(cx, obj->type());
} }
@ -3186,10 +3185,8 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSO
JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent); JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
if (obj) { if (obj)
obj->syncSpecialEquality();
MarkTypeObjectUnknownProperties(cx, obj->type()); MarkTypeObjectUnknownProperties(cx, obj->type());
}
return obj; return obj;
} }
@ -3608,8 +3605,6 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp
if (!nobj) if (!nobj)
return NULL; return NULL;
nobj->syncSpecialEquality();
if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0)) if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
return NULL; return NULL;

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

@ -1143,8 +1143,7 @@ JS_IsSystemObject(JSContext *cx, JSObject *obj)
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
JS_MakeSystemObject(JSContext *cx, JSObject *obj) JS_MakeSystemObject(JSContext *cx, JSObject *obj)
{ {
obj->setSystem(); return obj->setSystem(cx);
return true;
} }
/************************************************************************/ /************************************************************************/

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

@ -1895,19 +1895,24 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
{ {
JS_ASSERT(isFunction()); JS_ASSERT(isFunction());
flags |= JSObject::BOUND_FUNCTION;
setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg); setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen)); setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
if (argslen != 0) {
/* Convert to a dictionary to increase the slot span and cover the arguments. */
if (!toDictionaryMode(cx))
return false;
JS_ASSERT(slotSpan() == JSSLOT_FREE(&FunctionClass));
if (!setSlotSpan(cx, slotSpan() + argslen))
return false;
copySlotRange(FUN_CLASS_RESERVED_SLOTS, args, argslen); /*
} * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
* the slot span to cover the arguments.
*/
if (!toDictionaryMode(cx))
return false;
lastProperty()->base()->setObjectFlag(BaseShape::BOUND_FUNCTION);
JS_ASSERT(slotSpan() == JSSLOT_FREE(&FunctionClass));
if (!setSlotSpan(cx, slotSpan() + argslen))
return false;
copySlotRange(FUN_CLASS_RESERVED_SLOTS, args, argslen);
return true; return true;
} }
@ -2513,48 +2518,6 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
sop = NULL; sop = NULL;
} }
/*
* Historically, all objects have had a parent member as intrinsic scope
* chain link. We want to move away from this universal parent, but JS
* requires that function objects have something like parent (ES3 and ES5
* call it the [[Scope]] internal property), to bake a particular static
* scope environment into each function object.
*
* All function objects thus have parent, including all native functions.
* All native functions defined by the JS_DefineFunction* APIs are created
* via the call below to js_NewFunction, which passes obj as the parent
* parameter, and so binds fun's parent to obj using JSObject::setParent,
* under js_NewFunction (in JSObject::init, called from NewObject -- see
* jsobjinlines.h).
*
* But JSObject::setParent sets the DELEGATE object flag on its receiver,
* to mark the object as a proto or parent of another object. Such objects
* may intervene in property lookups and scope chain searches, so require
* special handling when caching lookup and search results (since such
* intervening objects can in general grow shadowing properties later).
*
* Thus using setParent prematurely flags certain objects, notably class
* prototypes, so that defining native methods on them, where the method's
* name (e.g., toString) is already bound on Object.prototype, triggers
* shadowingShapeChange events and gratuitous shape regeneration.
*
* To fix this longstanding bug, we set check whether obj is already a
* delegate, and if not, then if js_NewFunction flagged obj as a delegate,
* we clear the flag.
*
* We thus rely on the fact that native functions (including indirect eval)
* do not use the property cache or equivalent JIT techniques that require
* this bit to be set on their parent-linked scope chain objects.
*
* Note: we keep API compatibility by setting parent to obj for all native
* function objects, even if obj->getGlobal() would suffice. This should be
* revisited when parent is narrowed to exist only for function objects and
* possibly a few prehistoric scope objects (e.g. event targets).
*
* FIXME: bug 611190.
*/
bool wasDelegate = obj->isDelegate();
fun = js_NewFunction(cx, NULL, native, nargs, fun = js_NewFunction(cx, NULL, native, nargs,
attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO), attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO),
obj, obj,
@ -2562,9 +2525,6 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
if (!fun) if (!fun)
return NULL; return NULL;
if (!wasDelegate && obj->isDelegate())
obj->clearDelegate();
if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK)) if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
return NULL; return NULL;

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

@ -2881,7 +2881,7 @@ TypeObject::setFlags(JSContext *cx, TypeObjectFlags flags)
JS_ASSERT_IF(flags & OBJECT_FLAG_REENTRANT_FUNCTION, JS_ASSERT_IF(flags & OBJECT_FLAG_REENTRANT_FUNCTION,
interpretedFunction->script()->reentrantOuterFunction); interpretedFunction->script()->reentrantOuterFunction);
JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED, JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
singleton->flags & JSObject::ITERATED); singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
} }
this->flags |= flags; this->flags |= flags;
@ -5637,7 +5637,7 @@ JSObject::makeLazyType(JSContext *cx)
type->flags |= OBJECT_FLAG_REENTRANT_FUNCTION; type->flags |= OBJECT_FLAG_REENTRANT_FUNCTION;
} }
if (flags & ITERATED) if (lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
type->flags |= OBJECT_FLAG_ITERATED; type->flags |= OBJECT_FLAG_ITERATED;
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
@ -5696,6 +5696,9 @@ JSObject::hasNewType(TypeObject *type)
TypeObject * TypeObject *
JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown) JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown)
{ {
if (!setDelegate(cx))
return NULL;
JSCompartment::NewTypeObjectSet &table = cx->compartment->newTypeObjects; JSCompartment::NewTypeObjectSet &table = cx->compartment->newTypeObjects;
if (!table.initialized() && !table.init()) if (!table.initialized() && !table.init())
@ -5732,8 +5735,6 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown)
if (!table.relookupOrAdd(p, this, type)) if (!table.relookupOrAdd(p, this, type))
return NULL; return NULL;
setDelegate();
if (!cx->typeInferenceEnabled()) if (!cx->typeInferenceEnabled())
return type; return type;

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

@ -809,8 +809,10 @@ js::Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rva
JS_ASSERT(!scopeChain->getOps()->defineProperty); JS_ASSERT(!scopeChain->getOps()->defineProperty);
/* The VAROBJFIX option makes varObj == globalObj in global code. */ /* The VAROBJFIX option makes varObj == globalObj in global code. */
if (!cx->hasRunOption(JSOPTION_VAROBJFIX)) if (!cx->hasRunOption(JSOPTION_VAROBJFIX)) {
scopeChain->makeVarObj(); if (!scopeChain->setVarObj(cx))
return false;
}
/* Use the scope chain as 'this', modulo outerization. */ /* Use the scope chain as 'this', modulo outerization. */
JSObject *thisObj = scopeChain->thisObject(cx); JSObject *thisObj = scopeChain->thisObject(cx);
@ -930,7 +932,6 @@ js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *re
if (lval.isObject()) { if (lval.isObject()) {
JSObject *l = &lval.toObject(); JSObject *l = &lval.toObject();
JSObject *r = &rval.toObject(); JSObject *r = &rval.toObject();
l->assertSpecialEqualitySynced();
if (JSEqualityOp eq = l->getClass()->ext.equality) { if (JSEqualityOp eq = l->getClass()->ext.equality) {
return eq(cx, l, &rval, result); return eq(cx, l, &rval, result);

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

@ -473,7 +473,8 @@ VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &key
JS_ASSERT(!(flags & JSITER_FOREACH)); JS_ASSERT(!(flags & JSITER_FOREACH));
if (obj) { if (obj) {
obj->flags |= JSObject::ITERATED; if (obj->hasSingletonType() && !obj->setIteratedSingleton(cx))
return false;
types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED); types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
} }
@ -525,7 +526,8 @@ VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &k
JS_ASSERT(flags & JSITER_FOREACH); JS_ASSERT(flags & JSITER_FOREACH);
if (obj) { if (obj) {
obj->flags |= JSObject::ITERATED; if (obj->hasSingletonType() && !obj->setIteratedSingleton(cx))
return false;
types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED); types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
} }

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

@ -2966,10 +2966,7 @@ js_CreateThis(JSContext *cx, JSObject *callee)
JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL; JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
JSObject *parent = callee->getParent(); JSObject *parent = callee->getParent();
gc::AllocKind kind = NewObjectGCKind(cx, newclasp); gc::AllocKind kind = NewObjectGCKind(cx, newclasp);
JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind); return NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
if (obj)
obj->syncSpecialEquality();
return obj;
} }
static inline JSObject * static inline JSObject *
@ -4286,8 +4283,6 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
if (!type || !type->getEmptyShape(cx, proto->getClass(), FINALIZE_OBJECT0)) if (!type || !type->getEmptyShape(cx, proto->getClass(), FINALIZE_OBJECT0))
return NULL; return NULL;
proto->syncSpecialEquality();
/* After this point, control must exit via label bad or out. */ /* After this point, control must exit via label bad or out. */
JSObject *ctor; JSObject *ctor;
bool named = false; bool named = false;
@ -4568,6 +4563,8 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
JS_ASSERT(shape->compartment() == compartment()); JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary()); JS_ASSERT(!shape->inDictionary());
JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots()); JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots());
JS_ASSERT_IF(shape->getObjectClass()->ext.equality && !hasSingletonType(),
type()->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
size_t span = shape->slotSpan(); size_t span = shape->slotSpan();
@ -4594,6 +4591,8 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
JS_ASSERT(shape->compartment() == compartment()); JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary()); JS_ASSERT(!shape->inDictionary());
JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots()); JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots());
JS_ASSERT_IF(shape->getObjectClass()->ext.equality && !hasSingletonType(),
type()->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
JS_ASSERT(dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == 0); JS_ASSERT(dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == 0);
@ -5085,7 +5084,6 @@ js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *paren
if (!obj) if (!obj)
return NULL; return NULL;
obj->syncSpecialEquality();
MarkTypeObjectUnknownProperties(cx, obj->type()); MarkTypeObjectUnknownProperties(cx, obj->type());
Value rval; Value rval;
@ -7385,12 +7383,10 @@ js_DumpObject(JSObject *obj)
fprintf(stderr, "flags:"); fprintf(stderr, "flags:");
uint32 flags = obj->flags; uint32 flags = obj->flags;
if (flags & JSObject::DELEGATE) fprintf(stderr, " delegate"); if (obj->isDelegate()) fprintf(stderr, " delegate");
if (flags & JSObject::SYSTEM) fprintf(stderr, " system"); if (obj->isSystem()) fprintf(stderr, " system");
if (flags & JSObject::NOT_EXTENSIBLE) fprintf(stderr, " not_extensible"); if (!obj->isExtensible()) fprintf(stderr, " not_extensible");
if (flags & JSObject::GENERIC) fprintf(stderr, " generic"); if (obj->isIndexed()) fprintf(stderr, " indexed");
if (flags & JSObject::INDEXED) fprintf(stderr, " indexed");
if (flags & JSObject::HAS_EQUALITY) fprintf(stderr, " has_equality");
bool anyFlags = flags != 0; bool anyFlags = flags != 0;
if (obj->isNative()) { if (obj->isNative()) {

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

@ -522,16 +522,6 @@ struct JSObject : js::gc::Cell
inline bool nativeContains(JSContext *cx, const js::Shape &shape); inline bool nativeContains(JSContext *cx, const js::Shape &shape);
enum { enum {
DELEGATE = 0x01,
SYSTEM = 0x02,
NOT_EXTENSIBLE = 0x04,
GENERIC = 0x10,
INDEXED = 0x40,
BOUND_FUNCTION = 0x400,
HAS_EQUALITY = 0x800,
VAROBJ = 0x1000,
WATCHED = 0x2000,
ITERATED = 0x8000,
SINGLETON_TYPE = 0x10000, SINGLETON_TYPE = 0x10000,
LAZY_TYPE = 0x20000, LAZY_TYPE = 0x20000,
@ -571,50 +561,39 @@ struct JSObject : js::gc::Cell
* definition helps to optimize shape-based property cache invalidation * definition helps to optimize shape-based property cache invalidation
* (see Purge{Scope,Proto}Chain in jsobj.cpp). * (see Purge{Scope,Proto}Chain in jsobj.cpp).
*/ */
bool isDelegate() const { return !!(flags & DELEGATE); } inline bool isDelegate() const;
void setDelegate() { flags |= DELEGATE; } inline bool setDelegate(JSContext *cx);
void clearDelegate() { flags &= ~DELEGATE; }
bool isBoundFunction() const { return !!(flags & BOUND_FUNCTION); } inline bool isBoundFunction() const;
static void setDelegateNullSafe(JSObject *obj) {
if (obj)
obj->setDelegate();
}
/* /*
* The meaning of the system object bit is defined by the API client. It is * The meaning of the system object bit is defined by the API client. It is
* set in JS_NewSystemObject and is queried by JS_IsSystemObject, but it * set in JS_NewSystemObject and is queried by JS_IsSystemObject, but it
* has no intrinsic meaning to SpiderMonkey. * has no intrinsic meaning to SpiderMonkey.
*/ */
bool isSystem() const { return !!(flags & SYSTEM); } inline bool isSystem() const;
void setSystem() { flags |= SYSTEM; } inline bool setSystem(JSContext *cx);
bool generic() { return !!(flags & GENERIC); } inline bool hasSpecialEquality() const;
void setGeneric() { flags |= GENERIC; }
bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); } inline bool watched() const;
inline void assertSpecialEqualitySynced() const; inline bool setWatched(JSContext *cx);
/* Sets an object's HAS_EQUALITY flag based on its clasp. */ /* See StackFrame::varObj. */
inline void syncSpecialEquality(); inline bool isVarObj() const;
inline bool setVarObj(JSContext *cx);
bool watched() const { return !!(flags & WATCHED); }
bool setWatched(JSContext *cx) {
if (!watched()) {
flags |= WATCHED;
return generateOwnShape(cx);
}
return true;
}
/* See StackFrame::varObj. */
inline bool isVarObj() const { return flags & VAROBJ; }
inline void makeVarObj() { flags |= VAROBJ; }
private: private:
bool generateOwnShape(JSContext *cx, js::Shape *newShape = NULL); bool generateOwnShape(JSContext *cx, js::Shape *newShape = NULL);
enum GenerateShape {
GENERATE_NONE,
GENERATE_SHAPE
};
bool setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32 flag,
GenerateShape generateShape = GENERATE_NONE);
public: public:
inline bool nativeEmpty() const; inline bool nativeEmpty() const;
@ -627,11 +606,6 @@ struct JSObject : js::gc::Cell
bool protoShapeChange(JSContext *cx); bool protoShapeChange(JSContext *cx);
bool shadowingShapeChange(JSContext *cx, const js::Shape &shape); bool shadowingShapeChange(JSContext *cx, const js::Shape &shape);
bool extensibleShapeChange(JSContext *cx) {
/* This will do for now. */
return generateOwnShape(cx);
}
/* /*
* Read barrier to clone a joined function object stored as a method. * Read barrier to clone a joined function object stored as a method.
* Defined in jsobjinlines.h, but not declared inline per standard style in * Defined in jsobjinlines.h, but not declared inline per standard style in
@ -642,8 +616,8 @@ struct JSObject : js::gc::Cell
/* 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;
bool isIndexed() const { return !!(flags & INDEXED); } inline bool isIndexed() const;
void setIndexed() { flags |= INDEXED; } inline bool setIndexed(JSContext *cx);
/* /*
* Return true if this object is a native one that has been converted from * Return true if this object is a native one that has been converted from
@ -809,7 +783,7 @@ struct JSObject : js::gc::Cell
} }
/* Defined in jsscopeinlines.h to avoid including implementation dependencies here. */ /* Defined in jsscopeinlines.h to avoid including implementation dependencies here. */
inline void updateFlags(const js::Shape *shape, bool isDefinitelyAtom = false); inline bool updateFlags(JSContext *cx, jsid id, bool isDefinitelyAtom = false);
/* Extend this object to have shape as its last-added property. */ /* Extend this object to have shape as its last-added property. */
inline bool extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false); inline bool extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false);
@ -855,6 +829,8 @@ struct JSObject : js::gc::Cell
bool hasNewType(js::types::TypeObject *newType); bool hasNewType(js::types::TypeObject *newType);
#endif #endif
inline bool setIteratedSingleton(JSContext *cx);
/* Set a new prototype for an object with a singleton type. */ /* Set a new prototype for an object with a singleton type. */
bool splicePrototype(JSContext *cx, JSObject *proto); bool splicePrototype(JSContext *cx, JSObject *proto);
@ -925,7 +901,7 @@ struct JSObject : js::gc::Cell
inline void *&privateAddress(uint32 nfixed) const; inline void *&privateAddress(uint32 nfixed) const;
public: public:
bool isExtensible() const { return !(flags & NOT_EXTENSIBLE); } inline bool isExtensible() const;
bool preventExtensions(JSContext *cx, js::AutoIdVector *props); bool preventExtensions(JSContext *cx, js::AutoIdVector *props);
/* ES5 15.2.3.8: non-extensible, all props non-configurable */ /* ES5 15.2.3.8: non-extensible, all props non-configurable */
@ -1704,23 +1680,6 @@ js_CreateThis(JSContext *cx, JSObject *callee);
extern jsid extern jsid
js_CheckForStringIndex(jsid id); js_CheckForStringIndex(jsid id);
/*
* js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
* scope, else it reshapes the scope and prototype chains it links. It calls
* js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
* (i.e., obj has ever been on a prototype or parent chain).
*/
extern bool
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
inline bool
js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
{
if (obj->isDelegate())
return js_PurgeScopeChainHelper(cx, obj, id);
return true;
}
/* /*
* 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.

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

@ -74,12 +74,6 @@
#include "jsprobes.h" #include "jsprobes.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
inline void
JSObject::assertSpecialEqualitySynced() const
{
JS_ASSERT(!!getClass()->ext.equality == hasSpecialEquality());
}
inline bool inline bool
JSObject::isGlobal() const JSObject::isGlobal() const
{ {
@ -155,31 +149,6 @@ JSObject::thisObject(JSContext *cx)
return op ? op(cx, this) : this; return op ? op(cx, this) : this;
} }
inline bool
JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
{
JS_ASSERT(isExtensible());
if (js::FixOp fix = getOps()->fix) {
bool success;
if (!fix(cx, this, &success, props))
return false;
if (!success) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
} else {
if (!js::GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, props))
return false;
}
if (isNative() && !extensibleShapeChange(cx))
return false;
flags |= NOT_EXTENSIBLE;
return true;
}
inline JSBool inline JSBool
JSObject::defineProperty(JSContext *cx, jsid id, const js::Value &value, JSObject::defineProperty(JSContext *cx, jsid id, const js::Value &value,
JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
@ -283,15 +252,6 @@ JSObject::deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict)
return (op ? op : js_DeleteProperty)(cx, this, id, rval, strict); return (op ? op : js_DeleteProperty)(cx, this, id, rval, strict);
} }
inline void
JSObject::syncSpecialEquality()
{
if (getClass()->ext.equality) {
flags |= JSObject::HAS_EQUALITY;
JS_ASSERT_IF(!hasLazyType(), type()->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
}
}
inline void inline void
JSObject::finalize(JSContext *cx, bool background) JSObject::finalize(JSContext *cx, bool background)
{ {
@ -561,7 +521,8 @@ JSObject::canRemoveLastProperty()
*/ */
JS_ASSERT(!inDictionaryMode()); JS_ASSERT(!inDictionaryMode());
const js::Shape *previous = lastProperty()->previous(); const js::Shape *previous = lastProperty()->previous();
return previous->getObjectParent() == lastProperty()->getObjectParent(); return previous->getObjectParent() == lastProperty()->getObjectParent()
&& previous->getObjectFlags() == lastProperty()->getObjectFlags();
} }
inline js::Value inline js::Value
@ -951,11 +912,48 @@ JSObject::setType(js::types::TypeObject *newType)
for (JSObject *obj = newType->proto; obj; obj = obj->getProto()) for (JSObject *obj = newType->proto; obj; obj = obj->getProto())
JS_ASSERT(obj != this); JS_ASSERT(obj != this);
#endif #endif
JS_ASSERT_IF(hasSpecialEquality(), newType->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY)); JS_ASSERT_IF(!isNewborn() && hasSpecialEquality(),
newType->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
JS_ASSERT(!hasSingletonType()); JS_ASSERT(!hasSingletonType());
type_ = newType; type_ = newType;
} }
inline bool JSObject::setIteratedSingleton(JSContext *cx) {
return setFlag(cx, js::BaseShape::ITERATED_SINGLETON);
}
inline bool JSObject::setSystem(JSContext *cx) {
return setFlag(cx, js::BaseShape::SYSTEM);
}
inline bool JSObject::setDelegate(JSContext *cx) {
return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
}
inline bool JSObject::setIndexed(JSContext *cx) {
return setFlag(cx, js::BaseShape::INDEXED);
}
inline bool JSObject::setVarObj(JSContext *cx) {
return setFlag(cx, js::BaseShape::VAROBJ);
}
inline bool JSObject::setWatched(JSContext *cx) {
return setFlag(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
}
inline bool JSObject::isSystem() const { return lastProperty()->hasObjectFlag(js::BaseShape::SYSTEM); }
inline bool JSObject::isDelegate() const { return lastProperty()->hasObjectFlag(js::BaseShape::DELEGATE); }
inline bool JSObject::isVarObj() const { return lastProperty()->hasObjectFlag(js::BaseShape::VAROBJ); }
inline bool JSObject::isExtensible() const { return !lastProperty()->hasObjectFlag(js::BaseShape::NOT_EXTENSIBLE); }
inline bool JSObject::isBoundFunction() const { return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION); }
inline bool JSObject::isIndexed() const { return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED); }
inline bool JSObject::watched() const { return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED); }
inline bool JSObject::hasSpecialEquality() const {
return !!getClass()->ext.equality;
}
inline bool JSObject::isArguments() const { return isNormalArguments() || isStrictArguments(); } inline bool JSObject::isArguments() const { return isNormalArguments() || isStrictArguments(); }
inline bool JSObject::isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); } inline bool JSObject::isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); } inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
@ -1978,4 +1976,21 @@ js_GetProtoIfDenseArray(JSObject *obj)
return obj->isDenseArray() ? obj->getProto() : obj; return obj->isDenseArray() ? obj->getProto() : obj;
} }
/*
* js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
* scope, else it reshapes the scope and prototype chains it links. It calls
* js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
* (i.e., obj has ever been on a prototype or parent chain).
*/
extern bool
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
inline bool
js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
{
if (obj->isDelegate())
return js_PurgeScopeChainHelper(cx, obj, id);
return true;
}
#endif /* jsobjinlines_h___ */ #endif /* jsobjinlines_h___ */

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

@ -131,7 +131,8 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *po
* Make sure that a later shadowing assignment will enter * Make sure that a later shadowing assignment will enter
* PurgeProtoChain and invalidate this entry, bug 479198. * PurgeProtoChain and invalidate this entry, bug 479198.
*/ */
obj->setDelegate(); if (!obj->isDelegate())
return JS_NO_PROP_CACHE_FILL;
} }
} }

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

@ -748,17 +748,24 @@ JSObject::initRegExp(JSContext *cx, js::RegExp *re)
* will already have the relevant properties, at the relevant locations. * will already have the relevant properties, at the relevant locations.
*/ */
if (nativeEmpty()) { if (nativeEmpty()) {
const js::Shape *shape = js::BaseShape::lookupInitialShape(cx, getClass(), getParent(), if (isDelegate()) {
js::gc::FINALIZE_OBJECT8, lastProperty()); if (!assignInitialRegExpShape(cx))
if (!shape) return false;
return false; } else {
if (shape == lastProperty()) { const js::Shape *shape =
shape = assignInitialRegExpShape(cx); js::BaseShape::lookupInitialShape(cx, getClass(), getParent(),
js::gc::FINALIZE_OBJECT8, 0,
lastProperty());
if (!shape) if (!shape)
return false; return false;
js::BaseShape::insertInitialShape(cx, js::gc::FINALIZE_OBJECT8, shape); if (shape == lastProperty()) {
shape = assignInitialRegExpShape(cx);
if (!shape)
return false;
js::BaseShape::insertInitialShape(cx, js::gc::FINALIZE_OBJECT8, shape);
}
setLastPropertyInfallible(shape);
} }
setLastPropertyInfallible(shape);
JS_ASSERT(!nativeEmpty()); JS_ASSERT(!nativeEmpty());
} }

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

@ -416,7 +416,6 @@ JSObject::getChildProperty(JSContext *cx, Shape *parent, Shape &child)
return NULL; return NULL;
} }
updateFlags(shape);
return shape; return shape;
} }
@ -641,10 +640,14 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id,
} }
} }
if (!updateFlags(cx, id))
return NULL;
/* Find or create a property tree node labeled by our arguments. */ /* Find or create a property tree node labeled by our arguments. */
Shape *shape; Shape *shape;
{ {
BaseShape base(getClass(), getParentMaybeScope(), attrs, getter, setter); BaseShape base(getClass(), getParentMaybeScope(), lastProperty()->getObjectFlags(),
attrs, getter, setter);
BaseShape *nbase = BaseShape::lookup(cx, base); BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase) if (!nbase)
return NULL; return NULL;
@ -742,7 +745,8 @@ JSObject::putProperty(JSContext *cx, jsid id,
UnownedBaseShape *nbase; UnownedBaseShape *nbase;
{ {
BaseShape base(getClass(), getParentMaybeScope(), attrs, getter, setter); BaseShape base(getClass(), getParentMaybeScope(), lastProperty()->getObjectFlags(),
attrs, getter, setter);
nbase = BaseShape::lookup(cx, base); nbase = BaseShape::lookup(cx, base);
if (!nbase) if (!nbase)
return NULL; return NULL;
@ -808,7 +812,9 @@ JSObject::putProperty(JSContext *cx, jsid id,
* clause just below, getChildProperty handles this for us. First update * clause just below, getChildProperty handles this for us. First update
* flags. * flags.
*/ */
updateFlags(shape); jsuint index;
if (js_IdIsIndex(shape->propid(), &index))
shape->base()->setObjectFlag(BaseShape::INDEXED);
} else { } else {
/* /*
* Updating the last property in a non-dictionary-mode object. Such * Updating the last property in a non-dictionary-mode object. Such
@ -819,7 +825,8 @@ JSObject::putProperty(JSContext *cx, jsid id,
* If any shape in the tree has a property hashtable, it is shared and * If any shape in the tree has a property hashtable, it is shared and
* immutable too, therefore we must not update *spp. * immutable too, therefore we must not update *spp.
*/ */
BaseShape base(getClass(), getParentMaybeScope(), attrs, getter, setter); BaseShape base(getClass(), getParentMaybeScope(), lastProperty()->getObjectFlags(),
attrs, getter, setter);
BaseShape *nbase = BaseShape::lookup(cx, base); BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase) if (!nbase)
return NULL; return NULL;
@ -1155,6 +1162,59 @@ Shape::setObjectParent(JSContext *cx, JSObject *parent, Shape **listp)
return replaceLastProperty(cx, child, listp); return replaceLastProperty(cx, child, listp);
} }
bool
JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
{
JS_ASSERT(isExtensible());
if (props) {
if (js::FixOp fix = getOps()->fix) {
bool success;
if (!fix(cx, this, &success, props))
return false;
if (!success) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
} else {
if (!js::GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, props))
return false;
}
}
return setFlag(cx, BaseShape::NOT_EXTENSIBLE, GENERATE_SHAPE);
}
bool
JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32 flag_, GenerateShape generateShape)
{
BaseShape::Flag flag = (BaseShape::Flag) flag_;
if (inDictionaryMode()) {
if (generateShape == GENERATE_SHAPE && !generateOwnShape(cx))
return false;
lastProperty()->base()->setObjectFlag(flag);
return true;
}
return Shape::setObjectFlag(cx, flag, &shape_);
}
/* static */ bool
Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, Shape **listp)
{
BaseShape base(*(*listp)->base()->unowned());
base.flags |= flag;
BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase)
return false;
Shape child(*listp);
child.base_ = nbase;
return replaceLastProperty(cx, child, listp);
}
/* static */ inline HashNumber /* static */ inline HashNumber
JSCompartment::BaseShapeEntry::hash(const js::BaseShape *base) JSCompartment::BaseShapeEntry::hash(const js::BaseShape *base)
{ {
@ -1219,9 +1279,9 @@ BaseShape::lookup(JSContext *cx, const BaseShape &base)
/* static */ Shape * /* static */ Shape *
BaseShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent, BaseShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
AllocKind kind, Shape *initial) AllocKind kind, uint32 objectFlags, Shape *initial)
{ {
js::BaseShape base(clasp, parent); js::BaseShape base(clasp, parent, objectFlags);
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, base); JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, base);
if (!entry) if (!entry)
return NULL; return NULL;

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

@ -332,25 +332,45 @@ class UnownedBaseShape;
class BaseShape : public js::gc::Cell class BaseShape : public js::gc::Cell
{ {
public:
friend class Shape; friend class Shape;
friend struct JSCompartment::BaseShapeEntry; friend struct JSCompartment::BaseShapeEntry;
enum { enum Flag {
/* Owned by the referring shape. */ /* Owned by the referring shape. */
OWNED_SHAPE = 0x1, OWNED_SHAPE = 0x1,
/* getterObj/setterObj are active in unions below. */ /* getterObj/setterObj are active in unions below. */
HAS_GETTER_OBJECT = 0x2, HAS_GETTER_OBJECT = 0x2,
HAS_SETTER_OBJECT = 0x4, HAS_SETTER_OBJECT = 0x4,
/* /*
* For the last property in static Block objects and Bindings, * For the last property in static Block objects and Bindings,
* indicates that cloned Block or Call objects need unique shapes. * indicates that cloned Block or Call objects need unique shapes.
* See Shape::extensibleParents. * See Shape::extensibleParents.
*/ */
EXTENSIBLE_PARENTS = 0x8 EXTENSIBLE_PARENTS = 0x8,
/*
* Flags set which describe the referring object. Once set these cannot
* be unset, and are transferred from shape to shape as the object's
* last property changes. It is rare for an object to have any of these
* flags set.
*/
DELEGATE = 0x010,
SYSTEM = 0x020,
NOT_EXTENSIBLE = 0x040,
INDEXED = 0x080,
BOUND_FUNCTION = 0x100,
VAROBJ = 0x200,
WATCHED = 0x400,
ITERATED_SINGLETON = 0x800,
OBJECT_FLAG_MASK = 0xff0
}; };
private:
Class *clasp; /* Class of referring object. */ Class *clasp; /* Class of referring object. */
JSObject *parent; /* Parent of referring object. */ JSObject *parent; /* Parent of referring object. */
uint32 flags; /* Vector of above flags. */ uint32 flags; /* Vector of above flags. */
@ -378,17 +398,21 @@ class BaseShape : public js::gc::Cell
public: public:
void finalize(JSContext *cx, bool background); void finalize(JSContext *cx, bool background);
BaseShape(Class *clasp, JSObject *parent) { BaseShape(Class *clasp, JSObject *parent, uint32 objectFlags) {
JS_ASSERT(!(objectFlags & ~OBJECT_FLAG_MASK));
PodZero(this); PodZero(this);
this->clasp = clasp; this->clasp = clasp;
this->parent = parent; this->parent = parent;
this->flags = objectFlags;
} }
BaseShape(Class *clasp, JSObject *parent, BaseShape(Class *clasp, JSObject *parent, uint32 objectFlags,
uint8 attrs, js::PropertyOp rawGetter, js::StrictPropertyOp rawSetter) { uint8 attrs, js::PropertyOp rawGetter, js::StrictPropertyOp rawSetter) {
JS_ASSERT(!(objectFlags & ~OBJECT_FLAG_MASK));
PodZero(this); PodZero(this);
this->clasp = clasp; this->clasp = clasp;
this->parent = parent; this->parent = parent;
this->flags = objectFlags;
this->rawGetter = rawGetter; this->rawGetter = rawGetter;
this->rawSetter = rawSetter; this->rawSetter = rawSetter;
if ((attrs & JSPROP_GETTER) && rawGetter) if ((attrs & JSPROP_GETTER) && rawGetter)
@ -404,6 +428,8 @@ class BaseShape : public js::gc::Cell
void setParent(JSObject *obj) { parent = obj; } void setParent(JSObject *obj) { parent = obj; }
void setObjectFlag(Flag flag) { JS_ASSERT(!(flag & ~OBJECT_FLAG_MASK)); flags |= flag; }
bool hasGetterObject() const { return !!(flags & HAS_GETTER_OBJECT); } bool hasGetterObject() const { return !!(flags & HAS_GETTER_OBJECT); }
JSObject *getterObject() const { JS_ASSERT(hasGetterObject()); return getterObj; } JSObject *getterObject() const { JS_ASSERT(hasGetterObject()); return getterObj; }
@ -426,7 +452,8 @@ class BaseShape : public js::gc::Cell
* if none was found. * if none was found.
*/ */
static Shape *lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent, static Shape *lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
gc::AllocKind kind, Shape *initial = NULL); gc::AllocKind kind, uint32 objectFlags = 0,
Shape *initial = NULL);
/* Reinsert a possibly modified initial shape to the baseShapes table. */ /* Reinsert a possibly modified initial shape to the baseShapes table. */
static void insertInitialShape(JSContext *cx, gc::AllocKind kind, const Shape *initial); static void insertInitialShape(JSContext *cx, gc::AllocKind kind, const Shape *initial);
@ -443,6 +470,7 @@ class BaseShape : public js::gc::Cell
/* For JIT usage */ /* For JIT usage */
static inline size_t offsetOfClass() { return offsetof(BaseShape, clasp); } static inline size_t offsetOfClass() { return offsetof(BaseShape, clasp); }
static inline size_t offsetOfParent() { return offsetof(BaseShape, parent); } static inline size_t offsetOfParent() { return offsetof(BaseShape, parent); }
static inline size_t offsetOfFlags() { return offsetof(BaseShape, flags); }
private: private:
static void staticAsserts() { static void staticAsserts() {
@ -613,6 +641,13 @@ struct Shape : public js::gc::Cell
JSObject *getObjectParent() const { return base()->parent; } JSObject *getObjectParent() const { return base()->parent; }
static bool setObjectParent(JSContext *cx, JSObject *obj, Shape **listp); static bool setObjectParent(JSContext *cx, JSObject *obj, Shape **listp);
static bool setObjectFlag(JSContext *cx, BaseShape::Flag flag, Shape **listp);
uint32 getObjectFlags() const { return base()->flags & BaseShape::OBJECT_FLAG_MASK; }
bool hasObjectFlag(BaseShape::Flag flag) const {
JS_ASSERT(!(flag & ~BaseShape::OBJECT_FLAG_MASK));
return !!(base()->flags & flag);
}
protected: protected:
/* /*
@ -900,7 +935,7 @@ 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) { static EmptyShape *create(JSContext *cx, js::Class *clasp, JSObject *parent, uint32 nfixed) {
BaseShape lookup(clasp, parent); BaseShape lookup(clasp, parent, 0);
BaseShape *base = BaseShape::lookup(cx, lookup); BaseShape *base = BaseShape::lookup(cx, lookup);
if (!base) if (!base)
return NULL; return NULL;

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

@ -105,20 +105,24 @@ js::types::TypeObject::canProvideEmptyShape(js::Class *aclasp)
(!emptyShapes || emptyShapes->get(gc::FINALIZE_OBJECT0)->getObjectClass() == aclasp); (!emptyShapes || emptyShapes->get(gc::FINALIZE_OBJECT0)->getObjectClass() == aclasp);
} }
inline void inline bool
JSObject::updateFlags(const js::Shape *shape, bool isDefinitelyAtom) JSObject::updateFlags(JSContext *cx, jsid id, bool isDefinitelyAtom)
{ {
jsuint index; jsuint index;
if (!isDefinitelyAtom && js_IdIsIndex(shape->propid(), &index)) if (!isDefinitelyAtom && js_IdIsIndex(id, &index)) {
setIndexed(); if (!setIndexed(cx))
return false;
}
return true;
} }
inline bool inline bool
JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom) JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom)
{ {
if (!updateFlags(cx, shape->propid(), isDefinitelyAtom))
return false;
if (!setLastProperty(cx, shape)) if (!setLastProperty(cx, shape))
return false; return false;
updateFlags(shape, isDefinitelyAtom);
return true; return true;
} }
@ -130,17 +134,24 @@ StringObject::init(JSContext *cx, JSString *str)
JS_ASSERT(nativeEmpty()); JS_ASSERT(nativeEmpty());
JS_ASSERT(getAllocKind() == gc::FINALIZE_OBJECT2); JS_ASSERT(getAllocKind() == gc::FINALIZE_OBJECT2);
const js::Shape *shape = BaseShape::lookupInitialShape(cx, getClass(), getParent(), if (isDelegate()) {
gc::FINALIZE_OBJECT2, lastProperty()); if (!assignInitialShape(cx))
if (!shape) return false;
return false;
if (shape != lastProperty()) {
setLastPropertyInfallible(shape);
} else { } else {
shape = assignInitialShape(cx); const js::Shape *shape =
BaseShape::lookupInitialShape(cx, getClass(), getParent(),
gc::FINALIZE_OBJECT2, 0,
lastProperty());
if (!shape) if (!shape)
return false; return false;
BaseShape::insertInitialShape(cx, gc::FINALIZE_OBJECT2, shape); 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(!nativeEmpty());
JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT); JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT);
@ -157,13 +168,17 @@ BaseShape::adoptUnowned(UnownedBaseShape *other)
* unowned base shape of a new last property. * unowned base shape of a new last property.
*/ */
JS_ASSERT(isOwned()); JS_ASSERT(isOwned());
JS_ASSERT(parent == other->parent);
JSObject *parent = this->parent;
uint32 flags = (this->flags & OBJECT_FLAG_MASK);
uint32 span = slotSpan(); uint32 span = slotSpan();
PropertyTable *table = &this->table(); PropertyTable *table = &this->table();
*this = *static_cast<BaseShape *>(other); *this = *static_cast<BaseShape *>(other);
setOwned(other); setOwned(other);
this->parent = parent;
this->flags |= flags;
setTable(table); setTable(table);
setSlotSpan(span); setSlotSpan(span);
} }

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

@ -163,7 +163,7 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
id = ATOM_TO_JSID(name); id = ATOM_TO_JSID(name);
} }
BaseShape base(&CallClass, NULL, attrs, getter, setter); BaseShape base(&CallClass, NULL, BaseShape::VAROBJ, attrs, getter, setter);
BaseShape *nbase = BaseShape::lookup(cx, base); BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase) if (!nbase)
return NULL; return NULL;

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

@ -98,7 +98,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 = BaseShape::lookupInitialShape(cx, &CallClass, NULL, kind,
BaseShape::VAROBJ);
if (!lastBinding) if (!lastBinding)
return false; return false;
} }

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

@ -9160,6 +9160,8 @@ TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins,
if (l.isNull()) if (l.isNull())
op = LIR_eqp; op = LIR_eqp;
} else if (l.isObject()) { } else if (l.isObject()) {
JS_NOT_REACHED("FIXME");
#if 0
if (l.toObject().getClass()->ext.equality) if (l.toObject().getClass()->ext.equality)
RETURN_STOP_A("Can't trace extended class equality operator"); RETURN_STOP_A("Can't trace extended class equality operator");
LIns* flags_ins = w.ldiObjFlags(l_ins); LIns* flags_ins = w.ldiObjFlags(l_ins);
@ -9168,6 +9170,7 @@ TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins,
op = LIR_eqp; op = LIR_eqp;
cond = (l == r); cond = (l == r);
#endif
} else if (l.isBoolean()) { } else if (l.isBoolean()) {
JS_ASSERT(r.isBoolean()); JS_ASSERT(r.isBoolean());
cond = (l == r); cond = (l == r);

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

@ -1301,16 +1301,14 @@ class TypedArrayTemplate
JS_ASSERT(obj->getClass() == slowClass()); JS_ASSERT(obj->getClass() == slowClass());
js::Shape *empty = BaseShape::lookupInitialShape(cx, fastClass(), obj->getParent(), js::Shape *empty = BaseShape::lookupInitialShape(cx, fastClass(), obj->getParent(),
gc::FINALIZE_OBJECT8); gc::FINALIZE_OBJECT8,
BaseShape::NOT_EXTENSIBLE);
if (!empty) if (!empty)
return false; return false;
obj->setLastPropertyInfallible(empty); obj->setLastPropertyInfallible(empty);
JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS); JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS);
// FIXME Bug 599008: make it ok to call preventExtensions here.
obj->flags |= JSObject::NOT_EXTENSIBLE;
return obj; return obj;
} }

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

@ -174,10 +174,7 @@ NewBuiltinClassInstanceXML(JSContext *cx, Class *clasp)
if (!cx->runningWithTrustedPrincipals()) if (!cx->runningWithTrustedPrincipals())
++sE4XObjectsCreated; ++sE4XObjectsCreated;
JSObject *obj = NewBuiltinClassInstance(cx, clasp); return NewBuiltinClassInstance(cx, clasp);
if (obj)
obj->syncSpecialEquality();
return obj;
} }
#define DEFINE_GETTER(name,code) \ #define DEFINE_GETTER(name,code) \
@ -7277,7 +7274,6 @@ js_InitNamespaceClass(JSContext *cx, JSObject *obj)
JSFlatString *empty = cx->runtime->emptyString; JSFlatString *empty = cx->runtime->emptyString;
namespaceProto->setNamePrefix(empty); namespaceProto->setNamePrefix(empty);
namespaceProto->setNameURI(empty); namespaceProto->setNameURI(empty);
namespaceProto->syncSpecialEquality();
const uintN NAMESPACE_CTOR_LENGTH = 2; const uintN NAMESPACE_CTOR_LENGTH = 2;
JSFunction *ctor = global->createConstructor(cx, Namespace, &NamespaceClass, JSFunction *ctor = global->createConstructor(cx, Namespace, &NamespaceClass,
@ -7311,7 +7307,6 @@ js_InitQNameClass(JSContext *cx, JSObject *obj)
JSAtom *empty = cx->runtime->emptyString; JSAtom *empty = cx->runtime->emptyString;
if (!InitXMLQName(cx, qnameProto, empty, empty, empty)) if (!InitXMLQName(cx, qnameProto, empty, empty, empty))
return NULL; return NULL;
qnameProto->syncSpecialEquality();
const uintN QNAME_CTOR_LENGTH = 2; const uintN QNAME_CTOR_LENGTH = 2;
JSFunction *ctor = global->createConstructor(cx, QName, &QNameClass, JSFunction *ctor = global->createConstructor(cx, QName, &QNameClass,

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

@ -814,9 +814,13 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
addPtr(JSFrameReg, reg); addPtr(JSFrameReg, reg);
} }
void loadObjClass(RegisterID obj, RegisterID dest) { void loadBaseShape(RegisterID obj, RegisterID dest) {
loadPtr(Address(obj, JSObject::offsetOfShape()), dest); loadPtr(Address(obj, JSObject::offsetOfShape()), dest);
loadPtr(Address(dest, Shape::offsetOfBase()), dest); loadPtr(Address(dest, Shape::offsetOfBase()), dest);
}
void loadObjClass(RegisterID obj, RegisterID dest) {
loadBaseShape(obj, dest);
loadPtr(Address(dest, BaseShape::offsetOfClass()), dest); loadPtr(Address(dest, BaseShape::offsetOfClass()), dest);
} }
@ -825,8 +829,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
} }
Jump testObjClass(Condition cond, RegisterID obj, RegisterID temp, js::Class *clasp) { Jump testObjClass(Condition cond, RegisterID obj, RegisterID temp, js::Class *clasp) {
loadPtr(Address(obj, JSObject::offsetOfShape()), temp); loadBaseShape(obj, temp);
loadPtr(Address(temp, Shape::offsetOfBase()), temp);
return branchPtr(cond, Address(temp, BaseShape::offsetOfClass()), ImmPtr(clasp)); return branchPtr(cond, Address(temp, BaseShape::offsetOfClass()), ImmPtr(clasp));
} }

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

@ -6309,14 +6309,17 @@ mjit::Compiler::jsop_instanceof()
RegisterID tmp = frame.allocReg(); RegisterID tmp = frame.allocReg();
RegisterID obj = frame.tempRegForData(rhs); RegisterID obj = frame.tempRegForData(rhs);
Jump notFunction = masm.testFunction(Assembler::NotEqual, obj, tmp); masm.loadBaseShape(obj, tmp);
Jump notFunction = masm.branchPtr(Assembler::NotEqual,
Address(tmp, BaseShape::offsetOfClass()),
ImmPtr(&FunctionClass));
stubcc.linkExit(notFunction, Uses(2)); stubcc.linkExit(notFunction, Uses(2));
frame.freeReg(tmp);
/* Test for bound functions. */ /* Test for bound functions. */
Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)), Jump isBound = masm.branchTest32(Assembler::NonZero,
Imm32(JSObject::BOUND_FUNCTION)); Address(tmp, BaseShape::offsetOfFlags()),
Imm32(BaseShape::BOUND_FUNCTION));
{ {
stubcc.linkExit(isBound, Uses(2)); stubcc.linkExit(isBound, Uses(2));
stubcc.leave(); stubcc.leave();
@ -6324,6 +6327,7 @@ mjit::Compiler::jsop_instanceof()
firstSlow = stubcc.masm.jump(); firstSlow = stubcc.masm.jump();
} }
frame.freeReg(tmp);
/* This is sadly necessary because the error case needs the object. */ /* This is sadly necessary because the error case needs the object. */
frame.dup(); frame.dup();

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

@ -334,10 +334,10 @@ class EqualityCompiler : public BaseCompiler
linkToStub(rhsFail); linkToStub(rhsFail);
} }
Jump lhsHasEq = masm.branchTest32(Assembler::NonZero, masm.loadObjClass(lvr.dataReg(), ic.tempReg);
Address(lvr.dataReg(), Jump lhsHasEq = masm.branchPtr(Assembler::NotEqual,
offsetof(JSObject, flags)), Address(ic.tempReg, offsetof(Class, ext.equality)),
Imm32(JSObject::HAS_EQUALITY)); ImmPtr(NULL));
linkToStub(lhsHasEq); linkToStub(lhsHasEq);
if (rvr.isConstant()) { if (rvr.isConstant()) {

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

@ -886,7 +886,6 @@ StubEqualityOp(VMFrame &f)
cond = JSDOUBLE_COMPARE(l, !=, r, IFNAN); cond = JSDOUBLE_COMPARE(l, !=, r, IFNAN);
} else if (lval.isObject()) { } else if (lval.isObject()) {
JSObject *l = &lval.toObject(), *r = &rval.toObject(); JSObject *l = &lval.toObject(), *r = &rval.toObject();
l->assertSpecialEqualitySynced();
if (JSEqualityOp eq = l->getClass()->ext.equality) { if (JSEqualityOp eq = l->getClass()->ext.equality) {
if (!eq(cx, l, &rval, &cond)) if (!eq(cx, l, &rval, &cond))
return false; return false;

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

@ -64,7 +64,6 @@ CallObject::create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObje
/* Init immediately to avoid GC seeing a half-init'ed object. */ /* Init immediately to avoid GC seeing a half-init'ed object. */
if (!obj->initCall(cx, bindings, &scopeChain)) if (!obj->initCall(cx, bindings, &scopeChain))
return NULL; return NULL;
obj->makeVarObj();
#ifdef DEBUG #ifdef DEBUG
for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) { for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) {

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

@ -259,8 +259,8 @@ GlobalObject::create(JSContext *cx, Class *clasp)
return NULL; return NULL;
GlobalObject *globalObj = obj->asGlobal(); GlobalObject *globalObj = obj->asGlobal();
globalObj->makeVarObj(); if (!globalObj->setVarObj(cx))
globalObj->syncSpecialEquality(); return NULL;
/* Construct a regexp statics object for this global object. */ /* Construct a regexp statics object for this global object. */
JSObject *res = regexp_statics_construct(cx, globalObj); JSObject *res = regexp_statics_construct(cx, globalObj);