зеркало из https://github.com/mozilla/gecko-dev.git
Move JSObject::parent to BaseShape, bug 638316.
This commit is contained in:
Родитель
def71d2001
Коммит
c948505ab2
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче