Bug 816776 - Add debug-mode exact rooting assertions for Shape; r=sfink

--HG--
extra : rebase_source : fbd47f598964cbb03dcc782198c10164e09a26f2
This commit is contained in:
Terrence Cole 2012-11-29 10:22:10 -08:00
parent cdfe65034b
commit ea1ffaab45
64 changed files with 797 additions and 725 deletions

View File

@ -2075,7 +2075,7 @@ BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
*/
bool redeclared;
RootedId id(cx, NameToId(name));
Shape *shape = StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared);
RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared));
if (!shape) {
if (redeclared)
ReportRedeclaration(cx, parser, pn, false, name);

View File

@ -123,7 +123,7 @@ frontend::LexicalLookup(ContextT *ct, HandleAtom atom, int *slotp, typename Cont
continue;
StaticBlockObject &blockObj = *stmt->blockObj;
Shape *shape = blockObj.nativeLookup(ct->sc->context, AtomToId(atom));
UnrootedShape shape = blockObj.nativeLookup(ct->sc->context, AtomToId(atom));
if (shape) {
JS_ASSERT(shape->hasShortID());

View File

@ -71,7 +71,7 @@ static inline void
PushMarkStack(GCMarker *gcmarker, JSScript *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, Shape *thing);
PushMarkStack(GCMarker *gcmarker, UnrootedShape thing);
static inline void
PushMarkStack(GCMarker *gcmarker, JSString *thing);
@ -84,7 +84,7 @@ namespace gc {
static void MarkChildren(JSTracer *trc, JSString *str);
static void MarkChildren(JSTracer *trc, JSScript *script);
static void MarkChildren(JSTracer *trc, Shape *shape);
static void MarkChildren(JSTracer *trc, UnrootedShape shape);
static void MarkChildren(JSTracer *trc, UnrootedBaseShape base);
static void MarkChildren(JSTracer *trc, types::TypeObject *type);
static void MarkChildren(JSTracer *trc, ion::IonCode *code);
@ -292,12 +292,14 @@ Is##base##Marked(EncapsulatedPtr<type> *thingp)
return IsMarked<type>(thingp->unsafeGet()); \
} \
\
bool Is##base##AboutToBeFinalized(type **thingp) \
bool \
Is##base##AboutToBeFinalized(type **thingp) \
{ \
return IsAboutToBeFinalized<type>(thingp); \
} \
\
bool Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp) \
bool \
Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp) \
{ \
return IsAboutToBeFinalized<type>(thingp->unsafeGet()); \
}
@ -731,10 +733,10 @@ PushMarkStack(GCMarker *gcmarker, JSScript *thing)
}
static void
ScanShape(GCMarker *gcmarker, Shape *shape);
ScanShape(GCMarker *gcmarker, UnrootedShape shape);
static void
PushMarkStack(GCMarker *gcmarker, Shape *thing)
PushMarkStack(GCMarker *gcmarker, UnrootedShape thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
@ -766,7 +768,7 @@ PushMarkStack(GCMarker *gcmarker, UnrootedBaseShape thing)
}
static void
ScanShape(GCMarker *gcmarker, Shape *shape)
ScanShape(GCMarker *gcmarker, UnrootedShape shape)
{
restart:
PushMarkStack(gcmarker, shape->base());
@ -930,7 +932,7 @@ gc::MarkChildren(JSTracer *trc, JSScript *script)
}
static void
gc::MarkChildren(JSTracer *trc, Shape *shape)
gc::MarkChildren(JSTracer *trc, UnrootedShape shape)
{
shape->markChildren(trc);
}
@ -990,7 +992,7 @@ MarkCycleCollectorChildren(JSTracer *trc, UnrootedBaseShape base, JSObject **pre
* parent pointer will only be marked once.
*/
void
gc::MarkCycleCollectorChildren(JSTracer *trc, Shape *shape)
gc::MarkCycleCollectorChildren(JSTracer *trc, UnrootedShape shape)
{
JSObject *prevParent = NULL;
do {
@ -1021,7 +1023,7 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
if (type->newScript) {
PushMarkStack(gcmarker, type->newScript->fun);
PushMarkStack(gcmarker, type->newScript->shape);
PushMarkStack(gcmarker, type->newScript->shape.get());
}
if (type->interpretedFunction)
@ -1356,7 +1358,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
types::TypeObject *type = obj->typeFromGC();
PushMarkStack(this, type);
Shape *shape = obj->lastProperty();
UnrootedShape shape = obj->lastProperty();
PushMarkStack(this, shape);
/* Call the trace hook if necessary. */

View File

@ -236,7 +236,7 @@ MarkChildren(JSTracer *trc, JSObject *obj);
* JS_TraceShapeCycleCollectorChildren.
*/
void
MarkCycleCollectorChildren(JSTracer *trc, Shape *shape);
MarkCycleCollectorChildren(JSTracer *trc, UnrootedShape shape);
void
PushArena(GCMarker *gcmarker, ArenaHeader *aheader);

View File

@ -279,8 +279,7 @@ class MutableHandle : public js::MutableHandleBase<T>
}
template <typename S>
inline
MutableHandle(js::Rooted<S> *root,
inline MutableHandle(js::Rooted<S> *root,
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
void set(T v) {
@ -288,6 +287,9 @@ class MutableHandle : public js::MutableHandleBase<T>
*ptr = v;
}
template <typename S>
inline void set(const js::Unrooted<S> &v);
/*
* This may be called only if the location of the T is guaranteed
* to be marked (for some reason other than being a Rooted),
@ -478,6 +480,13 @@ class Unrooted
ptr_ = other;
return *this;
}
Unrooted &operator=(Unrooted other) {
JS_ASSERT(other.ptr_ != UninitializedTag());
if (ptr_ == UninitializedTag())
EnterAssertNoGCScope();
ptr_ = other.ptr_;
return *this;
}
operator T() const { return (ptr_ == UninitializedTag()) ? NULL : ptr_; }
T *operator&() { return &ptr_; }
@ -859,6 +868,13 @@ MutableHandle<T>::MutableHandle(js::Rooted<S> *root,
ptr = root->address();
}
template <typename T> template <typename S>
inline void MutableHandle<T>::set(const js::Unrooted<S> &v)
{
JS_ASSERT(!js::RootMethods<T>::poisoned(v));
*ptr = static_cast<S>(v);
}
/*
* The scoped guard object AutoAssertNoGC forces the GC to assert if a GC is
* attempted while the guard object is live. If you have a GC-unsafe operation

View File

@ -41,6 +41,7 @@ class CompilerRoot : public CompilerRootNode
public:
operator T () const { return static_cast<T>(ptr); }
operator Unrooted<T> () const { return static_cast<T>(ptr); }
T operator ->() const { return static_cast<T>(ptr); }
private:
@ -51,7 +52,9 @@ class CompilerRoot : public CompilerRootNode
typedef CompilerRoot<JSObject*> CompilerRootObject;
typedef CompilerRoot<JSFunction*> CompilerRootFunction;
typedef CompilerRoot<JSScript*> CompilerRootScript;
typedef CompilerRoot<PropertyName*> CompilerRootPropertyName;
typedef CompilerRoot<Shape*> CompilerRootShape;
typedef CompilerRoot<Value> CompilerRootValue;
} // namespace ion

View File

@ -4854,6 +4854,8 @@ bool
IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *actual,
types::StackTypeSet *observed)
{
AutoAssertNoGC nogc;
// If the instruction has no side effects, we'll resume the entire operation.
// The actual type barrier will occur in the interpreter. If the
// instruction is effectful, even if it has a singleton type, there
@ -4971,7 +4973,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
// For the fastest path, the property must be found, and it must be found
// as a normal data property on exactly the global object.
const js::Shape *shape = globalObj->nativeLookup(cx, id);
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
return jsop_getname(name);
@ -5048,7 +5050,7 @@ IonBuilder::jsop_setgname(HandlePropertyName name)
// For the fastest path, the property must be found, and it must be found
// as a normal data property on exactly the global object.
const js::Shape *shape = globalObj->nativeLookup(cx, id);
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
if (!shape || !shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot())
return jsop_setprop(name);
@ -6145,7 +6147,7 @@ IonBuilder::invalidatedIdempotentCache()
}
bool
IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType)
IonBuilder::loadSlot(MDefinition *obj, HandleShape shape, MIRType rvalType)
{
JS_ASSERT(shape->hasDefaultGetter());
JS_ASSERT(shape->hasSlot());
@ -6175,7 +6177,7 @@ IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType)
}
bool
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier)
IonBuilder::storeSlot(MDefinition *obj, UnrootedShape shape, MDefinition *value, bool needsBarrier)
{
JS_ASSERT(shape->hasDefaultSetter());
JS_ASSERT(shape->writable());
@ -6400,13 +6402,14 @@ bool
IonBuilder::getPropTryMonomorphic(bool *emitted, HandleId id, types::StackTypeSet *barrier,
TypeOracle::Unary unary, TypeOracle::UnaryTypes unaryTypes)
{
AssertCanGC();
JS_ASSERT(*emitted == false);
bool accessGetter = oracle->propertyReadAccessGetter(script(), pc);
if (unary.ival != MIRType_Object)
return true;
Shape *objShape = mjit::GetPICSingleShape(cx, script(), pc, info().constructing());
RootedShape objShape(cx, mjit::GetPICSingleShape(cx, script(), pc, info().constructing()));
if (!objShape || objShape->inDictionary()) {
spew("GETPROP not monomorphic");
return true;
@ -6421,7 +6424,7 @@ IonBuilder::getPropTryMonomorphic(bool *emitted, HandleId id, types::StackTypeSe
obj = addShapeGuard(obj, objShape, Bailout_CachedShapeGuard);
spew("Inlining monomorphic GETPROP");
Shape *shape = objShape->search(cx, id);
RootedShape shape(cx, objShape->search(cx, id));
JS_ASSERT(shape);
MIRType rvalType = unary.rval;
@ -6561,7 +6564,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
if (monitored) {
ins = MCallSetProperty::New(obj, value, name, script()->strict);
} else {
Shape *objShape;
UnrootedShape objShape;
if ((objShape = mjit::GetPICSingleShape(cx, script(), pc, info().constructing())) &&
!objShape->inDictionary())
{
@ -6571,7 +6574,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
// on dictionary mode shapes that aren't lastProperty is invalid.
obj = addShapeGuard(obj, objShape, Bailout_CachedShapeGuard);
Shape *shape = objShape->search(cx, NameToId(name));
UnrootedShape shape = DropUnrooted(objShape)->search(cx, NameToId(name));
JS_ASSERT(shape);
spew("Inlining monomorphic SETPROP");
@ -6579,7 +6582,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
jsid typeId = types::MakeTypeId(cx, id);
bool needsBarrier = oracle->propertyWriteNeedsBarrier(script(), pc, typeId);
return storeSlot(obj, shape, value, needsBarrier);
return storeSlot(obj, DropUnrooted(shape), value, needsBarrier);
}
spew("SETPROP not monomorphic");
@ -6962,7 +6965,7 @@ IonBuilder::addBoundsCheck(MDefinition *index, MDefinition *length)
}
MInstruction *
IonBuilder::addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind)
IonBuilder::addShapeGuard(MDefinition *obj, const UnrootedShape shape, BailoutKind bailoutKind)
{
MGuardShape *guard = MGuardShape::New(obj, shape, bailoutKind);
current->add(guard);

View File

@ -304,14 +304,14 @@ class IonBuilder : public MIRGenerator
MDefinition *walkScopeChain(unsigned hops);
MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
MInstruction *addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind);
MInstruction *addShapeGuard(MDefinition *obj, const UnrootedShape shape, BailoutKind bailoutKind);
JSObject *getNewArrayTemplateObject(uint32_t count);
bool invalidatedIdempotentCache();
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType);
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier);
bool loadSlot(MDefinition *obj, HandleShape shape, MIRType rvalType);
bool storeSlot(MDefinition *obj, UnrootedShape shape, MDefinition *value, bool needsBarrier);
// jsop_getprop() helpers.
bool getPropTryArgumentsLength(bool *emitted);

View File

@ -149,7 +149,7 @@ IsCacheableProtoChain(JSObject *obj, JSObject *holder)
}
static bool
IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, const Shape *shape)
IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, UnrootedShape shape)
{
if (!shape || !IsCacheableProtoChain(obj, holder))
return false;
@ -161,7 +161,7 @@ IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, const Shape *shape)
}
static bool
IsCacheableNoProperty(JSObject *obj, JSObject *holder, const Shape *shape, jsbytecode *pc,
IsCacheableNoProperty(JSObject *obj, JSObject *holder, UnrootedShape shape, jsbytecode *pc,
const TypedOrValueRegister &output)
{
if (shape)
@ -212,7 +212,7 @@ IsCacheableNoProperty(JSObject *obj, JSObject *holder, const Shape *shape, jsbyt
}
static bool
IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, const Shape *shape)
IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, UnrootedShape shape)
{
if (!shape || !IsCacheableProtoChain(obj, holder))
return false;
@ -225,7 +225,7 @@ IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, const Shape *shape
}
static bool
IsCacheableGetPropCallPropertyOp(JSObject *obj, JSObject *holder, const Shape *shape)
IsCacheableGetPropCallPropertyOp(JSObject *obj, JSObject *holder, UnrootedShape shape)
{
if (!shape || !IsCacheableProtoChain(obj, holder))
return false;
@ -243,7 +243,7 @@ struct GetNativePropertyStub
CodeOffsetLabel stubCodePatchOffset;
void generateReadSlot(JSContext *cx, MacroAssembler &masm, JSObject *obj, PropertyName *propName,
JSObject *holder, const Shape *shape, Register object, TypedOrValueRegister output,
JSObject *holder, HandleShape shape, Register object, TypedOrValueRegister output,
RepatchLabel *failures, Label *nonRepatchFailures = NULL)
{
// If there's a single jump to |failures|, we can patch the shape guard
@ -354,7 +354,7 @@ struct GetNativePropertyStub
}
bool generateCallGetter(JSContext *cx, MacroAssembler &masm, JSObject *obj,
PropertyName *propName, JSObject *holder, const Shape *shape,
PropertyName *propName, JSObject *holder, HandleShape shape,
RegisterSet &liveRegs, Register object, TypedOrValueRegister output,
void *returnAddr, jsbytecode *pc,
RepatchLabel *failures, Label *nonRepatchFailures = NULL)
@ -619,7 +619,7 @@ struct GetNativePropertyStub
bool
IonCacheGetProperty::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
const Shape *shape)
HandleShape shape)
{
MacroAssembler masm;
RepatchLabel failures;
@ -654,9 +654,10 @@ IonCacheGetProperty::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj
bool
IonCacheGetProperty::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj,
JSObject *holder, const Shape *shape,
JSObject *holder, HandleShape shape,
const SafepointIndex *safepointIndex, void *returnAddr)
{
AssertCanGC();
MacroAssembler masm;
RepatchLabel failures;
@ -1136,8 +1137,8 @@ IonCacheSetProperty::attachSetterCall(JSContext *cx, IonScript *ion,
bool
IonCacheSetProperty::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj,
const Shape *oldShape, const Shape *newShape,
const Shape *propShape)
HandleShape oldShape, HandleShape newShape,
HandleShape propShape)
{
MacroAssembler masm;
@ -1156,7 +1157,7 @@ IonCacheSetProperty::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject
JSObject *proto = obj->getProto();
Register protoReg = object();
while (proto) {
Shape *protoShape = proto->lastProperty();
UnrootedShape protoShape = proto->lastProperty();
// load next prototype
masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg);
@ -1248,7 +1249,7 @@ IsPropertyInlineable(JSObject *obj, IonCacheSetProperty &cache)
static bool
IsPropertySetInlineable(JSContext *cx, HandleObject obj, HandleId id, MutableHandleShape pshape)
{
Shape *shape = obj->nativeLookup(cx, id);
UnrootedShape shape = obj->nativeLookup(cx, id);
if (!shape)
return false;
@ -1299,7 +1300,7 @@ IsPropertyAddInlineable(JSContext *cx, HandleObject obj, jsid id, uint32_t oldSl
if (pShape.get())
return false;
Shape *shape = obj->nativeLookup(cx, id);
RootedShape shape(cx, obj->nativeLookup(cx, id));
if (!shape || shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter())
return false;
@ -1319,7 +1320,7 @@ IsPropertyAddInlineable(JSContext *cx, HandleObject obj, jsid id, uint32_t oldSl
return false;
// if prototype defines this property in a non-plain way, don't optimize
const Shape *protoShape = proto->nativeLookup(cx, id);
UnrootedShape protoShape = proto->nativeLookup(cx, id);
if (protoShape && !protoShape->hasDefaultSetter())
return false;
@ -1376,7 +1377,7 @@ js::ion::SetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, Ha
}
uint32_t oldSlots = obj->numDynamicSlots();
const Shape *oldShape = obj->lastProperty();
RootedShape oldShape(cx, obj->lastProperty());
// Set/Add the property on the object, the inlined cache are setup for the next execution.
if (!SetProperty(cx, obj, name, value, cache.strict(), isSetName))
@ -1385,7 +1386,7 @@ js::ion::SetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, Ha
// The property did not exists before, now we can try again to inline the
// procedure which is adding the property.
if (inlinable && IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape)) {
const Shape *newShape = obj->lastProperty();
RootedShape newShape(cx, obj->lastProperty());
cache.incrementStubCount();
if (!cache.attachNativeAdding(cx, ion, obj, oldShape, newShape, shape))
return false;
@ -1619,7 +1620,7 @@ IonCacheBindName::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeCha
static inline void
GenerateScopeChainGuard(MacroAssembler &masm, JSObject *scopeObj,
Register scopeObjReg, Shape *shape, Label *failures)
Register scopeObjReg, UnrootedShape shape, Label *failures)
{
AutoAssertNoGC nogc;
if (scopeObj->isCall()) {
@ -1789,8 +1790,10 @@ js::ion::BindNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain
}
bool
IonCacheName::attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject holder, Shape *shape)
IonCacheName::attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject holder,
HandleShape shape)
{
AssertCanGC();
MacroAssembler masm;
Label failures;

View File

@ -273,9 +273,9 @@ class IonCacheGetProperty : public IonCache
bool allowGetters() const { return u.getprop.allowGetters; }
bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
const Shape *shape);
HandleShape shape);
bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
const Shape *shape,
HandleShape shape,
const SafepointIndex *safepointIndex, void *returnAddr);
};
@ -305,8 +305,8 @@ class IonCacheSetProperty : public IonCache
bool attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape);
bool attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj,
HandleObject holder, HandleShape shape, void *returnAddr);
bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, const Shape *oldshape,
const Shape *newshape, const Shape *propshape);
bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape,
HandleShape newshape, HandleShape propshape);
};
class IonCacheGetElement : public IonCache
@ -412,7 +412,7 @@ class IonCacheName : public IonCache
}
bool attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject obj,
Shape *shape);
HandleShape shape);
};
bool

View File

@ -4455,8 +4455,8 @@ class MBindNameCache
: public MUnaryInstruction,
public SingleObjectPolicy
{
PropertyName *name_;
JSScript *script_;
CompilerRootPropertyName name_;
CompilerRootScript script_;
jsbytecode *pc_;
MBindNameCache(MDefinition *scopeChain, PropertyName *name, JSScript *script, jsbytecode *pc)
@ -4495,10 +4495,10 @@ class MGuardShape
: public MUnaryInstruction,
public SingleObjectPolicy
{
const Shape *shape_;
CompilerRootShape shape_;
BailoutKind bailoutKind_;
MGuardShape(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind)
MGuardShape(MDefinition *obj, UnrootedShape shape, BailoutKind bailoutKind)
: MUnaryInstruction(obj),
shape_(shape),
bailoutKind_(bailoutKind)
@ -4511,7 +4511,7 @@ class MGuardShape
public:
INSTRUCTION_HEADER(GuardShape)
static MGuardShape *New(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind) {
static MGuardShape *New(MDefinition *obj, UnrootedShape shape, BailoutKind bailoutKind) {
return new MGuardShape(obj, shape, bailoutKind);
}
@ -4521,7 +4521,7 @@ class MGuardShape
MDefinition *obj() const {
return getOperand(0);
}
const Shape *shape() const {
const UnrootedShape shape() const {
return shape_;
}
BailoutKind bailoutKind() const {

View File

@ -142,7 +142,7 @@ InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue v
if (name == cx->names().proto)
return baseops::SetPropertyHelper(cx, obj, obj, id, 0, &rval, false);
return !!DefineNativeProperty(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, 0, 0, 0);
return DefineNativeProperty(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, 0, 0, 0);
}
template<bool Equal>

View File

@ -98,6 +98,12 @@ struct ImmGCPtr
explicit ImmGCPtr(const gc::Cell *ptr) : value(reinterpret_cast<uintptr_t>(ptr))
{ }
// ImmGCPtr is rooted so we can convert safely directly from Unrooted<T>.
template <typename T>
explicit ImmGCPtr(Unrooted<T> ptr)
: value(reinterpret_cast<uintptr_t>(static_cast<T>(ptr)))
{ }
};
// Specifies a hardcoded, absolute address.

View File

@ -3829,7 +3829,7 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
if (flags != 0 && obj->isNative()) {
return !!DefineNativeProperty(cx, obj, id, value, getter, setter,
return DefineNativeProperty(cx, obj, id, value, getter, setter,
attrs, flags, tinyid);
}
return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
@ -4477,15 +4477,15 @@ JS_DeleteProperty(JSContext *cx, JSObject *objArg, const char *name)
return JS_DeleteProperty2(cx, objArg, name, &junk);
}
static Shape *
static UnrootedShape
LastConfigurableShape(JSObject *obj)
{
for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) {
Shape *shape = &r.front();
UnrootedShape shape = &r.front();
if (shape->configurable())
return shape;
}
return NULL;
return UnrootedShape(NULL);
}
JS_PUBLIC_API(void)
@ -4502,18 +4502,20 @@ JS_ClearNonGlobalObject(JSContext *cx, JSObject *objArg)
return;
/* Remove all configurable properties from obj. */
while (Shape *shape = LastConfigurableShape(obj)) {
RootedShape shape(cx);
while ((shape = LastConfigurableShape(obj))) {
if (!obj->removeProperty(cx, shape->propid()))
return;
}
/* Set all remaining writable plain data properties to undefined. */
for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) {
Shape *shape = &r.front();
UnrootedShape shape = &r.front();
if (shape->isDataDescriptor() &&
shape->writable() &&
shape->hasDefaultSetter() &&
shape->hasSlot()) {
shape->hasSlot())
{
obj->nativeSetSlot(shape->slot(), UndefinedValue());
}
}
@ -4556,7 +4558,7 @@ JS_Enumerate(JSContext *cx, JSObject *objArg)
* XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
* prop_iterator_class somehow...
* + preserve the obj->enumerate API while optimizing the native object case
* + native case here uses a Shape *, but that iterates in reverse!
* + native case here uses a JSShape *, but that iterates in reverse!
* + so we make non-native match, by reverse-iterating after JS_Enumerating
*/
const uint32_t JSSLOT_ITER_INDEX = 0;
@ -4588,7 +4590,7 @@ prop_iter_trace(JSTracer *trc, RawObject obj)
* barrier here because the pointer is updated via setPrivate, which
* always takes a barrier.
*/
Shape *tmp = (Shape *)pdata;
UnrootedShape tmp = static_cast<RawShape>(pdata);
MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
obj->setPrivateUnbarriered(tmp);
} else {
@ -4653,18 +4655,15 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp)
{
RootedObject iterobj(cx, iterobjArg);
AutoAssertNoGC nogc;
int32_t i;
Shape *shape;
JSIdArray *ida;
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, iterobj);
i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
int32_t i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
if (i < 0) {
/* Native case: private data is a property tree node pointer. */
JS_ASSERT(iterobj->getParent()->isNative());
shape = (Shape *) iterobj->getPrivate();
UnrootedShape shape = static_cast<RawShape>(iterobj->getPrivate());
while (shape->previous() && !shape->enumerable())
shape = shape->previous();
@ -4673,12 +4672,12 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp)
JS_ASSERT(shape->isEmptyShape());
*idp = JSID_VOID;
} else {
iterobj->setPrivateGCThing(const_cast<Shape *>(shape->previous().get()));
iterobj->setPrivateGCThing(const_cast<RawShape>(shape->previous().get()));
*idp = shape->propid();
}
} else {
/* Non-native case: use the ida enumerated when iterobj was created. */
ida = (JSIdArray *) iterobj->getPrivate();
JSIdArray *ida = (JSIdArray *) iterobj->getPrivate();
JS_ASSERT(i <= ida->length);
STATIC_ASSUME(i <= ida->length);
if (i == 0) {

View File

@ -206,14 +206,14 @@ js::StringIsArrayIndex(JSLinearString *str, uint32_t *indexp)
return false;
}
Shape *
UnrootedShape
js::GetDenseArrayShape(JSContext *cx, HandleObject globalObj)
{
JS_ASSERT(globalObj);
JSObject *proto = globalObj->global().getOrCreateArrayPrototype(cx);
if (!proto)
return NULL;
return UnrootedShape(NULL);
return EmptyShape::getInitialShape(cx, &ArrayClass, proto, proto->getParent(),
gc::FINALIZE_OBJECT0);
@ -265,7 +265,7 @@ JSObject::arrayGetOwnDataElement(JSContext *cx, size_t i, Value *vp)
if (!IndexToId(cx, i, &id))
return false;
Shape *shape = nativeLookup(cx, id);
UnrootedShape shape = nativeLookup(cx, id);
if (!shape || !shape->isDataDescriptor())
vp->setMagic(JS_ARRAY_HOLE);
else
@ -1254,7 +1254,7 @@ AddLengthProperty(JSContext *cx, HandleObject obj)
if (!obj->allocateSlowArrayElements(cx))
return false;
return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter,
return JSObject::addProperty(cx, obj, lengthId, array_length_getter, array_length_setter,
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0);
}
@ -1294,11 +1294,12 @@ JSObject::makeDenseArraySlow(JSContext *cx, HandleObject obj)
* on error. This is gross, but a better way is not obvious. Note: the
* exact contents of the array are not preserved on error.
*/
js::Shape *oldShape = obj->lastProperty();
RootedShape oldShape(cx, obj->lastProperty());
/* Create a native scope. */
{
gc::AllocKind kind = obj->getAllocKind();
Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, obj->getProto(),
UnrootedShape shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, obj->getProto(),
oldShape->getObjectParent(), kind);
if (!shape)
return false;
@ -1315,6 +1316,7 @@ JSObject::makeDenseArraySlow(JSContext *cx, HandleObject obj)
obj->prepareElementRangeForOverwrite(0, arrayInitialized);
obj->shape_ = shape;
}
/* Reset to an empty dense array. */
obj->elements = emptyObjectElements;

View File

@ -76,7 +76,7 @@ extern JSObject *
NewSlowEmptyArray(JSContext *cx);
/* Get the common shape used by all dense arrays with a prototype at globalObj. */
extern Shape *
extern UnrootedShape
GetDenseArrayShape(JSContext *cx, HandleObject globalObj);
extern JSBool

View File

@ -428,6 +428,7 @@ template<XDRMode mode>
bool
js::XDRAtom(XDRState<mode> *xdr, MutableHandleAtom atomp)
{
AssertCanGC();
if (mode == XDR_ENCODE) {
uint32_t nchars = atomp->length();
if (!xdr->codeUint32(&nchars))

View File

@ -573,7 +573,7 @@ js::ReportUsageError(JSContext *cx, HandleObject callee, const char *msg)
{
const char *usageStr = "usage";
PropertyName *usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName();
DebugOnly<Shape *> shape = callee->nativeLookup(cx, NameToId(usageAtom));
DebugOnly<RawShape> shape = static_cast<RawShape>(callee->nativeLookup(cx, NameToId(usageAtom)));
JS_ASSERT(!shape->configurable());
JS_ASSERT(!shape->writable());
JS_ASSERT(shape->hasDefaultGetter());

View File

@ -317,7 +317,7 @@ class NewObjectCache
inline void fillType(EntryIndex entry, Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, JSObject *obj);
/* Invalidate any entries which might produce an object with shape/proto. */
void invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto);
void invalidateEntriesForShape(JSContext *cx, HandleShape shape, HandleObject proto);
private:
inline bool lookup(Class *clasp, gc::Cell *key, gc::AllocKind kind, EntryIndex *pentry);

View File

@ -798,7 +798,7 @@ JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
/* This all should be reworked to avoid requiring JSScopeProperty types. */
static JSBool
GetPropertyDesc(JSContext *cx, JSObject *obj_, Shape *shape, JSPropertyDesc *pd)
GetPropertyDesc(JSContext *cx, JSObject *obj_, HandleShape shape, JSPropertyDesc *pd)
{
assertSameCompartment(cx, obj_);
pd->id = IdToJsval(shape->propid());
@ -901,7 +901,7 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj_, JSPropertyDescArray *pda)
goto bad;
if (!js_AddRoot(cx, &pd[i].value, NULL))
goto bad;
Shape *shape = const_cast<Shape *>(&r.front());
RootedShape shape(cx, const_cast<Shape *>(&r.front()));
if (!GetPropertyDesc(cx, obj, shape, &pd[i]))
goto bad;
if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))

View File

@ -256,7 +256,7 @@ JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props)
JS_FRIEND_API(void)
JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
{
MarkCycleCollectorChildren(trc, (Shape *)shape);
MarkCycleCollectorChildren(trc, static_cast<RawShape>(shape));
}
static bool
@ -905,7 +905,7 @@ js::IncrementalReferenceBarrier(void *ptr)
else if (kind == JSTRACE_SCRIPT)
JSScript::writeBarrierPre(reinterpret_cast<RawScript>(ptr));
else if (kind == JSTRACE_SHAPE)
Shape::writeBarrierPre((Shape *) ptr);
Shape::writeBarrierPre(reinterpret_cast<RawShape>(ptr));
else if (kind == JSTRACE_BASE_SHAPE)
BaseShape::writeBarrierPre(reinterpret_cast<RawBaseShape>(ptr));
else if (kind == JSTRACE_TYPE_OBJECT)

View File

@ -595,7 +595,7 @@ js_NewGCScript(JSContext *cx)
return js::gc::NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
}
inline js::Shape *
inline js::UnrootedShape
js_NewGCShape(JSContext *cx)
{
return js::gc::NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));

View File

@ -807,20 +807,22 @@ HeapTypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target)
}
/* If id is a normal slotful 'own' property of an object, get its shape. */
static inline Shape *
GetSingletonShape(JSContext *cx, HandleObject obj, jsid id)
static inline UnrootedShape
GetSingletonShape(JSContext *cx, RawObject obj, RawId id)
{
AssertCanGC();
if (!obj->isNative())
return NULL;
Shape *shape = obj->nativeLookup(cx, id);
return UnrootedShape(NULL);
UnrootedShape shape = DropUnrooted(obj)->nativeLookup(cx, DropUnrooted(id));
if (shape && shape->hasDefaultGetter() && shape->hasSlot())
return shape;
return NULL;
return UnrootedShape(NULL);
}
void
ScriptAnalysis::pruneTypeBarriers(JSContext *cx, uint32_t offset)
{
AssertCanGC();
TypeBarrier **pbarrier = &getCode(offset).typeBarriers;
while (*pbarrier) {
TypeBarrier *barrier = *pbarrier;
@ -831,8 +833,7 @@ ScriptAnalysis::pruneTypeBarriers(JSContext *cx, uint32_t offset)
}
if (barrier->singleton) {
JS_ASSERT(barrier->type.isPrimitive(JSVAL_TYPE_UNDEFINED));
RootedObject barrierSingleton(cx, barrier->singleton);
Shape *shape = GetSingletonShape(cx, barrierSingleton, barrier->singletonId);
UnrootedShape shape = GetSingletonShape(cx, barrier->singleton, barrier->singletonId);
if (shape && !barrier->singleton->nativeGetSlot(shape->slot()).isUndefined()) {
/*
* When we analyzed the script the singleton had an 'own'
@ -1674,6 +1675,7 @@ class TypeConstraintFreezeObjectFlags : public TypeConstraint
void newObjectState(JSContext *cx, TypeObject *object, bool force)
{
AutoAssertNoGC nogc;
if (!marked && (object->hasAnyFlags(flags) || (!flags && force))) {
marked = true;
cx->compartment->types.addPendingRecompile(cx, info);
@ -2548,6 +2550,7 @@ TypeCompartment::nukeTypes(FreeOp *fop)
void
TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
{
AutoAssertNoGC nogc;
CompilerOutput *co = info.compilerOutput(cx);
if (co->pendingRecompilation)
@ -3027,13 +3030,14 @@ struct types::ObjectTableKey
((uint32_t)obj->getTaggedProto().toWord() >> 2));
}
static inline bool match(const ObjectTableKey &v, JSObject *obj) {
static inline bool match(const ObjectTableKey &v, RawObject obj) {
if (obj->slotSpan() != v.nslots ||
obj->numFixedSlots() != v.nfixed ||
obj->getTaggedProto() != v.proto) {
return false;
}
Shape *shape = obj->lastProperty();
UnrootedShape shape = obj->lastProperty();
obj = NULL;
while (!shape->isEmptyShape()) {
if (shape->propid() != v.ids[shape->slot()])
return false;
@ -3075,7 +3079,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj)
return;
ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(obj.get());
Shape *baseShape = obj->lastProperty();
RootedShape baseShape(cx, obj->lastProperty());
if (p) {
/* The lookup ensures the shape matches, now check that the types match. */
@ -3086,7 +3090,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj)
if (NumberTypes(ntype, types[i])) {
if (types[i].isPrimitive(JSVAL_TYPE_INT32)) {
types[i] = Type::DoubleType();
Shape *shape = baseShape;
RootedShape shape(cx, baseShape);
while (!shape->isEmptyShape()) {
if (shape->slot() == i) {
Type type = Type::DoubleType();
@ -3127,7 +3131,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj)
return;
}
Shape *shape = baseShape;
RootedShape shape(cx, baseShape);
while (!shape->isEmptyShape()) {
ids[shape->slot()] = shape->propid();
types[shape->slot()] = GetValueTypeForTable(cx, obj->getSlot(shape->slot()));
@ -3194,7 +3198,7 @@ TypeObject::getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force
}
static inline void
UpdatePropertyType(JSContext *cx, TypeSet *types, HandleObject obj, Shape *shape, bool force)
UpdatePropertyType(JSContext *cx, TypeSet *types, RawObject obj, UnrootedShape shape, bool force)
{
types->setOwnProperty(cx, false);
if (!shape->writable())
@ -3239,14 +3243,14 @@ TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop)
RootedObject rSingleton(cx, singleton);
if (JSID_IS_VOID(id)) {
/* Go through all shapes on the object to get integer-valued properties. */
Shape *shape = singleton->lastProperty();
UnrootedShape shape = singleton->lastProperty();
while (!shape->isEmptyShape()) {
if (JSID_IS_VOID(MakeTypeId(cx, shape->propid())))
UpdatePropertyType(cx, &base->types, rSingleton, shape, true);
shape = shape->previous();
}
} else if (!JSID_IS_EMPTY(id) && singleton->isNative()) {
Shape *shape = singleton->nativeLookup(cx, id);
UnrootedShape shape = singleton->nativeLookup(cx, id);
if (shape)
UpdatePropertyType(cx, &base->types, rSingleton, shape, false);
}
@ -3278,7 +3282,7 @@ TypeObject::addDefiniteProperties(JSContext *cx, HandleObject obj)
/* Mark all properties of obj as definite properties of this type. */
AutoEnterTypeInference enter(cx);
Shape *shape = obj->lastProperty();
RootedShape shape(cx, obj->lastProperty());
while (!shape->isEmptyShape()) {
jsid id = MakeTypeId(cx, shape->propid());
if (!JSID_IS_VOID(id) && obj->isFixedSlot(shape->slot()) &&
@ -3306,7 +3310,7 @@ TypeObject::matchDefiniteProperties(HandleObject obj)
unsigned slot = prop->types.definiteSlot();
bool found = false;
Shape *shape = obj->lastProperty();
UnrootedShape shape = obj->lastProperty();
while (!shape->isEmptyShape()) {
if (shape->slot() == slot && shape->propid() == prop->id) {
found = true;
@ -3325,6 +3329,7 @@ TypeObject::matchDefiniteProperties(HandleObject obj)
inline void
InlineAddTypeProperty(JSContext *cx, TypeObject *obj, jsid id, Type type)
{
AssertCanGC();
JS_ASSERT(id == MakeTypeId(cx, id));
AutoEnterTypeInference enter(cx);
@ -3353,6 +3358,7 @@ TypeObject::addPropertyType(JSContext *cx, jsid id, const Value &value)
void
TypeObject::addPropertyType(JSContext *cx, const char *name, Type type)
{
AssertCanGC();
jsid id = JSID_VOID;
if (name) {
JSAtom *atom = Atomize(cx, name, strlen(name));
@ -3387,6 +3393,8 @@ TypeObject::markPropertyConfigured(JSContext *cx, jsid id)
void
TypeObject::markStateChange(JSContext *cx)
{
AutoAssertNoGC nogc;
if (unknownProperties())
return;
@ -5020,6 +5028,8 @@ CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, JSFunction *fun)
return;
}
AutoAssertNoGC nogc;
type->newScript->fun = fun;
type->newScript->allocKind = kind;
type->newScript->shape = baseobj->lastProperty();
@ -5828,6 +5838,7 @@ JSObject::setNewTypeUnknown(JSContext *cx)
TypeObject *
JSCompartment::getNewType(JSContext *cx, TaggedProto proto_, JSFunction *fun_, bool isDOM)
{
AssertCanGC();
JS_ASSERT_IF(fun_, proto_.isObject());
JS_ASSERT_IF(proto_.isObject(), cx->compartment == proto_.toObject()->compartment());

View File

@ -275,6 +275,7 @@ TypeFlagPrimitive(TypeFlags flags)
inline jsid
MakeTypeId(JSContext *cx, jsid id)
{
AutoAssertNoGC nogc;
JS_ASSERT(!JSID_IS_EMPTY(id));
/*
@ -546,6 +547,8 @@ TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
inline bool
TrackPropertyTypes(JSContext *cx, HandleObject obj, jsid id)
{
AutoAssertNoGC nogc;
if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
return false;
@ -559,6 +562,7 @@ TrackPropertyTypes(JSContext *cx, HandleObject obj, jsid id)
inline void
AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, Type type)
{
AssertCanGC();
if (cx->typeInferenceEnabled())
id = MakeTypeId(cx, id);
if (TrackPropertyTypes(cx, obj, id))
@ -568,6 +572,7 @@ AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, Type type)
inline void
AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, const Value &value)
{
AssertCanGC();
if (cx->typeInferenceEnabled())
id = MakeTypeId(cx, id);
if (TrackPropertyTypes(cx, obj, id))
@ -577,6 +582,7 @@ AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, const Value &value)
inline void
AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type)
{
AssertCanGC();
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
obj->addPropertyType(cx, name, type);
}
@ -584,6 +590,7 @@ AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type)
inline void
AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value)
{
AssertCanGC();
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
obj->addPropertyType(cx, name, value);
}
@ -629,8 +636,9 @@ MarkTypePropertyConfigured(JSContext *cx, HandleObject obj, jsid id)
/* Mark a state change on a particular object. */
inline void
MarkObjectStateChange(JSContext *cx, HandleObject obj)
MarkObjectStateChange(JSContext *cx, RawObject obj)
{
AutoAssertNoGC nogc;
if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
obj->type()->markStateChange(cx);
}
@ -1565,6 +1573,7 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool own)
inline HeapTypeSet *
TypeObject::maybeGetProperty(JSContext *cx, jsid id)
{
AutoAssertNoGC nogc;
JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
JS_ASSERT(!unknownProperties());

View File

@ -174,15 +174,16 @@ ValuePropertyBearer(JSContext *cx, StackFrame *fp, HandleValue v, int spindex)
}
inline bool
NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shape,
NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shapeArg,
unsigned getHow, MutableHandleValue vp)
{
if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
if (shapeArg->isDataDescriptor() && shapeArg->hasDefaultGetter()) {
/* Fast path for Object instance properties. */
JS_ASSERT(shape->hasSlot());
vp.set(pobj->nativeGetSlot(shape->slot()));
JS_ASSERT(shapeArg->hasSlot());
vp.set(pobj->nativeGetSlot(shapeArg->slot()));
} else {
if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp.address()))
RootedShape shape(cx, shapeArg);
if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))
return false;
}
return true;

View File

@ -431,8 +431,8 @@ NativeIterator::allocateIterator(JSContext *cx, uint32_t slength, const AutoIdVe
size_t plength = props.length();
NativeIterator *ni = (NativeIterator *)
cx->malloc_(sizeof(NativeIterator)
+ plength * sizeof(JSString *)
+ slength * sizeof(Shape *));
+ plength * sizeof(RawString)
+ slength * sizeof(RawShape));
if (!ni)
return NULL;
AutoValueVector strings(cx);
@ -602,7 +602,7 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa
return true;
}
Vector<Shape *, 8> shapes(cx);
Vector<RawShape, 8> shapes(cx);
uint32_t key = 0;
bool keysOnly = (flags == JSITER_ENUMERATE);
@ -651,6 +651,7 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa
* currently active.
*/
{
AutoAssertNoGC nogc;
RawObject pobj = obj;
do {
if (!pobj->isNative() ||
@ -660,9 +661,9 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa
shapes.clear();
goto miss;
}
Shape *shape = pobj->lastProperty();
RawShape shape = pobj->lastProperty();
key = (key + (key << 16)) ^ (uintptr_t(shape) >> 3);
if (!shapes.append((Shape *) shape))
if (!shapes.append(shape))
return false;
pobj = pobj->getProto();
} while (pobj);

View File

@ -197,7 +197,7 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
}
case JSTRACE_SHAPE:
{
Shape *shape = static_cast<Shape*>(thing);
UnrootedShape shape = static_cast<RawShape>(thing);
size_t propTableSize, kidsSize;
shape->sizeOfExcludingThis(rtStats->mallocSizeOf, &propTableSize, &kidsSize);
if (shape->inDictionary()) {

View File

@ -1348,7 +1348,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
}
if (!js_NativeGet(cx, obj, obj2, shape, 0, v.address()))
if (!js_NativeGet(cx, obj, obj2, shape, 0, &v))
return JS_FALSE;
}
@ -1880,11 +1880,11 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it)
* generic path below then any non-empty object will be converted to
* dictionary mode.
*/
Shape *last = EmptyShape::getInitialShape(cx, obj->getClass(),
RootedShape last(cx, EmptyShape::getInitialShape(cx, obj->getClass(),
obj->getTaggedProto(),
obj->getParent(),
obj->getAllocKind(),
obj->lastProperty()->getObjectFlags());
obj->lastProperty()->getObjectFlags()));
if (!last)
return false;
@ -2113,6 +2113,7 @@ static inline JSObject *
NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *parent,
gc::AllocKind kind)
{
AssertCanGC();
JS_ASSERT(clasp != &ArrayClass);
JS_ASSERT_IF(clasp == &FunctionClass,
kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
@ -2291,15 +2292,17 @@ js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
/* Get all the ids in the object, in order. */
js::AutoIdVector ids(cx);
{
for (unsigned i = 0; i <= shape->slot(); i++) {
if (!ids.append(JSID_VOID))
return NULL;
}
js::Shape *nshape = shape;
UnrootedShape nshape = shape;
while (!nshape->isEmptyShape()) {
ids[nshape->slot()] = nshape->propid();
nshape = nshape->previous();
}
}
/* Construct the new shape. */
RootedId id(cx);
@ -2340,9 +2343,10 @@ CreateThisForFunctionWithType(JSContext *cx, HandleTypeObject type, JSObject *pa
*/
gc::AllocKind kind = type->newScript->allocKind;
RootedObject res(cx, NewObjectWithType(cx, type, parent, kind));
if (res)
JS_ALWAYS_TRUE(JSObject::setLastProperty(cx, res,
(Shape *) type->newScript->shape.get()));
if (res) {
RootedShape shape(cx, type->newScript->shape);
JS_ALWAYS_TRUE(JSObject::setLastProperty(cx, res, shape));
}
return res;
}
@ -2550,9 +2554,12 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *obj)
return false;
}
RootedShape shape(cx);
RootedValue v(cx);
RootedId id(cx);
size_t n = shapes.length();
while (n > 0) {
Shape *shape = shapes[--n];
shape = shapes[--n];
unsigned attrs = shape->attributes();
PropertyOp getter = shape->getter();
StrictPropertyOp setter = shape->setter();
@ -2561,10 +2568,10 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *obj)
return false;
if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter))
return false;
RootedValue v(cx, shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue());
v = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue();
if (!cx->compartment->wrap(cx, v.address()))
return false;
Rooted<jsid> id(cx, shape->propid());
id = shape->propid();
if (!JSObject::defineGeneric(cx, target, id, v, getter, setter, attrs))
return false;
}
@ -2648,15 +2655,15 @@ struct JSObject::TradeGutsReserved {
Vector<Value> bvals;
int newafixed;
int newbfixed;
Shape *newashape;
Shape *newbshape;
RootedShape newashape;
RootedShape newbshape;
HeapSlot *newaslots;
HeapSlot *newbslots;
TradeGutsReserved(JSContext *cx)
: avals(cx), bvals(cx),
newafixed(0), newbfixed(0),
newashape(NULL), newbshape(NULL),
newashape(cx), newbshape(cx),
newaslots(NULL), newbslots(NULL)
{}
@ -2673,6 +2680,7 @@ bool
JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
TradeGutsReserved &reserved)
{
AssertCanGC();
JS_ASSERT(a->compartment() == b->compartment());
AutoCompartment ac(cx, a);
@ -2782,6 +2790,7 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
void
JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved)
{
AutoAssertNoGC nogc;
JS_ASSERT(a->compartment() == b->compartment());
JS_ASSERT(a->isFunction() == b->isFunction());
@ -2956,11 +2965,10 @@ DefineStandardSlot(JSContext *cx, HandleObject obj, JSProtoKey key, JSAtom *atom
JS_ASSERT(obj->isGlobal());
JS_ASSERT(obj->isNative());
Shape *shape = obj->nativeLookup(cx, id);
if (!shape) {
if (!obj->nativeLookup(cx, id)) {
uint32_t slot = 2 * JSProto_LIMIT + key;
obj->setReservedSlot(slot, v);
if (!obj->addProperty(cx, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0))
if (!JSObject::addProperty(cx, obj, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0))
return false;
AddTypePropertyId(cx, obj, id, v);
@ -3234,7 +3242,7 @@ JSObject::updateSlotsForSpan(JSContext *cx, HandleObject obj, size_t oldSpan, si
}
/* static */ bool
JSObject::setLastProperty(JSContext *cx, HandleObject obj, js::Shape *shape)
JSObject::setLastProperty(JSContext *cx, HandleObject obj, HandleShape shape)
{
JS_ASSERT(!obj->inDictionaryMode());
JS_ASSERT(!shape->inDictionary());
@ -3689,31 +3697,32 @@ js_FindClassObject(JSContext *cx, JSProtoKey protoKey, MutableHandleValue vp, Cl
return true;
}
bool
JSObject::allocSlot(JSContext *cx, uint32_t *slotp)
/* static */ bool
JSObject::allocSlot(JSContext *cx, HandleObject obj, uint32_t *slotp)
{
uint32_t slot = slotSpan();
JS_ASSERT(slot >= JSSLOT_FREE(getClass()));
AssertCanGC();
uint32_t slot = obj->slotSpan();
JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
/*
* If this object is in dictionary mode, try to pull a free slot from the
* shape table's slot-number freelist.
*/
if (inDictionaryMode()) {
ShapeTable &table = lastProperty()->table();
if (obj->inDictionaryMode()) {
ShapeTable &table = obj->lastProperty()->table();
uint32_t last = table.freelist;
if (last != SHAPE_INVALID_SLOT) {
#ifdef DEBUG
JS_ASSERT(last < slot);
uint32_t next = getSlot(last).toPrivateUint32();
uint32_t next = obj->getSlot(last).toPrivateUint32();
JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
#endif
*slotp = last;
const Value &vref = getSlot(last);
const Value &vref = obj->getSlot(last);
table.freelist = vref.toPrivateUint32();
setSlot(last, UndefinedValue());
obj->setSlot(last, UndefinedValue());
return true;
}
}
@ -3725,8 +3734,7 @@ JSObject::allocSlot(JSContext *cx, uint32_t *slotp)
*slotp = slot;
RootedObject self(cx, this);
if (inDictionaryMode() && !setSlotSpan(cx, self, slot + 1))
if (obj->inDictionaryMode() && !setSlotSpan(cx, obj, slot + 1))
return false;
return true;
@ -3758,13 +3766,12 @@ JSObject::freeSlot(uint32_t slot)
}
static bool
PurgeProtoChain(JSContext *cx, JSObject *obj_, jsid id_)
PurgeProtoChain(JSContext *cx, RawObject objArg, HandleId id)
{
Shape *shape;
RootedObject obj(cx, obj_);
RootedId id(cx, id_);
/* Root locally so we can re-assign. */
RootedObject obj(cx, objArg);
RootedShape shape(cx);
while (obj) {
/* Lookups will not be cached through non-native protos. */
if (!obj->isNative())
@ -3785,10 +3792,10 @@ PurgeProtoChain(JSContext *cx, JSObject *obj_, jsid id_)
}
bool
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj_, jsid id_)
js_PurgeScopeChainHelper(JSContext *cx, HandleObject objArg, HandleId id)
{
RootedObject obj(cx, obj_);
RootedId id(cx, id_);
/* Re-root locally so we can re-assign. */
RootedObject obj(cx, objArg);
JS_ASSERT(obj->isNative());
JS_ASSERT(obj->isDelegate());
@ -3810,29 +3817,27 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj_, jsid id_)
return true;
}
Shape *
js_AddNativeProperty(JSContext *cx, HandleObject obj, jsid id_,
UnrootedShape
js_AddNativeProperty(JSContext *cx, HandleObject obj, HandleId id,
PropertyOp getter, StrictPropertyOp setter, uint32_t slot,
unsigned attrs, unsigned flags, int shortid)
{
RootedId id(cx, id_);
/*
* Purge the property cache of now-shadowed id in obj's scope chain. Do
* this optimistically (assuming no failure below) before locking obj, so
* we can lock the shadowed scope.
*/
if (!js_PurgeScopeChain(cx, obj, id))
return NULL;
return UnrootedShape(NULL);
return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
return JSObject::putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid);
}
JSBool
baseops::DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0);
return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0);
}
JSBool
@ -3842,7 +3847,7 @@ baseops::DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleVa
Rooted<jsid> id(cx);
if (index <= JSID_INT_MAX) {
id = INT_TO_JSID(index);
return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0);
return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0);
}
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
@ -3850,7 +3855,7 @@ baseops::DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleVa
if (!IndexToId(cx, index, id.address()))
return false;
return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0);
return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0);
}
/*
@ -3878,7 +3883,7 @@ CallAddPropertyHook(JSContext *cx, Class *clasp, HandleObject obj, HandleShape s
return true;
}
Shape *
bool
js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
unsigned flags, int shortid, unsigned defineHow /* = 0 */)
@ -3908,7 +3913,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
RootedObject pobj(cx);
RootedShape prop(cx);
if (!baseops::LookupProperty(cx, obj, id, &pobj, &prop))
return NULL;
return false;
if (prop && pobj == obj) {
shape = prop;
if (shape->isAccessorDescriptor()) {
@ -3921,7 +3926,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
? setter
: shape->setter());
if (!shape)
return NULL;
return false;
} else {
shape = NULL;
}
@ -3935,7 +3940,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
*/
if (!(defineHow & DNP_DONT_PURGE)) {
if (!js_PurgeScopeChain(cx, obj, id))
return NULL;
return false;
}
/* Use the object's class getter and setter by default. */
@ -3956,10 +3961,10 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
}
if (!shape) {
shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
shape = JSObject::putProperty(cx, obj, id, getter, setter, SHAPE_INVALID_SLOT,
attrs, flags, shortid);
if (!shape)
return NULL;
return false;
}
/* Store valueCopy before calling addProperty, in case the latter GC's. */
@ -3968,7 +3973,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
if (!CallAddPropertyHook(cx, clasp, obj, shape, value)) {
obj->removeProperty(cx, id);
return NULL;
return false;
}
return shape;
@ -4051,7 +4056,7 @@ CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
objp.set(obj);
}
Shape *shape;
UnrootedShape shape;
if (!objp->nativeEmpty() && (shape = objp->nativeLookup(cx, id)))
propp.set(shape);
else
@ -4067,12 +4072,14 @@ LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsi
/* Search scopes starting with obj and following the prototype link. */
RootedObject current(cx, obj);
while (true) {
Shape *shape = current->nativeLookup(cx, id);
{
UnrootedShape shape = current->nativeLookup(cx, id);
if (shape) {
objp.set(current);
propp.set(shape);
return true;
}
}
/* Try obj's class resolve hook if id was not found in obj's scope. */
if (current->getClass()->resolve != JS_ResolveStub) {
@ -4177,18 +4184,19 @@ js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleOb
}
static JS_ALWAYS_INLINE JSBool
js_NativeGetInline(JSContext *cx, Handle<JSObject*> receiver, JSObject *obj, JSObject *pobj,
Shape *shape, unsigned getHow, Value *vp)
js_NativeGetInline(JSContext *cx, Handle<JSObject*> receiver, Handle<JSObject*> obj,
Handle<JSObject*> pobj, Handle<Shape*> shape, unsigned getHow,
MutableHandle<Value> vp)
{
JS_ASSERT(pobj->isNative());
if (shape->hasSlot()) {
*vp = pobj->nativeGetSlot(shape->slot());
JS_ASSERT(!vp->isMagic());
vp.set(pobj->nativeGetSlot(shape->slot()));
JS_ASSERT(!vp.isMagic());
JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetter(),
js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), *vp));
js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp));
} else {
vp->setUndefined();
vp.setUndefined();
}
if (shape->hasDefaultGetter())
return true;
@ -4201,24 +4209,19 @@ js_NativeGetInline(JSContext *cx, Handle<JSObject*> receiver, JSObject *obj, JSO
code->accessGetter = true;
}
Rooted<Shape*> shapeRoot(cx, shape);
RootedObject pobjRoot(cx, pobj);
RootedValue nvp(cx, *vp);
if (!shape->get(cx, receiver, obj, pobj, &nvp))
if (!shape->get(cx, receiver, obj, pobj, vp))
return false;
/* Update slotful shapes according to the value produced by the getter. */
if (shapeRoot->hasSlot() && pobjRoot->nativeContains(cx, shapeRoot))
pobjRoot->nativeSetSlot(shapeRoot->slot(), nvp);
if (shape->hasSlot() && pobj->nativeContains(cx, shape))
pobj->nativeSetSlot(shape->slot(), vp);
*vp = nvp;
return true;
}
JSBool
js_NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shape,
unsigned getHow, Value *vp)
js_NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Handle<Shape*> shape,
unsigned getHow, MutableHandle<Value> vp)
{
return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp);
}
@ -4358,7 +4361,7 @@ js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receive
cx->propertyCache().fill(cx, obj, obj2, shape);
/* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp.address()))
if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp))
return JS_FALSE;
return JS_TRUE;
@ -4638,7 +4641,7 @@ baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receive
if (!js_PurgeScopeChain(cx, obj, id))
return JS_FALSE;
shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
shape = JSObject::putProperty(cx, obj, id, getter, setter, SHAPE_INVALID_SLOT,
attrs, flags, shortid);
if (!shape)
return JS_FALSE;
@ -4809,7 +4812,7 @@ baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
bool
js::HasDataProperty(JSContext *cx, HandleObject obj, jsid id, Value *vp)
{
if (Shape *shape = obj->nativeLookup(cx, id)) {
if (UnrootedShape shape = obj->nativeLookup(cx, id)) {
if (shape->hasDefaultGetter() && shape->hasSlot()) {
*vp = obj->nativeGetSlot(shape->slot());
return true;
@ -5158,7 +5161,7 @@ js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
JSObject *obj = (JSObject *)trc->debugPrintArg;
uint32_t slot = uint32_t(trc->debugPrintIndex);
Shape *shape;
UnrootedShape shape;
if (obj->isNative()) {
shape = obj->lastProperty();
while (shape && (!shape->hasSlot() || shape->slot() != slot))
@ -5295,7 +5298,7 @@ DumpProperty(JSObject *obj, Shape &shape)
jsid id = shape.propid();
uint8_t attrs = shape.attributes();
fprintf(stderr, " ((Shape *) %p) ", (void *) &shape);
fprintf(stderr, " ((JSShape *) %p) ", (void *) &shape);
if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
@ -5396,7 +5399,7 @@ JSObject::dump()
if (obj->isNative()) {
fprintf(stderr, "properties:\n");
Vector<Shape *, 8, SystemAllocPolicy> props;
Vector<RawShape, 8, SystemAllocPolicy> props;
for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront())
props.append(&r.front());
for (size_t i = props.length(); i-- != 0;)

View File

@ -21,9 +21,6 @@
#include "jsclass.h"
#include "jsfriendapi.h"
#include "jsinfer.h"
#include "jspubtd.h"
#include "jsprvtd.h"
#include "jslock.h"
#include "gc/Barrier.h"
#include "gc/Heap.h"
@ -38,6 +35,8 @@ class BaseProxyHandler;
class CallObject;
struct GCMarker;
struct NativeIterator;
ForwardDeclare(Shape);
struct StackShape;
namespace mjit { class Compiler; }
@ -280,10 +279,10 @@ struct JSObject : public js::ObjectImpl
* Update the last property, keeping the number of allocated slots in sync
* with the object's new slot span.
*/
static bool setLastProperty(JSContext *cx, js::HandleObject obj, js::Shape *shape);
static bool setLastProperty(JSContext *cx, JS::HandleObject obj, js::HandleShape shape);
/* As above, but does not change the slot span. */
inline void setLastPropertyInfallible(js::Shape *shape);
inline void setLastPropertyInfallible(js::UnrootedShape shape);
/* Make a non-array object with the specified initial state. */
static inline JSObject *create(JSContext *cx,
@ -726,7 +725,7 @@ struct JSObject : public js::ObjectImpl
* after calling object-parameter-free shape methods, avoiding coupling
* logic across the object vs. shape module wall.
*/
bool allocSlot(JSContext *cx, uint32_t *slotp);
static bool allocSlot(JSContext *cx, JS::HandleObject obj, uint32_t *slotp);
void freeSlot(uint32_t slot);
public:
@ -744,7 +743,8 @@ struct JSObject : public js::ObjectImpl
js::MutableHandleValue vp);
private:
js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::StackShape &child);
static js::UnrootedShape getChildProperty(JSContext *cx, JS::HandleObject obj,
js::HandleShape parent, js::StackShape &child);
protected:
/*
@ -754,7 +754,8 @@ struct JSObject : public js::ObjectImpl
* 1. getter and setter must be normalized based on flags (see jsscope.cpp).
* 2. !isExtensible() checking must be done by callers.
*/
js::Shape *addPropertyInternal(JSContext *cx, jsid id,
static js::UnrootedShape addPropertyInternal(JSContext *cx,
JS::HandleObject obj, JS::HandleId id,
JSPropertyOp getter, JSStrictPropertyOp setter,
uint32_t slot, unsigned attrs,
unsigned flags, int shortid, js::Shape **spp,
@ -772,32 +773,37 @@ struct JSObject : public js::ObjectImpl
public:
/* Add a property whose id is not yet in this scope. */
js::Shape *addProperty(JSContext *cx, jsid id,
static js::UnrootedShape addProperty(JSContext *cx, JS::HandleObject, JS::HandleId id,
JSPropertyOp getter, JSStrictPropertyOp setter,
uint32_t slot, unsigned attrs,
unsigned flags, int shortid, bool allowDictionary = true);
uint32_t slot, unsigned attrs, unsigned flags,
int shortid, bool allowDictionary = true);
/* Add a data property whose id is not yet in this scope. */
js::Shape *addDataProperty(JSContext *cx, jsid id, uint32_t slot, unsigned attrs) {
js::UnrootedShape addDataProperty(JSContext *cx, jsid id_, uint32_t slot, unsigned attrs) {
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
return addProperty(cx, id, NULL, NULL, slot, attrs, 0, 0);
js::RootedObject self(cx, this);
js::RootedId id(cx, id_);
return addProperty(cx, self, id, NULL, NULL, slot, attrs, 0, 0);
}
/* Add or overwrite a property for id in this scope. */
js::Shape *putProperty(JSContext *cx, jsid id,
static js::UnrootedShape putProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JSPropertyOp getter, JSStrictPropertyOp setter,
uint32_t slot, unsigned attrs,
unsigned flags, int shortid);
inline js::Shape *
putProperty(JSContext *cx, js::PropertyName *name,
static js::UnrootedShape putProperty(JSContext *cx, JS::HandleObject obj,
js::PropertyName *name,
JSPropertyOp getter, JSStrictPropertyOp setter,
uint32_t slot, unsigned attrs, unsigned flags, int shortid) {
return putProperty(cx, js::NameToId(name), getter, setter, slot, attrs, flags, shortid);
uint32_t slot, unsigned attrs,
unsigned flags, int shortid)
{
js::RootedId id(cx, js::NameToId(name));
return putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid);
}
/* Change the given property into a sibling with the same id in this scope. */
static js::Shape *changeProperty(JSContext *cx, js::HandleObject obj,
js::Shape *shape, unsigned attrs, unsigned mask,
static js::UnrootedShape changeProperty(JSContext *cx, js::HandleObject obj,
js::RawShape shape, unsigned attrs, unsigned mask,
JSPropertyOp getter, JSStrictPropertyOp setter);
static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj,
@ -1176,14 +1182,14 @@ js_CreateThis(JSContext *cx, js::Class *clasp, js::HandleObject callee);
* Find or create a property named by id in obj's scope, with the given getter
* and setter, slot, attributes, and other members.
*/
extern js::Shape *
js_AddNativeProperty(JSContext *cx, js::HandleObject obj, jsid id,
extern js::UnrootedShape
js_AddNativeProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot,
unsigned attrs, unsigned flags, int shortid);
extern JSBool
js_DefineOwnProperty(JSContext *cx, js::HandleObject obj, js::HandleId id,
const js::Value &descriptor, JSBool *bp);
js_DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
const JS::Value &descriptor, JSBool *bp);
namespace js {
@ -1203,12 +1209,12 @@ const unsigned DNP_SKIP_TYPE = 8; /* Don't update type information */
/*
* Return successfully added or changed shape or NULL on error.
*/
extern Shape *
extern bool
DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
unsigned flags, int shortid, unsigned defineHow = 0);
inline Shape *
inline bool
DefineNativeProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
unsigned flags, int shortid, unsigned defineHow = 0)
@ -1292,7 +1298,7 @@ const unsigned JSGET_CACHE_RESULT = 1; // from a caching interpreter opcode
*/
extern JSBool
js_NativeGet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> pobj,
js::Shape *shape, unsigned getHow, js::Value *vp);
js::Handle<js::Shape*> shape, unsigned getHow, js::MutableHandle<js::Value> vp);
extern JSBool
js_NativeSet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> receiver,

View File

@ -272,7 +272,7 @@ JSObject::dynamicSlotIndex(size_t slot)
}
inline void
JSObject::setLastPropertyInfallible(js::Shape *shape)
JSObject::setLastPropertyInfallible(js::UnrootedShape shape)
{
JS_ASSERT(!shape->inDictionary());
JS_ASSERT(shape->compartment() == compartment());
@ -288,7 +288,8 @@ JSObject::removeLastProperty(JSContext *cx)
{
JS_ASSERT(canRemoveLastProperty());
js::RootedObject self(cx, this);
JS_ALWAYS_TRUE(setLastProperty(cx, self, lastProperty()->previous()));
js::RootedShape prev(cx, lastProperty()->previous());
JS_ALWAYS_TRUE(setLastProperty(cx, self, prev));
}
inline bool
@ -302,7 +303,7 @@ JSObject::canRemoveLastProperty()
* converted to dictionary mode instead. See BaseShape comment in jsscope.h
*/
JS_ASSERT(!inDictionaryMode());
js::Shape *previous = lastProperty()->previous();
js::UnrootedShape previous = lastProperty()->previous().get();
return previous->getObjectParent() == lastProperty()->getObjectParent()
&& previous->getObjectFlags() == lastProperty()->getObjectFlags();
}
@ -1522,7 +1523,8 @@ CopyInitializerObject(JSContext *cx, HandleObject baseobj)
if (!obj)
return NULL;
if (!JSObject::setLastProperty(cx, obj, baseobj->lastProperty()))
RootedShape lastProp(cx, baseobj->lastProperty());
if (!JSObject::setLastProperty(cx, obj, lastProp))
return NULL;
return obj;
@ -1558,7 +1560,7 @@ GuessArrayGCKind(size_t numSlots)
* may or may not need dynamic slots.
*/
inline bool
PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapSlot **slots)
PreallocateObjectDynamicSlots(JSContext *cx, UnrootedShape shape, HeapSlot **slots)
{
if (size_t count = JSObject::dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan())) {
*slots = cx->pod_malloc<HeapSlot>(count);
@ -1673,10 +1675,10 @@ js_InitClass(JSContext *cx, js::HandleObject obj, JSObject *parent_proto,
* (i.e., obj has ever been on a prototype or parent chain).
*/
extern bool
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
js_PurgeScopeChainHelper(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
inline bool
js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
js_PurgeScopeChain(JSContext *cx, JS::HandleObject obj, JS::HandleId id)
{
if (obj->isDelegate())
return js_PurgeScopeChainHelper(cx, obj, id);

View File

@ -35,7 +35,7 @@ js::PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj,
JS_ASSERT(this == &cx->propertyCache());
Shape *kshape = obj->lastProperty();
UnrootedShape kshape = obj->lastProperty();
entry = &table[hash(pc, kshape)];
PCMETER(pctestentry = entry);
PCMETER(tests++);
@ -64,9 +64,11 @@ JS_ALWAYS_INLINE bool
js::PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj,
PropertyCacheEntry **entryp, JSObject **obj2p, PropertyName **namep)
{
AutoAssertNoGC nogc;
JS_ASSERT(this == &cx->propertyCache());
Shape *kshape = obj->lastProperty();
UnrootedShape kshape = obj->lastProperty();
PropertyCacheEntry *entry = &table[hash(pc, kshape)];
*entryp = entry;
PCMETER(pctestentry = entry);

View File

@ -30,19 +30,17 @@ ShapeHasher::match(const Key k, const Lookup &l)
return k->matches(l);
}
Shape *
UnrootedShape
PropertyTree::newShape(JSContext *cx)
{
Shape *shape = js_NewGCShape(cx);
if (!shape) {
UnrootedShape shape = js_NewGCShape(cx);
if (!shape)
JS_ReportOutOfMemory(cx);
return NULL;
}
return shape;
}
static KidsHash *
HashChildren(Shape *kid1, Shape *kid2)
HashChildren(UnrootedShape kid1, UnrootedShape kid2)
{
KidsHash *hash = js_new<KidsHash>();
if (!hash || !hash->init(2)) {
@ -56,7 +54,7 @@ HashChildren(Shape *kid1, Shape *kid2)
}
bool
PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child)
PropertyTree::insertChild(JSContext *cx, UnrootedShape parent, UnrootedShape child)
{
JS_ASSERT(!parent->inDictionary());
JS_ASSERT(!child->parent);
@ -73,7 +71,7 @@ PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child)
}
if (kidp->isShape()) {
Shape *shape = kidp->toShape();
UnrootedShape shape = kidp->toShape();
JS_ASSERT(shape != child);
JS_ASSERT(!shape->matches(child));
@ -97,7 +95,7 @@ PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child)
}
void
Shape::removeChild(Shape *child)
Shape::removeChild(UnrootedShape child)
{
JS_ASSERT(!child->inDictionary());
JS_ASSERT(child->parent == this);
@ -127,12 +125,13 @@ Shape::removeChild(Shape *child)
}
}
Shape *
UnrootedShape
PropertyTree::getChild(JSContext *cx, Shape *parent_, uint32_t nfixed, const StackShape &child)
{
AssertCanGC();
Shape *shape = NULL;
{
UnrootedShape shape = NULL;
JS_ASSERT(parent_);
@ -146,7 +145,7 @@ PropertyTree::getChild(JSContext *cx, Shape *parent_, uint32_t nfixed, const Sta
*/
KidsPointer *kidp = &parent_->kids;
if (kidp->isShape()) {
Shape *kid = kidp->toShape();
UnrootedShape kid = kidp->toShape();
if (kid->matches(child))
shape = kid;
} else if (kidp->isHash()) {
@ -183,18 +182,19 @@ PropertyTree::getChild(JSContext *cx, Shape *parent_, uint32_t nfixed, const Sta
if (shape)
return shape;
}
StackShape::AutoRooter childRoot(cx, &child);
RootedShape parent(cx, parent_);
shape = newShape(cx);
UnrootedShape shape = newShape(cx);
if (!shape)
return NULL;
return UnrootedShape(NULL);
new (shape) Shape(child, nfixed);
if (!insertChild(cx, parent, shape))
return NULL;
return UnrootedShape(NULL);
return shape;
}
@ -236,7 +236,7 @@ Shape::finalize(FreeOp *fop)
#ifdef DEBUG
void
KidsPointer::checkConsistency(Shape *aKid) const
KidsPointer::checkConsistency(UnrootedShape aKid) const
{
if (isShape()) {
JS_ASSERT(toShape() == aKid);
@ -323,13 +323,13 @@ Shape::dumpSubtree(JSContext *cx, int level, FILE *fp) const
if (!kids.isNull()) {
++level;
if (kids.isShape()) {
Shape *kid = kids.toShape();
UnrootedShape kid = kids.toShape();
JS_ASSERT(kid->parent == this);
kid->dumpSubtree(cx, level, fp);
} else {
const KidsHash &hash = *kids.toHash();
for (KidsHash::Range range = hash.all(); !range.empty(); range.popFront()) {
Shape *kid = range.front();
RawShape kid = range.front();
JS_ASSERT(kid->parent == this);
kid->dumpSubtree(cx, level, fp);
@ -363,7 +363,7 @@ js::PropertyTree::dumpShapes(JSRuntime *rt)
typedef JSCompartment::EmptyShapeSet HS;
HS &h = c->emptyShapes;
for (HS::Range r = h.all(); !r.empty(); r.popFront()) {
Shape *empty = r.front();
RawShape empty = r.front();
empty->dumpSubtree(rt, 0, dumpfp);
putc('\n', dumpfp);
}

View File

@ -7,21 +7,22 @@
#ifndef jspropertytree_h___
#define jspropertytree_h___
#include "jsprvtd.h"
#include "js/HashTable.h"
namespace js {
ForwardDeclare(Shape);
struct StackShape;
struct ShapeHasher {
typedef js::Shape *Key;
typedef js::StackShape Lookup;
typedef RawShape Key;
typedef StackShape Lookup;
static inline HashNumber hash(const Lookup &l);
static inline bool match(Key k, const Lookup &l);
};
typedef HashSet<js::Shape *, ShapeHasher, SystemAllocPolicy> KidsHash;
typedef HashSet<RawShape, ShapeHasher, SystemAllocPolicy> KidsHash;
class KidsPointer {
private:
@ -38,14 +39,14 @@ class KidsPointer {
void setNull() { w = 0; }
bool isShape() const { return (w & TAG) == SHAPE && !isNull(); }
js::Shape *toShape() const {
UnrootedShape toShape() const {
JS_ASSERT(isShape());
return reinterpret_cast<js::Shape *>(w & ~uintptr_t(TAG));
return reinterpret_cast<RawShape>(w & ~uintptr_t(TAG));
}
void setShape(js::Shape *shape) {
void setShape(UnrootedShape shape) {
JS_ASSERT(shape);
JS_ASSERT((reinterpret_cast<uintptr_t>(shape) & TAG) == 0);
w = reinterpret_cast<uintptr_t>(shape) | SHAPE;
JS_ASSERT((reinterpret_cast<uintptr_t>(static_cast<RawShape>(shape)) & TAG) == 0);
w = reinterpret_cast<uintptr_t>(static_cast<RawShape>(shape)) | SHAPE;
}
bool isHash() const { return (w & TAG) == HASH; }
@ -60,7 +61,7 @@ class KidsPointer {
}
#ifdef DEBUG
void checkConsistency(js::Shape *aKid) const;
void checkConsistency(UnrootedShape aKid) const;
#endif
};
@ -70,7 +71,7 @@ class PropertyTree
JSCompartment *compartment;
bool insertChild(JSContext *cx, js::Shape *parent, js::Shape *child);
bool insertChild(JSContext *cx, UnrootedShape parent, UnrootedShape child);
PropertyTree();
@ -82,12 +83,11 @@ class PropertyTree
{
}
js::Shape *newShape(JSContext *cx);
js::Shape *getChild(JSContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child);
UnrootedShape newShape(JSContext *cx);
UnrootedShape getChild(JSContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child);
#ifdef DEBUG
static void dumpShapes(JSRuntime *rt);
static void meter(JSBasicStats *bs, js::Shape *node);
#endif
};

View File

@ -142,15 +142,7 @@ class InlineMap;
class LifoAlloc;
class BaseShape;
class UnownedBaseShape;
struct Shape;
struct EmptyShape;
class ShapeKindArray;
class Bindings;
struct StackBaseShape;
struct StackShape;
class Breakpoint;
class BreakpointSite;
@ -207,7 +199,6 @@ struct TypeCompartment;
} /* namespace types */
typedef JS::Handle<Shape*> HandleShape;
typedef JS::Handle<BaseShape*> HandleBaseShape;
typedef JS::Handle<types::TypeObject*> HandleTypeObject;
typedef JS::Handle<JSAtom*> HandleAtom;
typedef JS::Handle<PropertyName*> HandlePropertyName;
@ -218,7 +209,6 @@ typedef JS::MutableHandle<JSAtom*> MutableHandleAtom;
typedef JSAtom * RawAtom;
typedef js::Rooted<Shape*> RootedShape;
typedef js::Rooted<BaseShape*> RootedBaseShape;
typedef js::Rooted<types::TypeObject*> RootedTypeObject;
typedef js::Rooted<JSAtom*> RootedAtom;
typedef js::Rooted<PropertyName*> RootedPropertyName;

View File

@ -37,7 +37,7 @@ using namespace js::gc;
using mozilla::DebugOnly;
bool
ShapeTable::init(JSRuntime *rt, Shape *lastProp)
ShapeTable::init(JSRuntime *rt, UnrootedShape lastProp)
{
/*
* Either we're creating a table for a large scope that was populated
@ -92,7 +92,7 @@ Shape::makeOwnBaseShape(JSContext *cx, HandleShape shape)
}
void
Shape::handoffTableTo(Shape *shape)
Shape::handoffTableTo(UnrootedShape shape)
{
AutoAssertNoGC nogc;
JS_ASSERT(inDictionary() && shape->inDictionary());
@ -273,7 +273,7 @@ ShapeTable::grow(JSContext *cx)
return true;
}
Shape *
UnrootedShape
Shape::getChildBinding(JSContext *cx, const StackShape &child)
{
AssertCanGC();
@ -287,12 +287,10 @@ Shape::getChildBinding(JSContext *cx, const StackShape &child)
return cx->propertyTree().getChild(cx, this, nfixed, child);
}
/* static */ Shape *
/* static */ UnrootedShape
Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base,
TaggedProto proto, Shape *shape_)
TaggedProto proto, HandleShape shape)
{
RootedShape shape(cx, shape_);
JS_ASSERT(!shape->inDictionary());
if (!shape->parent) {
@ -307,7 +305,7 @@ Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base,
{
UnrootedUnownedBaseShape nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return NULL;
return UnrootedShape(NULL);
child.base = nbase;
}
@ -320,8 +318,8 @@ Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base,
* which must be lastProperty() if inDictionaryMode(), else parent must be
* one of lastProperty() or lastProperty()->parent.
*/
Shape *
JSObject::getChildProperty(JSContext *cx, Shape *parent, StackShape &child)
/* static */ UnrootedShape
JSObject::getChildProperty(JSContext *cx, HandleObject obj, HandleShape parent, StackShape &child)
{
/*
* Shared properties have no slot, but slot_ will reflect that of parent.
@ -333,40 +331,38 @@ JSObject::getChildProperty(JSContext *cx, Shape *parent, StackShape &child)
} else {
if (child.hasMissingSlot()) {
uint32_t slot;
if (!allocSlot(cx, &slot))
return NULL;
if (!allocSlot(cx, obj, &slot))
return UnrootedShape(NULL);
child.setSlot(slot);
} else {
/* Slots can only be allocated out of order on objects in dictionary mode. */
JS_ASSERT(inDictionaryMode() ||
JS_ASSERT(obj->inDictionaryMode() ||
parent->hasMissingSlot() ||
child.slot() == parent->maybeSlot() + 1);
}
}
Shape *shape;
RootedShape shape(cx);
RootedObject self(cx, this);
if (inDictionaryMode()) {
JS_ASSERT(parent == lastProperty());
if (obj->inDictionaryMode()) {
JS_ASSERT(parent == obj->lastProperty());
StackShape::AutoRooter childRoot(cx, &child);
shape = js_NewGCShape(cx);
if (!shape)
return NULL;
if (child.hasSlot() && child.slot() >= self->lastProperty()->base()->slotSpan()) {
if (!JSObject::setSlotSpan(cx, self, child.slot() + 1))
return NULL;
return UnrootedShape(NULL);
if (child.hasSlot() && child.slot() >= obj->lastProperty()->base()->slotSpan()) {
if (!JSObject::setSlotSpan(cx, obj, child.slot() + 1))
return UnrootedShape(NULL);
}
shape->initDictionaryShape(child, self->numFixedSlots(), &self->shape_);
shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_);
} else {
shape = cx->propertyTree().getChild(cx, parent, self->numFixedSlots(), child);
shape = cx->propertyTree().getChild(cx, parent, obj->numFixedSlots(), child);
if (!shape)
return NULL;
return UnrootedShape(NULL);
//JS_ASSERT(shape->parent == parent);
//JS_ASSERT_IF(parent != lastProperty(), parent == lastProperty()->parent);
if (!JSObject::setLastProperty(cx, self, shape))
return NULL;
if (!JSObject::setLastProperty(cx, obj, shape))
return UnrootedShape(NULL);
}
return shape;
@ -397,7 +393,7 @@ JSObject::toDictionaryMode(JSContext *cx)
while (shape) {
JS_ASSERT(!shape->inDictionary());
Shape *dprop = js_NewGCShape(cx);
UnrootedShape dprop = js_NewGCShape(cx);
if (!dprop) {
js_ReportOutOfMemory(cx);
return false;
@ -452,65 +448,60 @@ NormalizeGetterAndSetter(JSObject *obj,
return true;
}
Shape *
JSObject::addProperty(JSContext *cx, jsid id,
/* static */ UnrootedShape
JSObject::addProperty(JSContext *cx, HandleObject obj, HandleId id,
PropertyOp getter, StrictPropertyOp setter,
uint32_t slot, unsigned attrs,
unsigned flags, int shortid, bool allowDictionary)
{
JS_ASSERT(!JSID_IS_VOID(id));
if (!isExtensible()) {
reportNotExtensible(cx);
return NULL;
if (!obj->isExtensible()) {
obj->reportNotExtensible(cx);
return UnrootedShape(NULL);
}
NormalizeGetterAndSetter(this, id, attrs, flags, getter, setter);
RootedObject self(cx, this);
NormalizeGetterAndSetter(obj, id, attrs, flags, getter, setter);
Shape **spp = NULL;
if (inDictionaryMode())
spp = lastProperty()->table().search(id, true);
if (obj->inDictionaryMode())
spp = obj->lastProperty()->table().search(id, true);
return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid,
return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, shortid,
spp, allowDictionary);
}
Shape *
JSObject::addPropertyInternal(JSContext *cx, jsid id_,
/* static */ UnrootedShape
JSObject::addPropertyInternal(JSContext *cx, HandleObject obj, HandleId id,
PropertyOp getter, StrictPropertyOp setter,
uint32_t slot, unsigned attrs,
unsigned flags, int shortid, Shape **spp,
bool allowDictionary)
{
AssertCanGC();
JS_ASSERT_IF(!allowDictionary, !inDictionaryMode());
RootedId id(cx, id_);
RootedObject self(cx, this);
JS_ASSERT_IF(!allowDictionary, !obj->inDictionaryMode());
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
ShapeTable *table = NULL;
if (!inDictionaryMode()) {
if (!obj->inDictionaryMode()) {
bool stableSlot =
(slot == SHAPE_INVALID_SLOT) ||
lastProperty()->hasMissingSlot() ||
(slot == lastProperty()->maybeSlot() + 1);
obj->lastProperty()->hasMissingSlot() ||
(slot == obj->lastProperty()->maybeSlot() + 1);
JS_ASSERT_IF(!allowDictionary, stableSlot);
if (allowDictionary &&
(!stableSlot || lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT)) {
if (!toDictionaryMode(cx))
return NULL;
table = &self->lastProperty()->table();
(!stableSlot || obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT)) {
if (!obj->toDictionaryMode(cx))
return UnrootedShape(NULL);
table = &obj->lastProperty()->table();
spp = table->search(id, true);
}
} else {
table = &lastProperty()->table();
table = &obj->lastProperty()->table();
if (table->needsToGrow()) {
if (!table->grow(cx))
return NULL;
return UnrootedShape(NULL);
spp = table->search(id, true);
JS_ASSERT(!SHAPE_FETCH(spp));
}
@ -519,37 +510,36 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id_,
JS_ASSERT(!!table == !!spp);
/* Find or create a property tree node labeled by our arguments. */
Shape *shape;
UnrootedShape shape;
{
shape = self->lastProperty();
RootedShape last(cx, obj->lastProperty());
uint32_t index;
bool indexed = js_IdIsIndex(id, &index);
UnrootedUnownedBaseShape nbase;
if (shape->base()->matchesGetterSetter(getter, setter) && !indexed) {
nbase = shape->base()->unowned();
if (last->base()->matchesGetterSetter(getter, setter) && !indexed) {
nbase = last->base()->unowned();
} else {
StackBaseShape base(shape->base());
StackBaseShape base(last->base());
base.updateGetterSetter(attrs, getter, setter);
if (indexed)
base.flags |= BaseShape::INDEXED;
nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return NULL;
return UnrootedShape(NULL);
}
StackShape child(nbase, id, slot, self->numFixedSlots(), attrs, flags, shortid);
DropUnrooted(nbase);
shape = self->getChildProperty(cx, self->lastProperty(), child);
StackShape child(DropUnrooted(nbase), id, slot, obj->numFixedSlots(), attrs, flags, shortid);
shape = getChildProperty(cx, obj, last, child);
}
if (shape) {
JS_ASSERT(shape == self->lastProperty());
JS_ASSERT(shape == obj->lastProperty());
if (table) {
/* Store the tree node pointer in the table entry for id. */
SHAPE_STORE_PRESERVING_COLLISION(spp, shape);
SHAPE_STORE_PRESERVING_COLLISION(spp, static_cast<RawShape>(shape));
++table->entryCount;
/* Pass the table along to the new last property, namely shape. */
@ -557,12 +547,12 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id_,
shape->parent->handoffTableTo(shape);
}
self->checkShapeConsistency();
obj->checkShapeConsistency();
return shape;
}
self->checkShapeConsistency();
return NULL;
obj->checkShapeConsistency();
return UnrootedShape(NULL);
}
/*
@ -589,41 +579,39 @@ CheckCanChangeAttrs(JSContext *cx, JSObject *obj, Shape *shape, unsigned *attrsp
return true;
}
Shape *
JSObject::putProperty(JSContext *cx, jsid id_,
/* static */ UnrootedShape
JSObject::putProperty(JSContext *cx, HandleObject obj, HandleId id,
PropertyOp getter, StrictPropertyOp setter,
uint32_t slot, unsigned attrs,
unsigned flags, int shortid)
{
RootedId id(cx, id_);
JS_ASSERT(!JSID_IS_VOID(id));
NormalizeGetterAndSetter(this, id, attrs, flags, getter, setter);
NormalizeGetterAndSetter(obj, id, attrs, flags, getter, setter);
RootedObject self(cx, this);
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
/* Search for id in order to claim its entry if table has been allocated. */
Shape **spp;
RootedShape shape(cx, Shape::search(cx, lastProperty(), id, &spp, true));
RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &spp, true));
if (!shape) {
/*
* You can't add properties to a non-extensible object, but you can change
* attributes of properties in such objects.
*/
if (!self->isExtensible()) {
self->reportNotExtensible(cx);
return NULL;
if (!obj->isExtensible()) {
obj->reportNotExtensible(cx);
return UnrootedShape(NULL);
}
return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp, true);
return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, shortid, spp, true);
}
/* Property exists: search must have returned a valid *spp. */
JS_ASSERT_IF(spp, !SHAPE_IS_REMOVED(*spp));
if (!CheckCanChangeAttrs(cx, self, shape, &attrs))
return NULL;
if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
return UnrootedShape(NULL);
/*
* If the caller wants to allocate a slot, but doesn't care which slot,
@ -639,13 +627,13 @@ JSObject::putProperty(JSContext *cx, jsid id_,
{
uint32_t index;
bool indexed = js_IdIsIndex(id, &index);
StackBaseShape base(self->lastProperty()->base());
StackBaseShape base(obj->lastProperty()->base());
base.updateGetterSetter(attrs, getter, setter);
if (indexed)
base.flags |= BaseShape::INDEXED;
nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return NULL;
return UnrootedShape(NULL);
}
/*
@ -660,33 +648,33 @@ JSObject::putProperty(JSContext *cx, jsid id_,
* The shape tree is shared immutable, and we can't removeProperty and then
* addPropertyInternal because a failure under add would lose data.
*/
if (shape != self->lastProperty() && !self->inDictionaryMode()) {
if (!self->toDictionaryMode(cx))
return NULL;
spp = self->lastProperty()->table().search(shape->propid(), false);
if (shape != obj->lastProperty() && !obj->inDictionaryMode()) {
if (!obj->toDictionaryMode(cx))
return UnrootedShape(NULL);
spp = obj->lastProperty()->table().search(shape->propid(), false);
shape = SHAPE_FETCH(spp);
}
JS_ASSERT_IF(shape->hasSlot() && !(attrs & JSPROP_SHARED), shape->slot() == slot);
if (self->inDictionaryMode()) {
if (obj->inDictionaryMode()) {
/*
* Updating some property in a dictionary-mode object. Create a new
* shape for the existing property, and also generate a new shape for
* the last property of the dictionary (unless the modified property
* is also the last property).
*/
bool updateLast = (shape == self->lastProperty());
shape = self->replaceWithNewEquivalentShape(cx, shape);
bool updateLast = (shape == obj->lastProperty());
shape = obj->replaceWithNewEquivalentShape(cx, shape);
if (!shape)
return NULL;
if (!updateLast && !self->generateOwnShape(cx))
return NULL;
return UnrootedShape(NULL);
if (!updateLast && !obj->generateOwnShape(cx))
return UnrootedShape(NULL);
/* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */
if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED)) {
if (!self->allocSlot(cx, &slot))
return NULL;
if (!allocSlot(cx, obj, &slot))
return UnrootedShape(NULL);
}
if (updateLast)
@ -703,23 +691,24 @@ JSObject::putProperty(JSContext *cx, jsid id_,
* Updating the last property in a non-dictionary-mode object. Find an
* alternate shared child of the last property's previous shape.
*/
StackBaseShape base(self->lastProperty()->base());
StackBaseShape base(obj->lastProperty()->base());
base.updateGetterSetter(attrs, getter, setter);
UnrootedUnownedBaseShape nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return NULL;
return UnrootedShape(NULL);
JS_ASSERT(shape == self->lastProperty());
JS_ASSERT(shape == obj->lastProperty());
/* Find or create a property tree node labeled by our arguments. */
StackShape child(nbase, id, slot, self->numFixedSlots(), attrs, flags, shortid);
StackShape child(nbase, id, slot, obj->numFixedSlots(), attrs, flags, shortid);
DropUnrooted(nbase);
Shape *newShape = self->getChildProperty(cx, shape->parent, child);
RootedShape parent(cx, shape->parent);
UnrootedShape newShape = JSObject::getChildProperty(cx, obj, parent, child);
if (!newShape) {
self->checkShapeConsistency();
return NULL;
obj->checkShapeConsistency();
return UnrootedShape(NULL);
}
shape = newShape;
@ -732,18 +721,18 @@ JSObject::putProperty(JSContext *cx, jsid id_,
* property (shape here) has a slotSpan that does not cover it.
*/
if (hadSlot && !shape->hasSlot()) {
if (oldSlot < self->slotSpan())
self->freeSlot(oldSlot);
if (oldSlot < obj->slotSpan())
obj->freeSlot(oldSlot);
++cx->runtime->propertyRemovals;
}
self->checkShapeConsistency();
obj->checkShapeConsistency();
return shape;
}
/* static */ Shape *
JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned attrs, unsigned mask,
/* static */ UnrootedShape
JSObject::changeProperty(JSContext *cx, HandleObject obj, RawShape shape, unsigned attrs, unsigned mask,
PropertyOp getter, StrictPropertyOp setter)
{
JS_ASSERT(obj->nativeContainsNoAllocation(*shape));
@ -764,7 +753,7 @@ JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned
setter = NULL;
if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
return NULL;
return UnrootedShape(NULL);
if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
return shape;
@ -775,7 +764,8 @@ JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned
* removeProperty because it will free an allocated shape->slot, and
* putProperty won't re-allocate it.
*/
Shape *newShape = obj->putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(),
RootedId propid(cx, shape->propid());
UnrootedShape newShape = putProperty(cx, obj, propid, getter, setter, shape->maybeSlot(),
attrs, shape->flags, shape->maybeShortid());
obj->checkShapeConsistency();
@ -862,18 +852,20 @@ JSObject::removeProperty(JSContext *cx, jsid id_)
* checks not to alter significantly the complexity of the
* delete in debug builds, see bug 534493.
*/
Shape *aprop = self->lastProperty();
UnrootedShape aprop = self->lastProperty();
for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent)
JS_ASSERT_IF(aprop != shape, self->nativeContainsNoAllocation(*aprop));
#endif
}
{
/* Remove shape from its non-circular doubly linked list. */
Shape *oldLastProp = self->lastProperty();
UnrootedShape oldLastProp = self->lastProperty();
shape->removeFromDictionary(self);
/* Hand off table from the old to new last property. */
oldLastProp->handoffTableTo(self->lastProperty());
}
/* Generate a new shape for the object, infallibly. */
JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
@ -900,7 +892,7 @@ JSObject::removeProperty(JSContext *cx, jsid id_)
/* static */ void
JSObject::clear(JSContext *cx, HandleObject obj)
{
Shape *shape = obj->lastProperty();
RootedShape shape(cx, obj->lastProperty());
JS_ASSERT(obj->inDictionaryMode() == shape->inDictionary());
while (shape->parent) {
@ -936,6 +928,7 @@ JSObject::rollbackProperties(JSContext *cx, uint32_t slotSpan)
Shape *
JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *newShape)
{
AssertCanGC();
JS_ASSERT(cx->compartment == oldShape->compartment());
JS_ASSERT_IF(oldShape != lastProperty(),
inDictionaryMode() &&
@ -1016,7 +1009,7 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent)
return true;
}
Shape *newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), obj->shape_);
UnrootedShape newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), obj->shape_);
if (!newShape)
return false;
@ -1024,7 +1017,7 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent)
return true;
}
/* static */ Shape *
/* static */ UnrootedShape
Shape::setObjectParent(JSContext *cx, JSObject *parent, TaggedProto proto, Shape *last)
{
if (last->getObjectParent() == parent)
@ -1033,7 +1026,8 @@ Shape::setObjectParent(JSContext *cx, JSObject *parent, TaggedProto proto, Shape
StackBaseShape base(last);
base.parent = parent;
return replaceLastProperty(cx, base, proto, last);
RootedShape lastRoot(cx, last);
return replaceLastProperty(cx, base, proto, lastRoot);
}
bool
@ -1080,7 +1074,7 @@ JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateSha
return true;
}
Shape *newShape = Shape::setObjectFlag(cx, flag, getTaggedProto(), lastProperty());
UnrootedShape newShape = Shape::setObjectFlag(cx, flag, getTaggedProto(), lastProperty());
if (!newShape)
return false;
@ -1088,7 +1082,7 @@ JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateSha
return true;
}
/* static */ Shape *
/* static */ UnrootedShape
Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last)
{
if (last->getObjectFlags() & flag)
@ -1097,7 +1091,8 @@ Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Sha
StackBaseShape base(last);
base.flags |= flag;
return replaceLastProperty(cx, base, proto, last);
RootedShape lastRoot(cx, last);
return replaceLastProperty(cx, base, proto, lastRoot);
}
/* static */ inline HashNumber
@ -1238,7 +1233,7 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, TaggedProto proto, JSOb
if (!nbase)
return NULL;
Shape *shape = cx->propertyTree().newShape(cx);
UnrootedShape shape = cx->propertyTree().newShape(cx);
if (!shape)
return NULL;
new (shape) EmptyShape(nbase, nfixed);
@ -1253,8 +1248,9 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, TaggedProto proto, JSOb
}
void
NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto_)
NewObjectCache::invalidateEntriesForShape(JSContext *cx, HandleShape shape, HandleObject proto)
{
AssertCanGC();
Class *clasp = shape->getObjectClass();
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
@ -1262,8 +1258,7 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject
kind = GetBackgroundAllocKind(kind);
Rooted<GlobalObject *> global(cx, &shape->getObjectParent()->global());
RootedObject proto(cx, proto_);
types::TypeObject *type = proto->getNewType(cx);
Rooted<types::TypeObject *> type(cx, proto->getNewType(cx));
EntryIndex entry;
if (lookupGlobal(clasp, global, kind, &entry))
@ -1275,10 +1270,11 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject
}
/* static */ void
EmptyShape::insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto)
EmptyShape::insertInitialShape(JSContext *cx, HandleShape shape, HandleObject proto)
{
InitialShapeEntry::Lookup lookup(shape->getObjectClass(), proto, shape->getObjectParent(),
shape->numFixedSlots(), shape->getObjectFlags());
InitialShapeEntry::Lookup lookup(shape->getObjectClass(), TaggedProto(proto),
shape->getObjectParent(), shape->numFixedSlots(),
shape->getObjectFlags());
InitialShapeSet::Ptr p = cx->compartment->initialShapes.lookup(lookup);
JS_ASSERT(p);
@ -1288,13 +1284,13 @@ EmptyShape::insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto)
/* The new shape had better be rooted at the old one. */
#ifdef DEBUG
Shape *nshape = shape;
RawShape nshape = shape;
while (!nshape->isEmptyShape())
nshape = nshape->previous();
JS_ASSERT(nshape == entry.shape);
#endif
entry.shape = shape;
entry.shape = shape.get();
/*
* This affects the shape that will be produced by the various NewObject
@ -1315,7 +1311,7 @@ JSCompartment::sweepInitialShapeTable()
if (initialShapes.initialized()) {
for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
const InitialShapeEntry &entry = e.front();
Shape *shape = entry.shape;
RawShape shape = entry.shape;
JSObject *proto = entry.proto.raw();
if (IsShapeAboutToBeFinalized(&shape) || (entry.proto.isObject() && IsObjectAboutToBeFinalized(&proto))) {
e.removeFront();

View File

@ -90,8 +90,12 @@
* a single BaseShape.
*/
struct JSObject;
namespace js {
class Bindings;
/* Limit on the number of slotful properties in an object. */
static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
@ -132,7 +136,7 @@ struct ShapeTable {
uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift); }
/* Computes the size of the entries array for a given capacity. */
static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); }
static size_t sizeOfEntries(size_t cap) { return cap * sizeof(RawShape); }
/*
* This counts the ShapeTable object itself (which must be
@ -160,19 +164,11 @@ struct ShapeTable {
* cope or ignore. They do however use JSRuntime's calloc_ method in order
* to update the malloc counter on success.
*/
bool init(JSRuntime *rt, js::Shape *lastProp);
bool init(JSRuntime *rt, UnrootedShape lastProp);
bool change(int log2Delta, JSContext *cx);
js::Shape **search(jsid id, bool adding);
Shape **search(jsid id, bool adding);
};
} /* namespace js */
struct JSObject;
namespace js {
class PropertyTree;
/*
* Reuse the API-only JSPROP_INDEX attribute to mean shadowability.
*/
@ -229,6 +225,7 @@ class PropertyTree;
ForwardDeclare(UnownedBaseShape);
ForwardDeclare(BaseShape);
ForwardDeclare(Shape);
struct StackBaseShape;
class BaseShape : public js::gc::Cell
{
@ -272,13 +269,13 @@ class BaseShape : public js::gc::Cell
* dictionary last properties. */
union {
js::PropertyOp rawGetter; /* getter hook for shape */
PropertyOp rawGetter; /* getter hook for shape */
JSObject *getterObj; /* user-defined callable "get" object or
null if shape->hasGetterValue() */
};
union {
js::StrictPropertyOp rawSetter; /* setter hook for shape */
StrictPropertyOp rawSetter; /* setter hook for shape */
JSObject *setterObj; /* user-defined callable "set" object or
null if shape->hasSetterValue() */
};
@ -393,7 +390,7 @@ struct StackBaseShape
PropertyOp rawGetter;
StrictPropertyOp rawSetter;
StackBaseShape(UnrootedBaseShape base)
explicit StackBaseShape(UnrootedBaseShape base)
: flags(base->flags & BaseShape::OBJECT_FLAG_MASK),
clasp(base->clasp),
parent(base->parent),
@ -409,7 +406,7 @@ struct StackBaseShape
rawSetter(NULL)
{}
inline StackBaseShape(Shape *shape);
inline StackBaseShape(UnrootedShape shape);
inline void updateGetterSetter(uint8_t attrs,
PropertyOp rawGetter,
@ -498,10 +495,10 @@ struct Shape : public js::gc::Cell
last, else to obj->shape_ */
};
static inline Shape *search(JSContext *cx, Shape *start, jsid id,
static inline UnrootedShape search(JSContext *cx, Shape *start, jsid id,
Shape ***pspp, bool adding = false);
static inline Shape *searchNoAllocation(Shape *start, jsid id);
static inline UnrootedShape searchNoAllocation(UnrootedShape start, jsid id);
inline void removeFromDictionary(JSObject *obj);
inline void insertIntoDictionary(HeapPtrShape *dictp);
@ -509,16 +506,16 @@ struct Shape : public js::gc::Cell
inline void initDictionaryShape(const StackShape &child, uint32_t nfixed,
HeapPtrShape *dictp);
Shape *getChildBinding(JSContext *cx, const StackShape &child);
UnrootedShape getChildBinding(JSContext *cx, const StackShape &child);
/* Replace the base shape of the last shape in a non-dictionary lineage with base. */
static Shape *replaceLastProperty(JSContext *cx, const StackBaseShape &base,
TaggedProto proto, Shape *shape);
static UnrootedShape replaceLastProperty(JSContext *cx, const StackBaseShape &base,
TaggedProto proto, HandleShape shape);
static bool hashify(JSContext *cx, HandleShape shape);
void handoffTableTo(Shape *newShape);
void handoffTableTo(UnrootedShape newShape);
inline void setParent(js::Shape *p);
inline void setParent(UnrootedShape p);
bool ensureOwnBaseShape(JSContext *cx) {
if (base()->isOwned())
@ -531,7 +528,7 @@ struct Shape : public js::gc::Cell
public:
bool hasTable() const { return base()->hasTable(); }
js::ShapeTable &table() const { return base()->table(); }
ShapeTable &table() const { return base()->table(); }
void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
size_t *propTableSize, size_t *kidsSize) const {
@ -553,10 +550,12 @@ struct Shape : public js::gc::Cell
class Range {
protected:
friend struct Shape;
Shape *cursor;
/* |cursor| is rooted manually when necessary using Range::AutoRooter. */
RawShape cursor;
public:
Range(Shape *shape) : cursor(shape) { }
Range(UnrootedShape shape) : cursor(shape) { }
bool empty() const {
return !cursor || cursor->isEmptyShape();
@ -599,8 +598,8 @@ struct Shape : public js::gc::Cell
Class *getObjectClass() const { return base()->clasp; }
JSObject *getObjectParent() const { return base()->parent; }
static Shape *setObjectParent(JSContext *cx, JSObject *obj, TaggedProto proto, Shape *last);
static Shape *setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last);
static UnrootedShape setObjectParent(JSContext *cx, JSObject *obj, TaggedProto proto, Shape *last);
static UnrootedShape setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last);
uint32_t getObjectFlags() const { return base()->getObjectFlags(); }
bool hasObjectFlag(BaseShape::Flag flag) const {
@ -660,7 +659,7 @@ struct Shape : public js::gc::Cell
// Per ES5, decode null getterObj as the undefined value, which encodes as null.
Value getterValue() const {
JS_ASSERT(hasGetterValue());
return base()->getterObj ? js::ObjectValue(*base()->getterObj) : js::UndefinedValue();
return base()->getterObj ? ObjectValue(*base()->getterObj) : UndefinedValue();
}
Value getterOrUndefined() const {
@ -677,7 +676,7 @@ struct Shape : public js::gc::Cell
// Per ES5, decode null setterObj as the undefined value, which encodes as null.
Value setterValue() const {
JS_ASSERT(hasSetterValue());
return base()->setterObj ? js::ObjectValue(*base()->setterObj) : js::UndefinedValue();
return base()->setterObj ? ObjectValue(*base()->setterObj) : UndefinedValue();
}
Value setterOrUndefined() const {
@ -686,9 +685,9 @@ struct Shape : public js::gc::Cell
: UndefinedValue();
}
void update(js::PropertyOp getter, js::StrictPropertyOp setter, uint8_t attrs);
void update(PropertyOp getter, StrictPropertyOp setter, uint8_t attrs);
inline bool matches(const Shape *other) const;
inline bool matches(const UnrootedShape other) const;
inline bool matches(const StackShape &other) const;
inline bool matchesParamsAfterId(UnrootedBaseShape base,
uint32_t aslot, unsigned aattrs, unsigned aflags,
@ -697,7 +696,7 @@ struct Shape : public js::gc::Cell
bool get(JSContext* cx, HandleObject receiver, JSObject *obj, JSObject *pobj, MutableHandleValue vp);
bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp);
BaseShape* base() const { return base_; }
RawBaseShape base() const { return base_.get(); }
bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
@ -799,18 +798,18 @@ struct Shape : public js::gc::Cell
if (hasTable())
return table().entryCount;
js::Shape *shape = this;
UnrootedShape shape = this;
uint32_t count = 0;
for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront())
for (Shape::Range r = shape->all(); !r.empty(); r.popFront())
++count;
return count;
}
bool isBigEnoughForAShapeTable() {
JS_ASSERT(!hasTable());
js::Shape *shape = this;
UnrootedShape shape = this;
uint32_t count = 0;
for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) {
for (Shape::Range r = shape->all(); !r.empty(); r.popFront()) {
++count;
if (count >= ShapeTable::MIN_ENTRIES)
return true;
@ -824,23 +823,23 @@ struct Shape : public js::gc::Cell
#endif
void finalize(FreeOp *fop);
void removeChild(js::Shape *child);
void removeChild(UnrootedShape child);
static inline void writeBarrierPre(Shape *shape);
static inline void writeBarrierPost(Shape *shape, void *addr);
static inline void writeBarrierPre(UnrootedShape shape);
static inline void writeBarrierPost(UnrootedShape shape, void *addr);
/*
* All weak references need a read barrier for incremental GC. This getter
* method implements the read barrier. It's used to obtain initial shapes
* from the compartment.
*/
static inline void readBarrier(Shape *shape);
static inline void readBarrier(UnrootedShape shape);
static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; }
inline void markChildren(JSTracer *trc);
inline Shape *search(JSContext *cx, jsid id) {
inline UnrootedShape search(JSContext *cx, jsid id) {
Shape **_;
return search(cx, this, id, &_);
}
@ -913,7 +912,7 @@ struct EmptyShape : public js::Shape
* getInitialShape calls, until the new shape becomes unreachable in a GC
* and the table entry is purged.
*/
static void insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto);
static void insertInitialShape(JSContext *cx, HandleShape shape, HandleObject proto);
};
/*
@ -970,7 +969,7 @@ struct StackShape
uint8_t flags;
int16_t shortid;
StackShape(UnrootedUnownedBaseShape base, jsid propid, uint32_t slot,
explicit StackShape(UnrootedUnownedBaseShape base, jsid propid, uint32_t slot,
uint32_t nfixed, unsigned attrs, unsigned flags, int shortid)
: base(base),
propid(propid),
@ -984,9 +983,9 @@ struct StackShape
JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
}
StackShape(const Shape *shape)
StackShape(const UnrootedShape &shape)
: base(shape->base()->unowned()),
propid(const_cast<Shape *>(shape)->propidRef()),
propid(shape->propidRef()),
slot_(shape->slotInfo & Shape::SLOT_MASK),
attrs(shape->attrs),
flags(shape->flags),
@ -1034,26 +1033,26 @@ struct StackShape
/* js::Shape pointer tag bit indicating a collision. */
#define SHAPE_COLLISION (uintptr_t(1))
#define SHAPE_REMOVED ((js::Shape *) SHAPE_COLLISION)
#define SHAPE_REMOVED ((RawShape) SHAPE_COLLISION)
/* Macros to get and set shape pointer values and collision flags. */
#define SHAPE_IS_FREE(shape) ((shape) == NULL)
#define SHAPE_IS_REMOVED(shape) ((shape) == SHAPE_REMOVED)
#define SHAPE_IS_LIVE(shape) ((shape) > SHAPE_REMOVED)
#define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (js::Shape *) \
#define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (RawShape) \
(uintptr_t(shape) | SHAPE_COLLISION))
#define SHAPE_HAD_COLLISION(shape) (uintptr_t(shape) & SHAPE_COLLISION)
#define SHAPE_FETCH(spp) SHAPE_CLEAR_COLLISION(*(spp))
#define SHAPE_CLEAR_COLLISION(shape) \
((js::Shape *) (uintptr_t(shape) & ~SHAPE_COLLISION))
((RawShape) (uintptr_t(shape) & ~SHAPE_COLLISION))
#define SHAPE_STORE_PRESERVING_COLLISION(spp, shape) \
(*(spp) = (js::Shape *) (uintptr_t(shape) | SHAPE_HAD_COLLISION(*(spp))))
(*(spp) = (RawShape) (uintptr_t(shape) | SHAPE_HAD_COLLISION(*(spp))))
namespace js {
inline Shape *
inline UnrootedShape
Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
{
AssertCanGC();
@ -1097,28 +1096,28 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
start->incrementNumLinearSearches();
}
for (Shape *shape = start; shape; shape = shape->parent) {
for (UnrootedShape shape = start; shape; shape = shape->parent) {
if (shape->propidRef() == id)
return shape;
}
return NULL;
return UnrootedShape(NULL);
}
/* static */ inline Shape *
Shape::searchNoAllocation(Shape *start, jsid id)
/* static */ inline UnrootedShape
Shape::searchNoAllocation(UnrootedShape start, jsid id)
{
if (start->hasTable()) {
Shape **spp = start->table().search(id, false);
return SHAPE_FETCH(spp);
}
for (Shape *shape = start; shape; shape = shape->parent) {
for (UnrootedShape shape = start; shape; shape = shape->parent) {
if (shape->propidRef() == id)
return shape;
}
return NULL;
return UnrootedShape(NULL);
}
void

View File

@ -124,7 +124,7 @@ BaseShape::matchesGetterSetter(PropertyOp rawGetter, StrictPropertyOp rawSetter)
}
inline
StackBaseShape::StackBaseShape(Shape *shape)
StackBaseShape::StackBaseShape(UnrootedShape shape)
: flags(shape->getObjectFlags()),
clasp(shape->getObjectClass()),
parent(shape->getObjectParent())
@ -238,7 +238,7 @@ StackShape::hash() const
}
inline bool
Shape::matches(const js::Shape *other) const
Shape::matches(const UnrootedShape other) const
{
return propid_.get() == other->propid_.get() &&
matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs,
@ -334,7 +334,7 @@ Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict,
}
inline void
Shape::setParent(js::Shape *p)
Shape::setParent(UnrootedShape p)
{
JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
p->maybeSlot() <= maybeSlot());
@ -373,7 +373,7 @@ Shape::insertIntoDictionary(HeapPtrShape *dictp)
JS_ASSERT_IF(*dictp, (*dictp)->listp == dictp);
JS_ASSERT_IF(*dictp, compartment() == (*dictp)->compartment());
setParent(*dictp);
setParent(dictp->get());
if (parent)
parent->listp = &parent;
listp = (HeapPtrShape *) dictp;
@ -400,7 +400,7 @@ EmptyShape::EmptyShape(UnrootedUnownedBaseShape base, uint32_t nfixed)
}
inline void
Shape::writeBarrierPre(Shape *shape)
Shape::writeBarrierPre(UnrootedShape shape)
{
#ifdef JSGC_INCREMENTAL
if (!shape)
@ -408,7 +408,7 @@ Shape::writeBarrierPre(Shape *shape)
JSCompartment *comp = shape->compartment();
if (comp->needsBarrier()) {
Shape *tmp = const_cast<Shape *>(shape);
UnrootedShape tmp = shape;
MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
JS_ASSERT(tmp == shape);
}
@ -416,17 +416,17 @@ Shape::writeBarrierPre(Shape *shape)
}
inline void
Shape::writeBarrierPost(Shape *shape, void *addr)
Shape::writeBarrierPost(UnrootedShape shape, void *addr)
{
}
inline void
Shape::readBarrier(Shape *shape)
Shape::readBarrier(UnrootedShape shape)
{
#ifdef JSGC_INCREMENTAL
JSCompartment *comp = shape->compartment();
if (comp->needsBarrier()) {
Shape *tmp = const_cast<Shape *>(shape);
UnrootedShape tmp = shape;
MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
JS_ASSERT(tmp == shape);
}

View File

@ -132,9 +132,11 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalBindingsHandle self,
StackShape child(nbase, id, slot++, 0, attrs, Shape::HAS_SHORTID, frameIndex);
DropUnrooted(nbase);
self->callObjShape_ = self->callObjShape_->getChildBinding(cx, child);
if (!self->callObjShape_)
UnrootedShape shape = self->callObjShape_->getChildBinding(cx, child);
if (!shape)
return false;
self->callObjShape_ = shape;
}
JS_ASSERT(!bi);

View File

@ -191,7 +191,7 @@ class Bindings
unsigned count() const { return numArgs() + numVars(); }
/* Return the initial shape of call objects created for this scope. */
Shape *callObjShape() const { return callObjShape_; }
UnrootedShape callObjShape() const { return callObjShape_.get(); }
/* Convenience method to get the var index of 'arguments'. */
static unsigned argumentsVarIndex(JSContext *cx, InternalBindingsHandle);
@ -210,7 +210,7 @@ struct RootMethods<Bindings> {
static Bindings initial();
static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
static bool poisoned(const Bindings &bindings) {
return IsPoisonedPtr(bindings.callObjShape());
return IsPoisonedPtr(static_cast<RawShape>(bindings.callObjShape()));
}
};

View File

@ -3241,13 +3241,13 @@ static JSFunctionSpec string_static_methods[] = {
JS_FS_END
};
Shape *
UnrootedShape
StringObject::assignInitialShape(JSContext *cx)
{
JS_ASSERT(nativeEmpty());
return addDataProperty(cx, NameToId(cx->names().length),
LENGTH_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
RootedId lengthid(cx, NameToId(cx->names().length));
return addDataProperty(cx, lengthid, LENGTH_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
}
JSObject *

View File

@ -132,7 +132,7 @@ WatchpointMap::triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, M
Value old;
old.setUndefined();
if (obj->isNative()) {
if (Shape *shape = obj->nativeLookup(cx, id)) {
if (UnrootedShape shape = obj->nativeLookup(cx, id)) {
if (shape->hasSlot())
old = obj->nativeGetSlot(shape->slot());
}

View File

@ -4724,10 +4724,9 @@ xml_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
objp.set(NULL);
propp.set(NULL);
} else {
Shape *shape =
js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty,
RootedShape shape(cx, js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty,
SHAPE_INVALID_SLOT, JSPROP_ENUMERATE,
0, 0);
0, 0));
if (!shape)
return JS_FALSE;
@ -4756,13 +4755,12 @@ xml_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandle
return true;
}
jsid id;
if (!IndexToId(cx, index, &id))
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
Shape *shape =
js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, SHAPE_INVALID_SLOT,
JSPROP_ENUMERATE, 0, 0);
RootedShape shape(cx, js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty,
SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, 0, 0));
if (!shape)
return false;

View File

@ -197,7 +197,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::MIPSRegiste
loadPtr(Address(obj, JSObject::offsetOfShape()), shape);
}
Jump guardShape(RegisterID objReg, Shape *shape) {
Jump guardShape(RegisterID objReg, UnrootedShape shape) {
return branchPtr(NotEqual, Address(objReg, JSObject::offsetOfShape()), ImmPtr(shape));
}
@ -981,7 +981,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::MIPSRegiste
}
void loadObjProp(JSObject *obj, RegisterID objReg,
js::Shape *shape,
js::UnrootedShape shape,
RegisterID typeReg, RegisterID dataReg)
{
if (obj->isFixedSlot(shape->slot()))
@ -1342,6 +1342,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::MIPSRegiste
*/
Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject)
{
AutoAssertNoGC nogc;
gc::AllocKind allocKind = templateObject->getAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);

View File

@ -6079,7 +6079,7 @@ mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter)
for (unsigned i = 0; i < sc.hops; i++)
masm.loadPayload(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
Shape *shape = ScopeCoordinateToStaticScope(script_, PC).scopeShape();
UnrootedShape shape = ScopeCoordinateToStaticScope(script_, PC).scopeShape();
Address addr;
if (shape->numFixedSlots() <= sc.slot) {
masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
@ -6227,7 +6227,7 @@ mjit::Compiler::iter(unsigned flags)
masm.loadPtr(Address(T1, offsetof(types::TypeObject, proto)), T1);
masm.loadShape(T1, T1);
masm.loadPtr(Address(nireg, offsetof(NativeIterator, shapes_array)), T2);
masm.loadPtr(Address(T2, sizeof(Shape *)), T2);
masm.loadPtr(Address(T2, sizeof(RawShape)), T2);
Jump mismatchedProto = masm.branchPtr(Assembler::NotEqual, T1, T2);
stubcc.linkExit(mismatchedProto, Uses(1));
@ -6462,6 +6462,8 @@ mjit::Compiler::jsop_bindgname()
bool
mjit::Compiler::jsop_getgname(uint32_t index)
{
AssertCanGC();
/* Optimize undefined, NaN and Infinity. */
PropertyName *name = script_->getName(index);
if (name == cx->names().undefined) {
@ -6500,9 +6502,9 @@ mjit::Compiler::jsop_getgname(uint32_t index)
* then bake its address into the jitcode and guard against future
* reallocation of the global object's slots.
*/
js::Shape *shape = globalObj->nativeLookup(cx, NameToId(name));
UnrootedShape shape = globalObj->nativeLookup(cx, NameToId(name));
if (shape && shape->hasDefaultGetter() && shape->hasSlot()) {
HeapSlot *value = &globalObj->getSlotRef(shape->slot());
HeapSlot *value = &globalObj->getSlotRef(DropUnrooted(shape)->slot());
if (!value->isUndefined() &&
!propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) {
watchGlobalReallocation();
@ -6626,7 +6628,7 @@ mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed)
types::HeapTypeSet *types = globalObj->getType(cx)->getProperty(cx, id, false);
if (!types)
return false;
js::Shape *shape = globalObj->nativeLookup(cx, NameToId(name));
UnrootedShape shape = globalObj->nativeLookup(cx, NameToId(name));
if (shape && shape->hasDefaultSetter() &&
shape->writable() && shape->hasSlot() &&
!types->isOwnProperty(cx, globalObj->getType(cx), true)) {
@ -7911,6 +7913,8 @@ mjit::Compiler::BarrierState
mjit::Compiler::pushAddressMaybeBarrier(Address address, JSValueType type, bool reuseBase,
bool testUndefined)
{
AssertCanGC();
if (!hasTypeBarriers(PC) && !testUndefined) {
frame.push(address, type, reuseBase);
return BarrierState();

View File

@ -1515,7 +1515,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
ic.slowPathStart = stubcc.syncExit(Uses(3));
// Guard obj is a dense array.
Shape *shape = GetDenseArrayShape(cx, globalObj);
UnrootedShape shape = GetDenseArrayShape(cx, globalObj);
if (!shape)
return false;
ic.shapeGuard = masm.guardShape(ic.objReg, shape);
@ -2093,7 +2093,7 @@ mjit::Compiler::jsop_getelem()
}
// Guard obj is a dense array.
Shape *shape = GetDenseArrayShape(cx, globalObj);
UnrootedShape shape = GetDenseArrayShape(cx, globalObj);
if (!shape)
return false;
ic.shapeGuard = masm.guardShape(ic.objReg, shape);

View File

@ -1400,12 +1400,12 @@ GetPIC(JSContext *cx, JSScript *script, jsbytecode *pc, bool constructing)
return NULL;
}
Shape *
UnrootedShape
mjit::GetPICSingleShape(JSContext *cx, JSScript *script, jsbytecode *pc, bool constructing)
{
ic::PICInfo *pic = GetPIC(cx, script, pc, constructing);
if (!pic)
return NULL;
return UnrootedShape(NULL);
return pic->getSingleShape();
}

View File

@ -1035,7 +1035,7 @@ IsLowerableFunCallOrApply(jsbytecode *pc)
#endif
}
Shape *
UnrootedShape
GetPICSingleShape(JSContext *cx, JSScript *script, jsbytecode *pc, bool constructing);
static inline void

View File

@ -68,7 +68,9 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
RecompilationMonitor monitor(f.cx);
Shape *shape = obj->nativeLookup(f.cx, NameToId(name));
uint32_t slot;
{
RootedShape shape(f.cx, obj->nativeLookup(f.cx, NameToId(name)));
if (monitor.recompiled()) {
stubs::Name(f);
@ -84,7 +86,7 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
stubs::Name(f);
return;
}
uint32_t slot = shape->slot();
slot = shape->slot();
/* Patch shape guard. */
Repatcher repatcher(f.chunk());
@ -94,6 +96,7 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
uint32_t index = obj->dynamicSlotIndex(slot);
JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset);
repatcher.patchAddressOffsetForValueLoad(label, index * sizeof(Value));
}
/* Do load anyway... this time. */
stubs::Name(f);
@ -117,14 +120,14 @@ PatchSetFallback(VMFrame &f, ic::SetGlobalNameIC *ic)
}
void
SetGlobalNameIC::patchInlineShapeGuard(Repatcher &repatcher, Shape *shape)
SetGlobalNameIC::patchInlineShapeGuard(Repatcher &repatcher, UnrootedShape shape)
{
JSC::CodeLocationDataLabelPtr label = fastPathStart.dataLabelPtrAtOffset(shapeOffset);
repatcher.repatch(label, shape);
}
static LookupStatus
UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, Shape *shape)
UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, UnrootedShape shape)
{
/* Give globals a chance to appear. */
if (!shape)
@ -162,13 +165,15 @@ ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic)
RecompilationMonitor monitor(f.cx);
Shape *shape = obj->nativeLookup(f.cx, NameToId(name));
{
UnrootedShape shape = obj->nativeLookup(f.cx, NameToId(name));
if (!monitor.recompiled()) {
LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape);
if (status == Lookup_Error)
THROW();
}
}
stubs::SetName(f, name);
}

View File

@ -116,7 +116,7 @@ struct SetGlobalNameIC : public GlobalNameIC
/* SET only. */
ValueRemat vr; /* RHS value. */
void patchInlineShapeGuard(Repatcher &repatcher, Shape *shape);
void patchInlineShapeGuard(Repatcher &repatcher, UnrootedShape shape);
};
void JS_FASTCALL GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic);

View File

@ -189,7 +189,7 @@ class SetPropCompiler : public PICStubCompiler
repatcher.relink(pic.slowPathCall, target);
}
LookupStatus patchInline(Shape *shape)
LookupStatus patchInline(UnrootedShape shape)
{
JS_ASSERT(!pic.inlinePathPatched);
JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress());
@ -249,7 +249,7 @@ class SetPropCompiler : public PICStubCompiler
repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs);
}
LookupStatus generateStub(Shape *initialShape, Shape *shape, bool adding)
LookupStatus generateStub(UnrootedShape initialShape, UnrootedShape shape, bool adding)
{
if (hadGC())
return Lookup_Uncacheable;
@ -510,7 +510,7 @@ class SetPropCompiler : public PICStubCompiler
proto = proto->getProto();
}
Shape *initialShape = obj->lastProperty();
RootedShape initialShape(cx, obj->lastProperty());
uint32_t slots = obj->numDynamicSlots();
unsigned flags = 0;
@ -521,8 +521,7 @@ class SetPropCompiler : public PICStubCompiler
* populate the slot to satisfy the method invariant (in case we
* hit an early return below).
*/
shape =
obj->putProperty(cx, name, getter, clasp->setProperty,
shape = JSObject::putProperty(cx, obj, name, getter, clasp->setProperty,
SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0);
if (!shape)
return error();
@ -1016,7 +1015,7 @@ class GetPropCompiler : public PICStubCompiler
return Lookup_Cacheable;
}
LookupStatus patchInline(JSObject *holder, Shape *shape)
LookupStatus patchInline(JSObject *holder, UnrootedShape shape)
{
spew("patch", "inline");
Repatcher repatcher(f.chunk());
@ -1051,7 +1050,7 @@ class GetPropCompiler : public PICStubCompiler
}
/* For JSPropertyOp getters. */
void generateGetterStub(Assembler &masm, Shape *shape, jsid userid,
void generateGetterStub(Assembler &masm, UnrootedShape shape, jsid userid,
Label start, Vector<Jump, 8> &shapeMismatches)
{
AutoAssertNoGC nogc;
@ -1163,7 +1162,7 @@ class GetPropCompiler : public PICStubCompiler
}
/* For getters backed by a JSNative. */
void generateNativeGetterStub(Assembler &masm, Shape *shape,
void generateNativeGetterStub(Assembler &masm, UnrootedShape shape,
Label start, Vector<Jump, 8> &shapeMismatches)
{
AutoAssertNoGC nogc;
@ -1704,7 +1703,7 @@ class ScopeNameCompiler : public PICStubCompiler
JS_ASSERT(obj == getprop.holder);
JS_ASSERT(getprop.holder != &scopeChain->global());
Shape *shape = getprop.shape;
UnrootedShape shape = getprop.shape;
if (!shape->hasDefaultGetter())
return disable("unhandled callobj sprop getter");
@ -1833,7 +1832,17 @@ class ScopeNameCompiler : public PICStubCompiler
Rooted<JSObject*> normalized(cx, obj);
if (obj->isWith() && !shape->hasDefaultGetter())
normalized = &obj->asWith().object();
NATIVE_GET(cx, normalized, holder, shape, 0, vp.address(), return false);
if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
/* Fast path for Object instance properties. */
JS_ASSERT(shape->slot() != SHAPE_INVALID_SLOT || !shape->hasDefaultSetter());
if (shape->slot() != SHAPE_INVALID_SLOT)
vp.set(holder->nativeGetSlot(shape->slot()));
else
vp.setUndefined();
} else {
if (!js_NativeGet(cx, normalized, holder, shape, 0, vp))
return false;
}
return true;
}
};
@ -2402,7 +2411,7 @@ GetElementIC::attachGetProp(VMFrame &f, HandleObject obj, HandleValue v, HandleP
}
// Load the value.
Shape *shape = getprop.shape;
RootedShape shape(cx, getprop.shape);
masm.loadObjProp(holder, holderReg, shape, typeReg, objReg);
Jump done = masm.jump();

View File

@ -489,14 +489,14 @@ struct PICInfo : public BasePolyIC {
public:
void purge(Repatcher &repatcher);
void setInlinePathShape(Shape *shape) {
void setInlinePathShape(UnrootedShape shape) {
JS_ASSERT(!inlinePathShape_);
inlinePathShape_ = shape;
}
Shape *getSingleShape() {
UnrootedShape getSingleShape() {
if (disabled || hadUncacheable || stubsGenerated > 0)
return NULL;
return UnrootedShape(NULL);
return inlinePathShape_;
}

View File

@ -29,23 +29,8 @@ ReportAtomNotDefined(JSContext *cx, JSAtom *atom)
js_ReportIsNotDefined(cx, printable.ptr());
}
#define NATIVE_GET(cx,obj,pobj,shape,getHow,vp,onerr) \
JS_BEGIN_MACRO \
if (shape->isDataDescriptor() && shape->hasDefaultGetter()) { \
/* Fast path for Object instance properties. */ \
JS_ASSERT((shape)->slot() != SHAPE_INVALID_SLOT || \
!shape->hasDefaultSetter()); \
if (((shape)->slot() != SHAPE_INVALID_SLOT)) \
*(vp) = (pobj)->nativeGetSlot((shape)->slot()); \
else \
(vp)->setUndefined(); \
} else { \
if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp)) \
onerr; \
} \
JS_END_MACRO
}}
} /* namespace mjit */
} /* namespace js */
#endif /* jslogic_h__ */

View File

@ -2776,7 +2776,7 @@ CopyProperty(JSContext *cx, HandleObject obj, HandleObject referent, HandleId id
RootedValue value(cx, desc.value);
objp.set(obj);
return !!DefineNativeProperty(cx, obj, id, value, desc.getter, desc.setter,
return DefineNativeProperty(cx, obj, id, value, desc.getter, desc.setter,
desc.attrs, propFlags, desc.shortid);
}

View File

@ -849,7 +849,7 @@ Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value
/* Check that rv is {return: val} or {throw: val}. */
JSContext *cx = ac.ref().context();
Rooted<JSObject*> obj(cx);
Shape *shape;
RootedShape shape(cx);
jsid returnId = NameToId(cx->names().return_);
jsid throwId = NameToId(cx->names().throw_);
bool okResumption = rv.isObject();
@ -869,8 +869,10 @@ Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value
return handleUncaughtException(ac, vp, callHook);
}
if (!js_NativeGet(cx, obj, obj, shape, 0, vp) || !unwrapDebuggeeValue(cx, vp))
return handleUncaughtException(ac, vp, callHook);
RootedValue v(cx, *vp);
if (!js_NativeGet(cx, obj, obj, shape, 0, &v) || !unwrapDebuggeeValue(cx, v.address()))
return handleUncaughtException(ac, v.address(), callHook);
*vp = v;
ac.destroy();
if (!cx->compartment->wrap(cx, vp)) {

View File

@ -40,25 +40,25 @@ Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
} // namespace js
inline js::Shape *
inline js::UnrootedShape
js::ObjectImpl::nativeLookup(JSContext *cx, PropertyId pid)
{
return nativeLookup(cx, pid.asId());
}
inline js::Shape *
inline js::UnrootedShape
js::ObjectImpl::nativeLookup(JSContext *cx, PropertyName *name)
{
return nativeLookup(cx, PropertyId(name));
}
inline js::Shape *
inline js::UnrootedShape
js::ObjectImpl::nativeLookupNoAllocation(PropertyId pid)
{
return nativeLookupNoAllocation(pid.asId());
}
inline js::Shape *
inline js::UnrootedShape
js::ObjectImpl::nativeLookupNoAllocation(PropertyName *name)
{
return nativeLookupNoAllocation(PropertyId(name));

View File

@ -164,8 +164,8 @@ js::ObjectImpl::checkShapeConsistency()
MOZ_ASSERT(isNative());
Shape *shape = lastProperty();
Shape *prev = NULL;
UnrootedShape shape = lastProperty();
UnrootedShape prev = NULL;
if (inDictionaryMode()) {
MOZ_ASSERT(shape->hasTable());
@ -177,7 +177,7 @@ js::ObjectImpl::checkShapeConsistency()
}
for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
MOZ_ASSERT_IF(shape != lastProperty(), !shape->hasTable());
MOZ_ASSERT_IF(lastProperty() != shape, !shape->hasTable());
Shape **spp = table.search(shape->propid(), false);
MOZ_ASSERT(SHAPE_FETCH(spp) == shape);
@ -187,7 +187,7 @@ js::ObjectImpl::checkShapeConsistency()
for (int n = throttle; --n >= 0 && shape; shape = shape->parent) {
MOZ_ASSERT_IF(shape->slot() != SHAPE_INVALID_SLOT, shape->slot() < slotSpan());
if (!prev) {
MOZ_ASSERT(shape == lastProperty());
MOZ_ASSERT(lastProperty() == shape);
MOZ_ASSERT(shape->listp == &shape_);
} else {
MOZ_ASSERT(shape->listp == &prev->parent);
@ -257,15 +257,16 @@ js::ObjectImpl::slotInRange(uint32_t slot, SentinelAllowed sentinel) const
*/
MOZ_NEVER_INLINE
#endif
Shape *
js::ObjectImpl::nativeLookup(JSContext *cx, jsid id)
UnrootedShape
js::ObjectImpl::nativeLookup(JSContext *cx, jsid idArg)
{
MOZ_ASSERT(isNative());
Shape **spp;
RootedId id(cx, idArg);
return Shape::search(cx, lastProperty(), id, &spp);
}
Shape *
UnrootedShape
js::ObjectImpl::nativeLookupNoAllocation(jsid id)
{
MOZ_ASSERT(isNative());
@ -503,8 +504,11 @@ js::GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, PropertyId pid_, unsi
return false;
}
Shape *shape = obj->nativeLookup(cx, pid);
/* |shape| is always set /after/ a GC. */
UnrootedShape shape = obj->nativeLookup(cx, pid);
if (!shape) {
DropUnrooted(shape);
/* Not found: attempt to resolve it. */
Class *clasp = obj->getClass();
JSResolveOp resolve = clasp->resolve;

View File

@ -24,6 +24,7 @@ namespace js {
class Debugger;
class ObjectImpl;
ForwardDeclare(Shape);
class AutoPropDescArrayRooter;
@ -358,7 +359,7 @@ class ElementsHeader
} dense;
class {
friend class SparseElementsHeader;
Shape * shape;
RawShape shape;
} sparse;
class {
friend class ArrayBufferElementsHeader;
@ -449,7 +450,7 @@ class DenseElementsHeader : public ElementsHeader
class SparseElementsHeader : public ElementsHeader
{
public:
Shape * shape() {
UnrootedShape shape() {
MOZ_ASSERT(ElementsHeader::isSparseElements());
return sparse.shape;
}
@ -1155,13 +1156,13 @@ class ObjectImpl : public gc::Cell
/* Compute dynamicSlotsCount() for this object. */
inline uint32_t numDynamicSlots() const;
Shape * nativeLookup(JSContext *cx, jsid id);
inline Shape * nativeLookup(JSContext *cx, PropertyId pid);
inline Shape * nativeLookup(JSContext *cx, PropertyName *name);
UnrootedShape nativeLookup(JSContext *cx, jsid id);
inline UnrootedShape nativeLookup(JSContext *cx, PropertyId pid);
inline UnrootedShape nativeLookup(JSContext *cx, PropertyName *name);
Shape * nativeLookupNoAllocation(jsid id);
inline Shape * nativeLookupNoAllocation(PropertyId pid);
inline Shape * nativeLookupNoAllocation(PropertyName *name);
UnrootedShape nativeLookupNoAllocation(jsid id);
inline UnrootedShape nativeLookupNoAllocation(PropertyId pid);
inline UnrootedShape nativeLookupNoAllocation(PropertyName *name);
inline bool nativeContains(JSContext *cx, Handle<jsid> id);
inline bool nativeContains(JSContext *cx, Handle<PropertyName*> name);

View File

@ -322,7 +322,7 @@ RegExpObject::createShared(JSContext *cx, RegExpGuard *g)
return true;
}
Shape *
UnrootedShape
RegExpObject::assignInitialShape(JSContext *cx)
{
JS_ASSERT(isRegExp());
@ -338,27 +338,20 @@ RegExpObject::assignInitialShape(JSContext *cx)
RootedObject self(cx, this);
/* The lastIndex property alone is writable but non-configurable. */
if (!addDataProperty(cx, NameToId(cx->names().lastIndex),
LAST_INDEX_SLOT, JSPROP_PERMANENT))
{
return NULL;
}
if (!addDataProperty(cx, NameToId(cx->names().lastIndex), LAST_INDEX_SLOT, JSPROP_PERMANENT))
return UnrootedShape(NULL);
/* Remaining instance properties are non-writable and non-configurable. */
if (!self->addDataProperty(cx, NameToId(cx->names().source),
SOURCE_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
!self->addDataProperty(cx, NameToId(cx->names().global),
GLOBAL_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
!self->addDataProperty(cx, NameToId(cx->names().ignoreCase),
IGNORE_CASE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) ||
!self->addDataProperty(cx, NameToId(cx->names().multiline),
MULTILINE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY))
{
return NULL;
}
return self->addDataProperty(cx, NameToId(cx->names().sticky),
STICKY_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY);
unsigned attrs = JSPROP_PERMANENT | JSPROP_READONLY;
if (!self->addDataProperty(cx, NameToId(cx->names().source), SOURCE_SLOT, attrs))
return UnrootedShape(NULL);
if (!self->addDataProperty(cx, NameToId(cx->names().global), GLOBAL_FLAG_SLOT, attrs))
return UnrootedShape(NULL);
if (!self->addDataProperty(cx, NameToId(cx->names().ignoreCase), IGNORE_CASE_FLAG_SLOT, attrs))
return UnrootedShape(NULL);
if (!self->addDataProperty(cx, NameToId(cx->names().multiline), MULTILINE_FLAG_SLOT, attrs))
return UnrootedShape(NULL);
return self->addDataProperty(cx, NameToId(cx->names().sticky), STICKY_FLAG_SLOT, attrs);
}
inline bool
@ -371,10 +364,11 @@ RegExpObject::init(JSContext *cx, HandleAtom source, RegExpFlag flags)
if (!assignInitialShape(cx))
return false;
} else {
Shape *shape = assignInitialShape(cx);
RootedShape shape(cx, assignInitialShape(cx));
if (!shape)
return false;
EmptyShape::insertInitialShape(cx, shape, self->getProto());
RootedObject proto(cx, self->getProto());
EmptyShape::insertInitialShape(cx, shape, proto);
}
JS_ASSERT(!self->nativeEmpty());
}

View File

@ -405,7 +405,7 @@ class RegExpObject : public JSObject
* encoding their initial properties. Return the shape after
* changing this regular expression object's last property to it.
*/
Shape *assignInitialShape(JSContext *cx);
UnrootedShape assignInitialShape(JSContext *cx);
inline bool init(JSContext *cx, HandleAtom source, RegExpFlag flags);

View File

@ -58,12 +58,14 @@ StaticScopeIter::hasDynamicScopeObject() const
: obj->toFunction()->isHeavyweight();
}
Shape *
UnrootedShape
StaticScopeIter::scopeShape() const
{
JS_ASSERT(hasDynamicScopeObject());
JS_ASSERT(type() != NAMED_LAMBDA);
return type() == BLOCK ? block().lastProperty() : funScript()->bindings.callObjShape();
return type() == BLOCK
? UnrootedShape(block().lastProperty())
: funScript()->bindings.callObjShape();
}
StaticScopeIter::Type
@ -303,7 +305,7 @@ DeclEnvObject::createTemplateObject(JSContext *cx, HandleFunction fun)
Rooted<jsid> id(cx, AtomToId(fun->atom()));
Class *clasp = obj->getClass();
unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY;
if (!obj->putProperty(cx, id, clasp->getProperty, clasp->setProperty,
if (!JSObject::putProperty(cx, obj, id, clasp->getProperty, clasp->setProperty,
lambdaSlot(), attrs, 0, 0))
{
return NULL;
@ -689,7 +691,7 @@ StaticBlockObject::create(JSContext *cx)
return &obj->asStaticBlock();
}
/* static */ Shape *
/* static */ UnrootedShape
StaticBlockObject::addVar(JSContext *cx, Handle<StaticBlockObject*> block, HandleId id,
int index, bool *redeclared)
{
@ -701,7 +703,7 @@ StaticBlockObject::addVar(JSContext *cx, Handle<StaticBlockObject*> block, Handl
Shape **spp;
if (Shape::search(cx, block->lastProperty(), id, &spp, true)) {
*redeclared = true;
return NULL;
return UnrootedShape(NULL);
}
/*
@ -709,7 +711,7 @@ StaticBlockObject::addVar(JSContext *cx, Handle<StaticBlockObject*> block, Handl
* block's shape later.
*/
uint32_t slot = JSSLOT_FREE(&BlockClass) + index;
return block->addPropertyInternal(cx, id, /* getter = */ NULL, /* setter = */ NULL,
return JSObject::addPropertyInternal(cx, block, id, /* getter = */ NULL, /* setter = */ NULL,
slot, JSPROP_ENUMERATE | JSPROP_PERMANENT,
Shape::HAS_SHORTID, index, spp,
/* allowDictionary = */ false);
@ -800,7 +802,7 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, HandleObject enclosingScope, Handl
return false;
for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
Shape *shape = &r.front();
UnrootedShape shape = &r.front();
shapes[shape->shortid()] = shape;
}
@ -808,18 +810,21 @@ js::XDRStaticBlockObject(XDRState<mode> *xdr, HandleObject enclosingScope, Handl
* XDR the block object's properties. We know that there are 'count'
* properties to XDR, stored as id/shortid pairs.
*/
RootedShape shape(cx);
RootedId propid(cx);
RootedAtom atom(cx);
for (unsigned i = 0; i < count; i++) {
Shape *shape = shapes[i];
shape = shapes[i];
JS_ASSERT(shape->hasDefaultGetter());
JS_ASSERT(unsigned(shape->shortid()) == i);
jsid propid = shape->propid();
propid = shape->propid();
JS_ASSERT(JSID_IS_ATOM(propid) || JSID_IS_INT(propid));
/* The empty string indicates an int id. */
RootedAtom atom(cx, JSID_IS_ATOM(propid)
atom = JSID_IS_ATOM(propid)
? JSID_TO_ATOM(propid)
: cx->runtime->emptyString);
: cx->runtime->emptyString;
if (!XDRAtom(xdr, &atom))
return false;
@ -1222,7 +1227,7 @@ class DebugScopeProxy : public BaseProxyHandler
/* Handle unaliased let and catch bindings at block scope. */
if (scope->isClonedBlock()) {
ClonedBlockObject &block = scope->asClonedBlock();
Shape *shape = block.lastProperty()->search(cx, id);
UnrootedShape shape = block.lastProperty()->search(cx, id);
if (!shape)
return false;

View File

@ -65,7 +65,7 @@ class StaticScopeIter
/* Return whether this static scope will be on the dynamic scope chain. */
bool hasDynamicScopeObject() const;
Shape *scopeShape() const;
UnrootedShape scopeShape() const;
enum Type { BLOCK, FUNCTION, NAMED_LAMBDA };
Type type() const;
@ -346,7 +346,7 @@ class StaticBlockObject : public BlockObject
void initPrevBlockChainFromParser(StaticBlockObject *prev);
void resetPrevBlockChainFromParser();
static Shape *addVar(JSContext *cx, Handle<StaticBlockObject*> block, HandleId id,
static UnrootedShape addVar(JSContext *cx, Handle<StaticBlockObject*> block, HandleId id,
int index, bool *redeclared);
};

View File

@ -855,6 +855,7 @@ class AutoNameVector : public AutoVectorRooter<PropertyName *>
JS_ALWAYS_INLINE const jschar *
JSString::getChars(JSContext *cx)
{
JS::AutoAssertNoGC nogc;
if (JSLinearString *str = ensureLinear(cx))
return str->chars();
return NULL;
@ -863,6 +864,7 @@ JSString::getChars(JSContext *cx)
JS_ALWAYS_INLINE const jschar *
JSString::getCharsZ(JSContext *cx)
{
JS::AutoAssertNoGC nogc;
if (JSFlatString *str = ensureFlat(cx))
return str->chars();
return NULL;
@ -871,6 +873,7 @@ JSString::getCharsZ(JSContext *cx)
JS_ALWAYS_INLINE JSLinearString *
JSString::ensureLinear(JSContext *cx)
{
JS::AutoAssertNoGC nogc;
return isLinear()
? &asLinear()
: asRope().flatten(cx);
@ -879,6 +882,7 @@ JSString::ensureLinear(JSContext *cx)
JS_ALWAYS_INLINE JSFlatString *
JSString::ensureFlat(JSContext *cx)
{
JS::AutoAssertNoGC nogc;
return isFlat()
? &asFlat()
: isDependent()
@ -889,6 +893,7 @@ JSString::ensureFlat(JSContext *cx)
JS_ALWAYS_INLINE JSStableString *
JSString::ensureStable(JSContext *maybecx)
{
JS::AutoAssertNoGC nogc;
if (isRope()) {
JSFlatString *flat = asRope().flatten(maybecx);
if (!flat)

View File

@ -22,6 +22,7 @@ namespace js {
inline bool
StringObject::init(JSContext *cx, HandleString str)
{
AssertCanGC();
JS_ASSERT(gc::GetGCKindSlots(getAllocKind()) == 2);
Rooted<StringObject *> self(cx, this);
@ -31,10 +32,11 @@ StringObject::init(JSContext *cx, HandleString str)
if (!assignInitialShape(cx))
return false;
} else {
Shape *shape = assignInitialShape(cx);
RootedShape shape(cx, assignInitialShape(cx));
if (!shape)
return false;
EmptyShape::insertInitialShape(cx, shape, self->getProto());
RootedObject proto(cx, self->getProto());
EmptyShape::insertInitialShape(cx, shape, proto);
}
}

View File

@ -66,7 +66,7 @@ class StringObject : public JSObject
* encodes the initial length property. Return the shape after changing
* this String object's last property to it.
*/
Shape *assignInitialShape(JSContext *cx);
UnrootedShape assignInitialShape(JSContext *cx);
};
} // namespace js