summaryrefslogtreecommitdiffstats
path: root/js/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend')
-rw-r--r--js/src/frontend/BytecodeCompiler.cpp16
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp10
-rw-r--r--js/src/frontend/FullParseHandler.h6
-rw-r--r--js/src/frontend/ParseNode.h5
-rw-r--r--js/src/frontend/Parser.cpp85
-rw-r--r--js/src/frontend/Parser.h37
-rw-r--r--js/src/frontend/SharedContext.h11
-rw-r--r--js/src/frontend/SourceNotes.h3
-rw-r--r--js/src/frontend/SyntaxParseHandler.h2
9 files changed, 140 insertions, 35 deletions
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index a4b7dba6b..e0bb64e05 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -77,7 +77,13 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool canLazilyParse();
bool createParser();
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
- bool createScript(uint32_t preludeStart = 0);
+
+ // If toString{Start,End} are not explicitly passed, assume the script's
+ // offsets in the source used to parse it are the same as what should be
+ // used to compute its Function.prototype.toString() value.
+ bool createScript();
+ bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
+
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
@@ -242,11 +248,11 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No
}
bool
-BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
+BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */, uint32_t postludeEnd /* = 0 */)
{
script = JSScript::Create(cx, options,
sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
- preludeStart);
+ preludeStart, postludeEnd);
return script != nullptr;
}
@@ -458,7 +464,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
if (fn->pn_funbox->function()->isInterpreted()) {
MOZ_ASSERT(fun == fn->pn_funbox->function());
- if (!createScript(fn->pn_funbox->preludeStart))
+ if (!createScript(fn->pn_funbox->preludeStart, fn->pn_funbox->postludeEnd))
return false;
Maybe<BytecodeEmitter> emitter;
@@ -653,7 +659,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
lazy->begin(), lazy->end(),
- lazy->preludeStart()));
+ lazy->preludeStart(), lazy->postludeEnd()));
if (!script)
return false;
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index c15d67b7c..c788e0086 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7846,7 +7846,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
funbox->bufStart, funbox->bufEnd,
- funbox->preludeStart));
+ funbox->preludeStart,
+ funbox->postludeEnd));
if (!script)
return false;
@@ -10226,6 +10227,13 @@ BytecodeEmitter::emitClass(ParseNode* pn)
return false;
}
} else {
+ // In the case of default class constructors, emit the start and end
+ // offsets in the source buffer as source notes so that when we
+ // actually make the constructor during execution, we can give it the
+ // correct toString output.
+ if (!newSrcNote3(SRC_CLASS_SPAN, ptrdiff_t(pn->pn_pos.begin), ptrdiff_t(pn->pn_pos.end)))
+ return false;
+
JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty;
if (heritageExpression) {
if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR))
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index f0fc7700d..7ddd8d306 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -333,8 +333,10 @@ class FullParseHandler
return literal;
}
- ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock) {
- return new_<ClassNode>(name, heritage, methodBlock);
+ ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
+ const TokenPos& pos)
+ {
+ return new_<ClassNode>(name, heritage, methodBlock, pos);
}
ParseNode* newClassMethodList(uint32_t begin) {
return new_<ListNode>(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1));
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index c0669d85e..1f20f3988 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1309,8 +1309,9 @@ struct ClassNames : public BinaryNode {
};
struct ClassNode : public TernaryNode {
- ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock)
- : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock)
+ ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock,
+ const TokenPos& pos)
+ : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock, pos)
{
MOZ_ASSERT_IF(names, names->is<ClassNames>());
MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>() ||
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index d62a26f76..299b8b93a 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -141,7 +141,8 @@ StatementKindIsBraced(StatementKind kind)
kind == StatementKind::Switch ||
kind == StatementKind::Try ||
kind == StatementKind::Catch ||
- kind == StatementKind::Finally;
+ kind == StatementKind::Finally ||
+ kind == StatementKind::Class;
}
void
@@ -472,6 +473,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
startLine(1),
startColumn(0),
preludeStart(preludeStart),
+ postludeEnd(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)),
@@ -542,10 +544,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
allowNewTarget_ = true;
allowSuperProperty_ = fun->allowSuperProperty();
- if (kind == DerivedClassConstructor) {
- setDerivedClassConstructor();
- allowSuperCall_ = true;
- needsThisTDZChecks_ = true;
+ if (kind == ClassConstructor || kind == DerivedClassConstructor) {
+ auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
+ MOZ_ASSERT(stmt);
+ stmt->setConstructorBox(this);
+
+ if (kind == DerivedClassConstructor) {
+ setDerivedClassConstructor();
+ allowSuperCall_ = true;
+ needsThisTDZChecks_ = true;
+ }
}
if (isGenexpLambda)
@@ -566,6 +574,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
}
void
+FunctionBox::resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind)
+{
+ if (kind == ClassConstructor || kind == DerivedClassConstructor) {
+ auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
+ MOZ_ASSERT(stmt);
+ stmt->clearConstructorBoxForAbortedSyntaxParse(this);
+ }
+}
+
+void
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
{
if (!function()->isArrow()) {
@@ -3389,6 +3407,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// correctness.
parser->clearAbortedSyntaxParse();
usedNames.rewind(token);
+ funbox->resetForAbortedSyntaxParse(pc, kind);
MOZ_ASSERT_IF(parser->context->isJSContext(),
!parser->context->asJSContext()->isExceptionPending());
break;
@@ -3670,14 +3689,14 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
error(JSMSG_CURLY_AFTER_BODY);
return false;
}
- funbox->bufEnd = pos().end;
+ funbox->setEnd(pos().end);
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);
#endif
if (tokenStream.hadError())
return false;
- funbox->bufEnd = pos().end;
+ funbox->setEnd(pos().end);
if (kind == Statement && !matchOrInsertSemicolonAfterExpression())
return false;
}
@@ -6935,6 +6954,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
+ uint32_t classStartOffset = pos().begin;
bool savedStrictness = setLocalStrictMode(true);
TokenKind tt;
@@ -6960,16 +6980,20 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken();
}
+ // Push a ParseContext::ClassStatement to keep track of the constructor
+ // funbox.
+ ParseContext::ClassStatement classStmt(pc);
+
RootedAtom propAtom(context);
// A named class creates a new lexical scope with a const binding of the
- // class name.
- Maybe<ParseContext::Statement> classStmt;
- Maybe<ParseContext::Scope> classScope;
+ // class name for the "inner name".
+ Maybe<ParseContext::Statement> innerScopeStmt;
+ Maybe<ParseContext::Scope> innerScope;
if (name) {
- classStmt.emplace(pc, StatementKind::Block);
- classScope.emplace(this);
- if (!classScope->init(pc))
+ innerScopeStmt.emplace(pc, StatementKind::Block);
+ innerScope.emplace(this);
+ if (!innerScope->init(pc))
return null();
}
@@ -6996,7 +7020,6 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!classMethods)
return null();
- bool seenConstructor = false;
for (;;) {
TokenKind tt;
if (!tokenStream.getToken(&tt))
@@ -7048,16 +7071,17 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
propType = PropertyType::GetterNoExpressionClosure;
if (propType == PropertyType::Setter)
propType = PropertyType::SetterNoExpressionClosure;
- if (!isStatic && propAtom == context->names().constructor) {
+
+ bool isConstructor = !isStatic && propAtom == context->names().constructor;
+ if (isConstructor) {
if (propType != PropertyType::Method) {
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
- if (seenConstructor) {
+ if (classStmt.constructorBox()) {
errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
return null();
}
- seenConstructor = true;
propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor;
} else if (isStatic && propAtom == context->names().prototype) {
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
@@ -7082,7 +7106,12 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom;
}
- Node fn = methodDefinition(nameOffset, propType, funName);
+
+ // Calling toString on constructors need to return the source text for
+ // the entire class. The end offset is unknown at this point in
+ // parsing and will be amended when class parsing finishes below.
+ Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
+ propType, funName);
if (!fn)
return null();
@@ -7093,6 +7122,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
}
+ // Amend the postlude offset for the constructor now that we've finished
+ // parsing the class.
+ uint32_t classEndOffset = pos().end;
+ if (FunctionBox* ctorbox = classStmt.constructorBox()) {
+ if (ctorbox->function()->isInterpretedLazy())
+ ctorbox->function()->lazyScript()->setPostludeEnd(classEndOffset);
+ ctorbox->postludeEnd = classEndOffset;
+ }
+
Node nameNode = null();
Node methodsOrBlock = classMethods;
if (name) {
@@ -7104,15 +7142,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!innerName)
return null();
- Node classBlock = finishLexicalScope(*classScope, classMethods);
+ Node classBlock = finishLexicalScope(*innerScope, classMethods);
if (!classBlock)
return null();
methodsOrBlock = classBlock;
// Pop the inner scope.
- classScope.reset();
- classStmt.reset();
+ innerScope.reset();
+ innerScopeStmt.reset();
Node outerName = null();
if (classContext == ClassStatement) {
@@ -7132,7 +7170,8 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
- return handler.newClass(nameNode, classHeritage, methodsOrBlock);
+ return handler.newClass(nameNode, classHeritage, methodsOrBlock,
+ TokenPos(classStartOffset, classEndOffset));
}
template <class ParseHandler>
@@ -8388,7 +8427,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
uint32_t end = pos().end;
handler.setBeginPosition(comp, begin);
handler.setEndPosition(comp, end);
- genFunbox->bufEnd = end;
+ genFunbox->setEnd(end);
handler.addStatementToList(body, comp);
handler.setEndPosition(body, end);
handler.setBeginPosition(genfn, begin);
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 6b5ade425..efb543efa 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -85,6 +85,31 @@ class ParseContext : public Nestable<ParseContext>
}
};
+ class ClassStatement : public Statement
+ {
+ FunctionBox* constructorBox_;
+
+ public:
+ explicit ClassStatement(ParseContext* pc)
+ : Statement(pc, StatementKind::Class),
+ constructorBox_(nullptr)
+ { }
+
+ void clearConstructorBoxForAbortedSyntaxParse(FunctionBox* funbox) {
+ MOZ_ASSERT(constructorBox_ == funbox);
+ constructorBox_ = nullptr;
+ }
+
+ void setConstructorBox(FunctionBox* funbox) {
+ MOZ_ASSERT(!constructorBox_);
+ constructorBox_ = funbox;
+ }
+
+ FunctionBox* constructorBox() const {
+ return constructorBox_;
+ }
+ };
+
// The intra-function scope stack.
//
// Tracks declared and used names within a scope.
@@ -432,6 +457,11 @@ class ParseContext : public Nestable<ParseContext>
return Statement::findNearest<T>(innermostStatement_, predicate);
}
+ template <typename T>
+ T* findInnermostStatement() {
+ return Statement::findNearest<T>(innermostStatement_);
+ }
+
AtomVector& positionalFormalParameterNames() {
return *positionalFormalParameterNames_;
}
@@ -532,6 +562,13 @@ ParseContext::Statement::is<ParseContext::LabelStatement>() const
return kind_ == StatementKind::Label;
}
+template <>
+inline bool
+ParseContext::Statement::is<ParseContext::ClassStatement>() const
+{
+ return kind_ == StatementKind::Class;
+}
+
template <typename T>
inline T&
ParseContext::Statement::as()
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index f5a74e18c..213a0a461 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -38,6 +38,7 @@ enum class StatementKind : uint8_t
ForOfLoop,
DoLoop,
WhileLoop,
+ Class,
// Used only by BytecodeEmitter.
Spread
@@ -451,6 +452,7 @@ class FunctionBox : public ObjectBox, public SharedContext
uint32_t startLine;
uint32_t startColumn;
uint32_t preludeStart;
+ uint32_t postludeEnd;
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
@@ -501,6 +503,7 @@ class FunctionBox : public ObjectBox, public SharedContext
void initFromLazyFunction();
void initStandaloneFunction(Scope* enclosingScope);
void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
+ void resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind);
ObjectBox* toObjectBox() override { return this; }
JSFunction* function() const { return &object->as<JSFunction>(); }
@@ -603,6 +606,14 @@ class FunctionBox : public ObjectBox, public SharedContext
tokenStream.srcCoords.lineNumAndColumnIndex(bufStart, &startLine, &startColumn);
}
+ void setEnd(uint32_t end) {
+ // For all functions except class constructors, the buffer and
+ // postlude ending positions are the same. Class constructors override
+ // the postlude ending position with the end of the class definition.
+ bufEnd = end;
+ postludeEnd = end;
+ }
+
void trace(JSTracer* trc) override;
};
diff --git a/js/src/frontend/SourceNotes.h b/js/src/frontend/SourceNotes.h
index dd2a95ad1..6ae184ae4 100644
--- a/js/src/frontend/SourceNotes.h
+++ b/js/src/frontend/SourceNotes.h
@@ -56,13 +56,14 @@ namespace js {
M(SRC_NEXTCASE, "nextcase", 1) /* Distance forward from one CASE in a CONDSWITCH to \
the next. */ \
M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \
+ M(SRC_CLASS_SPAN, "class", 2) /* The starting and ending offsets for the class, used \
+ for toString correctness for default ctors. */ \
M(SRC_TRY, "try", 1) /* JSOP_TRY, offset points to goto at the end of the \
try block. */ \
/* All notes above here are "gettable". See SN_IS_GETTABLE below. */ \
M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \
M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \
M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \
- M(SRC_UNUSED20, "unused20", 0) /* Unused. */ \
M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \
M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \
M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index f492bab66..895ba6416 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -289,7 +289,7 @@ class SyntaxParseHandler
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; }
- Node newClass(Node name, Node heritage, Node methodBlock) { return NodeGeneric; }
+ Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; }
Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }