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 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 const int kValueOffset = kElementsStartOffset + kPointerSize; | 209 const int kValueOffset = kElementsStartOffset + kPointerSize; |
210 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 210 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
211 __ mov(Operand(r0, 0), value); | 211 __ mov(Operand(r0, 0), value); |
212 | 212 |
213 // Update write barrier. Make sure not to clobber the value. | 213 // Update write barrier. Make sure not to clobber the value. |
214 __ mov(r1, value); | 214 __ mov(r1, value); |
215 __ RecordWrite(elements, r0, r1); | 215 __ RecordWrite(elements, r0, r1); |
216 } | 216 } |
217 | 217 |
218 | 218 |
219 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | |
220 Label* miss, | |
221 Register elements, | |
222 Register key, | |
223 Register r0, | |
224 Register r1, | |
225 Register r2, | |
226 Register result) { | |
227 // Register use: | |
228 // | |
229 // elements - holds the slow-case elements of the receiver and is unchanged. | |
230 // | |
231 // key - holds the smi key on entry and is unchanged. | |
232 // | |
233 // Scratch registers: | |
234 // | |
235 // r0 - holds the untagged key on entry and holds the hash once computed. | |
236 // | |
237 // r1 - used to hold the capacity mask of the dictionary | |
238 // | |
239 // r2 - used for the index into the dictionary. | |
240 // | |
241 // result - holds the result on exit if the load succeeds and we fall through. | |
242 | |
243 Label done; | |
244 | |
245 // Compute the hash code from the untagged key. This must be kept in sync | |
246 // with ComputeIntegerHash in utils.h. | |
247 // | |
248 // hash = ~hash + (hash << 15); | |
249 __ mov(r1, r0); | |
250 __ not_(r0); | |
251 __ shl(r1, 15); | |
252 __ add(r0, Operand(r1)); | |
253 // hash = hash ^ (hash >> 12); | |
254 __ mov(r1, r0); | |
255 __ shr(r1, 12); | |
256 __ xor_(r0, Operand(r1)); | |
257 // hash = hash + (hash << 2); | |
258 __ lea(r0, Operand(r0, r0, times_4, 0)); | |
259 // hash = hash ^ (hash >> 4); | |
260 __ mov(r1, r0); | |
261 __ shr(r1, 4); | |
262 __ xor_(r0, Operand(r1)); | |
263 // hash = hash * 2057; | |
264 __ imul(r0, r0, 2057); | |
265 // hash = hash ^ (hash >> 16); | |
266 __ mov(r1, r0); | |
267 __ shr(r1, 16); | |
268 __ xor_(r0, Operand(r1)); | |
269 | |
270 // Compute capacity mask. | |
271 __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset)); | |
272 __ shr(r1, kSmiTagSize); // convert smi to int | |
273 __ dec(r1); | |
274 | |
275 // Generate an unrolled loop that performs a few probes before giving up. | |
276 const int kProbes = 4; | |
277 for (int i = 0; i < kProbes; i++) { | |
278 // Use r2 for index calculations and keep the hash intact in r0. | |
279 __ mov(r2, r0); | |
280 // Compute the masked index: (hash + i + i * i) & mask. | |
281 if (i > 0) { | |
282 __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i))); | |
283 } | |
284 __ and_(r2, Operand(r1)); | |
285 | |
286 // Scale the index by multiplying by the entry size. | |
287 ASSERT(NumberDictionary::kEntrySize == 3); | |
288 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 | |
289 | |
290 // Check if the key matches. | |
291 __ cmp(key, FieldOperand(elements, | |
292 r2, | |
293 times_pointer_size, | |
294 NumberDictionary::kElementsStartOffset)); | |
295 if (i != (kProbes - 1)) { | |
296 __ j(equal, &done); | |
297 } else { | |
298 __ j(not_equal, miss); | |
299 } | |
300 } | |
301 | |
302 __ bind(&done); | |
303 // Check that the value is a normal propety. | |
304 const int kDetailsOffset = | |
305 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | |
306 ASSERT_EQ(NORMAL, 0); | |
307 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | |
308 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | |
309 __ j(not_zero, miss); | |
310 | |
311 // Get the value at the masked, scaled index. | |
312 const int kValueOffset = | |
313 NumberDictionary::kElementsStartOffset + kPointerSize; | |
314 __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); | |
315 } | |
316 | |
317 | |
318 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 219 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
319 // ----------- S t a t e ------------- | 220 // ----------- S t a t e ------------- |
320 // -- eax : receiver | 221 // -- eax : receiver |
321 // -- ecx : name | 222 // -- ecx : name |
322 // -- esp[0] : return address | 223 // -- esp[0] : return address |
323 // ----------------------------------- | 224 // ----------------------------------- |
324 Label miss; | 225 Label miss; |
325 | 226 |
326 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); | 227 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); |
327 __ bind(&miss); | 228 __ bind(&miss); |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 // eax: key | 485 // eax: key |
585 // ecx: elements | 486 // ecx: elements |
586 __ CheckMap(ecx, | 487 __ CheckMap(ecx, |
587 isolate->factory()->hash_table_map(), | 488 isolate->factory()->hash_table_map(), |
588 &slow, | 489 &slow, |
589 DONT_DO_SMI_CHECK); | 490 DONT_DO_SMI_CHECK); |
590 Label slow_pop_receiver; | 491 Label slow_pop_receiver; |
591 // Push receiver on the stack to free up a register for the dictionary | 492 // Push receiver on the stack to free up a register for the dictionary |
592 // probing. | 493 // probing. |
593 __ push(edx); | 494 __ push(edx); |
594 GenerateNumberDictionaryLoad(masm, | 495 __ LoadFromNumberDictionary(&slow_pop_receiver, |
595 &slow_pop_receiver, | 496 ecx, |
596 ecx, | 497 eax, |
597 eax, | 498 ebx, |
598 ebx, | 499 edx, |
599 edx, | 500 edi, |
600 edi, | 501 eax); |
601 eax); | |
602 // Pop receiver before returning. | 502 // Pop receiver before returning. |
603 __ pop(edx); | 503 __ pop(edx); |
604 __ ret(0); | 504 __ ret(0); |
605 | 505 |
606 __ bind(&slow_pop_receiver); | 506 __ bind(&slow_pop_receiver); |
607 // Pop the receiver from the stack and jump to runtime. | 507 // Pop the receiver from the stack and jump to runtime. |
608 __ pop(edx); | 508 __ pop(edx); |
609 | 509 |
610 __ bind(&slow); | 510 __ bind(&slow); |
611 // Slow case: jump to runtime. | 511 // Slow case: jump to runtime. |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1193 // ecx: smi key | 1093 // ecx: smi key |
1194 // Check whether the elements is a number dictionary. | 1094 // Check whether the elements is a number dictionary. |
1195 __ CheckMap(eax, | 1095 __ CheckMap(eax, |
1196 isolate->factory()->hash_table_map(), | 1096 isolate->factory()->hash_table_map(), |
1197 &slow_load, | 1097 &slow_load, |
1198 DONT_DO_SMI_CHECK); | 1098 DONT_DO_SMI_CHECK); |
1199 __ mov(ebx, ecx); | 1099 __ mov(ebx, ecx); |
1200 __ SmiUntag(ebx); | 1100 __ SmiUntag(ebx); |
1201 // ebx: untagged index | 1101 // ebx: untagged index |
1202 // Receiver in edx will be clobbered, need to reload it on miss. | 1102 // Receiver in edx will be clobbered, need to reload it on miss. |
1203 GenerateNumberDictionaryLoad( | 1103 __ LoadFromNumberDictionary( |
1204 masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); | 1104 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); |
1205 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); | 1105 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); |
1206 __ jmp(&do_call); | 1106 __ jmp(&do_call); |
1207 | 1107 |
1208 __ bind(&slow_reload_receiver); | 1108 __ bind(&slow_reload_receiver); |
1209 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1109 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1210 | 1110 |
1211 __ bind(&slow_load); | 1111 __ bind(&slow_load); |
1212 // This branch is taken when calling KeyedCallIC_Miss is neither required | 1112 // This branch is taken when calling KeyedCallIC_Miss is neither required |
1213 // nor beneficial. | 1113 // nor beneficial. |
1214 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); | 1114 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); |
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1737 Condition cc = *jmp_address == Assembler::kJncShortOpcode | 1637 Condition cc = *jmp_address == Assembler::kJncShortOpcode |
1738 ? not_zero | 1638 ? not_zero |
1739 : zero; | 1639 : zero; |
1740 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1640 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1741 } | 1641 } |
1742 | 1642 |
1743 | 1643 |
1744 } } // namespace v8::internal | 1644 } } // namespace v8::internal |
1745 | 1645 |
1746 #endif // V8_TARGET_ARCH_IA32 | 1646 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |