Fast-codegen: Added support for arguments in functions.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Nov 2009 11:38:01 +0000 (11:38 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Nov 2009 11:38:01 +0000 (11:38 +0000)
Functions using "arguments" have their arguments object created on entry.
Also added support for variables rewritten into argument object property access.

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

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

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

index 56e7ac3..6ddf2ff 100644 (file)
@@ -55,26 +55,56 @@ namespace internal {
 void FastCodeGenerator::Generate(FunctionLiteral* fun) {
   function_ = fun;
   SetFunctionPosition(fun);
+  int locals_count = fun->scope()->num_stack_slots();
 
   __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+  if (locals_count > 0) {
+      // Load undefined value here, so the value is ready for the loop below.
+      __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  }
   // Adjust fp to point to caller's fp.
   __ add(fp, sp, Operand(2 * kPointerSize));
 
   { Comment cmnt(masm_, "[ Allocate locals");
-    int locals_count = fun->scope()->num_stack_slots();
-    if (locals_count > 0) {
-      __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
-    }
-    __ LoadRoot(r2, Heap::kStackLimitRootIndex);
     for (int i = 0; i < locals_count; i++) {
       __ push(ip);
     }
   }
 
+  bool function_in_register = true;
+
+  Variable* arguments = fun->scope()->arguments()->AsVariable();
+  if (arguments != NULL) {
+    // Function uses arguments object.
+    Comment cmnt(masm_, "[ Allocate arguments object");
+    __ mov(r3, r1);
+    // Receiver is just before the parameters on the caller's stack.
+    __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
+                               fun->num_parameters() * kPointerSize));
+    __ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
+    __ stm(db_w, sp, r1.bit() | r2.bit() | r3.bit());
+
+    // Arguments to ArgumentsAccessStub:
+    //   function, receiver address, parameter count.
+    // The stub will rewrite receiever and parameter count if the previous
+    // stack frame was an arguments adapter frame.
+    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    __ CallStub(&stub);
+    __ str(r0, MemOperand(fp, SlotOffset(arguments->slot())));
+    Slot* dot_arguments_slot =
+        fun->scope()->arguments_shadow()->AsVariable()->slot();
+    __ str(r0, MemOperand(fp, SlotOffset(dot_arguments_slot)));
+    function_in_register = false;
+  }
+
   // Possibly allocate a local context.
   if (fun->scope()->num_heap_slots() > 0) {
     Comment cmnt(masm_, "[ Allocate local context");
-    // Argument to NewContext is the function, still in r1.
+    if (!function_in_register) {
+      // Load this again, if it's used by the local context below.
+      __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+    }
+    // Argument to NewContext is the function, which is in r1.
     __ push(r1);
     __ CallRuntime(Runtime::kNewContext, 1);
     // Context is returned in both r0 and cp.  It replaces the context
@@ -94,6 +124,7 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
   // added to the implicit 8 byte offset that always applies to operations
   // with pc and gives a return address 12 bytes down.
   Comment cmnt(masm_, "[ Stack check");
+  __ LoadRoot(r2, Heap::kStackLimitRootIndex);
   __ add(lr, pc, Operand(Assembler::kInstrSize));
   __ cmp(sp, Operand(r2));
   StackCheckStub stub;
@@ -432,7 +463,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
     DropAndMove(expr->context(), r0);
-  } else {
+  } else if (rewrite->AsSlot() != NULL) {
     Slot* slot = rewrite->AsSlot();
     ASSERT_NE(NULL, slot);
     switch (slot->type()) {
@@ -474,6 +505,13 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
         UNREACHABLE();
         break;
     }
+  } else {
+    // The parameter variable has been rewritten into an explict access to
+    // the arguments object.
+    Property* property = rewrite->AsProperty();
+    ASSERT_NOT_NULL(property);
+    ASSERT_EQ(expr->context(), property->context());
+    Visit(property);
   }
 }
 
index 1329cd6..0f23992 100644 (file)
@@ -599,11 +599,6 @@ CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
     }
   }
 
-  if (scope->arguments() != NULL) {
-    if (FLAG_trace_bailout) PrintF("function uses 'arguments'\n");
-    return NORMAL;
-  }
-
   has_supported_syntax_ = true;
   VisitDeclarations(scope->declarations());
   if (!has_supported_syntax_) return NORMAL;
@@ -796,17 +791,21 @@ void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
   if (rewrite != NULL) {
     // Non-global.
     Slot* slot = rewrite->AsSlot();
-    if (slot == NULL) {
-      // This is a variable rewritten to an explicit property access
-      // on the arguments object.
-      BAILOUT("non-global/non-slot variable reference");
-    }
-
-    Slot::Type type = slot->type();
-    // When LOOKUP slots are enabled, some currently dead code
-    // implementing unary typeof will become live.
-    if (type == Slot::LOOKUP) {
-      BAILOUT("Lookup slot");
+    if (slot != NULL) {
+      Slot::Type type = slot->type();
+      // When LOOKUP slots are enabled, some currently dead code
+      // implementing unary typeof will become live.
+      if (type == Slot::LOOKUP) {
+        BAILOUT("Lookup slot");
+      }
+    } else {
+      Property* property = rewrite->AsProperty();
+      // In the presence of an arguments object, parameter variables
+      // are rewritten into property accesses on that object.
+      ASSERT_NOT_NULL(property);
+      ASSERT_NE(Expression::kUninitialized, context_);
+      Visit(property);
+      property->set_context(context_);
     }
   }
 }
index 4ea0950..571e28b 100644 (file)
@@ -67,11 +67,42 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
     }
   }
 
+  bool function_in_register = true;
+
+  Variable* arguments = fun->scope()->arguments()->AsVariable();
+  if (arguments != NULL) {
+    // Function uses arguments object.
+    Comment cmnt(masm_, "[ Allocate arguments object");
+    __ push(edi);
+    // Receiver is just before the parameters on the caller's stack.
+    __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
+                                 fun->num_parameters() * kPointerSize));
+    __ push(edx);
+    __ push(Immediate(Smi::FromInt(fun->num_parameters())));
+    // Arguments to ArgumentsAccessStub:
+    //   function, receiver address, parameter count.
+    // The stub will rewrite receiever and parameter count if the previous
+    // stack frame was an arguments adapter frame.
+    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    __ CallStub(&stub);
+    __ mov(Operand(ebp, SlotOffset(arguments->slot())), eax);
+    Slot* dot_arguments_slot =
+        fun->scope()->arguments_shadow()->AsVariable()->slot();
+    __ mov(Operand(ebp, SlotOffset(dot_arguments_slot)), eax);
+
+    function_in_register = false;
+  }
+
   // Possibly allocate a local context.
   if (fun->scope()->num_heap_slots() > 0) {
     Comment cmnt(masm_, "[ Allocate local context");
-    // Argument to NewContext is the function, still in edi.
-    __ push(edi);
+    if (function_in_register) {
+      // Argument to NewContext is the function, still in edi.
+      __ push(edi);
+    } else {
+      // Argument to NewContext is the function, no longer in edi.
+      __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+    }
     __ CallRuntime(Runtime::kNewContext, 1);
     // Context is returned in both eax and esi.  It replaces the context
     // passed to us.  It's saved in the stack and kept live in esi.
@@ -425,9 +456,8 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
     __ nop();
 
     DropAndMove(expr->context(), eax);
-  } else {
+  } else if (rewrite->AsSlot() != NULL) {
     Slot* slot = rewrite->AsSlot();
-    ASSERT_NE(NULL, slot);
     switch (slot->type()) {
       case Slot::LOCAL:
       case Slot::PARAMETER: {
@@ -468,6 +498,13 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
         UNREACHABLE();
         break;
     }
+  } else {
+    // The parameter variable has been rewritten into an explict access to
+    // the arguments object.
+    Property* property = rewrite->AsProperty();
+    ASSERT_NOT_NULL(property);
+    ASSERT_EQ(expr->context(), property->context());
+    Visit(property);
   }
 }
 
index 04e5239..a0037d4 100644 (file)
@@ -62,16 +62,54 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
 
   { Comment cmnt(masm_, "[ Allocate locals");
     int locals_count = fun->scope()->num_stack_slots();
-    for (int i = 0; i < locals_count; i++) {
-      __ PushRoot(Heap::kUndefinedValueRootIndex);
+    if (locals_count <= 1) {
+      if (locals_count > 0) {
+        __ PushRoot(Heap::kUndefinedValueRootIndex);
+      }
+    } else {
+      __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+      for (int i = 0; i < locals_count; i++) {
+        __ push(rdx);
+      }
     }
   }
 
+  bool function_in_register = true;
+
+  Variable* arguments = fun->scope()->arguments()->AsVariable();
+  if (arguments != NULL) {
+    // Function uses arguments object.
+    Comment cmnt(masm_, "[ Allocate arguments object");
+    __ push(rdi);
+    // The receiver is just before the parameters on the caller's stack.
+    __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
+                                 fun->num_parameters() * kPointerSize));
+    __ push(rdx);
+    __ Push(Smi::FromInt(fun->num_parameters()));
+    // Arguments to ArgumentsAccessStub:
+    //   function, receiver address, parameter count.
+    // The stub will rewrite receiver and parameter count if the previous
+    // stack frame was an arguments adapter frame.
+    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    __ CallStub(&stub);
+    // Store new arguments object in both "arguments" and ".arguments" slots.
+    __ movq(Operand(rbp, SlotOffset(arguments->slot())), rax);
+    Slot* dot_arguments_slot =
+        fun->scope()->arguments_shadow()->AsVariable()->slot();
+    __ movq(Operand(rbp, SlotOffset(dot_arguments_slot)), rax);
+    function_in_register = false;
+  }
+
   // Possibly allocate a local context.
   if (fun->scope()->num_heap_slots() > 0) {
     Comment cmnt(masm_, "[ Allocate local context");
-    // Argument to NewContext is the function, still in rdi.
-    __ push(rdi);
+    if (function_in_register) {
+      // Argument to NewContext is the function, still in rdi.
+      __ push(rdi);
+    } else {
+      // Argument to NewContext is the function, no longer in rdi.
+      __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+    }
     __ CallRuntime(Runtime::kNewContext, 1);
     // Context is returned in both rax and rsi.  It replaces the context
     // passed to us.  It's saved in the stack and kept live in rsi.
@@ -432,9 +470,8 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
     __ nop();
 
     DropAndMove(expr->context(), rax);
-  } else {
+  } else if (rewrite->AsSlot() != NULL) {
     Slot* slot = rewrite->AsSlot();
-    ASSERT_NE(NULL, slot);
     switch (slot->type()) {
       case Slot::LOCAL:
       case Slot::PARAMETER: {
@@ -475,6 +512,13 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
         UNREACHABLE();
         break;
     }
+  } else {
+    // The parameter variable has been rewritten into an explict access to
+    // the arguments object.
+    Property* property = rewrite->AsProperty();
+    ASSERT_NOT_NULL(property);
+    ASSERT_EQ(expr->context(), property->context());
+    Visit(property);
   }
 }