}
-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,
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)));
__ 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]);
__ 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);
}
// 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));
}
// 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));
}
// 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);
}
};
+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,
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);
__ 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,
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.
__ 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)) {
__ add(hash, character);
// hash ^= hash >> 6;
__ mov(scratch, hash);
- __ sar(scratch, 6);
+ __ shr(scratch, 6);
__ xor_(hash, scratch);
}
__ add(hash, scratch);
// hash ^= hash >> 6;
__ mov(scratch, hash);
- __ sar(scratch, 6);
+ __ shr(scratch, 6);
__ xor_(hash, scratch);
}
__ 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);
}
-
-
void MacroAssembler::Drop(int stack_elements) {
if (stack_elements > 0) {
add(esp, Immediate(stack_elements * kPointerSize));
}
-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,
__ sll(hash, character, 10);
__ addu(hash, hash, character);
// hash ^= hash >> 6;
- __ sra(at, hash, 6);
+ __ srl(at, hash, 6);
__ xor_(hash, hash, at);
}
__ sll(at, hash, 10);
__ addu(hash, hash, at);
// hash ^= hash >> 6;
- __ sra(at, hash, 6);
+ __ srl(at, hash, 6);
__ xor_(hash, hash, at);
}
__ 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);
};
+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,
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);
__ 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,
__ 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);
__ 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);
__ addl(hash, character);
// hash ^= hash >> 6;
__ movl(scratch, hash);
- __ sarl(scratch, Immediate(6));
+ __ shrl(scratch, Immediate(6));
__ xorl(hash, scratch);
}
__ addl(hash, scratch);
// hash ^= hash >> 6;
__ movl(scratch, hash);
- __ sarl(scratch, Immediate(6));
+ __ shrl(scratch, Immediate(6));
__ xorl(hash, scratch);
}
__ 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);
'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',
--- /dev/null
+// 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 <stdlib.h>
+
+#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<v8::Context> env;
+
+#define __ assm->
+
+
+void generate(MacroAssembler* assm, i::Vector<const char> 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<const char> 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<Object>(HEAP->undefined_value()))->ToObjectChecked());
+ CHECK(code->IsCode());
+
+ HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(Code::cast(code)->entry());
+ Handle<String> v8_string = FACTORY->NewStringFromAscii(string);
+ v8_string->set_hash_field(String::kEmptyHashField);
+#ifdef USE_SIMULATOR
+ uint32_t codegen_hash =
+ reinterpret_cast<uint32_t>(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<const char>(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<char>(a), static_cast<char>(b));
+ }
+ }
+ check(i::Vector<const char>("", 0));
+ check(i::Vector<const char>("*", 1));
+ check(i::Vector<const char>(".zZ", 3));
+ check(i::Vector<const char>("muc", 3));
+ check(i::Vector<const char>("(>'_')>", 7));
+ check(i::Vector<const char>("-=[ vee eight ftw ]=-", 21));
+}
+
+#undef __