Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 598062: Probe the symbol table for two character strings in native code... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/ia32/macro-assembler-ia32.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 9623 matching lines...) Expand 10 before | Expand all | Expand 10 after
9634 __ mov(eax, edx); 9634 __ mov(eax, edx);
9635 __ IncrementCounter(&Counters::string_add_native, 1); 9635 __ IncrementCounter(&Counters::string_add_native, 1);
9636 __ ret(2 * kPointerSize); 9636 __ ret(2 * kPointerSize);
9637 9637
9638 // Both strings are non-empty. 9638 // Both strings are non-empty.
9639 // eax: first string 9639 // eax: first string
9640 // ebx: length of first string 9640 // ebx: length of first string
9641 // ecx: length of second string 9641 // ecx: length of second string
9642 // edx: second string 9642 // edx: second string
9643 // Look at the length of the result of adding the two strings. 9643 // Look at the length of the result of adding the two strings.
9644 Label string_add_flat_result; 9644 Label string_add_flat_result, longer_than_two;
9645 __ bind(&both_not_zero_length); 9645 __ bind(&both_not_zero_length);
9646 __ add(ebx, Operand(ecx)); 9646 __ add(ebx, Operand(ecx));
9647 // Use the runtime system when adding two one character strings, as it 9647 // Use the runtime system when adding two one character strings, as it
9648 // contains optimizations for this specific case using the symbol table. 9648 // contains optimizations for this specific case using the symbol table.
9649 __ cmp(ebx, 2); 9649 __ cmp(ebx, 2);
9650 __ j(equal, &string_add_runtime); 9650 __ j(not_equal, &longer_than_two);
9651
9652 // Check that both strings are non-external ascii strings.
9653 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx,
9654 &string_add_runtime);
9655
9656 // Get the two characters forming the sub string.
9657 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
9658 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
9659
9660 // Try to lookup two character string in symbol table. If it is not found
9661 // just allocate a new one.
9662 Label make_two_character_string, make_flat_ascii_string;
9663 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi,
9664 &make_two_character_string);
9665 __ ret(2 * kPointerSize);
9666
9667 __ bind(&make_two_character_string);
9668 __ Set(ebx, Immediate(2));
9669 __ jmp(&make_flat_ascii_string);
9670
9671 __ bind(&longer_than_two);
9651 // Check if resulting string will be flat. 9672 // Check if resulting string will be flat.
9652 __ cmp(ebx, String::kMinNonFlatLength); 9673 __ cmp(ebx, String::kMinNonFlatLength);
9653 __ j(below, &string_add_flat_result); 9674 __ j(below, &string_add_flat_result);
9654 // Handle exceptionally long strings in the runtime system. 9675 // Handle exceptionally long strings in the runtime system.
9655 ASSERT((String::kMaxLength & 0x80000000) == 0); 9676 ASSERT((String::kMaxLength & 0x80000000) == 0);
9656 __ cmp(ebx, String::kMaxLength); 9677 __ cmp(ebx, String::kMaxLength);
9657 __ j(above, &string_add_runtime); 9678 __ j(above, &string_add_runtime);
9658 9679
9659 // If result is not supposed to be flat allocate a cons string object. If both 9680 // If result is not supposed to be flat allocate a cons string object. If both
9660 // strings are ascii the result is an ascii cons string. 9681 // strings are ascii the result is an ascii cons string.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
9707 Label non_ascii_string_add_flat_result; 9728 Label non_ascii_string_add_flat_result;
9708 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 9729 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
9709 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 9730 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
9710 ASSERT(kStringEncodingMask == kAsciiStringTag); 9731 ASSERT(kStringEncodingMask == kAsciiStringTag);
9711 __ test(ecx, Immediate(kAsciiStringTag)); 9732 __ test(ecx, Immediate(kAsciiStringTag));
9712 __ j(zero, &non_ascii_string_add_flat_result); 9733 __ j(zero, &non_ascii_string_add_flat_result);
9713 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 9734 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
9714 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 9735 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
9715 __ test(ecx, Immediate(kAsciiStringTag)); 9736 __ test(ecx, Immediate(kAsciiStringTag));
9716 __ j(zero, &string_add_runtime); 9737 __ j(zero, &string_add_runtime);
9738
9739 __ bind(&make_flat_ascii_string);
9717 // Both strings are ascii strings. As they are short they are both flat. 9740 // Both strings are ascii strings. As they are short they are both flat.
9741 // ebx: length of resulting flat string
9718 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); 9742 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
9719 // eax: result string 9743 // eax: result string
9720 __ mov(ecx, eax); 9744 __ mov(ecx, eax);
9721 // Locate first character of result. 9745 // Locate first character of result.
9722 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9746 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
9723 // Load first argument and locate first character. 9747 // Load first argument and locate first character.
9724 __ mov(edx, Operand(esp, 2 * kPointerSize)); 9748 __ mov(edx, Operand(esp, 2 * kPointerSize));
9725 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 9749 __ mov(edi, FieldOperand(edx, String::kLengthOffset));
9726 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 9750 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
9727 // eax: result string 9751 // eax: result string
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
9864 __ mov_b(Operand(dest, 0), scratch); 9888 __ mov_b(Operand(dest, 0), scratch);
9865 __ add(Operand(src), Immediate(1)); 9889 __ add(Operand(src), Immediate(1));
9866 __ add(Operand(dest), Immediate(1)); 9890 __ add(Operand(dest), Immediate(1));
9867 __ sub(Operand(count), Immediate(1)); 9891 __ sub(Operand(count), Immediate(1));
9868 __ j(not_zero, &loop); 9892 __ j(not_zero, &loop);
9869 9893
9870 __ bind(&done); 9894 __ bind(&done);
9871 } 9895 }
9872 9896
9873 9897
9898 void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
9899 Register c1,
9900 Register c2,
9901 Register scratch1,
9902 Register scratch2,
9903 Register scratch3,
9904 Label* not_found) {
9905 // Register scratch3 is the general scratch register in this function.
9906 Register scratch = scratch3;
9907
9908 // Make sure that both characters are not digits as such strings has a
9909 // different hash algorithm. Don't try to look for these in the symbol table.
9910 Label not_array_index;
9911 __ mov(scratch, c1);
9912 __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
9913 __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
9914 __ j(above, &not_array_index);
9915 __ mov(scratch, c2);
9916 __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
9917 __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
9918 __ j(below_equal, not_found);
9919
9920 __ bind(&not_array_index);
9921 // Calculate the two character string hash.
9922 Register hash = scratch1;
9923 GenerateHashInit(masm, hash, c1, scratch);
9924 GenerateHashAddCharacter(masm, hash, c2, scratch);
9925 GenerateHashGetHash(masm, hash, scratch);
9926
9927 // Collect the two characters in a register.
9928 Register chars = c1;
9929 __ shl(c2, kBitsPerByte);
9930 __ or_(chars, Operand(c2));
9931
9932 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
9933 // hash: hash of two character string.
9934
9935 // Load the symbol table.
9936 Register symbol_table = c2;
9937 ExternalReference roots_address = ExternalReference::roots_address();
9938 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
9939 __ mov(symbol_table,
9940 Operand::StaticArray(scratch, times_pointer_size, roots_address));
9941
9942 // Calculate capacity mask from the symbol table capacity.
9943 Register mask = scratch2;
9944 static const int kCapacityOffset =
9945 FixedArray::kHeaderSize +
9946 SymbolTable::kCapacityIndex * kPointerSize;
9947 __ mov(mask, FieldOperand(symbol_table, kCapacityOffset));
9948 __ SmiUntag(mask);
9949 __ sub(Operand(mask), Immediate(1));
9950
9951 // Registers
9952 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
9953 // hash: hash of two character string
9954 // symbol_table: symbol table
9955 // mask: capacity mask
9956 // scratch: -
9957
9958 // Perform a number of probes in the symbol table.
9959 static const int kProbes = 4;
9960 Label found_in_symbol_table;
9961 Label next_probe[kProbes], next_probe_pop_mask[kProbes];
9962 for (int i = 0; i < kProbes; i++) {
9963 // Calculate entry in symbol table.
9964 __ mov(scratch, hash);
9965 if (i > 0) {
9966 __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i)));
9967 }
9968 __ and_(scratch, Operand(mask));
9969
9970 // Load the entry from the symble table.
9971 Register candidate = scratch; // Scratch register contains candidate.
9972 ASSERT_EQ(1, SymbolTableShape::kEntrySize);
9973 static const int kFirstElementOffset =
9974 FixedArray::kHeaderSize +
9975 SymbolTable::kPrefixStartIndex * kPointerSize +
9976 SymbolTableShape::kPrefixSize * kPointerSize;
9977 __ mov(candidate,
9978 FieldOperand(symbol_table,
9979 scratch,
9980 times_pointer_size,
9981 kFirstElementOffset));
9982
9983 // If entry is undefined no string with this hash can be found.
9984 __ cmp(candidate, Factory::undefined_value());
9985 __ j(equal, not_found);
9986
9987 // If length is not 2 the string is not a candidate.
9988 __ cmp(FieldOperand(candidate, String::kLengthOffset), Immediate(2));
9989 __ j(not_equal, &next_probe[i]);
9990
9991 // As we are out of registers save the mask on the stack and use that as a
9992 // temporary.
9993 __ push(mask);
9994 Register temp = mask;
9995
9996 // Check that the candidate is a non-external ascii string.
9997 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset));
9998 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
9999 __ JumpIfInstanceTypeIsNotSequentialAscii(
10000 temp, temp, &next_probe_pop_mask[i]);
10001
10002 // Check if the two characters match.
10003 __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
10004 __ and_(temp, 0x0000ffff);
10005 __ cmp(chars, Operand(temp));
10006 __ j(equal, &found_in_symbol_table);
10007 __ bind(&next_probe_pop_mask[i]);
10008 __ pop(mask);
10009 __ bind(&next_probe[i]);
10010 }
10011
10012 // No matching 2 character string found by probing.
10013 __ jmp(not_found);
10014
10015 // Scratch register contains result when we fall through to here.
10016 Register result = scratch;
10017 __ bind(&found_in_symbol_table);
10018 __ pop(mask); // Pop temporally saved mask from the stack.
10019 if (!result.is(eax)) {
10020 __ mov(eax, result);
10021 }
10022 }
10023
10024
10025 void StringStubBase::GenerateHashInit(MacroAssembler* masm,
10026 Register hash,
10027 Register character,
10028 Register scratch) {
10029 // hash = character + (character << 10);
10030 __ mov(hash, character);
10031 __ shl(hash, 10);
10032 __ add(hash, Operand(character));
10033 // hash ^= hash >> 6;
10034 __ mov(scratch, hash);
10035 __ sar(scratch, 6);
10036 __ xor_(hash, Operand(scratch));
10037 }
10038
10039
10040 void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
10041 Register hash,
10042 Register character,
10043 Register scratch) {
10044 // hash += character;
10045 __ add(hash, Operand(character));
10046 // hash += hash << 10;
10047 __ mov(scratch, hash);
10048 __ shl(scratch, 10);
10049 __ add(hash, Operand(scratch));
10050 // hash ^= hash >> 6;
10051 __ mov(scratch, hash);
10052 __ sar(scratch, 6);
10053 __ xor_(hash, Operand(scratch));
10054 }
10055
10056
10057 void StringStubBase::GenerateHashGetHash(MacroAssembler* masm,
10058 Register hash,
10059 Register scratch) {
10060 // hash += hash << 3;
10061 __ mov(scratch, hash);
10062 __ shl(scratch, 3);
10063 __ add(hash, Operand(scratch));
10064 // hash ^= hash >> 11;
10065 __ mov(scratch, hash);
10066 __ sar(scratch, 11);
10067 __ xor_(hash, Operand(scratch));
10068 // hash += hash << 15;
10069 __ mov(scratch, hash);
10070 __ shl(scratch, 15);
10071 __ add(hash, Operand(scratch));
10072
10073 // if (hash == 0) hash = 27;
10074 Label hash_not_zero;
10075 __ test(hash, Operand(hash));
10076 __ j(not_zero, &hash_not_zero);
10077 __ mov(hash, Immediate(27));
10078 __ bind(&hash_not_zero);
10079 }
10080
10081
9874 void SubStringStub::Generate(MacroAssembler* masm) { 10082 void SubStringStub::Generate(MacroAssembler* masm) {
9875 Label runtime; 10083 Label runtime;
9876 10084
9877 // Stack frame on entry. 10085 // Stack frame on entry.
9878 // esp[0]: return address 10086 // esp[0]: return address
9879 // esp[4]: to 10087 // esp[4]: to
9880 // esp[8]: from 10088 // esp[8]: from
9881 // esp[12]: string 10089 // esp[12]: string
9882 10090
9883 // Make sure first argument is a string. 10091 // Make sure first argument is a string.
9884 __ mov(eax, Operand(esp, 3 * kPointerSize)); 10092 __ mov(eax, Operand(esp, 3 * kPointerSize));
9885 ASSERT_EQ(0, kSmiTag); 10093 ASSERT_EQ(0, kSmiTag);
9886 __ test(eax, Immediate(kSmiTagMask)); 10094 __ test(eax, Immediate(kSmiTagMask));
9887 __ j(zero, &runtime); 10095 __ j(zero, &runtime);
9888 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 10096 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
9889 __ j(NegateCondition(is_string), &runtime); 10097 __ j(NegateCondition(is_string), &runtime);
9890 10098
9891 // eax: string 10099 // eax: string
9892 // ebx: instance type 10100 // ebx: instance type
9893 // Calculate length of sub string using the smi values. 10101 // Calculate length of sub string using the smi values.
9894 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // to 10102 Label result_longer_than_two;
10103 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index.
9895 __ test(ecx, Immediate(kSmiTagMask)); 10104 __ test(ecx, Immediate(kSmiTagMask));
9896 __ j(not_zero, &runtime); 10105 __ j(not_zero, &runtime);
9897 __ mov(edx, Operand(esp, 2 * kPointerSize)); // from 10106 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index.
9898 __ test(edx, Immediate(kSmiTagMask)); 10107 __ test(edx, Immediate(kSmiTagMask));
9899 __ j(not_zero, &runtime); 10108 __ j(not_zero, &runtime);
9900 __ sub(ecx, Operand(edx)); 10109 __ sub(ecx, Operand(edx));
9901 // Handle sub-strings of length 2 and less in the runtime system. 10110 // Special handling of sub-strings of length 1 and 2. One character strings
10111 // are handled in the runtime system (looked up in the single character
10112 // cache). Two character strings are looked for in the symbol cache.
9902 __ SmiUntag(ecx); // Result length is no longer smi. 10113 __ SmiUntag(ecx); // Result length is no longer smi.
9903 __ cmp(ecx, 2); 10114 __ cmp(ecx, 2);
9904 __ j(below_equal, &runtime); 10115 __ j(greater, &result_longer_than_two);
10116 __ j(less, &runtime);
9905 10117
10118 // Sub string of length 2 requested.
10119 // eax: string
10120 // ebx: instance type
10121 // ecx: sub string length (value is 2)
10122 // edx: from index (smi)
10123 __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime);
10124
10125 // Get the two characters forming the sub string.
10126 __ SmiUntag(edx); // From index is no longer smi.
10127 __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize));
10128 __ movzx_b(ecx,
10129 FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1));
10130
10131 // Try to lookup two character string in symbol table.
10132 Label make_two_character_string;
10133 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi,
10134 &make_two_character_string);
10135 __ ret(2 * kPointerSize);
10136
10137 __ bind(&make_two_character_string);
10138 // Setup registers for allocating the two character string.
10139 __ mov(eax, Operand(esp, 3 * kPointerSize));
10140 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
10141 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
10142 __ Set(ecx, Immediate(2));
10143
10144 __ bind(&result_longer_than_two);
9906 // eax: string 10145 // eax: string
9907 // ebx: instance type 10146 // ebx: instance type
9908 // ecx: result string length 10147 // ecx: result string length
9909 // Check for flat ascii string 10148 // Check for flat ascii string
9910 Label non_ascii_flat; 10149 Label non_ascii_flat;
9911 __ and_(ebx, kStringRepresentationMask | kStringEncodingMask); 10150 __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat);
9912 __ cmp(ebx, kSeqStringTag | kAsciiStringTag);
9913 __ j(not_equal, &non_ascii_flat);
9914 10151
9915 // Allocate the result. 10152 // Allocate the result.
9916 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); 10153 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime);
9917 10154
9918 // eax: result string 10155 // eax: result string
9919 // ecx: result string length 10156 // ecx: result string length
9920 __ mov(edx, esi); // esi used by following code. 10157 __ mov(edx, esi); // esi used by following code.
9921 // Locate first character of result. 10158 // Locate first character of result.
9922 __ mov(edi, eax); 10159 __ mov(edi, eax);
9923 __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 10160 __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
10094 10331
10095 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 10332 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
10096 // tagged as a small integer. 10333 // tagged as a small integer.
10097 __ bind(&runtime); 10334 __ bind(&runtime);
10098 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); 10335 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
10099 } 10336 }
10100 10337
10101 #undef __ 10338 #undef __
10102 10339
10103 } } // namespace v8::internal 10340 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/ia32/macro-assembler-ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698