Move scope chains of scope objects to reserved slots, bug 694247.

This commit is contained in:
Brian Hackett 2011-10-12 22:29:43 -07:00
Родитель a4c76d19d1
Коммит 1ca40e7627
23 изменённых файлов: 293 добавлений и 178 удалений

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

@ -2429,7 +2429,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
jsClass = js::GetObjectClass(aObj); jsClass = js::GetObjectClass(aObj);
if (jsClass == &js::CallClass) { if (jsClass == &js::CallClass) {
aObj = js::GetObjectParent(aObj); aObj = js::GetObjectParentMaybeScope(aObj);
if (!aObj) if (!aObj)
return nsnull; return nsnull;
@ -2481,7 +2481,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
} }
} }
aObj = js::GetObjectParent(aObj); aObj = js::GetObjectParentMaybeScope(aObj);
if (!aObj) if (!aObj)
break; break;

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

@ -48,6 +48,7 @@
#include "nsJSUtils.h" #include "nsJSUtils.h"
#include "jsapi.h" #include "jsapi.h"
#include "jsdbgapi.h" #include "jsdbgapi.h"
#include "jsfriendapi.h"
#include "prprf.h" #include "prprf.h"
#include "nsIScriptContext.h" #include "nsIScriptContext.h"
#include "nsIScriptObjectOwner.h" #include "nsIScriptObjectOwner.h"
@ -107,8 +108,7 @@ nsJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj)
if (!glob) if (!glob)
return nsnull; return nsnull;
while ((parent = ::JS_GetParent(aContext, glob))) glob = js::GetGlobalForObject(glob);
glob = parent;
clazz = JS_GET_CLASS(aContext, glob); clazz = JS_GET_CLASS(aContext, glob);

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

@ -3063,6 +3063,7 @@ JS_PUBLIC_API(JSBool)
JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent) JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
JS_ASSERT(!obj->isScope());
JS_ASSERT(parent || !obj->getParent()); JS_ASSERT(parent || !obj->getParent());
assertSameCompartment(cx, obj, parent); assertSameCompartment(cx, obj, parent);
obj->setParent(parent); obj->setParent(parent);
@ -4346,7 +4347,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
JSMSG_BAD_CLONE_FUNOBJ_SCOPE); JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
return NULL; return NULL;
} }
obj = obj->getParent(); obj = obj->getParentOrScopeChain();
} }
Value v; Value v;

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

@ -389,7 +389,7 @@ DeepBail(JSContext *cx);
static JS_INLINE void static JS_INLINE void
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj) LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
{ {
if (!obj->getParent()) if (obj->isGlobal())
LeaveTrace(cx); LeaveTrace(cx);
} }

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

@ -170,6 +170,24 @@ AutoSwitchCompartment::~AutoSwitchCompartment()
cx->compartment = oldCompartment; cx->compartment = oldCompartment;
} }
bool
js::IsScopeObject(const JSObject *obj)
{
return obj->isScope();
}
JS_FRIEND_API(JSObject *)
js::GetObjectParentMaybeScope(const JSObject *obj)
{
return obj->getParentOrScopeChain();
}
JS_FRIEND_API(JSObject *)
js::GetGlobalForObject(JSObject *obj)
{
return obj->getGlobal();
}
/* /*
* The below code is for temporary telemetry use. It can be removed when * The below code is for temporary telemetry use. It can be removed when
* sufficient data has been harvested. * sufficient data has been harvested.

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

@ -236,12 +236,21 @@ GetObjectJSClass(const JSObject *obj)
return js::Jsvalify(GetObjectClass(obj)); return js::Jsvalify(GetObjectClass(obj));
} }
bool IsScopeObject(const JSObject *obj);
inline JSObject * inline JSObject *
GetObjectParent(const JSObject *obj) GetObjectParent(const JSObject *obj)
{ {
JS_ASSERT(!IsScopeObject(obj));
return reinterpret_cast<const shadow::Object*>(obj)->parent; return reinterpret_cast<const shadow::Object*>(obj)->parent;
} }
JS_FRIEND_API(JSObject *)
GetObjectParentMaybeScope(const JSObject *obj);
JS_FRIEND_API(JSObject *)
GetGlobalForObject(JSObject *obj);
inline JSObject * inline JSObject *
GetObjectProto(const JSObject *obj) GetObjectProto(const JSObject *obj)
{ {

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

@ -747,7 +747,9 @@ Class js::StrictArgumentsObjectClass = {
*/ */
Class js::DeclEnvClass = { Class js::DeclEnvClass = {
js_Object_str, js_Object_str,
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(CallObject::DECL_ENV_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */ JS_PropertyStub, /* getProperty */
@ -771,10 +773,12 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx); EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
if (!emptyDeclEnvShape) if (!emptyDeclEnvShape)
return NULL; return NULL;
envobj->init(cx, type, &fp->scopeChain(), false); envobj->init(cx, type, fp->scopeChain().getGlobal(), false);
envobj->setInitialPropertyInfallible(emptyDeclEnvShape); envobj->setInitialPropertyInfallible(emptyDeclEnvShape);
envobj->setPrivate(fp); envobj->setPrivate(fp);
envobj->setScopeChain(&fp->scopeChain());
return envobj; return envobj;
} }
@ -915,7 +919,7 @@ js_PutCallObject(StackFrame *fp)
/* Clear private pointers to fp, which is about to go away. */ /* Clear private pointers to fp, which is about to go away. */
if (js_IsNamedLambda(fun)) { if (js_IsNamedLambda(fun)) {
JSObject *env = callobj.getParent(); JSObject *env = callobj.scopeChain();
JS_ASSERT(env->isDeclEnv()); JS_ASSERT(env->isDeclEnv());
JS_ASSERT(env->getPrivate() == fp); JS_ASSERT(env->getPrivate() == fp);

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

@ -163,10 +163,7 @@ struct JSFunction : public JSObject_Slots2
return flags & JSFUN_JOINABLE; return flags & JSFUN_JOINABLE;
} }
JSObject *callScope() const { inline JSObject *callScope() const;
JS_ASSERT(isInterpreted());
return u.i.scope;
}
/* /*
* FunctionClass reserves two slots, which are free in JSObject::fslots * FunctionClass reserves two slots, which are free in JSObject::fslots
@ -286,49 +283,6 @@ extern JSFunction * JS_FASTCALL
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JSObject *proto); JSObject *proto);
inline JSFunction *
CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
bool ignoreSingletonClone = false)
{
JS_ASSERT(parent);
JSObject *proto;
if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
return NULL;
/*
* For attempts to clone functions at a function definition opcode or from
* a method barrier, don't perform the clone if the function has singleton
* type. CloneFunctionObject was called pessimistically, and we need to
* preserve the type's property that if it is singleton there is only a
* single object with its type in existence.
*/
if (ignoreSingletonClone && fun->hasSingletonType()) {
JS_ASSERT(fun->getProto() == proto);
fun->setParent(parent);
return fun;
}
return js_CloneFunctionObject(cx, fun, parent, proto);
}
inline JSFunction *
CloneFunctionObject(JSContext *cx, JSFunction *fun)
{
/*
* Variant which makes an exact clone of fun, preserving parent and proto.
* Calling the above version CloneFunctionObject(cx, fun, fun->getParent())
* is not equivalent: API clients, including XPConnect, can reparent
* objects so that fun->getGlobal() != fun->getProto()->getGlobal().
* See ReparentWrapperIfFound.
*/
JS_ASSERT(fun->getParent() && fun->getProto());
if (fun->hasSingletonType())
return fun;
return js_CloneFunctionObject(cx, fun, fun->getParent(), fun->getProto());
}
extern JSObject * JS_FASTCALL extern JSObject * JS_FASTCALL
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain); js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain);

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

@ -49,6 +49,14 @@ JSFunction::inStrictMode() const
return script()->strictModeCode; return script()->strictModeCode;
} }
inline JSObject *
JSFunction::callScope() const
{
JS_ASSERT(isInterpreted());
return getParent();
//return u.i.scope;
}
inline void inline void
JSFunction::setJoinable() JSFunction::setJoinable()
{ {
@ -223,6 +231,49 @@ IsBuiltinFunctionConstructor(JSFunction *fun);
const Shape * const Shape *
LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj); LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj);
inline JSFunction *
CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
bool ignoreSingletonClone = false)
{
JS_ASSERT(parent);
JSObject *proto;
if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
return NULL;
/*
* For attempts to clone functions at a function definition opcode or from
* a method barrier, don't perform the clone if the function has singleton
* type. CloneFunctionObject was called pessimistically, and we need to
* preserve the type's property that if it is singleton there is only a
* single object with its type in existence.
*/
if (ignoreSingletonClone && fun->hasSingletonType()) {
JS_ASSERT(fun->getProto() == proto);
fun->setParent(parent);
return fun;
}
return js_CloneFunctionObject(cx, fun, parent, proto);
}
inline JSFunction *
CloneFunctionObject(JSContext *cx, JSFunction *fun)
{
/*
* Variant which makes an exact clone of fun, preserving parent and proto.
* Calling the above version CloneFunctionObject(cx, fun, fun->getParent())
* is not equivalent: API clients, including XPConnect, can reparent
* objects so that fun->getGlobal() != fun->getProto()->getGlobal().
* See ReparentWrapperIfFound.
*/
JS_ASSERT(fun->getParent() && fun->getProto());
if (fun->hasSingletonType())
return fun;
return js_CloneFunctionObject(cx, fun, fun->getParent(), fun->getProto());
}
} /* namespace js */ } /* namespace js */
#endif /* jsfuninlines_h___ */ #endif /* jsfuninlines_h___ */

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

@ -711,7 +711,7 @@ ScanObject(GCMarker *gcmarker, JSObject *obj)
types::TypeObject *type = obj->typeFromGC(); types::TypeObject *type = obj->typeFromGC();
PushMarkStack(gcmarker, type); PushMarkStack(gcmarker, type);
if (JSObject *parent = obj->getParent()) if (JSObject *parent = obj->getParentMaybeScope())
PushMarkStack(gcmarker, parent); PushMarkStack(gcmarker, parent);
/* /*
@ -784,7 +784,7 @@ MarkChildren(JSTracer *trc, JSObject *obj)
MarkTypeObject(trc, obj->typeFromGC(), "type"); MarkTypeObject(trc, obj->typeFromGC(), "type");
/* Trace universal (ops-independent) members. */ /* Trace universal (ops-independent) members. */
if (JSObject *parent = obj->getParent()) if (JSObject *parent = obj->getParentMaybeScope())
MarkObject(trc, *parent, "parent"); MarkObject(trc, *parent, "parent");
Class *clasp = obj->getClass(); Class *clasp = obj->getClass();

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

@ -5115,7 +5115,7 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
* the script is nested inside. * the script is nested inside.
*/ */
while (!scope->isCall()) while (!scope->isCall())
scope = scope->getParent(); scope = scope->scopeChain();
CallObject &call = scope->asCall(); CallObject &call = scope->asCall();
@ -5148,7 +5148,7 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
if (!parent->ensureHasTypes(cx, parentFun)) if (!parent->ensureHasTypes(cx, parentFun))
return false; return false;
if (!parent->types->hasScope()) { if (!parent->types->hasScope()) {
if (!SetScope(cx, parent, scope->getParent())) if (!SetScope(cx, parent, scope->scopeChain()))
return false; return false;
parent->nesting()->activeCall = scope; parent->nesting()->activeCall = scope;
parent->nesting()->argArray = call.argArray(); parent->nesting()->argArray = call.argArray();
@ -5243,7 +5243,7 @@ CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
JS_ASSERT(parent); JS_ASSERT(parent);
while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent) while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
scope = scope->getParent(); scope = scope->scopeChain();
if (scope != parent->nesting()->activeCall) { if (scope != parent->nesting()->activeCall) {
parent->reentrantOuterFunction = true; parent->reentrantOuterFunction = true;
@ -5258,7 +5258,7 @@ CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
* parent. * parent.
*/ */
if (parent->nesting()->parent) { if (parent->nesting()->parent) {
scope = scope->getParent(); scope = scope->scopeChain();
script = parent; script = parent;
goto restart; goto restart;
} }

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

@ -300,7 +300,7 @@ GetScopeChainFull(JSContext *cx, StackFrame *fp, JSObject *blockChain)
*/ */
limitClone = &fp->scopeChain(); limitClone = &fp->scopeChain();
while (limitClone->isWith()) while (limitClone->isWith())
limitClone = limitClone->getParent(); limitClone = limitClone->scopeChain();
JS_ASSERT(limitClone); JS_ASSERT(limitClone);
/* /*
@ -358,10 +358,10 @@ GetScopeChainFull(JSContext *cx, StackFrame *fp, JSObject *blockChain)
if (!clone) if (!clone)
return NULL; return NULL;
newChild->setParent(clone); newChild->setScopeChain(clone);
newChild = clone; newChild = clone;
} }
newChild->setParent(&fp->scopeChain()); newChild->setScopeChain(&fp->scopeChain());
/* /*
@ -1208,7 +1208,7 @@ LeaveWith(JSContext *cx)
JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp())); JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0); JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
withobj->setPrivate(NULL); withobj->setPrivate(NULL);
cx->fp()->setScopeChainNoCallObj(*withobj->getParent()); cx->fp()->setScopeChainNoCallObj(*withobj->scopeChain());
} }
bool bool
@ -2185,7 +2185,7 @@ BEGIN_CASE(JSOP_POPN)
JS_ASSERT_IF(obj, JS_ASSERT_IF(obj,
OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
<= (size_t) (regs.sp - regs.fp()->base())); <= (size_t) (regs.sp - regs.fp()->base()));
for (obj = &regs.fp()->scopeChain(); obj; obj = obj->getParent()) { for (obj = &regs.fp()->scopeChain(); obj; obj = obj->getParentOrScopeChain()) {
if (!obj->isBlock() || !obj->isWith()) if (!obj->isBlock() || !obj->isWith())
continue; continue;
if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp())) if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp()))
@ -2683,7 +2683,7 @@ BEGIN_CASE(JSOP_BINDNAME)
* forms. * forms.
*/ */
obj = &regs.fp()->scopeChain(); obj = &regs.fp()->scopeChain();
if (!obj->getParent()) if (obj->isGlobal())
break; break;
PropertyCacheEntry *entry; PropertyCacheEntry *entry;
@ -4360,7 +4360,7 @@ BEGIN_CASE(JSOP_DEFFUN)
* windows, and user-defined JS functions precompiled and then shared among * windows, and user-defined JS functions precompiled and then shared among
* requests in server-side JS. * requests in server-side JS.
*/ */
if (obj->getParent() != obj2) { if (obj->toFunction()->callScope() != obj2) {
obj = CloneFunctionObject(cx, fun, obj2, true); obj = CloneFunctionObject(cx, fun, obj2, true);
if (!obj) if (!obj)
goto error; goto error;
@ -4487,7 +4487,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
if (!parent) if (!parent)
goto error; goto error;
if (obj->getParent() != parent) { if (obj->toFunction()->callScope() != parent) {
#ifdef JS_TRACER #ifdef JS_TRACER
if (TRACE_RECORDER(cx)) if (TRACE_RECORDER(cx))
AbortRecording(cx, "DEFLOCALFUN for closure"); AbortRecording(cx, "DEFLOCALFUN for closure");
@ -5472,13 +5472,13 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
*/ */
JSObject *obj2 = &regs.fp()->scopeChain(); JSObject *obj2 = &regs.fp()->scopeChain();
while (obj2->isWith()) while (obj2->isWith())
obj2 = obj2->getParent(); obj2 = obj2->scopeChain();
if (obj2->isBlock() && if (obj2->isBlock() &&
obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp())) { obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp())) {
JSObject *youngestProto = obj2->getProto(); JSObject *youngestProto = obj2->getProto();
JS_ASSERT(youngestProto->isStaticBlock()); JS_ASSERT(youngestProto->isStaticBlock());
JSObject *parent = obj; JSObject *parent = obj;
while ((parent = parent->getParent()) != youngestProto) while ((parent = parent->getParentOrScopeChain()) != youngestProto)
JS_ASSERT(parent); JS_ASSERT(parent);
} }
#endif #endif

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

@ -957,7 +957,7 @@ static void
AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj) AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
{ {
#ifdef DEBUG #ifdef DEBUG
for (JSObject *o = &scopeobj; o; o = o->getParent()) { for (JSObject *o = &scopeobj; o; o = o->getParentOrScopeChain()) {
if (JSObjectOp op = o->getClass()->ext.innerObject) if (JSObjectOp op = o->getClass()->ext.innerObject)
JS_ASSERT(op(cx, o) == o); JS_ASSERT(op(cx, o) == o);
} }
@ -3401,7 +3401,7 @@ with_ThisObject(JSContext *cx, JSObject *obj)
Class js::WithClass = { Class js::WithClass = {
"With", "With",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IS_ANONYMOUS,
JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */ JS_PropertyStub, /* getProperty */
@ -3470,7 +3470,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp()); StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
obj->init(cx, type, parent, false); obj->init(cx, type, parent->getGlobal(), false);
EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx); EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
if (!emptyWithShape) if (!emptyWithShape)
@ -3479,6 +3479,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
obj->setInitialPropertyInfallible(emptyWithShape); obj->setInitialPropertyInfallible(emptyWithShape);
OBJ_SET_BLOCK_DEPTH(cx, obj, depth); OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
obj->setScopeChain(parent);
obj->setPrivate(priv); obj->setPrivate(priv);
AutoObjectRooter tvr(cx, obj); AutoObjectRooter tvr(cx, obj);
@ -3499,7 +3500,7 @@ js_NewBlockObject(JSContext *cx)
* Null obj's proto slot so that Object.prototype.* does not pollute block * Null obj's proto slot so that Object.prototype.* does not pollute block
* scopes and to give the block object its own scope. * scopes and to give the block object its own scope.
*/ */
JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2); JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT4);
if (!blockObj) if (!blockObj)
return NULL; return NULL;
@ -3517,13 +3518,15 @@ js_NewBlockObject(JSContext *cx)
return blockObj; return blockObj;
} }
static const uint32 BLOCK_RESERVED_SLOTS = 2;
JSObject * JSObject *
js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp) js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
{ {
JS_ASSERT(proto->isStaticBlock()); JS_ASSERT(proto->isStaticBlock());
size_t count = OBJ_BLOCK_COUNT(cx, proto); size_t count = OBJ_BLOCK_COUNT(cx, proto);
gc::AllocKind kind = gc::GetGCObjectKind(count + 1); gc::AllocKind kind = gc::GetGCObjectKind(count + BLOCK_RESERVED_SLOTS + 1);
TypeObject *type = proto->getNewType(cx); TypeObject *type = proto->getNewType(cx);
if (!type) if (!type)
@ -3539,7 +3542,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
if (!clone->initClonedBlock(cx, type, priv)) if (!clone->initClonedBlock(cx, type, priv))
return NULL; return NULL;
JS_ASSERT(clone->slotSpan() >= count + 1); JS_ASSERT(clone->slotSpan() >= count + BLOCK_RESERVED_SLOTS);
clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH)); clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH));
@ -3575,7 +3578,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
/* We must clear the private slot even with errors. */ /* We must clear the private slot even with errors. */
obj->setPrivate(NULL); obj->setPrivate(NULL);
fp->setScopeChainNoCallObj(*obj->getParent()); fp->setScopeChainNoCallObj(*obj->scopeChain());
return normalUnwind; return normalUnwind;
} }
@ -4148,7 +4151,9 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
Class js::BlockClass = { Class js::BlockClass = {
"Block", "Block",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS, JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(BLOCK_RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS,
JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */ JS_PropertyStub, /* getProperty */
@ -4559,6 +4564,8 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
shape_ = const_cast<js::Shape *>(shape); shape_ = const_cast<js::Shape *>(shape);
updateSlotsForSpan(0, span); updateSlotsForSpan(0, span);
JS_ASSERT_IF(isScope(), parent);
return true; return true;
} }
@ -4579,6 +4586,8 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
size_t span = shape->slotSpan(); size_t span = shape->slotSpan();
if (span) if (span)
updateSlotsForSpan(0, span); updateSlotsForSpan(0, span);
JS_ASSERT_IF(isScope(), parent);
} }
bool bool
@ -4974,11 +4983,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
start = &fp->scopeChain(); start = &fp->scopeChain();
if (start) { if (start) {
/* Find the topmost object in the scope chain. */ obj = start->getGlobal();
do {
obj = start;
start = obj->getParent();
} while (start);
} else { } else {
obj = cx->globalObject; obj = cx->globalObject;
if (!obj) { if (!obj) {
@ -5169,7 +5174,7 @@ PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id)
if (!obj->shadowingShapeChange(cx, *shape)) if (!obj->shadowingShapeChange(cx, *shape))
return false; return false;
if (!obj->getParent()) { if (obj->isGlobal()) {
/* /*
* All scope chains end in a global object, so this will change * All scope chains end in a global object, so this will change
* the global shape. jstracer.cpp assumes that the global shape * the global shape. jstracer.cpp assumes that the global shape
@ -5198,7 +5203,7 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
* may gain such properties via eval introducing new vars; see bug 490364. * may gain such properties via eval introducing new vars; see bug 490364.
*/ */
if (obj->isCall()) { if (obj->isCall()) {
while ((obj = obj->getParent()) != NULL) { while ((obj = obj->getParentOrScopeChain()) != NULL) {
if (!PurgeProtoChain(cx, obj, id)) if (!PurgeProtoChain(cx, obj, id))
return false; return false;
} }
@ -5643,7 +5648,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, bool cacheResult, bool global,
/* Scan entries on the scope chain that we can cache across. */ /* Scan entries on the scope chain that we can cache across. */
entry = JS_NO_PROP_CACHE_FILL; entry = JS_NO_PROP_CACHE_FILL;
obj = scopeChain; obj = scopeChain;
parent = obj->getParent(); parent = obj->getParentOrScopeChain();
for (scopeIndex = 0; for (scopeIndex = 0;
parent parent
? IsCacheableNonGlobalScope(obj) ? IsCacheableNonGlobalScope(obj)
@ -5689,7 +5694,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, bool cacheResult, bool global,
goto out; goto out;
} }
obj = parent; obj = parent;
parent = obj->getParent(); parent = obj->getParentOrScopeChain();
} }
for (;;) { for (;;) {
@ -5704,7 +5709,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, bool cacheResult, bool global,
* We conservatively assume that a resolve hook could mutate the scope * We conservatively assume that a resolve hook could mutate the scope
* chain during JSObject::lookupProperty. So we read parent here again. * chain during JSObject::lookupProperty. So we read parent here again.
*/ */
parent = obj->getParent(); parent = obj->getParentOrScopeChain();
if (!parent) { if (!parent) {
pobj = NULL; pobj = NULL;
break; break;
@ -5738,7 +5743,6 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
* This function should not be called for a global object or from the * This function should not be called for a global object or from the
* trace and should have a valid cache entry for native scopeChain. * trace and should have a valid cache entry for native scopeChain.
*/ */
JS_ASSERT(scopeChain->getParent());
JS_ASSERT(!JS_ON_TRACE(cx)); JS_ASSERT(!JS_ON_TRACE(cx));
JSObject *obj = scopeChain; JSObject *obj = scopeChain;
@ -5753,7 +5757,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
* must not be passed a global object (i.e. one with null parent). * must not be passed a global object (i.e. one with null parent).
*/ */
for (int scopeIndex = 0; for (int scopeIndex = 0;
!obj->getParent() || IsCacheableNonGlobalScope(obj); obj->isGlobal() || IsCacheableNonGlobalScope(obj);
scopeIndex++) { scopeIndex++) {
JSObject *pobj; JSObject *pobj;
JSProperty *prop; JSProperty *prop;
@ -5761,17 +5765,17 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
return NULL; return NULL;
if (prop) { if (prop) {
if (!pobj->isNative()) { if (!pobj->isNative()) {
JS_ASSERT(!obj->getParent()); JS_ASSERT(obj->isGlobal());
return obj; return obj;
} }
JS_ASSERT_IF(obj->getParent(), pobj->getClass() == obj->getClass()); JS_ASSERT_IF(obj->isScope(), pobj->getClass() == obj->getClass());
DebugOnly<PropertyCacheEntry*> entry = DebugOnly<PropertyCacheEntry*> entry =
JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop); JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
JS_ASSERT(entry); JS_ASSERT(entry);
return obj; return obj;
} }
JSObject *parent = obj->getParent(); JSObject *parent = obj->getParentOrScopeChain();
if (!parent) if (!parent)
return obj; return obj;
obj = parent; obj = parent;
@ -5791,11 +5795,11 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
* chain during JSObject::lookupProperty. So we must check if parent is * chain during JSObject::lookupProperty. So we must check if parent is
* not null here even if it wasn't before the lookup. * not null here even if it wasn't before the lookup.
*/ */
JSObject *parent = obj->getParent(); JSObject *parent = obj->getParentOrScopeChain();
if (!parent) if (!parent)
break; break;
obj = parent; obj = parent;
} while (obj->getParent()); } while (obj->isScope());
return obj; return obj;
} }
@ -7098,7 +7102,7 @@ GlobalObject *
JSObject::getGlobal() const JSObject::getGlobal() const
{ {
JSObject *obj = const_cast<JSObject *>(this); JSObject *obj = const_cast<JSObject *>(this);
while (JSObject *parent = obj->getParent()) while (JSObject *parent = obj->getParentMaybeScope())
obj = parent; obj = parent;
return obj->asGlobal(); return obj->asGlobal();
} }
@ -7397,7 +7401,7 @@ js_DumpObject(JSObject *obj)
fputc('\n', stderr); fputc('\n', stderr);
fprintf(stderr, "parent "); fprintf(stderr, "parent ");
dumpValue(ObjectOrNullValue(obj->getParent())); dumpValue(ObjectOrNullValue(obj->getParentMaybeScope()));
fputc('\n', stderr); fputc('\n', stderr);
if (clasp->flags & JSCLASS_HAS_PRIVATE) if (clasp->flags & JSCLASS_HAS_PRIVATE)

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

@ -866,28 +866,31 @@ struct JSObject : js::gc::Cell
return type_->proto; return type_->proto;
} }
JSObject *getParent() const { inline JSObject *getParent() const;
return parent; inline void clearParent();
} inline void setParent(JSObject *newParent);
void clearParent() {
parent = NULL;
}
void setParent(JSObject *newParent) {
#ifdef DEBUG
for (JSObject *obj = newParent; obj; obj = obj->getParent())
JS_ASSERT(obj != this);
#endif
setDelegateNullSafe(newParent);
parent = newParent;
}
JS_FRIEND_API(js::GlobalObject *) getGlobal() const; JS_FRIEND_API(js::GlobalObject *) getGlobal() const;
inline bool isGlobal() const; inline bool isGlobal() const;
inline js::GlobalObject *asGlobal(); inline js::GlobalObject *asGlobal();
/*
* Information for non-global scope chain objects (call/with/etc.). All
* objects on a scope chain are either isScope() or isGlobal(). isScope()
* objects do not escape to script and only appear on scope chains.
*/
inline bool isScope() const;
inline JSObject *scopeChain() const;
inline void setScopeChain(JSObject *obj);
static inline size_t offsetOfScopeChain();
inline JSObject *getParentOrScopeChain() const;
inline JSObject *getParentMaybeScope() const;
static const uint32 SCOPE_CHAIN_SLOT = 0;
inline bool hasPrivate() const; inline bool hasPrivate() const;
inline void *getPrivate() const; inline void *getPrivate() const;
inline void *getPrivate(size_t nfixed) const; inline void *getPrivate(size_t nfixed) const;
@ -1520,21 +1523,22 @@ class ValueArray {
* Block scope object macros. The slots reserved by BlockClass are: * Block scope object macros. The slots reserved by BlockClass are:
* *
* private StackFrame * active frame pointer or null * private StackFrame * active frame pointer or null
* JSSLOT_SCOPE_CHAIN JSObject * scope chain, as for other scopes
* JSSLOT_BLOCK_DEPTH int depth of block slots in frame * JSSLOT_BLOCK_DEPTH int depth of block slots in frame
* *
* After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals. * After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
* *
* A With object is like a Block object, in that both have one reserved slot * A With object is like a Block object, in that both have a reserved slot
* telling the stack depth of the relevant slots (the slot whose value is the * telling the stack depth of the relevant slots (the slot whose value is the
* object named in the with statement, the slots containing the block's local * object named in the with statement, the slots containing the block's local
* variables); and both have a private slot referring to the StackFrame in * variables); and both have a private slot referring to the StackFrame in
* whose activation they were created (or null if the with or block object * whose activation they were created (or null if the with or block object
* outlives the frame). * outlives the frame).
*/ */
static const uint32 JSSLOT_BLOCK_DEPTH = 0; static const uint32 JSSLOT_BLOCK_DEPTH = 1;
static const uint32 JSSLOT_BLOCK_FIRST_FREE_SLOT = JSSLOT_BLOCK_DEPTH + 1; static const uint32 JSSLOT_BLOCK_FIRST_FREE_SLOT = JSSLOT_BLOCK_DEPTH + 1;
static const uint32 JSSLOT_WITH_THIS = 1; static const uint32 JSSLOT_WITH_THIS = 2;
#define OBJ_BLOCK_COUNT(cx,obj) \ #define OBJ_BLOCK_COUNT(cx,obj) \
(obj)->propertyCount() (obj)->propertyCount()

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

@ -315,6 +315,70 @@ JSObject::finalize(JSContext *cx, bool background)
finish(cx); finish(cx);
} }
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;
}
inline bool
JSObject::isScope() const
{
return isCall() || isDeclEnv() || isClonedBlock() || isWith();
}
inline JSObject *
JSObject::scopeChain() const
{
JS_ASSERT(isScope());
return &getFixedSlot(0).toObject();
}
inline JSObject *
JSObject::getParentOrScopeChain() const
{
return isScope() ? scopeChain() : getParent();
}
inline JSObject *
JSObject::getParentMaybeScope() const
{
return parent;
}
inline void
JSObject::setScopeChain(JSObject *obj)
{
JS_ASSERT(isScope());
setFixedSlot(0, JS::ObjectValue(*obj));
}
/*static*/ inline size_t
JSObject::offsetOfScopeChain()
{
return getFixedSlotOffset(0);
}
/* /*
* Initializer for Call objects for functions and eval frames. Set class, * Initializer for Call objects for functions and eval frames. Set class,
* parent, map, and shape, and allocate slots. * parent, map, and shape, and allocate slots.
@ -326,13 +390,15 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
if (!type) if (!type)
return false; return false;
init(cx, type, parent, false); init(cx, type, parent->getGlobal(), false);
if (!setInitialProperty(cx, bindings.lastShape())) if (!setInitialProperty(cx, bindings.lastShape()))
return false; return false;
JS_ASSERT(isCall()); JS_ASSERT(isCall());
JS_ASSERT(!inDictionaryMode()); JS_ASSERT(!inDictionaryMode());
setScopeChain(parent);
/* /*
* If |bindings| is for a function that has extensible parents, that means * If |bindings| is for a function that has extensible parents, that means
* its Call should have its own shape; see js::BaseShape::extensibleParents. * its Call should have its own shape; see js::BaseShape::extensibleParents.
@ -349,7 +415,7 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
inline bool inline bool
JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame) JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame)
{ {
init(cx, type, NULL, false); init(cx, type, frame->scopeChain().getGlobal(), false);
if (!setInitialProperty(cx, getProto()->lastProperty())) if (!setInitialProperty(cx, getProto()->lastProperty()))
return false; return false;
@ -382,7 +448,7 @@ JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp
JS_ASSERT(!fun->isClonedMethod()); JS_ASSERT(!fun->isClonedMethod());
JS_ASSERT(fun->isNullClosure()); JS_ASSERT(fun->isNullClosure());
fun = CloneFunctionObject(cx, fun); fun = js::CloneFunctionObject(cx, fun);
if (!fun) if (!fun)
return NULL; return NULL;
fun->setMethodObj(*this); fun->setMethodObj(*this);

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

@ -81,7 +81,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *po
JSObject *tmp = obj; JSObject *tmp = obj;
for (uintN i = 0; i != scopeIndex; i++) for (uintN i = 0; i != scopeIndex; i++)
tmp = tmp->getParent(); tmp = tmp->scopeChain();
uintN protoIndex = 0; uintN protoIndex = 0;
while (tmp != pobj) { while (tmp != pobj) {
@ -223,7 +223,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
if (JOF_MODE(cs.format) == JOF_NAME) { if (JOF_MODE(cs.format) == JOF_NAME) {
while (vindex & (PCINDEX_SCOPEMASK << PCINDEX_PROTOBITS)) { while (vindex & (PCINDEX_SCOPEMASK << PCINDEX_PROTOBITS)) {
tmp = pobj->getParent(); tmp = pobj->scopeChain();
if (!tmp || !tmp->isNative()) if (!tmp || !tmp->isNative())
break; break;
pobj = tmp; pobj = tmp;

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

@ -7460,7 +7460,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
JSObject *scopeChain = GetScopeChain(cx); JSObject *scopeChain = GetScopeChain(cx);
obj = NULL; obj = NULL;
for (tmp = scopeChain; tmp; tmp = tmp->getParent()) { for (tmp = scopeChain; tmp; tmp = tmp->getParentOrScopeChain()) {
Class *clasp = tmp->getClass(); Class *clasp = tmp->getClass();
if (clasp == &BlockClass || clasp == &WithClass) if (clasp == &BlockClass || clasp == &WithClass)
continue; continue;
@ -7655,7 +7655,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
return JS_TRUE; return JS_TRUE;
} }
} }
} while ((obj = obj->getParent()) != NULL); } while ((obj = obj->getParentOrScopeChain()) != NULL);
JSAutoByteString printable; JSAutoByteString printable;
JSString *str = ConvertQNameToString(cx, nameobj); JSString *str = ConvertQNameToString(cx, nameobj);

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

@ -1360,13 +1360,6 @@ class ScopeNameCompiler : public PICStubCompiler
return disable("non-cacheable scope chain object"); return disable("non-cacheable scope chain object");
JS_ASSERT(tobj->isNative()); JS_ASSERT(tobj->isNative());
if (tobj != scopeChain) {
/* scopeChain will never be NULL, but parents can be NULL. */
Jump j = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
if (!fails.append(j))
return error();
}
/* Guard on intervening shapes. */ /* Guard on intervening shapes. */
masm.loadShape(pic.objReg, pic.shapeReg); masm.loadShape(pic.objReg, pic.shapeReg);
Jump j = masm.branchPtr(Assembler::NotEqual, pic.shapeReg, Jump j = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
@ -1375,10 +1368,10 @@ class ScopeNameCompiler : public PICStubCompiler
return error(); return error();
/* Load the next link in the scope chain. */ /* Load the next link in the scope chain. */
Address parent(pic.objReg, offsetof(JSObject, parent)); Address parent(pic.objReg, JSObject::offsetOfScopeChain());
masm.loadPtr(parent, pic.objReg); masm.loadPtr(parent, pic.objReg);
tobj = tobj->getParent(); tobj = tobj->scopeChain();
} }
if (tobj != getprop.holder) if (tobj != getprop.holder)
@ -1657,7 +1650,7 @@ class ScopeNameCompiler : public PICStubCompiler
if (status != Lookup_Cacheable) if (status != Lookup_Cacheable)
return status; return status;
if (!obj->getParent()) if (obj->isGlobal())
return generateGlobalStub(obj); return generateGlobalStub(obj);
return disable("scope object not handled yet"); return disable("scope object not handled yet");
@ -1757,20 +1750,17 @@ class BindNameCompiler : public PICStubCompiler
/* Walk up the scope chain. */ /* Walk up the scope chain. */
JSObject *tobj = scopeChain; JSObject *tobj = scopeChain;
Address parent(pic.objReg, offsetof(JSObject, parent)); Address parent(pic.objReg, JSObject::offsetOfScopeChain());
while (tobj && tobj != obj) { while (tobj && tobj != obj) {
if (!IsCacheableNonGlobalScope(tobj)) if (!IsCacheableNonGlobalScope(tobj))
return disable("non-cacheable obj in scope chain"); return disable("non-cacheable obj in scope chain");
masm.loadPtr(parent, pic.objReg); masm.loadPtr(parent, pic.objReg);
Jump nullTest = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
if (!fails.append(nullTest))
return error();
masm.loadShape(pic.objReg, pic.shapeReg); masm.loadShape(pic.objReg, pic.shapeReg);
Jump shapeTest = masm.branchPtr(Assembler::NotEqual, pic.shapeReg, Jump shapeTest = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
ImmPtr(tobj->lastProperty())); ImmPtr(tobj->lastProperty()));
if (!fails.append(shapeTest)) if (!fails.append(shapeTest))
return error(); return error();
tobj = tobj->getParent(); tobj = tobj->scopeChain();
} }
if (tobj != obj) if (tobj != obj)
return disable("indirect hit"); return disable("indirect hit");
@ -1814,7 +1804,6 @@ class BindNameCompiler : public PICStubCompiler
JSObject *update() JSObject *update()
{ {
JS_ASSERT(scopeChain->getParent());
RecompilationMonitor monitor(cx); RecompilationMonitor monitor(cx);
JSObject *obj = js_FindIdentifierBase(cx, scopeChain, ATOM_TO_JSID(atom)); JSObject *obj = js_FindIdentifierBase(cx, scopeChain, ATOM_TO_JSID(atom));

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

@ -88,7 +88,7 @@ stubs::BindName(VMFrame &f)
PropertyCacheEntry *entry; PropertyCacheEntry *entry;
/* Fast-path should have caught this. See comment in interpreter. */ /* Fast-path should have caught this. See comment in interpreter. */
JS_ASSERT(f.fp()->scopeChain().getParent()); JS_ASSERT(f.fp()->scopeChain().isScope());
JSAtom *atom; JSAtom *atom;
JSObject *obj2; JSObject *obj2;
@ -1886,13 +1886,13 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
*/ */
JSObject *obj2 = &fp->scopeChain(); JSObject *obj2 = &fp->scopeChain();
while (obj2->isWith()) while (obj2->isWith())
obj2 = obj2->getParent(); obj2 = obj2->scopeChain();
if (obj2->isBlock() && if (obj2->isBlock() &&
obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) { obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
JSObject *youngestProto = obj2->getProto(); JSObject *youngestProto = obj2->getProto();
JS_ASSERT(youngestProto->isStaticBlock()); JS_ASSERT(youngestProto->isStaticBlock());
JSObject *parent = obj; JSObject *parent = obj;
while ((parent = parent->getParent()) != youngestProto) while ((parent = parent->getParentOrScopeChain()) != youngestProto)
JS_ASSERT(parent); JS_ASSERT(parent);
} }
#endif #endif

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

@ -48,16 +48,20 @@ class CallObject : public ::JSObject
/* /*
* Reserved slot structure for Call objects: * Reserved slot structure for Call objects:
* *
* private - the stack frame corresponding to the Call object * SCOPE_CHAIN_SLOT - The enclosing scope. This must come first, for
* until js_PutCallObject or its on-trace analog * JSObject::scopeParent.
* is called, null thereafter * CALLEE_SLOT - Callee function for the stack frame, or null if
* JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if * the stack frame is for strict mode eval code.
* the stack frame is for strict mode eval code * ARGUMENTS_SLOT - Arguments object for non-strict mode eval stack
* JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack * frames (not valid for strict mode eval frames).
* frames (not valid for strict mode eval frames) * private - The stack frame corresponding to the Call object
* until js_PutCallObject or its on-trace analog
* is called, null thereafter.
*
* DeclEnv objects use SCOPE_CHAIN_SLOT and private in the same fashion.
*/ */
static const uint32 CALLEE_SLOT = 0; static const uint32 CALLEE_SLOT = 1;
static const uint32 ARGUMENTS_SLOT = 1; static const uint32 ARGUMENTS_SLOT = 2;
public: public:
/* Create a CallObject for the given callee function. */ /* Create a CallObject for the given callee function. */
@ -65,6 +69,7 @@ public:
create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee); create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee);
static const uint32 RESERVED_SLOTS = 3; static const uint32 RESERVED_SLOTS = 3;
static const uint32 DECL_ENV_RESERVED_SLOTS = 1;
/* True if this is for a strict mode eval frame or for a function call. */ /* True if this is for a strict mode eval frame or for a function call. */
inline bool isForEval() const; inline bool isForEval() const;

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

@ -62,14 +62,39 @@ namespace js {
static inline bool static inline bool
IsCacheableNonGlobalScope(JSObject *obj) IsCacheableNonGlobalScope(JSObject *obj)
{ {
JS_ASSERT(obj->getParent());
bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv()); bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty); JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
return cacheable; return cacheable;
} }
inline JSObject &
StackFrame::scopeChain() const
{
JS_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
if (!(flags_ & HAS_SCOPECHAIN)) {
scopeChain_ = callee().getParent();
flags_ |= HAS_SCOPECHAIN;
}
return *scopeChain_;
}
inline JSObject &
StackFrame::varObj()
{
JSObject *obj = &scopeChain();
while (!obj->isVarObj())
obj = obj->getParentOrScopeChain();
return *obj;
}
inline JSCompartment *
StackFrame::compartment() const
{
JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
return scopeChain().compartment();
}
inline void inline void
StackFrame::initPrev(JSContext *cx) StackFrame::initPrev(JSContext *cx)
{ {
@ -352,10 +377,10 @@ StackFrame::setScopeChainNoCallObj(JSObject &obj)
if (hasCallObj()) { if (hasCallObj()) {
JSObject *pobj = &obj; JSObject *pobj = &obj;
while (pobj && pobj->getPrivate() != this) while (pobj && pobj->getPrivate() != this)
pobj = pobj->getParent(); pobj = pobj->scopeChain();
JS_ASSERT(pobj); JS_ASSERT(pobj);
} else { } else {
for (JSObject *pobj = &obj; pobj; pobj = pobj->getParent()) for (JSObject *pobj = &obj; pobj->isScope(); pobj = pobj->scopeChain())
JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this); JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
} }
} }
@ -381,7 +406,7 @@ StackFrame::callObj() const
JSObject *pobj = &scopeChain(); JSObject *pobj = &scopeChain();
while (JS_UNLIKELY(!pobj->isCall())) { while (JS_UNLIKELY(!pobj->isCall())) {
JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith()); JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith());
pobj = pobj->getParent(); pobj = pobj->scopeChain();
} }
return pobj->asCall(); return pobj->asCall();
} }
@ -454,7 +479,7 @@ StackFrame::markFunctionEpilogueDone()
*/ */
scopeChain_ = isFunctionFrame() scopeChain_ = isFunctionFrame()
? callee().getParent() ? callee().getParent()
: scopeChain_->getParent(); : scopeChain_->scopeChain();
flags_ &= ~HAS_CALL_OBJ; flags_ &= ~HAS_CALL_OBJ;
} }
} }

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

@ -151,7 +151,7 @@ StackFrame::stealFrameAndSlots(Value *vp, StackFrame *otherfp,
obj.setPrivate(this); obj.setPrivate(this);
otherfp->flags_ &= ~HAS_CALL_OBJ; otherfp->flags_ &= ~HAS_CALL_OBJ;
if (js_IsNamedLambda(fun())) { if (js_IsNamedLambda(fun())) {
JSObject *env = obj.getParent(); JSObject *env = obj.scopeChain();
JS_ASSERT(env->isDeclEnv()); JS_ASSERT(env->isDeclEnv());
env->setPrivate(this); env->setPrivate(this);
} }

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

@ -817,14 +817,7 @@ class StackFrame
* !fp->hasCall() && fp->scopeChain().isCall() * !fp->hasCall() && fp->scopeChain().isCall()
*/ */
JSObject &scopeChain() const { inline JSObject &scopeChain() const;
JS_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
if (!(flags_ & HAS_SCOPECHAIN)) {
scopeChain_ = callee().getParent();
flags_ |= HAS_SCOPECHAIN;
}
return *scopeChain_;
}
bool hasCallObj() const { bool hasCallObj() const {
bool ret = !!(flags_ & HAS_CALL_OBJ); bool ret = !!(flags_ & HAS_CALL_OBJ);
@ -873,12 +866,7 @@ class StackFrame
* variables object to collect and discard the script's global variables. * variables object to collect and discard the script's global variables.
*/ */
JSObject &varObj() { inline JSObject &varObj();
JSObject *obj = &scopeChain();
while (!obj->isVarObj())
obj = obj->getParent();
return *obj;
}
/* /*
* Frame compartment * Frame compartment
@ -887,10 +875,7 @@ class StackFrame
* compartment when the frame was pushed. * compartment when the frame was pushed.
*/ */
JSCompartment *compartment() const { inline JSCompartment *compartment() const;
JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
return scopeChain().compartment();
}
/* /*
* Imacropc * Imacropc