Browse Source

Land number collision fix for v8 3.6 by Erik Corry

- If V8 snapshots are enabled then the hash is only randomized at build time.

---
backport @10366, @10367 and @10402 to 3.6

Add seed to hash of numeric keyed properties.

Minor cleanups of numeric seeded hashing patch.

Split NumberDictionary into a randomly seeded and an unseeded version.
We don't want to randomize the stub cache.

Review URL: http://codereview.chromium.org/9190001/
v0.7.4-release
Fedor Indutny 13 years ago
parent
commit
1695332941
  1. 2
      deps/v8/src/arm/code-stubs-arm.cc
  2. 58
      deps/v8/src/arm/macro-assembler-arm.cc
  3. 1
      deps/v8/src/arm/macro-assembler-arm.h
  4. 8
      deps/v8/src/code-stubs.cc
  5. 4
      deps/v8/src/debug.h
  6. 15
      deps/v8/src/elements.cc
  7. 32
      deps/v8/src/factory.cc
  8. 15
      deps/v8/src/factory.h
  9. 8
      deps/v8/src/flag-definitions.h
  10. 3
      deps/v8/src/frames.cc
  11. 10
      deps/v8/src/handles.cc
  12. 6
      deps/v8/src/handles.h
  13. 20
      deps/v8/src/heap.cc
  14. 16
      deps/v8/src/heap.h
  15. 4
      deps/v8/src/ia32/code-stubs-ia32.cc
  16. 82
      deps/v8/src/ia32/macro-assembler-ia32.cc
  17. 1
      deps/v8/src/ia32/macro-assembler-ia32.h
  18. 2
      deps/v8/src/mips/code-stubs-mips.cc
  19. 78
      deps/v8/src/mips/macro-assembler-mips.cc
  20. 1
      deps/v8/src/mips/macro-assembler-mips.h
  21. 2
      deps/v8/src/objects-debug.cc
  22. 35
      deps/v8/src/objects-inl.h
  23. 242
      deps/v8/src/objects.cc
  24. 107
      deps/v8/src/objects.h
  25. 30
      deps/v8/src/profile-generator.cc
  26. 12
      deps/v8/src/profile-generator.h
  27. 48
      deps/v8/src/runtime.cc
  28. 5
      deps/v8/src/stub-cache.cc
  29. 6
      deps/v8/src/type-info.cc
  30. 2
      deps/v8/src/type-info.h
  31. 8
      deps/v8/src/utils.h
  32. 3
      deps/v8/src/v8globals.h
  33. 2
      deps/v8/src/x64/code-stubs-x64.cc
  34. 75
      deps/v8/src/x64/macro-assembler-x64.cc
  35. 1
      deps/v8/src/x64/macro-assembler-x64.h
  36. 88
      deps/v8/test/cctest/test-hashing.cc

2
deps/v8/src/arm/code-stubs-arm.cc

@ -5363,7 +5363,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register hash,
Register character) {
// hash = character + (character << 10);
__ LoadRoot(hash, Heap::kStringHashSeedRootIndex);
__ LoadRoot(hash, Heap::kHashSeedRootIndex);
// Untag smi seed and add the character.
__ add(hash, character, Operand(hash, LSR, kSmiTagSize));
// hash += hash << 10;

58
deps/v8/src/arm/macro-assembler-arm.cc

@ -1337,6 +1337,34 @@ 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::kHashSeedRootIndex);
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(2057));
mul(t0, t0, scratch);
// hash = hash ^ (hash >> 16);
eor(t0, t0, Operand(t0, LSR, 16));
}
void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements,
Register key,
@ -1366,26 +1394,10 @@ 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(2057));
mul(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));
ldr(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
sub(t1, t1, Operand(1));
@ -1396,17 +1408,17 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
mov(t2, t0);
// Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) {
add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
add(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
}
and_(t2, t2, Operand(t1));
// Scale the index by multiplying by the element size.
ASSERT(NumberDictionary::kEntrySize == 3);
ASSERT(SeededNumberDictionary::kEntrySize == 3);
add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
// Check if the key is identical to the name.
add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
ldr(ip, FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
cmp(key, Operand(ip));
if (i != kProbes - 1) {
b(eq, &done);
@ -1419,14 +1431,14 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Check that the value is a normal property.
// t2: elements + (index * kPointerSize)
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ldr(t1, FieldMemOperand(t2, kDetailsOffset));
tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
b(ne, miss);
// Get the value at the masked, scaled index and return.
const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize;
SeededNumberDictionary::kElementsStartOffset + kPointerSize;
ldr(result, FieldMemOperand(t2, kValueOffset));
}

1
deps/v8/src/arm/macro-assembler-arm.h

@ -441,6 +441,7 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* miss);
void GetNumberHash(Register t0, Register scratch);
void LoadFromNumberDictionary(Label* miss,
Register elements,

8
deps/v8/src/code-stubs.cc

@ -40,7 +40,7 @@ namespace internal {
bool CodeStub::FindCodeInCache(Code** code_out) {
Heap* heap = Isolate::Current()->heap();
int index = heap->code_stubs()->FindEntry(GetKey());
if (index != NumberDictionary::kNotFound) {
if (index != UnseededNumberDictionary::kNotFound) {
*code_out = Code::cast(heap->code_stubs()->ValueAt(index));
return true;
}
@ -121,9 +121,9 @@ Handle<Code> CodeStub::GetCode() {
FinishCode(*new_object);
// Update the dictionary and the root in Heap.
Handle<NumberDictionary> dict =
Handle<UnseededNumberDictionary> dict =
factory->DictionaryAtNumberPut(
Handle<NumberDictionary>(heap->code_stubs()),
Handle<UnseededNumberDictionary>(heap->code_stubs()),
GetKey(),
new_object);
heap->public_set_code_stubs(*dict);
@ -165,7 +165,7 @@ MaybeObject* CodeStub::TryGetCode() {
MaybeObject* maybe_new_object =
heap->code_stubs()->AtNumberPut(GetKey(), code);
if (maybe_new_object->ToObject(&new_object)) {
heap->public_set_code_stubs(NumberDictionary::cast(new_object));
heap->public_set_code_stubs(UnseededNumberDictionary::cast(new_object));
}
}

4
deps/v8/src/debug.h

@ -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; }

15
deps/v8/src/elements.cc

@ -392,7 +392,7 @@ class PixelElementsAccessor
class DictionaryElementsAccessor
: public ElementsAccessorBase<DictionaryElementsAccessor,
NumberDictionary> {
SeededNumberDictionary> {
public:
static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t key,
@ -405,9 +405,10 @@ class DictionaryElementsAccessor
if (is_arguments) {
backing_store = FixedArray::cast(backing_store->get(1));
}
NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(backing_store);
int entry = dictionary->FindEntry(key);
if (entry != NumberDictionary::kNotFound) {
if (entry != SeededNumberDictionary::kNotFound) {
Object* result = dictionary->DeleteProperty(entry, mode);
if (result == heap->true_value()) {
MaybeObject* maybe_elements = dictionary->Shrink(key);
@ -440,7 +441,7 @@ class DictionaryElementsAccessor
protected:
friend class ElementsAccessorBase<DictionaryElementsAccessor,
NumberDictionary>;
SeededNumberDictionary>;
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
@ -448,12 +449,12 @@ class DictionaryElementsAccessor
return DeleteCommon(obj, key, mode);
}
static MaybeObject* Get(NumberDictionary* backing_store,
static MaybeObject* Get(SeededNumberDictionary* backing_store,
uint32_t key,
JSObject* obj,
Object* receiver) {
int entry = backing_store->FindEntry(key);
if (entry != NumberDictionary::kNotFound) {
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = backing_store->ValueAt(entry);
PropertyDetails details = backing_store->DetailsAt(entry);
if (details.type() == CALLBACKS) {
@ -468,7 +469,7 @@ class DictionaryElementsAccessor
return obj->GetHeap()->the_hole_value();
}
static uint32_t GetKeyForIndex(NumberDictionary* dict,
static uint32_t GetKeyForIndex(SeededNumberDictionary* dict,
uint32_t index) {
Object* key = dict->KeyAt(index);
return Smi::cast(key)->value();

32
deps/v8/src/factory.cc

@ -77,11 +77,21 @@ Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) {
}
Handle<NumberDictionary> Factory::NewNumberDictionary(int at_least_space_for) {
Handle<SeededNumberDictionary> Factory::NewSeededNumberDictionary(
int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(isolate(),
NumberDictionary::Allocate(at_least_space_for),
NumberDictionary);
SeededNumberDictionary::Allocate(at_least_space_for),
SeededNumberDictionary);
}
Handle<UnseededNumberDictionary> Factory::NewUnseededNumberDictionary(
int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(isolate(),
UnseededNumberDictionary::Allocate(at_least_space_for),
UnseededNumberDictionary);
}
@ -990,13 +1000,23 @@ Handle<String> Factory::NumberToString(Handle<Object> number) {
}
Handle<NumberDictionary> Factory::DictionaryAtNumberPut(
Handle<NumberDictionary> dictionary,
Handle<SeededNumberDictionary> Factory::DictionaryAtNumberPut(
Handle<SeededNumberDictionary> dictionary,
uint32_t key,
Handle<Object> value) {
CALL_HEAP_FUNCTION(isolate(),
dictionary->AtNumberPut(key, *value),
SeededNumberDictionary);
}
Handle<UnseededNumberDictionary> Factory::DictionaryAtNumberPut(
Handle<UnseededNumberDictionary> dictionary,
uint32_t key,
Handle<Object> value) {
CALL_HEAP_FUNCTION(isolate(),
dictionary->AtNumberPut(key, *value),
NumberDictionary);
UnseededNumberDictionary);
}

15
deps/v8/src/factory.h

@ -54,7 +54,11 @@ class Factory {
int size,
PretenureFlag pretenure = NOT_TENURED);
Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for);
Handle<SeededNumberDictionary> NewSeededNumberDictionary(
int at_least_space_for);
Handle<UnseededNumberDictionary> NewUnseededNumberDictionary(
int at_least_space_for);
Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
@ -412,8 +416,13 @@ class Factory {
Handle<Object> stack_trace,
Handle<Object> stack_frames);
Handle<NumberDictionary> DictionaryAtNumberPut(
Handle<NumberDictionary>,
Handle<SeededNumberDictionary> DictionaryAtNumberPut(
Handle<SeededNumberDictionary>,
uint32_t key,
Handle<Object> value);
Handle<UnseededNumberDictionary> DictionaryAtNumberPut(
Handle<UnseededNumberDictionary>,
uint32_t key,
Handle<Object> value);

8
deps/v8/src/flag-definitions.h

@ -319,13 +319,13 @@ DEFINE_bool(trace_exception, false,
"print stack trace when throwing exceptions")
DEFINE_bool(preallocate_message_memory, false,
"preallocate some memory to build stack traces.")
DEFINE_bool(randomize_string_hashes,
DEFINE_bool(randomize_hashes,
true,
"randomize string hashes to avoid predictable hash collisions "
"randomize hashes to avoid predictable hash collisions "
"(with snapshots this option cannot override the baked-in seed)")
DEFINE_int(string_hash_seed,
DEFINE_int(hash_seed,
0,
"Fixed seed to use to string hashing (0 means random)"
"Fixed seed to use to hash property keys (0 means random)"
"(with snapshots this option cannot override the baked-in seed)")
// v8.cc

3
deps/v8/src/frames.cc

@ -1187,7 +1187,8 @@ PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
isolate_->counters()->pc_to_code()->Increment();
ASSERT(IsPowerOf2(kPcToCodeCacheSize));
uint32_t hash = ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)),
v8::internal::kZeroHashSeed);
uint32_t index = hash & (kPcToCodeCacheSize - 1);
PcToCodeCacheEntry* entry = cache(index);
if (entry->pc == pc) {

10
deps/v8/src/handles.cc

@ -214,10 +214,10 @@ void NormalizeProperties(Handle<JSObject> object,
}
Handle<NumberDictionary> NormalizeElements(Handle<JSObject> object) {
Handle<SeededNumberDictionary> NormalizeElements(Handle<JSObject> object) {
CALL_HEAP_FUNCTION(object->GetIsolate(),
object->NormalizeElements(),
NumberDictionary);
SeededNumberDictionary);
}
@ -229,14 +229,14 @@ void TransformToFastProperties(Handle<JSObject> object,
}
Handle<NumberDictionary> NumberDictionarySet(
Handle<NumberDictionary> dictionary,
Handle<SeededNumberDictionary> SeededNumberDictionarySet(
Handle<SeededNumberDictionary> dictionary,
uint32_t index,
Handle<Object> value,
PropertyDetails details) {
CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
dictionary->Set(index, *value, details),
NumberDictionary);
SeededNumberDictionary);
}

6
deps/v8/src/handles.h

@ -170,11 +170,11 @@ class HandleScope {
void NormalizeProperties(Handle<JSObject> object,
PropertyNormalizationMode mode,
int expected_additional_properties);
Handle<NumberDictionary> NormalizeElements(Handle<JSObject> object);
Handle<SeededNumberDictionary> NormalizeElements(Handle<JSObject> object);
void TransformToFastProperties(Handle<JSObject> object,
int unused_property_fields);
MUST_USE_RESULT Handle<NumberDictionary> NumberDictionarySet(
Handle<NumberDictionary> dictionary,
MUST_USE_RESULT Handle<SeededNumberDictionary> SeededNumberDictionarySet(
Handle<SeededNumberDictionary> dictionary,
uint32_t index,
Handle<Object> value,
PropertyDetails details);

20
deps/v8/src/heap.cc

@ -2181,17 +2181,17 @@ bool Heap::CreateInitialObjects() {
// Allocate the code_stubs dictionary. The initial size is set to avoid
// expanding the dictionary during bootstrapping.
{ MaybeObject* maybe_obj = NumberDictionary::Allocate(128);
{ MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_code_stubs(NumberDictionary::cast(obj));
set_code_stubs(UnseededNumberDictionary::cast(obj));
// Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
// is set to avoid expanding the dictionary during bootstrapping.
{ MaybeObject* maybe_obj = NumberDictionary::Allocate(64);
{ MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_non_monomorphic_cache(NumberDictionary::cast(obj));
set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
{ MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
if (!maybe_obj->ToObject(&obj)) return false;
@ -5362,14 +5362,14 @@ bool Heap::Setup(bool create_heap_objects) {
if (lo_space_ == NULL) return false;
if (!lo_space_->Setup()) return false;
// Set up the seed that is used to randomize the string hash function.
ASSERT(string_hash_seed() == 0);
if (FLAG_randomize_string_hashes) {
if (FLAG_string_hash_seed == 0) {
set_string_hash_seed(
// Setup the seed that is used to randomize the string hash function.
ASSERT(hash_seed() == 0);
if (FLAG_randomize_hashes) {
if (FLAG_hash_seed == 0) {
set_hash_seed(
Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
} else {
set_string_hash_seed(Smi::FromInt(FLAG_string_hash_seed));
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
}
}

16
deps/v8/src/heap.h

@ -79,7 +79,7 @@ inline Heap* _inline_get_heap_();
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
V(FixedArray, string_split_cache, StringSplitCache) \
V(Object, termination_exception, TerminationException) \
V(Smi, string_hash_seed, StringHashSeed) \
V(Smi, hash_seed, HashSeed) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \
V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \
@ -128,8 +128,8 @@ inline Heap* _inline_get_heap_();
V(Map, neander_map, NeanderMap) \
V(JSObject, message_listeners, MessageListeners) \
V(Foreign, prototype_accessors, PrototypeAccessors) \
V(NumberDictionary, code_stubs, CodeStubs) \
V(NumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(UnseededNumberDictionary, code_stubs, CodeStubs) \
V(UnseededNumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(PolymorphicCodeCache, polymorphic_code_cache, PolymorphicCodeCache) \
V(Code, js_entry_code, JsEntryCode) \
V(Code, js_construct_entry_code, JsConstructEntryCode) \
@ -1037,7 +1037,7 @@ class Heap {
inline AllocationSpace TargetSpaceId(InstanceType type);
// Sets the stub_cache_ (only used when expanding the dictionary).
void public_set_code_stubs(NumberDictionary* value) {
void public_set_code_stubs(UnseededNumberDictionary* value) {
roots_[kCodeStubsRootIndex] = value;
}
@ -1049,7 +1049,7 @@ class Heap {
}
// Sets the non_monomorphic_cache_ (only used when expanding the dictionary).
void public_set_non_monomorphic_cache(NumberDictionary* value) {
void public_set_non_monomorphic_cache(UnseededNumberDictionary* value) {
roots_[kNonMonomorphicCacheRootIndex] = value;
}
@ -1301,9 +1301,9 @@ class Heap {
if (global_gc_epilogue_callback_ != NULL) global_gc_epilogue_callback_();
}
uint32_t StringHashSeed() {
uint32_t seed = static_cast<uint32_t>(string_hash_seed()->value());
ASSERT(FLAG_randomize_string_hashes || seed == 0);
uint32_t HashSeed() {
uint32_t seed = static_cast<uint32_t>(hash_seed()->value());
ASSERT(FLAG_randomize_hashes || seed == 0);
return seed;
}

4
deps/v8/src/ia32/code-stubs-ia32.cc

@ -5610,7 +5610,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
if (Serializer::enabled()) {
ExternalReference roots_address =
ExternalReference::roots_address(masm->isolate());
__ mov(scratch, Immediate(Heap::kStringHashSeedRootIndex));
__ mov(scratch, Immediate(Heap::kHashSeedRootIndex));
__ mov(scratch, Operand::StaticArray(scratch,
times_pointer_size,
roots_address));
@ -5619,7 +5619,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
__ shl(scratch, 10);
__ add(hash, Operand(scratch));
} else {
int32_t seed = masm->isolate()->heap()->StringHashSeed();
int32_t seed = masm->isolate()->heap()->HashSeed();
__ lea(scratch, Operand(character, seed));
__ shl(scratch, 10);
__ lea(hash, Operand(scratch, character, times_1, seed));

82
deps/v8/src/ia32/macro-assembler-ia32.cc

@ -752,6 +752,51 @@ 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_address =
ExternalReference::roots_address(isolate());
mov(scratch, Immediate(Heap::kHashSeedRootIndex));
mov(scratch, Operand::StaticArray(scratch,
times_pointer_size,
roots_address));
SmiUntag(scratch);
xor_(r0, Operand(scratch));
} else {
int32_t seed = isolate()->heap()->HashSeed();
xor_(r0, seed);
}
// hash = ~hash + (hash << 15);
mov(scratch, r0);
not_(r0);
shl(scratch, 15);
add(r0, Operand(scratch));
// hash = hash ^ (hash >> 12);
mov(scratch, r0);
shr(scratch, 12);
xor_(r0, Operand(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, Operand(scratch));
// hash = hash * 2057;
imul(r0, r0, 2057);
// hash = hash ^ (hash >> 16);
mov(scratch, r0);
shr(scratch, 16);
xor_(r0, Operand(scratch));
}
void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements,
Register key,
@ -777,33 +822,10 @@ 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, Operand(r1));
// hash = hash ^ (hash >> 12);
mov(r1, r0);
shr(r1, 12);
xor_(r0, Operand(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, Operand(r1));
// hash = hash * 2057;
imul(r0, r0, 2057);
// hash = hash ^ (hash >> 16);
mov(r1, r0);
shr(r1, 16);
xor_(r0, Operand(r1));
GetNumberHash(r0, r1);
// Compute capacity mask.
mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
mov(r1, FieldOperand(elements, SeededNumberDictionary::kCapacityOffset));
shr(r1, kSmiTagSize); // convert smi to int
dec(r1);
@ -814,19 +836,19 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
mov(r2, r0);
// Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) {
add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
add(Operand(r2), Immediate(SeededNumberDictionary::GetProbeOffset(i)));
}
and_(r2, Operand(r1));
// Scale the index by multiplying by the entry size.
ASSERT(NumberDictionary::kEntrySize == 3);
ASSERT(SeededNumberDictionary::kEntrySize == 3);
lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
// Check if the key matches.
cmp(key, FieldOperand(elements,
r2,
times_pointer_size,
NumberDictionary::kElementsStartOffset));
SeededNumberDictionary::kElementsStartOffset));
if (i != (kProbes - 1)) {
j(equal, &done);
} else {
@ -837,7 +859,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
bind(&done);
// Check that the value is a normal propety.
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0);
test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
@ -845,7 +867,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Get the value at the masked, scaled index.
const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize;
SeededNumberDictionary::kElementsStartOffset + kPointerSize;
mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
}

1
deps/v8/src/ia32/macro-assembler-ia32.h

@ -354,6 +354,7 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* miss);
void GetNumberHash(Register r0, Register scratch);
void LoadFromNumberDictionary(Label* miss,
Register elements,

2
deps/v8/src/mips/code-stubs-mips.cc

@ -5580,7 +5580,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register hash,
Register character) {
// hash = seed + character + ((seed + character) << 10);
__ LoadRoot(hash, Heap::kStringHashSeedRootIndex);
__ LoadRoot(hash, Heap::kHashSeedRootIndex);
// Untag smi seed and add the character.
__ SmiUntag(hash);
__ addu(hash, hash, character);

78
deps/v8/src/mips/macro-assembler-mips.cc

@ -343,6 +343,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::kHashSeedRootIndex);
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,
@ -374,36 +412,10 @@ 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));
lw(reg1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
sra(reg1, reg1, kSmiTagSize);
Subu(reg1, reg1, Operand(1));
@ -414,12 +426,12 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
mov(reg2, reg0);
// Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) {
Addu(reg2, reg2, Operand(NumberDictionary::GetProbeOffset(i)));
Addu(reg2, reg2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
}
and_(reg2, reg2, reg1);
// Scale the index by multiplying by the element size.
ASSERT(NumberDictionary::kEntrySize == 3);
ASSERT(SeededNumberDictionary::kEntrySize == 3);
sll(at, reg2, 1); // 2x.
addu(reg2, reg2, at); // reg2 = reg2 * 3.
@ -427,7 +439,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
sll(at, reg2, kPointerSizeLog2);
addu(reg2, elements, at);
lw(at, FieldMemOperand(reg2, NumberDictionary::kElementsStartOffset));
lw(at, FieldMemOperand(reg2, SeededNumberDictionary::kElementsStartOffset));
if (i != kProbes - 1) {
Branch(&done, eq, key, Operand(at));
} else {
@ -439,14 +451,14 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Check that the value is a normal property.
// reg2: elements + (index * kPointerSize).
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize;
SeededNumberDictionary::kElementsStartOffset + kPointerSize;
lw(result, FieldMemOperand(reg2, kValueOffset));
}

1
deps/v8/src/mips/macro-assembler-mips.h

@ -266,6 +266,7 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* miss);
void GetNumberHash(Register reg0, Register scratch);
void LoadFromNumberDictionary(Label* miss,
Register elements,

2
deps/v8/src/objects-debug.cc

@ -700,7 +700,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
break;
}
case DICTIONARY_ELEMENTS: {
NumberDictionary* dict = element_dictionary();
SeededNumberDictionary* dict = element_dictionary();
info->number_of_slow_used_elements_ += dict->NumberOfElements();
info->number_of_slow_unused_elements_ +=
dict->Capacity() - dict->NumberOfElements();

35
deps/v8/src/objects-inl.h

@ -1789,7 +1789,7 @@ void FixedDoubleArray::Initialize(FixedArray* from) {
}
void FixedDoubleArray::Initialize(NumberDictionary* from) {
void FixedDoubleArray::Initialize(SeededNumberDictionary* from) {
int offset = kHeaderSize;
for (int current = 0; current < length(); ++current) {
WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());
@ -2077,7 +2077,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) {
@ -2092,14 +2092,14 @@ int HashTable<Shape, Key>::FindEntry(Isolate* isolate, Key key) {
}
bool NumberDictionary::requires_slow_elements() {
bool SeededNumberDictionary::requires_slow_elements() {
Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi()) return false;
return 0 !=
(Smi::cast(max_index_object)->value() & kRequiresSlowElementsMask);
}
uint32_t NumberDictionary::max_number_key() {
uint32_t SeededNumberDictionary::max_number_key() {
ASSERT(!requires_slow_elements());
Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi()) return 0;
@ -2107,7 +2107,7 @@ uint32_t NumberDictionary::max_number_key() {
return value >> kRequiresSlowElementsTagSize;
}
void NumberDictionary::set_requires_slow_elements() {
void SeededNumberDictionary::set_requires_slow_elements() {
set(kMaxNumberKeyIndex, Smi::FromInt(kRequiresSlowElementsMask));
}
@ -4211,9 +4211,9 @@ StringDictionary* JSObject::property_dictionary() {
}
NumberDictionary* JSObject::element_dictionary() {
SeededNumberDictionary* JSObject::element_dictionary() {
ASSERT(HasDictionaryElements());
return NumberDictionary::cast(elements());
return SeededNumberDictionary::cast(elements());
}
@ -4243,7 +4243,7 @@ StringHasher::StringHasher(int length, uint32_t seed)
is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize),
is_first_char_(true),
is_valid_(true) {
ASSERT(FLAG_randomize_string_hashes || raw_running_hash_ == 0);
ASSERT(FLAG_randomize_hashes || raw_running_hash_ == 0);
}
@ -4476,16 +4476,27 @@ bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
}
uint32_t NumberDictionaryShape::Hash(uint32_t key) {
return ComputeIntegerHash(key);
uint32_t UnseededNumberDictionaryShape::Hash(uint32_t key) {
return ComputeIntegerHash(key, 0);
}
uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) {
uint32_t UnseededNumberDictionaryShape::HashForObject(uint32_t key,
Object* other) {
ASSERT(other->IsNumber());
return ComputeIntegerHash(static_cast<uint32_t>(other->Number()));
return ComputeIntegerHash(static_cast<uint32_t>(other->Number()), 0);
}
uint32_t SeededNumberDictionaryShape::SeededHash(uint32_t key, uint32_t seed) {
return ComputeIntegerHash(key, seed);
}
uint32_t SeededNumberDictionaryShape::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);

242
deps/v8/src/objects.cc

@ -1951,9 +1951,10 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
if (!JSObject::cast(pt)->HasDictionaryElements()) {
continue;
}
NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
SeededNumberDictionary* dictionary =
JSObject::cast(pt)->element_dictionary();
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
if (entry != SeededNumberDictionary::kNotFound) {
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
*found = true;
@ -2928,11 +2929,11 @@ MaybeObject* JSObject::NormalizeElements() {
int old_capacity = 0;
int used_elements = 0;
GetElementsCapacityAndUsage(&old_capacity, &used_elements);
NumberDictionary* dictionary = NULL;
SeededNumberDictionary* dictionary = NULL;
{ Object* object;
MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
if (!maybe->ToObject(&object)) return maybe;
dictionary = NumberDictionary::cast(object);
dictionary = SeededNumberDictionary::cast(object);
}
// Copy the elements to the new backing store.
@ -2962,7 +2963,7 @@ MaybeObject* JSObject::NormalizeElements() {
MaybeObject* maybe_result =
dictionary->AddNumberEntry(i, value, details);
if (!maybe_result->ToObject(&result)) return maybe_result;
dictionary = NumberDictionary::cast(result);
dictionary = SeededNumberDictionary::cast(result);
}
}
@ -3277,7 +3278,8 @@ bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
if (!element->IsTheHole() && element == object) return true;
}
} else {
Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
Object* key =
SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
if (!key->IsUndefined()) return true;
}
return false;
@ -3416,9 +3418,9 @@ MaybeObject* JSObject::PreventExtensions() {
}
// If there are fast elements we normalize.
NumberDictionary* dictionary = NULL;
SeededNumberDictionary* dictionary = NULL;
{ MaybeObject* maybe = NormalizeElements();
if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
}
ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
// Make sure that we never go back to fast case.
@ -3581,11 +3583,11 @@ void JSObject::LookupCallback(String* name, LookupResult* result) {
// undefined if the element is read-only, or the getter/setter pair (fixed
// array) if there is an existing one, or the hole value if the element does
// not exist or is a normal non-getter/setter data element.
static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary,
static Object* FindGetterSetterInDictionary(SeededNumberDictionary* dictionary,
uint32_t index,
Heap* heap) {
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
if (entry != SeededNumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.IsReadOnly()) return heap->undefined_value();
@ -3647,7 +3649,8 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
if (probe == NULL || probe->IsTheHole()) {
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(arguments);
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(arguments);
probe = FindGetterSetterInDictionary(dictionary, index, heap);
if (!probe->IsTheHole()) return probe;
}
@ -3716,11 +3719,11 @@ MaybeObject* JSObject::SetElementCallback(uint32_t index,
PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
// Normalize elements to make this operation simple.
NumberDictionary* dictionary = NULL;
SeededNumberDictionary* dictionary = NULL;
{ Object* result;
MaybeObject* maybe = NormalizeElements();
if (!maybe->ToObject(&result)) return maybe;
dictionary = NumberDictionary::cast(result);
dictionary = SeededNumberDictionary::cast(result);
}
ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
@ -3728,7 +3731,7 @@ MaybeObject* JSObject::SetElementCallback(uint32_t index,
{ Object* result;
MaybeObject* maybe = dictionary->Set(index, structure, details);
if (!maybe->ToObject(&result)) return maybe;
dictionary = NumberDictionary::cast(result);
dictionary = SeededNumberDictionary::cast(result);
}
dictionary->set_requires_slow_elements();
@ -3933,9 +3936,9 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
obj = JSObject::cast(obj)->GetPrototype()) {
JSObject* js_object = JSObject::cast(obj);
if (js_object->HasDictionaryElements()) {
NumberDictionary* dictionary = js_object->element_dictionary();
SeededNumberDictionary* dictionary = js_object->element_dictionary();
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
@ -6077,14 +6080,14 @@ uint32_t String::ComputeAndSetHash() {
if (StringShape(this).IsSequentialAscii()) {
field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
len,
GetHeap()->StringHashSeed());
GetHeap()->HashSeed());
} else if (StringShape(this).IsSequentialTwoByte()) {
field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
len,
GetHeap()->StringHashSeed());
GetHeap()->HashSeed());
} else {
StringInputBuffer buffer(this);
field = ComputeHashField(&buffer, len, GetHeap()->StringHashSeed());
field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
}
// Store the hash code in the object.
@ -7276,7 +7279,7 @@ static void CopyFastElementsToFast(FixedArray* source,
}
static void CopySlowElementsToFast(NumberDictionary* source,
static void CopySlowElementsToFast(SeededNumberDictionary* source,
FixedArray* destination,
WriteBarrierMode mode) {
for (int i = 0; i < source->Capacity(); ++i) {
@ -7324,7 +7327,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
case DICTIONARY_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopySlowElementsToFast(NumberDictionary::cast(elements()),
CopySlowElementsToFast(SeededNumberDictionary::cast(elements()),
new_elements,
mode);
set_map(new_map);
@ -7339,7 +7342,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
FixedArray* parameter_map = FixedArray::cast(elements());
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
CopySlowElementsToFast(NumberDictionary::cast(arguments),
CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
new_elements,
mode);
} else {
@ -7426,7 +7429,7 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
break;
}
case DICTIONARY_ELEMENTS: {
elems->Initialize(NumberDictionary::cast(elements()));
elems->Initialize(SeededNumberDictionary::cast(elements()));
break;
}
default:
@ -7861,7 +7864,7 @@ bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
!= SeededNumberDictionary::kNotFound) {
return true;
}
break;
@ -7993,7 +7996,7 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index) !=
NumberDictionary::kNotFound) {
SeededNumberDictionary::kNotFound) {
return DICTIONARY_ELEMENT;
}
break;
@ -8010,8 +8013,9 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
// If not aliased, check the arguments.
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(arguments);
if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(arguments);
if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
return DICTIONARY_ELEMENT;
}
} else {
@ -8040,8 +8044,8 @@ bool JSObject::HasElementInElements(FixedArray* elements,
return true;
}
} else {
if (NumberDictionary::cast(elements)->FindEntry(index) !=
NumberDictionary::kNotFound) {
if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
SeededNumberDictionary::kNotFound) {
return true;
}
}
@ -8107,7 +8111,7 @@ bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
!= SeededNumberDictionary::kNotFound) {
return true;
}
break;
@ -8387,15 +8391,15 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
FixedArray* elements = FixedArray::cast(this->elements());
bool is_arguments =
(elements->map() == heap->non_strict_arguments_elements_map());
NumberDictionary* dictionary = NULL;
SeededNumberDictionary* dictionary = NULL;
if (is_arguments) {
dictionary = NumberDictionary::cast(elements->get(1));
dictionary = SeededNumberDictionary::cast(elements->get(1));
} else {
dictionary = NumberDictionary::cast(elements);
dictionary = SeededNumberDictionary::cast(elements);
}
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
@ -8440,13 +8444,13 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
FixedArrayBase* new_dictionary;
MaybeObject* maybe = dictionary->AtNumberPut(index, value);
if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
if (dictionary != NumberDictionary::cast(new_dictionary)) {
if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
if (is_arguments) {
elements->set(1, new_dictionary);
} else {
set_elements(new_dictionary);
}
dictionary = NumberDictionary::cast(new_dictionary);
dictionary = SeededNumberDictionary::cast(new_dictionary);
}
}
@ -8767,7 +8771,8 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
backing_store = FixedArray::cast(backing_store_base);
if (backing_store->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(backing_store);
*capacity = dictionary->Capacity();
*used = dictionary->NumberOfElements();
break;
@ -8781,8 +8786,8 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
}
break;
case DICTIONARY_ELEMENTS: {
NumberDictionary* dictionary =
NumberDictionary::cast(FixedArray::cast(elements()));
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(FixedArray::cast(elements()));
*capacity = dictionary->Capacity();
*used = dictionary->NumberOfElements();
break;
@ -8827,8 +8832,8 @@ bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
int old_capacity = 0;
int used_elements = 0;
GetElementsCapacityAndUsage(&old_capacity, &used_elements);
int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
NumberDictionary::kEntrySize;
int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
SeededNumberDictionary::kEntrySize;
return 3 * dictionary_size <= new_capacity;
}
@ -8842,11 +8847,11 @@ bool JSObject::ShouldConvertToFastElements() {
if (IsAccessCheckNeeded()) return false;
FixedArray* elements = FixedArray::cast(this->elements());
NumberDictionary* dictionary = NULL;
SeededNumberDictionary* dictionary = NULL;
if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
dictionary = NumberDictionary::cast(elements->get(1));
dictionary = SeededNumberDictionary::cast(elements->get(1));
} else {
dictionary = NumberDictionary::cast(elements);
dictionary = SeededNumberDictionary::cast(elements);
}
// If an element has been added at a very high index in the elements
// dictionary, we cannot go back to fast case.
@ -8861,7 +8866,7 @@ bool JSObject::ShouldConvertToFastElements() {
array_size = dictionary->max_number_key();
}
uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
NumberDictionary::kEntrySize;
SeededNumberDictionary::kEntrySize;
return 2 * dictionary_size >= array_size;
}
@ -8869,7 +8874,8 @@ bool JSObject::ShouldConvertToFastElements() {
bool JSObject::CanConvertToFastDoubleElements() {
if (FLAG_unbox_double_arrays) {
ASSERT(HasDictionaryElements());
NumberDictionary* dictionary = NumberDictionary::cast(elements());
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(elements());
for (int i = 0; i < dictionary->Capacity(); i++) {
Object* key = dictionary->KeyAt(i);
if (key->IsNumber()) {
@ -9082,7 +9088,7 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
}
case DICTIONARY_ELEMENTS: {
return element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound;
!= SeededNumberDictionary::kNotFound;
}
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
@ -9350,7 +9356,7 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage,
filter,
NumberDictionary::SORTED);
SeededNumberDictionary::SORTED);
}
counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
break;
@ -9362,9 +9368,11 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
if (arguments->IsDictionary()) {
// Copy the keys from arguments first, because Dictionary::CopyKeysTo
// will insert in storage starting at index 0.
NumberDictionary* dictionary = NumberDictionary::cast(arguments);
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(arguments);
if (storage != NULL) {
dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
dictionary->CopyKeysTo(
storage, filter, SeededNumberDictionary::UNSORTED);
}
counter += dictionary->NumberOfElementsFilterAttributes(filter);
for (int i = 0; i < mapped_length; ++i) {
@ -9671,7 +9679,7 @@ class SubStringAsciiSymbolKey : public HashTableKey {
uint32_t Hash() {
ASSERT(length_ >= 0);
ASSERT(from_ + length_ <= string_->length());
StringHasher hasher(length_, string_->GetHeap()->StringHashSeed());
StringHasher hasher(length_, string_->GetHeap()->HashSeed());
// Very long strings have a trivial hash that doesn't inspect the
// string contents.
@ -9880,7 +9888,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++) {
@ -9976,38 +9984,46 @@ template class HashTable<ObjectHashTableShape, JSObject*>;
template class Dictionary<StringDictionaryShape, String*>;
template class Dictionary<NumberDictionaryShape, uint32_t>;
template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
int);
template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
Allocate(int at_least_space_for);
template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
Allocate(int at_least_space_for);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
int);
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
uint32_t, Object*);
template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
Object*);
template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
AtPut(uint32_t, Object*);
template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
SlowReverseLookup(Object* value);
template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
Object*);
template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
FixedArray*,
PropertyAttributes,
Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
int, JSObject::DeleteMode);
template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
int, JSObject::DeleteMode);
template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
DeleteProperty(int, JSObject::DeleteMode);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
String*);
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
uint32_t);
template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
@ -10026,32 +10042,41 @@ template MaybeObject*
Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
template int
Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
PropertyAttributes);
Dictionary<SeededNumberDictionaryShape, uint32_t>::
NumberOfElementsFilterAttributes(PropertyAttributes);
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
uint32_t, Object*, PropertyDetails);
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
uint32_t, Object*, PropertyDetails);
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
EnsureCapacity(int, uint32_t);
template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
EnsureCapacity(int, uint32_t);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::
EnsureCapacity(int, String*);
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
uint32_t, Object*, PropertyDetails, uint32_t);
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
String*, Object*, PropertyDetails, uint32_t);
template
int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
template
int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
template
int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
// Collates undefined and unexisting elements below limit from position
@ -10061,7 +10086,7 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
// Must stay in dictionary mode, either because of requires_slow_elements,
// or because we are not going to sort (and therefore compact) all of the
// elements.
NumberDictionary* dict = element_dictionary();
SeededNumberDictionary* dict = element_dictionary();
HeapNumber* result_double = NULL;
if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
// Allocate space for result before we start mutating the object.
@ -10074,10 +10099,10 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Object* obj;
{ MaybeObject* maybe_obj =
NumberDictionary::Allocate(dict->NumberOfElements());
SeededNumberDictionary::Allocate(dict->NumberOfElements());
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
NumberDictionary* new_dict = NumberDictionary::cast(obj);
SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
AssertNoAllocation no_alloc;
@ -10163,7 +10188,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
if (HasDictionaryElements()) {
// Convert to fast elements containing only the existing properties.
// Ordering is irrelevant, since we are going to sort anyway.
NumberDictionary* dict = element_dictionary();
SeededNumberDictionary* dict = element_dictionary();
if (IsJSArray() || dict->requires_slow_elements() ||
dict->max_number_key() >= limit) {
return PrepareSlowElementsForSort(limit);
@ -10576,7 +10601,7 @@ bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
uint32_t c2,
String** symbol) {
TwoCharHashTableKey key(c1, c2, GetHeap()->StringHashSeed());
TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
int entry = FindEntry(&key);
if (entry == kNotFound) {
return false;
@ -10591,14 +10616,14 @@ bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
Object** s) {
Utf8SymbolKey key(str, GetHeap()->StringHashSeed());
Utf8SymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
Object** s) {
AsciiSymbolKey key(str, GetHeap()->StringHashSeed());
AsciiSymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
@ -10607,14 +10632,14 @@ MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
int from,
int length,
Object** s) {
SubStringAsciiSymbolKey key(str, from, length, GetHeap()->StringHashSeed());
SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
Object** s) {
TwoByteSymbolKey key(str, GetHeap()->StringHashSeed());
TwoByteSymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
@ -10905,7 +10930,7 @@ MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
}
void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
void SeededNumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
// Do nothing if the interval [from, to) is empty.
if (from >= to) return;
@ -10971,8 +10996,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));
}
@ -10987,8 +11013,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));
}
@ -11021,7 +11048,7 @@ MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
}
void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
// If the dictionary requires slow elements an element has already
// been added at a high index.
if (requires_slow_elements()) return;
@ -11040,31 +11067,44 @@ void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
}
MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
Object* value,
PropertyDetails details) {
MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
Object* value,
PropertyDetails details) {
UpdateMaxNumberKey(key);
SLOW_ASSERT(this->FindEntry(key) == kNotFound);
return Add(key, value, details);
}
MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
Object* value) {
SLOW_ASSERT(this->FindEntry(key) == kNotFound);
return Add(key, value, PropertyDetails(NONE, NORMAL));
}
MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
UpdateMaxNumberKey(key);
return AtPut(key, value);
}
MaybeObject* NumberDictionary::Set(uint32_t key,
Object* value,
PropertyDetails details) {
MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
Object* value) {
return AtPut(key, value);
}
MaybeObject* SeededNumberDictionary::Set(uint32_t key,
Object* value,
PropertyDetails details) {
int entry = FindEntry(key);
if (entry == kNotFound) return AddNumberEntry(key, value, details);
// Preserve enumeration index.
details = PropertyDetails(details.attributes(),
details.type(),
DetailsAt(entry).index());
MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
Object* object_key;
if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
SetEntry(entry, object_key, value, details);
@ -11072,6 +11112,18 @@ MaybeObject* NumberDictionary::Set(uint32_t key,
}
MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
Object* value) {
int entry = FindEntry(key);
if (entry == kNotFound) return AddNumberEntry(key, value);
MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
Object* object_key;
if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
SetEntry(entry, object_key, value);
return this;
}
template<typename Shape, typename Key>
int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(

107
deps/v8/src/objects.h

@ -1541,7 +1541,7 @@ class JSObject: public JSReceiver {
bool HasFastArgumentsElements();
bool HasDictionaryArgumentsElements();
inline bool AllowsSetElementsLength();
inline NumberDictionary* element_dictionary(); // Gets slow elements.
inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
// Requires: HasFastElements().
MUST_USE_RESULT inline MaybeObject* EnsureWritableFastElements();
@ -1902,8 +1902,6 @@ class JSObject: public JSReceiver {
PropertyNormalizationMode mode,
int expected_additional_properties);
// Convert and update the elements backing store to be a NumberDictionary
// dictionary. Returns the backing after conversion.
MUST_USE_RESULT MaybeObject* NormalizeElements();
MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code);
@ -2221,7 +2219,7 @@ class FixedDoubleArray: public FixedArrayBase {
public:
inline void Initialize(FixedArray* from);
inline void Initialize(FixedDoubleArray* from);
inline void Initialize(NumberDictionary* from);
inline void Initialize(SeededNumberDictionary* from);
// Setter and getter for elements.
inline double get_scalar(int index);
@ -2514,9 +2512,46 @@ 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) {
ASSERT(UsesSeed);
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) {
// I'm using map()->heap() to skip is_safe_to_read_maps assertion.
// That was done, because NumberDictionary is used inside GC.
return Shape::SeededHash(key, map()->heap()->HashSeed());
} else {
return Shape::Hash(key);
}
}
inline uint32_t HashForObject(Key key, Object* object) {
if (Shape::UsesSeed) {
// I'm using map()->heap() to skip is_safe_to_read_maps assertion.
// That was done, because NumberDictionary is used inside GC.
return Shape::SeededHashForObject(key, map()->heap()->HashSeed(), object);
} else {
return Shape::HashForObject(key, object);
}
}
// Returns the number of elements in the hash table.
int NumberOfElements() {
return Smi::cast(get(kNumberOfElementsIndex))->value();
@ -2658,7 +2693,6 @@ class HashTable: public FixedArray {
};
// HashTableKey is an abstract superclass for virtual key behavior.
class HashTableKey {
public:
@ -2675,7 +2709,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);
@ -2734,7 +2769,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);
@ -2890,7 +2925,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);
@ -2923,23 +2958,42 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
};
class NumberDictionaryShape {
class NumberDictionaryShape : public BaseShape<uint32_t> {
public:
static inline bool IsMatch(uint32_t key, Object* other);
static inline uint32_t Hash(uint32_t key);
static inline uint32_t HashForObject(uint32_t key, Object* object);
MUST_USE_RESULT static inline MaybeObject* AsObject(uint32_t key);
static const int kPrefixSize = 2;
static const int kEntrySize = 3;
static const bool kIsEnumerable = false;
};
class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
class SeededNumberDictionaryShape : public NumberDictionaryShape {
public:
static NumberDictionary* cast(Object* obj) {
static const bool UsesSeed = true;
static const int kPrefixSize = 2;
static inline uint32_t SeededHash(uint32_t key, uint32_t seed);
static inline uint32_t SeededHashForObject(uint32_t key,
uint32_t seed,
Object* object);
};
class UnseededNumberDictionaryShape : public NumberDictionaryShape {
public:
static const int kPrefixSize = 0;
static inline uint32_t Hash(uint32_t key);
static inline uint32_t HashForObject(uint32_t key, Object* object);
};
class SeededNumberDictionary
: public Dictionary<SeededNumberDictionaryShape, uint32_t> {
public:
static SeededNumberDictionary* cast(Object* obj) {
ASSERT(obj->IsDictionary());
return reinterpret_cast<NumberDictionary*>(obj);
return reinterpret_cast<SeededNumberDictionary*>(obj);
}
// Type specific at put (default NONE attributes is used when adding).
@ -2978,7 +3032,24 @@ class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
};
class ObjectHashTableShape {
class UnseededNumberDictionary
: public Dictionary<UnseededNumberDictionaryShape, uint32_t> {
public:
static UnseededNumberDictionary* cast(Object* obj) {
ASSERT(obj->IsDictionary());
return reinterpret_cast<UnseededNumberDictionary*>(obj);
}
// Type specific at put (default NONE attributes is used when adding).
MUST_USE_RESULT MaybeObject* AtNumberPut(uint32_t key, Object* value);
MUST_USE_RESULT MaybeObject* AddNumberEntry(uint32_t key, Object* value);
// Set an existing entry or add a new one if needed.
MUST_USE_RESULT MaybeObject* Set(uint32_t key, Object* value);
};
class ObjectHashTableShape : public BaseShape<Object*> {
public:
static inline bool IsMatch(JSObject* key, Object* other);
static inline uint32_t Hash(JSObject* key);
@ -5543,7 +5614,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);
@ -5643,7 +5714,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);

30
deps/v8/src/profile-generator.cc

@ -111,7 +111,7 @@ const char* StringsStorage::GetCopy(const char* src) {
OS::StrNCpy(dst, src, len);
dst[len] = '\0';
uint32_t hash =
HashSequentialString(dst.start(), len, HEAP->StringHashSeed());
HashSequentialString(dst.start(), len, HEAP->HashSeed());
return AddOrDisposeString(dst.start(), hash);
}
@ -145,7 +145,7 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
return format;
}
uint32_t hash = HashSequentialString(
str.start(), len, HEAP->StringHashSeed());
str.start(), len, HEAP->HashSeed());
return AddOrDisposeString(str.start(), hash);
}
@ -178,18 +178,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;
}
@ -1213,7 +1216,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
entries_sorted_(false) {
STATIC_ASSERT(
sizeof(HeapGraphEdge) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOLINT
SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize);
STATIC_ASSERT(
sizeof(HeapEntry) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT
@ -1466,10 +1469,11 @@ uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
const char* label = info->GetLabel();
id ^= HashSequentialString(label,
static_cast<int>(strlen(label)),
HEAP->StringHashSeed());
HEAP->HashSeed());
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;
}
@ -2131,7 +2135,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
}
}
} else if (js_obj->HasDictionaryElements()) {
NumberDictionary* dictionary = js_obj->element_dictionary();
SeededNumberDictionary* dictionary = js_obj->element_dictionary();
int length = dictionary->Capacity();
for (int i = 0; i < length; ++i) {
Object* k = dictionary->KeyAt(i);

12
deps/v8/src/profile-generator.h

@ -735,7 +735,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_;
@ -836,7 +837,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;
@ -1018,7 +1020,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 ||
@ -1096,7 +1099,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();

48
deps/v8/src/runtime.cc

@ -202,7 +202,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
break;
}
case DICTIONARY_ELEMENTS: {
NumberDictionary* element_dictionary = copy->element_dictionary();
SeededNumberDictionary* element_dictionary = copy->element_dictionary();
int capacity = element_dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = element_dictionary->KeyAt(i);
@ -978,14 +978,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
holder = Handle<JSObject>(JSObject::cast(proto));
}
FixedArray* elements = FixedArray::cast(holder->elements());
NumberDictionary* dictionary = NULL;
SeededNumberDictionary* dictionary = NULL;
if (elements->map() == heap->non_strict_arguments_elements_map()) {
dictionary = NumberDictionary::cast(elements->get(1));
dictionary = SeededNumberDictionary::cast(elements->get(1));
} else {
dictionary = NumberDictionary::cast(elements);
dictionary = SeededNumberDictionary::cast(elements);
}
int entry = dictionary->FindEntry(index);
ASSERT(entry != NumberDictionary::kNotFound);
ASSERT(entry != SeededNumberDictionary::kNotFound);
PropertyDetails details = dictionary->DetailsAt(entry);
switch (details.type()) {
case CALLBACKS: {
@ -4342,12 +4342,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
return isolate->Throw(*error);
}
Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
Handle<SeededNumberDictionary> dictionary = NormalizeElements(js_object);
// Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL);
Handle<NumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, obj_value, details);
Handle<SeededNumberDictionary> extended_dictionary =
SeededNumberDictionarySet(dictionary, index, obj_value, details);
if (*extended_dictionary != *dictionary) {
if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
@ -4408,12 +4408,12 @@ static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
Handle<Object> value,
PropertyAttributes attr) {
// Normalize the elements to enable attributes on the property.
Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
Handle<SeededNumberDictionary> dictionary = NormalizeElements(js_object);
// Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL);
Handle<NumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, value, details);
Handle<SeededNumberDictionary> extended_dictionary =
SeededNumberDictionarySet(dictionary, index, value, details);
if (*extended_dictionary != *dictionary) {
js_object->set_elements(*extended_dictionary);
}
@ -9485,8 +9485,9 @@ class ArrayConcatVisitor {
// Fall-through to dictionary mode.
}
ASSERT(!fast_elements_);
Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
Handle<NumberDictionary> result =
Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(*storage_));
Handle<SeededNumberDictionary> result =
isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
if (!result.is_identical_to(dict)) {
// Dictionary needed to grow.
@ -9524,14 +9525,15 @@ class ArrayConcatVisitor {
void SetDictionaryMode(uint32_t index) {
ASSERT(fast_elements_);
Handle<FixedArray> current_storage(*storage_);
Handle<NumberDictionary> slow_storage(
isolate_->factory()->NewNumberDictionary(current_storage->length()));
Handle<SeededNumberDictionary> slow_storage(
isolate_->factory()->NewSeededNumberDictionary(
current_storage->length()));
uint32_t current_length = static_cast<uint32_t>(current_storage->length());
for (uint32_t i = 0; i < current_length; i++) {
HandleScope loop_scope;
Handle<Object> element(current_storage->get(i));
if (!element->IsTheHole()) {
Handle<NumberDictionary> new_storage =
Handle<SeededNumberDictionary> new_storage =
isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
if (!new_storage.is_identical_to(slow_storage)) {
slow_storage = loop_scope.CloseAndEscape(new_storage);
@ -9578,8 +9580,8 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) {
break;
}
case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dictionary(
NumberDictionary::cast(array->elements()));
Handle<SeededNumberDictionary> dictionary(
SeededNumberDictionary::cast(array->elements()));
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Handle<Object> key(dictionary->KeyAt(i));
@ -9667,7 +9669,8 @@ static void CollectElementIndices(Handle<JSObject> object,
break;
}
case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(object->elements()));
uint32_t capacity = dict->Capacity();
for (uint32_t j = 0; j < capacity; j++) {
HandleScope loop_scope;
@ -9796,7 +9799,7 @@ static bool IterateElements(Isolate* isolate,
break;
}
case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(receiver->element_dictionary());
Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
List<uint32_t> indices(dict->Capacity() / 2);
// Collect all indices in the object and the prototypes less
// than length. This might introduce duplicates in the indices list.
@ -9945,7 +9948,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
uint32_t at_least_space_for = estimate_nof_elements +
(estimate_nof_elements >> 2);
storage = Handle<FixedArray>::cast(
isolate->factory()->NewNumberDictionary(at_least_space_for));
isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
}
ArrayConcatVisitor visitor(isolate, storage, fast_case);
@ -10031,7 +10034,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
CONVERT_CHECKED(JSObject, object, args[0]);
HeapObject* elements = object->elements();
if (elements->IsDictionary()) {
return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
return Smi::FromInt(result);
} else if (object->IsJSArray()) {
return JSArray::cast(object)->length();
} else {

5
deps/v8/src/stub-cache.cc

@ -860,7 +860,7 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
// Use raw_unchecked... so we don't get assert failures during GC.
NumberDictionary* dictionary =
UnseededNumberDictionary* dictionary =
isolate->heap()->raw_unchecked_non_monomorphic_cache();
int entry = dictionary->FindEntry(isolate, flags);
if (entry != -1) return dictionary->ValueAt(entry);
@ -882,7 +882,8 @@ MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
heap->undefined_value());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
heap->public_set_non_monomorphic_cache(
UnseededNumberDictionary::cast(result));
return probe;
}

6
deps/v8/src/type-info.cc

@ -69,7 +69,7 @@ TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) {
int entry = dictionary_->FindEntry(ast_id);
return entry != NumberDictionary::kNotFound
return entry != UnseededNumberDictionary::kNotFound
? Handle<Object>(dictionary_->ValueAt(entry))
: Isolate::Current()->factory()->undefined_value();
}
@ -470,7 +470,7 @@ void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
ZoneList<RelocInfo>* infos) {
DisableAssertNoAllocation allocation_allowed;
byte* old_start = code->instruction_start();
dictionary_ = FACTORY->NewNumberDictionary(infos->length());
dictionary_ = FACTORY->NewUnseededNumberDictionary(infos->length());
byte* new_start = code->instruction_start();
RelocateRelocInfos(infos, old_start, new_start);
}
@ -536,7 +536,7 @@ void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) {
void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
ASSERT(dictionary_->FindEntry(ast_id) == UnseededNumberDictionary::kNotFound);
MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
USE(maybe_result);
#ifdef DEBUG

2
deps/v8/src/type-info.h

@ -280,7 +280,7 @@ class TypeFeedbackOracle BASE_EMBEDDED {
Handle<Object> GetInfo(unsigned ast_id);
Handle<Context> global_context_;
Handle<NumberDictionary> dictionary_;
Handle<UnseededNumberDictionary> dictionary_;
DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle);
};

8
deps/v8/src/utils.h

@ -237,10 +237,13 @@ class BitField {
// ----------------------------------------------------------------------------
// Hash function.
static const uint32_t kZeroHashSeed = 0;
// Thomas Wang, Integer Hash Functions.
// http://www.concentric.net/~Ttwang/tech/inthash.htm
static inline uint32_t ComputeIntegerHash(uint32_t key) {
static 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);
@ -253,7 +256,8 @@ static inline uint32_t ComputeIntegerHash(uint32_t key) {
static 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);
}

3
deps/v8/src/v8globals.h

@ -131,7 +131,8 @@ class FixedArray;
class FunctionEntry;
class FunctionLiteral;
class FunctionTemplateInfo;
class NumberDictionary;
class SeededNumberDictionary;
class UnseededNumberDictionary;
class StringDictionary;
template <typename T> class Handle;
class Heap;

2
deps/v8/src/x64/code-stubs-x64.cc

@ -4610,7 +4610,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register character,
Register scratch) {
// hash = (seed + character) + ((seed + character) << 10);
__ LoadRoot(scratch, Heap::kStringHashSeedRootIndex);
__ LoadRoot(scratch, Heap::kHashSeedRootIndex);
__ SmiToInteger32(scratch, scratch);
__ addl(scratch, character);
__ movl(hash, scratch);

75
deps/v8/src/x64/macro-assembler-x64.cc

@ -3210,6 +3210,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::kHashSeedRootIndex);
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,
@ -3240,34 +3276,11 @@ 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,
FieldOperand(elements, NumberDictionary::kCapacityOffset));
SmiToInteger32(r1, FieldOperand(elements,
SeededNumberDictionary::kCapacityOffset));
decl(r1);
// Generate an unrolled loop that performs a few probes before giving up.
@ -3277,19 +3290,19 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
movq(r2, r0);
// Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) {
addl(r2, Immediate(NumberDictionary::GetProbeOffset(i)));
addl(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i)));
}
and_(r2, r1);
// Scale the index by multiplying by the entry size.
ASSERT(NumberDictionary::kEntrySize == 3);
ASSERT(SeededNumberDictionary::kEntrySize == 3);
lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
// Check if the key matches.
cmpq(key, FieldOperand(elements,
r2,
times_pointer_size,
NumberDictionary::kElementsStartOffset));
SeededNumberDictionary::kElementsStartOffset));
if (i != (kProbes - 1)) {
j(equal, &done);
} else {
@ -3300,7 +3313,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
bind(&done);
// Check that the value is a normal propety.
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0);
Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
Smi::FromInt(PropertyDetails::TypeField::kMask));
@ -3308,7 +3321,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Get the value at the masked, scaled index.
const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize;
SeededNumberDictionary::kElementsStartOffset + kPointerSize;
movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
}

1
deps/v8/src/x64/macro-assembler-x64.h

@ -845,6 +845,7 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* miss);
void GetNumberHash(Register r0, Register scratch);
void LoadFromNumberDictionary(Label* miss,
Register elements,

88
deps/v8/test/cctest/test-hashing.cc

@ -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()->HashSeed());
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…
Cancel
Save