- Specialized slow-case string equality nine ways based on the
authorchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 9 Oct 2008 08:08:04 +0000 (08:08 +0000)
committerchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 9 Oct 2008 08:08:04 +0000 (08:08 +0000)
  underlying string representation of the two strings involved.
- Renamed ascii and two byte string classes to sequential ascii and
  sequential two byte, and renamed IsAscii and friends to
  IsAsciiRepresentation.  This is to make a clear distinction between
  strings with an ascii/two-byte representation, of which there is
  four, and flat sequential ascii/two-byte string.

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

src/bootstrapper.cc
src/codegen-ia32.cc
src/heap.cc
src/jsregexp.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime.cc
test/cctest/test-heap.cc

index 925c8ff..958f917 100644 (file)
@@ -63,7 +63,7 @@ class SourceCodeCache BASE_EMBEDDED {
 
   bool Lookup(Vector<const char> name, Handle<JSFunction>* handle) {
     for (int i = 0; i < cache_->length(); i+=2) {
-      AsciiString* str = AsciiString::cast(cache_->get(i));
+      SeqAsciiString* str = SeqAsciiString::cast(cache_->get(i));
       if (str->IsEqualTo(name)) {
         *handle = Handle<JSFunction>(JSFunction::cast(cache_->get(i + 1)));
         return true;
@@ -751,7 +751,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
   // function and insert it into the cache.
   if (!cache->Lookup(name, &boilerplate)) {
 #ifdef DEBUG
-    ASSERT(source->IsAscii());
+    ASSERT(source->IsAsciiRepresentation());
 #endif
     Handle<String> script_name = Factory::NewStringFromUtf8(name);
     boilerplate =
index 7ff966b..b3b206f 100644 (file)
@@ -3156,13 +3156,14 @@ void Ia32CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
 
   // 2-byte string.
   // Load the 2-byte character code.
-  __ movzx_w(eax, FieldOperand(eax, ebx, times_2, TwoByteString::kHeaderSize));
+  __ movzx_w(eax,
+             FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
   __ jmp(&got_char_code);
 
   // ASCII string.
   __ bind(&ascii_string);
   // Load the byte.
-  __ movzx_b(eax, FieldOperand(eax, ebx, times_1, AsciiString::kHeaderSize));
+  __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
 
   __ bind(&got_char_code);
   ASSERT(kSmiTag == 0);
index c2bef29..c022576 100644 (file)
@@ -931,32 +931,32 @@ bool Heap::CreateInitialMaps() {
   STRING_TYPE_LIST(ALLOCATE_STRING_MAP);
 #undef ALLOCATE_STRING_MAP
 
-  obj = AllocateMap(SHORT_STRING_TYPE, TwoByteString::kHeaderSize);
+  obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kHeaderSize);
   if (obj->IsFailure()) return false;
   undetectable_short_string_map_ = Map::cast(obj);
   undetectable_short_string_map_->set_is_undetectable();
 
-  obj = AllocateMap(MEDIUM_STRING_TYPE, TwoByteString::kHeaderSize);
+  obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kHeaderSize);
   if (obj->IsFailure()) return false;
   undetectable_medium_string_map_ = Map::cast(obj);
   undetectable_medium_string_map_->set_is_undetectable();
 
-  obj = AllocateMap(LONG_STRING_TYPE, TwoByteString::kHeaderSize);
+  obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kHeaderSize);
   if (obj->IsFailure()) return false;
   undetectable_long_string_map_ = Map::cast(obj);
   undetectable_long_string_map_->set_is_undetectable();
 
-  obj = AllocateMap(SHORT_ASCII_STRING_TYPE, AsciiString::kHeaderSize);
+  obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
   if (obj->IsFailure()) return false;
   undetectable_short_ascii_string_map_ = Map::cast(obj);
   undetectable_short_ascii_string_map_->set_is_undetectable();
 
-  obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, AsciiString::kHeaderSize);
+  obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
   if (obj->IsFailure()) return false;
   undetectable_medium_ascii_string_map_ = Map::cast(obj);
   undetectable_medium_ascii_string_map_->set_is_undetectable();
 
-  obj = AllocateMap(LONG_ASCII_STRING_TYPE, AsciiString::kHeaderSize);
+  obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
   if (obj->IsFailure()) return false;
   undetectable_long_ascii_string_map_ = Map::cast(obj);
   undetectable_long_ascii_string_map_->set_is_undetectable();
@@ -1328,7 +1328,8 @@ Object* Heap::AllocateSharedFunctionInfo(Object* name) {
 
 Object* Heap::AllocateConsString(String* first, String* second) {
   int length = first->length() + second->length();
-  bool is_ascii = first->is_ascii() && second->is_ascii();
+  bool is_ascii = first->is_ascii_representation()
+      && second->is_ascii_representation();
 
   // If the resulting string is small make a flat string.
   if (length < ConsString::kMinLength) {
@@ -1385,13 +1386,13 @@ Object* Heap::AllocateSlicedString(String* buffer, int start, int end) {
 
   Map* map;
   if (length <= String::kMaxShortStringSize) {
-    map = buffer->is_ascii() ? short_sliced_ascii_string_map()
+    map = buffer->is_ascii_representation() ? short_sliced_ascii_string_map()
       : short_sliced_string_map();
   } else if (length <= String::kMaxMediumStringSize) {
-    map = buffer->is_ascii() ? medium_sliced_ascii_string_map()
+    map = buffer->is_ascii_representation() ? medium_sliced_ascii_string_map()
       : medium_sliced_string_map();
   } else {
-    map = buffer->is_ascii() ? long_sliced_ascii_string_map()
+    map = buffer->is_ascii_representation() ? long_sliced_ascii_string_map()
       : long_sliced_string_map();
   }
 
@@ -1417,7 +1418,7 @@ Object* Heap::AllocateSubString(String* buffer, int start, int end) {
   // Make an attempt to flatten the buffer to reduce access time.
   buffer->TryFlatten();
 
-  Object* result = buffer->is_ascii()
+  Object* result = buffer->is_ascii_representation()
       ? AllocateRawAsciiString(length)
       : AllocateRawTwoByteString(length);
   if (result->IsFailure()) return result;
@@ -1768,9 +1769,9 @@ Object* Heap::AllocateStringFromAscii(Vector<const char> string,
   if (result->IsFailure()) return result;
 
   // Copy the characters into the new object.
-  AsciiString* string_result = AsciiString::cast(result);
+  SeqAsciiString* string_result = SeqAsciiString::cast(result);
   for (int i = 0; i < string.length(); i++) {
-    string_result->AsciiStringSet(i, string[i]);
+    string_result->SeqAsciiStringSet(i, string[i]);
   }
   return result;
 }
@@ -1918,7 +1919,7 @@ Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
     } else {
       map = long_ascii_symbol_map();
     }
-    size = AsciiString::SizeFor(chars);
+    size = SeqAsciiString::SizeFor(chars);
   } else {
     if (chars <= String::kMaxShortStringSize) {
       map = short_symbol_map();
@@ -1927,7 +1928,7 @@ Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
     } else {
       map = long_symbol_map();
     }
-    size = TwoByteString::SizeFor(chars);
+    size = SeqTwoByteString::SizeFor(chars);
   }
 
   // Allocate string.
@@ -1952,7 +1953,7 @@ Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
 
 Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
   AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
-  int size = AsciiString::SizeFor(length);
+  int size = SeqAsciiString::SizeFor(length);
   if (size > MaxHeapObjectSize()) {
     space = LO_SPACE;
   }
@@ -1982,7 +1983,7 @@ Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
 
 Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
   AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
-  int size = TwoByteString::SizeFor(length);
+  int size = SeqTwoByteString::SizeFor(length);
   if (size > MaxHeapObjectSize()) {
     space = LO_SPACE;
   }
index bce9805..80cbe29 100644 (file)
@@ -128,7 +128,7 @@ Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
   ASSERT(!flat_string->IsConsString());
   ASSERT(flat_string->IsSeqString() || flat_string->IsSlicedString() ||
          flat_string->IsExternalString());
-  if (!flat_string->IsAscii()) {
+  if (!flat_string->IsAsciiRepresentation()) {
     return flat_string;
   }
 
index dda4dbb..c8bd70a 100644 (file)
@@ -119,13 +119,25 @@ bool Object::IsSeqString() {
 }
 
 
-bool Object::IsAsciiString() {
-  return IsString() && (String::cast(this)->is_ascii());
+bool Object::IsSeqAsciiString() {
+  return IsSeqString()
+      && String::cast(this)->IsAsciiRepresentation();
 }
 
 
-bool Object::IsTwoByteString() {
-  return IsString() && (!String::cast(this)->is_ascii());
+bool Object::IsSeqTwoByteString() {
+  return IsSeqString()
+      && !String::cast(this)->IsAsciiRepresentation();
+}
+
+
+bool Object::IsAsciiStringRepresentation() {
+  return IsString() && (String::cast(this)->is_ascii_representation());
+}
+
+
+bool Object::IsTwoByteStringRepresentation() {
+  return IsString() && (!String::cast(this)->is_ascii_representation());
 }
 
 
@@ -148,12 +160,12 @@ bool Object::IsExternalString() {
 
 
 bool Object::IsExternalAsciiString() {
-  return IsExternalString() && (String::cast(this)->is_ascii());
+  return IsExternalString() && (String::cast(this)->is_ascii_representation());
 }
 
 
 bool Object::IsExternalTwoByteString() {
-  return IsExternalString() && (!String::cast(this)->is_ascii());
+  return IsExternalString() && (!String::cast(this)->is_ascii_representation());
 }
 
 
@@ -1126,8 +1138,8 @@ CAST_ACCESSOR(CompilationCacheTable)
 CAST_ACCESSOR(MapCache)
 CAST_ACCESSOR(String)
 CAST_ACCESSOR(SeqString)
-CAST_ACCESSOR(AsciiString)
-CAST_ACCESSOR(TwoByteString)
+CAST_ACCESSOR(SeqAsciiString)
+CAST_ACCESSOR(SeqTwoByteString)
 CAST_ACCESSOR(ConsString)
 CAST_ACCESSOR(SlicedString)
 CAST_ACCESSOR(ExternalString)
@@ -1234,15 +1246,15 @@ uint16_t String::Get(int index) {
   ASSERT(index >= 0 && index < length());
   switch (representation_tag()) {
     case kSeqStringTag:
-      return is_ascii()
-        ? AsciiString::cast(this)->AsciiStringGet(index)
-        : TwoByteString::cast(this)->TwoByteStringGet(index);
+      return is_ascii_representation()
+        ? SeqAsciiString::cast(this)->SeqAsciiStringGet(index)
+        : SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index);
     case kConsStringTag:
       return ConsString::cast(this)->ConsStringGet(index);
     case kSlicedStringTag:
       return SlicedString::cast(this)->SlicedStringGet(index);
     case kExternalStringTag:
-      return is_ascii()
+      return is_ascii_representation()
         ? ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index)
         : ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index);
     default:
@@ -1258,14 +1270,14 @@ void String::Set(int index, uint16_t value) {
   ASSERT(index >= 0 && index < length());
   ASSERT(IsSeqString());
 
-  return is_ascii()
-      ? AsciiString::cast(this)->AsciiStringSet(index, value)
-      : TwoByteString::cast(this)->TwoByteStringSet(index, value);
+  return is_ascii_representation()
+      ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
+      : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
 }
 
 
-bool String::IsAscii() {
-  return is_ascii();
+bool String::IsAsciiRepresentation() {
+  return is_ascii_representation();
 }
 
 
@@ -1299,12 +1311,12 @@ bool String::is_symbol_map(Map* map) {
 }
 
 
-bool String::is_ascii() {
-  return is_ascii_map(map());
+bool String::is_ascii_representation() {
+  return is_ascii_representation_map(map());
 }
 
 
-bool String::is_ascii_map(Map* map) {
+bool String::is_ascii_representation_map(Map* map) {
   return (map->instance_type() & kStringEncodingMask) != 0;
 }
 
@@ -1336,42 +1348,42 @@ bool String::IsFlat() {
 }
 
 
-uint16_t AsciiString::AsciiStringGet(int index) {
+uint16_t SeqAsciiString::SeqAsciiStringGet(int index) {
   ASSERT(index >= 0 && index < length());
   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
 }
 
 
-void AsciiString::AsciiStringSet(int index, uint16_t value) {
+void SeqAsciiString::SeqAsciiStringSet(int index, uint16_t value) {
   ASSERT(index >= 0 && index < length() && value <= kMaxAsciiCharCode);
   WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize,
                    static_cast<byte>(value));
 }
 
 
-Address AsciiString::GetCharsAddress() {
+Address SeqAsciiString::GetCharsAddress() {
   return FIELD_ADDR(this, kHeaderSize);
 }
 
 
-Address TwoByteString::GetCharsAddress() {
+Address SeqTwoByteString::GetCharsAddress() {
   return FIELD_ADDR(this, kHeaderSize);
 }
 
 
-uint16_t TwoByteString::TwoByteStringGet(int index) {
+uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) {
   ASSERT(index >= 0 && index < length());
   return READ_SHORT_FIELD(this, kHeaderSize + index * kShortSize);
 }
 
 
-void TwoByteString::TwoByteStringSet(int index, uint16_t value) {
+void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
   ASSERT(index >= 0 && index < length());
   WRITE_SHORT_FIELD(this, kHeaderSize + index * kShortSize, value);
 }
 
 
-int TwoByteString::TwoByteStringSize(Map* map) {
+int SeqTwoByteString::SeqTwoByteStringSize(Map* map) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   // Use the map (and not 'this') to compute the size tag, since
@@ -1393,7 +1405,7 @@ int TwoByteString::TwoByteStringSize(Map* map) {
 }
 
 
-int AsciiString::AsciiStringSize(Map* map) {
+int SeqAsciiString::SeqAsciiStringSize(Map* map) {
   uint32_t length = READ_INT_FIELD(this, kLengthOffset);
 
   // Use the map (and not 'this') to compute the size tag, since
index c5399fa..25c8102 100644 (file)
@@ -522,7 +522,7 @@ Object* String::Flatten() {
       // an old space GC.
       PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
       int len = length();
-      Object* object = IsAscii() ?
+      Object* object = IsAsciiRepresentation() ?
           Heap::AllocateRawAsciiString(len, tenure) :
           Heap::AllocateRawTwoByteString(len, tenure);
       if (object->IsFailure()) return object;
@@ -755,10 +755,11 @@ int HeapObject::SlowSizeFromMap(Map* map) {
   if (instance_type < FIRST_NONSTRING_TYPE
       && (reinterpret_cast<String*>(this)->map_representation_tag(map)
           == kSeqStringTag)) {
-    if (reinterpret_cast<String*>(this)->is_ascii_map(map)) {
-      return reinterpret_cast<AsciiString*>(this)->AsciiStringSize(map);
+    if (reinterpret_cast<String*>(this)->is_ascii_representation_map(map)) {
+      return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(map);
     } else {
-      return reinterpret_cast<TwoByteString*>(this)->TwoByteStringSize(map);
+      SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
+      return self->SeqTwoByteStringSize(map);
     }
   }
 
@@ -2970,7 +2971,7 @@ bool String::LooksValid() {
 
 
 int String::Utf8Length() {
-  if (is_ascii()) return length();
+  if (is_ascii_representation()) return length();
   // Attempt to flatten before accessing the string.  It probably
   // doesn't make Utf8Length faster, but it is very likely that
   // the string will be accessed later (for example by WriteUtf8)
@@ -2985,6 +2986,69 @@ int String::Utf8Length() {
 }
 
 
+Vector<const char> String::ToAsciiVector() {
+  ASSERT(IsAsciiRepresentation());
+  ASSERT(IsFlat());
+
+  int offset = 0;
+  int length = this->length();
+  StringRepresentationTag string_tag = representation_tag();
+  String* string = this;
+  if (string_tag == kSlicedStringTag) {
+      SlicedString* sliced = SlicedString::cast(string);
+      offset += sliced->start();
+      string = String::cast(sliced->buffer());
+      string_tag = string->representation_tag();
+  } else if (string_tag == kConsStringTag) {
+      ConsString* cons = ConsString::cast(string);
+      ASSERT(String::cast(cons->second())->length() == 0);
+      string = String::cast(cons->first());
+      string_tag = string->representation_tag();
+  }
+  if (string_tag == kSeqStringTag) {
+    SeqAsciiString* seq = SeqAsciiString::cast(string);
+    char* start = reinterpret_cast<char*>(seq->GetCharsAddress());
+    return Vector<const char>(start + offset, length);
+  }
+  ASSERT(string_tag == kExternalStringTag);
+  ExternalAsciiString* ext = ExternalAsciiString::cast(string);
+  const char* start = ext->resource()->data();
+  return Vector<const char>(start + offset, length);
+}
+
+
+Vector<const uc16> String::ToUC16Vector() {
+  ASSERT(IsTwoByteStringRepresentation());
+  ASSERT(IsFlat());
+
+  int offset = 0;
+  int length = this->length();
+  StringRepresentationTag string_tag = representation_tag();
+  String* string = this;
+  if (string_tag == kSlicedStringTag) {
+      SlicedString* sliced = SlicedString::cast(string);
+      offset += sliced->start();
+      string = String::cast(sliced->buffer());
+      string_tag = string->representation_tag();
+  } else if (string_tag == kConsStringTag) {
+      ConsString* cons = ConsString::cast(string);
+      ASSERT(String::cast(cons->second())->length() == 0);
+      string = String::cast(cons->first());
+      string_tag = string->representation_tag();
+  }
+  if (string_tag == kSeqStringTag) {
+    SeqTwoByteString* seq = SeqTwoByteString::cast(string);
+    uc16* start = reinterpret_cast<uc16*>(seq->GetCharsAddress());
+    return Vector<const uc16>(start + offset, length);
+  }
+  ASSERT(string_tag == kExternalStringTag);
+  ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
+  const uc16* start =
+      reinterpret_cast<const uc16*>(ext->resource()->data());
+  return Vector<const uc16>(start + offset, length);
+}
+
+
 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
                                      RobustnessFlag robust_flag,
                                      int offset,
@@ -3051,10 +3115,10 @@ const uc16* String::GetTwoByteData() {
 
 
 const uc16* String::GetTwoByteData(unsigned start) {
-  ASSERT(!IsAscii());
+  ASSERT(!IsAsciiRepresentation());
   switch (representation_tag()) {
     case kSeqStringTag:
-      return TwoByteString::cast(this)->TwoByteStringGetData(start);
+      return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
     case kExternalStringTag:
       return ExternalTwoByteString::cast(this)->
         ExternalTwoByteStringGetData(start);
@@ -3100,13 +3164,13 @@ SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
 }
 
 
-const uc16* TwoByteString::TwoByteStringGetData(unsigned start) {
+const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
   return reinterpret_cast<uc16*>(
       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
 }
 
 
-void TwoByteString::TwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
+void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
                                                      unsigned* offset_ptr,
                                                      unsigned max_chars) {
   unsigned chars_read = 0;
@@ -3139,9 +3203,10 @@ void TwoByteString::TwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
 }
 
 
-const unibrow::byte* AsciiString::AsciiStringReadBlock(unsigned* remaining,
-                                                       unsigned* offset_ptr,
-                                                       unsigned max_chars) {
+const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
+    unsigned* remaining,
+    unsigned* offset_ptr,
+    unsigned max_chars) {
   // Cast const char* to unibrow::byte* (signedness difference).
   const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
       kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
@@ -3301,7 +3366,7 @@ void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
 }
 
 
-void AsciiString::AsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
+void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
                                                  unsigned* offset_ptr,
                                                  unsigned max_chars) {
   unsigned capacity = rbb->capacity - rbb->cursor;
@@ -3346,14 +3411,16 @@ const unibrow::byte* String::ReadBlock(String* input,
   }
   switch (input->representation_tag()) {
     case kSeqStringTag:
-      if (input->is_ascii()) {
-        return AsciiString::cast(input)->AsciiStringReadBlock(&rbb->remaining,
-                                                              offset_ptr,
-                                                              max_chars);
+      if (input->is_ascii_representation()) {
+        SeqAsciiString* str = SeqAsciiString::cast(input);
+        return str->SeqAsciiStringReadBlock(&rbb->remaining,
+                                            offset_ptr,
+                                            max_chars);
       } else {
-        TwoByteString::cast(input)->TwoByteStringReadBlockIntoBuffer(rbb,
-                                                                     offset_ptr,
-                                                                     max_chars);
+        SeqTwoByteString* str = SeqTwoByteString::cast(input);
+        str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
+                                                 offset_ptr,
+                                                 max_chars);
         return rbb->util_buffer;
       }
     case kConsStringTag:
@@ -3365,7 +3432,7 @@ const unibrow::byte* String::ReadBlock(String* input,
                                                               offset_ptr,
                                                               max_chars);
     case kExternalStringTag:
-      if (input->is_ascii()) {
+      if (input->is_ascii_representation()) {
         return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
             &rbb->remaining,
             offset_ptr,
@@ -3409,13 +3476,13 @@ void String::ReadBlockIntoBuffer(String* input,
 
   switch (input->representation_tag()) {
     case kSeqStringTag:
-      if (input->is_ascii()) {
-        AsciiString::cast(input)->AsciiStringReadBlockIntoBuffer(rbb,
+      if (input->is_ascii_representation()) {
+        SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
                                                                  offset_ptr,
                                                                  max_chars);
         return;
       } else {
-        TwoByteString::cast(input)->TwoByteStringReadBlockIntoBuffer(rbb,
+        SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
                                                                      offset_ptr,
                                                                      max_chars);
         return;
@@ -3431,7 +3498,7 @@ void String::ReadBlockIntoBuffer(String* input,
                                                                  max_chars);
       return;
     case kExternalStringTag:
-      if (input->is_ascii()) {
+      if (input->is_ascii_representation()) {
          ExternalAsciiString::cast(input)->
              ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
        } else {
@@ -3688,6 +3755,43 @@ uint16_t SlicedString::SlicedStringGet(int index) {
 }
 
 
+template <typename IteratorA, typename IteratorB>
+static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
+  // General slow case check.  We know that the ia and ib iterators
+  // have the same length.
+  while (ia->has_more()) {
+    uc32 ca = ia->GetNext();
+    uc32 cb = ib->GetNext();
+    if (ca != cb)
+      return false;
+  }
+  return true;
+}
+
+
+static StringInputBuffer string_compare_buffer_b;
+
+
+template <typename IteratorA>
+static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
+  if (b->IsFlat()) {
+    if (b->IsAsciiRepresentation()) {
+      VectorIterator<const char> ib(b->ToAsciiVector());
+      return CompareStringContents(ia, &ib);
+    } else {
+      VectorIterator<const uc16> ib(b->ToUC16Vector());
+      return CompareStringContents(ia, &ib);
+    }
+  } else {
+    string_compare_buffer_b.Reset(0, b);
+    return CompareStringContents(ia, &string_compare_buffer_b);
+  }
+}
+
+
+static StringInputBuffer string_compare_buffer_a;
+
+
 bool String::SlowEquals(String* other) {
   // Fast check: negative check with lengths.
   int len = length();
@@ -3700,24 +3804,18 @@ bool String::SlowEquals(String* other) {
     if (Hash() != other->Hash()) return false;
   }
 
-  // Fast case: avoid input buffers for small strings.
-  const int kMaxLenthForFastCaseCheck = 5;
-  for (int i = 0; i < kMaxLenthForFastCaseCheck; i++) {
-    if (Get(i) != other->Get(i)) return false;
-    if (i + 1 == len) return true;
-  }
-
-  // General slow case check.
-  static StringInputBuffer buf1;
-  static StringInputBuffer buf2;
-  buf1.Reset(kMaxLenthForFastCaseCheck, this);
-  buf2.Reset(kMaxLenthForFastCaseCheck, other);
-  while (buf1.has_more()) {
-    if (buf1.GetNext() != buf2.GetNext()) {
-      return false;
+  if (this->IsFlat()) {
+    if (this->IsAsciiRepresentation()) {
+      VectorIterator<const char> buf1(this->ToAsciiVector());
+      return CompareStringContentsPartial(&buf1, other);
+    } else {
+      VectorIterator<const uc16> buf1(this->ToUC16Vector());
+      return CompareStringContentsPartial(&buf1, other);
     }
+  } else {
+    string_compare_buffer_a.Reset(0, this);
+    return CompareStringContentsPartial(&string_compare_buffer_a, other);
   }
-  return true;
 }
 
 
index d21ad65..d1da915 100644 (file)
@@ -61,8 +61,8 @@
 //           - GlobalContext
 //       - String
 //         - SeqString
-//           - AsciiString
-//           - TwoByteString
+//           - SeqAsciiString
+//           - SeqTwoByteString
 //         - ConsString
 //         - SlicedString
 //         - ExternalString
@@ -272,12 +272,12 @@ class PropertyDetails BASE_EMBEDDED {
 // Since string types are not consecutive, this macro is used to
 // iterate over them.
 #define STRING_TYPE_LIST(V)                                                    \
-  V(SHORT_SYMBOL_TYPE, TwoByteString::kHeaderSize, short_symbol)               \
-  V(MEDIUM_SYMBOL_TYPE, TwoByteString::kHeaderSize, medium_symbol)             \
-  V(LONG_SYMBOL_TYPE, TwoByteString::kHeaderSize, long_symbol)                 \
-  V(SHORT_ASCII_SYMBOL_TYPE, AsciiString::kHeaderSize, short_ascii_symbol)     \
-  V(MEDIUM_ASCII_SYMBOL_TYPE, AsciiString::kHeaderSize, medium_ascii_symbol)   \
-  V(LONG_ASCII_SYMBOL_TYPE, AsciiString::kHeaderSize, long_ascii_symbol)       \
+  V(SHORT_SYMBOL_TYPE, SeqTwoByteString::kHeaderSize, short_symbol)            \
+  V(MEDIUM_SYMBOL_TYPE, SeqTwoByteString::kHeaderSize, medium_symbol)          \
+  V(LONG_SYMBOL_TYPE, SeqTwoByteString::kHeaderSize, long_symbol)              \
+  V(SHORT_ASCII_SYMBOL_TYPE, SeqAsciiString::kHeaderSize, short_ascii_symbol)  \
+  V(MEDIUM_ASCII_SYMBOL_TYPE, SeqAsciiString::kHeaderSize, medium_ascii_symbol)\
+  V(LONG_ASCII_SYMBOL_TYPE, SeqAsciiString::kHeaderSize, long_ascii_symbol)    \
   V(SHORT_CONS_SYMBOL_TYPE, ConsString::kSize, short_cons_symbol)              \
   V(MEDIUM_CONS_SYMBOL_TYPE, ConsString::kSize, medium_cons_symbol)            \
   V(LONG_CONS_SYMBOL_TYPE, ConsString::kSize, long_cons_symbol)                \
@@ -314,12 +314,12 @@ class PropertyDetails BASE_EMBEDDED {
   V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE,                                           \
     ExternalAsciiString::kSize,                                                \
     long_external_ascii_symbol)                                                \
-  V(SHORT_STRING_TYPE, TwoByteString::kHeaderSize, short_string)               \
-  V(MEDIUM_STRING_TYPE, TwoByteString::kHeaderSize, medium_string)             \
-  V(LONG_STRING_TYPE, TwoByteString::kHeaderSize, long_string)                 \
-  V(SHORT_ASCII_STRING_TYPE, AsciiString::kHeaderSize, short_ascii_string)     \
-  V(MEDIUM_ASCII_STRING_TYPE, AsciiString::kHeaderSize, medium_ascii_string)   \
-  V(LONG_ASCII_STRING_TYPE, AsciiString::kHeaderSize, long_ascii_string)       \
+  V(SHORT_STRING_TYPE, SeqTwoByteString::kHeaderSize, short_string)            \
+  V(MEDIUM_STRING_TYPE, SeqTwoByteString::kHeaderSize, medium_string)          \
+  V(LONG_STRING_TYPE, SeqTwoByteString::kHeaderSize, long_string)              \
+  V(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize, short_ascii_string)  \
+  V(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize, medium_ascii_string)\
+  V(LONG_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize, long_ascii_string)    \
   V(SHORT_CONS_STRING_TYPE, ConsString::kSize, short_cons_string)              \
   V(MEDIUM_CONS_STRING_TYPE, ConsString::kSize, medium_cons_string)            \
   V(LONG_CONS_STRING_TYPE, ConsString::kSize, long_cons_string)                \
@@ -584,8 +584,10 @@ class Object BASE_EMBEDDED {
   inline bool IsHeapNumber();
   inline bool IsString();
   inline bool IsSeqString();
-  inline bool IsAsciiString();
-  inline bool IsTwoByteString();
+  inline bool IsAsciiStringRepresentation();
+  inline bool IsTwoByteStringRepresentation();
+  inline bool IsSeqAsciiString();
+  inline bool IsSeqTwoByteString();
   inline bool IsConsString();
   inline bool IsSlicedString();
   inline bool IsExternalString();
@@ -2928,13 +2930,16 @@ class String: public HeapObject {
   inline void TryFlatten();
 
   // Is this string an ascii string.
-  inline bool IsAscii();
+  inline bool IsAsciiRepresentation();
 
   // Fast testing routines that assume the receiver is a string and
   // just check whether it is a certain kind of string.
   inline bool StringIsSlicedString();
   inline bool StringIsConsString();
 
+  Vector<const char> ToAsciiVector();
+  Vector<const uc16> ToUC16Vector();
+
   // Mark the string as an undetectable object. It only applies to
   // ascii and two byte string types.
   bool MarkAsUndetectable();
@@ -3005,8 +3010,8 @@ class String: public HeapObject {
   static inline bool is_symbol_map(Map* map);
 
   // True if the string is ASCII.
-  inline bool is_ascii();
-  static inline bool is_ascii_map(Map* map);
+  inline bool is_ascii_representation();
+  static inline bool is_ascii_representation_map(Map* map);
 
   // Get the representation tag.
   inline StringRepresentationTag representation_tag();
@@ -3145,22 +3150,22 @@ class SeqString: public String {
 
 // The AsciiString class captures sequential ascii string objects.
 // Each character in the AsciiString is an ascii character.
-class AsciiString: public SeqString {
+class SeqAsciiString: public SeqString {
  public:
   // Dispatched behavior.
-  inline uint16_t AsciiStringGet(int index);
-  inline void AsciiStringSet(int index, uint16_t value);
+  inline uint16_t SeqAsciiStringGet(int index);
+  inline void SeqAsciiStringSet(int index, uint16_t value);
 
   // Get the address of the characters in this string.
   inline Address GetCharsAddress();
 
   // Casting
-  static inline AsciiString* cast(Object* obj);
+  static inline SeqAsciiString* cast(Object* obj);
 
   // Garbage collection support.  This method is called by the
   // garbage collector to compute the actual size of an AsciiString
   // instance.
-  inline int AsciiStringSize(Map* map);
+  inline int SeqAsciiStringSize(Map* map);
 
   // Computes the size for an AsciiString instance of a given length.
   static int SizeFor(int length) {
@@ -3171,39 +3176,39 @@ class AsciiString: public SeqString {
   static const int kHeaderSize = String::kSize;
 
   // Support for StringInputBuffer.
-  inline void AsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
-                                             unsigned* offset,
-                                             unsigned chars);
-  inline const unibrow::byte* AsciiStringReadBlock(unsigned* remaining,
-                                                   unsigned* offset,
-                                                   unsigned chars);
+  inline void SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                                unsigned* offset,
+                                                unsigned chars);
+  inline const unibrow::byte* SeqAsciiStringReadBlock(unsigned* remaining,
+                                                      unsigned* offset,
+                                                      unsigned chars);
 
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(AsciiString);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SeqAsciiString);
 };
 
 
 // The TwoByteString class captures sequential unicode string objects.
 // Each character in the TwoByteString is a two-byte uint16_t.
-class TwoByteString: public SeqString {
+class SeqTwoByteString: public SeqString {
  public:
   // Dispatched behavior.
-  inline uint16_t TwoByteStringGet(int index);
-  inline void TwoByteStringSet(int index, uint16_t value);
+  inline uint16_t SeqTwoByteStringGet(int index);
+  inline void SeqTwoByteStringSet(int index, uint16_t value);
 
   // Get the address of the characters in this string.
   inline Address GetCharsAddress();
 
   // For regexp code.
-  const uint16_t* TwoByteStringGetData(unsigned start);
+  const uint16_t* SeqTwoByteStringGetData(unsigned start);
 
   // Casting
-  static inline TwoByteString* cast(Object* obj);
+  static inline SeqTwoByteString* cast(Object* obj);
 
   // Garbage collection support.  This method is called by the
   // garbage collector to compute the actual size of a TwoByteString
   // instance.
-  inline int TwoByteStringSize(Map* map);
+  inline int SeqTwoByteStringSize(Map* map);
 
   // Computes the size for a TwoByteString instance of a given length.
   static int SizeFor(int length) {
@@ -3214,12 +3219,12 @@ class TwoByteString: public SeqString {
   static const int kHeaderSize = String::kSize;
 
   // Support for StringInputBuffer.
-  inline void TwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
-                                               unsigned* offset_ptr,
-                                               unsigned chars);
+  inline void SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                                  unsigned* offset_ptr,
+                                                  unsigned chars);
 
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(TwoByteString);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SeqTwoByteString);
 };
 
 
@@ -3431,6 +3436,19 @@ class SafeStringInputBuffer
 };
 
 
+template <typename T>
+class VectorIterator {
+ public:
+  VectorIterator(T* d, int l) : data_(Vector<T>(d, l)), index_(0) { }
+  explicit VectorIterator(Vector<T> data) : data_(data), index_(0) { }
+  T GetNext() { return data_[index_++]; }
+  bool has_more() { return index_ < data_.length(); }
+ private:
+  Vector<T> data_;
+  int index_;
+};
+
+
 // The Oddball describes objects null, undefined, true, and false.
 class Oddball: public HeapObject {
  public:
index 4fe5fe8..a10e330 100644 (file)
@@ -952,68 +952,6 @@ static Object* Runtime_CharFromCode(Arguments args) {
 }
 
 
-static Vector<const char> ToAsciiVector(String *string) {
-  ASSERT(string->IsAscii());
-  ASSERT(string->IsFlat());
-
-  int offset = 0;
-  int length = string->length();
-  StringRepresentationTag string_tag = string->representation_tag();
-  if (string_tag == kSlicedStringTag) {
-      SlicedString* sliced = SlicedString::cast(string);
-      offset += sliced->start();
-      string = String::cast(sliced->buffer());
-      string_tag = string->representation_tag();
-  } else if (string_tag == kConsStringTag) {
-      ConsString* cons = ConsString::cast(string);
-      ASSERT(String::cast(cons->second())->length() == 0);
-      string = String::cast(cons->first());
-      string_tag = string->representation_tag();
-  }
-  if (string_tag == kSeqStringTag) {
-    AsciiString* seq = AsciiString::cast(string);
-    char* start = reinterpret_cast<char*>(seq->GetCharsAddress());
-    return Vector<const char>(start + offset, length);
-  }
-  ASSERT(string_tag == kExternalStringTag);
-  ExternalAsciiString* ext = ExternalAsciiString::cast(string);
-  const char* start = ext->resource()->data();
-  return Vector<const char>(start + offset, length);
-}
-
-
-static Vector<const uc16> ToUC16Vector(String *string) {
-  ASSERT(string->IsTwoByteString());
-  ASSERT(string->IsFlat());
-
-  int offset = 0;
-  int length = string->length();
-
-  StringRepresentationTag string_tag = string->representation_tag();
-  if (string_tag == kSlicedStringTag) {
-      SlicedString* sliced = SlicedString::cast(string);
-      offset += sliced->start();
-      string = String::cast(sliced->buffer());
-      string_tag = string->representation_tag();
-  } else if (string_tag == kConsStringTag) {
-      ConsString* cons = ConsString::cast(string);
-      ASSERT(String::cast(cons->second())->length() == 0);
-      string = String::cast(cons->first());
-      string_tag = string->representation_tag();
-  }
-  if (string_tag == kSeqStringTag) {
-    TwoByteString* seq = TwoByteString::cast(string);
-    uc16* start = reinterpret_cast<uc16*>(seq->GetCharsAddress());
-    return Vector<const uc16>(start + offset, length);
-  }
-  ASSERT(string_tag == kExternalStringTag);
-  ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
-  const uc16* start =
-      reinterpret_cast<const uc16*>(ext->resource()->data());
-  return Vector<const uc16>(start + offset, length);
-}
-
-
 template <typename schar, typename pchar>
 static int SingleCharIndexOf(Vector<const schar> string,
                              pchar pattern_char,
@@ -1202,18 +1140,18 @@ int Runtime::StringMatch(Handle<String> sub,
 
   AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
   // dispatch on type of strings
-  if (pat->is_ascii()) {
-    Vector<const char> pat_vector = ToAsciiVector(*pat);
-    if (sub->is_ascii()) {
-      return StringMatchStrategy(ToAsciiVector(*sub), pat_vector, start_index);
+  if (pat->is_ascii_representation()) {
+    Vector<const char> pat_vector = pat->ToAsciiVector();
+    if (sub->is_ascii_representation()) {
+      return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
     }
-    return StringMatchStrategy(ToUC16Vector(*sub), pat_vector, start_index);
+    return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
   }
-  Vector<const uc16> pat_vector = ToUC16Vector(*pat);
-  if (sub->is_ascii()) {
-    return StringMatchStrategy(ToAsciiVector(*sub), pat_vector, start_index);
+  Vector<const uc16> pat_vector = pat->ToUC16Vector();
+  if (sub->is_ascii_representation()) {
+    return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
   }
-  return StringMatchStrategy(ToUC16Vector(*sub), pat_vector, start_index);
+  return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
 }
 
 
@@ -2155,7 +2093,7 @@ static Object* ConvertCase(Arguments args,
   // character is also ascii.  This is currently the case, but it
   // might break in the future if we implement more context and locale
   // dependent upper/lower conversions.
-  Object* o = s->IsAscii()
+  Object* o = s->IsAsciiRepresentation()
       ? Heap::AllocateRawAsciiString(length)
       : Heap::AllocateRawTwoByteString(length);
   if (o->IsFailure()) return o;
@@ -2432,7 +2370,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
     if (first->IsString()) return first;
   }
 
-  bool ascii = special->IsAscii();
+  bool ascii = special->IsAsciiRepresentation();
   int position = 0;
   for (int i = 0; i < array_length; i++) {
     Object* elt = fixed_array->get(i);
@@ -2452,7 +2390,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
         return Failure::OutOfMemoryException();
       }
       position += element_length;
-      if (ascii && !element->IsAscii()) {
+      if (ascii && !element->IsAsciiRepresentation()) {
         ascii = false;
       }
     } else {
index 4f4a127..9bb9f98 100644 (file)
@@ -38,7 +38,7 @@ TEST(HeapMaps) {
   CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
   CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kHeaderSize);
   CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
-           TwoByteString::kHeaderSize);
+           SeqTwoByteString::kHeaderSize);
 }