Add support for all declarations in the top-level compiler:
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 5 Nov 2009 17:33:50 +0000 (17:33 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 5 Nov 2009 17:33:50 +0000 (17:33 +0000)
Until now we only handled global declarations. This change
adds declarations of local variables, consts and functions.

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

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

src/arm/fast-codegen-arm.cc
src/compiler.cc
src/fast-codegen.cc
src/ia32/fast-codegen-ia32.cc
src/x64/fast-codegen-x64.cc

index 65f21b12ef73bef338278994a062254d6f6af448..7b84bacae24bbdf5c0185606aaec28f11e140828 100644 (file)
@@ -294,6 +294,85 @@ void FastCodeGenerator::TestAndBranch(Register source,
 }
 
 
+void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
+  Variable* var = decl->proxy()->var();
+  ASSERT(var != NULL);  // Must have been resolved.
+  Slot* slot = var->slot();
+  ASSERT(slot != NULL);  // No global declarations here.
+
+  // We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
+  switch (slot->type()) {
+    case Slot::LOOKUP: {
+      __ mov(r2, Operand(var->name()));
+      // Declaration nodes are always introduced in one of two modes.
+      ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
+      PropertyAttributes attr = decl->mode() == Variable::VAR ?
+          NONE : READ_ONLY;
+      __ mov(r1, Operand(Smi::FromInt(attr)));
+      // Push initial value, if any.
+      // 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 (decl->mode() == Variable::CONST) {
+        __ mov(r0, Operand(Factory::the_hole_value()));
+        __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
+      } else if (decl->fun() != NULL) {
+        __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit());
+        Visit(decl->fun());  // Initial value for function decl.
+      } else {
+        __ mov(r0, Operand(Smi::FromInt(0)));  // No initial value!
+        __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
+      }
+      __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+      break;
+    }
+    case Slot::LOCAL:
+      if (decl->mode() == Variable::CONST) {
+        __ mov(r0, Operand(Factory::the_hole_value()));
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+        __ pop(r0);
+        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+      }
+      break;
+    case Slot::CONTEXT:
+      // The variable in the decl always resides in the current context.
+      ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
+      if (decl->mode() == Variable::CONST) {
+        __ mov(r0, Operand(Factory::the_hole_value()));
+        if (FLAG_debug_code) {
+          // Check if we have the correct context pointer.
+          __ ldr(r1, CodeGenerator::ContextOperand(
+              cp, Context::FCONTEXT_INDEX));
+          __ cmp(r1, cp);
+          __ Check(eq, "Unexpected declaration in current context.");
+        }
+        __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
+        // No write barrier since the_hole_value is in old space.
+        ASSERT(Heap::InNewSpace(*Factory::the_hole_value()));
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+        __ pop(r0);
+        if (FLAG_debug_code) {
+          // Check if we have the correct context pointer.
+          __ ldr(r1, CodeGenerator::ContextOperand(
+              cp, Context::FCONTEXT_INDEX));
+          __ cmp(r1, cp);
+          __ Check(eq, "Unexpected declaration in current context.");
+        }
+        __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
+        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+        __ mov(r2, Operand(offset));
+        __ RecordWrite(cp, r2, r0);
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
   // Call the runtime to declare the globals.
   // The context is the first argument.
index 53a4685a2ce99bb0ac3acf93ab0a33174e60d9b6..f172143f639081208675069c0903ed811802c04a 100644 (file)
@@ -647,9 +647,8 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
 
 
 void CodeGenSelector::VisitDeclaration(Declaration* decl) {
-  Variable* var = decl->proxy()->var();
-  if (!var->is_global() || var->mode() == Variable::CONST) {
-    BAILOUT("Non-global declaration");
+  if (decl->fun() != NULL) {
+    ProcessExpression(decl->fun(), Expression::kValue);
   }
 }
 
index ad76b10cacde456c9cf7f1651ce67e5a8904f021..f5a6157de94761041b0e0ca674c3142703db771b 100644 (file)
@@ -88,45 +88,44 @@ void FastCodeGenerator::VisitDeclarations(
     // time, we need to "declare" it at runtime to make sure it
     // actually exists in the local context.
     if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
-      UNREACHABLE();
+      VisitDeclaration(decl);
     } else {
       // Count global variables and functions for later processing
       globals++;
     }
   }
 
-  // Return in case of no declared global functions or variables.
-  if (globals == 0) return;
-
   // Compute array of global variable and function declarations.
-  Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
-  for (int j = 0, i = 0; i < length; i++) {
-    Declaration* decl = declarations->at(i);
-    Variable* var = decl->proxy()->var();
-    Slot* slot = var->slot();
-
-    if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
-      array->set(j++, *(var->name()));
-      if (decl->fun() == NULL) {
-        if (var->mode() == Variable::CONST) {
-          // In case this is const property use the hole.
-          array->set_the_hole(j++);
+  // Do nothing in case of no declared global functions or variables.
+  if (globals > 0) {
+    Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
+    for (int j = 0, i = 0; i < length; i++) {
+      Declaration* decl = declarations->at(i);
+      Variable* var = decl->proxy()->var();
+      Slot* slot = var->slot();
+
+      if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
+        array->set(j++, *(var->name()));
+        if (decl->fun() == NULL) {
+          if (var->mode() == Variable::CONST) {
+            // In case this is const property use the hole.
+            array->set_the_hole(j++);
+          } else {
+            array->set_undefined(j++);
+          }
         } else {
-          array->set_undefined(j++);
+          Handle<JSFunction> function =
+              Compiler::BuildBoilerplate(decl->fun(), script_, this);
+          // Check for stack-overflow exception.
+          if (HasStackOverflow()) return;
+          array->set(j++, *function);
         }
-      } else {
-        Handle<JSFunction> function =
-            Compiler::BuildBoilerplate(decl->fun(), script_, this);
-        // Check for stack-overflow exception.
-        if (HasStackOverflow()) return;
-        array->set(j++, *function);
       }
     }
+    // Invoke the platform-dependent code generator to do the actual
+    // declaration the global variables and functions.
+    DeclareGlobals(array);
   }
-
-  // Invoke the platform-dependent code generator to do the actual
-  // declaration the global variables and functions.
-  DeclareGlobals(array);
 }
 
 
@@ -232,11 +231,6 @@ void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
 }
 
 
-void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
-  UNREACHABLE();
-}
-
-
 void FastCodeGenerator::VisitBlock(Block* stmt) {
   Comment cmnt(masm_, "[ Block");
   SetStatementPosition(stmt);
index 638f90e4972ced47e2865e5bae047c609cbd1349..c4d0aa248f77bd24e40418b4bbc229c306b53ff7 100644 (file)
@@ -290,6 +290,80 @@ void FastCodeGenerator::TestAndBranch(Register source,
 }
 
 
+void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
+  Variable* var = decl->proxy()->var();
+  ASSERT(var != NULL);  // Must have been resolved.
+  Slot* slot = var->slot();
+  ASSERT(slot != NULL);  // No global declarations here.
+
+  // We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
+  switch (slot->type()) {
+    case Slot::LOOKUP: {
+      __ push(esi);
+      __ push(Immediate(var->name()));
+      // Declaration nodes are always introduced in one of two modes.
+      ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
+      PropertyAttributes attr =
+          (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
+      __ push(Immediate(Smi::FromInt(attr)));
+      // Push initial value, if any.
+      // 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 (decl->mode() == Variable::CONST) {
+        __ push(Immediate(Factory::the_hole_value()));
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+      } else {
+        __ push(Immediate(Smi::FromInt(0)));  // No initial value!
+      }
+      __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+      break;
+    }
+    case Slot::LOCAL:
+      if (decl->mode() == Variable::CONST) {
+        __ mov(Operand(ebp, SlotOffset(var->slot())),
+               Immediate(Factory::the_hole_value()));
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+        __ pop(Operand(ebp, SlotOffset(var->slot())));
+      }
+      break;
+    case Slot::CONTEXT:
+      // The variable in the decl always resides in the current context.
+      ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
+      if (decl->mode() == Variable::CONST) {
+        __ mov(eax, Immediate(Factory::the_hole_value()));
+        if (FLAG_debug_code) {
+          // Check if we have the correct context pointer.
+          __ mov(ebx,
+                 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
+          __ cmp(ebx, Operand(esi));
+          __ Check(equal, "Unexpected declaration in current context.");
+        }
+        __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
+        // No write barrier since the_hole_value is in old space.
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+        __ pop(eax);
+        if (FLAG_debug_code) {
+          // Check if we have the correct context pointer.
+          __ mov(ebx,
+                 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
+          __ cmp(ebx, Operand(esi));
+          __ Check(equal, "Unexpected declaration in current context.");
+        }
+        __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
+        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+        __ RecordWrite(esi, offset, eax, ecx);
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
   // Call the runtime to declare the globals.
   __ push(esi);  // The context is the first argument.
index 6ec17cae05b8ae80b2da39f7380ff642d62ff62e..8184b52a9fd40f1cfdc1ad33a7ab7e29f5fa874e 100644 (file)
@@ -297,6 +297,81 @@ void FastCodeGenerator::TestAndBranch(Register source,
 }
 
 
+void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
+  Variable* var = decl->proxy()->var();
+  ASSERT(var != NULL);  // Must have been resolved.
+  Slot* slot = var->slot();
+  ASSERT(slot != NULL);  // No global declarations here.
+
+  // We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
+  switch (slot->type()) {
+    case Slot::LOOKUP: {
+      __ push(rsi);
+      __ Push(var->name());
+      // Declaration nodes are always introduced in one of two modes.
+      ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
+      PropertyAttributes attr = decl->mode() == Variable::VAR ?
+          NONE : READ_ONLY;
+      __ Push(Smi::FromInt(attr));
+      // Push initial value, if any.
+      // 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 (decl->mode() == Variable::CONST) {
+        __ Push(Factory::the_hole_value());
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+      } else {
+        __ Push(Smi::FromInt(0));  // no initial value!
+      }
+      __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+      break;
+    }
+    case Slot::LOCAL:
+      if (decl->mode() == Variable::CONST) {
+        __ Move(Operand(rbp, SlotOffset(var->slot())),
+                Factory::the_hole_value());
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+        __ pop(Operand(rbp, SlotOffset(var->slot())));
+      }
+      break;
+    case Slot::CONTEXT:
+      // The variable in the decl always resides in the current context.
+      ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
+      if (decl->mode() == Variable::CONST) {
+        __ Move(rax, Factory::the_hole_value());
+        if (FLAG_debug_code) {
+          // Check if we have the correct context pointer.
+          __ movq(rbx, CodeGenerator::ContextOperand(
+              rsi, Context::FCONTEXT_INDEX));
+          __ cmpq(rbx, rsi);
+          __ Check(equal, "Unexpected declaration in current context.");
+        }
+        __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
+        // No write barrier since the_hole_value is in old space.
+        ASSERT(Heap::InNewSpace(*Factory::the_hole_value()));
+      } else if (decl->fun() != NULL) {
+        Visit(decl->fun());
+        __ pop(rax);
+        if (FLAG_debug_code) {
+          // Check if we have the correct context pointer.
+          __ movq(rbx, CodeGenerator::ContextOperand(
+              rsi, Context::FCONTEXT_INDEX));
+          __ cmpq(rbx, rsi);
+          __ Check(equal, "Unexpected declaration in current context.");
+        }
+        __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
+        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+        __ RecordWrite(rsi, offset, rax, rcx);
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
   // Call the runtime to declare the globals.
   __ push(rsi);  // The context is the first argument.