| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 4029)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -9000,16 +9000,11 @@
|
| // rbx: length of first string
|
| // rcx: length of second string
|
| // rdx: second string
|
| - // r8: instance type of first string if string check was performed above
|
| - // r9: instance type of first string if string check was performed above
|
| - Label string_add_flat_result;
|
| + // r8: map of first string if string check was performed above
|
| + // r9: map of second string if string check was performed above
|
| + Label string_add_flat_result, longer_than_two;
|
| __ bind(&both_not_zero_length);
|
| - // Look at the length of the result of adding the two strings.
|
| - __ addl(rbx, rcx);
|
| - // Use the runtime system when adding two one character strings, as it
|
| - // contains optimizations for this specific case using the symbol table.
|
| - __ cmpl(rbx, Immediate(2));
|
| - __ j(equal, &string_add_runtime);
|
| +
|
| // If arguments where known to be strings, maps are not loaded to r8 and r9
|
| // by the code above.
|
| if (!string_check_) {
|
| @@ -9019,6 +9014,35 @@
|
| // Get the instance types of the two strings as they will be needed soon.
|
| __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset));
|
| __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
|
| +
|
| + // Look at the length of the result of adding the two strings.
|
| + __ addl(rbx, rcx);
|
| + // Use the runtime system when adding two one character strings, as it
|
| + // contains optimizations for this specific case using the symbol table.
|
| + __ cmpl(rbx, Immediate(2));
|
| + __ j(not_equal, &longer_than_two);
|
| +
|
| + // Check that both strings are non-external ascii strings.
|
| + __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
|
| + &string_add_runtime);
|
| +
|
| + // Get the two characters forming the sub string.
|
| + __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
|
| + __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
|
| +
|
| + // Try to lookup two character string in symbol table. If it is not found
|
| + // just allocate a new one.
|
| + Label make_two_character_string, make_flat_ascii_string;
|
| + GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, r14, r12, rdi, r15,
|
| + &make_two_character_string);
|
| + __ IncrementCounter(&Counters::string_add_native, 1);
|
| + __ ret(2 * kPointerSize);
|
| +
|
| + __ bind(&make_two_character_string);
|
| + __ Set(rbx, 2);
|
| + __ jmp(&make_flat_ascii_string);
|
| +
|
| + __ bind(&longer_than_two);
|
| // Check if resulting string will be flat.
|
| __ cmpl(rbx, Immediate(String::kMinNonFlatLength));
|
| __ j(below, &string_add_flat_result);
|
| @@ -9085,6 +9109,8 @@
|
| __ j(zero, &non_ascii_string_add_flat_result);
|
| __ testl(r9, Immediate(kAsciiStringTag));
|
| __ j(zero, &string_add_runtime);
|
| +
|
| + __ bind(&make_flat_ascii_string);
|
| // Both strings are ascii strings. As they are short they are both flat.
|
| __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime);
|
| // rcx: result string
|
| @@ -9235,7 +9261,180 @@
|
| __ bind(&done);
|
| }
|
|
|
| +void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
|
| + Register c1,
|
| + Register c2,
|
| + Register scratch1,
|
| + Register scratch2,
|
| + Register scratch3,
|
| + Register scratch4,
|
| + Label* not_found) {
|
| + // Register scratch3 is the general scratch register in this function.
|
| + Register scratch = scratch3;
|
|
|
| + // Make sure that both characters are not digits as such strings has a
|
| + // different hash algorithm. Don't try to look for these in the symbol table.
|
| + Label not_array_index;
|
| + __ movq(scratch, c1);
|
| + __ subq(scratch, Immediate(static_cast<int>('0')));
|
| + __ cmpq(scratch, Immediate(static_cast<int>('9' - '0')));
|
| + __ j(above, ¬_array_index);
|
| + __ movq(scratch, c2);
|
| + __ subq(scratch, Immediate(static_cast<int>('0')));
|
| + __ cmpq(scratch, Immediate(static_cast<int>('9' - '0')));
|
| + __ j(below_equal, not_found);
|
| +
|
| + __ bind(¬_array_index);
|
| + // Calculate the two character string hash.
|
| + Register hash = scratch1;
|
| + GenerateHashInit(masm, hash, c1, scratch);
|
| + GenerateHashAddCharacter(masm, hash, c2, scratch);
|
| + GenerateHashGetHash(masm, hash, scratch);
|
| +
|
| + // Collect the two characters in a register.
|
| + Register chars = c1;
|
| + __ shl(c2, Immediate(kBitsPerByte));
|
| + __ orl(chars, c2);
|
| +
|
| + // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
|
| + // hash: hash of two character string.
|
| +
|
| + // Load the symbol table.
|
| + Register symbol_table = c2;
|
| + __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
|
| +
|
| + // Calculate capacity mask from the symbol table capacity.
|
| + Register mask = scratch2;
|
| + __ movq(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
|
| + __ SmiToInteger32(mask, mask);
|
| + __ decl(mask);
|
| +
|
| + Register undefined = scratch4;
|
| + __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
|
| +
|
| + // Registers
|
| + // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
|
| + // hash: hash of two character string (32-bit int)
|
| + // symbol_table: symbol table
|
| + // mask: capacity mask (32-bit int)
|
| + // undefined: undefined value
|
| + // scratch: -
|
| +
|
| + // Perform a number of probes in the symbol table.
|
| + static const int kProbes = 4;
|
| + Label found_in_symbol_table;
|
| + Label next_probe[kProbes];
|
| + for (int i = 0; i < kProbes; i++) {
|
| + // Calculate entry in symbol table.
|
| + __ movl(scratch, hash);
|
| + if (i > 0) {
|
| + __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
|
| + }
|
| + __ andl(scratch, mask);
|
| +
|
| + // Load the entry from the symble table.
|
| + Register candidate = scratch; // Scratch register contains candidate.
|
| + ASSERT_EQ(1, SymbolTable::kEntrySize);
|
| + __ movq(candidate,
|
| + FieldOperand(symbol_table,
|
| + scratch,
|
| + times_pointer_size,
|
| + SymbolTable::kElementsStartOffset));
|
| +
|
| + // If entry is undefined no string with this hash can be found.
|
| + __ cmpq(candidate, undefined);
|
| + __ j(equal, not_found);
|
| +
|
| + // If length is not 2 the string is not a candidate.
|
| + __ cmpl(FieldOperand(candidate, String::kLengthOffset), Immediate(2));
|
| + __ j(not_equal, &next_probe[i]);
|
| +
|
| + // We use kScratchRegister as a temporary register in assumption that
|
| + // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly
|
| + Register temp = kScratchRegister;
|
| +
|
| + // Check that the candidate is a non-external ascii string.
|
| + __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset));
|
| + __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
|
| + __ JumpIfInstanceTypeIsNotSequentialAscii(
|
| + temp, temp, &next_probe[i]);
|
| +
|
| + // Check if the two characters match.
|
| + __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
|
| + __ andl(temp, Immediate(0x0000ffff));
|
| + __ cmpl(chars, temp);
|
| + __ j(equal, &found_in_symbol_table);
|
| + __ bind(&next_probe[i]);
|
| + }
|
| +
|
| + // No matching 2 character string found by probing.
|
| + __ jmp(not_found);
|
| +
|
| + // Scratch register contains result when we fall through to here.
|
| + Register result = scratch;
|
| + __ bind(&found_in_symbol_table);
|
| + if (!result.is(rax)) {
|
| + __ movq(rax, result);
|
| + }
|
| +}
|
| +
|
| +
|
| +void StringStubBase::GenerateHashInit(MacroAssembler* masm,
|
| + Register hash,
|
| + Register character,
|
| + Register scratch) {
|
| + // hash = character + (character << 10);
|
| + __ movl(hash, character);
|
| + __ shll(hash, Immediate(10));
|
| + __ addl(hash, character);
|
| + // hash ^= hash >> 6;
|
| + __ movl(scratch, hash);
|
| + __ sarl(scratch, Immediate(6));
|
| + __ xorl(hash, scratch);
|
| +}
|
| +
|
| +
|
| +void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
|
| + Register hash,
|
| + Register character,
|
| + Register scratch) {
|
| + // hash += character;
|
| + __ addl(hash, character);
|
| + // hash += hash << 10;
|
| + __ movl(scratch, hash);
|
| + __ shll(scratch, Immediate(10));
|
| + __ addl(hash, scratch);
|
| + // hash ^= hash >> 6;
|
| + __ movl(scratch, hash);
|
| + __ sarl(scratch, Immediate(6));
|
| + __ xorl(hash, scratch);
|
| +}
|
| +
|
| +
|
| +void StringStubBase::GenerateHashGetHash(MacroAssembler* masm,
|
| + Register hash,
|
| + Register scratch) {
|
| + // hash += hash << 3;
|
| + __ movl(scratch, hash);
|
| + __ shll(scratch, Immediate(3));
|
| + __ addl(hash, scratch);
|
| + // hash ^= hash >> 11;
|
| + __ movl(scratch, hash);
|
| + __ sarl(scratch, Immediate(11));
|
| + __ xorl(hash, scratch);
|
| + // hash += hash << 15;
|
| + __ movl(scratch, hash);
|
| + __ shll(scratch, Immediate(15));
|
| + __ addl(hash, scratch);
|
| +
|
| + // if (hash == 0) hash = 27;
|
| + Label hash_not_zero;
|
| + __ testl(hash, hash);
|
| + __ j(not_zero, &hash_not_zero);
|
| + __ movl(hash, Immediate(27));
|
| + __ bind(&hash_not_zero);
|
| +}
|
| +
|
| void SubStringStub::Generate(MacroAssembler* masm) {
|
| Label runtime;
|
|
|
| @@ -9261,25 +9460,55 @@
|
| // rax: string
|
| // rbx: instance type
|
| // Calculate length of sub string using the smi values.
|
| + Label result_longer_than_two;
|
| __ movq(rcx, Operand(rsp, kToOffset));
|
| __ movq(rdx, Operand(rsp, kFromOffset));
|
| __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime);
|
|
|
| __ SmiSub(rcx, rcx, rdx, NULL); // Overflow doesn't happen.
|
| __ j(negative, &runtime);
|
| - // Handle sub-strings of length 2 and less in the runtime system.
|
| + // Special handling of sub-strings of length 1 and 2. One character strings
|
| + // are handled in the runtime system (looked up in the single character
|
| + // cache). Two character strings are looked for in the symbol cache.
|
| __ SmiToInteger32(rcx, rcx);
|
| __ cmpl(rcx, Immediate(2));
|
| - __ j(below_equal, &runtime);
|
| + __ j(greater, &result_longer_than_two);
|
| + __ j(less, &runtime);
|
|
|
| + // Sub string of length 2 requested.
|
| // rax: string
|
| // rbx: instance type
|
| + // rcx: sub string length (value is 2)
|
| + // rdx: from index (smi)
|
| + __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime);
|
| +
|
| + // Get the two characters forming the sub string.
|
| + __ SmiToInteger32(rdx, rdx); // From index is no longer smi.
|
| + __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize));
|
| + __ movzxbq(rcx,
|
| + FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1));
|
| +
|
| + // Try to lookup two character string in symbol table.
|
| + Label make_two_character_string;
|
| + GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, rax, rdx, rdi, r14,
|
| + &make_two_character_string);
|
| + __ ret(3 * kPointerSize);
|
| +
|
| + __ bind(&make_two_character_string);
|
| + // Setup registers for allocating the two character string.
|
| + __ movq(rax, Operand(rsp, kStringOffset));
|
| + __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
|
| + __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
|
| + __ Set(rcx, 2);
|
| +
|
| + __ bind(&result_longer_than_two);
|
| +
|
| + // rax: string
|
| + // rbx: instance type
|
| // rcx: result string length
|
| // Check for flat ascii string
|
| Label non_ascii_flat;
|
| - __ and_(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask));
|
| - __ cmpb(rbx, Immediate(kSeqStringTag | kAsciiStringTag));
|
| - __ j(not_equal, &non_ascii_flat);
|
| + __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat);
|
|
|
| // Allocate the result.
|
| __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime);
|
|
|