}
+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,
// 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));
Label* miss);
+ void GetNumberHash(Register t0, Register scratch);
+
+
void LoadFromNumberDictionary(Label* miss,
Register elements,
Register key,
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; }
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) {
}
+// 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,
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));
Label* miss);
+ void GetNumberHash(Register r0, Register scratch);
+
+
void LoadFromNumberDictionary(Label* miss,
Register elements,
Register key,
}
+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,
// 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));
Label* miss);
+ void GetNumberHash(Register reg0, Register scratch);
+
+
void LoadFromNumberDictionary(Label* miss,
Register elements,
Register 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) {
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);
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++) {
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));
}
{ 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));
}
// 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();
};
-
// HashTableKey is an abstract superclass for virtual key behavior.
class HashTableKey {
public:
virtual ~HashTableKey() {}
};
-class SymbolTableShape {
+
+class SymbolTableShape : public BaseShape<HashTableKey*> {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
};
-class MapCacheShape {
+class MapCacheShape : public BaseShape<HashTableKey*> {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
};
-class StringDictionaryShape {
+class StringDictionaryShape : public BaseShape<String*> {
public:
static inline bool IsMatch(String* key, Object* other);
static inline uint32_t Hash(String* key);
};
-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;
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);
};
-class CompilationCacheShape {
+class CompilationCacheShape : public BaseShape<HashTableKey*> {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
};
-class CodeCacheHashTableShape {
+class CodeCacheHashTableShape : public BaseShape<HashTableKey*> {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
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;
}
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;
}
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_;
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;
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 ||
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();
// ----------------------------------------------------------------------------
// 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);
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);
}
}
+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,
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,
Label* miss);
+ void GetNumberHash(Register r0, Register scratch);
+
+
void LoadFromNumberDictionary(Label* miss,
Register elements,
Register key,
}
+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];
}
+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++) {
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 __