From 80048c14b1a1902f7db81ab88868eb4952b6baff Mon Sep 17 00:00:00 2001 From: "keuchel@chromium.org" Date: Thu, 6 Oct 2011 15:24:20 +0000 Subject: [PATCH] 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 --- src/arm/full-codegen-arm.cc | 12 ++++++++++-- src/ia32/full-codegen-ia32.cc | 10 ++++++++-- src/x64/full-codegen-x64.cc | 10 ++++++++-- test/mjsunit/harmony/block-let-semantics.js | 25 ++++++++++++++++++++++++- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 2ee1594..ba21802 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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); - __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); + 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); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index d45a9cd..b66711f 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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); - __ mov(eax, isolate()->factory()->undefined_value()); + if (local->mode() == Variable::CONST) { + __ mov(eax, isolate()->factory()->undefined_value()); + } else { // Variable::LET + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + } } __ jmp(done); } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 1d9b8ff..afcf50a 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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); - __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); + if (local->mode() == Variable::CONST) { + __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); + } else { // Variable::LET + __ Push(var->name()); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + } } __ jmp(done); } diff --git a/test/mjsunit/harmony/block-let-semantics.js b/test/mjsunit/harmony/block-let-semantics.js index 198c3b4..3819a9c 100644 --- a/test/mjsunit/harmony/block-let-semantics.js +++ b/test/mjsunit/harmony/block-let-semantics.js @@ -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()); -- 2.7.4