Author: [email protected]
Date: Tue Apr 28 03:40:36 2009
New Revision: 1806

Modified:
    branches/bleeding_edge/src/codegen.h
    branches/bleeding_edge/src/debug.cc
    branches/bleeding_edge/src/ia32/codegen-ia32.cc
    branches/bleeding_edge/src/ia32/ic-ia32.cc
    branches/bleeding_edge/src/ic.cc
    branches/bleeding_edge/src/ic.h
    branches/bleeding_edge/src/v8-counters.h

Log:
Inline the inobject property case for named property loads.
Review URL: http://codereview.chromium.org/99120

Modified: branches/bleeding_edge/src/codegen.h
==============================================================================
--- branches/bleeding_edge/src/codegen.h        (original)
+++ branches/bleeding_edge/src/codegen.h        Tue Apr 28 03:40:36 2009
@@ -116,6 +116,9 @@
    JumpTarget* enter() { return &enter_; }
    void BindExit() { exit_.Bind(0); }
    void BindExit(Result* result) { exit_.Bind(result, 1); }
+  void BindExit(Result* result0, Result* result1) {
+    exit_.Bind(result0, result1, 2);
+  }
    void BindExit(Result* result0, Result* result1, Result* result2) {
      exit_.Bind(result0, result1, result2, 3);
    }

Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Tue Apr 28 03:40:36 2009
@@ -377,9 +377,7 @@
      // is set the patching performed by the runtime system will take place  
in
      // the code copy and will therefore have no effect on the running code
      // keeping it from using the inlined code.
-    if (code->is_keyed_load_stub() &&  
KeyedLoadIC::HasInlinedVersion(pc())) {
-      KeyedLoadIC::ClearInlinedVersion(pc());
-    }
+    if (code->is_keyed_load_stub()) KeyedLoadIC::ClearInlinedVersion(pc());
    }
  }


Modified: branches/bleeding_edge/src/ia32/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/codegen-ia32.cc     (original)
+++ branches/bleeding_edge/src/ia32/codegen-ia32.cc     Tue Apr 28 03:40:36 2009
@@ -30,6 +30,7 @@
  #include "bootstrapper.h"
  #include "codegen-inl.h"
  #include "debug.h"
+#include "ic-inl.h"
  #include "parser.h"
  #include "register-allocator-inl.h"
  #include "runtime.h"
@@ -3410,7 +3411,10 @@
                           ? RelocInfo::CODE_TARGET
                           : RelocInfo::CODE_TARGET_CONTEXT;
    Result answer = frame_->CallLoadIC(mode);
-
+  // A test eax instruction following the call signals that the inobject
+  // property case was inlined.  Ensure that there is not a test eax
+  // instruction here.
+  __ nop();
    // Discard the global object. The result is in answer.
    frame_->Drop();
    return answer;
@@ -5233,6 +5237,47 @@
  #endif


+class DeferredReferenceGetNamedValue: public DeferredCode {
+ public:
+  DeferredReferenceGetNamedValue(CodeGenerator* cgen, Handle<String> name)
+      : DeferredCode(cgen), name_(name) {
+    set_comment("[ DeferredReferenceGetNamedValue");
+  }
+
+  virtual void Generate();
+
+  Label* patch_site() { return &patch_site_; }
+
+ private:
+  Label patch_site_;
+  Handle<String> name_;
+};
+
+
+void DeferredReferenceGetNamedValue::Generate() {
+  CodeGenerator* cgen = generator();
+  Result receiver(cgen);
+  enter()->Bind(&receiver);
+
+  cgen->frame()->Push(&receiver);
+  cgen->frame()->Push(name_);
+  Result answer = cgen->frame()->CallLoadIC(RelocInfo::CODE_TARGET);
+  // The call must be followed by a test eax instruction to indicate
+  // that the inobject property case was inlined.
+  ASSERT(answer.is_register() && answer.reg().is(eax));
+  // Store the delta to the map check instruction here in the test
+  // instruction.
+  int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site());
+  // Here we use masm_-> instead of the double underscore macro because
+  // this is the instruction that gets patched and coverage code gets in
+  // the way.
+  masm_->test(answer.reg(), Immediate(-delta_to_patch_site));
+  __ IncrementCounter(&Counters::named_load_inline_miss, 1);
+  receiver = cgen->frame()->Pop();
+  exit_.Jump(&receiver, &answer);
+}
+
+
  class DeferredReferenceGetKeyedValue: public DeferredCode {
   public:
    DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global)
@@ -5334,16 +5379,63 @@
        // thrown below, we must distinguish between the two kinds of
        // loads (typeof expression loads must not throw a reference
        // error).
-      Comment cmnt(masm, "[ Load from named Property");
-      cgen_->frame()->Push(GetName());
-
        Variable* var = expression_->AsVariableProxy()->AsVariable();
-      ASSERT(var == NULL || var->is_global());
-      RelocInfo::Mode mode = (var == NULL)
-                             ? RelocInfo::CODE_TARGET
-                             : RelocInfo::CODE_TARGET_CONTEXT;
-      Result answer = cgen_->frame()->CallLoadIC(mode);
-      cgen_->frame()->Push(&answer);
+      bool is_global = var != NULL;
+      ASSERT(!is_global || var->is_global());
+
+      if (is_global || cgen_->scope()->is_global_scope()) {
+        // Do not inline the inobject property case for loads from the
+        // global object or loads in toplevel code.
+        Comment cmnt(masm, "[ Load from named Property");
+        cgen_->frame()->Push(GetName());
+
+        RelocInfo::Mode mode = is_global
+                               ? RelocInfo::CODE_TARGET_CONTEXT
+                               : RelocInfo::CODE_TARGET;
+        Result answer = cgen_->frame()->CallLoadIC(mode);
+        // A test eax instruction following the call signals that the
+        // inobject property case was inlined.  Ensure that there is not
+        // a test eax instruction here.
+        __ nop();
+        cgen_->frame()->Push(&answer);
+      } else {
+        // Inline the inobject property case.
+        Comment cmnt(masm, "[ Inlined named property load");
+        DeferredReferenceGetNamedValue* deferred =
+            new DeferredReferenceGetNamedValue(cgen_, GetName());
+        Result receiver = cgen_->frame()->Pop();
+        receiver.ToRegister();
+        // Check that the receiver is a heap object.
+        __ test(receiver.reg(), Immediate(kSmiTagMask));
+        deferred->enter()->Branch(zero, &receiver, not_taken);
+
+        // Preallocate the value register to ensure that there is no
+        // spill emitted between the patch site label and the offset in
+        // the load instruction.
+        Result value = cgen_->allocator()->Allocate();
+        ASSERT(value.is_valid());
+        __ bind(deferred->patch_site());
+        // This is the map check instruction that will be patched.
+        // Initially use an invalid map to force a failure.
+        __ cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
+               Immediate(Factory::null_value()));
+        deferred->enter()->Branch(not_equal, &receiver, not_taken);
+
+        // The delta from the patch label to the load offset must be
+        // statically known.
+        ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) ==
+               LoadIC::kOffsetToLoadInstruction);
+        // The initial (invalid) offset has to be large enough to force
+        // a 32-bit instruction encoding to allow patching with an
+        // arbitrary offset.  Use kMaxInt (minus kHeapObjectTag).
+        int offset = kMaxInt;
+        __ mov(value.reg(), FieldOperand(receiver.reg(), offset));
+
+        __ IncrementCounter(&Counters::named_load_inline, 1);
+        deferred->BindExit(&receiver, &value);
+        cgen_->frame()->Push(&receiver);
+        cgen_->frame()->Push(&value);
+      }
        break;
      }


Modified: branches/bleeding_edge/src/ia32/ic-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/ic-ia32.cc  (original)
+++ branches/bleeding_edge/src/ia32/ic-ia32.cc  Tue Apr 28 03:40:36 2009
@@ -729,36 +729,66 @@
  static const byte kTestEaxByte = 0xA9;


-bool KeyedLoadIC::HasInlinedVersion(Address address) {
-  Address test_instruction_address = address + 4;  // 4 = stub address
-  return *test_instruction_address == kTestEaxByte;
+void LoadIC::ClearInlinedVersion(Address address) {
+  // Reset the map check of the inlined inobject property load (if
+  // present) to guarantee failure by holding an invalid map (the null
+  // value).  The offset can be patched to anything.
+  PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
  }


  void KeyedLoadIC::ClearInlinedVersion(Address address) {
    // Insert null as the map to check for to make sure the map check fails
    // sending control flow to the IC instead of the inlined version.
-  PatchInlinedMapCheck(address, Heap::null_value());
+  PatchInlinedLoad(address, Heap::null_value());
+}
+
+
+bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
+  // The address of the instruction following the call.
+  Address test_instruction_address = address + 4;
+  // If the instruction following the call is not a test eax, nothing
+  // was inlined.
+  if (*test_instruction_address != kTestEaxByte) return false;
+
+  Address delta_address = test_instruction_address + 1;
+  // The delta to the start of the map check instruction.
+  int delta = *reinterpret_cast<int*>(delta_address);
+
+  // The map address is the last 4 bytes of the 7-byte
+  // operand-immediate compare instruction, so we add 3 to get the
+  // offset to the last 4 bytes.
+  Address map_address = test_instruction_address + delta + 3;
+  *(reinterpret_cast<Object**>(map_address)) = map;
+
+  // The offset is in the last 4 bytes of a six byte
+  // memory-to-register move instruction, so we add 2 to get the
+  // offset to the last 4 bytes.
+  Address offset_address =
+      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
+  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
+  return true;
  }


-void KeyedLoadIC::PatchInlinedMapCheck(Address address, Object* value) {
+bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
    Address test_instruction_address = address + 4;  // 4 = stub address
    // The keyed load has a fast inlined case if the IC call instruction
    // is immediately followed by a test instruction.
-  if (*test_instruction_address == kTestEaxByte) {
-    // Fetch the offset from the test instruction to the map cmp
-    // instruction.  This offset is stored in the last 4 bytes of the
-    // 5 byte test instruction.
-    Address offset_address = test_instruction_address + 1;
-    int offset_value = *(reinterpret_cast<int*>(offset_address));
-    // Compute the map address.  The map address is in the last 4
-    // bytes of the 7-byte operand-immediate compare instruction, so
-    // we add 3 to the offset to get the map address.
-    Address map_address = test_instruction_address + offset_value + 3;
-    // Patch the map check.
-    (*(reinterpret_cast<Object**>(map_address))) = value;
-  }
+  if (*test_instruction_address != kTestEaxByte) return false;
+
+  // Fetch the offset from the test instruction to the map cmp
+  // instruction.  This offset is stored in the last 4 bytes of the 5
+  // byte test instruction.
+  Address delta_address = test_instruction_address + 1;
+  int delta = *reinterpret_cast<int*>(delta_address);
+  // Compute the map address.  The map address is in the last 4 bytes
+  // of the 7-byte operand-immediate compare instruction, so we add 3
+  // to the offset to get the map address.
+  Address map_address = test_instruction_address + delta + 3;
+  // Patch the map check.
+  *(reinterpret_cast<Object**>(map_address)) = map;
+  return true;
  }



Modified: branches/bleeding_edge/src/ic.cc
==============================================================================
--- branches/bleeding_edge/src/ic.cc    (original)
+++ branches/bleeding_edge/src/ic.cc    Tue Apr 28 03:40:36 2009
@@ -42,7 +42,7 @@
    switch (state) {
      case UNINITIALIZED: return '0';
      case UNINITIALIZED_IN_LOOP: return 'L';
-    case PREMONOMORPHIC: return '0';
+    case PREMONOMORPHIC: return 'P';
      case MONOMORPHIC: return '1';
      case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
      case MEGAMORPHIC: return 'N';
@@ -244,6 +244,7 @@

  void LoadIC::Clear(Address address, Code* target) {
    if (target->ic_state() == UNINITIALIZED) return;
+  ClearInlinedVersion(address);
    SetTargetAtAddress(address, initialize_stub());
  }

@@ -523,6 +524,31 @@
      LOG(SuspectReadEvent(*name, *object));
    }

+  bool can_be_inlined =
+      FLAG_use_ic &&
+      state == PREMONOMORPHIC &&
+      lookup.IsValid() &&
+      lookup.IsLoaded() &&
+      lookup.IsCacheable() &&
+      lookup.holder() == *object &&
+      lookup.type() == FIELD &&
+      !object->IsAccessCheckNeeded();
+
+  if (can_be_inlined) {
+    Map* map = lookup.holder()->map();
+    // Property's index in the properties array.  If negative we have
+    // an inobject property.
+    int index = lookup.GetFieldIndex() - map->inobject_properties();
+    if (index < 0) {
+      // Index is an offset from the end of the object.
+      int offset = map->instance_size() + (index * kPointerSize);
+      if (PatchInlinedLoad(address(), map, offset)) {
+        set_target(megamorphic_stub());
+        return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
+      }
+    }
+  }
+
    // Update inline cache and stub cache.
    if (FLAG_use_ic && lookup.IsLoaded()) {
      UpdateCaches(&lookup, state, object, name);
@@ -734,7 +760,7 @@
          !object->IsJSValue() &&
          !JSObject::cast(*object)->HasIndexedInterceptor()) {
        Map* map = JSObject::cast(*object)->map();
-      PatchInlinedMapCheck(address(), map);
+      PatchInlinedLoad(address(), map);
      }
    }


Modified: branches/bleeding_edge/src/ic.h
==============================================================================
--- branches/bleeding_edge/src/ic.h     (original)
+++ branches/bleeding_edge/src/ic.h     Tue Apr 28 03:40:36 2009
@@ -216,6 +216,11 @@
    static void GenerateStringLength(MacroAssembler* masm);
    static void GenerateFunctionPrototype(MacroAssembler* masm);

+  // The offset from the inlined patch site to the start of the
+  // inlined load instruction.  It is 7 bytes (test eax, imm) plus
+  // 6 bytes (jne slow_label).
+  static const int kOffsetToLoadInstruction = 13;
+
   private:
    static void Generate(MacroAssembler* masm, const ExternalReference& f);

@@ -238,6 +243,12 @@
    }

    static void Clear(Address address, Code* target);
+
+  // Clear the use of the inlined version.
+  static void ClearInlinedVersion(Address address);
+
+  static bool PatchInlinedLoad(Address address, Object* map, int index);
+
    friend class IC;
  };

@@ -254,9 +265,6 @@
    static void GeneratePreMonomorphic(MacroAssembler* masm);
    static void GenerateGeneric(MacroAssembler* masm);

-  // Check if this IC corresponds to an inlined version.
-  static bool HasInlinedVersion(Address address);
-
    // Clear the use of the inlined version.
    static void ClearInlinedVersion(Address address);

@@ -287,7 +295,7 @@

    // Support for patching the map that is checked in an inlined
    // version of keyed load.
-  static void PatchInlinedMapCheck(Address address, Object* map);
+  static bool PatchInlinedLoad(Address address, Object* map);

    friend class IC;
  };

Modified: branches/bleeding_edge/src/v8-counters.h
==============================================================================
--- branches/bleeding_edge/src/v8-counters.h    (original)
+++ branches/bleeding_edge/src/v8-counters.h    Tue Apr 28 03:40:36 2009
@@ -116,6 +116,8 @@
    SC(keyed_load_interceptor, V8.KeyedLoadInterceptor)               \
    SC(keyed_load_inline, V8.KeyedLoadInline)                         \
    SC(keyed_load_inline_miss, V8.KeyedLoadInlineMiss)                \
+  SC(named_load_inline, V8.NamedLoadInline)                         \
+  SC(named_load_inline_miss, V8.NamedLoadInlineMiss)                \
    SC(keyed_store_field, V8.KeyedStoreField)                         \
    SC(for_in, V8.ForIn)                                              \
    SC(enum_cache_hits, V8.EnumCacheHits)                             \

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

Reply via email to