[parser] Track labels in the parser-base rather than parser+ast

Bug: v8:8088
Change-Id: Ie92499a43e2286e9bb1c64b0d553a515d74d5aa2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2059989
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66313}
This commit is contained in:
Toon Verwaest 2020-02-18 16:07:23 +01:00 committed by Commit Bot
parent b9e40f7c01
commit f5592da673
13 changed files with 264 additions and 510 deletions

View File

@ -1103,20 +1103,5 @@ const char* CallRuntime::debug_name() {
#endif // DEBUG #endif // DEBUG
} }
#define RETURN_LABELS(NodeType) \
case k##NodeType: \
return static_cast<const NodeType*>(this)->labels();
ZonePtrList<const AstRawString>* BreakableStatement::labels() const {
switch (node_type()) {
BREAKABLE_NODE_LIST(RETURN_LABELS)
ITERATION_NODE_LIST(RETURN_LABELS)
default:
UNREACHABLE();
}
}
#undef RETURN_LABELS
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -295,62 +295,28 @@ class FailureExpression : public Expression {
// V8's notion of BreakableStatement does not correspond to the notion of // V8's notion of BreakableStatement does not correspond to the notion of
// BreakableStatement in ECMAScript. In V8, the idea is that a // BreakableStatement in ECMAScript. In V8, the idea is that a
// BreakableStatement is a statement that can be the target of a break // BreakableStatement is a statement that can be the target of a break
// statement. The BreakableStatement AST node carries a list of labels, any of // statement.
// which can be used as an argument to the break statement in order to target
// it.
// //
// Since we don't want to attach a list of labels to all kinds of statements, we // Since we don't want to track a list of labels for all kinds of statements, we
// only declare switchs, loops, and blocks as BreakableStatements. This means // only declare switchs, loops, and blocks as BreakableStatements. This means
// that we implement breaks targeting other statement forms as breaks targeting // that we implement breaks targeting other statement forms as breaks targeting
// a substatement thereof. For instance, in "foo: if (b) { f(); break foo; }" we // a substatement thereof. For instance, in "foo: if (b) { f(); break foo; }" we
// pretend that foo is the label of the inner block. That's okay because one // pretend that foo is the label of the inner block. That's okay because one
// can't observe the difference. // can't observe the difference.
// // TODO(verwaest): Reconsider this optimization now that the tracking of labels
// This optimization makes it harder to detect invalid continue labels, see the // is done at runtime.
// need for own_labels in IterationStatement.
//
class BreakableStatement : public Statement { class BreakableStatement : public Statement {
public:
enum BreakableType {
TARGET_FOR_ANONYMOUS,
TARGET_FOR_NAMED_ONLY
};
// A list of all labels declared on the path up to the previous
// BreakableStatement (if any).
//
// Example: "l1: for (;;) l2: l3: { l4: if (b) l5: { s } }"
// labels() of the ForStatement will be l1.
// labels() of the Block { l4: ... } will be l2, l3.
// labels() of the Block { s } will be l4, l5.
ZonePtrList<const AstRawString>* labels() const;
// Testers.
bool is_target_for_anonymous() const {
return BreakableTypeField::decode(bit_field_) == TARGET_FOR_ANONYMOUS;
}
private:
using BreakableTypeField = Statement::NextBitField<BreakableType, 1>;
protected: protected:
BreakableStatement(BreakableType breakable_type, int position, NodeType type) BreakableStatement(int position, NodeType type) : Statement(position, type) {}
: Statement(position, type) {
bit_field_ |= BreakableTypeField::encode(breakable_type);
}
template <class T, int size>
using NextBitField = BreakableTypeField::Next<T, size>;
}; };
class Block : public BreakableStatement { class Block final : public BreakableStatement {
public: public:
ZonePtrList<Statement>* statements() { return &statements_; } ZonePtrList<Statement>* statements() { return &statements_; }
bool ignore_completion_value() const { bool ignore_completion_value() const {
return IgnoreCompletionField::decode(bit_field_); return IgnoreCompletionField::decode(bit_field_);
} }
bool is_breakable() const { return IsBreakableField::decode(bit_field_); }
inline ZonePtrList<const AstRawString>* labels() const;
Scope* scope() const { return scope_; } Scope* scope() const { return scope_; }
void set_scope(Scope* scope) { scope_ = scope; } void set_scope(Scope* scope) { scope_ = scope; }
@ -368,49 +334,22 @@ class Block : public BreakableStatement {
Scope* scope_; Scope* scope_;
using IgnoreCompletionField = BreakableStatement::NextBitField<bool, 1>; using IgnoreCompletionField = BreakableStatement::NextBitField<bool, 1>;
using IsLabeledField = IgnoreCompletionField::Next<bool, 1>; using IsBreakableField = IgnoreCompletionField::Next<bool, 1>;
protected: protected:
Block(Zone* zone, ZonePtrList<const AstRawString>* labels, int capacity, Block(Zone* zone, int capacity, bool ignore_completion_value,
bool ignore_completion_value) bool is_breakable)
: BreakableStatement(TARGET_FOR_NAMED_ONLY, kNoSourcePosition, kBlock), : BreakableStatement(kNoSourcePosition, kBlock),
statements_(capacity, zone), statements_(capacity, zone),
scope_(nullptr) { scope_(nullptr) {
bit_field_ |= IgnoreCompletionField::encode(ignore_completion_value) | bit_field_ |= IgnoreCompletionField::encode(ignore_completion_value) |
IsLabeledField::encode(labels != nullptr); IsBreakableField::encode(is_breakable);
} }
Block(ZonePtrList<const AstRawString>* labels, bool ignore_completion_value) Block(bool ignore_completion_value, bool is_breakable)
: Block(nullptr, labels, 0, ignore_completion_value) {} : Block(nullptr, 0, ignore_completion_value, is_breakable) {}
}; };
class LabeledBlock final : public Block {
private:
friend class AstNodeFactory;
friend class Block;
LabeledBlock(Zone* zone, ZonePtrList<const AstRawString>* labels,
int capacity, bool ignore_completion_value)
: Block(zone, labels, capacity, ignore_completion_value),
labels_(labels) {
DCHECK_NOT_NULL(labels);
DCHECK_GT(labels->length(), 0);
}
LabeledBlock(ZonePtrList<const AstRawString>* labels,
bool ignore_completion_value)
: LabeledBlock(nullptr, labels, 0, ignore_completion_value) {}
ZonePtrList<const AstRawString>* labels_;
};
inline ZonePtrList<const AstRawString>* Block::labels() const {
if (IsLabeledField::decode(bit_field_)) {
return static_cast<const LabeledBlock*>(this)->labels_;
}
return nullptr;
}
class Declaration : public AstNode { class Declaration : public AstNode {
public: public:
using List = base::ThreadedList<Declaration>; using List = base::ThreadedList<Declaration>;
@ -491,31 +430,12 @@ class IterationStatement : public BreakableStatement {
Statement* body() const { return body_; } Statement* body() const { return body_; }
void set_body(Statement* s) { body_ = s; } void set_body(Statement* s) { body_ = s; }
ZonePtrList<const AstRawString>* labels() const { return labels_; }
// A list of all labels that the iteration statement is directly prefixed
// with, i.e. all the labels that a continue statement in the body can use to
// continue this iteration statement. This is always a subset of {labels}.
//
// Example: "l1: { l2: if (b) l3: l4: for (;;) s }"
// labels() of the Block will be l1.
// labels() of the ForStatement will be l2, l3, l4.
// own_labels() of the ForStatement will be l3, l4.
ZonePtrList<const AstRawString>* own_labels() const { return own_labels_; }
protected: protected:
IterationStatement(ZonePtrList<const AstRawString>* labels, IterationStatement(int pos, NodeType type)
ZonePtrList<const AstRawString>* own_labels, int pos, : BreakableStatement(pos, type), body_(nullptr) {}
NodeType type)
: BreakableStatement(TARGET_FOR_ANONYMOUS, pos, type),
labels_(labels),
own_labels_(own_labels),
body_(nullptr) {}
void Initialize(Statement* body) { body_ = body; } void Initialize(Statement* body) { body_ = body; }
private: private:
ZonePtrList<const AstRawString>* labels_;
ZonePtrList<const AstRawString>* own_labels_;
Statement* body_; Statement* body_;
}; };
@ -532,10 +452,8 @@ class DoWhileStatement final : public IterationStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
DoWhileStatement(ZonePtrList<const AstRawString>* labels, explicit DoWhileStatement(int pos)
ZonePtrList<const AstRawString>* own_labels, int pos) : IterationStatement(pos, kDoWhileStatement), cond_(nullptr) {}
: IterationStatement(labels, own_labels, pos, kDoWhileStatement),
cond_(nullptr) {}
Expression* cond_; Expression* cond_;
}; };
@ -553,10 +471,8 @@ class WhileStatement final : public IterationStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
WhileStatement(ZonePtrList<const AstRawString>* labels, explicit WhileStatement(int pos)
ZonePtrList<const AstRawString>* own_labels, int pos) : IterationStatement(pos, kWhileStatement), cond_(nullptr) {}
: IterationStatement(labels, own_labels, pos, kWhileStatement),
cond_(nullptr) {}
Expression* cond_; Expression* cond_;
}; };
@ -579,9 +495,8 @@ class ForStatement final : public IterationStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
ForStatement(ZonePtrList<const AstRawString>* labels, explicit ForStatement(int pos)
ZonePtrList<const AstRawString>* own_labels, int pos) : IterationStatement(pos, kForStatement),
: IterationStatement(labels, own_labels, pos, kForStatement),
init_(nullptr), init_(nullptr),
cond_(nullptr), cond_(nullptr),
next_(nullptr) {} next_(nullptr) {}
@ -617,12 +532,8 @@ class ForEachStatement : public IterationStatement {
protected: protected:
friend class AstNodeFactory; friend class AstNodeFactory;
ForEachStatement(ZonePtrList<const AstRawString>* labels, ForEachStatement(int pos, NodeType type)
ZonePtrList<const AstRawString>* own_labels, int pos, : IterationStatement(pos, type), each_(nullptr), subject_(nullptr) {}
NodeType type)
: IterationStatement(labels, own_labels, pos, type),
each_(nullptr),
subject_(nullptr) {}
Expression* each_; Expression* each_;
Expression* subject_; Expression* subject_;
@ -632,9 +543,7 @@ class ForInStatement final : public ForEachStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
ForInStatement(ZonePtrList<const AstRawString>* labels, explicit ForInStatement(int pos) : ForEachStatement(pos, kForInStatement) {}
ZonePtrList<const AstRawString>* own_labels, int pos)
: ForEachStatement(labels, own_labels, pos, kForInStatement) {}
}; };
enum class IteratorType { kNormal, kAsync }; enum class IteratorType { kNormal, kAsync };
@ -645,11 +554,8 @@ class ForOfStatement final : public ForEachStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
ForOfStatement(ZonePtrList<const AstRawString>* labels, ForOfStatement(int pos, IteratorType type)
ZonePtrList<const AstRawString>* own_labels, int pos, : ForEachStatement(pos, kForOfStatement), type_(type) {}
IteratorType type)
: ForEachStatement(labels, own_labels, pos, kForOfStatement),
type_(type) {}
IteratorType type_; IteratorType type_;
}; };
@ -777,8 +683,6 @@ class CaseClause final : public ZoneObject {
class SwitchStatement final : public BreakableStatement { class SwitchStatement final : public BreakableStatement {
public: public:
ZonePtrList<const AstRawString>* labels() const { return labels_; }
Expression* tag() const { return tag_; } Expression* tag() const { return tag_; }
void set_tag(Expression* t) { tag_ = t; } void set_tag(Expression* t) { tag_ = t; }
@ -787,14 +691,9 @@ class SwitchStatement final : public BreakableStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
SwitchStatement(Zone* zone, ZonePtrList<const AstRawString>* labels, SwitchStatement(Zone* zone, Expression* tag, int pos)
Expression* tag, int pos) : BreakableStatement(pos, kSwitchStatement), tag_(tag), cases_(4, zone) {}
: BreakableStatement(TARGET_FOR_ANONYMOUS, pos, kSwitchStatement),
labels_(labels),
tag_(tag),
cases_(4, zone) {}
ZonePtrList<const AstRawString>* labels_;
Expression* tag_; Expression* tag_;
ZonePtrList<CaseClause> cases_; ZonePtrList<CaseClause> cases_;
}; };
@ -2824,59 +2723,46 @@ class AstNodeFactory final {
} }
Block* NewBlock(int capacity, bool ignore_completion_value) { Block* NewBlock(int capacity, bool ignore_completion_value) {
return new (zone_) Block(zone_, nullptr, capacity, ignore_completion_value); return new (zone_) Block(zone_, capacity, ignore_completion_value, false);
} }
Block* NewBlock(bool ignore_completion_value, Block* NewBlock(bool ignore_completion_value, bool is_breakable) {
ZonePtrList<const AstRawString>* labels) { return new (zone_) Block(ignore_completion_value, is_breakable);
return labels != nullptr
? new (zone_) LabeledBlock(labels, ignore_completion_value)
: new (zone_) Block(labels, ignore_completion_value);
} }
Block* NewBlock(bool ignore_completion_value, Block* NewBlock(bool ignore_completion_value,
const ScopedPtrList<Statement>& statements) { const ScopedPtrList<Statement>& statements) {
Block* result = NewBlock(ignore_completion_value, nullptr); Block* result = NewBlock(ignore_completion_value, false);
result->InitializeStatements(statements, zone_); result->InitializeStatements(statements, zone_);
return result; return result;
} }
#define STATEMENT_WITH_LABELS(NodeType) \ #define STATEMENT_WITH_POSITION(NodeType) \
NodeType* New##NodeType(ZonePtrList<const AstRawString>* labels, \ NodeType* New##NodeType(int pos) { return new (zone_) NodeType(pos); }
ZonePtrList<const AstRawString>* own_labels, \ STATEMENT_WITH_POSITION(DoWhileStatement)
int pos) { \ STATEMENT_WITH_POSITION(WhileStatement)
return new (zone_) NodeType(labels, own_labels, pos); \ STATEMENT_WITH_POSITION(ForStatement)
} #undef STATEMENT_WITH_POSITION
STATEMENT_WITH_LABELS(DoWhileStatement)
STATEMENT_WITH_LABELS(WhileStatement)
STATEMENT_WITH_LABELS(ForStatement)
#undef STATEMENT_WITH_LABELS
SwitchStatement* NewSwitchStatement(ZonePtrList<const AstRawString>* labels, SwitchStatement* NewSwitchStatement(Expression* tag, int pos) {
Expression* tag, int pos) { return new (zone_) SwitchStatement(zone_, tag, pos);
return new (zone_) SwitchStatement(zone_, labels, tag, pos);
} }
ForEachStatement* NewForEachStatement( ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode,
ForEachStatement::VisitMode visit_mode, int pos) {
ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
switch (visit_mode) { switch (visit_mode) {
case ForEachStatement::ENUMERATE: { case ForEachStatement::ENUMERATE: {
return new (zone_) ForInStatement(labels, own_labels, pos); return new (zone_) ForInStatement(pos);
} }
case ForEachStatement::ITERATE: { case ForEachStatement::ITERATE: {
return new (zone_) return new (zone_) ForOfStatement(pos, IteratorType::kNormal);
ForOfStatement(labels, own_labels, pos, IteratorType::kNormal);
} }
} }
UNREACHABLE(); UNREACHABLE();
} }
ForOfStatement* NewForOfStatement(ZonePtrList<const AstRawString>* labels, ForOfStatement* NewForOfStatement(int pos, IteratorType type) {
ZonePtrList<const AstRawString>* own_labels, return new (zone_) ForOfStatement(pos, type);
int pos, IteratorType type) {
return new (zone_) ForOfStatement(labels, own_labels, pos, type);
} }
ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) { ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {

View File

@ -659,15 +659,6 @@ void AstPrinter::Print(const char* format, ...) {
} }
} }
void AstPrinter::PrintLabels(ZonePtrList<const AstRawString>* labels) {
if (labels != nullptr) {
for (int i = 0; i < labels->length(); i++) {
PrintLiteral(labels->at(i), false);
Print(": ");
}
}
}
void AstPrinter::PrintLiteral(Literal* literal, bool quote) { void AstPrinter::PrintLiteral(Literal* literal, bool quote) {
switch (literal->type()) { switch (literal->type()) {
case Literal::kString: case Literal::kString:
@ -819,16 +810,6 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var,
} }
} }
void AstPrinter::PrintLabelsIndented(ZonePtrList<const AstRawString>* labels,
const char* prefix) {
if (labels == nullptr || labels->length() == 0) return;
PrintIndented(prefix);
Print("LABELS ");
PrintLabels(labels);
Print("\n");
}
void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) { void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) {
if (node != nullptr) { if (node != nullptr) {
IndentedScope indent(this, s, node->position()); IndentedScope indent(this, s, node->position());
@ -902,7 +883,6 @@ void AstPrinter::VisitBlock(Block* node) {
const char* block_txt = const char* block_txt =
node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK"; node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK";
IndentedScope indent(this, block_txt, node->position()); IndentedScope indent(this, block_txt, node->position());
PrintLabelsIndented(node->labels());
PrintStatements(node->statements()); PrintStatements(node->statements());
} }
@ -953,13 +933,11 @@ void AstPrinter::VisitIfStatement(IfStatement* node) {
void AstPrinter::VisitContinueStatement(ContinueStatement* node) { void AstPrinter::VisitContinueStatement(ContinueStatement* node) {
IndentedScope indent(this, "CONTINUE", node->position()); IndentedScope indent(this, "CONTINUE", node->position());
PrintLabelsIndented(node->target()->labels());
} }
void AstPrinter::VisitBreakStatement(BreakStatement* node) { void AstPrinter::VisitBreakStatement(BreakStatement* node) {
IndentedScope indent(this, "BREAK", node->position()); IndentedScope indent(this, "BREAK", node->position());
PrintLabelsIndented(node->target()->labels());
} }
@ -978,7 +956,6 @@ void AstPrinter::VisitWithStatement(WithStatement* node) {
void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
IndentedScope indent(this, "SWITCH", node->position()); IndentedScope indent(this, "SWITCH", node->position());
PrintLabelsIndented(node->labels());
PrintIndentedVisit("TAG", node->tag()); PrintIndentedVisit("TAG", node->tag());
for (CaseClause* clause : *node->cases()) { for (CaseClause* clause : *node->cases()) {
if (clause->is_default()) { if (clause->is_default()) {
@ -995,8 +972,6 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
IndentedScope indent(this, "DO", node->position()); IndentedScope indent(this, "DO", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("COND", node->cond());
} }
@ -1004,8 +979,6 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
void AstPrinter::VisitWhileStatement(WhileStatement* node) { void AstPrinter::VisitWhileStatement(WhileStatement* node) {
IndentedScope indent(this, "WHILE", node->position()); IndentedScope indent(this, "WHILE", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
} }
@ -1013,8 +986,6 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) {
void AstPrinter::VisitForStatement(ForStatement* node) { void AstPrinter::VisitForStatement(ForStatement* node) {
IndentedScope indent(this, "FOR", node->position()); IndentedScope indent(this, "FOR", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
if (node->init()) PrintIndentedVisit("INIT", node->init()); if (node->init()) PrintIndentedVisit("INIT", node->init());
if (node->cond()) PrintIndentedVisit("COND", node->cond()); if (node->cond()) PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
@ -1024,8 +995,6 @@ void AstPrinter::VisitForStatement(ForStatement* node) {
void AstPrinter::VisitForInStatement(ForInStatement* node) { void AstPrinter::VisitForInStatement(ForInStatement* node) {
IndentedScope indent(this, "FOR IN", node->position()); IndentedScope indent(this, "FOR IN", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("FOR", node->each()); PrintIndentedVisit("FOR", node->each());
PrintIndentedVisit("IN", node->subject()); PrintIndentedVisit("IN", node->subject());
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
@ -1034,8 +1003,6 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
void AstPrinter::VisitForOfStatement(ForOfStatement* node) { void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
IndentedScope indent(this, "FOR OF", node->position()); IndentedScope indent(this, "FOR OF", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
const char* for_type; const char* for_type;
switch (node->type()) { switch (node->type()) {
case IteratorType::kNormal: case IteratorType::kNormal:

View File

@ -232,8 +232,6 @@ class ParserBase {
using FuncNameInferrerState = typename Types::FuncNameInferrer::State; using FuncNameInferrerState = typename Types::FuncNameInferrer::State;
using SourceRange = typename Types::SourceRange; using SourceRange = typename Types::SourceRange;
using SourceRangeScope = typename Types::SourceRangeScope; using SourceRangeScope = typename Types::SourceRangeScope;
using TargetT = typename Types::Target;
using TargetScopeT = typename Types::TargetScope;
// All implementation-specific methods must be called through this. // All implementation-specific methods must be called through this.
Impl* impl() { return static_cast<Impl*>(this); } Impl* impl() { return static_cast<Impl*>(this); }
@ -320,7 +318,6 @@ class ParserBase {
int loop_nesting_depth() const { int loop_nesting_depth() const {
return function_state_->loop_nesting_depth(); return function_state_->loop_nesting_depth();
} }
int GetNextFunctionLiteralId() { return ++function_literal_id_; } int GetNextFunctionLiteralId() { return ++function_literal_id_; }
int GetLastFunctionLiteralId() const { return function_literal_id_; } int GetLastFunctionLiteralId() const { return function_literal_id_; }
@ -370,6 +367,93 @@ class ParserBase {
Scope* const outer_scope_; Scope* const outer_scope_;
}; };
// ---------------------------------------------------------------------------
// Target is a support class to facilitate manipulation of the
// Parser's target_stack_ (the stack of potential 'break' and
// 'continue' statement targets). Upon construction, a new target is
// added; it is removed upon destruction.
// |labels| is a list of all labels that can be used as a target for break.
// |own_labels| is a list of all labels that an iteration statement is
// directly prefixed with, i.e. all the labels that a continue statement in
// the body can use to continue this iteration statement. This is always a
// subset of |labels|.
//
// Example: "l1: { l2: if (b) l3: l4: for (;;) s }"
// labels() of the Block will be l1.
// labels() of the ForStatement will be l2, l3, l4.
// own_labels() of the ForStatement will be l3, l4.
class Target {
public:
enum TargetType { TARGET_FOR_ANONYMOUS, TARGET_FOR_NAMED_ONLY };
Target(ParserBase* parser, BreakableStatementT statement,
ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, TargetType target_type)
: stack_(parser->function_state_->target_stack_address()),
statement_(statement),
labels_(labels),
own_labels_(own_labels),
target_type_(target_type),
previous_(*stack_) {
DCHECK_IMPLIES(Impl::IsIterationStatement(statement_),
target_type == Target::TARGET_FOR_ANONYMOUS);
DCHECK_IMPLIES(!Impl::IsIterationStatement(statement_),
own_labels == nullptr);
*stack_ = this;
}
~Target() { *stack_ = previous_; }
const Target* previous() const { return previous_; }
const BreakableStatementT statement() const { return statement_; }
const ZonePtrList<const AstRawString>* labels() const { return labels_; }
const ZonePtrList<const AstRawString>* own_labels() const {
return own_labels_;
}
bool is_iteration() const { return Impl::IsIterationStatement(statement_); }
bool is_target_for_anonymous() const {
return target_type_ == TARGET_FOR_ANONYMOUS;
}
private:
Target** const stack_;
const BreakableStatementT statement_;
const ZonePtrList<const AstRawString>* const labels_;
const ZonePtrList<const AstRawString>* const own_labels_;
const TargetType target_type_;
Target* const previous_;
};
Target* target_stack() { return *function_state_->target_stack_address(); }
BreakableStatementT LookupBreakTarget(IdentifierT label) {
bool anonymous = impl()->IsNull(label);
for (const Target* t = target_stack(); t != nullptr; t = t->previous()) {
if ((anonymous && t->is_target_for_anonymous()) ||
(!anonymous &&
ContainsLabel(t->labels(),
impl()->GetRawNameFromIdentifier(label)))) {
return t->statement();
}
}
return impl()->NullStatement();
}
IterationStatementT LookupContinueTarget(IdentifierT label) {
bool anonymous = impl()->IsNull(label);
for (const Target* t = target_stack(); t != nullptr; t = t->previous()) {
if (!t->is_iteration()) continue;
DCHECK(t->is_target_for_anonymous());
if (anonymous || ContainsLabel(t->own_labels(),
impl()->GetRawNameFromIdentifier(label))) {
return impl()->AsIterationStatement(t->statement());
}
}
return impl()->NullStatement();
}
class FunctionState final : public BlockState { class FunctionState final : public BlockState {
public: public:
FunctionState(FunctionState** function_state_stack, Scope** scope_stack, FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
@ -427,7 +511,7 @@ class ParserBase {
PointerWithPayload<FunctionState, bool, 1> state_and_prev_value_; PointerWithPayload<FunctionState, bool, 1> state_and_prev_value_;
}; };
class LoopScope { class LoopScope final {
public: public:
explicit LoopScope(FunctionState* function_state) explicit LoopScope(FunctionState* function_state)
: function_state_(function_state) { : function_state_(function_state) {
@ -442,6 +526,8 @@ class ParserBase {
int loop_nesting_depth() const { return loop_nesting_depth_; } int loop_nesting_depth() const { return loop_nesting_depth_; }
Target** target_stack_address() { return &target_stack_; }
private: private:
// Properties count estimation. // Properties count estimation.
int expected_property_count_; int expected_property_count_;
@ -455,6 +541,7 @@ class ParserBase {
FunctionState** function_state_stack_; FunctionState** function_state_stack_;
FunctionState* outer_function_state_; FunctionState* outer_function_state_;
DeclarationScope* scope_; DeclarationScope* scope_;
Target* target_stack_ = nullptr; // for break, continue statements
// A reason, if any, why this function should not be optimized. // A reason, if any, why this function should not be optimized.
BailoutReason dont_optimize_reason_; BailoutReason dont_optimize_reason_;
@ -623,6 +710,46 @@ class ParserBase {
bool is_rest; bool is_rest;
}; };
void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
const AstRawString* label) {
if (ContainsLabel(*labels, label) || TargetStackContainsLabel(label)) {
ReportMessage(MessageTemplate::kLabelRedeclaration, label);
return;
}
// Add {label} to both {labels} and {own_labels}.
if (*labels == nullptr) {
DCHECK_NULL(*own_labels);
*labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
*own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
} else {
if (*own_labels == nullptr) {
*own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
}
}
(*labels)->Add(label, zone());
(*own_labels)->Add(label, zone());
}
bool ContainsLabel(const ZonePtrList<const AstRawString>* labels,
const AstRawString* label) {
DCHECK_NOT_NULL(label);
if (labels != nullptr) {
for (int i = labels->length(); i-- > 0;) {
if (labels->at(i) == label) return true;
}
}
return false;
}
bool TargetStackContainsLabel(const AstRawString* label) {
for (const Target* t = target_stack(); t != nullptr; t = t->previous()) {
if (ContainsLabel(t->labels(), label)) return true;
}
return false;
}
ClassLiteralProperty::Kind ClassPropertyKindFor(ParsePropertyKind kind) { ClassLiteralProperty::Kind ClassPropertyKindFor(ParsePropertyKind kind) {
switch (kind) { switch (kind) {
case ParsePropertyKind::kAccessorGetter: case ParsePropertyKind::kAccessorGetter:
@ -4809,10 +4936,6 @@ void ParserBase<Impl>::ParseStatementList(StatementListT* body,
} }
} }
// Allocate a target stack to use for this set of source elements. This way,
// all scripts and functions get their own target stack thus avoiding illegal
// breaks and continues across functions.
TargetScopeT target_scope(this);
while (peek() != end_token) { while (peek() != end_token) {
StatementT stat = ParseStatementListItem(); StatementT stat = ParseStatementListItem();
if (impl()->IsNull(stat)) return; if (impl()->IsNull(stat)) return;
@ -4932,8 +5055,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
// put the labels there. // put the labels there.
if (labels == nullptr) return ParseTryStatement(); if (labels == nullptr) return ParseTryStatement();
StatementListT statements(pointer_buffer()); StatementListT statements(pointer_buffer());
BlockT result = factory()->NewBlock(false, labels); BlockT result = factory()->NewBlock(false, true);
TargetT target(this, result); Target target(this, result, labels, nullptr,
Target::TARGET_FOR_NAMED_ONLY);
StatementT statement = ParseTryStatement(); StatementT statement = ParseTryStatement();
statements.Add(statement); statements.Add(statement);
result->InitializeStatements(statements, zone()); result->InitializeStatements(statements, zone());
@ -4981,7 +5105,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
// '{' StatementList '}' // '{' StatementList '}'
// Parse the statements and collect escaping labels. // Parse the statements and collect escaping labels.
BlockT body = factory()->NewBlock(false, labels); BlockT body = factory()->NewBlock(false, labels != nullptr);
StatementListT statements(pointer_buffer()); StatementListT statements(pointer_buffer());
CheckStackOverflow(); CheckStackOverflow();
@ -4989,7 +5113,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
{ {
BlockState block_state(zone(), &scope_); BlockState block_state(zone(), &scope_);
scope()->set_start_position(peek_position()); scope()->set_start_position(peek_position());
TargetT target(this, body); Target target(this, body, labels, nullptr, Target::TARGET_FOR_NAMED_ONLY);
Expect(Token::LBRACE); Expect(Token::LBRACE);
@ -5214,11 +5338,11 @@ ParserBase<Impl>::ParseContinueStatement() {
// ECMA allows "eval" or "arguments" as labels even in strict mode. // ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(); label = ParseIdentifier();
} }
IterationStatementT target = impl()->LookupContinueTarget(label); IterationStatementT target = LookupContinueTarget(label);
if (impl()->IsNull(target)) { if (impl()->IsNull(target)) {
// Illegal continue statement. // Illegal continue statement.
MessageTemplate message = MessageTemplate::kIllegalContinue; MessageTemplate message = MessageTemplate::kIllegalContinue;
BreakableStatementT breakable_target = impl()->LookupBreakTarget(label); BreakableStatementT breakable_target = LookupBreakTarget(label);
if (impl()->IsNull(label)) { if (impl()->IsNull(label)) {
message = MessageTemplate::kNoIterationStatement; message = MessageTemplate::kNoIterationStatement;
} else if (impl()->IsNull(breakable_target)) { } else if (impl()->IsNull(breakable_target)) {
@ -5250,11 +5374,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
} }
// Parse labeled break statements that target themselves into // Parse labeled break statements that target themselves into
// empty statements, e.g. 'l1: l2: l3: break l2;' // empty statements, e.g. 'l1: l2: l3: break l2;'
if (!impl()->IsNull(label) && impl()->ContainsLabel(labels, label)) { if (!impl()->IsNull(label) &&
impl()->ContainsLabel(labels, impl()->GetRawNameFromIdentifier(label))) {
ExpectSemicolon(); ExpectSemicolon();
return factory()->EmptyStatement(); return factory()->EmptyStatement();
} }
BreakableStatementT target = impl()->LookupBreakTarget(label); BreakableStatementT target = LookupBreakTarget(label);
if (impl()->IsNull(target)) { if (impl()->IsNull(target)) {
// Illegal break statement. // Illegal break statement.
MessageTemplate message = MessageTemplate::kIllegalBreak; MessageTemplate message = MessageTemplate::kIllegalBreak;
@ -5349,9 +5474,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
// 'do' Statement 'while' '(' Expression ')' ';' // 'do' Statement 'while' '(' Expression ')' ';'
typename FunctionState::LoopScope loop_scope(function_state_); typename FunctionState::LoopScope loop_scope(function_state_);
auto loop = auto loop = factory()->NewDoWhileStatement(peek_position());
factory()->NewDoWhileStatement(labels, own_labels, peek_position()); Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS);
TargetT target(this, loop);
SourceRange body_range; SourceRange body_range;
StatementT body = impl()->NullStatement(); StatementT body = impl()->NullStatement();
@ -5389,8 +5513,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
// 'while' '(' Expression ')' Statement // 'while' '(' Expression ')' Statement
typename FunctionState::LoopScope loop_scope(function_state_); typename FunctionState::LoopScope loop_scope(function_state_);
auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position()); auto loop = factory()->NewWhileStatement(peek_position());
TargetT target(this, loop); Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS);
SourceRange body_range; SourceRange body_range;
StatementT body = impl()->NullStatement(); StatementT body = impl()->NullStatement();
@ -5438,7 +5562,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
// CaseClause :: // CaseClause ::
// 'case' Expression ':' StatementList // 'case' Expression ':' StatementList
// 'default' ':' StatementList // 'default' ':' StatementList
int switch_pos = peek_position(); int switch_pos = peek_position();
Consume(Token::SWITCH); Consume(Token::SWITCH);
@ -5446,14 +5569,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
ExpressionT tag = ParseExpression(); ExpressionT tag = ParseExpression();
Expect(Token::RPAREN); Expect(Token::RPAREN);
auto switch_statement = auto switch_statement = factory()->NewSwitchStatement(tag, switch_pos);
factory()->NewSwitchStatement(labels, tag, switch_pos);
{ {
BlockState cases_block_state(zone(), &scope_); BlockState cases_block_state(zone(), &scope_);
scope()->set_start_position(switch_pos); scope()->set_start_position(switch_pos);
scope()->SetNonlinear(); scope()->SetNonlinear();
TargetT target(this, switch_statement); Target target(this, switch_statement, labels, nullptr,
Target::TARGET_FOR_ANONYMOUS);
bool default_seen = false; bool default_seen = false;
Expect(Token::LBRACE); Expect(Token::LBRACE);
@ -5788,9 +5911,8 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); BlockT init_block = impl()->RewriteForVarInLegacy(*for_info);
auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, auto loop = factory()->NewForEachStatement(for_info->mode, stmt_pos);
stmt_pos); Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS);
TargetT target(this, loop);
ExpressionT enumerable = impl()->NullExpression(); ExpressionT enumerable = impl()->NullExpression();
if (for_info->mode == ForEachStatement::ITERATE) { if (for_info->mode == ForEachStatement::ITERATE) {
@ -5852,9 +5974,8 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels) { ZonePtrList<const AstRawString>* own_labels) {
auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, auto loop = factory()->NewForEachStatement(for_info->mode, stmt_pos);
stmt_pos); Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS);
TargetT target(this, loop);
ExpressionT enumerable = impl()->NullExpression(); ExpressionT enumerable = impl()->NullExpression();
if (for_info->mode == ForEachStatement::ITERATE) { if (for_info->mode == ForEachStatement::ITERATE) {
@ -5943,8 +6064,8 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond,
StatementT* next, StatementT* body) { StatementT* next, StatementT* body) {
CheckStackOverflow(); CheckStackOverflow();
ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos); ForStatementT loop = factory()->NewForStatement(stmt_pos);
TargetT target(this, loop); Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS);
if (peek() != Token::SEMICOLON) { if (peek() != Token::SEMICOLON) {
*cond = ParseExpression(); *cond = ParseExpression();
@ -5988,13 +6109,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
scope()->set_start_position(scanner()->location().beg_pos); scope()->set_start_position(scanner()->location().beg_pos);
scope()->set_is_hidden(); scope()->set_is_hidden();
auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos, auto loop = factory()->NewForOfStatement(stmt_pos, IteratorType::kAsync);
IteratorType::kAsync);
// Two suspends: one for next() and one for return() // Two suspends: one for next() and one for return()
function_state_->AddSuspend(); function_state_->AddSuspend();
function_state_->AddSuspend(); function_state_->AddSuspend();
TargetT target(this, loop); Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS);
ExpressionT each_variable = impl()->NullExpression(); ExpressionT each_variable = impl()->NullExpression();

View File

@ -427,7 +427,6 @@ Parser::Parser(ParseInfo* info)
reusable_preparser_(nullptr), reusable_preparser_(nullptr),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
source_range_map_(info->source_range_map()), source_range_map_(info->source_range_map()),
target_stack_(nullptr),
total_preparse_skipped_(0), total_preparse_skipped_(0),
consumed_preparse_data_(info->consumed_preparse_data()), consumed_preparse_data_(info->consumed_preparse_data()),
preparse_data_buffer_(), preparse_data_buffer_(),
@ -566,7 +565,6 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
// isolate will be nullptr. // isolate will be nullptr.
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr); DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
DCHECK_NULL(scope_); DCHECK_NULL(scope_);
DCHECK_NULL(target_stack_);
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY); ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
ResetFunctionLiteralId(); ResetFunctionLiteralId();
@ -681,9 +679,6 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
info->set_max_function_literal_id(GetLastFunctionLiteralId()); info->set_max_function_literal_id(GetLastFunctionLiteralId());
// Make sure the target stack is empty.
DCHECK_NULL(target_stack_);
if (has_error()) return nullptr; if (has_error()) return nullptr;
RecordFunctionLiteralSourceRange(result); RecordFunctionLiteralSourceRange(result);
@ -848,7 +843,6 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr); DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
DCHECK_NOT_NULL(raw_name); DCHECK_NOT_NULL(raw_name);
DCHECK_NULL(scope_); DCHECK_NULL(scope_);
DCHECK_NULL(target_stack_);
DCHECK(ast_value_factory()); DCHECK(ast_value_factory());
fni_.PushEnclosingName(raw_name); fni_.PushEnclosingName(raw_name);
@ -972,8 +966,6 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
} }
} }
// Make sure the target stack is empty.
DCHECK_NULL(target_stack_);
DCHECK_IMPLIES(result, DCHECK_IMPLIES(result,
info->function_literal_id() == result->function_literal_id()); info->function_literal_id() == result->function_literal_id());
return result; return result;
@ -1601,43 +1593,6 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos) {
pos); pos);
} }
void Parser::DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
const AstRawString* label) {
// TODO(1240780): We don't check for redeclaration of labels during preparsing
// since keeping track of the set of active labels requires nontrivial changes
// to the way scopes are structured. However, these are probably changes we
// want to make later anyway so we should go back and fix this then.
if (ContainsLabel(*labels, label) || TargetStackContainsLabel(label)) {
ReportMessage(MessageTemplate::kLabelRedeclaration, label);
return;
}
// Add {label} to both {labels} and {own_labels}.
if (*labels == nullptr) {
DCHECK_NULL(*own_labels);
*labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
*own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
} else {
if (*own_labels == nullptr) {
*own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
}
}
(*labels)->Add(label, zone());
(*own_labels)->Add(label, zone());
}
bool Parser::ContainsLabel(ZonePtrList<const AstRawString>* labels,
const AstRawString* label) {
DCHECK_NOT_NULL(label);
if (labels != nullptr) {
for (int i = labels->length(); i-- > 0;) {
if (labels->at(i) == label) return true;
}
}
return false;
}
Block* Parser::IgnoreCompletion(Statement* statement) { Block* Parser::IgnoreCompletion(Statement* statement) {
Block* block = factory()->NewBlock(1, true); Block* block = factory()->NewBlock(1, true);
block->statements()->Add(statement, zone()); block->statements()->Add(statement, zone());
@ -2073,8 +2028,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// explicit break target, instead handing it directly to those nodes that // explicit break target, instead handing it directly to those nodes that
// need to know about it. This should be safe because we don't run any code // need to know about it. This should be safe because we don't run any code
// in this function that looks up break targets. // in this function that looks up break targets.
ForStatement* outer_loop = ForStatement* outer_loop = factory()->NewForStatement(kNoSourcePosition);
factory()->NewForStatement(nullptr, nullptr, kNoSourcePosition);
outer_block->statements()->Add(outer_loop, zone()); outer_block->statements()->Add(outer_loop, zone());
outer_block->set_scope(scope()); outer_block->set_scope(scope());
@ -3065,40 +3019,6 @@ void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Parser support // Parser support
bool Parser::TargetStackContainsLabel(const AstRawString* label) {
for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) {
if (ContainsLabel(t->statement()->labels(), label)) return true;
}
return false;
}
BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label) {
bool anonymous = label == nullptr;
for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) {
BreakableStatement* stat = t->statement();
if ((anonymous && stat->is_target_for_anonymous()) ||
(!anonymous && ContainsLabel(stat->labels(), label))) {
return stat;
}
}
return nullptr;
}
IterationStatement* Parser::LookupContinueTarget(const AstRawString* label) {
bool anonymous = label == nullptr;
for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) {
IterationStatement* stat = t->statement()->AsIterationStatement();
if (stat == nullptr) continue;
DCHECK(stat->is_target_for_anonymous());
if (anonymous || ContainsLabel(stat->own_labels(), label)) {
return stat;
}
if (ContainsLabel(stat->labels(), label)) break;
}
return nullptr;
}
void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) { void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) {
Handle<String> source_url = scanner_.SourceUrl(isolate); Handle<String> source_url = scanner_.SourceUrl(isolate);
if (!source_url.is_null()) { if (!source_url.is_null()) {

View File

@ -122,8 +122,6 @@ struct ParserTypes<Parser> {
using FuncNameInferrer = v8::internal::FuncNameInferrer; using FuncNameInferrer = v8::internal::FuncNameInferrer;
using SourceRange = v8::internal::SourceRange; using SourceRange = v8::internal::SourceRange;
using SourceRangeScope = v8::internal::SourceRangeScope; using SourceRangeScope = v8::internal::SourceRangeScope;
using Target = ParserTarget;
using TargetScope = ParserTargetScope;
}; };
class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
@ -279,11 +277,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
}; };
ZonePtrList<const NamedImport>* ParseNamedImports(int pos); ZonePtrList<const NamedImport>* ParseNamedImports(int pos);
Statement* BuildInitializationBlock(DeclarationParsingResult* parsing_result); Statement* BuildInitializationBlock(DeclarationParsingResult* parsing_result);
void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
const AstRawString* label);
bool ContainsLabel(ZonePtrList<const AstRawString>* labels,
const AstRawString* label);
Expression* RewriteReturn(Expression* return_value, int pos); Expression* RewriteReturn(Expression* return_value, int pos);
Statement* RewriteSwitchStatement(SwitchStatement* switch_statement, Statement* RewriteSwitchStatement(SwitchStatement* switch_statement,
Scope* scope); Scope* scope);
@ -407,10 +400,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Scope* declaration_scope, bool* was_added, int var_begin_pos, Scope* declaration_scope, bool* was_added, int var_begin_pos,
int var_end_pos = kNoSourcePosition); int var_end_pos = kNoSourcePosition);
bool TargetStackContainsLabel(const AstRawString* label);
BreakableStatement* LookupBreakTarget(const AstRawString* label);
IterationStatement* LookupContinueTarget(const AstRawString* label);
// Factory methods. // Factory methods.
FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super, FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super,
int pos, int end_pos); int pos, int end_pos);
@ -727,6 +716,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return arg; return arg;
} }
IterationStatement* AsIterationStatement(BreakableStatement* s) {
return s->AsIterationStatement();
}
void ReportUnexpectedTokenAt( void ReportUnexpectedTokenAt(
Scanner::Location location, Token::Value token, Scanner::Location location, Token::Value token,
MessageTemplate message = MessageTemplate::kUnexpectedToken); MessageTemplate message = MessageTemplate::kUnexpectedToken);
@ -750,6 +743,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return subject == nullptr; return subject == nullptr;
} }
V8_INLINE static bool IsIterationStatement(Statement* subject) {
return subject->AsIterationStatement() != nullptr;
}
// Non-null empty string. // Non-null empty string.
V8_INLINE const AstRawString* EmptyIdentifierString() const { V8_INLINE const AstRawString* EmptyIdentifierString() const {
return ast_value_factory()->empty_string(); return ast_value_factory()->empty_string();
@ -1047,9 +1044,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SourceRangeMap* source_range_map_ = nullptr; SourceRangeMap* source_range_map_ = nullptr;
friend class ParserTarget;
friend class ParserTargetScope; friend class ParserTargetScope;
ParserTarget* target_stack_; // for break, continue statements
ScriptCompiler::CompileOptions compile_options_; ScriptCompiler::CompileOptions compile_options_;
@ -1072,47 +1067,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
int parameters_end_pos_; int parameters_end_pos_;
}; };
// ----------------------------------------------------------------------------
// Target is a support class to facilitate manipulation of the
// Parser's target_stack_ (the stack of potential 'break' and
// 'continue' statement targets). Upon construction, a new target is
// added; it is removed upon destruction.
class ParserTarget {
public:
ParserTarget(ParserBase<Parser>* parser, BreakableStatement* statement)
: variable_(&parser->impl()->target_stack_),
statement_(statement),
previous_(parser->impl()->target_stack_) {
parser->impl()->target_stack_ = this;
}
~ParserTarget() { *variable_ = previous_; }
ParserTarget* previous() { return previous_; }
BreakableStatement* statement() { return statement_; }
private:
ParserTarget** variable_;
BreakableStatement* statement_;
ParserTarget* previous_;
};
class ParserTargetScope {
public:
explicit ParserTargetScope(ParserBase<Parser>* parser)
: variable_(&parser->impl()->target_stack_),
previous_(parser->impl()->target_stack_) {
parser->impl()->target_stack_ = nullptr;
}
~ParserTargetScope() { *variable_ = previous_; }
private:
ParserTarget** variable_;
ParserTarget* previous_;
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -416,6 +416,10 @@ class PreParserStatement {
return PreParserStatement(kUnknownStatement); return PreParserStatement(kUnknownStatement);
} }
static PreParserStatement Iteration() {
return PreParserStatement(kIterationStatement);
}
static PreParserStatement Null() { static PreParserStatement Null() {
return PreParserStatement(kNullStatement); return PreParserStatement(kNullStatement);
} }
@ -450,6 +454,8 @@ class PreParserStatement {
bool IsNull() { return code_ == kNullStatement; } bool IsNull() { return code_ == kNullStatement; }
bool IsIterationStatement() { return code_ == kIterationStatement; }
bool IsEmptyStatement() { bool IsEmptyStatement() {
DCHECK(!IsNull()); DCHECK(!IsNull());
return code_ == kEmptyStatement; return code_ == kEmptyStatement;
@ -478,6 +484,7 @@ class PreParserStatement {
kEmptyStatement, kEmptyStatement,
kUnknownStatement, kUnknownStatement,
kJumpStatement, kJumpStatement,
kIterationStatement,
kStringLiteralExpressionStatement, kStringLiteralExpressionStatement,
}; };
@ -691,8 +698,7 @@ class PreParserFactory {
return PreParserBlock::Default(); return PreParserBlock::Default();
} }
PreParserBlock NewBlock(bool ignore_completion_value, PreParserBlock NewBlock(bool ignore_completion_value, bool is_breakable) {
ZonePtrList<const AstRawString>* labels) {
return PreParserBlock::Default(); return PreParserBlock::Default();
} }
@ -737,20 +743,15 @@ class PreParserFactory {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
PreParserStatement NewDoWhileStatement( PreParserStatement NewDoWhileStatement(int pos) {
ZonePtrList<const AstRawString>* labels, return PreParserStatement::Iteration();
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default();
} }
PreParserStatement NewWhileStatement( PreParserStatement NewWhileStatement(int pos) {
ZonePtrList<const AstRawString>* labels, return PreParserStatement::Iteration();
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default();
} }
PreParserStatement NewSwitchStatement(ZonePtrList<const AstRawString>* labels, PreParserStatement NewSwitchStatement(const PreParserExpression& tag,
const PreParserExpression& tag,
int pos) { int pos) {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
@ -761,23 +762,17 @@ class PreParserFactory {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
PreParserStatement NewForStatement( PreParserStatement NewForStatement(int pos) {
ZonePtrList<const AstRawString>* labels, return PreParserStatement::Iteration();
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default();
} }
PreParserStatement NewForEachStatement( PreParserStatement NewForEachStatement(ForEachStatement::VisitMode visit_mode,
ForEachStatement::VisitMode visit_mode, int pos) {
ZonePtrList<const AstRawString>* labels, return PreParserStatement::Iteration();
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default();
} }
PreParserStatement NewForOfStatement( PreParserStatement NewForOfStatement(int pos, IteratorType type) {
ZonePtrList<const AstRawString>* labels, return PreParserStatement::Iteration();
ZonePtrList<const AstRawString>* own_labels, int pos, IteratorType type) {
return PreParserStatement::Default();
} }
PreParserExpression NewCallRuntime( PreParserExpression NewCallRuntime(
@ -819,17 +814,6 @@ class PreParserFormalParameters : public FormalParametersBase {
bool strict_parameter_error_ = false; bool strict_parameter_error_ = false;
}; };
class PreParserTarget {
public:
PreParserTarget(ParserBase<PreParser>* preparser,
PreParserStatement statement) {}
};
class PreParserTargetScope {
public:
explicit PreParserTargetScope(ParserBase<PreParser>* preparser) {}
};
class PreParserFuncNameInferrer { class PreParserFuncNameInferrer {
public: public:
explicit PreParserFuncNameInferrer(AstValueFactory* avf) {} explicit PreParserFuncNameInferrer(AstValueFactory* avf) {}
@ -904,8 +888,6 @@ struct ParserTypes<PreParser> {
using FuncNameInferrer = PreParserFuncNameInferrer; using FuncNameInferrer = PreParserFuncNameInferrer;
using SourceRange = PreParserSourceRange; using SourceRange = PreParserSourceRange;
using SourceRangeScope = PreParserSourceRangeScope; using SourceRangeScope = PreParserSourceRangeScope;
using Target = PreParserTarget;
using TargetScope = PreParserTargetScope;
}; };
@ -1070,18 +1052,6 @@ class PreParser : public ParserBase<PreParser> {
const PreParserScopedStatementList* body, PreParserStatement block, const PreParserScopedStatementList* body, PreParserStatement block,
const PreParserExpression& return_value) {} const PreParserExpression& return_value) {}
V8_INLINE void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
const AstRawString* label) {
DCHECK(!parsing_module_ || !label->IsOneByteEqualTo("await"));
}
// TODO(nikolaos): The preparser currently does not keep track of labels.
V8_INLINE bool ContainsLabel(ZonePtrList<const AstRawString>* labels,
const PreParserIdentifier& label) {
return false;
}
V8_INLINE PreParserExpression V8_INLINE PreParserExpression
RewriteReturn(const PreParserExpression& return_value, int pos) { RewriteReturn(const PreParserExpression& return_value, int pos) {
return return_value; return return_value;
@ -1186,17 +1156,6 @@ class PreParser : public ParserBase<PreParser> {
bool IdentifierEquals(const PreParserIdentifier& identifier, bool IdentifierEquals(const PreParserIdentifier& identifier,
const AstRawString* other); const AstRawString* other);
// TODO(nikolaos): The preparser currently does not keep track of labels
// and targets.
V8_INLINE PreParserStatement
LookupBreakTarget(const PreParserIdentifier& label) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement
LookupContinueTarget(const PreParserIdentifier& label) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement DeclareFunction( V8_INLINE PreParserStatement DeclareFunction(
const PreParserIdentifier& variable_name, const PreParserIdentifier& variable_name,
const PreParserExpression& function, VariableMode mode, VariableKind kind, const PreParserExpression& function, VariableMode mode, VariableKind kind,
@ -1498,7 +1457,7 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void ReportMessageAt(Scanner::Location source_location, V8_INLINE void ReportMessageAt(Scanner::Location source_location,
MessageTemplate message, MessageTemplate message,
const PreParserIdentifier& arg) { const PreParserIdentifier& arg) {
UNREACHABLE(); ReportMessageAt(source_location, message, arg.string_);
} }
void ReportMessageAt(Scanner::Location source_location, void ReportMessageAt(Scanner::Location source_location,
@ -1512,6 +1471,8 @@ class PreParser : public ParserBase<PreParser> {
return arg.string_; return arg.string_;
} }
PreParserStatement AsIterationStatement(PreParserStatement s) { return s; }
// "null" return type creators. // "null" return type creators.
V8_INLINE static PreParserIdentifier NullIdentifier() { V8_INLINE static PreParserIdentifier NullIdentifier() {
return PreParserIdentifier::Null(); return PreParserIdentifier::Null();
@ -1538,6 +1499,10 @@ class PreParser : public ParserBase<PreParser> {
return subject.IsNull(); return subject.IsNull();
} }
V8_INLINE static bool IsIterationStatement(PreParserStatement subject) {
return subject.IsIterationStatement();
}
V8_INLINE PreParserIdentifier EmptyIdentifierString() const { V8_INLINE PreParserIdentifier EmptyIdentifierString() const {
PreParserIdentifier result = PreParserIdentifier::Default(); PreParserIdentifier result = PreParserIdentifier::Default();
result.string_ = ast_value_factory()->empty_string(); result.string_ = ast_value_factory()->empty_string();

View File

@ -146,7 +146,7 @@ void Processor::VisitBlock(Block* node) {
// returns 'undefined'. To obtain the same behavior with v8, we need // returns 'undefined'. To obtain the same behavior with v8, we need
// to prevent rewriting in that case. // to prevent rewriting in that case.
if (!node->ignore_completion_value()) { if (!node->ignore_completion_value()) {
BreakableScope scope(this, node->labels() != nullptr); BreakableScope scope(this, node->is_breakable());
Process(node->statements()); Process(node->statements());
} }
replacement_ = node; replacement_ = node;

View File

@ -3258,25 +3258,6 @@ TEST(FuncNameInferrerEscaped) {
} }
TEST(RegressionLazyFunctionWithErrorWithArg) {
// Test only applies when lazy parsing.
if (!i::FLAG_lazy) return;
// The bug occurred when a lazy function had an error which requires a
// parameter (such as "unknown label" here). The error message was processed
// before the AstValueFactory containing the error message string was
// internalized.
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
LocalContext env;
i::FLAG_lazy = true;
CompileRun("function this_is_lazy() {\n"
" break p;\n"
"}\n"
"this_is_lazy();\n");
}
TEST(SerializationOfMaybeAssignmentFlag) { TEST(SerializationOfMaybeAssignmentFlag) {
i::Isolate* isolate = CcTest::i_isolate(); i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory(); i::Factory* factory = isolate->factory();

View File

@ -1,32 +1,14 @@
getPossibleBreakpoints should not crash during lazy compilation (crbug.com/715334) getPossibleBreakpoints should not crash during lazy compilation (crbug.com/715334)
{
method : Debugger.scriptParsed
params : {
endColumn : 21
endLine : 2
executionContextId : <executionContextId>
hasSourceURL : true
hash : 124cb0278e3aa9f250651d433cdefeb5618c7202
isLiveEdit : false
isModule : false
length : 52
scriptId : <scriptId>
sourceMapURL :
startColumn : 0
startLine : 0
url : test.js
}
}
{ {
method : Debugger.scriptFailedToParse method : Debugger.scriptFailedToParse
params : { params : {
endColumn : 21 endColumn : 23
endLine : 2 endLine : 2
executionContextId : <executionContextId> executionContextId : <executionContextId>
hasSourceURL : true hasSourceURL : true
hash : 124cb0278e3aa9f250651d433cdefeb5618c7202 hash : 1bce5d0c4da4d13a3ea6e6f35ea0f34705c26ba4
isModule : false isModule : false
length : 52 length : 56
scriptId : <scriptId> scriptId : <scriptId>
sourceMapURL : sourceMapURL :
startColumn : 0 startColumn : 0
@ -34,7 +16,6 @@ getPossibleBreakpoints should not crash during lazy compilation (crbug.com/71533
url : test.js url : test.js
} }
} }
One script is reported twice
{ {
id : <messageId> id : <messageId>
result : { result : {

View File

@ -3,26 +3,16 @@
// found in the LICENSE file. // found in the LICENSE file.
let {session, contextGroup, Protocol} = InspectorTest.start('getPossibleBreakpoints should not crash during lazy compilation (crbug.com/715334)'); let {session, contextGroup, Protocol} = InspectorTest.start('getPossibleBreakpoints should not crash during lazy compilation (crbug.com/715334)');
(async function test() {
contextGroup.addScript(` Protocol.Debugger.enable();
function test() { continue; } Protocol.Debugger.onScriptFailedToParse(async msg => {
//# sourceURL=test.js`); InspectorTest.logMessage(msg);
const response = await Protocol.Debugger.getPossibleBreakpoints({
(async function test() { start: {scriptId: msg.params.scriptId, lineNumber: 0, columnNumber: 0}});
Protocol.Debugger.enable(); InspectorTest.logMessage(response);
let script = await Protocol.Debugger.onceScriptParsed(); InspectorTest.completeTest();
InspectorTest.logMessage(script); });
let scriptId = script.params.scriptId; contextGroup.addScript(`
Protocol.Debugger.onScriptFailedToParse(msg => { function test() { continue; }
InspectorTest.logMessage(msg); //# sourceURL=test.js`);
if (msg.params.scriptId !== script.params.scriptId) {
InspectorTest.log('Failed script to parse event has different scriptId');
} else {
InspectorTest.log('One script is reported twice');
}
});
let response = await Protocol.Debugger.getPossibleBreakpoints({
start: {scriptId, lineNumber: 0, columnNumber: 0}});
InspectorTest.logMessage(response);
InspectorTest.completeTest();
})(); })();

View File

@ -7,10 +7,7 @@
function outer() { function outer() {
"use asm"; "use asm";
function inner() { function inner() {
switch (1) { /f(/
case 0:
break foo;
}
} }
} }
outer(); outer();

View File

@ -0,0 +1,8 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
assertThrows("function f() { break }", SyntaxError);
assertThrows("function f() { break a }", SyntaxError);
assertThrows("function f() { continue }", SyntaxError);
assertThrows("function f() { continue a }", SyntaxError);