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); |