Remove JSObject::privateData, bug 693479.

This commit is contained in:
Brian Hackett 2011-10-10 17:14:38 -07:00
parent f5a853bac0
commit e9b876258d
23 changed files with 202 additions and 93 deletions

View File

@ -52,7 +52,6 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
CHECK(savedCopy->flags == obj->flags);
CHECK(savedCopy->getProto() == obj->getProto());
CHECK(savedCopy->parent == obj->parent);
CHECK(savedCopy->privateData == obj->privateData);
return true;
}

View File

@ -1259,7 +1259,6 @@ Class js::ArrayClass = {
Class js::SlowArrayClass = {
"Array",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
slowarray_addProperty,
JS_PropertyStub, /* delProperty */

View File

@ -191,19 +191,20 @@ struct Object {
TypeObject *type;
uint32 flags;
JSObject *parent;
void *privateData;
js::Value *slots;
js::Value *_1;
#if JS_BITS_PER_WORD == 32
js::Value *_2;
#endif
static const uint32 FIXED_SLOTS_SHIFT = 27;
size_t numFixedSlots() const { return flags >> FIXED_SLOTS_SHIFT; }
Value *fixedSlots() const {
return (Value *)((jsuword) this + sizeof(shadow::Object));
}
js::Value &slotRef(size_t slot) const {
size_t nfixed = flags >> FIXED_SLOTS_SHIFT;
size_t nfixed = numFixedSlots();
if (slot < nfixed)
return ((Value *)((jsuword) this + sizeof(shadow::Object)))[slot];
return fixedSlots()[slot];
return slots[slot - nfixed];
}
};
@ -250,7 +251,9 @@ GetObjectProto(const JSObject *obj)
inline void *
GetObjectPrivate(const JSObject *obj)
{
return reinterpret_cast<const shadow::Object*>(obj)->privateData;
const shadow::Object *nobj = reinterpret_cast<const shadow::Object*>(obj);
void **addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]);
return *addr;
}
/*

View File

@ -199,7 +199,7 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
JS_STATIC_ASSERT(NormalArgumentsObject::RESERVED_SLOTS == 2);
JS_STATIC_ASSERT(StrictArgumentsObject::RESERVED_SLOTS == 2);
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT4);
if (!obj)
return NULL;
@ -215,7 +215,7 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
SetValueRangeToUndefined(data->slots, argc);
/* Can't fail from here on, so initialize everything in argsobj. */
obj->init(cx, type, proto->getParent(), NULL, false);
obj->init(cx, type, proto->getParent(), false);
obj->setInitialPropertyInfallible(emptyArgumentsShape);
ArgumentsObject *argsobj = obj->asArguments();
@ -225,6 +225,9 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
argsobj->setCalleeAndData(callee, data);
JS_ASSERT(argsobj->numFixedSlots() == NormalArgumentsObject::NFIXED_SLOTS);
JS_ASSERT(argsobj->numFixedSlots() == StrictArgumentsObject::NFIXED_SLOTS);
return argsobj;
}
@ -768,8 +771,9 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
if (!emptyDeclEnvShape)
return NULL;
envobj->init(cx, type, &fp->scopeChain(), fp, false);
envobj->init(cx, type, &fp->scopeChain(), false);
envobj->setInitialPropertyInfallible(emptyDeclEnvShape);
envobj->setPrivate(fp);
return envobj;
}

View File

@ -100,7 +100,7 @@
#define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
optimization level -- see above */
struct JSFunction : public JSObject_Slots2
struct JSFunction : public JSObject_Slots4
{
/* Functions always have two fixed slots (FUN_CLASS_RESERVED_SLOTS). */

View File

@ -77,6 +77,15 @@ GetGCObjectKind(size_t numSlots)
return slotsToThingKind[numSlots];
}
static inline AllocKind
GetGCObjectKind(Class *clasp)
{
uint32 nslots = JSCLASS_RESERVED_SLOTS(clasp);
if (clasp->flags & JSCLASS_HAS_PRIVATE)
nslots++;
return GetGCObjectKind(nslots);
}
/* As for GetGCObjectKind, but for dense array allocation. */
static inline AllocKind
GetGCArrayKind(size_t numSlots)
@ -400,7 +409,7 @@ js_NewGCFunction(JSContext *cx)
{
JSFunction *fun = NewGCThing<JSFunction>(cx, js::gc::FINALIZE_FUNCTION, sizeof(JSFunction));
if (fun)
fun->earlyInit(JSObject::FUN_CLASS_RESERVED_SLOTS);
fun->earlyInit(JSObject::FUN_CLASS_NFIXED_SLOTS + 1); /* Add one for private data. */
return fun;
}

View File

@ -405,7 +405,7 @@ NewIteratorObject(JSContext *cx, uintN flags)
* helper objects) expect it to have a non-null map pointer, so we
* share an empty Enumerator scope in the runtime.
*/
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
if (!obj)
return NULL;
@ -417,8 +417,10 @@ NewIteratorObject(JSContext *cx, uintN flags)
if (!emptyEnumeratorShape)
return NULL;
obj->init(cx, type, NULL, NULL, false);
obj->init(cx, type, NULL, false);
obj->setInitialPropertyInfallible(emptyEnumeratorShape);
JS_ASSERT(obj->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
return obj;
}

View File

@ -3464,13 +3464,13 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
if (!type)
return NULL;
obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
obj = js_NewGCObject(cx, FINALIZE_OBJECT4);
if (!obj)
return NULL;
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
obj->init(cx, type, parent, priv, false);
obj->init(cx, type, parent, false);
EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
if (!emptyWithShape)
@ -3479,6 +3479,8 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
obj->setInitialPropertyInfallible(emptyWithShape);
OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
obj->setPrivate(priv);
AutoObjectRooter tvr(cx, obj);
JSObject *thisp = proto->thisObject(cx);
if (!thisp)
@ -3509,7 +3511,7 @@ js_NewBlockObject(JSContext *cx)
if (!emptyBlockShape)
return NULL;
blockObj->init(cx, type, NULL, NULL, false);
blockObj->init(cx, type, NULL, false);
blockObj->setInitialPropertyInfallible(emptyBlockShape);
return blockObj;
@ -3757,7 +3759,7 @@ JS_CloneObject(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent)
return NULL;
}
if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE)
if (obj->hasPrivate())
clone->setPrivate(obj->getPrivate());
} else {
JS_ASSERT(obj->isProxy());
@ -3772,11 +3774,15 @@ struct JSObject::TradeGutsReserved {
JSContext *cx;
Vector<Value> avals;
Vector<Value> bvals;
uint32 newafixed;
uint32 newbfixed;
Value *newaslots;
Value *newbslots;
TradeGutsReserved(JSContext *cx)
: cx(cx), avals(cx), bvals(cx), newaslots(NULL), newbslots(NULL)
: cx(cx), avals(cx), bvals(cx),
newafixed(0), newbfixed(0),
newaslots(NULL), newbslots(NULL)
{}
~TradeGutsReserved()
@ -3798,7 +3804,7 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
* swaps can be performed infallibly.
*/
if (a->structSize() == b->structSize())
if (a->structSize() == b->structSize() && a->hasPrivate() == b->hasPrivate())
return true;
/*
@ -3821,17 +3827,32 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
JS_ASSERT(a->elements == emptyObjectElements);
JS_ASSERT(b->elements == emptyObjectElements);
/*
* The newafixed/newbfixed hold the number of fixed slots in the objects
* after the swap. Adjust these counts according to whether the objects
* use their last fixed slot for storing private data.
*/
reserved.newafixed = a->numFixedSlots();
reserved.newbfixed = b->numFixedSlots();
if (a->hasPrivate()) {
reserved.newafixed++;
reserved.newbfixed--;
}
if (b->hasPrivate()) {
reserved.newbfixed++;
reserved.newafixed--;
}
/*
* The newaslots/newbslots arrays hold any dynamic slots for the objects
* if they do not have enough fixed slots to accomodate the slots in the
* other object.
*/
unsigned afixed = a->numFixedSlots();
unsigned bfixed = b->numFixedSlots();
unsigned adynamic = dynamicSlotsCount(afixed, b->slotSpan());
unsigned bdynamic = dynamicSlotsCount(bfixed, a->slotSpan());
unsigned adynamic = dynamicSlotsCount(reserved.newafixed, b->slotSpan());
unsigned bdynamic = dynamicSlotsCount(reserved.newbfixed, a->slotSpan());
if (adynamic) {
reserved.newaslots = (Value *) cx->malloc_(sizeof(Value) * adynamic);
@ -3880,7 +3901,7 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
/* Trade the guts of the objects. */
const size_t size = a->structSize();
if (size == b->structSize()) {
if (size == b->structSize() && a->hasPrivate() == b->hasPrivate()) {
/*
* If the objects are the same size, then we make no assumptions about
* whether they have dynamically allocated slots and instead just copy
@ -3914,21 +3935,25 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
if (b->hasDynamicSlots())
cx->free_(b->slots);
unsigned afixed = a->numFixedSlots();
unsigned bfixed = b->numFixedSlots();
void *apriv = a->hasPrivate() ? a->getPrivate() : NULL;
void *bpriv = b->hasPrivate() ? b->getPrivate() : NULL;
JSObject tmp;
memcpy(&tmp, a, sizeof tmp);
memcpy(a, b, sizeof tmp);
memcpy(b, &tmp, sizeof tmp);
a->updateFixedSlots(afixed);
a->updateFixedSlots(reserved.newafixed);
a->slots = reserved.newaslots;
a->copySlotRange(0, reserved.bvals.begin(), bcap);
if (a->hasPrivate())
a->setPrivate(bpriv);
b->updateFixedSlots(bfixed);
b->updateFixedSlots(reserved.newbfixed);
b->slots = reserved.newbslots;
b->copySlotRange(0, reserved.avals.begin(), acap);
if (b->hasPrivate())
b->setPrivate(apriv);
/* Make sure the destructor for reserved doesn't free the slots. */
reserved.newaslots = NULL;
@ -4495,6 +4520,19 @@ JSObject::updateSlotsForSpan(size_t oldSpan, size_t newSpan)
invalidateSlotRange(newSpan, oldSpan - newSpan);
}
inline void
JSObject::initializePrivate()
{
size_t nfixed = numFixedSlots();
JS_ASSERT(nfixed != 0);
/* Remove a fixed slot, to make room for the private data. */
flags = flags ^ (nfixed << FIXED_SLOTS_SHIFT);
flags |= (nfixed - 1) << FIXED_SLOTS_SHIFT;
setPrivate(NULL);
}
bool
JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
{
@ -4502,6 +4540,9 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary());
if (shape->getClass()->flags & JSCLASS_HAS_PRIVATE)
initializePrivate();
size_t span = shape->slotSpan();
if (!span) {
@ -4524,6 +4565,10 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
JS_ASSERT(isNewborn());
JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary());
if (shape->getClass()->flags & JSCLASS_HAS_PRIVATE)
initializePrivate();
JS_ASSERT(dynamicSlotsCount(numFixedSlots(), shape->slotSpan()) == 0);
shape_ = const_cast<js::Shape *>(shape);

View File

@ -544,18 +544,12 @@ struct JSObject : js::gc::Cell
};
uint32 flags; /* flags */
JSObject *parent; /* object's parent */
void *privateData; /* private data */
private:
js::Value *slots; /* Slots for object properties. */
js::Value *elements; /* Slots for object elements. */
#if JS_BITS_PER_WORD == 32
void *padding;
#endif
public:
inline bool isNative() const;
@ -668,6 +662,8 @@ struct JSObject : js::gc::Cell
inline size_t numFixedSlots() const;
static const uint32 MAX_FIXED_SLOTS = 16;
private:
inline js::Value* fixedSlots() const;
public:
@ -685,6 +681,7 @@ struct JSObject : js::gc::Cell
/* JIT Accessors */
static inline size_t getFixedSlotOffset(size_t slot);
static inline size_t getPrivateDataOffset(size_t nfixed);
static inline size_t offsetOfSlots() { return offsetof(JSObject, slots); }
/* Minimum size for dynamically allocated slots. */
@ -891,7 +888,9 @@ struct JSObject : js::gc::Cell
inline bool isGlobal() const;
inline js::GlobalObject *asGlobal();
inline bool hasPrivate() const;
inline void *getPrivate() const;
inline void *getPrivate(size_t nfixed) const;
inline void setPrivate(void *data);
/* N.B. Infallible: NULL means 'no principal', not an error. */
@ -914,6 +913,9 @@ struct JSObject : js::gc::Cell
bool isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp);
inline void *&privateAddress(uint32 nfixed) const;
inline void initializePrivate();
public:
bool isExtensible() const { return !(flags & NOT_EXTENSIBLE); }
bool preventExtensions(JSContext *cx, js::AutoIdVector *props);
@ -1095,6 +1097,7 @@ struct JSObject : js::gc::Cell
public:
static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
static const uint32 FUN_CLASS_NFIXED_SLOTS = 3;
static size_t getFlatClosureUpvarsOffset() {
return getFixedSlotOffset(JSSLOT_FLAT_CLOSURE_UPVARS);
@ -1161,6 +1164,8 @@ struct JSObject : js::gc::Cell
* Iterator-specific getters and setters.
*/
static const uint32 ITER_CLASS_NFIXED_SLOTS = 1;
inline js::NativeIterator *getNativeIterator() const;
inline void setNativeIterator(js::NativeIterator *);
@ -1236,7 +1241,7 @@ struct JSObject : js::gc::Cell
/* The last property is not initialized here and should be set separately. */
void init(JSContext *cx, js::types::TypeObject *type,
JSObject *parent, void *priv, bool denseArray);
JSObject *parent, bool denseArray);
inline void finish(JSContext *cx);
JS_ALWAYS_INLINE void finalize(JSContext *cx, bool background);
@ -1433,7 +1438,6 @@ struct JSObject : js::gc::Cell
JS_STATIC_ASSERT(offsetof(JSObject, shape_) == offsetof(js::shadow::Object, shape));
JS_STATIC_ASSERT(offsetof(JSObject, flags) == offsetof(js::shadow::Object, flags));
JS_STATIC_ASSERT(offsetof(JSObject, parent) == offsetof(js::shadow::Object, parent));
JS_STATIC_ASSERT(offsetof(JSObject, privateData) == offsetof(js::shadow::Object, privateData));
JS_STATIC_ASSERT(offsetof(JSObject, slots) == offsetof(js::shadow::Object, slots));
JS_STATIC_ASSERT(offsetof(JSObject, type_) == offsetof(js::shadow::Object, type));
JS_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object));
@ -1474,6 +1478,11 @@ JSObject::getFixedSlotOffset(size_t slot) {
return sizeof(JSObject) + (slot * sizeof(js::Value));
}
/* static */ inline size_t
JSObject::getPrivateDataOffset(size_t nfixed) {
return getFixedSlotOffset(nfixed);
}
struct JSObject_Slots2 : JSObject { js::Value fslots[2]; };
struct JSObject_Slots4 : JSObject { js::Value fslots[4]; };
struct JSObject_Slots8 : JSObject { js::Value fslots[8]; };

View File

@ -93,25 +93,43 @@ JSObject::asGlobal()
return reinterpret_cast<js::GlobalObject *>(this);
}
inline void *
JSObject::getPrivate() const
inline bool
JSObject::hasPrivate() const
{
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
return privateData;
return getClass()->flags & JSCLASS_HAS_PRIVATE;
}
inline void *&
JSObject::privateAddress(uint32 nfixed) const
{
/*
* The private pointer of an object can hold any word sized value.
* Private pointers are stored immediately after the last fixed slot of
* the object.
*/
JS_ASSERT(nfixed == numFixedSlots());
JS_ASSERT_IF(!isNewborn(), hasPrivate());
js::Value *end = &fixedSlots()[nfixed];
return *reinterpret_cast<void**>(end);
}
inline void *
JSObject::getPrivate() const { return privateAddress(numFixedSlots()); }
inline void *
JSObject::getPrivate(size_t nfixed) const { return privateAddress(nfixed); }
inline JSFunction *
JSObject::getFunctionPrivate() const
{
JS_ASSERT(isFunction());
return reinterpret_cast<JSFunction *>(getPrivate());
return reinterpret_cast<JSFunction *>(getPrivate(FUN_CLASS_NFIXED_SLOTS));
}
inline void
JSObject::setPrivate(void *data)
{
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
privateData = data;
privateAddress(numFixedSlots()) = data;
}
inline bool
@ -315,7 +333,7 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
if (!type)
return false;
init(cx, type, parent, NULL, false);
init(cx, type, parent, false);
if (!setInitialProperty(cx, bindings.lastShape()))
return false;
@ -338,11 +356,13 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
inline bool
JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame)
{
init(cx, type, NULL, frame, false);
init(cx, type, NULL, false);
if (!setInitialProperty(cx, getProto()->lastProperty()))
return false;
setPrivate(frame);
JS_ASSERT(!inDictionaryMode());
JS_ASSERT(isClonedBlock());
@ -929,10 +949,8 @@ JSObject::isQName() const
inline void
JSObject::init(JSContext *cx, js::types::TypeObject *type,
JSObject *parent, void *priv, bool denseArray)
JSObject *parent, bool denseArray)
{
privateData = priv;
JS_STATIC_ASSERT(sizeof(js::ObjectElements) == 2 * sizeof(js::Value));
uint32 numSlots = numFixedSlots();
@ -948,7 +966,6 @@ JSObject::init(JSContext *cx, js::types::TypeObject *type,
new (getElementsHeader()) js::ObjectElements(numSlots - 2);
} else {
elements = js::emptyObjectElements;
js::ClearValueRange(fixedSlots(), numSlots);
}
setType(type);
@ -972,7 +989,7 @@ JSObject::initSharingEmptyShape(JSContext *cx,
void *privateValue,
js::gc::AllocKind kind)
{
init(cx, type, parent, privateValue, false);
init(cx, type, parent, false);
js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind);
if (!empty)
@ -981,6 +998,9 @@ JSObject::initSharingEmptyShape(JSContext *cx,
if (!setInitialProperty(cx, empty))
return false;
if (privateValue)
setPrivate(privateValue);
JS_ASSERT(!isDenseArray());
return true;
}
@ -1132,9 +1152,10 @@ JSObject::hasPropertyTable() const
inline size_t
JSObject::structSize() const
{
return (isFunction() && !getPrivate())
? sizeof(JSFunction)
: (sizeof(JSObject) + sizeof(js::Value) * numFixedSlots());
if (isFunction() && !getFunctionPrivate())
return sizeof(JSFunction);
uint32 nfixed = numFixedSlots() + (hasPrivate() ? 1 : 0);
return sizeof(JSObject) + (nfixed * sizeof(js::Value));
}
inline size_t
@ -1424,7 +1445,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
* the parent of the prototype's constructor.
*/
bool denseArray = (clasp == &ArrayClass);
obj->init(cx, type, parent, NULL, denseArray);
obj->init(cx, type, parent, denseArray);
JS_ASSERT(type->canProvideEmptyShape(clasp));
js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind);
@ -1437,7 +1458,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
{
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
}
@ -1486,7 +1507,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::AllocKind kind)
static inline JSObject *
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
{
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return NewBuiltinClassInstance(cx, clasp, kind);
}
@ -1578,8 +1599,8 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
if (!obj)
goto out;
/* This needs to match up with the size of JSFunction::data_padding. */
JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT2);
/* This needs to match up with the superclass of JSFunction. */
JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT4);
/*
* Default parent to the parent of the prototype, which was set from
@ -1587,7 +1608,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
*/
obj->init(cx, type,
(!parent && proto) ? proto->getParent() : parent,
NULL, clasp == &ArrayClass);
clasp == &ArrayClass);
if (clasp->isNative()
? !InitScopeForObject(cx, obj, clasp, type, kind)
@ -1608,14 +1629,14 @@ NewFunction(JSContext *cx, js::GlobalObject &global)
if (!js_GetClassPrototype(cx, &global, JSProto_Function, &proto))
return NULL;
return detail::NewObject<WithProto::Given, true>(cx, &FunctionClass, proto, &global,
gc::FINALIZE_OBJECT2);
gc::FINALIZE_OBJECT4);
}
static JS_ALWAYS_INLINE JSObject *
NewFunction(JSContext *cx, JSObject *parent)
{
return detail::NewObject<WithProto::Class, true>(cx, &FunctionClass, NULL, parent,
gc::FINALIZE_OBJECT2);
gc::FINALIZE_OBJECT4);
}
template <WithProto::e withProto>
@ -1630,7 +1651,7 @@ template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
@ -1648,7 +1669,7 @@ template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return NewObject<withProto>(cx, clasp, proto, parent, kind);
}
@ -1674,7 +1695,7 @@ NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::
*/
obj->init(cx, type,
(!parent && type->proto) ? type->proto->getParent() : parent,
NULL, false);
false);
if (!InitScopeForObject(cx, obj, &ObjectClass, type, kind)) {
obj = NULL;

View File

@ -74,8 +74,12 @@ using namespace js;
using namespace js::gc;
using namespace js::types;
/* slots can only be upto 255 */
static const uint8 ARRAYBUFFER_RESERVED_SLOTS = 16;
/*
* Allocate array buffers with the maximum number of fixed slots marked as
* reserved, so that the fixed slots may be used for the buffer's contents.
* The last fixed slot is kept for the object's private data.
*/
static const uint8 ARRAYBUFFER_RESERVED_SLOTS = JSObject::MAX_FIXED_SLOTS - 1;
static bool
ValueIsLength(JSContext *cx, const Value &v, jsuint *len)
@ -765,7 +769,7 @@ TypedArray::lengthOffset()
/* static */ int
TypedArray::dataOffset()
{
return offsetof(JSObject, privateData);
return JSObject::getPrivateDataOffset(NUM_FIXED_SLOTS);
}
/* Helper clamped uint8 type */
@ -1298,6 +1302,8 @@ class TypedArrayTemplate
return false;
obj->setLastPropertyInfallible(empty);
JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS);
// FIXME Bug 599008: make it ok to call preventExtensions here.
obj->flags |= JSObject::NOT_EXTENSIBLE;

View File

@ -193,7 +193,8 @@ struct JS_FRIEND_API(TypedArray) {
FIELD_BYTELENGTH,
FIELD_TYPE,
FIELD_BUFFER,
FIELD_MAX
FIELD_MAX,
NUM_FIXED_SLOTS = 7
};
// and MUST NOT be used to construct new objects.

View File

@ -95,7 +95,7 @@ TypedArray::getBuffer(JSObject *obj) {
inline void *
TypedArray::getDataOffset(JSObject *obj) {
return (void *)obj->getPrivate();
return (void *)obj->getPrivate(NUM_FIXED_SLOTS);
}
}

View File

@ -1253,6 +1253,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
JS_ASSERT(cx->typeInferenceEnabled());
JS_ASSERT(!templateObject->hasDynamicSlots());
JS_ASSERT(!templateObject->hasDynamicElements());
JS_ASSERT(!(templateObject->getClass()->flags & JSCLASS_HAS_PRIVATE));
#ifdef JS_GC_ZEAL
if (cx->runtime->needZealousGC())
@ -1304,7 +1305,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));
storePtr(ImmPtr(templateObject->privateData), Address(result, offsetof(JSObject, privateData)));
if (templateObject->isDenseArray()) {
/* Fill in the elements header. */

View File

@ -3340,7 +3340,7 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA
if (origCalleeType.isSet())
isObj = masm.testObject(Assembler::NotEqual, origCalleeType.reg());
Jump isFun = masm.testFunction(Assembler::NotEqual, origCalleeData, temp);
masm.loadObjPrivate(origCalleeData, origCalleeData);
masm.loadObjPrivate(origCalleeData, origCalleeData, JSObject::FUN_CLASS_NFIXED_SLOTS);
Native native = *PC == JSOP_FUNCALL ? js_fun_call : js_fun_apply;
Jump isNative = masm.branchPtr(Assembler::NotEqual,
Address(origCalleeData, JSFunction::offsetOfNativeOrScript()),
@ -3621,7 +3621,7 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew, FrameSize
Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData, tmp);
/* Test if the function is scripted. */
stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg);
stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg, JSObject::FUN_CLASS_NFIXED_SLOTS);
stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp);
stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp);
Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED));
@ -5670,7 +5670,7 @@ mjit::Compiler::iter(uintN flags)
stubcc.linkExit(nullIterator, Uses(1));
/* Get NativeIterator from iter obj. */
masm.loadObjPrivate(ioreg, nireg);
masm.loadObjPrivate(ioreg, nireg, JSObject::ITER_CLASS_NFIXED_SLOTS);
/* Test for active iterator. */
Address flagsAddr(nireg, offsetof(NativeIterator, flags));
@ -5759,7 +5759,7 @@ mjit::Compiler::iterNext(ptrdiff_t offset)
stubcc.linkExit(notFast, Uses(1));
/* Get private from iter obj. */
masm.loadObjPrivate(reg, T1);
masm.loadObjPrivate(reg, T1, JSObject::ITER_CLASS_NFIXED_SLOTS);
RegisterID T3 = frame.allocReg();
RegisterID T4 = frame.allocReg();
@ -5814,7 +5814,7 @@ mjit::Compiler::iterMore(jsbytecode *target)
stubcc.linkExitForBranch(notFast);
/* Get private from iter obj. */
masm.loadObjPrivate(reg, reg);
masm.loadObjPrivate(reg, reg, JSObject::ITER_CLASS_NFIXED_SLOTS);
/* Test that the iterator supports fast iteration. */
notFast = masm.branchTest32(Assembler::NonZero, Address(reg, offsetof(NativeIterator, flags)),
@ -5853,7 +5853,7 @@ mjit::Compiler::iterEnd()
stubcc.linkExit(notIterator, Uses(1));
/* Get private from iter obj. */
masm.loadObjPrivate(reg, T1);
masm.loadObjPrivate(reg, T1, JSObject::ITER_CLASS_NFIXED_SLOTS);
RegisterID T2 = frame.allocReg();

View File

@ -747,7 +747,7 @@ class CallCompiler : public BaseCompiler
/* Guard that it's the same function. */
JSFunction *fun = obj->getFunctionPrivate();
masm.loadObjPrivate(ic.funObjReg, t0);
masm.loadObjPrivate(ic.funObjReg, t0, JSObject::FUN_CLASS_NFIXED_SLOTS);
Jump funGuard = masm.branchPtr(Assembler::NotEqual, t0, ImmPtr(fun));
Jump done = masm.jump();

View File

@ -345,8 +345,8 @@ class NunboxAssembler : public JSC::MacroAssembler
loadPtr(payloadOf(privAddr), to);
}
void loadObjPrivate(RegisterID base, RegisterID to) {
Address priv(base, offsetof(JSObject, privateData));
void loadObjPrivate(RegisterID base, RegisterID to, uint32 nfixed) {
Address priv(base, JSObject::getPrivateDataOffset(nfixed));
loadPtr(priv, to);
}

View File

@ -357,7 +357,7 @@ class SetPropCompiler : public PICStubCompiler
uint16 slot = uint16(shape->shortid());
/* Guard that the call object has a frame. */
masm.loadObjPrivate(pic.objReg, pic.shapeReg);
masm.loadObjPrivate(pic.objReg, pic.shapeReg, obj->numFixedSlots());
Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
{
@ -1554,7 +1554,7 @@ class ScopeNameCompiler : public PICStubCompiler
}
/* Get callobj's stack frame. */
masm.loadObjPrivate(pic.objReg, pic.shapeReg);
masm.loadObjPrivate(pic.objReg, pic.shapeReg, getprop.holder->numFixedSlots());
JSFunction *fun = getprop.holder->asCall().getCalleeFunction();
uint16 slot = uint16(shape->shortid());
@ -2556,7 +2556,7 @@ GetElementIC::attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid
}
Jump holeCheck = masm.branchPtr(Assembler::Equal, objReg, ImmType(JSVAL_TYPE_MAGIC));
Address privateData(typeReg, offsetof(JSObject, privateData));
Address privateData(typeReg, JSObject::getPrivateDataOffset(ArgumentsObject::NFIXED_SLOTS));
Jump liveArguments = masm.branchPtr(Assembler::NotEqual, privateData, ImmPtr(0));
masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);

View File

@ -274,8 +274,8 @@ class PunboxAssembler : public JSC::MacroAssembler
lshiftPtr(Imm32(1), to);
}
void loadObjPrivate(RegisterID base, RegisterID to) {
Address priv(base, offsetof(JSObject, privateData));
void loadObjPrivate(RegisterID base, RegisterID to, uint32 nfixed) {
Address priv(base, JSObject::getPrivateDataOffset(nfixed));
loadPtr(priv, to);
}

View File

@ -436,10 +436,13 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
case ACCSET_OBJ_PRIVATE:
// base = <JSObject>
// ins = {ld,st}p.objprivate base[offsetof(JSObject, privateData)]
ok = false;
/*
ok = (op == LIR_ldi || op == LIR_ldp ||
op == LIR_sti || op == LIR_stp) &&
disp == offsetof(JSObject, privateData) &&
couldBeObjectOrString(base);
*/
break;
case ACCSET_OBJ_CAPACITY:
@ -497,9 +500,12 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
case ACCSET_ITER:
// base = ldp.objprivate ...[offsetof(JSObject, privateData)]
// ins = {ld,st}p.iter base[<disp within NativeIterator>]
ok = false;
/*
ok = (op == LIR_ldp || op == LIR_stp) &&
dispWithin(NativeIterator) &&
match(base, LIR_ldp, ACCSET_OBJ_PRIVATE, offsetof(JSObject, privateData));
*/
break;
case ACCSET_ITER_PROPS:

View File

@ -510,19 +510,22 @@ class Writer
}
nj::LIns *ldpObjPrivate(nj::LIns *obj) const {
return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, privateData),
JS_NOT_REACHED("FIXME");
return name(lir->insLoad(nj::LIR_ldp, obj, 0,
ACCSET_OBJ_PRIVATE),
"private");
}
nj::LIns *lduiObjPrivate(nj::LIns *obj) const {
return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, privateData),
JS_NOT_REACHED("FIXME");
return name(lir->insLoad(nj::LIR_ldi, obj, 0,
ACCSET_OBJ_PRIVATE),
"private_uint32");
}
nj::LIns *stuiObjPrivate(nj::LIns *obj, nj::LIns *value) const {
return name(lir->insStore(nj::LIR_sti, value, obj, offsetof(JSObject, privateData),
JS_NOT_REACHED("FIXME");
return name(lir->insStore(nj::LIR_sti, value, obj, 0,
ACCSET_OBJ_PRIVATE),
"private_uint32");
}
@ -557,7 +560,8 @@ class Writer
}
nj::LIns *ldpConstTypedArrayData(nj::LIns *obj) const {
return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, privateData), ACCSET_TARRAY, nj::LOAD_CONST), "typedArrayData");
JS_NOT_REACHED("FIXME");
return name(lir->insLoad(nj::LIR_ldp, obj, 0, ACCSET_TARRAY, nj::LOAD_CONST), "typedArrayData");
}
nj::LIns *ldc2iTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {

View File

@ -151,6 +151,7 @@ class ArgumentsObject : public ::JSObject
public:
static const uint32 RESERVED_SLOTS = 2;
static const uint32 NFIXED_SLOTS = 3;
private:
/* Lower-order bit stolen from the length slot. */

View File

@ -56,7 +56,7 @@ CallObject::create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObje
{
Bindings &bindings = script->bindings;
size_t argsVars = bindings.countArgsAndVars();
size_t slots = RESERVED_SLOTS + argsVars;
size_t slots = RESERVED_SLOTS + argsVars + 1; /* Add one for privateData. */
gc::AllocKind kind = gc::GetGCObjectKind(slots);
/*