зеркало из https://github.com/mozilla/gecko-dev.git
Move rarely set object flags to BaseShape, bug 694561.
This commit is contained in:
Родитель
52d3c3bbb6
Коммит
dd1be81b31
|
@ -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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче