diff --git a/src/ast/ast.cc b/src/ast/ast.cc index 095ea67029..031d64ad51 100644 --- a/src/ast/ast.cc +++ b/src/ast/ast.cc @@ -1103,20 +1103,5 @@ const char* CallRuntime::debug_name() { #endif // DEBUG } -#define RETURN_LABELS(NodeType) \ - case k##NodeType: \ - return static_cast(this)->labels(); - -ZonePtrList* BreakableStatement::labels() const { - switch (node_type()) { - BREAKABLE_NODE_LIST(RETURN_LABELS) - ITERATION_NODE_LIST(RETURN_LABELS) - default: - UNREACHABLE(); - } -} - -#undef RETURN_LABELS - } // namespace internal } // namespace v8 diff --git a/src/ast/ast.h b/src/ast/ast.h index f5eb536872..f55a653f65 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -295,62 +295,28 @@ class FailureExpression : public Expression { // V8's notion of BreakableStatement does not correspond to the notion of // BreakableStatement in ECMAScript. In V8, the idea is that a // BreakableStatement is a statement that can be the target of a break -// statement. The BreakableStatement AST node carries a list of labels, any of -// which can be used as an argument to the break statement in order to target -// it. +// statement. // -// 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 // that we implement breaks targeting other statement forms as breaks targeting // 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 // can't observe the difference. -// -// This optimization makes it harder to detect invalid continue labels, see the -// need for own_labels in IterationStatement. -// +// TODO(verwaest): Reconsider this optimization now that the tracking of labels +// is done at runtime. 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* labels() const; - - // Testers. - bool is_target_for_anonymous() const { - return BreakableTypeField::decode(bit_field_) == TARGET_FOR_ANONYMOUS; - } - - private: - using BreakableTypeField = Statement::NextBitField; - protected: - BreakableStatement(BreakableType breakable_type, int position, NodeType type) - : Statement(position, type) { - bit_field_ |= BreakableTypeField::encode(breakable_type); - } - - template - using NextBitField = BreakableTypeField::Next; + BreakableStatement(int position, NodeType type) : Statement(position, type) {} }; -class Block : public BreakableStatement { +class Block final : public BreakableStatement { public: ZonePtrList* statements() { return &statements_; } bool ignore_completion_value() const { return IgnoreCompletionField::decode(bit_field_); } - - inline ZonePtrList* labels() const; + bool is_breakable() const { return IsBreakableField::decode(bit_field_); } Scope* scope() const { return scope_; } void set_scope(Scope* scope) { scope_ = scope; } @@ -368,49 +334,22 @@ class Block : public BreakableStatement { Scope* scope_; using IgnoreCompletionField = BreakableStatement::NextBitField; - using IsLabeledField = IgnoreCompletionField::Next; + using IsBreakableField = IgnoreCompletionField::Next; protected: - Block(Zone* zone, ZonePtrList* labels, int capacity, - bool ignore_completion_value) - : BreakableStatement(TARGET_FOR_NAMED_ONLY, kNoSourcePosition, kBlock), + Block(Zone* zone, int capacity, bool ignore_completion_value, + bool is_breakable) + : BreakableStatement(kNoSourcePosition, kBlock), statements_(capacity, zone), scope_(nullptr) { bit_field_ |= IgnoreCompletionField::encode(ignore_completion_value) | - IsLabeledField::encode(labels != nullptr); + IsBreakableField::encode(is_breakable); } - Block(ZonePtrList* labels, bool ignore_completion_value) - : Block(nullptr, labels, 0, ignore_completion_value) {} + Block(bool ignore_completion_value, bool is_breakable) + : Block(nullptr, 0, ignore_completion_value, is_breakable) {} }; -class LabeledBlock final : public Block { - private: - friend class AstNodeFactory; - friend class Block; - - LabeledBlock(Zone* zone, ZonePtrList* 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* labels, - bool ignore_completion_value) - : LabeledBlock(nullptr, labels, 0, ignore_completion_value) {} - - ZonePtrList* labels_; -}; - -inline ZonePtrList* Block::labels() const { - if (IsLabeledField::decode(bit_field_)) { - return static_cast(this)->labels_; - } - return nullptr; -} - class Declaration : public AstNode { public: using List = base::ThreadedList; @@ -491,31 +430,12 @@ class IterationStatement : public BreakableStatement { Statement* body() const { return body_; } void set_body(Statement* s) { body_ = s; } - ZonePtrList* 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* own_labels() const { return own_labels_; } - protected: - IterationStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos, - NodeType type) - : BreakableStatement(TARGET_FOR_ANONYMOUS, pos, type), - labels_(labels), - own_labels_(own_labels), - body_(nullptr) {} + IterationStatement(int pos, NodeType type) + : BreakableStatement(pos, type), body_(nullptr) {} void Initialize(Statement* body) { body_ = body; } private: - ZonePtrList* labels_; - ZonePtrList* own_labels_; Statement* body_; }; @@ -532,10 +452,8 @@ class DoWhileStatement final : public IterationStatement { private: friend class AstNodeFactory; - DoWhileStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos) - : IterationStatement(labels, own_labels, pos, kDoWhileStatement), - cond_(nullptr) {} + explicit DoWhileStatement(int pos) + : IterationStatement(pos, kDoWhileStatement), cond_(nullptr) {} Expression* cond_; }; @@ -553,10 +471,8 @@ class WhileStatement final : public IterationStatement { private: friend class AstNodeFactory; - WhileStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos) - : IterationStatement(labels, own_labels, pos, kWhileStatement), - cond_(nullptr) {} + explicit WhileStatement(int pos) + : IterationStatement(pos, kWhileStatement), cond_(nullptr) {} Expression* cond_; }; @@ -579,9 +495,8 @@ class ForStatement final : public IterationStatement { private: friend class AstNodeFactory; - ForStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos) - : IterationStatement(labels, own_labels, pos, kForStatement), + explicit ForStatement(int pos) + : IterationStatement(pos, kForStatement), init_(nullptr), cond_(nullptr), next_(nullptr) {} @@ -617,12 +532,8 @@ class ForEachStatement : public IterationStatement { protected: friend class AstNodeFactory; - ForEachStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos, - NodeType type) - : IterationStatement(labels, own_labels, pos, type), - each_(nullptr), - subject_(nullptr) {} + ForEachStatement(int pos, NodeType type) + : IterationStatement(pos, type), each_(nullptr), subject_(nullptr) {} Expression* each_; Expression* subject_; @@ -632,9 +543,7 @@ class ForInStatement final : public ForEachStatement { private: friend class AstNodeFactory; - ForInStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos) - : ForEachStatement(labels, own_labels, pos, kForInStatement) {} + explicit ForInStatement(int pos) : ForEachStatement(pos, kForInStatement) {} }; enum class IteratorType { kNormal, kAsync }; @@ -645,11 +554,8 @@ class ForOfStatement final : public ForEachStatement { private: friend class AstNodeFactory; - ForOfStatement(ZonePtrList* labels, - ZonePtrList* own_labels, int pos, - IteratorType type) - : ForEachStatement(labels, own_labels, pos, kForOfStatement), - type_(type) {} + ForOfStatement(int pos, IteratorType type) + : ForEachStatement(pos, kForOfStatement), type_(type) {} IteratorType type_; }; @@ -777,8 +683,6 @@ class CaseClause final : public ZoneObject { class SwitchStatement final : public BreakableStatement { public: - ZonePtrList* labels() const { return labels_; } - Expression* tag() const { return tag_; } void set_tag(Expression* t) { tag_ = t; } @@ -787,14 +691,9 @@ class SwitchStatement final : public BreakableStatement { private: friend class AstNodeFactory; - SwitchStatement(Zone* zone, ZonePtrList* labels, - Expression* tag, int pos) - : BreakableStatement(TARGET_FOR_ANONYMOUS, pos, kSwitchStatement), - labels_(labels), - tag_(tag), - cases_(4, zone) {} + SwitchStatement(Zone* zone, Expression* tag, int pos) + : BreakableStatement(pos, kSwitchStatement), tag_(tag), cases_(4, zone) {} - ZonePtrList* labels_; Expression* tag_; ZonePtrList cases_; }; @@ -2824,59 +2723,46 @@ class AstNodeFactory final { } 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, - ZonePtrList* labels) { - return labels != nullptr - ? new (zone_) LabeledBlock(labels, ignore_completion_value) - : new (zone_) Block(labels, ignore_completion_value); + Block* NewBlock(bool ignore_completion_value, bool is_breakable) { + return new (zone_) Block(ignore_completion_value, is_breakable); } Block* NewBlock(bool ignore_completion_value, const ScopedPtrList& statements) { - Block* result = NewBlock(ignore_completion_value, nullptr); + Block* result = NewBlock(ignore_completion_value, false); result->InitializeStatements(statements, zone_); return result; } -#define STATEMENT_WITH_LABELS(NodeType) \ - NodeType* New##NodeType(ZonePtrList* labels, \ - ZonePtrList* own_labels, \ - int pos) { \ - return new (zone_) NodeType(labels, own_labels, pos); \ - } - STATEMENT_WITH_LABELS(DoWhileStatement) - STATEMENT_WITH_LABELS(WhileStatement) - STATEMENT_WITH_LABELS(ForStatement) -#undef STATEMENT_WITH_LABELS +#define STATEMENT_WITH_POSITION(NodeType) \ + NodeType* New##NodeType(int pos) { return new (zone_) NodeType(pos); } + STATEMENT_WITH_POSITION(DoWhileStatement) + STATEMENT_WITH_POSITION(WhileStatement) + STATEMENT_WITH_POSITION(ForStatement) +#undef STATEMENT_WITH_POSITION - SwitchStatement* NewSwitchStatement(ZonePtrList* labels, - Expression* tag, int pos) { - return new (zone_) SwitchStatement(zone_, labels, tag, pos); + SwitchStatement* NewSwitchStatement(Expression* tag, int pos) { + return new (zone_) SwitchStatement(zone_, tag, pos); } - ForEachStatement* NewForEachStatement( - ForEachStatement::VisitMode visit_mode, - ZonePtrList* labels, - ZonePtrList* own_labels, int pos) { + ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode, + int pos) { switch (visit_mode) { case ForEachStatement::ENUMERATE: { - return new (zone_) ForInStatement(labels, own_labels, pos); + return new (zone_) ForInStatement(pos); } case ForEachStatement::ITERATE: { - return new (zone_) - ForOfStatement(labels, own_labels, pos, IteratorType::kNormal); + return new (zone_) ForOfStatement(pos, IteratorType::kNormal); } } UNREACHABLE(); } - ForOfStatement* NewForOfStatement(ZonePtrList* labels, - ZonePtrList* own_labels, - int pos, IteratorType type) { - return new (zone_) ForOfStatement(labels, own_labels, pos, type); + ForOfStatement* NewForOfStatement(int pos, IteratorType type) { + return new (zone_) ForOfStatement(pos, type); } ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) { diff --git a/src/ast/prettyprinter.cc b/src/ast/prettyprinter.cc index 2f9ba3e29a..54cce2eda7 100644 --- a/src/ast/prettyprinter.cc +++ b/src/ast/prettyprinter.cc @@ -659,15 +659,6 @@ void AstPrinter::Print(const char* format, ...) { } } -void AstPrinter::PrintLabels(ZonePtrList* 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) { switch (literal->type()) { case Literal::kString: @@ -819,16 +810,6 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var, } } -void AstPrinter::PrintLabelsIndented(ZonePtrList* 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) { if (node != nullptr) { IndentedScope indent(this, s, node->position()); @@ -902,7 +883,6 @@ void AstPrinter::VisitBlock(Block* node) { const char* block_txt = node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK"; IndentedScope indent(this, block_txt, node->position()); - PrintLabelsIndented(node->labels()); PrintStatements(node->statements()); } @@ -953,13 +933,11 @@ void AstPrinter::VisitIfStatement(IfStatement* node) { void AstPrinter::VisitContinueStatement(ContinueStatement* node) { IndentedScope indent(this, "CONTINUE", node->position()); - PrintLabelsIndented(node->target()->labels()); } void AstPrinter::VisitBreakStatement(BreakStatement* node) { IndentedScope indent(this, "BREAK", node->position()); - PrintLabelsIndented(node->target()->labels()); } @@ -978,7 +956,6 @@ void AstPrinter::VisitWithStatement(WithStatement* node) { void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { IndentedScope indent(this, "SWITCH", node->position()); - PrintLabelsIndented(node->labels()); PrintIndentedVisit("TAG", node->tag()); for (CaseClause* clause : *node->cases()) { if (clause->is_default()) { @@ -995,8 +972,6 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { IndentedScope indent(this, "DO", node->position()); - PrintLabelsIndented(node->labels()); - PrintLabelsIndented(node->own_labels(), "OWN "); PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("COND", node->cond()); } @@ -1004,8 +979,6 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { void AstPrinter::VisitWhileStatement(WhileStatement* node) { IndentedScope indent(this, "WHILE", node->position()); - PrintLabelsIndented(node->labels()); - PrintLabelsIndented(node->own_labels(), "OWN "); PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("BODY", node->body()); } @@ -1013,8 +986,6 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) { void AstPrinter::VisitForStatement(ForStatement* node) { IndentedScope indent(this, "FOR", node->position()); - PrintLabelsIndented(node->labels()); - PrintLabelsIndented(node->own_labels(), "OWN "); if (node->init()) PrintIndentedVisit("INIT", node->init()); if (node->cond()) PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("BODY", node->body()); @@ -1024,8 +995,6 @@ void AstPrinter::VisitForStatement(ForStatement* node) { void AstPrinter::VisitForInStatement(ForInStatement* node) { IndentedScope indent(this, "FOR IN", node->position()); - PrintLabelsIndented(node->labels()); - PrintLabelsIndented(node->own_labels(), "OWN "); PrintIndentedVisit("FOR", node->each()); PrintIndentedVisit("IN", node->subject()); PrintIndentedVisit("BODY", node->body()); @@ -1034,8 +1003,6 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) { void AstPrinter::VisitForOfStatement(ForOfStatement* node) { IndentedScope indent(this, "FOR OF", node->position()); - PrintLabelsIndented(node->labels()); - PrintLabelsIndented(node->own_labels(), "OWN "); const char* for_type; switch (node->type()) { case IteratorType::kNormal: diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h index 16129a4c00..f3a72e6c39 100644 --- a/src/parsing/parser-base.h +++ b/src/parsing/parser-base.h @@ -232,8 +232,6 @@ class ParserBase { using FuncNameInferrerState = typename Types::FuncNameInferrer::State; using SourceRange = typename Types::SourceRange; using SourceRangeScope = typename Types::SourceRangeScope; - using TargetT = typename Types::Target; - using TargetScopeT = typename Types::TargetScope; // All implementation-specific methods must be called through this. Impl* impl() { return static_cast(this); } @@ -320,7 +318,6 @@ class ParserBase { int loop_nesting_depth() const { return function_state_->loop_nesting_depth(); } - int GetNextFunctionLiteralId() { return ++function_literal_id_; } int GetLastFunctionLiteralId() const { return function_literal_id_; } @@ -370,6 +367,93 @@ class ParserBase { 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* labels, + ZonePtrList* 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* labels() const { return labels_; } + const ZonePtrList* 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 labels_; + const ZonePtrList* 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 { public: FunctionState(FunctionState** function_state_stack, Scope** scope_stack, @@ -427,7 +511,7 @@ class ParserBase { PointerWithPayload state_and_prev_value_; }; - class LoopScope { + class LoopScope final { public: explicit LoopScope(FunctionState* function_state) : function_state_(function_state) { @@ -442,6 +526,8 @@ class ParserBase { int loop_nesting_depth() const { return loop_nesting_depth_; } + Target** target_stack_address() { return &target_stack_; } + private: // Properties count estimation. int expected_property_count_; @@ -455,6 +541,7 @@ class ParserBase { FunctionState** function_state_stack_; FunctionState* outer_function_state_; DeclarationScope* scope_; + Target* target_stack_ = nullptr; // for break, continue statements // A reason, if any, why this function should not be optimized. BailoutReason dont_optimize_reason_; @@ -623,6 +710,46 @@ class ParserBase { bool is_rest; }; + void DeclareLabel(ZonePtrList** labels, + ZonePtrList** 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(1, zone()); + *own_labels = new (zone()) ZonePtrList(1, zone()); + } else { + if (*own_labels == nullptr) { + *own_labels = new (zone()) ZonePtrList(1, zone()); + } + } + (*labels)->Add(label, zone()); + (*own_labels)->Add(label, zone()); + } + + bool ContainsLabel(const ZonePtrList* 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) { switch (kind) { case ParsePropertyKind::kAccessorGetter: @@ -4809,10 +4936,6 @@ void ParserBase::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) { StatementT stat = ParseStatementListItem(); if (impl()->IsNull(stat)) return; @@ -4932,8 +5055,9 @@ typename ParserBase::StatementT ParserBase::ParseStatement( // put the labels there. if (labels == nullptr) return ParseTryStatement(); StatementListT statements(pointer_buffer()); - BlockT result = factory()->NewBlock(false, labels); - TargetT target(this, result); + BlockT result = factory()->NewBlock(false, true); + Target target(this, result, labels, nullptr, + Target::TARGET_FOR_NAMED_ONLY); StatementT statement = ParseTryStatement(); statements.Add(statement); result->InitializeStatements(statements, zone()); @@ -4981,7 +5105,7 @@ typename ParserBase::BlockT ParserBase::ParseBlock( // '{' StatementList '}' // Parse the statements and collect escaping labels. - BlockT body = factory()->NewBlock(false, labels); + BlockT body = factory()->NewBlock(false, labels != nullptr); StatementListT statements(pointer_buffer()); CheckStackOverflow(); @@ -4989,7 +5113,7 @@ typename ParserBase::BlockT ParserBase::ParseBlock( { BlockState block_state(zone(), &scope_); scope()->set_start_position(peek_position()); - TargetT target(this, body); + Target target(this, body, labels, nullptr, Target::TARGET_FOR_NAMED_ONLY); Expect(Token::LBRACE); @@ -5214,11 +5338,11 @@ ParserBase::ParseContinueStatement() { // ECMA allows "eval" or "arguments" as labels even in strict mode. label = ParseIdentifier(); } - IterationStatementT target = impl()->LookupContinueTarget(label); + IterationStatementT target = LookupContinueTarget(label); if (impl()->IsNull(target)) { // Illegal continue statement. MessageTemplate message = MessageTemplate::kIllegalContinue; - BreakableStatementT breakable_target = impl()->LookupBreakTarget(label); + BreakableStatementT breakable_target = LookupBreakTarget(label); if (impl()->IsNull(label)) { message = MessageTemplate::kNoIterationStatement; } else if (impl()->IsNull(breakable_target)) { @@ -5250,11 +5374,12 @@ typename ParserBase::StatementT ParserBase::ParseBreakStatement( } // Parse labeled break statements that target themselves into // 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(); return factory()->EmptyStatement(); } - BreakableStatementT target = impl()->LookupBreakTarget(label); + BreakableStatementT target = LookupBreakTarget(label); if (impl()->IsNull(target)) { // Illegal break statement. MessageTemplate message = MessageTemplate::kIllegalBreak; @@ -5349,9 +5474,8 @@ typename ParserBase::StatementT ParserBase::ParseDoWhileStatement( // 'do' Statement 'while' '(' Expression ')' ';' typename FunctionState::LoopScope loop_scope(function_state_); - auto loop = - factory()->NewDoWhileStatement(labels, own_labels, peek_position()); - TargetT target(this, loop); + auto loop = factory()->NewDoWhileStatement(peek_position()); + Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS); SourceRange body_range; StatementT body = impl()->NullStatement(); @@ -5389,8 +5513,8 @@ typename ParserBase::StatementT ParserBase::ParseWhileStatement( // 'while' '(' Expression ')' Statement typename FunctionState::LoopScope loop_scope(function_state_); - auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position()); - TargetT target(this, loop); + auto loop = factory()->NewWhileStatement(peek_position()); + Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS); SourceRange body_range; StatementT body = impl()->NullStatement(); @@ -5438,7 +5562,6 @@ typename ParserBase::StatementT ParserBase::ParseSwitchStatement( // CaseClause :: // 'case' Expression ':' StatementList // 'default' ':' StatementList - int switch_pos = peek_position(); Consume(Token::SWITCH); @@ -5446,14 +5569,14 @@ typename ParserBase::StatementT ParserBase::ParseSwitchStatement( ExpressionT tag = ParseExpression(); Expect(Token::RPAREN); - auto switch_statement = - factory()->NewSwitchStatement(labels, tag, switch_pos); + auto switch_statement = factory()->NewSwitchStatement(tag, switch_pos); { BlockState cases_block_state(zone(), &scope_); scope()->set_start_position(switch_pos); scope()->SetNonlinear(); - TargetT target(this, switch_statement); + Target target(this, switch_statement, labels, nullptr, + Target::TARGET_FOR_ANONYMOUS); bool default_seen = false; Expect(Token::LBRACE); @@ -5788,9 +5911,8 @@ ParserBase::ParseForEachStatementWithDeclarations( BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); - auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, - stmt_pos); - TargetT target(this, loop); + auto loop = factory()->NewForEachStatement(for_info->mode, stmt_pos); + Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { @@ -5852,9 +5974,8 @@ ParserBase::ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZonePtrList* labels, ZonePtrList* own_labels) { - auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, - stmt_pos); - TargetT target(this, loop); + auto loop = factory()->NewForEachStatement(for_info->mode, stmt_pos); + Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { @@ -5943,8 +6064,8 @@ typename ParserBase::ForStatementT ParserBase::ParseStandardForLoop( ZonePtrList* own_labels, ExpressionT* cond, StatementT* next, StatementT* body) { CheckStackOverflow(); - ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos); - TargetT target(this, loop); + ForStatementT loop = factory()->NewForStatement(stmt_pos); + Target target(this, loop, labels, own_labels, Target::TARGET_FOR_ANONYMOUS); if (peek() != Token::SEMICOLON) { *cond = ParseExpression(); @@ -5988,13 +6109,12 @@ typename ParserBase::StatementT ParserBase::ParseForAwaitStatement( scope()->set_start_position(scanner()->location().beg_pos); scope()->set_is_hidden(); - auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos, - IteratorType::kAsync); + auto loop = factory()->NewForOfStatement(stmt_pos, IteratorType::kAsync); // Two suspends: one for next() and one for return() 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(); diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc index eb890bface..2516461943 100644 --- a/src/parsing/parser.cc +++ b/src/parsing/parser.cc @@ -427,7 +427,6 @@ Parser::Parser(ParseInfo* info) reusable_preparser_(nullptr), mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. source_range_map_(info->source_range_map()), - target_stack_(nullptr), total_preparse_skipped_(0), consumed_preparse_data_(info->consumed_preparse_data()), preparse_data_buffer_(), @@ -566,7 +565,6 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) { // isolate will be nullptr. DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr); DCHECK_NULL(scope_); - DCHECK_NULL(target_stack_); ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY); ResetFunctionLiteralId(); @@ -681,9 +679,6 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) { info->set_max_function_literal_id(GetLastFunctionLiteralId()); - // Make sure the target stack is empty. - DCHECK_NULL(target_stack_); - if (has_error()) return nullptr; RecordFunctionLiteralSourceRange(result); @@ -848,7 +843,6 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr); DCHECK_NOT_NULL(raw_name); DCHECK_NULL(scope_); - DCHECK_NULL(target_stack_); DCHECK(ast_value_factory()); 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, info->function_literal_id() == result->function_literal_id()); return result; @@ -1601,43 +1593,6 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos) { pos); } -void Parser::DeclareLabel(ZonePtrList** labels, - ZonePtrList** 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(1, zone()); - *own_labels = new (zone()) ZonePtrList(1, zone()); - } else { - if (*own_labels == nullptr) { - *own_labels = new (zone()) ZonePtrList(1, zone()); - } - } - (*labels)->Add(label, zone()); - (*own_labels)->Add(label, zone()); -} - -bool Parser::ContainsLabel(ZonePtrList* 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* block = factory()->NewBlock(1, true); block->statements()->Add(statement, zone()); @@ -2073,8 +2028,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // 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 // in this function that looks up break targets. - ForStatement* outer_loop = - factory()->NewForStatement(nullptr, nullptr, kNoSourcePosition); + ForStatement* outer_loop = factory()->NewForStatement(kNoSourcePosition); outer_block->statements()->Add(outer_loop, zone()); outer_block->set_scope(scope()); @@ -3065,40 +3019,6 @@ void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) { // ---------------------------------------------------------------------------- // 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