Top::MarkCompactPrologue(is_compacting);
ThreadManager::MarkCompactPrologue(is_compacting);
+
+ if (is_compacting) FlushNumberStringCache();
}
CreateFixedStubs();
- // Allocate the number->string conversion cache
- obj = AllocateFixedArray(kNumberStringCacheSize * 2);
- if (obj->IsFailure()) return false;
- set_number_string_cache(FixedArray::cast(obj));
+ if (InitializeNumberStringCache()->IsFailure()) return false;
// Allocate cache for single character strings.
obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
}
+Object* Heap::InitializeNumberStringCache() {
+ // Compute the size of the number string cache based on the max heap size.
+ // max_semispace_size_ == 512 KB => number_string_cache_size = 32.
+ // max_semispace_size_ == 8 MB => number_string_cache_size = 16KB.
+ int number_string_cache_size = max_semispace_size_ / 512;
+ number_string_cache_size = Max(32, Min(16*KB, number_string_cache_size));
+ Object* obj = AllocateFixedArray(number_string_cache_size * 2);
+ if (!obj->IsFailure()) set_number_string_cache(FixedArray::cast(obj));
+ return obj;
+}
+
+
+void Heap::FlushNumberStringCache() {
+ // Flush the number to string cache.
+ int len = number_string_cache()->length();
+ for (int i = 0; i < len; i++) {
+ number_string_cache()->set_undefined(i);
+ }
+}
+
+
static inline int double_get_hash(double d) {
DoubleRepresentation rep(d);
- return ((static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32)) &
- (Heap::kNumberStringCacheSize - 1));
+ return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
}
static inline int smi_get_hash(Smi* smi) {
- return (smi->value() & (Heap::kNumberStringCacheSize - 1));
+ return smi->value();
}
-
Object* Heap::GetNumberStringCache(Object* number) {
int hash;
+ int mask = (number_string_cache()->length() >> 1) - 1;
if (number->IsSmi()) {
- hash = smi_get_hash(Smi::cast(number));
+ hash = smi_get_hash(Smi::cast(number)) & mask;
} else {
- hash = double_get_hash(number->Number());
+ hash = double_get_hash(number->Number()) & mask;
}
Object* key = number_string_cache()->get(hash * 2);
if (key == number) {
void Heap::SetNumberStringCache(Object* number, String* string) {
int hash;
+ int mask = (number_string_cache()->length() >> 1) - 1;
if (number->IsSmi()) {
- hash = smi_get_hash(Smi::cast(number));
+ hash = smi_get_hash(Smi::cast(number)) & mask;
number_string_cache()->set(hash * 2, number, SKIP_WRITE_BARRIER);
} else {
- hash = double_get_hash(number->Number());
+ hash = double_get_hash(number->Number()) & mask;
number_string_cache()->set(hash * 2, number);
}
number_string_cache()->set(hash * 2 + 1, string);
// Update the cache with a new number-string pair.
static void SetNumberStringCache(Object* number, String* str);
- // Entries in the cache. Must be a power of 2.
- static const int kNumberStringCacheSize = 64;
-
// Adjusts the amount of registered external memory.
// Returns the adjusted value.
static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
SharedFunctionInfo* shared,
Object* prototype);
+
+ // Initializes the number to string cache based on the max semispace size.
+ static Object* InitializeNumberStringCache();
+ // Flush the number to string cache.
+ static void FlushNumberStringCache();
+
static const int kInitialSymbolTableSize = 2048;
static const int kInitialEvalCacheSize = 64;
}
-
-// Find entry for key otherwise return -1.
+// Find entry for key otherwise return kNotFound.
template<typename Shape, typename Key>
int HashTable<Shape, Key>::FindEntry(Key key) {
- uint32_t nof = NumberOfElements();
- if (nof == 0) return kNotFound; // Bail out if empty.
-
uint32_t capacity = Capacity();
- uint32_t hash = Shape::Hash(key);
- uint32_t entry = GetProbe(hash, 0, capacity);
-
- Object* element = KeyAt(entry);
- uint32_t passed_elements = 0;
- if (!element->IsNull()) {
- if (!element->IsUndefined() && Shape::IsMatch(key, element)) return entry;
- if (++passed_elements == nof) return kNotFound;
- }
- for (uint32_t i = 1; !element->IsUndefined(); i++) {
- entry = GetProbe(hash, i, capacity);
- element = KeyAt(entry);
- if (!element->IsNull()) {
- if (!element->IsUndefined() && Shape::IsMatch(key, element)) return entry;
- if (++passed_elements == nof) return kNotFound;
- }
+ uint32_t entry = FirstProbe(Shape::Hash(key), capacity);
+ uint32_t count = 1;
+ // EnsureCapacity will guarantee the hash table is never full.
+ while (true) {
+ Object* element = KeyAt(entry);
+ if (element->IsUndefined()) break; // Empty entry.
+ if (!element->IsNull() && Shape::IsMatch(key, element)) return entry;
+ entry = NextProbe(entry, count++, capacity);
}
return kNotFound;
}
}
+
template<typename Shape, typename Key>
uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
uint32_t capacity = Capacity();
- uint32_t entry = GetProbe(hash, 0, capacity);
- Object* element = KeyAt(entry);
-
- for (uint32_t i = 1; !(element->IsUndefined() || element->IsNull()); i++) {
- entry = GetProbe(hash, i, capacity);
- element = KeyAt(entry);
+ uint32_t entry = FirstProbe(hash, capacity);
+ uint32_t count = 1;
+ // EnsureCapacity will guarantee the hash table is never full.
+ while (true) {
+ Object* element = KeyAt(entry);
+ if (element->IsUndefined() || element->IsNull()) break;
+ entry = NextProbe(entry, count++, capacity);
}
-
return entry;
}
template
int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
+template
+int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
+
+
// Collates undefined and unexisting elements below limit from position
// zero of the elements. The object stays in Dictionary mode.
Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
return (hash + GetProbeOffset(number)) & (size - 1);
}
+ static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
+ return hash & (size - 1);
+ }
+
+ static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) {
+ return (last + number) & (size - 1);
+ }
+
// Ensure enough space for n additional elements.
Object* EnsureCapacity(int n, Key key);
};