Add heuristic for flattening strings before comparing them.
authorvitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 16 Mar 2010 12:30:04 +0000 (12:30 +0000)
committervitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 16 Mar 2010 12:30:04 +0000 (12:30 +0000)
Also switched to using CompareChars instead of memcmp since it's
faster than gcc's builtin and on par with msvc's builtin.

Review URL: http://codereview.chromium.org/991002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4145 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/heap-inl.h
src/heap.cc
src/heap.h
src/runtime.cc

index f32f1e867e47a983a7d749a1cb7be85557c90805..c4676fd74cf83ac0a5f4191f812e3df2d0f5f90e 100644 (file)
@@ -274,6 +274,25 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
 }
 
 
+Object* Heap::PrepareForCompare(String* str) {
+  // Always flatten small strings and force flattening of long strings
+  // after we have accumulated a certain amount we failed to flatten.
+  static const int kMaxAlwaysFlattenLength = 32;
+  static const int kFlattenLongThreshold = 16*KB;
+
+  const int length = str->length();
+  Object* obj = str->TryFlatten();
+  if (length <= kMaxAlwaysFlattenLength ||
+      unflattended_strings_length_ >= kFlattenLongThreshold) {
+    return obj;
+  }
+  if (obj->IsFailure()) {
+    unflattended_strings_length_ += length;
+  }
+  return str;
+}
+
+
 int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
   ASSERT(HasBeenSetup());
   int amount = amount_of_external_allocated_memory_ + change_in_bytes;
index 08a5db8ed6e9a92a96972c113c816c079b5c363e..b477b45e07b3340f729d1275445407fc7edbd4d7 100644 (file)
@@ -114,6 +114,8 @@ Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
 int Heap::mc_count_ = 0;
 int Heap::gc_count_ = 0;
 
+int Heap::unflattended_strings_length_ = 0;
+
 int Heap::always_allocate_scope_depth_ = 0;
 int Heap::linear_allocation_scope_depth_ = 0;
 int Heap::contexts_disposed_ = 0;
@@ -302,6 +304,7 @@ void Heap::ReportStatisticsAfterGC() {
 void Heap::GarbageCollectionPrologue() {
   TranscendentalCache::Clear();
   gc_count_++;
+  unflattended_strings_length_ = 0;
 #ifdef DEBUG
   ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
   allow_allocation(false);
index 1bcd4218ceadf15aeb7105293e30d49eb2f5fcf6..18ab44bf878b2842cbcb242b15d14d08ded8b6e8 100644 (file)
@@ -634,6 +634,15 @@ class Heap : public AllStatic {
   // NULL is returned if string is in new space or not flattened.
   static Map* SymbolMapForString(String* str);
 
+  // Tries to flatten a string before compare operation.
+  //
+  // Returns a failure in case it was decided that flattening was
+  // necessary and failed.  Note, if flattening is not necessary the
+  // string might stay non-flat even when not a failure is returned.
+  //
+  // Please note this function does not perform a garbage collection.
+  static inline Object* PrepareForCompare(String* str);
+
   // Converts the given boolean condition to JavaScript boolean value.
   static Object* ToBoolean(bool condition) {
     return condition ? true_value() : false_value();
@@ -955,6 +964,9 @@ class Heap : public AllStatic {
   static int mc_count_;  // how many mark-compact collections happened
   static int gc_count_;  // how many gc happened
 
+  // Total length of the strings we failed to flatten since the last GC.
+  static int unflattended_strings_length_;
+
 #define ROOT_ACCESSOR(type, name, camel_name)                                  \
   static inline void set_##name(type* value) {                                 \
     roots_[k##camel_name##RootIndex] = value;                                  \
index c425e312358e15400683d48a69f09426565d6d96..4e4856dd80ad71cb94532a74815a4b6946b7760d 100644 (file)
@@ -5073,7 +5073,7 @@ static Object* FlatStringCompare(String* x, String* y) {
     Vector<const char> x_chars = x->ToAsciiVector();
     if (y->IsAsciiRepresentation()) {
       Vector<const char> y_chars = y->ToAsciiVector();
-      r = memcmp(x_chars.start(), y_chars.start(), prefix_length);
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
     } else {
       Vector<const uc16> y_chars = y->ToUC16Vector();
       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
@@ -5121,8 +5121,10 @@ static Object* Runtime_StringCompare(Arguments args) {
   if (d < 0) return Smi::FromInt(LESS);
   else if (d > 0) return Smi::FromInt(GREATER);
 
-  x->TryFlatten();
-  y->TryFlatten();
+  Object* obj = Heap::PrepareForCompare(x);
+  if (obj->IsFailure()) return obj;
+  obj = Heap::PrepareForCompare(y);
+  if (obj->IsFailure()) return obj;
 
   return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
                                       : StringInputBufferCompare(x, y);