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

View File

@ -974,7 +974,7 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
int start_offset = previous_index;
int end_offset = subject_ptr->length();
bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
bool is_ascii = subject->IsAsciiRepresentation();
if (StringShape(subject_ptr).IsCons()) {
subject_ptr = ConsString::cast(subject_ptr)->first();
@ -985,7 +985,7 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
subject_ptr = slice->buffer();
}
// 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());
// String is now either Sequential or External
int char_size_shift = is_ascii ? 0 : 1;
@ -1112,7 +1112,7 @@ const byte* RegExpMacroAssemblerIA32::StringCharacterPosition(String* subject,
ASSERT(subject->IsExternalString() || subject->IsSeqString());
ASSERT(start_index >= 0);
ASSERT(start_index <= subject->length());
if (StringShape(subject).IsAsciiRepresentation()) {
if (subject->IsAsciiRepresentation()) {
const byte* address;
if (StringShape(subject).IsExternal()) {
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));
// Current string.
bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
bool is_ascii = subject->IsAsciiRepresentation();
ASSERT(re_code->instruction_start() <= *return_address);
ASSERT(*return_address <=
@ -1171,7 +1171,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
}
// 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
// code cannot be used, and we need to restart regexp matching from
// 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;
const byte* code_base = code_array->GetDataStartAddress();
uc16 previous_char = '\n';
if (StringShape(*subject).IsAsciiRepresentation()) {
if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector();
if (start_position != 0) previous_char = subject_vector[start_position - 1];
return RawMatch(code_base,

View File

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

View File

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

View File

@ -144,14 +144,14 @@ bool Object::IsSeqString() {
bool Object::IsSeqAsciiString() {
if (!IsString()) return false;
return StringShape(String::cast(this)).IsSequential() &&
StringShape(String::cast(this)).IsAsciiRepresentation();
String::cast(this)->IsAsciiRepresentation();
}
bool Object::IsSeqTwoByteString() {
if (!IsString()) return false;
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() {
if (!IsString()) return false;
return StringShape(String::cast(this)).IsExternal() &&
StringShape(String::cast(this)).IsAsciiRepresentation();
String::cast(this)->IsAsciiRepresentation();
}
bool Object::IsExternalTwoByteString() {
if (!IsString()) return false;
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() {
return (type_ & kStringEncodingMask) == kAsciiStringTag;
bool String::IsAsciiRepresentation() {
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() {
return (type_ & kStringEncodingMask) == kTwoByteStringTag;
bool String::IsTwoByteRepresentation() {
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(StringShape(this).IsSequential());
return StringShape(this).IsAsciiRepresentation()
return this->IsAsciiRepresentation()
? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
: SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
}
@ -1576,11 +1591,6 @@ int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
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));
}
@ -1613,10 +1623,6 @@ void ConsString::set_second(String* value, WriteBarrierMode mode) {
String* SlicedString::buffer() {
ASSERT(
StringShape(
String::cast(READ_FIELD(this, kBufferOffset))).IsAsciiRepresentation()
== StringShape(this).IsAsciiRepresentation());
return String::cast(READ_FIELD(this, kBufferOffset));
}

View File

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

View File

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

View File

@ -1282,7 +1282,7 @@ class ReplacementStringBuilder {
parts_(Factory::NewFixedArray(estimated_part_count)),
part_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
// extend the array will work.
ASSERT(estimated_part_count > 0);
@ -1326,7 +1326,7 @@ class ReplacementStringBuilder {
int length = string->length();
ASSERT(length > 0);
AddElement(*string);
if (!StringShape(*string).IsAsciiRepresentation()) {
if (!string->IsAsciiRepresentation()) {
is_ascii_ = false;
}
IncrementCharacterCount(length);
@ -1583,14 +1583,14 @@ void CompiledReplacement::Compile(Handle<String> replacement,
int capture_count,
int subject_length) {
ASSERT(replacement->IsFlat());
if (StringShape(*replacement).IsAsciiRepresentation()) {
if (replacement->IsAsciiRepresentation()) {
AssertNoAllocation no_alloc;
ParseReplacementPattern(&parts_,
replacement->ToAsciiVector(),
capture_count,
subject_length);
} else {
ASSERT(StringShape(*replacement).IsTwoByteRepresentation());
ASSERT(replacement->IsTwoByteRepresentation());
AssertNoAllocation no_alloc;
ParseReplacementPattern(&parts_,
@ -2165,7 +2165,7 @@ int Runtime::StringMatch(Handle<String> sub,
// algorithm is unnecessary overhead.
if (pattern_length == 1) {
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
if (StringShape(*sub).IsAsciiRepresentation()) {
if (sub->IsAsciiRepresentation()) {
uc16 pchar = pat->Get(0);
if (pchar > String::kMaxAsciiCharCode) {
return -1;
@ -2190,15 +2190,15 @@ int Runtime::StringMatch(Handle<String> sub,
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
// dispatch on type of strings
if (StringShape(*pat).IsAsciiRepresentation()) {
if (pat->IsAsciiRepresentation()) {
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->ToUC16Vector(), pat_vector, start_index);
}
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->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
// might break in the future if we implement more context and locale
// dependent upper/lower conversions.
Object* o = StringShape(s).IsAsciiRepresentation()
Object* o = s->IsAsciiRepresentation()
? Heap::AllocateRawAsciiString(length)
: Heap::AllocateRawTwoByteString(length);
if (o->IsFailure()) return o;
@ -3680,7 +3680,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
if (first->IsString()) return first;
}
bool ascii = StringShape(special).IsAsciiRepresentation();
bool ascii = special->IsAsciiRepresentation();
int position = 0;
for (int i = 0; i < array_length; i++) {
Object* elt = fixed_array->get(i);
@ -3700,7 +3700,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
return Failure::OutOfMemoryException();
}
position += element_length;
if (ascii && !StringShape(element).IsAsciiRepresentation()) {
if (ascii && !element->IsAsciiRepresentation()) {
ascii = false;
}
} else {
@ -4757,10 +4757,10 @@ static Object* Runtime_DateParseString(Arguments args) {
FixedArray* output_array = output->elements();
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
bool result;
if (StringShape(*str).IsAsciiRepresentation()) {
if (str->IsAsciiRepresentation()) {
result = DateParser::Parse(str->ToAsciiVector(), output_array);
} else {
ASSERT(StringShape(*str).IsTwoByteRepresentation());
ASSERT(str->IsTwoByteRepresentation());
result = DateParser::Parse(str->ToUC16Vector(), output_array);
}
@ -6574,9 +6574,9 @@ static bool IsExternalStringValid(Object* str) {
if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
return true;
}
if (StringShape(String::cast(str)).IsAsciiRepresentation()) {
if (String::cast(str)->IsAsciiRepresentation()) {
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;
} else {
return true;

View File

@ -420,7 +420,7 @@ class TestAsciiResource: public String::ExternalAsciiStringResource {
public:
static int dispose_count;
explicit TestAsciiResource(char* data)
explicit TestAsciiResource(const char* data)
: data_(data),
length_(strlen(data)) { }
@ -437,7 +437,7 @@ class TestAsciiResource: public String::ExternalAsciiStringResource {
return length_;
}
private:
char* data_;
const char* data_;
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 {
public:
RegExpStringModificationTest()
@ -6197,26 +6308,6 @@ class RegExpStringModificationTest {
}
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.
static const int kRequiredModifications = 5;
static const int kMaxModifications = 100;
@ -6240,25 +6331,7 @@ class RegExpStringModificationTest {
v8::Locker lock;
// Swap string between ascii and two-byte representation.
i::String* string = *input_;
CHECK(i::StringShape(string).IsExternal());
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_);
}
MorphAString(string, &ascii_resource_, &uc16_resource_);
morphs_++;
}
i::OS::Sleep(1);