2012-01-26 21:47:57 +00:00
|
|
|
// Copyright 2012 the V8 project authors. All rights reserved.
|
2014-04-29 06:42:26 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/parsing/parser.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2017-04-04 15:44:08 +00:00
|
|
|
#include <algorithm>
|
2016-07-25 10:24:45 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2016-11-28 11:40:22 +00:00
|
|
|
#include "src/ast/ast-function-literal-id-reindexer.h"
|
2016-07-25 08:25:49 +00:00
|
|
|
#include "src/ast/ast-traversal-visitor.h"
|
2016-08-22 11:33:30 +00:00
|
|
|
#include "src/ast/ast.h"
|
2018-12-03 14:34:35 +00:00
|
|
|
#include "src/ast/source-range-ast-visitor.h"
|
2019-02-08 00:32:59 +00:00
|
|
|
#include "src/base/ieee754.h"
|
2019-01-10 13:09:28 +00:00
|
|
|
#include "src/base/overflowing-math.h"
|
2014-06-30 13:25:46 +00:00
|
|
|
#include "src/base/platform/platform.h"
|
2019-05-21 09:30:15 +00:00
|
|
|
#include "src/codegen/bailout-reason.h"
|
2020-04-22 10:45:31 +00:00
|
|
|
#include "src/common/globals.h"
|
2019-06-26 08:30:17 +00:00
|
|
|
#include "src/common/message-template.h"
|
2017-04-04 15:44:08 +00:00
|
|
|
#include "src/compiler-dispatcher/compiler-dispatcher.h"
|
2019-11-25 11:23:12 +00:00
|
|
|
#include "src/logging/counters.h"
|
2019-05-20 09:15:06 +00:00
|
|
|
#include "src/logging/log.h"
|
2019-05-15 18:28:45 +00:00
|
|
|
#include "src/numbers/conversions-inl.h"
|
2018-07-10 12:37:41 +00:00
|
|
|
#include "src/objects/scope-info.h"
|
2016-08-22 11:33:30 +00:00
|
|
|
#include "src/parsing/parse-info.h"
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/parsing/rewriter.h"
|
2014-09-25 07:16:15 +00:00
|
|
|
#include "src/runtime/runtime.h"
|
2019-05-21 06:38:38 +00:00
|
|
|
#include "src/strings/char-predicates-inl.h"
|
|
|
|
#include "src/strings/string-stream.h"
|
2020-10-21 20:43:40 +00:00
|
|
|
#include "src/strings/unicode-inl.h"
|
2016-02-18 06:12:45 +00:00
|
|
|
#include "src/tracing/trace-event.h"
|
2019-02-14 21:10:30 +00:00
|
|
|
#include "src/zone/zone-list-inl.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2009-05-25 10:05:56 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2016-02-01 17:44:23 +00:00
|
|
|
FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
|
2016-12-29 22:12:51 +00:00
|
|
|
bool call_super, int pos,
|
|
|
|
int end_pos) {
|
2019-04-15 23:27:56 +00:00
|
|
|
int expected_property_count = 0;
|
2016-10-13 12:34:37 +00:00
|
|
|
const int parameter_count = 0;
|
2015-02-11 17:22:50 +00:00
|
|
|
|
2017-01-03 19:37:23 +00:00
|
|
|
FunctionKind kind = call_super ? FunctionKind::kDefaultDerivedConstructor
|
2015-02-12 20:06:52 +00:00
|
|
|
: FunctionKind::kDefaultBaseConstructor;
|
2016-08-05 14:30:54 +00:00
|
|
|
DeclarationScope* function_scope = NewFunctionScope(kind);
|
2017-10-16 10:55:06 +00:00
|
|
|
SetLanguageMode(function_scope, LanguageMode::kStrict);
|
2014-11-07 16:39:00 +00:00
|
|
|
// Set start and end position to the same value
|
|
|
|
function_scope->set_start_position(pos);
|
|
|
|
function_scope->set_end_position(pos);
|
2018-11-05 15:20:49 +00:00
|
|
|
ScopedPtrList<Statement> body(pointer_buffer());
|
2014-11-07 16:39:00 +00:00
|
|
|
|
|
|
|
{
|
2017-02-20 10:41:29 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, function_scope);
|
2014-11-07 16:39:00 +00:00
|
|
|
|
|
|
|
if (call_super) {
|
2016-12-01 09:42:07 +00:00
|
|
|
// Create a SuperCallReference and handle in BytecodeGenerator.
|
2016-06-13 18:07:18 +00:00
|
|
|
auto constructor_args_name = ast_value_factory()->empty_string();
|
|
|
|
bool is_rest = true;
|
|
|
|
bool is_optional = false;
|
2016-07-20 08:57:53 +00:00
|
|
|
Variable* constructor_args = function_scope->DeclareParameter(
|
2018-05-28 15:44:58 +00:00
|
|
|
constructor_args_name, VariableMode::kTemporary, is_optional, is_rest,
|
2018-10-09 08:35:05 +00:00
|
|
|
ast_value_factory(), pos);
|
2016-06-13 18:07:18 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
Expression* call;
|
|
|
|
{
|
|
|
|
ScopedPtrList<Expression> args(pointer_buffer());
|
|
|
|
Spread* spread_args = factory()->NewSpread(
|
|
|
|
factory()->NewVariableProxy(constructor_args), pos, pos);
|
2016-12-01 09:42:07 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
args.Add(spread_args);
|
|
|
|
Expression* super_call_ref = NewSuperCallReference(pos);
|
|
|
|
call = factory()->NewCall(super_call_ref, args, pos);
|
|
|
|
}
|
|
|
|
body.Add(factory()->NewReturnStatement(call, pos));
|
2014-11-07 16:39:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expected_property_count = function_state.expected_property_count();
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
|
2017-02-15 15:12:13 +00:00
|
|
|
name, function_scope, body, expected_property_count, parameter_count,
|
|
|
|
parameter_count, FunctionLiteral::kNoDuplicateParameters,
|
2019-08-23 02:28:45 +00:00
|
|
|
FunctionSyntaxKind::kAnonymousExpression, default_eager_compile_hint(),
|
|
|
|
pos, true, GetNextFunctionLiteralId());
|
2014-11-07 16:39:00 +00:00
|
|
|
return function_literal;
|
|
|
|
}
|
|
|
|
|
2019-01-18 23:55:49 +00:00
|
|
|
void Parser::ReportUnexpectedTokenAt(Scanner::Location location,
|
|
|
|
Token::Value token,
|
|
|
|
MessageTemplate message) {
|
|
|
|
const char* arg = nullptr;
|
2018-10-11 14:49:23 +00:00
|
|
|
switch (token) {
|
|
|
|
case Token::EOS:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedEOS;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::SMI:
|
|
|
|
case Token::NUMBER:
|
|
|
|
case Token::BIGINT:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedTokenNumber;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::STRING:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedTokenString;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::PRIVATE_NAME:
|
|
|
|
case Token::IDENTIFIER:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedTokenIdentifier;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::AWAIT:
|
|
|
|
case Token::ENUM:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedReserved;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::LET:
|
|
|
|
case Token::STATIC:
|
|
|
|
case Token::YIELD:
|
|
|
|
case Token::FUTURE_STRICT_RESERVED_WORD:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = is_strict(language_mode())
|
|
|
|
? MessageTemplate::kUnexpectedStrictReserved
|
|
|
|
: MessageTemplate::kUnexpectedTokenIdentifier;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::TEMPLATE_SPAN:
|
|
|
|
case Token::TEMPLATE_TAIL:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedTemplateString;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::ESCAPED_STRICT_RESERVED_WORD:
|
|
|
|
case Token::ESCAPED_KEYWORD:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kInvalidEscapedReservedWord;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
case Token::ILLEGAL:
|
|
|
|
if (scanner()->has_error()) {
|
2019-01-18 23:55:49 +00:00
|
|
|
message = scanner()->error();
|
|
|
|
location = scanner()->error_location();
|
2018-10-11 14:49:23 +00:00
|
|
|
} else {
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kInvalidOrUnexpectedToken;
|
2018-10-11 14:49:23 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Token::REGEXP_LITERAL:
|
2019-01-18 23:55:49 +00:00
|
|
|
message = MessageTemplate::kUnexpectedTokenRegExp;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
const char* name = Token::String(token);
|
|
|
|
DCHECK_NOT_NULL(name);
|
2019-01-18 23:55:49 +00:00
|
|
|
arg = name;
|
2018-10-11 14:49:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-01-18 23:55:49 +00:00
|
|
|
ReportMessageAt(location, message, arg);
|
2018-10-11 14:49:23 +00:00
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Implementation of Parser
|
|
|
|
|
2016-08-24 10:08:34 +00:00
|
|
|
bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x,
|
|
|
|
Expression* y,
|
|
|
|
Token::Value op, int pos) {
|
2017-10-24 00:53:27 +00:00
|
|
|
if ((*x)->IsNumberLiteral() && y->IsNumberLiteral()) {
|
|
|
|
double x_val = (*x)->AsLiteral()->AsNumber();
|
|
|
|
double y_val = y->AsLiteral()->AsNumber();
|
2014-03-17 13:54:42 +00:00
|
|
|
switch (op) {
|
|
|
|
case Token::ADD:
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(x_val + y_val, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
case Token::SUB:
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(x_val - y_val, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
case Token::MUL:
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(x_val * y_val, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
case Token::DIV:
|
2019-01-10 13:09:28 +00:00
|
|
|
*x = factory()->NewNumberLiteral(base::Divide(x_val, y_val), pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
case Token::BIT_OR: {
|
|
|
|
int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(value, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Token::BIT_AND: {
|
|
|
|
int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(value, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Token::BIT_XOR: {
|
|
|
|
int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(value, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Token::SHL: {
|
2019-01-25 00:33:28 +00:00
|
|
|
int value =
|
|
|
|
base::ShlWithWraparound(DoubleToInt32(x_val), DoubleToInt32(y_val));
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(value, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Token::SHR: {
|
2017-12-02 00:30:37 +00:00
|
|
|
uint32_t shift = DoubleToInt32(y_val) & 0x1F;
|
2014-03-17 13:54:42 +00:00
|
|
|
uint32_t value = DoubleToUint32(x_val) >> shift;
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(value, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Token::SAR: {
|
2017-12-02 00:30:37 +00:00
|
|
|
uint32_t shift = DoubleToInt32(y_val) & 0x1F;
|
2014-03-17 13:54:42 +00:00
|
|
|
int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
|
2017-05-11 09:26:33 +00:00
|
|
|
*x = factory()->NewNumberLiteral(value, pos);
|
2014-03-17 13:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
2019-02-08 00:32:59 +00:00
|
|
|
case Token::EXP:
|
|
|
|
*x = factory()->NewNumberLiteral(base::ieee754::pow(x_val, y_val), pos);
|
2016-03-18 13:53:52 +00:00
|
|
|
return true;
|
2014-03-17 13:54:42 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-25 10:47:24 +00:00
|
|
|
bool Parser::CollapseNaryExpression(Expression** x, Expression* y,
|
2017-11-23 10:28:43 +00:00
|
|
|
Token::Value op, int pos,
|
|
|
|
const SourceRange& range) {
|
2017-10-25 10:47:24 +00:00
|
|
|
// Filter out unsupported ops.
|
2017-10-26 16:28:25 +00:00
|
|
|
if (!Token::IsBinaryOp(op) || op == Token::EXP) return false;
|
2017-10-25 10:47:24 +00:00
|
|
|
|
|
|
|
// Convert *x into an nary operation with the given op, returning false if
|
|
|
|
// this is not possible.
|
|
|
|
NaryOperation* nary = nullptr;
|
|
|
|
if ((*x)->IsBinaryOperation()) {
|
|
|
|
BinaryOperation* binop = (*x)->AsBinaryOperation();
|
|
|
|
if (binop->op() != op) return false;
|
|
|
|
|
2017-10-30 11:24:48 +00:00
|
|
|
nary = factory()->NewNaryOperation(op, binop->left(), 2);
|
|
|
|
nary->AddSubsequent(binop->right(), binop->position());
|
2017-11-23 10:28:43 +00:00
|
|
|
ConvertBinaryToNaryOperationSourceRange(binop, nary);
|
2017-10-25 10:47:24 +00:00
|
|
|
*x = nary;
|
|
|
|
} else if ((*x)->IsNaryOperation()) {
|
|
|
|
nary = (*x)->AsNaryOperation();
|
|
|
|
if (nary->op() != op) return false;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append our current expression to the nary operation.
|
|
|
|
// TODO(leszeks): Do some literal collapsing here if we're appending Smi or
|
|
|
|
// String literals.
|
|
|
|
nary->AddSubsequent(y, pos);
|
2019-01-15 12:46:53 +00:00
|
|
|
nary->clear_parenthesized();
|
2017-11-23 10:28:43 +00:00
|
|
|
AppendNaryOperationSourceRange(nary, range);
|
|
|
|
|
2017-10-25 10:47:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-24 10:22:12 +00:00
|
|
|
Expression* Parser::BuildUnaryExpression(Expression* expression,
|
|
|
|
Token::Value op, int pos) {
|
2017-10-16 13:41:49 +00:00
|
|
|
DCHECK_NOT_NULL(expression);
|
2017-10-24 00:53:27 +00:00
|
|
|
const Literal* literal = expression->AsLiteral();
|
|
|
|
if (literal != nullptr) {
|
2014-03-19 14:08:47 +00:00
|
|
|
if (op == Token::NOT) {
|
|
|
|
// Convert the literal to a boolean condition and negate it.
|
2017-10-24 00:53:27 +00:00
|
|
|
return factory()->NewBooleanLiteral(literal->ToBooleanIsFalse(), pos);
|
|
|
|
} else if (literal->IsNumberLiteral()) {
|
2014-03-19 14:08:47 +00:00
|
|
|
// Compute some expressions involving only number literals.
|
2014-06-24 14:03:24 +00:00
|
|
|
double value = literal->AsNumber();
|
2014-03-19 14:08:47 +00:00
|
|
|
switch (op) {
|
|
|
|
case Token::ADD:
|
|
|
|
return expression;
|
|
|
|
case Token::SUB:
|
2017-05-11 09:26:33 +00:00
|
|
|
return factory()->NewNumberLiteral(-value, pos);
|
2014-03-19 14:08:47 +00:00
|
|
|
case Token::BIT_NOT:
|
2017-05-11 09:26:33 +00:00
|
|
|
return factory()->NewNumberLiteral(~DoubleToInt32(value), pos);
|
2014-03-19 14:08:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-24 10:22:12 +00:00
|
|
|
return factory()->NewUnaryOperation(op, expression, pos);
|
2014-03-19 14:08:47 +00:00
|
|
|
}
|
|
|
|
|
2016-08-19 08:11:04 +00:00
|
|
|
Expression* Parser::NewThrowError(Runtime::FunctionId id,
|
2018-10-11 21:35:34 +00:00
|
|
|
MessageTemplate message,
|
2016-08-19 08:11:04 +00:00
|
|
|
const AstRawString* arg, int pos) {
|
2018-10-24 14:28:25 +00:00
|
|
|
ScopedPtrList<Expression> args(pointer_buffer());
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(factory()->NewSmiLiteral(static_cast<int>(message), pos));
|
|
|
|
args.Add(factory()->NewStringLiteral(arg, pos));
|
2016-08-19 08:11:04 +00:00
|
|
|
CallRuntime* call_constructor = factory()->NewCallRuntime(id, args, pos);
|
|
|
|
return factory()->NewThrow(call_constructor, pos);
|
2014-04-02 11:03:05 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 08:44:59 +00:00
|
|
|
Expression* Parser::NewSuperPropertyReference(int pos) {
|
2015-06-04 16:22:29 +00:00
|
|
|
// this_function[home_object_symbol]
|
2016-08-25 08:44:59 +00:00
|
|
|
VariableProxy* this_function_proxy =
|
|
|
|
NewUnresolved(ast_value_factory()->this_function_string(), pos);
|
2017-02-09 16:05:53 +00:00
|
|
|
Expression* home_object_symbol_literal = factory()->NewSymbolLiteral(
|
|
|
|
AstSymbol::kHomeObjectSymbol, kNoSourcePosition);
|
2016-08-25 08:44:59 +00:00
|
|
|
Expression* home_object = factory()->NewProperty(
|
2015-06-04 16:22:29 +00:00
|
|
|
this_function_proxy, home_object_symbol_literal, pos);
|
2019-02-06 10:52:07 +00:00
|
|
|
return factory()->NewSuperPropertyReference(home_object, pos);
|
2014-08-18 12:35:34 +00:00
|
|
|
}
|
2014-02-14 11:24:26 +00:00
|
|
|
|
2016-08-25 08:44:59 +00:00
|
|
|
Expression* Parser::NewSuperCallReference(int pos) {
|
|
|
|
VariableProxy* new_target_proxy =
|
|
|
|
NewUnresolved(ast_value_factory()->new_target_string(), pos);
|
|
|
|
VariableProxy* this_function_proxy =
|
|
|
|
NewUnresolved(ast_value_factory()->this_function_string(), pos);
|
2019-02-06 10:52:07 +00:00
|
|
|
return factory()->NewSuperCallReference(new_target_proxy, this_function_proxy,
|
|
|
|
pos);
|
2016-08-11 12:04:02 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 08:44:59 +00:00
|
|
|
Expression* Parser::NewTargetExpression(int pos) {
|
2016-10-25 07:59:05 +00:00
|
|
|
auto proxy = NewUnresolved(ast_value_factory()->new_target_string(), pos);
|
2015-08-13 18:06:04 +00:00
|
|
|
proxy->set_is_new_target();
|
|
|
|
return proxy;
|
2015-06-09 15:43:07 +00:00
|
|
|
}
|
|
|
|
|
2017-10-10 19:57:40 +00:00
|
|
|
Expression* Parser::ImportMetaExpression(int pos) {
|
2018-10-24 14:28:25 +00:00
|
|
|
ScopedPtrList<Expression> args(pointer_buffer());
|
2018-10-24 12:02:06 +00:00
|
|
|
return factory()->NewCallRuntime(Runtime::kInlineGetImportMetaObject, args,
|
|
|
|
pos);
|
2017-10-10 19:57:40 +00:00
|
|
|
}
|
|
|
|
|
2018-11-07 15:38:15 +00:00
|
|
|
Expression* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
|
2014-02-14 11:24:26 +00:00
|
|
|
switch (token) {
|
|
|
|
case Token::NULL_LITERAL:
|
2016-08-25 08:44:59 +00:00
|
|
|
return factory()->NewNullLiteral(pos);
|
2014-02-14 11:24:26 +00:00
|
|
|
case Token::TRUE_LITERAL:
|
2016-08-25 08:44:59 +00:00
|
|
|
return factory()->NewBooleanLiteral(true, pos);
|
2014-02-14 11:24:26 +00:00
|
|
|
case Token::FALSE_LITERAL:
|
2016-08-25 08:44:59 +00:00
|
|
|
return factory()->NewBooleanLiteral(false, pos);
|
2015-03-03 11:04:49 +00:00
|
|
|
case Token::SMI: {
|
2016-11-09 16:11:56 +00:00
|
|
|
uint32_t value = scanner()->smi_value();
|
2016-08-25 08:44:59 +00:00
|
|
|
return factory()->NewSmiLiteral(value, pos);
|
2015-03-03 11:04:49 +00:00
|
|
|
}
|
2014-02-14 11:24:26 +00:00
|
|
|
case Token::NUMBER: {
|
2016-08-25 08:44:59 +00:00
|
|
|
double value = scanner()->DoubleValue();
|
2017-05-11 09:26:33 +00:00
|
|
|
return factory()->NewNumberLiteral(value, pos);
|
2014-02-14 11:24:26 +00:00
|
|
|
}
|
2017-10-13 18:23:53 +00:00
|
|
|
case Token::BIGINT:
|
|
|
|
return factory()->NewBigIntLiteral(
|
2017-10-27 19:53:15 +00:00
|
|
|
AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos);
|
2018-10-15 13:51:45 +00:00
|
|
|
case Token::STRING: {
|
2018-12-03 09:41:56 +00:00
|
|
|
return factory()->NewStringLiteral(GetSymbol(), pos);
|
2018-10-15 13:51:45 +00:00
|
|
|
}
|
2014-02-14 11:24:26 +00:00
|
|
|
default:
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(false);
|
2014-02-14 11:24:26 +00:00
|
|
|
}
|
2018-11-07 15:38:15 +00:00
|
|
|
return FailureExpression();
|
2014-02-14 11:24:26 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 11:03:46 +00:00
|
|
|
Expression* Parser::NewV8Intrinsic(const AstRawString* name,
|
2018-10-24 12:02:06 +00:00
|
|
|
const ScopedPtrList<Expression>& args,
|
2018-10-25 07:14:19 +00:00
|
|
|
int pos) {
|
2016-09-08 11:03:46 +00:00
|
|
|
if (extension_ != nullptr) {
|
|
|
|
// The extension structures are only accessible while parsing the
|
|
|
|
// very first time, not when reparsing because of lazy compilation.
|
|
|
|
GetClosureScope()->ForceEagerCompilation();
|
|
|
|
}
|
|
|
|
|
2019-04-02 09:23:28 +00:00
|
|
|
if (!name->is_one_byte()) {
|
|
|
|
// There are no two-byte named intrinsics.
|
|
|
|
ReportMessage(MessageTemplate::kNotDefined, name);
|
|
|
|
return FailureExpression();
|
|
|
|
}
|
|
|
|
|
2016-09-12 11:35:40 +00:00
|
|
|
const Runtime::Function* function =
|
|
|
|
Runtime::FunctionForName(name->raw_data(), name->length());
|
2016-09-08 11:03:46 +00:00
|
|
|
|
2020-06-17 16:56:54 +00:00
|
|
|
// Be more permissive when fuzzing. Intrinsics are not supported.
|
|
|
|
if (FLAG_fuzzing) {
|
2020-02-10 13:29:33 +00:00
|
|
|
return NewV8RuntimeFunctionForFuzzing(function, args, pos);
|
|
|
|
}
|
|
|
|
|
2016-09-08 11:03:46 +00:00
|
|
|
if (function != nullptr) {
|
|
|
|
// Check for possible name clash.
|
|
|
|
DCHECK_EQ(Context::kNotFound,
|
2016-09-12 11:35:40 +00:00
|
|
|
Context::IntrinsicIndexForName(name->raw_data(), name->length()));
|
2016-09-08 11:03:46 +00:00
|
|
|
|
|
|
|
// Check that the expected number of arguments are being passed.
|
2018-10-24 12:02:06 +00:00
|
|
|
if (function->nargs != -1 && function->nargs != args.length()) {
|
2016-09-08 11:03:46 +00:00
|
|
|
ReportMessage(MessageTemplate::kRuntimeWrongNumArgs);
|
2018-11-07 15:38:15 +00:00
|
|
|
return FailureExpression();
|
2016-09-08 11:03:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return factory()->NewCallRuntime(function, args, pos);
|
|
|
|
}
|
|
|
|
|
2016-09-12 11:35:40 +00:00
|
|
|
int context_index =
|
|
|
|
Context::IntrinsicIndexForName(name->raw_data(), name->length());
|
2016-09-08 11:03:46 +00:00
|
|
|
|
|
|
|
// Check that the function is defined.
|
|
|
|
if (context_index == Context::kNotFound) {
|
|
|
|
ReportMessage(MessageTemplate::kNotDefined, name);
|
2018-11-07 15:38:15 +00:00
|
|
|
return FailureExpression();
|
2016-09-08 11:03:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return factory()->NewCallRuntime(context_index, args, pos);
|
|
|
|
}
|
|
|
|
|
2020-02-10 13:29:33 +00:00
|
|
|
// More permissive runtime-function creation on fuzzers.
|
|
|
|
Expression* Parser::NewV8RuntimeFunctionForFuzzing(
|
|
|
|
const Runtime::Function* function, const ScopedPtrList<Expression>& args,
|
|
|
|
int pos) {
|
2020-06-17 16:56:54 +00:00
|
|
|
CHECK(FLAG_fuzzing);
|
2020-02-10 13:29:33 +00:00
|
|
|
|
2020-06-22 12:35:34 +00:00
|
|
|
// Intrinsics are not supported for fuzzing. Only allow allowlisted runtime
|
2020-02-10 13:29:33 +00:00
|
|
|
// functions. Also prevent later errors due to too few arguments and just
|
|
|
|
// ignore this call.
|
|
|
|
if (function == nullptr ||
|
2020-06-22 12:35:34 +00:00
|
|
|
!Runtime::IsAllowListedForFuzzing(function->function_id) ||
|
2020-02-10 13:29:33 +00:00
|
|
|
function->nargs > args.length()) {
|
|
|
|
return factory()->NewUndefinedLiteral(kNoSourcePosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flexible number of arguments permitted.
|
|
|
|
if (function->nargs == -1) {
|
|
|
|
return factory()->NewCallRuntime(function, args, pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise ignore superfluous arguments.
|
|
|
|
ScopedPtrList<Expression> permissive_args(pointer_buffer());
|
|
|
|
for (int i = 0; i < function->nargs; i++) {
|
|
|
|
permissive_args.Add(args.at(i));
|
|
|
|
}
|
|
|
|
return factory()->NewCallRuntime(function, permissive_args, pos);
|
|
|
|
}
|
|
|
|
|
2015-03-09 14:51:13 +00:00
|
|
|
Parser::Parser(ParseInfo* info)
|
2020-04-22 10:45:31 +00:00
|
|
|
: ParserBase<Parser>(
|
|
|
|
info->zone(), &scanner_, info->stack_limit(), info->extension(),
|
|
|
|
info->GetOrCreateAstValueFactory(), info->pending_error_handler(),
|
|
|
|
info->runtime_call_stats(), info->logger(), info->flags(), true),
|
2018-10-11 15:22:10 +00:00
|
|
|
info_(info),
|
2020-04-22 10:45:31 +00:00
|
|
|
scanner_(info->character_stream(), flags()),
|
2020-07-28 13:38:56 +00:00
|
|
|
preparser_zone_(info->zone()->allocator(), "pre-parser-zone"),
|
2016-11-07 13:23:01 +00:00
|
|
|
reusable_preparser_(nullptr),
|
2016-11-07 16:34:45 +00:00
|
|
|
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
|
2017-07-12 13:06:09 +00:00
|
|
|
source_range_map_(info->source_range_map()),
|
2014-09-02 11:36:21 +00:00
|
|
|
total_preparse_skipped_(0),
|
2019-01-07 14:09:18 +00:00
|
|
|
consumed_preparse_data_(info->consumed_preparse_data()),
|
2019-01-18 13:14:56 +00:00
|
|
|
preparse_data_buffer_(),
|
Implement new Function.prototype.toString --harmony-function-tostring
For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
starts at the "function" or "async" keyword and ends at the final "}".
The previous behavior would start the excerpt at the "(" of the
parameter list, and prepend a canonical `"function " + name` or
similar, which would discard comments and formatting surrounding the
function's name. Anonymous functions declared as function expressions
no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
generator methods), or property name, whichever comes first.
Previously, the toString representation for methods would use a
canonical prefix before the "(" of the parameter list. Note that any
"static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.
For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
"\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
but that was removed from the spec, and so this CL does not do it.
Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.
BUG=v8:4958, v8:4230
Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
2017-02-16 20:19:24 +00:00
|
|
|
parameters_end_pos_(info->parameters_end_pos()) {
|
2015-03-09 14:51:13 +00:00
|
|
|
// Even though we were passed ParseInfo, we should not store it in
|
2015-02-12 13:02:30 +00:00
|
|
|
// Parser - this makes sure that Isolate is not accidentally accessed via
|
2015-03-09 14:51:13 +00:00
|
|
|
// ParseInfo during background parsing.
|
2017-10-16 13:41:49 +00:00
|
|
|
DCHECK_NOT_NULL(info->character_stream());
|
2016-10-07 09:12:48 +00:00
|
|
|
// Determine if functions can be lazily compiled. This is necessary to
|
|
|
|
// allow some of our builtin JS files to be lazily compiled. These
|
|
|
|
// builtins cannot be handled lazily by the parser, since we have to know
|
|
|
|
// if a function uses the special natives syntax, which is something the
|
|
|
|
// parser records.
|
|
|
|
// If the debugger requests compilation for break points, we cannot be
|
|
|
|
// aggressive about lazy compilation, because it might trigger compilation
|
|
|
|
// of functions without an outer context when setting a breakpoint through
|
|
|
|
// Debug::FindSharedFunctionInfoInScript
|
2017-09-26 08:48:52 +00:00
|
|
|
// We also compile eagerly for kProduceExhaustiveCodeCache.
|
2020-04-22 10:45:31 +00:00
|
|
|
bool can_compile_lazily = flags().allow_lazy_compile() && !flags().is_eager();
|
2016-10-07 09:12:48 +00:00
|
|
|
|
|
|
|
set_default_eager_compile_hint(can_compile_lazily
|
|
|
|
? FunctionLiteral::kShouldLazyCompile
|
|
|
|
: FunctionLiteral::kShouldEagerCompile);
|
2020-04-22 10:45:31 +00:00
|
|
|
allow_lazy_ = flags().allow_lazy_compile() && flags().allow_lazy_parsing() &&
|
2019-03-29 17:53:11 +00:00
|
|
|
info->extension() == nullptr && can_compile_lazily;
|
2014-06-30 13:35:16 +00:00
|
|
|
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
|
|
|
++feature) {
|
|
|
|
use_counts_[feature] = 0;
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2018-08-28 12:00:28 +00:00
|
|
|
void Parser::InitializeEmptyScopeChain(ParseInfo* info) {
|
|
|
|
DCHECK_NULL(original_scope_);
|
|
|
|
DCHECK_NULL(info->script_scope());
|
2019-11-25 09:33:49 +00:00
|
|
|
DeclarationScope* script_scope =
|
2020-04-22 10:45:31 +00:00
|
|
|
NewScriptScope(flags().is_repl_mode() ? REPLMode::kYes : REPLMode::kNo);
|
2016-08-05 14:30:54 +00:00
|
|
|
info->set_script_scope(script_scope);
|
2018-08-28 12:00:28 +00:00
|
|
|
original_scope_ = script_scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::DeserializeScopeChain(
|
|
|
|
Isolate* isolate, ParseInfo* info,
|
2019-01-16 16:20:34 +00:00
|
|
|
MaybeHandle<ScopeInfo> maybe_outer_scope_info,
|
|
|
|
Scope::DeserializationMode mode) {
|
2018-08-28 12:00:28 +00:00
|
|
|
InitializeEmptyScopeChain(info);
|
2016-09-15 19:47:11 +00:00
|
|
|
Handle<ScopeInfo> outer_scope_info;
|
|
|
|
if (maybe_outer_scope_info.ToHandle(&outer_scope_info)) {
|
2019-03-11 09:35:40 +00:00
|
|
|
DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
|
2018-08-28 12:00:28 +00:00
|
|
|
original_scope_ = Scope::DeserializeScopeChain(
|
|
|
|
isolate, zone(), *outer_scope_info, info->script_scope(),
|
2019-01-16 16:20:34 +00:00
|
|
|
ast_value_factory(), mode);
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().is_eval() || IsArrowFunction(flags().function_kind())) {
|
2019-02-06 10:52:07 +00:00
|
|
|
original_scope_->GetReceiverScope()->DeserializeReceiver(
|
|
|
|
ast_value_factory());
|
|
|
|
}
|
2016-08-03 13:30:23 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2017-08-22 10:53:10 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) {
|
|
|
|
// Don't reset the character stream if there is an asm.js module since it will
|
|
|
|
// be used again by the asm-parser.
|
2018-12-14 14:17:48 +00:00
|
|
|
if (info->contains_asm_module()) {
|
|
|
|
if (FLAG_stress_validate_asm) return;
|
|
|
|
if (literal != nullptr && literal->scope()->ContainsAsmModule()) return;
|
2017-08-22 10:53:10 +00:00
|
|
|
}
|
2018-12-14 14:17:48 +00:00
|
|
|
info->ResetCharacterStream();
|
2017-08-22 10:53:10 +00:00
|
|
|
}
|
|
|
|
|
2018-12-03 14:34:35 +00:00
|
|
|
void MaybeProcessSourceRanges(ParseInfo* parse_info, Expression* root,
|
|
|
|
uintptr_t stack_limit_) {
|
|
|
|
if (root != nullptr && parse_info->source_range_map() != nullptr) {
|
|
|
|
SourceRangeAstVisitor visitor(stack_limit_, root,
|
|
|
|
parse_info->source_range_map());
|
|
|
|
visitor.Run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-22 10:53:10 +00:00
|
|
|
} // namespace
|
|
|
|
|
2020-05-05 16:27:30 +00:00
|
|
|
void Parser::ParseProgram(Isolate* isolate, Handle<Script> script,
|
|
|
|
ParseInfo* info,
|
|
|
|
MaybeHandle<ScopeInfo> maybe_outer_scope_info) {
|
2013-10-29 11:44:04 +00:00
|
|
|
// TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
|
|
|
|
// see comment for HistogramTimerScope class.
|
2020-04-22 10:45:31 +00:00
|
|
|
DCHECK_EQ(script->id(), flags().script_id());
|
2014-09-02 11:36:21 +00:00
|
|
|
|
2015-02-12 13:02:30 +00:00
|
|
|
// It's OK to use the Isolate & counters here, since this function is only
|
|
|
|
// called in the main thread.
|
|
|
|
DCHECK(parsing_on_main_thread_);
|
2016-11-15 16:08:16 +00:00
|
|
|
RuntimeCallTimerScope runtime_timer(
|
2020-04-22 10:45:31 +00:00
|
|
|
runtime_call_stats_, flags().is_eval()
|
2017-11-29 15:50:22 +00:00
|
|
|
? RuntimeCallCounterId::kParseEval
|
|
|
|
: RuntimeCallCounterId::kParseProgram);
|
2016-10-14 14:08:53 +00:00
|
|
|
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseProgram");
|
2014-06-30 13:25:46 +00:00
|
|
|
base::ElapsedTimer timer;
|
2017-11-14 09:12:52 +00:00
|
|
|
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Initialize parser state.
|
2020-03-18 12:52:03 +00:00
|
|
|
DeserializeScopeChain(isolate, info, maybe_outer_scope_info,
|
2019-01-16 16:20:34 +00:00
|
|
|
Scope::DeserializationMode::kIncludingVariables);
|
2016-08-03 13:30:23 +00:00
|
|
|
|
2020-03-18 12:52:03 +00:00
|
|
|
DCHECK_EQ(script->is_wrapped(), info->is_wrapped_as_function());
|
|
|
|
if (script->is_wrapped()) {
|
|
|
|
maybe_wrapped_arguments_ = handle(script->wrapped_arguments(), isolate);
|
|
|
|
}
|
|
|
|
|
2018-08-21 11:55:12 +00:00
|
|
|
scanner_.Initialize();
|
2018-06-19 08:30:34 +00:00
|
|
|
FunctionLiteral* result = DoParseProgram(isolate, info);
|
2017-08-22 10:53:10 +00:00
|
|
|
MaybeResetCharacterStream(info, result);
|
2018-12-03 14:34:35 +00:00
|
|
|
MaybeProcessSourceRanges(info, result, stack_limit_);
|
2020-05-05 16:27:30 +00:00
|
|
|
PostProcessParseResult(isolate, info, result);
|
2014-09-12 09:12:08 +00:00
|
|
|
|
2020-01-07 10:44:20 +00:00
|
|
|
HandleSourceURLComments(isolate, script);
|
2012-07-18 11:22:46 +00:00
|
|
|
|
2017-11-14 09:12:52 +00:00
|
|
|
if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) {
|
|
|
|
double ms = timer.Elapsed().InMillisecondsF();
|
|
|
|
const char* event_name = "parse-eval";
|
|
|
|
int start = -1;
|
|
|
|
int end = -1;
|
2020-04-22 10:45:31 +00:00
|
|
|
if (!flags().is_eval()) {
|
2017-11-14 09:12:52 +00:00
|
|
|
event_name = "parse-script";
|
|
|
|
start = 0;
|
2020-01-07 10:44:20 +00:00
|
|
|
end = String::cast(script->source()).length();
|
2017-11-14 09:12:52 +00:00
|
|
|
}
|
2020-04-22 10:45:31 +00:00
|
|
|
LOG(isolate,
|
|
|
|
FunctionEvent(event_name, flags().script_id(), ms, start, end, "", 0));
|
2017-11-14 09:12:52 +00:00
|
|
|
}
|
2010-12-07 14:03:59 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 08:30:34 +00:00
|
|
|
FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
|
2015-02-12 13:02:30 +00:00
|
|
|
// Note that this function can be called from the main thread or from a
|
|
|
|
// background thread. We should not access anything Isolate / heap dependent
|
2018-06-19 08:30:34 +00:00
|
|
|
// via ParseInfo, and also not pass it forward. If not on the main thread
|
|
|
|
// isolate will be nullptr.
|
|
|
|
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
|
2017-02-20 10:41:29 +00:00
|
|
|
DCHECK_NULL(scope_);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2016-11-16 12:40:16 +00:00
|
|
|
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
|
2016-11-28 11:40:22 +00:00
|
|
|
ResetFunctionLiteralId();
|
2015-04-27 12:13:45 +00:00
|
|
|
|
2017-10-13 16:33:03 +00:00
|
|
|
FunctionLiteral* result = nullptr;
|
2014-09-12 09:12:08 +00:00
|
|
|
{
|
2016-08-05 14:30:54 +00:00
|
|
|
Scope* outer = original_scope_;
|
2016-08-30 11:52:58 +00:00
|
|
|
DCHECK_NOT_NULL(outer);
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().is_eval()) {
|
2016-08-05 14:30:54 +00:00
|
|
|
outer = NewEvalScope(outer);
|
2020-04-22 10:45:31 +00:00
|
|
|
} else if (flags().is_module()) {
|
2016-08-18 08:50:55 +00:00
|
|
|
DCHECK_EQ(outer, info->script_scope());
|
|
|
|
outer = NewModuleScope(info->script_scope());
|
2011-11-15 13:48:40 +00:00
|
|
|
}
|
2015-04-16 12:42:43 +00:00
|
|
|
|
2016-08-05 14:30:54 +00:00
|
|
|
DeclarationScope* scope = outer->AsDeclarationScope();
|
2015-04-16 12:42:43 +00:00
|
|
|
scope->set_start_position(0);
|
2012-08-28 11:25:08 +00:00
|
|
|
|
2017-02-20 10:41:29 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, scope);
|
2018-11-05 15:20:49 +00:00
|
|
|
ScopedPtrList<Statement> body(pointer_buffer());
|
2014-02-14 12:13:33 +00:00
|
|
|
int beg_pos = scanner()->location().beg_pos;
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().is_module()) {
|
|
|
|
DCHECK(flags().is_module());
|
2016-09-12 12:54:47 +00:00
|
|
|
|
2016-12-12 09:57:17 +00:00
|
|
|
PrepareGeneratorVariables();
|
2016-09-30 07:53:43 +00:00
|
|
|
Expression* initial_yield =
|
|
|
|
BuildInitialYield(kNoSourcePosition, kGeneratorFunction);
|
2018-11-05 15:20:49 +00:00
|
|
|
body.Add(
|
|
|
|
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().allow_harmony_top_level_await()) {
|
2019-09-23 15:42:10 +00:00
|
|
|
// First parse statements into a buffer. Then, if there was a
|
|
|
|
// top level await, create an inner block and rewrite the body of the
|
|
|
|
// module as an async function. Otherwise merge the statements back
|
|
|
|
// into the main body.
|
|
|
|
BlockT block = impl()->NullBlock();
|
|
|
|
{
|
|
|
|
StatementListT statements(pointer_buffer());
|
|
|
|
ParseModuleItemList(&statements);
|
|
|
|
// Modules will always have an initial yield. If there are any
|
|
|
|
// additional suspends, i.e. awaits, then we treat the module as an
|
|
|
|
// AsyncModule.
|
|
|
|
if (function_state.suspend_count() > 1) {
|
|
|
|
scope->set_is_async_module();
|
|
|
|
block = factory()->NewBlock(true, statements);
|
|
|
|
} else {
|
|
|
|
statements.MergeInto(&body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (IsAsyncModule(scope->function_kind())) {
|
|
|
|
impl()->RewriteAsyncFunctionBody(
|
|
|
|
&body, block, factory()->NewUndefinedLiteral(kNoSourcePosition));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ParseModuleItemList(&body);
|
|
|
|
}
|
2019-01-23 11:32:39 +00:00
|
|
|
if (!has_error() &&
|
|
|
|
!module()->Validate(this->scope()->AsModuleScope(),
|
2018-10-31 12:57:01 +00:00
|
|
|
pending_error_handler(), zone())) {
|
|
|
|
scanner()->set_parser_error();
|
|
|
|
}
|
2017-12-18 08:10:06 +00:00
|
|
|
} else if (info->is_wrapped_as_function()) {
|
2020-01-07 10:44:20 +00:00
|
|
|
DCHECK(parsing_on_main_thread_);
|
2018-11-05 15:20:49 +00:00
|
|
|
ParseWrapped(isolate, info, &body, scope, zone());
|
2020-04-22 10:45:31 +00:00
|
|
|
} else if (flags().is_repl_mode()) {
|
2019-11-25 09:33:49 +00:00
|
|
|
ParseREPLProgram(info, &body, scope);
|
2015-01-27 21:06:36 +00:00
|
|
|
} else {
|
2016-04-22 13:37:10 +00:00
|
|
|
// Don't count the mode in the use counters--give the program a chance
|
|
|
|
// to enable script-wide strict mode below.
|
2016-07-19 10:06:38 +00:00
|
|
|
this->scope()->SetLanguageMode(info->language_mode());
|
2018-11-05 15:20:49 +00:00
|
|
|
ParseStatementList(&body, Token::EOS);
|
2015-01-27 21:06:36 +00:00
|
|
|
}
|
2014-07-02 07:01:31 +00:00
|
|
|
|
2015-04-16 12:42:43 +00:00
|
|
|
// The parser will peek but not consume EOS. Our scope logically goes all
|
|
|
|
// the way to the EOS, though.
|
2018-10-31 12:57:01 +00:00
|
|
|
scope->set_end_position(peek_position());
|
2015-04-16 12:42:43 +00:00
|
|
|
|
2018-10-31 12:57:01 +00:00
|
|
|
if (is_strict(language_mode())) {
|
|
|
|
CheckStrictOctalLiteral(beg_pos, end_position());
|
2015-07-10 16:39:47 +00:00
|
|
|
}
|
2018-10-31 12:57:01 +00:00
|
|
|
if (is_sloppy(language_mode())) {
|
2015-09-30 23:48:26 +00:00
|
|
|
// TODO(littledan): Function bindings on the global object that modify
|
|
|
|
// pre-existing bindings should be made writable, enumerable and
|
|
|
|
// nonconfigurable if possible, whereas this code will leave attributes
|
|
|
|
// unchanged if the property already exists.
|
2016-09-15 16:41:03 +00:00
|
|
|
InsertSloppyBlockFunctionVarBindings(scope);
|
2015-09-30 23:48:26 +00:00
|
|
|
}
|
2019-01-16 16:20:34 +00:00
|
|
|
// Internalize the ast strings in the case of eval so we can check for
|
|
|
|
// conflicting var declarations with outer scope-info-backed scopes.
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().is_eval()) {
|
2019-01-16 16:20:34 +00:00
|
|
|
DCHECK(parsing_on_main_thread_);
|
[offthread] Add an OffThreadIsolate
The Factory/OffThreadFactory allows us to cleanly separate object
construction behaviour between main-thread and off-thread in a
syntactically consistent way (so that methods templated on the factory
type can be made to work on both).
However, there are cases where we also have to access the Isolate, for
handle creation or exception throwing. So far we have been pushing more
and more "customization points" into the factories to allow these
factory-templated methods to dispatch on this isolate behaviour via
these factory methods. Unfortunately, this is an increasing layering
violation between Factory and Isolate, particularly around exception
handling.
Now, we introduce an OffThreadIsolate, analogous to Isolate in the same
way as OffThreadFactory is analogous to Factory. All methods which were
templated on Factory are now templated on Isolate, and methods which
used to take an Isolate, and which were recently changed to take a
templated Factory, are changed/reverted to take a templated Isolate.
OffThreadFactory gets an isolate() method to match Factory's.
Notably, FactoryHandle is changed to "HandleFor", where the template
argument can be either of the Isolate type or the Factory type (allowing
us to dispatch on both depending on what is available).
Bug: chromium:1011762
Change-Id: Id144176f7da534dd76f3d535ab2ade008b6845e3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2030909
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66101}
2020-02-04 10:50:53 +00:00
|
|
|
info->ast_value_factory()->Internalize(isolate);
|
2019-01-16 16:20:34 +00:00
|
|
|
}
|
2018-10-31 12:57:01 +00:00
|
|
|
CheckConflictingVarDeclarations(scope);
|
2011-09-01 12:31:18 +00:00
|
|
|
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
|
2018-11-05 15:20:49 +00:00
|
|
|
if (body.length() != 1 || !body.at(0)->IsExpressionStatement() ||
|
|
|
|
!body.at(0)
|
|
|
|
->AsExpressionStatement()
|
|
|
|
->expression()
|
|
|
|
->IsFunctionLiteral()) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessage(MessageTemplate::kSingleFunctionLiteral);
|
2013-03-07 15:46:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 19:04:44 +00:00
|
|
|
int parameter_count = 0;
|
2018-10-31 12:57:01 +00:00
|
|
|
result = factory()->NewScriptOrEvalFunctionLiteral(
|
|
|
|
scope, body, function_state.expected_property_count(), parameter_count);
|
|
|
|
result->set_suspend_count(function_state.suspend_count());
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 17:19:55 +00:00
|
|
|
info->set_max_function_literal_id(GetLastFunctionLiteralId());
|
|
|
|
|
2018-11-07 15:38:15 +00:00
|
|
|
if (has_error()) return nullptr;
|
2019-05-16 11:56:18 +00:00
|
|
|
|
|
|
|
RecordFunctionLiteralSourceRange(result);
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-05 16:27:30 +00:00
|
|
|
void Parser::PostProcessParseResult(Isolate* isolate, ParseInfo* info,
|
|
|
|
FunctionLiteral* literal) {
|
|
|
|
if (literal == nullptr) return;
|
|
|
|
|
|
|
|
info->set_literal(literal);
|
|
|
|
info->set_language_mode(literal->language_mode());
|
|
|
|
if (info->flags().is_eval()) {
|
|
|
|
info->set_allow_eval_cache(allow_eval_cache());
|
|
|
|
}
|
|
|
|
|
|
|
|
// We cannot internalize on a background thread; a foreground task will take
|
|
|
|
// care of calling AstValueFactory::Internalize just before compilation.
|
|
|
|
DCHECK_EQ(isolate != nullptr, parsing_on_main_thread_);
|
|
|
|
if (isolate) info->ast_value_factory()->Internalize(isolate);
|
|
|
|
|
|
|
|
{
|
|
|
|
RuntimeCallTimerScope runtimeTimer(info->runtime_call_stats(),
|
|
|
|
RuntimeCallCounterId::kCompileAnalyse,
|
|
|
|
RuntimeCallStats::kThreadSpecific);
|
|
|
|
if (!Rewriter::Rewrite(info) || !DeclarationScope::Analyze(info)) {
|
|
|
|
// Null out the literal to indicate that something failed.
|
|
|
|
info->set_literal(nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString>* Parser::PrepareWrappedArguments(
|
|
|
|
Isolate* isolate, ParseInfo* info, Zone* zone) {
|
2017-12-18 08:10:06 +00:00
|
|
|
DCHECK(parsing_on_main_thread_);
|
2018-06-19 08:30:34 +00:00
|
|
|
DCHECK_NOT_NULL(isolate);
|
2020-03-18 12:52:03 +00:00
|
|
|
Handle<FixedArray> arguments = maybe_wrapped_arguments_.ToHandleChecked();
|
2017-12-18 08:10:06 +00:00
|
|
|
int arguments_length = arguments->length();
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function =
|
2020-07-12 13:27:55 +00:00
|
|
|
zone->New<ZonePtrList<const AstRawString>>(arguments_length, zone);
|
2017-12-18 08:10:06 +00:00
|
|
|
for (int i = 0; i < arguments_length; i++) {
|
|
|
|
const AstRawString* argument_string = ast_value_factory()->GetString(
|
2018-06-19 08:30:34 +00:00
|
|
|
Handle<String>(String::cast(arguments->get(i)), isolate));
|
2017-12-18 08:10:06 +00:00
|
|
|
arguments_for_wrapped_function->Add(argument_string, zone);
|
|
|
|
}
|
|
|
|
return arguments_for_wrapped_function;
|
|
|
|
}
|
|
|
|
|
2018-06-19 08:30:34 +00:00
|
|
|
void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info,
|
2018-11-05 15:20:49 +00:00
|
|
|
ScopedPtrList<Statement>* body,
|
2018-10-31 12:57:01 +00:00
|
|
|
DeclarationScope* outer_scope, Zone* zone) {
|
2020-01-07 10:44:20 +00:00
|
|
|
DCHECK(parsing_on_main_thread_);
|
2017-12-18 08:10:06 +00:00
|
|
|
DCHECK(info->is_wrapped_as_function());
|
|
|
|
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
|
|
|
|
|
|
|
// Set function and block state for the outer eval scope.
|
|
|
|
DCHECK(outer_scope->is_eval_scope());
|
|
|
|
FunctionState function_state(&function_state_, &scope_, outer_scope);
|
|
|
|
|
|
|
|
const AstRawString* function_name = nullptr;
|
|
|
|
Scanner::Location location(0, 0);
|
|
|
|
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function =
|
2018-06-19 08:30:34 +00:00
|
|
|
PrepareWrappedArguments(isolate, info, zone);
|
2017-12-18 08:10:06 +00:00
|
|
|
|
|
|
|
FunctionLiteral* function_literal = ParseFunctionLiteral(
|
|
|
|
function_name, location, kSkipFunctionNameCheck, kNormalFunction,
|
2019-08-23 02:28:45 +00:00
|
|
|
kNoSourcePosition, FunctionSyntaxKind::kWrapped, LanguageMode::kSloppy,
|
2018-10-25 07:14:19 +00:00
|
|
|
arguments_for_wrapped_function);
|
2017-12-18 08:10:06 +00:00
|
|
|
|
|
|
|
Statement* return_statement = factory()->NewReturnStatement(
|
|
|
|
function_literal, kNoSourcePosition, kNoSourcePosition);
|
2018-11-05 15:20:49 +00:00
|
|
|
body->Add(return_statement);
|
2017-12-18 08:10:06 +00:00
|
|
|
}
|
|
|
|
|
2019-11-25 09:33:49 +00:00
|
|
|
void Parser::ParseREPLProgram(ParseInfo* info, ScopedPtrList<Statement>* body,
|
|
|
|
DeclarationScope* scope) {
|
|
|
|
// REPL scripts are handled nearly the same way as the body of an async
|
|
|
|
// function. The difference is the value used to resolve the async
|
|
|
|
// promise.
|
|
|
|
// For a REPL script this is the completion value of the
|
|
|
|
// script instead of the expression of some "return" statement. The
|
|
|
|
// completion value of the script is obtained by manually invoking
|
|
|
|
// the {Rewriter} which will return a VariableProxy referencing the
|
|
|
|
// result.
|
2020-04-22 10:45:31 +00:00
|
|
|
DCHECK(flags().is_repl_mode());
|
2019-11-25 09:33:49 +00:00
|
|
|
this->scope()->SetLanguageMode(info->language_mode());
|
|
|
|
PrepareGeneratorVariables();
|
|
|
|
|
|
|
|
BlockT block = impl()->NullBlock();
|
|
|
|
{
|
|
|
|
StatementListT statements(pointer_buffer());
|
|
|
|
ParseStatementList(&statements, Token::EOS);
|
|
|
|
block = factory()->NewBlock(true, statements);
|
|
|
|
}
|
|
|
|
|
2020-01-28 06:25:15 +00:00
|
|
|
if (has_error()) return;
|
|
|
|
|
2019-11-25 09:33:49 +00:00
|
|
|
base::Optional<VariableProxy*> maybe_result =
|
|
|
|
Rewriter::RewriteBody(info, scope, block->statements());
|
|
|
|
Expression* result_value =
|
|
|
|
(maybe_result && *maybe_result)
|
|
|
|
? static_cast<Expression*>(*maybe_result)
|
|
|
|
: factory()->NewUndefinedLiteral(kNoSourcePosition);
|
|
|
|
|
2019-12-18 08:16:30 +00:00
|
|
|
impl()->RewriteAsyncFunctionBody(body, block, WrapREPLResult(result_value),
|
|
|
|
REPLMode::kYes);
|
2019-11-25 09:33:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expression* Parser::WrapREPLResult(Expression* value) {
|
|
|
|
// REPL scripts additionally wrap the ".result" variable in an
|
|
|
|
// object literal:
|
|
|
|
//
|
|
|
|
// return %_AsyncFunctionResolve(
|
|
|
|
// .generator_object, {.repl_result: .result});
|
|
|
|
//
|
|
|
|
// Should ".result" be a resolved promise itself, the async return
|
|
|
|
// would chain the promises and return the resolve value instead of
|
|
|
|
// the promise.
|
|
|
|
|
|
|
|
Literal* property_name = factory()->NewStringLiteral(
|
|
|
|
ast_value_factory()->dot_repl_result_string(), kNoSourcePosition);
|
|
|
|
ObjectLiteralProperty* property =
|
|
|
|
factory()->NewObjectLiteralProperty(property_name, value, true);
|
|
|
|
|
|
|
|
ScopedPtrList<ObjectLiteralProperty> properties(pointer_buffer());
|
|
|
|
properties.Add(property);
|
|
|
|
return factory()->NewObjectLiteral(properties, false, kNoSourcePosition,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2020-05-05 16:27:30 +00:00
|
|
|
void Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
|
|
|
|
Handle<SharedFunctionInfo> shared_info) {
|
2015-02-12 13:02:30 +00:00
|
|
|
// It's OK to use the Isolate & counters here, since this function is only
|
|
|
|
// called in the main thread.
|
|
|
|
DCHECK(parsing_on_main_thread_);
|
2016-11-15 16:08:16 +00:00
|
|
|
RuntimeCallTimerScope runtime_timer(runtime_call_stats_,
|
2017-11-29 15:50:22 +00:00
|
|
|
RuntimeCallCounterId::kParseFunction);
|
2016-10-14 14:08:53 +00:00
|
|
|
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseFunction");
|
2014-06-30 13:25:46 +00:00
|
|
|
base::ElapsedTimer timer;
|
2017-11-14 09:12:52 +00:00
|
|
|
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
|
|
|
|
|
2020-03-18 12:52:03 +00:00
|
|
|
MaybeHandle<ScopeInfo> maybe_outer_scope_info;
|
|
|
|
if (shared_info->HasOuterScopeInfo()) {
|
|
|
|
maybe_outer_scope_info = handle(shared_info->GetOuterScopeInfo(), isolate);
|
|
|
|
}
|
|
|
|
DeserializeScopeChain(isolate, info, maybe_outer_scope_info,
|
2019-01-16 16:20:34 +00:00
|
|
|
Scope::DeserializationMode::kIncludingVariables);
|
2017-09-15 08:13:10 +00:00
|
|
|
DCHECK_EQ(factory()->zone(), info->zone());
|
2012-07-18 11:22:46 +00:00
|
|
|
|
2020-03-18 12:52:03 +00:00
|
|
|
if (shared_info->is_wrapped()) {
|
|
|
|
maybe_wrapped_arguments_ = handle(
|
|
|
|
Script::cast(shared_info->script()).wrapped_arguments(), isolate);
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:45:31 +00:00
|
|
|
int start_position = shared_info->StartPosition();
|
|
|
|
int end_position = shared_info->EndPosition();
|
|
|
|
int function_literal_id = shared_info->function_literal_id();
|
|
|
|
|
2010-12-07 14:03:59 +00:00
|
|
|
// Initialize parser state.
|
2018-06-19 08:30:34 +00:00
|
|
|
Handle<String> name(shared_info->Name(), isolate);
|
2017-08-21 12:59:45 +00:00
|
|
|
info->set_function_name(ast_value_factory()->GetString(name));
|
2018-08-21 11:55:12 +00:00
|
|
|
scanner_.Initialize();
|
2017-08-21 12:59:45 +00:00
|
|
|
|
2019-09-06 00:06:32 +00:00
|
|
|
FunctionLiteral* result;
|
|
|
|
if (V8_UNLIKELY(shared_info->private_name_lookup_skips_outer_class() &&
|
|
|
|
original_scope_->is_class_scope())) {
|
|
|
|
// If the function skips the outer class and the outer scope is a class, the
|
|
|
|
// function is in heritage position. Otherwise the function scope's skip bit
|
|
|
|
// will be correctly inherited from the outer scope.
|
|
|
|
ClassScope::HeritageParsingScope heritage(original_scope_->AsClassScope());
|
2020-04-22 10:45:31 +00:00
|
|
|
result = DoParseFunction(isolate, info, start_position, end_position,
|
|
|
|
function_literal_id, info->function_name());
|
2019-09-06 00:06:32 +00:00
|
|
|
} else {
|
2020-04-22 10:45:31 +00:00
|
|
|
result = DoParseFunction(isolate, info, start_position, end_position,
|
|
|
|
function_literal_id, info->function_name());
|
2019-09-06 00:06:32 +00:00
|
|
|
}
|
2017-08-22 10:53:10 +00:00
|
|
|
MaybeResetCharacterStream(info, result);
|
2018-12-03 14:34:35 +00:00
|
|
|
MaybeProcessSourceRanges(info, result, stack_limit_);
|
2017-08-21 12:59:45 +00:00
|
|
|
if (result != nullptr) {
|
2018-06-19 08:30:34 +00:00
|
|
|
Handle<String> inferred_name(shared_info->inferred_name(), isolate);
|
2017-08-21 12:59:45 +00:00
|
|
|
result->set_inferred_name(inferred_name);
|
2010-12-07 14:03:59 +00:00
|
|
|
}
|
2020-05-05 16:27:30 +00:00
|
|
|
PostProcessParseResult(isolate, info, result);
|
2012-07-18 11:22:46 +00:00
|
|
|
|
2017-11-14 09:12:52 +00:00
|
|
|
if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) {
|
2013-08-29 09:15:13 +00:00
|
|
|
double ms = timer.Elapsed().InMillisecondsF();
|
2020-05-05 16:27:30 +00:00
|
|
|
// We should already be internalized by now, so the debug name will be
|
|
|
|
// available.
|
2017-11-14 09:12:52 +00:00
|
|
|
DeclarationScope* function_scope = result->scope();
|
|
|
|
std::unique_ptr<char[]> function_name = result->GetDebugName();
|
2018-06-04 14:41:00 +00:00
|
|
|
LOG(isolate,
|
2020-04-22 10:45:31 +00:00
|
|
|
FunctionEvent("parse-function", flags().script_id(), ms,
|
2017-11-14 09:12:52 +00:00
|
|
|
function_scope->start_position(),
|
|
|
|
function_scope->end_position(), function_name.get(),
|
|
|
|
strlen(function_name.get())));
|
2012-07-18 11:22:46 +00:00
|
|
|
}
|
2010-12-07 14:03:59 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 08:30:34 +00:00
|
|
|
FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
|
2020-04-22 10:45:31 +00:00
|
|
|
int start_position, int end_position,
|
|
|
|
int function_literal_id,
|
2017-08-18 20:34:14 +00:00
|
|
|
const AstRawString* raw_name) {
|
2018-06-19 08:30:34 +00:00
|
|
|
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
|
2017-04-06 11:58:38 +00:00
|
|
|
DCHECK_NOT_NULL(raw_name);
|
2017-02-20 10:41:29 +00:00
|
|
|
DCHECK_NULL(scope_);
|
2010-12-07 14:03:59 +00:00
|
|
|
|
2014-09-11 09:52:36 +00:00
|
|
|
DCHECK(ast_value_factory());
|
2018-09-21 11:20:02 +00:00
|
|
|
fni_.PushEnclosingName(raw_name);
|
2010-08-23 13:26:03 +00:00
|
|
|
|
2016-11-28 11:40:22 +00:00
|
|
|
ResetFunctionLiteralId();
|
2020-04-22 10:45:31 +00:00
|
|
|
DCHECK_LT(0, function_literal_id);
|
|
|
|
SkipFunctionLiterals(function_literal_id - 1);
|
2016-11-28 11:40:22 +00:00
|
|
|
|
2012-08-07 14:47:36 +00:00
|
|
|
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Place holder for the result.
|
2016-07-19 10:06:38 +00:00
|
|
|
FunctionLiteral* result = nullptr;
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
// Parse the function literal.
|
2016-08-30 11:52:58 +00:00
|
|
|
Scope* outer = original_scope_;
|
2016-09-27 09:49:26 +00:00
|
|
|
DeclarationScope* outer_function = outer->GetClosureScope();
|
2016-08-30 11:52:58 +00:00
|
|
|
DCHECK(outer);
|
2017-02-20 10:41:29 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, outer_function);
|
|
|
|
BlockState block_state(&scope_, outer);
|
2016-08-30 11:52:58 +00:00
|
|
|
DCHECK(is_sloppy(outer->language_mode()) ||
|
2015-02-12 13:02:30 +00:00
|
|
|
is_strict(info->language_mode()));
|
2020-04-22 10:45:31 +00:00
|
|
|
FunctionKind kind = flags().function_kind();
|
|
|
|
DCHECK_IMPLIES(IsConciseMethod(kind) || IsAccessorFunction(kind),
|
|
|
|
flags().function_syntax_kind() ==
|
|
|
|
FunctionSyntaxKind::kAccessorOrMethod);
|
2014-07-21 09:58:01 +00:00
|
|
|
|
2016-09-28 21:23:53 +00:00
|
|
|
if (IsArrowFunction(kind)) {
|
2017-01-10 23:27:02 +00:00
|
|
|
if (IsAsyncFunction(kind)) {
|
2018-08-24 11:38:13 +00:00
|
|
|
DCHECK(!scanner()->HasLineTerminatorAfterNext());
|
2016-07-11 19:28:56 +00:00
|
|
|
if (!Check(Token::ASYNC)) {
|
|
|
|
CHECK(stack_overflow());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!(peek_any_identifier() || peek() == Token::LPAREN)) {
|
|
|
|
CHECK(stack_overflow());
|
|
|
|
return nullptr;
|
|
|
|
}
|
2016-05-16 23:17:13 +00:00
|
|
|
}
|
|
|
|
|
2016-01-14 19:20:56 +00:00
|
|
|
// TODO(adamk): We should construct this scope from the ScopeInfo.
|
2016-09-28 21:23:53 +00:00
|
|
|
DeclarationScope* scope = NewFunctionScope(kind);
|
2019-01-28 12:46:24 +00:00
|
|
|
scope->set_has_checked_syntax(true);
|
2016-01-14 19:20:56 +00:00
|
|
|
|
2017-02-28 18:47:15 +00:00
|
|
|
// This bit only needs to be explicitly set because we're
|
2016-01-14 19:20:56 +00:00
|
|
|
// not passing the ScopeInfo to the Scope constructor.
|
2016-08-04 08:51:29 +00:00
|
|
|
SetLanguageMode(scope, info->language_mode());
|
2016-01-14 19:20:56 +00:00
|
|
|
|
2020-04-22 10:45:31 +00:00
|
|
|
scope->set_start_position(start_position);
|
2015-07-23 11:53:31 +00:00
|
|
|
ParserFormalParameters formals(scope);
|
2015-06-15 17:06:34 +00:00
|
|
|
{
|
2019-01-08 12:26:54 +00:00
|
|
|
ParameterDeclarationParsingScope formals_scope(this);
|
2015-06-15 17:06:34 +00:00
|
|
|
// Parsing patterns as variable reference expression creates
|
2017-03-31 08:40:38 +00:00
|
|
|
// NewUnresolved references in current scope. Enter arrow function
|
2015-06-15 17:06:34 +00:00
|
|
|
// scope for formal parameter parsing.
|
2017-02-20 10:41:29 +00:00
|
|
|
BlockState block_state(&scope_, scope);
|
2015-06-15 17:06:34 +00:00
|
|
|
if (Check(Token::LPAREN)) {
|
|
|
|
// '(' StrictFormalParameters ')'
|
2018-10-25 07:14:19 +00:00
|
|
|
ParseFormalParameterList(&formals);
|
2018-10-31 12:57:01 +00:00
|
|
|
Expect(Token::RPAREN);
|
2015-06-15 17:06:34 +00:00
|
|
|
} else {
|
|
|
|
// BindingIdentifier
|
2018-12-17 09:28:27 +00:00
|
|
|
ParameterParsingScope scope(impl(), &formals);
|
2018-10-25 07:14:19 +00:00
|
|
|
ParseFormalParameter(&formals);
|
2018-10-31 12:57:01 +00:00
|
|
|
DeclareFormalParameters(&formals);
|
2015-06-15 17:06:34 +00:00
|
|
|
}
|
2019-01-21 09:47:58 +00:00
|
|
|
formals.duplicate_loc = formals_scope.duplicate_location();
|
2015-04-21 14:44:18 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 10:45:31 +00:00
|
|
|
if (GetLastFunctionLiteralId() != function_literal_id - 1) {
|
2018-11-12 08:06:22 +00:00
|
|
|
if (has_error()) return nullptr;
|
2018-10-31 12:57:01 +00:00
|
|
|
// If there were FunctionLiterals in the parameters, we need to
|
|
|
|
// renumber them to shift down so the next function literal id for
|
|
|
|
// the arrow function is the one requested.
|
|
|
|
AstFunctionLiteralIdReindexer reindexer(
|
|
|
|
stack_limit_,
|
2020-04-22 10:45:31 +00:00
|
|
|
(function_literal_id - 1) - GetLastFunctionLiteralId());
|
2018-10-31 12:57:01 +00:00
|
|
|
for (auto p : formals.params) {
|
|
|
|
if (p->pattern != nullptr) reindexer.Reindex(p->pattern);
|
|
|
|
if (p->initializer() != nullptr) {
|
|
|
|
reindexer.Reindex(p->initializer());
|
2016-11-28 11:40:22 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-31 12:57:01 +00:00
|
|
|
ResetFunctionLiteralId();
|
2020-04-22 10:45:31 +00:00
|
|
|
SkipFunctionLiterals(function_literal_id - 1);
|
2018-10-31 12:57:01 +00:00
|
|
|
}
|
2016-11-28 11:40:22 +00:00
|
|
|
|
2018-11-27 16:51:45 +00:00
|
|
|
Expression* expression = ParseArrowFunctionLiteral(formals);
|
2018-10-31 12:57:01 +00:00
|
|
|
// Scanning must end at the same position that was recorded
|
|
|
|
// previously. If not, parsing has been interrupted due to a stack
|
|
|
|
// overflow, at which point the partially parsed arrow function
|
|
|
|
// concise body happens to be a valid expression. This is a problem
|
|
|
|
// only for arrow functions with single expression bodies, since there
|
|
|
|
// is no end token such as "}" for normal functions.
|
2020-04-22 10:45:31 +00:00
|
|
|
if (scanner()->location().end_pos == end_position) {
|
2018-10-31 12:57:01 +00:00
|
|
|
// The pre-parser saw an arrow function here, so the full parser
|
|
|
|
// must produce a FunctionLiteral.
|
|
|
|
DCHECK(expression->IsFunctionLiteral());
|
|
|
|
result = expression->AsFunctionLiteral();
|
2015-03-20 00:17:41 +00:00
|
|
|
}
|
2016-09-28 21:23:53 +00:00
|
|
|
} else if (IsDefaultConstructor(kind)) {
|
2016-08-30 11:52:58 +00:00
|
|
|
DCHECK_EQ(scope(), outer);
|
2017-01-03 19:37:23 +00:00
|
|
|
result = DefaultConstructor(raw_name, IsDerivedConstructor(kind),
|
2020-04-22 10:45:31 +00:00
|
|
|
start_position, end_position);
|
2014-07-21 09:58:01 +00:00
|
|
|
} else {
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function =
|
2018-06-19 08:30:34 +00:00
|
|
|
info->is_wrapped_as_function()
|
|
|
|
? PrepareWrappedArguments(isolate, info, zone())
|
|
|
|
: nullptr;
|
2016-09-28 21:23:53 +00:00
|
|
|
result = ParseFunctionLiteral(
|
2017-08-18 20:34:14 +00:00
|
|
|
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
|
2020-04-22 10:45:31 +00:00
|
|
|
kNoSourcePosition, flags().function_syntax_kind(),
|
2019-08-23 02:28:45 +00:00
|
|
|
info->language_mode(), arguments_for_wrapped_function);
|
2017-11-27 09:56:36 +00:00
|
|
|
}
|
|
|
|
|
2018-11-07 15:38:15 +00:00
|
|
|
if (has_error()) return nullptr;
|
2018-11-06 12:06:39 +00:00
|
|
|
result->set_requires_instance_members_initializer(
|
2020-04-22 10:45:31 +00:00
|
|
|
flags().requires_instance_members_initializer());
|
2020-03-03 18:23:03 +00:00
|
|
|
result->set_class_scope_has_private_brand(
|
2020-04-22 10:45:31 +00:00
|
|
|
flags().class_scope_has_private_brand());
|
2020-03-06 14:44:50 +00:00
|
|
|
result->set_has_static_private_methods_or_accessors(
|
2020-04-22 10:45:31 +00:00
|
|
|
flags().has_static_private_methods_or_accessors());
|
|
|
|
if (flags().is_oneshot_iife()) {
|
2019-01-21 10:13:52 +00:00
|
|
|
result->mark_as_oneshot_iife();
|
2019-01-17 15:59:03 +00:00
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 10:45:31 +00:00
|
|
|
DCHECK_IMPLIES(result, function_literal_id == result->function_literal_id());
|
2008-07-03 15:10:15 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Statement* Parser::ParseModuleItem() {
|
2016-07-18 07:27:10 +00:00
|
|
|
// ecma262/#prod-ModuleItem
|
2015-01-27 21:06:36 +00:00
|
|
|
// ModuleItem :
|
|
|
|
// ImportDeclaration
|
|
|
|
// ExportDeclaration
|
|
|
|
// StatementListItem
|
2012-02-20 14:02:59 +00:00
|
|
|
|
2017-01-31 18:58:53 +00:00
|
|
|
Token::Value next = peek();
|
|
|
|
|
|
|
|
if (next == Token::EXPORT) {
|
2018-10-25 07:14:19 +00:00
|
|
|
return ParseExportDeclaration();
|
2012-02-20 14:02:59 +00:00
|
|
|
}
|
2017-01-31 18:58:53 +00:00
|
|
|
|
2017-10-07 17:12:07 +00:00
|
|
|
if (next == Token::IMPORT) {
|
|
|
|
// We must be careful not to parse a dynamic import expression as an import
|
|
|
|
// declaration. Same for import.meta expressions.
|
|
|
|
Token::Value peek_ahead = PeekAhead();
|
2020-11-03 17:20:46 +00:00
|
|
|
if (peek_ahead != Token::LPAREN && peek_ahead != Token::PERIOD) {
|
2018-10-25 07:14:19 +00:00
|
|
|
ParseImportDeclaration();
|
2018-10-30 14:41:34 +00:00
|
|
|
return factory()->EmptyStatement();
|
2017-10-07 17:12:07 +00:00
|
|
|
}
|
2017-01-31 18:58:53 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
return ParseStatementListItem();
|
2012-02-20 14:02:59 +00:00
|
|
|
}
|
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
void Parser::ParseModuleItemList(ScopedPtrList<Statement>* body) {
|
2016-07-18 07:27:10 +00:00
|
|
|
// ecma262/#prod-Module
|
2015-01-27 21:06:36 +00:00
|
|
|
// Module :
|
|
|
|
// ModuleBody?
|
|
|
|
//
|
2016-07-18 07:27:10 +00:00
|
|
|
// ecma262/#prod-ModuleItemList
|
2015-01-27 21:06:36 +00:00
|
|
|
// ModuleBody :
|
|
|
|
// ModuleItem*
|
2012-02-20 14:02:59 +00:00
|
|
|
|
2016-07-19 10:06:38 +00:00
|
|
|
DCHECK(scope()->is_module_scope());
|
2015-02-24 22:39:26 +00:00
|
|
|
while (peek() != Token::EOS) {
|
2018-10-25 07:14:19 +00:00
|
|
|
Statement* stat = ParseModuleItem();
|
2018-11-07 17:00:35 +00:00
|
|
|
if (stat == nullptr) return;
|
2018-10-30 14:41:34 +00:00
|
|
|
if (stat->IsEmptyStatement()) continue;
|
2018-11-05 15:20:49 +00:00
|
|
|
body->Add(stat);
|
2012-02-20 14:02:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
const AstRawString* Parser::ParseModuleSpecifier() {
|
2015-02-06 17:52:20 +00:00
|
|
|
// ModuleSpecifier :
|
|
|
|
// StringLiteral
|
2012-02-20 14:02:59 +00:00
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::STRING);
|
2016-08-25 08:44:59 +00:00
|
|
|
return GetSymbol();
|
2012-02-20 14:02:59 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 14:20:41 +00:00
|
|
|
ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
|
2020-10-21 20:43:40 +00:00
|
|
|
Scanner::Location* reserved_loc,
|
|
|
|
Scanner::Location* string_literal_local_name_loc) {
|
2015-01-30 03:26:50 +00:00
|
|
|
// ExportClause :
|
2015-01-28 19:18:37 +00:00
|
|
|
// '{' '}'
|
2015-01-30 03:26:50 +00:00
|
|
|
// '{' ExportsList '}'
|
|
|
|
// '{' ExportsList ',' '}'
|
2015-01-28 19:18:37 +00:00
|
|
|
//
|
2015-01-30 03:26:50 +00:00
|
|
|
// ExportsList :
|
|
|
|
// ExportSpecifier
|
|
|
|
// ExportsList ',' ExportSpecifier
|
2015-01-28 19:18:37 +00:00
|
|
|
//
|
2015-01-30 03:26:50 +00:00
|
|
|
// ExportSpecifier :
|
2015-01-28 19:18:37 +00:00
|
|
|
// IdentifierName
|
|
|
|
// IdentifierName 'as' IdentifierName
|
2020-10-21 20:43:40 +00:00
|
|
|
// IdentifierName 'as' ModuleExportName
|
|
|
|
// ModuleExportName
|
|
|
|
// ModuleExportName 'as' ModuleExportName
|
|
|
|
//
|
|
|
|
// ModuleExportName :
|
|
|
|
// StringLiteral
|
2018-07-23 14:20:41 +00:00
|
|
|
ZoneChunkList<ExportClauseData>* export_data =
|
2020-07-12 13:27:55 +00:00
|
|
|
zone()->New<ZoneChunkList<ExportClauseData>>(zone());
|
2015-01-28 19:18:37 +00:00
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::LBRACE);
|
2015-01-28 19:18:37 +00:00
|
|
|
|
2015-01-30 03:26:50 +00:00
|
|
|
Token::Value name_tok;
|
|
|
|
while ((name_tok = peek()) != Token::RBRACE) {
|
2020-10-21 20:43:40 +00:00
|
|
|
const AstRawString* local_name = ParseExportSpecifierName();
|
|
|
|
if (!string_literal_local_name_loc->IsValid() &&
|
|
|
|
name_tok == Token::STRING) {
|
|
|
|
// Keep track of the first string literal local name exported for error
|
|
|
|
// reporting. These must be followed by a 'from' clause.
|
|
|
|
*string_literal_local_name_loc = scanner()->location();
|
|
|
|
} else if (!reserved_loc->IsValid() &&
|
|
|
|
!Token::IsValidIdentifier(name_tok, LanguageMode::kStrict, false,
|
|
|
|
flags().is_module())) {
|
|
|
|
// Keep track of the first reserved word encountered in case our
|
|
|
|
// caller needs to report an error.
|
2015-01-30 03:26:50 +00:00
|
|
|
*reserved_loc = scanner()->location();
|
|
|
|
}
|
2020-10-21 20:43:40 +00:00
|
|
|
const AstRawString* export_name;
|
2016-10-26 15:09:47 +00:00
|
|
|
Scanner::Location location = scanner()->location();
|
2018-11-13 13:50:45 +00:00
|
|
|
if (CheckContextualKeyword(ast_value_factory()->as_string())) {
|
2020-10-21 20:43:40 +00:00
|
|
|
export_name = ParseExportSpecifierName();
|
2016-10-26 15:09:47 +00:00
|
|
|
// Set the location to the whole "a as b" string, so that it makes sense
|
|
|
|
// both for errors due to "a" and for errors due to "b".
|
|
|
|
location.end_pos = scanner()->location().end_pos;
|
2020-10-21 20:43:40 +00:00
|
|
|
} else {
|
2015-02-19 20:14:55 +00:00
|
|
|
export_name = local_name;
|
|
|
|
}
|
2018-07-23 14:20:41 +00:00
|
|
|
export_data->push_back({export_name, local_name, location});
|
2015-01-28 19:18:37 +00:00
|
|
|
if (peek() == Token::RBRACE) break;
|
2018-11-07 17:00:35 +00:00
|
|
|
if (V8_UNLIKELY(!Check(Token::COMMA))) {
|
|
|
|
ReportUnexpectedToken(Next());
|
|
|
|
break;
|
|
|
|
}
|
2015-01-28 19:18:37 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::RBRACE);
|
2018-07-23 14:20:41 +00:00
|
|
|
return export_data;
|
2015-01-28 19:18:37 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 20:43:40 +00:00
|
|
|
const AstRawString* Parser::ParseExportSpecifierName() {
|
|
|
|
Token::Value next = Next();
|
|
|
|
|
|
|
|
// IdentifierName
|
|
|
|
if (V8_LIKELY(Token::IsPropertyName(next))) {
|
|
|
|
return GetSymbol();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ModuleExportName
|
|
|
|
if (next == Token::STRING) {
|
|
|
|
const AstRawString* export_name = GetSymbol();
|
|
|
|
if (V8_LIKELY(export_name->is_one_byte())) return export_name;
|
|
|
|
if (!unibrow::Utf16::HasUnpairedSurrogate(
|
|
|
|
reinterpret_cast<const uint16_t*>(export_name->raw_data()),
|
|
|
|
export_name->length())) {
|
|
|
|
return export_name;
|
|
|
|
}
|
|
|
|
ReportMessage(MessageTemplate::kInvalidModuleExportName);
|
|
|
|
return EmptyIdentifierString();
|
|
|
|
}
|
|
|
|
|
|
|
|
ReportUnexpectedToken(next);
|
|
|
|
return EmptyIdentifierString();
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
|
2015-01-30 03:26:50 +00:00
|
|
|
// NamedImports :
|
|
|
|
// '{' '}'
|
|
|
|
// '{' ImportsList '}'
|
|
|
|
// '{' ImportsList ',' '}'
|
|
|
|
//
|
|
|
|
// ImportsList :
|
|
|
|
// ImportSpecifier
|
|
|
|
// ImportsList ',' ImportSpecifier
|
|
|
|
//
|
|
|
|
// ImportSpecifier :
|
|
|
|
// BindingIdentifier
|
|
|
|
// IdentifierName 'as' BindingIdentifier
|
2020-10-21 20:43:40 +00:00
|
|
|
// ModuleExportName 'as' BindingIdentifier
|
2015-01-30 03:26:50 +00:00
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::LBRACE);
|
2015-01-30 03:26:50 +00:00
|
|
|
|
2020-07-12 13:27:55 +00:00
|
|
|
auto result = zone()->New<ZonePtrList<const NamedImport>>(1, zone());
|
2015-02-25 19:40:39 +00:00
|
|
|
while (peek() != Token::RBRACE) {
|
2020-10-21 20:43:40 +00:00
|
|
|
const AstRawString* import_name = ParseExportSpecifierName();
|
2015-02-25 19:40:39 +00:00
|
|
|
const AstRawString* local_name = import_name;
|
2016-10-26 15:09:47 +00:00
|
|
|
Scanner::Location location = scanner()->location();
|
2015-01-30 03:26:50 +00:00
|
|
|
// In the presence of 'as', the left-side of the 'as' can
|
|
|
|
// be any IdentifierName. But without 'as', it must be a valid
|
2015-02-25 19:40:39 +00:00
|
|
|
// BindingIdentifier.
|
2018-11-13 13:50:45 +00:00
|
|
|
if (CheckContextualKeyword(ast_value_factory()->as_string())) {
|
2018-12-03 11:01:25 +00:00
|
|
|
local_name = ParsePropertyName();
|
2015-02-25 19:40:39 +00:00
|
|
|
}
|
2018-11-30 14:26:42 +00:00
|
|
|
if (!Token::IsValidIdentifier(scanner()->current_token(),
|
|
|
|
LanguageMode::kStrict, false,
|
2020-04-22 10:45:31 +00:00
|
|
|
flags().is_module())) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessage(MessageTemplate::kUnexpectedReserved);
|
2016-07-18 07:27:10 +00:00
|
|
|
return nullptr;
|
2015-02-25 19:40:39 +00:00
|
|
|
} else if (IsEvalOrArguments(local_name)) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessage(MessageTemplate::kStrictEvalArguments);
|
2016-07-18 07:27:10 +00:00
|
|
|
return nullptr;
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
2016-07-18 07:27:10 +00:00
|
|
|
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareUnboundVariable(local_name, VariableMode::kConst,
|
|
|
|
kNeedsInitialization, position());
|
2016-07-18 07:27:10 +00:00
|
|
|
|
2016-10-26 15:09:47 +00:00
|
|
|
NamedImport* import =
|
2020-07-12 13:27:55 +00:00
|
|
|
zone()->New<NamedImport>(import_name, local_name, location);
|
2016-07-18 07:27:10 +00:00
|
|
|
result->Add(import, zone());
|
|
|
|
|
2015-01-30 03:26:50 +00:00
|
|
|
if (peek() == Token::RBRACE) break;
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::COMMA);
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::RBRACE);
|
2015-02-26 18:40:50 +00:00
|
|
|
return result;
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 19:08:51 +00:00
|
|
|
ImportAssertions* Parser::ParseImportAssertClause() {
|
2020-10-14 19:12:37 +00:00
|
|
|
// AssertClause :
|
|
|
|
// assert '{' '}'
|
|
|
|
// assert '{' AssertEntries '}'
|
|
|
|
|
|
|
|
// AssertEntries :
|
|
|
|
// IdentifierName: AssertionKey
|
|
|
|
// IdentifierName: AssertionKey , AssertEntries
|
|
|
|
|
|
|
|
// AssertionKey :
|
|
|
|
// IdentifierName
|
|
|
|
// StringLiteral
|
|
|
|
|
2020-10-17 01:27:26 +00:00
|
|
|
auto import_assertions = zone()->New<ImportAssertions>(zone());
|
|
|
|
|
2020-10-14 19:12:37 +00:00
|
|
|
if (!FLAG_harmony_import_assertions) {
|
2020-10-17 01:27:26 +00:00
|
|
|
return import_assertions;
|
2020-10-14 19:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Assert clause is optional, and cannot be preceded by a LineTerminator.
|
|
|
|
if (scanner()->HasLineTerminatorBeforeNext() ||
|
|
|
|
!CheckContextualKeyword(ast_value_factory()->assert_string())) {
|
2020-10-17 01:27:26 +00:00
|
|
|
return import_assertions;
|
2020-10-14 19:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expect(Token::LBRACE);
|
|
|
|
|
2020-10-17 01:27:26 +00:00
|
|
|
while (peek() != Token::RBRACE) {
|
|
|
|
const AstRawString* attribute_key = nullptr;
|
|
|
|
if (Check(Token::STRING)) {
|
|
|
|
attribute_key = GetSymbol();
|
|
|
|
} else {
|
|
|
|
attribute_key = ParsePropertyName();
|
|
|
|
}
|
|
|
|
|
|
|
|
Scanner::Location location = scanner()->location();
|
|
|
|
|
|
|
|
Expect(Token::COLON);
|
|
|
|
Expect(Token::STRING);
|
|
|
|
|
|
|
|
const AstRawString* attribute_value = GetSymbol();
|
|
|
|
|
|
|
|
// Set the location to the whole "key: 'value'"" string, so that it makes
|
|
|
|
// sense both for errors due to the key and errors due to the value.
|
|
|
|
location.end_pos = scanner()->location().end_pos;
|
|
|
|
|
|
|
|
auto result = import_assertions->insert(std::make_pair(
|
|
|
|
attribute_key, std::make_pair(attribute_value, location)));
|
|
|
|
if (!result.second) {
|
|
|
|
// It is a syntax error if two AssertEntries have the same key.
|
|
|
|
ReportMessageAt(location, MessageTemplate::kImportAssertionDuplicateKey,
|
|
|
|
attribute_key);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (peek() == Token::RBRACE) break;
|
|
|
|
if (V8_UNLIKELY(!Check(Token::COMMA))) {
|
|
|
|
ReportUnexpectedToken(Next());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-10-14 19:12:37 +00:00
|
|
|
|
|
|
|
Expect(Token::RBRACE);
|
2020-10-17 01:27:26 +00:00
|
|
|
|
|
|
|
return import_assertions;
|
2020-10-14 19:12:37 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
void Parser::ParseImportDeclaration() {
|
2015-01-30 03:26:50 +00:00
|
|
|
// ImportDeclaration :
|
|
|
|
// 'import' ImportClause 'from' ModuleSpecifier ';'
|
|
|
|
// 'import' ModuleSpecifier ';'
|
2020-10-14 19:12:37 +00:00
|
|
|
// 'import' ImportClause 'from' ModuleSpecifier [no LineTerminator here]
|
|
|
|
// AssertClause ';'
|
|
|
|
// 'import' ModuleSpecifier [no LineTerminator here] AssertClause';'
|
2012-02-29 12:12:52 +00:00
|
|
|
//
|
2015-01-30 03:26:50 +00:00
|
|
|
// ImportClause :
|
2016-07-18 07:27:10 +00:00
|
|
|
// ImportedDefaultBinding
|
2015-01-30 03:26:50 +00:00
|
|
|
// NameSpaceImport
|
|
|
|
// NamedImports
|
|
|
|
// ImportedDefaultBinding ',' NameSpaceImport
|
|
|
|
// ImportedDefaultBinding ',' NamedImports
|
|
|
|
//
|
|
|
|
// NameSpaceImport :
|
|
|
|
// '*' 'as' ImportedBinding
|
2012-02-29 12:12:52 +00:00
|
|
|
|
2013-10-14 09:24:58 +00:00
|
|
|
int pos = peek_position();
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::IMPORT);
|
2015-01-30 03:26:50 +00:00
|
|
|
|
|
|
|
Token::Value tok = peek();
|
|
|
|
|
|
|
|
// 'import' ModuleSpecifier ';'
|
|
|
|
if (tok == Token::STRING) {
|
2017-06-21 12:30:56 +00:00
|
|
|
Scanner::Location specifier_loc = scanner()->peek_location();
|
2018-10-25 07:14:19 +00:00
|
|
|
const AstRawString* module_specifier = ParseModuleSpecifier();
|
2020-10-17 01:27:26 +00:00
|
|
|
const ImportAssertions* import_assertions = ParseImportAssertClause();
|
2018-10-25 07:14:19 +00:00
|
|
|
ExpectSemicolon();
|
Plumb import assertions through SourceTextModuleDescriptor's ModuleRequestMap
This change plumbs import assertions from SourceTextModuleDescriptor's
ModuleRequestMap into SourceTextModuleInfo via a new ModuleRequest
type, where previously there had been only the specifier.
SourceTextModuleDescriptor::module_map now deduplicates module requests
using the specifier and the import assertions. Continuing to use the
specifier alone would cause a loss of information in the event that
a module imports from the same specifier multiple times using different
sets of assertions. Failing to deduplicate at all would result in
multiple requests for statements like `import {a,b,c} from "foo.js"`,
which would be a potential performance issue. See design doc at
https://docs.google.com/document/d/1yuXgNHSbTAPubT1Mg0JXp5uTrfirkvO1g5cHHCe-LmY
for more detail on this decision.
v8::internal::ModuleRequest holds the assertions as an array of the form
[key1, value1, position1, key2, value2, assertion2, ...]. However the
parser still needs to use a map, since duplicate assertion keys need to
be detected at parse time. A follow-up change will ensure that
assertions are sorted using a proper lexicographic sort.
Bug: v8:10958
Change-Id: Iff13fb9a37d58fc1622cd3cce78925ad2b7a14bb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2493060
Commit-Queue: Dan Clark <daniec@microsoft.com>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71066}
2020-11-09 22:59:00 +00:00
|
|
|
module()->AddEmptyImport(module_specifier, import_assertions, specifier_loc,
|
|
|
|
zone());
|
2016-07-19 19:45:50 +00:00
|
|
|
return;
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse ImportedDefaultBinding if present.
|
2016-07-18 07:27:10 +00:00
|
|
|
const AstRawString* import_default_binding = nullptr;
|
|
|
|
Scanner::Location import_default_binding_loc;
|
2015-01-30 03:26:50 +00:00
|
|
|
if (tok != Token::MUL && tok != Token::LBRACE) {
|
2018-12-03 10:23:04 +00:00
|
|
|
import_default_binding = ParseNonRestrictedIdentifier();
|
2016-07-18 07:27:10 +00:00
|
|
|
import_default_binding_loc = scanner()->location();
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareUnboundVariable(import_default_binding, VariableMode::kConst,
|
|
|
|
kNeedsInitialization, pos);
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
|
|
|
|
2016-07-18 07:27:10 +00:00
|
|
|
// Parse NameSpaceImport or NamedImports if present.
|
|
|
|
const AstRawString* module_namespace_binding = nullptr;
|
|
|
|
Scanner::Location module_namespace_binding_loc;
|
2018-07-03 14:44:16 +00:00
|
|
|
const ZonePtrList<const NamedImport>* named_imports = nullptr;
|
2016-07-18 07:27:10 +00:00
|
|
|
if (import_default_binding == nullptr || Check(Token::COMMA)) {
|
2015-01-30 03:26:50 +00:00
|
|
|
switch (peek()) {
|
|
|
|
case Token::MUL: {
|
|
|
|
Consume(Token::MUL);
|
2018-11-13 13:50:45 +00:00
|
|
|
ExpectContextualKeyword(ast_value_factory()->as_string());
|
2018-12-03 10:23:04 +00:00
|
|
|
module_namespace_binding = ParseNonRestrictedIdentifier();
|
2016-07-18 07:27:10 +00:00
|
|
|
module_namespace_binding_loc = scanner()->location();
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareUnboundVariable(module_namespace_binding, VariableMode::kConst,
|
|
|
|
kCreatedInitialized, pos);
|
2015-01-30 03:26:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-02-29 12:12:52 +00:00
|
|
|
|
2015-01-30 03:26:50 +00:00
|
|
|
case Token::LBRACE:
|
2018-10-25 07:14:19 +00:00
|
|
|
named_imports = ParseNamedImports(pos);
|
2015-01-30 03:26:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ReportUnexpectedToken(scanner()->current_token());
|
2016-07-19 19:45:50 +00:00
|
|
|
return;
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
2012-02-29 12:12:52 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 13:50:45 +00:00
|
|
|
ExpectContextualKeyword(ast_value_factory()->from_string());
|
2017-06-21 12:30:56 +00:00
|
|
|
Scanner::Location specifier_loc = scanner()->peek_location();
|
2018-10-25 07:14:19 +00:00
|
|
|
const AstRawString* module_specifier = ParseModuleSpecifier();
|
2020-10-17 01:27:26 +00:00
|
|
|
const ImportAssertions* import_assertions = ParseImportAssertClause();
|
2018-10-25 07:14:19 +00:00
|
|
|
ExpectSemicolon();
|
2015-04-09 22:09:44 +00:00
|
|
|
|
2016-07-18 07:27:10 +00:00
|
|
|
// Now that we have all the information, we can make the appropriate
|
|
|
|
// declarations.
|
|
|
|
|
2016-08-09 08:48:34 +00:00
|
|
|
// TODO(neis): Would prefer to call DeclareVariable for each case below rather
|
|
|
|
// than above and in ParseNamedImports, but then a possible error message
|
|
|
|
// would point to the wrong location. Maybe have a DeclareAt version of
|
|
|
|
// Declare that takes a location?
|
2016-07-18 07:27:10 +00:00
|
|
|
|
2016-08-08 09:46:51 +00:00
|
|
|
if (module_namespace_binding != nullptr) {
|
|
|
|
module()->AddStarImport(module_namespace_binding, module_specifier,
|
2020-10-17 01:27:26 +00:00
|
|
|
import_assertions, module_namespace_binding_loc,
|
|
|
|
specifier_loc, zone());
|
2016-08-08 09:46:51 +00:00
|
|
|
}
|
|
|
|
|
2016-07-18 07:27:10 +00:00
|
|
|
if (import_default_binding != nullptr) {
|
2016-07-19 10:06:38 +00:00
|
|
|
module()->AddImport(ast_value_factory()->default_string(),
|
|
|
|
import_default_binding, module_specifier,
|
2020-10-17 01:27:26 +00:00
|
|
|
import_assertions, import_default_binding_loc,
|
|
|
|
specifier_loc, zone());
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
2015-01-27 21:06:36 +00:00
|
|
|
|
2016-07-18 07:27:10 +00:00
|
|
|
if (named_imports != nullptr) {
|
|
|
|
if (named_imports->length() == 0) {
|
2020-10-17 01:27:26 +00:00
|
|
|
module()->AddEmptyImport(module_specifier, import_assertions,
|
Plumb import assertions through SourceTextModuleDescriptor's ModuleRequestMap
This change plumbs import assertions from SourceTextModuleDescriptor's
ModuleRequestMap into SourceTextModuleInfo via a new ModuleRequest
type, where previously there had been only the specifier.
SourceTextModuleDescriptor::module_map now deduplicates module requests
using the specifier and the import assertions. Continuing to use the
specifier alone would cause a loss of information in the event that
a module imports from the same specifier multiple times using different
sets of assertions. Failing to deduplicate at all would result in
multiple requests for statements like `import {a,b,c} from "foo.js"`,
which would be a potential performance issue. See design doc at
https://docs.google.com/document/d/1yuXgNHSbTAPubT1Mg0JXp5uTrfirkvO1g5cHHCe-LmY
for more detail on this decision.
v8::internal::ModuleRequest holds the assertions as an array of the form
[key1, value1, position1, key2, value2, assertion2, ...]. However the
parser still needs to use a map, since duplicate assertion keys need to
be detected at parse time. A follow-up change will ensure that
assertions are sorted using a proper lexicographic sort.
Bug: v8:10958
Change-Id: Iff13fb9a37d58fc1622cd3cce78925ad2b7a14bb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2493060
Commit-Queue: Dan Clark <daniec@microsoft.com>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71066}
2020-11-09 22:59:00 +00:00
|
|
|
specifier_loc, zone());
|
2016-07-18 07:27:10 +00:00
|
|
|
} else {
|
2019-03-29 10:00:57 +00:00
|
|
|
for (const NamedImport* import : *named_imports) {
|
2016-07-19 10:06:38 +00:00
|
|
|
module()->AddImport(import->import_name, import->local_name,
|
2020-10-17 01:27:26 +00:00
|
|
|
module_specifier, import_assertions,
|
|
|
|
import->location, specifier_loc, zone());
|
2016-07-18 07:27:10 +00:00
|
|
|
}
|
2015-02-26 18:40:50 +00:00
|
|
|
}
|
2012-02-29 12:12:52 +00:00
|
|
|
}
|
2012-02-20 14:02:59 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Statement* Parser::ParseExportDefault() {
|
2015-01-28 19:18:37 +00:00
|
|
|
// Supports the following productions, starting after the 'default' token:
|
2016-07-18 07:27:10 +00:00
|
|
|
// 'export' 'default' HoistableDeclaration
|
2015-01-28 19:18:37 +00:00
|
|
|
// 'export' 'default' ClassDeclaration
|
|
|
|
// 'export' 'default' AssignmentExpression[In] ';'
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::DEFAULT);
|
2015-02-19 20:14:55 +00:00
|
|
|
Scanner::Location default_loc = scanner()->location();
|
|
|
|
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString> local_names(1, zone());
|
2016-01-15 20:38:16 +00:00
|
|
|
Statement* result = nullptr;
|
2015-01-28 19:18:37 +00:00
|
|
|
switch (peek()) {
|
2016-07-01 09:20:23 +00:00
|
|
|
case Token::FUNCTION:
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseHoistableDeclaration(&local_names, true);
|
2015-01-28 19:18:37 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Token::CLASS:
|
2016-01-15 20:38:16 +00:00
|
|
|
Consume(Token::CLASS);
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseClassDeclaration(&local_names, true);
|
2015-01-28 19:18:37 +00:00
|
|
|
break;
|
|
|
|
|
2016-05-16 23:17:13 +00:00
|
|
|
case Token::ASYNC:
|
2017-01-10 23:27:02 +00:00
|
|
|
if (PeekAhead() == Token::FUNCTION &&
|
2018-08-24 11:38:13 +00:00
|
|
|
!scanner()->HasLineTerminatorAfterNext()) {
|
2016-05-16 23:17:13 +00:00
|
|
|
Consume(Token::ASYNC);
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseAsyncFunctionDeclaration(&local_names, true);
|
2016-05-16 23:17:13 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-02-15 19:38:09 +00:00
|
|
|
V8_FALLTHROUGH;
|
2016-05-16 23:17:13 +00:00
|
|
|
|
2015-01-28 19:18:37 +00:00
|
|
|
default: {
|
2016-07-18 07:27:10 +00:00
|
|
|
int pos = position();
|
2018-11-09 15:19:17 +00:00
|
|
|
AcceptINScope scope(this, true);
|
|
|
|
Expression* value = ParseAssignmentExpression();
|
2016-07-18 07:27:10 +00:00
|
|
|
SetFunctionName(value, ast_value_factory()->default_string());
|
|
|
|
|
|
|
|
const AstRawString* local_name =
|
2019-03-04 14:12:53 +00:00
|
|
|
ast_value_factory()->dot_default_string();
|
2016-07-18 07:27:10 +00:00
|
|
|
local_names.Add(local_name, zone());
|
|
|
|
|
2018-05-28 15:44:58 +00:00
|
|
|
// It's fine to declare this as VariableMode::kConst because the user has
|
|
|
|
// no way of writing to it.
|
2018-12-21 10:21:01 +00:00
|
|
|
VariableProxy* proxy =
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareBoundVariable(local_name, VariableMode::kConst, pos);
|
2018-12-21 10:21:01 +00:00
|
|
|
proxy->var()->set_initializer_position(position());
|
2016-07-18 07:27:10 +00:00
|
|
|
|
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2018-12-21 10:21:01 +00:00
|
|
|
Token::INIT, proxy, value, kNoSourcePosition);
|
2017-02-27 16:22:25 +00:00
|
|
|
result = IgnoreCompletion(
|
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition));
|
2015-04-22 12:35:05 +00:00
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
ExpectSemicolon();
|
2015-01-28 19:18:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 17:00:35 +00:00
|
|
|
if (result != nullptr) {
|
|
|
|
DCHECK_EQ(local_names.length(), 1);
|
|
|
|
module()->AddExport(local_names.first(),
|
|
|
|
ast_value_factory()->default_string(), default_loc,
|
|
|
|
zone());
|
|
|
|
}
|
2015-01-28 19:18:37 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-10-10 09:35:07 +00:00
|
|
|
const AstRawString* Parser::NextInternalNamespaceExportName() {
|
|
|
|
const char* prefix = ".ns-export";
|
|
|
|
std::string s(prefix);
|
|
|
|
s.append(std::to_string(number_of_named_namespace_exports_++));
|
|
|
|
return ast_value_factory()->GetOneByteString(s.c_str());
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
void Parser::ParseExportStar() {
|
2018-10-10 09:35:07 +00:00
|
|
|
int pos = position();
|
|
|
|
Consume(Token::MUL);
|
|
|
|
|
2020-10-30 17:16:38 +00:00
|
|
|
if (!PeekContextualKeyword(ast_value_factory()->as_string())) {
|
2018-10-10 09:35:07 +00:00
|
|
|
// 'export' '*' 'from' ModuleSpecifier ';'
|
|
|
|
Scanner::Location loc = scanner()->location();
|
2018-11-13 13:50:45 +00:00
|
|
|
ExpectContextualKeyword(ast_value_factory()->from_string());
|
2018-10-10 09:35:07 +00:00
|
|
|
Scanner::Location specifier_loc = scanner()->peek_location();
|
2018-10-25 07:14:19 +00:00
|
|
|
const AstRawString* module_specifier = ParseModuleSpecifier();
|
2020-10-17 01:27:26 +00:00
|
|
|
const ImportAssertions* import_assertions = ParseImportAssertClause();
|
2018-10-25 07:14:19 +00:00
|
|
|
ExpectSemicolon();
|
2020-10-17 01:27:26 +00:00
|
|
|
module()->AddStarExport(module_specifier, import_assertions, loc,
|
|
|
|
specifier_loc, zone());
|
2018-10-10 09:35:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
|
|
|
|
//
|
|
|
|
// Desugaring:
|
|
|
|
// export * as x from "...";
|
|
|
|
// ~>
|
|
|
|
// import * as .x from "..."; export {.x as x};
|
2020-10-21 20:43:40 +00:00
|
|
|
//
|
|
|
|
// Note that the desugared internal namespace export name (.x above) will
|
|
|
|
// never conflict with a string literal export name, as literal string export
|
|
|
|
// names in local name positions (i.e. left of 'as' or in a clause without
|
|
|
|
// 'as') are disallowed without a following 'from' clause.
|
2018-10-10 09:35:07 +00:00
|
|
|
|
2018-11-13 13:50:45 +00:00
|
|
|
ExpectContextualKeyword(ast_value_factory()->as_string());
|
2020-10-21 20:43:40 +00:00
|
|
|
const AstRawString* export_name = ParseExportSpecifierName();
|
2018-10-10 09:35:07 +00:00
|
|
|
Scanner::Location export_name_loc = scanner()->location();
|
|
|
|
const AstRawString* local_name = NextInternalNamespaceExportName();
|
|
|
|
Scanner::Location local_name_loc = Scanner::Location::invalid();
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareUnboundVariable(local_name, VariableMode::kConst, kCreatedInitialized,
|
|
|
|
pos);
|
2018-10-10 09:35:07 +00:00
|
|
|
|
2018-11-13 13:50:45 +00:00
|
|
|
ExpectContextualKeyword(ast_value_factory()->from_string());
|
2018-10-10 09:35:07 +00:00
|
|
|
Scanner::Location specifier_loc = scanner()->peek_location();
|
2018-10-25 07:14:19 +00:00
|
|
|
const AstRawString* module_specifier = ParseModuleSpecifier();
|
2020-10-17 01:27:26 +00:00
|
|
|
const ImportAssertions* import_assertions = ParseImportAssertClause();
|
2018-10-25 07:14:19 +00:00
|
|
|
ExpectSemicolon();
|
2018-10-10 09:35:07 +00:00
|
|
|
|
2020-10-17 01:27:26 +00:00
|
|
|
module()->AddStarImport(local_name, module_specifier, import_assertions,
|
|
|
|
local_name_loc, specifier_loc, zone());
|
2018-10-10 09:35:07 +00:00
|
|
|
module()->AddExport(local_name, export_name, export_name_loc, zone());
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Statement* Parser::ParseExportDeclaration() {
|
2012-02-29 12:12:52 +00:00
|
|
|
// ExportDeclaration:
|
2015-01-28 19:18:37 +00:00
|
|
|
// 'export' '*' 'from' ModuleSpecifier ';'
|
2020-10-14 19:12:37 +00:00
|
|
|
// 'export' '*' 'from' ModuleSpecifier [no LineTerminator here]
|
|
|
|
// AssertClause ';'
|
2018-10-10 09:35:07 +00:00
|
|
|
// 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
|
2020-10-14 19:12:37 +00:00
|
|
|
// 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier
|
|
|
|
// [no LineTerminator here] AssertClause ';'
|
2020-10-21 20:43:40 +00:00
|
|
|
// 'export' '*' 'as' ModuleExportName 'from' ModuleSpecifier ';'
|
|
|
|
// 'export' '*' 'as' ModuleExportName 'from' ModuleSpecifier ';'
|
|
|
|
// [no LineTerminator here] AssertClause ';'
|
2015-01-28 19:18:37 +00:00
|
|
|
// 'export' ExportClause ('from' ModuleSpecifier)? ';'
|
2020-10-14 19:12:37 +00:00
|
|
|
// 'export' ExportClause ('from' ModuleSpecifier [no LineTerminator here]
|
|
|
|
// AssertClause)? ';'
|
2015-01-28 19:18:37 +00:00
|
|
|
// 'export' VariableStatement
|
|
|
|
// 'export' Declaration
|
|
|
|
// 'export' 'default' ... (handled in ParseExportDefault)
|
2020-10-21 20:43:40 +00:00
|
|
|
//
|
|
|
|
// ModuleExportName :
|
|
|
|
// StringLiteral
|
2012-02-29 12:12:52 +00:00
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::EXPORT);
|
2016-07-18 07:27:10 +00:00
|
|
|
Statement* result = nullptr;
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString> names(1, zone());
|
2016-10-26 15:09:47 +00:00
|
|
|
Scanner::Location loc = scanner()->peek_location();
|
2012-02-29 12:12:52 +00:00
|
|
|
switch (peek()) {
|
2015-01-28 19:18:37 +00:00
|
|
|
case Token::DEFAULT:
|
2018-10-25 07:14:19 +00:00
|
|
|
return ParseExportDefault();
|
2015-01-28 19:18:37 +00:00
|
|
|
|
2018-10-10 09:35:07 +00:00
|
|
|
case Token::MUL:
|
2018-10-25 07:14:19 +00:00
|
|
|
ParseExportStar();
|
2018-10-30 14:41:34 +00:00
|
|
|
return factory()->EmptyStatement();
|
2012-02-29 12:12:52 +00:00
|
|
|
|
2015-01-30 03:26:50 +00:00
|
|
|
case Token::LBRACE: {
|
|
|
|
// There are two cases here:
|
|
|
|
//
|
|
|
|
// 'export' ExportClause ';'
|
|
|
|
// and
|
|
|
|
// 'export' ExportClause FromClause ';'
|
|
|
|
//
|
|
|
|
// In the first case, the exported identifiers in ExportClause must
|
|
|
|
// not be reserved words, while in the latter they may be. We
|
|
|
|
// pass in a location that gets filled with the first reserved word
|
|
|
|
// encountered, and then throw a SyntaxError if we are in the
|
|
|
|
// non-FromClause case.
|
|
|
|
Scanner::Location reserved_loc = Scanner::Location::invalid();
|
2020-10-21 20:43:40 +00:00
|
|
|
Scanner::Location string_literal_local_name_loc =
|
|
|
|
Scanner::Location::invalid();
|
2018-07-23 14:20:41 +00:00
|
|
|
ZoneChunkList<ExportClauseData>* export_data =
|
2020-10-21 20:43:40 +00:00
|
|
|
ParseExportClause(&reserved_loc, &string_literal_local_name_loc);
|
2018-11-13 13:50:45 +00:00
|
|
|
if (CheckContextualKeyword(ast_value_factory()->from_string())) {
|
2020-10-14 19:12:37 +00:00
|
|
|
Scanner::Location specifier_loc = scanner()->peek_location();
|
|
|
|
const AstRawString* module_specifier = ParseModuleSpecifier();
|
2020-10-17 01:27:26 +00:00
|
|
|
const ImportAssertions* import_assertions = ParseImportAssertClause();
|
2020-10-14 19:12:37 +00:00
|
|
|
ExpectSemicolon();
|
|
|
|
|
|
|
|
if (export_data->is_empty()) {
|
2020-10-17 01:27:26 +00:00
|
|
|
module()->AddEmptyImport(module_specifier, import_assertions,
|
Plumb import assertions through SourceTextModuleDescriptor's ModuleRequestMap
This change plumbs import assertions from SourceTextModuleDescriptor's
ModuleRequestMap into SourceTextModuleInfo via a new ModuleRequest
type, where previously there had been only the specifier.
SourceTextModuleDescriptor::module_map now deduplicates module requests
using the specifier and the import assertions. Continuing to use the
specifier alone would cause a loss of information in the event that
a module imports from the same specifier multiple times using different
sets of assertions. Failing to deduplicate at all would result in
multiple requests for statements like `import {a,b,c} from "foo.js"`,
which would be a potential performance issue. See design doc at
https://docs.google.com/document/d/1yuXgNHSbTAPubT1Mg0JXp5uTrfirkvO1g5cHHCe-LmY
for more detail on this decision.
v8::internal::ModuleRequest holds the assertions as an array of the form
[key1, value1, position1, key2, value2, assertion2, ...]. However the
parser still needs to use a map, since duplicate assertion keys need to
be detected at parse time. A follow-up change will ensure that
assertions are sorted using a proper lexicographic sort.
Bug: v8:10958
Change-Id: Iff13fb9a37d58fc1622cd3cce78925ad2b7a14bb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2493060
Commit-Queue: Dan Clark <daniec@microsoft.com>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71066}
2020-11-09 22:59:00 +00:00
|
|
|
specifier_loc, zone());
|
2020-10-14 19:12:37 +00:00
|
|
|
} else {
|
|
|
|
for (const ExportClauseData& data : *export_data) {
|
|
|
|
module()->AddExport(data.local_name, data.export_name,
|
2020-10-17 01:27:26 +00:00
|
|
|
module_specifier, import_assertions,
|
|
|
|
data.location, specifier_loc, zone());
|
2020-10-14 19:12:37 +00:00
|
|
|
}
|
2015-02-19 20:14:55 +00:00
|
|
|
}
|
|
|
|
} else {
|
2020-10-14 19:12:37 +00:00
|
|
|
if (reserved_loc.IsValid()) {
|
|
|
|
// No FromClause, so reserved words are invalid in ExportClause.
|
|
|
|
ReportMessageAt(reserved_loc, MessageTemplate::kUnexpectedReserved);
|
|
|
|
return nullptr;
|
2020-10-21 20:43:40 +00:00
|
|
|
} else if (string_literal_local_name_loc.IsValid()) {
|
|
|
|
ReportMessageAt(string_literal_local_name_loc,
|
|
|
|
MessageTemplate::kModuleExportNameWithoutFromClause);
|
|
|
|
return nullptr;
|
2020-10-14 19:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExpectSemicolon();
|
|
|
|
|
2018-07-23 14:20:41 +00:00
|
|
|
for (const ExportClauseData& data : *export_data) {
|
2020-10-14 19:12:37 +00:00
|
|
|
module()->AddExport(data.local_name, data.export_name, data.location,
|
2018-07-23 14:20:41 +00:00
|
|
|
zone());
|
2015-02-19 20:14:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-30 14:41:34 +00:00
|
|
|
return factory()->EmptyStatement();
|
2015-01-30 03:26:50 +00:00
|
|
|
}
|
2015-01-28 19:18:37 +00:00
|
|
|
|
2012-02-29 12:12:52 +00:00
|
|
|
case Token::FUNCTION:
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseHoistableDeclaration(&names, false);
|
2012-02-29 12:12:52 +00:00
|
|
|
break;
|
|
|
|
|
2014-09-16 22:15:39 +00:00
|
|
|
case Token::CLASS:
|
2016-01-15 20:38:16 +00:00
|
|
|
Consume(Token::CLASS);
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseClassDeclaration(&names, false);
|
2014-09-16 22:15:39 +00:00
|
|
|
break;
|
|
|
|
|
2012-02-29 12:12:52 +00:00
|
|
|
case Token::VAR:
|
|
|
|
case Token::LET:
|
|
|
|
case Token::CONST:
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseVariableStatement(kStatementListItem, &names);
|
2012-02-29 12:12:52 +00:00
|
|
|
break;
|
|
|
|
|
2016-05-16 23:17:13 +00:00
|
|
|
case Token::ASYNC:
|
2017-01-10 23:27:02 +00:00
|
|
|
Consume(Token::ASYNC);
|
2018-10-18 14:04:14 +00:00
|
|
|
if (peek() == Token::FUNCTION &&
|
|
|
|
!scanner()->HasLineTerminatorBeforeNext()) {
|
2018-10-25 07:14:19 +00:00
|
|
|
result = ParseAsyncFunctionDeclaration(&names, false);
|
2018-10-18 14:04:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
V8_FALLTHROUGH;
|
2016-05-16 23:17:13 +00:00
|
|
|
|
2012-02-29 12:12:52 +00:00
|
|
|
default:
|
2014-02-14 12:13:33 +00:00
|
|
|
ReportUnexpectedToken(scanner()->current_token());
|
2016-07-18 07:27:10 +00:00
|
|
|
return nullptr;
|
2012-02-29 12:12:52 +00:00
|
|
|
}
|
2016-10-26 15:09:47 +00:00
|
|
|
loc.end_pos = scanner()->location().end_pos;
|
2012-02-29 12:12:52 +00:00
|
|
|
|
2019-06-19 17:07:58 +00:00
|
|
|
SourceTextModuleDescriptor* descriptor = module();
|
2019-03-29 10:00:57 +00:00
|
|
|
for (const AstRawString* name : names) {
|
|
|
|
descriptor->AddExport(name, name, loc, zone());
|
2012-02-29 12:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2012-02-20 14:02:59 +00:00
|
|
|
}
|
|
|
|
|
2019-01-24 17:00:48 +00:00
|
|
|
void Parser::DeclareUnboundVariable(const AstRawString* name, VariableMode mode,
|
|
|
|
InitializationFlag init, int pos) {
|
|
|
|
bool was_added;
|
|
|
|
Variable* var = DeclareVariable(name, NORMAL_VARIABLE, mode, init, scope(),
|
|
|
|
&was_added, pos, end_position());
|
|
|
|
// The variable will be added to the declarations list, but since we are not
|
|
|
|
// binding it to anything, we can simply ignore it here.
|
|
|
|
USE(var);
|
2016-08-09 08:48:34 +00:00
|
|
|
}
|
|
|
|
|
2019-01-24 17:00:48 +00:00
|
|
|
VariableProxy* Parser::DeclareBoundVariable(const AstRawString* name,
|
|
|
|
VariableMode mode, int pos) {
|
2016-08-08 10:23:34 +00:00
|
|
|
DCHECK_NOT_NULL(name);
|
2018-12-21 10:21:01 +00:00
|
|
|
VariableProxy* proxy =
|
|
|
|
factory()->NewVariableProxy(name, NORMAL_VARIABLE, position());
|
2019-01-21 12:30:41 +00:00
|
|
|
bool was_added;
|
2019-01-24 17:00:48 +00:00
|
|
|
Variable* var = DeclareVariable(name, NORMAL_VARIABLE, mode,
|
|
|
|
Variable::DefaultInitializationFlag(mode),
|
|
|
|
scope(), &was_added, pos, end_position());
|
|
|
|
proxy->BindTo(var);
|
2018-12-21 10:21:01 +00:00
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
2019-01-24 17:00:48 +00:00
|
|
|
void Parser::DeclareAndBindVariable(VariableProxy* proxy, VariableKind kind,
|
2019-07-26 11:09:31 +00:00
|
|
|
VariableMode mode, Scope* scope,
|
|
|
|
bool* was_added, int initializer_position) {
|
|
|
|
Variable* var = DeclareVariable(
|
|
|
|
proxy->raw_name(), kind, mode, Variable::DefaultInitializationFlag(mode),
|
|
|
|
scope, was_added, proxy->position(), kNoSourcePosition);
|
|
|
|
var->set_initializer_position(initializer_position);
|
2019-01-24 17:00:48 +00:00
|
|
|
proxy->BindTo(var);
|
|
|
|
}
|
|
|
|
|
|
|
|
Variable* Parser::DeclareVariable(const AstRawString* name, VariableKind kind,
|
|
|
|
VariableMode mode, InitializationFlag init,
|
|
|
|
Scope* scope, bool* was_added, int begin,
|
|
|
|
int end) {
|
2017-08-18 17:26:54 +00:00
|
|
|
Declaration* declaration;
|
2018-12-21 10:21:01 +00:00
|
|
|
if (mode == VariableMode::kVar && !scope->is_declaration_scope()) {
|
|
|
|
DCHECK(scope->is_block_scope() || scope->is_with_scope());
|
2019-01-15 15:04:30 +00:00
|
|
|
declaration = factory()->NewNestedVariableDeclaration(scope, begin);
|
2017-08-18 17:26:54 +00:00
|
|
|
} else {
|
2019-01-15 15:04:30 +00:00
|
|
|
declaration = factory()->NewVariableDeclaration(begin);
|
2017-08-18 17:26:54 +00:00
|
|
|
}
|
2019-01-24 17:00:48 +00:00
|
|
|
Declare(declaration, name, kind, mode, init, scope, was_added, begin, end);
|
|
|
|
return declaration->var();
|
2016-07-18 07:27:10 +00:00
|
|
|
}
|
|
|
|
|
2019-01-24 17:00:48 +00:00
|
|
|
void Parser::Declare(Declaration* declaration, const AstRawString* name,
|
2019-01-15 15:04:30 +00:00
|
|
|
VariableKind variable_kind, VariableMode mode,
|
2019-01-21 12:30:41 +00:00
|
|
|
InitializationFlag init, Scope* scope, bool* was_added,
|
2019-01-24 17:00:48 +00:00
|
|
|
int var_begin_pos, int var_end_pos) {
|
2018-10-25 07:14:19 +00:00
|
|
|
bool local_ok = true;
|
2016-08-29 12:36:30 +00:00
|
|
|
bool sloppy_mode_block_scope_function_redefinition = false;
|
2019-01-21 12:30:41 +00:00
|
|
|
scope->DeclareVariable(
|
2019-01-24 17:00:48 +00:00
|
|
|
declaration, name, var_begin_pos, mode, variable_kind, init, was_added,
|
2019-01-21 12:30:41 +00:00
|
|
|
&sloppy_mode_block_scope_function_redefinition, &local_ok);
|
2018-10-31 09:45:46 +00:00
|
|
|
if (!local_ok) {
|
2016-10-27 11:03:06 +00:00
|
|
|
// If we only have the start position of a proxy, we can't highlight the
|
|
|
|
// whole variable name. Pretend its length is 1 so that we highlight at
|
|
|
|
// least the first character.
|
2019-01-24 17:00:48 +00:00
|
|
|
Scanner::Location loc(var_begin_pos, var_end_pos != kNoSourcePosition
|
|
|
|
? var_end_pos
|
|
|
|
: var_begin_pos + 1);
|
2019-01-10 14:32:34 +00:00
|
|
|
if (variable_kind == PARAMETER_VARIABLE) {
|
2017-10-05 00:30:10 +00:00
|
|
|
ReportMessageAt(loc, MessageTemplate::kParamDupe);
|
|
|
|
} else {
|
2016-10-27 11:03:06 +00:00
|
|
|
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration,
|
2019-01-15 15:04:30 +00:00
|
|
|
declaration->var()->raw_name());
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2018-10-31 09:45:46 +00:00
|
|
|
} else if (sloppy_mode_block_scope_function_redefinition) {
|
2016-08-29 12:36:30 +00:00
|
|
|
++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 10:00:31 +00:00
|
|
|
Statement* Parser::BuildInitializationBlock(
|
2019-01-21 12:17:55 +00:00
|
|
|
DeclarationParsingResult* parsing_result) {
|
2019-01-11 10:00:31 +00:00
|
|
|
ScopedPtrList<Statement> statements(pointer_buffer());
|
2018-08-22 17:01:47 +00:00
|
|
|
for (const auto& declaration : parsing_result->declarations) {
|
2019-01-23 12:49:23 +00:00
|
|
|
if (!declaration.initializer) continue;
|
2019-01-21 09:47:58 +00:00
|
|
|
InitializeVariables(&statements, parsing_result->descriptor.kind,
|
2019-01-21 12:17:55 +00:00
|
|
|
&declaration);
|
2015-05-15 09:56:31 +00:00
|
|
|
}
|
2019-01-11 10:00:31 +00:00
|
|
|
return factory()->NewBlock(true, statements);
|
2015-05-15 09:56:31 +00:00
|
|
|
}
|
|
|
|
|
2016-09-09 07:57:59 +00:00
|
|
|
Statement* Parser::DeclareFunction(const AstRawString* variable_name,
|
2017-01-16 12:07:57 +00:00
|
|
|
FunctionLiteral* function, VariableMode mode,
|
2019-01-25 11:45:28 +00:00
|
|
|
VariableKind kind, int beg_pos, int end_pos,
|
2018-10-25 07:14:19 +00:00
|
|
|
ZonePtrList<const AstRawString>* names) {
|
2019-01-25 11:45:28 +00:00
|
|
|
Declaration* declaration =
|
|
|
|
factory()->NewFunctionDeclaration(function, beg_pos);
|
2019-01-21 12:30:41 +00:00
|
|
|
bool was_added;
|
2019-01-25 11:45:28 +00:00
|
|
|
Declare(declaration, variable_name, kind, mode, kCreatedInitialized, scope(),
|
|
|
|
&was_added, beg_pos);
|
2020-04-22 10:45:31 +00:00
|
|
|
if (info()->flags().coverage_enabled()) {
|
2019-02-05 15:26:03 +00:00
|
|
|
// Force the function to be allocated when collecting source coverage, so
|
|
|
|
// that even dead functions get source coverage data.
|
|
|
|
declaration->var()->set_is_used();
|
|
|
|
}
|
2016-09-09 07:57:59 +00:00
|
|
|
if (names) names->Add(variable_name, zone());
|
2019-01-25 11:45:28 +00:00
|
|
|
if (kind == SLOPPY_BLOCK_FUNCTION_VARIABLE) {
|
|
|
|
Token::Value init = loop_nesting_depth() > 0 ? Token::ASSIGN : Token::INIT;
|
2017-01-16 12:07:57 +00:00
|
|
|
SloppyBlockFunctionStatement* statement =
|
2019-01-25 11:45:28 +00:00
|
|
|
factory()->NewSloppyBlockFunctionStatement(end_pos, declaration->var(),
|
|
|
|
init);
|
|
|
|
GetDeclarationScope()->DeclareSloppyBlockFunction(statement);
|
2017-01-16 12:07:57 +00:00
|
|
|
return statement;
|
2016-09-09 07:57:59 +00:00
|
|
|
}
|
2018-10-30 14:41:34 +00:00
|
|
|
return factory()->EmptyStatement();
|
2016-09-09 07:57:59 +00:00
|
|
|
}
|
|
|
|
|
2016-09-28 13:42:20 +00:00
|
|
|
Statement* Parser::DeclareClass(const AstRawString* variable_name,
|
|
|
|
Expression* value,
|
2018-07-03 14:44:16 +00:00
|
|
|
ZonePtrList<const AstRawString>* names,
|
2018-10-25 07:14:19 +00:00
|
|
|
int class_token_pos, int end_pos) {
|
2018-12-21 10:21:01 +00:00
|
|
|
VariableProxy* proxy =
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareBoundVariable(variable_name, VariableMode::kLet, class_token_pos);
|
2018-12-21 10:21:01 +00:00
|
|
|
proxy->var()->set_initializer_position(end_pos);
|
2017-02-28 12:40:46 +00:00
|
|
|
if (names) names->Add(variable_name, zone());
|
|
|
|
|
2018-12-21 10:21:01 +00:00
|
|
|
Assignment* assignment =
|
|
|
|
factory()->NewAssignment(Token::INIT, proxy, value, class_token_pos);
|
2017-02-27 16:22:25 +00:00
|
|
|
return IgnoreCompletion(
|
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition));
|
2016-09-28 13:42:20 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
Statement* Parser::DeclareNative(const AstRawString* name, int pos) {
|
2016-09-28 13:42:20 +00:00
|
|
|
// Make sure that the function containing the native declaration
|
|
|
|
// isn't lazily compiled. The extension structures are only
|
|
|
|
// accessible while parsing the first time not when reparsing
|
|
|
|
// because of lazy compilation.
|
|
|
|
GetClosureScope()->ForceEagerCompilation();
|
|
|
|
|
|
|
|
// TODO(1240846): It's weird that native function declarations are
|
|
|
|
// introduced dynamically when we meet their declarations, whereas
|
|
|
|
// other functions are set up when entering the surrounding scope.
|
2019-01-24 17:00:48 +00:00
|
|
|
VariableProxy* proxy = DeclareBoundVariable(name, VariableMode::kVar, pos);
|
2016-09-28 13:42:20 +00:00
|
|
|
NativeFunctionLiteral* lit =
|
|
|
|
factory()->NewNativeFunctionLiteral(name, extension_, kNoSourcePosition);
|
|
|
|
return factory()->NewExpressionStatement(
|
2018-12-21 10:21:01 +00:00
|
|
|
factory()->NewAssignment(Token::INIT, proxy, lit, kNoSourcePosition),
|
2016-09-28 13:42:20 +00:00
|
|
|
pos);
|
|
|
|
}
|
|
|
|
|
2017-02-27 16:22:25 +00:00
|
|
|
Block* Parser::IgnoreCompletion(Statement* statement) {
|
2017-08-29 18:01:54 +00:00
|
|
|
Block* block = factory()->NewBlock(1, true);
|
2017-02-27 16:22:25 +00:00
|
|
|
block->statements()->Add(statement, zone());
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
2016-09-10 17:04:50 +00:00
|
|
|
Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
|
2017-01-03 19:37:23 +00:00
|
|
|
if (IsDerivedConstructor(function_state_->kind())) {
|
2017-03-31 06:01:01 +00:00
|
|
|
// For subclass constructors we need to return this in case of undefined;
|
|
|
|
// other primitive values trigger an exception in the ConstructStub.
|
2016-09-10 17:04:50 +00:00
|
|
|
//
|
|
|
|
// return expr;
|
|
|
|
//
|
|
|
|
// Is rewritten as:
|
|
|
|
//
|
2017-03-31 06:01:01 +00:00
|
|
|
// return (temp = expr) === undefined ? this : temp;
|
2016-09-10 17:04:50 +00:00
|
|
|
|
|
|
|
// temp = expr
|
|
|
|
Variable* temp = NewTemporary(ast_value_factory()->empty_string());
|
|
|
|
Assignment* assign = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
|
|
|
|
|
|
|
|
// temp === undefined
|
|
|
|
Expression* is_undefined = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT, assign,
|
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
|
|
|
|
|
2017-03-31 06:01:01 +00:00
|
|
|
// is_undefined ? this : temp
|
2019-02-06 10:52:07 +00:00
|
|
|
// We don't need to call UseThis() since it's guaranteed to be called
|
|
|
|
// for derived constructors after parsing the constructor in
|
|
|
|
// ParseFunctionBody.
|
2017-03-31 06:01:01 +00:00
|
|
|
return_value =
|
2019-02-06 10:52:07 +00:00
|
|
|
factory()->NewConditional(is_undefined, factory()->ThisExpression(),
|
2017-03-31 06:01:01 +00:00
|
|
|
factory()->NewVariableProxy(temp), pos);
|
2016-09-10 17:04:50 +00:00
|
|
|
}
|
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
|
2017-08-30 21:59:48 +00:00
|
|
|
Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement,
|
2017-07-12 13:06:09 +00:00
|
|
|
Scope* scope) {
|
2015-08-24 18:57:08 +00:00
|
|
|
// In order to get the CaseClauses to execute in their own lexical scope,
|
|
|
|
// but without requiring downstream code to have special scope handling
|
|
|
|
// code for switch statements, desugar into blocks as follows:
|
|
|
|
// { // To group the statements--harmless to evaluate Expression in scope
|
|
|
|
// .tag_variable = Expression;
|
|
|
|
// { // To give CaseClauses a scope
|
|
|
|
// switch (.tag_variable) { CaseClause* }
|
|
|
|
// }
|
|
|
|
// }
|
2017-08-30 21:59:48 +00:00
|
|
|
DCHECK_NOT_NULL(scope);
|
|
|
|
DCHECK(scope->is_block_scope());
|
|
|
|
DCHECK_GE(switch_statement->position(), scope->start_position());
|
|
|
|
DCHECK_LT(switch_statement->position(), scope->end_position());
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
Block* switch_block = factory()->NewBlock(2, false);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2017-08-30 21:59:48 +00:00
|
|
|
Expression* tag = switch_statement->tag();
|
2015-08-24 18:57:08 +00:00
|
|
|
Variable* tag_variable =
|
2016-08-09 19:49:25 +00:00
|
|
|
NewTemporary(ast_value_factory()->dot_switch_tag_string());
|
2015-08-24 18:57:08 +00:00
|
|
|
Assignment* tag_assign = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(tag_variable), tag,
|
|
|
|
tag->position());
|
2017-08-30 21:59:48 +00:00
|
|
|
// Wrap with IgnoreCompletion so the tag isn't returned as the completion
|
|
|
|
// value, in case the switch statements don't have a value.
|
|
|
|
Statement* tag_statement = IgnoreCompletion(
|
|
|
|
factory()->NewExpressionStatement(tag_assign, kNoSourcePosition));
|
2015-10-01 13:59:36 +00:00
|
|
|
switch_block->statements()->Add(tag_statement, zone());
|
2015-08-24 18:57:08 +00:00
|
|
|
|
2017-08-30 21:59:48 +00:00
|
|
|
switch_statement->set_tag(factory()->NewVariableProxy(tag_variable));
|
2017-08-29 18:01:54 +00:00
|
|
|
Block* cases_block = factory()->NewBlock(1, false);
|
2016-09-12 09:39:34 +00:00
|
|
|
cases_block->statements()->Add(switch_statement, zone());
|
|
|
|
cases_block->set_scope(scope);
|
2015-10-01 13:59:36 +00:00
|
|
|
switch_block->statements()->Add(cases_block, zone());
|
2015-08-24 18:57:08 +00:00
|
|
|
return switch_block;
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2019-01-23 12:49:23 +00:00
|
|
|
void Parser::InitializeVariables(
|
|
|
|
ScopedPtrList<Statement>* statements, VariableKind kind,
|
|
|
|
const DeclarationParsingResult::Declaration* declaration) {
|
|
|
|
if (has_error()) return;
|
|
|
|
|
|
|
|
DCHECK_NOT_NULL(declaration->initializer);
|
|
|
|
|
|
|
|
int pos = declaration->value_beg_pos;
|
|
|
|
if (pos == kNoSourcePosition) {
|
|
|
|
pos = declaration->initializer->position();
|
|
|
|
}
|
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
|
|
|
Token::INIT, declaration->pattern, declaration->initializer, pos);
|
|
|
|
statements->Add(factory()->NewExpressionStatement(assignment, pos));
|
|
|
|
}
|
|
|
|
|
2018-12-19 09:10:42 +00:00
|
|
|
Block* Parser::RewriteCatchPattern(CatchInfo* catch_info) {
|
|
|
|
DCHECK_NOT_NULL(catch_info->pattern);
|
|
|
|
|
|
|
|
DeclarationParsingResult::Declaration decl(
|
2019-01-23 12:49:23 +00:00
|
|
|
catch_info->pattern, factory()->NewVariableProxy(catch_info->variable));
|
2018-12-19 09:10:42 +00:00
|
|
|
|
2019-01-11 10:00:31 +00:00
|
|
|
ScopedPtrList<Statement> init_statements(pointer_buffer());
|
2019-01-21 12:17:55 +00:00
|
|
|
InitializeVariables(&init_statements, NORMAL_VARIABLE, &decl);
|
2019-01-11 10:00:31 +00:00
|
|
|
return factory()->NewBlock(true, init_statements);
|
2016-09-16 09:12:14 +00:00
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2018-12-19 13:43:06 +00:00
|
|
|
void Parser::ReportVarRedeclarationIn(const AstRawString* name, Scope* scope) {
|
2018-12-19 09:10:42 +00:00
|
|
|
for (Declaration* decl : *scope->declarations()) {
|
2019-01-15 15:04:30 +00:00
|
|
|
if (decl->var()->raw_name() == name) {
|
|
|
|
int position = decl->position();
|
2016-09-16 09:12:14 +00:00
|
|
|
Scanner::Location location =
|
|
|
|
position == kNoSourcePosition
|
|
|
|
? Scanner::Location::invalid()
|
2018-12-19 09:10:42 +00:00
|
|
|
: Scanner::Location(position, position + name->length());
|
2016-09-16 09:12:14 +00:00
|
|
|
ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
|
2018-12-19 09:10:42 +00:00
|
|
|
return;
|
2015-11-05 20:21:20 +00:00
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2018-12-19 09:10:42 +00:00
|
|
|
UNREACHABLE();
|
2016-09-16 09:12:14 +00:00
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2016-09-16 09:12:14 +00:00
|
|
|
Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
|
2017-07-07 12:04:58 +00:00
|
|
|
const SourceRange& catch_range,
|
2016-09-16 09:12:14 +00:00
|
|
|
Block* finally_block,
|
2017-07-07 12:04:58 +00:00
|
|
|
const SourceRange& finally_range,
|
2016-09-16 09:12:14 +00:00
|
|
|
const CatchInfo& catch_info, int pos) {
|
2008-07-03 15:10:15 +00:00
|
|
|
// Simplify the AST nodes by converting:
|
2011-06-08 13:55:33 +00:00
|
|
|
// 'try B0 catch B1 finally B2'
|
2008-07-03 15:10:15 +00:00
|
|
|
// to:
|
2011-06-08 13:55:33 +00:00
|
|
|
// 'try { try B0 catch B1 } finally B2'
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2016-09-16 09:12:14 +00:00
|
|
|
if (catch_block != nullptr && finally_block != nullptr) {
|
2011-06-30 14:37:55 +00:00
|
|
|
// If we have both, create an inner try/catch.
|
2016-07-22 06:04:07 +00:00
|
|
|
TryCatchStatement* statement;
|
2016-12-14 21:03:47 +00:00
|
|
|
statement = factory()->NewTryCatchStatement(try_block, catch_info.scope,
|
2017-07-12 13:06:09 +00:00
|
|
|
catch_block, kNoSourcePosition);
|
|
|
|
RecordTryCatchStatementSourceRange(statement, catch_range);
|
2016-07-22 06:04:07 +00:00
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
try_block = factory()->NewBlock(1, false);
|
2015-10-01 13:59:36 +00:00
|
|
|
try_block->statements()->Add(statement, zone());
|
2016-09-16 09:12:14 +00:00
|
|
|
catch_block = nullptr; // Clear to indicate it's been handled.
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2016-09-16 09:12:14 +00:00
|
|
|
if (catch_block != nullptr) {
|
|
|
|
DCHECK_NULL(finally_block);
|
2017-07-12 13:06:09 +00:00
|
|
|
TryCatchStatement* stmt = factory()->NewTryCatchStatement(
|
|
|
|
try_block, catch_info.scope, catch_block, pos);
|
|
|
|
RecordTryCatchStatementSourceRange(stmt, catch_range);
|
|
|
|
return stmt;
|
2010-11-02 11:45:47 +00:00
|
|
|
} else {
|
2016-09-16 09:12:14 +00:00
|
|
|
DCHECK_NOT_NULL(finally_block);
|
2017-07-12 13:06:09 +00:00
|
|
|
TryFinallyStatement* stmt =
|
|
|
|
factory()->NewTryFinallyStatement(try_block, finally_block, pos);
|
|
|
|
RecordTryFinallyStatementSourceRange(stmt, finally_range);
|
|
|
|
return stmt;
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
void Parser::ParseAndRewriteGeneratorFunctionBody(
|
2018-11-05 15:20:49 +00:00
|
|
|
int pos, FunctionKind kind, ScopedPtrList<Statement>* body) {
|
2017-06-05 19:54:14 +00:00
|
|
|
// For ES6 Generators, we just prepend the initial yield.
|
|
|
|
Expression* initial_yield = BuildInitialYield(pos, kind);
|
2018-11-05 15:20:49 +00:00
|
|
|
body->Add(
|
|
|
|
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
|
2018-11-07 17:00:35 +00:00
|
|
|
ParseStatementList(body, Token::RBRACE);
|
2017-06-05 19:54:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::ParseAndRewriteAsyncGeneratorFunctionBody(
|
2018-11-05 15:20:49 +00:00
|
|
|
int pos, FunctionKind kind, ScopedPtrList<Statement>* body) {
|
2017-03-22 04:34:36 +00:00
|
|
|
// For ES2017 Async Generators, we produce:
|
|
|
|
//
|
|
|
|
// try {
|
|
|
|
// InitialYield;
|
|
|
|
// ...body...;
|
2019-05-15 19:41:48 +00:00
|
|
|
// // fall through to the implicit return after the try-finally
|
2017-03-22 04:34:36 +00:00
|
|
|
// } catch (.catch) {
|
|
|
|
// %AsyncGeneratorReject(generator, .catch);
|
|
|
|
// } finally {
|
|
|
|
// %_GeneratorClose(generator);
|
|
|
|
// }
|
|
|
|
//
|
2017-01-20 08:58:54 +00:00
|
|
|
// - InitialYield yields the actual generator object.
|
|
|
|
// - Any return statement inside the body will have its argument wrapped
|
2017-03-22 04:34:36 +00:00
|
|
|
// in an iterator result object with a "done" property set to `true`.
|
2017-01-20 08:58:54 +00:00
|
|
|
// - If the generator terminates for whatever reason, we must close it.
|
|
|
|
// Hence the finally clause.
|
2017-03-22 04:34:36 +00:00
|
|
|
// - BytecodeGenerator performs special handling for ReturnStatements in
|
|
|
|
// async generator functions, resolving the appropriate Promise with an
|
|
|
|
// "done" iterator result object containing a Promise-unwrapped value.
|
2017-06-05 19:54:14 +00:00
|
|
|
DCHECK(IsAsyncGeneratorFunction(kind));
|
2017-01-20 08:58:54 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
Block* try_block;
|
|
|
|
{
|
|
|
|
ScopedPtrList<Statement> statements(pointer_buffer());
|
|
|
|
Expression* initial_yield = BuildInitialYield(pos, kind);
|
|
|
|
statements.Add(
|
|
|
|
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
|
2018-11-07 17:00:35 +00:00
|
|
|
ParseStatementList(&statements, Token::RBRACE);
|
2020-02-20 22:12:12 +00:00
|
|
|
// Since the whole body is wrapped in a try-catch, make the implicit
|
|
|
|
// end-of-function return explicit to ensure BytecodeGenerator's special
|
|
|
|
// handling for ReturnStatements in async generators applies.
|
|
|
|
statements.Add(factory()->NewSyntheticAsyncReturnStatement(
|
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition));
|
2017-01-20 08:58:54 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
// Don't create iterator result for async generators, as the resume methods
|
|
|
|
// will create it.
|
|
|
|
try_block = factory()->NewBlock(false, statements);
|
|
|
|
}
|
2017-03-22 04:34:36 +00:00
|
|
|
|
2017-06-05 19:54:14 +00:00
|
|
|
// For AsyncGenerators, a top-level catch block will reject the Promise.
|
2017-09-07 12:05:46 +00:00
|
|
|
Scope* catch_scope = NewHiddenCatchScope();
|
2017-03-22 04:34:36 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
Block* catch_block;
|
|
|
|
{
|
|
|
|
ScopedPtrList<Expression> reject_args(pointer_buffer());
|
|
|
|
reject_args.Add(factory()->NewVariableProxy(
|
|
|
|
function_state_->scope()->generator_object_var()));
|
|
|
|
reject_args.Add(factory()->NewVariableProxy(catch_scope->catch_variable()));
|
2017-03-22 04:34:36 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
Expression* reject_call = factory()->NewCallRuntime(
|
|
|
|
Runtime::kInlineAsyncGeneratorReject, reject_args, kNoSourcePosition);
|
|
|
|
catch_block = IgnoreCompletion(
|
|
|
|
factory()->NewReturnStatement(reject_call, kNoSourcePosition));
|
|
|
|
}
|
2017-03-22 04:34:36 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
{
|
|
|
|
ScopedPtrList<Statement> statements(pointer_buffer());
|
|
|
|
TryStatement* try_catch = factory()->NewTryCatchStatementForAsyncAwait(
|
|
|
|
try_block, catch_scope, catch_block, kNoSourcePosition);
|
|
|
|
statements.Add(try_catch);
|
|
|
|
try_block = factory()->NewBlock(false, statements);
|
|
|
|
}
|
2017-03-22 04:34:36 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
Expression* close_call;
|
|
|
|
{
|
|
|
|
ScopedPtrList<Expression> close_args(pointer_buffer());
|
|
|
|
VariableProxy* call_proxy = factory()->NewVariableProxy(
|
|
|
|
function_state_->scope()->generator_object_var());
|
|
|
|
close_args.Add(call_proxy);
|
|
|
|
close_call = factory()->NewCallRuntime(Runtime::kInlineGeneratorClose,
|
|
|
|
close_args, kNoSourcePosition);
|
|
|
|
}
|
2017-01-20 08:58:54 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
Block* finally_block;
|
|
|
|
{
|
|
|
|
ScopedPtrList<Statement> statements(pointer_buffer());
|
|
|
|
statements.Add(
|
|
|
|
factory()->NewExpressionStatement(close_call, kNoSourcePosition));
|
|
|
|
finally_block = factory()->NewBlock(false, statements);
|
|
|
|
}
|
2017-01-20 08:58:54 +00:00
|
|
|
|
|
|
|
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
|
2018-11-05 15:20:49 +00:00
|
|
|
kNoSourcePosition));
|
2017-01-20 08:58:54 +00:00
|
|
|
}
|
|
|
|
|
2017-11-22 00:49:14 +00:00
|
|
|
void Parser::DeclareFunctionNameVar(const AstRawString* function_name,
|
2019-08-23 02:28:45 +00:00
|
|
|
FunctionSyntaxKind function_syntax_kind,
|
2017-11-22 00:49:14 +00:00
|
|
|
DeclarationScope* function_scope) {
|
2019-08-23 02:28:45 +00:00
|
|
|
if (function_syntax_kind == FunctionSyntaxKind::kNamedExpression &&
|
2017-11-22 00:49:14 +00:00
|
|
|
function_scope->LookupLocal(function_name) == nullptr) {
|
|
|
|
DCHECK_EQ(function_scope, scope());
|
|
|
|
function_scope->DeclareFunctionVar(function_name);
|
2017-01-20 08:58:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-21 10:38:56 +00:00
|
|
|
// Special case for legacy for
|
|
|
|
//
|
|
|
|
// for (var x = initializer in enumerable) body
|
|
|
|
//
|
|
|
|
// An initialization block of the form
|
|
|
|
//
|
|
|
|
// {
|
|
|
|
// x = initializer;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// is returned in this case. It has reserved space for two statements,
|
|
|
|
// so that (later on during parsing), the equivalent of
|
|
|
|
//
|
|
|
|
// for (x in enumerable) body
|
|
|
|
//
|
|
|
|
// is added as a second statement to it.
|
|
|
|
Block* Parser::RewriteForVarInLegacy(const ForInfo& for_info) {
|
|
|
|
const DeclarationParsingResult::Declaration& decl =
|
|
|
|
for_info.parsing_result.declarations[0];
|
|
|
|
if (!IsLexicalVariableMode(for_info.parsing_result.descriptor.mode) &&
|
2019-01-28 14:55:17 +00:00
|
|
|
decl.initializer != nullptr && decl.pattern->IsVariableProxy()) {
|
2016-09-21 10:38:56 +00:00
|
|
|
++use_counts_[v8::Isolate::kForInInitializer];
|
|
|
|
const AstRawString* name = decl.pattern->AsVariableProxy()->raw_name();
|
|
|
|
VariableProxy* single_var = NewUnresolved(name);
|
2017-08-29 18:20:42 +00:00
|
|
|
Block* init_block = factory()->NewBlock(2, true);
|
2016-09-21 10:38:56 +00:00
|
|
|
init_block->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(Token::ASSIGN, single_var,
|
2019-01-23 12:49:23 +00:00
|
|
|
decl.initializer, decl.value_beg_pos),
|
2016-09-21 10:38:56 +00:00
|
|
|
kNoSourcePosition),
|
|
|
|
zone());
|
|
|
|
return init_block;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rewrite a for-in/of statement of the form
|
|
|
|
//
|
|
|
|
// for (let/const/var x in/of e) b
|
|
|
|
//
|
|
|
|
// into
|
|
|
|
//
|
|
|
|
// {
|
2017-07-25 17:59:06 +00:00
|
|
|
// var temp;
|
|
|
|
// for (temp in/of e) {
|
|
|
|
// let/const/var x = temp;
|
2016-09-21 10:38:56 +00:00
|
|
|
// b;
|
|
|
|
// }
|
|
|
|
// let x; // for TDZ
|
|
|
|
// }
|
|
|
|
void Parser::DesugarBindingInForEachStatement(ForInfo* for_info,
|
|
|
|
Block** body_block,
|
2018-10-25 07:14:19 +00:00
|
|
|
Expression** each_variable) {
|
2017-09-07 11:53:26 +00:00
|
|
|
DCHECK_EQ(1, for_info->parsing_result.declarations.size());
|
2016-09-21 10:38:56 +00:00
|
|
|
DeclarationParsingResult::Declaration& decl =
|
|
|
|
for_info->parsing_result.declarations[0];
|
|
|
|
Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
|
2019-01-11 10:00:31 +00:00
|
|
|
ScopedPtrList<Statement> each_initialization_statements(pointer_buffer());
|
2019-01-29 10:06:45 +00:00
|
|
|
DCHECK_IMPLIES(!has_error(), decl.pattern != nullptr);
|
2019-01-23 12:49:23 +00:00
|
|
|
decl.initializer = factory()->NewVariableProxy(temp, for_info->position);
|
2019-01-21 12:17:55 +00:00
|
|
|
InitializeVariables(&each_initialization_statements, NORMAL_VARIABLE, &decl);
|
2016-09-21 10:38:56 +00:00
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
*body_block = factory()->NewBlock(3, false);
|
2019-01-11 10:00:31 +00:00
|
|
|
(*body_block)
|
|
|
|
->statements()
|
|
|
|
->Add(factory()->NewBlock(true, each_initialization_statements), zone());
|
2016-10-25 07:59:05 +00:00
|
|
|
*each_variable = factory()->NewVariableProxy(temp, for_info->position);
|
2016-09-21 10:38:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a TDZ for any lexically-bound names in for in/of statements.
|
|
|
|
Block* Parser::CreateForEachStatementTDZ(Block* init_block,
|
2018-10-25 07:14:19 +00:00
|
|
|
const ForInfo& for_info) {
|
2016-09-21 10:38:56 +00:00
|
|
|
if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
|
|
|
|
DCHECK_NULL(init_block);
|
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
init_block = factory()->NewBlock(1, false);
|
2016-09-21 10:38:56 +00:00
|
|
|
|
2019-03-29 10:00:57 +00:00
|
|
|
for (const AstRawString* bound_name : for_info.bound_names) {
|
2016-09-21 10:38:56 +00:00
|
|
|
// TODO(adamk): This needs to be some sort of special
|
|
|
|
// INTERNAL variable that's invisible to the debugger
|
|
|
|
// but visible to everything else.
|
2019-01-24 17:00:48 +00:00
|
|
|
VariableProxy* tdz_proxy = DeclareBoundVariable(
|
2019-03-29 10:00:57 +00:00
|
|
|
bound_name, VariableMode::kLet, kNoSourcePosition);
|
2018-12-21 10:21:01 +00:00
|
|
|
tdz_proxy->var()->set_initializer_position(position());
|
2016-09-21 10:38:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return init_block;
|
|
|
|
}
|
|
|
|
|
2015-03-03 18:34:30 +00:00
|
|
|
Statement* Parser::DesugarLexicalBindingsInForStatement(
|
2014-06-24 14:03:24 +00:00
|
|
|
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
|
2018-10-31 12:57:01 +00:00
|
|
|
Statement* body, Scope* inner_scope, const ForInfo& for_info) {
|
2015-10-08 13:56:49 +00:00
|
|
|
// ES6 13.7.4.8 specifies that on each loop iteration the let variables are
|
|
|
|
// copied into a new environment. Moreover, the "next" statement must be
|
|
|
|
// evaluated not in the environment of the just completed iteration but in
|
|
|
|
// that of the upcoming one. We achieve this with the following desugaring.
|
|
|
|
// Extra care is needed to preserve the completion value of the original loop.
|
2014-05-26 08:07:02 +00:00
|
|
|
//
|
2015-10-08 13:56:49 +00:00
|
|
|
// We are given a for statement of the form
|
2014-05-26 08:07:02 +00:00
|
|
|
//
|
2015-03-03 18:34:30 +00:00
|
|
|
// labels: for (let/const x = i; cond; next) body
|
2014-05-26 08:07:02 +00:00
|
|
|
//
|
2015-10-08 13:56:49 +00:00
|
|
|
// and rewrite it as follows. Here we write {{ ... }} for init-blocks, ie.,
|
|
|
|
// blocks whose ignore_completion_value_ flag is set.
|
2014-05-26 08:07:02 +00:00
|
|
|
//
|
|
|
|
// {
|
2015-03-03 18:34:30 +00:00
|
|
|
// let/const x = i;
|
2014-11-14 19:32:53 +00:00
|
|
|
// temp_x = x;
|
|
|
|
// first = 1;
|
2015-06-18 11:54:03 +00:00
|
|
|
// undefined;
|
2014-11-14 19:32:53 +00:00
|
|
|
// outer: for (;;) {
|
2015-10-08 13:56:49 +00:00
|
|
|
// let/const x = temp_x;
|
|
|
|
// {{ if (first == 1) {
|
|
|
|
// first = 0;
|
|
|
|
// } else {
|
|
|
|
// next;
|
|
|
|
// }
|
|
|
|
// flag = 1;
|
|
|
|
// if (!cond) break;
|
|
|
|
// }}
|
2014-11-14 19:32:53 +00:00
|
|
|
// labels: for (; flag == 1; flag = 0, temp_x = x) {
|
2015-10-08 13:56:49 +00:00
|
|
|
// body
|
2014-11-14 19:32:53 +00:00
|
|
|
// }
|
2015-10-08 13:56:49 +00:00
|
|
|
// {{ if (flag == 1) // Body used break.
|
|
|
|
// break;
|
|
|
|
// }}
|
2014-11-14 19:32:53 +00:00
|
|
|
// }
|
2014-05-26 08:07:02 +00:00
|
|
|
// }
|
|
|
|
|
2017-10-16 13:41:49 +00:00
|
|
|
DCHECK_GT(for_info.bound_names.length(), 0);
|
2019-02-26 10:14:32 +00:00
|
|
|
ScopedPtrList<Variable> temps(pointer_buffer());
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
Block* outer_block =
|
|
|
|
factory()->NewBlock(for_info.bound_names.length() + 4, false);
|
2014-11-14 19:32:53 +00:00
|
|
|
|
2015-03-03 18:34:30 +00:00
|
|
|
// Add statement: let/const x = i.
|
2015-10-01 13:59:36 +00:00
|
|
|
outer_block->statements()->Add(init, zone());
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2014-09-11 09:52:36 +00:00
|
|
|
const AstRawString* temp_name = ast_value_factory()->dot_for_string();
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2015-03-03 18:34:30 +00:00
|
|
|
// For each lexical variable x:
|
2014-05-26 08:07:02 +00:00
|
|
|
// make statement: temp_x = x.
|
2019-03-29 10:00:57 +00:00
|
|
|
for (const AstRawString* bound_name : for_info.bound_names) {
|
|
|
|
VariableProxy* proxy = NewUnresolved(bound_name);
|
2016-08-09 19:49:25 +00:00
|
|
|
Variable* temp = NewTemporary(temp_name);
|
2014-05-26 08:07:02 +00:00
|
|
|
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
|
2016-06-30 09:26:30 +00:00
|
|
|
Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, temp_proxy,
|
|
|
|
proxy, kNoSourcePosition);
|
|
|
|
Statement* assignment_statement =
|
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
|
2015-10-01 13:59:36 +00:00
|
|
|
outer_block->statements()->Add(assignment_statement, zone());
|
2019-02-26 10:14:32 +00:00
|
|
|
temps.Add(temp);
|
2014-05-26 08:07:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-13 16:33:03 +00:00
|
|
|
Variable* first = nullptr;
|
2014-11-14 19:32:53 +00:00
|
|
|
// Make statement: first = 1.
|
|
|
|
if (next) {
|
2016-08-09 19:49:25 +00:00
|
|
|
first = NewTemporary(temp_name);
|
2014-11-14 19:32:53 +00:00
|
|
|
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
|
2014-05-26 08:07:02 +00:00
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2016-06-30 09:26:30 +00:00
|
|
|
Token::ASSIGN, first_proxy, const1, kNoSourcePosition);
|
2014-11-14 19:32:53 +00:00
|
|
|
Statement* assignment_statement =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
|
2015-10-01 13:59:36 +00:00
|
|
|
outer_block->statements()->Add(assignment_statement, zone());
|
2014-05-26 08:07:02 +00:00
|
|
|
}
|
|
|
|
|
2015-06-18 11:54:03 +00:00
|
|
|
// make statement: undefined;
|
2015-10-01 13:59:36 +00:00
|
|
|
outer_block->statements()->Add(
|
2015-06-18 11:54:03 +00:00
|
|
|
factory()->NewExpressionStatement(
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition),
|
2015-06-18 11:54:03 +00:00
|
|
|
zone());
|
|
|
|
|
2014-11-14 19:32:53 +00:00
|
|
|
// Make statement: outer: for (;;)
|
|
|
|
// Note that we don't actually create the label, or set this loop up as an
|
|
|
|
// explicit break target, instead handing it directly to those nodes that
|
|
|
|
// need to know about it. This should be safe because we don't run any code
|
|
|
|
// in this function that looks up break targets.
|
2020-02-18 15:07:23 +00:00
|
|
|
ForStatement* outer_loop = factory()->NewForStatement(kNoSourcePosition);
|
2015-10-01 13:59:36 +00:00
|
|
|
outer_block->statements()->Add(outer_loop, zone());
|
2016-07-19 10:06:38 +00:00
|
|
|
outer_block->set_scope(scope());
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
Block* inner_block = factory()->NewBlock(3, false);
|
2016-01-14 19:25:09 +00:00
|
|
|
{
|
2017-02-20 10:41:29 +00:00
|
|
|
BlockState block_state(&scope_, inner_scope);
|
2016-01-14 19:25:09 +00:00
|
|
|
|
2017-08-29 18:01:54 +00:00
|
|
|
Block* ignore_completion_block =
|
|
|
|
factory()->NewBlock(for_info.bound_names.length() + 3, true);
|
2019-02-26 10:14:32 +00:00
|
|
|
ScopedPtrList<Variable> inner_vars(pointer_buffer());
|
2016-01-14 19:25:09 +00:00
|
|
|
// For each let variable x:
|
|
|
|
// make statement: let/const x = temp_x.
|
2016-09-21 10:38:56 +00:00
|
|
|
for (int i = 0; i < for_info.bound_names.length(); i++) {
|
2019-01-24 17:00:48 +00:00
|
|
|
VariableProxy* proxy = DeclareBoundVariable(
|
2016-09-21 10:38:56 +00:00
|
|
|
for_info.bound_names[i], for_info.parsing_result.descriptor.mode,
|
2018-10-25 07:14:19 +00:00
|
|
|
kNoSourcePosition);
|
2019-02-26 10:14:32 +00:00
|
|
|
inner_vars.Add(proxy->var());
|
2016-01-14 19:25:09 +00:00
|
|
|
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
|
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2018-12-21 10:21:01 +00:00
|
|
|
Token::INIT, proxy, temp_proxy, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
Statement* assignment_statement =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
|
2017-08-29 18:20:42 +00:00
|
|
|
int declaration_pos = for_info.parsing_result.descriptor.declaration_pos;
|
2017-10-16 13:41:49 +00:00
|
|
|
DCHECK_NE(declaration_pos, kNoSourcePosition);
|
2018-12-21 10:21:01 +00:00
|
|
|
proxy->var()->set_initializer_position(declaration_pos);
|
2016-01-14 19:25:09 +00:00
|
|
|
ignore_completion_block->statements()->Add(assignment_statement, zone());
|
|
|
|
}
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make statement: if (first == 1) { first = 0; } else { next; }
|
|
|
|
if (next) {
|
|
|
|
DCHECK(first);
|
2017-10-13 16:33:03 +00:00
|
|
|
Expression* compare = nullptr;
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make compare expression: first == 1.
|
|
|
|
{
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
|
|
|
|
compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
2017-10-13 16:33:03 +00:00
|
|
|
Statement* clear_first = nullptr;
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make statement: first = 0.
|
|
|
|
{
|
|
|
|
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const0 = factory()->NewSmiLiteral(0, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2016-06-30 09:26:30 +00:00
|
|
|
Token::ASSIGN, first_proxy, const0, kNoSourcePosition);
|
|
|
|
clear_first =
|
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
|
|
|
Statement* clear_first_or_next = factory()->NewIfStatement(
|
2016-06-30 09:26:30 +00:00
|
|
|
compare, clear_first, next, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
ignore_completion_block->statements()->Add(clear_first_or_next, zone());
|
2014-05-26 08:07:02 +00:00
|
|
|
}
|
2016-01-14 19:25:09 +00:00
|
|
|
|
2016-08-09 19:49:25 +00:00
|
|
|
Variable* flag = NewTemporary(temp_name);
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make statement: flag = 1.
|
2014-05-26 08:07:02 +00:00
|
|
|
{
|
2016-01-14 19:25:09 +00:00
|
|
|
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
|
2014-05-26 08:07:02 +00:00
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2016-06-30 09:26:30 +00:00
|
|
|
Token::ASSIGN, flag_proxy, const1, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
Statement* assignment_statement =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
ignore_completion_block->statements()->Add(assignment_statement, zone());
|
2014-05-26 08:07:02 +00:00
|
|
|
}
|
2015-10-08 13:56:49 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make statement: if (!cond) break.
|
|
|
|
if (cond) {
|
|
|
|
Statement* stop =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewBreakStatement(outer_loop, kNoSourcePosition);
|
2018-10-30 14:41:34 +00:00
|
|
|
Statement* noop = factory()->EmptyStatement();
|
2016-01-14 19:25:09 +00:00
|
|
|
ignore_completion_block->statements()->Add(
|
|
|
|
factory()->NewIfStatement(cond, noop, stop, cond->position()),
|
|
|
|
zone());
|
|
|
|
}
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
inner_block->statements()->Add(ignore_completion_block, zone());
|
|
|
|
// Make cond expression for main loop: flag == 1.
|
2017-10-13 16:33:03 +00:00
|
|
|
Expression* flag_cond = nullptr;
|
2014-11-14 19:32:53 +00:00
|
|
|
{
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
|
2014-11-14 19:32:53 +00:00
|
|
|
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
2016-01-14 19:25:09 +00:00
|
|
|
flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition);
|
2014-11-14 19:32:53 +00:00
|
|
|
}
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
// Create chain of expressions "flag = 0, temp_x = x, ..."
|
2017-10-13 16:33:03 +00:00
|
|
|
Statement* compound_next_statement = nullptr;
|
2016-01-14 19:25:09 +00:00
|
|
|
{
|
2017-10-13 16:33:03 +00:00
|
|
|
Expression* compound_next = nullptr;
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make expression: flag = 0.
|
|
|
|
{
|
|
|
|
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const0 = factory()->NewSmiLiteral(0, kNoSourcePosition);
|
|
|
|
compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
|
|
|
|
const0, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
2014-11-14 19:32:53 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make the comma-separated list of temp_x = x assignments.
|
|
|
|
int inner_var_proxy_pos = scanner()->location().beg_pos;
|
2016-09-21 10:38:56 +00:00
|
|
|
for (int i = 0; i < for_info.bound_names.length(); i++) {
|
2016-01-14 19:25:09 +00:00
|
|
|
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
|
|
|
|
VariableProxy* proxy =
|
|
|
|
factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
|
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2016-06-30 09:26:30 +00:00
|
|
|
Token::ASSIGN, temp_proxy, proxy, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
compound_next = factory()->NewBinaryOperation(
|
2016-06-30 09:26:30 +00:00
|
|
|
Token::COMMA, compound_next, assignment, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
2014-11-14 19:32:53 +00:00
|
|
|
|
2016-06-30 09:26:30 +00:00
|
|
|
compound_next_statement =
|
|
|
|
factory()->NewExpressionStatement(compound_next, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
|
|
|
|
// Note that we re-use the original loop node, which retains its labels
|
|
|
|
// and ensures that any break or continue statements in body point to
|
|
|
|
// the right place.
|
2017-10-13 16:33:03 +00:00
|
|
|
loop->Initialize(nullptr, flag_cond, compound_next_statement, body);
|
2016-01-14 19:25:09 +00:00
|
|
|
inner_block->statements()->Add(loop, zone());
|
|
|
|
|
|
|
|
// Make statement: {{if (flag == 1) break;}}
|
2014-11-14 19:32:53 +00:00
|
|
|
{
|
2017-10-13 16:33:03 +00:00
|
|
|
Expression* compare = nullptr;
|
2016-01-14 19:25:09 +00:00
|
|
|
// Make compare expresion: flag == 1.
|
|
|
|
{
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
|
|
|
compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
|
2016-06-30 09:26:30 +00:00
|
|
|
kNoSourcePosition);
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
|
|
|
Statement* stop =
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewBreakStatement(outer_loop, kNoSourcePosition);
|
2018-10-30 14:41:34 +00:00
|
|
|
Statement* empty = factory()->EmptyStatement();
|
2016-06-30 09:26:30 +00:00
|
|
|
Statement* if_flag_break =
|
|
|
|
factory()->NewIfStatement(compare, stop, empty, kNoSourcePosition);
|
2017-02-27 16:22:25 +00:00
|
|
|
inner_block->statements()->Add(IgnoreCompletion(if_flag_break), zone());
|
2016-01-14 19:25:09 +00:00
|
|
|
}
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2016-01-14 19:25:09 +00:00
|
|
|
inner_block->set_scope(inner_scope);
|
|
|
|
}
|
2014-05-26 08:07:02 +00:00
|
|
|
|
2017-10-13 16:33:03 +00:00
|
|
|
outer_loop->Initialize(nullptr, nullptr, nullptr, inner_block);
|
2017-07-12 13:06:09 +00:00
|
|
|
|
2014-05-26 08:07:02 +00:00
|
|
|
return outer_block;
|
|
|
|
}
|
|
|
|
|
2018-12-17 09:28:27 +00:00
|
|
|
void ParserFormalParameters::ValidateDuplicate(Parser* parser) const {
|
|
|
|
if (has_duplicate()) {
|
|
|
|
parser->ReportMessageAt(duplicate_loc, MessageTemplate::kParamDupe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void ParserFormalParameters::ValidateStrictMode(Parser* parser) const {
|
|
|
|
if (strict_error_loc.IsValid()) {
|
|
|
|
parser->ReportMessageAt(strict_error_loc, strict_error_message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 18:01:58 +00:00
|
|
|
void Parser::AddArrowFunctionFormalParameters(
|
2018-10-25 07:14:19 +00:00
|
|
|
ParserFormalParameters* parameters, Expression* expr, int end_pos) {
|
2015-04-21 14:44:18 +00:00
|
|
|
// ArrowFunctionFormals ::
|
2017-10-25 10:50:45 +00:00
|
|
|
// Nary(Token::COMMA, VariableProxy*, Tail)
|
2015-06-10 16:11:25 +00:00
|
|
|
// Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail)
|
|
|
|
// Tail
|
|
|
|
// NonTailArrowFunctionFormals ::
|
|
|
|
// Binary(Token::COMMA, NonTailArrowFunctionFormals, VariableProxy)
|
|
|
|
// VariableProxy
|
|
|
|
// Tail ::
|
2015-04-21 14:44:18 +00:00
|
|
|
// VariableProxy
|
2015-06-10 16:11:25 +00:00
|
|
|
// Spread(VariableProxy)
|
2015-04-21 14:44:18 +00:00
|
|
|
//
|
2017-10-25 10:50:45 +00:00
|
|
|
// We need to visit the parameters in left-to-right order
|
2015-04-21 14:44:18 +00:00
|
|
|
//
|
2017-10-25 10:50:45 +00:00
|
|
|
|
|
|
|
// For the Nary case, we simply visit the parameters in a loop.
|
|
|
|
if (expr->IsNaryOperation()) {
|
|
|
|
NaryOperation* nary = expr->AsNaryOperation();
|
|
|
|
// The classifier has already run, so we know that the expression is a valid
|
|
|
|
// arrow function formals production.
|
|
|
|
DCHECK_EQ(nary->op(), Token::COMMA);
|
|
|
|
// Each op position is the end position of the *previous* expr, with the
|
|
|
|
// second (i.e. first "subsequent") op position being the end position of
|
|
|
|
// the first child expression.
|
|
|
|
Expression* next = nary->first();
|
|
|
|
for (size_t i = 0; i < nary->subsequent_length(); ++i) {
|
2018-10-25 07:14:19 +00:00
|
|
|
AddArrowFunctionFormalParameters(parameters, next,
|
|
|
|
nary->subsequent_op_position(i));
|
2017-10-25 10:50:45 +00:00
|
|
|
next = nary->subsequent(i);
|
|
|
|
}
|
2018-10-25 07:14:19 +00:00
|
|
|
AddArrowFunctionFormalParameters(parameters, next, end_pos);
|
2017-10-25 10:50:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For the binary case, we recurse on the left-hand side of binary comma
|
|
|
|
// expressions.
|
2015-04-21 14:44:18 +00:00
|
|
|
if (expr->IsBinaryOperation()) {
|
|
|
|
BinaryOperation* binop = expr->AsBinaryOperation();
|
2015-05-13 13:32:27 +00:00
|
|
|
// The classifier has already run, so we know that the expression is a valid
|
|
|
|
// arrow function formals production.
|
|
|
|
DCHECK_EQ(binop->op(), Token::COMMA);
|
2015-04-21 14:44:18 +00:00
|
|
|
Expression* left = binop->left();
|
|
|
|
Expression* right = binop->right();
|
2016-04-20 20:48:32 +00:00
|
|
|
int comma_pos = binop->position();
|
2018-10-25 07:14:19 +00:00
|
|
|
AddArrowFunctionFormalParameters(parameters, left, comma_pos);
|
2015-04-21 14:44:18 +00:00
|
|
|
// LHS of comma expression should be unparenthesized.
|
|
|
|
expr = right;
|
|
|
|
}
|
2015-04-21 11:09:53 +00:00
|
|
|
|
2015-06-10 16:11:25 +00:00
|
|
|
// Only the right-most expression may be a rest parameter.
|
2015-07-23 11:53:31 +00:00
|
|
|
DCHECK(!parameters->has_rest);
|
2015-06-10 16:11:25 +00:00
|
|
|
|
2015-07-23 11:53:31 +00:00
|
|
|
bool is_rest = expr->IsSpread();
|
2015-07-23 14:28:59 +00:00
|
|
|
if (is_rest) {
|
|
|
|
expr = expr->AsSpread()->expression();
|
|
|
|
parameters->has_rest = true;
|
|
|
|
}
|
2017-09-25 05:31:24 +00:00
|
|
|
DCHECK_IMPLIES(parameters->is_simple, !is_rest);
|
|
|
|
DCHECK_IMPLIES(parameters->is_simple, expr->IsVariableProxy());
|
2015-06-10 16:11:25 +00:00
|
|
|
|
2015-08-24 18:00:59 +00:00
|
|
|
Expression* initializer = nullptr;
|
2016-07-22 23:28:10 +00:00
|
|
|
if (expr->IsAssignment()) {
|
2015-08-24 18:00:59 +00:00
|
|
|
Assignment* assignment = expr->AsAssignment();
|
2017-08-16 16:50:09 +00:00
|
|
|
DCHECK(!assignment->IsCompoundAssignment());
|
2015-08-24 18:00:59 +00:00
|
|
|
initializer = assignment->value();
|
|
|
|
expr = assignment->target();
|
2015-08-17 12:01:55 +00:00
|
|
|
}
|
|
|
|
|
2019-01-24 17:00:48 +00:00
|
|
|
AddFormalParameter(parameters, expr, initializer, end_pos, is_rest);
|
2015-08-05 12:00:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-27 18:01:58 +00:00
|
|
|
void Parser::DeclareArrowFunctionFormalParameters(
|
2015-08-05 12:00:41 +00:00
|
|
|
ParserFormalParameters* parameters, Expression* expr,
|
2018-10-25 07:14:19 +00:00
|
|
|
const Scanner::Location& params_loc) {
|
2018-10-31 16:03:42 +00:00
|
|
|
if (expr->IsEmptyParentheses() || has_error()) return;
|
2015-08-26 09:36:39 +00:00
|
|
|
|
2018-10-25 07:14:19 +00:00
|
|
|
AddArrowFunctionFormalParameters(parameters, expr, params_loc.end_pos);
|
2016-07-22 23:28:10 +00:00
|
|
|
|
2016-10-13 12:34:37 +00:00
|
|
|
if (parameters->arity > Code::kMaxArguments) {
|
2016-08-25 08:48:45 +00:00
|
|
|
ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
|
2016-04-20 20:48:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-09 12:20:10 +00:00
|
|
|
DeclareFormalParameters(parameters);
|
2018-10-31 16:03:42 +00:00
|
|
|
DCHECK_IMPLIES(parameters->is_simple,
|
|
|
|
parameters->scope->has_simple_parameters());
|
Implement handling of arrow functions in the parser
Arrow functions are parsed from ParseAssignmentExpression(). Handling the
parameter list is done by letting ParseConditionalExpression() parse a comma
separated list of identifiers, and it returns a tree of BinaryOperation nodes
with VariableProxy leaves, or a single VariableProxy if there is only one
parameter. When the arrow token "=>" is found, the VariableProxy nodes are
passed to ParseArrowFunctionLiteral(), which will then skip parsing the
paramaeter list. This avoids having to rewind when the arrow is found and
restart parsing the parameter list.
Note that the empty parameter list "()" is handled directly in
ParsePrimaryExpression(): after is has consumed the opening parenthesis,
if a closing parenthesis follows, then the only valid input is an arrow
function. In this case, ParsePrimaryExpression() directly calls
ParseArrowFunctionLiteral(), to avoid needing to return a sentinel value
to signal the empty parameter list. Because it will consume the body of
the arrow function, ParseAssignmentExpression() will not see the arrow
"=>" token as next, and return the already-parser expression.
The implementation is done in ParserBase, so it was needed to do some
additions to ParserBase, ParserTraits and PreParserTraits. Some of the
glue code can be removed later on when more more functionality is moved
to ParserBase.
Additionally, this adds a runtime flag "harmony_arrow_functions"
(disabled by default); enabling "harmony" will enable it as well.
BUG=v8:2700
LOG=N
R=marja@chromium.org
Review URL: https://codereview.chromium.org/383983002
Patch from Adrián Pérez de Castro <aperez@igalia.com>.
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22366 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-07-14 07:55:45 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 09:57:17 +00:00
|
|
|
void Parser::PrepareGeneratorVariables() {
|
2016-09-30 07:53:43 +00:00
|
|
|
// Calling a generator returns a generator object. That object is stored
|
|
|
|
// in a temporary variable, a definition that is used by "yield"
|
|
|
|
// expressions.
|
2017-02-10 14:38:58 +00:00
|
|
|
function_state_->scope()->DeclareGeneratorObjectVar(
|
|
|
|
ast_value_factory()->dot_generator_object_string());
|
2016-09-30 07:53:43 +00:00
|
|
|
}
|
2015-06-26 21:39:43 +00:00
|
|
|
|
2013-06-06 13:28:22 +00:00
|
|
|
FunctionLiteral* Parser::ParseFunctionLiteral(
|
2014-09-10 16:39:42 +00:00
|
|
|
const AstRawString* function_name, Scanner::Location function_name_location,
|
2015-07-09 21:31:11 +00:00
|
|
|
FunctionNameValidity function_name_validity, FunctionKind kind,
|
2019-08-23 02:28:45 +00:00
|
|
|
int function_token_pos, FunctionSyntaxKind function_syntax_kind,
|
2017-12-18 08:10:06 +00:00
|
|
|
LanguageMode language_mode,
|
2018-10-25 07:14:19 +00:00
|
|
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
|
2008-07-03 15:10:15 +00:00
|
|
|
// Function ::
|
|
|
|
// '(' FormalParameterList? ')' '{' FunctionBody '}'
|
2014-06-17 07:23:26 +00:00
|
|
|
//
|
|
|
|
// Getter ::
|
|
|
|
// '(' ')' '{' FunctionBody '}'
|
|
|
|
//
|
|
|
|
// Setter ::
|
|
|
|
// '(' PropertySetParameterList ')' '{' FunctionBody '}'
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2019-08-23 02:28:45 +00:00
|
|
|
bool is_wrapped = function_syntax_kind == FunctionSyntaxKind::kWrapped;
|
2017-12-18 08:10:06 +00:00
|
|
|
DCHECK_EQ(is_wrapped, arguments_for_wrapped_function != nullptr);
|
|
|
|
|
2016-06-30 09:26:30 +00:00
|
|
|
int pos = function_token_pos == kNoSourcePosition ? peek_position()
|
|
|
|
: function_token_pos;
|
2017-12-18 08:10:06 +00:00
|
|
|
DCHECK_NE(kNoSourcePosition, pos);
|
2013-10-14 09:24:58 +00:00
|
|
|
|
2011-08-08 16:14:46 +00:00
|
|
|
// Anonymous functions were passed either the empty symbol or a null
|
|
|
|
// handle as the function name. Remember if we were passed a non-empty
|
|
|
|
// handle to decide whether to invoke function name inference.
|
2017-10-13 16:33:03 +00:00
|
|
|
bool should_infer_name = function_name == nullptr;
|
2011-08-08 16:14:46 +00:00
|
|
|
|
2017-06-19 15:13:45 +00:00
|
|
|
// We want a non-null handle as the function name by default. We will handle
|
|
|
|
// the "function does not have a shared name" case later.
|
|
|
|
if (should_infer_name) {
|
|
|
|
function_name = ast_value_factory()->empty_string();
|
|
|
|
}
|
|
|
|
|
2016-08-04 19:15:18 +00:00
|
|
|
FunctionLiteral::EagerCompileHint eager_compile_hint =
|
2017-12-18 08:10:06 +00:00
|
|
|
function_state_->next_function_is_likely_called() || is_wrapped
|
2016-08-04 19:15:18 +00:00
|
|
|
? FunctionLiteral::kShouldEagerCompile
|
2016-10-07 09:12:48 +00:00
|
|
|
: default_eager_compile_hint();
|
2016-08-04 19:15:18 +00:00
|
|
|
|
|
|
|
// Determine if the function can be parsed lazily. Lazy parsing is
|
|
|
|
// different from lazy compilation; we need to parse more eagerly than we
|
|
|
|
// compile.
|
|
|
|
|
|
|
|
// We can only parse lazily if we also compile lazily. The heuristics for lazy
|
|
|
|
// compilation are:
|
|
|
|
// - It must not have been prohibited by the caller to Parse (some callers
|
|
|
|
// need a full AST).
|
|
|
|
// - The outer scope must allow lazy compilation of inner functions.
|
|
|
|
// - The function mustn't be a function expression with an open parenthesis
|
|
|
|
// before; we consider that a hint that the function will be called
|
|
|
|
// immediately, and it would be a waste of time to make it lazily
|
|
|
|
// compiled.
|
|
|
|
// These are all things we can know at this point, without looking at the
|
|
|
|
// function itself.
|
|
|
|
|
2016-09-27 09:48:17 +00:00
|
|
|
// We separate between lazy parsing top level functions and lazy parsing inner
|
|
|
|
// functions, because the latter needs to do more work. In particular, we need
|
|
|
|
// to track unresolved variables to distinguish between these cases:
|
2016-08-04 19:15:18 +00:00
|
|
|
// (function foo() {
|
|
|
|
// bar = function() { return 1; }
|
|
|
|
// })();
|
|
|
|
// and
|
|
|
|
// (function foo() {
|
|
|
|
// var a = 1;
|
|
|
|
// bar = function() { return a; }
|
|
|
|
// })();
|
|
|
|
|
|
|
|
// Now foo will be parsed eagerly and compiled eagerly (optimization: assume
|
|
|
|
// parenthesis before the function means that it will be called
|
2016-09-27 09:48:17 +00:00
|
|
|
// immediately). bar can be parsed lazily, but we need to parse it in a mode
|
|
|
|
// that tracks unresolved variables.
|
2020-04-22 10:45:31 +00:00
|
|
|
DCHECK_IMPLIES(parse_lazily(), info()->flags().allow_lazy_compile());
|
2018-11-26 08:55:02 +00:00
|
|
|
DCHECK_IMPLIES(parse_lazily(), has_error() || allow_lazy_);
|
2016-11-07 16:34:45 +00:00
|
|
|
DCHECK_IMPLIES(parse_lazily(), extension_ == nullptr);
|
2016-09-27 09:48:17 +00:00
|
|
|
|
2017-04-24 08:49:35 +00:00
|
|
|
const bool is_lazy =
|
|
|
|
eager_compile_hint == FunctionLiteral::kShouldLazyCompile;
|
2017-11-22 01:44:04 +00:00
|
|
|
const bool is_top_level = AllowsLazyParsingWithoutUnresolvedVariables();
|
2018-10-11 15:22:10 +00:00
|
|
|
const bool is_eager_top_level_function = !is_lazy && is_top_level;
|
2017-04-24 08:49:35 +00:00
|
|
|
const bool is_lazy_top_level_function = is_lazy && is_top_level;
|
|
|
|
const bool is_lazy_inner_function = is_lazy && !is_top_level;
|
2016-09-27 09:48:17 +00:00
|
|
|
|
2016-11-16 18:51:32 +00:00
|
|
|
RuntimeCallTimerScope runtime_timer(
|
2019-11-25 11:23:12 +00:00
|
|
|
runtime_call_stats_, RuntimeCallCounterId::kParseFunctionLiteral,
|
|
|
|
RuntimeCallStats::kThreadSpecific);
|
2017-11-14 09:12:52 +00:00
|
|
|
base::ElapsedTimer timer;
|
|
|
|
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
|
2016-11-15 16:08:16 +00:00
|
|
|
|
2016-09-27 09:48:17 +00:00
|
|
|
// Determine whether we can still lazy parse the inner function.
|
2016-08-04 19:15:18 +00:00
|
|
|
// The preconditions are:
|
|
|
|
// - Lazy compilation has to be enabled.
|
|
|
|
// - Neither V8 natives nor native function declarations can be allowed,
|
|
|
|
// since parsing one would retroactively force the function to be
|
|
|
|
// eagerly compiled.
|
|
|
|
// - The invoker of this parser can't depend on the AST being eagerly
|
|
|
|
// built (either because the function is about to be compiled, or
|
|
|
|
// because the AST is going to be inspected for some reason).
|
|
|
|
// - Because of the above, we can't be attempting to parse a
|
|
|
|
// FunctionExpression; even without enclosing parentheses it might be
|
|
|
|
// immediately invoked.
|
|
|
|
// - The function literal shouldn't be hinted to eagerly compile.
|
2016-09-27 09:48:17 +00:00
|
|
|
|
|
|
|
// Inner functions will be parsed using a temporary Zone. After parsing, we
|
|
|
|
// will migrate unresolved variable into a Scope in the main Zone.
|
2017-04-24 08:49:35 +00:00
|
|
|
|
2018-10-09 08:38:26 +00:00
|
|
|
const bool should_preparse_inner = parse_lazily() && is_lazy_inner_function;
|
2017-04-24 08:49:35 +00:00
|
|
|
|
2018-10-11 15:22:10 +00:00
|
|
|
// If parallel compile tasks are enabled, and the function is an eager
|
|
|
|
// top level function, then we can pre-parse the function and parse / compile
|
|
|
|
// in a parallel task on a worker thread.
|
|
|
|
bool should_post_parallel_task =
|
|
|
|
parse_lazily() && is_eager_top_level_function &&
|
|
|
|
FLAG_parallel_compile_tasks && info()->parallel_tasks() &&
|
|
|
|
scanner()->stream()->can_be_cloned_for_parallel_access();
|
|
|
|
|
2017-04-24 08:49:35 +00:00
|
|
|
// This may be modified later to reflect preparsing decision taken
|
2018-10-11 15:22:10 +00:00
|
|
|
bool should_preparse = (parse_lazily() && is_lazy_top_level_function) ||
|
|
|
|
should_preparse_inner || should_post_parallel_task;
|
2016-08-04 19:15:18 +00:00
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
ScopedPtrList<Statement> body(pointer_buffer());
|
2019-04-15 23:27:56 +00:00
|
|
|
int expected_property_count = 0;
|
2018-01-24 11:16:52 +00:00
|
|
|
int suspend_count = -1;
|
2016-11-04 15:04:03 +00:00
|
|
|
int num_parameters = -1;
|
|
|
|
int function_length = -1;
|
|
|
|
bool has_duplicate_parameters = false;
|
2016-11-28 11:40:22 +00:00
|
|
|
int function_literal_id = GetNextFunctionLiteralId();
|
2019-01-07 14:09:18 +00:00
|
|
|
ProducedPreparseData* produced_preparse_data = nullptr;
|
2016-09-28 15:58:22 +00:00
|
|
|
|
2018-09-24 10:34:49 +00:00
|
|
|
// This Scope lives in the main zone. We'll migrate data into that zone later.
|
2018-09-26 13:23:55 +00:00
|
|
|
Zone* parse_zone = should_preparse ? &preparser_zone_ : zone();
|
2019-04-15 23:52:07 +00:00
|
|
|
DeclarationScope* scope = NewFunctionScope(kind, parse_zone);
|
2018-09-24 10:34:49 +00:00
|
|
|
SetLanguageMode(scope, language_mode);
|
2016-08-01 13:25:39 +00:00
|
|
|
#ifdef DEBUG
|
2018-09-24 10:34:49 +00:00
|
|
|
scope->SetScopeName(function_name);
|
2016-08-01 13:25:39 +00:00
|
|
|
#endif
|
2017-08-18 20:34:14 +00:00
|
|
|
|
2018-11-07 17:00:35 +00:00
|
|
|
if (!is_wrapped && V8_UNLIKELY(!Check(Token::LPAREN))) {
|
|
|
|
ReportUnexpectedToken(Next());
|
|
|
|
return nullptr;
|
2018-10-25 07:14:19 +00:00
|
|
|
}
|
2018-09-26 13:23:55 +00:00
|
|
|
scope->set_start_position(position());
|
2018-09-24 10:34:49 +00:00
|
|
|
|
|
|
|
// Eager or lazy parse? If is_lazy_top_level_function, we'll parse
|
|
|
|
// lazily. We'll call SkipFunction, which may decide to
|
|
|
|
// abort lazy parsing if it suspects that wasn't a good idea. If so (in
|
|
|
|
// which case the parser is expected to have backtracked), or if we didn't
|
|
|
|
// try to lazy parse in the first place, we'll have to parse eagerly.
|
2018-09-28 08:14:08 +00:00
|
|
|
bool did_preparse_successfully =
|
2019-04-11 10:43:45 +00:00
|
|
|
should_preparse &&
|
2019-08-23 02:28:45 +00:00
|
|
|
SkipFunction(function_name, kind, function_syntax_kind, scope,
|
|
|
|
&num_parameters, &function_length, &produced_preparse_data);
|
2019-01-07 15:24:22 +00:00
|
|
|
|
2018-09-28 08:14:08 +00:00
|
|
|
if (!did_preparse_successfully) {
|
2018-12-18 15:54:28 +00:00
|
|
|
// If skipping aborted, it rewound the scanner until before the LPAREN.
|
|
|
|
// Consume it in that case.
|
|
|
|
if (should_preparse) Consume(Token::LPAREN);
|
2018-10-11 15:22:10 +00:00
|
|
|
should_post_parallel_task = false;
|
2019-08-23 02:28:45 +00:00
|
|
|
ParseFunction(&body, function_name, pos, kind, function_syntax_kind, scope,
|
2018-11-05 15:20:49 +00:00
|
|
|
&num_parameters, &function_length, &has_duplicate_parameters,
|
|
|
|
&expected_property_count, &suspend_count,
|
|
|
|
arguments_for_wrapped_function);
|
2018-09-24 10:34:49 +00:00
|
|
|
}
|
2016-09-28 13:36:30 +00:00
|
|
|
|
2018-09-24 10:34:49 +00:00
|
|
|
if (V8_UNLIKELY(FLAG_log_function_events)) {
|
|
|
|
double ms = timer.Elapsed().InMillisecondsF();
|
|
|
|
const char* event_name =
|
|
|
|
should_preparse
|
|
|
|
? (is_top_level ? "preparse-no-resolution" : "preparse-resolution")
|
|
|
|
: "full-parse";
|
|
|
|
logger_->FunctionEvent(
|
2020-04-22 10:45:31 +00:00
|
|
|
event_name, flags().script_id(), ms, scope->start_position(),
|
2018-09-24 10:34:49 +00:00
|
|
|
scope->end_position(),
|
|
|
|
reinterpret_cast<const char*>(function_name->raw_data()),
|
2020-09-24 07:39:15 +00:00
|
|
|
function_name->byte_length(), function_name->is_one_byte());
|
2018-09-24 10:34:49 +00:00
|
|
|
}
|
2019-03-07 17:26:16 +00:00
|
|
|
if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled()) &&
|
|
|
|
did_preparse_successfully) {
|
2018-09-24 14:09:43 +00:00
|
|
|
if (runtime_call_stats_) {
|
|
|
|
runtime_call_stats_->CorrectCurrentCounterId(
|
2019-11-25 11:23:12 +00:00
|
|
|
RuntimeCallCounterId::kPreParseWithVariableResolution,
|
|
|
|
RuntimeCallStats::kThreadSpecific);
|
2016-10-18 08:00:03 +00:00
|
|
|
}
|
2018-09-24 10:34:49 +00:00
|
|
|
}
|
2016-10-18 08:00:03 +00:00
|
|
|
|
2018-09-24 10:34:49 +00:00
|
|
|
// Validate function name. We can do this only after parsing the function,
|
|
|
|
// since the function can declare itself strict.
|
|
|
|
language_mode = scope->language_mode();
|
|
|
|
CheckFunctionName(language_mode, function_name, function_name_validity,
|
2018-10-25 07:14:19 +00:00
|
|
|
function_name_location);
|
2015-02-06 18:04:11 +00:00
|
|
|
|
2018-09-24 10:34:49 +00:00
|
|
|
if (is_strict(language_mode)) {
|
2018-10-25 07:14:19 +00:00
|
|
|
CheckStrictOctalLiteral(scope->start_position(), scope->end_position());
|
2018-09-24 10:34:49 +00:00
|
|
|
}
|
2011-09-01 12:31:18 +00:00
|
|
|
|
2015-04-21 11:09:53 +00:00
|
|
|
FunctionLiteral::ParameterFlag duplicate_parameters =
|
2015-05-13 11:45:04 +00:00
|
|
|
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
|
|
|
|
: FunctionLiteral::kNoDuplicateParameters;
|
2015-04-21 11:09:53 +00:00
|
|
|
|
2016-08-04 19:15:18 +00:00
|
|
|
// Note that the FunctionLiteral needs to be created in the main Zone again.
|
2014-07-21 09:58:01 +00:00
|
|
|
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
|
2017-02-15 15:12:13 +00:00
|
|
|
function_name, scope, body, expected_property_count, num_parameters,
|
2019-08-23 02:28:45 +00:00
|
|
|
function_length, duplicate_parameters, function_syntax_kind,
|
|
|
|
eager_compile_hint, pos, true, function_literal_id,
|
|
|
|
produced_preparse_data);
|
2013-10-14 09:24:58 +00:00
|
|
|
function_literal->set_function_token_position(function_token_pos);
|
2018-01-24 11:16:52 +00:00
|
|
|
function_literal->set_suspend_count(suspend_count);
|
2011-04-07 14:45:34 +00:00
|
|
|
|
2019-05-16 11:56:18 +00:00
|
|
|
RecordFunctionLiteralSourceRange(function_literal);
|
|
|
|
|
2018-10-11 15:22:10 +00:00
|
|
|
if (should_post_parallel_task) {
|
|
|
|
// Start a parallel parse / compile task on the compiler dispatcher.
|
|
|
|
info()->parallel_tasks()->Enqueue(info(), function_name, function_literal);
|
|
|
|
}
|
|
|
|
|
2016-09-02 11:44:48 +00:00
|
|
|
if (should_infer_name) {
|
2018-09-21 11:20:02 +00:00
|
|
|
fni_.AddFunction(function_literal);
|
2016-09-02 11:44:48 +00:00
|
|
|
}
|
2011-04-07 14:45:34 +00:00
|
|
|
return function_literal;
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2019-01-07 14:09:18 +00:00
|
|
|
bool Parser::SkipFunction(const AstRawString* function_name, FunctionKind kind,
|
2019-08-23 02:28:45 +00:00
|
|
|
FunctionSyntaxKind function_syntax_kind,
|
2019-01-07 14:09:18 +00:00
|
|
|
DeclarationScope* function_scope, int* num_parameters,
|
2019-04-11 10:43:45 +00:00
|
|
|
int* function_length,
|
2019-01-07 14:09:18 +00:00
|
|
|
ProducedPreparseData** produced_preparse_data) {
|
2017-04-04 15:44:08 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, function_scope);
|
2018-09-26 13:23:55 +00:00
|
|
|
function_scope->set_zone(&preparser_zone_);
|
2017-04-04 15:44:08 +00:00
|
|
|
|
2016-11-04 15:04:03 +00:00
|
|
|
DCHECK_NE(kNoSourcePosition, function_scope->start_position());
|
Implement new Function.prototype.toString --harmony-function-tostring
For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
starts at the "function" or "async" keyword and ends at the final "}".
The previous behavior would start the excerpt at the "(" of the
parameter list, and prepend a canonical `"function " + name` or
similar, which would discard comments and formatting surrounding the
function's name. Anonymous functions declared as function expressions
no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
generator methods), or property name, whichever comes first.
Previously, the toString representation for methods would use a
canonical prefix before the "(" of the parameter list. Note that any
"static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.
For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
"\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
but that was removed from the spec, and so this CL does not do it.
Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.
BUG=v8:4958, v8:4230
Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
2017-02-16 20:19:24 +00:00
|
|
|
DCHECK_EQ(kNoSourcePosition, parameters_end_pos_);
|
2014-10-01 16:54:42 +00:00
|
|
|
|
2016-11-04 15:04:03 +00:00
|
|
|
DCHECK_IMPLIES(IsArrowFunction(kind),
|
|
|
|
scanner()->current_token() == Token::ARROW);
|
|
|
|
|
2018-02-20 14:14:54 +00:00
|
|
|
// FIXME(marja): There are 2 ways to skip functions now. Unify them.
|
2019-01-07 14:09:18 +00:00
|
|
|
if (consumed_preparse_data_) {
|
2017-06-30 10:38:38 +00:00
|
|
|
int end_position;
|
|
|
|
LanguageMode language_mode;
|
|
|
|
int num_inner_functions;
|
|
|
|
bool uses_super_property;
|
2019-01-21 17:30:28 +00:00
|
|
|
if (stack_overflow()) return true;
|
2019-01-07 14:09:18 +00:00
|
|
|
*produced_preparse_data =
|
|
|
|
consumed_preparse_data_->GetDataForSkippableFunction(
|
2017-06-30 10:38:38 +00:00
|
|
|
main_zone(), function_scope->start_position(), &end_position,
|
2019-04-11 10:43:45 +00:00
|
|
|
num_parameters, function_length, &num_inner_functions,
|
|
|
|
&uses_super_property, &language_mode);
|
2017-06-30 10:38:38 +00:00
|
|
|
|
2019-01-07 14:09:18 +00:00
|
|
|
function_scope->outer_scope()->SetMustUsePreparseData();
|
2017-06-30 10:38:38 +00:00
|
|
|
function_scope->set_is_skipped_function(true);
|
|
|
|
function_scope->set_end_position(end_position);
|
|
|
|
scanner()->SeekForward(end_position - 1);
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::RBRACE);
|
2017-06-30 10:38:38 +00:00
|
|
|
SetLanguageMode(function_scope, language_mode);
|
|
|
|
if (uses_super_property) {
|
|
|
|
function_scope->RecordSuperPropertyUsage();
|
2017-03-13 16:16:52 +00:00
|
|
|
}
|
2017-06-30 10:38:38 +00:00
|
|
|
SkipFunctionLiterals(num_inner_functions);
|
2018-09-24 10:34:49 +00:00
|
|
|
function_scope->ResetAfterPreparsing(ast_value_factory_, false);
|
2018-09-24 14:09:43 +00:00
|
|
|
return true;
|
2017-03-13 16:16:52 +00:00
|
|
|
}
|
|
|
|
|
2018-09-24 14:09:43 +00:00
|
|
|
Scanner::BookmarkScope bookmark(scanner());
|
2018-12-18 15:54:28 +00:00
|
|
|
bookmark.Set(function_scope->start_position());
|
2018-09-24 14:09:43 +00:00
|
|
|
|
2019-04-08 16:06:25 +00:00
|
|
|
UnresolvedList::Iterator unresolved_private_tail;
|
2019-09-06 00:06:32 +00:00
|
|
|
PrivateNameScopeIterator private_name_scope_iter(function_scope);
|
|
|
|
if (!private_name_scope_iter.Done()) {
|
2019-04-08 16:06:25 +00:00
|
|
|
unresolved_private_tail =
|
2019-09-06 00:06:32 +00:00
|
|
|
private_name_scope_iter.GetScope()->GetUnresolvedPrivateNameTail();
|
2019-04-08 16:06:25 +00:00
|
|
|
}
|
|
|
|
|
2014-12-08 11:47:44 +00:00
|
|
|
// With no cached data, we partially parse the function, without building an
|
|
|
|
// AST. This gathers the data needed to build a lazy function.
|
2016-11-15 16:50:24 +00:00
|
|
|
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
|
|
|
|
|
2018-09-26 13:23:55 +00:00
|
|
|
PreParser::PreParseResult result = reusable_preparser()->PreParseFunction(
|
2019-08-23 02:28:45 +00:00
|
|
|
function_name, kind, function_syntax_kind, function_scope, use_counts_,
|
2020-04-22 10:45:31 +00:00
|
|
|
produced_preparse_data);
|
2018-09-24 10:34:49 +00:00
|
|
|
|
2014-12-08 11:47:44 +00:00
|
|
|
if (result == PreParser::kPreParseStackOverflow) {
|
|
|
|
// Propagate stack overflow.
|
|
|
|
set_stack_overflow();
|
2018-10-11 14:49:23 +00:00
|
|
|
} else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
|
2018-11-22 12:20:38 +00:00
|
|
|
// Make sure we don't re-preparse inner functions of the aborted function.
|
|
|
|
// The error might be in an inner function.
|
|
|
|
allow_lazy_ = false;
|
|
|
|
mode_ = PARSE_EAGERLY;
|
2018-10-29 14:47:36 +00:00
|
|
|
DCHECK(!pending_error_handler()->stack_overflow());
|
2018-09-28 08:14:08 +00:00
|
|
|
// If we encounter an error that the preparser can not identify we reset to
|
|
|
|
// the state before preparsing. The caller may then fully parse the function
|
|
|
|
// to identify the actual error.
|
|
|
|
bookmark.Apply();
|
2019-09-06 00:06:32 +00:00
|
|
|
if (!private_name_scope_iter.Done()) {
|
|
|
|
private_name_scope_iter.GetScope()->ResetUnresolvedPrivateNameTail(
|
2019-04-08 16:06:25 +00:00
|
|
|
unresolved_private_tail);
|
|
|
|
}
|
|
|
|
function_scope->ResetAfterPreparsing(ast_value_factory_, true);
|
2018-10-11 14:49:23 +00:00
|
|
|
pending_error_handler()->clear_unidentifiable_error();
|
2018-09-28 08:14:08 +00:00
|
|
|
return false;
|
2018-09-24 10:34:49 +00:00
|
|
|
} else if (pending_error_handler()->has_pending_error()) {
|
2018-10-29 14:47:36 +00:00
|
|
|
DCHECK(!pending_error_handler()->stack_overflow());
|
2018-10-31 12:01:43 +00:00
|
|
|
DCHECK(has_error());
|
2018-09-24 10:34:49 +00:00
|
|
|
} else {
|
2018-10-29 14:47:36 +00:00
|
|
|
DCHECK(!pending_error_handler()->stack_overflow());
|
2018-09-24 10:34:49 +00:00
|
|
|
set_allow_eval_cache(reusable_preparser()->allow_eval_cache());
|
2018-02-16 19:39:53 +00:00
|
|
|
|
2018-09-24 10:34:49 +00:00
|
|
|
PreParserLogger* logger = reusable_preparser()->logger();
|
|
|
|
function_scope->set_end_position(logger->end());
|
2018-10-25 07:14:19 +00:00
|
|
|
Expect(Token::RBRACE);
|
2018-09-24 10:34:49 +00:00
|
|
|
total_preparse_skipped_ +=
|
|
|
|
function_scope->end_position() - function_scope->start_position();
|
|
|
|
*num_parameters = logger->num_parameters();
|
2019-04-11 10:43:45 +00:00
|
|
|
*function_length = logger->function_length();
|
2018-09-24 10:34:49 +00:00
|
|
|
SkipFunctionLiterals(logger->num_inner_functions());
|
2019-09-06 00:06:32 +00:00
|
|
|
if (!private_name_scope_iter.Done()) {
|
|
|
|
private_name_scope_iter.GetScope()->MigrateUnresolvedPrivateNameTail(
|
2019-04-08 16:06:25 +00:00
|
|
|
factory(), unresolved_private_tail);
|
|
|
|
}
|
2019-09-09 16:48:01 +00:00
|
|
|
function_scope->AnalyzePartially(this, factory(), MaybeParsingArrowhead());
|
2018-09-24 10:34:49 +00:00
|
|
|
}
|
2018-02-16 19:39:53 +00:00
|
|
|
|
2018-09-24 14:09:43 +00:00
|
|
|
return true;
|
2014-04-15 08:29:24 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 14:15:53 +00:00
|
|
|
Block* Parser::BuildParameterInitializationBlock(
|
2018-10-25 07:14:19 +00:00
|
|
|
const ParserFormalParameters& parameters) {
|
2015-07-23 14:28:59 +00:00
|
|
|
DCHECK(!parameters.is_simple);
|
2016-07-19 10:06:38 +00:00
|
|
|
DCHECK(scope()->is_function_scope());
|
[parser] Skipping inner funcs: simplify rest parameter handling.
With the params (a, b, ...c) the param / variable declaration order used to be
"temp, temp, c, a, b". Now it is "temp, temp, a, b, c" as you'd expect. This
makes it easier for PreParser to match the parameter order of Parser.
R=verwaest@chromium.org
BUG=v8:5516
Change-Id: I79da04ef3f812bf52c032bed6263c009fecb7988
Reviewed-on: https://chromium-review.googlesource.com/447677
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43490}
2017-02-28 14:01:36 +00:00
|
|
|
DCHECK_EQ(scope(), parameters.scope);
|
2019-01-11 10:00:31 +00:00
|
|
|
ScopedPtrList<Statement> init_statements(pointer_buffer());
|
2016-11-28 11:23:38 +00:00
|
|
|
int index = 0;
|
|
|
|
for (auto parameter : parameters.params) {
|
2015-08-17 12:01:55 +00:00
|
|
|
Expression* initial_value =
|
2016-11-28 11:23:38 +00:00
|
|
|
factory()->NewVariableProxy(parameters.scope->parameter(index));
|
2018-10-17 09:37:12 +00:00
|
|
|
if (parameter->initializer() != nullptr) {
|
2015-08-17 12:01:55 +00:00
|
|
|
// IS_UNDEFINED($param) ? initializer : $param
|
2015-12-04 17:20:10 +00:00
|
|
|
|
2015-08-17 12:01:55 +00:00
|
|
|
auto condition = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT,
|
2016-11-28 11:23:38 +00:00
|
|
|
factory()->NewVariableProxy(parameters.scope->parameter(index)),
|
2016-06-30 09:26:30 +00:00
|
|
|
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
|
2018-10-17 09:37:12 +00:00
|
|
|
initial_value =
|
|
|
|
factory()->NewConditional(condition, parameter->initializer(),
|
|
|
|
initial_value, kNoSourcePosition);
|
2015-08-17 12:01:55 +00:00
|
|
|
}
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
|
2019-12-18 11:28:41 +00:00
|
|
|
BlockState block_state(&scope_, scope()->AsDeclarationScope());
|
2019-01-23 12:49:23 +00:00
|
|
|
DeclarationParsingResult::Declaration decl(parameter->pattern,
|
|
|
|
initial_value);
|
2019-12-18 11:28:41 +00:00
|
|
|
InitializeVariables(&init_statements, PARAMETER_VARIABLE, &decl);
|
2016-08-08 19:19:30 +00:00
|
|
|
|
2016-11-28 11:23:38 +00:00
|
|
|
++index;
|
2015-06-22 14:15:53 +00:00
|
|
|
}
|
2019-01-11 10:00:31 +00:00
|
|
|
return factory()->NewBlock(true, init_statements);
|
2015-06-22 14:15:53 +00:00
|
|
|
}
|
|
|
|
|
2017-09-07 12:05:46 +00:00
|
|
|
Scope* Parser::NewHiddenCatchScope() {
|
|
|
|
Scope* catch_scope = NewScopeWithParent(scope(), CATCH_SCOPE);
|
2019-01-21 12:30:41 +00:00
|
|
|
bool was_added;
|
2018-05-28 15:44:58 +00:00
|
|
|
catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(),
|
2019-01-21 12:30:41 +00:00
|
|
|
VariableMode::kVar, NORMAL_VARIABLE, &was_added);
|
|
|
|
DCHECK(was_added);
|
2017-03-02 14:14:43 +00:00
|
|
|
catch_scope->set_is_hidden();
|
|
|
|
return catch_scope;
|
|
|
|
}
|
|
|
|
|
2019-12-18 08:16:30 +00:00
|
|
|
Block* Parser::BuildRejectPromiseOnException(Block* inner_block,
|
|
|
|
REPLMode repl_mode) {
|
2016-08-26 22:17:52 +00:00
|
|
|
// try {
|
|
|
|
// <inner_block>
|
|
|
|
// } catch (.catch) {
|
2018-10-11 08:35:56 +00:00
|
|
|
// return %_AsyncFunctionReject(.generator_object, .catch, can_suspend);
|
2016-08-26 22:17:52 +00:00
|
|
|
// }
|
2018-10-11 08:35:56 +00:00
|
|
|
Block* result = factory()->NewBlock(1, true);
|
2016-08-26 22:17:52 +00:00
|
|
|
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
// catch (.catch) {
|
2018-10-11 08:35:56 +00:00
|
|
|
// return %_AsyncFunctionReject(.generator_object, .catch, can_suspend)
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
// }
|
2017-09-07 12:05:46 +00:00
|
|
|
Scope* catch_scope = NewHiddenCatchScope();
|
2016-05-17 00:26:53 +00:00
|
|
|
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
Expression* reject_promise;
|
2016-08-26 22:17:52 +00:00
|
|
|
{
|
2018-10-24 14:28:25 +00:00
|
|
|
ScopedPtrList<Expression> args(pointer_buffer());
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(factory()->NewVariableProxy(
|
|
|
|
function_state_->scope()->generator_object_var()));
|
|
|
|
args.Add(factory()->NewVariableProxy(catch_scope->catch_variable()));
|
|
|
|
args.Add(factory()->NewBooleanLiteral(function_state_->CanSuspend(),
|
|
|
|
kNoSourcePosition));
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
reject_promise = factory()->NewCallRuntime(
|
|
|
|
Runtime::kInlineAsyncFunctionReject, args, kNoSourcePosition);
|
2016-08-26 22:17:52 +00:00
|
|
|
}
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
Block* catch_block = IgnoreCompletion(
|
|
|
|
factory()->NewReturnStatement(reject_promise, kNoSourcePosition));
|
2016-05-17 00:26:53 +00:00
|
|
|
|
2019-12-18 08:16:30 +00:00
|
|
|
// Treat the exception for REPL mode scripts as UNCAUGHT. This will
|
|
|
|
// keep the corresponding JSMessageObject alive on the Isolate. The
|
|
|
|
// message object is used by the inspector to provide better error
|
|
|
|
// messages for REPL inputs that throw.
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
TryStatement* try_catch_statement =
|
2019-12-18 08:16:30 +00:00
|
|
|
repl_mode == REPLMode::kYes
|
|
|
|
? factory()->NewTryCatchStatementForReplAsyncAwait(
|
|
|
|
inner_block, catch_scope, catch_block, kNoSourcePosition)
|
|
|
|
: factory()->NewTryCatchStatementForAsyncAwait(
|
|
|
|
inner_block, catch_scope, catch_block, kNoSourcePosition);
|
[async] Improve async function handling.
This change introduces new intrinsics used to desugar async functions
in the Parser and the BytecodeGenerator, namely we introduce a new
%_AsyncFunctionEnter intrinsic that constructs the generator object
for the async function (and in the future will also create the outer
promise for the async function). This generator object is internal
and never escapes to user code, plus since async functions don't have
a "prototype" property, we can just a single map here instead of tracking
the prototype/initial_map on every async function. This saves one word
per async function plus one initial_map per async function that was
invoked at least once.
We also introduce two new intrinsics %_AsyncFunctionReject, which
rejects the outer promise with the caught exception, and another
%_AsyncFunctionResolve, which resolves the outer promise with the
right hand side of the `return` statement. These functions also perform
the DevTools part of the job (aka popping from the promise stack and
sending the debug event). This allows us to get rid of the implicit
try-finally from async functions completely; because the finally
block only called to the %AsyncFunctionPromiseRelease builtin, which
was used to inform DevTools.
In essence we now turn an async function like
```js
async function f(x) { return await bar(x); }
```
into something like this (in Parser and BytecodeGenerator respectively):
```
function f(x) {
.generator_object = %_AsyncFunctionEnter(.closure, this);
.promise = %AsyncFunctionCreatePromise();
try {
.tmp = await bar(x);
return %_AsyncFunctionResolve(.promise, .tmp);
} catch (e) {
return %_AsyncFunctionReject(.promise, e);
}
}
```
Overall the bytecode for async functions gets significantly shorter
already (and will get even shorter once we put the outer promise into
the async function generator object). For example the bytecode for a
simple async function
```js
async function f(x) { return await x; }
```
goes from 175 bytes to 110 bytes (a ~38% reduction in size), which
is in particular due to the simplification around the try-finally
removal.
Overall this seems to improve the doxbee-async-es2017-native test by
around 2-3%. On the test case mentioned in v8:8276 we go from
1124ms to 441ms, which corresponds to a 60% reduction in total
execution time!
Tbr: marja@chromium.org
Bug: v8:7253, v8:7522, v8:8276
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Id29dc92de7490b387ff697860c900cee44c9a7a4
Reviewed-on: https://chromium-review.googlesource.com/c/1269041
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56502}
2018-10-10 05:54:39 +00:00
|
|
|
result->statements()->Add(try_catch_statement, zone());
|
2016-08-26 22:17:52 +00:00
|
|
|
return result;
|
2016-05-17 00:26:53 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 07:53:43 +00:00
|
|
|
Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) {
|
2017-06-09 23:55:01 +00:00
|
|
|
Expression* yield_result = factory()->NewVariableProxy(
|
|
|
|
function_state_->scope()->generator_object_var());
|
2016-09-30 07:53:43 +00:00
|
|
|
// The position of the yield is important for reporting the exception
|
|
|
|
// caused by calling the .throw method on a generator suspended at the
|
|
|
|
// initial yield (i.e. right after generator instantiation).
|
2018-01-24 11:16:52 +00:00
|
|
|
function_state_->AddSuspend();
|
2017-07-14 15:20:23 +00:00
|
|
|
return factory()->NewYield(yield_result, scope()->start_position(),
|
|
|
|
Suspend::kOnExceptionThrow);
|
2016-09-30 07:53:43 +00:00
|
|
|
}
|
|
|
|
|
2018-11-05 15:20:49 +00:00
|
|
|
void Parser::ParseFunction(
|
|
|
|
ScopedPtrList<Statement>* body, const AstRawString* function_name, int pos,
|
2019-08-23 02:28:45 +00:00
|
|
|
FunctionKind kind, FunctionSyntaxKind function_syntax_kind,
|
2016-11-04 15:04:03 +00:00
|
|
|
DeclarationScope* function_scope, int* num_parameters, int* function_length,
|
2017-12-18 08:10:06 +00:00
|
|
|
bool* has_duplicate_parameters, int* expected_property_count,
|
2018-01-24 11:16:52 +00:00
|
|
|
int* suspend_count,
|
2018-10-25 07:14:19 +00:00
|
|
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
|
2020-04-02 12:26:18 +00:00
|
|
|
FunctionParsingScope function_parsing_scope(this);
|
2016-11-21 14:58:46 +00:00
|
|
|
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
|
|
|
|
|
2017-02-20 10:41:29 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, function_scope);
|
2016-11-04 15:04:03 +00:00
|
|
|
|
2019-08-23 02:28:45 +00:00
|
|
|
bool is_wrapped = function_syntax_kind == FunctionSyntaxKind::kWrapped;
|
2017-12-18 08:10:06 +00:00
|
|
|
|
Implement new Function.prototype.toString --harmony-function-tostring
For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
starts at the "function" or "async" keyword and ends at the final "}".
The previous behavior would start the excerpt at the "(" of the
parameter list, and prepend a canonical `"function " + name` or
similar, which would discard comments and formatting surrounding the
function's name. Anonymous functions declared as function expressions
no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
generator methods), or property name, whichever comes first.
Previously, the toString representation for methods would use a
canonical prefix before the "(" of the parameter list. Note that any
"static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.
For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
"\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
but that was removed from the spec, and so this CL does not do it.
Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.
BUG=v8:4958, v8:4230
Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
2017-02-16 20:19:24 +00:00
|
|
|
int expected_parameters_end_pos = parameters_end_pos_;
|
|
|
|
if (expected_parameters_end_pos != kNoSourcePosition) {
|
|
|
|
// This is the first function encountered in a CreateDynamicFunction eval.
|
|
|
|
parameters_end_pos_ = kNoSourcePosition;
|
2017-06-19 15:13:45 +00:00
|
|
|
// The function name should have been ignored, giving us the empty string
|
Implement new Function.prototype.toString --harmony-function-tostring
For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
starts at the "function" or "async" keyword and ends at the final "}".
The previous behavior would start the excerpt at the "(" of the
parameter list, and prepend a canonical `"function " + name` or
similar, which would discard comments and formatting surrounding the
function's name. Anonymous functions declared as function expressions
no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
generator methods), or property name, whichever comes first.
Previously, the toString representation for methods would use a
canonical prefix before the "(" of the parameter list. Note that any
"static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.
For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
"\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
but that was removed from the spec, and so this CL does not do it.
Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.
BUG=v8:4958, v8:4230
Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
2017-02-16 20:19:24 +00:00
|
|
|
// here.
|
2017-06-19 15:13:45 +00:00
|
|
|
DCHECK_EQ(function_name, ast_value_factory()->empty_string());
|
Implement new Function.prototype.toString --harmony-function-tostring
For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
starts at the "function" or "async" keyword and ends at the final "}".
The previous behavior would start the excerpt at the "(" of the
parameter list, and prepend a canonical `"function " + name` or
similar, which would discard comments and formatting surrounding the
function's name. Anonymous functions declared as function expressions
no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
generator methods), or property name, whichever comes first.
Previously, the toString representation for methods would use a
canonical prefix before the "(" of the parameter list. Note that any
"static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.
For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
"\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
but that was removed from the spec, and so this CL does not do it.
Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.
BUG=v8:4958, v8:4230
Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
2017-02-16 20:19:24 +00:00
|
|
|
}
|
|
|
|
|
2016-11-04 15:04:03 +00:00
|
|
|
ParserFormalParameters formals(function_scope);
|
2017-12-18 08:10:06 +00:00
|
|
|
|
2019-01-08 12:26:54 +00:00
|
|
|
{
|
|
|
|
ParameterDeclarationParsingScope formals_scope(this);
|
|
|
|
if (is_wrapped) {
|
|
|
|
// For a function implicitly wrapped in function header and footer, the
|
|
|
|
// function arguments are provided separately to the source, and are
|
|
|
|
// declared directly here.
|
2019-03-29 10:00:57 +00:00
|
|
|
for (const AstRawString* arg : *arguments_for_wrapped_function) {
|
2019-01-08 12:26:54 +00:00
|
|
|
const bool is_rest = false;
|
2019-03-29 10:00:57 +00:00
|
|
|
Expression* argument = ExpressionFromIdentifier(arg, kNoSourcePosition);
|
2019-01-08 12:26:54 +00:00
|
|
|
AddFormalParameter(&formals, argument, NullExpression(),
|
|
|
|
kNoSourcePosition, is_rest);
|
2017-12-18 08:10:06 +00:00
|
|
|
}
|
2019-03-29 10:00:57 +00:00
|
|
|
DCHECK_EQ(arguments_for_wrapped_function->length(),
|
|
|
|
formals.num_parameters());
|
2019-01-08 12:26:54 +00:00
|
|
|
DeclareFormalParameters(&formals);
|
|
|
|
} else {
|
|
|
|
// For a regular function, the function arguments are parsed from source.
|
|
|
|
DCHECK_NULL(arguments_for_wrapped_function);
|
|
|
|
ParseFormalParameterList(&formals);
|
|
|
|
if (expected_parameters_end_pos != kNoSourcePosition) {
|
|
|
|
// Check for '(' or ')' shenanigans in the parameter string for dynamic
|
|
|
|
// functions.
|
|
|
|
int position = peek_position();
|
|
|
|
if (position < expected_parameters_end_pos) {
|
|
|
|
ReportMessageAt(Scanner::Location(position, position + 1),
|
|
|
|
MessageTemplate::kArgStringTerminatesParametersEarly);
|
|
|
|
return;
|
|
|
|
} else if (position > expected_parameters_end_pos) {
|
|
|
|
ReportMessageAt(Scanner::Location(expected_parameters_end_pos - 2,
|
|
|
|
expected_parameters_end_pos),
|
|
|
|
MessageTemplate::kUnexpectedEndOfArgString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(Token::RPAREN);
|
|
|
|
int formals_end_position = scanner()->location().end_pos;
|
2017-12-18 08:10:06 +00:00
|
|
|
|
2019-01-08 12:26:54 +00:00
|
|
|
CheckArityRestrictions(formals.arity, kind, formals.has_rest,
|
|
|
|
function_scope->start_position(),
|
|
|
|
formals_end_position);
|
|
|
|
Expect(Token::LBRACE);
|
|
|
|
}
|
2019-01-21 09:47:58 +00:00
|
|
|
formals.duplicate_loc = formals_scope.duplicate_location();
|
Implement new Function.prototype.toString --harmony-function-tostring
For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
starts at the "function" or "async" keyword and ends at the final "}".
The previous behavior would start the excerpt at the "(" of the
parameter list, and prepend a canonical `"function " + name` or
similar, which would discard comments and formatting surrounding the
function's name. Anonymous functions declared as function expressions
no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
generator methods), or property name, whichever comes first.
Previously, the toString representation for methods would use a
canonical prefix before the "(" of the parameter list. Note that any
"static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.
For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
"\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
but that was removed from the spec, and so this CL does not do it.
Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.
BUG=v8:4958, v8:4230
Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
2017-02-16 20:19:24 +00:00
|
|
|
}
|
2019-01-08 12:26:54 +00:00
|
|
|
|
2016-11-04 15:04:03 +00:00
|
|
|
*num_parameters = formals.num_parameters();
|
|
|
|
*function_length = formals.function_length;
|
|
|
|
|
2018-11-09 15:19:17 +00:00
|
|
|
AcceptINScope scope(this, true);
|
2019-08-23 02:28:45 +00:00
|
|
|
ParseFunctionBody(body, function_name, pos, formals, kind,
|
|
|
|
function_syntax_kind, FunctionBodyType::kBlock);
|
2016-11-04 15:04:03 +00:00
|
|
|
|
2018-11-22 16:53:22 +00:00
|
|
|
*has_duplicate_parameters = formals.has_duplicate();
|
2016-11-04 15:04:03 +00:00
|
|
|
|
|
|
|
*expected_property_count = function_state.expected_property_count();
|
2018-01-24 11:16:52 +00:00
|
|
|
*suspend_count = function_state.suspend_count();
|
2016-11-04 15:04:03 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 14:33:02 +00:00
|
|
|
void Parser::DeclareClassVariable(ClassScope* scope, const AstRawString* name,
|
2018-10-25 07:14:19 +00:00
|
|
|
ClassInfo* class_info, int class_token_pos) {
|
2016-08-01 13:25:39 +00:00
|
|
|
#ifdef DEBUG
|
2019-10-10 14:33:02 +00:00
|
|
|
scope->SetScopeName(name);
|
2016-08-01 13:25:39 +00:00
|
|
|
#endif
|
2014-11-14 15:05:05 +00:00
|
|
|
|
2019-10-10 14:33:02 +00:00
|
|
|
DCHECK_IMPLIES(name == nullptr, class_info->is_anonymous);
|
|
|
|
// Declare a special class variable for anonymous classes with the dot
|
|
|
|
// if we need to save it for static private method access.
|
|
|
|
Variable* class_variable =
|
|
|
|
scope->DeclareClassVariable(ast_value_factory(), name, class_token_pos);
|
|
|
|
Declaration* declaration = factory()->NewVariableDeclaration(class_token_pos);
|
|
|
|
scope->declarations()->Add(declaration);
|
|
|
|
declaration->set_var(class_variable);
|
2016-09-28 13:42:20 +00:00
|
|
|
}
|
|
|
|
|
2017-11-08 00:13:52 +00:00
|
|
|
// TODO(gsathya): Ideally, this should just bypass scope analysis and
|
|
|
|
// allocate a slot directly on the context. We should just store this
|
|
|
|
// index in the AST, instead of storing the variable.
|
2018-10-25 07:14:19 +00:00
|
|
|
Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name) {
|
2018-12-21 10:21:01 +00:00
|
|
|
VariableProxy* proxy =
|
2019-01-24 17:00:48 +00:00
|
|
|
DeclareBoundVariable(name, VariableMode::kConst, kNoSourcePosition);
|
2018-12-21 10:21:01 +00:00
|
|
|
proxy->var()->ForceContextAllocation();
|
|
|
|
return proxy->var();
|
2017-11-08 00:13:52 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 12:34:09 +00:00
|
|
|
Variable* Parser::CreatePrivateNameVariable(ClassScope* scope,
|
|
|
|
VariableMode mode,
|
2019-09-11 10:56:40 +00:00
|
|
|
IsStaticFlag is_static_flag,
|
2019-07-30 12:34:09 +00:00
|
|
|
const AstRawString* name) {
|
2019-04-08 16:06:25 +00:00
|
|
|
DCHECK_NOT_NULL(name);
|
|
|
|
int begin = position();
|
|
|
|
int end = end_position();
|
|
|
|
bool was_added = false;
|
2019-07-30 12:34:09 +00:00
|
|
|
DCHECK(IsConstVariableMode(mode));
|
2019-09-11 10:56:40 +00:00
|
|
|
Variable* var =
|
|
|
|
scope->DeclarePrivateName(name, mode, is_static_flag, &was_added);
|
2019-04-08 16:06:25 +00:00
|
|
|
if (!was_added) {
|
|
|
|
Scanner::Location loc(begin, end);
|
|
|
|
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration, var->raw_name());
|
|
|
|
}
|
|
|
|
VariableProxy* proxy = factory()->NewVariableProxy(var, begin);
|
|
|
|
return proxy->var();
|
|
|
|
}
|
|
|
|
|
2019-05-13 19:39:54 +00:00
|
|
|
void Parser::DeclarePublicClassField(ClassScope* scope,
|
|
|
|
ClassLiteralProperty* property,
|
|
|
|
bool is_static, bool is_computed_name,
|
|
|
|
ClassInfo* class_info) {
|
2017-11-08 00:13:52 +00:00
|
|
|
if (is_static) {
|
2017-10-20 21:00:43 +00:00
|
|
|
class_info->static_fields->Add(property, zone());
|
|
|
|
} else {
|
2017-11-08 00:13:52 +00:00
|
|
|
class_info->instance_fields->Add(property, zone());
|
|
|
|
}
|
|
|
|
|
2017-11-27 13:47:40 +00:00
|
|
|
if (is_computed_name) {
|
2017-11-08 00:13:52 +00:00
|
|
|
// We create a synthetic variable name here so that scope
|
|
|
|
// analysis doesn't dedupe the vars.
|
2018-10-25 07:14:19 +00:00
|
|
|
Variable* computed_name_var =
|
|
|
|
CreateSyntheticContextVariable(ClassFieldVariableName(
|
|
|
|
ast_value_factory(), class_info->computed_field_count));
|
2017-11-08 00:13:52 +00:00
|
|
|
property->set_computed_name_var(computed_name_var);
|
2019-10-10 19:00:28 +00:00
|
|
|
class_info->public_members->Add(property, zone());
|
2019-05-13 19:39:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::DeclarePrivateClassMember(ClassScope* scope,
|
|
|
|
const AstRawString* property_name,
|
|
|
|
ClassLiteralProperty* property,
|
|
|
|
ClassLiteralProperty::Kind kind,
|
|
|
|
bool is_static, ClassInfo* class_info) {
|
|
|
|
if (kind == ClassLiteralProperty::Kind::FIELD) {
|
|
|
|
if (is_static) {
|
|
|
|
class_info->static_fields->Add(property, zone());
|
|
|
|
} else {
|
|
|
|
class_info->instance_fields->Add(property, zone());
|
2019-04-08 16:06:25 +00:00
|
|
|
}
|
2018-01-29 18:11:24 +00:00
|
|
|
}
|
2019-05-13 19:39:54 +00:00
|
|
|
|
2019-09-11 10:56:40 +00:00
|
|
|
Variable* private_name_var = CreatePrivateNameVariable(
|
|
|
|
scope, GetVariableMode(kind),
|
|
|
|
is_static ? IsStaticFlag::kStatic : IsStaticFlag::kNotStatic,
|
|
|
|
property_name);
|
2019-05-13 19:39:54 +00:00
|
|
|
int pos = property->value()->position();
|
|
|
|
if (pos == kNoSourcePosition) {
|
|
|
|
pos = property->key()->position();
|
|
|
|
}
|
|
|
|
private_name_var->set_initializer_position(pos);
|
|
|
|
property->set_private_name_var(private_name_var);
|
2019-10-10 19:00:28 +00:00
|
|
|
class_info->private_members->Add(property, zone());
|
2016-09-28 13:42:20 +00:00
|
|
|
}
|
|
|
|
|
2019-01-08 01:09:40 +00:00
|
|
|
// This method declares a property of the given class. It updates the
|
|
|
|
// following fields of class_info, as appropriate:
|
|
|
|
// - constructor
|
|
|
|
// - properties
|
2019-05-13 19:39:54 +00:00
|
|
|
void Parser::DeclarePublicClassMethod(const AstRawString* class_name,
|
|
|
|
ClassLiteralProperty* property,
|
|
|
|
bool is_constructor,
|
|
|
|
ClassInfo* class_info) {
|
2019-01-08 01:09:40 +00:00
|
|
|
if (is_constructor) {
|
|
|
|
DCHECK(!class_info->constructor);
|
|
|
|
class_info->constructor = property->value()->AsFunctionLiteral();
|
|
|
|
DCHECK_NOT_NULL(class_info->constructor);
|
|
|
|
class_info->constructor->set_raw_name(
|
|
|
|
class_name != nullptr ? ast_value_factory()->NewConsString(class_name)
|
|
|
|
: nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-10 19:00:28 +00:00
|
|
|
class_info->public_members->Add(property, zone());
|
2019-01-08 01:09:40 +00:00
|
|
|
}
|
|
|
|
|
2017-11-08 00:13:52 +00:00
|
|
|
FunctionLiteral* Parser::CreateInitializerFunction(
|
2018-09-07 18:00:58 +00:00
|
|
|
const char* name, DeclarationScope* scope,
|
|
|
|
ZonePtrList<ClassLiteral::Property>* fields) {
|
2018-01-04 22:36:27 +00:00
|
|
|
DCHECK_EQ(scope->function_kind(),
|
2018-11-06 12:06:39 +00:00
|
|
|
FunctionKind::kClassMembersInitializerFunction);
|
2017-11-08 00:13:52 +00:00
|
|
|
// function() { .. class fields initializer .. }
|
2018-11-05 15:20:49 +00:00
|
|
|
ScopedPtrList<Statement> statements(pointer_buffer());
|
2019-05-13 19:39:54 +00:00
|
|
|
InitializeClassMembersStatement* stmt =
|
2018-11-06 12:06:39 +00:00
|
|
|
factory()->NewInitializeClassMembersStatement(fields, kNoSourcePosition);
|
2019-05-13 19:39:54 +00:00
|
|
|
statements.Add(stmt);
|
2019-05-16 11:56:18 +00:00
|
|
|
FunctionLiteral* result = factory()->NewFunctionLiteral(
|
2018-09-07 18:00:58 +00:00
|
|
|
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
|
2017-11-08 00:13:52 +00:00
|
|
|
FunctionLiteral::kNoDuplicateParameters,
|
2019-08-23 02:28:45 +00:00
|
|
|
FunctionSyntaxKind::kAccessorOrMethod,
|
2018-09-17 21:46:39 +00:00
|
|
|
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
|
2017-11-08 00:13:52 +00:00
|
|
|
GetNextFunctionLiteralId());
|
2019-05-16 11:56:18 +00:00
|
|
|
|
|
|
|
RecordFunctionLiteralSourceRange(result);
|
|
|
|
|
|
|
|
return result;
|
2017-11-08 00:13:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-04 17:00:44 +00:00
|
|
|
// This method generates a ClassLiteral AST node.
|
2016-09-28 13:42:20 +00:00
|
|
|
// It uses the following fields of class_info:
|
|
|
|
// - constructor (if missing, it updates it with a default constructor)
|
|
|
|
// - proxy
|
|
|
|
// - extends
|
|
|
|
// - properties
|
2016-12-07 10:34:15 +00:00
|
|
|
// - has_name_static_property
|
|
|
|
// - has_static_computed_names
|
2019-04-08 16:06:25 +00:00
|
|
|
Expression* Parser::RewriteClassLiteral(ClassScope* block_scope,
|
2017-05-04 17:00:44 +00:00
|
|
|
const AstRawString* name,
|
2016-09-28 13:42:20 +00:00
|
|
|
ClassInfo* class_info, int pos,
|
2018-10-25 07:14:19 +00:00
|
|
|
int end_pos) {
|
2017-05-04 17:00:44 +00:00
|
|
|
DCHECK_NOT_NULL(block_scope);
|
2019-04-08 16:06:25 +00:00
|
|
|
DCHECK_EQ(block_scope->scope_type(), CLASS_SCOPE);
|
2017-10-16 10:55:06 +00:00
|
|
|
DCHECK_EQ(block_scope->language_mode(), LanguageMode::kStrict);
|
2014-11-14 15:05:05 +00:00
|
|
|
|
2016-09-28 13:42:20 +00:00
|
|
|
bool has_extends = class_info->extends != nullptr;
|
|
|
|
bool has_default_constructor = class_info->constructor == nullptr;
|
2016-09-16 00:42:30 +00:00
|
|
|
if (has_default_constructor) {
|
2016-12-29 22:12:51 +00:00
|
|
|
class_info->constructor =
|
|
|
|
DefaultConstructor(name, has_extends, pos, end_pos);
|
2014-11-14 15:05:05 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 09:04:13 +00:00
|
|
|
if (name != nullptr) {
|
2019-10-10 14:33:02 +00:00
|
|
|
DCHECK_NOT_NULL(block_scope->class_variable());
|
|
|
|
block_scope->class_variable()->set_initializer_position(end_pos);
|
2014-11-14 15:05:05 +00:00
|
|
|
}
|
|
|
|
|
2017-10-25 21:38:06 +00:00
|
|
|
FunctionLiteral* static_fields_initializer = nullptr;
|
|
|
|
if (class_info->has_static_class_fields) {
|
2017-11-08 00:13:52 +00:00
|
|
|
static_fields_initializer = CreateInitializerFunction(
|
2018-09-07 18:00:58 +00:00
|
|
|
"<static_fields_initializer>", class_info->static_fields_scope,
|
|
|
|
class_info->static_fields);
|
2017-11-08 00:13:52 +00:00
|
|
|
}
|
|
|
|
|
2018-11-06 12:06:39 +00:00
|
|
|
FunctionLiteral* instance_members_initializer_function = nullptr;
|
|
|
|
if (class_info->has_instance_members) {
|
|
|
|
instance_members_initializer_function = CreateInitializerFunction(
|
|
|
|
"<instance_members_initializer>", class_info->instance_members_scope,
|
2018-09-07 18:00:58 +00:00
|
|
|
class_info->instance_fields);
|
2018-11-06 12:06:39 +00:00
|
|
|
class_info->constructor->set_requires_instance_members_initializer(true);
|
2019-04-15 23:27:56 +00:00
|
|
|
class_info->constructor->add_expected_properties(
|
|
|
|
class_info->instance_fields->length());
|
2017-10-25 21:38:06 +00:00
|
|
|
}
|
|
|
|
|
2020-03-03 18:23:03 +00:00
|
|
|
if (class_info->requires_brand) {
|
|
|
|
class_info->constructor->set_class_scope_has_private_brand(true);
|
|
|
|
}
|
2020-03-06 14:44:50 +00:00
|
|
|
if (class_info->has_static_private_methods) {
|
|
|
|
class_info->constructor->set_has_static_private_methods_or_accessors(true);
|
|
|
|
}
|
2016-07-25 19:16:21 +00:00
|
|
|
ClassLiteral* class_literal = factory()->NewClassLiteral(
|
2019-10-10 14:33:02 +00:00
|
|
|
block_scope, class_info->extends, class_info->constructor,
|
2019-10-10 19:00:28 +00:00
|
|
|
class_info->public_members, class_info->private_members,
|
|
|
|
static_fields_initializer, instance_members_initializer_function, pos,
|
|
|
|
end_pos, class_info->has_name_static_property,
|
|
|
|
class_info->has_static_computed_names, class_info->is_anonymous,
|
|
|
|
class_info->has_private_methods);
|
2016-07-25 19:16:21 +00:00
|
|
|
|
2016-11-15 21:57:25 +00:00
|
|
|
AddFunctionForNameInference(class_info->constructor);
|
2017-10-25 21:38:06 +00:00
|
|
|
return class_literal;
|
2014-11-14 15:05:05 +00:00
|
|
|
}
|
|
|
|
|
2015-10-01 10:42:23 +00:00
|
|
|
void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) {
|
|
|
|
// For each var-binding that shadows a parameter, insert an assignment
|
|
|
|
// initializing the variable with the parameter.
|
|
|
|
Scope* inner_scope = inner_block->scope();
|
|
|
|
DCHECK(inner_scope->is_declaration_scope());
|
|
|
|
Scope* function_scope = inner_scope->outer_scope();
|
|
|
|
DCHECK(function_scope->is_function_scope());
|
2017-02-20 10:41:29 +00:00
|
|
|
BlockState block_state(&scope_, inner_scope);
|
2016-11-02 14:08:33 +00:00
|
|
|
for (Declaration* decl : *inner_scope->declarations()) {
|
2019-01-15 15:04:30 +00:00
|
|
|
if (decl->var()->mode() != VariableMode::kVar ||
|
2018-05-28 15:44:58 +00:00
|
|
|
!decl->IsVariableDeclaration()) {
|
2016-08-10 08:10:18 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-01-15 15:04:30 +00:00
|
|
|
const AstRawString* name = decl->var()->raw_name();
|
2015-10-01 10:42:23 +00:00
|
|
|
Variable* parameter = function_scope->LookupLocal(name);
|
|
|
|
if (parameter == nullptr) continue;
|
2016-08-11 12:04:02 +00:00
|
|
|
VariableProxy* to = NewUnresolved(name);
|
2015-10-01 10:42:23 +00:00
|
|
|
VariableProxy* from = factory()->NewVariableProxy(parameter);
|
2016-06-30 09:26:30 +00:00
|
|
|
Expression* assignment =
|
|
|
|
factory()->NewAssignment(Token::ASSIGN, to, from, kNoSourcePosition);
|
|
|
|
Statement* statement =
|
|
|
|
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
|
2015-10-01 10:42:23 +00:00
|
|
|
inner_block->statements()->InsertAt(0, statement, zone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-15 16:41:03 +00:00
|
|
|
void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
|
|
|
|
// For the outermost eval scope, we cannot hoist during parsing: let
|
|
|
|
// declarations in the surrounding scope may prevent hoisting, but the
|
|
|
|
// information is unaccessible during parsing. In this case, we hoist later in
|
|
|
|
// DeclarationScope::Analyze.
|
|
|
|
if (scope->is_eval_scope() && scope->outer_scope() == original_scope_) {
|
|
|
|
return;
|
2015-09-21 04:30:50 +00:00
|
|
|
}
|
2016-09-15 16:41:03 +00:00
|
|
|
scope->HoistSloppyBlockFunctions(factory());
|
2015-09-21 04:30:50 +00:00
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Parser support
|
|
|
|
|
[offthread] Allow off-thread bytecode finalization
Add the remaining missing templatizations to allow an initial wiring in
of the off-thread factory into streaming compilation finalization.
The off-thread finalization is behind a flag, disabled by default:
--finalize-streaming-on-background
When the flag is enabled, background tasks will perform perform the
finalization during their background execution, and will release the
parser and compilation jobs once they are no longer needed.
The implementation is complete enough for performance testing, but not
enough for launch. Notably, there is no support for:
* Class boilerplates (the code is marked unreachable),
* Exceptions during finalization, i.e. parse/compile warnings/errors,
* Allocation sampling,
* Logging,
* Asm.js,
* Parallel complication tasks
* Forced source positions (for "NeedsDetailedOptimizedCodeLineInfo()")
This patch also adds some tracing events for the various stages of the
off-thread finalization (including the main-thread merge) for further
performance improvements.
Bug: chromium:1011762
Change-Id: Ia44fa56975dd689f0d92c1543b294cdb063eb199
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2066965
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66566}
2020-03-03 13:49:06 +00:00
|
|
|
template <typename LocalIsolate>
|
|
|
|
void Parser::HandleSourceURLComments(LocalIsolate* isolate,
|
|
|
|
Handle<Script> script) {
|
2016-08-10 08:40:24 +00:00
|
|
|
Handle<String> source_url = scanner_.SourceUrl(isolate);
|
|
|
|
if (!source_url.is_null()) {
|
2015-02-20 09:39:32 +00:00
|
|
|
script->set_source_url(*source_url);
|
2014-07-02 07:01:31 +00:00
|
|
|
}
|
2016-08-10 08:40:24 +00:00
|
|
|
Handle<String> source_mapping_url = scanner_.SourceMappingUrl(isolate);
|
|
|
|
if (!source_mapping_url.is_null()) {
|
2015-02-20 09:39:32 +00:00
|
|
|
script->set_source_mapping_url(*source_mapping_url);
|
2014-07-02 07:01:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[offthread] Allow off-thread bytecode finalization
Add the remaining missing templatizations to allow an initial wiring in
of the off-thread factory into streaming compilation finalization.
The off-thread finalization is behind a flag, disabled by default:
--finalize-streaming-on-background
When the flag is enabled, background tasks will perform perform the
finalization during their background execution, and will release the
parser and compilation jobs once they are no longer needed.
The implementation is complete enough for performance testing, but not
enough for launch. Notably, there is no support for:
* Class boilerplates (the code is marked unreachable),
* Exceptions during finalization, i.e. parse/compile warnings/errors,
* Allocation sampling,
* Logging,
* Asm.js,
* Parallel complication tasks
* Forced source positions (for "NeedsDetailedOptimizedCodeLineInfo()")
This patch also adds some tracing events for the various stages of the
off-thread finalization (including the main-thread merge) for further
performance improvements.
Bug: chromium:1011762
Change-Id: Ia44fa56975dd689f0d92c1543b294cdb063eb199
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2066965
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66566}
2020-03-03 13:49:06 +00:00
|
|
|
template void Parser::HandleSourceURLComments(Isolate* isolate,
|
|
|
|
Handle<Script> script);
|
2020-08-13 12:12:17 +00:00
|
|
|
template void Parser::HandleSourceURLComments(LocalIsolate* isolate,
|
[offthread] Allow off-thread bytecode finalization
Add the remaining missing templatizations to allow an initial wiring in
of the off-thread factory into streaming compilation finalization.
The off-thread finalization is behind a flag, disabled by default:
--finalize-streaming-on-background
When the flag is enabled, background tasks will perform perform the
finalization during their background execution, and will release the
parser and compilation jobs once they are no longer needed.
The implementation is complete enough for performance testing, but not
enough for launch. Notably, there is no support for:
* Class boilerplates (the code is marked unreachable),
* Exceptions during finalization, i.e. parse/compile warnings/errors,
* Allocation sampling,
* Logging,
* Asm.js,
* Parallel complication tasks
* Forced source positions (for "NeedsDetailedOptimizedCodeLineInfo()")
This patch also adds some tracing events for the various stages of the
off-thread finalization (including the main-thread merge) for further
performance improvements.
Bug: chromium:1011762
Change-Id: Ia44fa56975dd689f0d92c1543b294cdb063eb199
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2066965
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66566}
2020-03-03 13:49:06 +00:00
|
|
|
Handle<Script> script);
|
|
|
|
|
2017-02-10 15:01:29 +00:00
|
|
|
void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) {
|
2020-08-03 13:01:17 +00:00
|
|
|
CHECK_NOT_NULL(isolate);
|
|
|
|
|
2014-09-02 11:36:21 +00:00
|
|
|
// Move statistics to Isolate.
|
2014-06-30 13:35:16 +00:00
|
|
|
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
|
|
|
++feature) {
|
2016-06-14 21:39:36 +00:00
|
|
|
if (use_counts_[feature] > 0) {
|
2015-02-20 09:39:32 +00:00
|
|
|
isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
|
2014-06-30 13:35:16 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-27 18:18:25 +00:00
|
|
|
if (scanner_.FoundHtmlComment()) {
|
|
|
|
isolate->CountUsage(v8::Isolate::kHtmlComment);
|
|
|
|
if (script->line_offset() == 0 && script->column_offset() == 0) {
|
|
|
|
isolate->CountUsage(v8::Isolate::kHtmlCommentInExternalScript);
|
|
|
|
}
|
|
|
|
}
|
2015-02-20 09:39:32 +00:00
|
|
|
isolate->counters()->total_preparse_skipped()->Increment(
|
2014-09-02 11:36:21 +00:00
|
|
|
total_preparse_skipped_);
|
2014-06-30 13:35:16 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 10:45:31 +00:00
|
|
|
void Parser::ParseOnBackground(ParseInfo* info, int start_position,
|
|
|
|
int end_position, int function_literal_id) {
|
2017-11-29 15:50:22 +00:00
|
|
|
RuntimeCallTimerScope runtimeTimer(
|
|
|
|
runtime_call_stats_, RuntimeCallCounterId::kParseBackgroundProgram);
|
2015-02-12 13:02:30 +00:00
|
|
|
parsing_on_main_thread_ = false;
|
|
|
|
|
2017-10-16 13:41:49 +00:00
|
|
|
DCHECK_NULL(info->literal());
|
2017-10-13 16:33:03 +00:00
|
|
|
FunctionLiteral* result = nullptr;
|
2014-09-12 09:12:08 +00:00
|
|
|
|
2018-08-21 11:55:12 +00:00
|
|
|
scanner_.Initialize();
|
2014-09-12 09:12:08 +00:00
|
|
|
|
2016-08-03 13:30:23 +00:00
|
|
|
DCHECK(original_scope_);
|
|
|
|
|
2014-09-12 09:12:08 +00:00
|
|
|
// When streaming, we don't know the length of the source until we have parsed
|
|
|
|
// it. The raw data can be UTF-8, so we wouldn't know the source length until
|
|
|
|
// we have decoded it anyway even if we knew the raw data length (which we
|
|
|
|
// don't). We work around this by storing all the scopes which need their end
|
|
|
|
// position set at the end of the script (the top scope and possible eval
|
|
|
|
// scopes) and set their end position after we know the script length.
|
2020-04-22 10:45:31 +00:00
|
|
|
if (flags().is_toplevel()) {
|
|
|
|
DCHECK_EQ(start_position, 0);
|
|
|
|
DCHECK_EQ(end_position, 0);
|
|
|
|
DCHECK_EQ(function_literal_id, kFunctionLiteralIdTopLevel);
|
2018-06-19 08:30:34 +00:00
|
|
|
result = DoParseProgram(/* isolate = */ nullptr, info);
|
2016-10-11 10:36:56 +00:00
|
|
|
} else {
|
2020-04-22 10:45:31 +00:00
|
|
|
result = DoParseFunction(/* isolate = */ nullptr, info, start_position,
|
|
|
|
end_position, function_literal_id,
|
|
|
|
info->function_name());
|
2016-08-05 13:18:42 +00:00
|
|
|
}
|
2017-08-22 10:53:10 +00:00
|
|
|
MaybeResetCharacterStream(info, result);
|
2020-03-25 17:09:17 +00:00
|
|
|
MaybeProcessSourceRanges(info, result, stack_limit_);
|
2020-05-05 16:27:30 +00:00
|
|
|
PostProcessParseResult(/* isolate = */ nullptr, info, result);
|
2014-09-12 09:12:08 +00:00
|
|
|
}
|
2014-11-14 18:53:41 +00:00
|
|
|
|
2016-08-23 16:34:39 +00:00
|
|
|
Parser::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) {
|
2020-07-12 13:27:55 +00:00
|
|
|
return zone()->New<TemplateLiteral>(zone(), pos);
|
2014-11-14 18:53:41 +00:00
|
|
|
}
|
|
|
|
|
2017-02-22 21:20:32 +00:00
|
|
|
void Parser::AddTemplateSpan(TemplateLiteralState* state, bool should_cook,
|
|
|
|
bool tail) {
|
2014-11-14 18:53:41 +00:00
|
|
|
int end = scanner()->location().end_pos - (tail ? 1 : 2);
|
2017-10-24 20:43:22 +00:00
|
|
|
const AstRawString* raw = scanner()->CurrentRawSymbol(ast_value_factory());
|
2017-02-22 21:20:32 +00:00
|
|
|
if (should_cook) {
|
2017-10-24 20:43:22 +00:00
|
|
|
const AstRawString* cooked = scanner()->CurrentSymbol(ast_value_factory());
|
2017-02-22 21:20:32 +00:00
|
|
|
(*state)->AddTemplateSpan(cooked, raw, end, zone());
|
|
|
|
} else {
|
2017-10-24 20:43:22 +00:00
|
|
|
(*state)->AddTemplateSpan(nullptr, raw, end, zone());
|
2017-02-22 21:20:32 +00:00
|
|
|
}
|
2014-11-14 18:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::AddTemplateExpression(TemplateLiteralState* state,
|
|
|
|
Expression* expression) {
|
|
|
|
(*state)->AddExpression(expression, zone());
|
|
|
|
}
|
|
|
|
|
|
|
|
Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
|
|
|
|
Expression* tag) {
|
|
|
|
TemplateLiteral* lit = *state;
|
|
|
|
int pos = lit->position();
|
2018-07-03 14:44:16 +00:00
|
|
|
const ZonePtrList<const AstRawString>* cooked_strings = lit->cooked();
|
|
|
|
const ZonePtrList<const AstRawString>* raw_strings = lit->raw();
|
|
|
|
const ZonePtrList<Expression>* expressions = lit->expressions();
|
2014-12-03 14:17:16 +00:00
|
|
|
DCHECK_EQ(cooked_strings->length(), raw_strings->length());
|
|
|
|
DCHECK_EQ(cooked_strings->length(), expressions->length() + 1);
|
2014-11-14 18:53:41 +00:00
|
|
|
|
|
|
|
if (!tag) {
|
2018-03-10 17:27:18 +00:00
|
|
|
if (cooked_strings->length() == 1) {
|
|
|
|
return factory()->NewStringLiteral(cooked_strings->first(), pos);
|
2014-11-14 18:53:41 +00:00
|
|
|
}
|
2018-03-10 17:27:18 +00:00
|
|
|
return factory()->NewTemplateLiteral(cooked_strings, expressions, pos);
|
2014-11-14 18:53:41 +00:00
|
|
|
} else {
|
2017-09-22 09:57:29 +00:00
|
|
|
// GetTemplateObject
|
2017-10-24 20:43:22 +00:00
|
|
|
Expression* template_object =
|
[esnext] implement spec change to TaggedTemplate callsite caching
Implements the change outlined in https://github.com/tc39/ecma262/pull/890,
which has been ratified and pulled into the specification. In particular,
template callsite objects are no longer kept in a global, eternal Map, but
are instead associated with their callsite, which can be collected. This
prevents a memory leak incurred by TaggedTemplate calls.
Changes, summarized:
- Remove the TemplateMap and TemplateMapShape objects, instead caching
template objects in the feedback vector.
- Remove the `hash` member of TemplateObjectDescriptor, and the Equals
method (used by TemplateMap)
- Add a new FeedbackSlotKind (kTemplateObject), which behaves similarly
to FeedbackSlotKind::kLiteral, but prevents eval caching. This ensures
that a new feedback vector is always created for eval() containing tagged
templates, even when the CompilationCache is used.
- GetTemplateObject bytecode now takes a feedback index, and only calls
into the runtime if the feedback is Smi::kZero (uninitialized).
BUG=v8:3230, v8:2891
R=littledan@chromium.org, yangguo@chromium.org, bmeurer@chromium.org,
rmcilroy@chromium.org
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I7827bc148d3d93e2b056ebf63dd624da196ad423
Reviewed-on: https://chromium-review.googlesource.com/624564
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51248}
2018-02-12 16:27:02 +00:00
|
|
|
factory()->NewGetTemplateObject(cooked_strings, raw_strings, pos);
|
2014-11-14 18:53:41 +00:00
|
|
|
|
|
|
|
// Call TagFn
|
2018-10-24 14:28:25 +00:00
|
|
|
ScopedPtrList<Expression> call_args(pointer_buffer());
|
2018-10-24 12:02:06 +00:00
|
|
|
call_args.Add(template_object);
|
2020-07-10 18:20:11 +00:00
|
|
|
call_args.AddAll(expressions->ToConstVector());
|
2017-10-12 12:46:04 +00:00
|
|
|
return factory()->NewTaggedTemplate(tag, call_args, pos);
|
2014-11-14 18:53:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-22 09:57:29 +00:00
|
|
|
namespace {
|
|
|
|
|
2018-10-24 12:02:06 +00:00
|
|
|
bool OnlyLastArgIsSpread(const ScopedPtrList<Expression>& args) {
|
|
|
|
for (int i = 0; i < args.length() - 1; i++) {
|
|
|
|
if (args.at(i)->IsSpread()) {
|
2017-01-23 09:03:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2018-10-24 12:02:06 +00:00
|
|
|
return args.at(args.length() - 1)->IsSpread();
|
2017-01-23 09:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
ArrayLiteral* Parser::ArrayLiteralFromListWithSpread(
|
2018-10-24 12:02:06 +00:00
|
|
|
const ScopedPtrList<Expression>& list) {
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
// If there's only a single spread argument, a fast path using CallWithSpread
|
|
|
|
// is taken.
|
2018-10-24 12:02:06 +00:00
|
|
|
DCHECK_LT(1, list.length());
|
2018-03-01 19:06:38 +00:00
|
|
|
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
// The arguments of the spread call become a single ArrayLiteral.
|
|
|
|
int first_spread = 0;
|
2018-10-24 12:02:06 +00:00
|
|
|
for (; first_spread < list.length() && !list.at(first_spread)->IsSpread();
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
++first_spread) {
|
2018-03-02 09:29:25 +00:00
|
|
|
}
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
|
2018-10-24 12:02:06 +00:00
|
|
|
DCHECK_LT(first_spread, list.length());
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
return factory()->NewArrayLiteral(list, first_spread, kNoSourcePosition);
|
2015-04-09 19:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expression* Parser::SpreadCall(Expression* function,
|
2018-10-24 12:02:06 +00:00
|
|
|
const ScopedPtrList<Expression>& args_list,
|
2019-08-07 20:52:23 +00:00
|
|
|
int pos, Call::PossiblyEval is_possibly_eval,
|
|
|
|
bool optional_chain) {
|
2017-07-13 18:06:15 +00:00
|
|
|
// Handle this case in BytecodeGenerator.
|
2018-04-13 13:14:27 +00:00
|
|
|
if (OnlyLastArgIsSpread(args_list) || function->IsSuperCallReference()) {
|
2019-08-07 20:52:23 +00:00
|
|
|
return factory()->NewCall(function, args_list, pos, Call::NOT_EVAL,
|
|
|
|
optional_chain);
|
2017-01-23 09:03:35 +00:00
|
|
|
}
|
|
|
|
|
2018-10-24 14:28:25 +00:00
|
|
|
ScopedPtrList<Expression> args(pointer_buffer());
|
2018-04-13 13:14:27 +00:00
|
|
|
if (function->IsProperty()) {
|
|
|
|
// Method calls
|
|
|
|
if (function->AsProperty()->IsSuperAccess()) {
|
2019-02-06 10:52:07 +00:00
|
|
|
Expression* home = ThisExpression();
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(function);
|
|
|
|
args.Add(home);
|
2015-04-09 19:37:14 +00:00
|
|
|
} else {
|
2018-04-13 13:14:27 +00:00
|
|
|
Variable* temp = NewTemporary(ast_value_factory()->empty_string());
|
|
|
|
VariableProxy* obj = factory()->NewVariableProxy(temp);
|
|
|
|
Assignment* assign_obj = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, obj, function->AsProperty()->obj(), kNoSourcePosition);
|
2019-08-07 20:52:23 +00:00
|
|
|
function =
|
|
|
|
factory()->NewProperty(assign_obj, function->AsProperty()->key(),
|
|
|
|
kNoSourcePosition, optional_chain);
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(function);
|
2018-04-13 13:14:27 +00:00
|
|
|
obj = factory()->NewVariableProxy(temp);
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(obj);
|
2015-04-09 19:37:14 +00:00
|
|
|
}
|
2018-04-13 13:14:27 +00:00
|
|
|
} else {
|
|
|
|
// Non-method calls
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(function);
|
|
|
|
args.Add(factory()->NewUndefinedLiteral(kNoSourcePosition));
|
2015-04-09 19:37:14 +00:00
|
|
|
}
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(ArrayLiteralFromListWithSpread(args_list));
|
2018-04-13 13:14:27 +00:00
|
|
|
return factory()->NewCallRuntime(Context::REFLECT_APPLY_INDEX, args, pos);
|
2015-04-09 19:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expression* Parser::SpreadCallNew(Expression* function,
|
2018-10-24 12:02:06 +00:00
|
|
|
const ScopedPtrList<Expression>& args_list,
|
|
|
|
int pos) {
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
if (OnlyLastArgIsSpread(args_list)) {
|
2017-01-23 09:03:35 +00:00
|
|
|
// Handle in BytecodeGenerator.
|
Reland "[parsing] inline ArrayLiteral creation for spread calls"
This reverts commit f48e7349035430ea13dd0ce1ed1e775f6eecabeb.
Reason for revert: innocent!!
Original change's description:
> Revert "[parsing] inline ArrayLiteral creation for spread calls"
>
> This reverts commit 93fc3841c3da0fc85662e66a57d881555238d634.
>
> Reason for revert: may break node.js integration
>
> Original change's description:
> > [parsing] inline ArrayLiteral creation for spread calls
> >
> > Instead of using runtime calls to generate the Array Literal passed to
> > %reflect_call / %reflect_construct, we create an ArrayLiteral from the
> > list of arguments, and perform spreads using the interpreter mechanism for
> > spreading in ArrayLiterals (thus, the spreading becomes inline). This
> > array literal is still passed to %reflect_call / %reflect_construct as
> > before.
> >
> > This cuts the runtime for bench-spread-call.js -> testSpread roughly in
> > half, and will likely improve further once
> > https://chromium-review.googlesource.com/c/v8/v8/+/915364 has landed.
> >
> > BUG=v8:7446
> > R=neis@chromium.org, adamk@chromium.org
> >
> > Change-Id: I74a6acd3a60aad422e4ac575275c7b567659d8ad
> > Reviewed-on: https://chromium-review.googlesource.com/939587
> > Commit-Queue: Georg Neis <neis@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#51678}
>
> TBR=adamk@chromium.org,neis@chromium.org,caitp@igalia.com,bmeurer@chromium.org
>
> Change-Id: I4730077591bce0e5e7b2ce7d59678e8b7135cc08
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: v8:7446
> Reviewed-on: https://chromium-review.googlesource.com/945769
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51682}
TBR=adamk@chromium.org,neis@chromium.org,sigurds@chromium.org,caitp@igalia.com,bmeurer@chromium.org
Change-Id: I977513bea06a4f3fba03fa4a89270298475422e2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7446
Reviewed-on: https://chromium-review.googlesource.com/945808
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51686}
2018-03-02 10:03:27 +00:00
|
|
|
return factory()->NewCallNew(function, args_list, pos);
|
2017-01-23 09:03:35 +00:00
|
|
|
}
|
2018-10-24 14:28:25 +00:00
|
|
|
ScopedPtrList<Expression> args(pointer_buffer());
|
2018-10-24 12:02:06 +00:00
|
|
|
args.Add(function);
|
|
|
|
args.Add(ArrayLiteralFromListWithSpread(args_list));
|
2015-04-09 19:37:14 +00:00
|
|
|
|
2015-08-26 11:16:38 +00:00
|
|
|
return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args, pos);
|
2015-04-09 19:37:14 +00:00
|
|
|
}
|
2015-11-05 19:52:36 +00:00
|
|
|
|
|
|
|
void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) {
|
|
|
|
v8::Isolate::UseCounterFeature feature;
|
|
|
|
if (is_sloppy(mode))
|
|
|
|
feature = v8::Isolate::kSloppyMode;
|
|
|
|
else if (is_strict(mode))
|
|
|
|
feature = v8::Isolate::kStrictMode;
|
|
|
|
else
|
|
|
|
UNREACHABLE();
|
|
|
|
++use_counts_[feature];
|
|
|
|
scope->SetLanguageMode(mode);
|
|
|
|
}
|
|
|
|
|
2016-09-05 13:42:01 +00:00
|
|
|
void Parser::SetAsmModule() {
|
|
|
|
// Store the usage count; The actual use counter on the isolate is
|
|
|
|
// incremented after parsing is done.
|
|
|
|
++use_counts_[v8::Isolate::kUseAsm];
|
|
|
|
DCHECK(scope()->is_declaration_scope());
|
2018-12-14 14:17:48 +00:00
|
|
|
scope()->AsDeclarationScope()->set_is_asm_module();
|
|
|
|
info_->set_contains_asm_module(true);
|
2015-11-05 19:52:36 +00:00
|
|
|
}
|
|
|
|
|
2018-10-24 12:02:06 +00:00
|
|
|
Expression* Parser::ExpressionListToExpression(
|
|
|
|
const ScopedPtrList<Expression>& args) {
|
|
|
|
Expression* expr = args.at(0);
|
2018-10-24 12:12:32 +00:00
|
|
|
if (args.length() == 1) return expr;
|
|
|
|
if (args.length() == 2) {
|
|
|
|
return factory()->NewBinaryOperation(Token::COMMA, expr, args.at(1),
|
2018-11-08 10:07:42 +00:00
|
|
|
args.at(1)->position());
|
2016-05-16 23:17:13 +00:00
|
|
|
}
|
2018-10-24 12:12:32 +00:00
|
|
|
NaryOperation* result =
|
|
|
|
factory()->NewNaryOperation(Token::COMMA, expr, args.length() - 1);
|
|
|
|
for (int i = 1; i < args.length(); i++) {
|
2018-11-08 10:07:42 +00:00
|
|
|
result->AddSubsequent(args.at(i), args.at(i)->position());
|
2018-10-24 12:12:32 +00:00
|
|
|
}
|
|
|
|
return result;
|
2016-05-16 23:17:13 +00:00
|
|
|
}
|
|
|
|
|
2016-09-27 18:01:58 +00:00
|
|
|
// This method completes the desugaring of the body of async_function.
|
2018-11-05 15:20:49 +00:00
|
|
|
void Parser::RewriteAsyncFunctionBody(ScopedPtrList<Statement>* body,
|
2019-12-18 08:16:30 +00:00
|
|
|
Block* block, Expression* return_value,
|
|
|
|
REPLMode repl_mode) {
|
2016-09-27 18:01:58 +00:00
|
|
|
// function async_function() {
|
2018-10-11 08:35:56 +00:00
|
|
|
// .generator_object = %_AsyncFunctionEnter();
|
2016-09-27 18:01:58 +00:00
|
|
|
// BuildRejectPromiseOnException({
|
|
|
|
// ... block ...
|
2018-10-11 08:35:56 +00:00
|
|
|
// return %_AsyncFunctionResolve(.generator_object, expr);
|
2016-09-27 18:01:58 +00:00
|
|
|
// })
|
|
|
|
// }
|
|
|
|
|
2019-09-04 06:53:15 +00:00
|
|
|
block->statements()->Add(factory()->NewSyntheticAsyncReturnStatement(
|
2018-10-08 17:57:52 +00:00
|
|
|
return_value, return_value->position()),
|
|
|
|
zone());
|
2019-12-18 08:16:30 +00:00
|
|
|
block = BuildRejectPromiseOnException(block, repl_mode);
|
2018-11-05 15:20:49 +00:00
|
|
|
body->Add(block);
|
2016-09-27 18:01:58 +00:00
|
|
|
}
|
|
|
|
|
2017-06-19 15:13:45 +00:00
|
|
|
void Parser::SetFunctionNameFromPropertyName(LiteralProperty* property,
|
|
|
|
const AstRawString* name,
|
|
|
|
const AstRawString* prefix) {
|
2018-10-31 10:47:57 +00:00
|
|
|
if (has_error()) return;
|
2017-06-19 15:13:45 +00:00
|
|
|
// Ensure that the function we are going to create has shared name iff
|
|
|
|
// we are not going to set it later.
|
|
|
|
if (property->NeedsSetFunctionName()) {
|
|
|
|
name = nullptr;
|
|
|
|
prefix = nullptr;
|
|
|
|
} else {
|
|
|
|
// If the property value is an anonymous function or an anonymous class or
|
|
|
|
// a concise method or an accessor function which doesn't require the name
|
|
|
|
// to be set then the shared name must be provided.
|
|
|
|
DCHECK_IMPLIES(property->value()->IsAnonymousFunctionDefinition() ||
|
|
|
|
property->value()->IsConciseMethodDefinition() ||
|
|
|
|
property->value()->IsAccessorFunctionDefinition(),
|
|
|
|
name != nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expression* value = property->value();
|
|
|
|
SetFunctionName(value, name, prefix);
|
2016-09-06 18:49:04 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 08:48:45 +00:00
|
|
|
void Parser::SetFunctionNameFromPropertyName(ObjectLiteralProperty* property,
|
2017-06-19 15:13:45 +00:00
|
|
|
const AstRawString* name,
|
|
|
|
const AstRawString* prefix) {
|
2016-01-06 23:38:28 +00:00
|
|
|
// Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
|
|
|
|
// of an object literal.
|
2017-06-19 15:13:45 +00:00
|
|
|
// See ES #sec-__proto__-property-names-in-object-initializers.
|
2018-10-31 10:47:57 +00:00
|
|
|
if (property->IsPrototype() || has_error()) return;
|
2016-01-06 23:38:28 +00:00
|
|
|
|
2017-06-19 15:13:45 +00:00
|
|
|
DCHECK(!property->value()->IsAnonymousFunctionDefinition() ||
|
2016-09-06 18:49:04 +00:00
|
|
|
property->kind() == ObjectLiteralProperty::COMPUTED);
|
2017-06-19 15:13:45 +00:00
|
|
|
|
|
|
|
SetFunctionNameFromPropertyName(static_cast<LiteralProperty*>(property), name,
|
|
|
|
prefix);
|
2016-09-06 17:43:17 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 08:48:45 +00:00
|
|
|
void Parser::SetFunctionNameFromIdentifierRef(Expression* value,
|
|
|
|
Expression* identifier) {
|
2018-11-07 15:38:15 +00:00
|
|
|
if (!identifier->IsVariableProxy()) return;
|
2016-08-25 08:48:45 +00:00
|
|
|
SetFunctionName(value, identifier->AsVariableProxy()->raw_name());
|
2016-07-18 07:27:10 +00:00
|
|
|
}
|
2016-01-13 23:35:32 +00:00
|
|
|
|
2017-06-19 15:13:45 +00:00
|
|
|
void Parser::SetFunctionName(Expression* value, const AstRawString* name,
|
|
|
|
const AstRawString* prefix) {
|
|
|
|
if (!value->IsAnonymousFunctionDefinition() &&
|
|
|
|
!value->IsConciseMethodDefinition() &&
|
|
|
|
!value->IsAccessorFunctionDefinition()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-02-01 17:44:23 +00:00
|
|
|
auto function = value->AsFunctionLiteral();
|
2017-05-04 17:00:44 +00:00
|
|
|
if (value->IsClassLiteral()) {
|
|
|
|
function = value->AsClassLiteral()->constructor();
|
|
|
|
}
|
2016-02-01 17:44:23 +00:00
|
|
|
if (function != nullptr) {
|
2017-06-19 15:13:45 +00:00
|
|
|
AstConsString* cons_name = nullptr;
|
|
|
|
if (name != nullptr) {
|
|
|
|
if (prefix != nullptr) {
|
|
|
|
cons_name = ast_value_factory()->NewConsString(prefix, name);
|
|
|
|
} else {
|
|
|
|
cons_name = ast_value_factory()->NewConsString(name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DCHECK_NULL(prefix);
|
|
|
|
}
|
|
|
|
function->set_raw_name(cons_name);
|
2016-01-13 23:35:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-19 08:11:04 +00:00
|
|
|
Statement* Parser::CheckCallable(Variable* var, Expression* error, int pos) {
|
2016-06-30 09:26:30 +00:00
|
|
|
const int nopos = kNoSourcePosition;
|
2016-02-19 19:19:52 +00:00
|
|
|
Statement* validate_var;
|
|
|
|
{
|
2016-08-19 08:11:04 +00:00
|
|
|
Expression* type_of = factory()->NewUnaryOperation(
|
|
|
|
Token::TYPEOF, factory()->NewVariableProxy(var), nopos);
|
|
|
|
Expression* function_literal = factory()->NewStringLiteral(
|
|
|
|
ast_value_factory()->function_string(), nopos);
|
|
|
|
Expression* condition = factory()->NewCompareOperation(
|
2016-02-19 19:19:52 +00:00
|
|
|
Token::EQ_STRICT, type_of, function_literal, nopos);
|
|
|
|
|
2016-08-19 08:11:04 +00:00
|
|
|
Statement* throw_call = factory()->NewExpressionStatement(error, pos);
|
2016-02-19 19:19:52 +00:00
|
|
|
|
2016-08-19 08:11:04 +00:00
|
|
|
validate_var = factory()->NewIfStatement(
|
2018-10-30 14:41:34 +00:00
|
|
|
condition, factory()->EmptyStatement(), throw_call, nopos);
|
2016-02-19 19:19:52 +00:00
|
|
|
}
|
|
|
|
return validate_var;
|
|
|
|
}
|
2016-02-04 14:12:37 +00:00
|
|
|
|
2015-06-01 22:46:54 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|