зеркало из 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);
|
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 = ®s.fp()->scopeChain(); obj; obj = obj->getParent()) {
|
for (obj = ®s.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 = ®s.fp()->scopeChain();
|
obj = ®s.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 = ®s.fp()->scopeChain();
|
JSObject *obj2 = ®s.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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче