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 hash,
Register character) { Register character) {
// hash = character + (character << 10); // hash = character + (character << 10);
__ LoadRoot(hash, Heap::kStringHashSeedRootIndex); __ LoadRoot(hash, Heap::kHashSeedRootIndex);
// Untag smi seed and add the character. // Untag smi seed and add the character.
__ add(hash, character, Operand(hash, LSR, kSmiTagSize)); __ add(hash, character, Operand(hash, LSR, kSmiTagSize));
// hash += hash << 10; // 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, void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements, Register elements,
Register key, Register key,
@ -1366,26 +1394,10 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// t2 - used for the index into the dictionary. // t2 - used for the index into the dictionary.
Label done; Label done;
// Compute the hash code from the untagged key. This must be kept in sync GetNumberHash(t0, t1);
// 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));
// Compute the capacity mask. // 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 mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
sub(t1, t1, Operand(1)); sub(t1, t1, Operand(1));
@ -1396,17 +1408,17 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
mov(t2, t0); mov(t2, t0);
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) { if (i > 0) {
add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i))); add(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
} }
and_(t2, t2, Operand(t1)); and_(t2, t2, Operand(t1));
// Scale the index by multiplying by the element size. // 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 add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
// Check if the key is identical to the name. // Check if the key is identical to the name.
add(t2, elements, Operand(t2, LSL, kPointerSizeLog2)); add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset)); ldr(ip, FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
cmp(key, Operand(ip)); cmp(key, Operand(ip));
if (i != kProbes - 1) { if (i != kProbes - 1) {
b(eq, &done); b(eq, &done);
@ -1419,14 +1431,14 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Check that the value is a normal property. // Check that the value is a normal property.
// t2: elements + (index * kPointerSize) // t2: elements + (index * kPointerSize)
const int kDetailsOffset = const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize; SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ldr(t1, FieldMemOperand(t2, kDetailsOffset)); ldr(t1, FieldMemOperand(t2, kDetailsOffset));
tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask))); tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
b(ne, miss); b(ne, miss);
// Get the value at the masked, scaled index and return. // Get the value at the masked, scaled index and return.
const int kValueOffset = const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize; SeededNumberDictionary::kElementsStartOffset + kPointerSize;
ldr(result, FieldMemOperand(t2, kValueOffset)); ldr(result, FieldMemOperand(t2, kValueOffset));
} }

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

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

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

@ -40,7 +40,7 @@ namespace internal {
bool CodeStub::FindCodeInCache(Code** code_out) { bool CodeStub::FindCodeInCache(Code** code_out) {
Heap* heap = Isolate::Current()->heap(); Heap* heap = Isolate::Current()->heap();
int index = heap->code_stubs()->FindEntry(GetKey()); int index = heap->code_stubs()->FindEntry(GetKey());
if (index != NumberDictionary::kNotFound) { if (index != UnseededNumberDictionary::kNotFound) {
*code_out = Code::cast(heap->code_stubs()->ValueAt(index)); *code_out = Code::cast(heap->code_stubs()->ValueAt(index));
return true; return true;
} }
@ -121,9 +121,9 @@ Handle<Code> CodeStub::GetCode() {
FinishCode(*new_object); FinishCode(*new_object);
// Update the dictionary and the root in Heap. // Update the dictionary and the root in Heap.
Handle<NumberDictionary> dict = Handle<UnseededNumberDictionary> dict =
factory->DictionaryAtNumberPut( factory->DictionaryAtNumberPut(
Handle<NumberDictionary>(heap->code_stubs()), Handle<UnseededNumberDictionary>(heap->code_stubs()),
GetKey(), GetKey(),
new_object); new_object);
heap->public_set_code_stubs(*dict); heap->public_set_code_stubs(*dict);
@ -165,7 +165,7 @@ MaybeObject* CodeStub::TryGetCode() {
MaybeObject* maybe_new_object = MaybeObject* maybe_new_object =
heap->code_stubs()->AtNumberPut(GetKey(), code); heap->code_stubs()->AtNumberPut(GetKey(), code);
if (maybe_new_object->ToObject(&new_object)) { 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: private:
// Calculate the hash value from the key (script id). // 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. // Scripts match if their keys (script id) match.
static bool ScriptMatch(void* key1, void* key2) { return key1 == key2; } static bool ScriptMatch(void* key1, void* key2) { return key1 == key2; }

15
deps/v8/src/elements.cc

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

15
deps/v8/src/factory.h

@ -54,7 +54,11 @@ class Factory {
int size, int size,
PretenureFlag pretenure = NOT_TENURED); 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); Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
@ -412,8 +416,13 @@ class Factory {
Handle<Object> stack_trace, Handle<Object> stack_trace,
Handle<Object> stack_frames); Handle<Object> stack_frames);
Handle<NumberDictionary> DictionaryAtNumberPut( Handle<SeededNumberDictionary> DictionaryAtNumberPut(
Handle<NumberDictionary>, Handle<SeededNumberDictionary>,
uint32_t key,
Handle<Object> value);
Handle<UnseededNumberDictionary> DictionaryAtNumberPut(
Handle<UnseededNumberDictionary>,
uint32_t key, uint32_t key,
Handle<Object> value); 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") "print stack trace when throwing exceptions")
DEFINE_bool(preallocate_message_memory, false, DEFINE_bool(preallocate_message_memory, false,
"preallocate some memory to build stack traces.") "preallocate some memory to build stack traces.")
DEFINE_bool(randomize_string_hashes, DEFINE_bool(randomize_hashes,
true, 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)") "(with snapshots this option cannot override the baked-in seed)")
DEFINE_int(string_hash_seed, DEFINE_int(hash_seed,
0, 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)") "(with snapshots this option cannot override the baked-in seed)")
// v8.cc // v8.cc

3
deps/v8/src/frames.cc

@ -1187,7 +1187,8 @@ PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
isolate_->counters()->pc_to_code()->Increment(); isolate_->counters()->pc_to_code()->Increment();
ASSERT(IsPowerOf2(kPcToCodeCacheSize)); ASSERT(IsPowerOf2(kPcToCodeCacheSize));
uint32_t hash = ComputeIntegerHash( 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); uint32_t index = hash & (kPcToCodeCacheSize - 1);
PcToCodeCacheEntry* entry = cache(index); PcToCodeCacheEntry* entry = cache(index);
if (entry->pc == pc) { 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(), CALL_HEAP_FUNCTION(object->GetIsolate(),
object->NormalizeElements(), object->NormalizeElements(),
NumberDictionary); SeededNumberDictionary);
} }
@ -229,14 +229,14 @@ void TransformToFastProperties(Handle<JSObject> object,
} }
Handle<NumberDictionary> NumberDictionarySet( Handle<SeededNumberDictionary> SeededNumberDictionarySet(
Handle<NumberDictionary> dictionary, Handle<SeededNumberDictionary> dictionary,
uint32_t index, uint32_t index,
Handle<Object> value, Handle<Object> value,
PropertyDetails details) { PropertyDetails details) {
CALL_HEAP_FUNCTION(dictionary->GetIsolate(), CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
dictionary->Set(index, *value, details), dictionary->Set(index, *value, details),
NumberDictionary); SeededNumberDictionary);
} }

6
deps/v8/src/handles.h

@ -170,11 +170,11 @@ class HandleScope {
void NormalizeProperties(Handle<JSObject> object, void NormalizeProperties(Handle<JSObject> object,
PropertyNormalizationMode mode, PropertyNormalizationMode mode,
int expected_additional_properties); int expected_additional_properties);
Handle<NumberDictionary> NormalizeElements(Handle<JSObject> object); Handle<SeededNumberDictionary> NormalizeElements(Handle<JSObject> object);
void TransformToFastProperties(Handle<JSObject> object, void TransformToFastProperties(Handle<JSObject> object,
int unused_property_fields); int unused_property_fields);
MUST_USE_RESULT Handle<NumberDictionary> NumberDictionarySet( MUST_USE_RESULT Handle<SeededNumberDictionary> SeededNumberDictionarySet(
Handle<NumberDictionary> dictionary, Handle<SeededNumberDictionary> dictionary,
uint32_t index, uint32_t index,
Handle<Object> value, Handle<Object> value,
PropertyDetails details); 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 // Allocate the code_stubs dictionary. The initial size is set to avoid
// expanding the dictionary during bootstrapping. // expanding the dictionary during bootstrapping.
{ MaybeObject* maybe_obj = NumberDictionary::Allocate(128); { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
if (!maybe_obj->ToObject(&obj)) return false; 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 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
// is set to avoid expanding the dictionary during bootstrapping. // 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; 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(); { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
if (!maybe_obj->ToObject(&obj)) return false; 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_ == NULL) return false;
if (!lo_space_->Setup()) return false; if (!lo_space_->Setup()) return false;
// Set up the seed that is used to randomize the string hash function. // Setup the seed that is used to randomize the string hash function.
ASSERT(string_hash_seed() == 0); ASSERT(hash_seed() == 0);
if (FLAG_randomize_string_hashes) { if (FLAG_randomize_hashes) {
if (FLAG_string_hash_seed == 0) { if (FLAG_hash_seed == 0) {
set_string_hash_seed( set_hash_seed(
Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff)); Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
} else { } 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, single_character_string_cache, SingleCharacterStringCache) \
V(FixedArray, string_split_cache, StringSplitCache) \ V(FixedArray, string_split_cache, StringSplitCache) \
V(Object, termination_exception, TerminationException) \ V(Object, termination_exception, TerminationException) \
V(Smi, string_hash_seed, StringHashSeed) \ V(Smi, hash_seed, HashSeed) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \ V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \ V(ByteArray, empty_byte_array, EmptyByteArray) \
V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \ V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \
@ -128,8 +128,8 @@ inline Heap* _inline_get_heap_();
V(Map, neander_map, NeanderMap) \ V(Map, neander_map, NeanderMap) \
V(JSObject, message_listeners, MessageListeners) \ V(JSObject, message_listeners, MessageListeners) \
V(Foreign, prototype_accessors, PrototypeAccessors) \ V(Foreign, prototype_accessors, PrototypeAccessors) \
V(NumberDictionary, code_stubs, CodeStubs) \ V(UnseededNumberDictionary, code_stubs, CodeStubs) \
V(NumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \ V(UnseededNumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(PolymorphicCodeCache, polymorphic_code_cache, PolymorphicCodeCache) \ V(PolymorphicCodeCache, polymorphic_code_cache, PolymorphicCodeCache) \
V(Code, js_entry_code, JsEntryCode) \ V(Code, js_entry_code, JsEntryCode) \
V(Code, js_construct_entry_code, JsConstructEntryCode) \ V(Code, js_construct_entry_code, JsConstructEntryCode) \
@ -1037,7 +1037,7 @@ class Heap {
inline AllocationSpace TargetSpaceId(InstanceType type); inline AllocationSpace TargetSpaceId(InstanceType type);
// Sets the stub_cache_ (only used when expanding the dictionary). // 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; roots_[kCodeStubsRootIndex] = value;
} }
@ -1049,7 +1049,7 @@ class Heap {
} }
// Sets the non_monomorphic_cache_ (only used when expanding the dictionary). // 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; roots_[kNonMonomorphicCacheRootIndex] = value;
} }
@ -1301,9 +1301,9 @@ class Heap {
if (global_gc_epilogue_callback_ != NULL) global_gc_epilogue_callback_(); if (global_gc_epilogue_callback_ != NULL) global_gc_epilogue_callback_();
} }
uint32_t StringHashSeed() { uint32_t HashSeed() {
uint32_t seed = static_cast<uint32_t>(string_hash_seed()->value()); uint32_t seed = static_cast<uint32_t>(hash_seed()->value());
ASSERT(FLAG_randomize_string_hashes || seed == 0); ASSERT(FLAG_randomize_hashes || seed == 0);
return seed; return seed;
} }

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

@ -5610,7 +5610,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
if (Serializer::enabled()) { if (Serializer::enabled()) {
ExternalReference roots_address = ExternalReference roots_address =
ExternalReference::roots_address(masm->isolate()); ExternalReference::roots_address(masm->isolate());
__ mov(scratch, Immediate(Heap::kStringHashSeedRootIndex)); __ mov(scratch, Immediate(Heap::kHashSeedRootIndex));
__ mov(scratch, Operand::StaticArray(scratch, __ mov(scratch, Operand::StaticArray(scratch,
times_pointer_size, times_pointer_size,
roots_address)); roots_address));
@ -5619,7 +5619,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
__ shl(scratch, 10); __ shl(scratch, 10);
__ add(hash, Operand(scratch)); __ add(hash, Operand(scratch));
} else { } else {
int32_t seed = masm->isolate()->heap()->StringHashSeed(); int32_t seed = masm->isolate()->heap()->HashSeed();
__ lea(scratch, Operand(character, seed)); __ lea(scratch, Operand(character, seed));
__ shl(scratch, 10); __ shl(scratch, 10);
__ lea(hash, Operand(scratch, character, times_1, seed)); __ 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, void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements, Register elements,
Register key, Register key,
@ -777,33 +822,10 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Label done; Label done;
// Compute the hash code from the untagged key. This must be kept in sync GetNumberHash(r0, r1);
// 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));
// Compute capacity mask. // Compute capacity mask.
mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset)); mov(r1, FieldOperand(elements, SeededNumberDictionary::kCapacityOffset));
shr(r1, kSmiTagSize); // convert smi to int shr(r1, kSmiTagSize); // convert smi to int
dec(r1); dec(r1);
@ -814,19 +836,19 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
mov(r2, r0); mov(r2, r0);
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) { if (i > 0) {
add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i))); add(Operand(r2), Immediate(SeededNumberDictionary::GetProbeOffset(i)));
} }
and_(r2, Operand(r1)); and_(r2, Operand(r1));
// Scale the index by multiplying by the entry size. // 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 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
// Check if the key matches. // Check if the key matches.
cmp(key, FieldOperand(elements, cmp(key, FieldOperand(elements,
r2, r2,
times_pointer_size, times_pointer_size,
NumberDictionary::kElementsStartOffset)); SeededNumberDictionary::kElementsStartOffset));
if (i != (kProbes - 1)) { if (i != (kProbes - 1)) {
j(equal, &done); j(equal, &done);
} else { } else {
@ -837,7 +859,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
bind(&done); bind(&done);
// Check that the value is a normal propety. // Check that the value is a normal propety.
const int kDetailsOffset = const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize; SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0); ASSERT_EQ(NORMAL, 0);
test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize)); Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
@ -845,7 +867,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Get the value at the masked, scaled index. // Get the value at the masked, scaled index.
const int kValueOffset = const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize; SeededNumberDictionary::kElementsStartOffset + kPointerSize;
mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); 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, Register scratch,
Label* miss); Label* miss);
void GetNumberHash(Register r0, Register scratch);
void LoadFromNumberDictionary(Label* miss, void LoadFromNumberDictionary(Label* miss,
Register elements, Register elements,

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

@ -5580,7 +5580,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register hash, Register hash,
Register character) { Register character) {
// hash = seed + character + ((seed + character) << 10); // hash = seed + character + ((seed + character) << 10);
__ LoadRoot(hash, Heap::kStringHashSeedRootIndex); __ LoadRoot(hash, Heap::kHashSeedRootIndex);
// Untag smi seed and add the character. // Untag smi seed and add the character.
__ SmiUntag(hash); __ SmiUntag(hash);
__ addu(hash, hash, character); __ 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, void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements, Register elements,
Register key, Register key,
@ -374,36 +412,10 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// at - Temporary (avoid MacroAssembler instructions also using 'at'). // at - Temporary (avoid MacroAssembler instructions also using 'at').
Label done; Label done;
// Compute the hash code from the untagged key. This must be kept in sync GetNumberHash(reg0, reg1);
// 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);
// Compute the capacity mask. // Compute the capacity mask.
lw(reg1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset)); lw(reg1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
sra(reg1, reg1, kSmiTagSize); sra(reg1, reg1, kSmiTagSize);
Subu(reg1, reg1, Operand(1)); Subu(reg1, reg1, Operand(1));
@ -414,12 +426,12 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
mov(reg2, reg0); mov(reg2, reg0);
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) { if (i > 0) {
Addu(reg2, reg2, Operand(NumberDictionary::GetProbeOffset(i))); Addu(reg2, reg2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
} }
and_(reg2, reg2, reg1); and_(reg2, reg2, reg1);
// Scale the index by multiplying by the element size. // Scale the index by multiplying by the element size.
ASSERT(NumberDictionary::kEntrySize == 3); ASSERT(SeededNumberDictionary::kEntrySize == 3);
sll(at, reg2, 1); // 2x. sll(at, reg2, 1); // 2x.
addu(reg2, reg2, at); // reg2 = reg2 * 3. addu(reg2, reg2, at); // reg2 = reg2 * 3.
@ -427,7 +439,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
sll(at, reg2, kPointerSizeLog2); sll(at, reg2, kPointerSizeLog2);
addu(reg2, elements, at); addu(reg2, elements, at);
lw(at, FieldMemOperand(reg2, NumberDictionary::kElementsStartOffset)); lw(at, FieldMemOperand(reg2, SeededNumberDictionary::kElementsStartOffset));
if (i != kProbes - 1) { if (i != kProbes - 1) {
Branch(&done, eq, key, Operand(at)); Branch(&done, eq, key, Operand(at));
} else { } else {
@ -439,14 +451,14 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Check that the value is a normal property. // Check that the value is a normal property.
// reg2: elements + (index * kPointerSize). // reg2: elements + (index * kPointerSize).
const int kDetailsOffset = const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize; SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
lw(reg1, FieldMemOperand(reg2, kDetailsOffset)); lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask))); And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
Branch(miss, ne, at, Operand(zero_reg)); Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return. // Get the value at the masked, scaled index and return.
const int kValueOffset = const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize; SeededNumberDictionary::kElementsStartOffset + kPointerSize;
lw(result, FieldMemOperand(reg2, kValueOffset)); lw(result, FieldMemOperand(reg2, kValueOffset));
} }

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

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

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

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

107
deps/v8/src/objects.h

@ -1541,7 +1541,7 @@ class JSObject: public JSReceiver {
bool HasFastArgumentsElements(); bool HasFastArgumentsElements();
bool HasDictionaryArgumentsElements(); bool HasDictionaryArgumentsElements();
inline bool AllowsSetElementsLength(); inline bool AllowsSetElementsLength();
inline NumberDictionary* element_dictionary(); // Gets slow elements. inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
// Requires: HasFastElements(). // Requires: HasFastElements().
MUST_USE_RESULT inline MaybeObject* EnsureWritableFastElements(); MUST_USE_RESULT inline MaybeObject* EnsureWritableFastElements();
@ -1902,8 +1902,6 @@ class JSObject: public JSReceiver {
PropertyNormalizationMode mode, PropertyNormalizationMode mode,
int expected_additional_properties); 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* NormalizeElements();
MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code); MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code);
@ -2221,7 +2219,7 @@ class FixedDoubleArray: public FixedArrayBase {
public: public:
inline void Initialize(FixedArray* from); inline void Initialize(FixedArray* from);
inline void Initialize(FixedDoubleArray* from); inline void Initialize(FixedDoubleArray* from);
inline void Initialize(NumberDictionary* from); inline void Initialize(SeededNumberDictionary* from);
// Setter and getter for elements. // Setter and getter for elements.
inline double get_scalar(int index); 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 // beginning of the backing storage that can be used for non-element
// information by subclasses. // 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> template<typename Shape, typename Key>
class HashTable: public FixedArray { class HashTable: public FixedArray {
public: 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. // Returns the number of elements in the hash table.
int NumberOfElements() { int NumberOfElements() {
return Smi::cast(get(kNumberOfElementsIndex))->value(); return Smi::cast(get(kNumberOfElementsIndex))->value();
@ -2658,7 +2693,6 @@ class HashTable: public FixedArray {
}; };
// HashTableKey is an abstract superclass for virtual key behavior. // HashTableKey is an abstract superclass for virtual key behavior.
class HashTableKey { class HashTableKey {
public: public:
@ -2675,7 +2709,8 @@ class HashTableKey {
virtual ~HashTableKey() {} virtual ~HashTableKey() {}
}; };
class SymbolTableShape {
class SymbolTableShape : public BaseShape<HashTableKey*> {
public: public:
static inline bool IsMatch(HashTableKey* key, Object* value) { static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value); return key->IsMatch(value);
@ -2734,7 +2769,7 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> {
}; };
class MapCacheShape { class MapCacheShape : public BaseShape<HashTableKey*> {
public: public:
static inline bool IsMatch(HashTableKey* key, Object* value) { static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value); return key->IsMatch(value);
@ -2890,7 +2925,7 @@ class Dictionary: public HashTable<Shape, Key> {
}; };
class StringDictionaryShape { class StringDictionaryShape : public BaseShape<String*> {
public: public:
static inline bool IsMatch(String* key, Object* other); static inline bool IsMatch(String* key, Object* other);
static inline uint32_t Hash(String* key); 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: public:
static inline bool IsMatch(uint32_t key, Object* other); 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); MUST_USE_RESULT static inline MaybeObject* AsObject(uint32_t key);
static const int kPrefixSize = 2;
static const int kEntrySize = 3; static const int kEntrySize = 3;
static const bool kIsEnumerable = false; static const bool kIsEnumerable = false;
}; };
class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> { class SeededNumberDictionaryShape : public NumberDictionaryShape {
public: 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()); ASSERT(obj->IsDictionary());
return reinterpret_cast<NumberDictionary*>(obj); return reinterpret_cast<SeededNumberDictionary*>(obj);
} }
// Type specific at put (default NONE attributes is used when adding). // 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: public:
static inline bool IsMatch(JSObject* key, Object* other); static inline bool IsMatch(JSObject* key, Object* other);
static inline uint32_t Hash(JSObject* key); static inline uint32_t Hash(JSObject* key);
@ -5543,7 +5614,7 @@ class JSRegExp: public JSObject {
}; };
class CompilationCacheShape { class CompilationCacheShape : public BaseShape<HashTableKey*> {
public: public:
static inline bool IsMatch(HashTableKey* key, Object* value) { static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value); return key->IsMatch(value);
@ -5643,7 +5714,7 @@ class CodeCache: public Struct {
}; };
class CodeCacheHashTableShape { class CodeCacheHashTableShape : public BaseShape<HashTableKey*> {
public: public:
static inline bool IsMatch(HashTableKey* key, Object* value) { static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(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); OS::StrNCpy(dst, src, len);
dst[len] = '\0'; dst[len] = '\0';
uint32_t hash = uint32_t hash =
HashSequentialString(dst.start(), len, HEAP->StringHashSeed()); HashSequentialString(dst.start(), len, HEAP->HashSeed());
return AddOrDisposeString(dst.start(), hash); return AddOrDisposeString(dst.start(), hash);
} }
@ -145,7 +145,7 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
return format; return format;
} }
uint32_t hash = HashSequentialString( uint32_t hash = HashSequentialString(
str.start(), len, HEAP->StringHashSeed()); str.start(), len, HEAP->HashSeed());
return AddOrDisposeString(str.start(), hash); return AddOrDisposeString(str.start(), hash);
} }
@ -178,18 +178,21 @@ void CodeEntry::CopyData(const CodeEntry& source) {
uint32_t CodeEntry::GetCallUid() const { uint32_t CodeEntry::GetCallUid() const {
uint32_t hash = ComputeIntegerHash(tag_); uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed);
if (shared_id_ != 0) { if (shared_id_ != 0) {
hash ^= ComputeIntegerHash( hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_),
static_cast<uint32_t>(shared_id_)); v8::internal::kZeroHashSeed);
} else { } else {
hash ^= ComputeIntegerHash( 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( 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( hash ^= ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_))); static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)),
hash ^= ComputeIntegerHash(line_number_); v8::internal::kZeroHashSeed);
hash ^= ComputeIntegerHash(line_number_, v8::internal::kZeroHashSeed);
} }
return hash; return hash;
} }
@ -1213,7 +1216,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
entries_sorted_(false) { entries_sorted_(false) {
STATIC_ASSERT( STATIC_ASSERT(
sizeof(HeapGraphEdge) == sizeof(HeapGraphEdge) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOLINT SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize);
STATIC_ASSERT( STATIC_ASSERT(
sizeof(HeapEntry) == sizeof(HeapEntry) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT
@ -1466,10 +1469,11 @@ uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
const char* label = info->GetLabel(); const char* label = info->GetLabel();
id ^= HashSequentialString(label, id ^= HashSequentialString(label,
static_cast<int>(strlen(label)), static_cast<int>(strlen(label)),
HEAP->StringHashSeed()); HEAP->HashSeed());
intptr_t element_count = info->GetElementCount(); intptr_t element_count = info->GetElementCount();
if (element_count != -1) 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; return id << 1;
} }
@ -2131,7 +2135,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
} }
} }
} else if (js_obj->HasDictionaryElements()) { } else if (js_obj->HasDictionaryElements()) {
NumberDictionary* dictionary = js_obj->element_dictionary(); SeededNumberDictionary* dictionary = js_obj->element_dictionary();
int length = dictionary->Capacity(); int length = dictionary->Capacity();
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
Object* k = dictionary->KeyAt(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) { static uint32_t AddressHash(Address addr) {
return ComputeIntegerHash( 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_; bool initial_fill_mode_;
@ -836,7 +837,8 @@ class HeapEntriesMap {
static uint32_t Hash(HeapThing thing) { static uint32_t Hash(HeapThing thing) {
return ComputeIntegerHash( 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) { static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
return key1 == key2; return key1 == key2;
@ -1018,7 +1020,8 @@ class NativeObjectsExplorer : public HeapEntriesAllocator {
void VisitSubtreeWrapper(Object** p, uint16_t class_id); void VisitSubtreeWrapper(Object** p, uint16_t class_id);
static uint32_t InfoHash(v8::RetainedObjectInfo* info) { 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) { static bool RetainedInfosMatch(void* key1, void* key2) {
return key1 == key2 || return key1 == key2 ||
@ -1096,7 +1099,8 @@ class HeapSnapshotJSONSerializer {
INLINE(static uint32_t ObjectHash(const void* key)) { INLINE(static uint32_t ObjectHash(const void* key)) {
return ComputeIntegerHash( 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(); void EnumerateNodes();

48
deps/v8/src/runtime.cc

@ -202,7 +202,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
break; break;
} }
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
NumberDictionary* element_dictionary = copy->element_dictionary(); SeededNumberDictionary* element_dictionary = copy->element_dictionary();
int capacity = element_dictionary->Capacity(); int capacity = element_dictionary->Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = element_dictionary->KeyAt(i); Object* k = element_dictionary->KeyAt(i);
@ -978,14 +978,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
holder = Handle<JSObject>(JSObject::cast(proto)); holder = Handle<JSObject>(JSObject::cast(proto));
} }
FixedArray* elements = FixedArray::cast(holder->elements()); FixedArray* elements = FixedArray::cast(holder->elements());
NumberDictionary* dictionary = NULL; SeededNumberDictionary* dictionary = NULL;
if (elements->map() == heap->non_strict_arguments_elements_map()) { if (elements->map() == heap->non_strict_arguments_elements_map()) {
dictionary = NumberDictionary::cast(elements->get(1)); dictionary = SeededNumberDictionary::cast(elements->get(1));
} else { } else {
dictionary = NumberDictionary::cast(elements); dictionary = SeededNumberDictionary::cast(elements);
} }
int entry = dictionary->FindEntry(index); int entry = dictionary->FindEntry(index);
ASSERT(entry != NumberDictionary::kNotFound); ASSERT(entry != SeededNumberDictionary::kNotFound);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
switch (details.type()) { switch (details.type()) {
case CALLBACKS: { case CALLBACKS: {
@ -4342,12 +4342,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
return isolate->Throw(*error); 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. // Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements(); dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL); PropertyDetails details = PropertyDetails(attr, NORMAL);
Handle<NumberDictionary> extended_dictionary = Handle<SeededNumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, obj_value, details); SeededNumberDictionarySet(dictionary, index, obj_value, details);
if (*extended_dictionary != *dictionary) { if (*extended_dictionary != *dictionary) {
if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) { if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
FixedArray::cast(js_object->elements())->set(1, *extended_dictionary); FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
@ -4408,12 +4408,12 @@ static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attr) { PropertyAttributes attr) {
// Normalize the elements to enable attributes on the property. // 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. // Make sure that we never go back to fast case.
dictionary->set_requires_slow_elements(); dictionary->set_requires_slow_elements();
PropertyDetails details = PropertyDetails(attr, NORMAL); PropertyDetails details = PropertyDetails(attr, NORMAL);
Handle<NumberDictionary> extended_dictionary = Handle<SeededNumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, value, details); SeededNumberDictionarySet(dictionary, index, value, details);
if (*extended_dictionary != *dictionary) { if (*extended_dictionary != *dictionary) {
js_object->set_elements(*extended_dictionary); js_object->set_elements(*extended_dictionary);
} }
@ -9485,8 +9485,9 @@ class ArrayConcatVisitor {
// Fall-through to dictionary mode. // Fall-through to dictionary mode.
} }
ASSERT(!fast_elements_); ASSERT(!fast_elements_);
Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_)); Handle<SeededNumberDictionary> dict(
Handle<NumberDictionary> result = SeededNumberDictionary::cast(*storage_));
Handle<SeededNumberDictionary> result =
isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
if (!result.is_identical_to(dict)) { if (!result.is_identical_to(dict)) {
// Dictionary needed to grow. // Dictionary needed to grow.
@ -9524,14 +9525,15 @@ class ArrayConcatVisitor {
void SetDictionaryMode(uint32_t index) { void SetDictionaryMode(uint32_t index) {
ASSERT(fast_elements_); ASSERT(fast_elements_);
Handle<FixedArray> current_storage(*storage_); Handle<FixedArray> current_storage(*storage_);
Handle<NumberDictionary> slow_storage( Handle<SeededNumberDictionary> slow_storage(
isolate_->factory()->NewNumberDictionary(current_storage->length())); isolate_->factory()->NewSeededNumberDictionary(
current_storage->length()));
uint32_t current_length = static_cast<uint32_t>(current_storage->length()); uint32_t current_length = static_cast<uint32_t>(current_storage->length());
for (uint32_t i = 0; i < current_length; i++) { for (uint32_t i = 0; i < current_length; i++) {
HandleScope loop_scope; HandleScope loop_scope;
Handle<Object> element(current_storage->get(i)); Handle<Object> element(current_storage->get(i));
if (!element->IsTheHole()) { if (!element->IsTheHole()) {
Handle<NumberDictionary> new_storage = Handle<SeededNumberDictionary> new_storage =
isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
if (!new_storage.is_identical_to(slow_storage)) { if (!new_storage.is_identical_to(slow_storage)) {
slow_storage = loop_scope.CloseAndEscape(new_storage); slow_storage = loop_scope.CloseAndEscape(new_storage);
@ -9578,8 +9580,8 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) {
break; break;
} }
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dictionary( Handle<SeededNumberDictionary> dictionary(
NumberDictionary::cast(array->elements())); SeededNumberDictionary::cast(array->elements()));
int capacity = dictionary->Capacity(); int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Handle<Object> key(dictionary->KeyAt(i)); Handle<Object> key(dictionary->KeyAt(i));
@ -9667,7 +9669,8 @@ static void CollectElementIndices(Handle<JSObject> object,
break; break;
} }
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements())); Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(object->elements()));
uint32_t capacity = dict->Capacity(); uint32_t capacity = dict->Capacity();
for (uint32_t j = 0; j < capacity; j++) { for (uint32_t j = 0; j < capacity; j++) {
HandleScope loop_scope; HandleScope loop_scope;
@ -9796,7 +9799,7 @@ static bool IterateElements(Isolate* isolate,
break; break;
} }
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(receiver->element_dictionary()); Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
List<uint32_t> indices(dict->Capacity() / 2); List<uint32_t> indices(dict->Capacity() / 2);
// Collect all indices in the object and the prototypes less // Collect all indices in the object and the prototypes less
// than length. This might introduce duplicates in the indices list. // 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 + uint32_t at_least_space_for = estimate_nof_elements +
(estimate_nof_elements >> 2); (estimate_nof_elements >> 2);
storage = Handle<FixedArray>::cast( storage = Handle<FixedArray>::cast(
isolate->factory()->NewNumberDictionary(at_least_space_for)); isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
} }
ArrayConcatVisitor visitor(isolate, storage, fast_case); ArrayConcatVisitor visitor(isolate, storage, fast_case);
@ -10031,7 +10034,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
CONVERT_CHECKED(JSObject, object, args[0]); CONVERT_CHECKED(JSObject, object, args[0]);
HeapObject* elements = object->elements(); HeapObject* elements = object->elements();
if (elements->IsDictionary()) { if (elements->IsDictionary()) {
return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements()); int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
return Smi::FromInt(result);
} else if (object->IsJSArray()) { } else if (object->IsJSArray()) {
return JSArray::cast(object)->length(); return JSArray::cast(object)->length();
} else { } 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) { static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
// Use raw_unchecked... so we don't get assert failures during GC. // Use raw_unchecked... so we don't get assert failures during GC.
NumberDictionary* dictionary = UnseededNumberDictionary* dictionary =
isolate->heap()->raw_unchecked_non_monomorphic_cache(); isolate->heap()->raw_unchecked_non_monomorphic_cache();
int entry = dictionary->FindEntry(isolate, flags); int entry = dictionary->FindEntry(isolate, flags);
if (entry != -1) return dictionary->ValueAt(entry); if (entry != -1) return dictionary->ValueAt(entry);
@ -882,7 +882,8 @@ MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
heap->undefined_value()); heap->undefined_value());
if (!maybe_result->ToObject(&result)) return maybe_result; 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; 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) { Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) {
int entry = dictionary_->FindEntry(ast_id); int entry = dictionary_->FindEntry(ast_id);
return entry != NumberDictionary::kNotFound return entry != UnseededNumberDictionary::kNotFound
? Handle<Object>(dictionary_->ValueAt(entry)) ? Handle<Object>(dictionary_->ValueAt(entry))
: Isolate::Current()->factory()->undefined_value(); : Isolate::Current()->factory()->undefined_value();
} }
@ -470,7 +470,7 @@ void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
ZoneList<RelocInfo>* infos) { ZoneList<RelocInfo>* infos) {
DisableAssertNoAllocation allocation_allowed; DisableAssertNoAllocation allocation_allowed;
byte* old_start = code->instruction_start(); byte* old_start = code->instruction_start();
dictionary_ = FACTORY->NewNumberDictionary(infos->length()); dictionary_ = FACTORY->NewUnseededNumberDictionary(infos->length());
byte* new_start = code->instruction_start(); byte* new_start = code->instruction_start();
RelocateRelocInfos(infos, old_start, new_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) { 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); MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
USE(maybe_result); USE(maybe_result);
#ifdef DEBUG #ifdef DEBUG

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

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

8
deps/v8/src/utils.h

@ -237,10 +237,13 @@ class BitField {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Hash function. // Hash function.
static const uint32_t kZeroHashSeed = 0;
// Thomas Wang, Integer Hash Functions. // Thomas Wang, Integer Hash Functions.
// http://www.concentric.net/~Ttwang/tech/inthash.htm // 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; uint32_t hash = key;
hash = hash ^ seed;
hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1; hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
hash = hash ^ (hash >> 12); hash = hash ^ (hash >> 12);
hash = hash + (hash << 2); hash = hash + (hash << 2);
@ -253,7 +256,8 @@ static inline uint32_t ComputeIntegerHash(uint32_t key) {
static inline uint32_t ComputePointerHash(void* ptr) { static inline uint32_t ComputePointerHash(void* ptr) {
return ComputeIntegerHash( 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 FunctionEntry;
class FunctionLiteral; class FunctionLiteral;
class FunctionTemplateInfo; class FunctionTemplateInfo;
class NumberDictionary; class SeededNumberDictionary;
class UnseededNumberDictionary;
class StringDictionary; class StringDictionary;
template <typename T> class Handle; template <typename T> class Handle;
class Heap; class Heap;

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

@ -4610,7 +4610,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register character, Register character,
Register scratch) { Register scratch) {
// hash = (seed + character) + ((seed + character) << 10); // hash = (seed + character) + ((seed + character) << 10);
__ LoadRoot(scratch, Heap::kStringHashSeedRootIndex); __ LoadRoot(scratch, Heap::kHashSeedRootIndex);
__ SmiToInteger32(scratch, scratch); __ SmiToInteger32(scratch, scratch);
__ addl(scratch, character); __ addl(scratch, character);
__ movl(hash, scratch); __ 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, void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements, Register elements,
Register key, Register key,
@ -3240,34 +3276,11 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Label done; Label done;
// Compute the hash code from the untagged key. This must be kept in sync GetNumberHash(r0, r1);
// 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);
// Compute capacity mask. // Compute capacity mask.
SmiToInteger32(r1, SmiToInteger32(r1, FieldOperand(elements,
FieldOperand(elements, NumberDictionary::kCapacityOffset)); SeededNumberDictionary::kCapacityOffset));
decl(r1); decl(r1);
// Generate an unrolled loop that performs a few probes before giving up. // Generate an unrolled loop that performs a few probes before giving up.
@ -3277,19 +3290,19 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
movq(r2, r0); movq(r2, r0);
// Compute the masked index: (hash + i + i * i) & mask. // Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) { if (i > 0) {
addl(r2, Immediate(NumberDictionary::GetProbeOffset(i))); addl(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i)));
} }
and_(r2, r1); and_(r2, r1);
// Scale the index by multiplying by the entry size. // 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 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
// Check if the key matches. // Check if the key matches.
cmpq(key, FieldOperand(elements, cmpq(key, FieldOperand(elements,
r2, r2,
times_pointer_size, times_pointer_size,
NumberDictionary::kElementsStartOffset)); SeededNumberDictionary::kElementsStartOffset));
if (i != (kProbes - 1)) { if (i != (kProbes - 1)) {
j(equal, &done); j(equal, &done);
} else { } else {
@ -3300,7 +3313,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
bind(&done); bind(&done);
// Check that the value is a normal propety. // Check that the value is a normal propety.
const int kDetailsOffset = const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize; SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0); ASSERT_EQ(NORMAL, 0);
Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
Smi::FromInt(PropertyDetails::TypeField::kMask)); Smi::FromInt(PropertyDetails::TypeField::kMask));
@ -3308,7 +3321,7 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss,
// Get the value at the masked, scaled index. // Get the value at the masked, scaled index.
const int kValueOffset = const int kValueOffset =
NumberDictionary::kElementsStartOffset + kPointerSize; SeededNumberDictionary::kElementsStartOffset + kPointerSize;
movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); 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, Register scratch,
Label* miss); Label* miss);
void GetNumberHash(Register r0, Register scratch);
void LoadFromNumberDictionary(Label* miss, void LoadFromNumberDictionary(Label* miss,
Register elements, 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) { void check(i::Vector<const char> string) {
v8::HandleScope scope; v8::HandleScope scope;
v8::internal::byte buffer[2048]; 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) { void check_twochars(char a, char b) {
char ab[2] = {a, b}; char ab[2] = {a, b};
check(i::Vector<const char>(ab, 2)); check(i::Vector<const char>(ab, 2));
} }
static uint32_t PseudoRandom(uint32_t i, uint32_t j) {
return ~(~((i * 781) ^ (j * 329)));
}
TEST(StringHash) { TEST(StringHash) {
if (env.IsEmpty()) env = v8::Context::New(); if (env.IsEmpty()) env = v8::Context::New();
for (int a = 0; a < String::kMaxAsciiCharCode; a++) { for (int a = 0; a < String::kMaxAsciiCharCode; a++) {
@ -169,4 +239,22 @@ TEST(StringHash) {
check(i::Vector<const char>("-=[ vee eight ftw ]=-", 21)); 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 __ #undef __

Loading…
Cancel
Save