Move JSObject::parent to BaseShape, bug 638316.

This commit is contained in:
Brian Hackett 2011-10-13 20:21:36 -07:00
Родитель def71d2001
Коммит c948505ab2
41 изменённых файлов: 433 добавлений и 365 удалений

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

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

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

@ -3066,8 +3066,7 @@ JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
JS_ASSERT(!obj->isScope());
JS_ASSERT(parent || !obj->getParent());
assertSameCompartment(cx, obj, parent);
obj->setParent(parent);
return true;
return obj->setParent(cx, parent);
}
JS_PUBLIC_API(JSObject *)

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

@ -1338,7 +1338,8 @@ JSObject::makeDenseArraySlow(JSContext *cx)
/* Create a native scope. */
gc::AllocKind kind = getAllocKind();
if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind)) {
if (!InitScopeForObject(cx, this, &SlowArrayClass, oldShape->getObjectParent(),
getProto()->getNewType(cx), kind)) {
setLastPropertyInfallible(oldShape);
return false;
}

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

@ -309,6 +309,9 @@ JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, A
JSObject* FASTCALL
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent)
{
JS_NOT_REACHED("FIXME");
return NULL;
#if 0
JS_ASSERT(funobj->isFunction());
JS_ASSERT(proto->isFunction());
JS_ASSERT(JS_ON_TRACE(cx));
@ -328,6 +331,7 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa
return NULL;
}
return closure;
#endif
}
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,
0, ACCSET_STORE_ANY)

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

@ -88,16 +88,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
regExpAllocator(NULL),
#endif
propertyTree(thisForCtor()),
emptyStrictArgumentsShape(NULL),
emptyNormalArgumentsShape(NULL),
emptyBlockShape(NULL),
emptyCallShape(NULL),
emptyDeclEnvShape(NULL),
emptyEnumeratorShape(NULL),
emptyWithShape(NULL),
emptyTypeObject(NULL),
initialRegExpShape(NULL),
initialStringShape(NULL),
debugModeBits(rt->debugMode ? DebugFromC : 0),
mathCache(NULL),
breakpointSites(rt),
@ -281,7 +272,8 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
JS_ASSERT(obj->isCrossCompartmentWrapper());
if (global->getJSClass() != &js_dummy_class && obj->getParent() != global) {
do {
obj->setParent(global);
if (!obj->setParent(cx, global))
return false;
obj = obj->getProto();
} while (obj && obj->isCrossCompartmentWrapper());
}
@ -335,7 +327,8 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (!crossCompartmentWrappers.put(GetProxyPrivate(wrapper), *vp))
return false;
wrapper->setParent(global);
if (!wrapper->setParent(cx, global))
return false;
return true;
}
@ -492,14 +485,6 @@ JSCompartment::markTypes(JSTracer *trc)
MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan");
}
template <class T>
void
CheckWeakReference(JSContext *cx, T *&ptr)
{
if (ptr && IsAboutToBeFinalized(cx, ptr))
ptr = NULL;
}
void
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
{
@ -516,21 +501,11 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
/* Remove dead references held weakly by the compartment. */
CheckWeakReference(cx, emptyStrictArgumentsShape);
CheckWeakReference(cx, emptyNormalArgumentsShape);
CheckWeakReference(cx, emptyBlockShape);
CheckWeakReference(cx, emptyCallShape);
CheckWeakReference(cx, emptyDeclEnvShape);
CheckWeakReference(cx, emptyEnumeratorShape);
CheckWeakReference(cx, emptyWithShape);
CheckWeakReference(cx, initialRegExpShape);
CheckWeakReference(cx, initialStringShape);
sweepBaseShapeTable(cx);
sweepNewTypeObjectTable(cx);
CheckWeakReference(cx, emptyTypeObject);
if (emptyTypeObject && IsAboutToBeFinalized(cx, emptyTypeObject))
emptyTypeObject = NULL;
sweepBreakpoints(cx);

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

@ -474,25 +474,22 @@ struct JS_FRIEND_API(JSCompartment) {
#endif
/*
* Runtime-shared empty scopes for well-known built-in objects that lack
* class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
*/
js::EmptyShape *emptyStrictArgumentsShape;
js::EmptyShape *emptyNormalArgumentsShape;
js::EmptyShape *emptyBlockShape;
js::EmptyShape *emptyCallShape;
js::EmptyShape *emptyDeclEnvShape;
js::EmptyShape *emptyEnumeratorShape;
js::EmptyShape *emptyWithShape;
/*
* Set of all unowned base shapes in the compartment, with optional empty
* scopes. For sharing between shapes with common state.
* Set of all unowned base shapes in the compartment, with optional initial
* shape for objects with the base shape. The initial shape is filled in
* several circumstances:
*
* - For non-native classes and classes without class prototypes (scope
* chain classes, arguments, and iterators), the initial shape is set to
* an empty shape for the class/parent.
*
* - For the String and RegExp classes, the initial shape is preloaded with
* non-configurable properties of the objects mapping the class's various
* fixed slots.
*/
struct BaseShapeEntry {
js::UnownedBaseShape *base;
js::EmptyShape *empty;
js::Shape *shape;
typedef const js::BaseShape *Lookup;
@ -529,18 +526,6 @@ struct JS_FRIEND_API(JSCompartment) {
/* Get the default 'new' type for objects with a NULL prototype. */
inline js::types::TypeObject *getEmptyType(JSContext *cx);
/*
* Initial shapes given to RegExp and String objects, encoding the initial
* sets of built-in instance properties and the fixed slots where they must
* be stored (see JSObject::JSSLOT_(REGEXP|STRING)_*). Later property
* additions may cause these shapes to not be used by a RegExp or String
* (even along the entire shape parent chain, should the object go into
* dictionary mode). But because all the initial properties are
* non-configurable, they will always map to fixed slots.
*/
const js::Shape *initialRegExpShape;
const js::Shape *initialStringShape;
private:
enum { DebugFromC = 1, DebugFromJS = 2 };

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

@ -1374,7 +1374,8 @@ js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox,
js_PushStatement(tc, stmt, STMT_BLOCK, top);
stmt->flags |= SIF_SCOPE;
blockBox->parent = tc->blockChainBox;
blockBox->object->setParent(tc->blockChain());
if (tc->blockChain())
blockBox->object->setScopeChain(tc->blockChain());
stmt->downScope = tc->topScopeStmt;
tc->topScopeStmt = stmt;
tc->blockChainBox = blockBox;
@ -2029,8 +2030,8 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
*/
if ((cg->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
cg->bindings.extensibleParents()) {
Shape *shape = Shape::setExtensibleParents(cx, blockObj->lastProperty());
if (!shape)
Shape *shape = blockObj->lastProperty();
if (!Shape::setExtensibleParents(cx, &shape))
return false;
blockObj->setLastPropertyInfallible(shape);
}

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

@ -720,7 +720,7 @@ Exception(JSContext *cx, uintN argc, Value *vp)
}
JSObject *errProto = &protov.toObject();
JSObject *obj = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
JSObject *obj = NewNativeClassInstance(cx, &ErrorClass, errProto);
if (!obj)
return false;
@ -1168,7 +1168,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
goto out;
tv[0] = OBJECT_TO_JSVAL(errProto);
errObject = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
errObject = NewNativeClassInstance(cx, &ErrorClass, errProto);
if (!errObject) {
ok = JS_FALSE;
goto out;
@ -1356,7 +1356,7 @@ js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope)
JSObject *proto;
if (!js_GetClassPrototype(cx, scope->getGlobal(), GetExceptionProtoKey(copy->exnType), &proto))
return NULL;
JSObject *copyobj = NewNativeClassInstance(cx, &ErrorClass, proto, proto->getParent());
JSObject *copyobj = NewNativeClassInstance(cx, &ErrorClass, proto);
copyobj->setPrivate(copy);
autoFree.p = NULL;
return copyobj;

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

@ -180,6 +180,7 @@ struct TypeObject {
struct BaseShape {
js::Class *clasp;
JSObject *parent;
};
struct Shape {
@ -190,7 +191,7 @@ struct Object {
Shape *shape;
TypeObject *type;
uint32 flags;
JSObject *parent;
uint32 _2;
js::Value *slots;
js::Value *_1;
@ -242,7 +243,7 @@ inline JSObject *
GetObjectParent(const JSObject *obj)
{
JS_ASSERT(!IsScopeObject(obj));
return reinterpret_cast<const shadow::Object*>(obj)->parent;
return reinterpret_cast<const shadow::Object*>(obj)->shape->base->parent;
}
JS_FRIEND_API(JSObject *)

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

@ -204,7 +204,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
return NULL;
bool strict = callee.toFunction()->inStrictMode();
EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx, strict);
Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
Shape *emptyArgumentsShape = BaseShape::lookupInitialShape(cx, clasp, proto->getParent());
if (!emptyArgumentsShape)
return NULL;
@ -215,7 +216,7 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
SetValueRangeToUndefined(data->slots, argc);
/* Can't fail from here on, so initialize everything in argsobj. */
obj->init(cx, type, proto->getParent(), false);
obj->init(cx, type, false);
obj->setInitialPropertyInfallible(emptyArgumentsShape);
ArgumentsObject *argsobj = obj->asArguments();
@ -770,10 +771,11 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
if (!type)
return NULL;
EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
JSObject *parent = fp->scopeChain().getGlobal();
Shape *emptyDeclEnvShape = BaseShape::lookupInitialShape(cx, &DeclEnvClass, parent);
if (!emptyDeclEnvShape)
return NULL;
envobj->init(cx, type, fp->scopeChain().getGlobal(), false);
envobj->init(cx, type, false);
envobj->setInitialPropertyInfallible(emptyDeclEnvShape);
envobj->setPrivate(fp);
@ -1435,11 +1437,10 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
* Make the prototype object an instance of Object with the same parent
* as the function object itself.
*/
JSObject *parent = obj->getParent();
JSObject *objProto;
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto))
if (!js_GetClassPrototype(cx, obj->getParent(), JSProto_Object, &objProto))
return NULL;
JSObject *proto = NewNativeClassInstance(cx, &ObjectClass, objProto, parent);
JSObject *proto = NewNativeClassInstance(cx, &ObjectClass, objProto);
if (!proto || !proto->setSingletonType(cx))
return NULL;
@ -1572,7 +1573,8 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
if (!fun)
return false;
fun->clearParent();
if (!fun->clearParent(cx))
return false;
if (!fun->clearType(cx))
return false;
}
@ -2060,7 +2062,8 @@ fun_bind(JSContext *cx, uintN argc, Value *vp)
return false;
/* NB: Bound functions abuse |parent| to store their target. */
funobj->setParent(target);
if (!funobj->setParent(cx, target))
return false;
/* Steps 7-9. */
Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();

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

@ -5094,6 +5094,14 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
JS_ASSERT_IF(fun && scope, fun->getGlobal() == scope->getGlobal());
script->types->global = fun ? fun->getGlobal() : scope->getGlobal();
/*
* Update the parent in the script's bindings. The bindings are created
* with a NULL parent, and fixing the parent now avoids the need to reshape
* every time a call object is created from the bindings.
*/
if (!script->bindings.setParent(cx, script->types->global))
return false;
if (!cx->typeInferenceEnabled())
return true;

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

@ -800,11 +800,9 @@ struct TypeObject : gc::Cell
}
/*
* Return an immutable, shareable, empty shape with the same clasp as this
* and the same slotSpan as this had when empty.
*
* If |this| is the scope of an object |proto|, the resulting scope can be
* used as the scope of a new object whose prototype is |proto|.
* Return an immutable, shareable, empty shape for objects with this type
* and the specified class, and finalize kind (fixed slot count). Objects
* created with this shape have the same parent as the type's prototype.
*/
inline bool canProvideEmptyShape(js::Class *clasp);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind);

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

@ -192,7 +192,7 @@ js::GetBlockChain(JSContext *cx, StackFrame *fp)
else if (op == JSOP_ENTERBLOCK)
blockChain = script->getObject(indexBase + GET_INDEX(pc));
else if (op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR)
blockChain = blockChain->getParent();
blockChain = blockChain->getStaticBlockScopeChain();
else if (op == JSOP_BLOCKCHAIN)
blockChain = script->getObject(indexBase + GET_INDEX(pc));
else if (op == JSOP_NULLBLOCKCHAIN)
@ -347,7 +347,7 @@ GetScopeChainFull(JSContext *cx, StackFrame *fp, JSObject *blockChain)
JSObject *newChild = innermostNewChild;
for (;;) {
JS_ASSERT(newChild->getProto() == sharedBlock);
sharedBlock = sharedBlock->getParent();
sharedBlock = sharedBlock->getStaticBlockScopeChain();
/* Sometimes limitBlock will be NULL, so check that first. */
if (sharedBlock == limitBlock || !sharedBlock)

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

@ -413,11 +413,11 @@ NewIteratorObject(JSContext *cx, uintN flags)
if (!type)
return NULL;
EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx);
Shape *emptyEnumeratorShape = BaseShape::lookupInitialShape(cx, &IteratorClass, NULL);
if (!emptyEnumeratorShape)
return NULL;
obj->init(cx, type, NULL, false);
obj->init(cx, type, false);
obj->setInitialPropertyInfallible(emptyEnumeratorShape);
JS_ASSERT(obj->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);

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

@ -3087,6 +3087,9 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, ST
JSObject * FASTCALL
js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
{
JS_NOT_REACHED("FIXME");
return NULL;
#if 0
#ifdef DEBUG
JS_ASSERT(ctor->isFunction());
JS_ASSERT(ctor->toFunction()->isInterpreted());
@ -3113,6 +3116,7 @@ js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
return NewNativeClassInstance(cx, &ObjectClass, proto, parent, kind);
#endif
}
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0,
nanojit::ACCSET_STORE_ANY)
@ -3459,9 +3463,9 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
obj->init(cx, type, parent->getGlobal(), false);
obj->init(cx, type, false);
EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
Shape *emptyWithShape = BaseShape::lookupInitialShape(cx, &WithClass, parent->getGlobal());
if (!emptyWithShape)
return NULL;
@ -3497,11 +3501,11 @@ js_NewBlockObject(JSContext *cx)
if (!type)
return NULL;
EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx);
Shape *emptyBlockShape = BaseShape::lookupInitialShape(cx, &BlockClass, NULL);
if (!emptyBlockShape)
return NULL;
blockObj->init(cx, type, NULL, false);
blockObj->init(cx, type, false);
blockObj->setInitialPropertyInfallible(emptyBlockShape);
return blockObj;
@ -4044,7 +4048,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
if (xdr->mode == JSXDR_ENCODE) {
obj = *objp;
parent = obj->getParent();
parent = obj->scopeChain();
parentId = JSScript::isValidOffset(xdr->script->objectsOffset)
? FindObjectIndex(xdr->script->objects(), parent)
: NO_PARENT_INDEX;
@ -4075,7 +4079,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
parent = NULL;
else
parent = xdr->script->getObject(parentId);
obj->setParent(parent);
obj->setScopeChain(parent);
}
AutoObjectRooter tvr(cx, obj);
@ -4537,7 +4541,7 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary());
if (shape->getClass()->flags & JSCLASS_HAS_PRIVATE)
if (shape->getObjectClass()->flags & JSCLASS_HAS_PRIVATE)
initializePrivate();
size_t span = shape->slotSpan();
@ -4554,7 +4558,6 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
shape_ = const_cast<js::Shape *>(shape);
updateSlotsForSpan(0, span);
JS_ASSERT_IF(isScope(), parent);
return true;
}
@ -4565,7 +4568,7 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary());
if (shape->getClass()->flags & JSCLASS_HAS_PRIVATE)
if (shape->getObjectClass()->flags & JSCLASS_HAS_PRIVATE)
initializePrivate();
JS_ASSERT(dynamicSlotsCount(numFixedSlots(), shape->slotSpan()) == 0);
@ -4575,8 +4578,6 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
size_t span = shape->slotSpan();
if (span)
updateSlotsForSpan(0, span);
JS_ASSERT_IF(isScope(), parent);
}
bool

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

@ -498,6 +498,14 @@ struct JSObject : js::gc::Cell
/* As above, but the slot span is guaranteed to fit in the fixed slots. */
void setInitialPropertyInfallible(const js::Shape *shape);
/*
* Remove the last property of an object, provided that it is safe to do so
* (the shape and previous shape do not carry conflicting information about
* the object itself).
*/
inline void removeLastProperty(JSContext *cx);
inline bool canRemoveLastProperty();
/*
* Update the slot span directly for a dictionary object, and allocate
* slots to cover the new span if necessary.
@ -544,7 +552,8 @@ struct JSObject : js::gc::Cell
};
uint32 flags; /* flags */
JSObject *parent; /* object's parent */
uint32 padding;
private:
js::Value *slots; /* Slots for object properties. */
@ -843,7 +852,6 @@ struct JSObject : js::gc::Cell
static inline size_t offsetOfType() { return offsetof(JSObject, type_); }
inline bool clearType(JSContext *cx);
inline void setType(js::types::TypeObject *newType);
js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
@ -867,8 +875,7 @@ struct JSObject : js::gc::Cell
}
inline JSObject *getParent() const;
inline void clearParent();
inline void setParent(JSObject *newParent);
bool setParent(JSContext *cx, JSObject *newParent);
JS_FRIEND_API(js::GlobalObject *) getGlobal() const;
@ -888,6 +895,7 @@ struct JSObject : js::gc::Cell
inline JSObject *getParentOrScopeChain() const;
inline JSObject *getParentMaybeScope() const;
inline JSObject *getStaticBlockScopeChain() const;
static const uint32 SCOPE_CHAIN_SLOT = 0;
@ -899,6 +907,10 @@ struct JSObject : js::gc::Cell
/* N.B. Infallible: NULL means 'no principal', not an error. */
inline JSPrincipals *principals(JSContext *cx);
/* Remove the type (and prototype) or parent from a new object. */
inline bool clearType(JSContext *cx);
bool clearParent(JSContext *cx);
/*
* ES5 meta-object properties and operations.
*/
@ -1237,8 +1249,7 @@ struct JSObject : js::gc::Cell
}
/* The last property is not initialized here and should be set separately. */
void init(JSContext *cx, js::types::TypeObject *type,
JSObject *parent, bool denseArray);
void init(JSContext *cx, js::types::TypeObject *type, bool denseArray);
inline void finish(JSContext *cx);
JS_ALWAYS_INLINE void finalize(JSContext *cx, bool background);
@ -1250,7 +1261,6 @@ struct JSObject : js::gc::Cell
inline bool initSharingEmptyShape(JSContext *cx,
js::Class *clasp,
js::types::TypeObject *type,
JSObject *parent,
void *priv,
js::gc::AllocKind kind);
@ -1434,7 +1444,6 @@ struct JSObject : js::gc::Cell
JS_STATIC_ASSERT(offsetof(JSObject, shape_) == offsetof(js::shadow::Object, shape));
JS_STATIC_ASSERT(offsetof(JSObject, flags) == offsetof(js::shadow::Object, flags));
JS_STATIC_ASSERT(offsetof(JSObject, parent) == offsetof(js::shadow::Object, parent));
JS_STATIC_ASSERT(offsetof(JSObject, slots) == offsetof(js::shadow::Object, slots));
JS_STATIC_ASSERT(offsetof(JSObject, type_) == offsetof(js::shadow::Object, type));
JS_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object));

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

@ -319,32 +319,13 @@ inline JSObject *
JSObject::getParent() const
{
JS_ASSERT(!isScope());
return parent;
}
inline void
JSObject::clearParent()
{
JS_ASSERT(!isScope());
parent = NULL;
}
inline void
JSObject::setParent(JSObject *newParent)
{
#ifdef DEBUG
JS_ASSERT_IF(!isNewborn(), !isScope());
for (JSObject *obj = newParent; obj; obj = obj->getParentOrScopeChain())
JS_ASSERT(obj != this);
#endif
setDelegateNullSafe(newParent);
parent = newParent;
return lastProperty()->getObjectParent();
}
inline bool
JSObject::isScope() const
{
return isCall() || isDeclEnv() || isClonedBlock() || isWith();
return isCall() || isDeclEnv() || isBlock() || isWith();
}
inline JSObject *
@ -360,10 +341,21 @@ JSObject::getParentOrScopeChain() const
return isScope() ? scopeChain() : getParent();
}
inline JSObject *
JSObject::getStaticBlockScopeChain() const
{
/*
* Unlike other scope objects, static blocks not nested in one another
* do not have a scope chain.
*/
JS_ASSERT(isStaticBlock());
return getFixedSlot(0).isObject() ? &getFixedSlot(0).toObject() : NULL;
}
inline JSObject *
JSObject::getParentMaybeScope() const
{
return parent;
return lastProperty()->getObjectParent();
}
inline void
@ -390,10 +382,22 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
if (!type)
return false;
init(cx, type, parent->getGlobal(), false);
init(cx, type, false);
if (!setInitialProperty(cx, bindings.lastShape()))
return false;
/*
* Update the parent for bindings associated with non-compileAndGo scripts,
* whose call objects do not have a consistent global variable and need
* to be updated dynamically.
*/
JSObject *global = parent->getGlobal();
if (global != getParentMaybeScope()) {
JS_ASSERT(getParentMaybeScope() == NULL);
if (!setParent(cx, global))
return false;
}
JS_ASSERT(isCall());
JS_ASSERT(!inDictionaryMode());
@ -415,11 +419,19 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
inline bool
JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame)
{
init(cx, type, frame->scopeChain().getGlobal(), false);
init(cx, type, false);
if (!setInitialProperty(cx, getProto()->lastProperty()))
return false;
/* Set the parent if necessary, as for call objects. */
JSObject *global = frame->scopeChain().getGlobal();
if (global != getParentMaybeScope()) {
JS_ASSERT(getParentMaybeScope() == NULL);
if (!setParent(cx, global))
return false;
}
setPrivate(frame);
JS_ASSERT(!inDictionaryMode());
@ -529,6 +541,28 @@ JSObject::setLastPropertyInfallible(const js::Shape *shape)
shape_ = const_cast<js::Shape *>(shape);
}
inline void
JSObject::removeLastProperty(JSContext *cx)
{
JS_ASSERT(canRemoveLastProperty());
JS_ALWAYS_TRUE(setLastProperty(cx, lastProperty()->previous()));
}
inline bool
JSObject::canRemoveLastProperty()
{
/*
* Some information stored in shapes describes the object itself, and can
* be changed via replaceLastProperty without converting to a dictionary.
* Parent shapes in the property tree may not have this information set,
* and we need to ensure when unwinding properties that the per-object
* information is not accidentally reset.
*/
JS_ASSERT(!inDictionaryMode());
const js::Shape *previous = lastProperty()->previous();
return previous->getObjectParent() == lastProperty()->getObjectParent();
}
inline js::Value
JSObject::getReservedSlot(uintN index) const
{
@ -985,8 +1019,7 @@ JSObject::isQName() const
}
inline void
JSObject::init(JSContext *cx, js::types::TypeObject *type,
JSObject *parent, bool denseArray)
JSObject::init(JSContext *cx, js::types::TypeObject *type, bool denseArray)
{
JS_STATIC_ASSERT(sizeof(js::ObjectElements) == 2 * sizeof(js::Value));
@ -1006,7 +1039,6 @@ JSObject::init(JSContext *cx, js::types::TypeObject *type,
}
setType(type);
setParent(parent);
}
inline void
@ -1022,11 +1054,10 @@ inline bool
JSObject::initSharingEmptyShape(JSContext *cx,
js::Class *aclasp,
js::types::TypeObject *type,
JSObject *parent,
void *privateValue,
js::gc::AllocKind kind)
{
init(cx, type, parent, false);
init(cx, type, false);
js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind);
if (!empty)
@ -1396,18 +1427,18 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri
};
static inline bool
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::TypeObject *type,
gc::AllocKind kind)
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject *parent,
js::types::TypeObject *type, gc::AllocKind kind)
{
JS_ASSERT(clasp->isNative());
/* Share proto's emptyShape only if obj is similar to proto. */
js::EmptyShape *empty = NULL;
if (type->canProvideEmptyShape(clasp))
if (type->canProvideEmptyShape(clasp) && parent == type->proto->getParent())
empty = type->getEmptyShape(cx, clasp, kind);
else
empty = js::EmptyShape::create(cx, clasp);
empty = js::EmptyShape::create(cx, clasp, parent);
if (!empty) {
JS_ASSERT(obj->isNewborn());
return false;
@ -1417,13 +1448,14 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::Ty
}
static inline bool
InitScopeForNonNativeObject(JSContext *cx, JSObject *obj, js::Class *clasp)
InitScopeForNonNativeObject(JSContext *cx, JSObject *obj, js::Class *clasp, JSObject *parent)
{
JS_ASSERT(!clasp->isNative());
js::EmptyShape *empty = js::BaseShape::lookupEmpty(cx, clasp);
const js::Shape *empty = js::BaseShape::lookupInitialShape(cx, clasp, parent);
if (!empty)
return false;
JS_ASSERT(empty->isEmptyShape());
obj->setInitialPropertyInfallible(empty);
return true;
@ -1450,15 +1482,12 @@ CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp)
/*
* Helper optimized for creating a native instance of the given class (not the
* class's prototype object). Use this in preference to NewObject, but use
* NewBuiltinClassInstance if you need the default class prototype as proto,
* and its parent global as parent.
* NewBuiltinClassInstance if you need the default class prototype as proto.
*/
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
JSObject *parent, gc::AllocKind kind)
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, gc::AllocKind kind)
{
JS_ASSERT(proto);
JS_ASSERT(parent);
JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST);
types::TypeObject *type = proto->getNewType(cx);
@ -1482,9 +1511,10 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
* the parent of the prototype's constructor.
*/
bool denseArray = (clasp == &ArrayClass);
obj->init(cx, type, parent, denseArray);
obj->init(cx, type, denseArray);
JS_ASSERT(type->canProvideEmptyShape(clasp));
js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind);
if (!empty || !obj->setInitialProperty(cx, empty))
return NULL;
@ -1493,10 +1523,10 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
}
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto)
{
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
return NewNativeClassInstance(cx, clasp, proto, kind);
}
bool
@ -1532,13 +1562,13 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::AllocKind kind)
JSObject *proto;
if (v.isObject()) {
proto = &v.toObject();
JS_ASSERT(proto->getParent() == global);
} else {
if (!FindClassPrototype(cx, global, protoKey, &proto, clasp))
return NULL;
}
JS_ASSERT(proto->getParent() == global);
return NewNativeClassInstance(cx, clasp, proto, global, kind);
return NewNativeClassInstance(cx, clasp, proto, kind);
}
static inline JSObject *
@ -1636,17 +1666,18 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
if (!obj)
goto out;
obj->init(cx, type, clasp == &ArrayClass);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(cx, type,
(!parent && proto) ? proto->getParent() : parent,
clasp == &ArrayClass);
if (!parent && proto)
parent = proto->getParent();
if (clasp->isNative()
? !InitScopeForObject(cx, obj, clasp, type, kind)
: !InitScopeForNonNativeObject(cx, obj, clasp)) {
? !InitScopeForObject(cx, obj, clasp, parent, type, kind)
: !InitScopeForNonNativeObject(cx, obj, clasp, parent)) {
obj = NULL;
}
@ -1703,15 +1734,16 @@ NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::
if (!obj)
goto out;
obj->init(cx, type, false);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(cx, type,
(!parent && type->proto) ? type->proto->getParent() : parent,
false);
if (!parent && type->proto)
parent = type->proto->getParent();
if (!InitScopeForObject(cx, obj, &ObjectClass, type, kind)) {
if (!InitScopeForObject(cx, obj, &ObjectClass, parent, type, kind)) {
obj = NULL;
goto out;
}
@ -1777,7 +1809,7 @@ NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
if (!obj)
return NULL;
if (!obj->initSharingEmptyShape(cx, clasp, type, proto->getParent(), NULL, kind))
if (!obj->initSharingEmptyShape(cx, clasp, type, NULL, kind))
return NULL;
return obj;
}

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

@ -1946,7 +1946,8 @@ Parser::newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0),
parent, atom);
if (fun && !tc->compileAndGo()) {
fun->clearParent();
if (!fun->clearParent(context))
return NULL;
if (!fun->clearType(context))
return NULL;
}
@ -5529,7 +5530,8 @@ Parser::letStatement()
stmt->downScope = tc->topScopeStmt;
tc->topScopeStmt = stmt;
obj->setParent(tc->blockChain());
if (tc->blockChain())
obj->setScopeChain(tc->blockChain());
blockbox->parent = tc->blockChainBox;
tc->blockChainBox = blockbox;
stmt->blockBox = blockbox;
@ -8884,7 +8886,8 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
if (!obj)
return NULL;
if (!tc->compileAndGo()) {
obj->clearParent();
if (!obj->clearParent(context))
return NULL;
if (!obj->clearType(context))
return NULL;
}

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

@ -282,7 +282,7 @@ Shape::dumpSubtree(JSContext *cx, int level, FILE *fp) const
if (!parent) {
JS_ASSERT(level == 0);
JS_ASSERT(JSID_IS_EMPTY(propid_));
fprintf(fp, "class %s emptyShape\n", getClass()->name);
fprintf(fp, "class %s emptyShape\n", getObjectClass()->name);
} else {
fprintf(fp, "%*sid ", level, "");
dump(cx, fp);

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

@ -1571,7 +1571,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
return false;
}
JSObject *newobj = NewNativeClassInstance(cx, &ObjectClass, proto, proto->getParent());
JSObject *newobj = NewNativeClassInstance(cx, &ObjectClass, proto);
if (!newobj)
return false;

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

@ -144,7 +144,7 @@ js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
JS_ASSERT(obj->isRegExp());
JS_ASSERT(proto->isRegExp());
JSObject *clone = NewNativeClassInstance(cx, &RegExpClass, proto, proto->getParent());
JSObject *clone = NewNativeClassInstance(cx, &RegExpClass, proto);
if (!clone)
return NULL;
@ -310,7 +310,6 @@ RegExp::createFlagged(JSContext *cx, JSString *str, JSString *opt, TokenStream *
const Shape *
JSObject::assignInitialRegExpShape(JSContext *cx)
{
JS_ASSERT(!cx->compartment->initialRegExpShape);
JS_ASSERT(isRegExp());
JS_ASSERT(nativeEmpty());
@ -468,7 +467,8 @@ js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp)
JSObject *obj = NewBuiltinClassInstance(xdr->cx, &RegExpClass);
if (!obj)
return false;
obj->clearParent();
if (!obj->clearParent(xdr->cx))
return false;
if (!obj->clearType(xdr->cx))
return false;

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

@ -747,13 +747,17 @@ JSObject::initRegExp(JSContext *cx, js::RegExp *re)
* will already have the relevant properties, at the relevant locations.
*/
if (nativeEmpty()) {
const js::Shape **shapep = &cx->compartment->initialRegExpShape;
if (!*shapep) {
*shapep = assignInitialRegExpShape(cx);
if (!*shapep)
const js::Shape *shape = js::BaseShape::lookupInitialShape(cx, getClass(), getParent(),
lastProperty());
if (!shape)
return false;
if (shape == lastProperty()) {
shape = assignInitialRegExpShape(cx);
if (!shape)
return false;
js::BaseShape::insertInitialShape(cx, shape);
}
setLastPropertyInfallible(*shapep);
setLastPropertyInfallible(shape);
JS_ASSERT(!nativeEmpty());
}

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

@ -134,14 +134,10 @@ Shape::handoffTableTo(Shape *shape)
BaseShape *nbase = base();
uint32 span = nbase->slotSpan();
JS_ASSERT_IF(shape->hasSlot(), span > shape->slot());
PropertyTable &table = nbase->table();
JS_ASSERT_IF(shape->hasSlot(), nbase->slotSpan() > shape->slot());
this->base_ = nbase->baseUnowned();
new (nbase) BaseShape(shape->base()->toUnowned(), &table, span);
nbase->adoptUnowned(shape->base()->toUnowned());
shape->base_ = nbase;
}
@ -321,6 +317,30 @@ Shape::getChildBinding(JSContext *cx, const js::Shape &child, Shape **lastBindin
return shape;
}
/* static */ bool
Shape::replaceLastProperty(JSContext *cx, const js::Shape &child, Shape **lastp)
{
Shape *shape = *lastp;
JS_ASSERT(!child.inDictionary());
JS_ASSERT(!shape->inDictionary());
Shape *newShape;
if (shape->parent) {
newShape = JS_PROPERTY_TREE(cx).getChild(cx, shape->parent, child);
if (!newShape)
return false;
} else {
newShape = js_NewGCShape(cx);
if (!newShape)
return false;
new (newShape) Shape(&child);
}
*lastp = newShape;
return true;
}
/*
* Get or create a property-tree or dictionary child property of parent, which
* must be lastProp if inDictionaryMode(), else parent must be one of lastProp
@ -600,7 +620,7 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id,
/* Find or create a property tree node labeled by our arguments. */
Shape *shape;
{
BaseShape base(getClass(), attrs, getter, setter);
BaseShape base(getClass(), getParentMaybeScope(), attrs, getter, setter);
BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase)
return NULL;
@ -698,7 +718,7 @@ JSObject::putProperty(JSContext *cx, jsid id,
UnownedBaseShape *nbase;
{
BaseShape base(getClass(), attrs, getter, setter);
BaseShape base(getClass(), getParentMaybeScope(), attrs, getter, setter);
nbase = BaseShape::lookup(cx, base);
if (!nbase)
return NULL;
@ -748,13 +768,10 @@ JSObject::putProperty(JSContext *cx, jsid id,
return NULL;
}
if (shape == lastProperty()) {
uint32 span = shape->base()->slotSpan();
PropertyTable *table = &shape->base()->table();
new (shape->base()) BaseShape(nbase, table, span);
} else {
if (shape == lastProperty())
shape->base()->adoptUnowned(nbase);
else
shape->base_ = nbase;
}
shape->slot_ = slot;
shape->attrs = uint8(attrs);
@ -778,7 +795,7 @@ JSObject::putProperty(JSContext *cx, jsid id,
* If any shape in the tree has a property hashtable, it is shared and
* immutable too, therefore we must not update *spp.
*/
BaseShape base(getClass(), attrs, getter, setter);
BaseShape base(getClass(), getParentMaybeScope(), attrs, getter, setter);
BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase)
return NULL;
@ -865,8 +882,11 @@ JSObject::removeProperty(JSContext *cx, jsid id)
if (!shape)
return true;
/* If shape is not the last property added, switch to dictionary mode. */
if (shape != lastProperty() && !inDictionaryMode()) {
/*
* If shape is not the last property added, or the last property cannot
* be removed, switch to dictionary mode.
*/
if (!inDictionaryMode() && (shape != lastProperty() || !canRemoveLastProperty())) {
if (!toDictionaryMode(cx))
return false;
spp = nativeSearch(cx, shape->propid());
@ -944,7 +964,7 @@ JSObject::removeProperty(JSContext *cx, jsid id)
* lineage.
*/
JS_ASSERT(shape == lastProperty());
JS_ALWAYS_TRUE(setLastProperty(cx, shape->parent));
removeLastProperty(cx);
}
CHECK_SHAPE_CONSISTENCY(this);
@ -976,17 +996,22 @@ JSObject::clear(JSContext *cx)
void
JSObject::rollbackProperties(JSContext *cx, uint32 slotSpan)
{
/* Remove properties from this object until it has a matching slot span. */
/*
* Remove properties from this object until it has a matching slot span.
* The object cannot have escaped in a way which would prevent safe
* removal of the last properties.
*/
JS_ASSERT(!inDictionaryMode() && slotSpan <= this->slotSpan());
while (this->slotSpan() != slotSpan) {
JS_ASSERT(lastProperty()->hasSlot() && getSlot(lastProperty()->slot()).isUndefined());
JS_ALWAYS_TRUE(setLastProperty(cx, lastProperty()->parent));
removeLastProperty(cx);
}
}
bool
JSObject::generateOwnShape(JSContext *cx, Shape *newShape)
{
#if 0
#ifdef JS_TRACER
JS_ASSERT_IF(!parent && JS_ON_TRACE(cx), JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit);
LeaveTraceIfGlobalObject(cx, this);
@ -998,6 +1023,7 @@ JSObject::generateOwnShape(JSContext *cx, Shape *newShape)
*/
if (TraceRecorder *tr = TRACE_RECORDER(cx))
tr->forgetGuardedShapesForObject(this);
#endif
#endif
if (!inDictionaryMode() && !toDictionaryMode(cx))
@ -1073,13 +1099,46 @@ JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape)
return generateOwnShape(cx);
}
bool
JSObject::clearParent(JSContext *cx)
{
return setParent(cx, NULL);
}
bool
JSObject::setParent(JSContext *cx, JSObject *parent)
{
if (inDictionaryMode()) {
lastProperty()->base()->setParent(parent);
return true;
}
return Shape::setObjectParent(cx, parent, &shape_);
}
/* static */ bool
Shape::setObjectParent(JSContext *cx, JSObject *parent, Shape **listp)
{
BaseShape base(*(*listp)->base()->unowned());
base.setParent(parent);
BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase)
return false;
Shape child(*listp);
child.base_ = nbase;
return replaceLastProperty(cx, child, listp);
}
/* static */ inline HashNumber
JSCompartment::BaseShapeEntry::hash(const js::BaseShape *base)
{
JS_ASSERT(!base->isOwned());
JSDHashNumber hash = base->flags;
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(base->clasp);
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsuword(base->clasp) >> 3);
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsuword(base->parent) >> 3);
if (base->rawGetter)
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(base->rawGetter);
if (base->rawSetter)
@ -1095,6 +1154,7 @@ JSCompartment::BaseShapeEntry::match(const BaseShapeEntry &entry, const BaseShap
return key->flags == lookup->flags
&& key->clasp == lookup->clasp
&& key->parent == lookup->parent
&& key->getterObj == lookup->getterObj
&& key->setterObj == lookup->setterObj;
}
@ -1118,7 +1178,7 @@ LookupBaseShape(JSContext *cx, const BaseShape &base)
JSCompartment::BaseShapeEntry entry;
entry.base = static_cast<UnownedBaseShape *>(nbase);
entry.empty = NULL;
entry.shape = NULL;
if (!table.relookupOrAdd(p, &base, entry))
return NULL;
@ -1133,20 +1193,33 @@ BaseShape::lookup(JSContext *cx, const BaseShape &base)
return entry ? entry->base : NULL;
}
/* static */ EmptyShape *
BaseShape::lookupEmpty(JSContext *cx, Class *clasp)
/* static */ Shape *
BaseShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent, Shape *initial)
{
js::BaseShape base(clasp);
js::BaseShape base(clasp, parent);
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, base);
if (!entry)
return NULL;
if (entry->empty)
return entry->empty;
if (entry->shape)
return entry->shape;
entry->empty = (EmptyShape *) JS_PROPERTY_TREE(cx).newShape(cx);
if (!entry->empty)
if (initial) {
entry->shape = initial;
return entry->shape;
}
entry->shape = JS_PROPERTY_TREE(cx).newShape(cx);
if (!entry->shape)
return NULL;
return new (entry->empty) EmptyShape(entry->base);
return new (entry->shape) EmptyShape(entry->base);
}
/* static */ void
BaseShape::insertInitialShape(JSContext *cx, const Shape *initial)
{
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, *initial->base());
JS_ASSERT(entry && entry->base == initial->base());
entry->shape = const_cast<Shape *>(initial);
}
void
@ -1158,8 +1231,8 @@ JSCompartment::sweepBaseShapeTable(JSContext *cx)
const_cast<JSCompartment::BaseShapeEntry &>(e.front());
if (!entry.base->isMarked())
e.removeFront();
else if (entry.empty && !entry.empty->isMarked())
entry.empty = NULL;
else if (entry.shape && !entry.shape->isMarked())
entry.shape = NULL;
}
}
}
@ -1173,32 +1246,22 @@ BaseShape::finalize(JSContext *cx, bool background)
}
}
/* static */ Shape *
Shape::setExtensibleParents(JSContext *cx, Shape *shape)
/* static */ bool
Shape::setExtensibleParents(JSContext *cx, Shape **listp)
{
Shape *shape = *listp;
JS_ASSERT(!shape->inDictionary());
BaseShape base(shape->getClass(), shape->attrs, shape->getter(), shape->setter());
BaseShape base(*shape->base()->unowned());
base.flags |= BaseShape::EXTENSIBLE_PARENTS;
BaseShape *nbase = BaseShape::lookup(cx, base);
if (!nbase)
return NULL;
Shape child(nbase, shape->maybePropid(), shape->maybeSlot(),
shape->attrs, shape->flags, shape->maybeShortid());
Shape *newShape;
if (shape->parent) {
newShape = JS_PROPERTY_TREE(cx).getChild(cx, shape->parent, child);
if (!newShape)
return NULL;
} else {
newShape = js_NewGCShape(cx);
if (!newShape)
return NULL;
new (newShape) Shape(child);
}
Shape child(shape);
child.base_ = nbase;
return newShape;
return replaceLastProperty(cx, child, listp);
}
bool
@ -1206,9 +1269,13 @@ Bindings::setExtensibleParents(JSContext *cx)
{
if (!ensureShape(cx))
return false;
Shape *shape = Shape::setExtensibleParents(cx, lastBinding);
if (!shape)
return false;
lastBinding = shape;
return true;
return Shape::setExtensibleParents(cx, &lastBinding);
}
bool
Bindings::setParent(JSContext *cx, JSObject *obj)
{
if (!ensureShape(cx))
return false;
return Shape::setObjectParent(cx, obj, &lastBinding);
}

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

@ -350,7 +350,8 @@ class BaseShape : public js::gc::Cell
EXTENSIBLE_PARENTS = 0x8
};
Class *clasp; /* Class of referring shape/object. */
Class *clasp; /* Class of referring object. */
JSObject *parent; /* Parent of referring object. */
uint32 flags; /* Vector of above flags. */
uint32 slotSpan_; /* Object slot span for BaseShapes at
* dictionary last properties. */
@ -373,21 +374,20 @@ class BaseShape : public js::gc::Cell
/* For owned BaseShapes, the shape's property table. */
PropertyTable *table_;
#if JS_BITS_PER_WORD == 32
void *padding;
#endif
public:
void finalize(JSContext *cx, bool background);
BaseShape(Class *clasp) {
BaseShape(Class *clasp, JSObject *parent) {
PodZero(this);
this->clasp = clasp;
this->parent = parent;
}
BaseShape(Class *clasp, uint8 attrs, js::PropertyOp rawGetter, js::StrictPropertyOp rawSetter) {
BaseShape(Class *clasp, JSObject *parent,
uint8 attrs, js::PropertyOp rawGetter, js::StrictPropertyOp rawSetter) {
PodZero(this);
this->clasp = clasp;
this->parent = parent;
this->rawGetter = rawGetter;
this->rawSetter = rawSetter;
if ((attrs & JSPROP_GETTER) && rawGetter)
@ -396,11 +396,13 @@ class BaseShape : public js::gc::Cell
flags |= HAS_SETTER_OBJECT;
}
inline BaseShape(UnownedBaseShape *base, PropertyTable *table, uint32 slotSpan);
inline void adoptUnowned(UnownedBaseShape *other);
bool isOwned() const { return !!(flags & OWNED_SHAPE); }
void setOwned(UnownedBaseShape *unowned) { flags |= OWNED_SHAPE; this->unowned_ = unowned; }
void setParent(JSObject *obj) { parent = obj; }
bool hasGetterObject() const { return !!(flags & HAS_GETTER_OBJECT); }
JSObject *getterObject() const { JS_ASSERT(hasGetterObject()); return getterObj; }
@ -416,7 +418,17 @@ class BaseShape : public js::gc::Cell
/* Lookup base shapes from the compartment's baseShapes table. */
static UnownedBaseShape *lookup(JSContext *cx, const BaseShape &base);
static EmptyShape *lookupEmpty(JSContext *cx, Class *clasp);
/*
* Lookup a base shape from the baseShapes table, returning any associated
* initial shape and, constructing one (or reusing the 'shape' parameter)
* if none was found.
*/
static Shape *lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
Shape *initial = NULL);
/* Reinsert a possibly modified initial shape to the baseShapes table. */
static void insertInitialShape(JSContext *cx, const Shape *initial);
/* Get the canonical base shape. */
inline UnownedBaseShape *unowned();
@ -429,6 +441,7 @@ class BaseShape : public js::gc::Cell
/* For JIT usage */
static inline size_t offsetOfClass() { return offsetof(BaseShape, clasp); }
static inline size_t offsetOfParent() { return offsetof(BaseShape, parent); }
private:
static void staticAsserts() {
@ -438,14 +451,6 @@ class BaseShape : public js::gc::Cell
class UnownedBaseShape : public BaseShape {};
BaseShape::BaseShape(UnownedBaseShape *base, PropertyTable *table, uint32 slotSpan)
{
*this = *static_cast<BaseShape *>(base);
setOwned(base);
setTable(table);
setSlotSpan(slotSpan);
}
UnownedBaseShape *
BaseShape::unowned()
{
@ -462,7 +467,7 @@ UnownedBaseShape *
BaseShape::baseUnowned()
{
JS_ASSERT(isOwned() && unowned_); return unowned_;
}
}
struct Shape : public js::gc::Cell
{
@ -520,6 +525,9 @@ struct Shape : public js::gc::Cell
js::Shape *getChildBinding(JSContext *cx, const js::Shape &child, js::Shape **lastBinding);
/* Replace the last shape in a non-dictionary lineage with child. */
static bool replaceLastProperty(JSContext *cx, const js::Shape &child, Shape **lastp);
bool hashify(JSContext *cx);
void handoffTableTo(Shape *newShape);
@ -553,7 +561,7 @@ struct Shape : public js::gc::Cell
}
bool isNative() const {
JS_ASSERT(!(flags & NON_NATIVE) == getClass()->isNative());
JS_ASSERT(!(flags & NON_NATIVE) == getObjectClass()->isNative());
return !(flags & NON_NATIVE);
}
@ -590,7 +598,10 @@ struct Shape : public js::gc::Cell
return Range(this);
}
Class *getClass() const { return base()->clasp; }
Class *getObjectClass() const { return base()->clasp; }
JSObject *getObjectParent() const { return base()->parent; }
static bool setObjectParent(JSContext *cx, JSObject *obj, Shape **listp);
protected:
/*
@ -610,9 +621,15 @@ struct Shape : public js::gc::Cell
Shape(BaseShape *base, jsid id, uint32 slot, uintN attrs, uintN flags, intN shortid);
/* Get a shape identical to this one, without parent/kids information. */
Shape(const Shape *other);
/* Used by EmptyShape (see jsscopeinlines.h). */
Shape(BaseShape *base);
/* Copy constructor disabled, to avoid misuse of the above form. */
Shape(const Shape &other);
bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; }
/*
@ -717,7 +734,7 @@ struct Shape : public js::gc::Cell
uint32 slotSpan() const {
JS_ASSERT(!inDictionary());
uint32 free = JSSLOT_FREE(getClass());
uint32 free = JSSLOT_FREE(getObjectClass());
return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
}
@ -806,7 +823,7 @@ struct Shape : public js::gc::Cell
* Call or Block objects need unique shapes. If the flag is clear, then we
* can use lastBinding's shape.
*/
static Shape * setExtensibleParents(JSContext *cx, Shape *shape);
static bool setExtensibleParents(JSContext *cx, Shape **listp);
bool extensibleParents() const { return !!(base()->flags & BaseShape::EXTENSIBLE_PARENTS); }
uint32 entryCount() const {
@ -842,8 +859,8 @@ struct EmptyShape : public js::Shape
{
EmptyShape(BaseShape *base);
static EmptyShape *create(JSContext *cx, js::Class *clasp) {
BaseShape lookup(clasp);
static EmptyShape *create(JSContext *cx, js::Class *clasp, JSObject *parent) {
BaseShape lookup(clasp, parent);
BaseShape *base = BaseShape::lookup(cx, lookup);
if (!base)
return NULL;
@ -853,23 +870,6 @@ struct EmptyShape : public js::Shape
return NULL;
return new (eprop) EmptyShape(base);
}
static EmptyShape *ensure(JSContext *cx, js::Class *clasp, EmptyShape **shapep) {
EmptyShape *shape = *shapep;
if (!shape) {
if (!(shape = create(cx, clasp)))
return NULL;
return *shapep = shape;
}
return shape;
}
static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx, bool strict);
static inline EmptyShape *getEmptyBlockShape(JSContext *cx);
static inline EmptyShape *getEmptyCallShape(JSContext *cx);
static inline EmptyShape *getEmptyDeclEnvShape(JSContext *cx);
static inline EmptyShape *getEmptyEnumeratorShape(JSContext *cx);
static inline EmptyShape *getEmptyWithShape(JSContext *cx);
};
} /* namespace js */
@ -938,7 +938,7 @@ Shape::search(JSContext *cx, js::Shape **pstart, jsid id, bool adding)
inline js::Class *
JSObject::getClass() const
{
return lastProperty()->getClass();
return lastProperty()->getObjectClass();
}
inline JSClass *

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

@ -63,8 +63,7 @@ static const uint32 TYPE_OBJECT_EMPTY_SHAPE_COUNT =
((js::gc::FINALIZE_FUNCTION - js::gc::FINALIZE_OBJECT0) / 2) + 1;
inline js::EmptyShape *
js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
gc::AllocKind kind)
js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind)
{
JS_ASSERT(!singleton);
@ -92,7 +91,7 @@ js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
* Always fill in emptyShapes[0], so canProvideEmptyShape works.
* Other empty shapes are filled in lazily.
*/
emptyShapes[0] = EmptyShape::create(cx, aclasp);
emptyShapes[0] = EmptyShape::create(cx, aclasp, proto->getParent());
if (!emptyShapes[0]) {
cx->free_(emptyShapes);
emptyShapes = NULL;
@ -100,10 +99,10 @@ js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
}
}
JS_ASSERT(aclasp == emptyShapes[0]->getClass());
JS_ASSERT(aclasp == emptyShapes[0]->getObjectClass());
if (!emptyShapes[i]) {
emptyShapes[i] = EmptyShape::create(cx, aclasp);
emptyShapes[i] = EmptyShape::create(cx, aclasp, proto->getParent());
if (!emptyShapes[i])
return NULL;
}
@ -114,7 +113,7 @@ js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
inline bool
js::types::TypeObject::canProvideEmptyShape(js::Class *aclasp)
{
return proto && !singleton && (!emptyShapes || emptyShapes[0]->getClass() == aclasp);
return proto && !singleton && (!emptyShapes || emptyShapes[0]->getObjectClass() == aclasp);
}
inline void
@ -141,15 +140,18 @@ StringObject::init(JSContext *cx, JSString *str)
{
JS_ASSERT(nativeEmpty());
const Shape **shapep = &cx->compartment->initialStringShape;
if (*shapep) {
setLastPropertyInfallible(*shapep);
const js::Shape *shape = BaseShape::lookupInitialShape(cx, getClass(), getParent(),
lastProperty());
if (!shape)
return false;
if (shape != lastProperty()) {
setLastPropertyInfallible(shape);
} else {
*shapep = assignInitialShape(cx);
if (!*shapep)
shape = assignInitialShape(cx);
if (!shape)
return false;
BaseShape::insertInitialShape(cx, shape);
}
JS_ASSERT(*shapep == lastProperty());
JS_ASSERT(!nativeEmpty());
JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT);
@ -157,6 +159,25 @@ StringObject::init(JSContext *cx, JSString *str)
return true;
}
inline void
BaseShape::adoptUnowned(UnownedBaseShape *other)
{
/*
* This is a base shape owned by a dictionary object, update it to reflect the
* unowned base shape of a new last property.
*/
JS_ASSERT(isOwned());
JS_ASSERT(parent == other->parent);
uint32 span = slotSpan();
PropertyTable *table = &this->table();
*this = *static_cast<BaseShape *>(other);
setOwned(other);
setTable(table);
setSlotSpan(span);
}
inline
Shape::Shape(BaseShape *base, jsid propid, uint32 slot,
uintN attrs, uintN flags, intN shortid)
@ -175,6 +196,20 @@ Shape::Shape(BaseShape *base, jsid propid, uint32 slot,
kids.setNull();
}
inline
Shape::Shape(const Shape *other)
: base_(other->base()->unowned()),
propid_(other->maybePropid()),
numLinearSearches(0),
slot_(other->maybeSlot()),
attrs(other->attrs),
flags(other->flags),
shortid_(other->maybeShortid()),
parent(NULL)
{
kids.setNull();
}
inline
Shape::Shape(BaseShape *base)
: base_(base),
@ -321,48 +356,10 @@ EmptyShape::EmptyShape(BaseShape *base)
: js::Shape(base)
{
/* Only empty shapes can be NON_NATIVE. */
if (!getClass()->isNative())
if (!getObjectClass()->isNative())
flags |= NON_NATIVE;
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyArgumentsShape(JSContext *cx, bool strict)
{
if (strict)
return ensure(cx, &StrictArgumentsObjectClass, &cx->compartment->emptyStrictArgumentsShape);
return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyNormalArgumentsShape);
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyBlockShape(JSContext *cx)
{
return ensure(cx, &BlockClass, &cx->compartment->emptyBlockShape);
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyCallShape(JSContext *cx)
{
return ensure(cx, &CallClass, &cx->compartment->emptyCallShape);
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyDeclEnvShape(JSContext *cx)
{
return ensure(cx, &DeclEnvClass, &cx->compartment->emptyDeclEnvShape);
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyEnumeratorShape(JSContext *cx)
{
return ensure(cx, &IteratorClass, &cx->compartment->emptyEnumeratorShape);
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyWithShape(JSContext *cx)
{
return ensure(cx, &WithClass, &cx->compartment->emptyWithShape);
}
} /* namespace js */
#endif /* jsscopeinlines_h___ */

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

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

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

@ -211,6 +211,8 @@ class Bindings {
inline bool extensibleParents();
bool setExtensibleParents(JSContext *cx);
bool setParent(JSContext *cx, JSObject *obj);
enum {
/*
* A script may have no more than this many arguments, variables, or

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

@ -93,7 +93,7 @@ bool
Bindings::ensureShape(JSContext *cx)
{
if (!lastBinding) {
lastBinding = EmptyShape::getEmptyCallShape(cx);
lastBinding = BaseShape::lookupInitialShape(cx, &CallClass, NULL);
if (!lastBinding)
return false;
}

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

@ -2983,7 +2983,6 @@ static JSFunctionSpec string_static_methods[] = {
const Shape *
StringObject::assignInitialShape(JSContext *cx)
{
JS_ASSERT(!cx->compartment->initialStringShape);
JS_ASSERT(nativeEmpty());
return addDataProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),

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

@ -11131,7 +11131,7 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
JS_ASSERT(!pval.isPrimitive());
JSObject *proto = &pval.toObject();
JS_ASSERT(!proto->isDenseArray());
JS_ASSERT_IF(clasp != &ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getClass() == clasp);
JS_ASSERT_IF(clasp != &ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getObjectClass() == clasp);
proto_ins = w.immpObjGC(proto);
return RECORD_CONTINUE;
@ -11158,7 +11158,7 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
JS_ASSERT(proto->getNewType(cx)->emptyShapes);
EmptyShape *empty = proto->getNewType(cx)->emptyShapes[0];
JS_ASSERT(empty);
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getObjectClass()) == key);
}
#endif

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

@ -221,7 +221,7 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes)
JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
js::EmptyShape *empty = BaseShape::lookupEmpty(cx, &ArrayBufferClass);
js::Shape *empty = BaseShape::lookupInitialShape(cx, &ArrayBufferClass, obj->getParent());
if (!empty)
return false;
obj->setLastPropertyInfallible(empty);
@ -1297,7 +1297,7 @@ class TypedArrayTemplate
JS_ASSERT(obj->getClass() == slowClass());
js::EmptyShape *empty = BaseShape::lookupEmpty(cx, fastClass());
js::Shape *empty = BaseShape::lookupInitialShape(cx, fastClass(), obj->getParent());
if (!empty)
return false;
obj->setLastPropertyInfallible(empty);

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

@ -1304,7 +1304,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
storePtr(ImmPtr(templateObject->type()), Address(result, JSObject::offsetOfType()));
store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));
if (templateObject->isDenseArray()) {
/* Fill in the elements header. */

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

@ -123,7 +123,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())),
loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())),
denseArrayShape(NULL),
stubcc(cx, *thisFromCtor(), frame),
debugMode_(cx->compartment->debugMode()),
#if defined JS_TRACER
@ -999,7 +998,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
}
jit->pcLengths = pcLengths;
jit->denseArrayShape = denseArrayShape;
/*
* WARNING: mics(), callICs() et al depend on the ordering of these
@ -5480,11 +5478,13 @@ mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
RESERVE_IC_SPACE(masm);
pic.fastPathStart = masm.label();
Address parent(pic.objReg, offsetof(JSObject, parent));
masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
masm.loadPtr(Address(pic.objReg, JSObject::offsetOfShape()), pic.shapeReg);
masm.loadPtr(Address(pic.shapeReg, Shape::offsetOfBase()), pic.shapeReg);
Address parent(pic.shapeReg, BaseShape::offsetOfParent());
pic.shapeGuard = masm.label();
Jump inlineJump = masm.branchPtr(Assembler::NotEqual, parent, ImmPtr(0));
Jump inlineJump = masm.branchPtr(Assembler::NotEqual, parent, ImmPtr(NULL));
{
RESERVE_OOL_SPACE(stubcc.masm);
pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(0));

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

@ -436,7 +436,6 @@ class Compiler : public BaseCompiler
js::Vector<uint32, 16> jumpTableOffsets;
js::Vector<LoopEntry, 16> loopEntries;
js::Vector<JSObject *, 0, CompilerAllocPolicy> rootedObjects;
Shape *denseArrayShape;
StubCompiler stubcc;
Label invokeLabel;
Label arityLabel;

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

@ -1552,18 +1552,12 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
RESERVE_OOL_SPACE(stubcc.masm);
ic.slowPathStart = stubcc.syncExit(Uses(3));
if (!denseArrayShape) {
denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass);
if (!denseArrayShape)
return false;
}
// Guard obj is a dense array.
ic.shapeGuard = masm.branchPtr(Assembler::NotEqual,
Address(ic.objReg, JSObject::offsetOfShape()),
ImmPtr(denseArrayShape));
ic.shapeGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, ic.objReg, &ArrayClass);
stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
masm.rematPayload(ic.objRemat, ic.objReg);
// Load the dynamic elements vector.
masm.loadPtr(Address(ic.objReg, JSObject::offsetOfElements()), ic.objReg);
@ -2113,16 +2107,8 @@ mjit::Compiler::jsop_getelem(bool isCall)
stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
}
if (!denseArrayShape) {
denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass);
if (!denseArrayShape)
return false;
}
// Guard obj is a dense array.
ic.shapeGuard = masm.branchPtr(Assembler::NotEqual,
Address(ic.objReg, JSObject::offsetOfShape()),
ImmPtr(denseArrayShape));
ic.shapeGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, ic.typeReg, &ArrayClass);
stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
Int32Key key = id->isConstant()

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

@ -1325,9 +1325,6 @@ JITScript::trace(JSTracer *trc)
for (uint32 i = 0; i < nRootedObjects; ++i)
MarkObject(trc, *rootedObjects()[i], "mjit rooted object");
if (denseArrayShape)
MarkShape(trc, denseArrayShape, "mjit rooted shape");
}
/* static */ const double mjit::Assembler::oneDouble = 1.0;

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

@ -640,9 +640,6 @@ struct JITScript {
// Additional ExecutablePools for native call and getter stubs.
Vector<NativeCallStub, 0, SystemAllocPolicy> nativeCallStubs;
// Rooted shape for dense arrays. :XXX: bug 685358 remove
Shape *denseArrayShape;
NativeMapEntry *nmap() const;
js::mjit::InlineFrame *inlineFrames() const;
js::mjit::CallSite *callSites() const;

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

@ -3019,6 +3019,9 @@ SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key)
Assembler masm;
// Restore |obj|.
masm.rematPayload(StateRemat::FromInt32(objRemat), objReg);
// Guard on this typed array's shape.
Jump shapeGuard = masm.guardShape(objReg, obj);
@ -3030,9 +3033,6 @@ SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key)
else
outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
// Restore |obj|.
masm.rematPayload(StateRemat::FromInt32(objRemat), objReg);
// Load the array's packed data vector.
masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);

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

@ -88,7 +88,7 @@ stubs::BindName(VMFrame &f)
PropertyCacheEntry *entry;
/* Fast-path should have caught this. See comment in interpreter. */
JS_ASSERT(f.fp()->scopeChain().isScope());
JS_ASSERT(!f.fp()->scopeChain().isGlobal());
JSAtom *atom;
JSObject *obj2;

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

@ -430,7 +430,8 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
break;
case ACCSET_OBJ_PARENT:
ok = OK_OBJ_FIELD(LIR_ldp, parent);
ok = false;
//ok = OK_OBJ_FIELD(LIR_ldp, parent);
break;
case ACCSET_OBJ_PRIVATE:

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

@ -505,7 +505,8 @@ class Writer
}
nj::LIns *ldpObjParent(nj::LIns *obj) const {
return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, parent), ACCSET_OBJ_PARENT),
JS_NOT_REACHED("FIXME");
return name(lir->insLoad(nj::LIR_ldp, obj, 0, ACCSET_OBJ_PARENT),
"parent");
}