mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 20:55:39 +00:00
Bug 930414 - Add module scopes, using ModuleObject as the static scope and ModuleEnvironementObject as the dynamic scope r=shu
This commit is contained in:
parent
a920d4b2e6
commit
381c692f63
@ -413,6 +413,8 @@ bool
|
||||
ParseContext<ParseHandler>::generateBindings(ExclusiveContext* cx, TokenStream& ts, LifoAlloc& alloc,
|
||||
MutableHandle<Bindings> bindings) const
|
||||
{
|
||||
MOZ_ASSERT_IF(sc->isFunctionBox(), args_.length() < ARGNO_LIMIT);
|
||||
MOZ_ASSERT_IF(sc->isModuleBox(), args_.length() == 0);
|
||||
MOZ_ASSERT(vars_.length() + bodyLevelLexicals_.length() < LOCALNO_LIMIT);
|
||||
|
||||
/*
|
||||
@ -448,29 +450,7 @@ ParseContext<ParseHandler>::generateBindings(ExclusiveContext* cx, TokenStream&
|
||||
return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
|
||||
bodyLevelLexicals_.length(), blockScopeDepth,
|
||||
numUnaliasedVars, numUnaliasedBodyLevelLexicals,
|
||||
packedBindings);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext* cx, TokenStream& ts,
|
||||
LifoAlloc& alloc,
|
||||
MutableHandle<Bindings> bindings) const
|
||||
{
|
||||
MOZ_ASSERT(sc->isFunctionBox());
|
||||
MOZ_ASSERT(args_.length() < ARGNO_LIMIT);
|
||||
return generateBindings(cx, ts, alloc, bindings);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
ParseContext<ParseHandler>::generateModuleBindings(ExclusiveContext* cx, TokenStream& ts,
|
||||
LifoAlloc& alloc,
|
||||
MutableHandle<Bindings> bindings) const
|
||||
{
|
||||
MOZ_ASSERT(sc->isModuleBox());
|
||||
MOZ_ASSERT(args_.length() == 0);
|
||||
return generateBindings(cx, ts, alloc, bindings);
|
||||
packedBindings, sc->isModuleBox());
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@ -883,7 +863,7 @@ Parser<ParseHandler>::standaloneModule(HandleModuleObject module)
|
||||
return null();
|
||||
|
||||
Rooted<Bindings> bindings(context, modulebox->bindings);
|
||||
if (!modulepc.generateModuleBindings(context, tokenStream, alloc, &bindings))
|
||||
if (!modulepc.generateBindings(context, tokenStream, alloc, &bindings))
|
||||
return null();
|
||||
modulebox->bindings = bindings;
|
||||
|
||||
@ -973,7 +953,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
}
|
||||
|
||||
Rooted<Bindings> bindings(context, funbox->bindings);
|
||||
if (!funpc.generateFunctionBindings(context, tokenStream, alloc, &bindings))
|
||||
if (!funpc.generateBindings(context, tokenStream, alloc, &bindings))
|
||||
return null();
|
||||
funbox->bindings = bindings;
|
||||
|
||||
@ -1529,7 +1509,7 @@ ConvertDefinitionToNamedLambdaUse(TokenStream& ts, ParseContext<FullParseHandler
|
||||
* Since 'dn' is a placeholder, it has not been defined in the
|
||||
* ParseContext and hence we must manually flag a closed-over
|
||||
* callee name as needing a dynamic scope (this is done for all
|
||||
* definitions in the ParseContext by generateFunctionBindings).
|
||||
* definitions in the ParseContext by generateBindings).
|
||||
*
|
||||
* If 'dn' has been assigned to, then we also flag the function
|
||||
* scope has needing a dynamic scope so that dynamic scope
|
||||
@ -1690,7 +1670,7 @@ Parser<FullParseHandler>::leaveFunction(ParseNode* fn, ParseContext<FullParseHan
|
||||
}
|
||||
|
||||
Rooted<Bindings> bindings(context, funbox->bindings);
|
||||
if (!pc->generateFunctionBindings(context, tokenStream, alloc, &bindings))
|
||||
if (!pc->generateBindings(context, tokenStream, alloc, &bindings))
|
||||
return false;
|
||||
funbox->bindings = bindings;
|
||||
|
||||
@ -2716,7 +2696,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
|
||||
}
|
||||
|
||||
Rooted<Bindings> bindings(context, funbox->bindings);
|
||||
if (!pc->generateFunctionBindings(context, tokenStream, alloc, &bindings))
|
||||
if (!pc->generateBindings(context, tokenStream, alloc, &bindings))
|
||||
return null();
|
||||
funbox->bindings = bindings;
|
||||
|
||||
@ -3231,7 +3211,7 @@ Parser<FullParseHandler>::bindLexical(BindData<FullParseHandler>* data,
|
||||
// script->nfixed and body-level lets.
|
||||
//
|
||||
// For body-level lets, the index is bogus at this point and is adjusted
|
||||
// when creating Bindings. See ParseContext::generateFunctionBindings and
|
||||
// when creating Bindings. See ParseContext::generateBindings and
|
||||
// AppendPackedBindings.
|
||||
if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index))
|
||||
return false;
|
||||
|
@ -212,19 +212,9 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
|
||||
* - Sometimes a script's bindings are accessed at runtime to retrieve the
|
||||
* contents of the lexical scope (e.g., from the debugger).
|
||||
*/
|
||||
private:
|
||||
bool generateBindings(ExclusiveContext* cx, TokenStream& ts, LifoAlloc& alloc,
|
||||
MutableHandle<Bindings> bindings) const;
|
||||
|
||||
public:
|
||||
bool generateFunctionBindings(ExclusiveContext* cx, TokenStream& ts,
|
||||
LifoAlloc& alloc,
|
||||
MutableHandle<Bindings> bindings) const;
|
||||
|
||||
bool generateModuleBindings(ExclusiveContext* cx, TokenStream& ts,
|
||||
LifoAlloc& alloc,
|
||||
MutableHandle<Bindings> bindings) const;
|
||||
|
||||
private:
|
||||
ParseContext** parserPC; /* this points to the Parser's active pc
|
||||
and holds either |this| or one of
|
||||
|
@ -230,6 +230,7 @@ JSObject::isQualifiedVarObj() const
|
||||
MOZ_ASSERT_IF(rv,
|
||||
is<js::GlobalObject>() ||
|
||||
is<js::CallObject>() ||
|
||||
is<js::ModuleEnvironmentObject>() ||
|
||||
is<js::NonSyntacticVariablesObject>() ||
|
||||
(is<js::DynamicWithObject>() && !as<js::DynamicWithObject>().isSyntactic()));
|
||||
return rv;
|
||||
|
@ -75,7 +75,7 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings>
|
||||
uint32_t numArgs, uint32_t numVars,
|
||||
uint32_t numBodyLevelLexicals, uint32_t numBlockScoped,
|
||||
uint32_t numUnaliasedVars, uint32_t numUnaliasedBodyLevelLexicals,
|
||||
const Binding* bindingArray)
|
||||
const Binding* bindingArray, bool isModule /* = false */)
|
||||
{
|
||||
MOZ_ASSERT(!self.callObjShape());
|
||||
MOZ_ASSERT(self.bindingArrayUsingTemporaryStorage());
|
||||
@ -141,9 +141,10 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings>
|
||||
uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(nslots));
|
||||
|
||||
// Start with the empty shape and then append one shape per aliased binding.
|
||||
const Class* cls = isModule ? &ModuleEnvironmentObject::class_ : &CallObject::class_;
|
||||
RootedShape shape(cx,
|
||||
EmptyShape::getInitialShape(cx, &CallObject::class_, TaggedProto(nullptr),
|
||||
nfixed, BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE));
|
||||
EmptyShape::getInitialShape(cx, cls, TaggedProto(nullptr), nfixed,
|
||||
BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE));
|
||||
if (!shape)
|
||||
return false;
|
||||
|
||||
@ -169,9 +170,7 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings>
|
||||
}
|
||||
#endif
|
||||
|
||||
StackBaseShape stackBase(cx, &CallObject::class_,
|
||||
BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE);
|
||||
|
||||
StackBaseShape stackBase(cx, cls, BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE);
|
||||
UnownedBaseShape* base = BaseShape::getUnowned(cx, stackBase);
|
||||
if (!base)
|
||||
return false;
|
||||
|
@ -274,7 +274,8 @@ class Bindings : public JS::Traceable
|
||||
uint32_t numBlockScoped,
|
||||
uint32_t numUnaliasedVars,
|
||||
uint32_t numUnaliasedBodyLevelLexicals,
|
||||
const Binding* bindingArray);
|
||||
const Binding* bindingArray,
|
||||
bool isModule = false);
|
||||
|
||||
// Initialize a trivial Bindings with no slots and an empty callObjShape.
|
||||
bool initTrivial(ExclusiveContext* cx);
|
||||
|
@ -4245,18 +4245,28 @@ DumpStaticScopeChain(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
|
||||
ReportUsageError(cx, callee, "Argument must be an interpreted function");
|
||||
if (!args[0].isObject() ||
|
||||
!(args[0].toObject().is<JSFunction>() || args[0].toObject().is<ModuleObject>()))
|
||||
{
|
||||
ReportUsageError(cx, callee, "Argument must be an interpreted function or a module");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
|
||||
if (!fun->isInterpreted()) {
|
||||
ReportUsageError(cx, callee, "Argument must be an interpreted function");
|
||||
return false;
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
RootedScript script(cx);
|
||||
|
||||
if (obj->is<JSFunction>()) {
|
||||
RootedFunction fun(cx, &obj->as<JSFunction>());
|
||||
if (!fun->isInterpreted()) {
|
||||
ReportUsageError(cx, callee, "Argument must be an interpreted function");
|
||||
return false;
|
||||
}
|
||||
script = fun->getOrCreateScript(cx);
|
||||
} else {
|
||||
script = obj->as<ModuleObject>().script();
|
||||
}
|
||||
|
||||
js::DumpStaticScopeChain(fun->getOrCreateScript(cx));
|
||||
js::DumpStaticScopeChain(script);
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -4910,8 +4920,8 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_FN_HELP("dumpStaticScopeChain", DumpStaticScopeChain, 1, 0,
|
||||
"dumpStaticScopeChain(fun)",
|
||||
" Prints the static scope chain of an interpreted function fun."),
|
||||
"dumpStaticScopeChain(obj)",
|
||||
" Prints the static scope chain of an interpreted function or a module."),
|
||||
#endif
|
||||
|
||||
JS_FS_HELP_END
|
||||
|
@ -1259,6 +1259,7 @@ PopScope(JSContext* cx, ScopeIter& si)
|
||||
case ScopeIter::With:
|
||||
si.initialFrame().popWith(cx);
|
||||
break;
|
||||
case ScopeIter::Module:
|
||||
case ScopeIter::Call:
|
||||
case ScopeIter::Eval:
|
||||
case ScopeIter::NonSyntactic:
|
||||
|
@ -80,6 +80,8 @@ StaticScopeIter<allowGC>::operator++(int)
|
||||
obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
|
||||
} else if (obj->template is<StaticNonSyntacticScopeObjects>()) {
|
||||
obj = obj->template as<StaticNonSyntacticScopeObjects>().enclosingScopeForStaticScopeIter();
|
||||
} else if (obj->template is<ModuleObject>()) {
|
||||
obj = obj->template as<ModuleObject>().script()->enclosingStaticScope();
|
||||
} else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) {
|
||||
onNamedLambda = false;
|
||||
JSFunction& fun = obj->template as<JSFunction>();
|
||||
@ -104,6 +106,8 @@ StaticScopeIter<allowGC>::hasSyntacticDynamicScopeObject() const
|
||||
return fun.functionBox()->isHeavyweight();
|
||||
return fun.isHeavyweight();
|
||||
}
|
||||
if (obj->template is<ModuleObject>())
|
||||
return true;
|
||||
if (obj->template is<StaticBlockObject>())
|
||||
return obj->template as<StaticBlockObject>().needsClone();
|
||||
if (obj->template is<StaticWithObject>())
|
||||
@ -122,6 +126,8 @@ StaticScopeIter<allowGC>::scopeShape() const
|
||||
MOZ_ASSERT(type() != NamedLambda && type() != Eval);
|
||||
if (type() == Block)
|
||||
return block().lastProperty();
|
||||
if (type() == Module)
|
||||
return moduleScript()->callObjShape();
|
||||
return funScript()->callObjShape();
|
||||
}
|
||||
|
||||
@ -131,15 +137,17 @@ StaticScopeIter<allowGC>::type() const
|
||||
{
|
||||
if (onNamedLambda)
|
||||
return NamedLambda;
|
||||
return obj->template is<StaticBlockObject>()
|
||||
? Block
|
||||
: (obj->template is<StaticWithObject>()
|
||||
? With
|
||||
: (obj->template is<StaticEvalObject>()
|
||||
? Eval
|
||||
: (obj->template is<StaticNonSyntacticScopeObjects>())
|
||||
? NonSyntactic
|
||||
: Function));
|
||||
if (obj->template is<StaticBlockObject>())
|
||||
return Block;
|
||||
if (obj->template is<StaticWithObject>())
|
||||
return With;
|
||||
if (obj->template is<StaticEvalObject>())
|
||||
return Eval;
|
||||
if (obj->template is<StaticNonSyntacticScopeObjects>())
|
||||
return NonSyntactic;
|
||||
if (obj->template is<ModuleObject>())
|
||||
return Module;
|
||||
return Function;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
@ -200,6 +208,22 @@ StaticScopeIter<allowGC>::maybeFunctionBox() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline JSScript*
|
||||
StaticScopeIter<allowGC>::moduleScript() const
|
||||
{
|
||||
MOZ_ASSERT(type() == Module);
|
||||
return obj->template as<ModuleObject>().script();
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline ModuleObject&
|
||||
StaticScopeIter<allowGC>::module() const
|
||||
{
|
||||
MOZ_ASSERT(type() == Module);
|
||||
return obj->template as<ModuleObject>();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
inline JSObject*
|
||||
|
@ -191,8 +191,8 @@ CallObject::createTemplateObject(JSContext* cx, HandleScript script, gc::Initial
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
// Set uninitialized lexicals even on template objects, as Ion will use
|
||||
// copy over the template object's slot values in the fast path.
|
||||
// Set uninitialized lexicals even on template objects, as Ion will copy
|
||||
// over the template object's slot values in the fast path.
|
||||
obj->as<CallObject>().initAliasedLexicalsToThrowOnTouch(script);
|
||||
|
||||
return &obj->as<CallObject>();
|
||||
@ -311,6 +311,59 @@ const Class CallObject::class_ = {
|
||||
JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS)
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const Class ModuleEnvironmentObject::class_ = {
|
||||
"ModuleEnvironmentObject",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ModuleEnvironmentObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS
|
||||
};
|
||||
|
||||
/* static */ ModuleEnvironmentObject*
|
||||
ModuleEnvironmentObject::create(ExclusiveContext* cx, HandleModuleObject module)
|
||||
{
|
||||
RootedScript script(cx, module->script());
|
||||
RootedShape shape(cx, script->bindings.callObjShape());
|
||||
MOZ_ASSERT(shape->getObjectClass() == &class_);
|
||||
|
||||
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
|
||||
MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
|
||||
kind = gc::GetBackgroundAllocKind(kind);
|
||||
|
||||
JSObject* obj = JSObject::create(cx, kind, TenuredHeap, shape, group);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Rooted<ModuleEnvironmentObject*> scope(cx, &obj->as<ModuleEnvironmentObject>());
|
||||
|
||||
// Set uninitialized lexicals even on template objects, as Ion will use
|
||||
// copy over the template object's slot values in the fast path.
|
||||
scope->initAliasedLexicalsToThrowOnTouch(script);
|
||||
|
||||
scope->initFixedSlot(MODULE_SLOT, ObjectValue(*module));
|
||||
if (!JSObject::setSingleton(cx, scope))
|
||||
return nullptr;
|
||||
|
||||
// Initialize this early so that we can manipulate the scope object without
|
||||
// causing assertions.
|
||||
scope->setEnclosingScope(cx->global());
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
ModuleObject&
|
||||
ModuleEnvironmentObject::module() const
|
||||
{
|
||||
return getReservedSlot(MODULE_SLOT).toObject().as<ModuleObject>();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const Class DeclEnvObject::class_ = {
|
||||
js_Object_str,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(DeclEnvObject::RESERVED_SLOTS) |
|
||||
@ -1075,6 +1128,9 @@ ScopeIter::settle()
|
||||
#ifdef DEBUG
|
||||
if (!ssi_.done() && hasAnyScopeObject()) {
|
||||
switch (ssi_.type()) {
|
||||
case StaticScopeIter<CanGC>::Module:
|
||||
MOZ_ASSERT(scope_->as<ModuleEnvironmentObject>().module() == ssi_.module());
|
||||
break;
|
||||
case StaticScopeIter<CanGC>::Function:
|
||||
MOZ_ASSERT(scope_->as<CallObject>().callee().nonLazyScript() == ssi_.funScript());
|
||||
break;
|
||||
@ -1118,6 +1174,8 @@ ScopeIter::type() const
|
||||
MOZ_ASSERT(!done());
|
||||
|
||||
switch (ssi_.type()) {
|
||||
case StaticScopeIter<CanGC>::Module:
|
||||
return Module;
|
||||
case StaticScopeIter<CanGC>::Function:
|
||||
return Call;
|
||||
case StaticScopeIter<CanGC>::Block:
|
||||
@ -1151,6 +1209,8 @@ ScopeIter::maybeStaticScope() const
|
||||
switch (ssi_.type()) {
|
||||
case StaticScopeIter<CanGC>::Function:
|
||||
return &fun();
|
||||
case StaticScopeIter<CanGC>::Module:
|
||||
return &module();
|
||||
case StaticScopeIter<CanGC>::Block:
|
||||
return &staticBlock();
|
||||
case StaticScopeIter<CanGC>::With:
|
||||
@ -2387,6 +2447,10 @@ GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
|
||||
*/
|
||||
DebugScopeObject* debugScope = nullptr;
|
||||
switch (si.type()) {
|
||||
case ScopeIter::Module:
|
||||
MOZ_CRASH(); // TODO: Implement debug scopes for modules.
|
||||
break;
|
||||
|
||||
case ScopeIter::Call: {
|
||||
RootedFunction callee(cx, &si.fun());
|
||||
// Generators should always reify their scopes.
|
||||
@ -2592,6 +2656,9 @@ js::DumpStaticScopeChain(JSObject* staticScope)
|
||||
{
|
||||
for (StaticScopeIter<NoGC> ssi(staticScope); !ssi.done(); ssi++) {
|
||||
switch (ssi.type()) {
|
||||
case StaticScopeIter<NoGC>::Module:
|
||||
fprintf(stdout, "module [%p]", &ssi.module());
|
||||
break;
|
||||
case StaticScopeIter<NoGC>::Function:
|
||||
if (ssi.fun().isBeingParsed())
|
||||
fprintf(stdout, "funbox [%p fun=%p]", ssi.maybeFunctionBox(), &ssi.fun());
|
||||
|
@ -130,7 +130,7 @@ class StaticScopeIter
|
||||
bool hasSyntacticDynamicScopeObject() const;
|
||||
Shape* scopeShape() const;
|
||||
|
||||
enum Type { Function, Block, With, NamedLambda, Eval, NonSyntactic };
|
||||
enum Type { Module, Function, Block, With, NamedLambda, Eval, NonSyntactic };
|
||||
Type type() const;
|
||||
|
||||
StaticBlockObject& block() const;
|
||||
@ -140,6 +140,8 @@ class StaticScopeIter
|
||||
JSScript* funScript() const;
|
||||
JSFunction& fun() const;
|
||||
frontend::FunctionBox* maybeFunctionBox() const;
|
||||
JSScript* moduleScript() const;
|
||||
ModuleObject& module() const;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -218,6 +220,8 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
|
||||
* | | DeclEnvObject Holds name of recursive/heavyweight named lambda
|
||||
* | |
|
||||
* | CallObject Scope of entire function or strict eval
|
||||
* | |
|
||||
* | ModuleEnvironmentObject Module top-level scope on run-time scope chain
|
||||
* |
|
||||
* NestedScopeObject Statement scopes; don't cross script boundaries
|
||||
* | | |
|
||||
@ -286,6 +290,7 @@ class ScopeObject : public NativeObject
|
||||
|
||||
class CallObject : public ScopeObject
|
||||
{
|
||||
protected:
|
||||
static const uint32_t CALLEE_SLOT = 1;
|
||||
|
||||
static CallObject*
|
||||
@ -371,6 +376,21 @@ class CallObject : public ScopeObject
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleEnvironmentObject : public CallObject
|
||||
{
|
||||
static const uint32_t MODULE_SLOT = CallObject::CALLEE_SLOT;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
static ModuleEnvironmentObject* create(ExclusiveContext* cx, HandleModuleObject module);
|
||||
ModuleObject& module() const;
|
||||
};
|
||||
|
||||
typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
|
||||
typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject;
|
||||
typedef MutableHandle<ModuleEnvironmentObject*> MutableHandleModuleEnvironmentObject;
|
||||
|
||||
class DeclEnvObject : public ScopeObject
|
||||
{
|
||||
// Pre-allocated slot for the named lambda.
|
||||
@ -830,7 +850,7 @@ class ScopeIter
|
||||
inline JSObject& enclosingScope() const;
|
||||
|
||||
// If !done():
|
||||
enum Type { Call, Block, With, Eval, NonSyntactic };
|
||||
enum Type { Module, Call, Block, With, Eval, NonSyntactic };
|
||||
Type type() const;
|
||||
|
||||
inline bool hasNonSyntacticScopeObject() const;
|
||||
@ -845,6 +865,7 @@ class ScopeIter
|
||||
StaticEvalObject& staticEval() const { return ssi_.eval(); }
|
||||
StaticNonSyntacticScopeObjects& staticNonSyntactic() const { return ssi_.nonSyntactic(); }
|
||||
JSFunction& fun() const { return ssi_.fun(); }
|
||||
ModuleObject& module() const { return ssi_.module(); }
|
||||
|
||||
bool withinInitialFrame() const { return !!frame_; }
|
||||
AbstractFramePtr initialFrame() const { MOZ_ASSERT(withinInitialFrame()); return frame_; }
|
||||
@ -1076,6 +1097,14 @@ JSObject::is<js::NestedScopeObject>() const
|
||||
is<js::DynamicWithObject>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool
|
||||
JSObject::is<js::CallObject>() const
|
||||
{
|
||||
return getClass() == &js::CallObject::class_ ||
|
||||
is<js::ModuleEnvironmentObject>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool
|
||||
JSObject::is<js::ScopeObject>() const
|
||||
@ -1174,15 +1203,16 @@ ScopeIter::canHaveSyntacticScopeObject() const
|
||||
return false;
|
||||
|
||||
switch (type()) {
|
||||
case Module:
|
||||
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;
|
||||
}
|
||||
|
@ -149,6 +149,10 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject*
|
||||
}
|
||||
} else if (i.hasSyntacticDynamicScopeObject()) {
|
||||
switch (i.type()) {
|
||||
case StaticScopeIter<NoGC>::Module:
|
||||
MOZ_ASSERT(scope->as<ModuleEnvironmentObject>().module().script() == i.moduleScript());
|
||||
scope = &scope->as<ModuleEnvironmentObject>().enclosingScope();
|
||||
break;
|
||||
case StaticScopeIter<NoGC>::Function:
|
||||
MOZ_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
|
||||
scope = &scope->as<CallObject>().enclosingScope();
|
||||
|
Loading…
Reference in New Issue
Block a user