Remove some initialization checks based on source positions.
This depends on http://codereview.chromium.org/8352039 and http://codereview.chromium.org/8423005 . Review URL: http://codereview.chromium.org/8422010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9870 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
58123bff56
commit
fd21937812
@ -1283,9 +1283,38 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
Comment cmnt(masm_, var->IsContextSlot()
|
||||
? "Context variable"
|
||||
: "Stack variable");
|
||||
if (!var->binding_needs_init()) {
|
||||
context()->Plug(var);
|
||||
} else {
|
||||
if (var->binding_needs_init()) {
|
||||
// var->scope() may be NULL when the proxy is located in eval code and
|
||||
// refers to a potential outside binding. Currently those bindings are
|
||||
// always looked up dynamically, i.e. in that case
|
||||
// var->location() == LOOKUP.
|
||||
// always holds.
|
||||
ASSERT(var->scope() != NULL);
|
||||
|
||||
// Check if the binding really needs an initialization check. The check
|
||||
// can be skipped in the following situation: we have a LET or CONST
|
||||
// binding in harmony mode, both the Variable and the VariableProxy have
|
||||
// the same declaration scope (i.e. they are both in global code, in the
|
||||
// same function or in the same eval code) and the VariableProxy is in
|
||||
// the source physically located after the initializer of the variable.
|
||||
//
|
||||
// We cannot skip any initialization checks for CONST in non-harmony
|
||||
// mode because const variables may be declared but never initialized:
|
||||
// if (false) { const x; }; var y = x;
|
||||
//
|
||||
// The condition on the declaration scopes is a conservative check for
|
||||
// nested functions that access a binding and are called before the
|
||||
// binding is initialized:
|
||||
// function() { f(); let x = 1; function f() { x = 2; } }
|
||||
//
|
||||
// Check that we always have valid source position.
|
||||
ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
|
||||
ASSERT(proxy->position() != RelocInfo::kNoPosition);
|
||||
bool skip_init_check =
|
||||
var->mode() != CONST &&
|
||||
var->scope()->DeclarationScope() == scope()->DeclarationScope() &&
|
||||
var->initializer_position() < proxy->position();
|
||||
if (!skip_init_check) {
|
||||
// Let and const need a read barrier.
|
||||
GetVar(r0, var);
|
||||
__ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
|
||||
@ -1304,7 +1333,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
|
||||
}
|
||||
context()->Plug(r0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context()->Plug(var);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1234,9 +1234,38 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
Comment cmnt(masm_, var->IsContextSlot()
|
||||
? "Context variable"
|
||||
: "Stack variable");
|
||||
if (!var->binding_needs_init()) {
|
||||
context()->Plug(var);
|
||||
} else {
|
||||
if (var->binding_needs_init()) {
|
||||
// var->scope() may be NULL when the proxy is located in eval code and
|
||||
// refers to a potential outside binding. Currently those bindings are
|
||||
// always looked up dynamically, i.e. in that case
|
||||
// var->location() == LOOKUP.
|
||||
// always holds.
|
||||
ASSERT(var->scope() != NULL);
|
||||
|
||||
// Check if the binding really needs an initialization check. The check
|
||||
// can be skipped in the following situation: we have a LET or CONST
|
||||
// binding in harmony mode, both the Variable and the VariableProxy have
|
||||
// the same declaration scope (i.e. they are both in global code, in the
|
||||
// same function or in the same eval code) and the VariableProxy is in
|
||||
// the source physically located after the initializer of the variable.
|
||||
//
|
||||
// We cannot skip any initialization checks for CONST in non-harmony
|
||||
// mode because const variables may be declared but never initialized:
|
||||
// if (false) { const x; }; var y = x;
|
||||
//
|
||||
// The condition on the declaration scopes is a conservative check for
|
||||
// nested functions that access a binding and are called before the
|
||||
// binding is initialized:
|
||||
// function() { f(); let x = 1; function f() { x = 2; } }
|
||||
//
|
||||
// Check that we always have valid source position.
|
||||
ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
|
||||
ASSERT(proxy->position() != RelocInfo::kNoPosition);
|
||||
bool skip_init_check =
|
||||
var->mode() != CONST &&
|
||||
var->scope()->DeclarationScope() == scope()->DeclarationScope() &&
|
||||
var->initializer_position() < proxy->position();
|
||||
if (!skip_init_check) {
|
||||
// Let and const need a read barrier.
|
||||
Label done;
|
||||
GetVar(eax, var);
|
||||
@ -1254,7 +1283,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
}
|
||||
__ bind(&done);
|
||||
context()->Plug(eax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context()->Plug(var);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1773,7 +1773,7 @@ Block* Parser::ParseVariableDeclarations(
|
||||
// For let/const declarations in harmony mode, we can also immediately
|
||||
// pre-resolve the proxy because it resides in the same scope as the
|
||||
// declaration.
|
||||
Declare(name, mode, NULL, mode != VAR, CHECK_OK);
|
||||
VariableProxy* proxy = Declare(name, mode, NULL, mode != VAR, CHECK_OK);
|
||||
nvars++;
|
||||
if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
|
||||
ReportMessageAt(scanner().location(), "too_many_variables",
|
||||
@ -1828,6 +1828,11 @@ Block* Parser::ParseVariableDeclarations(
|
||||
if (decl_props != NULL) *decl_props = kHasInitializers;
|
||||
}
|
||||
|
||||
// Record the end position of the initializer.
|
||||
if (proxy->var() != NULL) {
|
||||
proxy->var()->set_initializer_position(scanner().location().end_pos);
|
||||
}
|
||||
|
||||
// Make sure that 'const x' and 'let x' initialize 'x' to undefined.
|
||||
if (value == NULL && needs_init) {
|
||||
value = GetLiteralUndefined();
|
||||
|
@ -66,6 +66,7 @@ Variable::Variable(Scope* scope,
|
||||
kind_(kind),
|
||||
location_(UNALLOCATED),
|
||||
index_(-1),
|
||||
initializer_position_(RelocInfo::kNoPosition),
|
||||
local_if_not_shadowed_(NULL),
|
||||
is_valid_LHS_(is_valid_LHS),
|
||||
is_accessed_from_inner_scope_(false),
|
||||
|
@ -103,6 +103,9 @@ class Variable: public ZoneObject {
|
||||
bool is_used() { return is_used_; }
|
||||
void set_is_used(bool flag) { is_used_ = flag; }
|
||||
|
||||
int initializer_position() { return initializer_position_; }
|
||||
void set_initializer_position(int pos) { initializer_position_ = pos; }
|
||||
|
||||
bool IsVariable(Handle<String> n) const {
|
||||
return !is_this() && name().is_identical_to(n);
|
||||
}
|
||||
@ -163,6 +166,7 @@ class Variable: public ZoneObject {
|
||||
Kind kind_;
|
||||
Location location_;
|
||||
int index_;
|
||||
int initializer_position_;
|
||||
|
||||
// If this field is set, this variable references the stored locally bound
|
||||
// variable, but it might be shadowed by variable bindings introduced by
|
||||
|
@ -1240,9 +1240,38 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
case Variable::LOCAL:
|
||||
case Variable::CONTEXT: {
|
||||
Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
|
||||
if (!var->binding_needs_init()) {
|
||||
context()->Plug(var);
|
||||
} else {
|
||||
if (var->binding_needs_init()) {
|
||||
// var->scope() may be NULL when the proxy is located in eval code and
|
||||
// refers to a potential outside binding. Currently those bindings are
|
||||
// always looked up dynamically, i.e. in that case
|
||||
// var->location() == LOOKUP.
|
||||
// always holds.
|
||||
ASSERT(var->scope() != NULL);
|
||||
|
||||
// Check if the binding really needs an initialization check. The check
|
||||
// can be skipped in the following situation: we have a LET or CONST
|
||||
// binding in harmony mode, both the Variable and the VariableProxy have
|
||||
// the same declaration scope (i.e. they are both in global code, in the
|
||||
// same function or in the same eval code) and the VariableProxy is in
|
||||
// the source physically located after the initializer of the variable.
|
||||
//
|
||||
// We cannot skip any initialization checks for CONST in non-harmony
|
||||
// mode because const variables may be declared but never initialized:
|
||||
// if (false) { const x; }; var y = x;
|
||||
//
|
||||
// The condition on the declaration scopes is a conservative check for
|
||||
// nested functions that access a binding and are called before the
|
||||
// binding is initialized:
|
||||
// function() { f(); let x = 1; function f() { x = 2; } }
|
||||
//
|
||||
// Check that we always have valid source position.
|
||||
ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
|
||||
ASSERT(proxy->position() != RelocInfo::kNoPosition);
|
||||
bool skip_init_check =
|
||||
var->mode() != CONST &&
|
||||
var->scope()->DeclarationScope() == scope()->DeclarationScope() &&
|
||||
var->initializer_position() < proxy->position();
|
||||
if (!skip_init_check) {
|
||||
// Let and const need a read barrier.
|
||||
Label done;
|
||||
GetVar(rax, var);
|
||||
@ -1260,7 +1289,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
}
|
||||
__ bind(&done);
|
||||
context()->Plug(rax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context()->Plug(var);
|
||||
break;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user