switch (slot->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ cmp(r1, ip);
+ __ Check(eq, "Let binding re-initialization.");
+ }
// Perform the assignment.
__ str(result_register(), MemOperand(fp, SlotOffset(slot)));
break;
case Slot::CONTEXT: {
MemOperand target = EmitSlotSearch(slot, r1);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ ldr(r3, target);
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ cmp(r3, ip);
+ __ Check(eq, "Let binding re-initialization.");
+ }
// Perform the assignment and issue the write barrier.
__ str(result_register(), target);
// RecordWrite may destroy all its register arguments.
}
case Slot::LOOKUP:
+ ASSERT(op != Token::INIT_LET);
// Call the runtime for the assignment.
__ push(r0); // Value.
__ mov(r1, Operand(slot->var()->name()));
switch (slot->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ mov(edx, Operand(ebp, SlotOffset(slot)));
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ Check(equal, "Let binding re-initialization.");
+ }
// Perform the assignment.
__ mov(Operand(ebp, SlotOffset(slot)), eax);
break;
case Slot::CONTEXT: {
MemOperand target = EmitSlotSearch(slot, ecx);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ mov(edx, target);
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ Check(equal, "Let binding re-initialization.");
+ }
// Perform the assignment and issue the write barrier.
__ mov(target, eax);
// The value of the assignment is in eax. RecordWrite clobbers its
}
case Slot::LOOKUP:
+ ASSERT(op != Token::INIT_LET);
// Call the runtime for the assignment.
__ push(eax); // Value.
__ push(esi); // Context.
block->AddStatement(new(zone()) ExpressionStatement(initialize));
}
- // Add an assignment node to the initialization statement block if
- // we still have a pending initialization value. We must distinguish
- // between variables and constants: Variable initializations are simply
+ // Add an assignment node to the initialization statement block if we still
+ // have a pending initialization value. We must distinguish between
+ // different kinds of declarations: 'var' initializations are simply
// assignments (with all the consequences if they are inside a 'with'
// statement - they may change a 'with' object property). Constant
// initializations always assign to the declared constant which is
// always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is
- // the top context for variables). Sigh...
+ // the top context for var declared variables). Sigh...
+ // For 'let' declared variables the initialization is in the same scope
+ // as the declaration. Thus dynamic lookups are unnecessary even if the
+ // block scope is inside a with.
if (value != NULL) {
- bool in_with = is_const ? false : inside_with();
+ bool in_with = mode == Variable::VAR ? inside_with() : false;
VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment =
switch (slot->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ movq(rdx, Operand(rbp, SlotOffset(slot)));
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ Check(equal, "Let binding re-initialization.");
+ }
// Perform the assignment.
__ movq(Operand(rbp, SlotOffset(slot)), rax);
break;
case Slot::CONTEXT: {
MemOperand target = EmitSlotSearch(slot, rcx);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ movq(rdx, target);
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ Check(equal, "Let binding re-initialization.");
+ }
// Perform the assignment and issue the write barrier.
__ movq(target, rax);
// The value of the assignment is in rax. RecordWrite clobbers its
}
case Slot::LOOKUP:
+ ASSERT(op != Token::INIT_LET);
// Call the runtime for the assignment.
__ push(rax); // Value.
__ push(rsi); // Context.
EndTest();
+// With block and a block local variable.
+BeginTest("With block 5");
+
+function with_block_5() {
+ with({a:1}) {
+ let a = 2;
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({a:2}, 0, exec_state);
+ CheckScopeContent({a:1}, 1, exec_state);
+};
+with_block_5();
+EndTest();
+
+
// Simple closure formed by returning an inner function referering to an outer
// block local variable and an outer function's parameter.
BeginTest("Closure 1");