Revision: 3543
Author: [email protected]
Date: Wed Jan  6 03:19:28 2010
Log: - Adjust the number to string cache based on the max semispace size.
  Flushed at compacting mark sweep.
- Simplified FindEntry by eliminating the counter.

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

Modified:
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h

=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Jan  5 03:30:05 2010
+++ /branches/bleeding_edge/src/heap.cc Wed Jan  6 03:19:28 2010
@@ -576,6 +576,8 @@

   Top::MarkCompactPrologue(is_compacting);
   ThreadManager::MarkCompactPrologue(is_compacting);
+
+  if (is_compacting) FlushNumberStringCache();
 }


@@ -1573,10 +1575,7 @@

   CreateFixedStubs();

-  // Allocate the number->string conversion cache
-  obj = AllocateFixedArray(kNumberStringCacheSize * 2);
-  if (obj->IsFailure()) return false;
-  set_number_string_cache(FixedArray::cast(obj));
+  if (InitializeNumberStringCache()->IsFailure()) return false;

   // Allocate cache for single character strings.
   obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
@@ -1605,27 +1604,47 @@

   return true;
 }
+
+
+Object* Heap::InitializeNumberStringCache() {
+ // Compute the size of the number string cache based on the max heap size.
+  // max_semispace_size_ == 512 KB => number_string_cache_size = 32.
+  // max_semispace_size_ ==   8 MB => number_string_cache_size = 16KB.
+  int number_string_cache_size = max_semispace_size_ / 512;
+  number_string_cache_size = Max(32, Min(16*KB, number_string_cache_size));
+  Object* obj = AllocateFixedArray(number_string_cache_size * 2);
+  if (!obj->IsFailure()) set_number_string_cache(FixedArray::cast(obj));
+  return obj;
+}
+
+
+void Heap::FlushNumberStringCache() {
+  // Flush the number to string cache.
+  int len = number_string_cache()->length();
+  for (int i = 0; i < len; i++) {
+    number_string_cache()->set_undefined(i);
+  }
+}


 static inline int double_get_hash(double d) {
   DoubleRepresentation rep(d);
-  return ((static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32)) &
-          (Heap::kNumberStringCacheSize - 1));
+  return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
 }


 static inline int smi_get_hash(Smi* smi) {
-  return (smi->value() & (Heap::kNumberStringCacheSize - 1));
-}
-
+  return smi->value();
+}


 Object* Heap::GetNumberStringCache(Object* number) {
   int hash;
+  int mask = (number_string_cache()->length() >> 1) - 1;
   if (number->IsSmi()) {
-    hash = smi_get_hash(Smi::cast(number));
+    hash = smi_get_hash(Smi::cast(number)) & mask;
   } else {
-    hash = double_get_hash(number->Number());
+    hash = double_get_hash(number->Number()) & mask;
   }
   Object* key = number_string_cache()->get(hash * 2);
   if (key == number) {
@@ -1641,11 +1660,12 @@

 void Heap::SetNumberStringCache(Object* number, String* string) {
   int hash;
+  int mask = (number_string_cache()->length() >> 1) - 1;
   if (number->IsSmi()) {
-    hash = smi_get_hash(Smi::cast(number));
+    hash = smi_get_hash(Smi::cast(number)) & mask;
     number_string_cache()->set(hash * 2, number, SKIP_WRITE_BARRIER);
   } else {
-    hash = double_get_hash(number->Number());
+    hash = double_get_hash(number->Number()) & mask;
     number_string_cache()->set(hash * 2, number);
   }
   number_string_cache()->set(hash * 2 + 1, string);
=======================================
--- /branches/bleeding_edge/src/heap.h  Tue Dec 22 05:07:27 2009
+++ /branches/bleeding_edge/src/heap.h  Wed Jan  6 03:19:28 2010
@@ -820,9 +820,6 @@
   // Update the cache with a new number-string pair.
   static void SetNumberStringCache(Object* number, String* str);

-  // Entries in the cache.  Must be a power of 2.
-  static const int kNumberStringCacheSize = 64;
-
   // Adjusts the amount of registered external memory.
   // Returns the adjusted value.
static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
@@ -1098,6 +1095,12 @@
                                            SharedFunctionInfo* shared,
                                            Object* prototype);

+
+ // Initializes the number to string cache based on the max semispace size.
+  static Object* InitializeNumberStringCache();
+  // Flush the number to string cache.
+  static void FlushNumberStringCache();
+
   static const int kInitialSymbolTableSize = 2048;
   static const int kInitialEvalCacheSize = 64;

=======================================
--- /branches/bleeding_edge/src/objects.cc      Tue Jan  5 04:33:55 2010
+++ /branches/bleeding_edge/src/objects.cc      Wed Jan  6 03:19:28 2010
@@ -6848,30 +6848,18 @@
 }


-
-// Find entry for key otherwise return -1.
+// Find entry for key otherwise return kNotFound.
 template<typename Shape, typename Key>
 int HashTable<Shape, Key>::FindEntry(Key key) {
-  uint32_t nof = NumberOfElements();
-  if (nof == 0) return kNotFound;  // Bail out if empty.
-
   uint32_t capacity = Capacity();
-  uint32_t hash = Shape::Hash(key);
-  uint32_t entry = GetProbe(hash, 0, capacity);
-
-  Object* element = KeyAt(entry);
-  uint32_t passed_elements = 0;
-  if (!element->IsNull()) {
- if (!element->IsUndefined() && Shape::IsMatch(key, element)) return entry;
-    if (++passed_elements == nof) return kNotFound;
-  }
-  for (uint32_t i = 1; !element->IsUndefined(); i++) {
-    entry = GetProbe(hash, i, capacity);
-    element = KeyAt(entry);
-    if (!element->IsNull()) {
- if (!element->IsUndefined() && Shape::IsMatch(key, element)) return entry;
-      if (++passed_elements == nof) return kNotFound;
-    }
+  uint32_t entry = FirstProbe(Shape::Hash(key), capacity);
+  uint32_t count = 1;
+  // EnsureCapacity will guarantee the hash table is never full.
+  while (true) {
+    Object* element = KeyAt(entry);
+    if (element->IsUndefined()) break;  // Empty entry.
+    if (!element->IsNull() && Shape::IsMatch(key, element)) return entry;
+    entry = NextProbe(entry, count++, capacity);
   }
   return kNotFound;
 }
@@ -6916,19 +6904,20 @@
   table->SetNumberOfDeletedElements(0);
   return table;
 }
+


 template<typename Shape, typename Key>
 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
   uint32_t capacity = Capacity();
-  uint32_t entry = GetProbe(hash, 0, capacity);
-  Object* element = KeyAt(entry);
-
- for (uint32_t i = 1; !(element->IsUndefined() || element->IsNull()); i++) {
-    entry = GetProbe(hash, i, capacity);
-    element = KeyAt(entry);
-  }
-
+  uint32_t entry = FirstProbe(hash, capacity);
+  uint32_t count = 1;
+  // EnsureCapacity will guarantee the hash table is never full.
+  while (true) {
+    Object* element = KeyAt(entry);
+    if (element->IsUndefined() || element->IsNull()) break;
+    entry = NextProbe(entry, count++, capacity);
+  }
   return entry;
 }

@@ -7007,6 +6996,10 @@
 template
 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();

+template
+int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
+
+
 // Collates undefined and unexisting elements below limit from position
 // zero of the elements. The object stays in Dictionary mode.
 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Jan  6 03:09:30 2010
+++ /branches/bleeding_edge/src/objects.h       Wed Jan  6 03:19:28 2010
@@ -1987,6 +1987,14 @@
     ASSERT(IsPowerOf2(size));
     return (hash + GetProbeOffset(number)) & (size - 1);
   }
+
+  static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
+    return hash & (size - 1);
+  }
+
+ static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) {
+    return (last + number) & (size - 1);
+  }

   // Ensure enough space for n additional elements.
   Object* EnsureCapacity(int n, Key key);
-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to