Revision: 9164
Author:   [email protected]
Date:     Wed Sep  7 04:28:48 2011
Log:      Optimize the common obfuscator pattern where ["foo","bar","baz"]
gets converted fo "foo,bar,baz".split(",").  If the inputs are
symbols we cache the result and make the substrings into symbols.
Review URL: http://codereview.chromium.org/7782025
http://code.google.com/p/v8/source/detail?r=9164

Modified:
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/runtime.cc

=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Sep  5 03:35:31 2011
+++ /branches/bleeding_edge/src/heap.cc Wed Sep  7 04:28:48 2011
@@ -842,6 +842,7 @@
   isolate_->keyed_lookup_cache()->Clear();
   isolate_->context_slot_cache()->Clear();
   isolate_->descriptor_lookup_cache()->Clear();
+  StringSplitCache::Clear(string_split_cache());

   isolate_->compilation_cache()->MarkCompactPrologue();

@@ -2223,6 +2224,13 @@
   }
   set_single_character_string_cache(FixedArray::cast(obj));

+  // Allocate cache for string split.
+  { MaybeObject* maybe_obj =
+ AllocateFixedArray(StringSplitCache::kStringSplitCacheSize, TENURED);
+    if (!maybe_obj->ToObject(&obj)) return false;
+  }
+  set_string_split_cache(FixedArray::cast(obj));
+
   // Allocate cache for external strings pointing to native source code.
{ MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
     if (!maybe_obj->ToObject(&obj)) return false;
@@ -2246,6 +2254,75 @@

   return true;
 }
+
+
+Object* StringSplitCache::Lookup(
+    FixedArray* cache, String* string, String* pattern) {
+  if (!string->IsSymbol() || !pattern->IsSymbol()) return Smi::FromInt(0);
+  uintptr_t hash = string->Hash();
+  uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) &
+      ~(kArrayEntriesPerCacheEntry - 1));
+  if (cache->get(index + kStringOffset) == string &&
+      cache->get(index + kPatternOffset) == pattern) {
+    return cache->get(index + kArrayOffset);
+  }
+ index = ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
+  if (cache->get(index + kStringOffset) == string &&
+      cache->get(index + kPatternOffset) == pattern) {
+    return cache->get(index + kArrayOffset);
+  }
+  return Smi::FromInt(0);
+}
+
+
+void StringSplitCache::Enter(Heap* heap,
+                             FixedArray* cache,
+                             String* string,
+                             String* pattern,
+                             FixedArray* array) {
+  if (!string->IsSymbol() || !pattern->IsSymbol()) return;
+  uintptr_t hash = string->Hash();
+  array->set_map(heap->fixed_cow_array_map());
+  uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) &
+      ~(kArrayEntriesPerCacheEntry - 1));
+  if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
+    cache->set(index + kStringOffset, string);
+    cache->set(index + kPatternOffset, pattern);
+    cache->set(index + kArrayOffset, array);
+    return;
+  }
+  uintptr_t index2 =
+      ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
+  if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
+    cache->set(index2 + kStringOffset, string);
+    cache->set(index2 + kPatternOffset, pattern);
+    cache->set(index2 + kArrayOffset, array);
+    return;
+  }
+  cache->set(index2 + kStringOffset, Smi::FromInt(0));
+  cache->set(index2 + kPatternOffset, Smi::FromInt(0));
+  cache->set(index2 + kArrayOffset, Smi::FromInt(0));
+  cache->set(index + kStringOffset, string);
+  cache->set(index + kPatternOffset, pattern);
+  cache->set(index + kArrayOffset, array);
+ if (array->length() < 100) { // Limit how many new symbols we want to make.
+    for (int i = 0; i < array->length(); i++) {
+      String* str = String::cast(array->get(i));
+      Object* symbol;
+      MaybeObject* maybe_symbol = heap->LookupSymbol(str);
+      if (maybe_symbol->ToObject(&symbol)) {
+        array->set(i, symbol);
+      }
+    }
+  }
+}
+
+
+void StringSplitCache::Clear(FixedArray* cache) {
+  for (int i = 0; i < kStringSplitCacheSize; i++) {
+    cache->set(i, Smi::FromInt(0));
+  }
+}


 MaybeObject* Heap::InitializeNumberStringCache() {
=======================================
--- /branches/bleeding_edge/src/heap.h  Fri Sep  2 05:43:28 2011
+++ /branches/bleeding_edge/src/heap.h  Wed Sep  7 04:28:48 2011
@@ -77,6 +77,7 @@
V(Object, instanceof_cache_map, InstanceofCacheMap) \ V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \ V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \ + V(FixedArray, string_split_cache, StringSplitCache) \ V(Object, termination_exception, TerminationException) \ V(FixedArray, empty_fixed_array, EmptyFixedArray) \ V(ByteArray, empty_byte_array, EmptyByteArray) \
@@ -2176,6 +2177,27 @@
 };


+class StringSplitCache {
+ public:
+ static Object* Lookup(FixedArray* cache, String* string, String* pattern);
+  static void Enter(Heap* heap,
+                    FixedArray* cache,
+                    String* string,
+                    String* pattern,
+                    FixedArray* array);
+  static void Clear(FixedArray* cache);
+  static const int kStringSplitCacheSize = 0x100;
+
+ private:
+  static const int kArrayEntriesPerCacheEntry = 4;
+  static const int kStringOffset = 0;
+  static const int kPatternOffset = 1;
+  static const int kArrayOffset = 2;
+
+  static MaybeObject* WrapFixedArrayInJSArray(Object* fixed_array);
+};
+
+
 class TranscendentalCache {
  public:
   enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches};
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Mon Sep  5 00:30:35 2011
+++ /branches/bleeding_edge/src/runtime.cc      Wed Sep  7 04:28:48 2011
@@ -5984,6 +5984,19 @@
   int pattern_length = pattern->length();
   RUNTIME_ASSERT(pattern_length > 0);

+  if (limit == 0xffffffffu) {
+    Handle<Object> cached_answer(StringSplitCache::Lookup(
+        isolate->heap()->string_split_cache(),
+        *subject,
+        *pattern));
+    if (*cached_answer != Smi::FromInt(0)) {
+      Handle<JSArray> result =
+          isolate->factory()->NewJSArrayWithElements(
+              Handle<FixedArray>::cast(cached_answer));
+      return *result;
+    }
+  }
+
   // The limit can be very large (0xffffffffu), but since the pattern
   // isn't empty, we can never create more parts than ~half the length
   // of the subject.
@@ -6076,6 +6089,14 @@
     elements->set(i, *substring);
     part_start = part_end + pattern_length;
   }
+
+  if (limit == 0xffffffffu) {
+    StringSplitCache::Enter(isolate->heap(),
+                            isolate->heap()->string_split_cache(),
+                            *subject,
+                            *pattern,
+                            *elements);
+  }

   return *result;
 }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to