Bug 1185106 - Part 1: Add AsyncFunction flag in FunctionBox, JSScript, and LazyScript. r=efaust,till
MozReview-Commit-ID: 6nOsJO3doV9
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -7063,17 +7063,17 @@ ParseFunction(ModuleValidator& m, ParseN
RootedFunction& fun = m.dummyFunction();
fun->setAtom(name);
fun->setArgCount(0);
ParseContext* outerpc = m.parser().pc;
Directives directives(outerpc);
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator,
- /* tryAnnexB = */ false);
+ SyncFunction, /* tryAnnexB = */ false);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);
Directives newDirectives = directives;
ParseContext funpc(&m.parser(), funbox, &newDirectives);
if (!funpc.init())
return false;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -431,30 +431,31 @@ UsedNameTracker::rewind(RewindToken toke
scopeCounter_ = token.scopeId;
for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront())
r.front().value().resetToScope(token.scriptId, token.scopeId);
}
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
JSFunction* fun, Directives directives, bool extraWarnings,
- GeneratorKind generatorKind)
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead),
SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
enclosingScope_(nullptr),
namedLambdaBindings_(nullptr),
functionScopeBindings_(nullptr),
extraVarScopeBindings_(nullptr),
functionNode(nullptr),
bufStart(0),
bufEnd(0),
startLine(1),
startColumn(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
+ asyncKindBits_(AsyncKindAsBits(asyncKind)),
isGenexpLambda(false),
hasDestructuringArgs(false),
hasParameterExprs(false),
hasDirectEvalInParameterExpr(false),
hasDuplicateParameters(false),
useAsm(false),
insideUseAsm(false),
isAnnexB(false),
@@ -729,31 +730,32 @@ Parser<ParseHandler>::newObjectBox(JSObj
traceListHead = objbox;
return objbox;
}
template <typename ParseHandler>
FunctionBox*
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives,
- GeneratorKind generatorKind, bool tryAnnexB)
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+ bool tryAnnexB)
{
MOZ_ASSERT(fun);
MOZ_ASSERT_IF(tryAnnexB, !pc->sc()->strict());
/*
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
* on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
* arenas containing the entries must be alive until we are done with
* scanning, parsing and code generation for the whole script or top-level
* function.
*/
FunctionBox* funbox =
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
- options().extraWarningsOption, generatorKind);
+ options().extraWarningsOption, generatorKind, asyncKind);
if (!funbox) {
ReportOutOfMemory(context);
return nullptr;
}
traceListHead = funbox;
if (fn)
handler.setFunctionBox(fn, funbox);
@@ -2190,16 +2192,17 @@ Parser<SyntaxParseHandler>::finishFuncti
if (!lazy)
return false;
// Flags that need to be copied into the JSScript when we do the full
// parse.
if (pc->sc()->strict())
lazy->setStrict();
lazy->setGeneratorKind(funbox->generatorKind());
+ lazy->setAsyncKind(funbox->asyncKind());
if (funbox->isLikelyConstructorWrapper())
lazy->setLikelyConstructorWrapper();
if (funbox->isDerivedClassConstructor())
lazy->setIsDerivedClassConstructor();
if (funbox->needsHomeObject())
lazy->setNeedsHomeObject();
if (funbox->declaredArguments)
lazy->setShouldDeclareArguments();
@@ -2230,17 +2233,17 @@ Parser<FullParseHandler>::standaloneFunc
return null();
ParseNode* argsbody = handler.newList(PNK_PARAMSBODY);
if (!argsbody)
return null();
fn->pn_body = argsbody;
FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
- /* tryAnnexB = */ false);
+ SyncFunction, /* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initStandaloneFunction(enclosingScope);
ParseContext funpc(this, funbox, newDirectives);
if (!funpc.init())
return null();
funpc.setIsStandaloneFunctionBody();
@@ -2916,17 +2919,17 @@ Parser<FullParseHandler>::skipLazyInnerF
// When a lazily-parsed function is called, we only fully parse (and emit)
// that function, not any of its nested children. The initial syntax-only
// parse recorded the free variables of nested functions and their extents,
// so we can skip over them after accounting for their free variables.
RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator());
FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false),
- fun->generatorKind(), tryAnnexB);
+ fun->generatorKind(), fun->asyncKind(), tryAnnexB);
if (!funbox)
return false;
LazyScript* lazy = fun->lazyScript();
if (lazy->needsHomeObject())
funbox->setNeedsHomeObject();
PropagateTransitiveParseFlags(lazy, pc->sc());
@@ -3138,17 +3141,17 @@ Parser<FullParseHandler>::trySyntaxParse
tokenStream.tell(&position);
if (!parser->tokenStream.seek(position, tokenStream))
return false;
// Make a FunctionBox before we enter the syntax parser, because |pn|
// still expects a FunctionBox to be attached to it during BCE, and
// the syntax parser cannot attach one to it.
FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
- tryAnnexB);
+ SyncFunction, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(pc, kind);
if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling,
yieldHandling, kind, inheritedDirectives, newDirectives))
{
if (parser->hadAbortedSyntaxParse()) {
@@ -3226,17 +3229,18 @@ Parser<ParseHandler>::innerFunction(Node
bool tryAnnexB, Directives inheritedDirectives,
Directives* newDirectives)
{
// Note that it is possible for outerpc != this->pc, as we may be
// attempting to syntax parse an inner function from an outer full
// parser. In that case, outerpc is a ParseContext from the full parser
// instead of the current top of the stack of the syntax parser.
- FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind, tryAnnexB);
+ FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
+ SyncFunction, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, kind);
return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives,
newDirectives);
}
@@ -3266,17 +3270,17 @@ Parser<FullParseHandler>::standaloneLazy
{
MOZ_ASSERT(checkOptionsCalled);
Node pn = handler.newFunctionDefinition();
if (!pn)
return null();
Directives directives(strict);
- FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind,
+ FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, SyncFunction,
/* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initFromLazyFunction();
Directives newDirectives = directives;
ParseContext funpc(this, funbox, &newDirectives);
if (!funpc.init())
@@ -7812,17 +7816,17 @@ Parser<ParseHandler>::generatorComprehen
RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression,
StarGenerator, proto));
if (!fun)
return null();
// Create box for fun->object early to root it.
Directives directives(/* strict = */ outerpc->sc()->strict());
- FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator,
+ FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction,
/* tryAnnexB = */ false);
if (!genFunbox)
return null();
genFunbox->isGenexpLambda = true;
genFunbox->initWithEnclosingParseContext(outerpc, Expression);
ParseContext genpc(this, genFunbox, /* newDirectives = */ nullptr);
if (!genpc.init())
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -493,16 +493,20 @@ class ParseContext : public Nestable<Par
bool isLegacyGenerator() const {
return generatorKind() == LegacyGenerator;
}
bool isStarGenerator() const {
return generatorKind() == StarGenerator;
}
+ bool isAsync() const {
+ return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
+ }
+
bool isArrowFunction() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isArrow();
}
bool isMethod() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isMethod();
}
@@ -935,17 +939,18 @@ class Parser final : private JS::AutoGCR
Node parse();
/*
* Allocate a new parsed object or function container from
* cx->tempLifoAlloc.
*/
ObjectBox* newObjectBox(JSObject* obj);
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives,
- GeneratorKind generatorKind, bool tryAnnexB);
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+ bool tryAnnexB);
/*
* Create a new function object given a name (which is optional if this is
* a function expression).
*/
JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind,
HandleObject proto);
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -448,16 +448,18 @@ class FunctionBox : public ObjectBox, pu
ParseNode* functionNode; /* back pointer used by asm.js for error messages */
uint32_t bufStart;
uint32_t bufEnd;
uint32_t startLine;
uint32_t startColumn;
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
+ uint8_t asyncKindBits_; /* The FunctionAsyncKing of this function. */
+
bool isGenexpLambda:1; /* lambda from generator expression */
bool hasDestructuringArgs:1; /* parameter list contains destructuring expression */
bool hasParameterExprs:1; /* parameter list contains expressions */
bool hasDirectEvalInParameterExpr:1; /* parameter list contains direct eval */
bool hasDuplicateParameters:1; /* parameter list contains duplicate names */
bool useAsm:1; /* see useAsmOrInsideUseAsm */
bool insideUseAsm:1; /* see useAsmOrInsideUseAsm */
bool isAnnexB:1; /* need to emit a synthesized Annex B assignment */
@@ -468,17 +470,18 @@ class FunctionBox : public ObjectBox, pu
bool usesArguments:1; /* contains a free use of 'arguments' */
bool usesApply:1; /* contains an f.apply() call */
bool usesThis:1; /* contains 'this' */
bool usesReturn:1; /* contains a 'return' statement */
FunctionContextFlags funCxFlags;
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
- Directives directives, bool extraWarnings, GeneratorKind generatorKind);
+ Directives directives, bool extraWarnings, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind);
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
return MutableHandle<LexicalScope::Data*>::fromMarkedLocation(&namedLambdaBindings_);
}
MutableHandle<FunctionScope::Data*> functionScopeBindings() {
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
@@ -527,16 +530,18 @@ class FunctionBox : public ObjectBox, pu
bool isLikelyConstructorWrapper() const {
return usesArguments && usesApply && usesThis && !usesReturn;
}
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
bool isGenerator() const { return generatorKind() != NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
+ FunctionAsyncKind asyncKind() const { return AsyncKindFromBits(asyncKindBits_); }
+ bool isAsync() const { return asyncKind() == AsyncFunction; }
bool isArrow() const { return function()->isArrow(); }
void setGeneratorKind(GeneratorKind kind) {
// A generator kind can be set at initialization, or when "yield" is
// first seen. In both cases the transition can only happen from
// NotGenerator.
MOZ_ASSERT(!isGenerator());
generatorKindBits_ = GeneratorKindAsBits(kind);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -296,16 +296,23 @@ class JSFunction : public js::NativeObje
void setResolvedLength() {
flags_ |= RESOLVED_LENGTH;
}
void setResolvedName() {
flags_ |= RESOLVED_NAME;
}
+ void setAsyncKind(js::FunctionAsyncKind asyncKind) {
+ if (isInterpretedLazy())
+ lazyScript()->setAsyncKind(asyncKind);
+ else
+ nonLazyScript()->setAsyncKind(asyncKind);
+ }
+
bool getUnresolvedLength(JSContext* cx, js::MutableHandleValue v);
JSAtom* getUnresolvedName(JSContext* cx);
JSAtom* name() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
// Because display names (see Debugger.Object.displayName) are already stored
// on functions and will always contain a valid es6 function name, as described
@@ -464,16 +471,28 @@ class JSFunction : public js::NativeObje
}
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
+ js::FunctionAsyncKind asyncKind() const {
+ return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind();
+ }
+
+ bool isAsync() const {
+ if (isInterpretedLazy())
+ return lazyScript()->asyncKind() == js::AsyncFunction;
+ if (hasScript())
+ return nonLazyScript()->asyncKind() == js::AsyncFunction;
+ return false;
+ }
+
void setScript(JSScript* script_) {
mutableScript() = script_;
}
void initScript(JSScript* script_) {
mutableScript().init(script_);
}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2610,16 +2610,17 @@ JSScript::initFromFunctionBox(ExclusiveC
script->functionHasThisBinding_ = funbox->hasThisBinding();
script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
script->funLength_ = funbox->length;
script->isGeneratorExp_ = funbox->isGenexpLambda;
script->setGeneratorKind(funbox->generatorKind());
+ script->setAsyncKind(funbox->asyncKind());
PositionalFormalParameterIter fi(script);
while (fi && !fi.closedOver())
fi++;
script->funHasAnyAliasedFormal_ = !!fi;
script->setHasInnerFunctions(funbox->hasInnerFunctions());
}
@@ -3267,16 +3268,17 @@ js::detail::CopyScript(JSContext* cx, Ha
dst->hasSingletons_ = src->hasSingletons();
dst->treatAsRunOnce_ = src->treatAsRunOnce();
dst->hasInnerFunctions_ = src->hasInnerFunctions();
dst->isGeneratorExp_ = src->isGeneratorExp();
dst->setGeneratorKind(src->generatorKind());
dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
dst->needsHomeObject_ = src->needsHomeObject();
dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
+ dst->isAsync_ = src->asyncKind() == AsyncFunction;
if (nconsts != 0) {
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
dst->consts()->vector = vector;
for (unsigned i = 0; i < nconsts; ++i)
MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
}
if (nobjects != 0) {
@@ -3999,16 +4001,17 @@ LazyScript::Create(ExclusiveContext* cx,
union {
PackedView p;
uint64_t packedFields;
};
p.version = version;
p.shouldDeclareArguments = false;
p.hasThisBinding = false;
+ p.isAsync = false;
p.numClosedOverBindings = closedOverBindings.length();
p.numInnerFunctions = innerFunctions.length();
p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
p.strict = false;
p.bindingsAccessedDynamically = false;
p.hasDebuggerStatement = false;
p.hasDirectEval = false;
p.isLikelyConstructorWrapper = false;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -635,28 +635,40 @@ class ScriptSourceObject : public Native
static const uint32_t SOURCE_SLOT = 0;
static const uint32_t ELEMENT_SLOT = 1;
static const uint32_t ELEMENT_PROPERTY_SLOT = 2;
static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3;
static const uint32_t RESERVED_SLOTS = 4;
};
enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
+enum FunctionAsyncKind { SyncFunction, AsyncFunction };
static inline unsigned
GeneratorKindAsBits(GeneratorKind generatorKind) {
return static_cast<unsigned>(generatorKind);
}
static inline GeneratorKind
GeneratorKindFromBits(unsigned val) {
MOZ_ASSERT(val <= StarGenerator);
return static_cast<GeneratorKind>(val);
}
+static inline unsigned
+AsyncKindAsBits(FunctionAsyncKind asyncKind) {
+ return static_cast<unsigned>(asyncKind);
+}
+
+static inline FunctionAsyncKind
+AsyncKindFromBits(unsigned val) {
+ MOZ_ASSERT(val <= AsyncFunction);
+ return static_cast<FunctionAsyncKind>(val);
+}
+
/*
* NB: after a successful XDR_DECODE, XDRScript callers must do any required
* subsequent set-up of owning function or script object and then call
* CallNewScriptHook.
*/
template<XDRMode mode>
bool
XDRScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript enclosingScript,
@@ -983,16 +995,18 @@ class JSScript : public js::gc::TenuredC
// script.
bool hasInnerFunctions_:1;
bool needsHomeObject_:1;
bool isDerivedClassConstructor_:1;
bool isDefaultClassConstructor_:1;
+ bool isAsync_:1;
+
// Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
#if JS_BITS_PER_WORD == 32
// Currently no padding is needed.
#endif
//
@@ -1271,16 +1285,24 @@ class JSScript : public js::gc::TenuredC
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
void setGeneratorKind(js::GeneratorKind kind) {
// A script only gets its generator kind set as part of initialization,
// so it can only transition from not being a generator.
MOZ_ASSERT(!isGenerator());
generatorKindBits_ = GeneratorKindAsBits(kind);
}
+ js::FunctionAsyncKind asyncKind() const {
+ return isAsync_ ? js::AsyncFunction : js::SyncFunction;
+ }
+
+ void setAsyncKind(js::FunctionAsyncKind kind) {
+ isAsync_ = kind == js::AsyncFunction;
+ }
+
void setNeedsHomeObject() {
needsHomeObject_ = true;
}
bool needsHomeObject() const {
return needsHomeObject_;
}
bool isDerivedClassConstructor() const {
@@ -1882,17 +1904,18 @@ class LazyScript : public gc::TenuredCel
private:
struct PackedView {
// Assorted bits that should really be in ScriptSourceObject.
uint32_t version : 8;
uint32_t shouldDeclareArguments : 1;
uint32_t hasThisBinding : 1;
- uint32_t numClosedOverBindings : 22;
+ uint32_t isAsync : 1;
+ uint32_t numClosedOverBindings : 21;
uint32_t numInnerFunctions : 20;
uint32_t generatorKindBits : 2;
// N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
// If you add another boolean here, make sure to initialze it in
// LazyScript::CreateRaw().
uint32_t strict : 1;
@@ -2019,16 +2042,24 @@ class LazyScript : public gc::TenuredCel
// A script only gets its generator kind set as part of initialization,
// so it can only transition from NotGenerator.
MOZ_ASSERT(!isGenerator());
// Legacy generators cannot currently be lazy.
MOZ_ASSERT(kind != LegacyGenerator);
p_.generatorKindBits = GeneratorKindAsBits(kind);
}
+ FunctionAsyncKind asyncKind() const {
+ return p_.isAsync ? AsyncFunction : SyncFunction;
+ }
+
+ void setAsyncKind(FunctionAsyncKind kind) {
+ p_.isAsync = kind == AsyncFunction;
+ }
+
bool strict() const {
return p_.strict;
}
void setStrict() {
p_.strict = true;
}
bool bindingsAccessedDynamically() const {