- Specialized slow-case string equality nine ways based on the

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