Commit 5e725a2b authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[parser] Don't desugar destructuring declarations.

Emit a single destructuring assignment for destructuring declarations,
which can be desugared by the bytecode generator. This allows us to
remove destructuring desugaring from the parser (specifically, the
pattern rewriter) entirely.

The pattern "rewriter" is now only responsible for walking the
destructuring pattern to declare variables, mark them assigned, and
potentially rewrite scopes for the edge case of parameters with a sloppy
eval.

Note that since the rewriter is no longer rewriting, we have to flip the
VariableProxy copying logic for var re-lookup, so that we now pass the
new VariableProxy to the variable declaration and leave the original
unresolved (rather than passing the original through and rewriting to a
new unresolved VariableProxy).

This change does have some effect on breakpoint locations, due to some
of the available information changing between the parser and bytecode
generator, however the new locations appear to be more consistent
between assignments and declarations.

Change-Id: I3a58dd0a387d2bfb8e5e9e22dde0acc5f440cb82
Reviewed-on: https://chromium-review.googlesource.com/c/1382462
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58670}
parent 5f138ac1
......@@ -2730,34 +2730,14 @@ class GetIterator final : public Expression {
Expression* iterable() const { return iterable_; }
Expression* iterable_for_call_printer() const {
return destructured_iterable_ != nullptr ? destructured_iterable_
: iterable_;
}
private:
friend class AstNodeFactory;
GetIterator(Expression* iterable, Expression* destructured_iterable,
IteratorType hint, int pos)
: Expression(pos, kGetIterator),
hint_(hint),
iterable_(iterable),
destructured_iterable_(destructured_iterable) {}
GetIterator(Expression* iterable, IteratorType hint, int pos)
: Expression(pos, kGetIterator),
hint_(hint),
iterable_(iterable),
destructured_iterable_(nullptr) {}
: Expression(pos, kGetIterator), hint_(hint), iterable_(iterable) {}
IteratorType hint_;
Expression* iterable_;
// iterable_ is the variable proxy, while destructured_iterable_ points to
// the raw value stored in the variable proxy. This is only used for
// pretty printing error messages.
Expression* destructured_iterable_;
};
// Represents the spec operation `GetTemplateObject(templateLiteral)`
......@@ -3397,12 +3377,6 @@ class AstNodeFactory final {
return new (zone_) EmptyParentheses(pos);
}
GetIterator* NewGetIterator(Expression* iterable,
Expression* destructured_iterable,
IteratorType hint, int pos) {
return new (zone_) GetIterator(iterable, destructured_iterable, hint, pos);
}
GetIterator* NewGetIterator(Expression* iterable, IteratorType hint,
int pos) {
return new (zone_) GetIterator(iterable, hint, pos);
......
......@@ -285,7 +285,24 @@ void CallPrinter::VisitVariableProxy(VariableProxy* node) {
void CallPrinter::VisitAssignment(Assignment* node) {
Find(node->target());
Find(node->value());
if (node->target()->IsArrayLiteral()) {
// Special case the visit for destructuring array assignment.
bool was_found = false;
if (node->value()->position() == position_) {
is_iterator_error_ = true;
was_found = !found_;
if (was_found) {
found_ = true;
}
}
Find(node->value(), true);
if (was_found) {
done_ = true;
found_ = false;
}
} else {
Find(node->value());
}
}
void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
......@@ -347,7 +364,7 @@ void CallPrinter::VisitCall(Call* node) {
found_ = true;
}
Find(node->expression(), true);
if (!was_found) Print("(...)");
if (!was_found && !is_iterator_error_) Print("(...)");
FindArguments(node->arguments());
if (was_found) {
done_ = true;
......@@ -371,7 +388,7 @@ void CallPrinter::VisitCallNew(CallNew* node) {
}
found_ = true;
}
Find(node->expression(), was_found);
Find(node->expression(), was_found || is_iterator_error_);
FindArguments(node->arguments());
if (was_found) {
done_ = true;
......@@ -465,7 +482,7 @@ void CallPrinter::VisitGetIterator(GetIterator* node) {
found_ = true;
}
}
Find(node->iterable_for_call_printer(), true);
Find(node->iterable(), true);
if (was_found) {
done_ = true;
found_ = false;
......
......@@ -3197,7 +3197,8 @@ Expression* BytecodeGenerator::GetDestructuringDefaultValue(
// %FinalizeIteration(iterator, done, iteration_continuation)
// }
void BytecodeGenerator::BuildDestructuringArrayAssignment(
ArrayLiteral* pattern) {
ArrayLiteral* pattern, Token::Value op,
LookupHoistingMode lookup_hoisting_mode) {
RegisterAllocationScope scope(this);
Register value = register_allocator()->NewRegister();
......@@ -3302,8 +3303,7 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
}
builder()->Bind(&do_assignment);
// TODO(leszeks): This should be the position of the assignment.
BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
BuildAssignment(lhs_data, op, lookup_hoisting_mode);
} else {
DCHECK_EQ(lhs_data.assign_type(), NON_PROPERTY);
is_done.Bind(builder());
......@@ -3312,10 +3312,14 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
if (spread) {
RegisterAllocationScope scope(this);
builder()->SetExpressionAsStatementPosition(spread);
// A spread is turned into a loop over the remainer of the iterator.
Expression* target = spread->expression();
if (!target->IsPattern()) {
builder()->SetExpressionAsStatementPosition(spread);
}
AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
// var array = [];
......@@ -3339,7 +3343,7 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
// Assign the array to the LHS.
builder()->LoadAccumulatorWithRegister(array);
BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
BuildAssignment(lhs_data, op, lookup_hoisting_mode);
}
}
try_control_builder.EndTry();
......@@ -3393,7 +3397,8 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
//
// b.c = %CopyDataPropertiesWithExcludedProperties.call(rest_runtime_callargs);
void BytecodeGenerator::BuildDestructuringObjectAssignment(
ObjectLiteral* pattern) {
ObjectLiteral* pattern, Token::Value op,
LookupHoistingMode lookup_hoisting_mode) {
RegisterAllocationScope scope(this);
// if (value === null || value === undefined)
......@@ -3411,6 +3416,7 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
// TODO(leszeks): Don't do this calculation here, but instead do it in a
// runtime method.
auto source_position = pattern->position();
const AstRawString* property_name = ast_string_constants()->empty_string();
MessageTemplate msg = MessageTemplate::kNonCoercible;
for (ObjectLiteralProperty* pattern_property : *pattern->properties()) {
......@@ -3418,12 +3424,14 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
if (key->IsPropertyName()) {
property_name = key->AsLiteral()->AsRawPropertyName();
msg = MessageTemplate::kNonCoercibleWithProperty;
source_position = key->position();
break;
}
}
RegisterList new_type_error_args = register_allocator()->NewRegisterList(2);
// throw %NewTypeError(msg, property_name, source_position)
builder()->SetExpressionPosition(source_position);
builder()
->LoadLiteral(Smi::FromEnum(msg))
.StoreAccumulatorInRegister(new_type_error_args[0])
......@@ -3528,7 +3536,7 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
builder()->Bind(&value_not_undefined);
}
BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
BuildAssignment(lhs_data, op, lookup_hoisting_mode);
i++;
}
......@@ -3546,14 +3554,10 @@ void BytecodeGenerator::BuildAssignment(
case NON_PROPERTY: {
if (ObjectLiteral* pattern = lhs_data.expr()->AsObjectLiteral()) {
// Split object literals into destructuring.
DCHECK_EQ(op, Token::ASSIGN);
DCHECK_EQ(lookup_hoisting_mode, LookupHoistingMode::kNormal);
BuildDestructuringObjectAssignment(pattern);
BuildDestructuringObjectAssignment(pattern, op, lookup_hoisting_mode);
} else if (ArrayLiteral* pattern = lhs_data.expr()->AsArrayLiteral()) {
// Split object literals into destructuring.
DCHECK_EQ(op, Token::ASSIGN);
DCHECK_EQ(lookup_hoisting_mode, LookupHoistingMode::kNormal);
BuildDestructuringArrayAssignment(pattern);
BuildDestructuringArrayAssignment(pattern, op, lookup_hoisting_mode);
} else {
DCHECK(lhs_data.expr()->IsVariableProxy());
VariableProxy* proxy = lhs_data.expr()->AsVariableProxy();
......
......@@ -200,8 +200,12 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
LookupHoistingMode lookup_hoisting_mode);
Expression* GetDestructuringDefaultValue(Expression** target);
void BuildDestructuringArrayAssignment(ArrayLiteral* pattern);
void BuildDestructuringObjectAssignment(ObjectLiteral* pattern);
void BuildDestructuringArrayAssignment(
ArrayLiteral* pattern, Token::Value op,
LookupHoistingMode lookup_hoisting_mode);
void BuildDestructuringObjectAssignment(
ObjectLiteral* pattern, Token::Value op,
LookupHoistingMode lookup_hoisting_mode);
void BuildLoadNamedProperty(const Expression* object_expr, Register object,
const AstRawString* name);
......
......@@ -12,6 +12,19 @@ namespace v8 {
namespace internal {
// An AST visitor which performs declaration and assignment related tasks,
// particularly for destructuring patterns:
//
// 1. Declares variables from variable proxies (particularly for destructuring
// declarations),
// 2. Marks destructuring-assigned variable proxies as assigned, and
// 3. Rewrites scopes for parameters containing a sloppy eval.
//
// Historically this also rewrote destructuring assignments/declarations as a
// block of multiple assignments, hence the named, however this is now done
// during bytecode generation.
//
// TODO(leszeks): Rename or remove this class
class PatternRewriter final : public AstVisitor<PatternRewriter> {
public:
// Limit the allowed number of local variables in a function. The hard limit
......@@ -32,75 +45,41 @@ class PatternRewriter final : public AstVisitor<PatternRewriter> {
ZonePtrList<const AstRawString>* names);
private:
enum PatternContext : uint8_t { BINDING, ASSIGNMENT };
PatternRewriter(Parser* parser, PatternContext context,
const DeclarationDescriptor* descriptor = nullptr,
ZonePtrList<const AstRawString>* names = nullptr,
PatternRewriter(Parser* parser, const DeclarationDescriptor* descriptor,
ZonePtrList<const AstRawString>* names, bool has_initializer,
int initializer_position = kNoSourcePosition,
int value_beg_position = kNoSourcePosition,
bool declares_parameter_containing_sloppy_eval = false)
: parser_(parser),
block_(nullptr),
descriptor_(descriptor),
names_(names),
current_value_(nullptr),
initializer_position_(initializer_position),
value_beg_position_(value_beg_position),
context_(context),
has_initializer_(has_initializer),
declares_parameter_containing_sloppy_eval_(
declares_parameter_containing_sloppy_eval),
recursion_level_(0) {}
declares_parameter_containing_sloppy_eval) {}
#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
// Visiting functions for AST nodes make this an AstVisitor.
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
PatternContext context() const { return context_; }
void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
Expression* old_value = current_value_;
current_value_ = value;
recursion_level_++;
Visit(pattern);
recursion_level_--;
current_value_ = old_value;
}
void RecurseIntoSubpattern(AstNode* pattern) { Visit(pattern); }
Expression* Rewrite(Assignment* assign) {
Expression* Visit(Assignment* assign) {
if (parser_->has_error()) return parser_->FailureExpression();
DCHECK_EQ(Token::ASSIGN, assign->op());
int pos = assign->position();
DCHECK_NULL(block_);
block_ = factory()->NewBlock(8, true);
Variable* temp = nullptr;
Expression* pattern = assign->target();
Expression* old_value = current_value_;
current_value_ = assign->value();
if (pattern->IsObjectLiteral()) {
VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
VisitObjectLiteral(pattern->AsObjectLiteral());
} else {
DCHECK(pattern->IsArrayLiteral());
VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
VisitArrayLiteral(pattern->AsArrayLiteral());
}
DCHECK_NOT_NULL(temp);
current_value_ = old_value;
return factory()->NewDoExpression(block_, temp, pos);
return assign;
}
void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);
bool IsBindingContext() const { return context_ == BINDING; }
bool IsAssignmentContext() const { return context_ == ASSIGNMENT; }
bool IsSubPattern() const { return recursion_level_ > 1; }
void RewriteParameterScopes(Expression* expr);
Variable* CreateTempVar(Expression* value = nullptr);
AstNodeFactory* factory() const { return parser_->factory(); }
AstValueFactory* ast_value_factory() const {
return parser_->ast_value_factory();
......@@ -112,15 +91,11 @@ class PatternRewriter final : public AstVisitor<PatternRewriter> {
Scope* scope() const { return parser_->scope(); }
Parser* const parser_;
Block* block_;
const DeclarationDescriptor* descriptor_;
ZonePtrList<const AstRawString>* names_;
Expression* current_value_;
const int initializer_position_;
const int value_beg_position_;
PatternContext context_;
const bool declares_parameter_containing_sloppy_eval_ : 1;
int recursion_level_;
const bool has_initializer_;
const bool declares_parameter_containing_sloppy_eval_;
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
......@@ -132,6 +107,17 @@ void Parser::InitializeVariables(
if (has_error()) return;
PatternRewriter::InitializeVariables(this, block, declaration_descriptor,
declaration, names);
if (declaration->initializer) {
int pos = declaration->value_beg_position;
if (pos == kNoSourcePosition) {
pos = declaration->initializer_position;
}
Assignment* assignment = factory()->NewAssignment(
Token::INIT, declaration->pattern, declaration->initializer, pos);
block->statements()->Add(factory()->NewExpressionStatement(assignment, pos),
zone());
}
}
void PatternRewriter::InitializeVariables(
......@@ -141,38 +127,39 @@ void PatternRewriter::InitializeVariables(
ZonePtrList<const AstRawString>* names) {
DCHECK(block->ignore_completion_value());
PatternRewriter rewriter(parser, BINDING, declaration_descriptor, names,
PatternRewriter rewriter(parser, declaration_descriptor, names,
declaration->initializer != nullptr,
declaration->initializer_position,
declaration->value_beg_position,
declaration_descriptor->declaration_kind ==
DeclarationDescriptor::PARAMETER &&
parser->scope()->is_block_scope());
rewriter.block_ = block;
rewriter.RecurseIntoSubpattern(declaration->pattern,
declaration->initializer);
rewriter.RecurseIntoSubpattern(declaration->pattern);
}
void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
Expression* value = current_value_;
if (IsAssignmentContext()) {
// In an assignment context, simply perform the assignment
Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, proxy,
value, proxy->position());
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, proxy->position()),
zone());
return;
}
DCHECK_NOT_NULL(block_);
DCHECK_NOT_NULL(descriptor_);
Scope* target_scope = scope();
if (declares_parameter_containing_sloppy_eval_) {
// When an extra declaration scope needs to be inserted to account for
// a sloppy eval in a default parameter or function body, the parameter
// needs to be declared in the function's scope, not in the varblock
// scope which will be used for the initializer expression.
DCHECK_EQ(descriptor_->mode, VariableMode::kLet);
target_scope = target_scope->outer_scope();
}
Scope* var_init_scope = scope();
#ifdef DEBUG
// Calculate the scope we expect the variable to be declared in, for DCHECKs.
Scope* expected_declaration_scope =
declares_parameter_containing_sloppy_eval_
? scope()->outer_scope()
: (IsLexicalVariableMode(descriptor_->mode)
? scope()
: scope()->GetDeclarationScope());
#endif
// Declare variable.
// Note that we *always* must treat the initial value via a separate init
......@@ -182,10 +169,34 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
// which the variable or constant is declared. Only function variables have
// an initial value in the declaration (because they are initialized upon
// entering the function).
// When an extra declaration scope needs to be inserted to account for
// a sloppy eval in a default parameter or function body, the parameter
// needs to be declared in the function's scope, not in the varblock
// scope which will be used for the initializer expression.
// A declaration of the form:
//
// var v = x;
//
// is syntactic sugar for:
//
// var v; v = x;
//
// In particular, we need to re-lookup 'v' if it may be a different 'v' than
// the 'v' in the declaration (e.g., if we are inside a 'with' statement or
// 'catch' block).
//
// For 'let' and 'const' declared variables the initialization always assigns
// to the declared variable. But for var initializations that are declared in
// a different scope we need to do a new lookup, so clone the variable for the
// declaration and don't consider the original variable resolved.
if (has_initializer_ && descriptor_->mode == VariableMode::kVar &&
!var_init_scope->is_declaration_scope()) {
DCHECK_EQ(target_scope->GetDeclarationScope(), expected_declaration_scope);
// The cloned variable is not added to the unresolved list of the target
// scope, as it is about to be resolved by the declaration. The original
// variable will be left unresolved for now.
var_init_scope->AddUnresolved(proxy);
proxy = factory()->NewVariableProxy(proxy->raw_name(), NORMAL_VARIABLE,
proxy->position());
}
parser_->DeclareVariable(
proxy, descriptor_->declaration_kind, descriptor_->mode,
Variable::DefaultInitializationFlag(descriptor_->mode), target_scope,
......@@ -195,15 +206,11 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
Variable* var = proxy->var();
DCHECK_NOT_NULL(var);
DCHECK(proxy->is_resolved());
DCHECK_EQ(var->scope(), expected_declaration_scope);
DCHECK_NE(initializer_position_, kNoSourcePosition);
var->set_initializer_position(initializer_position_);
Scope* declaration_scope = var->scope();
DCHECK_EQ(declaration_scope, declares_parameter_containing_sloppy_eval_
? scope()->outer_scope()
: (IsLexicalVariableMode(descriptor_->mode)
? scope()
: scope()->GetDeclarationScope()));
if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
if (var->scope()->num_var() > kMaxNumFunctionLocals) {
parser_->ReportMessage(MessageTemplate::kTooManyVariables);
return;
}
......@@ -212,57 +219,10 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
}
// If there's no initializer, we're done.
if (value == nullptr) return;
if (!has_initializer_) return;
Scope* var_init_scope = scope();
Parser::MarkLoopVariableAsAssigned(var_init_scope, proxy->var(),
descriptor_->declaration_kind);
// A declaration of the form:
//
// var v = x;
//
// is syntactic sugar for:
//
// var v; v = x;
//
// In particular, we need to re-lookup 'v' if it may be a different 'v' than
// the 'v' in the declaration (e.g., if we are inside a 'with' statement or
// 'catch' block).
// For 'let' and 'const' declared variables the initialization always assigns
// to the declared variable. But for var declarations that target a different
// scope we need to do a new lookup.
if (descriptor_->mode == VariableMode::kVar &&
var_init_scope != declaration_scope) {
proxy = var_init_scope->NewUnresolved(factory(), proxy->raw_name());
} else {
DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(proxy->var());
}
// Add break location for destructured sub-pattern.
int pos = value_beg_position_;
if (pos == kNoSourcePosition) {
pos = IsSubPattern() ? proxy->position() : value->position();
}
Assignment* assignment =
factory()->NewAssignment(Token::INIT, proxy, value, pos);
block_->statements()->Add(factory()->NewExpressionStatement(assignment, pos),
zone());
}
Variable* PatternRewriter::CreateTempVar(Expression* value) {
auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
if (value != nullptr) {
auto assignment = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), value,
kNoSourcePosition);
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, kNoSourcePosition),
zone());
}
return temp;
}
// When an extra declaration scope needs to be inserted to account for
......@@ -275,371 +235,38 @@ void PatternRewriter::RewriteParameterScopes(Expression* expr) {
}
}
void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
Variable** temp_var) {
auto temp = *temp_var = CreateTempVar(current_value_);
ScopedPtrList<Expression> rest_runtime_callargs(pointer_buffer());
if (pattern->has_rest_property()) {
rest_runtime_callargs.Add(factory()->NewVariableProxy(temp));
}
block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
zone());
void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
for (ObjectLiteralProperty* property : *pattern->properties()) {
Expression* value;
if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
// var { y, [x++]: a, ...c } = temp
// becomes
// var y = temp.y;
// var temp1 = %ToName(x++);
// var a = temp[temp1];
// var c;
// c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
value = factory()->NewCallRuntime(
Runtime::kCopyDataPropertiesWithExcludedProperties,
rest_runtime_callargs, kNoSourcePosition);
} else {
Expression* key = property->key();
if (!key->IsLiteral()) {
// Computed property names contain expressions which might require
// scope rewriting.
RewriteParameterScopes(key);
}
if (pattern->has_rest_property()) {
Expression* excluded_property = key;
if (property->is_computed_name()) {
DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
ScopedPtrList<Expression> args(pointer_buffer());
args.Add(key);
auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
Runtime::kToName, args, kNoSourcePosition));
key = factory()->NewVariableProxy(to_name_key);
excluded_property = factory()->NewVariableProxy(to_name_key);
} else {
DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
}
rest_runtime_callargs.Add(excluded_property);
}
value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
kNoSourcePosition);
Expression* key = property->key();
if (!key->IsLiteral()) {
// Computed property names contain expressions which might require
// scope rewriting.
RewriteParameterScopes(key);
}
RecurseIntoSubpattern(property->value(), value);
RecurseIntoSubpattern(property->value());
}
}
void PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
Variable* temp_var = nullptr;
VisitObjectLiteral(node, &temp_var);
}
void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
Variable** temp_var) {
DCHECK(block_->ignore_completion_value());
auto temp = *temp_var = CreateTempVar(current_value_);
auto iterator = CreateTempVar(factory()->NewGetIterator(
factory()->NewVariableProxy(temp), current_value_, IteratorType::kNormal,
current_value_->position()));
auto next = CreateTempVar(factory()->NewProperty(
factory()->NewVariableProxy(iterator),
factory()->NewStringLiteral(ast_value_factory()->next_string(),
kNoSourcePosition),
kNoSourcePosition));
auto done =
CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
auto result = CreateTempVar();
auto v = CreateTempVar();
auto completion = CreateTempVar();
auto nopos = kNoSourcePosition;
// For the purpose of iterator finalization, we temporarily set block_ to a
// new block. In the main body of this function, we write to block_ (both
// explicitly and implicitly via recursion). At the end of the function, we
// wrap this new block in a try-finally statement, restore block_ to its
// original value, and add the try-finally statement to block_.
auto target = block_;
block_ = factory()->NewBlock(8, true);
Spread* spread = nullptr;
void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
for (Expression* value : *node->values()) {
if (value->IsSpread()) {
spread = value->AsSpread();
break;
}
// if (!done) {
// done = true; // If .next, .done or .value throws, don't close.
// result = IteratorNext(iterator);
// if (result.done) {
// v = undefined;
// } else {
// v = result.value;
// done = false;
// }
// }
Statement* if_not_done;
{
auto result_done = factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->done_string(),
kNoSourcePosition),
kNoSourcePosition);
auto assign_undefined = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(v),
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
auto assign_value = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(v),
factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->value_string(),
kNoSourcePosition),
kNoSourcePosition),
kNoSourcePosition);
auto unset_done = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(false, kNoSourcePosition),
kNoSourcePosition);
auto inner_else = factory()->NewBlock(2, true);
inner_else->statements()->Add(
factory()->NewExpressionStatement(assign_value, nopos), zone());
inner_else->statements()->Add(
factory()->NewExpressionStatement(unset_done, nopos), zone());
auto inner_if = factory()->NewIfStatement(
result_done,
factory()->NewExpressionStatement(assign_undefined, nopos),
inner_else, nopos);
auto next_block = factory()->NewBlock(3, true);
next_block->statements()->Add(
factory()->NewExpressionStatement(
factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(true, nopos), nopos),
nopos),
zone());
next_block->statements()->Add(
factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult(
factory()->NewVariableProxy(iterator),
factory()->NewVariableProxy(next), result,
IteratorType::kNormal, kNoSourcePosition),
kNoSourcePosition),
zone());
next_block->statements()->Add(inner_if, zone());
if_not_done = factory()->NewIfStatement(
factory()->NewUnaryOperation(
Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
next_block, factory()->EmptyStatement(), kNoSourcePosition);
}
block_->statements()->Add(if_not_done, zone());
if (!value->IsTheHoleLiteral()) {
{
// completion = kAbruptCompletion;
Expression* proxy = factory()->NewVariableProxy(completion);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, proxy,
factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, nopos), zone());
}
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
{
// completion = kNormalCompletion;
Expression* proxy = factory()->NewVariableProxy(completion);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, proxy,
factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, nopos), zone());
}
}
}
if (spread != nullptr) {
// A spread can only occur as the last component. It is not handled by
// RecurseIntoSubpattern above.
// let array = [];
// let index = 0;
// while (!done) {
// done = true; // If .next, .done or .value throws, don't close.
// result = IteratorNext(iterator);
// if (!result.done) {
// StoreInArrayLiteral(array, index, result.value);
// done = false;
// }
// index++;
// }
// let array = [];
Variable* array;
{
ScopedPtrList<Expression> empty_exprs(pointer_buffer());
array = CreateTempVar(
factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
}
// let index = 0;
Variable* index =
CreateTempVar(factory()->NewSmiLiteral(0, kNoSourcePosition));
// done = true;
Statement* set_done = factory()->NewExpressionStatement(
factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(true, nopos), nopos),
nopos);
// result = IteratorNext(iterator);
Statement* get_next = factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
factory()->NewVariableProxy(next),
result, IteratorType::kNormal, nopos),
nopos);
// StoreInArrayLiteral(array, index, result.value);
Statement* store;
{
auto value = factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->value_string(),
nopos),
nopos);
store = factory()->NewExpressionStatement(
factory()->NewStoreInArrayLiteral(factory()->NewVariableProxy(array),
factory()->NewVariableProxy(index),
value, nopos),
nopos);
}
// done = false;
Statement* unset_done = factory()->NewExpressionStatement(
factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(false, nopos), nopos),
nopos);
// if (!result.done) { #store; #unset_done }
Statement* maybe_store_and_unset_done;
{
Expression* result_done =
factory()->NewProperty(factory()->NewVariableProxy(result),
factory()->NewStringLiteral(
ast_value_factory()->done_string(), nopos),
nopos);
Block* then = factory()->NewBlock(2, true);
then->statements()->Add(store, zone());
then->statements()->Add(unset_done, zone());
maybe_store_and_unset_done = factory()->NewIfStatement(
factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
factory()->EmptyStatement(), nopos);
}
// index++;
Statement* increment_index;
{
increment_index = factory()->NewExpressionStatement(
factory()->NewCountOperation(
Token::INC, false, factory()->NewVariableProxy(index), nopos),
nopos);
}
// while (!done) {
// #set_done;
// #get_next;
// #maybe_store_and_unset_done;
// #increment_index;
// }
WhileStatement* loop =
factory()->NewWhileStatement(nullptr, nullptr, nopos);
{
Expression* condition = factory()->NewUnaryOperation(
Token::NOT, factory()->NewVariableProxy(done), nopos);
Block* body = factory()->NewBlock(4, true);
body->statements()->Add(set_done, zone());
body->statements()->Add(get_next, zone());
body->statements()->Add(maybe_store_and_unset_done, zone());
body->statements()->Add(increment_index, zone());
loop->Initialize(condition, body);
}
block_->statements()->Add(loop, zone());
RecurseIntoSubpattern(spread->expression(),
factory()->NewVariableProxy(array));
if (value->IsTheHoleLiteral()) continue;
RecurseIntoSubpattern(value);
}
Expression* closing_condition = factory()->NewUnaryOperation(
Token::NOT, factory()->NewVariableProxy(done), nopos);
parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
target, IteratorType::kNormal);
block_ = target;
}
void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
Variable* temp_var = nullptr;
VisitArrayLiteral(node, &temp_var);
}
void PatternRewriter::VisitAssignment(Assignment* node) {
// let {<pattern> = <init>} = <value>
// becomes
// temp = <value>;
// <pattern> = temp === undefined ? <init> : temp;
DCHECK_EQ(Token::ASSIGN, node->op());
auto initializer = node->value();
auto value = initializer;
auto temp = CreateTempVar(current_value_);
Expression* is_undefined = factory()->NewCompareOperation(
Token::EQ_STRICT, factory()->NewVariableProxy(temp),
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
value = factory()->NewConditional(is_undefined, initializer,
factory()->NewVariableProxy(temp),
kNoSourcePosition);
// Initializer may have been parsed in the wrong scope.
RewriteParameterScopes(initializer);
RewriteParameterScopes(node->value());
RecurseIntoSubpattern(node->target(), value);
RecurseIntoSubpattern(node->target());
}
// =============== AssignmentPattern only ==================
void PatternRewriter::VisitProperty(v8::internal::Property* node) {
DCHECK(IsAssignmentContext());
auto value = current_value_;
Assignment* assignment =
factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
void PatternRewriter::VisitSpread(Spread* node) {
RecurseIntoSubpattern(node->expression());
}
// =============== UNREACHABLE =============================
#define NOT_A_PATTERN(Node) \
......@@ -675,11 +302,11 @@ NOT_A_PATTERN(IfStatement)
NOT_A_PATTERN(ImportCallExpression)
NOT_A_PATTERN(Literal)
NOT_A_PATTERN(NativeFunctionLiteral)
NOT_A_PATTERN(Property)
NOT_A_PATTERN(RegExpLiteral)
NOT_A_PATTERN(ResolvedProperty)
NOT_A_PATTERN(ReturnStatement)
NOT_A_PATTERN(SloppyBlockFunctionStatement)
NOT_A_PATTERN(Spread)
NOT_A_PATTERN(StoreInArrayLiteral)
NOT_A_PATTERN(SuperPropertyReference)
NOT_A_PATTERN(SuperCallReference)
......
......@@ -300,7 +300,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 22 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 31 S> */ B(Mov), R(3), R(0),
/* 42 S> */ B(LdaFalse),
B(Star), R(21),
B(Mov), R(2), R(19),
......
......@@ -18,7 +18,7 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(0),
/* 10 E> */ B(StackCheck),
B(Star), R(1),
/* 22 S> */ B(Star), R(1),
/* 42 S> */ B(Return),
]
constant pool: [
......@@ -38,8 +38,8 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(0),
/* 10 E> */ B(StackCheck),
B(Mov), R(arg0), R(1),
B(Mov), R(0), R(2),
/* 12 S> */ B(Mov), R(arg0), R(1),
/* 25 S> */ B(Mov), R(0), R(2),
/* 29 S> */ B(Ldar), R(2),
/* 45 S> */ B(Return),
]
......@@ -60,8 +60,8 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(0),
/* 10 E> */ B(StackCheck),
B(Mov), R(arg0), R(1),
B(Mov), R(0), R(2),
/* 12 S> */ B(Mov), R(arg0), R(1),
/* 25 S> */ B(Mov), R(0), R(2),
/* 29 S> */ B(LdaZero),
/* 44 E> */ B(LdaKeyedProperty), R(2), U8(0),
/* 48 S> */ B(Return),
......@@ -85,8 +85,8 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(0),
/* 10 E> */ B(StackCheck),
B(Mov), R(arg0), R(1),
B(Mov), R(0), R(2),
/* 12 S> */ B(Mov), R(arg0), R(1),
/* 25 S> */ B(Mov), R(0), R(2),
/* 29 S> */ B(LdaZero),
/* 44 E> */ B(LdaKeyedProperty), R(2), U8(1),
B(Star), R(4),
......
......@@ -371,7 +371,7 @@ bytecodes: [
B(Star), R(2),
B(LdaConstant), U8(1),
B(Star), R(3),
/* 57 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
/* 54 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
B(Star), R(4),
/* 54 S> */ B(LdaNamedProperty), R(4), U8(1), U8(1),
......@@ -406,7 +406,7 @@ bytecodes: [
B(Star), R(2),
B(LdaConstant), U8(1),
B(Star), R(3),
/* 66 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
/* 57 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
/* 61 S> */ B(Star), R(4),
B(LdaNamedProperty), R(4), U8(1), U8(1),
......@@ -440,7 +440,7 @@ bytecodes: [
B(Star), R(2),
B(LdaConstant), U8(1),
B(Star), R(3),
/* 74 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
/* 64 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
B(Star), R(4),
/* 64 S> */ B(LdaConstant), U8(1),
......
......@@ -73,13 +73,13 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 23 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 38 S> */ B(Mov), R(3), R(0),
B(LdaZero),
B(Star), R(7),
B(JumpLoop), U8(79), I8(0),
B(Jump), U8(37),
B(Star), R(16),
B(CreateCatchContext), R(16), U8(9),
/* 38 E> */ B(CreateCatchContext), R(16), U8(9),
B(Star), R(15),
B(LdaTheHole),
B(SetPendingMessage),
......@@ -289,7 +289,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 23 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 38 S> */ B(Mov), R(3), R(0),
/* 56 S> */ B(LdaSmi), I8(1),
B(Star), R(12),
B(Mov), R(8), R(13),
......@@ -517,7 +517,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 23 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 38 S> */ B(Mov), R(3), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
/* 69 E> */ B(TestEqual), R(0), U8(17),
B(JumpIfFalse), U8(4),
......
......@@ -81,7 +81,7 @@ bytecodes: [
B(JumpIfUndefined), U8(8),
B(Star), R(1),
/* 54 E> */ B(StackCheck),
B(Star), R(2),
/* 63 S> */ B(Star), R(2),
/* 82 S> */ B(Return),
B(ForInStep), R(7),
B(Star), R(7),
......@@ -121,7 +121,7 @@ bytecodes: [
B(JumpIfUndefined), U8(17),
B(Star), R(1),
/* 45 E> */ B(StackCheck),
B(Star), R(2),
/* 54 S> */ B(Star), R(2),
/* 70 S> */ B(Ldar), R(1),
/* 75 E> */ B(Add), R(0), U8(2),
B(Mov), R(0), R(8),
......
......@@ -42,13 +42,13 @@ bytecodes: [
B(Star), R(5),
B(Mov), R(6), R(0),
/* 34 E> */ B(StackCheck),
B(Mov), R(0), R(1),
/* 43 S> */ B(Mov), R(0), R(1),
B(LdaZero),
B(Star), R(5),
B(JumpLoop), U8(44), I8(0),
B(Jump), U8(33),
B(Star), R(13),
B(CreateCatchContext), R(13), U8(5),
/* 43 E> */ B(CreateCatchContext), R(13), U8(5),
B(PushContext), R(13),
B(Star), R(12),
B(LdaSmi), I8(2),
......@@ -173,7 +173,7 @@ bytecodes: [
B(Star), R(6),
B(Mov), R(7), R(1),
/* 54 E> */ B(StackCheck),
B(Mov), R(1), R(2),
/* 63 S> */ B(Mov), R(1), R(2),
/* 73 S> */ B(LdaSmi), I8(1),
B(Star), R(10),
B(Mov), R(7), R(11),
......@@ -310,7 +310,7 @@ bytecodes: [
B(Star), R(5),
B(Mov), R(6), R(0),
/* 34 E> */ B(StackCheck),
B(Mov), R(0), R(1),
/* 43 S> */ B(Mov), R(0), R(1),
/* 66 S> */ B(LdaSmi), I8(10),
/* 72 E> */ B(TestEqual), R(1), U8(13),
B(JumpIfFalse), U8(4),
......
......@@ -45,7 +45,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 20 E> */ B(StackCheck),
B(Mov), R(3), R(1),
/* 29 S> */ B(Mov), R(3), R(1),
/* 49 S> */ B(Mov), R(1), R(0),
B(LdaZero),
B(Star), R(7),
......@@ -195,8 +195,8 @@ bytecodes: [
B(PushContext), R(15),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(Ldar), R(5),
B(StaCurrentContextSlot), U8(4),
/* 29 S> */ B(Ldar), R(5),
/* 29 E> */ B(StaCurrentContextSlot), U8(4),
/* 41 S> */ B(LdaLookupGlobalSlot), U8(7), U8(12), U8(3),
B(Star), R(16),
B(LdaConstant), U8(8),
......@@ -353,8 +353,8 @@ bytecodes: [
B(PushContext), R(13),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(Ldar), R(6),
B(StaCurrentContextSlot), U8(4),
/* 29 S> */ B(Ldar), R(6),
/* 29 E> */ B(StaCurrentContextSlot), U8(4),
/* 41 S> */ B(CreateClosure), U8(5), U8(12), U8(2),
B(Star), R(14),
/* 67 E> */ B(CallUndefinedReceiver0), R(14), U8(13),
......@@ -460,125 +460,124 @@ snippet: "
"
frame size: 20
parameter count: 2
bytecode array length: 283
bytecode array length: 280
bytecodes: [
/* 10 E> */ B(StackCheck),
B(LdaZero),
B(Star), R(10),
B(Star), R(9),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16),
B(Mov), R(context), R(17),
/* 41 S> */ B(LdaNamedProperty), R(arg0), U8(0), U8(0),
B(Star), R(19),
B(CallProperty0), R(19), R(arg0), U8(2),
B(Mov), R(arg0), R(18),
B(Star), R(18),
B(CallProperty0), R(18), R(arg0), U8(2),
B(Mov), R(arg0), R(17),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(6),
/* 41 E> */ B(LdaNamedProperty), R(6), U8(1), U8(4),
B(Star), R(7),
/* 41 E> */ B(LdaNamedProperty), R(7), U8(1), U8(4),
/* 36 S> */ B(CallProperty0), R(7), R(6), U8(6),
B(Star), R(8),
/* 36 S> */ B(CallProperty0), R(8), R(7), U8(6),
B(Star), R(9),
/* 36 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(9), U8(1),
/* 36 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(8), U8(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
B(LdaNamedProperty), R(9), U8(2), U8(8),
B(JumpIfToBooleanTrue), U8(66),
B(LdaNamedProperty), R(9), U8(3), U8(10),
B(Star), R(11),
B(LdaSmi), I8(2),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
B(LdaNamedProperty), R(8), U8(2), U8(8),
B(JumpIfToBooleanTrue), U8(63),
B(LdaNamedProperty), R(8), U8(3), U8(10),
B(Star), R(10),
B(Mov), R(11), R(5),
B(LdaSmi), I8(2),
B(Star), R(9),
B(Mov), R(10), R(5),
/* 20 E> */ B(StackCheck),
B(Mov), R(5), R(6),
B(Ldar), R(6),
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
/* 36 S> */ B(Ldar), R(5),
B(JumpIfNull), U8(4),
B(JumpIfNotUndefined), U8(16),
B(LdaSmi), I8(81),
B(Star), R(18),
B(Star), R(17),
B(LdaConstant), U8(4),
B(Star), R(18),
/* 31 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(17), U8(2),
B(Throw),
B(Star), R(19),
B(CallRuntime), U16(Runtime::kNewTypeError), R(18), U8(2),
/* 31 E> */ B(Throw),
/* 31 S> */ B(LdaNamedProperty), R(6), U8(4), U8(12),
/* 31 S> */ B(LdaNamedProperty), R(19), U8(4), U8(12),
B(Star), R(1),
/* 34 S> */ B(LdaNamedProperty), R(6), U8(5), U8(14),
/* 34 S> */ B(LdaNamedProperty), R(19), U8(5), U8(14),
B(Star), R(2),
/* 56 S> */ B(Ldar), R(2),
/* 58 E> */ B(Add), R(1), U8(16),
B(Star), R(0),
B(LdaZero),
B(Star), R(10),
B(JumpLoop), U8(85), I8(0),
B(Star), R(9),
B(JumpLoop), U8(82), I8(0),
B(Jump), U8(33),
B(Star), R(18),
/* 56 E> */ B(CreateCatchContext), R(18), U8(6),
B(PushContext), R(18),
B(Star), R(17),
/* 56 E> */ B(CreateCatchContext), R(17), U8(6),
B(PushContext), R(17),
B(Star), R(16),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(10), U8(17),
B(TestEqualStrict), R(9), U8(17),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Star), R(10),
B(Star), R(9),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(19),
B(CallRuntime), U16(Runtime::kReThrow), R(19), U8(1),
B(PopContext), R(18),
B(Star), R(18),
B(CallRuntime), U16(Runtime::kReThrow), R(18), U8(1),
B(PopContext), R(17),
B(LdaSmi), I8(-1),
B(Star), R(15),
B(Star), R(14),
B(Star), R(13),
B(Jump), U8(7),
B(Star), R(15),
B(LdaZero),
B(Star), R(14),
B(LdaZero),
B(Star), R(13),
B(LdaTheHole),
B(SetPendingMessage),
B(Star), R(16),
B(Star), R(15),
B(LdaZero),
B(TestEqualStrict), R(10), U8(18),
B(TestEqualStrict), R(9), U8(18),
B(JumpIfTrue), U8(90),
B(LdaNamedProperty), R(7), U8(7), U8(19),
B(Star), R(12),
B(LdaNamedProperty), R(6), U8(7), U8(19),
B(Star), R(11),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(79),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(10), U8(21),
B(TestEqualStrict), R(9), U8(21),
B(JumpIfFalse), U8(47),
B(Ldar), R(12),
B(Ldar), R(11),
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(154),
B(Star), R(17),
B(Star), R(16),
B(LdaConstant), U8(8),
B(Star), R(18),
B(CallRuntime), U16(Runtime::kNewTypeError), R(17), U8(2),
B(Star), R(17),
B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
B(Throw),
B(Mov), R(context), R(17),
B(Mov), R(12), R(18),
B(Mov), R(7), R(19),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(18), U8(2),
B(Mov), R(context), R(16),
B(Mov), R(11), R(17),
B(Mov), R(6), R(18),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(17), U8(2),
B(Jump), U8(6),
B(LdaTheHole),
B(SetPendingMessage),
B(Ldar), R(17),
B(Ldar), R(16),
B(Jump), U8(27),
B(Mov), R(12), R(17),
B(Mov), R(7), R(18),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(17), U8(2),
B(Star), R(13),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(13), U8(1),
B(Mov), R(11), R(16),
B(Mov), R(6), R(17),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(16), U8(2),
B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(12), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
B(Ldar), R(16),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
B(Ldar), R(15),
B(SetPendingMessage),
B(LdaZero),
B(TestReferenceEqual), R(14),
B(TestReferenceEqual), R(13),
B(JumpIfFalse), U8(5),
B(Ldar), R(15),
B(Ldar), R(14),
B(ReThrow),
B(LdaUndefined),
/* 65 S> */ B(Return),
......@@ -595,9 +594,9 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
[7, 159, 167],
[10, 126, 128],
[227, 237, 239],
[7, 156, 164],
[10, 123, 125],
[224, 234, 236],
]
---
......@@ -653,7 +652,7 @@ bytecodes: [
B(Star), R(8),
B(Mov), R(9), R(4),
/* 21 E> */ B(StackCheck),
B(Mov), R(4), R(1),
/* 30 S> */ B(Mov), R(4), R(1),
/* 50 S> */ B(Mov), R(1), R(0),
B(LdaZero),
B(Star), R(8),
......@@ -801,7 +800,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 21 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 30 S> */ B(Mov), R(3), R(0),
/* 40 S> */ B(LdaFalse),
B(Star), R(16),
B(Mov), R(0), R(15),
......@@ -961,7 +960,7 @@ bytecodes: [
B(Star), R(8),
B(Mov), R(9), R(4),
/* 26 E> */ B(StackCheck),
B(Mov), R(4), R(1),
/* 35 S> */ B(Mov), R(4), R(1),
/* 55 S> */ B(Mov), R(1), R(0),
B(LdaZero),
B(Star), R(8),
......@@ -1125,7 +1124,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 26 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 35 S> */ B(Mov), R(3), R(0),
/* 45 S> */ B(Mov), R(2), R(16),
B(Mov), R(0), R(17),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(16), U8(2),
......
......@@ -145,7 +145,7 @@ bytecodes: [
B(Star), R(7),
B(Mov), R(8), R(3),
/* 16 E> */ B(StackCheck),
B(Mov), R(3), R(0),
/* 25 S> */ B(Mov), R(3), R(0),
/* 36 S> */ B(LdaFalse),
B(Star), R(16),
B(Mov), R(0), R(15),
......
......@@ -220,23 +220,22 @@ snippet: "
"
frame size: 6
parameter count: 1
bytecode array length: 64
bytecode array length: 62
bytecodes: [
/* 10 E> */ B(StackCheck),
B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(Star), R(3),
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
/* 37 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(JumpIfNull), U8(4),
B(JumpIfNotUndefined), U8(16),
B(LdaSmi), I8(81),
B(Star), R(4),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
/* 28 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(3), U8(2),
B(Throw),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kNewTypeError), R(4), U8(2),
/* 28 E> */ B(Throw),
/* 37 S> */ B(LdaNamedProperty), R(3), U8(1), U8(1),
/* 28 S> */ B(LdaNamedProperty), R(5), U8(1), U8(1),
B(Star), R(1),
/* 37 S> */ B(LdaNamedProperty), R(3), U8(2), U8(3),
/* 31 S> */ B(LdaNamedProperty), R(5), U8(2), U8(3),
B(Star), R(2),
/* 55 S> */ B(LdaZero),
/* 55 E> */ B(TestGreaterThan), R(2), U8(5),
......
......@@ -57,7 +57,7 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(closure), R(1),
/* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3),
/* 136 S> */ B(Mov), R(2), R(3),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(LdaSmi), I8(1),
......@@ -99,7 +99,7 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(closure), R(1),
/* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3),
/* 136 S> */ B(Mov), R(2), R(3),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(CreateEmptyArrayLiteral), U8(0),
......
......@@ -3724,9 +3724,9 @@ TEST(MaybeAssignedInsideLoop) {
{true, "for (let j=x; j<10; ++j) { let foo; [foo] = [j] }", {0, 0}},
{true, "for (let j=x; j<10; ++j) { let foo; [[foo]=[42]] = [] }", {0, 0}},
{false, "for (let j=x; j<10; ++j) { let foo = j }", {0, 0}},
{false, "for (let j=x; j<10; ++j) { let [foo] = [j] }", {0, 0, 0}},
{false, "for (let j=x; j<10; ++j) { let [foo] = [j] }", {0, 0}},
{false, "for (let j=x; j<10; ++j) { const foo = j }", {0, 0}},
{false, "for (let j=x; j<10; ++j) { const [foo] = [j] }", {0, 0, 0}},
{false, "for (let j=x; j<10; ++j) { const [foo] = [j] }", {0, 0}},
{false,
"for (let j=x; j<10; ++j) { function foo() {return j} }",
{0, 0, 0}},
......@@ -3746,9 +3746,9 @@ TEST(MaybeAssignedInsideLoop) {
"for (let {j}=x; j<10; ++j) { let foo; [[foo]=[42]] = [] }",
{0, 0}},
{false, "for (let {j}=x; j<10; ++j) { let foo = j }", {0, 0}},
{false, "for (let {j}=x; j<10; ++j) { let [foo] = [j] }", {0, 0, 0}},
{false, "for (let {j}=x; j<10; ++j) { let [foo] = [j] }", {0, 0}},
{false, "for (let {j}=x; j<10; ++j) { const foo = j }", {0, 0}},
{false, "for (let {j}=x; j<10; ++j) { const [foo] = [j] }", {0, 0, 0}},
{false, "for (let {j}=x; j<10; ++j) { const [foo] = [j] }", {0, 0}},
{false,
"for (let {j}=x; j<10; ++j) { function foo(){return j} }",
{0, 0, 0}},
......
......@@ -21,89 +21,89 @@ function listener(event, exec_state, event_data, data) {
} catch (e) {
exception = e;
print(e);
}
} // B34
};
Debug.setListener(listener);
var id = x => x; // B9 B10 B36 B37
var id = x => x; // B11 B12 B42 B43
function test() {
debugger; // B0
function fx1([
a, // B2
b // B3
]) {
assertEquals([1, 2], [a, b]); // B4
} // B5
a, // B3
b // B4
]) { // B2
assertEquals([1, 2], [a, b]); // B5
} // B6
fx1([1, 2, 3]); // B1
function f2([
a, // B7
b = id(3) // B8
]) {
assertEquals([4, 3], [a, b]); // B11
} // B12
f2([4]); // B6
a, // B9
b = id(3) // B10
]) { // B8
assertEquals([4, 3], [a, b]); // B13
} // B14
f2([4]); // B7
function f3({
x: a, // B14
y: b // B15
}) {
assertEquals([5, 6], [a, b]); // B16
} // B17
f3({y: 6, x: 5}); // B13
x: a, // B17
y: b // B18
}) { // B16
assertEquals([5, 6], [a, b]); // B19
} // B20
f3({y: 6, x: 5}); // B15
function f4([
a, // B19
a, // B23
{
b, // B20
c, // B21
b, // B24
c, // B25
}
]) {
assertEquals([2, 4, 6], [a, b, c]); // B22
} // B23
f4([2, {c: 6, b: 4}]); // B18
]) { // B22
assertEquals([2, 4, 6], [a, b, c]); // B26
} // B27
f4([2, {c: 6, b: 4}]); // B21
function f5([
{
a, // B25
b = 7 // B26
a, // B30
b = 7 // B31
},
c = 3 // B27
] = [{a:1}]) {
assertEquals([1, 7, 3], [a, b, c]); // B28
} // B29
f5(); // B24
c = 3 // B32
] = [{a:1}]) { // B29
assertEquals([1, 7, 3], [a, b, c]); // B33
} // B34
f5(); // B28
var name = "x"; // B30
var name = "x"; // B35
function f6({
[id(name)]: a, // B34 B35
b = a // B38
}) {
assertEquals([9, 9], [a, b]); // B39
} // B40
var o6 = {}; // B31
o6[name] = 9; // B32
f6(o6); // B33
[id(name)]: a, // B40 B41
b = a // B44
}) { // B39
assertEquals([9, 9], [a, b]); // B45
} // B46
var o6 = {}; // B36
o6[name] = 9; // B37
f6(o6); // B38
try {
throw [3, 4]; // B41
throw [3, 4]; // B47
} catch ([
a, // B42
b, // B43
c = 6 // B44
]) {
assertEquals([3, 4, 6], [a, b, c]); // B45
a, // B49
b, // B50
c = 6 // B51
]) { // B48
assertEquals([3, 4, 6], [a, b, c]); // B52
}
var {
x: a,
y: b = 9
} = { x: 4 }; // B46
assertEquals([4, 9], [a, b]); // B47
} // B48
x: a, // B54
y: b = 9 // B55
} = { x: 4 }; // B53
assertEquals([4, 9], [a, b]); // B56
} // B57
test();
Debug.setListener(null); // B49
Debug.setListener(null); // B58
assertNull(exception);
......@@ -41,5 +41,5 @@ Debug.setListener(null); // c
assertNull(exception);
assertEquals("default", result);
assertEquals(["a0","b13","f18b13","d2f18b13","d19f18b13","g14b13","c0"],
assertEquals(["a0","b13","f31b13","f18b13","d2f18b13","d19f18b13","g14b13","c0"],
log);
......@@ -15,7 +15,7 @@ function testFunction() {
var y = |_|(a = 100);
var z = |_|x + (a = 1) + (a = 2) + (a = 3) + |C|f();
function f() {
for (let { x, y } = |_|{ x: 0, y: 1 }; y |_|> 0; --|_|y) { let z = |_|x + y; }
for (let { |_|x, |_|y } = |_|{ x: 0, y: 1 }; y |_|> 0; --|_|y) { let z = |_|x + y; }
|R|}
var b = obj1.|_|a;
|_|(async function asyncF() {
......@@ -89,6 +89,20 @@ testFunction (test.js:10:44)
for (let { x, y } = #{ x: 0, y: 1 }; y > 0; --y) { let z = x + y; }
}
f (test.js:12:15)
testFunction (test.js:10:44)
(anonymous) (expr.js:0:0)
function f() {
for (let { #x, y } = { x: 0, y: 1 }; y > 0; --y) { let z = x + y; }
}
f (test.js:12:18)
testFunction (test.js:10:44)
(anonymous) (expr.js:0:0)
function f() {
for (let { x, #y } = { x: 0, y: 1 }; y > 0; --y) { let z = x + y; }
}
f (test.js:12:42)
testFunction (test.js:10:44)
(anonymous) (expr.js:0:0)
......
......@@ -15,7 +15,7 @@ function testFunction() {
var y = |_|(a = 100);
var z = |_|x + (a = 1) + (a = 2) + (a = 3) + |C|f();
function f() {
for (let { x, y } = |_|{ x: 0, y: 1 }; y |_|> 0; --|_|y) { let z = |_|x + y; }
for (let { |_|x, |_|y } = |_|{ x: 0, y: 1 }; y |_|> 0; --|_|y) { let z = |_|x + y; }
|R|}
var b = obj1.|_|a;
|_|(async function asyncF() {
......@@ -89,6 +89,20 @@ testFunction (test.js:10:44)
for (let { x, y } = #{ x: 0, y: 1 }; y > 0; --y) { let z = x + y; }
}
f (test.js:12:15)
testFunction (test.js:10:44)
(anonymous) (expr.js:0:0)
function f() {
for (let { #x, y } = { x: 0, y: 1 }; y > 0; --y) { let z = x + y; }
}
f (test.js:12:18)
testFunction (test.js:10:44)
(anonymous) (expr.js:0:0)
function f() {
for (let { x, #y } = { x: 0, y: 1 }; y > 0; --y) { let z = x + y; }
}
f (test.js:12:42)
testFunction (test.js:10:44)
(anonymous) (expr.js:0:0)
......
......@@ -251,6 +251,12 @@ testFunction (test.js:25:11)
return { value: this.i++, done: false };#
}
testFunction (test.js:25:11)
(anonymous) (expr.js:0:0)
};
for (var #k of iterable) { all.push(k); }
iterable.i = 0;
testFunction (test.js:25:32)
(anonymous) (expr.js:0:0)
};
......@@ -337,6 +343,12 @@ testFunction (test.js:27:11)
return { value: this.i++, done: false };#
}
testFunction (test.js:27:11)
(anonymous) (expr.js:0:0)
iterable.i = 0;
for (let #k of iterable) { all.push(k); }
}
testFunction (test.js:27:32)
(anonymous) (expr.js:0:0)
iterable.i = 0;
......
......@@ -10,6 +10,12 @@ paused
#c(f, 2);
}
paused
function c(f#, ...args) { return f(...args); }
paused
function c(f, ...args#) { return f(...args); }
paused
function c(f, ...args) { #return f(...args); }
......
......@@ -2,4 +2,4 @@
var { [x] : y } = undefined;
^
TypeError: Cannot destructure 'undefined' or 'null'.
at *%(basename)s:5:19
at *%(basename)s:5:5
......@@ -2,4 +2,4 @@
var { 1: x } = undefined;
^
TypeError: Cannot destructure 'undefined' or 'null'.
at *%(basename)s:5:16
at *%(basename)s:5:5
......@@ -2,4 +2,4 @@
var { x } = undefined;
^
TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
at *%(basename)s:5:13
at *%(basename)s:5:7
*%(basename)s:7: TypeError: nonIterable(...) is not a function or its return value is not iterable
*%(basename)s:7: TypeError: nonIterable is not a function or its return value is not iterable
[...nonIterable()];
^
TypeError: nonIterable(...) is not a function or its return value is not iterable
TypeError: nonIterable is not a function or its return value is not iterable
at *%(basename)s:7:5
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