Commit 93b3397e authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[es6/cleanup]: re-implement ES6 array spreads in BytecodeGenerator

This gets rid of all the RewriteNonPattern gunk in the parser and
expression classifier, and removes one use of RewritableExpression.

This borrows pieces from several other CLs of mine which are currently
open, and includes a new and modernized abstraction for dealing with
iterators in BytecodeGenerator (so, this CL adds that, moves code from
BuildGetIterator around, and makes some minor changes to yield* which
should maintain compatability with the old behaviour).

This also implements a portion of the changes to the iteration protocol
(implemented fully in
https://chromium-review.googlesource.com/c/v8/v8/+/687997), but only for
the spread operator in Array Literals (the rest will follow).

BUG=v8:5940, v8:3018
R=rmcilroy@chromium.org, marja@chromium.org, adamk@chromium.org
TBR=adamk@chromium.org

Change-Id: Ifc494d663d8e46066a439c3541c33f0243726234
Reviewed-on: https://chromium-review.googlesource.com/804396
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: 's avatarAleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50138}
parent e9770dfe
...@@ -514,7 +514,6 @@ bool ArrayLiteral::is_empty() const { ...@@ -514,7 +514,6 @@ bool ArrayLiteral::is_empty() const {
} }
int ArrayLiteral::InitDepthAndFlags() { int ArrayLiteral::InitDepthAndFlags() {
DCHECK_LT(first_spread_index_, 0);
if (is_initialized()) return depth(); if (is_initialized()) return depth();
int constants_length = values()->length(); int constants_length = values()->length();
...@@ -525,7 +524,6 @@ int ArrayLiteral::InitDepthAndFlags() { ...@@ -525,7 +524,6 @@ int ArrayLiteral::InitDepthAndFlags() {
int array_index = 0; int array_index = 0;
for (; array_index < constants_length; array_index++) { for (; array_index < constants_length; array_index++) {
Expression* element = values()->at(array_index); Expression* element = values()->at(array_index);
DCHECK(!element->IsSpread());
MaterializedLiteral* literal = element->AsMaterializedLiteral(); MaterializedLiteral* literal = element->AsMaterializedLiteral();
if (literal != nullptr) { if (literal != nullptr) {
int subliteral_depth = literal->InitDepthAndFlags() + 1; int subliteral_depth = literal->InitDepthAndFlags() + 1;
...@@ -546,11 +544,10 @@ int ArrayLiteral::InitDepthAndFlags() { ...@@ -546,11 +544,10 @@ int ArrayLiteral::InitDepthAndFlags() {
} }
void ArrayLiteral::BuildConstantElements(Isolate* isolate) { void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
DCHECK_LT(first_spread_index_, 0);
if (!constant_elements_.is_null()) return; if (!constant_elements_.is_null()) return;
int constants_length = values()->length(); int constants_length =
first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
ElementsKind kind = FIRST_FAST_ELEMENTS_KIND; ElementsKind kind = FIRST_FAST_ELEMENTS_KIND;
Handle<FixedArray> fixed_array = Handle<FixedArray> fixed_array =
isolate->factory()->NewFixedArrayWithHoles(constants_length); isolate->factory()->NewFixedArrayWithHoles(constants_length);
...@@ -614,11 +611,6 @@ bool ArrayLiteral::IsFastCloningSupported() const { ...@@ -614,11 +611,6 @@ bool ArrayLiteral::IsFastCloningSupported() const {
ConstructorBuiltins::kMaximumClonedShallowArrayElements; ConstructorBuiltins::kMaximumClonedShallowArrayElements;
} }
void ArrayLiteral::RewindSpreads() {
values_->Rewind(first_spread_index_);
first_spread_index_ = -1;
}
bool MaterializedLiteral::IsSimple() const { bool MaterializedLiteral::IsSimple() const {
if (IsArrayLiteral()) return AsArrayLiteral()->is_simple(); if (IsArrayLiteral()) return AsArrayLiteral()->is_simple();
if (IsObjectLiteral()) return AsObjectLiteral()->is_simple(); if (IsObjectLiteral()) return AsObjectLiteral()->is_simple();
......
...@@ -1450,15 +1450,15 @@ class ArrayLiteral final : public AggregateLiteral { ...@@ -1450,15 +1450,15 @@ class ArrayLiteral final : public AggregateLiteral {
} }
// Provide a mechanism for iterating through values to rewrite spreads. // Provide a mechanism for iterating through values to rewrite spreads.
ZoneList<Expression*>::iterator FirstSpread() const { ZoneList<Expression*>::iterator FirstSpreadOrEndValue() const {
return (first_spread_index_ >= 0) ? values_->begin() + first_spread_index_ return (first_spread_index_ >= 0) ? values_->begin() + first_spread_index_
: values_->end(); : values_->end();
} }
ZoneList<Expression*>::iterator BeginValue() const {
return values_->begin();
}
ZoneList<Expression*>::iterator EndValue() const { return values_->end(); } ZoneList<Expression*>::iterator EndValue() const { return values_->end(); }
// Rewind an array literal omitting everything from the first spread on.
void RewindSpreads();
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
......
...@@ -26,6 +26,7 @@ CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js) ...@@ -26,6 +26,7 @@ CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js)
is_iterator_error_ = false; is_iterator_error_ = false;
is_async_iterator_error_ = false; is_async_iterator_error_ = false;
is_user_js_ = is_user_js; is_user_js_ = is_user_js;
function_kind_ = kNormalFunction;
InitializeAstVisitor(isolate); InitializeAstVisitor(isolate);
} }
...@@ -187,7 +188,10 @@ void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {} ...@@ -187,7 +188,10 @@ void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {}
void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) { void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
FunctionKind last_function_kind = function_kind_;
function_kind_ = node->kind();
FindStatements(node->body()); FindStatements(node->body());
function_kind_ = last_function_kind;
} }
...@@ -250,7 +254,17 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { ...@@ -250,7 +254,17 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) {
Print("["); Print("[");
for (int i = 0; i < node->values()->length(); i++) { for (int i = 0; i < node->values()->length(); i++) {
if (i != 0) Print(","); if (i != 0) Print(",");
Find(node->values()->at(i), true); Expression* subexpr = node->values()->at(i);
Spread* spread = subexpr->AsSpread();
if (spread != nullptr && !found_ &&
position_ == spread->expression()->position()) {
found_ = true;
is_iterator_error_ = true;
Find(spread->expression(), true);
done_ = true;
return;
}
Find(subexpr, true);
} }
Print("]"); Print("]");
} }
...@@ -277,7 +291,17 @@ void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) { ...@@ -277,7 +291,17 @@ void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); }
void CallPrinter::VisitYieldStar(YieldStar* node) { Find(node->expression()); } void CallPrinter::VisitYieldStar(YieldStar* node) {
if (!found_ && position_ == node->expression()->position()) {
found_ = true;
if (IsAsyncFunction(function_kind_))
is_async_iterator_error_ = true;
else
is_iterator_error_ = true;
Print("yield* ");
}
Find(node->expression());
}
void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); } void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); }
......
...@@ -50,6 +50,7 @@ class CallPrinter final : public AstVisitor<CallPrinter> { ...@@ -50,6 +50,7 @@ class CallPrinter final : public AstVisitor<CallPrinter> {
bool is_iterator_error_; bool is_iterator_error_;
bool is_async_iterator_error_; bool is_async_iterator_error_;
bool is_call_error_; bool is_call_error_;
FunctionKind function_kind_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
protected: protected:
......
...@@ -835,6 +835,32 @@ class BytecodeGenerator::FeedbackSlotCache : public ZoneObject { ...@@ -835,6 +835,32 @@ class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
ZoneMap<Key, FeedbackSlot> map_; ZoneMap<Key, FeedbackSlot> map_;
}; };
class BytecodeGenerator::IteratorRecord final {
public:
// TODO(caitp): This constructor is used for legacy code which doesn't load
// the `next` method immediately during GetIterator. It should be removed once
// the followup CL lands.
IteratorRecord(Register object_register,
IteratorType type = IteratorType::kNormal)
: type_(type), object_(object_register) {
DCHECK(object_.is_valid());
}
IteratorRecord(Register object_register, Register next_register,
IteratorType type = IteratorType::kNormal)
: type_(type), object_(object_register), next_(next_register) {
DCHECK(object_.is_valid() && next_.is_valid());
}
inline IteratorType type() const { return type_; }
inline Register object() const { return object_; }
inline Register next() const { return next_; }
private:
IteratorType type_;
Register object_;
Register next_;
};
BytecodeGenerator::BytecodeGenerator( BytecodeGenerator::BytecodeGenerator(
CompilationInfo* info, const AstStringConstants* ast_string_constants) CompilationInfo* info, const AstStringConstants* ast_string_constants)
: zone_(info->zone()), : zone_(info->zone()),
...@@ -2290,31 +2316,25 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -2290,31 +2316,25 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->CreateArrayLiteral(entry, literal_index, flags); builder()->CreateArrayLiteral(entry, literal_index, flags);
array_literals_.push_back(std::make_pair(expr, entry)); array_literals_.push_back(std::make_pair(expr, entry));
Register index, literal; Register index = register_allocator()->NewRegister();
Register literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
// We'll reuse the same literal slot for all of the non-constant // We'll reuse the same literal slot for all of the non-constant
// subexpressions that use a keyed store IC. // subexpressions that use a keyed store IC.
// Evaluate all the non-constant subexpressions and store them into the // Evaluate all the non-constant subexpressions and store them into the
// newly cloned array. // newly cloned array.
bool literal_in_accumulator = true;
FeedbackSlot slot; FeedbackSlot slot;
for (int array_index = 0; array_index < expr->values()->length(); int array_index = 0;
array_index++) { ZoneList<Expression*>::iterator iter = expr->BeginValue();
Expression* subexpr = expr->values()->at(array_index); for (; iter != expr->FirstSpreadOrEndValue(); ++iter, array_index++) {
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; Expression* subexpr = *iter;
DCHECK(!subexpr->IsSpread()); DCHECK(!subexpr->IsSpread());
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
if (literal_in_accumulator) {
index = register_allocator()->NewRegister();
literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
if (slot.IsInvalid()) { if (slot.IsInvalid()) {
slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
} }
builder() builder()
->LoadLiteral(Smi::FromInt(array_index)) ->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index); .StoreAccumulatorInRegister(index);
...@@ -2323,10 +2343,68 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -2323,10 +2343,68 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
language_mode()); language_mode());
} }
if (!literal_in_accumulator) { // Handle spread elements and elements following.
// Restore literal array into accumulator. for (; iter != expr->EndValue(); ++iter) {
builder()->LoadAccumulatorWithRegister(literal); Expression* subexpr = *iter;
if (subexpr->IsSpread()) {
BuildArrayLiteralSpread(subexpr->AsSpread(), literal);
} else if (!subexpr->IsTheHoleLiteral()) {
// Perform %AppendElement(array, <subexpr>)
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(subexpr, args[1]);
builder()->CallRuntime(Runtime::kAppendElement, args);
} else {
// Peform ++<array>.length;
// TODO(caitp): Why can't we just %AppendElement(array, <The Hole>?)
auto length = ast_string_constants()->length_string();
builder()->LoadNamedProperty(
literal, length, feedback_index(feedback_spec()->AddLoadICSlot()));
builder()->UnaryOperation(
Token::INC, feedback_index(feedback_spec()->AddBinaryOpICSlot()));
builder()->StoreNamedProperty(
literal, length,
feedback_index(
feedback_spec()->AddStoreICSlot(LanguageMode::kStrict)),
LanguageMode::kStrict);
}
} }
// Restore literal array into accumulator.
builder()->LoadAccumulatorWithRegister(literal);
}
void BytecodeGenerator::BuildArrayLiteralSpread(Spread* spread,
Register array) {
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()->MoveRegister(array, args[0]);
Register next_result = args[1];
builder()->SetExpressionAsStatementPosition(spread->expression());
IteratorRecord iterator =
BuildGetIteratorRecord(spread->expression(), IteratorType::kNormal);
LoopBuilder loop_builder(builder(), nullptr, nullptr);
loop_builder.LoopHeader();
// Call the iterator's .next() method. Break from the loop if the `done`
// property is truthy, otherwise load the value from the iterator result and
// append the argument.
BuildIteratorNext(iterator, next_result);
builder()->LoadNamedProperty(
next_result, ast_string_constants()->done_string(),
feedback_index(feedback_spec()->AddLoadICSlot()));
loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
loop_builder.LoopBody();
builder()
->LoadNamedProperty(next_result, ast_string_constants()->value_string(),
feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kAppendElement, args);
loop_builder.BindContinueTarget();
loop_builder.JumpToHeader(loop_depth_);
} }
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
...@@ -2965,10 +3043,10 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { ...@@ -2965,10 +3043,10 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
RegisterList iterator_and_input = register_allocator()->NewRegisterList(2); RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
Register iterator = iterator_and_input[0]; IteratorRecord iterator(iterator_and_input[0], iterator_type);
BuildGetIterator(expr->expression(), iterator_type); BuildGetIterator(expr->expression(), iterator_type);
builder()->StoreAccumulatorInRegister(iterator); builder()->StoreAccumulatorInRegister(iterator.object());
Register input = iterator_and_input[1]; Register input = iterator_and_input[1];
builder()->LoadUndefined().StoreAccumulatorInRegister(input); builder()->LoadUndefined().StoreAccumulatorInRegister(input);
builder() builder()
...@@ -3005,7 +3083,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { ...@@ -3005,7 +3083,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot(); FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot(); FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder() builder()
->LoadNamedProperty(iterator, ->LoadNamedProperty(iterator.object(),
ast_string_constants()->next_string(), ast_string_constants()->next_string(),
feedback_index(load_slot)) feedback_index(load_slot))
.StoreAccumulatorInRegister(iterator_next) .StoreAccumulatorInRegister(iterator_next)
...@@ -3024,7 +3102,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { ...@@ -3024,7 +3102,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot(); FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot(); FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder() builder()
->LoadNamedProperty(iterator, ->LoadNamedProperty(iterator.object(),
ast_string_constants()->return_string(), ast_string_constants()->return_string(),
feedback_index(load_slot)) feedback_index(load_slot))
.JumpIfUndefined(return_input.New()) .JumpIfUndefined(return_input.New())
...@@ -3057,7 +3135,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { ...@@ -3057,7 +3135,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot(); FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot(); FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder() builder()
->LoadNamedProperty(iterator, ->LoadNamedProperty(iterator.object(),
ast_string_constants()->throw_string(), ast_string_constants()->throw_string(),
feedback_index(load_slot)) feedback_index(load_slot))
.JumpIfUndefined(iterator_throw_is_undefined.New()) .JumpIfUndefined(iterator_throw_is_undefined.New())
...@@ -3079,14 +3157,14 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { ...@@ -3079,14 +3157,14 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot(); FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot(); FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder() builder()
->LoadNamedProperty(iterator, ->LoadNamedProperty(iterator.object(),
ast_string_constants()->return_string(), ast_string_constants()->return_string(),
feedback_index(load_slot)) feedback_index(load_slot))
.StoreAccumulatorInRegister(iterator_return); .StoreAccumulatorInRegister(iterator_return);
builder() builder()
->JumpIfUndefined(throw_throw_method_missing.New()) ->JumpIfUndefined(throw_throw_method_missing.New())
.JumpIfNull(throw_throw_method_missing.New()) .JumpIfNull(throw_throw_method_missing.New())
.CallProperty(iterator_return, RegisterList(iterator), .CallProperty(iterator_return, RegisterList(iterator.object()),
feedback_index(call_slot)); feedback_index(call_slot));
if (iterator_type == IteratorType::kAsync) { if (iterator_type == IteratorType::kAsync) {
...@@ -4073,6 +4151,38 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable, ...@@ -4073,6 +4151,38 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
} }
} }
// Returns an IteratorRecord which is valid for the lifetime of the current
// register_allocation_scope.
BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
Expression* iterable, IteratorType hint) {
BuildGetIterator(iterable, hint);
Register object = register_allocator()->NewRegister();
Register next = register_allocator()->NewRegister();
builder()
->StoreAccumulatorInRegister(object)
.LoadNamedProperty(object, ast_string_constants()->next_string(),
feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(next);
return IteratorRecord(object, next, hint);
}
void BytecodeGenerator::BuildIteratorNext(const IteratorRecord& iterator,
Register next_result) {
DCHECK(next_result.is_valid());
builder()->CallProperty(iterator.next(), RegisterList(iterator.object()),
feedback_index(feedback_spec()->AddCallICSlot()));
// TODO(caitp): support async IteratorNext here.
BytecodeLabel is_object;
builder()
->StoreAccumulatorInRegister(next_result)
.JumpIfJSReceiver(&is_object)
.CallRuntime(Runtime::kThrowIteratorResultNotAnObject, next_result)
.Bind(&is_object);
}
void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
builder()->SetExpressionPosition(expr); builder()->SetExpressionPosition(expr);
BuildGetIterator(expr->iterable(), expr->hint()); BuildGetIterator(expr->iterable(), expr->hint());
......
...@@ -56,6 +56,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -56,6 +56,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class EffectResultScope; class EffectResultScope;
class FeedbackSlotCache; class FeedbackSlotCache;
class GlobalDeclarationsBuilder; class GlobalDeclarationsBuilder;
class IteratorRecord;
class NaryCodeCoverageSlots; class NaryCodeCoverageSlots;
class RegisterAllocationScope; class RegisterAllocationScope;
class TestResultScope; class TestResultScope;
...@@ -150,6 +151,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -150,6 +151,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildAwait(int suspend_id); void BuildAwait(int suspend_id);
void BuildGetIterator(Expression* iterable, IteratorType hint); void BuildGetIterator(Expression* iterable, IteratorType hint);
IteratorRecord BuildGetIteratorRecord(Expression* iterable,
IteratorType hint);
void BuildIteratorNext(const IteratorRecord& iterator, Register next_result);
void BuildArrayLiteralSpread(Spread* spread, Register array);
void AllocateTopLevelRegisters(); void AllocateTopLevelRegisters();
void VisitArgumentsObject(Variable* variable); void VisitArgumentsObject(Variable* variable);
......
...@@ -97,14 +97,12 @@ class ExpressionClassifier { ...@@ -97,14 +97,12 @@ class ExpressionClassifier {
: base_(base), : base_(base),
previous_(base->classifier_), previous_(base->classifier_),
zone_(base->impl()->zone()), zone_(base->impl()->zone()),
non_patterns_to_rewrite_(base->impl()->GetNonPatternList()),
reported_errors_(base->impl()->GetReportedErrorList()), reported_errors_(base->impl()->GetReportedErrorList()),
duplicate_finder_(duplicate_finder), duplicate_finder_(duplicate_finder),
invalid_productions_(0), invalid_productions_(0),
function_properties_(0) { function_properties_(0) {
base->classifier_ = this; base->classifier_ = this;
reported_errors_begin_ = reported_errors_end_ = reported_errors_->length(); reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
non_pattern_begin_ = non_patterns_to_rewrite_->length();
} }
V8_INLINE ~ExpressionClassifier() { V8_INLINE ~ExpressionClassifier() {
...@@ -291,19 +289,10 @@ class ExpressionClassifier { ...@@ -291,19 +289,10 @@ class ExpressionClassifier {
Add(Error(loc, message, kLetPatternProduction, arg)); Add(Error(loc, message, kLetPatternProduction, arg));
} }
void Accumulate(ExpressionClassifier* inner, unsigned productions, void Accumulate(ExpressionClassifier* inner, unsigned productions) {
bool merge_non_patterns = true) {
DCHECK_EQ(inner->reported_errors_, reported_errors_); DCHECK_EQ(inner->reported_errors_, reported_errors_);
DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_); DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_);
DCHECK_EQ(inner->reported_errors_end_, reported_errors_->length()); DCHECK_EQ(inner->reported_errors_end_, reported_errors_->length());
DCHECK_EQ(inner->non_patterns_to_rewrite_, non_patterns_to_rewrite_);
DCHECK_LE(non_pattern_begin_, inner->non_pattern_begin_);
DCHECK_LE(inner->non_pattern_begin_, non_patterns_to_rewrite_->length());
// Merge non-patterns from the inner classifier, or discard them.
if (merge_non_patterns)
inner->non_pattern_begin_ = non_patterns_to_rewrite_->length();
else
non_patterns_to_rewrite_->Rewind(inner->non_pattern_begin_);
// Propagate errors from inner, but don't overwrite already recorded // Propagate errors from inner, but don't overwrite already recorded
// errors. // errors.
unsigned non_arrow_inner_invalid_productions = unsigned non_arrow_inner_invalid_productions =
...@@ -368,16 +357,12 @@ class ExpressionClassifier { ...@@ -368,16 +357,12 @@ class ExpressionClassifier {
reported_errors_end_; reported_errors_end_;
} }
V8_INLINE int GetNonPatternBegin() const { return non_pattern_begin_; }
V8_INLINE void Discard() { V8_INLINE void Discard() {
if (reported_errors_end_ == reported_errors_->length()) { if (reported_errors_end_ == reported_errors_->length()) {
reported_errors_->Rewind(reported_errors_begin_); reported_errors_->Rewind(reported_errors_begin_);
reported_errors_end_ = reported_errors_begin_; reported_errors_end_ = reported_errors_begin_;
} }
DCHECK_EQ(reported_errors_begin_, reported_errors_end_); DCHECK_EQ(reported_errors_begin_, reported_errors_end_);
DCHECK_LE(non_pattern_begin_, non_patterns_to_rewrite_->length());
non_patterns_to_rewrite_->Rewind(non_pattern_begin_);
} }
ExpressionClassifier* previous() const { return previous_; } ExpressionClassifier* previous() const { return previous_; }
...@@ -424,16 +409,8 @@ class ExpressionClassifier { ...@@ -424,16 +409,8 @@ class ExpressionClassifier {
typename Types::Base* base_; typename Types::Base* base_;
ExpressionClassifier* previous_; ExpressionClassifier* previous_;
Zone* zone_; Zone* zone_;
ZoneList<typename Types::RewritableExpression>* non_patterns_to_rewrite_;
ZoneList<Error>* reported_errors_; ZoneList<Error>* reported_errors_;
DuplicateFinder* duplicate_finder_; DuplicateFinder* duplicate_finder_;
// The uint16_t for non_pattern_begin_ will not be enough in the case,
// e.g., of an array literal containing more than 64K inner array
// literals with spreads, as in:
// var N=65536; eval("var x=[];" + "[" + "[...x],".repeat(N) + "].length");
// An implementation limit error in ParserBase::AddNonPatternForRewriting
// will be triggered in this case.
uint16_t non_pattern_begin_;
unsigned invalid_productions_ : 14; unsigned invalid_productions_ : 14;
unsigned function_properties_ : 2; unsigned function_properties_ : 2;
// The uint16_t for reported_errors_begin_ and reported_errors_end_ will // The uint16_t for reported_errors_begin_ and reported_errors_end_ will
......
...@@ -451,14 +451,6 @@ class ParserBase { ...@@ -451,14 +451,6 @@ class ParserBase {
destructuring_assignments_to_rewrite_.Add(expr, scope_->zone()); destructuring_assignments_to_rewrite_.Add(expr, scope_->zone());
} }
void AddNonPatternForRewriting(RewritableExpressionT expr, bool* ok) {
non_patterns_to_rewrite_.Add(expr, scope_->zone());
if (non_patterns_to_rewrite_.length() >=
std::numeric_limits<uint16_t>::max()) {
*ok = false;
}
}
// Properties count estimation. // Properties count estimation.
int expected_property_count_; int expected_property_count_;
...@@ -1078,10 +1070,8 @@ class ParserBase { ...@@ -1078,10 +1070,8 @@ class ParserBase {
return ParsePrimaryExpression(&is_async, ok); return ParsePrimaryExpression(&is_async, ok);
} }
// This method wraps the parsing of the expression inside a new expression // Use when parsing an expression that is known to not be a pattern or part
// classifier and calls RewriteNonPattern if parsing is successful. // of a pattern.
// It should be used whenever we're parsing an expression that is known
// to not be a pattern or part of a pattern.
V8_INLINE ExpressionT ParseExpression(bool accept_IN, bool* ok); V8_INLINE ExpressionT ParseExpression(bool accept_IN, bool* ok);
// This method does not wrap the parsing of the expression inside a // This method does not wrap the parsing of the expression inside a
...@@ -1463,21 +1453,18 @@ class ParserBase { ...@@ -1463,21 +1453,18 @@ class ParserBase {
// Accumulates the classifier that is on top of the stack (inner) to // Accumulates the classifier that is on top of the stack (inner) to
// the one that is right below (outer) and pops the inner. // the one that is right below (outer) and pops the inner.
V8_INLINE void Accumulate(unsigned productions, V8_INLINE void Accumulate(unsigned productions) {
bool merge_non_patterns = true) {
DCHECK_NOT_NULL(classifier_); DCHECK_NOT_NULL(classifier_);
ExpressionClassifier* previous = classifier_->previous(); ExpressionClassifier* previous = classifier_->previous();
DCHECK_NOT_NULL(previous); DCHECK_NOT_NULL(previous);
previous->Accumulate(classifier_, productions, merge_non_patterns); previous->Accumulate(classifier_, productions);
classifier_ = previous; classifier_ = previous;
} }
V8_INLINE void AccumulateNonBindingPatternErrors() { V8_INLINE void AccumulateNonBindingPatternErrors() {
static const bool kMergeNonPatterns = true;
this->Accumulate(ExpressionClassifier::AllProductions & this->Accumulate(ExpressionClassifier::AllProductions &
~(ExpressionClassifier::BindingPatternProduction | ~(ExpressionClassifier::BindingPatternProduction |
ExpressionClassifier::LetPatternProduction), ExpressionClassifier::LetPatternProduction));
kMergeNonPatterns);
} }
// Pops and discards the classifier that is on top of the stack // Pops and discards the classifier that is on top of the stack
...@@ -1942,7 +1929,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( ...@@ -1942,7 +1929,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
bool accept_IN, bool* ok) { bool accept_IN, bool* ok) {
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK); ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
return result; return result;
} }
...@@ -2068,22 +2055,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( ...@@ -2068,22 +2055,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
} }
Expect(Token::RBRACK, CHECK_OK); Expect(Token::RBRACK, CHECK_OK);
ExpressionT result = return factory()->NewArrayLiteral(values, first_spread_index, pos);
factory()->NewArrayLiteral(values, first_spread_index, pos);
if (first_spread_index >= 0) {
auto rewritable = factory()->NewRewritableExpression(result, scope());
impl()->QueueNonPatternForRewriting(rewritable, ok);
if (!*ok) {
// If the non-pattern rewriting mechanism is used in the future for
// rewriting other things than spreads, this error message will have
// to change. Also, this error message will never appear while pre-
// parsing (this is OK, as it is an implementation limitation).
ReportMessage(MessageTemplate::kTooManySpreads);
return impl()->NullExpression();
}
result = rewritable;
}
return result;
} }
template <class Impl> template <class Impl>
...@@ -2198,7 +2170,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( ...@@ -2198,7 +2170,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
Consume(Token::LBRACK); Consume(Token::LBRACK);
ExpressionClassifier computed_name_classifier(this); ExpressionClassifier computed_name_classifier(this);
expression = ParseAssignmentExpression(true, CHECK_OK); expression = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors(); AccumulateFormalParameterContainmentErrors();
Expect(Token::RBRACK, CHECK_OK); Expect(Token::RBRACK, CHECK_OK);
break; break;
...@@ -2441,7 +2413,7 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, ...@@ -2441,7 +2413,7 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info,
initializer = initializer =
ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression)); ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpression)); ValidateExpression(CHECK_OK_CUSTOM(NullExpression));
} else { } else {
initializer = factory()->NewUndefinedLiteral(kNoSourcePosition); initializer = factory()->NewUndefinedLiteral(kNoSourcePosition);
} }
...@@ -2560,7 +2532,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, ...@@ -2560,7 +2532,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
ExpressionClassifier rhs_classifier(this); ExpressionClassifier rhs_classifier(this);
ExpressionT rhs = ParseAssignmentExpression( ExpressionT rhs = ParseAssignmentExpression(
true, CHECK_OK_CUSTOM(NullLiteralProperty)); true, CHECK_OK_CUSTOM(NullLiteralProperty));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullLiteralProperty)); ValidateExpression(CHECK_OK_CUSTOM(NullLiteralProperty));
AccumulateFormalParameterContainmentErrors(); AccumulateFormalParameterContainmentErrors();
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
kNoSourcePosition); kNoSourcePosition);
...@@ -2738,7 +2710,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( ...@@ -2738,7 +2710,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
*is_simple_parameter_list = false; *is_simple_parameter_list = false;
} }
if (!maybe_arrow) { if (!maybe_arrow) {
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList)); ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList));
} }
if (is_spread) { if (is_spread) {
if (is_simple_parameter_list != nullptr) { if (is_simple_parameter_list != nullptr) {
...@@ -2784,7 +2756,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( ...@@ -2784,7 +2756,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
if (!maybe_arrow || peek() != Token::ARROW) { if (!maybe_arrow || peek() != Token::ARROW) {
if (maybe_arrow) { if (maybe_arrow) {
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList)); ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList));
} }
} }
...@@ -2914,15 +2886,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { ...@@ -2914,15 +2886,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
productions &= ~ExpressionClassifier::ExpressionProduction; productions &= ~ExpressionClassifier::ExpressionProduction;
} }
if (!Token::IsAssignmentOp(peek())) { Accumulate(productions);
// Parsed conditional expression only (no assignment). if (!Token::IsAssignmentOp(peek())) return expression;
// Pending non-pattern expressions must be merged.
Accumulate(productions);
return expression;
} else {
// Pending non-pattern expressions must be discarded.
Accumulate(productions, false);
}
if (is_destructuring_assignment) { if (is_destructuring_assignment) {
ValidateAssignmentPattern(CHECK_OK); ValidateAssignmentPattern(CHECK_OK);
...@@ -2945,7 +2910,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { ...@@ -2945,7 +2910,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
ExpressionClassifier rhs_classifier(this); ExpressionClassifier rhs_classifier(this);
ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK); ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors(); AccumulateFormalParameterContainmentErrors();
// We try to estimate the set of properties set by constructors. We define a // We try to estimate the set of properties set by constructors. We define a
...@@ -3019,7 +2984,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( ...@@ -3019,7 +2984,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
// Delegating yields require an RHS; fall through. // Delegating yields require an RHS; fall through.
default: default:
expression = ParseAssignmentExpression(accept_IN, CHECK_OK); expression = ParseAssignmentExpression(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
break; break;
} }
} }
...@@ -3052,7 +3017,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, ...@@ -3052,7 +3017,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// We start using the binary expression parser for prec >= 4 only! // We start using the binary expression parser for prec >= 4 only!
ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
if (peek() != Token::CONDITIONAL) return expression; if (peek() != Token::CONDITIONAL) return expression;
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
...@@ -3067,7 +3032,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, ...@@ -3067,7 +3032,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
left = ParseAssignmentExpression(true, CHECK_OK); left = ParseAssignmentExpression(true, CHECK_OK);
AccumulateNonBindingPatternErrors(); AccumulateNonBindingPatternErrors();
} }
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
ExpressionT right; ExpressionT right;
{ {
SourceRangeScope range_scope(scanner(), &else_range); SourceRangeScope range_scope(scanner(), &else_range);
...@@ -3076,7 +3041,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, ...@@ -3076,7 +3041,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
right = ParseAssignmentExpression(accept_IN, CHECK_OK); right = ParseAssignmentExpression(accept_IN, CHECK_OK);
AccumulateNonBindingPatternErrors(); AccumulateNonBindingPatternErrors();
} }
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
ExpressionT expr = factory()->NewConditional(expression, left, right, pos); ExpressionT expr = factory()->NewConditional(expression, left, right, pos);
impl()->RecordConditionalSourceRange(expr, then_range, else_range); impl()->RecordConditionalSourceRange(expr, then_range, else_range);
return expr; return expr;
...@@ -3093,7 +3058,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( ...@@ -3093,7 +3058,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
// prec1 >= 4 // prec1 >= 4
while (Precedence(peek(), accept_IN) == prec1) { while (Precedence(peek(), accept_IN) == prec1) {
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
...@@ -3105,7 +3070,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( ...@@ -3105,7 +3070,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
const int next_prec = is_right_associative ? prec1 : prec1 + 1; const int next_prec = is_right_associative ? prec1 : prec1 + 1;
ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK); ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK);
right_range_scope.Finalize(); right_range_scope.Finalize();
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) { if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) {
continue; continue;
...@@ -3171,7 +3136,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( ...@@ -3171,7 +3136,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
} }
ExpressionT expression = ParseUnaryExpression(CHECK_OK); ExpressionT expression = ParseUnaryExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
if (op == Token::DELETE && is_strict(language_mode())) { if (op == Token::DELETE && is_strict(language_mode())) {
if (impl()->IsIdentifier(expression)) { if (impl()->IsIdentifier(expression)) {
...@@ -3200,7 +3165,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( ...@@ -3200,7 +3165,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
expression, beg_pos, scanner()->location().end_pos, expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK); MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
impl()->MarkExpressionAsAssigned(expression); impl()->MarkExpressionAsAssigned(expression);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
return factory()->NewCountOperation(op, return factory()->NewCountOperation(op,
true /* prefix */, true /* prefix */,
...@@ -3245,7 +3210,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( ...@@ -3245,7 +3210,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
expression, lhs_beg_pos, scanner()->location().end_pos, expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK); MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
impl()->MarkExpressionAsAssigned(expression); impl()->MarkExpressionAsAssigned(expression);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
Token::Value next = Next(); Token::Value next = Next();
expression = expression =
...@@ -3270,13 +3235,13 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { ...@@ -3270,13 +3235,13 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
while (true) { while (true) {
switch (peek()) { switch (peek()) {
case Token::LBRACK: { case Token::LBRACK: {
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK); Consume(Token::LBRACK);
int pos = position(); int pos = position();
ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
result = factory()->NewProperty(result, index, pos); result = factory()->NewProperty(result, index, pos);
Expect(Token::RBRACK, CHECK_OK); Expect(Token::RBRACK, CHECK_OK);
break; break;
...@@ -3284,7 +3249,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { ...@@ -3284,7 +3249,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
case Token::LPAREN: { case Token::LPAREN: {
int pos; int pos;
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
if (scanner()->current_token() == Token::IDENTIFIER || if (scanner()->current_token() == Token::IDENTIFIER ||
scanner()->current_token() == Token::SUPER || scanner()->current_token() == Token::SUPER ||
...@@ -3376,7 +3341,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { ...@@ -3376,7 +3341,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
} }
case Token::PERIOD: { case Token::PERIOD: {
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
Consume(Token::PERIOD); Consume(Token::PERIOD);
...@@ -3390,7 +3355,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { ...@@ -3390,7 +3355,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
case Token::TEMPLATE_SPAN: case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: { case Token::TEMPLATE_TAIL: {
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
result = ParseTemplateLiteral(result, position(), true, CHECK_OK); result = ParseTemplateLiteral(result, position(), true, CHECK_OK);
...@@ -3449,7 +3414,7 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async, ...@@ -3449,7 +3414,7 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
} else { } else {
result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK); result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK);
} }
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
if (peek() == Token::LPAREN) { if (peek() == Token::LPAREN) {
// NewExpression with arguments. // NewExpression with arguments.
Scanner::Location spread_pos; Scanner::Location spread_pos;
...@@ -3660,14 +3625,14 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, ...@@ -3660,14 +3625,14 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
switch (peek()) { switch (peek()) {
case Token::LBRACK: { case Token::LBRACK: {
*is_async = false; *is_async = false;
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK); Consume(Token::LBRACK);
int pos = position(); int pos = position();
ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
expression = factory()->NewProperty(expression, index, pos); expression = factory()->NewProperty(expression, index, pos);
impl()->PushPropertyName(index); impl()->PushPropertyName(index);
Expect(Token::RBRACK, CHECK_OK); Expect(Token::RBRACK, CHECK_OK);
...@@ -3675,7 +3640,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, ...@@ -3675,7 +3640,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
} }
case Token::PERIOD: { case Token::PERIOD: {
*is_async = false; *is_async = false;
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
...@@ -3690,7 +3655,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, ...@@ -3690,7 +3655,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
case Token::TEMPLATE_SPAN: case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: { case Token::TEMPLATE_TAIL: {
*is_async = false; *is_async = false;
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken(); BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken(); ArrowFormalParametersUnexpectedToken();
int pos; int pos;
...@@ -3746,7 +3711,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters, ...@@ -3746,7 +3711,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
} }
ExpressionClassifier init_classifier(this); ExpressionClassifier init_classifier(this);
initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void)); initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void)); ValidateExpression(CHECK_OK_CUSTOM(Void));
ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
parameters->is_simple = false; parameters->is_simple = false;
DiscardExpressionClassifier(); DiscardExpressionClassifier();
...@@ -3885,7 +3850,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( ...@@ -3885,7 +3850,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
value = ParseAssignmentExpression(var_context != kForStatement, value = ParseAssignmentExpression(var_context != kForStatement,
CHECK_OK_CUSTOM(NullStatement)); CHECK_OK_CUSTOM(NullStatement));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullStatement)); ValidateExpression(CHECK_OK_CUSTOM(NullStatement));
variable_loc.end_pos = scanner()->location().end_pos; variable_loc.end_pos = scanner()->location().end_pos;
if (!parsing_result->first_initializer_loc.IsValid()) { if (!parsing_result->first_initializer_loc.IsValid()) {
...@@ -4473,7 +4438,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( ...@@ -4473,7 +4438,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
FuncNameInferrer::State fni_state(fni_); FuncNameInferrer::State fni_state(fni_);
ExpressionClassifier extends_classifier(this); ExpressionClassifier extends_classifier(this);
class_info.extends = ParseLeftHandSideExpression(CHECK_OK); class_info.extends = ParseLeftHandSideExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors(); AccumulateFormalParameterContainmentErrors();
} }
...@@ -4505,7 +4470,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( ...@@ -4505,7 +4470,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
class_info.computed_field_count++; class_info.computed_field_count++;
} }
is_constructor &= class_info.has_seen_constructor; is_constructor &= class_info.has_seen_constructor;
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors(); AccumulateFormalParameterContainmentErrors();
impl()->DeclareClassProperty(name, property, property_kind, is_static, impl()->DeclareClassProperty(name, property, property_kind, is_static,
...@@ -4530,7 +4495,7 @@ void ParserBase<Impl>::ParseSingleExpressionFunctionBody(StatementListT body, ...@@ -4530,7 +4495,7 @@ void ParserBase<Impl>::ParseSingleExpressionFunctionBody(StatementListT body,
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK_VOID); ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK_VOID);
impl()->RewriteNonPattern(CHECK_OK_VOID); ValidateExpression(CHECK_OK_VOID);
if (is_async) { if (is_async) {
BlockT block = factory()->NewBlock(1, true); BlockT block = factory()->NewBlock(1, true);
...@@ -4654,7 +4619,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( ...@@ -4654,7 +4619,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
int expr_pos = peek_position(); int expr_pos = peek_position();
ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK); ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
impl()->AddTemplateExpression(&ts, expression); impl()->AddTemplateExpression(&ts, expression);
if (peek() != Token::RBRACE) { if (peek() != Token::RBRACE) {
...@@ -5692,7 +5657,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5692,7 +5657,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
if (is_destructuring) { if (is_destructuring) {
ValidateAssignmentPattern(CHECK_OK); ValidateAssignmentPattern(CHECK_OK);
} else { } else {
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
} }
if (is_for_each) { if (is_for_each) {
...@@ -5755,7 +5720,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( ...@@ -5755,7 +5720,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
if (for_info->mode == ForEachStatement::ITERATE) { if (for_info->mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK); enumerable = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
} else { } else {
enumerable = ParseExpression(true, CHECK_OK); enumerable = ParseExpression(true, CHECK_OK);
} }
...@@ -5831,7 +5796,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ...@@ -5831,7 +5796,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
if (for_info->mode == ForEachStatement::ITERATE) { if (for_info->mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK); enumerable = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
} else { } else {
enumerable = ParseExpression(true, CHECK_OK); enumerable = ParseExpression(true, CHECK_OK);
} }
...@@ -6019,7 +5984,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -6019,7 +5984,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) { if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) {
ValidateAssignmentPattern(CHECK_OK); ValidateAssignmentPattern(CHECK_OK);
} else { } else {
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
each_variable = CheckAndRewriteReferenceExpression( each_variable = CheckAndRewriteReferenceExpression(
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
kSyntaxError, CHECK_OK); kSyntaxError, CHECK_OK);
...@@ -6035,7 +6000,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -6035,7 +6000,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
{ {
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK); iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK); ValidateExpression(CHECK_OK);
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
......
...@@ -1251,7 +1251,6 @@ Statement* Parser::ParseExportDefault(bool* ok) { ...@@ -1251,7 +1251,6 @@ Statement* Parser::ParseExportDefault(bool* ok) {
int pos = position(); int pos = position();
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
Expression* value = ParseAssignmentExpression(true, CHECK_OK); Expression* value = ParseAssignmentExpression(true, CHECK_OK);
RewriteNonPattern(CHECK_OK);
SetFunctionName(value, ast_value_factory()->default_string()); SetFunctionName(value, ast_value_factory()->default_string());
const AstRawString* local_name = const AstRawString* local_name =
...@@ -3810,24 +3809,6 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block, ...@@ -3810,24 +3809,6 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block,
body->Add(block, zone()); body->Add(block, zone());
} }
void Parser::RewriteNonPattern(bool* ok) {
ValidateExpression(CHECK_OK_VOID);
auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite();
int begin = classifier()->GetNonPatternBegin();
int end = non_patterns_to_rewrite->length();
if (begin < end) {
for (int i = begin; i < end; i++) {
RewritableExpression* expr = non_patterns_to_rewrite->at(i);
// TODO(adamk): Make this more typesafe.
DCHECK(expr->expression()->IsArrayLiteral());
ArrayLiteral* lit = expr->expression()->AsArrayLiteral();
expr->Rewrite(RewriteSpreads(lit));
}
non_patterns_to_rewrite->Rewind(begin);
}
}
void Parser::RewriteDestructuringAssignments() { void Parser::RewriteDestructuringAssignments() {
const auto& assignments = const auto& assignments =
function_state_->destructuring_assignments_to_rewrite(); function_state_->destructuring_assignments_to_rewrite();
...@@ -3847,102 +3828,11 @@ void Parser::RewriteDestructuringAssignments() { ...@@ -3847,102 +3828,11 @@ void Parser::RewriteDestructuringAssignments() {
} }
} }
Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
// Array literals containing spreads are rewritten using do expressions, e.g.
// [1, 2, 3, ...x, 4, ...y, 5]
// is roughly rewritten as:
// do {
// $R = [1, 2, 3];
// for ($i of x) %AppendElement($R, $i);
// %AppendElement($R, 4);
// for ($j of y) %AppendElement($R, $j);
// %AppendElement($R, 5);
// $R
// }
// where $R, $i and $j are fresh temporary variables.
ZoneList<Expression*>::iterator s = lit->FirstSpread();
if (s == lit->EndValue()) return nullptr; // no spread, no rewriting...
Variable* result = NewTemporary(ast_value_factory()->dot_result_string());
// NOTE: The value assigned to R is the whole original array literal,
// spreads included. This will be fixed before the rewritten AST is returned.
// $R = lit
Expression* init_result = factory()->NewAssignment(
Token::INIT, factory()->NewVariableProxy(result), lit, kNoSourcePosition);
Block* do_block = factory()->NewBlock(16, false);
do_block->statements()->Add(
factory()->NewExpressionStatement(init_result, kNoSourcePosition),
zone());
// Traverse the array literal starting from the first spread.
while (s != lit->EndValue()) {
Expression* value = *s++;
Spread* spread = value->AsSpread();
if (spread == nullptr) {
// If the element is not a spread, we're adding a single:
// %AppendElement($R, value)
// or, in case of a hole,
// ++($R.length)
if (!value->IsTheHoleLiteral()) {
ZoneList<Expression*>* append_element_args = NewExpressionList(2);
append_element_args->Add(factory()->NewVariableProxy(result), zone());
append_element_args->Add(value, zone());
do_block->statements()->Add(
factory()->NewExpressionStatement(
factory()->NewCallRuntime(Runtime::kAppendElement,
append_element_args,
kNoSourcePosition),
kNoSourcePosition),
zone());
} else {
Property* length_property = factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->length_string(),
kNoSourcePosition),
kNoSourcePosition);
CountOperation* count_op = factory()->NewCountOperation(
Token::INC, true /* prefix */, length_property, kNoSourcePosition);
do_block->statements()->Add(
factory()->NewExpressionStatement(count_op, kNoSourcePosition),
zone());
}
} else {
// If it's a spread, we're adding a for/of loop iterating through it.
Variable* each = NewTemporary(ast_value_factory()->dot_for_string());
Expression* subject = spread->expression();
// %AppendElement($R, each)
Statement* append_body;
{
ZoneList<Expression*>* append_element_args = NewExpressionList(2);
append_element_args->Add(factory()->NewVariableProxy(result), zone());
append_element_args->Add(factory()->NewVariableProxy(each), zone());
append_body = factory()->NewExpressionStatement(
factory()->NewCallRuntime(Runtime::kAppendElement,
append_element_args, kNoSourcePosition),
kNoSourcePosition);
}
// for (each of spread) %AppendElement($R, each)
ForOfStatement* loop =
factory()->NewForOfStatement(nullptr, kNoSourcePosition);
const bool finalize = false;
InitializeForOfStatement(loop, factory()->NewVariableProxy(each), subject,
append_body, finalize, IteratorType::kNormal);
do_block->statements()->Add(loop, zone());
}
}
// Now, rewind the original array literal to truncate everything from the
// first spread (included) until the end. This fixes $R's initialization.
lit->RewindSpreads();
return factory()->NewDoExpression(do_block, result, lit->position());
}
void Parser::QueueDestructuringAssignmentForRewriting( void Parser::QueueDestructuringAssignmentForRewriting(
RewritableExpression* expr) { RewritableExpression* expr) {
function_state_->AddDestructuringAssignment(expr); function_state_->AddDestructuringAssignment(expr);
} }
void Parser::QueueNonPatternForRewriting(RewritableExpression* expr, bool* ok) {
function_state_->AddNonPatternForRewriting(expr, ok);
}
void Parser::SetFunctionNameFromPropertyName(LiteralProperty* property, void Parser::SetFunctionNameFromPropertyName(LiteralProperty* property,
const AstRawString* name, const AstRawString* name,
const AstRawString* prefix) { const AstRawString* prefix) {
......
...@@ -553,13 +553,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -553,13 +553,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* RewriteSpreads(ArrayLiteral* lit); Expression* RewriteSpreads(ArrayLiteral* lit);
// Rewrite expressions that are not used as patterns
V8_INLINE void RewriteNonPattern(bool* ok);
V8_INLINE void QueueDestructuringAssignmentForRewriting( V8_INLINE void QueueDestructuringAssignmentForRewriting(
RewritableExpression* assignment); RewritableExpression* assignment);
V8_INLINE void QueueNonPatternForRewriting(RewritableExpression* expr,
bool* ok);
friend class InitializerRewriter; friend class InitializerRewriter;
void RewriteParameterInitializer(Expression* expr); void RewriteParameterInitializer(Expression* expr);
...@@ -984,10 +979,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -984,10 +979,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return function_state_->GetReportedErrorList(); return function_state_->GetReportedErrorList();
} }
V8_INLINE ZoneList<RewritableExpression*>* GetNonPatternList() const {
return function_state_->non_patterns_to_rewrite();
}
V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) {
++use_counts_[feature]; ++use_counts_[feature];
} }
......
...@@ -999,7 +999,6 @@ class PreParser : public ParserBase<PreParser> { ...@@ -999,7 +999,6 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void RewriteAsyncFunctionBody( V8_INLINE void RewriteAsyncFunctionBody(
PreParserStatementList body, PreParserStatement block, PreParserStatementList body, PreParserStatement block,
const PreParserExpression& return_value, bool* ok) {} const PreParserExpression& return_value, bool* ok) {}
V8_INLINE void RewriteNonPattern(bool* ok) { ValidateExpression(ok); }
void DeclareAndInitializeVariables( void DeclareAndInitializeVariables(
PreParserStatement block, PreParserStatement block,
...@@ -1186,8 +1185,6 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1186,8 +1185,6 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void QueueDestructuringAssignmentForRewriting( V8_INLINE void QueueDestructuringAssignmentForRewriting(
PreParserExpression assignment) {} PreParserExpression assignment) {}
V8_INLINE void QueueNonPatternForRewriting(const PreParserExpression& expr,
bool* ok) {}
// Helper functions for recursive descent. // Helper functions for recursive descent.
V8_INLINE bool IsEval(const PreParserIdentifier& identifier) const { V8_INLINE bool IsEval(const PreParserIdentifier& identifier) const {
...@@ -1665,10 +1662,6 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1665,10 +1662,6 @@ class PreParser : public ParserBase<PreParser> {
return function_state_->GetReportedErrorList(); return function_state_->GetReportedErrorList();
} }
V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const {
return function_state_->non_patterns_to_rewrite();
}
V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) {
if (use_counts_ != nullptr) ++use_counts_[feature]; if (use_counts_ != nullptr) ++use_counts_[feature];
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment