mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1165486 - Add StaticNonSyntacticScopeObjects and teach scope iterators about it. (r=luke)
This commit is contained in:
parent
c27c964ec1
commit
3c634f08a1
@ -1548,14 +1548,14 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
|
||||
// Use generic ops if a catch block is encountered.
|
||||
return false;
|
||||
}
|
||||
if (ssi.hasDynamicScopeObject())
|
||||
if (ssi.hasSyntacticDynamicScopeObject())
|
||||
hops++;
|
||||
continue;
|
||||
}
|
||||
RootedScript script(cx, ssi.funScript());
|
||||
if (script->functionNonDelazifying()->atom() == pn->pn_atom)
|
||||
return false;
|
||||
if (ssi.hasDynamicScopeObject()) {
|
||||
if (ssi.hasSyntacticDynamicScopeObject()) {
|
||||
uint32_t slot;
|
||||
if (lookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot, pn)) {
|
||||
JSOp op;
|
||||
|
@ -1177,6 +1177,7 @@ PopScope(JSContext* cx, ScopeIter& si)
|
||||
break;
|
||||
case ScopeIter::Call:
|
||||
case ScopeIter::Eval:
|
||||
case ScopeIter::NonSyntactic:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3934,7 +3935,7 @@ CASE(JSOP_SUPERBASE)
|
||||
{
|
||||
ScopeIter si(cx, REGS.fp()->scopeChain(), REGS.fp()->script()->innermostStaticScope(REGS.pc));
|
||||
for (; !si.done(); ++si) {
|
||||
if (si.hasScopeObject() && si.type() == ScopeIter::Call) {
|
||||
if (si.hasSyntacticScopeObject() && si.type() == ScopeIter::Call) {
|
||||
JSFunction& callee = si.scope().as<CallObject>().callee();
|
||||
|
||||
// Arrow functions don't have the information we're looking for,
|
||||
|
@ -84,6 +84,8 @@ StaticScopeIter<allowGC>::operator++(int)
|
||||
obj = obj->template as<NestedScopeObject>().enclosingScopeForStaticScopeIter();
|
||||
} else if (obj->template is<StaticEvalObject>()) {
|
||||
obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
|
||||
} else if (obj->template is<StaticNonSyntacticScopeObjects>()) {
|
||||
obj = obj->template as<StaticNonSyntacticScopeObjects>().enclosingScopeForStaticScopeIter();
|
||||
} else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) {
|
||||
onNamedLambda = false;
|
||||
obj = obj->template as<JSFunction>().nonLazyScript()->enclosingStaticScope();
|
||||
@ -92,27 +94,32 @@ StaticScopeIter<allowGC>::operator++(int)
|
||||
}
|
||||
MOZ_ASSERT_IF(obj, obj->template is<NestedScopeObject>() ||
|
||||
obj->template is<StaticEvalObject>() ||
|
||||
obj->template is<StaticNonSyntacticScopeObjects>() ||
|
||||
obj->template is<JSFunction>());
|
||||
MOZ_ASSERT_IF(onNamedLambda, obj->template is<JSFunction>());
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline bool
|
||||
StaticScopeIter<allowGC>::hasDynamicScopeObject() const
|
||||
StaticScopeIter<allowGC>::hasSyntacticDynamicScopeObject() const
|
||||
{
|
||||
return obj->template is<StaticBlockObject>()
|
||||
? obj->template as<StaticBlockObject>().needsClone()
|
||||
: (obj->template is<StaticEvalObject>()
|
||||
? obj->template as<StaticEvalObject>().isStrict()
|
||||
: (obj->template is<StaticWithObject>() ||
|
||||
obj->template as<JSFunction>().isHeavyweight()));
|
||||
if (obj->template is<JSFunction>())
|
||||
return obj->template as<JSFunction>().isHeavyweight();
|
||||
if (obj->template is<StaticBlockObject>())
|
||||
return obj->template as<StaticBlockObject>().needsClone();
|
||||
if (obj->template is<StaticWithObject>())
|
||||
return true;
|
||||
if (obj->template is<StaticEvalObject>())
|
||||
return obj->template as<StaticEvalObject>().isStrict();
|
||||
MOZ_ASSERT(obj->template is<StaticNonSyntacticScopeObjects>());
|
||||
return false;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline Shape*
|
||||
StaticScopeIter<allowGC>::scopeShape() const
|
||||
{
|
||||
MOZ_ASSERT(hasDynamicScopeObject());
|
||||
MOZ_ASSERT(hasSyntacticDynamicScopeObject());
|
||||
MOZ_ASSERT(type() != NamedLambda && type() != Eval);
|
||||
if (type() == Block)
|
||||
return block().lastProperty();
|
||||
@ -131,6 +138,8 @@ StaticScopeIter<allowGC>::type() const
|
||||
? With
|
||||
: (obj->template is<StaticEvalObject>()
|
||||
? Eval
|
||||
: (obj->template is<StaticNonSyntacticScopeObjects>())
|
||||
? NonSyntactic
|
||||
: Function));
|
||||
}
|
||||
|
||||
@ -158,6 +167,14 @@ StaticScopeIter<allowGC>::eval() const
|
||||
return obj->template as<StaticEvalObject>();
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline StaticNonSyntacticScopeObjects&
|
||||
StaticScopeIter<allowGC>::nonSyntactic() const
|
||||
{
|
||||
MOZ_ASSERT(type() == NonSyntactic);
|
||||
return obj->template as<StaticNonSyntacticScopeObjects>();
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline JSScript*
|
||||
StaticScopeIter<allowGC>::funScript() const
|
||||
|
@ -43,7 +43,7 @@ js::ScopeCoordinateToStaticScopeShape(JSScript* script, jsbytecode* pc)
|
||||
uint32_t hops = ScopeCoordinate(pc).hops();
|
||||
while (true) {
|
||||
MOZ_ASSERT(!ssi.done());
|
||||
if (ssi.hasDynamicScopeObject()) {
|
||||
if (ssi.hasSyntacticDynamicScopeObject()) {
|
||||
if (!hops)
|
||||
break;
|
||||
hops--;
|
||||
@ -107,7 +107,7 @@ js::ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc)
|
||||
StaticScopeIter<NoGC> ssi(script->innermostStaticScopeInScript(pc));
|
||||
uint32_t hops = ScopeCoordinate(pc).hops();
|
||||
while (true) {
|
||||
if (ssi.hasDynamicScopeObject()) {
|
||||
if (ssi.hasSyntacticDynamicScopeObject()) {
|
||||
if (!hops)
|
||||
break;
|
||||
hops--;
|
||||
@ -212,7 +212,7 @@ CallObject::create(JSContext* cx, HandleScript script, HandleObject enclosing, H
|
||||
if (!callobj)
|
||||
return nullptr;
|
||||
|
||||
callobj->as<ScopeObject>().setEnclosingScope(enclosing);
|
||||
callobj->setEnclosingScope(enclosing);
|
||||
callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
|
||||
|
||||
if (script->treatAsRunOnce()) {
|
||||
@ -420,7 +420,7 @@ DynamicWithObject::create(JSContext* cx, HandleObject object, HandleObject enclo
|
||||
if (!thisp)
|
||||
return nullptr;
|
||||
|
||||
obj->as<ScopeObject>().setEnclosingScope(enclosing);
|
||||
obj->setEnclosingScope(enclosing);
|
||||
obj->setFixedSlot(OBJECT_SLOT, ObjectValue(*object));
|
||||
obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
|
||||
obj->setFixedSlot(KIND_SLOT, Int32Value(kind));
|
||||
@ -551,6 +551,25 @@ const Class StaticEvalObject::class_ = {
|
||||
JSCLASS_IS_ANONYMOUS
|
||||
};
|
||||
|
||||
/* static */ StaticNonSyntacticScopeObjects*
|
||||
StaticNonSyntacticScopeObjects::create(JSContext*cx, HandleObject enclosing)
|
||||
{
|
||||
StaticNonSyntacticScopeObjects* obj =
|
||||
NewObjectWithNullTaggedProto<StaticNonSyntacticScopeObjects>(cx, TenuredObject,
|
||||
BaseShape::DELEGATE);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing));
|
||||
return obj;
|
||||
}
|
||||
|
||||
const Class StaticNonSyntacticScopeObjects::class_ = {
|
||||
"StaticNonSyntacticScopeObjects",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(StaticNonSyntacticScopeObjects::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* static */ ClonedBlockObject*
|
||||
@ -845,7 +864,7 @@ UninitializedLexicalObject::create(JSContext* cx, HandleObject enclosing)
|
||||
BaseShape::DELEGATE);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
obj->as<ScopeObject>().setEnclosingScope(enclosing);
|
||||
obj->setEnclosingScope(enclosing);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -983,7 +1002,14 @@ ScopeIter::ScopeIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
|
||||
void
|
||||
ScopeIter::incrementStaticScopeIter()
|
||||
{
|
||||
ssi_++;
|
||||
// If settled on a non-syntactic static scope, only increment ssi_ once
|
||||
// we've iterated through all the non-syntactic dynamic ScopeObjects.
|
||||
if (ssi_.type() == StaticScopeIter<CanGC>::NonSyntactic) {
|
||||
if (!hasNonSyntacticScopeObject())
|
||||
ssi_++;
|
||||
} else {
|
||||
ssi_++;
|
||||
}
|
||||
|
||||
// For named lambdas, DeclEnvObject scopes are always attached to their
|
||||
// CallObjects. Skip it here, as they are special cased in users of
|
||||
@ -1010,7 +1036,7 @@ ScopeIter::settle()
|
||||
frame_ = NullFramePtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!ssi_.done() && hasScopeObject()) {
|
||||
if (!ssi_.done() && hasAnyScopeObject()) {
|
||||
switch (ssi_.type()) {
|
||||
case StaticScopeIter<CanGC>::Function:
|
||||
MOZ_ASSERT(scope_->as<CallObject>().callee().nonLazyScript() == ssi_.funScript());
|
||||
@ -1024,6 +1050,9 @@ ScopeIter::settle()
|
||||
case StaticScopeIter<CanGC>::Eval:
|
||||
MOZ_ASSERT(scope_->as<CallObject>().isForEval());
|
||||
break;
|
||||
case StaticScopeIter<CanGC>::NonSyntactic:
|
||||
MOZ_ASSERT(!IsSyntacticScope(scope_));
|
||||
break;
|
||||
case StaticScopeIter<CanGC>::NamedLambda:
|
||||
MOZ_CRASH("named lambda static scopes should have been skipped");
|
||||
}
|
||||
@ -1034,7 +1063,7 @@ ScopeIter::settle()
|
||||
ScopeIter&
|
||||
ScopeIter::operator++()
|
||||
{
|
||||
if (hasScopeObject()) {
|
||||
if (hasAnyScopeObject()) {
|
||||
scope_ = &scope_->as<ScopeObject>().enclosingScope();
|
||||
if (scope_->is<DeclEnvObject>())
|
||||
scope_ = &scope_->as<DeclEnvObject>().enclosingScope();
|
||||
@ -1060,6 +1089,8 @@ ScopeIter::type() const
|
||||
return With;
|
||||
case StaticScopeIter<CanGC>::Eval:
|
||||
return Eval;
|
||||
case StaticScopeIter<CanGC>::NonSyntactic:
|
||||
return NonSyntactic;
|
||||
case StaticScopeIter<CanGC>::NamedLambda:
|
||||
MOZ_CRASH("named lambda static scopes should have been skipped");
|
||||
default:
|
||||
@ -1070,7 +1101,7 @@ ScopeIter::type() const
|
||||
ScopeObject&
|
||||
ScopeIter::scope() const
|
||||
{
|
||||
MOZ_ASSERT(hasScopeObject());
|
||||
MOZ_ASSERT(hasAnyScopeObject());
|
||||
return scope_->as<ScopeObject>();
|
||||
}
|
||||
|
||||
@ -1089,6 +1120,8 @@ ScopeIter::maybeStaticScope() const
|
||||
return &staticWith();
|
||||
case StaticScopeIter<CanGC>::Eval:
|
||||
return &staticEval();
|
||||
case StaticScopeIter<CanGC>::NonSyntactic:
|
||||
return &staticNonSyntactic();
|
||||
case StaticScopeIter<CanGC>::NamedLambda:
|
||||
MOZ_CRASH("named lambda static scopes should have been skipped");
|
||||
default:
|
||||
@ -1688,7 +1721,7 @@ const DebugScopeProxy DebugScopeProxy::singleton;
|
||||
DebugScopeObject::create(JSContext* cx, ScopeObject& scope, HandleObject enclosing)
|
||||
{
|
||||
MOZ_ASSERT(scope.compartment() == cx->compartment());
|
||||
MOZ_ASSERT(!IsSyntacticScope(enclosing));
|
||||
MOZ_ASSERT(!enclosing->is<ScopeObject>());
|
||||
|
||||
RootedValue priv(cx, ObjectValue(scope));
|
||||
JSObject* obj = NewProxyObject(cx, &DebugScopeProxy::singleton, priv,
|
||||
@ -1950,7 +1983,7 @@ DebugScopes::addDebugScope(JSContext* cx, ScopeObject& scope, DebugScopeObject&
|
||||
DebugScopeObject*
|
||||
DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si)
|
||||
{
|
||||
MOZ_ASSERT(!si.hasScopeObject());
|
||||
MOZ_ASSERT(!si.hasSyntacticScopeObject());
|
||||
|
||||
DebugScopes* scopes = cx->compartment()->debugScopes;
|
||||
if (!scopes)
|
||||
@ -1966,7 +1999,7 @@ DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si)
|
||||
bool
|
||||
DebugScopes::addDebugScope(JSContext* cx, const ScopeIter& si, DebugScopeObject& debugScope)
|
||||
{
|
||||
MOZ_ASSERT(!si.hasScopeObject());
|
||||
MOZ_ASSERT(!si.hasSyntacticScopeObject());
|
||||
MOZ_ASSERT(cx->compartment() == debugScope.compartment());
|
||||
MOZ_ASSERT_IF(si.withinInitialFrame() && si.initialFrame().isFunctionFrame(),
|
||||
!si.initialFrame().callee()->isGenerator());
|
||||
@ -2184,7 +2217,7 @@ DebugScopes::updateLiveScopes(JSContext* cx)
|
||||
continue;
|
||||
|
||||
for (ScopeIter si(cx, frame, i.pc()); si.withinInitialFrame(); ++si) {
|
||||
if (si.hasScopeObject()) {
|
||||
if (si.hasSyntacticScopeObject()) {
|
||||
MOZ_ASSERT(si.scope().compartment() == cx->compartment());
|
||||
DebugScopes* scopes = ensureCompartmentData(cx);
|
||||
if (!scopes)
|
||||
@ -2302,7 +2335,7 @@ GetDebugScopeForScope(JSContext* cx, const ScopeIter& si)
|
||||
static DebugScopeObject*
|
||||
GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
|
||||
{
|
||||
MOZ_ASSERT(!si.hasScopeObject() && si.canHaveScopeObject());
|
||||
MOZ_ASSERT(!si.hasSyntacticScopeObject() && si.canHaveSyntacticScopeObject());
|
||||
|
||||
if (DebugScopeObject* debugScope = DebugScopes::hasDebugScope(cx, si))
|
||||
return debugScope;
|
||||
@ -2369,6 +2402,8 @@ GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
|
||||
case ScopeIter::With:
|
||||
case ScopeIter::Eval:
|
||||
MOZ_CRASH("should already have a scope");
|
||||
case ScopeIter::NonSyntactic:
|
||||
MOZ_CRASH("non-syntactic scopes cannot be synthesized");
|
||||
}
|
||||
if (!debugScope)
|
||||
return nullptr;
|
||||
@ -2383,11 +2418,11 @@ static JSObject*
|
||||
GetDebugScopeForNonScopeObject(const ScopeIter& si)
|
||||
{
|
||||
JSObject& enclosing = si.enclosingScope();
|
||||
MOZ_ASSERT(!IsSyntacticScope(&enclosing));
|
||||
MOZ_ASSERT(!enclosing.is<ScopeObject>());
|
||||
#ifdef DEBUG
|
||||
JSObject* o = &enclosing;
|
||||
while ((o = o->enclosingScope()))
|
||||
MOZ_ASSERT(!IsSyntacticScope(o));
|
||||
MOZ_ASSERT(!o->is<ScopeObject>());
|
||||
#endif
|
||||
return &enclosing;
|
||||
}
|
||||
@ -2400,10 +2435,10 @@ GetDebugScope(JSContext* cx, const ScopeIter& si)
|
||||
if (si.done())
|
||||
return GetDebugScopeForNonScopeObject(si);
|
||||
|
||||
if (si.hasScopeObject())
|
||||
if (si.hasAnyScopeObject())
|
||||
return GetDebugScopeForScope(cx, si);
|
||||
|
||||
if (si.canHaveScopeObject())
|
||||
if (si.canHaveSyntacticScopeObject())
|
||||
return GetDebugScopeForMissing(cx, si);
|
||||
|
||||
ScopeIter copy(cx, si);
|
||||
|
@ -22,6 +22,7 @@ namespace frontend { struct Definition; }
|
||||
|
||||
class StaticWithObject;
|
||||
class StaticEvalObject;
|
||||
class StaticNonSyntacticScopeObjects;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@ -62,6 +63,7 @@ class StaticScopeIter
|
||||
obj->is<StaticBlockObject>() ||
|
||||
obj->is<StaticWithObject>() ||
|
||||
obj->is<StaticEvalObject>() ||
|
||||
obj->is<StaticNonSyntacticScopeObjects>() ||
|
||||
obj->is<JSFunction>());
|
||||
}
|
||||
|
||||
@ -81,6 +83,7 @@ class StaticScopeIter
|
||||
obj->is<StaticBlockObject>() ||
|
||||
obj->is<StaticWithObject>() ||
|
||||
obj->is<StaticEvalObject>() ||
|
||||
obj->is<StaticNonSyntacticScopeObjects>() ||
|
||||
obj->is<JSFunction>());
|
||||
}
|
||||
|
||||
@ -95,16 +98,19 @@ class StaticScopeIter
|
||||
bool done() const;
|
||||
void operator++(int);
|
||||
|
||||
/* Return whether this static scope will be on the dynamic scope chain. */
|
||||
bool hasDynamicScopeObject() const;
|
||||
// Return whether this static scope will have a syntactic scope (i.e. a
|
||||
// ScopeObject that isn't a non-syntactic With or
|
||||
// NonSyntacticVariablesObject) on the dynamic scope chain.
|
||||
bool hasSyntacticDynamicScopeObject() const;
|
||||
Shape* scopeShape() const;
|
||||
|
||||
enum Type { Function, Block, With, NamedLambda, Eval };
|
||||
enum Type { Function, Block, With, NamedLambda, Eval, NonSyntactic };
|
||||
Type type() const;
|
||||
|
||||
StaticBlockObject& block() const;
|
||||
StaticWithObject& staticWith() const;
|
||||
StaticEvalObject& eval() const;
|
||||
StaticNonSyntacticScopeObjects& nonSyntactic() const;
|
||||
JSScript* funScript() const;
|
||||
JSFunction& fun() const;
|
||||
};
|
||||
@ -175,26 +181,28 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
|
||||
* scope objects is:
|
||||
*
|
||||
* JSObject Generic object
|
||||
* \
|
||||
* ScopeObject Engine-internal scope
|
||||
* \ \ \ \
|
||||
* \ \ \ StaticEvalObject Placeholder so eval scopes may be iterated through
|
||||
* \ \ \
|
||||
* \ \ DeclEnvObject Holds name of recursive/heavyweight named lambda
|
||||
* \ \
|
||||
* \ CallObject Scope of entire function or strict eval
|
||||
* \
|
||||
* NestedScopeObject Scope created for a statement
|
||||
* \ \ \
|
||||
* \ \ StaticWithObject Template for "with" object in static scope chain
|
||||
* \ \
|
||||
* \ DynamicWithObject Run-time "with" object on scope chain
|
||||
* \
|
||||
* BlockObject Shared interface of cloned/static block objects
|
||||
* \ \
|
||||
* \ ClonedBlockObject let, switch, catch, for
|
||||
* \
|
||||
* StaticBlockObject See NB
|
||||
* |
|
||||
* ScopeObject---+---+ Engine-internal scope
|
||||
* | | | | |
|
||||
* | | | | StaticNonSyntacticScopeObjects See NB2
|
||||
* | | | |
|
||||
* | | | StaticEvalObject Placeholder so eval scopes may be iterated through
|
||||
* | | |
|
||||
* | | DeclEnvObject Holds name of recursive/heavyweight named lambda
|
||||
* | |
|
||||
* | CallObject Scope of entire function or strict eval
|
||||
* |
|
||||
* NestedScopeObject Scope created for a statement
|
||||
* | | |
|
||||
* | | StaticWithObject Template for "with" object in static scope chain
|
||||
* | |
|
||||
* | DynamicWithObject Run-time "with" object on scope chain
|
||||
* |
|
||||
* BlockObject Shared interface of cloned/static block objects
|
||||
* | |
|
||||
* | ClonedBlockObject let, switch, catch, for
|
||||
* |
|
||||
* StaticBlockObject See NB
|
||||
*
|
||||
* This hierarchy represents more than just the interface hierarchy: reserved
|
||||
* slots in base classes are fixed for all derived classes. Thus, for example,
|
||||
@ -206,6 +214,9 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
|
||||
* are cloned at runtime. These objects should never escape into the wild and
|
||||
* support a restricted set of ScopeObject operations.
|
||||
*
|
||||
* NB2: StaticNonSyntacticScopeObjects notify either of 0+ non-syntactic
|
||||
* DynamicWithObjects on the dynamic scope chain or a NonSyntacticScopeObject.
|
||||
*
|
||||
* See also "Debug scope objects" below.
|
||||
*/
|
||||
|
||||
@ -352,8 +363,9 @@ class DeclEnvObject : public ScopeObject
|
||||
}
|
||||
};
|
||||
|
||||
// Static eval scope template objects on the static scope. Created at the
|
||||
// time of compiling the eval script, and set as its static enclosing scope.
|
||||
// Static eval scope placeholder objects on the static scope chain. Created at
|
||||
// the time of compiling the eval script, and set as its static enclosing
|
||||
// scope.
|
||||
class StaticEvalObject : public ScopeObject
|
||||
{
|
||||
static const uint32_t STRICT_SLOT = 1;
|
||||
@ -383,6 +395,34 @@ class StaticEvalObject : public ScopeObject
|
||||
}
|
||||
};
|
||||
|
||||
// Static scope objects that stand in for one or more "polluting global"
|
||||
// scopes on the dynamic scope chain.
|
||||
//
|
||||
// There are two flavors of polluting global scopes on the dynamic scope
|
||||
// chain:
|
||||
//
|
||||
// 1. 0+ non-syntactic DynamicWithObjects. This static scope helps ScopeIter
|
||||
// iterate these DynamicWithObjects.
|
||||
//
|
||||
// 2. 1 PlainObject that is a both a QualifiedVarObj and an UnqualifiedVarObj,
|
||||
// created exclusively in js::ExecuteInGlobalAndReturnScope.
|
||||
//
|
||||
// Since this PlainObject is not a ScopeObject, ScopeIter cannot iterate
|
||||
// through it. Instead, this PlainObject always comes after the syntactic
|
||||
// portion of the dynamic scope chain in front of a GlobalObject.
|
||||
class StaticNonSyntacticScopeObjects : public ScopeObject
|
||||
{
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
static const Class class_;
|
||||
|
||||
static StaticNonSyntacticScopeObjects* create(JSContext* cx, HandleObject enclosing);
|
||||
|
||||
JSObject* enclosingScopeForStaticScopeIter() {
|
||||
return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
|
||||
}
|
||||
};
|
||||
|
||||
class NestedScopeObject : public ScopeObject
|
||||
{
|
||||
public:
|
||||
@ -747,17 +787,20 @@ class ScopeIter
|
||||
inline JSObject& enclosingScope() const;
|
||||
|
||||
// If !done():
|
||||
enum Type { Call, Block, With, Eval };
|
||||
enum Type { Call, Block, With, Eval, NonSyntactic };
|
||||
Type type() const;
|
||||
|
||||
inline bool hasScopeObject() const;
|
||||
inline bool canHaveScopeObject() const;
|
||||
inline bool hasNonSyntacticScopeObject() const;
|
||||
inline bool hasSyntacticScopeObject() const;
|
||||
inline bool hasAnyScopeObject() const;
|
||||
inline bool canHaveSyntacticScopeObject() const;
|
||||
ScopeObject& scope() const;
|
||||
|
||||
JSObject* maybeStaticScope() const;
|
||||
StaticBlockObject& staticBlock() const { return ssi_.block(); }
|
||||
StaticWithObject& staticWith() const { return ssi_.staticWith(); }
|
||||
StaticEvalObject& staticEval() const { return ssi_.eval(); }
|
||||
StaticNonSyntacticScopeObjects& staticNonSyntactic() const { return ssi_.nonSyntactic(); }
|
||||
JSFunction& fun() const { return ssi_.fun(); }
|
||||
|
||||
bool withinInitialFrame() const { return !!frame_; }
|
||||
@ -1054,16 +1097,50 @@ ScopeIter::done() const
|
||||
}
|
||||
|
||||
inline bool
|
||||
ScopeIter::hasScopeObject() const
|
||||
ScopeIter::hasSyntacticScopeObject() const
|
||||
{
|
||||
return ssi_.hasDynamicScopeObject();
|
||||
return ssi_.hasSyntacticDynamicScopeObject();
|
||||
}
|
||||
|
||||
inline bool
|
||||
ScopeIter::canHaveScopeObject() const
|
||||
ScopeIter::hasNonSyntacticScopeObject() const
|
||||
{
|
||||
// Non-strict eval scopes cannot have dynamic scope objects.
|
||||
return !ssi_.done() && (type() != Eval || staticEval().isStrict());
|
||||
// The case we're worrying about here is a NonSyntactic static scope which
|
||||
// has 0+ corresponding non-syntactic DynamicWithObject scopes or a
|
||||
// NonSyntacticVariablesObject.
|
||||
if (ssi_.type() == StaticScopeIter<CanGC>::NonSyntactic) {
|
||||
MOZ_ASSERT_IF(scope_->is<DynamicWithObject>(),
|
||||
!scope_->as<DynamicWithObject>().isSyntactic());
|
||||
return scope_->is<DynamicWithObject>();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ScopeIter::hasAnyScopeObject() const
|
||||
{
|
||||
return hasSyntacticScopeObject() || hasNonSyntacticScopeObject();
|
||||
}
|
||||
|
||||
inline bool
|
||||
ScopeIter::canHaveSyntacticScopeObject() const
|
||||
{
|
||||
if (ssi_.done())
|
||||
return false;
|
||||
|
||||
switch (type()) {
|
||||
case Call:
|
||||
return true;
|
||||
case Block:
|
||||
return true;
|
||||
case With:
|
||||
return true;
|
||||
case Eval:
|
||||
// Only strict eval scopes can have dynamic scope objects.
|
||||
return staticEval().isStrict();
|
||||
case NonSyntactic:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline JSObject&
|
||||
|
@ -153,7 +153,12 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject*
|
||||
#ifdef DEBUG
|
||||
RootedObject enclosingScope(cx, script->enclosingStaticScope());
|
||||
for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
|
||||
if (i.hasDynamicScopeObject()) {
|
||||
if (i.type() == StaticScopeIter<NoGC>::NonSyntactic) {
|
||||
while (scope->is<DynamicWithObject>()) {
|
||||
MOZ_ASSERT(!scope->as<DynamicWithObject>().isSyntactic());
|
||||
scope = &scope->as<DynamicWithObject>().enclosingScope();
|
||||
}
|
||||
} else if (i.hasSyntacticDynamicScopeObject()) {
|
||||
switch (i.type()) {
|
||||
case StaticScopeIter<NoGC>::Function:
|
||||
MOZ_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
|
||||
@ -173,13 +178,16 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject*
|
||||
case StaticScopeIter<NoGC>::Eval:
|
||||
scope = &scope->as<CallObject>().enclosingScope();
|
||||
break;
|
||||
case StaticScopeIter<NoGC>::NonSyntactic:
|
||||
MOZ_CRASH("NonSyntactic should not have a syntactic scope");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The scope chain is always ended by one or more non-syntactic
|
||||
// ScopeObjects (viz. GlobalObject or a non-syntactic WithObject).
|
||||
MOZ_ASSERT(!IsSyntacticScope(scope));
|
||||
// ScopeObjects (viz. GlobalObject or an unqualified varobj).
|
||||
MOZ_ASSERT(!scope->is<ScopeObject>());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -246,7 +254,7 @@ InterpreterFrame::epilogue(JSContext* cx)
|
||||
DebugScopes::onPopStrictEvalScope(this);
|
||||
} else if (isDirectEvalFrame()) {
|
||||
if (isDebuggerEvalFrame())
|
||||
MOZ_ASSERT(!IsSyntacticScope(scopeChain()));
|
||||
MOZ_ASSERT(!scopeChain()->is<ScopeObject>());
|
||||
} else {
|
||||
/*
|
||||
* Debugger.Object.prototype.evalInGlobal creates indirect eval
|
||||
|
Loading…
Reference in New Issue
Block a user