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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9164 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
765cf1f25e
commit
260d65d584
77
src/heap.cc
77
src/heap.cc
@ -842,6 +842,7 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
|
||||
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 @@ bool Heap::CreateInitialObjects() {
|
||||
}
|
||||
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;
|
||||
@ -2248,6 +2256,75 @@ bool Heap::CreateInitialObjects() {
|
||||
}
|
||||
|
||||
|
||||
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() {
|
||||
// Compute the size of the number string cache based on the max heap size.
|
||||
// max_semispace_size_ == 512 KB => number_string_cache_size = 32.
|
||||
|
22
src/heap.h
22
src/heap.h
@ -77,6 +77,7 @@ inline Heap* _inline_get_heap_();
|
||||
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 GCTracer BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
|
||||
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};
|
||||
|
@ -5984,6 +5984,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
|
||||
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.
|
||||
@ -6077,6 +6090,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
|
||||
part_start = part_end + pattern_length;
|
||||
}
|
||||
|
||||
if (limit == 0xffffffffu) {
|
||||
StringSplitCache::Enter(isolate->heap(),
|
||||
isolate->heap()->string_split_cache(),
|
||||
*subject,
|
||||
*pattern,
|
||||
*elements);
|
||||
}
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user