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 {
}
int ArrayLiteral::InitDepthAndFlags() {
DCHECK_LT(first_spread_index_, 0);
if (is_initialized()) return depth();
int constants_length = values()->length();
......@@ -525,7 +524,6 @@ int ArrayLiteral::InitDepthAndFlags() {
int array_index = 0;
for (; array_index < constants_length; array_index++) {
Expression* element = values()->at(array_index);
DCHECK(!element->IsSpread());
MaterializedLiteral* literal = element->AsMaterializedLiteral();
if (literal != nullptr) {
int subliteral_depth = literal->InitDepthAndFlags() + 1;
......@@ -546,11 +544,10 @@ int ArrayLiteral::InitDepthAndFlags() {
}
void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
DCHECK_LT(first_spread_index_, 0);
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;
Handle<FixedArray> fixed_array =
isolate->factory()->NewFixedArrayWithHoles(constants_length);
......@@ -614,11 +611,6 @@ bool ArrayLiteral::IsFastCloningSupported() const {
ConstructorBuiltins::kMaximumClonedShallowArrayElements;
}
void ArrayLiteral::RewindSpreads() {
values_->Rewind(first_spread_index_);
first_spread_index_ = -1;
}
bool MaterializedLiteral::IsSimple() const {
if (IsArrayLiteral()) return AsArrayLiteral()->is_simple();
if (IsObjectLiteral()) return AsObjectLiteral()->is_simple();
......
......@@ -1450,15 +1450,15 @@ class ArrayLiteral final : public AggregateLiteral {
}
// 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_
: values_->end();
}
ZoneList<Expression*>::iterator BeginValue() const {
return values_->begin();
}
ZoneList<Expression*>::iterator EndValue() const { return values_->end(); }
// Rewind an array literal omitting everything from the first spread on.
void RewindSpreads();
private:
friend class AstNodeFactory;
......
......@@ -26,6 +26,7 @@ CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js)
is_iterator_error_ = false;
is_async_iterator_error_ = false;
is_user_js_ = is_user_js;
function_kind_ = kNormalFunction;
InitializeAstVisitor(isolate);
}
......@@ -187,7 +188,10 @@ void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {}
void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
FunctionKind last_function_kind = function_kind_;
function_kind_ = node->kind();
FindStatements(node->body());
function_kind_ = last_function_kind;
}
......@@ -250,7 +254,17 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) {
Print("[");
for (int i = 0; i < node->values()->length(); i++) {
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("]");
}
......@@ -277,7 +291,17 @@ void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
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()); }
......
......@@ -50,6 +50,7 @@ class CallPrinter final : public AstVisitor<CallPrinter> {
bool is_iterator_error_;
bool is_async_iterator_error_;
bool is_call_error_;
FunctionKind function_kind_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
protected:
......
......@@ -835,6 +835,32 @@ class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
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(
CompilationInfo* info, const AstStringConstants* ast_string_constants)
: zone_(info->zone()),
......@@ -2290,31 +2316,25 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->CreateArrayLiteral(entry, literal_index, flags);
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
// subexpressions that use a keyed store IC.
// Evaluate all the non-constant subexpressions and store them into the
// newly cloned array.
bool literal_in_accumulator = true;
FeedbackSlot slot;
for (int array_index = 0; array_index < expr->values()->length();
array_index++) {
Expression* subexpr = expr->values()->at(array_index);
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
int array_index = 0;
ZoneList<Expression*>::iterator iter = expr->BeginValue();
for (; iter != expr->FirstSpreadOrEndValue(); ++iter, array_index++) {
Expression* subexpr = *iter;
DCHECK(!subexpr->IsSpread());
if (literal_in_accumulator) {
index = register_allocator()->NewRegister();
literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
if (slot.IsInvalid()) {
slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
}
builder()
->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index);
......@@ -2323,10 +2343,68 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
language_mode());
}
if (!literal_in_accumulator) {
// Restore literal array into accumulator.
builder()->LoadAccumulatorWithRegister(literal);
// Handle spread elements and elements following.
for (; iter != expr->EndValue(); ++iter) {
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) {
......@@ -2965,10 +3043,10 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
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);
builder()->StoreAccumulatorInRegister(iterator);
builder()->StoreAccumulatorInRegister(iterator.object());
Register input = iterator_and_input[1];
builder()->LoadUndefined().StoreAccumulatorInRegister(input);
builder()
......@@ -3005,7 +3083,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
->LoadNamedProperty(iterator,
->LoadNamedProperty(iterator.object(),
ast_string_constants()->next_string(),
feedback_index(load_slot))
.StoreAccumulatorInRegister(iterator_next)
......@@ -3024,7 +3102,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
->LoadNamedProperty(iterator,
->LoadNamedProperty(iterator.object(),
ast_string_constants()->return_string(),
feedback_index(load_slot))
.JumpIfUndefined(return_input.New())
......@@ -3057,7 +3135,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
->LoadNamedProperty(iterator,
->LoadNamedProperty(iterator.object(),
ast_string_constants()->throw_string(),
feedback_index(load_slot))
.JumpIfUndefined(iterator_throw_is_undefined.New())
......@@ -3079,14 +3157,14 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
->LoadNamedProperty(iterator,
->LoadNamedProperty(iterator.object(),
ast_string_constants()->return_string(),
feedback_index(load_slot))
.StoreAccumulatorInRegister(iterator_return);
builder()
->JumpIfUndefined(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));
if (iterator_type == IteratorType::kAsync) {
......@@ -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) {
builder()->SetExpressionPosition(expr);
BuildGetIterator(expr->iterable(), expr->hint());
......
......@@ -56,6 +56,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class EffectResultScope;
class FeedbackSlotCache;
class GlobalDeclarationsBuilder;
class IteratorRecord;
class NaryCodeCoverageSlots;
class RegisterAllocationScope;
class TestResultScope;
......@@ -150,6 +151,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildAwait(int suspend_id);
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 VisitArgumentsObject(Variable* variable);
......
......@@ -97,14 +97,12 @@ class ExpressionClassifier {
: base_(base),
previous_(base->classifier_),
zone_(base->impl()->zone()),
non_patterns_to_rewrite_(base->impl()->GetNonPatternList()),
reported_errors_(base->impl()->GetReportedErrorList()),
duplicate_finder_(duplicate_finder),
invalid_productions_(0),
function_properties_(0) {
base->classifier_ = this;
reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
non_pattern_begin_ = non_patterns_to_rewrite_->length();
}
V8_INLINE ~ExpressionClassifier() {
......@@ -291,19 +289,10 @@ class ExpressionClassifier {
Add(Error(loc, message, kLetPatternProduction, arg));
}
void Accumulate(ExpressionClassifier* inner, unsigned productions,
bool merge_non_patterns = true) {
void Accumulate(ExpressionClassifier* inner, unsigned productions) {
DCHECK_EQ(inner->reported_errors_, reported_errors_);
DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_);
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
// errors.
unsigned non_arrow_inner_invalid_productions =
......@@ -368,16 +357,12 @@ class ExpressionClassifier {
reported_errors_end_;
}
V8_INLINE int GetNonPatternBegin() const { return non_pattern_begin_; }
V8_INLINE void Discard() {
if (reported_errors_end_ == reported_errors_->length()) {
reported_errors_->Rewind(reported_errors_begin_);
reported_errors_end_ = reported_errors_begin_;
}
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_; }
......@@ -424,16 +409,8 @@ class ExpressionClassifier {
typename Types::Base* base_;
ExpressionClassifier* previous_;
Zone* zone_;
ZoneList<typename Types::RewritableExpression>* non_patterns_to_rewrite_;
ZoneList<Error>* reported_errors_;
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 function_properties_ : 2;
// The uint16_t for reported_errors_begin_ and reported_errors_end_ will
......
......@@ -451,14 +451,6 @@ class ParserBase {
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.
int expected_property_count_;
......@@ -1078,10 +1070,8 @@ class ParserBase {
return ParsePrimaryExpression(&is_async, ok);
}
// This method wraps the parsing of the expression inside a new expression
// classifier and calls RewriteNonPattern if parsing is successful.
// It should be used whenever we're parsing an expression that is known
// to not be a pattern or part of a pattern.
// Use when 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);
// This method does not wrap the parsing of the expression inside a
......@@ -1463,21 +1453,18 @@ class ParserBase {
// Accumulates the classifier that is on top of the stack (inner) to
// the one that is right below (outer) and pops the inner.
V8_INLINE void Accumulate(unsigned productions,
bool merge_non_patterns = true) {
V8_INLINE void Accumulate(unsigned productions) {
DCHECK_NOT_NULL(classifier_);
ExpressionClassifier* previous = classifier_->previous();
DCHECK_NOT_NULL(previous);
previous->Accumulate(classifier_, productions, merge_non_patterns);
previous->Accumulate(classifier_, productions);
classifier_ = previous;
}
V8_INLINE void AccumulateNonBindingPatternErrors() {
static const bool kMergeNonPatterns = true;
this->Accumulate(ExpressionClassifier::AllProductions &
~(ExpressionClassifier::BindingPatternProduction |
ExpressionClassifier::LetPatternProduction),
kMergeNonPatterns);
~(ExpressionClassifier::BindingPatternProduction |
ExpressionClassifier::LetPatternProduction));
}
// Pops and discards the classifier that is on top of the stack
......@@ -1942,7 +1929,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
bool accept_IN, bool* ok) {
ExpressionClassifier classifier(this);
ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
return result;
}
......@@ -2068,22 +2055,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
}
Expect(Token::RBRACK, CHECK_OK);
ExpressionT result =
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;
return factory()->NewArrayLiteral(values, first_spread_index, pos);
}
template <class Impl>
......@@ -2198,7 +2170,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
Consume(Token::LBRACK);
ExpressionClassifier computed_name_classifier(this);
expression = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors();
Expect(Token::RBRACK, CHECK_OK);
break;
......@@ -2441,7 +2413,7 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info,
initializer =
ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpression));
ValidateExpression(CHECK_OK_CUSTOM(NullExpression));
} else {
initializer = factory()->NewUndefinedLiteral(kNoSourcePosition);
}
......@@ -2560,7 +2532,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
ExpressionClassifier rhs_classifier(this);
ExpressionT rhs = ParseAssignmentExpression(
true, CHECK_OK_CUSTOM(NullLiteralProperty));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullLiteralProperty));
ValidateExpression(CHECK_OK_CUSTOM(NullLiteralProperty));
AccumulateFormalParameterContainmentErrors();
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
kNoSourcePosition);
......@@ -2738,7 +2710,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
*is_simple_parameter_list = false;
}
if (!maybe_arrow) {
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList));
ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList));
}
if (is_spread) {
if (is_simple_parameter_list != nullptr) {
......@@ -2784,7 +2756,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
if (!maybe_arrow || peek() != Token::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) {
productions &= ~ExpressionClassifier::ExpressionProduction;
}
if (!Token::IsAssignmentOp(peek())) {
// Parsed conditional expression only (no assignment).
// Pending non-pattern expressions must be merged.
Accumulate(productions);
return expression;
} else {
// Pending non-pattern expressions must be discarded.
Accumulate(productions, false);
}
Accumulate(productions);
if (!Token::IsAssignmentOp(peek())) return expression;
if (is_destructuring_assignment) {
ValidateAssignmentPattern(CHECK_OK);
......@@ -2945,7 +2910,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
ExpressionClassifier rhs_classifier(this);
ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors();
// 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(
// Delegating yields require an RHS; fall through.
default:
expression = ParseAssignmentExpression(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
break;
}
}
......@@ -3052,7 +3017,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// We start using the binary expression parser for prec >= 4 only!
ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
if (peek() != Token::CONDITIONAL) return expression;
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -3067,7 +3032,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
left = ParseAssignmentExpression(true, CHECK_OK);
AccumulateNonBindingPatternErrors();
}
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
ExpressionT right;
{
SourceRangeScope range_scope(scanner(), &else_range);
......@@ -3076,7 +3041,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
right = ParseAssignmentExpression(accept_IN, CHECK_OK);
AccumulateNonBindingPatternErrors();
}
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
ExpressionT expr = factory()->NewConditional(expression, left, right, pos);
impl()->RecordConditionalSourceRange(expr, then_range, else_range);
return expr;
......@@ -3093,7 +3058,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
// prec1 >= 4
while (Precedence(peek(), accept_IN) == prec1) {
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -3105,7 +3070,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
const int next_prec = is_right_associative ? prec1 : prec1 + 1;
ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK);
right_range_scope.Finalize();
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) {
continue;
......@@ -3171,7 +3136,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
}
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
if (op == Token::DELETE && is_strict(language_mode())) {
if (impl()->IsIdentifier(expression)) {
......@@ -3200,7 +3165,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
impl()->MarkExpressionAsAssigned(expression);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
return factory()->NewCountOperation(op,
true /* prefix */,
......@@ -3245,7 +3210,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
impl()->MarkExpressionAsAssigned(expression);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
Token::Value next = Next();
expression =
......@@ -3270,13 +3235,13 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
while (true) {
switch (peek()) {
case Token::LBRACK: {
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK);
int pos = position();
ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
result = factory()->NewProperty(result, index, pos);
Expect(Token::RBRACK, CHECK_OK);
break;
......@@ -3284,7 +3249,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
case Token::LPAREN: {
int pos;
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
if (scanner()->current_token() == Token::IDENTIFIER ||
scanner()->current_token() == Token::SUPER ||
......@@ -3376,7 +3341,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
}
case Token::PERIOD: {
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
Consume(Token::PERIOD);
......@@ -3390,7 +3355,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
result = ParseTemplateLiteral(result, position(), true, CHECK_OK);
......@@ -3449,7 +3414,7 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
} else {
result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK);
}
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
if (peek() == Token::LPAREN) {
// NewExpression with arguments.
Scanner::Location spread_pos;
......@@ -3660,14 +3625,14 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
switch (peek()) {
case Token::LBRACK: {
*is_async = false;
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK);
int pos = position();
ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
expression = factory()->NewProperty(expression, index, pos);
impl()->PushPropertyName(index);
Expect(Token::RBRACK, CHECK_OK);
......@@ -3675,7 +3640,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
}
case Token::PERIOD: {
*is_async = false;
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -3690,7 +3655,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
*is_async = false;
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
int pos;
......@@ -3746,7 +3711,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
}
ExpressionClassifier init_classifier(this);
initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void));
ValidateExpression(CHECK_OK_CUSTOM(Void));
ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
parameters->is_simple = false;
DiscardExpressionClassifier();
......@@ -3885,7 +3850,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
ExpressionClassifier classifier(this);
value = ParseAssignmentExpression(var_context != kForStatement,
CHECK_OK_CUSTOM(NullStatement));
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullStatement));
ValidateExpression(CHECK_OK_CUSTOM(NullStatement));
variable_loc.end_pos = scanner()->location().end_pos;
if (!parsing_result->first_initializer_loc.IsValid()) {
......@@ -4473,7 +4438,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
FuncNameInferrer::State fni_state(fni_);
ExpressionClassifier extends_classifier(this);
class_info.extends = ParseLeftHandSideExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors();
}
......@@ -4505,7 +4470,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
class_info.computed_field_count++;
}
is_constructor &= class_info.has_seen_constructor;
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors();
impl()->DeclareClassProperty(name, property, property_kind, is_static,
......@@ -4530,7 +4495,7 @@ void ParserBase<Impl>::ParseSingleExpressionFunctionBody(StatementListT body,
ExpressionClassifier classifier(this);
ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK_VOID);
impl()->RewriteNonPattern(CHECK_OK_VOID);
ValidateExpression(CHECK_OK_VOID);
if (is_async) {
BlockT block = factory()->NewBlock(1, true);
......@@ -4654,7 +4619,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
int expr_pos = peek_position();
ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
impl()->AddTemplateExpression(&ts, expression);
if (peek() != Token::RBRACE) {
......@@ -5692,7 +5657,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
if (is_destructuring) {
ValidateAssignmentPattern(CHECK_OK);
} else {
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
}
if (is_for_each) {
......@@ -5755,7 +5720,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
if (for_info->mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
} else {
enumerable = ParseExpression(true, CHECK_OK);
}
......@@ -5831,7 +5796,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
if (for_info->mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
} else {
enumerable = ParseExpression(true, CHECK_OK);
}
......@@ -6019,7 +5984,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) {
ValidateAssignmentPattern(CHECK_OK);
} else {
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
each_variable = CheckAndRewriteReferenceExpression(
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
kSyntaxError, CHECK_OK);
......@@ -6035,7 +6000,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
{
ExpressionClassifier classifier(this);
iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
ValidateExpression(CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
......
......@@ -1251,7 +1251,6 @@ Statement* Parser::ParseExportDefault(bool* ok) {
int pos = position();
ExpressionClassifier classifier(this);
Expression* value = ParseAssignmentExpression(true, CHECK_OK);
RewriteNonPattern(CHECK_OK);
SetFunctionName(value, ast_value_factory()->default_string());
const AstRawString* local_name =
......@@ -3810,24 +3809,6 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block,
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() {
const auto& assignments =
function_state_->destructuring_assignments_to_rewrite();
......@@ -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(
RewritableExpression* expr) {
function_state_->AddDestructuringAssignment(expr);
}
void Parser::QueueNonPatternForRewriting(RewritableExpression* expr, bool* ok) {
function_state_->AddNonPatternForRewriting(expr, ok);
}
void Parser::SetFunctionNameFromPropertyName(LiteralProperty* property,
const AstRawString* name,
const AstRawString* prefix) {
......
......@@ -553,13 +553,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* RewriteSpreads(ArrayLiteral* lit);
// Rewrite expressions that are not used as patterns
V8_INLINE void RewriteNonPattern(bool* ok);
V8_INLINE void QueueDestructuringAssignmentForRewriting(
RewritableExpression* assignment);
V8_INLINE void QueueNonPatternForRewriting(RewritableExpression* expr,
bool* ok);
friend class InitializerRewriter;
void RewriteParameterInitializer(Expression* expr);
......@@ -984,10 +979,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
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) {
++use_counts_[feature];
}
......
......@@ -999,7 +999,6 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void RewriteAsyncFunctionBody(
PreParserStatementList body, PreParserStatement block,
const PreParserExpression& return_value, bool* ok) {}
V8_INLINE void RewriteNonPattern(bool* ok) { ValidateExpression(ok); }
void DeclareAndInitializeVariables(
PreParserStatement block,
......@@ -1186,8 +1185,6 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void QueueDestructuringAssignmentForRewriting(
PreParserExpression assignment) {}
V8_INLINE void QueueNonPatternForRewriting(const PreParserExpression& expr,
bool* ok) {}
// Helper functions for recursive descent.
V8_INLINE bool IsEval(const PreParserIdentifier& identifier) const {
......@@ -1665,10 +1662,6 @@ class PreParser : public ParserBase<PreParser> {
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) {
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