HasOnlyAsciiChars can return incorrect results. Fixup usages and rename.

R=ulan@chromium.org
BUG=

Review URL: https://codereview.chromium.org/14509012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14453 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
dcarney@chromium.org 2013-04-26 11:34:44 +00:00
parent f28bd182b0
commit 0a32b57594
12 changed files with 85 additions and 121 deletions

View File

@ -1183,12 +1183,10 @@ class V8EXPORT String : public Primitive {
int Utf8Length() const;
/**
* A fast conservative check for non-ASCII characters. May
* return true even for ASCII strings, but if it returns
* false you can be sure that all characters are in the range
* 0-127.
* This function is no longer useful.
*/
bool MayContainNonAscii() const;
// TODO(dcarney): deprecate
V8_INLINE(bool MayContainNonAscii()) const { return true; }
/**
* Returns whether this string contains only one byte data.

View File

@ -4055,14 +4055,6 @@ int String::Length() const {
return str->length();
}
bool String::MayContainNonAscii() const {
i::Handle<i::String> str = Utils::OpenHandle(this);
if (IsDeadCheck(str->GetIsolate(), "v8::String::MayContainNonAscii()")) {
return false;
}
return !str->HasOnlyAsciiChars();
}
bool String::IsOneByte() const {
i::Handle<i::String> str = Utils::OpenHandle(this);
@ -4516,25 +4508,6 @@ int String::WriteAscii(char* buffer,
FlattenString(str); // Flatten the string for efficiency.
}
if (str->HasOnlyAsciiChars()) {
// WriteToFlat is faster than using the StringCharacterStream.
if (length == -1) length = str->length() + 1;
int len = i::Min(length, str->length() - start);
i::String::WriteToFlat(*str,
reinterpret_cast<uint8_t*>(buffer),
start,
start + len);
if (!(options & PRESERVE_ASCII_NULL)) {
for (int i = 0; i < len; i++) {
if (buffer[i] == '\0') buffer[i] = ' ';
}
}
if (!(options & NO_NULL_TERMINATION) && length > len) {
buffer[len] = '\0';
}
return len;
}
int end = length;
if ((length == -1) || (length > str->length() - start)) {
end = str->length() - start;

View File

@ -5950,16 +5950,16 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
// to contain only ASCII characters.
// to contain only one byte characters.
// r4: first instance type.
// r5: second instance type.
__ tst(r4, Operand(kAsciiDataHintMask));
__ tst(r5, Operand(kAsciiDataHintMask), ne);
__ tst(r4, Operand(kOneByteDataHintMask));
__ tst(r5, Operand(kOneByteDataHintMask), ne);
__ b(ne, &ascii_data);
__ eor(r4, r4, Operand(r5));
STATIC_ASSERT(kOneByteStringTag != 0 && kAsciiDataHintTag != 0);
__ and_(r4, r4, Operand(kOneByteStringTag | kAsciiDataHintTag));
__ cmp(r4, Operand(kOneByteStringTag | kAsciiDataHintTag));
STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
__ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
__ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
__ b(eq, &ascii_data);
// Allocate a two byte cons string.

View File

@ -3424,14 +3424,14 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
return Failure::OutOfMemoryException(0x4);
}
bool is_ascii_data_in_two_byte_string = false;
bool is_one_byte_data_in_two_byte_string = false;
if (!is_one_byte) {
// At least one of the strings uses two-byte representation so we
// can't use the fast case code for short ASCII strings below, but
// we can try to save memory if all chars actually fit in ASCII.
is_ascii_data_in_two_byte_string =
first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
if (is_ascii_data_in_two_byte_string) {
is_one_byte_data_in_two_byte_string =
first->HasOnlyOneByteChars() && second->HasOnlyOneByteChars();
if (is_one_byte_data_in_two_byte_string) {
isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
}
}
@ -3466,7 +3466,7 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
for (int i = 0; i < second_length; i++) *dest++ = src[i];
return result;
} else {
if (is_ascii_data_in_two_byte_string) {
if (is_one_byte_data_in_two_byte_string) {
Object* result;
{ MaybeObject* maybe_result = AllocateRawOneByteString(length);
if (!maybe_result->ToObject(&result)) return maybe_result;
@ -3491,7 +3491,7 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
}
}
Map* map = (is_one_byte || is_ascii_data_in_two_byte_string) ?
Map* map = (is_one_byte || is_one_byte_data_in_two_byte_string) ?
cons_ascii_string_map() : cons_string_map();
Object* result;
@ -3637,11 +3637,11 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte(
// For small strings we check whether the resource contains only
// one byte characters. If yes, we use a different string map.
static const size_t kAsciiCheckLengthLimit = 32;
bool is_one_byte = length <= kAsciiCheckLengthLimit &&
static const size_t kOneByteCheckLengthLimit = 32;
bool is_one_byte = length <= kOneByteCheckLengthLimit &&
String::IsOneByte(resource->data(), static_cast<int>(length));
Map* map = is_one_byte ?
external_string_with_ascii_data_map() : external_string_map();
external_string_with_one_byte_data_map() : external_string_map();
Object* result;
{ MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
@ -4977,14 +4977,14 @@ Map* Heap::InternalizedStringMapForString(String* string) {
case EXTERNAL_STRING_TYPE: return external_internalized_string_map();
case EXTERNAL_ASCII_STRING_TYPE:
return external_ascii_internalized_string_map();
case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
return external_internalized_string_with_ascii_data_map();
case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
return external_internalized_string_with_one_byte_data_map();
case SHORT_EXTERNAL_STRING_TYPE:
return short_external_internalized_string_map();
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
return short_external_ascii_internalized_string_map();
case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
return short_external_internalized_string_with_ascii_data_map();
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
return short_external_internalized_string_with_one_byte_data_map();
default: return NULL; // No match found.
}
}

View File

@ -95,12 +95,14 @@ namespace internal {
V(Map, sliced_string_map, SlicedStringMap) \
V(Map, sliced_ascii_string_map, SlicedAsciiStringMap) \
V(Map, external_string_map, ExternalStringMap) \
V(Map, external_string_with_ascii_data_map, ExternalStringWithAsciiDataMap) \
V(Map, \
external_string_with_one_byte_data_map, \
ExternalStringWithOneByteDataMap) \
V(Map, external_ascii_string_map, ExternalAsciiStringMap) \
V(Map, short_external_string_map, ShortExternalStringMap) \
V(Map, \
short_external_string_with_ascii_data_map, \
ShortExternalStringWithAsciiDataMap) \
short_external_string_with_one_byte_data_map, \
ShortExternalStringWithOneByteDataMap) \
V(Map, internalized_string_map, InternalizedStringMap) \
V(Map, ascii_internalized_string_map, AsciiInternalizedStringMap) \
V(Map, cons_internalized_string_map, ConsInternalizedStringMap) \
@ -109,8 +111,8 @@ namespace internal {
external_internalized_string_map, \
ExternalInternalizedStringMap) \
V(Map, \
external_internalized_string_with_ascii_data_map, \
ExternalInternalizedStringWithAsciiDataMap) \
external_internalized_string_with_one_byte_data_map, \
ExternalInternalizedStringWithOneByteDataMap) \
V(Map, \
external_ascii_internalized_string_map, \
ExternalAsciiInternalizedStringMap) \
@ -118,8 +120,8 @@ namespace internal {
short_external_internalized_string_map, \
ShortExternalInternalizedStringMap) \
V(Map, \
short_external_internalized_string_with_ascii_data_map, \
ShortExternalInternalizedStringWithAsciiDataMap) \
short_external_internalized_string_with_one_byte_data_map, \
ShortExternalInternalizedStringWithOneByteDataMap) \
V(Map, \
short_external_ascii_internalized_string_map, \
ShortExternalAsciiInternalizedStringMap) \

View File

@ -5828,17 +5828,17 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ ret(2 * kPointerSize);
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
// to contain only ASCII characters.
// to contain only one byte characters.
// ecx: first instance type AND second instance type.
// edi: second instance type.
__ test(ecx, Immediate(kAsciiDataHintMask));
__ test(ecx, Immediate(kOneByteDataHintMask));
__ j(not_zero, &ascii_data);
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ xor_(edi, ecx);
STATIC_ASSERT(kOneByteStringTag != 0 && kAsciiDataHintTag != 0);
__ and_(edi, kOneByteStringTag | kAsciiDataHintTag);
__ cmp(edi, kOneByteStringTag | kAsciiDataHintTag);
STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
__ and_(edi, kOneByteStringTag | kOneByteDataHintTag);
__ cmp(edi, kOneByteStringTag | kOneByteDataHintTag);
__ j(equal, &ascii_data);
// Allocate a two byte cons string.
__ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime);

View File

@ -335,15 +335,6 @@ class Logger::NameBuffer {
void AppendString(String* str) {
if (str == NULL) return;
if (str->HasOnlyAsciiChars()) {
int utf8_length = Min(str->length(), kUtf8BufferSize - utf8_pos_);
String::WriteToFlat(str,
reinterpret_cast<uint8_t*>(utf8_buffer_ + utf8_pos_),
0,
utf8_length);
utf8_pos_ += utf8_length;
return;
}
int uc16_length = Min(str->length(), kUtf16BufferSize);
String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
int previous = unibrow::Utf16::kNoPreviousCharacter;

View File

@ -355,14 +355,14 @@ bool String::IsTwoByteRepresentationUnderneath() {
}
bool String::HasOnlyAsciiChars() {
bool String::HasOnlyOneByteChars() {
uint32_t type = map()->instance_type();
return (type & kAsciiDataHintMask) == kAsciiDataHintTag;
return (type & kOneByteDataHintMask) == kOneByteDataHintTag;
}
bool String::IsOneByteConvertible() {
return HasOnlyAsciiChars() || IsOneByteRepresentation();
return HasOnlyOneByteChars() || IsOneByteRepresentation();
}

View File

@ -495,11 +495,11 @@ static const char* TypeToString(InstanceType type) {
return "CONS_STRING";
case EXTERNAL_STRING_TYPE:
case EXTERNAL_ASCII_STRING_TYPE:
case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
return "EXTERNAL_STRING";
case SHORT_EXTERNAL_STRING_TYPE:
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
return "SHORT_EXTERNAL_STRING";
case INTERNALIZED_STRING_TYPE: return "INTERNALIZED_STRING";
case ASCII_INTERNALIZED_STRING_TYPE: return "ASCII_INTERNALIZED_STRING";
@ -508,11 +508,11 @@ static const char* TypeToString(InstanceType type) {
return "CONS_ASCII_INTERNALIZED_STRING";
case EXTERNAL_INTERNALIZED_STRING_TYPE:
case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE:
case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
return "EXTERNAL_INTERNALIZED_STRING";
case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
return "SHORT_EXTERNAL_INTERNALIZED_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";

View File

@ -1130,21 +1130,21 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
this->set_map_no_write_barrier(
is_internalized
? (is_ascii
? heap->external_internalized_string_with_ascii_data_map()
? heap->external_internalized_string_with_one_byte_data_map()
: heap->external_internalized_string_map())
: (is_ascii
? heap->external_string_with_ascii_data_map()
? heap->external_string_with_one_byte_data_map()
: heap->external_string_map()));
} else {
this->set_map_no_write_barrier(
is_internalized
? (is_ascii
? heap->
short_external_internalized_string_with_ascii_data_map()
: heap->short_external_internalized_string_map())
: (is_ascii
? heap->short_external_string_with_ascii_data_map()
: heap->short_external_string_map()));
? (is_ascii
? heap->
short_external_internalized_string_with_one_byte_data_map()
: heap->short_external_internalized_string_map())
: (is_ascii
? heap->short_external_string_with_one_byte_data_map()
: heap->short_external_string_map()));
}
ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
self->set_resource(resource);

View File

@ -330,10 +330,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
V(SLICED_STRING_TYPE) \
V(EXTERNAL_STRING_TYPE) \
V(EXTERNAL_ASCII_STRING_TYPE) \
V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \
V(EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE) \
V(SHORT_EXTERNAL_STRING_TYPE) \
V(SHORT_EXTERNAL_ASCII_STRING_TYPE) \
V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \
V(SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE) \
\
V(INTERNALIZED_STRING_TYPE) \
V(ASCII_INTERNALIZED_STRING_TYPE) \
@ -341,10 +341,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
V(CONS_ASCII_INTERNALIZED_STRING_TYPE) \
V(EXTERNAL_INTERNALIZED_STRING_TYPE) \
V(EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \
V(EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE) \
V(EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE) \
V(SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \
V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE) \
V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE) \
\
V(SYMBOL_TYPE) \
V(MAP_TYPE) \
@ -461,10 +461,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
ExternalAsciiString::kSize, \
external_ascii_string, \
ExternalAsciiString) \
V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \
V(EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE, \
ExternalTwoByteString::kSize, \
external_string_with_ascii_data, \
ExternalStringWithAsciiData) \
external_string_with_one_bytei_data, \
ExternalStringWithOneByteData) \
V(SHORT_EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kShortSize, \
short_external_string, \
@ -473,10 +473,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
ExternalAsciiString::kShortSize, \
short_external_ascii_string, \
ShortExternalAsciiString) \
V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \
V(SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE, \
ExternalTwoByteString::kShortSize, \
short_external_string_with_ascii_data, \
ShortExternalStringWithAsciiData) \
short_external_string_with_one_byte_data, \
ShortExternalStringWithOneByteData) \
\
V(INTERNALIZED_STRING_TYPE, \
kVariableSizeSentinel, \
@ -502,10 +502,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
ExternalAsciiString::kSize, \
external_ascii_internalized_string, \
ExternalAsciiInternalizedString) \
V(EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE, \
V(EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE, \
ExternalTwoByteString::kSize, \
external_internalized_string_with_ascii_data, \
ExternalInternalizedStringWithAsciiData) \
external_internalized_string_with_one_byte_data, \
ExternalInternalizedStringWithOneByteData) \
V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE, \
ExternalTwoByteString::kShortSize, \
short_external_internalized_string, \
@ -514,10 +514,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
ExternalAsciiString::kShortSize, \
short_external_ascii_internalized_string, \
ShortExternalAsciiInternalizedString) \
V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE, \
V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE, \
ExternalTwoByteString::kShortSize, \
short_external_internalized_string_with_ascii_data, \
ShortExternalInternalizedStringWithAsciiData) \
short_external_internalized_string_with_one_byte_data, \
ShortExternalInternalizedStringWithOneByteData) \
// A struct is a simple object a set of object-valued fields. Including an
// object type in this causes the compiler to generate most of the boilerplate
@ -605,9 +605,9 @@ const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
// If bit 7 is clear, then bit 3 indicates whether this two-byte
// string actually contains ASCII data.
const uint32_t kAsciiDataHintMask = 0x08;
const uint32_t kAsciiDataHintTag = 0x08;
// string actually contains one byte data.
const uint32_t kOneByteDataHintMask = 0x08;
const uint32_t kOneByteDataHintTag = 0x08;
// If bit 7 is clear and string representation indicates an external string,
// then bit 4 indicates whether the data pointer is cached.
@ -637,13 +637,13 @@ enum InstanceType {
SLICED_ASCII_STRING_TYPE = kOneByteStringTag | kSlicedStringTag,
EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag,
EXTERNAL_ASCII_STRING_TYPE = kOneByteStringTag | kExternalStringTag,
EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
EXTERNAL_STRING_TYPE | kAsciiDataHintTag,
EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE =
EXTERNAL_STRING_TYPE | kOneByteDataHintTag,
SHORT_EXTERNAL_STRING_TYPE = EXTERNAL_STRING_TYPE | kShortExternalStringTag,
SHORT_EXTERNAL_ASCII_STRING_TYPE =
EXTERNAL_ASCII_STRING_TYPE | kShortExternalStringTag,
SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kShortExternalStringTag,
SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE =
EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE | kShortExternalStringTag,
INTERNALIZED_STRING_TYPE = STRING_TYPE | kInternalizedTag,
ASCII_INTERNALIZED_STRING_TYPE = ASCII_STRING_TYPE | kInternalizedTag,
@ -653,14 +653,14 @@ enum InstanceType {
EXTERNAL_INTERNALIZED_STRING_TYPE = EXTERNAL_STRING_TYPE | kInternalizedTag,
EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE =
EXTERNAL_ASCII_STRING_TYPE | kInternalizedTag,
EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE =
EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kInternalizedTag,
EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE =
EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE | kInternalizedTag,
SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE =
SHORT_EXTERNAL_STRING_TYPE | kInternalizedTag,
SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE =
SHORT_EXTERNAL_ASCII_STRING_TYPE | kInternalizedTag,
SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE =
SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kInternalizedTag,
SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE =
SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE | kInternalizedTag,
// Non-string names
SYMBOL_TYPE = kNotStringTag, // LAST_NAME_TYPE, FIRST_NONSTRING_TYPE
@ -7636,7 +7636,7 @@ class String: public Name {
// NOTE: this should be considered only a hint. False negatives are
// possible.
inline bool HasOnlyAsciiChars();
inline bool HasOnlyOneByteChars();
inline bool IsOneByteConvertible();

View File

@ -4913,16 +4913,16 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ ret(2 * kPointerSize);
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
// to contain only ASCII characters.
// to contain only one byte characters.
// rcx: first instance type AND second instance type.
// r8: first instance type.
// r9: second instance type.
__ testb(rcx, Immediate(kAsciiDataHintMask));
__ testb(rcx, Immediate(kOneByteDataHintMask));
__ j(not_zero, &ascii_data);
__ xor_(r8, r9);
STATIC_ASSERT(kOneByteStringTag != 0 && kAsciiDataHintTag != 0);
__ andb(r8, Immediate(kOneByteStringTag | kAsciiDataHintTag));
__ cmpb(r8, Immediate(kOneByteStringTag | kAsciiDataHintTag));
STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
__ andb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag));
__ cmpb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag));
__ j(equal, &ascii_data);
// Allocate a two byte cons string.
__ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime);