MIPS: port Temporal dead zone behaviour for let bindings.
authorkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 31 Aug 2011 10:01:43 +0000 (10:01 +0000)
committerkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 31 Aug 2011 10:01:43 +0000 (10:01 +0000)
Ported r9070 (1cfdac01)

BUG=
TEST=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9080 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/mips/full-codegen-mips.cc

index 3c0c316e8bb5e56ea21b8ea468c6f5606cb3c029..788fe750ffaf7f4e3fcd0ba9a387a6dcf67a0a8d 100644 (file)
@@ -700,12 +700,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
   switch (slot->type()) {
     case Slot::PARAMETER:
     case Slot::LOCAL:
-      if (mode == Variable::CONST) {
-        __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
-        __ sw(t0, MemOperand(fp, SlotOffset(slot)));
-      } else if (function != NULL) {
+      if (function != NULL) {
         VisitForAccumulatorValue(function);
         __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
+      } else if (mode == Variable::CONST || mode == Variable::LET) {
+          __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+          __ sw(t0, MemOperand(fp, SlotOffset(slot)));
       }
       break;
 
@@ -726,17 +726,17 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
         __ Check(ne, "Declaration in catch context.",
                  a1, Operand(t0));
       }
-      if (mode == Variable::CONST) {
-        __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-        __ sw(at, ContextOperand(cp, slot->index()));
-        // No write barrier since the_hole_value is in old space.
-      } else if (function != NULL) {
+      if (function != NULL) {
         VisitForAccumulatorValue(function);
         __ sw(result_register(), ContextOperand(cp, slot->index()));
         int offset = Context::SlotOffset(slot->index());
         // We know that we have written a function, which is not a smi.
         __ mov(a1, cp);
         __ RecordWrite(a1, Operand(offset), a2, result_register());
+      } else if (mode == Variable::CONST || mode == Variable::LET) {
+          __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+          __ sw(at, ContextOperand(cp, slot->index()));
+          // No write barrier since the_hole_value is in old space.
       }
       break;
 
@@ -752,13 +752,13 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
       // Note: For variables we must not push an initial value (such as
       // 'undefined') because we may have a (legal) redeclaration and we
       // must not destroy the current value.
-      if (mode == Variable::CONST) {
-        __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
-        __ Push(cp, a2, a1, a0);
-      } else if (function != NULL) {
+      if (function != NULL) {
         __ Push(cp, a2, a1);
         // Push initial value for function declaration.
         VisitForStackValue(function);
+      } else if (mode == Variable::CONST || mode == Variable::LET) {
+          __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
+          __ Push(cp, a2, a1, a0);
       } else {
         ASSERT(Smi::FromInt(0) == 0);
         // No initial value!
@@ -1279,9 +1279,22 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
        __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
        __ movz(v0, a0, at);  // Conditional move.
        context()->Plug(v0);
-     } else {
-       context()->Plug(slot);
-     }
+    } else if (var->mode() == Variable::LET) {
+      // Let bindings may be the hole value if they have not been initialized.
+      // Throw a type error in this case.
+      Label done;
+      MemOperand slot_operand = EmitSlotSearch(slot, a0);
+      __ lw(v0, slot_operand);
+      __ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
+      __ Branch(&done, ne, v0, Operand(a1));
+      __ li(v0, Operand(var->name()));
+      __ push(v0);
+      __ CallRuntime(Runtime::kThrowReferenceError, 1);
+      __ bind(&done);
+      context()->Plug(v0);
+    } else {
+      context()->Plug(slot);
+    }
   }
 }
 
@@ -1863,6 +1876,56 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
         break;
     }
     __ bind(&skip);
+  } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
+    // Perform the assignment for non-const variables.  Const assignments
+    // are simply skipped.
+    Slot* slot = var->AsSlot();
+    switch (slot->type()) {
+      case Slot::PARAMETER:
+      case Slot::LOCAL: {
+        Label assign;
+        // Check for an initialized let binding.
+        __ lw(a1, MemOperand(fp, SlotOffset(slot)));
+        __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+        __ Branch(&assign, ne, a1, Operand(t0));
+        __ li(a1, Operand(var->name()));
+        __ push(a1);
+        __ CallRuntime(Runtime::kThrowReferenceError, 1);
+        // Perform the assignment.
+        __ bind(&assign);
+        __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
+        break;
+      }
+      case Slot::CONTEXT: {
+        // Let variables may be the hole value if they have not been
+        // initialized. Throw a type error in this case.
+        Label assign;
+        MemOperand target = EmitSlotSearch(slot, a1);
+        // Check for an initialized let binding.
+        __ lw(a3, target);
+        __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+        __ Branch(&assign, ne, a3, Operand(t0));
+        __ li(a3, Operand(var->name()));
+        __ push(a3);
+        __ CallRuntime(Runtime::kThrowReferenceError, 1);
+        // Perform the assignment.
+        __ bind(&assign);
+        __ sw(result_register(), target);
+        // RecordWrite may destroy all its register arguments.
+        __ mov(a3, result_register());
+        int offset = Context::SlotOffset(slot->index());
+        __ RecordWrite(a1, Operand(offset), a2, a3);
+        break;
+      }
+      case Slot::LOOKUP:
+        // Call the runtime for the assignment.
+        __ push(v0);  // Value.
+        __ li(a1, Operand(slot->var()->name()));
+        __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
+        __ Push(cp, a1, a0);  // Context, name, strict mode.
+        __ CallRuntime(Runtime::kStoreContextSlot, 4);
+        break;
+    }
 
   } else if (var->mode() != Variable::CONST) {
     // Perform the assignment for non-const variables.  Const assignments