зеркало из https://github.com/mozilla/gecko-dev.git
Move scope chains of scope objects to reserved slots, bug 694247.
This commit is contained in:
Родитель
a4c76d19d1
Коммит
1ca40e7627
|
@ -2429,7 +2429,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
|
|||
jsClass = js::GetObjectClass(aObj);
|
||||
|
||||
if (jsClass == &js::CallClass) {
|
||||
aObj = js::GetObjectParent(aObj);
|
||||
aObj = js::GetObjectParentMaybeScope(aObj);
|
||||
|
||||
if (!aObj)
|
||||
return nsnull;
|
||||
|
@ -2481,7 +2481,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
|
|||
}
|
||||
}
|
||||
|
||||
aObj = js::GetObjectParent(aObj);
|
||||
aObj = js::GetObjectParentMaybeScope(aObj);
|
||||
|
||||
if (!aObj)
|
||||
break;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsJSUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "prprf.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptObjectOwner.h"
|
||||
|
@ -107,8 +108,7 @@ nsJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj)
|
|||
if (!glob)
|
||||
return nsnull;
|
||||
|
||||
while ((parent = ::JS_GetParent(aContext, glob)))
|
||||
glob = parent;
|
||||
glob = js::GetGlobalForObject(glob);
|
||||
|
||||
clazz = JS_GET_CLASS(aContext, glob);
|
||||
|
||||
|
|
|
@ -3063,6 +3063,7 @@ JS_PUBLIC_API(JSBool)
|
|||
JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
JS_ASSERT(!obj->isScope());
|
||||
JS_ASSERT(parent || !obj->getParent());
|
||||
assertSameCompartment(cx, obj, parent);
|
||||
obj->setParent(parent);
|
||||
|
@ -4346,7 +4347,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
|||
JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
|
||||
return NULL;
|
||||
}
|
||||
obj = obj->getParent();
|
||||
obj = obj->getParentOrScopeChain();
|
||||
}
|
||||
|
||||
Value v;
|
||||
|
|
|
@ -389,7 +389,7 @@ DeepBail(JSContext *cx);
|
|||
static JS_INLINE void
|
||||
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
if (!obj->getParent())
|
||||
if (obj->isGlobal())
|
||||
LeaveTrace(cx);
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,24 @@ AutoSwitchCompartment::~AutoSwitchCompartment()
|
|||
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
|
||||
* sufficient data has been harvested.
|
||||
|
|
|
@ -236,12 +236,21 @@ GetObjectJSClass(const JSObject *obj)
|
|||
return js::Jsvalify(GetObjectClass(obj));
|
||||
}
|
||||
|
||||
bool IsScopeObject(const JSObject *obj);
|
||||
|
||||
inline JSObject *
|
||||
GetObjectParent(const JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(!IsScopeObject(obj));
|
||||
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 *
|
||||
GetObjectProto(const JSObject *obj)
|
||||
{
|
||||
|
|
|
@ -747,7 +747,9 @@ Class js::StrictArgumentsObjectClass = {
|
|||
*/
|
||||
Class js::DeclEnvClass = {
|
||||
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, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
|
@ -771,10 +773,12 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
|
|||
EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
|
||||
if (!emptyDeclEnvShape)
|
||||
return NULL;
|
||||
envobj->init(cx, type, &fp->scopeChain(), false);
|
||||
envobj->init(cx, type, fp->scopeChain().getGlobal(), false);
|
||||
envobj->setInitialPropertyInfallible(emptyDeclEnvShape);
|
||||
envobj->setPrivate(fp);
|
||||
|
||||
envobj->setScopeChain(&fp->scopeChain());
|
||||
|
||||
return envobj;
|
||||
}
|
||||
|
||||
|
@ -915,7 +919,7 @@ js_PutCallObject(StackFrame *fp)
|
|||
|
||||
/* Clear private pointers to fp, which is about to go away. */
|
||||
if (js_IsNamedLambda(fun)) {
|
||||
JSObject *env = callobj.getParent();
|
||||
JSObject *env = callobj.scopeChain();
|
||||
|
||||
JS_ASSERT(env->isDeclEnv());
|
||||
JS_ASSERT(env->getPrivate() == fp);
|
||||
|
|
|
@ -163,10 +163,7 @@ struct JSFunction : public JSObject_Slots2
|
|||
return flags & JSFUN_JOINABLE;
|
||||
}
|
||||
|
||||
JSObject *callScope() const {
|
||||
JS_ASSERT(isInterpreted());
|
||||
return u.i.scope;
|
||||
}
|
||||
inline JSObject *callScope() const;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
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
|
||||
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain);
|
||||
|
||||
|
|
|
@ -49,6 +49,14 @@ JSFunction::inStrictMode() const
|
|||
return script()->strictModeCode;
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
JSFunction::callScope() const
|
||||
{
|
||||
JS_ASSERT(isInterpreted());
|
||||
return getParent();
|
||||
//return u.i.scope;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSFunction::setJoinable()
|
||||
{
|
||||
|
@ -223,6 +231,49 @@ IsBuiltinFunctionConstructor(JSFunction *fun);
|
|||
const Shape *
|
||||
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 */
|
||||
|
||||
#endif /* jsfuninlines_h___ */
|
||||
|
|
|
@ -711,7 +711,7 @@ ScanObject(GCMarker *gcmarker, JSObject *obj)
|
|||
types::TypeObject *type = obj->typeFromGC();
|
||||
PushMarkStack(gcmarker, type);
|
||||
|
||||
if (JSObject *parent = obj->getParent())
|
||||
if (JSObject *parent = obj->getParentMaybeScope())
|
||||
PushMarkStack(gcmarker, parent);
|
||||
|
||||
/*
|
||||
|
@ -784,7 +784,7 @@ MarkChildren(JSTracer *trc, JSObject *obj)
|
|||
MarkTypeObject(trc, obj->typeFromGC(), "type");
|
||||
|
||||
/* Trace universal (ops-independent) members. */
|
||||
if (JSObject *parent = obj->getParent())
|
||||
if (JSObject *parent = obj->getParentMaybeScope())
|
||||
MarkObject(trc, *parent, "parent");
|
||||
|
||||
Class *clasp = obj->getClass();
|
||||
|
|
|
@ -5115,7 +5115,7 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
|
|||
* the script is nested inside.
|
||||
*/
|
||||
while (!scope->isCall())
|
||||
scope = scope->getParent();
|
||||
scope = scope->scopeChain();
|
||||
|
||||
CallObject &call = scope->asCall();
|
||||
|
||||
|
@ -5148,7 +5148,7 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
|
|||
if (!parent->ensureHasTypes(cx, parentFun))
|
||||
return false;
|
||||
if (!parent->types->hasScope()) {
|
||||
if (!SetScope(cx, parent, scope->getParent()))
|
||||
if (!SetScope(cx, parent, scope->scopeChain()))
|
||||
return false;
|
||||
parent->nesting()->activeCall = scope;
|
||||
parent->nesting()->argArray = call.argArray();
|
||||
|
@ -5243,7 +5243,7 @@ CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
|
|||
JS_ASSERT(parent);
|
||||
|
||||
while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
|
||||
scope = scope->getParent();
|
||||
scope = scope->scopeChain();
|
||||
|
||||
if (scope != parent->nesting()->activeCall) {
|
||||
parent->reentrantOuterFunction = true;
|
||||
|
@ -5258,7 +5258,7 @@ CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
|
|||
* parent.
|
||||
*/
|
||||
if (parent->nesting()->parent) {
|
||||
scope = scope->getParent();
|
||||
scope = scope->scopeChain();
|
||||
script = parent;
|
||||
goto restart;
|
||||
}
|
||||
|
|
|
@ -300,7 +300,7 @@ GetScopeChainFull(JSContext *cx, StackFrame *fp, JSObject *blockChain)
|
|||
*/
|
||||
limitClone = &fp->scopeChain();
|
||||
while (limitClone->isWith())
|
||||
limitClone = limitClone->getParent();
|
||||
limitClone = limitClone->scopeChain();
|
||||
JS_ASSERT(limitClone);
|
||||
|
||||
/*
|
||||
|
@ -358,10 +358,10 @@ GetScopeChainFull(JSContext *cx, StackFrame *fp, JSObject *blockChain)
|
|||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
newChild->setParent(clone);
|
||||
newChild->setScopeChain(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(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
|
||||
withobj->setPrivate(NULL);
|
||||
cx->fp()->setScopeChainNoCallObj(*withobj->getParent());
|
||||
cx->fp()->setScopeChainNoCallObj(*withobj->scopeChain());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2185,7 +2185,7 @@ BEGIN_CASE(JSOP_POPN)
|
|||
JS_ASSERT_IF(obj,
|
||||
OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
|
||||
<= (size_t) (regs.sp - regs.fp()->base()));
|
||||
for (obj = ®s.fp()->scopeChain(); obj; obj = obj->getParent()) {
|
||||
for (obj = ®s.fp()->scopeChain(); obj; obj = obj->getParentOrScopeChain()) {
|
||||
if (!obj->isBlock() || !obj->isWith())
|
||||
continue;
|
||||
if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp()))
|
||||
|
@ -2683,7 +2683,7 @@ BEGIN_CASE(JSOP_BINDNAME)
|
|||
* forms.
|
||||
*/
|
||||
obj = ®s.fp()->scopeChain();
|
||||
if (!obj->getParent())
|
||||
if (obj->isGlobal())
|
||||
break;
|
||||
|
||||
PropertyCacheEntry *entry;
|
||||
|
@ -4360,7 +4360,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
* windows, and user-defined JS functions precompiled and then shared among
|
||||
* requests in server-side JS.
|
||||
*/
|
||||
if (obj->getParent() != obj2) {
|
||||
if (obj->toFunction()->callScope() != obj2) {
|
||||
obj = CloneFunctionObject(cx, fun, obj2, true);
|
||||
if (!obj)
|
||||
goto error;
|
||||
|
@ -4487,7 +4487,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
|
|||
if (!parent)
|
||||
goto error;
|
||||
|
||||
if (obj->getParent() != parent) {
|
||||
if (obj->toFunction()->callScope() != parent) {
|
||||
#ifdef JS_TRACER
|
||||
if (TRACE_RECORDER(cx))
|
||||
AbortRecording(cx, "DEFLOCALFUN for closure");
|
||||
|
@ -5472,13 +5472,13 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
|
|||
*/
|
||||
JSObject *obj2 = ®s.fp()->scopeChain();
|
||||
while (obj2->isWith())
|
||||
obj2 = obj2->getParent();
|
||||
obj2 = obj2->scopeChain();
|
||||
if (obj2->isBlock() &&
|
||||
obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp())) {
|
||||
JSObject *youngestProto = obj2->getProto();
|
||||
JS_ASSERT(youngestProto->isStaticBlock());
|
||||
JSObject *parent = obj;
|
||||
while ((parent = parent->getParent()) != youngestProto)
|
||||
while ((parent = parent->getParentOrScopeChain()) != youngestProto)
|
||||
JS_ASSERT(parent);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -957,7 +957,7 @@ static void
|
|||
AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
|
||||
{
|
||||
#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)
|
||||
JS_ASSERT(op(cx, o) == o);
|
||||
}
|
||||
|
@ -3401,7 +3401,7 @@ with_ThisObject(JSContext *cx, JSObject *obj)
|
|||
|
||||
Class js::WithClass = {
|
||||
"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, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
|
@ -3470,7 +3470,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
|
|||
|
||||
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);
|
||||
if (!emptyWithShape)
|
||||
|
@ -3479,6 +3479,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
|
|||
obj->setInitialPropertyInfallible(emptyWithShape);
|
||||
OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
|
||||
|
||||
obj->setScopeChain(parent);
|
||||
obj->setPrivate(priv);
|
||||
|
||||
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
|
||||
* 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)
|
||||
return NULL;
|
||||
|
||||
|
@ -3517,13 +3518,15 @@ js_NewBlockObject(JSContext *cx)
|
|||
return blockObj;
|
||||
}
|
||||
|
||||
static const uint32 BLOCK_RESERVED_SLOTS = 2;
|
||||
|
||||
JSObject *
|
||||
js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
|
||||
{
|
||||
JS_ASSERT(proto->isStaticBlock());
|
||||
|
||||
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);
|
||||
if (!type)
|
||||
|
@ -3539,7 +3542,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
|
|||
if (!clone->initClonedBlock(cx, type, priv))
|
||||
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));
|
||||
|
||||
|
@ -3575,7 +3578,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
|
||||
/* We must clear the private slot even with errors. */
|
||||
obj->setPrivate(NULL);
|
||||
fp->setScopeChainNoCallObj(*obj->getParent());
|
||||
fp->setScopeChainNoCallObj(*obj->scopeChain());
|
||||
return normalUnwind;
|
||||
}
|
||||
|
||||
|
@ -4148,7 +4151,9 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
|
|||
|
||||
Class js::BlockClass = {
|
||||
"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, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
|
@ -4559,6 +4564,8 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
|
|||
|
||||
shape_ = const_cast<js::Shape *>(shape);
|
||||
updateSlotsForSpan(0, span);
|
||||
|
||||
JS_ASSERT_IF(isScope(), parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4579,6 +4586,8 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
|
|||
size_t span = shape->slotSpan();
|
||||
if (span)
|
||||
updateSlotsForSpan(0, span);
|
||||
|
||||
JS_ASSERT_IF(isScope(), parent);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4974,11 +4983,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
|||
start = &fp->scopeChain();
|
||||
|
||||
if (start) {
|
||||
/* Find the topmost object in the scope chain. */
|
||||
do {
|
||||
obj = start;
|
||||
start = obj->getParent();
|
||||
} while (start);
|
||||
obj = start->getGlobal();
|
||||
} else {
|
||||
obj = cx->globalObject;
|
||||
if (!obj) {
|
||||
|
@ -5169,7 +5174,7 @@ PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id)
|
|||
if (!obj->shadowingShapeChange(cx, *shape))
|
||||
return false;
|
||||
|
||||
if (!obj->getParent()) {
|
||||
if (obj->isGlobal()) {
|
||||
/*
|
||||
* All scope chains end in a global object, so this will change
|
||||
* 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.
|
||||
*/
|
||||
if (obj->isCall()) {
|
||||
while ((obj = obj->getParent()) != NULL) {
|
||||
while ((obj = obj->getParentOrScopeChain()) != NULL) {
|
||||
if (!PurgeProtoChain(cx, obj, id))
|
||||
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. */
|
||||
entry = JS_NO_PROP_CACHE_FILL;
|
||||
obj = scopeChain;
|
||||
parent = obj->getParent();
|
||||
parent = obj->getParentOrScopeChain();
|
||||
for (scopeIndex = 0;
|
||||
parent
|
||||
? IsCacheableNonGlobalScope(obj)
|
||||
|
@ -5689,7 +5694,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, bool cacheResult, bool global,
|
|||
goto out;
|
||||
}
|
||||
obj = parent;
|
||||
parent = obj->getParent();
|
||||
parent = obj->getParentOrScopeChain();
|
||||
}
|
||||
|
||||
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
|
||||
* chain during JSObject::lookupProperty. So we read parent here again.
|
||||
*/
|
||||
parent = obj->getParent();
|
||||
parent = obj->getParentOrScopeChain();
|
||||
if (!parent) {
|
||||
pobj = NULL;
|
||||
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
|
||||
* trace and should have a valid cache entry for native scopeChain.
|
||||
*/
|
||||
JS_ASSERT(scopeChain->getParent());
|
||||
JS_ASSERT(!JS_ON_TRACE(cx));
|
||||
|
||||
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).
|
||||
*/
|
||||
for (int scopeIndex = 0;
|
||||
!obj->getParent() || IsCacheableNonGlobalScope(obj);
|
||||
obj->isGlobal() || IsCacheableNonGlobalScope(obj);
|
||||
scopeIndex++) {
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
|
@ -5761,17 +5765,17 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
|
|||
return NULL;
|
||||
if (prop) {
|
||||
if (!pobj->isNative()) {
|
||||
JS_ASSERT(!obj->getParent());
|
||||
JS_ASSERT(obj->isGlobal());
|
||||
return obj;
|
||||
}
|
||||
JS_ASSERT_IF(obj->getParent(), pobj->getClass() == obj->getClass());
|
||||
JS_ASSERT_IF(obj->isScope(), pobj->getClass() == obj->getClass());
|
||||
DebugOnly<PropertyCacheEntry*> entry =
|
||||
JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
|
||||
JS_ASSERT(entry);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject *parent = obj->getParent();
|
||||
JSObject *parent = obj->getParentOrScopeChain();
|
||||
if (!parent)
|
||||
return obj;
|
||||
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
|
||||
* not null here even if it wasn't before the lookup.
|
||||
*/
|
||||
JSObject *parent = obj->getParent();
|
||||
JSObject *parent = obj->getParentOrScopeChain();
|
||||
if (!parent)
|
||||
break;
|
||||
obj = parent;
|
||||
} while (obj->getParent());
|
||||
} while (obj->isScope());
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -7098,7 +7102,7 @@ GlobalObject *
|
|||
JSObject::getGlobal() const
|
||||
{
|
||||
JSObject *obj = const_cast<JSObject *>(this);
|
||||
while (JSObject *parent = obj->getParent())
|
||||
while (JSObject *parent = obj->getParentMaybeScope())
|
||||
obj = parent;
|
||||
return obj->asGlobal();
|
||||
}
|
||||
|
@ -7397,7 +7401,7 @@ js_DumpObject(JSObject *obj)
|
|||
fputc('\n', stderr);
|
||||
|
||||
fprintf(stderr, "parent ");
|
||||
dumpValue(ObjectOrNullValue(obj->getParent()));
|
||||
dumpValue(ObjectOrNullValue(obj->getParentMaybeScope()));
|
||||
fputc('\n', stderr);
|
||||
|
||||
if (clasp->flags & JSCLASS_HAS_PRIVATE)
|
||||
|
|
|
@ -866,28 +866,31 @@ struct JSObject : js::gc::Cell
|
|||
return type_->proto;
|
||||
}
|
||||
|
||||
JSObject *getParent() const {
|
||||
return parent;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
inline JSObject *getParent() const;
|
||||
inline void clearParent();
|
||||
inline void setParent(JSObject *newParent);
|
||||
|
||||
JS_FRIEND_API(js::GlobalObject *) getGlobal() const;
|
||||
|
||||
inline bool isGlobal() const;
|
||||
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 void *getPrivate() const;
|
||||
inline void *getPrivate(size_t nfixed) const;
|
||||
|
@ -1520,21 +1523,22 @@ class ValueArray {
|
|||
* Block scope object macros. The slots reserved by BlockClass are:
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* whose activation they were created (or null if the with or block object
|
||||
* 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_WITH_THIS = 1;
|
||||
static const uint32 JSSLOT_WITH_THIS = 2;
|
||||
|
||||
#define OBJ_BLOCK_COUNT(cx,obj) \
|
||||
(obj)->propertyCount()
|
||||
|
|
|
@ -315,6 +315,70 @@ JSObject::finalize(JSContext *cx, bool background)
|
|||
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,
|
||||
* parent, map, and shape, and allocate slots.
|
||||
|
@ -326,13 +390,15 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
|
|||
if (!type)
|
||||
return false;
|
||||
|
||||
init(cx, type, parent, false);
|
||||
init(cx, type, parent->getGlobal(), false);
|
||||
if (!setInitialProperty(cx, bindings.lastShape()))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(!inDictionaryMode());
|
||||
|
||||
setScopeChain(parent);
|
||||
|
||||
/*
|
||||
* If |bindings| is for a function that has extensible parents, that means
|
||||
* 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
|
||||
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()))
|
||||
return false;
|
||||
|
@ -382,7 +448,7 @@ JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp
|
|||
JS_ASSERT(!fun->isClonedMethod());
|
||||
JS_ASSERT(fun->isNullClosure());
|
||||
|
||||
fun = CloneFunctionObject(cx, fun);
|
||||
fun = js::CloneFunctionObject(cx, fun);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
fun->setMethodObj(*this);
|
||||
|
|
|
@ -81,7 +81,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *po
|
|||
|
||||
JSObject *tmp = obj;
|
||||
for (uintN i = 0; i != scopeIndex; i++)
|
||||
tmp = tmp->getParent();
|
||||
tmp = tmp->scopeChain();
|
||||
|
||||
uintN protoIndex = 0;
|
||||
while (tmp != pobj) {
|
||||
|
@ -223,7 +223,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
|
|||
|
||||
if (JOF_MODE(cs.format) == JOF_NAME) {
|
||||
while (vindex & (PCINDEX_SCOPEMASK << PCINDEX_PROTOBITS)) {
|
||||
tmp = pobj->getParent();
|
||||
tmp = pobj->scopeChain();
|
||||
if (!tmp || !tmp->isNative())
|
||||
break;
|
||||
pobj = tmp;
|
||||
|
|
|
@ -7460,7 +7460,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
|
|||
JSObject *scopeChain = GetScopeChain(cx);
|
||||
|
||||
obj = NULL;
|
||||
for (tmp = scopeChain; tmp; tmp = tmp->getParent()) {
|
||||
for (tmp = scopeChain; tmp; tmp = tmp->getParentOrScopeChain()) {
|
||||
Class *clasp = tmp->getClass();
|
||||
if (clasp == &BlockClass || clasp == &WithClass)
|
||||
continue;
|
||||
|
@ -7655,7 +7655,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
|
|||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
} while ((obj = obj->getParent()) != NULL);
|
||||
} while ((obj = obj->getParentOrScopeChain()) != NULL);
|
||||
|
||||
JSAutoByteString printable;
|
||||
JSString *str = ConvertQNameToString(cx, nameobj);
|
||||
|
|
|
@ -1360,13 +1360,6 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
return disable("non-cacheable scope chain object");
|
||||
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. */
|
||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
Jump j = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
|
||||
|
@ -1375,10 +1368,10 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
return error();
|
||||
|
||||
/* 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);
|
||||
|
||||
tobj = tobj->getParent();
|
||||
tobj = tobj->scopeChain();
|
||||
}
|
||||
|
||||
if (tobj != getprop.holder)
|
||||
|
@ -1657,7 +1650,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
if (status != Lookup_Cacheable)
|
||||
return status;
|
||||
|
||||
if (!obj->getParent())
|
||||
if (obj->isGlobal())
|
||||
return generateGlobalStub(obj);
|
||||
|
||||
return disable("scope object not handled yet");
|
||||
|
@ -1757,20 +1750,17 @@ class BindNameCompiler : public PICStubCompiler
|
|||
|
||||
/* Walk up the scope chain. */
|
||||
JSObject *tobj = scopeChain;
|
||||
Address parent(pic.objReg, offsetof(JSObject, parent));
|
||||
Address parent(pic.objReg, JSObject::offsetOfScopeChain());
|
||||
while (tobj && tobj != obj) {
|
||||
if (!IsCacheableNonGlobalScope(tobj))
|
||||
return disable("non-cacheable obj in scope chain");
|
||||
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);
|
||||
Jump shapeTest = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
|
||||
ImmPtr(tobj->lastProperty()));
|
||||
if (!fails.append(shapeTest))
|
||||
return error();
|
||||
tobj = tobj->getParent();
|
||||
tobj = tobj->scopeChain();
|
||||
}
|
||||
if (tobj != obj)
|
||||
return disable("indirect hit");
|
||||
|
@ -1814,7 +1804,6 @@ class BindNameCompiler : public PICStubCompiler
|
|||
|
||||
JSObject *update()
|
||||
{
|
||||
JS_ASSERT(scopeChain->getParent());
|
||||
RecompilationMonitor monitor(cx);
|
||||
|
||||
JSObject *obj = js_FindIdentifierBase(cx, scopeChain, ATOM_TO_JSID(atom));
|
||||
|
|
|
@ -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().getParent());
|
||||
JS_ASSERT(f.fp()->scopeChain().isScope());
|
||||
|
||||
JSAtom *atom;
|
||||
JSObject *obj2;
|
||||
|
@ -1886,13 +1886,13 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
|
|||
*/
|
||||
JSObject *obj2 = &fp->scopeChain();
|
||||
while (obj2->isWith())
|
||||
obj2 = obj2->getParent();
|
||||
obj2 = obj2->scopeChain();
|
||||
if (obj2->isBlock() &&
|
||||
obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
|
||||
JSObject *youngestProto = obj2->getProto();
|
||||
JS_ASSERT(youngestProto->isStaticBlock());
|
||||
JSObject *parent = obj;
|
||||
while ((parent = parent->getParent()) != youngestProto)
|
||||
while ((parent = parent->getParentOrScopeChain()) != youngestProto)
|
||||
JS_ASSERT(parent);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -48,16 +48,20 @@ class CallObject : public ::JSObject
|
|||
/*
|
||||
* Reserved slot structure for Call objects:
|
||||
*
|
||||
* private - the stack frame corresponding to the Call object
|
||||
* until js_PutCallObject or its on-trace analog
|
||||
* is called, null thereafter
|
||||
* JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if
|
||||
* the stack frame is for strict mode eval code
|
||||
* JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack
|
||||
* frames (not valid for strict mode eval frames)
|
||||
* SCOPE_CHAIN_SLOT - The enclosing scope. This must come first, for
|
||||
* JSObject::scopeParent.
|
||||
* CALLEE_SLOT - Callee function for the stack frame, or null if
|
||||
* the stack frame is for strict mode eval code.
|
||||
* ARGUMENTS_SLOT - Arguments object for non-strict mode eval stack
|
||||
* 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 ARGUMENTS_SLOT = 1;
|
||||
static const uint32 CALLEE_SLOT = 1;
|
||||
static const uint32 ARGUMENTS_SLOT = 2;
|
||||
|
||||
public:
|
||||
/* Create a CallObject for the given callee function. */
|
||||
|
@ -65,6 +69,7 @@ public:
|
|||
create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee);
|
||||
|
||||
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. */
|
||||
inline bool isForEval() const;
|
||||
|
|
|
@ -62,14 +62,39 @@ namespace js {
|
|||
static inline bool
|
||||
IsCacheableNonGlobalScope(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->getParent());
|
||||
|
||||
bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
|
||||
|
||||
JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
|
||||
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
|
||||
StackFrame::initPrev(JSContext *cx)
|
||||
{
|
||||
|
@ -352,10 +377,10 @@ StackFrame::setScopeChainNoCallObj(JSObject &obj)
|
|||
if (hasCallObj()) {
|
||||
JSObject *pobj = &obj;
|
||||
while (pobj && pobj->getPrivate() != this)
|
||||
pobj = pobj->getParent();
|
||||
pobj = pobj->scopeChain();
|
||||
JS_ASSERT(pobj);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +406,7 @@ StackFrame::callObj() const
|
|||
JSObject *pobj = &scopeChain();
|
||||
while (JS_UNLIKELY(!pobj->isCall())) {
|
||||
JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith());
|
||||
pobj = pobj->getParent();
|
||||
pobj = pobj->scopeChain();
|
||||
}
|
||||
return pobj->asCall();
|
||||
}
|
||||
|
@ -454,7 +479,7 @@ StackFrame::markFunctionEpilogueDone()
|
|||
*/
|
||||
scopeChain_ = isFunctionFrame()
|
||||
? callee().getParent()
|
||||
: scopeChain_->getParent();
|
||||
: scopeChain_->scopeChain();
|
||||
flags_ &= ~HAS_CALL_OBJ;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ StackFrame::stealFrameAndSlots(Value *vp, StackFrame *otherfp,
|
|||
obj.setPrivate(this);
|
||||
otherfp->flags_ &= ~HAS_CALL_OBJ;
|
||||
if (js_IsNamedLambda(fun())) {
|
||||
JSObject *env = obj.getParent();
|
||||
JSObject *env = obj.scopeChain();
|
||||
JS_ASSERT(env->isDeclEnv());
|
||||
env->setPrivate(this);
|
||||
}
|
||||
|
|
|
@ -817,14 +817,7 @@ class StackFrame
|
|||
* !fp->hasCall() && fp->scopeChain().isCall()
|
||||
*/
|
||||
|
||||
JSObject &scopeChain() const {
|
||||
JS_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
|
||||
if (!(flags_ & HAS_SCOPECHAIN)) {
|
||||
scopeChain_ = callee().getParent();
|
||||
flags_ |= HAS_SCOPECHAIN;
|
||||
}
|
||||
return *scopeChain_;
|
||||
}
|
||||
inline JSObject &scopeChain() const;
|
||||
|
||||
bool hasCallObj() const {
|
||||
bool ret = !!(flags_ & HAS_CALL_OBJ);
|
||||
|
@ -873,12 +866,7 @@ class StackFrame
|
|||
* variables object to collect and discard the script's global variables.
|
||||
*/
|
||||
|
||||
JSObject &varObj() {
|
||||
JSObject *obj = &scopeChain();
|
||||
while (!obj->isVarObj())
|
||||
obj = obj->getParent();
|
||||
return *obj;
|
||||
}
|
||||
inline JSObject &varObj();
|
||||
|
||||
/*
|
||||
* Frame compartment
|
||||
|
@ -887,10 +875,7 @@ class StackFrame
|
|||
* compartment when the frame was pushed.
|
||||
*/
|
||||
|
||||
JSCompartment *compartment() const {
|
||||
JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
|
||||
return scopeChain().compartment();
|
||||
}
|
||||
inline JSCompartment *compartment() const;
|
||||
|
||||
/*
|
||||
* Imacropc
|
||||
|
|
Загрузка…
Ссылка в новой задаче