diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 6bf4d99b77..be85fa15be 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -5246,70 +5246,6 @@ void StringCharAtGenerator::GenerateSlow( } -class StringHelper : public AllStatic { - public: - // Generate code for copying characters using a simple loop. This should only - // be used in places where the number of characters is small and the - // additional setup and checking in GenerateCopyCharactersLong adds too much - // overhead. Copying of overlapping regions is not supported. - // Dest register ends at the position after the last character written. - static void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii); - - // Generate code for copying a large number of characters. This function - // is allowed to spend extra time setting up conditions to make copying - // faster. Copying of overlapping regions is not supported. - // Dest register ends at the position after the last character written. - static void GenerateCopyCharactersLong(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - int flags); - - - // Probe the symbol table for a two character string. If the string is - // not found by probing a jump to the label not_found is performed. This jump - // does not guarantee that the string is not in the symbol table. If the - // string is found the code falls through with the string in register r0. - // Contents of both c1 and c2 registers are modified. At the exit c1 is - // guaranteed to contain halfword with low and high bytes equal to - // initial contents of c1 and c2 respectively. - static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - Label* not_found); - - // Generate string hash. - static void GenerateHashInit(MacroAssembler* masm, - Register hash, - Register character); - - static void GenerateHashAddCharacter(MacroAssembler* masm, - Register hash, - Register character); - - static void GenerateHashGetHash(MacroAssembler* masm, - Register hash); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); -}; - - void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest, Register src, @@ -5562,9 +5498,8 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, static const int kProbes = 4; Label found_in_symbol_table; Label next_probe[kProbes]; + Register candidate = scratch5; // Scratch register contains candidate. for (int i = 0; i < kProbes; i++) { - Register candidate = scratch5; // Scratch register contains candidate. - // Calculate entry in symbol table. if (i > 0) { __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i))); @@ -5589,11 +5524,11 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ cmp(undefined, candidate); __ b(eq, not_found); - // Must be null (deleted entry). + // Must be the hole (deleted entry). if (FLAG_debug_code) { - __ LoadRoot(ip, Heap::kNullValueRootIndex); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ cmp(ip, candidate); - __ Assert(eq, "oddball in symbol table is not undefined or null"); + __ Assert(eq, "oddball in symbol table is not undefined or the hole"); } __ jmp(&next_probe[i]); @@ -5621,7 +5556,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ jmp(not_found); // Scratch register contains result when we fall through to here. - Register result = scratch; + Register result = candidate; __ bind(&found_in_symbol_table); __ Move(r0, result); } @@ -5633,7 +5568,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, // hash = character + (character << 10); __ add(hash, character, Operand(character, LSL, 10)); // hash ^= hash >> 6; - __ eor(hash, hash, Operand(hash, ASR, 6)); + __ eor(hash, hash, Operand(hash, LSR, 6)); } @@ -5645,7 +5580,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, // hash += hash << 10; __ add(hash, hash, Operand(hash, LSL, 10)); // hash ^= hash >> 6; - __ eor(hash, hash, Operand(hash, ASR, 6)); + __ eor(hash, hash, Operand(hash, LSR, 6)); } @@ -5654,12 +5589,15 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, // hash += hash << 3; __ add(hash, hash, Operand(hash, LSL, 3)); // hash ^= hash >> 11; - __ eor(hash, hash, Operand(hash, ASR, 11)); + __ eor(hash, hash, Operand(hash, LSR, 11)); // hash += hash << 15; __ add(hash, hash, Operand(hash, LSL, 15), SetCC); + uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; + __ and_(hash, hash, Operand(kHashShiftCutOffMask)); + // if (hash == 0) hash = 27; - __ mov(hash, Operand(27), LeaveCC, ne); + __ mov(hash, Operand(27), LeaveCC, eq); } diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h index 365ba4f73b..4e1261b7ee 100644 --- a/src/arm/code-stubs-arm.h +++ b/src/arm/code-stubs-arm.h @@ -244,6 +244,70 @@ class BinaryOpStub: public CodeStub { }; +class StringHelper : public AllStatic { + public: + // Generate code for copying characters using a simple loop. This should only + // be used in places where the number of characters is small and the + // additional setup and checking in GenerateCopyCharactersLong adds too much + // overhead. Copying of overlapping regions is not supported. + // Dest register ends at the position after the last character written. + static void GenerateCopyCharacters(MacroAssembler* masm, + Register dest, + Register src, + Register count, + Register scratch, + bool ascii); + + // Generate code for copying a large number of characters. This function + // is allowed to spend extra time setting up conditions to make copying + // faster. Copying of overlapping regions is not supported. + // Dest register ends at the position after the last character written. + static void GenerateCopyCharactersLong(MacroAssembler* masm, + Register dest, + Register src, + Register count, + Register scratch1, + Register scratch2, + Register scratch3, + Register scratch4, + Register scratch5, + int flags); + + + // Probe the symbol table for a two character string. If the string is + // not found by probing a jump to the label not_found is performed. This jump + // does not guarantee that the string is not in the symbol table. If the + // string is found the code falls through with the string in register r0. + // Contents of both c1 and c2 registers are modified. At the exit c1 is + // guaranteed to contain halfword with low and high bytes equal to + // initial contents of c1 and c2 respectively. + static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, + Register c1, + Register c2, + Register scratch1, + Register scratch2, + Register scratch3, + Register scratch4, + Register scratch5, + Label* not_found); + + // Generate string hash. + static void GenerateHashInit(MacroAssembler* masm, + Register hash, + Register character); + + static void GenerateHashAddCharacter(MacroAssembler* masm, + Register hash, + Register character); + + static void GenerateHashGetHash(MacroAssembler* masm, + Register hash); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); +}; + + // Flag that indicates how to generate code for the stub StringAddStub. enum StringAddFlags { NO_STRING_ADD_FLAGS = 0, diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 629f5851f5..6a96a5b8cb 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -5772,6 +5772,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, static const int kProbes = 4; Label found_in_symbol_table; Label next_probe[kProbes], next_probe_pop_mask[kProbes]; + Register candidate = scratch; // Scratch register contains candidate. for (int i = 0; i < kProbes; i++) { // Calculate entry in symbol table. __ mov(scratch, hash); @@ -5781,7 +5782,6 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ and_(scratch, mask); // Load the entry from the symbol table. - Register candidate = scratch; // Scratch register contains candidate. STATIC_ASSERT(SymbolTable::kEntrySize == 1); __ mov(candidate, FieldOperand(symbol_table, @@ -5793,7 +5793,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, Factory* factory = masm->isolate()->factory(); __ cmp(candidate, factory->undefined_value()); __ j(equal, not_found); - __ cmp(candidate, factory->null_value()); + __ cmp(candidate, factory->the_hole_value()); __ j(equal, &next_probe[i]); // If length is not 2 the string is not a candidate. @@ -5826,7 +5826,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ jmp(not_found); // Scratch register contains result when we fall through to here. - Register result = scratch; + Register result = candidate; __ bind(&found_in_symbol_table); __ pop(mask); // Pop saved mask from the stack. if (!result.is(eax)) { @@ -5845,7 +5845,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, __ add(hash, character); // hash ^= hash >> 6; __ mov(scratch, hash); - __ sar(scratch, 6); + __ shr(scratch, 6); __ xor_(hash, scratch); } @@ -5862,7 +5862,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, __ add(hash, scratch); // hash ^= hash >> 6; __ mov(scratch, hash); - __ sar(scratch, 6); + __ shr(scratch, 6); __ xor_(hash, scratch); } @@ -5876,13 +5876,16 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, __ add(hash, scratch); // hash ^= hash >> 11; __ mov(scratch, hash); - __ sar(scratch, 11); + __ shr(scratch, 11); __ xor_(hash, scratch); // hash += hash << 15; __ mov(scratch, hash); __ shl(scratch, 15); __ add(hash, scratch); + uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; + __ and_(hash, kHashShiftCutOffMask); + // if (hash == 0) hash = 27; Label hash_not_zero; __ test(hash, hash); diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index f035354946..bb4f71b389 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -2145,8 +2145,6 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) { } - - void MacroAssembler::Drop(int stack_elements) { if (stack_elements > 0) { add(esp, Immediate(stack_elements * kPointerSize)); diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index c45b8a5d18..06955951a8 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -5462,70 +5462,6 @@ void StringCharAtGenerator::GenerateSlow( } -class StringHelper : public AllStatic { - public: - // Generate code for copying characters using a simple loop. This should only - // be used in places where the number of characters is small and the - // additional setup and checking in GenerateCopyCharactersLong adds too much - // overhead. Copying of overlapping regions is not supported. - // Dest register ends at the position after the last character written. - static void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii); - - // Generate code for copying a large number of characters. This function - // is allowed to spend extra time setting up conditions to make copying - // faster. Copying of overlapping regions is not supported. - // Dest register ends at the position after the last character written. - static void GenerateCopyCharactersLong(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - int flags); - - - // Probe the symbol table for a two character string. If the string is - // not found by probing a jump to the label not_found is performed. This jump - // does not guarantee that the string is not in the symbol table. If the - // string is found the code falls through with the string in register r0. - // Contents of both c1 and c2 registers are modified. At the exit c1 is - // guaranteed to contain halfword with low and high bytes equal to - // initial contents of c1 and c2 respectively. - static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Register scratch4, - Register scratch5, - Label* not_found); - - // Generate string hash. - static void GenerateHashInit(MacroAssembler* masm, - Register hash, - Register character); - - static void GenerateHashAddCharacter(MacroAssembler* masm, - Register hash, - Register character); - - static void GenerateHashGetHash(MacroAssembler* masm, - Register hash); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); -}; - - void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest, Register src, @@ -5819,7 +5755,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, __ sll(hash, character, 10); __ addu(hash, hash, character); // hash ^= hash >> 6; - __ sra(at, hash, 6); + __ srl(at, hash, 6); __ xor_(hash, hash, at); } @@ -5833,7 +5769,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, __ sll(at, hash, 10); __ addu(hash, hash, at); // hash ^= hash >> 6; - __ sra(at, hash, 6); + __ srl(at, hash, 6); __ xor_(hash, hash, at); } @@ -5844,12 +5780,16 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, __ sll(at, hash, 3); __ addu(hash, hash, at); // hash ^= hash >> 11; - __ sra(at, hash, 11); + __ srl(at, hash, 11); __ xor_(hash, hash, at); // hash += hash << 15; __ sll(at, hash, 15); __ addu(hash, hash, at); + uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; + __ li(at, Operand(kHashShiftCutOffMask)); + __ and_(hash, hash, at); + // if (hash == 0) hash = 27; __ ori(at, zero_reg, 27); __ movz(hash, at, hash); diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h index 7612a7cd72..f45ad2b213 100644 --- a/src/mips/code-stubs-mips.h +++ b/src/mips/code-stubs-mips.h @@ -245,6 +245,70 @@ class BinaryOpStub: public CodeStub { }; +class StringHelper : public AllStatic { + public: + // Generate code for copying characters using a simple loop. This should only + // be used in places where the number of characters is small and the + // additional setup and checking in GenerateCopyCharactersLong adds too much + // overhead. Copying of overlapping regions is not supported. + // Dest register ends at the position after the last character written. + static void GenerateCopyCharacters(MacroAssembler* masm, + Register dest, + Register src, + Register count, + Register scratch, + bool ascii); + + // Generate code for copying a large number of characters. This function + // is allowed to spend extra time setting up conditions to make copying + // faster. Copying of overlapping regions is not supported. + // Dest register ends at the position after the last character written. + static void GenerateCopyCharactersLong(MacroAssembler* masm, + Register dest, + Register src, + Register count, + Register scratch1, + Register scratch2, + Register scratch3, + Register scratch4, + Register scratch5, + int flags); + + + // Probe the symbol table for a two character string. If the string is + // not found by probing a jump to the label not_found is performed. This jump + // does not guarantee that the string is not in the symbol table. If the + // string is found the code falls through with the string in register r0. + // Contents of both c1 and c2 registers are modified. At the exit c1 is + // guaranteed to contain halfword with low and high bytes equal to + // initial contents of c1 and c2 respectively. + static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, + Register c1, + Register c2, + Register scratch1, + Register scratch2, + Register scratch3, + Register scratch4, + Register scratch5, + Label* not_found); + + // Generate string hash. + static void GenerateHashInit(MacroAssembler* masm, + Register hash, + Register character); + + static void GenerateHashAddCharacter(MacroAssembler* masm, + Register hash, + Register character); + + static void GenerateHashGetHash(MacroAssembler* masm, + Register hash); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); +}; + + // Flag that indicates how to generate code for the stub StringAddStub. enum StringAddFlags { NO_STRING_ADD_FLAGS = 0, diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index cd269cb6f3..2001b80d82 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -4705,6 +4705,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, static const int kProbes = 4; Label found_in_symbol_table; Label next_probe[kProbes]; + Register candidate = scratch; // Scratch register contains candidate. for (int i = 0; i < kProbes; i++) { // Calculate entry in symbol table. __ movl(scratch, hash); @@ -4714,7 +4715,6 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ andl(scratch, mask); // Load the entry from the symbol table. - Register candidate = scratch; // Scratch register contains candidate. STATIC_ASSERT(SymbolTable::kEntrySize == 1); __ movq(candidate, FieldOperand(symbol_table, @@ -4729,7 +4729,12 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); __ j(equal, not_found); - // Must be null (deleted entry). + // Must be the hole (deleted entry). + if (FLAG_debug_code) { + __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); + __ cmpq(kScratchRegister, candidate); + __ Assert(equal, "oddball in symbol table is not undefined or the hole"); + } __ jmp(&next_probe[i]); __ bind(&is_string); @@ -4760,7 +4765,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, __ jmp(not_found); // Scratch register contains result when we fall through to here. - Register result = scratch; + Register result = candidate; __ bind(&found_in_symbol_table); if (!result.is(rax)) { __ movq(rax, result); @@ -4778,7 +4783,7 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, __ addl(hash, character); // hash ^= hash >> 6; __ movl(scratch, hash); - __ sarl(scratch, Immediate(6)); + __ shrl(scratch, Immediate(6)); __ xorl(hash, scratch); } @@ -4795,7 +4800,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, __ addl(hash, scratch); // hash ^= hash >> 6; __ movl(scratch, hash); - __ sarl(scratch, Immediate(6)); + __ shrl(scratch, Immediate(6)); __ xorl(hash, scratch); } @@ -4807,13 +4812,16 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, __ leal(hash, Operand(hash, hash, times_8, 0)); // hash ^= hash >> 11; __ movl(scratch, hash); - __ sarl(scratch, Immediate(11)); + __ shrl(scratch, Immediate(11)); __ xorl(hash, scratch); // hash += hash << 15; __ movl(scratch, hash); __ shll(scratch, Immediate(15)); __ addl(hash, scratch); + uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; + __ andl(hash, Immediate(kHashShiftCutOffMask)); + // if (hash == 0) hash = 27; Label hash_not_zero; __ j(not_zero, &hash_not_zero); diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index efcbad7169..3b8f4f653d 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -68,6 +68,7 @@ 'test-fixed-dtoa.cc', 'test-flags.cc', 'test-func-name-inference.cc', + 'test-hashing.cc', 'test-hashmap.cc', 'test-heap.cc', 'test-heap-profiler.cc', diff --git a/test/cctest/test-hashing.cc b/test/cctest/test-hashing.cc new file mode 100644 index 0000000000..b91ac1f17f --- /dev/null +++ b/test/cctest/test-hashing.cc @@ -0,0 +1,158 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "v8.h" + +#include "factory.h" +#include "macro-assembler.h" +#include "cctest.h" +#include "code-stubs.h" +#include "objects.h" + +#ifdef USE_SIMULATOR +#include "simulator.h" +#endif + +using namespace v8::internal; + + +typedef uint32_t (*HASH_FUNCTION)(); + +static v8::Persistent env; + +#define __ assm-> + + +void generate(MacroAssembler* assm, i::Vector string) { +#ifdef V8_TARGET_ARCH_IA32 + __ mov(eax, Immediate(0)); + if (string.length() > 0) { + __ mov(ebx, Immediate(string.at(0))); + StringHelper::GenerateHashInit(assm, eax, ebx, ecx); + } + for (int i = 1; i < string.length(); i++) { + __ mov(ebx, Immediate(string.at(i))); + StringHelper::GenerateHashAddCharacter(assm, eax, ebx, ecx); + } + StringHelper::GenerateHashGetHash(assm, eax, ecx); + __ Ret(); +#elif V8_TARGET_ARCH_X64 + __ movq(rax, Immediate(0)); + if (string.length() > 0) { + __ movq(rbx, Immediate(string.at(0))); + StringHelper::GenerateHashInit(assm, rax, rbx, rcx); + } + for (int i = 1; i < string.length(); i++) { + __ movq(rbx, Immediate(string.at(i))); + StringHelper::GenerateHashAddCharacter(assm, rax, rbx, rcx); + } + StringHelper::GenerateHashGetHash(assm, rax, rcx); + __ Ret(); +#elif V8_TARGET_ARCH_ARM + __ mov(r0, Operand(0)); + if (string.length() > 0) { + __ mov(r1, Operand(string.at(0))); + StringHelper::GenerateHashInit(assm, r0, r1); + } + for (int i = 1; i < string.length(); i++) { + __ mov(r1, Operand(string.at(i))); + StringHelper::GenerateHashAddCharacter(assm, r0, r1); + } + StringHelper::GenerateHashGetHash(assm, r0); + __ mov(pc, Operand(lr)); +#elif V8_TARGET_ARCH_MIPS + __ li(v0, Operand(0)); + if (string.length() > 0) { + __ li(v1, Operand(string.at(0))); + StringHelper::GenerateHashInit(assm, v0, v1); + } + for (int i = 1; i < string.length(); i++) { + __ li(v1, Operand(string.at(i))); + StringHelper::GenerateHashAddCharacter(assm, v0, v1); + } + StringHelper::GenerateHashGetHash(assm, v0); + __ jr(ra); +#endif +} + + +void check(i::Vector string) { + v8::HandleScope scope; + v8::internal::byte buffer[2048]; + MacroAssembler assm(Isolate::Current(), buffer, sizeof buffer); + + generate(&assm, string); + + CodeDesc desc; + assm.GetCode(&desc); + Code* code = Code::cast(HEAP->CreateCode( + desc, + Code::ComputeFlags(Code::STUB), + Handle(HEAP->undefined_value()))->ToObjectChecked()); + CHECK(code->IsCode()); + + HASH_FUNCTION hash = FUNCTION_CAST(Code::cast(code)->entry()); + Handle v8_string = FACTORY->NewStringFromAscii(string); + v8_string->set_hash_field(String::kEmptyHashField); +#ifdef USE_SIMULATOR + uint32_t codegen_hash = + reinterpret_cast(CALL_GENERATED_CODE(hash, 0, 0, 0, 0, 0)); +#else + uint32_t codegen_hash = hash(); +#endif + uint32_t runtime_hash = v8_string->Hash(); + CHECK(runtime_hash == codegen_hash); +} + + +void check_twochars(char a, char b) { + char ab[2] = {a, b}; + check(i::Vector(ab, 2)); +} + + +TEST(StringHash) { + if (env.IsEmpty()) env = v8::Context::New(); + for (int a = 0; a < String::kMaxAsciiCharCode; a++) { + // Numbers are hashed differently. + if (a >= '0' && a <= '9') continue; + for (int b = 0; b < String::kMaxAsciiCharCode; b++) { + if (b >= '0' && b <= '9') continue; + check_twochars(static_cast(a), static_cast(b)); + } + } + check(i::Vector("", 0)); + check(i::Vector("*", 1)); + check(i::Vector(".zZ", 3)); + check(i::Vector("muc", 3)); + check(i::Vector("(>'_')>", 7)); + check(i::Vector("-=[ vee eight ftw ]=-", 21)); +} + +#undef __