summaryrefslogtreecommitdiffstats
path: root/js/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend')
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp255
-rw-r--r--js/src/frontend/CompileScript.cpp81
-rw-r--r--js/src/frontend/FoldConstants.cpp1
-rw-r--r--js/src/frontend/FullParseHandler.h18
-rw-r--r--js/src/frontend/NameFunctions.cpp1
-rw-r--r--js/src/frontend/ParseContext.cpp69
-rw-r--r--js/src/frontend/ParseContext.h11
-rw-r--r--js/src/frontend/ParseNode.h28
-rw-r--r--js/src/frontend/Parser.cpp36
-rw-r--r--js/src/frontend/SharedContext.cpp3
-rw-r--r--js/src/frontend/SharedContext.h9
-rw-r--r--js/src/frontend/Stencil.cpp12
-rw-r--r--js/src/frontend/SyntaxParseHandler.h25
-rw-r--r--js/src/frontend/UsedNameTracker.h4
-rwxr-xr-xjs/src/frontend/align_stack_comment.py2
15 files changed, 372 insertions, 183 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index df44743768..2759fa5924 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -925,6 +925,7 @@ restart:
// Watch out for getters!
case ParseNodeKind::OptionalDotExpr:
case ParseNodeKind::DotExpr:
+ case ParseNodeKind::ArgumentsLength:
MOZ_ASSERT(pn->is<BinaryNode>());
*answer = true;
return true;
@@ -2601,6 +2602,7 @@ bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
*emitted = 0;
break;
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &target->as<PropertyAccess>();
bool isSuper = prop->isSuper();
@@ -2760,6 +2762,7 @@ bool BytecodeEmitter::emitSetOrInitializeDestructuring(
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
// The reference is already pushed by emitDestructuringLHSRef.
// [stack] # if Super
@@ -4367,6 +4370,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
: NameOpEmitter::Kind::SimpleAssignment);
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &lhs->as<PropertyAccess>();
bool isSuper = prop->isSuper();
@@ -4466,6 +4470,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
if (isCompound) {
MOZ_ASSERT(rhs);
switch (lhs->getKind()) {
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &lhs->as<PropertyAccess>();
if (!poe->emitGet(prop->key().atom())) {
@@ -4512,6 +4517,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
}
offset += noe->emittedBindOp();
break;
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr:
if (!poe->prepareForRhs()) {
// [stack] # if Simple Assignment with Super
@@ -4579,6 +4585,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
}
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &lhs->as<PropertyAccess>();
if (!poe->emitAssignment(prop->key().atom())) {
@@ -4666,7 +4673,7 @@ bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) {
numPushed = noe->emittedBindOp();
break;
}
-
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &lhs->as<PropertyAccess>();
bool isSuper = prop->isSuper();
@@ -4802,7 +4809,7 @@ bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) {
}
break;
}
-
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &lhs->as<PropertyAccess>();
@@ -7326,6 +7333,7 @@ bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode* deleteNode) {
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr:
case ParseNodeKind::OptionalDotExpr: {
auto* propExpr = &kid->as<PropertyAccessBase>();
@@ -7978,6 +7986,7 @@ bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode* callee,
}
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
PropertyAccess* prop = &callee->as<PropertyAccess>();
@@ -8076,6 +8085,7 @@ bool BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, CallNode* maybeCall,
}
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
PropertyAccess* prop = &callee->as<PropertyAccess>();
@@ -8197,6 +8207,7 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* callNode,
coordNode = argsList;
switch (calleeNode->getKind()) {
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr:
// Use the position of a property access identifier.
//
@@ -8658,6 +8669,7 @@ bool BytecodeEmitter::emitOptionalTree(
}
break;
}
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &pn->as<PropertyAccess>();
bool isSuper = prop->isSuper();
@@ -9015,6 +9027,7 @@ bool BytecodeEmitter::emitSequenceExpr(ListNode* node, ValueUsage valueUsage) {
MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(UnaryNode* incDec,
ValueUsage valueUsage) {
switch (incDec->kid()->getKind()) {
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr:
return emitPropIncDec(incDec, valueUsage);
case ParseNodeKind::ElemExpr:
@@ -9859,6 +9872,12 @@ static bool NeedsPrivateBrand(ParseNode* member) {
!member->as<ClassMethod>().isStatic();
}
+#ifdef ENABLE_DECORATORS
+static bool HasDecorators(ParseNode* member) {
+ return member->is<ClassMethod>() && member->as<ClassMethod>().decorators();
+}
+#endif
+
mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
ListNode* classMembers, FieldPlacement placement) {
bool isStatic = placement == FieldPlacement::Static;
@@ -9866,6 +9885,9 @@ mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
size_t numFields = 0;
size_t numPrivateInitializers = 0;
bool hasPrivateBrand = false;
+#ifdef ENABLE_DECORATORS
+ bool hasDecorators = false;
+#endif
for (ParseNode* member : classMembers->contents()) {
if (NeedsFieldInitializer(member, isStatic)) {
numFields++;
@@ -9875,6 +9897,11 @@ mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
} else if (NeedsPrivateBrand(member)) {
hasPrivateBrand = true;
}
+#ifdef ENABLE_DECORATORS
+ if (!hasDecorators && HasDecorators(member)) {
+ hasDecorators = true;
+ }
+#endif
}
// If there are more initializers than can be represented, return invalid.
@@ -9882,8 +9909,11 @@ mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
MemberInitializers::MaxInitializers) {
return Nothing();
}
- return Some(
- MemberInitializers(hasPrivateBrand, numFields + numPrivateInitializers));
+ return Some(MemberInitializers(hasPrivateBrand,
+#ifdef ENABLE_DECORATORS
+ hasDecorators,
+#endif
+ numFields + numPrivateInitializers));
}
// Purpose of .fieldKeys:
@@ -10691,119 +10721,122 @@ bool BytecodeEmitter::emitInitializeInstanceMembers(
}
}
#ifdef ENABLE_DECORATORS
- // Decorators Proposal
- // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
- // 4. For each element e of elements, do
- // 4.a. If elementRecord.[[Kind]] is field or accessor, then
- // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
- //
+ if (memberInitializers.hasDecorators) {
+ // Decorators Proposal
+ // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
+ // 4. For each element e of elements, do
+ // 4.a. If elementRecord.[[Kind]] is field or accessor, then
+ // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
+ //
- // TODO: (See Bug 1817993) At the moment, we're applying the initialization
- // logic in two steps. The pre-decorator initialization code runs, stores
- // the initial value, and then we retrieve it here and apply the
- // initializers added by decorators. We should unify these two steps.
- if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
- // [stack] ARRAY
- return false;
- }
+ // TODO: (See Bug 1817993) At the moment, we're applying the
+ // initialization logic in two steps. The pre-decorator initialization
+ // code runs, stores the initial value, and then we retrieve it here and
+ // apply the initializers added by decorators. We should unify these two
+ // steps.
+ if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
+ // [stack] ARRAY
+ return false;
+ }
- if (!emit1(JSOp::Dup)) {
- // [stack] ARRAY ARRAY
- return false;
- }
+ if (!emit1(JSOp::Dup)) {
+ // [stack] ARRAY ARRAY
+ return false;
+ }
- if (!emitAtomOp(JSOp::GetProp,
- TaggedParserAtomIndex::WellKnown::length())) {
- // [stack] ARRAY LENGTH
- return false;
- }
+ if (!emitAtomOp(JSOp::GetProp,
+ TaggedParserAtomIndex::WellKnown::length())) {
+ // [stack] ARRAY LENGTH
+ return false;
+ }
- if (!emitNumberOp(static_cast<double>(numInitializers))) {
- // [stack] ARRAY LENGTH INDEX
- return false;
- }
+ if (!emitNumberOp(static_cast<double>(numInitializers))) {
+ // [stack] ARRAY LENGTH INDEX
+ return false;
+ }
- InternalWhileEmitter wh(this);
- // At this point, we have no context to determine offsets in the
- // code for this while statement. Ideally, it would correspond to
- // the field we're initializing.
- if (!wh.emitCond()) {
- // [stack] ARRAY LENGTH INDEX
- return false;
- }
+ InternalWhileEmitter wh(this);
+ // At this point, we have no context to determine offsets in the
+ // code for this while statement. Ideally, it would correspond to
+ // the field we're initializing.
+ if (!wh.emitCond()) {
+ // [stack] ARRAY LENGTH INDEX
+ return false;
+ }
- if (!emit1(JSOp::Dup)) {
- // [stack] ARRAY LENGTH INDEX INDEX
- return false;
- }
+ if (!emit1(JSOp::Dup)) {
+ // [stack] ARRAY LENGTH INDEX INDEX
+ return false;
+ }
- if (!emitDupAt(2)) {
- // [stack] ARRAY LENGTH INDEX INDEX LENGTH
- return false;
- }
+ if (!emitDupAt(2)) {
+ // [stack] ARRAY LENGTH INDEX INDEX LENGTH
+ return false;
+ }
- if (!emit1(JSOp::Lt)) {
- // [stack] ARRAY LENGTH INDEX BOOL
- return false;
- }
+ if (!emit1(JSOp::Lt)) {
+ // [stack] ARRAY LENGTH INDEX BOOL
+ return false;
+ }
- if (!wh.emitBody()) {
- // [stack] ARRAY LENGTH INDEX
- return false;
- }
+ if (!wh.emitBody()) {
+ // [stack] ARRAY LENGTH INDEX
+ return false;
+ }
- if (!emitDupAt(2)) {
- // [stack] ARRAY LENGTH INDEX ARRAY
- return false;
- }
+ if (!emitDupAt(2)) {
+ // [stack] ARRAY LENGTH INDEX ARRAY
+ return false;
+ }
- if (!emitDupAt(1)) {
- // [stack] ARRAY LENGTH INDEX ARRAY INDEX
- return false;
- }
+ if (!emitDupAt(1)) {
+ // [stack] ARRAY LENGTH INDEX ARRAY INDEX
+ return false;
+ }
- // Retrieve initializers for this field
- if (!emit1(JSOp::GetElem)) {
- // [stack] ARRAY LENGTH INDEX INITIALIZERS
- return false;
- }
+ // Retrieve initializers for this field
+ if (!emit1(JSOp::GetElem)) {
+ // [stack] ARRAY LENGTH INDEX INITIALIZERS
+ return false;
+ }
- // This is guaranteed to run after super(), so we don't need TDZ checks.
- if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
- // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS
- return false;
- }
+ // This is guaranteed to run after super(), so we don't need TDZ checks.
+ if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
+ // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS
+ return false;
+ }
- if (!emit1(JSOp::Swap)) {
- // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS
- return false;
- }
+ if (!emit1(JSOp::Swap)) {
+ // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS
+ return false;
+ }
- DecoratorEmitter de(this);
- if (!de.emitInitializeFieldOrAccessor()) {
- // [stack] ARRAY LENGTH INDEX
- return false;
- }
+ DecoratorEmitter de(this);
+ if (!de.emitInitializeFieldOrAccessor()) {
+ // [stack] ARRAY LENGTH INDEX
+ return false;
+ }
- if (!emit1(JSOp::Inc)) {
- // [stack] ARRAY LENGTH INDEX
- return false;
- }
+ if (!emit1(JSOp::Inc)) {
+ // [stack] ARRAY LENGTH INDEX
+ return false;
+ }
- if (!wh.emitEnd()) {
- // [stack] ARRAY LENGTH INDEX
- return false;
- }
+ if (!wh.emitEnd()) {
+ // [stack] ARRAY LENGTH INDEX
+ return false;
+ }
- if (!emitPopN(3)) {
- // [stack]
- return false;
- }
- // 5. Return unused.
+ if (!emitPopN(3)) {
+ // [stack]
+ return false;
+ }
+ // 5. Return unused.
- if (!de.emitCallExtraInitializers(TaggedParserAtomIndex::WellKnown::
- dot_instanceExtraInitializers_())) {
- return false;
+ if (!de.emitCallExtraInitializers(TaggedParserAtomIndex::WellKnown::
+ dot_instanceExtraInitializers_())) {
+ return false;
+ }
}
#endif
}
@@ -12502,6 +12535,32 @@ bool BytecodeEmitter::emitTree(
break;
}
+ case ParseNodeKind::ArgumentsLength: {
+ if (sc->isFunctionBox() &&
+ sc->asFunctionBox()->isEligibleForArgumentsLength() &&
+ !sc->asFunctionBox()->needsArgsObj()) {
+ if (!emit1(JSOp::ArgumentsLength)) {
+ return false;
+ }
+ } else {
+ PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
+ PropOpEmitter::ObjKind::Other);
+ if (!poe.prepareForObj()) {
+ return false;
+ }
+
+ NameOpEmitter noe(this, TaggedParserAtomIndex::WellKnown::arguments(),
+ NameOpEmitter::Kind::Get);
+ if (!noe.emitGet()) {
+ return false;
+ }
+ if (!poe.emitGet(TaggedParserAtomIndex::WellKnown::length())) {
+ return false;
+ }
+ }
+ break;
+ }
+
case ParseNodeKind::ElemExpr: {
PropertyByValue* elem = &pn->as<PropertyByValue>();
bool isSuper = elem->isSuper();
diff --git a/js/src/frontend/CompileScript.cpp b/js/src/frontend/CompileScript.cpp
index 925b8201a2..b561d7d124 100644
--- a/js/src/frontend/CompileScript.cpp
+++ b/js/src/frontend/CompileScript.cpp
@@ -87,73 +87,46 @@ JS_PUBLIC_API const JSErrorReport* JS::GetFrontendWarningAt(
return &fc->warnings()[index];
}
-JS::CompilationStorage::~CompilationStorage() {
- if (input_ && !isBorrowed_) {
- js_delete(input_);
- input_ = nullptr;
- }
-}
-
-size_t JS::CompilationStorage::sizeOfIncludingThis(
- mozilla::MallocSizeOf mallocSizeOf) const {
- size_t sizeOfCompilationInput =
- input_ ? input_->sizeOfExcludingThis(mallocSizeOf) : 0;
- return mallocSizeOf(this) + sizeOfCompilationInput;
-}
-
-bool JS::CompilationStorage::allocateInput(
- FrontendContext* fc, const JS::ReadOnlyCompileOptions& options) {
- MOZ_ASSERT(!input_);
- input_ = fc->getAllocator()->new_<frontend::CompilationInput>(options);
- return !!input_;
-}
-
-void JS::CompilationStorage::trace(JSTracer* trc) {
- if (input_) {
- input_->trace(trc);
- }
-}
-
template <typename CharT>
static already_AddRefed<JS::Stencil> CompileGlobalScriptToStencilImpl(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
- JS::SourceText<CharT>& srcBuf, JS::CompilationStorage& compilationStorage) {
+ JS::SourceText<CharT>& srcBuf) {
ScopeKind scopeKind =
options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
JS::SourceText<CharT> data(std::move(srcBuf));
- compilationStorage.allocateInput(fc, options);
- if (!compilationStorage.hasInput()) {
- return nullptr;
- }
+ frontend::CompilationInput compilationInput(options);
frontend::NoScopeBindingCache scopeCache;
LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
- RefPtr<frontend::CompilationStencil> stencil_ =
- frontend::CompileGlobalScriptToStencil(nullptr, fc, tempLifoAlloc,
- compilationStorage.getInput(),
- &scopeCache, data, scopeKind);
+ RefPtr<JS::Stencil> stencil_ = frontend::CompileGlobalScriptToStencil(
+ nullptr, fc, tempLifoAlloc, compilationInput, &scopeCache, data,
+ scopeKind);
+ // CompilationInput initialized with CompileGlobalScriptToStencil only
+ // references information from the JS::Stencil context and the
+ // ref-counted ScriptSource, which are both GC-free.
+ JS_HAZ_VALUE_IS_GC_SAFE(compilationInput);
return stencil_.forget();
}
template <typename CharT>
static already_AddRefed<JS::Stencil> CompileModuleScriptToStencilImpl(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
- JS::SourceText<CharT>& srcBuf, JS::CompilationStorage& compilationStorage) {
+ JS::SourceText<CharT>& srcBuf) {
JS::CompileOptions options(nullptr, optionsInput);
options.setModule();
- compilationStorage.allocateInput(fc, options);
- if (!compilationStorage.hasInput()) {
- return nullptr;
- }
+ frontend::CompilationInput compilationInput(options);
NoScopeBindingCache scopeCache;
js::LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
- RefPtr<JS::Stencil> stencil =
- ParseModuleToStencil(nullptr, fc, tempLifoAlloc,
- compilationStorage.getInput(), &scopeCache, srcBuf);
+ RefPtr<JS::Stencil> stencil = ParseModuleToStencil(
+ nullptr, fc, tempLifoAlloc, compilationInput, &scopeCache, srcBuf);
+ // CompilationInput initialized with ParseModuleToStencil only
+ // references information from the JS::Stencil context and the
+ // ref-counted ScriptSource, which are both GC-free.
+ JS_HAZ_VALUE_IS_GC_SAFE(compilationInput);
if (!stencil) {
return nullptr;
}
@@ -164,42 +137,38 @@ static already_AddRefed<JS::Stencil> CompileModuleScriptToStencilImpl(
already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
- JS::SourceText<mozilla::Utf8Unit>& srcBuf,
- JS::CompilationStorage& compileStorage) {
+ JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
- return CompileGlobalScriptToStencilImpl(fc, options, srcBuf, compileStorage);
+ return CompileGlobalScriptToStencilImpl(fc, options, srcBuf);
}
already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
- JS::SourceText<char16_t>& srcBuf, JS::CompilationStorage& compileStorage) {
+ JS::SourceText<char16_t>& srcBuf) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
- return CompileGlobalScriptToStencilImpl(fc, options, srcBuf, compileStorage);
+ return CompileGlobalScriptToStencilImpl(fc, options, srcBuf);
}
already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
- JS::SourceText<mozilla::Utf8Unit>& srcBuf,
- JS::CompilationStorage& compileStorage) {
+ JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
- return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf,
- compileStorage);
+ return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf);
}
already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
- JS::SourceText<char16_t>& srcBuf, JS::CompilationStorage& compileStorage) {
+ JS::SourceText<char16_t>& srcBuf) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
- return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf,
- compileStorage);
+ return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf);
}
bool JS::PrepareForInstantiate(JS::FrontendContext* fc, JS::Stencil& stencil,
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
index 8a434418b1..b72c6d4726 100644
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -407,6 +407,7 @@ restart:
case ParseNodeKind::ObjectExpr:
case ParseNodeKind::PropertyNameExpr:
case ParseNodeKind::DotExpr:
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::ElemExpr:
case ParseNodeKind::Arguments:
case ParseNodeKind::CallExpr:
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index 384d16b7d8..9209ba4d67 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -103,7 +103,8 @@ class FullParseHandler {
bool isPropertyOrPrivateMemberAccess(Node node) {
return node->isKind(ParseNodeKind::DotExpr) ||
node->isKind(ParseNodeKind::ElemExpr) ||
- node->isKind(ParseNodeKind::PrivateMemberExpr);
+ node->isKind(ParseNodeKind::PrivateMemberExpr) ||
+ node->isKind(ParseNodeKind::ArgumentsLength);
}
bool isOptionalPropertyOrPrivateMemberAccess(Node node) {
@@ -887,6 +888,11 @@ class FullParseHandler {
key->pn_pos.end);
}
+ ArgumentsLengthResult newArgumentsLength(Node expr, NameNodeType key) {
+ return newResult<ArgumentsLength>(expr, key, expr->pn_pos.begin,
+ key->pn_pos.end);
+ }
+
PropertyByValueResult newPropertyByValue(Node lhs, Node index, uint32_t end) {
return newResult<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
}
@@ -1137,6 +1143,12 @@ class FullParseHandler {
TaggedParserAtomIndex::WellKnown::arguments();
}
+ bool isLengthName(Node node) {
+ return node->isKind(ParseNodeKind::PropertyNameExpr) &&
+ node->as<NameNode>().atom() ==
+ TaggedParserAtomIndex::WellKnown::length();
+ }
+
bool isEvalName(Node node) {
return node->isKind(ParseNodeKind::Name) &&
node->as<NameNode>().atom() ==
@@ -1150,6 +1162,10 @@ class FullParseHandler {
TaggedParserAtomIndex::WellKnown::async();
}
+ bool isArgumentsLength(Node node) {
+ return node->isKind(ParseNodeKind::ArgumentsLength);
+ }
+
bool isPrivateName(Node node) {
return node->isKind(ParseNodeKind::PrivateName);
}
diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp
index 0ad8e55758..46b5bb074c 100644
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -92,6 +92,7 @@ class NameResolver : public ParseNodeVisitor<NameResolver> {
*/
bool nameExpression(ParseNode* n, bool* foundName) {
switch (n->getKind()) {
+ case ParseNodeKind::ArgumentsLength:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &n->as<PropertyAccess>();
if (!nameExpression(&prop->expression(), foundName)) {
diff --git a/js/src/frontend/ParseContext.cpp b/js/src/frontend/ParseContext.cpp
index ececac705b..622c467822 100644
--- a/js/src/frontend/ParseContext.cpp
+++ b/js/src/frontend/ParseContext.cpp
@@ -593,6 +593,14 @@ bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
return false;
}
+bool ParseContext::hasClosedOverName(const UsedNameTracker& usedNames,
+ TaggedParserAtomIndex name) {
+ if (auto p = usedNames.lookup(name)) {
+ return p->value().isClosedOver(scriptId());
+ }
+ return false;
+}
+
bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
TaggedParserAtomIndex name) {
MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments() ||
@@ -602,6 +610,13 @@ bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
functionBox()->bindingsAccessedDynamically();
}
+bool ParseContext::hasClosedOverFunctionSpecialName(
+ const UsedNameTracker& usedNames, TaggedParserAtomIndex name) {
+ MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments());
+ return hasClosedOverName(usedNames, name) ||
+ functionBox()->bindingsAccessedDynamically();
+}
+
bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
bool canSkipLazyClosedOverBindings) {
// The asm.js validator does all its own symbol-table management so, as an
@@ -644,17 +659,41 @@ bool ParseContext::declareFunctionArgumentsObject(
ParseContext::Scope& funScope = functionScope();
ParseContext::Scope& _varScope = varScope();
- bool usesArguments = false;
bool hasExtraBodyVarScope = &funScope != &_varScope;
// Time to implement the odd semantics of 'arguments'.
auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();
- bool tryDeclareArguments;
+ bool tryDeclareArguments = false;
+ bool needsArgsObject = false;
+
+ // When delazifying simply defer to the function box.
if (canSkipLazyClosedOverBindings) {
tryDeclareArguments = funbox->shouldDeclareArguments();
+ needsArgsObject = funbox->needsArgsObj();
} else {
- tryDeclareArguments = hasUsedFunctionSpecialName(usedNames, argumentsName);
+ // We cannot compute these values when delazifying, hence why we need to
+ // rely on the function box flags instead.
+ bool bindingClosedOver =
+ hasClosedOverFunctionSpecialName(usedNames, argumentsName);
+ bool bindingUsedOnlyHere =
+ hasUsedFunctionSpecialName(usedNames, argumentsName) &&
+ !bindingClosedOver;
+
+ // Declare arguments if there's a closed-over consumer of the binding, or if
+ // there is a non-length use and we will reference the binding during
+ // bytecode emission.
+ tryDeclareArguments =
+ !funbox->isEligibleForArgumentsLength() || bindingClosedOver;
+ // If we have a use and the binding isn't closed over, then we will do
+ // bytecode emission with the arguments intrinsic.
+ if (bindingUsedOnlyHere && funbox->isEligibleForArgumentsLength()) {
+ // If we're using the intrinsic we should not be declaring the binding.
+ MOZ_ASSERT(!tryDeclareArguments);
+ funbox->setUsesArgumentsIntrinsics();
+ } else if (tryDeclareArguments) {
+ needsArgsObject = true;
+ }
}
// ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
@@ -670,9 +709,19 @@ bool ParseContext::declareFunctionArgumentsObject(
DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
if (p && p->value()->kind() == DeclarationKind::Var) {
if (hasExtraBodyVarScope) {
+ // While there is a binding in the var scope, we should declare
+ // the binding in the function scope.
tryDeclareArguments = true;
} else {
- usesArguments = true;
+ // A binding in the function scope (since varScope and functionScope are
+ // the same) exists, so arguments is used.
+ if (needsArgsObject) {
+ funbox->setNeedsArgsObj();
+ }
+
+ // There is no point in continuing on below: We know we already have
+ // a declaration of arguments in the function scope.
+ return true;
}
}
@@ -685,17 +734,11 @@ bool ParseContext::declareFunctionArgumentsObject(
return false;
}
funbox->setShouldDeclareArguments();
- usesArguments = true;
- } else if (hasExtraBodyVarScope) {
- // Formal parameters shadow the arguments object.
- return true;
+ if (needsArgsObject) {
+ funbox->setNeedsArgsObj();
+ }
}
}
-
- if (usesArguments) {
- funbox->setNeedsArgsObj();
- }
-
return true;
}
diff --git a/js/src/frontend/ParseContext.h b/js/src/frontend/ParseContext.h
index 8124073bf9..796b776d85 100644
--- a/js/src/frontend/ParseContext.h
+++ b/js/src/frontend/ParseContext.h
@@ -661,8 +661,12 @@ class ParseContext : public Nestable<ParseContext> {
bool hasUsedName(const UsedNameTracker& usedNames,
TaggedParserAtomIndex name);
+ bool hasClosedOverName(const UsedNameTracker& usedNames,
+ TaggedParserAtomIndex name);
bool hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
TaggedParserAtomIndex name);
+ bool hasClosedOverFunctionSpecialName(const UsedNameTracker& usedNames,
+ TaggedParserAtomIndex name);
bool declareFunctionThis(const UsedNameTracker& usedNames,
bool canSkipLazyClosedOverBindings);
@@ -673,6 +677,13 @@ class ParseContext : public Nestable<ParseContext> {
bool declareDotGeneratorName();
bool declareTopLevelDotGeneratorName();
+ // Used to determine if we have non-length uses of the arguments binding.
+ // This works by incrementing this counter each time we encounter the
+ // arguments name, and decrementing each time it is combined into
+ // arguments.length; as a result, if this is non-zero at the end of parsing,
+ // we have identified a non-length use of the arguments binding.
+ size_t numberOfArgumentsNames = 0;
+
private:
[[nodiscard]] bool isVarRedeclaredInInnermostScope(
TaggedParserAtomIndex name, ParserBase* parser, DeclarationKind kind,
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index 61c009c6e4..a6747897d6 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -75,6 +75,7 @@ class FunctionBox;
F(PostDecrementExpr, UnaryNode) \
F(PropertyNameExpr, NameNode) \
F(DotExpr, PropertyAccess) \
+ F(ArgumentsLength, ArgumentsLength) \
F(ElemExpr, PropertyByValue) \
F(PrivateMemberExpr, PrivateMemberAccess) \
F(OptionalDotExpr, OptionalPropertyAccess) \
@@ -616,6 +617,7 @@ inline bool IsTypeofKind(ParseNodeKind kind) {
MACRO(ClassNames) \
MACRO(ForNode) \
MACRO(PropertyAccess) \
+ MACRO(ArgumentsLength) \
MACRO(OptionalPropertyAccess) \
MACRO(PropertyByValue) \
MACRO(OptionalPropertyByValue) \
@@ -2014,7 +2016,8 @@ class PropertyAccessBase : public BinaryNode {
static bool test(const ParseNode& node) {
bool match = node.isKind(ParseNodeKind::DotExpr) ||
- node.isKind(ParseNodeKind::OptionalDotExpr);
+ node.isKind(ParseNodeKind::OptionalDotExpr) ||
+ node.isKind(ParseNodeKind::ArgumentsLength);
MOZ_ASSERT_IF(match, node.is<BinaryNode>());
MOZ_ASSERT_IF(match, node.as<BinaryNode>().right()->isKind(
ParseNodeKind::PropertyNameExpr));
@@ -2042,7 +2045,8 @@ class PropertyAccess : public PropertyAccessBase {
}
static bool test(const ParseNode& node) {
- bool match = node.isKind(ParseNodeKind::DotExpr);
+ bool match = node.isKind(ParseNodeKind::DotExpr) ||
+ node.isKind(ParseNodeKind::ArgumentsLength);
MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
return match;
}
@@ -2051,6 +2055,26 @@ class PropertyAccess : public PropertyAccessBase {
// ParseNodeKind::SuperBase cannot result from any expression syntax.
return expression().isKind(ParseNodeKind::SuperBase);
}
+
+ protected:
+ using PropertyAccessBase::PropertyAccessBase;
+};
+
+class ArgumentsLength : public PropertyAccess {
+ public:
+ ArgumentsLength(ParseNode* lhs, NameNode* name, uint32_t begin, uint32_t end)
+ : PropertyAccess(ParseNodeKind::ArgumentsLength, lhs, name, begin, end) {
+ MOZ_ASSERT(lhs);
+ MOZ_ASSERT(name);
+ }
+
+ static bool test(const ParseNode& node) {
+ bool match = node.isKind(ParseNodeKind::ArgumentsLength);
+ MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
+ return match;
+ }
+
+ bool isSuper() const { return false; }
};
class OptionalPropertyAccess : public PropertyAccessBase {
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index bcd6c30c02..5cb47f2425 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2472,6 +2472,11 @@ GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling,
}
}
+ if (pc_->numberOfArgumentsNames > 0 || kind == FunctionSyntaxKind::Arrow) {
+ MOZ_ASSERT(pc_->isFunctionBox());
+ pc_->sc()->setIneligibleForArgumentsLength();
+ }
+
// Declare the 'arguments', 'this', and 'new.target' bindings if necessary
// before finishing up the scope so these special bindings get marked as
// closed over if necessary. Arrow functions don't have these bindings.
@@ -6570,6 +6575,8 @@ bool GeneralParser<ParseHandler, Unit>::forHeadStart(
return false;
}
}
+ } else if (handler_.isArgumentsLength(*forInitialPart)) {
+ pc_->sc()->setIneligibleForArgumentsLength();
} else if (handler_.isPropertyOrPrivateMemberAccess(*forInitialPart)) {
// Permitted: no additional testing/fixup needed.
} else if (handler_.isFunctionCall(*forInitialPart)) {
@@ -7917,7 +7924,12 @@ bool GeneralParser<ParseHandler, Unit>::finishClassConstructor(
bool hasPrivateBrand = classInitializedMembers.hasPrivateBrand();
if (hasPrivateBrand || numMemberInitializers > 0) {
// Now that we have full set of initializers, update the constructor.
- MemberInitializers initializers(hasPrivateBrand, numMemberInitializers);
+ MemberInitializers initializers(
+ hasPrivateBrand,
+#ifdef ENABLE_DECORATORS
+ classInitializedMembers.hasInstanceDecorators,
+#endif
+ numMemberInitializers);
ctorbox->setMemberInitializers(initializers);
// Field initialization need access to `this`.
@@ -10220,6 +10232,8 @@ typename ParseHandler::NodeResult GeneralParser<ParseHandler, Unit>::assignExpr(
return errorResult();
}
}
+ } else if (handler_.isArgumentsLength(lhs)) {
+ pc_->sc()->setIneligibleForArgumentsLength();
} else if (handler_.isPropertyOrPrivateMemberAccess(lhs)) {
// Permitted: no additional testing/fixup needed.
} else if (handler_.isFunctionCall(lhs)) {
@@ -10280,6 +10294,8 @@ bool GeneralParser<ParseHandler, Unit>::checkIncDecOperand(
return false;
}
}
+ } else if (handler_.isArgumentsLength(operand)) {
+ pc_->sc()->setIneligibleForArgumentsLength();
} else if (handler_.isPropertyOrPrivateMemberAccess(operand)) {
// Permitted: no additional testing/fixup needed.
} else if (handler_.isFunctionCall(operand)) {
@@ -10898,6 +10914,9 @@ template <class ParseHandler>
inline typename ParseHandler::NameNodeResult
PerHandlerParser<ParseHandler>::newName(TaggedParserAtomIndex name,
TokenPos pos) {
+ if (name == TaggedParserAtomIndex::WellKnown::arguments()) {
+ this->pc_->numberOfArgumentsNames++;
+ }
return handler_.newName(name, pos);
}
@@ -10926,6 +10945,13 @@ GeneralParser<ParseHandler, Unit>::memberPropertyAccess(
MOZ_ASSERT(!handler_.isSuperBase(lhs));
return handler_.newOptionalPropertyAccess(lhs, name);
}
+
+ if (handler_.isArgumentsName(lhs) && handler_.isLengthName(name)) {
+ MOZ_ASSERT(pc_->numberOfArgumentsNames > 0);
+ pc_->numberOfArgumentsNames--;
+ return handler_.newArgumentsLength(lhs, name);
+ }
+
return handler_.newPropertyAccess(lhs, name);
}
@@ -11484,6 +11510,10 @@ void GeneralParser<ParseHandler, Unit>::checkDestructuringAssignmentName(
return;
}
+ if (handler_.isArgumentsLength(name)) {
+ pc_->sc()->setIneligibleForArgumentsLength();
+ }
+
if (pc_->sc()->strict()) {
if (handler_.isArgumentsName(name)) {
if (pc_->sc()->strict()) {
@@ -12143,6 +12173,10 @@ GeneralParser<ParseHandler, Unit>::objectLiteral(YieldHandling yieldHandling,
}
}
+ if (handler_.isArgumentsLength(lhs)) {
+ pc_->sc()->setIneligibleForArgumentsLength();
+ }
+
Node rhs;
MOZ_TRY_VAR(rhs,
assignExpr(InAllowed, yieldHandling, TripledotProhibited));
diff --git a/js/src/frontend/SharedContext.cpp b/js/src/frontend/SharedContext.cpp
index 7fa3b724fb..488e3bd384 100644
--- a/js/src/frontend/SharedContext.cpp
+++ b/js/src/frontend/SharedContext.cpp
@@ -45,7 +45,8 @@ SharedContext::SharedContext(FrontendContext* fc, Kind kind,
inClass_(false),
localStrict(false),
hasExplicitUseStrict_(false),
- isScriptExtraFieldCopiedToStencil(false) {
+ isScriptExtraFieldCopiedToStencil(false),
+ eligibleForArgumentsLength(true) {
// Compute the script kind "input" flags.
if (kind == Kind::FunctionBox) {
setFlag(ImmutableFlags::IsFunction);
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index 12f9a6ed12..ab0606527e 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -180,6 +180,10 @@ class SharedContext {
// FunctionBox::copyUpdated* methods.
bool isScriptExtraFieldCopiedToStencil : 1;
+ // Indicates this shared context is eligible to use JSOp::ArgumentsLength
+ // when emitting the ArgumentsLength parse node.
+ bool eligibleForArgumentsLength : 1;
+
// End of fields.
enum class Kind : uint8_t { FunctionBox, Global, Eval, Module };
@@ -273,6 +277,11 @@ class SharedContext {
return retVal;
}
+ bool isEligibleForArgumentsLength() {
+ return eligibleForArgumentsLength && !bindingsAccessedDynamically();
+ }
+ void setIneligibleForArgumentsLength() { eligibleForArgumentsLength = false; }
+
void copyScriptExtraFields(ScriptStencilExtra& scriptExtra);
};
diff --git a/js/src/frontend/Stencil.cpp b/js/src/frontend/Stencil.cpp
index 7c6eba4c5a..30d1588415 100644
--- a/js/src/frontend/Stencil.cpp
+++ b/js/src/frontend/Stencil.cpp
@@ -575,7 +575,7 @@ void ScopeContext::cacheEnclosingScope(const InputScope& enclosingScope) {
}
bool hasEnv = si.hasSyntacticEnvironment();
- auto setCacthAll = [&](NameLocation loc) {
+ auto setCatchAll = [&](NameLocation loc) {
return si.scope().match([&](auto& scope_ref) {
using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref));
BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref);
@@ -604,7 +604,7 @@ void ScopeContext::cacheEnclosingScope(const InputScope& enclosingScope) {
case ScopeKind::Function:
if (hasEnv) {
if (si.scope().funHasExtensibleScope()) {
- setCacthAll(NameLocation::Dynamic());
+ setCatchAll(NameLocation::Dynamic());
return;
}
@@ -733,21 +733,21 @@ void ScopeContext::cacheEnclosingScope(const InputScope& enclosingScope) {
if (!hasEnv) {
ScopeKind kind = si.scope().enclosing().kind();
if (kind == ScopeKind::Global || kind == ScopeKind::NonSyntactic) {
- setCacthAll(NameLocation::Global(BindingKind::Var));
+ setCatchAll(NameLocation::Global(BindingKind::Var));
return;
}
}
- setCacthAll(NameLocation::Dynamic());
+ setCatchAll(NameLocation::Dynamic());
return;
case ScopeKind::Global:
- setCacthAll(NameLocation::Global(BindingKind::Var));
+ setCatchAll(NameLocation::Global(BindingKind::Var));
return;
case ScopeKind::With:
case ScopeKind::NonSyntactic:
- setCacthAll(NameLocation::Dynamic());
+ setCatchAll(NameLocation::Dynamic());
return;
case ScopeKind::WasmInstance:
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index aa06eaa246..fa63b1e9d3 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -57,8 +57,9 @@ enum SyntaxParseHandlerNode {
// casing.
NodeName,
- // Nodes representing the names "arguments" and "eval".
+ // Nodes representing the names "arguments", "length" and "eval".
NodeArgumentsName,
+ NodeLengthName,
NodeEvalName,
// Node representing the "async" name, which may actually be a
@@ -77,6 +78,10 @@ enum SyntaxParseHandlerNode {
NodePrivateMemberAccess,
NodeOptionalPrivateMemberAccess,
+ // Node representing the compound Arguments.length expression;
+ // Used only for property access, not assignment.
+ NodeArgumentsLength,
+
// Destructuring target patterns can't be parenthesized: |([a]) = [3];|
// must be a syntax error. (We can't use NodeGeneric instead of these
// because that would trigger invalid-left-hand-side ReferenceError
@@ -164,7 +169,7 @@ class SyntaxParseHandler {
bool isPropertyOrPrivateMemberAccess(Node node) {
return node == NodeDottedProperty || node == NodeElement ||
- node == NodePrivateMemberAccess;
+ node == NodePrivateMemberAccess || node == NodeArgumentsLength;
}
bool isOptionalPropertyOrPrivateMemberAccess(Node node) {
@@ -572,6 +577,9 @@ class SyntaxParseHandler {
NameNodeResult newPropertyName(TaggedParserAtomIndex name,
const TokenPos& pos) {
lastAtom = name;
+ if (name == TaggedParserAtomIndex::WellKnown::length()) {
+ return NodeLengthName;
+ }
return NodeGeneric;
}
@@ -579,6 +587,10 @@ class SyntaxParseHandler {
return NodeDottedProperty;
}
+ PropertyAccessResult newArgumentsLength(Node expr, NameNodeType key) {
+ return NodeArgumentsLength;
+ }
+
PropertyAccessResult newOptionalPropertyAccess(Node expr, NameNodeType key) {
return NodeOptionalDottedProperty;
}
@@ -777,13 +789,17 @@ class SyntaxParseHandler {
bool isName(Node node) {
return node == NodeName || node == NodeArgumentsName ||
- node == NodeEvalName || node == NodePotentialAsyncKeyword;
+ node == NodeLengthName || node == NodeEvalName ||
+ node == NodePotentialAsyncKeyword;
}
bool isArgumentsName(Node node) { return node == NodeArgumentsName; }
+ bool isLengthName(Node node) { return node == NodeLengthName; }
bool isEvalName(Node node) { return node == NodeEvalName; }
bool isAsyncKeyword(Node node) { return node == NodePotentialAsyncKeyword; }
+ bool isArgumentsLength(Node node) { return node == NodeArgumentsLength; }
+
bool isPrivateName(Node node) { return node == NodePrivateName; }
bool isPrivateMemberAccess(Node node) {
return node == NodePrivateMemberAccess;
@@ -795,7 +811,8 @@ class SyntaxParseHandler {
// |this|. It's not really eligible for the funapply/funcall
// optimizations as they're currently implemented (assuming a single
// value is used for both retrieval and |this|).
- if (node != NodeDottedProperty && node != NodeOptionalDottedProperty) {
+ if (node != NodeDottedProperty && node != NodeOptionalDottedProperty &&
+ node != NodeArgumentsLength) {
return TaggedParserAtomIndex::null();
}
return lastAtom;
diff --git a/js/src/frontend/UsedNameTracker.h b/js/src/frontend/UsedNameTracker.h
index 2a52208128..f118d6101b 100644
--- a/js/src/frontend/UsedNameTracker.h
+++ b/js/src/frontend/UsedNameTracker.h
@@ -160,6 +160,10 @@ class UsedNameTracker {
return !uses_.empty() && uses_.back().scriptId >= scriptId;
}
+ bool isClosedOver(uint32_t scriptId) const {
+ return !uses_.empty() && uses_.back().scriptId > scriptId;
+ }
+
// To allow disambiguating public and private symbols
bool isPublic() { return visibility_ == NameVisibility::Public; }
diff --git a/js/src/frontend/align_stack_comment.py b/js/src/frontend/align_stack_comment.py
index 28d5d8cf7f..6e279a90c6 100755
--- a/js/src/frontend/align_stack_comment.py
+++ b/js/src/frontend/align_stack_comment.py
@@ -22,7 +22,7 @@ ALIGNMENT_COLUMN = 20
# The maximum column for comment
MAX_CHARS_PER_LINE = 80
-stack_comment_pat = re.compile("^( *//) *(\[stack\].*)$")
+stack_comment_pat = re.compile(r"^( *//) *(\[stack\].*)$")
def align_stack_comment(path):