Revision: 3760
Author: [email protected]
Date: Mon Feb  1 09:01:58 2010
Log: Implement simple fast-path code for functions containing this property stores and global variables.

Code is specialized to the initial receiver.

Review URL: http://codereview.chromium.org/553149
http://code.google.com/p/v8/source/detail?r=3760

Added:
 /branches/bleeding_edge/src/arm/fast-codegen-arm.cc
 /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc
 /branches/bleeding_edge/src/x64/fast-codegen-x64.cc
Modified:
 /branches/bleeding_edge/src/SConscript
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/compiler.cc
 /branches/bleeding_edge/src/compiler.h
 /branches/bleeding_edge/src/data-flow.cc
 /branches/bleeding_edge/src/data-flow.h
 /branches/bleeding_edge/src/fast-codegen.cc
 /branches/bleeding_edge/src/fast-codegen.h
 /branches/bleeding_edge/src/full-codegen.cc
 /branches/bleeding_edge/src/full-codegen.h
 /branches/bleeding_edge/src/ia32/codegen-ia32.h
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/x64/codegen-x64.h
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/tools/gyp/v8.gyp
 /branches/bleeding_edge/tools/visual_studio/v8_base.vcproj
 /branches/bleeding_edge/tools/visual_studio/v8_base_arm.vcproj
 /branches/bleeding_edge/tools/visual_studio/v8_base_x64.vcproj

=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Feb 1 09:01:58 2010
@@ -0,0 +1,139 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "fast-codegen.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm())
+
+void FastCodeGenerator::EmitLoadReceiver(Register reg) {
+  // Offset 2 is due to return address and saved frame pointer.
+  int index = 2 + function()->scope()->num_parameters();
+  __ ldr(reg, MemOperand(sp, index * kPointerSize));
+}
+
+
+void FastCodeGenerator::EmitReceiverMapCheck() {
+  Comment cmnt(masm(), ";; MapCheck(this)");
+  if (FLAG_print_ir) {
+    PrintF("MapCheck(this)\n");
+  }
+
+  EmitLoadReceiver(r1);
+  __ BranchOnSmi(r1, bailout());
+
+  ASSERT(has_receiver() && receiver()->IsHeapObject());
+  Handle<HeapObject> object = Handle<HeapObject>::cast(receiver());
+  Handle<Map> map(object->map());
+  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ mov(ip, Operand(map));
+  __ cmp(r3, ip);
+  __ b(ne, bailout());
+}
+
+
+void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
+  // Compile global variable accesses as load IC calls.  The only live
+ // registers are cp (context) and possibly r1 (this). Both are also saved
+  // in the stack and cp is preserved by the call.
+  __ ldr(ip, CodeGenerator::GlobalObject());
+  __ push(ip);
+  __ mov(r2, Operand(name));
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+  if (has_this_properties()) {
+    // Restore this.
+    EmitLoadReceiver(r1);
+  }
+}
+
+
+void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
+  LookupResult lookup;
+  receiver()->Lookup(*name, &lookup);
+
+  ASSERT(lookup.holder() == *receiver());
+  ASSERT(lookup.type() == FIELD);
+  Handle<Map> map(Handle<HeapObject>::cast(receiver())->map());
+  int index = lookup.GetFieldIndex() - map->inobject_properties();
+  int offset = index * kPointerSize;
+
+  // Negative offsets are inobject properties.
+  if (offset < 0) {
+    offset += map->instance_size();
+    __ mov(r2, r1);  // Copy receiver for write barrier.
+  } else {
+    offset += FixedArray::kHeaderSize;
+    __ ldr(r2, FieldMemOperand(r1, JSObject::kPropertiesOffset));
+  }
+  // Perform the store.
+  __ str(r0, FieldMemOperand(r2, offset));
+  __ mov(r3, Operand(offset));
+  __ RecordWrite(r2, r3, ip);
+}
+
+
+void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
+  ASSERT(function_ == NULL);
+  ASSERT(info_ == NULL);
+  function_ = fun;
+  info_ = info;
+
+  // Save the caller's frame pointer and set up our own.
+  Comment prologue_cmnt(masm(), ";; Prologue");
+  __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+  // Note that we keep a live register reference to cp (context) at
+  // this point.
+
+  // Receiver (this) is allocated to r1 if there are this properties.
+  if (has_this_properties()) EmitReceiverMapCheck();
+
+  VisitStatements(fun->body());
+
+  Comment return_cmnt(masm(), ";; Return(<undefined>)");
+  __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
+
+  Comment epilogue_cmnt(masm(), ";; Epilogue");
+  __ mov(sp, fp);
+  __ ldm(ia_w, sp, fp.bit() | lr.bit());
+  int32_t sp_delta = (fun->scope()->num_parameters() + 1) * kPointerSize;
+  __ add(sp, sp, Operand(sp_delta));
+  __ Jump(lr);
+
+  __ bind(&bailout_);
+}
+
+
+#undef __
+
+
+} }  // namespace v8::internal
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Mon Feb 1 09:01:58 2010
@@ -0,0 +1,141 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "fast-codegen.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm())
+
+void FastCodeGenerator::EmitLoadReceiver(Register reg) {
+  // Offset 2 is due to return address and saved frame pointer.
+  int index = 2 + function()->scope()->num_parameters();
+  __ mov(reg, Operand(ebp, index * kPointerSize));
+}
+
+
+void FastCodeGenerator::EmitReceiverMapCheck() {
+  Comment cmnt(masm(), ";; MapCheck(this)");
+  if (FLAG_print_ir) {
+    PrintF("MapCheck(this)\n");
+  }
+
+  EmitLoadReceiver(edx);
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, bailout());
+
+  ASSERT(has_receiver() && receiver()->IsHeapObject());
+  Handle<HeapObject> object = Handle<HeapObject>::cast(receiver());
+  Handle<Map> map(object->map());
+  __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Immediate(map));
+  __ j(not_equal, bailout());
+}
+
+
+void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
+  // Compile global variable accesses as load IC calls.  The only live
+  // registers are esi (context) and possibly edx (this).  Both are also
+  // saved in the stack and esi is preserved by the call.
+  __ push(CodeGenerator::GlobalObject());
+  __ mov(ecx, name);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+  __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+  if (has_this_properties()) {
+    // Restore this.
+    EmitLoadReceiver(edx);
+  } else {
+ __ nop(); // Not test eax, indicates IC has no inlined code at call site.
+  }
+}
+
+
+void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
+  LookupResult lookup;
+  receiver()->Lookup(*name, &lookup);
+
+  ASSERT(lookup.holder() == *receiver());
+  ASSERT(lookup.type() == FIELD);
+  Handle<Map> map(Handle<HeapObject>::cast(receiver())->map());
+  int index = lookup.GetFieldIndex() - map->inobject_properties();
+  int offset = index * kPointerSize;
+
+  // Negative offsets are inobject properties.
+  if (offset < 0) {
+    offset += map->instance_size();
+    __ mov(ecx, edx);  // Copy receiver for write barrier.
+  } else {
+    offset += FixedArray::kHeaderSize;
+    __ mov(ecx, FieldOperand(edx, JSObject::kPropertiesOffset));
+  }
+  // Perform the store.
+  __ mov(FieldOperand(ecx, offset), eax);
+  // Preserve value from write barrier in case it's needed.
+  __ mov(ebx, eax);
+  __ RecordWrite(ecx, offset, ebx, edi);
+}
+
+
+void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
+  ASSERT(function_ == NULL);
+  ASSERT(info_ == NULL);
+  function_ = fun;
+  info_ = info;
+
+  // Save the caller's frame pointer and set up our own.
+  Comment prologue_cmnt(masm(), ";; Prologue");
+  __ push(ebp);
+  __ mov(ebp, esp);
+  __ push(esi);  // Context.
+  __ push(edi);  // Closure.
+  // Note that we keep a live register reference to esi (context) at this
+  // point.
+
+  // Receiver (this) is allocated to edx if there are this properties.
+  if (has_this_properties()) EmitReceiverMapCheck();
+
+  VisitStatements(fun->body());
+
+  Comment return_cmnt(masm(), ";; Return(<undefined>)");
+  __ mov(eax, Factory::undefined_value());
+
+  Comment epilogue_cmnt(masm(), ";; Epilogue");
+  __ mov(esp, ebp);
+  __ pop(ebp);
+  __ ret((fun->scope()->num_parameters() + 1) * kPointerSize);
+
+  __ bind(&bailout_);
+}
+
+
+#undef __
+
+
+} }  // namespace v8::internal
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Feb 1 09:01:58 2010
@@ -0,0 +1,140 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "fast-codegen.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm())
+
+void FastCodeGenerator::EmitLoadReceiver(Register reg) {
+  // Offset 2 is due to return address and saved frame pointer.
+  int index = 2 + function()->scope()->num_parameters();
+  __ movq(reg, Operand(rbp, index * kPointerSize));
+}
+
+
+void FastCodeGenerator::EmitReceiverMapCheck() {
+  Comment cmnt(masm(), ";; MapCheck(this)");
+  if (FLAG_print_ir) {
+    PrintF("MapCheck(this)\n");
+  }
+
+  EmitLoadReceiver(rdx);
+  __ JumpIfSmi(rdx, bailout());
+
+  ASSERT(has_receiver() && receiver()->IsHeapObject());
+  Handle<HeapObject> object = Handle<HeapObject>::cast(receiver());
+  Handle<Map> map(object->map());
+  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), map);
+  __ j(not_equal, bailout());
+}
+
+
+void FastCodeGenerator::EmitGlobalVariableLoad(Handle<String> name) {
+  // Compile global variable accesses as load IC calls.  The only live
+  // registers are rsi (context) and possibly rdx (this).  Both are also
+  // saved in the stack and rsi is preserved by the call.
+  __ push(CodeGenerator::GlobalObject());
+  __ Move(rcx, name);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+  __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+  if (has_this_properties()) {
+    // Restore this.
+    EmitLoadReceiver(rdx);
+  } else {
+ __ nop(); // Not test rax, indicates IC has no inlined code at call site.
+  }
+}
+
+
+void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
+  LookupResult lookup;
+  receiver()->Lookup(*name, &lookup);
+
+  ASSERT(lookup.holder() == *receiver());
+  ASSERT(lookup.type() == FIELD);
+  Handle<Map> map(Handle<HeapObject>::cast(receiver())->map());
+  int index = lookup.GetFieldIndex() - map->inobject_properties();
+  int offset = index * kPointerSize;
+
+  // Negative offsets are inobject properties.
+  if (offset < 0) {
+    offset += map->instance_size();
+    __ movq(rcx, rdx);  // Copy receiver for write barrier.
+  } else {
+    offset += FixedArray::kHeaderSize;
+    __ movq(rcx, FieldOperand(rdx, JSObject::kPropertiesOffset));
+  }
+  // Perform the store.
+  __ movq(FieldOperand(rcx, offset), rax);
+  // Preserve value from write barrier in case it's needed.
+  __ movq(rbx, rax);
+  __ RecordWrite(rcx, offset, rbx, rdi);
+}
+
+
+void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
+  ASSERT(function_ == NULL);
+  ASSERT(info_ == NULL);
+  function_ = fun;
+  info_ = info;
+
+  // Save the caller's frame pointer and set up our own.
+  Comment prologue_cmnt(masm(), ";; Prologue");
+  __ push(rbp);
+  __ movq(rbp, rsp);
+  __ push(rsi);  // Context.
+  __ push(rdi);  // Closure.
+  // Note that we keep a live register reference to esi (context) at this
+  // point.
+
+  // Receiver (this) is allocated to rdx if there are this properties.
+  if (has_this_properties()) EmitReceiverMapCheck();
+
+  VisitStatements(fun->body());
+
+  Comment return_cmnt(masm(), ";; Return(<undefined>)");
+  __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+
+  Comment epilogue_cmnt(masm(), ";; Epilogue");
+  __ movq(rsp, rbp);
+  __ pop(rbp);
+  __ ret((fun->scope()->num_parameters() + 1) * kPointerSize);
+
+  __ bind(&bailout_);
+}
+
+
+#undef __
+
+
+} }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/SConscript      Fri Jan 29 01:42:13 2010
+++ /branches/bleeding_edge/src/SConscript      Mon Feb  1 09:01:58 2010
@@ -114,6 +114,7 @@
     arm/cpu-arm.cc
     arm/debug-arm.cc
     arm/disasm-arm.cc
+    arm/fast-codegen-arm.cc
     arm/frames-arm.cc
     arm/full-codegen-arm.cc
     arm/ic-arm.cc
@@ -137,6 +138,7 @@
     ia32/cpu-ia32.cc
     ia32/debug-ia32.cc
     ia32/disasm-ia32.cc
+    ia32/fast-codegen-ia32.cc
     ia32/frames-ia32.cc
     ia32/full-codegen-ia32.cc
     ia32/ic-ia32.cc
@@ -154,6 +156,7 @@
     x64/cpu-x64.cc
     x64/debug-x64.cc
     x64/disasm-x64.cc
+    x64/fast-codegen-x64.cc
     x64/frames-x64.cc
     x64/full-codegen-x64.cc
     x64/ic-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Mon Feb  1 05:07:53 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Mon Feb  1 09:01:58 2010
@@ -444,6 +444,7 @@
   friend class VirtualFrame;
   friend class JumpTarget;
   friend class Reference;
+  friend class FastCodeGenerator;
   friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Feb 1 05:20:43 2010 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Feb 1 09:01:58 2010
@@ -52,80 +52,84 @@
 //
 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
 // frames-arm.h for its layout.
-void FullCodeGenerator::Generate(FunctionLiteral* fun) {
+void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
   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.
+
+  if (mode == PRIMARY) {
+    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");
-    for (int i = 0; i < locals_count; i++) {
-      __ push(ip);
-    }
-  }
-
-  bool function_in_register = true;
-
-  // Possibly allocate a local context.
-  if (fun->scope()->num_heap_slots() > 0) {
-    Comment cmnt(masm_, "[ Allocate local context");
-    // Argument to NewContext is the function, which is in r1.
-    __ push(r1);
-    __ CallRuntime(Runtime::kNewContext, 1);
-    function_in_register = false;
-    // Context is returned in both r0 and cp.  It replaces the context
-    // passed to us.  It's saved in the stack and kept live in cp.
-    __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-    // Copy any necessary parameters into the context.
-    int num_parameters = fun->scope()->num_parameters();
-    for (int i = 0; i < num_parameters; i++) {
-      Slot* slot = fun->scope()->parameter(i)->slot();
-      if (slot != NULL && slot->type() == Slot::CONTEXT) {
-        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
-                               (num_parameters - 1 - i) * kPointerSize;
-        // Load parameter from stack.
-        __ ldr(r0, MemOperand(fp, parameter_offset));
-        // Store it in the context
-        __ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
+    }
+    // Adjust fp to point to caller's fp.
+    __ add(fp, sp, Operand(2 * kPointerSize));
+
+    { Comment cmnt(masm_, "[ Allocate locals");
+      for (int i = 0; i < locals_count; i++) {
+        __ push(ip);
+      }
+    }
+
+    bool function_in_register = true;
+
+    // Possibly allocate a local context.
+    if (fun->scope()->num_heap_slots() > 0) {
+      Comment cmnt(masm_, "[ Allocate local context");
+      // Argument to NewContext is the function, which is in r1.
+      __ push(r1);
+      __ CallRuntime(Runtime::kNewContext, 1);
+      function_in_register = false;
+      // Context is returned in both r0 and cp.  It replaces the context
+      // passed to us.  It's saved in the stack and kept live in cp.
+      __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      // Copy any necessary parameters into the context.
+      int num_parameters = fun->scope()->num_parameters();
+      for (int i = 0; i < num_parameters; i++) {
+        Slot* slot = fun->scope()->parameter(i)->slot();
+        if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+                                   (num_parameters - 1 - i) * kPointerSize;
+          // Load parameter from stack.
+          __ ldr(r0, MemOperand(fp, parameter_offset));
+          // Store it in the context
+          __ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
+        }
       }
     }
-  }
-
-  Variable* arguments = fun->scope()->arguments()->AsVariable();
-  if (arguments != NULL) {
-    // Function uses arguments object.
-    Comment cmnt(masm_, "[ Allocate arguments object");
-    if (!function_in_register) {
-      // Load this again, if it's used by the local context below.
- __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-    } else {
-      __ 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, r3.bit() | r2.bit() | r1.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);
-    // Duplicate the value; move-to-slot operation might clobber registers.
-    __ mov(r3, r0);
-    Move(arguments->slot(), r0, r1, r2);
-    Slot* dot_arguments_slot =
-        fun->scope()->arguments_shadow()->AsVariable()->slot();
-    Move(dot_arguments_slot, r3, r1, r2);
+
+    Variable* arguments = fun->scope()->arguments()->AsVariable();
+    if (arguments != NULL) {
+      // Function uses arguments object.
+      Comment cmnt(masm_, "[ Allocate arguments object");
+      if (!function_in_register) {
+        // Load this again, if it's used by the local context below.
+ __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+      } else {
+        __ 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, r3.bit() | r2.bit() | r1.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);
+ // Duplicate the value; move-to-slot operation might clobber registers.
+      __ mov(r3, r0);
+      Move(arguments->slot(), r0, r1, r2);
+      Slot* dot_arguments_slot =
+          fun->scope()->arguments_shadow()->AsVariable()->slot();
+      Move(dot_arguments_slot, r3, r1, r2);
+    }
   }

   // Check the stack for overflow or break request.
@@ -133,15 +137,15 @@
   // 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;
-  __ mov(pc,
-         Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
-                 RelocInfo::CODE_TARGET),
-         LeaveCC,
-         lo);
+    __ LoadRoot(r2, Heap::kStackLimitRootIndex);
+    __ add(lr, pc, Operand(Assembler::kInstrSize));
+    __ cmp(sp, Operand(r2));
+    StackCheckStub stub;
+    __ mov(pc,
+           Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
+                   RelocInfo::CODE_TARGET),
+           LeaveCC,
+           lo);
   }

   { Comment cmnt(masm_, "[ Declarations");
=======================================
--- /branches/bleeding_edge/src/compiler.cc     Mon Feb  1 04:56:56 2010
+++ /branches/bleeding_edge/src/compiler.cc     Mon Feb  1 09:01:58 2010
@@ -112,8 +112,7 @@
     FastCodeGenSyntaxChecker checker;
     checker.Check(literal, info);
     if (checker.has_supported_syntax()) {
-      // Does not yet generate code.
-      FastCodeGenerator::MakeCode(literal, script, is_eval, info);
+      return FastCodeGenerator::MakeCode(literal, script, is_eval, info);
     }
   }

@@ -490,8 +489,8 @@
       FastCodeGenSyntaxChecker checker;
       checker.Check(literal, &info);
       if (checker.has_supported_syntax()) {
-        // Does not yet generate code.
-        FastCodeGenerator::MakeCode(literal, script, false, &info);
+        code = FastCodeGenerator::MakeCode(literal, script, false, &info);
+        is_compiled = true;
       }
     }

=======================================
--- /branches/bleeding_edge/src/compiler.h      Fri Jan 29 07:29:33 2010
+++ /branches/bleeding_edge/src/compiler.h      Mon Feb  1 09:01:58 2010
@@ -43,7 +43,9 @@
                   int loop_nesting)
       : shared_info_(shared_info),
         receiver_(receiver),
-        loop_nesting_(loop_nesting) {
+        loop_nesting_(loop_nesting),
+        has_this_properties_(false),
+        has_globals_(false) {
   }

   Handle<SharedFunctionInfo> shared_info() { return shared_info_; }
@@ -52,11 +54,19 @@
   Handle<Object> receiver() { return receiver_; }

   int loop_nesting() { return loop_nesting_; }
+
+  bool has_this_properties() { return has_this_properties_; }
+  void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
+
+  bool has_globals() { return has_globals_; }
+  void set_has_globals(bool flag) { has_globals_ = flag; }

  private:
   Handle<SharedFunctionInfo> shared_info_;
   Handle<Object> receiver_;
   int loop_nesting_;
+  bool has_this_properties_;
+  bool has_globals_;
 };


=======================================
--- /branches/bleeding_edge/src/data-flow.cc    Fri Jan 29 01:42:13 2010
+++ /branches/bleeding_edge/src/data-flow.cc    Mon Feb  1 09:01:58 2010
@@ -196,9 +196,12 @@
   ASSERT(prop != NULL);
   if (prop != NULL) {
     ASSERT(prop->key()->IsPropertyName());
-    if (prop->obj()->AsVariableProxy() == NULL ||
-        !prop->obj()->AsVariableProxy()->var()->is_this())
+    VariableProxy* proxy = prop->obj()->AsVariableProxy();
+    if (proxy != NULL && proxy->var()->is_this()) {
+      has_this_properties_ = true;
+    } else {
       Visit(prop->obj());
+    }
   }
   Visit(expr->value());
   expr->set_num(next_number_++);
=======================================
--- /branches/bleeding_edge/src/data-flow.h     Fri Jan 29 01:42:13 2010
+++ /branches/bleeding_edge/src/data-flow.h     Mon Feb  1 09:01:58 2010
@@ -38,9 +38,11 @@
 // their evaluation order (post-order left-to-right traversal).
 class AstLabeler: public AstVisitor {
  public:
-  AstLabeler() : next_number_(0) {}
+  AstLabeler() : next_number_(0), has_this_properties_(false) {}

   void Label(FunctionLiteral* fun);
+
+  bool has_this_properties() { return has_this_properties_; }

  private:
   void VisitDeclarations(ZoneList<Declaration*>* decls);
@@ -54,6 +56,8 @@
   // Traversal number for labelling AST nodes.
   int next_number_;

+  bool has_this_properties_;
+
   DISALLOW_COPY_AND_ASSIGN(AstLabeler);
 };

=======================================
--- /branches/bleeding_edge/src/fast-codegen.cc Fri Jan 29 07:29:33 2010
+++ /branches/bleeding_edge/src/fast-codegen.cc Mon Feb  1 09:01:58 2010
@@ -27,8 +27,10 @@

 #include "v8.h"

+#include "codegen-inl.h"
 #include "data-flow.h"
 #include "fast-codegen.h"
+#include "full-codegen.h"
 #include "scopes.h"

 namespace v8 {
@@ -54,8 +56,12 @@
                                      CompilationInfo* info) {
   info_ = info;

-  // We do not specialize if we do not have a receiver.
+  // We do not specialize if we do not have a receiver or if it is not a
+  // JS object with fast mode properties.
   if (!info->has_receiver()) BAILOUT("No receiver");
+ if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
+  Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
+ if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");

   // We do not support stack or heap slots (both of which require
   // allocation).
@@ -325,25 +331,42 @@
 #undef CHECK_BAILOUT


-void FastCodeGenerator::MakeCode(FunctionLiteral* fun,
-                                 Handle<Script> script,
-                                 bool is_eval,
-                                 CompilationInfo* info) {
+#define __ ACCESS_MASM(masm())
+
+Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
+                                         Handle<Script> script,
+                                         bool is_eval,
+                                         CompilationInfo* info) {
+  // Label the AST before calling MakeCodePrologue, so AST node numbers are
+  // printed with the AST.
   AstLabeler labeler;
-  FastCodeGenerator cgen(script, is_eval);
   labeler.Label(fun);
-  cgen.Generate(fun, info);
-}
-
-
-void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
-  ASSERT(function_ == NULL);
-  ASSERT(info_ == NULL);
-  function_ = fun;
-  info_ = info;
-  VisitStatements(fun->body());
-  function_ = NULL;
-  info_ = NULL;
+  info->set_has_this_properties(labeler.has_this_properties());
+
+  CodeGenerator::MakeCodePrologue(fun);
+
+  const int kInitialBufferSize = 4 * KB;
+  MacroAssembler masm(NULL, kInitialBufferSize);
+
+  // Generate the fast-path code.
+  FastCodeGenerator fast_cgen(&masm, script, is_eval);
+  fast_cgen.Generate(fun, info);
+  if (fast_cgen.HasStackOverflow()) {
+    ASSERT(!Top::has_pending_exception());
+    return Handle<Code>::null();
+  }
+
+ // Generate the full code for the function in bailout mode, using the same
+  // macro assembler.
+  FullCodeGenerator full_cgen(&masm, script, is_eval);
+  full_cgen.Generate(fun, FullCodeGenerator::SECONDARY);
+  if (full_cgen.HasStackOverflow()) {
+    ASSERT(!Top::has_pending_exception());
+    return Handle<Code>::null();
+  }
+
+  Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
+  return CodeGenerator::MakeCodeEpilogue(fun, &masm, flags, script);
 }


@@ -459,11 +482,13 @@


 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
+  ASSERT(expr->var()->is_global() && !expr->var()->is_this());
+  Comment cmnt(masm(), ";; Global");
   if (FLAG_print_ir) {
-    ASSERT(expr->var()->is_global() && !expr->var()->is_this());
     SmartPointer<char> name = expr->name()->ToCString();
     PrintF("%d: t%d = Global(%s)\n", expr->num(), expr->num(), *name);
   }
+  EmitGlobalVariableLoad(expr->name());
 }


@@ -496,18 +521,22 @@
   // Known to be a simple this property assignment.
   Visit(expr->value());

+  Property* prop = expr->target()->AsProperty();
+  ASSERT_NOT_NULL(prop);
+  ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
+  ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
+  ASSERT(prop->key()->IsPropertyName());
+  Handle<String> name =
+      Handle<String>::cast(prop->key()->AsLiteral()->handle());
+
+  Comment cmnt(masm(), ";; Store(this)");
   if (FLAG_print_ir) {
-    Property* prop = expr->target()->AsProperty();
-    ASSERT_NOT_NULL(prop);
-    ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
-    ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
-    ASSERT(prop->key()->IsPropertyName());
-    Handle<String> key =
-        Handle<String>::cast(prop->key()->AsLiteral()->handle());
-    SmartPointer<char> name = key->ToCString();
+    SmartPointer<char> name_string = name->ToCString();
     PrintF("%d: t%d = Store(this, \"%s\", t%d)\n",
-           expr->num(), expr->num(), *name, expr->value()->num());
-  }
+           expr->num(), expr->num(), *name_string, expr->value()->num());
+  }
+
+  EmitThisPropertyStore(name);
 }


@@ -559,5 +588,8 @@
 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
   UNREACHABLE();
 }
+
+#undef __
+

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/fast-codegen.h  Fri Jan 29 07:29:33 2010
+++ /branches/bleeding_edge/src/fast-codegen.h  Mon Feb  1 09:01:58 2010
@@ -65,27 +65,54 @@

 class FastCodeGenerator: public AstVisitor {
  public:
-  FastCodeGenerator(Handle<Script> script, bool is_eval)
-      : masm_(NULL),
+ FastCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
+      : masm_(masm),
         script_(script),
         is_eval_(is_eval),
         function_(NULL),
         info_(NULL) {
   }

-  static void MakeCode(FunctionLiteral* fun,
-                       Handle<Script> script,
-                       bool is_eval,
-                       CompilationInfo* info);
+  static Handle<Code> MakeCode(FunctionLiteral* fun,
+                               Handle<Script> script,
+                               bool is_eval,
+                               CompilationInfo* info);

   void Generate(FunctionLiteral* fun, CompilationInfo* info);

  private:
+  MacroAssembler* masm() { return masm_; }
+  FunctionLiteral* function() { return function_; }
+  Label* bailout() { return &bailout_; }
+
+  bool has_receiver() { return !info_->receiver().is_null(); }
+  Handle<Object> receiver() { return info_->receiver(); }
+  bool has_this_properties() { return info_->has_this_properties(); }
+
   // AST node visit functions.
 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT

+  // Emit code to load the receiver from the stack into a given register.
+  void EmitLoadReceiver(Register reg);
+
+  // Emit code to check that the receiver has the same map as the
+  // compile-time receiver.  Receiver is expected in {ia32-edx, x64-rdx,
+  // arm-r1}.  Emit a branch to the (single) bailout label if check fails.
+  void EmitReceiverMapCheck();
+
+  // Emit code to load a global variable value into {is32-eax, x64-rax,
+  // arm-r0}.  Register {ia32-edx, x64-rdx, arm-r1} is preserved if it is
+  // holding the receiver and {is32-ecx, x64-rcx, arm-r2} is always
+  // clobbered.
+  void EmitGlobalVariableLoad(Handle<String> name);
+
+  // Emit a store to an own property of this.  The stored value is expected
+  // in {ia32-eax, x64-rax, arm-r0} and the receiver in {is32-edx, x64-rdx,
+  // arm-r1}.  Both are preserve.
+  void EmitThisPropertyStore(Handle<String> name);
+
   MacroAssembler* masm_;
   Handle<Script> script_;
   bool is_eval_;
@@ -93,6 +120,8 @@
   FunctionLiteral* function_;
   CompilationInfo* info_;

+  Label bailout_;
+
   DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
 };

=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Fri Jan 29 04:41:11 2010
+++ /branches/bleeding_edge/src/full-codegen.cc Mon Feb  1 09:01:58 2010
@@ -462,7 +462,7 @@
   const int kInitialBufferSize = 4 * KB;
   MacroAssembler masm(NULL, kInitialBufferSize);
   FullCodeGenerator cgen(&masm, script, is_eval);
-  cgen.Generate(fun);
+  cgen.Generate(fun, PRIMARY);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
     return Handle<Code>::null();
@@ -1160,7 +1160,6 @@
   __ PopTryHandler();
   return 0;
 }
-

 #undef __

=======================================
--- /branches/bleeding_edge/src/full-codegen.h  Wed Jan 27 07:23:48 2010
+++ /branches/bleeding_edge/src/full-codegen.h  Mon Feb  1 09:01:58 2010
@@ -63,11 +63,16 @@

 class FullCodeGenerator: public AstVisitor {
  public:
+  enum Mode {
+    PRIMARY,
+    SECONDARY
+  };
+
FullCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
       : masm_(masm),
-        function_(NULL),
         script_(script),
         is_eval_(is_eval),
+        function_(NULL),
         nesting_stack_(NULL),
         loop_depth_(0),
         location_(kStack),
@@ -79,7 +84,7 @@
                                Handle<Script> script,
                                bool is_eval);

-  void Generate(FunctionLiteral* fun);
+  void Generate(FunctionLiteral* fun, Mode mode);

  private:
   class Breakable;
@@ -422,9 +427,11 @@
   void EmitLogicalOperation(BinaryOperation* expr);

   MacroAssembler* masm_;
-  FunctionLiteral* function_;
   Handle<Script> script_;
   bool is_eval_;
+
+  FunctionLiteral* function_;
+
   Label return_label_;
   NestedStatement* nesting_stack_;
   int loop_depth_;
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h     Mon Feb  1 05:07:53 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h     Mon Feb  1 09:01:58 2010
@@ -633,6 +633,7 @@
   friend class JumpTarget;
   friend class Reference;
   friend class Result;
+  friend class FastCodeGenerator;
   friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;

=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Feb 1 05:20:43 2010 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Feb 1 09:01:58 2010
@@ -51,80 +51,82 @@
 //
 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
 // frames-ia32.h for its layout.
-void FullCodeGenerator::Generate(FunctionLiteral* fun) {
+void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
   function_ = fun;
   SetFunctionPosition(fun);

-  __ push(ebp);  // Caller's frame pointer.
-  __ mov(ebp, esp);
-  __ push(esi);  // Callee's context.
-  __ push(edi);  // Callee's JS Function.
-
-  { Comment cmnt(masm_, "[ Allocate locals");
-    int locals_count = fun->scope()->num_stack_slots();
-    if (locals_count == 1) {
-      __ push(Immediate(Factory::undefined_value()));
-    } else if (locals_count > 1) {
-      __ mov(eax, Immediate(Factory::undefined_value()));
-      for (int i = 0; i < locals_count; i++) {
-       __ push(eax);
+  if (mode == PRIMARY) {
+    __ push(ebp);  // Caller's frame pointer.
+    __ mov(ebp, esp);
+    __ push(esi);  // Callee's context.
+    __ push(edi);  // Callee's JS Function.
+
+    { Comment cmnt(masm_, "[ Allocate locals");
+      int locals_count = fun->scope()->num_stack_slots();
+      if (locals_count == 1) {
+        __ push(Immediate(Factory::undefined_value()));
+      } else if (locals_count > 1) {
+        __ mov(eax, Immediate(Factory::undefined_value()));
+        for (int i = 0; i < locals_count; i++) {
+          __ push(eax);
+        }
       }
     }
-  }
-
-  bool function_in_register = true;
-
-  // Possibly allocate a local context.
-  if (fun->scope()->num_heap_slots() > 0) {
-    Comment cmnt(masm_, "[ Allocate local context");
-    // Argument to NewContext is the function, which is still in edi.
-    __ push(edi);
-    __ CallRuntime(Runtime::kNewContext, 1);
-    function_in_register = false;
-    // 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.
-    __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
-
-    // Copy parameters into context if necessary.
-    int num_parameters = fun->scope()->num_parameters();
-    for (int i = 0; i < num_parameters; i++) {
-      Slot* slot = fun->scope()->parameter(i)->slot();
-      if (slot != NULL && slot->type() == Slot::CONTEXT) {
-        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
-                               (num_parameters - 1 - i) * kPointerSize;
-        // Load parameter from stack.
-        __ mov(eax, Operand(ebp, parameter_offset));
-        // Store it in the context
-        __ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
+
+    bool function_in_register = true;
+
+    // Possibly allocate a local context.
+    if (fun->scope()->num_heap_slots() > 0) {
+      Comment cmnt(masm_, "[ Allocate local context");
+      // Argument to NewContext is the function, which is still in edi.
+      __ push(edi);
+      __ CallRuntime(Runtime::kNewContext, 1);
+      function_in_register = false;
+      // 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.
+      __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
+
+      // Copy parameters into context if necessary.
+      int num_parameters = fun->scope()->num_parameters();
+      for (int i = 0; i < num_parameters; i++) {
+        Slot* slot = fun->scope()->parameter(i)->slot();
+        if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+ (num_parameters - 1 - i) * kPointerSize;
+          // Load parameter from stack.
+          __ mov(eax, Operand(ebp, parameter_offset));
+          // Store it in the context
+          __ mov(Operand(esi, Context::SlotOffset(slot->index())), eax);
+        }
       }
     }
-  }
-
-  Variable* arguments = fun->scope()->arguments()->AsVariable();
-  if (arguments != NULL) {
-    // Function uses arguments object.
-    Comment cmnt(masm_, "[ Allocate arguments object");
-    if (function_in_register) {
-      __ push(edi);
-    } else {
-      __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-    }
-    // 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 receiver and parameter count if the previous
-    // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
-    __ CallStub(&stub);
-    __ mov(ecx, eax);  // Duplicate result.
-    Move(arguments->slot(), eax, ebx, edx);
-    Slot* dot_arguments_slot =
-        fun->scope()->arguments_shadow()->AsVariable()->slot();
-    Move(dot_arguments_slot, ecx, ebx, edx);
+
+    Variable* arguments = fun->scope()->arguments()->AsVariable();
+    if (arguments != NULL) {
+      // Function uses arguments object.
+      Comment cmnt(masm_, "[ Allocate arguments object");
+      if (function_in_register) {
+        __ push(edi);
+      } else {
+        __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+      }
+      // 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 receiver and parameter count if the previous
+      // stack frame was an arguments adapter frame.
+      ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+      __ CallStub(&stub);
+      __ mov(ecx, eax);  // Duplicate result.
+      Move(arguments->slot(), eax, ebx, edx);
+      Slot* dot_arguments_slot =
+          fun->scope()->arguments_shadow()->AsVariable()->slot();
+      Move(dot_arguments_slot, ecx, ebx, edx);
+    }
   }

   { Comment cmnt(masm_, "[ Declarations");
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Mon Feb  1 05:07:53 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Mon Feb  1 09:01:58 2010
@@ -630,6 +630,7 @@
   friend class JumpTarget;
   friend class Reference;
   friend class Result;
+  friend class FastCodeGenerator;
   friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;

=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Feb 1 05:20:43 2010 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Feb 1 09:01:58 2010
@@ -51,83 +51,85 @@
 //
 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
 // frames-x64.h for its layout.
-void FullCodeGenerator::Generate(FunctionLiteral* fun) {
+void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) {
   function_ = fun;
   SetFunctionPosition(fun);

-  __ push(rbp);  // Caller's frame pointer.
-  __ movq(rbp, rsp);
-  __ push(rsi);  // Callee's context.
-  __ push(rdi);  // Callee's JS Function.
-
-  { Comment cmnt(masm_, "[ Allocate locals");
-    int locals_count = fun->scope()->num_stack_slots();
-    if (locals_count == 1) {
-      __ PushRoot(Heap::kUndefinedValueRootIndex);
-    } else if (locals_count > 1) {
-      __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
-      for (int i = 0; i < locals_count; i++) {
-        __ push(rdx);
+  if (mode == PRIMARY) {
+    __ push(rbp);  // Caller's frame pointer.
+    __ movq(rbp, rsp);
+    __ push(rsi);  // Callee's context.
+    __ push(rdi);  // Callee's JS Function.
+
+    { Comment cmnt(masm_, "[ Allocate locals");
+      int locals_count = fun->scope()->num_stack_slots();
+      if (locals_count == 1) {
+        __ PushRoot(Heap::kUndefinedValueRootIndex);
+      } else if (locals_count > 1) {
+        __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+        for (int i = 0; i < locals_count; i++) {
+          __ push(rdx);
+        }
       }
     }
-  }
-
-  bool function_in_register = true;
-
-  // Possibly allocate a local context.
-  if (fun->scope()->num_heap_slots() > 0) {
-    Comment cmnt(masm_, "[ Allocate local context");
-    // Argument to NewContext is the function, which is still in rdi.
-    __ push(rdi);
-    __ CallRuntime(Runtime::kNewContext, 1);
-    function_in_register = false;
-    // 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.
-    __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
-
-    // Copy any necessary parameters into the context.
-    int num_parameters = fun->scope()->num_parameters();
-    for (int i = 0; i < num_parameters; i++) {
-      Slot* slot = fun->scope()->parameter(i)->slot();
-      if (slot != NULL && slot->type() == Slot::CONTEXT) {
-        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
-                               (num_parameters - 1 - i) * kPointerSize;
-        // Load parameter from stack.
-        __ movq(rax, Operand(rbp, parameter_offset));
-        // Store it in the context
-        __ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
+
+    bool function_in_register = true;
+
+    // Possibly allocate a local context.
+    if (fun->scope()->num_heap_slots() > 0) {
+      Comment cmnt(masm_, "[ Allocate local context");
+      // Argument to NewContext is the function, which is still in rdi.
+      __ push(rdi);
+      __ CallRuntime(Runtime::kNewContext, 1);
+      function_in_register = false;
+      // 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.
+      __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
+
+      // Copy any necessary parameters into the context.
+      int num_parameters = fun->scope()->num_parameters();
+      for (int i = 0; i < num_parameters; i++) {
+        Slot* slot = fun->scope()->parameter(i)->slot();
+        if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+ (num_parameters - 1 - i) * kPointerSize;
+          // Load parameter from stack.
+          __ movq(rax, Operand(rbp, parameter_offset));
+          // Store it in the context
+          __ movq(Operand(rsi, Context::SlotOffset(slot->index())), rax);
+        }
       }
     }
-  }
-
-  // Possibly allocate an arguments object.
-  Variable* arguments = fun->scope()->arguments()->AsVariable();
-  if (arguments != NULL) {
-    // Arguments object must be allocated after the context object, in
-    // case the "arguments" or ".arguments" variables are in the context.
-    Comment cmnt(masm_, "[ Allocate arguments object");
-    if (function_in_register) {
-      __ push(rdi);
-    } else {
-      __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
-    }
-    // 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(rcx, rax);
-    Move(arguments->slot(), rax, rbx, rdx);
-    Slot* dot_arguments_slot =
-        fun->scope()->arguments_shadow()->AsVariable()->slot();
-    Move(dot_arguments_slot, rcx, rbx, rdx);
+
+    // Possibly allocate an arguments object.
+    Variable* arguments = fun->scope()->arguments()->AsVariable();
+    if (arguments != NULL) {
+      // Arguments object must be allocated after the context object, in
+      // case the "arguments" or ".arguments" variables are in the context.
+      Comment cmnt(masm_, "[ Allocate arguments object");
+      if (function_in_register) {
+        __ push(rdi);
+      } else {
+        __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+      }
+      // 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(rcx, rax);
+      Move(arguments->slot(), rax, rbx, rdx);
+      Slot* dot_arguments_slot =
+          fun->scope()->arguments_shadow()->AsVariable()->slot();
+      Move(dot_arguments_slot, rcx, rbx, rdx);
+    }
   }

   { Comment cmnt(masm_, "[ Declarations");
=======================================
--- /branches/bleeding_edge/tools/gyp/v8.gyp    Fri Jan 29 01:42:13 2010
+++ /branches/bleeding_edge/tools/gyp/v8.gyp    Mon Feb  1 09:01:58 2010
@@ -412,6 +412,7 @@
             '../../src/arm/cpu-arm.cc',
             '../../src/arm/debug-arm.cc',
             '../../src/arm/disasm-arm.cc',
+            '../../src/arm/fast-codegen-arm.cc',
             '../../src/arm/frames-arm.cc',
             '../../src/arm/frames-arm.h',
             '../../src/arm/full-codegen-arm.cc',
@@ -450,6 +451,7 @@
             '../../src/ia32/cpu-ia32.cc',
             '../../src/ia32/debug-ia32.cc',
             '../../src/ia32/disasm-ia32.cc',
+            '../../src/ia32/fast-codegen-ia32.cc',
             '../../src/ia32/frames-ia32.cc',
             '../../src/ia32/frames-ia32.h',
             '../../src/ia32/full-codegen-ia32.cc',
@@ -479,6 +481,7 @@
             '../../src/x64/cpu-x64.cc',
             '../../src/x64/debug-x64.cc',
             '../../src/x64/disasm-x64.cc',
+            '../../src/x64/fast-codegen-x64.cc',
             '../../src/x64/frames-x64.cc',
             '../../src/x64/frames-x64.h',
             '../../src/x64/full-codegen-x64.cc',
=======================================
--- /branches/bleeding_edge/tools/visual_studio/v8_base.vcproj Fri Jan 29 01:42:13 2010 +++ /branches/bleeding_edge/tools/visual_studio/v8_base.vcproj Mon Feb 1 09:01:58 2010
@@ -397,6 +397,10 @@
                                >
                        </File>
                         <File
+ RelativePath="..\..\src\ia32\fast-codegen-ia32.cc"
+                                >
+                        </File>
+                        <File
                                 RelativePath="..\..\src\fast-codegen.cc"
                                 >
                         </File>
=======================================
--- /branches/bleeding_edge/tools/visual_studio/v8_base_arm.vcproj Fri Jan 29 01:42:13 2010 +++ /branches/bleeding_edge/tools/visual_studio/v8_base_arm.vcproj Mon Feb 1 09:01:58 2010
@@ -405,6 +405,10 @@
                                >
                        </File>
                         <File
+ RelativePath="..\..\src\arm\fast-codegen-arm.cc"
+                                >
+                        </File>
+                        <File
                                 RelativePath="..\..\src\fast-codegen.cc"
                                 >
                         </File>
=======================================
--- /branches/bleeding_edge/tools/visual_studio/v8_base_x64.vcproj Fri Jan 29 01:42:13 2010 +++ /branches/bleeding_edge/tools/visual_studio/v8_base_x64.vcproj Mon Feb 1 09:01:58 2010
@@ -395,6 +395,10 @@
                        <File
                                RelativePath="..\..\src\factory.h"
                                >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\x64\fast-codegen-x64.cc"
+                               >
                        </File>
                         <File
                                 RelativePath="..\..\src\fast-codegen.cc"
@@ -441,15 +445,15 @@
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\full-codegen.cc"
+                               RelativePath="..\..\src\x64\full-codegen-x64.cc"
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\full-codegen.h"
+                               RelativePath="..\..\src\full-codegen.cc"
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\x64\full-codegen-x64.cc"
+                               RelativePath="..\..\src\full-codegen.h"
                                >
                        </File>
                        <File

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to