summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorMartok <martok@martoks-place.de>2023-04-11 03:02:33 +0200
committerMartok <martok@martoks-place.de>2023-05-01 17:16:21 +0200
commit7b74607f1fa0e93d00dc9261b6cd47d10324c92e (patch)
treef681a259d093dbcd65e6ccb67455ede16d1e02f3 /js
parent0f3f695117064813969f6fc29f92a69ff5cafb85 (diff)
downloaduxp-7b74607f1fa0e93d00dc9261b6cd47d10324c92e.tar.gz
Issue #2142 - Track isFieldInitializer on JSScript instead of Scope
Introduce a FunctionSyntaxKind for FieldInitializer since special rules (around `arguments`) apply. At the same time we can move the flag from the scope to the JSScript. This is similar to how derived constructors are handled and makes the initWithEnclosingScope code closer to initWithEnclosingContext. This version is a bit more complex than Mozilla's due to different storage of bit flags on JSScript. Based-on: m-c 1636800
Diffstat (limited to 'js')
-rw-r--r--js/src/frontend/ParseNode.h4
-rw-r--r--js/src/frontend/Parser.cpp46
-rw-r--r--js/src/frontend/Parser.h5
-rw-r--r--js/src/frontend/SharedContext.h8
-rw-r--r--js/src/jsfun.cpp13
-rw-r--r--js/src/jsfun.h1
-rw-r--r--js/src/jsscript.cpp7
-rw-r--r--js/src/jsscript.h19
-rw-r--r--js/src/vm/Scope.cpp13
-rw-r--r--js/src/vm/Scope.h9
10 files changed, 77 insertions, 48 deletions
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index 57a65a9e9b..4c9f1cc914 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -625,7 +625,8 @@ enum class FunctionSyntaxKind
Expression, // A non-arrow function expression.
Statement, // A named function appearing as a Statement.
Arrow,
- Method, // Method of a class or object. Field initializers also desugar to methods.
+ Method, // Method of a class or object.
+ FieldInitializer, // Field initializers desugar to methods.
ClassConstructor,
DerivedClassConstructor,
Getter,
@@ -659,6 +660,7 @@ static inline bool
IsMethodDefinitionKind(FunctionSyntaxKind kind)
{
return kind == FunctionSyntaxKind::Method ||
+ kind == FunctionSyntaxKind::FieldInitializer ||
IsConstructorKind(kind) ||
IsGetterKind(kind) || IsSetterKind(kind);
}
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index c319924fa7..f69e3cf08a 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -221,7 +221,7 @@ SharedContext::computeAllowSyntax(Scope* scope)
allowNewTarget_ = true;
allowSuperProperty_ = fun->allowSuperProperty();
allowSuperCall_ = fun->isDerivedClassConstructor();
- if (funScope->isFieldInitializer()) {
+ if (fun->isFieldInitializer()) {
allowSuperCall_ = false;
allowArguments_ = false;
}
@@ -526,6 +526,11 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
allowNewTarget_ = true;
allowSuperProperty_ = fun->allowSuperProperty();
+ if (kind == FunctionSyntaxKind::FieldInitializer) {
+ setFieldInitializer();
+ allowArguments_ = false;
+ }
+
if (IsConstructorKind(kind)) {
auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
MOZ_ASSERT(stmt);
@@ -556,13 +561,6 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
}
void
-FunctionBox::initFieldInitializer(ParseContext* enclosing)
-{
- this->initWithEnclosingParseContext(enclosing, FunctionSyntaxKind::Method);
- allowArguments_ = false;
-}
-
-void
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
{
if (!function()->isArrow()) {
@@ -1883,8 +1881,7 @@ Parser<FullParseHandler>::newEvalScopeData(ParseContext::Scope& scope)
template <>
Maybe<FunctionScope::Data*>
-Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs,
- bool isFieldInitializer)
+Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs)
{
Vector<BindingName> positionalFormals(context);
Vector<BindingName> formals(context);
@@ -1958,8 +1955,6 @@ Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool
if (!bindings)
return Nothing();
- bindings->isFieldInitializer = isFieldInitializer;
-
// The ordering here is important. See comments in FunctionScope.
BindingName* start = bindings->trailingNames.start();
BindingName* cursor = start;
@@ -2408,8 +2403,7 @@ Parser<ParseHandler>::finishFunctionScopes(bool isStandaloneFunction)
template <>
bool
-Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */,
- bool isFieldInitializer /* = false */)
+Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */)
{
if (!finishFunctionScopes(isStandaloneFunction))
return false;
@@ -2426,8 +2420,7 @@ Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */
{
Maybe<FunctionScope::Data*> bindings = newFunctionScopeData(pc->functionScope(),
- hasParameterExprs,
- isFieldInitializer);
+ hasParameterExprs);
if (!bindings)
return false;
funbox->functionScopeBindings().set(*bindings);
@@ -2445,8 +2438,7 @@ Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */
template <>
bool
-Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */,
- bool isFieldInitializer /* = false */)
+Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */)
{
// The LazyScript for a lazily parsed function needs to know its set of
// free variables and inner functions so that when it is fully parsed, we
@@ -2816,6 +2808,7 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case FunctionSyntaxKind::Method:
+ case FunctionSyntaxKind::FieldInitializer:
MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator);
flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
? JSFunction::INTERPRETED_METHOD
@@ -3056,6 +3049,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
bool duplicatedParam = false;
bool disallowDuplicateParams = kind == FunctionSyntaxKind::Arrow ||
kind == FunctionSyntaxKind::Method ||
+ kind == FunctionSyntaxKind::FieldInitializer ||
kind == FunctionSyntaxKind::ClassConstructor;
AtomVector& positionalFormals = pc->positionalFormalParameterNames();
@@ -3614,7 +3608,11 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
syntaxKind = FunctionSyntaxKind::ClassConstructor;
}
} else if (fun->isMethod()) {
- syntaxKind = FunctionSyntaxKind::Method;
+ if (fun->isFieldInitializer()) {
+ syntaxKind = FunctionSyntaxKind::FieldInitializer;
+ } else {
+ syntaxKind = FunctionSyntaxKind::Method;
+ }
} else if (fun->isGetter()) {
syntaxKind = FunctionSyntaxKind::Getter;
} else if (fun->isSetter()) {
@@ -7991,15 +7989,16 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& clas
}
// Create the anonymous function object.
+ FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::FieldInitializer;
RootedFunction fun(context,
- newFunction(nullptr, FunctionSyntaxKind::Method,
+ newFunction(nullptr, syntaxKind,
GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction));
if (!fun)
return null();
// Create the top-level field initializer node.
- FunctionNodeType funNode = handler.newFunction(FunctionSyntaxKind::Method, firstTokenPos);
+ FunctionNodeType funNode = handler.newFunction(syntaxKind, firstTokenPos);
if (!funNode)
return null();
@@ -8010,7 +8009,8 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& clas
FunctionAsyncKind::SyncFunction, false);
if (!funbox)
return null();
- funbox->initFieldInitializer(pc);
+ funbox->initWithEnclosingParseContext(pc, syntaxKind);
+ MOZ_ASSERT(funbox->isFieldInitializer());
funbox->setStart(tokenStream, firstTokenPos);
// Push a SourceParseContext on to the stack.
@@ -8139,7 +8139,7 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& clas
funbox->setNeedsHomeObject();
}
- if (!finishFunction(false, true))
+ if (!finishFunction())
return null();
if (!leaveInnerFunction(outerpc))
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index ec6595b908..d0318e405d 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1582,7 +1582,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
bool finishFunctionScopes(bool isStandaloneFunction);
- bool finishFunction(bool isStandaloneFunction = false, bool isFieldInitializer = false);
+ bool finishFunction(bool isStandaloneFunction = false);
bool leaveInnerFunction(ParseContext* outerpc);
bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier);
@@ -1630,8 +1630,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
mozilla::Maybe<ModuleScope::Data*> newModuleScopeData(ParseContext::Scope& scope);
mozilla::Maybe<EvalScope::Data*> newEvalScopeData(ParseContext::Scope& scope);
mozilla::Maybe<FunctionScope::Data*> newFunctionScopeData(ParseContext::Scope& scope,
- bool hasParameterExprs,
- bool isFieldInitializer);
+ bool hasParameterExprs);
mozilla::Maybe<VarScope::Data*> newVarScopeData(ParseContext::Scope& scope);
mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope);
LexicalScopeNodeType finishLexicalScope(ParseContext::Scope& scope, Node body);
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index 8aa068c1fc..4ac2da6fcd 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -155,6 +155,7 @@ class FunctionContextFlags
bool needsHomeObject:1;
bool isDerivedClassConstructor:1;
+ bool isFieldInitializer:1;
// Whether this function has a .this binding. If true, we need to emit
// JSOP_FUNCTIONTHIS in the prologue to initialize it.
@@ -170,6 +171,7 @@ class FunctionContextFlags
definitelyNeedsArgsObj(false),
needsHomeObject(false),
isDerivedClassConstructor(false),
+ isFieldInitializer(false),
hasThisBinding(false),
hasInnerFunctions(false)
{ }
@@ -454,8 +456,7 @@ class FunctionBox : public ObjectBox, public SharedContext
void initFromLazyFunction();
void initStandaloneFunction(Scope* enclosingScope);
- void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
- void initFieldInitializer(ParseContext* enclosing);
+ void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
ObjectBox* toObjectBox() override { return this; }
JSFunction* function() const { return &object->as<JSFunction>(); }
@@ -537,6 +538,7 @@ class FunctionBox : public ObjectBox, public SharedContext
bool needsHomeObject() const { return funCxFlags.needsHomeObject; }
bool isDerivedClassConstructor() const { return funCxFlags.isDerivedClassConstructor; }
bool hasInnerFunctions() const { return funCxFlags.hasInnerFunctions; }
+ bool isFieldInitializer() const { return funCxFlags.isFieldInitializer; }
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
void setHasThisBinding() { funCxFlags.hasThisBinding = true; }
@@ -548,6 +550,8 @@ class FunctionBox : public ObjectBox, public SharedContext
void setDerivedClassConstructor() { MOZ_ASSERT(function()->isClassConstructor());
funCxFlags.isDerivedClassConstructor = true; }
void setHasInnerFunctions() { funCxFlags.hasInnerFunctions = true; }
+ void setFieldInitializer() { MOZ_ASSERT(function()->isMethod());
+ funCxFlags.isFieldInitializer = true; }
bool hasSimpleParameterList() const {
return !hasRest() && !hasParameterExprs && !hasDestructuringArgs;
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 2f3bd8ca55..67df78c2f1 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1286,6 +1286,19 @@ JSFunction::isDerivedClassConstructor()
return derived;
}
+bool
+JSFunction::isFieldInitializer() const
+{
+ bool init;
+ if (isInterpretedLazy()) {
+ init = lazyScript()->isFieldInitializer();
+ } else {
+ init = nonLazyScript()->isFieldInitializer();
+ }
+ MOZ_ASSERT_IF(init, isMethod());
+ return init;
+}
+
/* static */ bool
JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length)
{
diff --git a/js/src/jsfun.h b/js/src/jsfun.h
index ad6eb07a2c..1833aaeea5 100644
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -595,6 +595,7 @@ class JSFunction : public js::NativeObject
}
bool isDerivedClassConstructor();
+ bool isFieldInitializer() const;
static unsigned offsetOfNativeOrScript() {
static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index 1a148578a1..a3f5f07068 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -350,6 +350,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
NeedsHomeObject,
IsDerivedClassConstructor,
IsDefaultClassConstructor,
+ IsFieldInitializer,
};
uint32_t length, lineno, column, nfixed, nslots;
@@ -474,6 +475,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
scriptBits |= (1 << IsDerivedClassConstructor);
if (script->isDefaultClassConstructor())
scriptBits |= (1 << IsDefaultClassConstructor);
+ if (script->isFieldInitializer())
+ scriptBits |= (1 << IsFieldInitializer);
}
if (!xdr->codeUint32(&prologueLength))
@@ -620,6 +623,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
script->isDerivedClassConstructor_ = true;
if (scriptBits & (1 << IsDefaultClassConstructor))
script->isDefaultClassConstructor_ = true;
+ if (scriptBits & (1 << IsFieldInitializer))
+ script->isFieldInitializer_ = true;
if (scriptBits & (1 << IsLegacyGenerator)) {
MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
@@ -2807,6 +2812,7 @@ JSScript::initFromFunctionBox(ExclusiveContext* cx, HandleScript script,
script->funHasExtensibleScope_ = funbox->hasExtensibleScope();
script->needsHomeObject_ = funbox->needsHomeObject();
script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
+ script->isFieldInitializer_ = funbox->isFieldInitializer();
if (funbox->argumentsHasLocalBinding()) {
script->setArgumentsHasVarBinding();
@@ -3485,6 +3491,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->isGeneratorExp_ = src->isGeneratorExp();
dst->setGeneratorKind(src->generatorKind());
dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
+ dst->isFieldInitializer_ = src->isFieldInitializer();
dst->needsHomeObject_ = src->needsHomeObject();
dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
dst->isAsync_ = src->asyncKind() == AsyncFunction;
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
index 5534df5806..5d6c09dba6 100644
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1120,6 +1120,8 @@ class JSScript : public js::gc::TenuredCell
bool isDerivedClassConstructor_:1;
bool isDefaultClassConstructor_:1;
+ bool isFieldInitializer_:1;
+
bool isAsync_:1;
bool hasRest_:1;
@@ -1129,7 +1131,10 @@ class JSScript : public js::gc::TenuredCell
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
#if JS_BITS_PER_WORD == 32
- // Currently no padding is needed.
+# ifndef DEBUG
+ // DEBUG is currently 4 bytes larger and doesn't need padding to gc::CellSize
+ uint32_t padding_;
+# endif
#endif
//
@@ -1458,6 +1463,10 @@ class JSScript : public js::gc::TenuredCell
return isDerivedClassConstructor_;
}
+ bool isFieldInitializer() const {
+ return isFieldInitializer_;
+ }
+
/*
* As an optimization, even when argsHasLocalBinding, the function prologue
* may not need to create an arguments object. This is determined by
@@ -2096,6 +2105,7 @@ class LazyScript : public gc::TenuredCell
uint32_t hasBeenCloned : 1;
uint32_t treatAsRunOnce : 1;
uint32_t isDerivedClassConstructor : 1;
+ uint32_t isFieldInitializer : 1;
uint32_t needsHomeObject : 1;
uint32_t hasRest : 1;
uint32_t parseGoal : 1;
@@ -2312,6 +2322,13 @@ class LazyScript : public gc::TenuredCell
p_.isDerivedClassConstructor = true;
}
+ bool isFieldInitializer() const {
+ return p_.isFieldInitializer;
+ }
+ void setIsFieldInitializer() {
+ p_.isFieldInitializer = true;
+ }
+
bool needsHomeObject() const {
return p_.needsHomeObject;
}
diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
index 870add219f..60d845836e 100644
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -610,14 +610,12 @@ FunctionScope::create(ExclusiveContext* cx, Handle<Data*> dataArg,
if (!data)
return nullptr;
- return createWithData(cx, &data, hasParameterExprs, dataArg ? dataArg->isFieldInitializer : false,
- needsEnvironment, fun, enclosing);
+ return createWithData(cx, &data, hasParameterExprs, needsEnvironment, fun, enclosing);
}
/* static */ FunctionScope*
FunctionScope::createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data,
- bool hasParameterExprs, bool isFieldInitializer,
- bool needsEnvironment,
+ bool hasParameterExprs, bool needsEnvironment,
HandleFunction fun, HandleScope enclosing)
{
MOZ_ASSERT(data);
@@ -638,7 +636,6 @@ FunctionScope::createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data
return nullptr;
}
- data->isFieldInitializer = isFieldInitializer;
data->hasParameterExprs = hasParameterExprs;
data->canonicalFunction.init(fun);
@@ -740,20 +737,16 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin
uint8_t needsEnvironment;
uint8_t hasParameterExprs;
- uint8_t isFieldInitializer;
uint32_t nextFrameSlot;
if (mode == XDR_ENCODE) {
needsEnvironment = scope->hasEnvironment();
hasParameterExprs = data->hasParameterExprs;
- isFieldInitializer = data->isFieldInitializer;
nextFrameSlot = data->nextFrameSlot;
}
if (!xdr->codeUint8(&needsEnvironment))
return false;
if (!xdr->codeUint8(&hasParameterExprs))
return false;
- if (!xdr->codeUint8(&isFieldInitializer))
- return false;
if (!xdr->codeUint16(&data->nonPositionalFormalStart))
return false;
if (!xdr->codeUint16(&data->varStart))
@@ -768,7 +761,7 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin
MOZ_ASSERT(!data->nextFrameSlot);
}
- scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, !!isFieldInitializer,
+ scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs,
needsEnvironment, fun, enclosing));
if (!scope)
return false;
diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h
index a1e52e3800..b4e83dfc9c 100644
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -500,9 +500,6 @@ class FunctionScope : public Scope
// bindings.
bool hasParameterExprs = false;
- // Anonymous functions used in field initializers are limited.
- bool isFieldInitializer = false;
-
// Bindings are sorted by kind in both frames and environments.
//
// Positional formal parameter names are those that are not
@@ -551,7 +548,7 @@ class FunctionScope : public Scope
private:
static FunctionScope* createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data,
- bool hasParameterExprs, bool isFieldInitializer,
+ bool hasParameterExprs,
bool needsEnvironment, HandleFunction fun,
HandleScope enclosing);
@@ -578,10 +575,6 @@ class FunctionScope : public Scope
return data().hasParameterExprs;
}
- bool isFieldInitializer() const {
- return data().isFieldInitializer;
- }
-
uint32_t numPositionalFormalParameters() const {
return data().nonPositionalFormalStart;
}