Index: src/mips/code-stubs-mips.cc |
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc |
index 47f24a0ddfcbaa3256e73a072af4d4595a66ce7c..33968deea68d85b0073a6fa57fe490e4ea37d839 100644 |
--- a/src/mips/code-stubs-mips.cc |
+++ b/src/mips/code-stubs-mips.cc |
@@ -6417,7 +6417,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) { |
void StringAddStub::Generate(MacroAssembler* masm) { |
- Label string_add_runtime, call_builtin; |
+ Label call_runtime, call_builtin; |
Builtins::JavaScript builtin_id = Builtins::ADD; |
Counters* counters = masm->isolate()->counters(); |
@@ -6432,7 +6432,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// Make sure that both arguments are strings if not known in advance. |
if (flags_ == NO_STRING_ADD_FLAGS) { |
- __ JumpIfEitherSmi(a0, a1, &string_add_runtime); |
+ __ JumpIfEitherSmi(a0, a1, &call_runtime); |
// Load instance types. |
__ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
@@ -6442,7 +6442,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// If either is not a string, go to runtime. |
__ Or(t4, t0, Operand(t1)); |
__ And(t4, t4, Operand(kIsNotStringMask)); |
- __ Branch(&string_add_runtime, ne, t4, Operand(zero_reg)); |
+ __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
} else { |
// Here at least one of the arguments is definitely a string. |
// We convert the one that is not known to be a string. |
@@ -6481,8 +6481,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ Branch(&strings_not_empty, ne, t4, Operand(zero_reg)); |
__ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
- __ Addu(sp, sp, Operand(2 * kPointerSize)); |
- __ Ret(); |
+ __ DropAndRet(2); |
__ bind(&strings_not_empty); |
} |
@@ -6515,7 +6514,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
} |
__ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3, |
- &string_add_runtime); |
+ &call_runtime); |
// Get the two characters forming the sub string. |
__ lbu(a2, FieldMemOperand(a0, SeqAsciiString::kHeaderSize)); |
@@ -6525,10 +6524,9 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// just allocate a new one. |
Label make_two_character_string; |
StringHelper::GenerateTwoCharacterSymbolTableProbe( |
- masm, a2, a3, t2, t3, t0, t1, t4, &make_two_character_string); |
+ masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string); |
__ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
- __ Addu(sp, sp, Operand(2 * kPointerSize)); |
- __ Ret(); |
+ __ DropAndRet(2); |
__ bind(&make_two_character_string); |
// Resulting string has length 2 and first chars of two strings |
@@ -6537,11 +6535,10 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// halfword store instruction (which assumes that processor is |
// in a little endian mode). |
__ li(t2, Operand(2)); |
- __ AllocateAsciiString(v0, t2, t0, t1, t4, &string_add_runtime); |
+ __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); |
__ sh(a2, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); |
__ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
- __ Addu(sp, sp, Operand(2 * kPointerSize)); |
- __ Ret(); |
+ __ DropAndRet(2); |
__ bind(&longer_than_two); |
// Check if resulting string will be flat. |
@@ -6551,7 +6548,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
// kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
- __ Branch(&string_add_runtime, hs, t2, Operand(String::kMaxLength + 1)); |
+ __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1)); |
// If result is not supposed to be flat, allocate a cons string object. |
// If both strings are ASCII the result is an ASCII cons string. |
@@ -6570,15 +6567,13 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// Allocate an ASCII cons string. |
__ bind(&ascii_data); |
- __ AllocateAsciiConsString(t3, t2, t0, t1, &string_add_runtime); |
+ __ AllocateAsciiConsString(v0, t2, t0, t1, &call_runtime); |
__ bind(&allocated); |
// Fill the fields of the cons string. |
- __ sw(a0, FieldMemOperand(t3, ConsString::kFirstOffset)); |
- __ sw(a1, FieldMemOperand(t3, ConsString::kSecondOffset)); |
- __ mov(v0, t3); |
+ __ sw(a0, FieldMemOperand(v0, ConsString::kFirstOffset)); |
+ __ sw(a1, FieldMemOperand(v0, ConsString::kSecondOffset)); |
__ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
- __ Addu(sp, sp, Operand(2 * kPointerSize)); |
- __ Ret(); |
+ __ DropAndRet(2); |
__ bind(&non_ascii); |
// At least one of the strings is two-byte. Check whether it happens |
@@ -6596,11 +6591,13 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ Branch(&ascii_data, eq, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
// Allocate a two byte cons string. |
- __ AllocateTwoByteConsString(t3, t2, t0, t1, &string_add_runtime); |
+ __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime); |
__ Branch(&allocated); |
- // Handle creating a flat result. First check that both strings are |
- // sequential and that they have the same encoding. |
+ // We cannot encounter sliced strings or cons strings here since: |
+ STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
+ // Handle creating a flat result from either external or sequential strings. |
+ // Locate the first characters' locations. |
// a0: first string |
// a1: second string |
// a2: length of first string |
@@ -6608,6 +6605,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
// t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
// t2: sum of lengths. |
+ Label first_prepared, second_prepared; |
__ bind(&string_add_flat_result); |
if (flags_ != NO_STRING_ADD_FLAGS) { |
__ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
@@ -6615,101 +6613,86 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
__ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
} |
- // Check that both strings are sequential, meaning that we |
- // branch to runtime if either string tag is non-zero. |
+ // Check whether both strings have same encoding |
+ __ Xor(t3, t0, Operand(t1)); |
+ __ And(t3, t3, Operand(kStringEncodingMask)); |
+ __ Branch(&call_runtime, ne, t3, Operand(zero_reg)); |
+ |
STATIC_ASSERT(kSeqStringTag == 0); |
- __ Or(t4, t0, Operand(t1)); |
- __ And(t4, t4, Operand(kStringRepresentationMask)); |
- __ Branch(&string_add_runtime, ne, t4, Operand(zero_reg)); |
+ __ And(t4, t0, Operand(kStringRepresentationMask)); |
+ |
+ STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
+ Label skip_first_add; |
+ __ Branch(&skip_first_add, ne, t4, Operand(zero_reg)); |
+ __ Branch(USE_DELAY_SLOT, &first_prepared); |
+ __ addiu(t3, a0, SeqAsciiString::kHeaderSize - kHeapObjectTag); |
+ __ bind(&skip_first_add); |
+ // External string: rule out short external string and load string resource. |
+ STATIC_ASSERT(kShortExternalStringTag != 0); |
+ __ And(t4, t0, Operand(kShortExternalStringMask)); |
+ __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
+ __ lw(t3, FieldMemOperand(a0, ExternalString::kResourceDataOffset)); |
+ __ bind(&first_prepared); |
- // Now check if both strings have the same encoding (ASCII/Two-byte). |
- // a0: first string |
- // a1: second string |
+ STATIC_ASSERT(kSeqStringTag == 0); |
+ __ And(t4, t1, Operand(kStringRepresentationMask)); |
+ STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
+ Label skip_second_add; |
+ __ Branch(&skip_second_add, ne, t4, Operand(zero_reg)); |
+ __ Branch(USE_DELAY_SLOT, &second_prepared); |
+ __ addiu(a1, a1, SeqAsciiString::kHeaderSize - kHeapObjectTag); |
+ __ bind(&skip_second_add); |
+ // External string: rule out short external string and load string resource. |
+ STATIC_ASSERT(kShortExternalStringTag != 0); |
+ __ And(t4, t1, Operand(kShortExternalStringMask)); |
+ __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
+ __ lw(a1, FieldMemOperand(a1, ExternalString::kResourceDataOffset)); |
+ __ bind(&second_prepared); |
+ |
+ Label non_ascii_string_add_flat_result; |
+ // t3: first character of first string |
+ // a1: first character of second string |
// a2: length of first string |
// a3: length of second string |
- // t0: first string instance type |
- // t1: second string instance type |
// t2: sum of lengths. |
- Label non_ascii_string_add_flat_result; |
- ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. |
- __ xor_(t3, t1, t0); |
- __ And(t3, t3, Operand(kStringEncodingMask)); |
- __ Branch(&string_add_runtime, ne, t3, Operand(zero_reg)); |
- // And see if it's ASCII (0) or two-byte (1). |
- __ And(t3, t0, Operand(kStringEncodingMask)); |
- __ Branch(&non_ascii_string_add_flat_result, eq, t3, Operand(zero_reg)); |
- |
- // Both strings are sequential ASCII strings. We also know that they are |
- // short (since the sum of the lengths is less than kMinNonFlatLength). |
- // t2: length of resulting flat string |
- __ AllocateAsciiString(t3, t2, t0, t1, t4, &string_add_runtime); |
- // Locate first character of result. |
- __ Addu(t2, t3, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
- // Locate first character of first argument. |
- __ Addu(a0, a0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
- // a0: first character of first string. |
- // a1: second string. |
+ // Both strings have the same encoding. |
+ STATIC_ASSERT(kTwoByteStringTag == 0); |
+ __ And(t4, t1, Operand(kStringEncodingMask)); |
+ __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg)); |
+ |
+ __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); |
+ __ Addu(t2, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ // v0: result string. |
+ // t3: first character of first string. |
+ // a1: first character of second string |
// a2: length of first string. |
// a3: length of second string. |
// t2: first character of result. |
- // t3: result string. |
- StringHelper::GenerateCopyCharacters(masm, t2, a0, a2, t0, true); |
- // Load second argument and locate first character. |
- __ Addu(a1, a1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
- // a1: first character of second string. |
- // a3: length of second string. |
+ StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, true); |
// t2: next character of result. |
- // t3: result string. |
StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true); |
- __ mov(v0, t3); |
__ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
- __ Addu(sp, sp, Operand(2 * kPointerSize)); |
- __ Ret(); |
+ __ DropAndRet(2); |
__ bind(&non_ascii_string_add_flat_result); |
- // Both strings are sequential two byte strings. |
- // a0: first string. |
- // a1: second string. |
- // a2: length of first string. |
- // a3: length of second string. |
- // t2: sum of length of strings. |
- __ AllocateTwoByteString(t3, t2, t0, t1, t4, &string_add_runtime); |
- // a0: first string. |
- // a1: second string. |
- // a2: length of first string. |
- // a3: length of second string. |
- // t3: result string. |
- |
- // Locate first character of result. |
- __ Addu(t2, t3, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
- // Locate first character of first argument. |
- __ Addu(a0, a0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
- |
- // a0: first character of first string. |
- // a1: second string. |
+ __ AllocateTwoByteString(v0, t2, t0, t1, t5, &call_runtime); |
+ __ Addu(t2, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
+ // v0: result string. |
+ // t3: first character of first string. |
+ // a1: first character of second string. |
// a2: length of first string. |
// a3: length of second string. |
// t2: first character of result. |
- // t3: result string. |
- StringHelper::GenerateCopyCharacters(masm, t2, a0, a2, t0, false); |
- |
- // Locate first character of second argument. |
- __ Addu(a1, a1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
- |
- // a1: first character of second string. |
- // a3: length of second string. |
- // t2: next character of result (after copy of first string). |
- // t3: result string. |
+ StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false); |
+ // t2: next character of result. |
StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false); |
- __ mov(v0, t3); |
__ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
- __ Addu(sp, sp, Operand(2 * kPointerSize)); |
- __ Ret(); |
+ __ DropAndRet(2); |
// Just jump to runtime to add the two strings. |
- __ bind(&string_add_runtime); |
+ __ bind(&call_runtime); |
__ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
if (call_builtin.is_linked()) { |