Implement simple fast-path code for functions containing this property stores and...
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 1 Feb 2010 17:01:58 +0000 (17:01 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 1 Feb 2010 17:01:58 +0000 (17:01 +0000)
Code is specialized to the initial receiver.

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

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

22 files changed:
src/SConscript
src/arm/codegen-arm.h
src/arm/fast-codegen-arm.cc [new file with mode: 0644]
src/arm/full-codegen-arm.cc
src/compiler.cc
src/compiler.h
src/data-flow.cc
src/data-flow.h
src/fast-codegen.cc
src/fast-codegen.h
src/full-codegen.cc
src/full-codegen.h
src/ia32/codegen-ia32.h
src/ia32/fast-codegen-ia32.cc [new file with mode: 0644]
src/ia32/full-codegen-ia32.cc
src/x64/codegen-x64.h
src/x64/fast-codegen-x64.cc [new file with mode: 0644]
src/x64/full-codegen-x64.cc
tools/gyp/v8.gyp
tools/visual_studio/v8_base.vcproj
tools/visual_studio/v8_base_arm.vcproj
tools/visual_studio/v8_base_x64.vcproj

index 1ffa743452e828a6f70f5bc5cfce457efd6f91fd..ebda77ac20aabcc6dcb50cfe56862237eee637a6 100755 (executable)
@@ -114,6 +114,7 @@ SOURCES = {
     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 @@ SOURCES = {
     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 @@ SOURCES = {
     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
index 862fd0571e495efe28d7108f767d2daf62c8108d..4f56c84fc21c89bf768cfe3873fc82c77d6bac41 100644 (file)
@@ -444,6 +444,7 @@ class CodeGenerator: public AstVisitor {
   friend class VirtualFrame;
   friend class JumpTarget;
   friend class Reference;
+  friend class FastCodeGenerator;
   friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;
 
diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc
new file mode 100644 (file)
index 0000000..62b5f6f
--- /dev/null
@@ -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
index 07b0c798b78fe99d0c02d7607335cf665f2f1670..386d201ac02a088f2ef7be0836ce539c3db15645 100644 (file)
@@ -52,80 +52,84 @@ namespace internal {
 //
 // 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.
-      __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
-  }
-  // Adjust fp to point to caller's fp.
-  __ add(fp, sp, Operand(2 * kPointerSize));
+  if (mode == PRIMARY) {
+    int locals_count = fun->scope()->num_stack_slots();
 
-  { Comment cmnt(masm_, "[ Allocate locals");
-    for (int i = 0; i < locals_count; i++) {
-      __ push(ip);
+    __ 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));
 
-  bool function_in_register = true;
+    { Comment cmnt(masm_, "[ Allocate locals");
+      for (int i = 0; i < locals_count; i++) {
+        __ push(ip);
+      }
+    }
 
-  // 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())));
+    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);
+    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);
     }
-    // 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 @@ void FullCodeGenerator::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;
-  __ 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");
index 7a5541bc8900d39223ee3be00eb247e9bcc691fd..a5e1e5c885156e2e435a643f6fde5ab6f17a13b1 100755 (executable)
@@ -112,8 +112,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
     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 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
       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;
       }
     }
 
index d12423df86cbdd17604f7049a30f56d0274e50e6..19499de71ba79a48ad43d4388c7cc9452b210a57 100644 (file)
@@ -43,7 +43,9 @@ class CompilationInfo BASE_EMBEDDED {
                   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_; }
@@ -53,10 +55,18 @@ class CompilationInfo BASE_EMBEDDED {
 
   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_;
 };
 
 
index ef15244a4e6aa4c964d1f4000cf3d711367b355a..0e30b315173f879a91d87a9a42d163402cbaf40b 100644 (file)
@@ -196,9 +196,12 @@ void AstLabeler::VisitAssignment(Assignment* expr) {
   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_++);
index e1f2200df8b93b6328740daf50eb825138422be0..ac8350318832f57593ab72382644b36d38865b5e 100644 (file)
@@ -38,10 +38,12 @@ namespace internal {
 // 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);
   void VisitStatements(ZoneList<Statement*>* stmts);
@@ -54,6 +56,8 @@ class AstLabeler: public AstVisitor {
   // Traversal number for labelling AST nodes.
   int next_number_;
 
+  bool has_this_properties_;
+
   DISALLOW_COPY_AND_ASSIGN(AstLabeler);
 };
 
index db0205c3ca0dfb675fbd522ad1352a13c44c35a0..1ead93c3fefd0557d9de609e010be0bb69377482 100644 (file)
 
 #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 @@ void FastCodeGenSyntaxChecker::Check(FunctionLiteral* fun,
                                      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 @@ void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
 #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);
-}
+  info->set_has_this_properties(labeler.has_this_properties());
 
+  CodeGenerator::MakeCodePrologue(fun);
 
-void FastCodeGenerator::Generate(FunctionLiteral* fun, CompilationInfo* info) {
-  ASSERT(function_ == NULL);
-  ASSERT(info_ == NULL);
-  function_ = fun;
-  info_ = info;
-  VisitStatements(fun->body());
-  function_ = NULL;
-  info_ = NULL;
+  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::VisitSlot(Slot* expr) {
 
 
 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 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
   // 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);
 }
 
 
@@ -560,4 +589,7 @@ void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
   UNREACHABLE();
 }
 
+#undef __
+
+
 } }  // namespace v8::internal
index f28a0ea810a0b6e76d79b1c428206f79f494266e..b40f6fb7f912036e975b70528fcdd39905eb110f 100644 (file)
@@ -65,27 +65,54 @@ class FastCodeGenSyntaxChecker: public AstVisitor {
 
 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 @@ class FastCodeGenerator: public AstVisitor {
   FunctionLiteral* function_;
   CompilationInfo* info_;
 
+  Label bailout_;
+
   DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
 };
 
index ca8fb032c47c3c73141aa2a76c3ddedccaf40fa3..4a1a7d37c0ea8aa5c2d9079b5fc7c99873df2eb4 100644 (file)
@@ -462,7 +462,7 @@ Handle<Code> FullCodeGenerator::MakeCode(FunctionLiteral* fun,
   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();
@@ -1161,7 +1161,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
   return 0;
 }
 
-
 #undef __
 
 
index 3c8e198f5fc18892fe0908f1d6c8d9081cb4b17f..6688ff7c57c2fcda050f57df368c31571f1643c1 100644 (file)
@@ -63,11 +63,16 @@ class FullCodeGenSyntaxChecker: public AstVisitor {
 
 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 @@ class FullCodeGenerator: public AstVisitor {
                                Handle<Script> script,
                                bool is_eval);
 
-  void Generate(FunctionLiteral* fun);
+  void Generate(FunctionLiteral* fun, Mode mode);
 
  private:
   class Breakable;
@@ -422,9 +427,11 @@ class FullCodeGenerator: public AstVisitor {
   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_;
index a82b822a23393055956c8ef1b05e3fe90077137d..e036a1d64ec01e870619c27d4d6d58a8470888cb 100644 (file)
@@ -633,6 +633,7 @@ class CodeGenerator: public AstVisitor {
   friend class JumpTarget;
   friend class Reference;
   friend class Result;
+  friend class FastCodeGenerator;
   friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;
 
diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc
new file mode 100644 (file)
index 0000000..2a15733
--- /dev/null
@@ -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
index 438ad94f8f88e7fc825dae53a7040c0471ffaa81..ba03eafe935d80bd4441f701087458a88361bfc1 100644 (file)
@@ -51,80 +51,82 @@ namespace internal {
 //
 // 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));
+    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);
     }
-    // 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");
index 5e21c0d563729311521935511fe481e034363167..c3c0fb53ed86c22bb494a42b666aa4c261176756 100644 (file)
@@ -630,6 +630,7 @@ class CodeGenerator: public AstVisitor {
   friend class JumpTarget;
   friend class Reference;
   friend class Result;
+  friend class FastCodeGenerator;
   friend class FullCodeGenerator;
   friend class FullCodeGenSyntaxChecker;
 
diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc
new file mode 100644 (file)
index 0000000..12b5653
--- /dev/null
@@ -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
index 9804b832a8d1da3c452a1243317eb3ec840ed1c8..60069bdde03dbc41c961c35d01583e8009bf0f51 100644 (file)
@@ -51,83 +51,85 @@ namespace internal {
 //
 // 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));
+    // 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);
     }
-    // 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");
index 88dba5756402b3100c4f1e5820ebde29532ac23f..f2d1b98eee9c5cd2f46c38a19ef55e8fa80cb321 100644 (file)
             '../../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',
             '../../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',
             '../../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',
index 00e4c0a3ff6e025a1c032da2b096379dc176f123..e58e8ff31fd168a92b4133500c25df49560a93e4 100644 (file)
                                RelativePath="..\..\src\factory.h"
                                >
                        </File>
+                        <File
+                                RelativePath="..\..\src\ia32\fast-codegen-ia32.cc"
+                                >
+                        </File>
                         <File
                                 RelativePath="..\..\src\fast-codegen.cc"
                                 >
index fe3dac3c8c0622424018d53e5e6c80f70af3046a..4b37b538c2ce4a1f31face01f94a178599612a75 100644 (file)
                                RelativePath="..\..\src\factory.h"
                                >
                        </File>
+                        <File
+                                RelativePath="..\..\src\arm\fast-codegen-arm.cc"
+                                >
+                        </File>
                         <File
                                 RelativePath="..\..\src\fast-codegen.cc"
                                 >
index e9f6bce7700893b2cd76de92f3d19fa7e170d3cd..b6d5c7d8283ddd8837ee2cd730d5b66adc1ff3d3 100644 (file)
                                RelativePath="..\..\src\factory.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\..\src\x64\fast-codegen-x64.cc"
+                               >
+                       </File>
                         <File
                                 RelativePath="..\..\src\fast-codegen.cc"
                                 >
                                >
                        </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