Commit 08f68102 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[parser] Allow declaring variables without a proxy

Declare Variables with a name and position, rather than by passing
through a VariableProxy. This allows us to not create dummy proxies
for things like function declarations, and allows us to consider those
declarations unused.

As a side-effect, we also have to check if a variable is unused in the
bytecode generator (as it will no longer be allocated), and we end up
skip generating code/SFIs for dead variables/functions.

Change-Id: I4c2c872473f23e124f9456b4b92f87159658f8e0
Reviewed-on: https://chromium-review.googlesource.com/c/1414916
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59088}
parent 2452e598
......@@ -558,13 +558,13 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
const AstRawString* name = index_and_name.second;
if (factory) {
DCHECK(!is_being_lazily_parsed_);
VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE);
auto declaration = factory->NewVariableDeclaration(kNoSourcePosition);
bool was_added;
// Based on the preceding checks, it doesn't matter what we pass as
// sloppy_mode_block_scope_function_redefinition.
bool ok = true;
DeclareVariable(declaration, proxy, VariableMode::kVar, NORMAL_VARIABLE,
DeclareVariable(declaration, name, kNoSourcePosition, VariableMode::kVar,
NORMAL_VARIABLE,
Variable::DefaultInitializationFlag(VariableMode::kVar),
&was_added, nullptr, &ok);
DCHECK(ok);
......@@ -949,15 +949,29 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
mode == VariableMode::kVar || mode == VariableMode::kLet ||
mode == VariableMode::kConst);
DCHECK(!GetDeclarationScope()->was_lazily_parsed());
return Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
Variable* var =
Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
// Pessimistically assume that top-level variables will be assigned and used.
//
// Top-level variables in a script can be accessed by other scripts or even
// become global properties. While this does not apply to top-level variables
// in a module (assuming they are not exported), we must still mark these as
// assigned because they might be accessed by a lazily parsed top-level
// function, which, for efficiency, we preparse without variable tracking.
if (is_script_scope() || is_module_scope()) {
if (mode != VariableMode::kConst) var->set_maybe_assigned();
var->set_is_used();
}
return var;
}
// TODO(leszeks): Avoid passing the proxy into here, passing the raw_name alone
// instead.
Variable* Scope::DeclareVariable(
Declaration* declaration, VariableProxy* proxy, VariableMode mode,
VariableKind kind, InitializationFlag init, bool* was_added,
bool* sloppy_mode_block_scope_function_redefinition, bool* ok) {
Declaration* declaration, const AstRawString* name, int pos,
VariableMode mode, VariableKind kind, InitializationFlag init,
bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
bool* ok) {
DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_);
DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
......@@ -965,7 +979,7 @@ Variable* Scope::DeclareVariable(
if (mode == VariableMode::kVar && !is_declaration_scope()) {
return GetDeclarationScope()->DeclareVariable(
declaration, proxy, mode, kind, init, was_added,
declaration, name, pos, mode, kind, init, was_added,
sloppy_mode_block_scope_function_redefinition, ok);
}
DCHECK(!is_catch_scope());
......@@ -973,19 +987,7 @@ Variable* Scope::DeclareVariable(
DCHECK(is_declaration_scope() ||
(IsLexicalVariableMode(mode) && is_block_scope()));
DCHECK_NOT_NULL(proxy->raw_name());
const AstRawString* name = proxy->raw_name();
// Pessimistically assume that top-level variables will be assigned.
//
// Top-level variables in a script can be accessed by other scripts or even
// become global properties. While this does not apply to top-level variables
// in a module (assuming they are not exported), we must still mark these as
// assigned because they might be accessed by a lazily parsed top-level
// function, which, for efficiency, we preparse without variable tracking.
if (is_script_scope() || is_module_scope()) {
if (mode != VariableMode::kConst) proxy->set_is_assigned();
}
DCHECK_NOT_NULL(name);
Variable* var = LookupLocal(name);
// Declare the variable in the declaration scope.
......@@ -998,7 +1000,9 @@ Variable* Scope::DeclareVariable(
// The proxy is bound to a lookup variable to force a dynamic declaration
// using the DeclareEvalVar or DeclareEvalFunction runtime functions.
DCHECK_EQ(NORMAL_VARIABLE, kind);
var = NonLocal(proxy->raw_name(), VariableMode::kDynamic);
var = NonLocal(name, VariableMode::kDynamic);
// Mark the var as used in case anyone outside the eval wants to use it.
var->set_is_used();
} else {
// Declare the name.
var = DeclareLocal(name, mode, kind, was_added, init);
......@@ -1051,7 +1055,6 @@ Variable* Scope::DeclareVariable(
// lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
decls_.Add(declaration);
declaration->set_var(var);
proxy->BindTo(var);
return var;
}
......@@ -2048,8 +2051,8 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(proxy->IsPrivateName());
return false;
}
var->set_is_used();
if (!var->is_dynamic()) {
var->set_is_used();
var->ForceContextAllocation();
if (proxy->is_assigned()) var->set_maybe_assigned();
}
......
......@@ -225,8 +225,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
VariableKind kind, bool* was_added,
InitializationFlag init_flag = kCreatedInitialized);
Variable* DeclareVariable(Declaration* declaration, VariableProxy* proxy,
VariableMode mode, VariableKind kind,
Variable* DeclareVariable(Declaration* declaration, const AstRawString* name,
int pos, VariableMode mode, VariableKind kind,
InitializationFlag init, bool* was_added,
bool* sloppy_mode_block_scope_function_redefinition,
bool* ok);
......
......@@ -1221,6 +1221,9 @@ void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
Variable* variable = decl->var();
// Unused variables don't need to be visited.
if (!variable->is_used()) return;
switch (variable->location()) {
case VariableLocation::UNALLOCATED: {
DCHECK(!variable->binding_needs_init());
......@@ -1275,6 +1278,9 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
DCHECK(variable->mode() == VariableMode::kLet ||
variable->mode() == VariableMode::kVar ||
variable->mode() == VariableMode::kDynamic);
// Unused variables don't need to be visited.
if (!variable->is_used()) return;
switch (variable->location()) {
case VariableLocation::UNALLOCATED: {
FeedbackSlot slot =
......
......@@ -274,7 +274,7 @@ class VariableDeclarationParsingScope : public ExpressionScope<Types> {
VariableProxy* Declare(VariableProxy* proxy) {
VariableKind kind = NORMAL_VARIABLE;
bool was_added;
this->parser()->DeclareVariable(
this->parser()->DeclareAndBindVariable(
proxy, kind, mode_, Variable::DefaultInitializationFlag(mode_),
this->parser()->scope(), &was_added, proxy->position());
if (was_added &&
......@@ -346,7 +346,7 @@ class ParameterDeclarationParsingScope : public ExpressionScope<Types> {
VariableKind kind = PARAMETER_VARIABLE;
VariableMode mode = VariableMode::kVar;
bool was_added;
this->parser()->DeclareVariable(
this->parser()->DeclareAndBindVariable(
proxy, kind, mode, Variable::DefaultInitializationFlag(mode),
this->parser()->scope(), &was_added, proxy->position());
if (!has_duplicate() && !was_added) {
......@@ -670,9 +670,9 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
for (int i = 0; i < this->variable_list()->length(); i++) {
VariableProxy* proxy = this->variable_list()->at(i);
bool was_added;
this->parser()->DeclareVariable(proxy, kind, mode,
Variable::DefaultInitializationFlag(mode),
result, &was_added, proxy->position());
this->parser()->DeclareAndBindVariable(
proxy, kind, mode, Variable::DefaultInitializationFlag(mode), result,
&was_added, proxy->position());
if (!was_added) {
ExpressionScope<Types>::Report(proxy->location(),
MessageTemplate::kParamDupe);
......
......@@ -1015,8 +1015,8 @@ ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
return nullptr;
}
DeclareVariable(local_name, VariableMode::kConst, kNeedsInitialization,
position());
DeclareUnboundVariable(local_name, VariableMode::kConst,
kNeedsInitialization, position());
NamedImport* import =
new (zone()) NamedImport(import_name, local_name, location);
......@@ -1065,8 +1065,8 @@ void Parser::ParseImportDeclaration() {
if (tok != Token::MUL && tok != Token::LBRACE) {
import_default_binding = ParseNonRestrictedIdentifier();
import_default_binding_loc = scanner()->location();
DeclareVariable(import_default_binding, VariableMode::kConst,
kNeedsInitialization, pos);
DeclareUnboundVariable(import_default_binding, VariableMode::kConst,
kNeedsInitialization, pos);
}
// Parse NameSpaceImport or NamedImports if present.
......@@ -1080,8 +1080,8 @@ void Parser::ParseImportDeclaration() {
ExpectContextualKeyword(ast_value_factory()->as_string());
module_namespace_binding = ParseNonRestrictedIdentifier();
module_namespace_binding_loc = scanner()->location();
DeclareVariable(module_namespace_binding, VariableMode::kConst,
kCreatedInitialized, pos);
DeclareUnboundVariable(module_namespace_binding, VariableMode::kConst,
kCreatedInitialized, pos);
break;
}
......@@ -1177,7 +1177,7 @@ Statement* Parser::ParseExportDefault() {
// It's fine to declare this as VariableMode::kConst because the user has
// no way of writing to it.
VariableProxy* proxy =
DeclareVariable(local_name, VariableMode::kConst, pos);
DeclareBoundVariable(local_name, VariableMode::kConst, pos);
proxy->var()->set_initializer_position(position());
Assignment* assignment = factory()->NewAssignment(
......@@ -1236,7 +1236,8 @@ void Parser::ParseExportStar() {
Scanner::Location export_name_loc = scanner()->location();
const AstRawString* local_name = NextInternalNamespaceExportName();
Scanner::Location local_name_loc = Scanner::Location::invalid();
DeclareVariable(local_name, VariableMode::kConst, kCreatedInitialized, pos);
DeclareUnboundVariable(local_name, VariableMode::kConst, kCreatedInitialized,
pos);
ExpectContextualKeyword(ast_value_factory()->from_string());
Scanner::Location specifier_loc = scanner()->peek_location();
......@@ -1350,28 +1351,42 @@ Statement* Parser::ParseExportDeclaration() {
return result;
}
VariableProxy* Parser::DeclareVariable(const AstRawString* name,
VariableMode mode, int pos) {
return DeclareVariable(name, mode, Variable::DefaultInitializationFlag(mode),
pos);
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);
}
VariableProxy* Parser::DeclareVariable(const AstRawString* name,
VariableMode mode,
InitializationFlag init, int pos) {
VariableProxy* Parser::DeclareBoundVariable(const AstRawString* name,
VariableMode mode, int pos) {
DCHECK_NOT_NULL(name);
VariableProxy* proxy =
factory()->NewVariableProxy(name, NORMAL_VARIABLE, position());
bool was_added;
DeclareVariable(proxy, NORMAL_VARIABLE, mode, init, scope(), &was_added, pos,
end_position());
Variable* var = DeclareVariable(name, NORMAL_VARIABLE, mode,
Variable::DefaultInitializationFlag(mode),
scope(), &was_added, pos, end_position());
proxy->BindTo(var);
return proxy;
}
void Parser::DeclareVariable(VariableProxy* proxy, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* scope, bool* was_added, int begin,
int end) {
void Parser::DeclareAndBindVariable(VariableProxy* proxy, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* scope, bool* was_added, int begin,
int end) {
Variable* var = DeclareVariable(proxy->raw_name(), kind, mode, init, scope,
was_added, begin, end);
proxy->BindTo(var);
}
Variable* Parser::DeclareVariable(const AstRawString* name, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* scope, bool* was_added, int begin,
int end) {
Declaration* declaration;
if (mode == VariableMode::kVar && !scope->is_declaration_scope()) {
DCHECK(scope->is_block_scope() || scope->is_with_scope());
......@@ -1379,25 +1394,26 @@ void Parser::DeclareVariable(VariableProxy* proxy, VariableKind kind,
} else {
declaration = factory()->NewVariableDeclaration(begin);
}
return Declare(declaration, proxy, kind, mode, init, scope, was_added, end);
Declare(declaration, name, kind, mode, init, scope, was_added, begin, end);
return declaration->var();
}
void Parser::Declare(Declaration* declaration, VariableProxy* proxy,
void Parser::Declare(Declaration* declaration, const AstRawString* name,
VariableKind variable_kind, VariableMode mode,
InitializationFlag init, Scope* scope, bool* was_added,
int var_end_pos) {
int var_begin_pos, int var_end_pos) {
bool local_ok = true;
bool sloppy_mode_block_scope_function_redefinition = false;
scope->DeclareVariable(
declaration, proxy, mode, variable_kind, init, was_added,
declaration, name, var_begin_pos, mode, variable_kind, init, was_added,
&sloppy_mode_block_scope_function_redefinition, &local_ok);
if (!local_ok) {
// 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.
Scanner::Location loc(proxy->position(), var_end_pos != kNoSourcePosition
? var_end_pos
: proxy->position() + 1);
Scanner::Location loc(var_begin_pos, var_end_pos != kNoSourcePosition
? var_end_pos
: var_begin_pos + 1);
if (variable_kind == PARAMETER_VARIABLE) {
ReportMessageAt(loc, MessageTemplate::kParamDupe);
} else {
......@@ -1425,13 +1441,11 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
int beg_pos, int end_pos,
bool is_sloppy_block_function,
ZonePtrList<const AstRawString>* names) {
VariableProxy* proxy =
factory()->NewVariableProxy(variable_name, NORMAL_VARIABLE, beg_pos);
Declaration* declaration = factory()->NewFunctionDeclaration(
function, is_sloppy_block_function, beg_pos);
bool was_added;
Declare(declaration, proxy, NORMAL_VARIABLE, mode, kCreatedInitialized,
scope(), &was_added);
Declare(declaration, variable_name, NORMAL_VARIABLE, mode,
kCreatedInitialized, scope(), &was_added, beg_pos);
if (names) names->Add(variable_name, zone());
if (is_sloppy_block_function) {
SloppyBlockFunctionStatement* statement =
......@@ -1448,7 +1462,7 @@ Statement* Parser::DeclareClass(const AstRawString* variable_name,
ZonePtrList<const AstRawString>* names,
int class_token_pos, int end_pos) {
VariableProxy* proxy =
DeclareVariable(variable_name, VariableMode::kLet, class_token_pos);
DeclareBoundVariable(variable_name, VariableMode::kLet, class_token_pos);
proxy->var()->set_initializer_position(end_pos);
if (names) names->Add(variable_name, zone());
......@@ -1468,7 +1482,7 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos) {
// 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.
VariableProxy* proxy = DeclareVariable(name, VariableMode::kVar, pos);
VariableProxy* proxy = DeclareBoundVariable(name, VariableMode::kVar, pos);
NativeFunctionLiteral* lit =
factory()->NewNativeFunctionLiteral(name, extension_, kNoSourcePosition);
return factory()->NewExpressionStatement(
......@@ -1862,7 +1876,7 @@ Block* Parser::CreateForEachStatementTDZ(Block* init_block,
// TODO(adamk): This needs to be some sort of special
// INTERNAL variable that's invisible to the debugger
// but visible to everything else.
VariableProxy* tdz_proxy = DeclareVariable(
VariableProxy* tdz_proxy = DeclareBoundVariable(
for_info.bound_names[i], VariableMode::kLet, kNoSourcePosition);
tdz_proxy->var()->set_initializer_position(position());
}
......@@ -1974,7 +1988,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// For each let variable x:
// make statement: let/const x = temp_x.
for (int i = 0; i < for_info.bound_names.length(); i++) {
VariableProxy* proxy = DeclareVariable(
VariableProxy* proxy = DeclareBoundVariable(
for_info.bound_names[i], for_info.parsing_result.descriptor.mode,
kNoSourcePosition);
inner_vars.Add(proxy->var(), zone());
......@@ -2188,8 +2202,7 @@ void Parser::AddArrowFunctionFormalParameters(
expr = assignment->target();
}
AddFormalParameter(parameters, expr, initializer,
end_pos, is_rest);
AddFormalParameter(parameters, expr, initializer, end_pos, is_rest);
}
void Parser::DeclareArrowFunctionFormalParameters(
......@@ -2800,7 +2813,7 @@ void Parser::DeclareClassVariable(const AstRawString* name,
if (name != nullptr) {
VariableProxy* proxy =
DeclareVariable(name, VariableMode::kConst, class_token_pos);
DeclareBoundVariable(name, VariableMode::kConst, class_token_pos);
class_info->variable = proxy->var();
}
}
......@@ -2810,7 +2823,7 @@ void Parser::DeclareClassVariable(const AstRawString* name,
// index in the AST, instead of storing the variable.
Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name) {
VariableProxy* proxy =
DeclareVariable(name, VariableMode::kConst, kNoSourcePosition);
DeclareBoundVariable(name, VariableMode::kConst, kNoSourcePosition);
proxy->var()->ForceContextAllocation();
return proxy->var();
}
......@@ -3099,13 +3112,11 @@ void Parser::AddTemplateSpan(TemplateLiteralState* state, bool should_cook,
}
}
void Parser::AddTemplateExpression(TemplateLiteralState* state,
Expression* expression) {
(*state)->AddExpression(expression, zone());
}
Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
Expression* tag) {
TemplateLiteral* lit = *state;
......@@ -3212,7 +3223,6 @@ Expression* Parser::SpreadCallNew(Expression* function,
return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args, pos);
}
void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) {
v8::Isolate::UseCounterFeature feature;
if (is_sloppy(mode))
......
......@@ -410,17 +410,23 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// Implement sloppy block-scoped functions, ES2015 Annex B 3.3
void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope);
VariableProxy* DeclareVariable(const AstRawString* name, VariableMode mode,
int pos);
VariableProxy* DeclareVariable(const AstRawString* name, VariableMode mode,
InitializationFlag init, int pos);
void DeclareVariable(VariableProxy* proxy, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* declaration_scope, bool* added, int begin,
int end = kNoSourcePosition);
void Declare(Declaration* declaration, VariableProxy* proxy,
void DeclareUnboundVariable(const AstRawString* name, VariableMode mode,
InitializationFlag init, int pos);
V8_WARN_UNUSED_RESULT
VariableProxy* DeclareBoundVariable(const AstRawString* name,
VariableMode mode, int pos);
void DeclareAndBindVariable(VariableProxy* proxy, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* declaration_scope, bool* was_added,
int begin, int end = kNoSourcePosition);
V8_WARN_UNUSED_RESULT
Variable* DeclareVariable(const AstRawString* name, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* declaration_scope, bool* was_added,
int begin, int end = kNoSourcePosition);
void Declare(Declaration* declaration, const AstRawString* name,
VariableKind kind, VariableMode mode, InitializationFlag init,
Scope* declaration_scope, bool* added,
Scope* declaration_scope, bool* was_added, int var_begin_pos,
int var_end_pos = kNoSourcePosition);
bool TargetStackContainsLabel(const AstRawString* label);
......
......@@ -1087,11 +1087,18 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default();
}
void DeclareVariable(VariableProxy* proxy, VariableKind kind,
void DeclareVariable(const AstRawString* name, VariableKind kind,
VariableMode mode, InitializationFlag init, Scope* scope,
bool* was_added, int position) {
DeclareVariableName(name, mode, scope, was_added, position, kind);
}
void DeclareAndBindVariable(const VariableProxy* proxy, VariableKind kind,
VariableMode mode, InitializationFlag init,
Scope* scope, bool* was_added, int position) {
DeclareVariableName(proxy->raw_name(), mode, scope, was_added, position,
kind);
// Don't bother actually binding the proxy.
}
void DeclareVariableName(const AstRawString* name, VariableMode mode,
......
......@@ -9,16 +9,14 @@ wrap: yes
snippet: "
const x = 10; function f1() {return x;}
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 21
bytecode array length: 15
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(10),
/* 44 E> */ B(StaCurrentContextSlot), U8(4),
......@@ -27,7 +25,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -36,16 +33,14 @@ handlers: [
snippet: "
const x = 10; function f1() {return x;} return x;
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 22
bytecode array length: 16
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(10),
/* 44 E> */ B(StaCurrentContextSlot), U8(4),
......@@ -54,7 +49,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -63,21 +57,19 @@ handlers: [
snippet: "
const x = (x = 20); function f1() {return x;}
"
frame size: 3
frame size: 2
parameter count: 1
bytecode array length: 32
bytecode array length: 26
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(20),
B(Star), R(2),
B(Star), R(1),
B(LdaCurrentContextSlot), U8(4),
/* 47 E> */ B(ThrowReferenceErrorIfHole), U8(2),
/* 47 E> */ B(ThrowReferenceErrorIfHole), U8(1),
B(CallRuntime), U16(Runtime::kThrowConstAssignError), R(0), U8(0),
/* 44 E> */ B(StaCurrentContextSlot), U8(4),
B(LdaUndefined),
......@@ -85,7 +77,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
]
handlers: [
......@@ -95,16 +86,14 @@ handlers: [
snippet: "
const x = 10; x = 20; function f1() {return x;}
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 28
bytecode array length: 22
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(10),
/* 44 E> */ B(StaCurrentContextSlot), U8(4),
......@@ -115,7 +104,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......
......@@ -9,16 +9,14 @@ wrap: yes
snippet: "
let x = 10; function f1() {return x;}
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 21
bytecode array length: 15
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(10),
/* 42 E> */ B(StaCurrentContextSlot), U8(4),
......@@ -27,7 +25,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -36,16 +33,14 @@ handlers: [
snippet: "
let x = 10; function f1() {return x;} return x;
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 22
bytecode array length: 16
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(10),
/* 42 E> */ B(StaCurrentContextSlot), U8(4),
......@@ -54,7 +49,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -63,22 +57,20 @@ handlers: [
snippet: "
let x = (x = 20); function f1() {return x;}
"
frame size: 3
frame size: 2
parameter count: 1
bytecode array length: 31
bytecode array length: 25
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(20),
B(Star), R(2),
B(Star), R(1),
B(LdaCurrentContextSlot), U8(4),
/* 45 E> */ B(ThrowReferenceErrorIfHole), U8(2),
B(Ldar), R(2),
/* 45 E> */ B(ThrowReferenceErrorIfHole), U8(1),
B(Ldar), R(1),
B(StaCurrentContextSlot), U8(4),
/* 42 E> */ B(StaCurrentContextSlot), U8(4),
B(LdaUndefined),
......@@ -86,7 +78,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
]
handlers: [
......@@ -96,16 +87,14 @@ handlers: [
snippet: "
let x = 10; x = 20; function f1() {return x;}
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 25
bytecode array length: 19
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1),
B(PushContext), R(0),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(10),
/* 42 E> */ B(StaCurrentContextSlot), U8(4),
......@@ -116,7 +105,6 @@ bytecodes: [
]
constant pool: [
SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......
......@@ -3615,7 +3615,7 @@ static void TestMaybeAssigned(Input input, const char* variable, bool module,
}
CHECK_NOT_NULL(var);
CHECK(var->is_used());
CHECK_IMPLIES(input.assigned, var->is_used());
STATIC_ASSERT(true == i::kMaybeAssigned);
CHECK_EQ(input.assigned, var->maybe_assigned() == i::kMaybeAssigned);
}
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --no-always-opt --no-stress-opt
Debug = debug.Debug
var exception = null;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
// Evaluating the live function should succeed.
assertEquals(exec_state.frame(0).evaluate("live()").value(), 1);
// Evaluating the dead function should fail.
assertThrows(()=>exec_state.frame(0).evaluate("dead()"), ReferenceError);
} catch (e) {
exception = e;
print(e + e.stack);
}
}
Debug.setListener(listener);
(function() {
"use strict";
function live() { return 1; }
function dead() { return 2; }
// Use 'foo' to make it non-dead.
live;
debugger;
})();
Debug.setListener(null);
assertNull(exception);
......@@ -33,6 +33,8 @@ Debug.setListener(listener);
a *= 2;
e *= 2;
}
// Make sure bar is 'used' so that it is visible to the debugger.
bar;
debugger;
assertEquals(5, a);
assertEquals(7, e);
......
......@@ -32,6 +32,8 @@ Debug.setListener(listener);
function* generator(a, b) {
function set_a_to_5() { a = 5 }
// Make sure set_a_to_5 is 'used' so that it is visible to the debugger.
set_a_to_5;
var b = 3; // Shadows a parameter.
debugger;
yield a;
......
......@@ -37,11 +37,16 @@ function f(e, x) {
// and 'e' binds to the exception.
function write_0(v) { e = v }
function write_1(v) { x = v }
// Make sure write_0 and write_1 are 'used' so that they are visible to the
// debugger.
write_0, write_1;
debugger;
assertEquals("foo", e); // overwritten by the debugger
}
assertEquals("argument", e); // debugger did not overwrite
function write_2(v) { e = v }
// Make sure write_2 is 'used' so that it is visible to the debugger.
write_2;
debugger;
assertEquals("bar", e);
assertEquals("modified", x);
......
......@@ -970,17 +970,6 @@ Running test: testPreciseCountCoveragePartial
}
]
}
[6] : {
functionName : nested_4
isBlockCoverage : false
ranges : [
[0] : {
count : 0
endOffset : 201
startOffset : 179
}
]
}
]
scriptId : <scriptId>
url : testPreciseCountCoveragePartial
......
......@@ -753,17 +753,6 @@ Running test: testPreciseCountCoveragePartial
}
]
}
[6] : {
functionName : nested_4
isBlockCoverage : false
ranges : [
[0] : {
count : 0
endOffset : 201
startOffset : 179
}
]
}
]
scriptId : <scriptId>
url : testPreciseCountCoveragePartial
......
......@@ -267,7 +267,11 @@ function foo6() { Promise.resolve().then(() => 42^) }
Running test: arrowFunctionReturn
#() => #239#
#
function foo() { function boo() { #return 239# } #}
function foo() { function boo() { return 239 } #}
#
function foo() { function boo() { #return 239# }; #boo #}
#
function foo() { let boo = #function() { #return 239# }; #}
#
#() => { #239 #}
#
......
......@@ -135,6 +135,8 @@ function foo6() { Promise.resolve().then(() => 42) }
checkSource('() => 239\n', { lineNumber: 0, columnNumber: 0 })
.then(() => checkSource('function foo() { function boo() { return 239 } }\n', { lineNumber: 0, columnNumber: 0 }))
.then(() => checkSource('function foo() { function boo() { return 239 }; boo }\n', { lineNumber: 0, columnNumber: 0 }))
.then(() => checkSource('function foo() { let boo = function() { return 239 }; }\n', { lineNumber: 0, columnNumber: 0 }))
.then(() => checkSource('() => { 239 }\n', { lineNumber: 0, columnNumber: 0 }))
.then(() => checkSource('function foo() { 239 }\n', { lineNumber: 0, columnNumber: 0 }))
// TODO(kozyatinskiy): lineNumber for return position should be only 9, not 8.
......
......@@ -10,6 +10,7 @@ function testFunction()
var o = 0;
function f() { return 1; }
function g() { o = 2; return o; }
f,g;
debugger;
}
//# sourceURL=foo.js`);
......
*%(basename)s:8: SyntaxError: Identifier '*default*' has already been declared
export default x = 1;
^
^^^^^^^^^^^^^
SyntaxError: Identifier '*default*' has already been declared
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment