Chromium Code Reviews| Index: src/objects.cc |
| =================================================================== |
| --- src/objects.cc (revision 3335) |
| +++ src/objects.cc (working copy) |
| @@ -416,6 +416,12 @@ |
| Object* value, |
| PropertyDetails details) { |
| ASSERT(!HasFastProperties()); |
| + // Optimization for packer.js. We make short keys into symbols to avoid |
| + // constantly reallocating them. |
|
Søren Thygesen Gjesse
2009/11/19 21:42:57
This code is duplicated below, please refactor.
Erik Corry
2009/11/20 10:12:46
Instead I removed this occurrence since it is very
|
| + if (!name->IsSymbol() && name->length() <= 2) { |
| + Object* symbol_version = Heap::LookupSymbol(name); |
| + if (!symbol_version->IsFailure()) name = String::cast(symbol_version); |
| + } |
| int entry = property_dictionary()->FindEntry(name); |
| if (entry == StringDictionary::kNotFound) { |
| Object* store_value = value; |
| @@ -1463,8 +1469,8 @@ |
| Object* JSObject::ReplaceSlowProperty(String* name, |
| - Object* value, |
| - PropertyAttributes attributes) { |
| + Object* value, |
| + PropertyAttributes attributes) { |
| StringDictionary* dictionary = property_dictionary(); |
| int old_index = dictionary->FindEntry(name); |
| int new_enumeration_index = 0; // 0 means "Use the next available index." |
| @@ -1478,6 +1484,7 @@ |
| return SetNormalizedProperty(name, value, new_details); |
| } |
| + |
| Object* JSObject::ConvertDescriptorToFieldAndMapTransition( |
| String* name, |
| Object* new_value, |
| @@ -1869,6 +1876,13 @@ |
| // interceptor calls. |
| AssertNoContextChange ncc; |
| + // Optimization for packer.js. We make short keys into symbols to avoid |
| + // constantly reallocating them. |
| + if (!name->IsSymbol() && name->length() <= 2) { |
| + Object* symbol_version = Heap::LookupSymbol(name); |
| + if (!symbol_version->IsFailure()) name = String::cast(symbol_version); |
| + } |
| + |
| // Check access rights if needed. |
| if (IsAccessCheckNeeded() |
| && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
| @@ -5240,9 +5254,7 @@ |
| Handle<JSArray> self(this); |
| Handle<FixedArray> old_backing(FixedArray::cast(elements())); |
| int old_size = old_backing->length(); |
| - // Doubling in size would be overkill, but leave some slack to avoid |
| - // constantly growing. |
| - int new_size = required_size + (required_size >> 3); |
| + int new_size = required_size > old_size ? required_size : old_size; |
| Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size); |
| // Can't use this any more now because we may have had a GC! |
| for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); |
| @@ -7327,6 +7339,63 @@ |
| } |
| +// This class is used for looking up two character strings in the symbol table. |
| +// If we don't have a hit we don't want to waste much time so we unroll the |
| +// string hash calculation loop here for speed. Doesn't work if the two |
| +// characters form a decimal integer, since such strings have a different hash |
| +// algorithm. |
| +class TwoCharHashTableKey : public HashTableKey { |
| + public: |
| + TwoCharHashTableKey(uint32_t c1, uint32_t c2) |
| + : c1_(c1), c2_(c2) { |
|
Søren Thygesen Gjesse
2009/11/19 21:42:57
How about ASSERT(c1 > '9' || c2 > '9') here? I see
Erik Corry
2009/11/20 10:12:46
Added a comment to the ASSERT_EQ below instead.
|
| + // Char 1. |
| + uint32_t hash = c1 + (c1 << 10); |
| + hash ^= hash >> 6; |
| + // Char 2. |
| + hash += c2; |
| + hash += hash << 10; |
| + hash ^= hash >> 6; |
| + // GetHash. |
| + hash += hash << 3; |
| + hash ^= hash >> 11; |
| + hash += hash << 15; |
| + if (hash == 0) hash = 27; |
| +#ifdef DEBUG |
| + StringHasher hasher(2); |
| + hasher.AddCharacter(c1); |
| + hasher.AddCharacter(c2); |
| + ASSERT_EQ((int)hasher.GetHash(), (int)hash); |
| +#endif |
| + hash_ = hash; |
| + } |
| + |
| + bool IsMatch(Object* o) { |
| + if (!o->IsString()) return false; |
| + String* other = String::cast(o); |
| + if (other->length() != 2) return false; |
| + if (other->Get(0) != c1_) return false; |
| + return other->Get(1) == c2_; |
| + } |
| + |
| + uint32_t Hash() { return hash_; } |
| + uint32_t HashForObject(Object* key) { |
| + if (!key->IsString()) return 0; |
| + return String::cast(key)->Hash(); |
| + } |
| + |
| + Object* AsObject() { |
| + // The TwoCharHashTableKey is only used for looking in the symbol |
| + // table, not for adding to it. |
| + UNREACHABLE(); |
| + return NULL; |
| + } |
| + private: |
| + uint32_t c1_; |
| + uint32_t c2_; |
| + uint32_t hash_; |
| +}; |
| + |
| + |
| bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { |
| SymbolKey key(string); |
| int entry = FindEntry(&key); |
| @@ -7341,6 +7410,22 @@ |
| } |
| +bool SymbolTable::LookupTwoCharsIfExists(uint32_t c1, |
| + uint32_t c2, |
| + String** symbol) { |
| + TwoCharHashTableKey key(c1, c2); |
| + int entry = FindEntry(&key); |
| + if (entry == kNotFound) { |
| + return false; |
| + } else { |
| + String* result = String::cast(KeyAt(entry)); |
| + ASSERT(StringShape(result).IsSymbol()); |
| + *symbol = result; |
| + return true; |
| + } |
| +} |
| + |
| + |
| Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) { |
| Utf8SymbolKey key(str); |
| return LookupKey(&key, s); |