More efficient use of space in AllocationSite.
authormvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 13 Jan 2014 10:28:01 +0000 (10:28 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 13 Jan 2014 10:28:01 +0000 (10:28 +0000)
We can eliminate one word from the object by sharing the pretenuring decision and the found memento count.

R=bmeurer@chromium.org, hpayer@chromium.org

Review URL: https://codereview.chromium.org/132063004

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

src/code-stubs-hydrogen.cc
src/heap-snapshot-generator.cc
src/heap.cc
src/hydrogen-instructions.cc
src/hydrogen.cc
src/objects-inl.h
src/objects-printer.cc
src/objects.cc
src/objects.h

index 67f9dc8..785b9ca 100644 (file)
@@ -491,20 +491,16 @@ HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
                             AllocationSite::kNestedSiteOffset),
                         graph()->GetConstant0());
 
-  // Pretenuring calculation fields.
+  // Pretenuring calculation field.
   Add<HStoreNamedField>(object,
                         HObjectAccess::ForAllocationSiteOffset(
-                            AllocationSite::kMementoFoundCountOffset),
+                            AllocationSite::kPretenureDataOffset),
                         graph()->GetConstant0());
 
+  // Pretenuring memento creation count field.
   Add<HStoreNamedField>(object,
                         HObjectAccess::ForAllocationSiteOffset(
-                            AllocationSite::kMementoCreateCountOffset),
-                        graph()->GetConstant0());
-
-  Add<HStoreNamedField>(object,
-                        HObjectAccess::ForAllocationSiteOffset(
-                            AllocationSite::kPretenureDecisionOffset),
+                            AllocationSite::kPretenureCreateCountOffset),
                         graph()->GetConstant0());
 
   // Store an empty fixed array for the code dependency.
index 3125a26..6be580f 100644 (file)
@@ -1403,15 +1403,12 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
                        AllocationSite::kTransitionInfoOffset);
   SetInternalReference(site, entry, "nested_site", site->nested_site(),
                        AllocationSite::kNestedSiteOffset);
-  SetInternalReference(site, entry, "memento_found_count",
-                       site->memento_found_count(),
-                       AllocationSite::kMementoFoundCountOffset);
-  SetInternalReference(site, entry, "memento_create_count",
-                       site->memento_create_count(),
-                       AllocationSite::kMementoCreateCountOffset);
-  SetInternalReference(site, entry, "pretenure_decision",
-                       site->pretenure_decision(),
-                       AllocationSite::kPretenureDecisionOffset);
+  SetInternalReference(site, entry, "pretenure_data",
+                       site->pretenure_data(),
+                       AllocationSite::kPretenureDataOffset);
+  SetInternalReference(site, entry, "pretenure_create_count",
+                       site->pretenure_create_count(),
+                       AllocationSite::kPretenureCreateCountOffset);
   SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
                        AllocationSite::kDependentCodeOffset);
 }
index 60b425c..5ca85ec 100644 (file)
@@ -526,8 +526,8 @@ void Heap::ProcessPretenuringFeedback() {
               list_element->IsAllocationSite()) {
       AllocationSite* site = use_scratchpad ?
         allocation_sites_scratchpad[i] : AllocationSite::cast(list_element);
-      allocation_mementos_found += site->memento_found_count()->value();
-      if (site->memento_found_count()->value() > 0) {
+      allocation_mementos_found += site->memento_found_count();
+      if (site->memento_found_count() > 0) {
         active_allocation_sites++;
       }
       if (site->DigestPretenuringFeedback()) {
index 4991668..4e614d8 100644 (file)
@@ -4284,11 +4284,9 @@ HObjectAccess HObjectAccess::ForAllocationSiteOffset(int offset) {
       return HObjectAccess(kInobject, offset, Representation::Tagged());
     case AllocationSite::kNestedSiteOffset:
       return HObjectAccess(kInobject, offset, Representation::Tagged());
-    case AllocationSite::kMementoFoundCountOffset:
+    case AllocationSite::kPretenureDataOffset:
       return HObjectAccess(kInobject, offset, Representation::Smi());
-    case AllocationSite::kMementoCreateCountOffset:
-      return HObjectAccess(kInobject, offset, Representation::Smi());
-    case AllocationSite::kPretenureDecisionOffset:
+    case AllocationSite::kPretenureCreateCountOffset:
       return HObjectAccess(kInobject, offset, Representation::Smi());
     case AllocationSite::kDependentCodeOffset:
       return HObjectAccess(kInobject, offset, Representation::Tagged());
index 90f9c34..dbd52a4 100644 (file)
@@ -2642,7 +2642,7 @@ void HGraphBuilder::BuildCreateAllocationMemento(
   if (FLAG_allocation_site_pretenuring) {
     HValue* memento_create_count = Add<HLoadNamedField>(
         allocation_site, HObjectAccess::ForAllocationSiteOffset(
-            AllocationSite::kMementoCreateCountOffset));
+            AllocationSite::kPretenureCreateCountOffset));
     memento_create_count = AddUncasted<HAdd>(
         memento_create_count, graph()->GetConstant1());
     // This smi value is reset to zero after every gc, overflow isn't a problem
@@ -2650,7 +2650,7 @@ void HGraphBuilder::BuildCreateAllocationMemento(
     memento_create_count->ClearFlag(HValue::kCanOverflow);
     HStoreNamedField* store = Add<HStoreNamedField>(
         allocation_site, HObjectAccess::ForAllocationSiteOffset(
-            AllocationSite::kMementoCreateCountOffset), memento_create_count);
+            AllocationSite::kPretenureCreateCountOffset), memento_create_count);
     // No write barrier needed to store a smi.
     store->SkipWriteBarrier();
   }
index bcfb598..49e4d69 100644 (file)
@@ -48,6 +48,7 @@
 #include "factory.h"
 #include "incremental-marking.h"
 #include "transitions-inl.h"
+#include "objects-visiting.h"
 
 namespace v8 {
 namespace internal {
@@ -1304,9 +1305,8 @@ void AllocationSite::Initialize() {
   set_transition_info(Smi::FromInt(0));
   SetElementsKind(GetInitialFastElementsKind());
   set_nested_site(Smi::FromInt(0));
-  set_memento_create_count(Smi::FromInt(0));
-  set_memento_found_count(Smi::FromInt(0));
-  set_pretenure_decision(Smi::FromInt(0));
+  set_pretenure_data(Smi::FromInt(0));
+  set_pretenure_create_count(Smi::FromInt(0));
   set_dependent_code(DependentCode::cast(GetHeap()->empty_fixed_array()),
                      SKIP_WRITE_BARRIER);
 }
@@ -1315,7 +1315,7 @@ void AllocationSite::Initialize() {
 void AllocationSite::MarkZombie() {
   ASSERT(!IsZombie());
   Initialize();
-  set_pretenure_decision(Smi::FromInt(kZombie));
+  set_pretenure_decision(kZombie);
 }
 
 
@@ -1367,35 +1367,50 @@ inline DependentCode::DependencyGroup AllocationSite::ToDependencyGroup(
 }
 
 
+inline void AllocationSite::set_memento_found_count(int count) {
+  int value = pretenure_data()->value();
+  // Verify that we can count more mementos than we can possibly find in one
+  // new space collection.
+  ASSERT((GetHeap()->MaxSemiSpaceSize() /
+          (StaticVisitorBase::kMinObjectSizeInWords * kPointerSize +
+           AllocationMemento::kSize)) < MementoFoundCountBits::kMax);
+  ASSERT(count < MementoFoundCountBits::kMax);
+  set_pretenure_data(
+      Smi::FromInt(MementoFoundCountBits::update(value, count)),
+      SKIP_WRITE_BARRIER);
+}
+
 inline bool AllocationSite::IncrementMementoFoundCount() {
   if (IsZombie()) return false;
 
-  int value = memento_found_count()->value();
-  set_memento_found_count(Smi::FromInt(value + 1));
+  int value = memento_found_count();
+  set_memento_found_count(value + 1);
   return value == 0;
 }
 
 
 inline void AllocationSite::IncrementMementoCreateCount() {
   ASSERT(FLAG_allocation_site_pretenuring);
-  int value = memento_create_count()->value();
-  set_memento_create_count(Smi::FromInt(value + 1));
+  int value = memento_create_count();
+  set_memento_create_count(value + 1);
 }
 
 
 inline bool AllocationSite::DigestPretenuringFeedback() {
   bool decision_made = false;
-  int create_count = memento_create_count()->value();
+  int create_count = memento_create_count();
   if (create_count >= kPretenureMinimumCreated) {
-    int found_count = memento_found_count()->value();
+    int found_count = memento_found_count();
     double ratio = static_cast<double>(found_count) / create_count;
     if (FLAG_trace_track_allocation_sites) {
       PrintF("AllocationSite: %p (created, found, ratio) (%d, %d, %f)\n",
              static_cast<void*>(this), create_count, found_count, ratio);
     }
     int current_mode = GetPretenureMode();
-    int result = ratio >= kPretenureRatio ? kTenure : kDontTenure;
-    set_pretenure_decision(Smi::FromInt(result));
+    PretenureDecision result = ratio >= kPretenureRatio
+        ? kTenure
+        : kDontTenure;
+    set_pretenure_decision(result);
     decision_made = true;
     if (current_mode != GetPretenureMode()) {
       dependent_code()->DeoptimizeDependentCodeGroup(
@@ -1405,8 +1420,8 @@ inline bool AllocationSite::DigestPretenuringFeedback() {
   }
 
   // Clear feedback calculation fields until the next gc.
-  set_memento_found_count(Smi::FromInt(0));
-  set_memento_create_count(Smi::FromInt(0));
+  set_memento_found_count(0);
+  set_memento_create_count(0);
   return decision_made;
 }
 
@@ -4600,10 +4615,9 @@ ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
 
 ACCESSORS(AllocationSite, transition_info, Object, kTransitionInfoOffset)
 ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
-ACCESSORS_TO_SMI(AllocationSite, memento_found_count, kMementoFoundCountOffset)
-ACCESSORS_TO_SMI(AllocationSite, memento_create_count,
-                 kMementoCreateCountOffset)
-ACCESSORS_TO_SMI(AllocationSite, pretenure_decision, kPretenureDecisionOffset)
+ACCESSORS_TO_SMI(AllocationSite, pretenure_data, kPretenureDataOffset)
+ACCESSORS_TO_SMI(AllocationSite, pretenure_create_count,
+                 kPretenureCreateCountOffset)
 ACCESSORS(AllocationSite, dependent_code, DependentCode,
           kDependentCodeOffset)
 ACCESSORS(AllocationSite, weak_next, Object, kWeakNextOffset)
index 1da9852..219b692 100644 (file)
@@ -1136,11 +1136,11 @@ void AllocationSite::AllocationSitePrint(FILE* out) {
   PrintF(out, "\n - nested site: ");
   nested_site()->ShortPrint(out);
   PrintF(out, "\n - memento found count: ");
-  memento_found_count()->ShortPrint(out);
+  Smi::FromInt(memento_found_count())->ShortPrint(out);
   PrintF(out, "\n - memento create count: ");
-  memento_create_count()->ShortPrint(out);
+  Smi::FromInt(memento_create_count())->ShortPrint(out);
   PrintF(out, "\n - pretenure decision: ");
-  pretenure_decision()->ShortPrint(out);
+  Smi::FromInt(pretenure_decision())->ShortPrint(out);
   PrintF(out, "\n - transition_info: ");
   if (transition_info()->IsSmi()) {
     ElementsKind kind = GetElementsKind();
index 539d4af..5f24920 100644 (file)
@@ -45,7 +45,6 @@
 #include "isolate-inl.h"
 #include "log.h"
 #include "objects-inl.h"
-#include "objects-visiting.h"
 #include "objects-visiting-inl.h"
 #include "macro-assembler.h"
 #include "mark-compact.h"
@@ -12797,14 +12796,14 @@ void AllocationSite::ResetPretenureDecision() {
   dependent_code()->DeoptimizeDependentCodeGroup(
       GetIsolate(),
       DependentCode::kAllocationSiteTenuringChangedGroup);
-  set_pretenure_decision(Smi::FromInt(kUndecided));
-  set_memento_found_count(Smi::FromInt(0));
-  set_memento_create_count(Smi::FromInt(0));
+  set_pretenure_decision(kUndecided);
+  set_memento_found_count(0);
+  set_memento_create_count(0);
 }
 
 
 PretenureFlag AllocationSite::GetPretenureMode() {
-  int mode = pretenure_decision()->value();
+  PretenureDecision mode = pretenure_decision();
   // Zombie objects "decide" to be untenured.
   return (mode == kTenure && GetHeap()->GetPretenureMode() == TENURED)
       ? TENURED : NOT_TENURED;
index 1dc54b2..f9e416a 100644 (file)
@@ -8125,11 +8125,12 @@ class AllocationSite: public Struct {
   static const int kPretenureMinimumCreated = 100;
 
   // Values for pretenure decision field.
-  enum {
+  enum PretenureDecision {
     kUndecided = 0,
     kDontTenure = 1,
     kTenure = 2,
-    kZombie = 3
+    kZombie = 3,
+    kLastPretenureDecisionValue = kZombie
   };
 
   DECL_ACCESSORS(transition_info, Object)
@@ -8137,11 +8138,8 @@ class AllocationSite: public Struct {
   // walked in a particular order. So [[1, 2], 1, 2] will have one
   // nested_site, but [[1, 2], 3, [4]] will have a list of two.
   DECL_ACCESSORS(nested_site, Object)
-  DECL_ACCESSORS(memento_found_count, Smi)
-  DECL_ACCESSORS(memento_create_count, Smi)
-  // TODO(mvstanton): we don't need a whole integer to record pretenure
-  // decision. Consider sharing space with memento_found_count.
-  DECL_ACCESSORS(pretenure_decision, Smi)
+  DECL_ACCESSORS(pretenure_data, Smi)
+  DECL_ACCESSORS(pretenure_create_count, Smi)
   DECL_ACCESSORS(dependent_code, DependentCode)
   DECL_ACCESSORS(weak_next, Object)
 
@@ -8150,10 +8148,16 @@ class AllocationSite: public Struct {
   // This method is expensive, it should only be called for reporting.
   bool IsNestedSite();
 
+  // transition_info bitfields, for constructed array transition info.
   class ElementsKindBits:       public BitField<ElementsKind, 0,  15> {};
   class UnusedBits:             public BitField<int,          15, 14> {};
   class DoNotInlineBit:         public BitField<bool,         29,  1> {};
 
+  // Bitfields for pretenure_data
+  class MementoFoundCountBits:  public BitField<int,          0, 28> {};
+  class PretenureDecisionBits:  public BitField<PretenureDecision, 28, 2> {};
+  STATIC_ASSERT(PretenureDecisionBits::kMax >= kLastPretenureDecisionValue);
+
   // Increments the mementos found counter and returns true when the first
   // memento was found for a given allocation site.
   inline bool IncrementMementoFoundCount();
@@ -8164,12 +8168,39 @@ class AllocationSite: public Struct {
 
   void ResetPretenureDecision();
 
+  PretenureDecision pretenure_decision() {
+    int value = pretenure_data()->value();
+    return PretenureDecisionBits::decode(value);
+  }
+
+  void set_pretenure_decision(PretenureDecision decision) {
+    int value = pretenure_data()->value();
+    set_pretenure_data(
+        Smi::FromInt(PretenureDecisionBits::update(value, decision)),
+        SKIP_WRITE_BARRIER);
+  }
+
+  int memento_found_count() {
+    int value = pretenure_data()->value();
+    return MementoFoundCountBits::decode(value);
+  }
+
+  inline void set_memento_found_count(int count);
+
+  int memento_create_count() {
+    return pretenure_create_count()->value();
+  }
+
+  void set_memento_create_count(int count) {
+    set_pretenure_create_count(Smi::FromInt(count), SKIP_WRITE_BARRIER);
+  }
+
   // The pretenuring decision is made during gc, and the zombie state allows
   // us to recognize when an allocation site is just being kept alive because
   // a later traversal of new space may discover AllocationMementos that point
   // to this AllocationSite.
   bool IsZombie() {
-    return pretenure_decision()->value() == kZombie;
+    return pretenure_decision() == kZombie;
   }
 
   inline void MarkZombie();
@@ -8227,13 +8258,11 @@ class AllocationSite: public Struct {
 
   static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
   static const int kNestedSiteOffset = kTransitionInfoOffset + kPointerSize;
-  static const int kMementoFoundCountOffset = kNestedSiteOffset + kPointerSize;
-  static const int kMementoCreateCountOffset =
-      kMementoFoundCountOffset + kPointerSize;
-  static const int kPretenureDecisionOffset =
-      kMementoCreateCountOffset + kPointerSize;
+  static const int kPretenureDataOffset = kNestedSiteOffset + kPointerSize;
+  static const int kPretenureCreateCountOffset =
+      kPretenureDataOffset + kPointerSize;
   static const int kDependentCodeOffset =
-      kPretenureDecisionOffset + kPointerSize;
+      kPretenureCreateCountOffset + kPointerSize;
   static const int kWeakNextOffset = kDependentCodeOffset + kPointerSize;
   static const int kSize = kWeakNextOffset + kPointerSize;
 
@@ -8250,7 +8279,7 @@ class AllocationSite: public Struct {
  private:
   inline DependentCode::DependencyGroup ToDependencyGroup(Reason reason);
   bool PretenuringDecisionMade() {
-    return pretenure_decision()->value() != kUndecided;
+    return pretenure_decision() != kUndecided;
   }
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSite);