OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 times_pointer_size, | 218 times_pointer_size, |
219 kValueOffset - kHeapObjectTag)); | 219 kValueOffset - kHeapObjectTag)); |
220 __ movq(Operand(scratch1, 0), value); | 220 __ movq(Operand(scratch1, 0), value); |
221 | 221 |
222 // Update write barrier. Make sure not to clobber the value. | 222 // Update write barrier. Make sure not to clobber the value. |
223 __ movq(scratch0, value); | 223 __ movq(scratch0, value); |
224 __ RecordWrite(elements, scratch1, scratch0); | 224 __ RecordWrite(elements, scratch1, scratch0); |
225 } | 225 } |
226 | 226 |
227 | 227 |
228 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | |
229 Label* miss, | |
230 Register elements, | |
231 Register key, | |
232 Register r0, | |
233 Register r1, | |
234 Register r2, | |
235 Register result) { | |
236 // Register use: | |
237 // | |
238 // elements - holds the slow-case elements of the receiver on entry. | |
239 // Unchanged unless 'result' is the same register. | |
240 // | |
241 // key - holds the smi key on entry. | |
242 // Unchanged unless 'result' is the same register. | |
243 // | |
244 // Scratch registers: | |
245 // | |
246 // r0 - holds the untagged key on entry and holds the hash once computed. | |
247 // | |
248 // r1 - used to hold the capacity mask of the dictionary | |
249 // | |
250 // r2 - used for the index into the dictionary. | |
251 // | |
252 // result - holds the result on exit if the load succeeded. | |
253 // Allowed to be the same as 'key' or 'result'. | |
254 // Unchanged on bailout so 'key' or 'result' can be used | |
255 // in further computation. | |
256 | |
257 Label done; | |
258 | |
259 // Compute the hash code from the untagged key. This must be kept in sync | |
260 // with ComputeIntegerHash in utils.h. | |
261 // | |
262 // hash = ~hash + (hash << 15); | |
263 __ movl(r1, r0); | |
264 __ notl(r0); | |
265 __ shll(r1, Immediate(15)); | |
266 __ addl(r0, r1); | |
267 // hash = hash ^ (hash >> 12); | |
268 __ movl(r1, r0); | |
269 __ shrl(r1, Immediate(12)); | |
270 __ xorl(r0, r1); | |
271 // hash = hash + (hash << 2); | |
272 __ leal(r0, Operand(r0, r0, times_4, 0)); | |
273 // hash = hash ^ (hash >> 4); | |
274 __ movl(r1, r0); | |
275 __ shrl(r1, Immediate(4)); | |
276 __ xorl(r0, r1); | |
277 // hash = hash * 2057; | |
278 __ imull(r0, r0, Immediate(2057)); | |
279 // hash = hash ^ (hash >> 16); | |
280 __ movl(r1, r0); | |
281 __ shrl(r1, Immediate(16)); | |
282 __ xorl(r0, r1); | |
283 | |
284 // Compute capacity mask. | |
285 __ SmiToInteger32(r1, | |
286 FieldOperand(elements, NumberDictionary::kCapacityOffset)); | |
287 __ decl(r1); | |
288 | |
289 // Generate an unrolled loop that performs a few probes before giving up. | |
290 const int kProbes = 4; | |
291 for (int i = 0; i < kProbes; i++) { | |
292 // Use r2 for index calculations and keep the hash intact in r0. | |
293 __ movq(r2, r0); | |
294 // Compute the masked index: (hash + i + i * i) & mask. | |
295 if (i > 0) { | |
296 __ addl(r2, Immediate(NumberDictionary::GetProbeOffset(i))); | |
297 } | |
298 __ and_(r2, r1); | |
299 | |
300 // Scale the index by multiplying by the entry size. | |
301 ASSERT(NumberDictionary::kEntrySize == 3); | |
302 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 | |
303 | |
304 // Check if the key matches. | |
305 __ cmpq(key, FieldOperand(elements, | |
306 r2, | |
307 times_pointer_size, | |
308 NumberDictionary::kElementsStartOffset)); | |
309 if (i != (kProbes - 1)) { | |
310 __ j(equal, &done); | |
311 } else { | |
312 __ j(not_equal, miss); | |
313 } | |
314 } | |
315 | |
316 __ bind(&done); | |
317 // Check that the value is a normal propety. | |
318 const int kDetailsOffset = | |
319 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | |
320 ASSERT_EQ(NORMAL, 0); | |
321 __ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | |
322 Smi::FromInt(PropertyDetails::TypeField::mask())); | |
323 __ j(not_zero, miss); | |
324 | |
325 // Get the value at the masked, scaled index. | |
326 const int kValueOffset = | |
327 NumberDictionary::kElementsStartOffset + kPointerSize; | |
328 __ movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); | |
329 } | |
330 | |
331 | |
332 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 228 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
333 // ----------- S t a t e ------------- | 229 // ----------- S t a t e ------------- |
334 // -- rax : receiver | 230 // -- rax : receiver |
335 // -- rcx : name | 231 // -- rcx : name |
336 // -- rsp[0] : return address | 232 // -- rsp[0] : return address |
337 // ----------------------------------- | 233 // ----------------------------------- |
338 Label miss; | 234 Label miss; |
339 | 235 |
340 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); | 236 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); |
341 __ bind(&miss); | 237 __ bind(&miss); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 424 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); |
529 | 425 |
530 // Check whether the elements is a number dictionary. | 426 // Check whether the elements is a number dictionary. |
531 // rdx: receiver | 427 // rdx: receiver |
532 // rax: key | 428 // rax: key |
533 // rbx: key as untagged int32 | 429 // rbx: key as untagged int32 |
534 // rcx: elements | 430 // rcx: elements |
535 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 431 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
536 Heap::kHashTableMapRootIndex); | 432 Heap::kHashTableMapRootIndex); |
537 __ j(not_equal, &slow); | 433 __ j(not_equal, &slow); |
538 GenerateNumberDictionaryLoad(masm, &slow, rcx, rax, rbx, r9, rdi, rax); | 434 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax); |
539 __ ret(0); | 435 __ ret(0); |
540 | 436 |
541 __ bind(&slow); | 437 __ bind(&slow); |
542 // Slow case: Jump to runtime. | 438 // Slow case: Jump to runtime. |
543 // rdx: receiver | 439 // rdx: receiver |
544 // rax: key | 440 // rax: key |
545 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); | 441 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); |
546 GenerateRuntimeGetProperty(masm); | 442 GenerateRuntimeGetProperty(masm); |
547 | 443 |
548 __ bind(&check_string); | 444 __ bind(&check_string); |
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1092 | 988 |
1093 __ bind(&check_number_dictionary); | 989 __ bind(&check_number_dictionary); |
1094 // rax: elements | 990 // rax: elements |
1095 // rcx: smi key | 991 // rcx: smi key |
1096 // Check whether the elements is a number dictionary. | 992 // Check whether the elements is a number dictionary. |
1097 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 993 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
1098 Heap::kHashTableMapRootIndex); | 994 Heap::kHashTableMapRootIndex); |
1099 __ j(not_equal, &slow_load); | 995 __ j(not_equal, &slow_load); |
1100 __ SmiToInteger32(rbx, rcx); | 996 __ SmiToInteger32(rbx, rcx); |
1101 // ebx: untagged index | 997 // ebx: untagged index |
1102 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); | 998 __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi); |
1103 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); | 999 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); |
1104 __ jmp(&do_call); | 1000 __ jmp(&do_call); |
1105 | 1001 |
1106 __ bind(&slow_load); | 1002 __ bind(&slow_load); |
1107 // This branch is taken when calling KeyedCallIC_Miss is neither required | 1003 // This branch is taken when calling KeyedCallIC_Miss is neither required |
1108 // nor beneficial. | 1004 // nor beneficial. |
1109 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); | 1005 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); |
1110 __ EnterInternalFrame(); | 1006 __ EnterInternalFrame(); |
1111 __ push(rcx); // save the key | 1007 __ push(rcx); // save the key |
1112 __ push(rdx); // pass the receiver | 1008 __ push(rdx); // pass the receiver |
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1766 Condition cc = *jmp_address == Assembler::kJncShortOpcode | 1662 Condition cc = *jmp_address == Assembler::kJncShortOpcode |
1767 ? not_zero | 1663 ? not_zero |
1768 : zero; | 1664 : zero; |
1769 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1665 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1770 } | 1666 } |
1771 | 1667 |
1772 | 1668 |
1773 } } // namespace v8::internal | 1669 } } // namespace v8::internal |
1774 | 1670 |
1775 #endif // V8_TARGET_ARCH_X64 | 1671 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |