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) { ...@@ -558,13 +558,13 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
const AstRawString* name = index_and_name.second; const AstRawString* name = index_and_name.second;
if (factory) { if (factory) {
DCHECK(!is_being_lazily_parsed_); DCHECK(!is_being_lazily_parsed_);
VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE);
auto declaration = factory->NewVariableDeclaration(kNoSourcePosition); auto declaration = factory->NewVariableDeclaration(kNoSourcePosition);
bool was_added; bool was_added;
// Based on the preceding checks, it doesn't matter what we pass as // Based on the preceding checks, it doesn't matter what we pass as
// sloppy_mode_block_scope_function_redefinition. // sloppy_mode_block_scope_function_redefinition.
bool ok = true; bool ok = true;
DeclareVariable(declaration, proxy, VariableMode::kVar, NORMAL_VARIABLE, DeclareVariable(declaration, name, kNoSourcePosition, VariableMode::kVar,
NORMAL_VARIABLE,
Variable::DefaultInitializationFlag(VariableMode::kVar), Variable::DefaultInitializationFlag(VariableMode::kVar),
&was_added, nullptr, &ok); &was_added, nullptr, &ok);
DCHECK(ok); DCHECK(ok);
...@@ -949,15 +949,29 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, ...@@ -949,15 +949,29 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
mode == VariableMode::kVar || mode == VariableMode::kLet || mode == VariableMode::kVar || mode == VariableMode::kLet ||
mode == VariableMode::kConst); mode == VariableMode::kConst);
DCHECK(!GetDeclarationScope()->was_lazily_parsed()); 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( Variable* Scope::DeclareVariable(
Declaration* declaration, VariableProxy* proxy, VariableMode mode, Declaration* declaration, const AstRawString* name, int pos,
VariableKind kind, InitializationFlag init, bool* was_added, VariableMode mode, VariableKind kind, InitializationFlag init,
bool* sloppy_mode_block_scope_function_redefinition, bool* ok) { bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
bool* ok) {
DCHECK(IsDeclaredVariableMode(mode)); DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_); DCHECK(!already_resolved_);
DCHECK(!GetDeclarationScope()->is_being_lazily_parsed()); DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
...@@ -965,7 +979,7 @@ Variable* Scope::DeclareVariable( ...@@ -965,7 +979,7 @@ Variable* Scope::DeclareVariable(
if (mode == VariableMode::kVar && !is_declaration_scope()) { if (mode == VariableMode::kVar && !is_declaration_scope()) {
return GetDeclarationScope()->DeclareVariable( 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); sloppy_mode_block_scope_function_redefinition, ok);
} }
DCHECK(!is_catch_scope()); DCHECK(!is_catch_scope());
...@@ -973,19 +987,7 @@ Variable* Scope::DeclareVariable( ...@@ -973,19 +987,7 @@ Variable* Scope::DeclareVariable(
DCHECK(is_declaration_scope() || DCHECK(is_declaration_scope() ||
(IsLexicalVariableMode(mode) && is_block_scope())); (IsLexicalVariableMode(mode) && is_block_scope()));
DCHECK_NOT_NULL(proxy->raw_name()); DCHECK_NOT_NULL(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();
}
Variable* var = LookupLocal(name); Variable* var = LookupLocal(name);
// Declare the variable in the declaration scope. // Declare the variable in the declaration scope.
...@@ -998,7 +1000,9 @@ Variable* Scope::DeclareVariable( ...@@ -998,7 +1000,9 @@ Variable* Scope::DeclareVariable(
// The proxy is bound to a lookup variable to force a dynamic declaration // The proxy is bound to a lookup variable to force a dynamic declaration
// using the DeclareEvalVar or DeclareEvalFunction runtime functions. // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
DCHECK_EQ(NORMAL_VARIABLE, kind); 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 { } else {
// Declare the name. // Declare the name.
var = DeclareLocal(name, mode, kind, was_added, init); var = DeclareLocal(name, mode, kind, was_added, init);
...@@ -1051,7 +1055,6 @@ Variable* Scope::DeclareVariable( ...@@ -1051,7 +1055,6 @@ Variable* Scope::DeclareVariable(
// lead to repeated DeclareEvalVar or DeclareEvalFunction calls. // lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
decls_.Add(declaration); decls_.Add(declaration);
declaration->set_var(var); declaration->set_var(var);
proxy->BindTo(var);
return var; return var;
} }
...@@ -2048,8 +2051,8 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) { ...@@ -2048,8 +2051,8 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(proxy->IsPrivateName()); DCHECK(proxy->IsPrivateName());
return false; return false;
} }
if (!var->is_dynamic()) {
var->set_is_used(); var->set_is_used();
if (!var->is_dynamic()) {
var->ForceContextAllocation(); var->ForceContextAllocation();
if (proxy->is_assigned()) var->set_maybe_assigned(); if (proxy->is_assigned()) var->set_maybe_assigned();
} }
......
...@@ -225,8 +225,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -225,8 +225,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
VariableKind kind, bool* was_added, VariableKind kind, bool* was_added,
InitializationFlag init_flag = kCreatedInitialized); InitializationFlag init_flag = kCreatedInitialized);
Variable* DeclareVariable(Declaration* declaration, VariableProxy* proxy, Variable* DeclareVariable(Declaration* declaration, const AstRawString* name,
VariableMode mode, VariableKind kind, int pos, VariableMode mode, VariableKind kind,
InitializationFlag init, bool* was_added, InitializationFlag init, bool* was_added,
bool* sloppy_mode_block_scope_function_redefinition, bool* sloppy_mode_block_scope_function_redefinition,
bool* ok); bool* ok);
......
...@@ -1221,6 +1221,9 @@ void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) { ...@@ -1221,6 +1221,9 @@ void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
Variable* variable = decl->var(); Variable* variable = decl->var();
// Unused variables don't need to be visited.
if (!variable->is_used()) return;
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::UNALLOCATED: { case VariableLocation::UNALLOCATED: {
DCHECK(!variable->binding_needs_init()); DCHECK(!variable->binding_needs_init());
...@@ -1275,6 +1278,9 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { ...@@ -1275,6 +1278,9 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
DCHECK(variable->mode() == VariableMode::kLet || DCHECK(variable->mode() == VariableMode::kLet ||
variable->mode() == VariableMode::kVar || variable->mode() == VariableMode::kVar ||
variable->mode() == VariableMode::kDynamic); variable->mode() == VariableMode::kDynamic);
// Unused variables don't need to be visited.
if (!variable->is_used()) return;
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::UNALLOCATED: { case VariableLocation::UNALLOCATED: {
FeedbackSlot slot = FeedbackSlot slot =
......
...@@ -274,7 +274,7 @@ class VariableDeclarationParsingScope : public ExpressionScope<Types> { ...@@ -274,7 +274,7 @@ class VariableDeclarationParsingScope : public ExpressionScope<Types> {
VariableProxy* Declare(VariableProxy* proxy) { VariableProxy* Declare(VariableProxy* proxy) {
VariableKind kind = NORMAL_VARIABLE; VariableKind kind = NORMAL_VARIABLE;
bool was_added; bool was_added;
this->parser()->DeclareVariable( this->parser()->DeclareAndBindVariable(
proxy, kind, mode_, Variable::DefaultInitializationFlag(mode_), proxy, kind, mode_, Variable::DefaultInitializationFlag(mode_),
this->parser()->scope(), &was_added, proxy->position()); this->parser()->scope(), &was_added, proxy->position());
if (was_added && if (was_added &&
...@@ -346,7 +346,7 @@ class ParameterDeclarationParsingScope : public ExpressionScope<Types> { ...@@ -346,7 +346,7 @@ class ParameterDeclarationParsingScope : public ExpressionScope<Types> {
VariableKind kind = PARAMETER_VARIABLE; VariableKind kind = PARAMETER_VARIABLE;
VariableMode mode = VariableMode::kVar; VariableMode mode = VariableMode::kVar;
bool was_added; bool was_added;
this->parser()->DeclareVariable( this->parser()->DeclareAndBindVariable(
proxy, kind, mode, Variable::DefaultInitializationFlag(mode), proxy, kind, mode, Variable::DefaultInitializationFlag(mode),
this->parser()->scope(), &was_added, proxy->position()); this->parser()->scope(), &was_added, proxy->position());
if (!has_duplicate() && !was_added) { if (!has_duplicate() && !was_added) {
...@@ -670,9 +670,9 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { ...@@ -670,9 +670,9 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
for (int i = 0; i < this->variable_list()->length(); i++) { for (int i = 0; i < this->variable_list()->length(); i++) {
VariableProxy* proxy = this->variable_list()->at(i); VariableProxy* proxy = this->variable_list()->at(i);
bool was_added; bool was_added;
this->parser()->DeclareVariable(proxy, kind, mode, this->parser()->DeclareAndBindVariable(
Variable::DefaultInitializationFlag(mode), proxy, kind, mode, Variable::DefaultInitializationFlag(mode), result,
result, &was_added, proxy->position()); &was_added, proxy->position());
if (!was_added) { if (!was_added) {
ExpressionScope<Types>::Report(proxy->location(), ExpressionScope<Types>::Report(proxy->location(),
MessageTemplate::kParamDupe); MessageTemplate::kParamDupe);
......
This diff is collapsed.
...@@ -410,17 +410,23 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -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 // Implement sloppy block-scoped functions, ES2015 Annex B 3.3
void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope); void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope);
VariableProxy* DeclareVariable(const AstRawString* name, VariableMode mode, void DeclareUnboundVariable(const AstRawString* name, VariableMode mode,
int pos);
VariableProxy* DeclareVariable(const AstRawString* name, VariableMode mode,
InitializationFlag init, int pos); InitializationFlag init, int pos);
void DeclareVariable(VariableProxy* proxy, VariableKind kind, 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, VariableMode mode, InitializationFlag init,
Scope* declaration_scope, bool* added, int begin, Scope* declaration_scope, bool* was_added,
int end = kNoSourcePosition); int begin, int end = kNoSourcePosition);
void Declare(Declaration* declaration, VariableProxy* proxy, void Declare(Declaration* declaration, const AstRawString* name,
VariableKind kind, VariableMode mode, InitializationFlag init, 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); int var_end_pos = kNoSourcePosition);
bool TargetStackContainsLabel(const AstRawString* label); bool TargetStackContainsLabel(const AstRawString* label);
......
...@@ -1087,11 +1087,18 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1087,11 +1087,18 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
void DeclareVariable(VariableProxy* proxy, VariableKind kind, void DeclareVariable(const AstRawString* name, VariableKind kind,
VariableMode mode, InitializationFlag init, Scope* scope, VariableMode mode, InitializationFlag init, Scope* scope,
bool* was_added, int position) { 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, DeclareVariableName(proxy->raw_name(), mode, scope, was_added, position,
kind); kind);
// Don't bother actually binding the proxy.
} }
void DeclareVariableName(const AstRawString* name, VariableMode mode, void DeclareVariableName(const AstRawString* name, VariableMode mode,
......
...@@ -9,16 +9,14 @@ wrap: yes ...@@ -9,16 +9,14 @@ wrap: yes
snippet: " snippet: "
const x = 10; function f1() {return x;} const x = 10; function f1() {return x;}
" "
frame size: 2 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 21 bytecode array length: 15
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(10), /* 44 S> */ B(LdaSmi), I8(10),
/* 44 E> */ B(StaCurrentContextSlot), U8(4), /* 44 E> */ B(StaCurrentContextSlot), U8(4),
...@@ -27,7 +25,6 @@ bytecodes: [ ...@@ -27,7 +25,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
] ]
handlers: [ handlers: [
] ]
...@@ -36,16 +33,14 @@ handlers: [ ...@@ -36,16 +33,14 @@ handlers: [
snippet: " snippet: "
const x = 10; function f1() {return x;} return x; const x = 10; function f1() {return x;} return x;
" "
frame size: 2 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 22 bytecode array length: 16
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(10), /* 44 S> */ B(LdaSmi), I8(10),
/* 44 E> */ B(StaCurrentContextSlot), U8(4), /* 44 E> */ B(StaCurrentContextSlot), U8(4),
...@@ -54,7 +49,6 @@ bytecodes: [ ...@@ -54,7 +49,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
] ]
handlers: [ handlers: [
] ]
...@@ -63,21 +57,19 @@ handlers: [ ...@@ -63,21 +57,19 @@ handlers: [
snippet: " snippet: "
const x = (x = 20); function f1() {return x;} const x = (x = 20); function f1() {return x;}
" "
frame size: 3 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 32 bytecode array length: 26
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(20), /* 44 S> */ B(LdaSmi), I8(20),
B(Star), R(2), B(Star), R(1),
B(LdaCurrentContextSlot), U8(4), 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), B(CallRuntime), U16(Runtime::kThrowConstAssignError), R(0), U8(0),
/* 44 E> */ B(StaCurrentContextSlot), U8(4), /* 44 E> */ B(StaCurrentContextSlot), U8(4),
B(LdaUndefined), B(LdaUndefined),
...@@ -85,7 +77,6 @@ bytecodes: [ ...@@ -85,7 +77,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
] ]
handlers: [ handlers: [
...@@ -95,16 +86,14 @@ handlers: [ ...@@ -95,16 +86,14 @@ handlers: [
snippet: " snippet: "
const x = 10; x = 20; function f1() {return x;} const x = 10; x = 20; function f1() {return x;}
" "
frame size: 2 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 28 bytecode array length: 22
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 44 S> */ B(LdaSmi), I8(10), /* 44 S> */ B(LdaSmi), I8(10),
/* 44 E> */ B(StaCurrentContextSlot), U8(4), /* 44 E> */ B(StaCurrentContextSlot), U8(4),
...@@ -115,7 +104,6 @@ bytecodes: [ ...@@ -115,7 +104,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
] ]
handlers: [ handlers: [
] ]
......
...@@ -9,16 +9,14 @@ wrap: yes ...@@ -9,16 +9,14 @@ wrap: yes
snippet: " snippet: "
let x = 10; function f1() {return x;} let x = 10; function f1() {return x;}
" "
frame size: 2 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 21 bytecode array length: 15
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(10), /* 42 S> */ B(LdaSmi), I8(10),
/* 42 E> */ B(StaCurrentContextSlot), U8(4), /* 42 E> */ B(StaCurrentContextSlot), U8(4),
...@@ -27,7 +25,6 @@ bytecodes: [ ...@@ -27,7 +25,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
] ]
handlers: [ handlers: [
] ]
...@@ -36,16 +33,14 @@ handlers: [ ...@@ -36,16 +33,14 @@ handlers: [
snippet: " snippet: "
let x = 10; function f1() {return x;} return x; let x = 10; function f1() {return x;} return x;
" "
frame size: 2 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 22 bytecode array length: 16
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(10), /* 42 S> */ B(LdaSmi), I8(10),
/* 42 E> */ B(StaCurrentContextSlot), U8(4), /* 42 E> */ B(StaCurrentContextSlot), U8(4),
...@@ -54,7 +49,6 @@ bytecodes: [ ...@@ -54,7 +49,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
] ]
handlers: [ handlers: [
] ]
...@@ -63,22 +57,20 @@ handlers: [ ...@@ -63,22 +57,20 @@ handlers: [
snippet: " snippet: "
let x = (x = 20); function f1() {return x;} let x = (x = 20); function f1() {return x;}
" "
frame size: 3 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 31 bytecode array length: 25
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(20), /* 42 S> */ B(LdaSmi), I8(20),
B(Star), R(2), B(Star), R(1),
B(LdaCurrentContextSlot), U8(4), B(LdaCurrentContextSlot), U8(4),
/* 45 E> */ B(ThrowReferenceErrorIfHole), U8(2), /* 45 E> */ B(ThrowReferenceErrorIfHole), U8(1),
B(Ldar), R(2), B(Ldar), R(1),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
/* 42 E> */ B(StaCurrentContextSlot), U8(4), /* 42 E> */ B(StaCurrentContextSlot), U8(4),
B(LdaUndefined), B(LdaUndefined),
...@@ -86,7 +78,6 @@ bytecodes: [ ...@@ -86,7 +78,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
] ]
handlers: [ handlers: [
...@@ -96,16 +87,14 @@ handlers: [ ...@@ -96,16 +87,14 @@ handlers: [
snippet: " snippet: "
let x = 10; x = 20; function f1() {return x;} let x = 10; x = 20; function f1() {return x;}
" "
frame size: 2 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 25 bytecode array length: 19
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(0), U8(1), B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaTheHole), B(LdaTheHole),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(10), /* 42 S> */ B(LdaSmi), I8(10),
/* 42 E> */ B(StaCurrentContextSlot), U8(4), /* 42 E> */ B(StaCurrentContextSlot), U8(4),
...@@ -116,7 +105,6 @@ bytecodes: [ ...@@ -116,7 +105,6 @@ bytecodes: [
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
] ]
handlers: [ handlers: [
] ]
......
...@@ -3615,7 +3615,7 @@ static void TestMaybeAssigned(Input input, const char* variable, bool module, ...@@ -3615,7 +3615,7 @@ static void TestMaybeAssigned(Input input, const char* variable, bool module,
} }
CHECK_NOT_NULL(var); CHECK_NOT_NULL(var);
CHECK(var->is_used()); CHECK_IMPLIES(input.assigned, var->is_used());
STATIC_ASSERT(true == i::kMaybeAssigned); STATIC_ASSERT(true == i::kMaybeAssigned);
CHECK_EQ(input.assigned, var->maybe_assigned() == 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); ...@@ -33,6 +33,8 @@ Debug.setListener(listener);
a *= 2; a *= 2;
e *= 2; e *= 2;
} }
// Make sure bar is 'used' so that it is visible to the debugger.
bar;
debugger; debugger;
assertEquals(5, a); assertEquals(5, a);
assertEquals(7, e); assertEquals(7, e);
......
...@@ -32,6 +32,8 @@ Debug.setListener(listener); ...@@ -32,6 +32,8 @@ Debug.setListener(listener);
function* generator(a, b) { function* generator(a, b) {
function set_a_to_5() { a = 5 } 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. var b = 3; // Shadows a parameter.
debugger; debugger;
yield a; yield a;
......
...@@ -37,11 +37,16 @@ function f(e, x) { ...@@ -37,11 +37,16 @@ function f(e, x) {
// and 'e' binds to the exception. // and 'e' binds to the exception.
function write_0(v) { e = v } function write_0(v) { e = v }
function write_1(v) { x = 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; debugger;
assertEquals("foo", e); // overwritten by the debugger assertEquals("foo", e); // overwritten by the debugger
} }
assertEquals("argument", e); // debugger did not overwrite assertEquals("argument", e); // debugger did not overwrite
function write_2(v) { e = v } function write_2(v) { e = v }
// Make sure write_2 is 'used' so that it is visible to the debugger.
write_2;
debugger; debugger;
assertEquals("bar", e); assertEquals("bar", e);
assertEquals("modified", x); assertEquals("modified", x);
......
...@@ -970,17 +970,6 @@ Running test: testPreciseCountCoveragePartial ...@@ -970,17 +970,6 @@ Running test: testPreciseCountCoveragePartial
} }
] ]
} }
[6] : {
functionName : nested_4
isBlockCoverage : false
ranges : [
[0] : {
count : 0
endOffset : 201
startOffset : 179
}
]
}
] ]
scriptId : <scriptId> scriptId : <scriptId>
url : testPreciseCountCoveragePartial url : testPreciseCountCoveragePartial
......
...@@ -753,17 +753,6 @@ Running test: testPreciseCountCoveragePartial ...@@ -753,17 +753,6 @@ Running test: testPreciseCountCoveragePartial
} }
] ]
} }
[6] : {
functionName : nested_4
isBlockCoverage : false
ranges : [
[0] : {
count : 0
endOffset : 201
startOffset : 179
}
]
}
] ]
scriptId : <scriptId> scriptId : <scriptId>
url : testPreciseCountCoveragePartial url : testPreciseCountCoveragePartial
......
...@@ -267,7 +267,11 @@ function foo6() { Promise.resolve().then(() => 42^) } ...@@ -267,7 +267,11 @@ function foo6() { Promise.resolve().then(() => 42^) }
Running test: arrowFunctionReturn Running test: arrowFunctionReturn
#() => #239# #() => #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 #} #() => { #239 #}
# #
......
...@@ -135,6 +135,8 @@ function foo6() { Promise.resolve().then(() => 42) } ...@@ -135,6 +135,8 @@ function foo6() { Promise.resolve().then(() => 42) }
checkSource('() => 239\n', { lineNumber: 0, columnNumber: 0 }) 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 } }\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('() => { 239 }\n', { lineNumber: 0, columnNumber: 0 }))
.then(() => checkSource('function foo() { 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. // TODO(kozyatinskiy): lineNumber for return position should be only 9, not 8.
......
...@@ -10,6 +10,7 @@ function testFunction() ...@@ -10,6 +10,7 @@ function testFunction()
var o = 0; var o = 0;
function f() { return 1; } function f() { return 1; }
function g() { o = 2; return o; } function g() { o = 2; return o; }
f,g;
debugger; debugger;
} }
//# sourceURL=foo.js`); //# sourceURL=foo.js`);
......
*%(basename)s:8: SyntaxError: Identifier '*default*' has already been declared *%(basename)s:8: SyntaxError: Identifier '*default*' has already been declared
export default x = 1; export default x = 1;
^ ^^^^^^^^^^^^^
SyntaxError: Identifier '*default*' has already been declared 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