Fix load of potentially eval-shadowed let bindings.

BUG=
TEST=test/mjsunit/harmony/block-let-semantics.js

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9541 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
keuchel@chromium.org 2011-10-06 15:24:20 +00:00
parent fa425b54b7
commit 80048c14b1
4 changed files with 50 additions and 7 deletions

View File

@ -1225,9 +1225,17 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed();
__ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == Variable::CONST) {
if (local->mode() == Variable::CONST ||
local->mode() == Variable::LET) {
__ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
if (local->mode() == Variable::CONST) {
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
} else { // Variable::LET
__ b(ne, done);
__ mov(r0, Operand(var->name()));
__ push(r0);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
}
}
__ jmp(done);
}

View File

@ -1207,10 +1207,16 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed();
__ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == Variable::CONST) {
if (local->mode() == Variable::CONST ||
local->mode() == Variable::LET) {
__ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, done);
if (local->mode() == Variable::CONST) {
__ mov(eax, isolate()->factory()->undefined_value());
} else { // Variable::LET
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kThrowReferenceError, 1);
}
}
__ jmp(done);
}

View File

@ -1184,10 +1184,16 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed();
__ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == Variable::CONST) {
if (local->mode() == Variable::CONST ||
local->mode() == Variable::LET) {
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
__ j(not_equal, done);
if (local->mode() == Variable::CONST) {
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
} else { // Variable::LET
__ Push(var->name());
__ CallRuntime(Runtime::kThrowReferenceError, 1);
}
}
__ jmp(done);
}

View File

@ -81,13 +81,20 @@ TestAll('f()(); let x; function f() { return function() { x += 1; } }');
TestAll('f()(); let x; function f() { return function() { ++x; } }');
TestAll('f()(); let x; function f() { return function() { x++; } }');
// Use in before initialization with a dynamic lookup.
// Use before initialization with a dynamic lookup.
TestAll('eval("x + 1;"); let x;');
TestAll('eval("x = 1;"); let x;');
TestAll('eval("x += 1;"); let x;');
TestAll('eval("++x;"); let x;');
TestAll('eval("x++;"); let x;');
// Use before initialization with check for eval-shadowed bindings.
TestAll('function f() { eval("var y = 2;"); x + 1; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); x = 1; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); x += 1; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); ++x; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); x++; }; f(); let x;');
// Test that variables introduced by function declarations are created and
// initialized upon entering a function / block scope.
function f() {
@ -136,3 +143,19 @@ function f2() {
}
assertEquals(5, n());
}
// Test that resolution of let bound variables works with scopes that call eval.
function outer() {
function middle() {
function inner() {
return x;
}
eval("1 + 1");
return x + inner();
}
let x = 1;
return middle();
}
assertEquals(2, outer());