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:
parent
83d1d02df7
commit
ad23017469
12
src/heap.cc
12
src/heap.cc
@ -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;
|
||||
|
@ -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).
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user