| Index: src/x64/code-stubs-x64.cc
 | 
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
 | 
| index 1e68bdf8e8f52eb28ea096f84c338a4ac1b42206..63076dccfa6ecab438209da5eabed639a048bdd7 100644
 | 
| --- a/src/x64/code-stubs-x64.cc
 | 
| +++ b/src/x64/code-stubs-x64.cc
 | 
| @@ -350,7 +350,7 @@ void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void NewStringAddStub::InitializeInterfaceDescriptor(
 | 
| +void StringAddStub::InitializeInterfaceDescriptor(
 | 
|      Isolate* isolate,
 | 
|      CodeStubInterfaceDescriptor* descriptor) {
 | 
|    static Register registers[] = { rdx, rax };
 | 
| @@ -3244,365 +3244,6 @@ void StringCharFromCodeGenerator::GenerateSlow(
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void StringAddStub::Generate(MacroAssembler* masm) {
 | 
| -  Label call_runtime, call_builtin;
 | 
| -  Builtins::JavaScript builtin_id = Builtins::ADD;
 | 
| -
 | 
| -  // Load the two arguments.
 | 
| -  StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
 | 
| -  __ movp(rax, args.GetArgumentOperand(0));  // First argument (left).
 | 
| -  __ movp(rdx, args.GetArgumentOperand(1));  // Second argument (right).
 | 
| -
 | 
| -  // Make sure that both arguments are strings if not known in advance.
 | 
| -  // Otherwise, at least one of the arguments is definitely a string,
 | 
| -  // and we convert the one that is not known to be a string.
 | 
| -  if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
 | 
| -    ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
 | 
| -    ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
 | 
| -    __ JumpIfSmi(rax, &call_runtime);
 | 
| -    __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
 | 
| -    __ j(above_equal, &call_runtime);
 | 
| -
 | 
| -    // First argument is a a string, test second.
 | 
| -    __ JumpIfSmi(rdx, &call_runtime);
 | 
| -    __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
 | 
| -    __ j(above_equal, &call_runtime);
 | 
| -  } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
 | 
| -    ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
 | 
| -    GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi,
 | 
| -                            &call_builtin);
 | 
| -    builtin_id = Builtins::STRING_ADD_RIGHT;
 | 
| -  } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
 | 
| -    ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
 | 
| -    GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi,
 | 
| -                            &call_builtin);
 | 
| -    builtin_id = Builtins::STRING_ADD_LEFT;
 | 
| -  }
 | 
| -
 | 
| -  // Both arguments are strings.
 | 
| -  // rax: first string
 | 
| -  // rdx: second string
 | 
| -  // Check if either of the strings are empty. In that case return the other.
 | 
| -  Label second_not_zero_length, both_not_zero_length;
 | 
| -  __ movp(rcx, FieldOperand(rdx, String::kLengthOffset));
 | 
| -  __ SmiTest(rcx);
 | 
| -  __ j(not_zero, &second_not_zero_length, Label::kNear);
 | 
| -  // Second string is empty, result is first string which is already in rax.
 | 
| -  Counters* counters = masm->isolate()->counters();
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -  __ bind(&second_not_zero_length);
 | 
| -  __ movp(rbx, FieldOperand(rax, String::kLengthOffset));
 | 
| -  __ SmiTest(rbx);
 | 
| -  __ j(not_zero, &both_not_zero_length, Label::kNear);
 | 
| -  // First string is empty, result is second string which is in rdx.
 | 
| -  __ movp(rax, rdx);
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -
 | 
| -  // Both strings are non-empty.
 | 
| -  // rax: first string
 | 
| -  // rbx: length of first string
 | 
| -  // rcx: length of second string
 | 
| -  // rdx: second string
 | 
| -  // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS)
 | 
| -  // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS)
 | 
| -  Label string_add_flat_result, longer_than_two;
 | 
| -  __ bind(&both_not_zero_length);
 | 
| -
 | 
| -  // If arguments where known to be strings, maps are not loaded to r8 and r9
 | 
| -  // by the code above.
 | 
| -  if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
 | 
| -    __ movp(r8, FieldOperand(rax, HeapObject::kMapOffset));
 | 
| -    __ movp(r9, FieldOperand(rdx, HeapObject::kMapOffset));
 | 
| -  }
 | 
| -  // 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.
 | 
| -  STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
 | 
| -  __ SmiAdd(rbx, rbx, rcx);
 | 
| -  // Use the string table when adding two one character strings, as it
 | 
| -  // helps later optimizations to return an internalized string here.
 | 
| -  __ SmiCompare(rbx, Smi::FromInt(2));
 | 
| -  __ j(not_equal, &longer_than_two);
 | 
| -
 | 
| -  // Check that both strings are non-external ASCII strings.
 | 
| -  __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
 | 
| -                                                  &call_runtime);
 | 
| -
 | 
| -  // Get the two characters forming the sub string.
 | 
| -  __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize));
 | 
| -  __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize));
 | 
| -
 | 
| -  // Try to lookup two character string in string table. If it is not found
 | 
| -  // just allocate a new one.
 | 
| -  Label make_two_character_string, make_flat_ascii_string;
 | 
| -  StringHelper::GenerateTwoCharacterStringTableProbe(
 | 
| -      masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -
 | 
| -  __ bind(&make_two_character_string);
 | 
| -  __ Set(rdi, 2);
 | 
| -  __ AllocateAsciiString(rax, rdi, r8, r9, r11, &call_runtime);
 | 
| -  // rbx - first byte: first character
 | 
| -  // rbx - second byte: *maybe* second character
 | 
| -  // Make sure that the second byte of rbx contains the second character.
 | 
| -  __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize));
 | 
| -  __ shll(rcx, Immediate(kBitsPerByte));
 | 
| -  __ orl(rbx, rcx);
 | 
| -  // Write both characters to the new string.
 | 
| -  __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx);
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -
 | 
| -  __ bind(&longer_than_two);
 | 
| -  // Check if resulting string will be flat.
 | 
| -  __ SmiCompare(rbx, Smi::FromInt(ConsString::kMinLength));
 | 
| -  __ j(below, &string_add_flat_result);
 | 
| -  // Handle exceptionally long strings in the runtime system.
 | 
| -  STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
 | 
| -  __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength));
 | 
| -  __ j(above, &call_runtime);
 | 
| -
 | 
| -  // 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.
 | 
| -  // rax: first string
 | 
| -  // rbx: length of resulting flat string
 | 
| -  // rdx: second string
 | 
| -  // r8: instance type of first string
 | 
| -  // r9: instance type of second string
 | 
| -  Label non_ascii, allocated, ascii_data;
 | 
| -  __ movl(rcx, r8);
 | 
| -  __ and_(rcx, r9);
 | 
| -  STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
 | 
| -  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
 | 
| -  __ testl(rcx, Immediate(kStringEncodingMask));
 | 
| -  __ j(zero, &non_ascii);
 | 
| -  __ bind(&ascii_data);
 | 
| -  // Allocate an ASCII cons string.
 | 
| -  __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime);
 | 
| -  __ bind(&allocated);
 | 
| -  // Fill the fields of the cons string.
 | 
| -  __ movp(FieldOperand(rcx, ConsString::kLengthOffset), rbx);
 | 
| -  __ movp(FieldOperand(rcx, ConsString::kHashFieldOffset),
 | 
| -          Immediate(String::kEmptyHashField));
 | 
| -
 | 
| -  Label skip_write_barrier, after_writing;
 | 
| -  ExternalReference high_promotion_mode = ExternalReference::
 | 
| -      new_space_high_promotion_mode_active_address(masm->isolate());
 | 
| -  __ Load(rbx, high_promotion_mode);
 | 
| -  __ testb(rbx, Immediate(1));
 | 
| -  __ j(zero, &skip_write_barrier);
 | 
| -
 | 
| -  __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax);
 | 
| -  __ RecordWriteField(rcx,
 | 
| -                      ConsString::kFirstOffset,
 | 
| -                      rax,
 | 
| -                      rbx,
 | 
| -                      kDontSaveFPRegs);
 | 
| -  __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
 | 
| -  __ RecordWriteField(rcx,
 | 
| -                      ConsString::kSecondOffset,
 | 
| -                      rdx,
 | 
| -                      rbx,
 | 
| -                      kDontSaveFPRegs);
 | 
| -  __ jmp(&after_writing);
 | 
| -
 | 
| -  __ bind(&skip_write_barrier);
 | 
| -  __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax);
 | 
| -  __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
 | 
| -
 | 
| -  __ bind(&after_writing);
 | 
| -
 | 
| -  __ movp(rax, rcx);
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -  __ bind(&non_ascii);
 | 
| -  // At least one of the strings is two-byte. Check whether it happens
 | 
| -  // 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(kOneByteDataHintMask));
 | 
| -  __ j(not_zero, &ascii_data);
 | 
| -  __ xor_(r8, r9);
 | 
| -  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);
 | 
| -  __ jmp(&allocated);
 | 
| -
 | 
| -  // We cannot encounter sliced strings or cons strings here since:
 | 
| -  STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
 | 
| -  // Handle creating a flat result from either external or sequential strings.
 | 
| -  // Locate the first characters' locations.
 | 
| -  // rax: first string
 | 
| -  // rbx: length of resulting flat string as smi
 | 
| -  // rdx: second string
 | 
| -  // r8: instance type of first string
 | 
| -  // r9: instance type of first string
 | 
| -  Label first_prepared, second_prepared;
 | 
| -  Label first_is_sequential, second_is_sequential;
 | 
| -  __ bind(&string_add_flat_result);
 | 
| -
 | 
| -  __ SmiToInteger32(r14, FieldOperand(rax, SeqString::kLengthOffset));
 | 
| -  // r14: length of first string
 | 
| -  STATIC_ASSERT(kSeqStringTag == 0);
 | 
| -  __ testb(r8, Immediate(kStringRepresentationMask));
 | 
| -  __ j(zero, &first_is_sequential, Label::kNear);
 | 
| -  // Rule out short external string and load string resource.
 | 
| -  STATIC_ASSERT(kShortExternalStringTag != 0);
 | 
| -  __ testb(r8, Immediate(kShortExternalStringMask));
 | 
| -  __ j(not_zero, &call_runtime);
 | 
| -  __ movp(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset));
 | 
| -  __ jmp(&first_prepared, Label::kNear);
 | 
| -  __ bind(&first_is_sequential);
 | 
| -  STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
 | 
| -  __ lea(rcx, FieldOperand(rax, SeqOneByteString::kHeaderSize));
 | 
| -  __ bind(&first_prepared);
 | 
| -
 | 
| -  // Check whether both strings have same encoding.
 | 
| -  __ xorl(r8, r9);
 | 
| -  __ testb(r8, Immediate(kStringEncodingMask));
 | 
| -  __ j(not_zero, &call_runtime);
 | 
| -
 | 
| -  __ SmiToInteger32(r15, FieldOperand(rdx, SeqString::kLengthOffset));
 | 
| -  // r15: length of second string
 | 
| -  STATIC_ASSERT(kSeqStringTag == 0);
 | 
| -  __ testb(r9, Immediate(kStringRepresentationMask));
 | 
| -  __ j(zero, &second_is_sequential, Label::kNear);
 | 
| -  // Rule out short external string and load string resource.
 | 
| -  STATIC_ASSERT(kShortExternalStringTag != 0);
 | 
| -  __ testb(r9, Immediate(kShortExternalStringMask));
 | 
| -  __ j(not_zero, &call_runtime);
 | 
| -  __ movp(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset));
 | 
| -  __ jmp(&second_prepared, Label::kNear);
 | 
| -  __ bind(&second_is_sequential);
 | 
| -  STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
 | 
| -  __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize));
 | 
| -  __ bind(&second_prepared);
 | 
| -
 | 
| -  Label non_ascii_string_add_flat_result;
 | 
| -  // r9: instance type of second string
 | 
| -  // First string and second string have the same encoding.
 | 
| -  STATIC_ASSERT(kTwoByteStringTag == 0);
 | 
| -  __ SmiToInteger32(rbx, rbx);
 | 
| -  __ testb(r9, Immediate(kStringEncodingMask));
 | 
| -  __ j(zero, &non_ascii_string_add_flat_result);
 | 
| -
 | 
| -  __ bind(&make_flat_ascii_string);
 | 
| -  // Both strings are ASCII strings. As they are short they are both flat.
 | 
| -  __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime);
 | 
| -  // rax: result string
 | 
| -  // Locate first character of result.
 | 
| -  __ lea(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize));
 | 
| -  // rcx: first char of first string
 | 
| -  // rbx: first character of result
 | 
| -  // r14: length of first string
 | 
| -  StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, true);
 | 
| -  // rbx: next character of result
 | 
| -  // rdx: first char of second string
 | 
| -  // r15: length of second string
 | 
| -  StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, true);
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -
 | 
| -  __ bind(&non_ascii_string_add_flat_result);
 | 
| -  // Both strings are ASCII strings. As they are short they are both flat.
 | 
| -  __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime);
 | 
| -  // rax: result string
 | 
| -  // Locate first character of result.
 | 
| -  __ lea(rbx, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
 | 
| -  // rcx: first char of first string
 | 
| -  // rbx: first character of result
 | 
| -  // r14: length of first string
 | 
| -  StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, false);
 | 
| -  // rbx: next character of result
 | 
| -  // rdx: first char of second string
 | 
| -  // r15: length of second string
 | 
| -  StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false);
 | 
| -  __ IncrementCounter(counters->string_add_native(), 1);
 | 
| -  __ ret(2 * kPointerSize);
 | 
| -
 | 
| -  // Just jump to runtime to add the two strings.
 | 
| -  __ bind(&call_runtime);
 | 
| -  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
 | 
| -
 | 
| -  if (call_builtin.is_linked()) {
 | 
| -    __ bind(&call_builtin);
 | 
| -    __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
 | 
| -  __ push(rax);
 | 
| -  __ push(rdx);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm,
 | 
| -                                            Register temp) {
 | 
| -  __ PopReturnAddressTo(temp);
 | 
| -  __ pop(rdx);
 | 
| -  __ pop(rax);
 | 
| -  __ PushReturnAddressFrom(temp);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
 | 
| -                                            int stack_offset,
 | 
| -                                            Register arg,
 | 
| -                                            Register scratch1,
 | 
| -                                            Register scratch2,
 | 
| -                                            Register scratch3,
 | 
| -                                            Label* slow) {
 | 
| -  // First check if the argument is already a string.
 | 
| -  Label not_string, done;
 | 
| -  __ JumpIfSmi(arg, ¬_string);
 | 
| -  __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
 | 
| -  __ j(below, &done);
 | 
| -
 | 
| -  // Check the number to string cache.
 | 
| -  __ bind(¬_string);
 | 
| -  // Puts the cached result into scratch1.
 | 
| -  __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow);
 | 
| -  __ movp(arg, scratch1);
 | 
| -  __ movp(Operand(rsp, stack_offset), arg);
 | 
| -  __ bind(&done);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
 | 
| -                                          Register dest,
 | 
| -                                          Register src,
 | 
| -                                          Register count,
 | 
| -                                          bool ascii) {
 | 
| -  Label loop;
 | 
| -  __ bind(&loop);
 | 
| -  // This loop just copies one character at a time, as it is only used for very
 | 
| -  // short strings.
 | 
| -  if (ascii) {
 | 
| -    __ movb(kScratchRegister, Operand(src, 0));
 | 
| -    __ movb(Operand(dest, 0), kScratchRegister);
 | 
| -    __ incq(src);
 | 
| -    __ incq(dest);
 | 
| -  } else {
 | 
| -    __ movzxwl(kScratchRegister, Operand(src, 0));
 | 
| -    __ movw(Operand(dest, 0), kScratchRegister);
 | 
| -    __ addq(src, Immediate(2));
 | 
| -    __ addq(dest, Immediate(2));
 | 
| -  }
 | 
| -  __ decl(count);
 | 
| -  __ j(not_zero, &loop);
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
 | 
|                                               Register dest,
 | 
|                                               Register src,
 | 
| @@ -3659,133 +3300,6 @@ void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
 | 
|    __ bind(&done);
 | 
|  }
 | 
|  
 | 
| -void StringHelper::GenerateTwoCharacterStringTableProbe(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 string table.
 | 
| -  Label not_array_index;
 | 
| -  __ leal(scratch, Operand(c1, -'0'));
 | 
| -  __ cmpl(scratch, Immediate(static_cast<int>('9' - '0')));
 | 
| -  __ j(above, ¬_array_index, Label::kNear);
 | 
| -  __ leal(scratch, Operand(c2, -'0'));
 | 
| -  __ cmpl(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 string table.
 | 
| -  Register string_table = c2;
 | 
| -  __ LoadRoot(string_table, Heap::kStringTableRootIndex);
 | 
| -
 | 
| -  // Calculate capacity mask from the string table capacity.
 | 
| -  Register mask = scratch2;
 | 
| -  __ SmiToInteger32(mask,
 | 
| -                    FieldOperand(string_table, StringTable::kCapacityOffset));
 | 
| -  __ decl(mask);
 | 
| -
 | 
| -  Register map = scratch4;
 | 
| -
 | 
| -  // 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)
 | 
| -  // string_table: string table
 | 
| -  // mask:         capacity mask (32-bit int)
 | 
| -  // map:          -
 | 
| -  // scratch:      -
 | 
| -
 | 
| -  // Perform a number of probes in the string table.
 | 
| -  static const int kProbes = 4;
 | 
| -  Label found_in_string_table;
 | 
| -  Label next_probe[kProbes];
 | 
| -  Register candidate = scratch;  // Scratch register contains candidate.
 | 
| -  for (int i = 0; i < kProbes; i++) {
 | 
| -    // Calculate entry in string table.
 | 
| -    __ movl(scratch, hash);
 | 
| -    if (i > 0) {
 | 
| -      __ addl(scratch, Immediate(StringTable::GetProbeOffset(i)));
 | 
| -    }
 | 
| -    __ andl(scratch, mask);
 | 
| -
 | 
| -    // Load the entry from the string table.
 | 
| -    STATIC_ASSERT(StringTable::kEntrySize == 1);
 | 
| -    __ movp(candidate,
 | 
| -            FieldOperand(string_table,
 | 
| -                         scratch,
 | 
| -                         times_pointer_size,
 | 
| -                         StringTable::kElementsStartOffset));
 | 
| -
 | 
| -    // If entry is undefined no string with this hash can be found.
 | 
| -    Label is_string;
 | 
| -    __ CmpObjectType(candidate, ODDBALL_TYPE, map);
 | 
| -    __ j(not_equal, &is_string, Label::kNear);
 | 
| -
 | 
| -    __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex);
 | 
| -    __ j(equal, not_found);
 | 
| -    // Must be the hole (deleted entry).
 | 
| -    if (FLAG_debug_code) {
 | 
| -      __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
 | 
| -      __ cmpq(kScratchRegister, candidate);
 | 
| -      __ Assert(equal, kOddballInStringTableIsNotUndefinedOrTheHole);
 | 
| -    }
 | 
| -    __ jmp(&next_probe[i]);
 | 
| -
 | 
| -    __ bind(&is_string);
 | 
| -
 | 
| -    // If length is not 2 the string is not a candidate.
 | 
| -    __ SmiCompare(FieldOperand(candidate, String::kLengthOffset),
 | 
| -                  Smi::FromInt(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.
 | 
| -    __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset));
 | 
| -    __ JumpIfInstanceTypeIsNotSequentialAscii(
 | 
| -        temp, temp, &next_probe[i]);
 | 
| -
 | 
| -    // Check if the two characters match.
 | 
| -    __ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize));
 | 
| -    __ andl(temp, Immediate(0x0000ffff));
 | 
| -    __ cmpl(chars, temp);
 | 
| -    __ j(equal, &found_in_string_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 = candidate;
 | 
| -  __ bind(&found_in_string_table);
 | 
| -  if (!result.is(rax)) {
 | 
| -    __ movp(rax, result);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
|  
 | 
|  void StringHelper::GenerateHashInit(MacroAssembler* masm,
 | 
|                                      Register hash,
 | 
| 
 |