• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include <stdlib.h>
29 
30 #include "v8.h"
31 
32 #include "factory.h"
33 #include "macro-assembler.h"
34 #include "cctest.h"
35 #include "code-stubs.h"
36 #include "objects.h"
37 
38 #ifdef USE_SIMULATOR
39 #include "simulator.h"
40 #endif
41 
42 using namespace v8::internal;
43 
44 
45 typedef uint32_t (*HASH_FUNCTION)();
46 
47 #define __ masm->
48 
49 
generate(MacroAssembler * masm,i::Vector<const uint8_t> string)50 void generate(MacroAssembler* masm, i::Vector<const uint8_t> string) {
51   // GenerateHashInit takes the first character as an argument so it can't
52   // handle the zero length string.
53   ASSERT(string.length() > 0);
54 #if V8_TARGET_ARCH_IA32
55   __ push(ebx);
56   __ push(ecx);
57   __ mov(eax, Immediate(0));
58   __ mov(ebx, Immediate(string.at(0)));
59   StringHelper::GenerateHashInit(masm, eax, ebx, ecx);
60   for (int i = 1; i < string.length(); i++) {
61     __ mov(ebx, Immediate(string.at(i)));
62     StringHelper::GenerateHashAddCharacter(masm, eax, ebx, ecx);
63   }
64   StringHelper::GenerateHashGetHash(masm, eax, ecx);
65   __ pop(ecx);
66   __ pop(ebx);
67   __ Ret();
68 #elif V8_TARGET_ARCH_X64
69   __ push(kRootRegister);
70   __ InitializeRootRegister();
71   __ push(rbx);
72   __ push(rcx);
73   __ movq(rax, Immediate(0));
74   __ movq(rbx, Immediate(string.at(0)));
75   StringHelper::GenerateHashInit(masm, rax, rbx, rcx);
76   for (int i = 1; i < string.length(); i++) {
77     __ movq(rbx, Immediate(string.at(i)));
78     StringHelper::GenerateHashAddCharacter(masm, rax, rbx, rcx);
79   }
80   StringHelper::GenerateHashGetHash(masm, rax, rcx);
81   __ pop(rcx);
82   __ pop(rbx);
83   __ pop(kRootRegister);
84   __ Ret();
85 #elif V8_TARGET_ARCH_ARM
86   __ push(kRootRegister);
87   __ InitializeRootRegister();
88 
89   __ mov(r0, Operand(0));
90   __ mov(ip, Operand(string.at(0)));
91   StringHelper::GenerateHashInit(masm, r0, ip);
92   for (int i = 1; i < string.length(); i++) {
93     __ mov(ip, Operand(string.at(i)));
94     StringHelper::GenerateHashAddCharacter(masm, r0, ip);
95   }
96   StringHelper::GenerateHashGetHash(masm, r0);
97   __ pop(kRootRegister);
98   __ mov(pc, Operand(lr));
99 #elif V8_TARGET_ARCH_MIPS
100   __ push(kRootRegister);
101   __ InitializeRootRegister();
102 
103   __ li(v0, Operand(0));
104   __ li(t1, Operand(string.at(0)));
105   StringHelper::GenerateHashInit(masm, v0, t1);
106   for (int i = 1; i < string.length(); i++) {
107     __ li(t1, Operand(string.at(i)));
108     StringHelper::GenerateHashAddCharacter(masm, v0, t1);
109   }
110   StringHelper::GenerateHashGetHash(masm, v0);
111   __ pop(kRootRegister);
112   __ jr(ra);
113   __ nop();
114 #endif
115 }
116 
117 
generate(MacroAssembler * masm,uint32_t key)118 void generate(MacroAssembler* masm, uint32_t key) {
119 #if V8_TARGET_ARCH_IA32
120   __ push(ebx);
121   __ mov(eax, Immediate(key));
122   __ GetNumberHash(eax, ebx);
123   __ pop(ebx);
124   __ Ret();
125 #elif V8_TARGET_ARCH_X64
126   __ push(kRootRegister);
127   __ InitializeRootRegister();
128   __ push(rbx);
129   __ movq(rax, Immediate(key));
130   __ GetNumberHash(rax, rbx);
131   __ pop(rbx);
132   __ pop(kRootRegister);
133   __ Ret();
134 #elif V8_TARGET_ARCH_ARM
135   __ push(kRootRegister);
136   __ InitializeRootRegister();
137   __ mov(r0, Operand(key));
138   __ GetNumberHash(r0, ip);
139   __ pop(kRootRegister);
140   __ mov(pc, Operand(lr));
141 #elif V8_TARGET_ARCH_MIPS
142   __ push(kRootRegister);
143   __ InitializeRootRegister();
144   __ li(v0, Operand(key));
145   __ GetNumberHash(v0, t1);
146   __ pop(kRootRegister);
147   __ jr(ra);
148   __ nop();
149 #endif
150 }
151 
152 
check(i::Vector<const uint8_t> string)153 void check(i::Vector<const uint8_t> string) {
154   Isolate* isolate = CcTest::i_isolate();
155   Factory* factory = isolate->factory();
156   HandleScope scope(isolate);
157 
158   v8::internal::byte buffer[2048];
159   MacroAssembler masm(isolate, buffer, sizeof buffer);
160 
161   generate(&masm, string);
162 
163   CodeDesc desc;
164   masm.GetCode(&desc);
165   Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
166   Handle<Code> code = factory->NewCode(desc,
167                                        Code::ComputeFlags(Code::STUB),
168                                        undefined);
169   CHECK(code->IsCode());
170 
171   HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(code->entry());
172   Handle<String> v8_string = factory->NewStringFromOneByte(string);
173   v8_string->set_hash_field(String::kEmptyHashField);
174 #ifdef USE_SIMULATOR
175   uint32_t codegen_hash =
176       reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(hash, 0, 0, 0, 0, 0));
177 #else
178   uint32_t codegen_hash = hash();
179 #endif
180   uint32_t runtime_hash = v8_string->Hash();
181   CHECK(runtime_hash == codegen_hash);
182 }
183 
184 
check(i::Vector<const char> s)185 void check(i::Vector<const char> s) {
186   check(i::Vector<const uint8_t>::cast(s));
187 }
188 
189 
check(uint32_t key)190 void check(uint32_t key) {
191   Isolate* isolate = CcTest::i_isolate();
192   Factory* factory = isolate->factory();
193   HandleScope scope(isolate);
194 
195   v8::internal::byte buffer[2048];
196   MacroAssembler masm(CcTest::i_isolate(), buffer, sizeof buffer);
197 
198   generate(&masm, key);
199 
200   CodeDesc desc;
201   masm.GetCode(&desc);
202   Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
203   Handle<Code> code = factory->NewCode(desc,
204                                        Code::ComputeFlags(Code::STUB),
205                                        undefined);
206   CHECK(code->IsCode());
207 
208   HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(code->entry());
209 #ifdef USE_SIMULATOR
210   uint32_t codegen_hash =
211       reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(hash, 0, 0, 0, 0, 0));
212 #else
213   uint32_t codegen_hash = hash();
214 #endif
215 
216   uint32_t runtime_hash = ComputeIntegerHash(key, isolate->heap()->HashSeed());
217   CHECK(runtime_hash == codegen_hash);
218 }
219 
220 
check_twochars(uint8_t a,uint8_t b)221 void check_twochars(uint8_t a, uint8_t b) {
222   uint8_t ab[2] = {a, b};
223   check(i::Vector<const uint8_t>(ab, 2));
224 }
225 
226 
PseudoRandom(uint32_t i,uint32_t j)227 static uint32_t PseudoRandom(uint32_t i, uint32_t j) {
228   return ~(~((i * 781) ^ (j * 329)));
229 }
230 
231 
TEST(StringHash)232 TEST(StringHash) {
233   v8::Isolate* isolate = CcTest::isolate();
234   v8::HandleScope handle_scope(isolate);
235   v8::Context::Scope context_scope(v8::Context::New(isolate));
236 
237   for (uint8_t a = 0; a < String::kMaxOneByteCharCode; a++) {
238     // Numbers are hashed differently.
239     if (a >= '0' && a <= '9') continue;
240     for (uint8_t b = 0; b < String::kMaxOneByteCharCode; b++) {
241       if (b >= '0' && b <= '9') continue;
242       check_twochars(a, b);
243     }
244   }
245   check(i::Vector<const char>("*",       1));
246   check(i::Vector<const char>(".zZ",     3));
247   check(i::Vector<const char>("muc",     3));
248   check(i::Vector<const char>("(>'_')>", 7));
249   check(i::Vector<const char>("-=[ vee eight ftw ]=-", 21));
250 }
251 
252 
TEST(NumberHash)253 TEST(NumberHash) {
254   v8::Isolate* isolate = CcTest::isolate();
255   v8::HandleScope handle_scope(isolate);
256   v8::Context::Scope context_scope(v8::Context::New(isolate));
257 
258   // Some specific numbers
259   for (uint32_t key = 0; key < 42; key += 7) {
260     check(key);
261   }
262 
263   // Some pseudo-random numbers
264   static const uint32_t kLimit = 1000;
265   for (uint32_t i = 0; i < 5; i++) {
266     for (uint32_t j = 0; j < 5; j++) {
267       check(PseudoRandom(i, j) % kLimit);
268     }
269   }
270 }
271 
272 #undef __
273