[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:
parent
b9e40f7c01
commit
f5592da673
@ -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
|
||||||
|
208
src/ast/ast.h
208
src/ast/ast.h
@ -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) {
|
||||||
|
@ -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:
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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()) {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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 : {
|
||||||
|
@ -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();
|
|
||||||
})();
|
})();
|
||||||
|
@ -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();
|
||||||
|
8
test/mjsunit/prepare-missing-label-syntax-error.js
Normal file
8
test/mjsunit/prepare-missing-label-syntax-error.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user