Revision: 12470
Author:   [email protected]
Date:     Fri Sep  7 02:01:54 2012
Log:      Fixed deoptimization of inlined getters.

It is necessary to explicitly handle the internal frame lying between the caller
of the getter and the getter itself in the deoptimizer: When the getter is
inlined, leaving the internal frame restores the correct context.

BUG=http://crbug/134609
TEST=mjsunit/regress/regress-crbug-134609

Review URL: https://chromiumcodereview.appspot.com/10910110
http://code.google.com/p/v8/source/detail?r=12470

Added:
 /branches/bleeding_edge/test/mjsunit/regress/regress-crbug-134609.js
Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/arm/deoptimizer-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/builtins.cc
 /branches/bleeding_edge/src/builtins.h
 /branches/bleeding_edge/src/deoptimizer.cc
 /branches/bleeding_edge/src/deoptimizer.h
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/mips/deoptimizer-mips.cc
 /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/x64/deoptimizer-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-crbug-134609.js Fri Sep 7 02:01:54 2012
@@ -0,0 +1,59 @@
+// Copyright 2012 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.
+
+// Flags: --allow-natives-syntax --inline-accessors
+
+var forceDeopt = {x:0};
+
+var objectWithGetterProperty = (function (value) {
+  var obj = {};
+  Object.defineProperty(obj, "getterProperty", {
+    get: function foo() {
+      forceDeopt.x;
+      return value;
+    },
+  });
+  return obj;
+})("bad");
+
+function test() {
+  var iAmContextAllocated = "good";
+  objectWithGetterProperty.getterProperty;
+  return iAmContextAllocated;
+
+  // Make sure that the local variable is context allocated.
+  function unused() { iAmContextAllocated; }
+}
+
+assertEquals("good", test());
+assertEquals("good", test());
+%OptimizeFunctionOnNextCall(test);
+assertEquals("good", test());
+
+// At this point, foo should have been inlined into test. Let's deopt...
+delete forceDeopt.x;
+assertEquals("good", test());
=======================================
--- /branches/bleeding_edge/include/v8.h        Tue Sep  4 05:23:22 2012
+++ /branches/bleeding_edge/include/v8.h        Fri Sep  7 02:01:54 2012
@@ -4042,7 +4042,7 @@
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptySymbolRootIndex = 115;
+  static const int kEmptySymbolRootIndex = 116;

   static const int kJSObjectType = 0xaa;
   static const int kFirstNonstringType = 0x80;
=======================================
--- /branches/bleeding_edge/src/arm/deoptimizer-arm.cc Fri Aug 17 03:43:32 2012 +++ /branches/bleeding_edge/src/arm/deoptimizer-arm.cc Fri Sep 7 02:01:54 2012
@@ -595,30 +595,34 @@
 }


-void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
-                                           int frame_index) {
-  JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver and the implicit return value are expected in registers by the - // StoreIC, so they don't belong to the output stack frame. This means that we
-  // have to use a height of 0.
+void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
+                                             int frame_index,
+                                             bool is_setter_stub_frame) {
+ JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
+  // The receiver (and the implicit return value, if any) are expected in
+ // registers by the LoadIC/StoreIC, so they don't belong to the output stack
+  // frame. This means that we have to use a height of 0.
   unsigned height = 0;
   unsigned height_in_bytes = height * kPointerSize;
+  const char* kind = is_setter_stub_frame ? "setter" : "getter";
   if (FLAG_trace_deopt) {
-    PrintF("  translating setter stub => height=%u\n", height_in_bytes);
+    PrintF("  translating %s stub => height=%u\n", kind, height_in_bytes);
   }

// We need 5 stack entries from StackFrame::INTERNAL (lr, fp, cp, frame type, - // code object, see MacroAssembler::EnterFrame) + 1 stack entry from setter - // stub (implicit return value, see StoreStubCompiler::CompileStoreViaSetter).
-  unsigned fixed_frame_size = (5 + 1) * kPointerSize;
+ // code object, see MacroAssembler::EnterFrame). For a setter stub frames we
+  // need one additional entry for the implicit return value, see
+  // StoreStubCompiler::CompileStoreViaSetter.
+  unsigned fixed_frame_entries = 5 + (is_setter_stub_frame ? 1 : 0);
+  unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
   unsigned output_frame_size = height_in_bytes + fixed_frame_size;

   // Allocate and store the output frame description.
   FrameDescription* output_frame =
-      new(output_frame_size) FrameDescription(output_frame_size, setter);
+      new(output_frame_size) FrameDescription(output_frame_size, accessor);
   output_frame->SetFrameType(StackFrame::INTERNAL);

-  // A frame for a setter stub can not be the topmost or bottommost one.
+  // A frame for an accessor stub can not be the topmost or bottommost one.
   ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
   ASSERT(output_[frame_index] == NULL);
   output_[frame_index] = output_frame;
@@ -668,15 +672,17 @@
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
-           " ; function (setter sentinel)\n",
-           top_address + output_offset, output_offset, value);
+           " ; function (%s sentinel)\n",
+           top_address + output_offset, output_offset, value, kind);
   }

-  // Get Code object from setter stub.
+  // Get Code object from accessor stub.
   output_offset -= kPointerSize;
-  Code* setter_stub =
-      isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
-  value = reinterpret_cast<intptr_t>(setter_stub);
+  Builtins::Name name = is_setter_stub_frame ?
+      Builtins::kStoreIC_Setter_ForDeopt :
+      Builtins::kLoadIC_Getter_ForDeopt;
+  Code* accessor_stub = isolate_->builtins()->builtin(name);
+  value = reinterpret_cast<intptr_t>(accessor_stub);
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
@@ -689,16 +695,20 @@
       static_cast<Translation::Opcode>(iterator->Next());
   iterator->Skip(Translation::NumberOfOperandsFor(opcode));

-  // The implicit return value was part of the artificial setter stub
-  // environment.
-  output_offset -= kPointerSize;
-  DoTranslateCommand(iterator, frame_index, output_offset);
+  if (is_setter_stub_frame) {
+    // The implicit return value was part of the artificial setter stub
+    // environment.
+    output_offset -= kPointerSize;
+    DoTranslateCommand(iterator, frame_index, output_offset);
+  }

   ASSERT(0 == output_offset);

+  Smi* offset = is_setter_stub_frame ?
+      isolate_->heap()->setter_stub_deopt_pc_offset() :
+      isolate_->heap()->getter_stub_deopt_pc_offset();
   intptr_t pc = reinterpret_cast<intptr_t>(
-      setter_stub->instruction_start() +
-      isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+      accessor_stub->instruction_start() + offset->value());
   output_frame->SetPc(pc);
 }

=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Aug 31 07:45:31 2012 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Sep 7 02:01:54 2012
@@ -484,6 +484,11 @@
     case JS_CONSTRUCT:
       translation->BeginConstructStubFrame(closure_id, translation_size);
       break;
+    case JS_GETTER:
+      ASSERT(translation_size == 1);
+      ASSERT(height == 0);
+      translation->BeginGetterStubFrame(closure_id);
+      break;
     case JS_SETTER:
       ASSERT(translation_size == 2);
       ASSERT(height == 0);
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Aug 28 23:12:46 2012 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Sep 7 02:01:54 2012
@@ -2949,6 +2949,43 @@
   // Return the generated code.
   return GetCode(Code::CALLBACKS, name);
 }
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
+                                             Handle<JSFunction> getter) {
+  // ----------- S t a t e -------------
+  //  -- r0    : receiver
+  //  -- r2    : name
+  //  -- lr    : return address
+  // -----------------------------------
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    if (!getter.is_null()) {
+      // Call the JavaScript getter with the receiver on the stack.
+      __ push(r0);
+      ParameterCount actual(0);
+      __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
+                        CALL_AS_METHOD);
+    } else {
+ // If we generate a global code snippet for deoptimization only, remember
+      // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore context register.
+    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  }
+  __ Ret();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())


 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
@@ -2967,19 +3004,7 @@
   __ JumpIfSmi(r0, &miss);
   CheckPrototypes(receiver, r0, holder, r3, r4, r1, name, &miss);

-  {
-    FrameScope scope(masm(), StackFrame::INTERNAL);
-
-    // Call the JavaScript getter with the receiver on the stack.
-    __ push(r0);
-    ParameterCount actual(0);
-    __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
-                      CALL_AS_METHOD);
-
-    // Restore context register.
-    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
-  __ Ret();
+  GenerateLoadViaGetter(masm(), getter);

   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
=======================================
--- /branches/bleeding_edge/src/builtins.cc     Fri Aug 17 03:43:32 2012
+++ /branches/bleeding_edge/src/builtins.cc     Fri Sep  7 02:01:54 2012
@@ -1290,6 +1290,11 @@
 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
   LoadIC::GenerateNormal(masm);
 }
+
+
+static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) {
+  LoadStubCompiler::GenerateLoadViaGetter(masm, Handle<JSFunction>());
+}


 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
=======================================
--- /branches/bleeding_edge/src/builtins.h      Fri Aug 17 03:43:32 2012
+++ /branches/bleeding_edge/src/builtins.h      Fri Sep  7 02:01:54 2012
@@ -123,6 +123,8 @@
                                     Code::kNoExtraICState)              \
   V(LoadIC_Megamorphic,             LOAD_IC, MEGAMORPHIC,               \
                                     Code::kNoExtraICState)              \
+  V(LoadIC_Getter_ForDeopt,         LOAD_IC, MONOMORPHIC,               \
+                                    Code::kNoExtraICState)              \
                                                                         \
   V(KeyedLoadIC_Initialize,         KEYED_LOAD_IC, UNINITIALIZED,       \
                                     Code::kNoExtraICState)              \
=======================================
--- /branches/bleeding_edge/src/deoptimizer.cc  Wed Aug 22 08:58:16 2012
+++ /branches/bleeding_edge/src/deoptimizer.cc  Fri Sep  7 02:01:54 2012
@@ -589,8 +589,11 @@
       case Translation::CONSTRUCT_STUB_FRAME:
         DoComputeConstructStubFrame(&iterator, i);
         break;
+      case Translation::GETTER_STUB_FRAME:
+        DoComputeAccessorStubFrame(&iterator, i, false);
+        break;
       case Translation::SETTER_STUB_FRAME:
-        DoComputeSetterStubFrame(&iterator, i);
+        DoComputeAccessorStubFrame(&iterator, i, true);
         break;
       case Translation::BEGIN:
       case Translation::REGISTER:
@@ -722,6 +725,7 @@
     case Translation::JS_FRAME:
     case Translation::ARGUMENTS_ADAPTOR_FRAME:
     case Translation::CONSTRUCT_STUB_FRAME:
+    case Translation::GETTER_STUB_FRAME:
     case Translation::SETTER_STUB_FRAME:
     case Translation::DUPLICATE:
       UNREACHABLE();
@@ -1018,6 +1022,7 @@
     case Translation::JS_FRAME:
     case Translation::ARGUMENTS_ADAPTOR_FRAME:
     case Translation::CONSTRUCT_STUB_FRAME:
+    case Translation::GETTER_STUB_FRAME:
     case Translation::SETTER_STUB_FRAME:
     case Translation::DUPLICATE:
       UNREACHABLE();  // Malformed input.
@@ -1480,6 +1485,12 @@
   buffer_->Add(literal_id, zone());
   buffer_->Add(height, zone());
 }
+
+
+void Translation::BeginGetterStubFrame(int literal_id) {
+  buffer_->Add(GETTER_STUB_FRAME, zone());
+  buffer_->Add(literal_id, zone());
+}


 void Translation::BeginSetterStubFrame(int literal_id) {
@@ -1574,6 +1585,7 @@
     case ARGUMENTS_OBJECT:
     case DUPLICATE:
       return 0;
+    case GETTER_STUB_FRAME:
     case SETTER_STUB_FRAME:
     case REGISTER:
     case INT32_REGISTER:
@@ -1609,6 +1621,8 @@
       return "ARGUMENTS_ADAPTOR_FRAME";
     case CONSTRUCT_STUB_FRAME:
       return "CONSTRUCT_STUB_FRAME";
+    case GETTER_STUB_FRAME:
+      return "GETTER_STUB_FRAME";
     case SETTER_STUB_FRAME:
       return "SETTER_STUB_FRAME";
     case REGISTER:
@@ -1671,6 +1685,7 @@
     case Translation::JS_FRAME:
     case Translation::ARGUMENTS_ADAPTOR_FRAME:
     case Translation::CONSTRUCT_STUB_FRAME:
+    case Translation::GETTER_STUB_FRAME:
     case Translation::SETTER_STUB_FRAME:
       // Peeled off before getting here.
       break;
=======================================
--- /branches/bleeding_edge/src/deoptimizer.h   Wed Aug 22 08:44:17 2012
+++ /branches/bleeding_edge/src/deoptimizer.h   Fri Sep  7 02:01:54 2012
@@ -284,8 +284,9 @@
                                       int frame_index);
   void DoComputeConstructStubFrame(TranslationIterator* iterator,
                                    int frame_index);
-  void DoComputeSetterStubFrame(TranslationIterator* iterator,
-                                int frame_index);
+  void DoComputeAccessorStubFrame(TranslationIterator* iterator,
+                                  int frame_index,
+                                  bool is_setter_stub_frame);
   void DoTranslateCommand(TranslationIterator* iterator,
                           int frame_index,
                           unsigned output_offset);
@@ -561,6 +562,7 @@
     BEGIN,
     JS_FRAME,
     CONSTRUCT_STUB_FRAME,
+    GETTER_STUB_FRAME,
     SETTER_STUB_FRAME,
     ARGUMENTS_ADAPTOR_FRAME,
     REGISTER,
@@ -595,6 +597,7 @@
   void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
   void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
   void BeginConstructStubFrame(int literal_id, unsigned height);
+  void BeginGetterStubFrame(int literal_id);
   void BeginSetterStubFrame(int literal_id);
   void StoreRegister(Register reg);
   void StoreInt32Register(Register reg);
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h      Thu Sep  6 08:01:20 2012
+++ /branches/bleeding_edge/src/flag-definitions.h      Fri Sep  7 02:01:54 2012
@@ -213,7 +213,7 @@
             "cache optimized code for closures")
 DEFINE_bool(inline_construct, true, "inline constructor calls")
DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
-DEFINE_bool(inline_accessors, false, "inline JavaScript accessors")
+DEFINE_bool(inline_accessors, true, "inline JavaScript accessors")
 DEFINE_int(loop_weight, 1, "loop weight for representation inference")

 DEFINE_bool(optimize_for_in, true,
=======================================
--- /branches/bleeding_edge/src/heap.h  Tue Sep  4 05:23:22 2012
+++ /branches/bleeding_edge/src/heap.h  Fri Sep  7 02:01:54 2012
@@ -153,6 +153,7 @@
V(StringDictionary, intrinsic_function_names, IntrinsicFunctionNames) \ V(Smi, arguments_adaptor_deopt_pc_offset, ArgumentsAdaptorDeoptPCOffset) \ V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \ + V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \
   V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset)

 #define ROOT_LIST(V)                                  \
@@ -1591,6 +1592,11 @@
     ASSERT(construct_stub_deopt_pc_offset() == Smi::FromInt(0));
     set_construct_stub_deopt_pc_offset(Smi::FromInt(pc_offset));
   }
+
+  void SetGetterStubDeoptPCOffset(int pc_offset) {
+    ASSERT(getter_stub_deopt_pc_offset() == Smi::FromInt(0));
+    set_getter_stub_deopt_pc_offset(Smi::FromInt(pc_offset));
+  }

   void SetSetterStubDeoptPCOffset(int pc_offset) {
     ASSERT(setter_stub_deopt_pc_offset() == Smi::FromInt(0));
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Thu Aug 30 10:31:32 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Fri Sep 7 02:01:54 2012
@@ -1415,6 +1415,7 @@
   NORMAL_RETURN,          // Normal function/method call and return.
DROP_EXTRA_ON_RETURN, // Drop an extra value from the environment on return.
   CONSTRUCT_CALL_RETURN,  // Either use allocated receiver or return value.
+ GETTER_CALL_RETURN, // Returning from a getter, need to restore context. SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
 };

=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Thu Aug 30 11:10:09 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Fri Sep  7 02:01:54 2012
@@ -7280,7 +7280,7 @@
                    NULL,
                    prop->id(),
                    prop->LoadId(),
-                   NORMAL_RETURN);
+                   GETTER_CALL_RETURN);
 }


@@ -9594,6 +9594,10 @@
// actually be the constructor function, but we pass the newly allocated
     // object instead, DoComputeConstructStubFrame() relies on that.
     outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
+  } else if (inlining_kind == GETTER_CALL_RETURN) {
+    // We need an additional StackFrame::INTERNAL frame for restoring the
+    // correct context.
+    outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
   } else if (inlining_kind == SETTER_CALL_RETURN) {
// We need an additional StackFrame::INTERNAL frame for temporarily saving // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Thu Aug 23 14:08:58 2012
+++ /branches/bleeding_edge/src/hydrogen.h      Fri Sep  7 02:01:54 2012
@@ -421,6 +421,7 @@
 enum FrameType {
   JS_FUNCTION,
   JS_CONSTRUCT,
+  JS_GETTER,
   JS_SETTER,
   ARGUMENTS_ADAPTOR
 };
=======================================
--- /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc Fri Aug 17 03:43:32 2012 +++ /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc Fri Sep 7 02:01:54 2012
@@ -694,31 +694,35 @@
 }


-void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
-                                           int frame_index) {
-  JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver and the implicit return value are expected in registers by the - // StoreIC, so they don't belong to the output stack frame. This means that we
-  // have to use a height of 0.
+void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
+                                             int frame_index,
+                                             bool is_setter_stub_frame) {
+ JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
+  // The receiver (and the implicit return value, if any) are expected in
+ // registers by the LoadIC/StoreIC, so they don't belong to the output stack
+  // frame. This means that we have to use a height of 0.
   unsigned height = 0;
   unsigned height_in_bytes = height * kPointerSize;
+  const char* kind = is_setter_stub_frame ? "setter" : "getter";
   if (FLAG_trace_deopt) {
-    PrintF("  translating setter stub => height=%u\n", height_in_bytes);
+    PrintF("  translating %s stub => height=%u\n", kind, height_in_bytes);
   }

   // We need 1 stack entry for the return address + 4 stack entries from
   // StackFrame::INTERNAL (FP, context, frame type, code object, see
-  // MacroAssembler::EnterFrame) + 1 stack entry from setter stub (implicit
-  // return value, see StoreStubCompiler::CompileStoreViaSetter).
-  unsigned fixed_frame_size = (1 + 4 + 1) * kPointerSize;
+ // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
+  // entry for the implicit return value, see
+  // StoreStubCompiler::CompileStoreViaSetter.
+  unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
+  unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
   unsigned output_frame_size = height_in_bytes + fixed_frame_size;

   // Allocate and store the output frame description.
   FrameDescription* output_frame =
-      new(output_frame_size) FrameDescription(output_frame_size, setter);
+      new(output_frame_size) FrameDescription(output_frame_size, accessor);
   output_frame->SetFrameType(StackFrame::INTERNAL);

-  // A frame for a setter stub can not be the topmost or bottommost one.
+  // A frame for an accessor stub can not be the topmost or bottommost one.
   ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
   ASSERT(output_[frame_index] == NULL);
   output_[frame_index] = output_frame;
@@ -768,15 +772,17 @@
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
-           " ; function (setter sentinel)\n",
-           top_address + output_offset, output_offset, value);
+           " ; function (%s sentinel)\n",
+           top_address + output_offset, output_offset, value, kind);
   }

-  // Get Code object from setter stub.
+  // Get Code object from accessor stub.
   output_offset -= kPointerSize;
-  Code* setter_stub =
-      isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
-  value = reinterpret_cast<intptr_t>(setter_stub);
+  Builtins::Name name = is_setter_stub_frame ?
+      Builtins::kStoreIC_Setter_ForDeopt :
+      Builtins::kLoadIC_Getter_ForDeopt;
+  Code* accessor_stub = isolate_->builtins()->builtin(name);
+  value = reinterpret_cast<intptr_t>(accessor_stub);
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
@@ -789,16 +795,20 @@
       static_cast<Translation::Opcode>(iterator->Next());
   iterator->Skip(Translation::NumberOfOperandsFor(opcode));

-  // The implicit return value was part of the artificial setter stub
-  // environment.
-  output_offset -= kPointerSize;
-  DoTranslateCommand(iterator, frame_index, output_offset);
+  if (is_setter_stub_frame) {
+    // The implicit return value was part of the artificial setter stub
+    // environment.
+    output_offset -= kPointerSize;
+    DoTranslateCommand(iterator, frame_index, output_offset);
+  }

   ASSERT(0 == output_offset);

+  Smi* offset = is_setter_stub_frame ?
+      isolate_->heap()->setter_stub_deopt_pc_offset() :
+      isolate_->heap()->getter_stub_deopt_pc_offset();
   intptr_t pc = reinterpret_cast<intptr_t>(
-      setter_stub->instruction_start() +
-      isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+      accessor_stub->instruction_start() + offset->value());
   output_frame->SetPc(pc);
 }

=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Aug 31 07:45:31 2012 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Sep 7 02:01:54 2012
@@ -423,6 +423,11 @@
     case JS_CONSTRUCT:
       translation->BeginConstructStubFrame(closure_id, translation_size);
       break;
+    case JS_GETTER:
+      ASSERT(translation_size == 1);
+      ASSERT(height == 0);
+      translation->BeginGetterStubFrame(closure_id);
+      break;
     case JS_SETTER:
       ASSERT(translation_size == 2);
       ASSERT(height == 0);
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Aug 28 23:12:46 2012 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Sep 7 02:01:54 2012
@@ -2994,6 +2994,43 @@
   // Return the generated code.
   return GetCode(Code::CALLBACKS, name);
 }
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
+                                             Handle<JSFunction> getter) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- edx    : receiver
+  //  -- esp[0] : return address
+  // -----------------------------------
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    if (!getter.is_null()) {
+      // Call the JavaScript getter with the receiver on the stack.
+      __ push(edx);
+      ParameterCount actual(0);
+      __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
+                        CALL_AS_METHOD);
+    } else {
+ // If we generate a global code snippet for deoptimization only, remember
+      // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore context register.
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  }
+  __ ret(0);
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())


 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
@@ -3012,19 +3049,7 @@
   __ JumpIfSmi(edx, &miss);
   CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss);

-  {
-    FrameScope scope(masm(), StackFrame::INTERNAL);
-
-    // Call the JavaScript getter with the receiver on the stack.
-    __ push(edx);
-    ParameterCount actual(0);
-    __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
-                      CALL_AS_METHOD);
-
-    // Restore context register.
-    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  }
-  __ ret(0);
+  GenerateLoadViaGetter(masm(), getter);

   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
=======================================
--- /branches/bleeding_edge/src/mips/deoptimizer-mips.cc Fri Aug 17 03:43:32 2012 +++ /branches/bleeding_edge/src/mips/deoptimizer-mips.cc Fri Sep 7 02:01:54 2012
@@ -582,30 +582,34 @@
 }


-void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
-                                           int frame_index) {
-  JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver and the implicit return value are expected in registers by the - // StoreIC, so they don't belong to the output stack frame. This means that we
-  // have to use a height of 0.
+void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
+                                             int frame_index,
+                                             bool is_setter_stub_frame) {
+ JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
+  // The receiver (and the implicit return value, if any) are expected in
+ // registers by the LoadIC/StoreIC, so they don't belong to the output stack
+  // frame. This means that we have to use a height of 0.
   unsigned height = 0;
   unsigned height_in_bytes = height * kPointerSize;
+  const char* kind = is_setter_stub_frame ? "setter" : "getter";
   if (FLAG_trace_deopt) {
-    PrintF("  translating setter stub => height=%u\n", height_in_bytes);
+    PrintF("  translating %s stub => height=%u\n", kind, height_in_bytes);
   }

// We need 5 stack entries from StackFrame::INTERNAL (ra, fp, cp, frame type, - // code object, see MacroAssembler::EnterFrame) + 1 stack entry from setter - // stub (implicit return value, see StoreStubCompiler::CompileStoreViaSetter).
-  unsigned fixed_frame_size = (5 + 1) * kPointerSize;
+ // code object, see MacroAssembler::EnterFrame). For a setter stub frame we
+  // need one additional entry for the implicit return value, see
+  // StoreStubCompiler::CompileStoreViaSetter.
+  unsigned fixed_frame_entries = 5 + (is_setter_stub_frame ? 1 : 0);
+  unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
   unsigned output_frame_size = height_in_bytes + fixed_frame_size;

   // Allocate and store the output frame description.
   FrameDescription* output_frame =
-      new(output_frame_size) FrameDescription(output_frame_size, setter);
+      new(output_frame_size) FrameDescription(output_frame_size, accessor);
   output_frame->SetFrameType(StackFrame::INTERNAL);

-  // A frame for a setter stub can not be the topmost or bottommost one.
+  // A frame for an accessor stub can not be the topmost or bottommost one.
   ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
   ASSERT(output_[frame_index] == NULL);
   output_[frame_index] = output_frame;
@@ -655,15 +659,17 @@
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
-           " ; function (setter sentinel)\n",
-           top_address + output_offset, output_offset, value);
+           " ; function (%s sentinel)\n",
+           top_address + output_offset, output_offset, value, kind);
   }

-  // Get Code object from setter stub.
+  // Get Code object from accessor stub.
   output_offset -= kPointerSize;
-  Code* setter_stub =
-      isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
-  value = reinterpret_cast<intptr_t>(setter_stub);
+  Builtins::Name name = is_setter_stub_frame ?
+      Builtins::kStoreIC_Setter_ForDeopt :
+      Builtins::kLoadIC_Getter_ForDeopt;
+  Code* accessor_stub = isolate_->builtins()->builtin(name);
+  value = reinterpret_cast<intptr_t>(accessor_stub);
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
@@ -676,16 +682,20 @@
       static_cast<Translation::Opcode>(iterator->Next());
   iterator->Skip(Translation::NumberOfOperandsFor(opcode));

-  // The implicit return value was part of the artificial setter stub
-  // environment.
-  output_offset -= kPointerSize;
-  DoTranslateCommand(iterator, frame_index, output_offset);
+  if (is_setter_stub_frame) {
+    // The implicit return value was part of the artificial setter stub
+    // environment.
+    output_offset -= kPointerSize;
+    DoTranslateCommand(iterator, frame_index, output_offset);
+  }

   ASSERT(0 == output_offset);

+  Smi* offset = is_setter_stub_frame ?
+      isolate_->heap()->setter_stub_deopt_pc_offset() :
+      isolate_->heap()->getter_stub_deopt_pc_offset();
   intptr_t pc = reinterpret_cast<intptr_t>(
-      setter_stub->instruction_start() +
-      isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+      accessor_stub->instruction_start() + offset->value());
   output_frame->SetPc(pc);
 }

=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Sun Sep 2 23:36:19 2012 +++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Fri Sep 7 02:01:54 2012
@@ -452,6 +452,11 @@
     case JS_CONSTRUCT:
       translation->BeginConstructStubFrame(closure_id, translation_size);
       break;
+    case JS_GETTER:
+      ASSERT(translation_size == 1);
+      ASSERT(height == 0);
+      translation->BeginGetterStubFrame(closure_id);
+      break;
     case JS_SETTER:
       ASSERT(translation_size == 2);
       ASSERT(height == 0);
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Tue Aug 28 23:12:46 2012 +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Fri Sep 7 02:01:54 2012
@@ -2954,6 +2954,43 @@
   // Return the generated code.
   return GetCode(Code::CALLBACKS, name);
 }
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
+                                             Handle<JSFunction> getter) {
+  // ----------- S t a t e -------------
+  //  -- a0    : receiver
+  //  -- a2    : name
+  //  -- ra    : return address
+  // -----------------------------------
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    if (!getter.is_null()) {
+      // Call the JavaScript getter with the receiver on the stack.
+      __ push(a0);
+      ParameterCount actual(0);
+      __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
+                        CALL_AS_METHOD);
+    } else {
+ // If we generate a global code snippet for deoptimization only, remember
+      // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore context register.
+    __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  }
+  __ Ret();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())


 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
@@ -2972,19 +3009,7 @@
   __ JumpIfSmi(a0, &miss);
   CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);

-  {
-    FrameScope scope(masm(), StackFrame::INTERNAL);
-
-    // Call the JavaScript getter with the receiver on the stack.
-    __ push(a0);
-    ParameterCount actual(0);
-    __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
-                      CALL_AS_METHOD);
-
-    // Restore context register.
-    __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
-  __ Ret();
+  GenerateLoadViaGetter(masm(), getter);

   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);
=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed Sep  5 09:08:13 2012
+++ /branches/bleeding_edge/src/objects.cc      Fri Sep  7 02:01:54 2012
@@ -8291,6 +8291,7 @@
           break;
         }

+        case Translation::GETTER_STUB_FRAME:
         case Translation::SETTER_STUB_FRAME: {
           int function_id = iterator.Next();
           JSFunction* function =
=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Tue Aug 28 23:12:46 2012
+++ /branches/bleeding_edge/src/stub-cache.h    Fri Sep  7 02:01:54 2012
@@ -619,6 +619,9 @@
                                    Handle<JSObject> holder,
                                    Handle<AccessorInfo> callback);

+  static void GenerateLoadViaGetter(MacroAssembler* masm,
+                                    Handle<JSFunction> getter);
+
   Handle<Code> CompileLoadViaGetter(Handle<String> name,
                                     Handle<JSObject> receiver,
                                     Handle<JSObject> holder,
=======================================
--- /branches/bleeding_edge/src/x64/deoptimizer-x64.cc Fri Aug 17 03:43:32 2012 +++ /branches/bleeding_edge/src/x64/deoptimizer-x64.cc Fri Sep 7 02:01:54 2012
@@ -591,31 +591,35 @@
 }


-void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
-                                           int frame_index) {
-  JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver and the implicit return value are expected in registers by the - // StoreIC, so they don't belong to the output stack frame. This means that we
-  // have to use a height of 0.
+void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
+                                             int frame_index,
+                                             bool is_setter_stub_frame) {
+ JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
+  // The receiver (and the implicit return value, if any) are expected in
+ // registers by the LoadIC/StoreIC, so they don't belong to the output stack
+  // frame. This means that we have to use a height of 0.
   unsigned height = 0;
   unsigned height_in_bytes = height * kPointerSize;
+  const char* kind = is_setter_stub_frame ? "setter" : "getter";
   if (FLAG_trace_deopt) {
-    PrintF("  translating setter stub => height=%u\n", height_in_bytes);
+    PrintF("  translating %s stub => height=%u\n", kind, height_in_bytes);
   }

   // We need 1 stack entry for the return address + 4 stack entries from
   // StackFrame::INTERNAL (FP, context, frame type, code object, see
-  // MacroAssembler::EnterFrame) + 1 stack entry from setter stub (implicit
-  // return value, see StoreStubCompiler::CompileStoreViaSetter).
-  unsigned fixed_frame_size = (1 + 4 + 1) * kPointerSize;
+ // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
+  // entry for the implicit return value, see
+  // StoreStubCompiler::CompileStoreViaSetter.
+  unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
+  unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
   unsigned output_frame_size = height_in_bytes + fixed_frame_size;

   // Allocate and store the output frame description.
   FrameDescription* output_frame =
-      new(output_frame_size) FrameDescription(output_frame_size, setter);
+      new(output_frame_size) FrameDescription(output_frame_size, accessor);
   output_frame->SetFrameType(StackFrame::INTERNAL);

-  // A frame for a setter stub can not be the topmost or bottommost one.
+  // A frame for an accessor stub can not be the topmost or bottommost one.
   ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
   ASSERT(output_[frame_index] == NULL);
   output_[frame_index] = output_frame;
@@ -665,15 +669,17 @@
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
-           " ; function (setter sentinel)\n",
-           top_address + output_offset, output_offset, value);
+           " ; function (%s sentinel)\n",
+           top_address + output_offset, output_offset, value, kind);
   }

-  // Get Code object from setter stub.
+  // Get Code object from accessor stub.
   output_offset -= kPointerSize;
-  Code* setter_stub =
-      isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
-  value = reinterpret_cast<intptr_t>(setter_stub);
+  Builtins::Name name = is_setter_stub_frame ?
+      Builtins::kStoreIC_Setter_ForDeopt :
+      Builtins::kLoadIC_Getter_ForDeopt;
+  Code* accessor_stub = isolate_->builtins()->builtin(name);
+  value = reinterpret_cast<intptr_t>(accessor_stub);
   output_frame->SetFrameSlot(output_offset, value);
   if (FLAG_trace_deopt) {
     PrintF("    0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
@@ -686,16 +692,20 @@
       static_cast<Translation::Opcode>(iterator->Next());
   iterator->Skip(Translation::NumberOfOperandsFor(opcode));

-  // The implicit return value was part of the artificial setter stub
-  // environment.
-  output_offset -= kPointerSize;
-  DoTranslateCommand(iterator, frame_index, output_offset);
+  if (is_setter_stub_frame) {
+    // The implicit return value was part of the artificial setter stub
+    // environment.
+    output_offset -= kPointerSize;
+    DoTranslateCommand(iterator, frame_index, output_offset);
+  }

   ASSERT(0 == output_offset);

+  Smi* offset = is_setter_stub_frame ?
+      isolate_->heap()->setter_stub_deopt_pc_offset() :
+      isolate_->heap()->getter_stub_deopt_pc_offset();
   intptr_t pc = reinterpret_cast<intptr_t>(
-      setter_stub->instruction_start() +
-      isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+      accessor_stub->instruction_start() + offset->value());
   output_frame->SetPc(pc);
 }

=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Sep 4 02:35:43 2012 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Sep 7 02:01:54 2012
@@ -371,6 +371,11 @@
     case JS_CONSTRUCT:
       translation->BeginConstructStubFrame(closure_id, translation_size);
       break;
+    case JS_GETTER:
+      ASSERT(translation_size == 1);
+      ASSERT(height == 0);
+      translation->BeginGetterStubFrame(closure_id);
+      break;
     case JS_SETTER:
       ASSERT(translation_size == 2);
       ASSERT(height == 0);
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Aug 28 23:12:46 2012 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Sep 7 02:01:54 2012
@@ -2817,6 +2817,43 @@
   // Return the generated code.
   return GetCode(Code::CALLBACKS, name);
 }
+
+
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
+                                             Handle<JSFunction> getter) {
+  // ----------- S t a t e -------------
+  //  -- rax    : receiver
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  // -----------------------------------
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    if (!getter.is_null()) {
+      // Call the JavaScript getter with the receiver on the stack.
+      __ push(rax);
+      ParameterCount actual(0);
+      __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
+                        CALL_AS_METHOD);
+    } else {
+ // If we generate a global code snippet for deoptimization only, remember
+      // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore context register.
+    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+  }
+  __ ret(0);
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())


 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
@@ -2835,19 +2872,7 @@
   __ JumpIfSmi(rax, &miss);
   CheckPrototypes(receiver, rax, holder, rbx, rdx, rdi, name, &miss);

-  {
-    FrameScope scope(masm(), StackFrame::INTERNAL);
-
-    // Call the JavaScript getter with the receiver on the stack.
-    __ push(rax);
-    ParameterCount actual(0);
-    __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
-                      CALL_AS_METHOD);
-
-    // Restore context register.
-    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
-  }
-  __ ret(0);
+  GenerateLoadViaGetter(masm(), getter),

   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::LOAD_IC);

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

Reply via email to