Commit 8b34f463 authored by keuchel@chromium.org's avatar keuchel@chromium.org

Hydrogen support for stack local harmony bindings in function scope.

This is the first CL in a series that add support for the harmony scoping
features to crankshaft. This CL specifically adds support for stack
allocated 'let' and 'const' declared variables in function scopes.

TEST=mjsunit/harmony/block-let-crankshaft.js

Review URL: http://codereview.chromium.org/8806012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10171 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 087737cb
...@@ -3228,11 +3228,11 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { ...@@ -3228,11 +3228,11 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
Variable* variable = expr->var(); Variable* variable = expr->var();
if (variable->mode() == LET) {
return Bailout("reference to let variable");
}
switch (variable->location()) { switch (variable->location()) {
case Variable::UNALLOCATED: { case Variable::UNALLOCATED: {
if (variable->mode() == LET || variable->mode() == CONST_HARMONY) {
return Bailout("reference to global harmony declared variable");
}
// Handle known global constants like 'undefined' specially to avoid a // Handle known global constants like 'undefined' specially to avoid a
// load from a global cell for them. // load from a global cell for them.
Handle<Object> constant_value = Handle<Object> constant_value =
...@@ -3275,14 +3275,19 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { ...@@ -3275,14 +3275,19 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
case Variable::PARAMETER: case Variable::PARAMETER:
case Variable::LOCAL: { case Variable::LOCAL: {
HValue* value = environment()->Lookup(variable); HValue* value = environment()->Lookup(variable);
if (variable->mode() == CONST && if (value == graph()->GetConstantHole()) {
value == graph()->GetConstantHole()) { ASSERT(variable->mode() == CONST ||
return Bailout("reference to uninitialized const variable"); variable->mode() == CONST_HARMONY ||
variable->mode() == LET);
return Bailout("reference to uninitialized variable");
} }
return ast_context()->ReturnValue(value); return ast_context()->ReturnValue(value);
} }
case Variable::CONTEXT: { case Variable::CONTEXT: {
if (variable->mode() == LET || variable->mode() == CONST_HARMONY) {
return Bailout("reference to harmony declared context slot");
}
if (variable->mode() == CONST) { if (variable->mode() == CONST) {
return Bailout("reference to const context slot"); return Bailout("reference to const context slot");
} }
...@@ -3963,7 +3968,16 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -3963,7 +3968,16 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
HValue* old_value = environment()->Lookup(var); HValue* old_value = environment()->Lookup(var);
AddInstruction(new HUseConst(old_value)); AddInstruction(new HUseConst(old_value));
} else if (var->mode() == LET) { } else if (var->mode() == LET) {
return Bailout("unsupported assignment to let"); if (!var->IsStackAllocated()) {
return Bailout("assignment to let context slot");
}
} else if (var->mode() == CONST_HARMONY) {
if (expr->op() != Token::INIT_CONST_HARMONY) {
return Bailout("non-initializer assignment to const");
}
if (!var->IsStackAllocated()) {
return Bailout("assignment to const context slot");
}
} }
if (proxy->IsArguments()) return Bailout("assignment to arguments"); if (proxy->IsArguments()) return Bailout("assignment to arguments");
...@@ -3980,6 +3994,14 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -3980,6 +3994,14 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
case Variable::PARAMETER: case Variable::PARAMETER:
case Variable::LOCAL: { case Variable::LOCAL: {
// Perform an initialization check for let declared variables
// or parameters.
if (var->mode() == LET && expr->op() == Token::ASSIGN) {
HValue* env_value = environment()->Lookup(var);
if (env_value == graph()->GetConstantHole()) {
return Bailout("assignment to let variable before initialization");
}
}
// We do not allow the arguments object to occur in a context where it // We do not allow the arguments object to occur in a context where it
// may escape, but assignments to stack-allocated locals are // may escape, but assignments to stack-allocated locals are
// permitted. // permitted.
...@@ -6191,23 +6213,22 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) { ...@@ -6191,23 +6213,22 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) {
void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
VariableMode mode, VariableMode mode,
FunctionLiteral* function) { FunctionLiteral* function) {
if (mode == LET || mode == CONST_HARMONY) {
return Bailout("unsupported harmony declaration");
}
Variable* var = proxy->var(); Variable* var = proxy->var();
bool binding_needs_init =
(mode == CONST || mode == CONST_HARMONY || mode == LET);
switch (var->location()) { switch (var->location()) {
case Variable::UNALLOCATED: case Variable::UNALLOCATED:
return Bailout("unsupported global declaration"); return Bailout("unsupported global declaration");
case Variable::PARAMETER: case Variable::PARAMETER:
case Variable::LOCAL: case Variable::LOCAL:
case Variable::CONTEXT: case Variable::CONTEXT:
if (mode == CONST || function != NULL) { if (binding_needs_init || function != NULL) {
HValue* value = NULL; HValue* value = NULL;
if (mode == CONST) { if (function != NULL) {
value = graph()->GetConstantHole();
} else {
VisitForValue(function); VisitForValue(function);
value = Pop(); value = Pop();
} else {
value = graph()->GetConstantHole();
} }
if (var->IsContextSlot()) { if (var->IsContextSlot()) {
HValue* context = environment()->LookupContext(); HValue* context = environment()->LookupContext();
......
...@@ -30,8 +30,116 @@ ...@@ -30,8 +30,116 @@
// TODO(ES6): properly activate extended mode // TODO(ES6): properly activate extended mode
"use strict"; "use strict";
// Check that the following functions are optimizable.
var functions = [ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12 ];
for (var i = 0; i < functions.length; ++i) {
var func = functions[i];
print("Testing:");
print(func);
for (var j = 0; j < 10; ++j) {
func(12);
}
%OptimizeFunctionOnNextCall(func);
func(12);
assertTrue(%GetOptimizationStatus(func) != 2);
}
function f1() { }
function f2(x) { }
function f3() {
let x;
}
function f4() {
function foo() {
}
}
function f5() {
let x = 1;
}
function f6() {
const x = 1;
}
function f7(x) {
return x;
}
function f8() {
let x;
return x;
}
function f9() {
function x() {
}
return x;
}
function f10(x) {
x = 1;
}
function f11() {
let x;
x = 1;
}
function f12() {
function x() {};
x = 1;
}
// Test that temporal dead zone semantics for function and block scoped // Test that temporal dead zone semantics for function and block scoped
// ket bindings are handled by the optimizing compiler. // let bindings are handled by the optimizing compiler.
function TestFunctionLocal(s) {
'use strict';
var func = eval("(function baz(){" + s + "; })");
print("Testing:");
print(func);
for (var i = 0; i < 5; ++i) {
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
%OptimizeFunctionOnNextCall(func);
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
function TestAll(s) {
TestFunctionLocal(s);
}
// Use before initialization in declaration statement.
TestAll('let x = x + 1');
TestAll('let x = x += 1');
TestAll('let x = x++');
TestAll('let x = ++x');
TestAll('const x = x + 1');
// Use before initialization in prior statement.
TestAll('x + 1; let x;');
TestAll('x = 1; let x;');
TestAll('x += 1; let x;');
TestAll('++x; let x;');
TestAll('x++; let x;');
TestAll('let y = x; const x = 1;');
function f(x, b) { function f(x, b) {
let y = (b ? y : x) + 42; let y = (b ? y : x) + 42;
......
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