Add seed to hash of numeric keyed properties. This is a commit of http://codereview...
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 10 Jan 2012 12:58:41 +0000 (12:58 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 10 Jan 2012 12:58:41 +0000 (12:58 +0000)
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10366 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

17 files changed:
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/debug.h
src/frames.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/mips/macro-assembler-mips.cc
src/mips/macro-assembler-mips.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/profile-generator.cc
src/profile-generator.h
src/utils.h
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
test/cctest/test-hashing.cc

index d2d1523..05d6746 100644 (file)
@@ -1414,6 +1414,35 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 }
 
 
+void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
+  // First of all we assign the hash seed to scratch.
+  LoadRoot(scratch, Heap::kStringHashSeedRootIndex);
+  SmiUntag(scratch);
+
+  // Xor original key with a seed.
+  eor(t0, t0, Operand(scratch));
+
+  // Compute the hash code from the untagged key.  This must be kept in sync
+  // with ComputeIntegerHash in utils.h.
+  //
+  // hash = ~hash + (hash << 15);
+  mvn(scratch, Operand(t0));
+  add(t0, scratch, Operand(t0, LSL, 15));
+  // hash = hash ^ (hash >> 12);
+  eor(t0, t0, Operand(t0, LSR, 12));
+  // hash = hash + (hash << 2);
+  add(t0, t0, Operand(t0, LSL, 2));
+  // hash = hash ^ (hash >> 4);
+  eor(t0, t0, Operand(t0, LSR, 4));
+  // hash = hash * 2057;
+  mov(scratch, Operand(t0, LSL, 11));
+  add(t0, t0, Operand(t0, LSL, 3));
+  add(t0, t0, scratch);
+  // hash = hash ^ (hash >> 16);
+  eor(t0, t0, Operand(t0, LSR, 16));
+}
+
+
 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
                                               Register elements,
                                               Register key,
@@ -1443,24 +1472,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
   // t2 - used for the index into the dictionary.
   Label done;
 
-  // Compute the hash code from the untagged key.  This must be kept in sync
-  // with ComputeIntegerHash in utils.h.
-  //
-  // hash = ~hash + (hash << 15);
-  mvn(t1, Operand(t0));
-  add(t0, t1, Operand(t0, LSL, 15));
-  // hash = hash ^ (hash >> 12);
-  eor(t0, t0, Operand(t0, LSR, 12));
-  // hash = hash + (hash << 2);
-  add(t0, t0, Operand(t0, LSL, 2));
-  // hash = hash ^ (hash >> 4);
-  eor(t0, t0, Operand(t0, LSR, 4));
-  // hash = hash * 2057;
-  mov(t1, Operand(t0, LSL, 11));
-  add(t0, t0, Operand(t0, LSL, 3));
-  add(t0, t0, t1);
-  // hash = hash ^ (hash >> 16);
-  eor(t0, t0, Operand(t0, LSR, 16));
+  GetNumberHash(t0, t1);
 
   // Compute the capacity mask.
   ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
index fff6def..9ce0892 100644 (file)
@@ -591,6 +591,9 @@ class MacroAssembler: public Assembler {
                               Label* miss);
 
 
+  void GetNumberHash(Register t0, Register scratch);
+
+
   void LoadFromNumberDictionary(Label* miss,
                                 Register elements,
                                 Register key,
index a39d801..05a6b59 100644 (file)
@@ -178,7 +178,9 @@ class ScriptCache : private HashMap {
 
  private:
   // Calculate the hash value from the key (script id).
-  static uint32_t Hash(int key) { return ComputeIntegerHash(key); }
+  static uint32_t Hash(int key) {
+    return ComputeIntegerHash(key, v8::internal::kZeroHashSeed);
+  }
 
   // Scripts match if their keys (script id) match.
   static bool ScriptMatch(void* key1, void* key2) { return key1 == key2; }
index e3ed2de..2e363fd 100644 (file)
@@ -1303,7 +1303,8 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
   isolate_->counters()->pc_to_code()->Increment();
   ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
   uint32_t hash = ComputeIntegerHash(
-      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)));
+      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
+      v8::internal::kZeroHashSeed);
   uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
   InnerPointerToCodeCacheEntry* entry = cache(index);
   if (entry->inner_pointer == inner_pointer) {
index 66bfb65..f0cacc9 100644 (file)
@@ -992,6 +992,49 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 }
 
 
+// Compute the hash code from the untagged key.  This must be kept in sync
+// with ComputeIntegerHash in utils.h.
+//
+// Note: r0 will contain hash code
+void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
+  // Xor original key with a seed.
+  if (Serializer::enabled()) {
+    ExternalReference roots_array_start =
+        ExternalReference::roots_array_start(isolate());
+    mov(scratch, Immediate(Heap::kStringHashSeedRootIndex));
+    xor_(r0, Operand::StaticArray(scratch,
+                                  times_pointer_size,
+                                  roots_array_start));
+  } else {
+    int32_t seed = isolate()->heap()->StringHashSeed();
+    xor_(r0, Immediate(seed));
+  }
+
+  // hash = ~hash + (hash << 15);
+  mov(scratch, r0);
+  not_(r0);
+  shl(scratch, 15);
+  add(r0, scratch);
+  // hash = hash ^ (hash >> 12);
+  mov(scratch, r0);
+  shr(scratch, 12);
+  xor_(r0, scratch);
+  // hash = hash + (hash << 2);
+  lea(r0, Operand(r0, r0, times_4, 0));
+  // hash = hash ^ (hash >> 4);
+  mov(scratch, r0);
+  shr(scratch, 4);
+  xor_(r0, scratch);
+  // hash = hash * 2057;
+  imul(r0, r0, 2057);
+  // hash = hash ^ (hash >> 16);
+  mov(scratch, r0);
+  shr(scratch, 16);
+  xor_(r0, scratch);
+}
+
+
+
 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
                                               Register elements,
                                               Register key,
@@ -1017,30 +1060,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
 
   Label done;
 
-  // Compute the hash code from the untagged key.  This must be kept in sync
-  // with ComputeIntegerHash in utils.h.
-  //
-  // hash = ~hash + (hash << 15);
-  mov(r1, r0);
-  not_(r0);
-  shl(r1, 15);
-  add(r0, r1);
-  // hash = hash ^ (hash >> 12);
-  mov(r1, r0);
-  shr(r1, 12);
-  xor_(r0, r1);
-  // hash = hash + (hash << 2);
-  lea(r0, Operand(r0, r0, times_4, 0));
-  // hash = hash ^ (hash >> 4);
-  mov(r1, r0);
-  shr(r1, 4);
-  xor_(r0, r1);
-  // hash = hash * 2057;
-  imul(r0, r0, 2057);
-  // hash = hash ^ (hash >> 16);
-  mov(r1, r0);
-  shr(r1, 16);
-  xor_(r0, r1);
+  GetNumberHash(r0, r1);
 
   // Compute capacity mask.
   mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
index f7400ad..a35b5c7 100644 (file)
@@ -498,6 +498,9 @@ class MacroAssembler: public Assembler {
                               Label* miss);
 
 
+  void GetNumberHash(Register r0, Register scratch);
+
+
   void LoadFromNumberDictionary(Label* miss,
                                 Register elements,
                                 Register key,
index cdacbf3..2a566f2 100644 (file)
@@ -409,6 +409,44 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 }
 
 
+void MacroAssembler::GetNumberHash(Register reg0, Register scratch) {
+  // First of all we assign the hash seed to scratch.
+  LoadRoot(scratch, Heap::kStringHashSeedRootIndex);
+  SmiUntag(scratch);
+
+  // Xor original key with a seed.
+  xor_(reg0, reg0, scratch);
+
+  // Compute the hash code from the untagged key.  This must be kept in sync
+  // with ComputeIntegerHash in utils.h.
+  //
+  // hash = ~hash + (hash << 15);
+  nor(scratch, reg0, zero_reg);
+  sll(at, reg0, 15);
+  addu(reg0, scratch, at);
+
+  // hash = hash ^ (hash >> 12);
+  srl(at, reg0, 12);
+  xor_(reg0, reg0, at);
+
+  // hash = hash + (hash << 2);
+  sll(at, reg0, 2);
+  addu(reg0, reg0, at);
+
+  // hash = hash ^ (hash >> 4);
+  srl(at, reg0, 4);
+  xor_(reg0, reg0, at);
+
+  // hash = hash * 2057;
+  li(scratch, Operand(2057));
+  mul(reg0, reg0, scratch);
+
+  // hash = hash ^ (hash >> 16);
+  srl(at, reg0, 16);
+  xor_(reg0, reg0, at);
+}
+
+
 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
                                               Register elements,
                                               Register key,
@@ -440,33 +478,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
   // at   - Temporary (avoid MacroAssembler instructions also using 'at').
   Label done;
 
-  // Compute the hash code from the untagged key.  This must be kept in sync
-  // with ComputeIntegerHash in utils.h.
-  //
-  // hash = ~hash + (hash << 15);
-  nor(reg1, reg0, zero_reg);
-  sll(at, reg0, 15);
-  addu(reg0, reg1, at);
-
-  // hash = hash ^ (hash >> 12);
-  srl(at, reg0, 12);
-  xor_(reg0, reg0, at);
-
-  // hash = hash + (hash << 2);
-  sll(at, reg0, 2);
-  addu(reg0, reg0, at);
-
-  // hash = hash ^ (hash >> 4);
-  srl(at, reg0, 4);
-  xor_(reg0, reg0, at);
-
-  // hash = hash * 2057;
-  li(reg1, Operand(2057));
-  mul(reg0, reg0, reg1);
-
-  // hash = hash ^ (hash >> 16);
-  srl(at, reg0, 16);
-  xor_(reg0, reg0, at);
+  GetNumberHash(reg0, reg1);
 
   // Compute the capacity mask.
   lw(reg1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
index cefd4ac..57fcd27 100644 (file)
@@ -406,6 +406,9 @@ class MacroAssembler: public Assembler {
                               Label* miss);
 
 
+  void GetNumberHash(Register reg0, Register scratch);
+
+
   void LoadFromNumberDictionary(Label* miss,
                                 Register elements,
                                 Register key,
index c5cf060..7406f2c 100644 (file)
@@ -2057,7 +2057,7 @@ int HashTable<Shape, Key>::FindEntry(Key key) {
 template<typename Shape, typename Key>
 int HashTable<Shape, Key>::FindEntry(Isolate* isolate, Key key) {
   uint32_t capacity = Capacity();
-  uint32_t entry = FirstProbe(Shape::Hash(key), capacity);
+  uint32_t entry = FirstProbe(HashTable<Shape, Key>::Hash(key), capacity);
   uint32_t count = 1;
   // EnsureCapacity will guarantee the hash table is never full.
   while (true) {
@@ -4536,15 +4536,28 @@ bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
 
 
 uint32_t NumberDictionaryShape::Hash(uint32_t key) {
-  return ComputeIntegerHash(key);
+  // This function is unreachable, since shape has UsesSeed=true flag.
+  UNREACHABLE();
+  return 0;
 }
 
 
 uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) {
-  ASSERT(other->IsNumber());
-  return ComputeIntegerHash(static_cast<uint32_t>(other->Number()));
+  // This function is unreachable, since shape has UsesSeed=true flag.
+  UNREACHABLE();
+  return 0;
 }
 
+uint32_t NumberDictionaryShape::SeededHash(uint32_t key, uint32_t seed) {
+  return ComputeIntegerHash(key, seed);
+}
+
+uint32_t NumberDictionaryShape::SeededHashForObject(uint32_t key,
+                                                    uint32_t seed,
+                                                    Object* other) {
+  ASSERT(other->IsNumber());
+  return ComputeIntegerHash(static_cast<uint32_t>(other->Number()), seed);
+}
 
 MaybeObject* NumberDictionaryShape::AsObject(uint32_t key) {
   return Isolate::Current()->heap()->NumberFromUint32(key);
index 061d3b6..23f82df 100644 (file)
@@ -10927,7 +10927,7 @@ MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
     uint32_t from_index = EntryToIndex(i);
     Object* k = get(from_index);
     if (IsKey(k)) {
-      uint32_t hash = Shape::HashForObject(key, k);
+      uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
       uint32_t insertion_index =
           EntryToIndex(new_table->FindInsertionEntry(hash));
       for (int j = 0; j < Shape::kEntrySize; j++) {
@@ -12013,8 +12013,9 @@ MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
     if (!maybe_k->ToObject(&k)) return maybe_k;
   }
   PropertyDetails details = PropertyDetails(NONE, NORMAL);
-  return Dictionary<Shape, Key>::cast(obj)->
-      AddEntry(key, value, details, Shape::Hash(key));
+
+  return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
+      Dictionary<Shape, Key>::Hash(key));
 }
 
 
@@ -12029,8 +12030,9 @@ MaybeObject* Dictionary<Shape, Key>::Add(Key key,
   { MaybeObject* maybe_obj = EnsureCapacity(1, key);
     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
   }
-  return Dictionary<Shape, Key>::cast(obj)->
-      AddEntry(key, value, details, Shape::Hash(key));
+
+  return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
+      Dictionary<Shape, Key>::Hash(key));
 }
 
 
index 90d459b..f94073b 100644 (file)
@@ -2593,9 +2593,44 @@ class DescriptorArray: public FixedArray {
 // beginning of the backing storage that can be used for non-element
 // information by subclasses.
 
+template<typename Key>
+class BaseShape {
+ public:
+  static const bool UsesSeed = false;
+  static uint32_t Hash(Key key) { return 0; }
+  static uint32_t SeededHash(Key key, uint32_t seed) {
+    // Won't be called if UsesSeed isn't overridden by child class.
+    return Hash(key);
+  }
+  static uint32_t HashForObject(Key key, Object* object) { return 0; }
+  static uint32_t SeededHashForObject(Key key, uint32_t seed, Object* object) {
+    // Won't be called if UsesSeed isn't overridden by child class.
+    return HashForObject(key, object);
+  }
+};
+
 template<typename Shape, typename Key>
 class HashTable: public FixedArray {
  public:
+  // Wrapper methods
+  inline uint32_t Hash(Key key) {
+    if (Shape::UsesSeed) {
+      return Shape::SeededHash(key,
+          GetHeap()->StringHashSeed());
+    } else {
+      return Shape::Hash(key);
+    }
+  }
+
+  inline uint32_t HashForObject(Key key, Object* object) {
+    if (Shape::UsesSeed) {
+      return Shape::SeededHashForObject(key,
+          GetHeap()->StringHashSeed(), object);
+    } else {
+      return Shape::HashForObject(key, object);
+    }
+  }
+
   // Returns the number of elements in the hash table.
   int NumberOfElements() {
     return Smi::cast(get(kNumberOfElementsIndex))->value();
@@ -2737,7 +2772,6 @@ class HashTable: public FixedArray {
 };
 
 
-
 // HashTableKey is an abstract superclass for virtual key behavior.
 class HashTableKey {
  public:
@@ -2754,7 +2788,8 @@ class HashTableKey {
   virtual ~HashTableKey() {}
 };
 
-class SymbolTableShape {
+
+class SymbolTableShape : public BaseShape<HashTableKey*> {
  public:
   static inline bool IsMatch(HashTableKey* key, Object* value) {
     return key->IsMatch(value);
@@ -2813,7 +2848,7 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> {
 };
 
 
-class MapCacheShape {
+class MapCacheShape : public BaseShape<HashTableKey*> {
  public:
   static inline bool IsMatch(HashTableKey* key, Object* value) {
     return key->IsMatch(value);
@@ -2969,7 +3004,7 @@ class Dictionary: public HashTable<Shape, Key> {
 };
 
 
-class StringDictionaryShape {
+class StringDictionaryShape : public BaseShape<String*> {
  public:
   static inline bool IsMatch(String* key, Object* other);
   static inline uint32_t Hash(String* key);
@@ -3002,11 +3037,17 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
 };
 
 
-class NumberDictionaryShape {
+class NumberDictionaryShape : public BaseShape<uint32_t> {
  public:
+  static const bool UsesSeed = true;
+
   static inline bool IsMatch(uint32_t key, Object* other);
   static inline uint32_t Hash(uint32_t key);
+  static inline uint32_t SeededHash(uint32_t key, uint32_t seed);
   static inline uint32_t HashForObject(uint32_t key, Object* object);
+  static inline uint32_t SeededHashForObject(uint32_t key,
+                                             uint32_t seed,
+                                             Object* object);
   MUST_USE_RESULT static inline MaybeObject* AsObject(uint32_t key);
   static const int kPrefixSize = 2;
   static const int kEntrySize = 3;
@@ -3062,7 +3103,7 @@ class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
 
 
 template <int entrysize>
-class ObjectHashTableShape {
+class ObjectHashTableShape : public BaseShape<Object*> {
  public:
   static inline bool IsMatch(Object* key, Object* other);
   static inline uint32_t Hash(Object* key);
@@ -5974,7 +6015,7 @@ class JSRegExp: public JSObject {
 };
 
 
-class CompilationCacheShape {
+class CompilationCacheShape : public BaseShape<HashTableKey*> {
  public:
   static inline bool IsMatch(HashTableKey* key, Object* value) {
     return key->IsMatch(value);
@@ -6078,7 +6119,7 @@ class CodeCache: public Struct {
 };
 
 
-class CodeCacheHashTableShape {
+class CodeCacheHashTableShape : public BaseShape<HashTableKey*> {
  public:
   static inline bool IsMatch(HashTableKey* key, Object* value) {
     return key->IsMatch(value);
index 00fc7b7..162157b 100644 (file)
@@ -181,18 +181,21 @@ void CodeEntry::CopyData(const CodeEntry& source) {
 
 
 uint32_t CodeEntry::GetCallUid() const {
-  uint32_t hash = ComputeIntegerHash(tag_);
+  uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed);
   if (shared_id_ != 0) {
-    hash ^= ComputeIntegerHash(
-        static_cast<uint32_t>(shared_id_));
+    hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_),
+                               v8::internal::kZeroHashSeed);
   } else {
     hash ^= ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)),
+        v8::internal::kZeroHashSeed);
     hash ^= ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)),
+        v8::internal::kZeroHashSeed);
     hash ^= ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
-    hash ^= ComputeIntegerHash(line_number_);
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)),
+        v8::internal::kZeroHashSeed);
+    hash ^= ComputeIntegerHash(line_number_, v8::internal::kZeroHashSeed);
   }
   return hash;
 }
@@ -1509,7 +1512,8 @@ uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
                              HEAP->StringHashSeed());
   intptr_t element_count = info->GetElementCount();
   if (element_count != -1)
-    id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count));
+    id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count),
+                             v8::internal::kZeroHashSeed);
   return id << 1;
 }
 
index b47ce82..51f2882 100644 (file)
@@ -750,7 +750,8 @@ class HeapObjectsMap {
 
   static uint32_t AddressHash(Address addr) {
     return ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)),
+        v8::internal::kZeroHashSeed);
   }
 
   bool initial_fill_mode_;
@@ -851,7 +852,8 @@ class HeapEntriesMap {
 
   static uint32_t Hash(HeapThing thing) {
     return ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)));
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
+        v8::internal::kZeroHashSeed);
   }
   static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
     return key1 == key2;
@@ -1047,7 +1049,8 @@ class NativeObjectsExplorer : public HeapEntriesAllocator {
   void VisitSubtreeWrapper(Object** p, uint16_t class_id);
 
   static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
-    return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()));
+    return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
+                              v8::internal::kZeroHashSeed);
   }
   static bool RetainedInfosMatch(void* key1, void* key2) {
     return key1 == key2 ||
@@ -1125,7 +1128,8 @@ class HeapSnapshotJSONSerializer {
 
   INLINE(static uint32_t ObjectHash(const void* key)) {
     return ComputeIntegerHash(
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)));
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)),
+        v8::internal::kZeroHashSeed);
   }
 
   void EnumerateNodes();
index 68b1517..17bf06f 100644 (file)
@@ -252,10 +252,13 @@ class BitField {
 // ----------------------------------------------------------------------------
 // Hash function.
 
+static const uint32_t kZeroHashSeed = 0;
+
 // Thomas Wang, Integer Hash Functions.
 // http://www.concentric.net/~Ttwang/tech/inthash.htm
-inline uint32_t ComputeIntegerHash(uint32_t key) {
+inline uint32_t ComputeIntegerHash(uint32_t key, uint32_t seed) {
   uint32_t hash = key;
+  hash = hash ^ seed;
   hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
   hash = hash ^ (hash >> 12);
   hash = hash + (hash << 2);
@@ -280,7 +283,8 @@ inline uint32_t ComputeLongHash(uint64_t key) {
 
 inline uint32_t ComputePointerHash(void* ptr) {
   return ComputeIntegerHash(
-      static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)));
+      static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)),
+      v8::internal::kZeroHashSeed);
 }
 
 
index 3aa78e9..bae0107 100644 (file)
@@ -3419,6 +3419,42 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 }
 
 
+void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
+  // First of all we assign the hash seed to scratch.
+  LoadRoot(scratch, Heap::kStringHashSeedRootIndex);
+  SmiToInteger32(scratch, scratch);
+
+  // Xor original key with a seed.
+  xorl(r0, scratch);
+
+  // Compute the hash code from the untagged key.  This must be kept in sync
+  // with ComputeIntegerHash in utils.h.
+  //
+  // hash = ~hash + (hash << 15);
+  movl(scratch, r0);
+  notl(r0);
+  shll(scratch, Immediate(15));
+  addl(r0, scratch);
+  // hash = hash ^ (hash >> 12);
+  movl(scratch, r0);
+  shrl(scratch, Immediate(12));
+  xorl(r0, scratch);
+  // hash = hash + (hash << 2);
+  leal(r0, Operand(r0, r0, times_4, 0));
+  // hash = hash ^ (hash >> 4);
+  movl(scratch, r0);
+  shrl(scratch, Immediate(4));
+  xorl(r0, scratch);
+  // hash = hash * 2057;
+  imull(r0, r0, Immediate(2057));
+  // hash = hash ^ (hash >> 16);
+  movl(scratch, r0);
+  shrl(scratch, Immediate(16));
+  xorl(r0, scratch);
+}
+
+
+
 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
                                               Register elements,
                                               Register key,
@@ -3449,30 +3485,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
 
   Label done;
 
-  // Compute the hash code from the untagged key.  This must be kept in sync
-  // with ComputeIntegerHash in utils.h.
-  //
-  // hash = ~hash + (hash << 15);
-  movl(r1, r0);
-  notl(r0);
-  shll(r1, Immediate(15));
-  addl(r0, r1);
-  // hash = hash ^ (hash >> 12);
-  movl(r1, r0);
-  shrl(r1, Immediate(12));
-  xorl(r0, r1);
-  // hash = hash + (hash << 2);
-  leal(r0, Operand(r0, r0, times_4, 0));
-  // hash = hash ^ (hash >> 4);
-  movl(r1, r0);
-  shrl(r1, Immediate(4));
-  xorl(r0, r1);
-  // hash = hash * 2057;
-  imull(r0, r0, Immediate(2057));
-  // hash = hash ^ (hash >> 16);
-  movl(r1, r0);
-  shrl(r1, Immediate(16));
-  xorl(r0, r1);
+  GetNumberHash(r0, r1);
 
   // Compute capacity mask.
   SmiToInteger32(r1,
index 82f8f6d..f2e59c8 100644 (file)
@@ -987,6 +987,9 @@ class MacroAssembler: public Assembler {
                               Label* miss);
 
 
+  void GetNumberHash(Register r0, Register scratch);
+
+
   void LoadFromNumberDictionary(Label* miss,
                                 Register elements,
                                 Register key,
index 9aa8461..c661638 100644 (file)
@@ -117,6 +117,41 @@ void generate(MacroAssembler* masm, i::Vector<const char> string) {
 }
 
 
+void generate(MacroAssembler* masm, uint32_t key) {
+#ifdef V8_TARGET_ARCH_IA32
+  __ push(ebx);
+  __ mov(eax, Immediate(key));
+  __ GetNumberHash(eax, ebx);
+  __ pop(ebx);
+  __ Ret();
+#elif V8_TARGET_ARCH_X64
+  __ push(kRootRegister);
+  __ InitializeRootRegister();
+  __ push(rbx);
+  __ movq(rax, Immediate(key));
+  __ GetNumberHash(rax, rbx);
+  __ pop(rbx);
+  __ pop(kRootRegister);
+  __ Ret();
+#elif V8_TARGET_ARCH_ARM
+  __ push(kRootRegister);
+  __ InitializeRootRegister();
+  __ mov(r0, Operand(key));
+  __ GetNumberHash(r0, ip);
+  __ pop(kRootRegister);
+  __ mov(pc, Operand(lr));
+#elif V8_TARGET_ARCH_MIPS
+  __ push(kRootRegister);
+  __ InitializeRootRegister();
+  __ li(v0, Operand(key));
+  __ GetNumberHash(v0, t1);
+  __ pop(kRootRegister);
+  __ jr(ra);
+  __ nop();
+#endif
+}
+
+
 void check(i::Vector<const char> string) {
   v8::HandleScope scope;
   v8::internal::byte buffer[2048];
@@ -146,12 +181,47 @@ void check(i::Vector<const char> string) {
 }
 
 
+void check(uint32_t key) {
+  v8::HandleScope scope;
+  v8::internal::byte buffer[2048];
+  MacroAssembler masm(Isolate::Current(), buffer, sizeof buffer);
+
+  generate(&masm, key);
+
+  CodeDesc desc;
+  masm.GetCode(&desc);
+  Code* code = Code::cast(HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
+  CHECK(code->IsCode());
+
+  HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(code->entry());
+#ifdef USE_SIMULATOR
+  uint32_t codegen_hash =
+      reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(hash, 0, 0, 0, 0, 0));
+#else
+  uint32_t codegen_hash = hash();
+#endif
+
+  uint32_t runtime_hash = ComputeIntegerHash(
+      key,
+      Isolate::Current()->heap()->StringHashSeed());
+  CHECK(runtime_hash == codegen_hash);
+}
+
+
 void check_twochars(char a, char b) {
   char ab[2] = {a, b};
   check(i::Vector<const char>(ab, 2));
 }
 
 
+static uint32_t PseudoRandom(uint32_t i, uint32_t j) {
+  return ~(~((i * 781) ^ (j * 329)));
+}
+
+
 TEST(StringHash) {
   if (env.IsEmpty()) env = v8::Context::New();
   for (int a = 0; a < String::kMaxAsciiCharCode; a++) {
@@ -169,4 +239,22 @@ TEST(StringHash) {
   check(i::Vector<const char>("-=[ vee eight ftw ]=-", 21));
 }
 
+
+TEST(NumberHash) {
+  if (env.IsEmpty()) env = v8::Context::New();
+
+  // Some specific numbers
+  for (uint32_t key = 0; key < 42; key += 7) {
+    check(key);
+  }
+
+  // Some pseudo-random numbers
+  static const uint32_t kLimit = 1000;
+  for (uint32_t i = 0; i < 5; i++) {
+    for (uint32_t j = 0; j < 5; j++) {
+      check(PseudoRandom(i, j) % kLimit);
+    }
+  }
+}
+
 #undef __