Index: src/ia32/code-stubs-ia32.cc |
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc |
index eabf201d7877c7f6f4e8baa97e31c5ac24a44c45..b035be137407024d684097e6f2b7bb0038993a51 100644 |
--- a/src/ia32/code-stubs-ia32.cc |
+++ b/src/ia32/code-stubs-ia32.cc |
@@ -5474,7 +5474,7 @@ void StringCharAtGenerator::GenerateSlow( |
void StringAddStub::Generate(MacroAssembler* masm) { |
- Label string_add_runtime, call_builtin; |
+ Label call_runtime, call_builtin; |
Builtins::JavaScript builtin_id = Builtins::ADD; |
// Load the two arguments. |
@@ -5483,14 +5483,14 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// Make sure that both arguments are strings if not known in advance. |
if (flags_ == NO_STRING_ADD_FLAGS) { |
- __ JumpIfSmi(eax, &string_add_runtime); |
+ __ JumpIfSmi(eax, &call_runtime); |
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); |
- __ j(above_equal, &string_add_runtime); |
+ __ j(above_equal, &call_runtime); |
// First argument is a a string, test second. |
- __ JumpIfSmi(edx, &string_add_runtime); |
+ __ JumpIfSmi(edx, &call_runtime); |
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); |
- __ j(above_equal, &string_add_runtime); |
+ __ j(above_equal, &call_runtime); |
} else { |
// Here at least one of the arguments is definitely a string. |
// We convert the one that is not known to be a string. |
@@ -5541,15 +5541,14 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ add(ebx, ecx); |
STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); |
// Handle exceptionally long strings in the runtime system. |
- __ j(overflow, &string_add_runtime); |
+ __ j(overflow, &call_runtime); |
// Use the symbol table when adding two one character strings, as it |
// helps later optimizations to return a symbol here. |
__ cmp(ebx, Immediate(Smi::FromInt(2))); |
__ j(not_equal, &longer_than_two); |
// Check that both strings are non-external ascii strings. |
- __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, |
- &string_add_runtime); |
+ __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); |
// Get the two characters forming the new string. |
__ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
@@ -5574,11 +5573,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
__ bind(&make_two_character_string_no_reload); |
__ IncrementCounter(counters->string_add_make_two_char(), 1); |
- __ AllocateAsciiString(eax, // Result. |
- 2, // Length. |
- edi, // Scratch 1. |
- edx, // Scratch 2. |
- &string_add_runtime); |
+ __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); |
// Pack both characters in ebx. |
__ shl(ecx, kBitsPerByte); |
__ or_(ebx, ecx); |
@@ -5603,10 +5598,10 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
__ test(ecx, Immediate(kStringEncodingMask)); |
- __ j(zero, &non_ascii); |
+ __ j(zero, &non_ascii, Label::kNear); |
__ bind(&ascii_data); |
// Allocate an acsii cons string. |
- __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |
+ __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); |
__ bind(&allocated); |
// Fill the fields of the cons string. |
if (FLAG_debug_code) __ AbortIfNotSmi(ebx); |
@@ -5633,64 +5628,95 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); |
__ j(equal, &ascii_data); |
// Allocate a two byte cons string. |
- __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); |
+ __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); |
__ jmp(&allocated); |
- // Handle creating a flat result. First check that both strings are not |
- // external strings. |
+ // 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. |
// eax: first string |
// ebx: length of resulting flat string as a smi |
// edx: second string |
+ Label first_prepared, second_prepared; |
+ Label first_is_sequential, second_is_sequential; |
__ bind(&string_add_flat_result); |
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
- __ and_(ecx, kStringRepresentationMask); |
- __ cmp(ecx, kExternalStringTag); |
- __ j(equal, &string_add_runtime); |
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
- __ and_(ecx, kStringRepresentationMask); |
- __ cmp(ecx, kExternalStringTag); |
- __ j(equal, &string_add_runtime); |
- // We cannot encounter sliced strings here since: |
- STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
- // Now check if both strings are ascii strings. |
- // eax: first string |
- // ebx: length of resulting flat string as a smi |
- // edx: second string |
- Label non_ascii_string_add_flat_result; |
- STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
- STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
- __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); |
+ // ecx: instance type of first string |
+ STATIC_ASSERT(kSeqStringTag == 0); |
+ __ test_b(ecx, kStringRepresentationMask); |
+ __ j(zero, &first_is_sequential, Label::kNear); |
+ // Rule out short external string and prepare it so that offset-wise, it |
+ // looks like a sequential string. |
+ STATIC_ASSERT(kShortExternalStringTag != 0); |
+ __ test_b(ecx, kShortExternalStringMask); |
+ __ j(not_zero, &call_runtime); |
+ __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); |
+ STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
+ __ jmp(&first_prepared, Label::kNear); |
+ __ bind(&first_is_sequential); |
+ __ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ bind(&first_prepared); |
+ |
+ __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
+ __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |
+ // Check whether both strings have same encoding. |
+ // edi: instance type of second string |
+ __ xor_(ecx, edi); |
+ __ test_b(ecx, kStringEncodingMask); |
+ __ j(not_zero, &call_runtime); |
+ STATIC_ASSERT(kSeqStringTag == 0); |
+ __ test_b(edi, kStringRepresentationMask); |
+ __ j(zero, &second_is_sequential, Label::kNear); |
+ // Rule out short external string and prepare it so that offset-wise, it |
+ // looks like a sequential string. |
+ STATIC_ASSERT(kShortExternalStringTag != 0); |
+ __ test_b(edi, kShortExternalStringMask); |
+ __ j(not_zero, &call_runtime); |
+ __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); |
+ STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
+ __ jmp(&second_prepared, Label::kNear); |
+ __ bind(&second_is_sequential); |
+ __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ bind(&second_prepared); |
+ |
+ // Push the addresses of both strings' first characters onto the stack. |
+ __ push(edx); |
+ __ push(eax); |
+ |
+ Label non_ascii_string_add_flat_result, call_runtime_drop_two; |
+ // edi: instance type of second string |
+ // First string and second string have the same encoding. |
+ STATIC_ASSERT(kTwoByteStringTag == 0); |
+ __ test_b(edi, kStringEncodingMask); |
__ j(zero, &non_ascii_string_add_flat_result); |
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); |
- __ j(zero, &string_add_runtime); |
- // Both strings are ascii strings. As they are short they are both flat. |
+ // Both strings are ascii strings. |
// ebx: length of resulting flat string as a smi |
__ SmiUntag(ebx); |
- __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
+ __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); |
// eax: result string |
__ mov(ecx, eax); |
// Locate first character of result. |
__ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
- // Load first argument and locate first character. |
- __ mov(edx, Operand(esp, 2 * kPointerSize)); |
+ // Load first argument's length and first character location. Account for |
+ // values currently on the stack when fetching arguments from it. |
+ __ mov(edx, Operand(esp, 4 * kPointerSize)); |
__ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
__ SmiUntag(edi); |
- __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ pop(edx); |
// eax: result string |
// ecx: first character of result |
// edx: first char of first argument |
// edi: length of first argument |
StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
- // Load second argument and locate first character. |
- __ mov(edx, Operand(esp, 1 * kPointerSize)); |
+ // Load second argument's length and first character location. Account for |
+ // values currently on the stack when fetching arguments from it. |
+ __ mov(edx, Operand(esp, 2 * kPointerSize)); |
__ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
__ SmiUntag(edi); |
- __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ pop(edx); |
// eax: result string |
// ecx: next character of result |
// edx: first char of second argument |
@@ -5704,34 +5730,31 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// ebx: length of resulting flat string as a smi |
// edx: second string |
__ bind(&non_ascii_string_add_flat_result); |
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); |
- __ j(not_zero, &string_add_runtime); |
- // Both strings are two byte strings. As they are short they are both |
- // flat. |
+ // Both strings are two byte strings. |
__ SmiUntag(ebx); |
- __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
+ __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); |
// eax: result string |
__ mov(ecx, eax); |
// Locate first character of result. |
__ add(ecx, |
Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
- // Load first argument and locate first character. |
- __ mov(edx, Operand(esp, 2 * kPointerSize)); |
+ // Load second argument's length and first character location. Account for |
+ // values currently on the stack when fetching arguments from it. |
+ __ mov(edx, Operand(esp, 4 * kPointerSize)); |
__ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
__ SmiUntag(edi); |
- __ add(edx, |
- Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
+ __ pop(edx); |
// eax: result string |
// ecx: first character of result |
// edx: first char of first argument |
// edi: length of first argument |
StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
- // Load second argument and locate first character. |
- __ mov(edx, Operand(esp, 1 * kPointerSize)); |
+ // Load second argument's length and first character location. Account for |
+ // values currently on the stack when fetching arguments from it. |
+ __ mov(edx, Operand(esp, 2 * kPointerSize)); |
__ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
__ SmiUntag(edi); |
- __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ pop(edx); |
// eax: result string |
// ecx: next character of result |
// edx: first char of second argument |
@@ -5740,8 +5763,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
__ IncrementCounter(counters->string_add_native(), 1); |
__ ret(2 * kPointerSize); |
+ // Recover stack pointer before jumping to runtime. |
+ __ bind(&call_runtime_drop_two); |
+ __ Drop(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()) { |