Add seed to hash of numeric keyed properties. This is a commit of http://codereview.chromium.org/9148006/ for Fedor Indutny.
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10366 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
0aff6c26d3
commit
6178a8d42c
@ -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));
|
||||
|
@ -591,6 +591,9 @@ class MacroAssembler: public Assembler {
|
||||
Label* miss);
|
||||
|
||||
|
||||
void GetNumberHash(Register t0, Register scratch);
|
||||
|
||||
|
||||
void LoadFromNumberDictionary(Label* miss,
|
||||
Register elements,
|
||||
Register key,
|
||||
|
@ -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; }
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -498,6 +498,9 @@ class MacroAssembler: public Assembler {
|
||||
Label* miss);
|
||||
|
||||
|
||||
void GetNumberHash(Register r0, Register scratch);
|
||||
|
||||
|
||||
void LoadFromNumberDictionary(Label* miss,
|
||||
Register elements,
|
||||
Register key,
|
||||
|
@ -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));
|
||||
|
@ -406,6 +406,9 @@ class MacroAssembler: public Assembler {
|
||||
Label* miss);
|
||||
|
||||
|
||||
void GetNumberHash(Register reg0, Register scratch);
|
||||
|
||||
|
||||
void LoadFromNumberDictionary(Label* miss,
|
||||
Register elements,
|
||||
Register key,
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -987,6 +987,9 @@ class MacroAssembler: public Assembler {
|
||||
Label* miss);
|
||||
|
||||
|
||||
void GetNumberHash(Register r0, Register scratch);
|
||||
|
||||
|
||||
void LoadFromNumberDictionary(Label* miss,
|
||||
Register elements,
|
||||
Register key,
|
||||
|
@ -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 __
|
||||
|
Loading…
Reference in New Issue
Block a user