When strings can change from an ASCII representation to a

UC16 representation we need to be careful about flat strings.
Flat strings can be sliced or cons strings that have a flat
string under them, so when we ask a flat cons or a slice whether
it is ASCII or not we should ask the underlying string about
its representation.  This should fix
http://code.google.com/p/chromium/issues/detail?id=10971
Review URL: http://codereview.chromium.org/100249

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1830 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
erik.corry@gmail.com 2009-05-01 11:16:29 +00:00
parent 83d1d02df7
commit ad23017469
10 changed files with 187 additions and 108 deletions

View File

@ -1423,8 +1423,8 @@ Object* Heap::AllocateConsString(String* first,
int first_length = first->length(); int first_length = first->length();
int second_length = second->length(); int second_length = second->length();
int length = first_length + second_length; int length = first_length + second_length;
bool is_ascii = StringShape(first).IsAsciiRepresentation() bool is_ascii = first->IsAsciiRepresentation()
&& StringShape(second).IsAsciiRepresentation(); && second->IsAsciiRepresentation();
// If the resulting string is small make a flat string. // If the resulting string is small make a flat string.
if (length < String::kMinNonFlatLength) { if (length < String::kMinNonFlatLength) {
@ -1484,15 +1484,15 @@ Object* Heap::AllocateSlicedString(String* buffer,
Map* map; Map* map;
if (length <= String::kMaxShortStringSize) { if (length <= String::kMaxShortStringSize) {
map = StringShape(buffer).IsAsciiRepresentation() ? map = buffer->IsAsciiRepresentation() ?
short_sliced_ascii_string_map() : short_sliced_ascii_string_map() :
short_sliced_string_map(); short_sliced_string_map();
} else if (length <= String::kMaxMediumStringSize) { } else if (length <= String::kMaxMediumStringSize) {
map = StringShape(buffer).IsAsciiRepresentation() ? map = buffer->IsAsciiRepresentation() ?
medium_sliced_ascii_string_map() : medium_sliced_ascii_string_map() :
medium_sliced_string_map(); medium_sliced_string_map();
} else { } else {
map = StringShape(buffer).IsAsciiRepresentation() ? map = buffer->IsAsciiRepresentation() ?
long_sliced_ascii_string_map() : long_sliced_ascii_string_map() :
long_sliced_string_map(); long_sliced_string_map();
} }
@ -1524,7 +1524,7 @@ Object* Heap::AllocateSubString(String* buffer,
buffer->TryFlatten(); buffer->TryFlatten();
} }
Object* result = StringShape(buffer).IsAsciiRepresentation() Object* result = buffer->IsAsciiRepresentation()
? AllocateRawAsciiString(length) ? AllocateRawAsciiString(length)
: AllocateRawTwoByteString(length); : AllocateRawTwoByteString(length);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;

View File

@ -974,7 +974,7 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
int start_offset = previous_index; int start_offset = previous_index;
int end_offset = subject_ptr->length(); int end_offset = subject_ptr->length();
bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); bool is_ascii = subject->IsAsciiRepresentation();
if (StringShape(subject_ptr).IsCons()) { if (StringShape(subject_ptr).IsCons()) {
subject_ptr = ConsString::cast(subject_ptr)->first(); subject_ptr = ConsString::cast(subject_ptr)->first();
@ -985,7 +985,7 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
subject_ptr = slice->buffer(); subject_ptr = slice->buffer();
} }
// Ensure that an underlying string has the same ascii-ness. // Ensure that an underlying string has the same ascii-ness.
ASSERT(StringShape(subject_ptr).IsAsciiRepresentation() == is_ascii); ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii);
ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString()); ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
// String is now either Sequential or External // String is now either Sequential or External
int char_size_shift = is_ascii ? 0 : 1; int char_size_shift = is_ascii ? 0 : 1;
@ -1112,7 +1112,7 @@ const byte* RegExpMacroAssemblerIA32::StringCharacterPosition(String* subject,
ASSERT(subject->IsExternalString() || subject->IsSeqString()); ASSERT(subject->IsExternalString() || subject->IsSeqString());
ASSERT(start_index >= 0); ASSERT(start_index >= 0);
ASSERT(start_index <= subject->length()); ASSERT(start_index <= subject->length());
if (StringShape(subject).IsAsciiRepresentation()) { if (subject->IsAsciiRepresentation()) {
const byte* address; const byte* address;
if (StringShape(subject).IsExternal()) { if (StringShape(subject).IsExternal()) {
const char* data = ExternalAsciiString::cast(subject)->resource()->data(); const char* data = ExternalAsciiString::cast(subject)->resource()->data();
@ -1152,7 +1152,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
// Current string. // Current string.
bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); bool is_ascii = subject->IsAsciiRepresentation();
ASSERT(re_code->instruction_start() <= *return_address); ASSERT(re_code->instruction_start() <= *return_address);
ASSERT(*return_address <= ASSERT(*return_address <=
@ -1171,7 +1171,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
} }
// String might have changed. // String might have changed.
if (StringShape(*subject).IsAsciiRepresentation() != is_ascii) { if (subject->IsAsciiRepresentation() != is_ascii) {
// If we changed between an ASCII and an UC16 string, the specialized // If we changed between an ASCII and an UC16 string, the specialized
// code cannot be used, and we need to restart regexp matching from // code cannot be used, and we need to restart regexp matching from
// scratch (including, potentially, compiling a new version of the code). // scratch (including, potentially, compiling a new version of the code).

View File

@ -574,7 +574,7 @@ bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
AssertNoAllocation a; AssertNoAllocation a;
const byte* code_base = code_array->GetDataStartAddress(); const byte* code_base = code_array->GetDataStartAddress();
uc16 previous_char = '\n'; uc16 previous_char = '\n';
if (StringShape(*subject).IsAsciiRepresentation()) { if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector(); Vector<const char> subject_vector = subject->ToAsciiVector();
if (start_position != 0) previous_char = subject_vector[start_position - 1]; if (start_position != 0) previous_char = subject_vector[start_position - 1];
return RawMatch(code_base, return RawMatch(code_base,

View File

@ -440,7 +440,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
#ifdef V8_ARCH_IA32 #ifdef V8_ARCH_IA32
RegExpMacroAssemblerIA32::Result res; RegExpMacroAssemblerIA32::Result res;
do { do {
bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); bool is_ascii = subject->IsAsciiRepresentation();
if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) { if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
return Handle<Object>::null(); return Handle<Object>::null();
} }
@ -463,7 +463,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
rc = (res == RegExpMacroAssemblerIA32::SUCCESS); rc = (res == RegExpMacroAssemblerIA32::SUCCESS);
#endif #endif
} else { } else {
bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); bool is_ascii = subject->IsAsciiRepresentation();
if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) { if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
return Handle<Object>::null(); return Handle<Object>::null();
} }

View File

@ -366,7 +366,7 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
if (len > 0x1000) if (len > 0x1000)
len = 0x1000; len = 0x1000;
if (show_impl_info) { if (show_impl_info) {
Append(StringShape(str).IsAsciiRepresentation() ? 'a' : '2'); Append(str->IsAsciiRepresentation() ? 'a' : '2');
if (StringShape(str).IsExternal()) if (StringShape(str).IsExternal())
Append('e'); Append('e');
if (StringShape(str).IsSymbol()) if (StringShape(str).IsSymbol())

View File

@ -144,14 +144,14 @@ bool Object::IsSeqString() {
bool Object::IsSeqAsciiString() { bool Object::IsSeqAsciiString() {
if (!IsString()) return false; if (!IsString()) return false;
return StringShape(String::cast(this)).IsSequential() && return StringShape(String::cast(this)).IsSequential() &&
StringShape(String::cast(this)).IsAsciiRepresentation(); String::cast(this)->IsAsciiRepresentation();
} }
bool Object::IsSeqTwoByteString() { bool Object::IsSeqTwoByteString() {
if (!IsString()) return false; if (!IsString()) return false;
return StringShape(String::cast(this)).IsSequential() && return StringShape(String::cast(this)).IsSequential() &&
StringShape(String::cast(this)).IsTwoByteRepresentation(); String::cast(this)->IsTwoByteRepresentation();
} }
@ -164,14 +164,14 @@ bool Object::IsExternalString() {
bool Object::IsExternalAsciiString() { bool Object::IsExternalAsciiString() {
if (!IsString()) return false; if (!IsString()) return false;
return StringShape(String::cast(this)).IsExternal() && return StringShape(String::cast(this)).IsExternal() &&
StringShape(String::cast(this)).IsAsciiRepresentation(); String::cast(this)->IsAsciiRepresentation();
} }
bool Object::IsExternalTwoByteString() { bool Object::IsExternalTwoByteString() {
if (!IsString()) return false; if (!IsString()) return false;
return StringShape(String::cast(this)).IsExternal() && return StringShape(String::cast(this)).IsExternal() &&
StringShape(String::cast(this)).IsTwoByteRepresentation(); String::cast(this)->IsTwoByteRepresentation();
} }
@ -211,13 +211,28 @@ bool StringShape::IsSymbol() {
} }
bool StringShape::IsAsciiRepresentation() { bool String::IsAsciiRepresentation() {
return (type_ & kStringEncodingMask) == kAsciiStringTag; uint32_t type = map()->instance_type();
if ((type & kStringRepresentationMask) == kSlicedStringTag) {
return SlicedString::cast(this)->buffer()->IsAsciiRepresentation();
}
if ((type & kStringRepresentationMask) == kConsStringTag &&
ConsString::cast(this)->second()->length() == 0) {
return ConsString::cast(this)->first()->IsAsciiRepresentation();
}
return (type & kStringEncodingMask) == kAsciiStringTag;
} }
bool StringShape::IsTwoByteRepresentation() { bool String::IsTwoByteRepresentation() {
return (type_ & kStringEncodingMask) == kTwoByteStringTag; uint32_t type = map()->instance_type();
if ((type & kStringRepresentationMask) == kSlicedStringTag) {
return SlicedString::cast(this)->buffer()->IsTwoByteRepresentation();
} else if ((type & kStringRepresentationMask) == kConsStringTag &&
ConsString::cast(this)->second()->length() == 0) {
return ConsString::cast(this)->first()->IsTwoByteRepresentation();
}
return (type & kStringEncodingMask) == kTwoByteStringTag;
} }
@ -1476,7 +1491,7 @@ void String::Set(int index, uint16_t value) {
ASSERT(index >= 0 && index < length()); ASSERT(index >= 0 && index < length());
ASSERT(StringShape(this).IsSequential()); ASSERT(StringShape(this).IsSequential());
return StringShape(this).IsAsciiRepresentation() return this->IsAsciiRepresentation()
? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value) ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
: SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value); : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
} }
@ -1576,11 +1591,6 @@ int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
String* ConsString::first() { String* ConsString::first() {
ASSERT(String::cast(READ_FIELD(this, kSecondOffset))->length() != 0 ||
StringShape(
String::cast(
READ_FIELD(this, kFirstOffset))).IsAsciiRepresentation()
== StringShape(this).IsAsciiRepresentation());
return String::cast(READ_FIELD(this, kFirstOffset)); return String::cast(READ_FIELD(this, kFirstOffset));
} }
@ -1613,10 +1623,6 @@ void ConsString::set_second(String* value, WriteBarrierMode mode) {
String* SlicedString::buffer() { String* SlicedString::buffer() {
ASSERT(
StringShape(
String::cast(READ_FIELD(this, kBufferOffset))).IsAsciiRepresentation()
== StringShape(this).IsAsciiRepresentation());
return String::cast(READ_FIELD(this, kBufferOffset)); return String::cast(READ_FIELD(this, kBufferOffset));
} }

View File

@ -602,8 +602,6 @@ Object* String::TryFlatten() {
if (StringShape(String::cast(ok)).IsCons()) { if (StringShape(String::cast(ok)).IsCons()) {
ss->set_buffer(ConsString::cast(ok)->first()); ss->set_buffer(ConsString::cast(ok)->first());
} }
ASSERT(StringShape(this).IsAsciiRepresentation() ==
StringShape(ss->buffer()).IsAsciiRepresentation());
return this; return this;
} }
case kConsStringTag: { case kConsStringTag: {
@ -618,7 +616,7 @@ Object* String::TryFlatten() {
int len = length(); int len = length();
Object* object; Object* object;
String* result; String* result;
if (StringShape(this).IsAsciiRepresentation()) { if (IsAsciiRepresentation()) {
object = Heap::AllocateRawAsciiString(len, tenure); object = Heap::AllocateRawAsciiString(len, tenure);
if (object->IsFailure()) return object; if (object->IsFailure()) return object;
result = String::cast(object); result = String::cast(object);
@ -956,10 +954,11 @@ int HeapObject::SlowSizeFromMap(Map* map) {
// Avoid calling functions such as FixedArray::cast during GC, which // Avoid calling functions such as FixedArray::cast during GC, which
// read map pointer of this object again. // read map pointer of this object again.
InstanceType instance_type = map->instance_type(); InstanceType instance_type = map->instance_type();
uint32_t type = static_cast<uint32_t>(instance_type);
if (instance_type < FIRST_NONSTRING_TYPE if (instance_type < FIRST_NONSTRING_TYPE
&& (StringShape(instance_type).IsSequential())) { && (StringShape(instance_type).IsSequential())) {
if (StringShape(instance_type).IsAsciiRepresentation()) { if ((type & kStringEncodingMask) == kAsciiStringTag) {
SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this); SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this);
return seq_ascii_this->SeqAsciiStringSize(instance_type); return seq_ascii_this->SeqAsciiStringSize(instance_type);
} else { } else {
@ -3235,7 +3234,7 @@ bool String::LooksValid() {
int String::Utf8Length() { int String::Utf8Length() {
if (StringShape(this).IsAsciiRepresentation()) return length(); if (IsAsciiRepresentation()) 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)
@ -3251,7 +3250,7 @@ int String::Utf8Length() {
Vector<const char> String::ToAsciiVector() { Vector<const char> String::ToAsciiVector() {
ASSERT(StringShape(this).IsAsciiRepresentation()); ASSERT(IsAsciiRepresentation());
ASSERT(IsFlat()); ASSERT(IsFlat());
int offset = 0; int offset = 0;
@ -3282,7 +3281,7 @@ Vector<const char> String::ToAsciiVector() {
Vector<const uc16> String::ToUC16Vector() { Vector<const uc16> String::ToUC16Vector() {
ASSERT(StringShape(this).IsTwoByteRepresentation()); ASSERT(IsTwoByteRepresentation());
ASSERT(IsFlat()); ASSERT(IsFlat());
int offset = 0; int offset = 0;
@ -3385,7 +3384,7 @@ const uc16* String::GetTwoByteData() {
const uc16* String::GetTwoByteData(unsigned start) { const uc16* String::GetTwoByteData(unsigned start) {
ASSERT(!StringShape(this).IsAsciiRepresentation()); ASSERT(!IsAsciiRepresentation());
switch (StringShape(this).representation_tag()) { switch (StringShape(this).representation_tag()) {
case kSeqStringTag: case kSeqStringTag:
return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
@ -3680,7 +3679,7 @@ const unibrow::byte* String::ReadBlock(String* input,
} }
switch (StringShape(input).representation_tag()) { switch (StringShape(input).representation_tag()) {
case kSeqStringTag: case kSeqStringTag:
if (StringShape(input).IsAsciiRepresentation()) { if (input->IsAsciiRepresentation()) {
SeqAsciiString* str = SeqAsciiString::cast(input); SeqAsciiString* str = SeqAsciiString::cast(input);
return str->SeqAsciiStringReadBlock(&rbb->remaining, return str->SeqAsciiStringReadBlock(&rbb->remaining,
offset_ptr, offset_ptr,
@ -3701,7 +3700,7 @@ const unibrow::byte* String::ReadBlock(String* input,
offset_ptr, offset_ptr,
max_chars); max_chars);
case kExternalStringTag: case kExternalStringTag:
if (StringShape(input).IsAsciiRepresentation()) { if (input->IsAsciiRepresentation()) {
return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
&rbb->remaining, &rbb->remaining,
offset_ptr, offset_ptr,
@ -3754,7 +3753,7 @@ void FlatStringReader::RefreshState() {
if (str_ == NULL) return; if (str_ == NULL) return;
Handle<String> str(str_); Handle<String> str(str_);
ASSERT(str->IsFlat()); ASSERT(str->IsFlat());
is_ascii_ = StringShape(*str).IsAsciiRepresentation(); is_ascii_ = str->IsAsciiRepresentation();
if (is_ascii_) { if (is_ascii_) {
start_ = str->ToAsciiVector().start(); start_ = str->ToAsciiVector().start();
} else { } else {
@ -3795,7 +3794,7 @@ void String::ReadBlockIntoBuffer(String* input,
switch (StringShape(input).representation_tag()) { switch (StringShape(input).representation_tag()) {
case kSeqStringTag: case kSeqStringTag:
if (StringShape(input).IsAsciiRepresentation()) { if (input->IsAsciiRepresentation()) {
SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
offset_ptr, offset_ptr,
max_chars); max_chars);
@ -3817,7 +3816,7 @@ void String::ReadBlockIntoBuffer(String* input,
max_chars); max_chars);
return; return;
case kExternalStringTag: case kExternalStringTag:
if (StringShape(input).IsAsciiRepresentation()) { if (input->IsAsciiRepresentation()) {
ExternalAsciiString::cast(input)-> ExternalAsciiString::cast(input)->
ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
} else { } else {
@ -4147,7 +4146,7 @@ static StringInputBuffer string_compare_buffer_b;
template <typename IteratorA> template <typename IteratorA>
static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
if (b->IsFlat()) { if (b->IsFlat()) {
if (StringShape(b).IsAsciiRepresentation()) { if (b->IsAsciiRepresentation()) {
VectorIterator<char> ib(b->ToAsciiVector()); VectorIterator<char> ib(b->ToAsciiVector());
return CompareStringContents(ia, &ib); return CompareStringContents(ia, &ib);
} else { } else {
@ -4187,10 +4186,10 @@ bool String::SlowEquals(String* other) {
} }
if (this->IsFlat()) { if (this->IsFlat()) {
if (StringShape(this).IsAsciiRepresentation()) { if (IsAsciiRepresentation()) {
Vector<const char> vec1 = this->ToAsciiVector(); Vector<const char> vec1 = this->ToAsciiVector();
if (other->IsFlat()) { if (other->IsFlat()) {
if (StringShape(other).IsAsciiRepresentation()) { if (other->IsAsciiRepresentation()) {
Vector<const char> vec2 = other->ToAsciiVector(); Vector<const char> vec2 = other->ToAsciiVector();
return CompareRawStringContents(vec1, vec2); return CompareRawStringContents(vec1, vec2);
} else { } else {
@ -4209,7 +4208,7 @@ bool String::SlowEquals(String* other) {
Vector<const uc16> vec1 = this->ToUC16Vector(); Vector<const uc16> vec1 = this->ToUC16Vector();
if (CheckVectorForBug9746(vec1)) return false; if (CheckVectorForBug9746(vec1)) return false;
if (other->IsFlat()) { if (other->IsFlat()) {
if (StringShape(other).IsAsciiRepresentation()) { if (other->IsAsciiRepresentation()) {
VectorIterator<uc16> buf1(vec1); VectorIterator<uc16> buf1(vec1);
VectorIterator<char> ib(other->ToAsciiVector()); VectorIterator<char> ib(other->ToAsciiVector());
return CompareStringContents(&buf1, &ib); return CompareStringContents(&buf1, &ib);

View File

@ -3207,8 +3207,6 @@ class StringShape BASE_EMBEDDED {
inline explicit StringShape(String* s); inline explicit StringShape(String* s);
inline explicit StringShape(Map* s); inline explicit StringShape(Map* s);
inline explicit StringShape(InstanceType t); inline explicit StringShape(InstanceType t);
inline bool IsAsciiRepresentation();
inline bool IsTwoByteRepresentation();
inline bool IsSequential(); inline bool IsSequential();
inline bool IsExternal(); inline bool IsExternal();
inline bool IsCons(); inline bool IsCons();
@ -3260,6 +3258,9 @@ class String: public HeapObject {
inline uint32_t length_field(); inline uint32_t length_field();
inline void set_length_field(uint32_t value); inline void set_length_field(uint32_t value);
inline bool IsAsciiRepresentation();
inline bool IsTwoByteRepresentation();
// Get and set individual two byte chars in the string. // Get and set individual two byte chars in the string.
inline void Set(int index, uint16_t value); inline void Set(int index, uint16_t value);
// Get individual two byte char in the string. Repeated calls // Get individual two byte char in the string. Repeated calls

View File

@ -1282,7 +1282,7 @@ class ReplacementStringBuilder {
parts_(Factory::NewFixedArray(estimated_part_count)), parts_(Factory::NewFixedArray(estimated_part_count)),
part_count_(0), part_count_(0),
character_count_(0), character_count_(0),
is_ascii_(StringShape(*subject).IsAsciiRepresentation()) { is_ascii_(subject->IsAsciiRepresentation()) {
// Require a non-zero initial size. Ensures that doubling the size to // Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work. // extend the array will work.
ASSERT(estimated_part_count > 0); ASSERT(estimated_part_count > 0);
@ -1326,7 +1326,7 @@ class ReplacementStringBuilder {
int length = string->length(); int length = string->length();
ASSERT(length > 0); ASSERT(length > 0);
AddElement(*string); AddElement(*string);
if (!StringShape(*string).IsAsciiRepresentation()) { if (!string->IsAsciiRepresentation()) {
is_ascii_ = false; is_ascii_ = false;
} }
IncrementCharacterCount(length); IncrementCharacterCount(length);
@ -1583,14 +1583,14 @@ void CompiledReplacement::Compile(Handle<String> replacement,
int capture_count, int capture_count,
int subject_length) { int subject_length) {
ASSERT(replacement->IsFlat()); ASSERT(replacement->IsFlat());
if (StringShape(*replacement).IsAsciiRepresentation()) { if (replacement->IsAsciiRepresentation()) {
AssertNoAllocation no_alloc; AssertNoAllocation no_alloc;
ParseReplacementPattern(&parts_, ParseReplacementPattern(&parts_,
replacement->ToAsciiVector(), replacement->ToAsciiVector(),
capture_count, capture_count,
subject_length); subject_length);
} else { } else {
ASSERT(StringShape(*replacement).IsTwoByteRepresentation()); ASSERT(replacement->IsTwoByteRepresentation());
AssertNoAllocation no_alloc; AssertNoAllocation no_alloc;
ParseReplacementPattern(&parts_, ParseReplacementPattern(&parts_,
@ -2165,7 +2165,7 @@ int Runtime::StringMatch(Handle<String> sub,
// algorithm is unnecessary overhead. // algorithm is unnecessary overhead.
if (pattern_length == 1) { if (pattern_length == 1) {
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
if (StringShape(*sub).IsAsciiRepresentation()) { if (sub->IsAsciiRepresentation()) {
uc16 pchar = pat->Get(0); uc16 pchar = pat->Get(0);
if (pchar > String::kMaxAsciiCharCode) { if (pchar > String::kMaxAsciiCharCode) {
return -1; return -1;
@ -2190,15 +2190,15 @@ 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 (StringShape(*pat).IsAsciiRepresentation()) { if (pat->IsAsciiRepresentation()) {
Vector<const char> pat_vector = pat->ToAsciiVector(); Vector<const char> pat_vector = pat->ToAsciiVector();
if (StringShape(*sub).IsAsciiRepresentation()) { if (sub->IsAsciiRepresentation()) {
return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
} }
return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
} }
Vector<const uc16> pat_vector = pat->ToUC16Vector(); Vector<const uc16> pat_vector = pat->ToUC16Vector();
if (StringShape(*sub).IsAsciiRepresentation()) { if (sub->IsAsciiRepresentation()) {
return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
} }
return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
@ -3329,7 +3329,7 @@ static Object* ConvertCaseHelper(String* s,
// 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 = StringShape(s).IsAsciiRepresentation() 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;
@ -3680,7 +3680,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
if (first->IsString()) return first; if (first->IsString()) return first;
} }
bool ascii = StringShape(special).IsAsciiRepresentation(); 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);
@ -3700,7 +3700,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
return Failure::OutOfMemoryException(); return Failure::OutOfMemoryException();
} }
position += element_length; position += element_length;
if (ascii && !StringShape(element).IsAsciiRepresentation()) { if (ascii && !element->IsAsciiRepresentation()) {
ascii = false; ascii = false;
} }
} else { } else {
@ -4757,10 +4757,10 @@ static Object* Runtime_DateParseString(Arguments args) {
FixedArray* output_array = output->elements(); FixedArray* output_array = output->elements();
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
bool result; bool result;
if (StringShape(*str).IsAsciiRepresentation()) { if (str->IsAsciiRepresentation()) {
result = DateParser::Parse(str->ToAsciiVector(), output_array); result = DateParser::Parse(str->ToAsciiVector(), output_array);
} else { } else {
ASSERT(StringShape(*str).IsTwoByteRepresentation()); ASSERT(str->IsTwoByteRepresentation());
result = DateParser::Parse(str->ToUC16Vector(), output_array); result = DateParser::Parse(str->ToUC16Vector(), output_array);
} }
@ -6574,9 +6574,9 @@ static bool IsExternalStringValid(Object* str) {
if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) { if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
return true; return true;
} }
if (StringShape(String::cast(str)).IsAsciiRepresentation()) { if (String::cast(str)->IsAsciiRepresentation()) {
return ExternalAsciiString::cast(str)->resource() != NULL; return ExternalAsciiString::cast(str)->resource() != NULL;
} else if (StringShape(String::cast(str)).IsTwoByteRepresentation()) { } else if (String::cast(str)->IsTwoByteRepresentation()) {
return ExternalTwoByteString::cast(str)->resource() != NULL; return ExternalTwoByteString::cast(str)->resource() != NULL;
} else { } else {
return true; return true;

View File

@ -420,7 +420,7 @@ class TestAsciiResource: public String::ExternalAsciiStringResource {
public: public:
static int dispose_count; static int dispose_count;
explicit TestAsciiResource(char* data) explicit TestAsciiResource(const char* data)
: data_(data), : data_(data),
length_(strlen(data)) { } length_(strlen(data)) { }
@ -437,7 +437,7 @@ class TestAsciiResource: public String::ExternalAsciiStringResource {
return length_; return length_;
} }
private: private:
char* data_; const char* data_;
size_t length_; size_t length_;
}; };
@ -6153,6 +6153,117 @@ TEST(ObjectClone) {
} }
class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
public:
explicit AsciiVectorResource(i::Vector<const char> vector)
: data_(vector) {}
virtual ~AsciiVectorResource() {}
virtual size_t length() const { return data_.length(); }
virtual const char* data() const { return data_.start(); }
private:
i::Vector<const char> data_;
};
class UC16VectorResource : public v8::String::ExternalStringResource {
public:
explicit UC16VectorResource(i::Vector<const i::uc16> vector)
: data_(vector) {}
virtual ~UC16VectorResource() {}
virtual size_t length() const { return data_.length(); }
virtual const i::uc16* data() const { return data_.start(); }
private:
i::Vector<const i::uc16> data_;
};
static void MorphAString(i::String* string,
AsciiVectorResource* ascii_resource,
UC16VectorResource* uc16_resource) {
CHECK(i::StringShape(string).IsExternal());
if (string->IsAsciiRepresentation()) {
// Check old map is not symbol or long.
CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
string->map() == i::Heap::medium_external_ascii_string_map());
// Morph external string to be TwoByte string.
if (string->length() <= i::String::kMaxShortStringSize) {
string->set_map(i::Heap::short_external_string_map());
} else {
string->set_map(i::Heap::medium_external_string_map());
}
i::ExternalTwoByteString* morphed =
i::ExternalTwoByteString::cast(string);
morphed->set_resource(uc16_resource);
} else {
// Check old map is not symbol or long.
CHECK(string->map() == i::Heap::short_external_string_map() ||
string->map() == i::Heap::medium_external_string_map());
// Morph external string to be ASCII string.
if (string->length() <= i::String::kMaxShortStringSize) {
string->set_map(i::Heap::short_external_ascii_string_map());
} else {
string->set_map(i::Heap::medium_external_ascii_string_map());
}
i::ExternalAsciiString* morphed =
i::ExternalAsciiString::cast(string);
morphed->set_resource(ascii_resource);
}
}
// Test that we can still flatten a string if the components it is built up
// from have been turned into 16 bit strings in the mean time.
THREADED_TEST(MorphCompositeStringTest) {
const char* c_string = "Now is the time for all good men"
" to come to the aid of the party";
uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
{
v8::HandleScope scope;
LocalContext env;
AsciiVectorResource ascii_resource(
i::Vector<const char>(c_string, strlen(c_string)));
UC16VectorResource uc16_resource(
i::Vector<const uint16_t>(two_byte_string, strlen(c_string)));
Local<String> lhs(v8::Utils::ToLocal(
i::Factory::NewExternalStringFromAscii(&ascii_resource)));
Local<String> rhs(v8::Utils::ToLocal(
i::Factory::NewExternalStringFromAscii(&ascii_resource)));
env->Global()->Set(v8_str("lhs"), lhs);
env->Global()->Set(v8_str("rhs"), rhs);
CompileRun(
"var cons = lhs + rhs;"
"var slice = lhs.substring(1, lhs.length - 1);"
"var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
// Now do some stuff to make sure the strings are flattened, etc.
CompileRun(
"/[^a-z]/.test(cons);"
"/[^a-z]/.test(slice);"
"/[^a-z]/.test(slice_on_cons);");
const char* expected_cons =
"Now is the time for all good men to come to the aid of the party"
"Now is the time for all good men to come to the aid of the party";
const char* expected_slice =
"ow is the time for all good men to come to the aid of the part";
const char* expected_slice_on_cons =
"ow is the time for all good men to come to the aid of the party"
"Now is the time for all good men to come to the aid of the part";
CHECK_EQ(String::New(expected_cons),
env->Global()->Get(v8_str("cons")));
CHECK_EQ(String::New(expected_slice),
env->Global()->Get(v8_str("slice")));
CHECK_EQ(String::New(expected_slice_on_cons),
env->Global()->Get(v8_str("slice_on_cons")));
}
}
class RegExpStringModificationTest { class RegExpStringModificationTest {
public: public:
RegExpStringModificationTest() RegExpStringModificationTest()
@ -6197,26 +6308,6 @@ class RegExpStringModificationTest {
} }
private: private:
class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
public:
explicit AsciiVectorResource(i::Vector<const char> vector)
: data_(vector) {}
virtual ~AsciiVectorResource() {}
virtual size_t length() const { return data_.length(); }
virtual const char* data() const { return data_.start(); }
private:
i::Vector<const char> data_;
};
class UC16VectorResource : public v8::String::ExternalStringResource {
public:
explicit UC16VectorResource(i::Vector<const i::uc16> vector)
: data_(vector) {}
virtual ~UC16VectorResource() {}
virtual size_t length() const { return data_.length(); }
virtual const i::uc16* data() const { return data_.start(); }
private:
i::Vector<const i::uc16> data_;
};
// Number of string modifications required. // Number of string modifications required.
static const int kRequiredModifications = 5; static const int kRequiredModifications = 5;
static const int kMaxModifications = 100; static const int kMaxModifications = 100;
@ -6240,25 +6331,7 @@ class RegExpStringModificationTest {
v8::Locker lock; v8::Locker lock;
// Swap string between ascii and two-byte representation. // Swap string between ascii and two-byte representation.
i::String* string = *input_; i::String* string = *input_;
CHECK(i::StringShape(string).IsExternal()); MorphAString(string, &ascii_resource_, &uc16_resource_);
if (i::StringShape(string).IsAsciiRepresentation()) {
// Morph external string to be TwoByte string.
i::ExternalAsciiString* ext_string =
i::ExternalAsciiString::cast(string);
i::ExternalTwoByteString* morphed =
reinterpret_cast<i::ExternalTwoByteString*>(ext_string);
morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE);
morphed->set_resource(&uc16_resource_);
} else {
// Morph external string to be ASCII string.
i::ExternalTwoByteString* ext_string =
i::ExternalTwoByteString::cast(string);
i::ExternalAsciiString* morphed =
reinterpret_cast<i::ExternalAsciiString*>(ext_string);
morphed->map()->set_instance_type(
i::SHORT_EXTERNAL_ASCII_STRING_TYPE);
morphed->set_resource(&ascii_resource_);
}
morphs_++; morphs_++;
} }
i::OS::Sleep(1); i::OS::Sleep(1);