OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include "src/arm/assembler-arm.h" | 9 #include "src/arm/assembler-arm.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 304 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
305 STATIC_ASSERT(kInternalizedTag == 0); | 305 STATIC_ASSERT(kInternalizedTag == 0); |
306 __ tst(hash, Operand(kIsNotInternalizedMask)); | 306 __ tst(hash, Operand(kIsNotInternalizedMask)); |
307 __ b(ne, not_unique); | 307 __ b(ne, not_unique); |
308 | 308 |
309 __ bind(&unique); | 309 __ bind(&unique); |
310 } | 310 } |
311 | 311 |
312 | 312 |
313 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 313 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
314 // ----------- S t a t e ------------- | 314 // The return address is in lr. |
315 // -- r2 : name | 315 Register receiver = ReceiverRegister(); |
316 // -- lr : return address | 316 Register name = NameRegister(); |
317 // -- r0 : receiver | 317 ASSERT(receiver.is(r1)); |
318 // ----------------------------------- | 318 ASSERT(name.is(r2)); |
319 ASSERT(r0.is(ReceiverRegister())); | |
320 ASSERT(r2.is(NameRegister())); | |
321 | 319 |
322 // Probe the stub cache. | 320 // Probe the stub cache. |
323 Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC); | 321 Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC); |
324 masm->isolate()->stub_cache()->GenerateProbe( | 322 masm->isolate()->stub_cache()->GenerateProbe( |
325 masm, flags, r0, r2, r3, r4, r5, r6); | 323 masm, flags, receiver, name, r3, r4, r5, r6); |
326 | 324 |
327 // Cache miss: Jump to runtime. | 325 // Cache miss: Jump to runtime. |
328 GenerateMiss(masm); | 326 GenerateMiss(masm); |
329 } | 327 } |
330 | 328 |
331 | 329 |
332 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 330 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
333 // ----------- S t a t e ------------- | 331 // ----------- S t a t e ------------- |
334 // -- r2 : name | 332 // -- r2 : name |
335 // -- lr : return address | 333 // -- lr : return address |
336 // -- r0 : receiver | 334 // -- r1 : receiver |
337 // ----------------------------------- | 335 // ----------------------------------- |
338 ASSERT(r0.is(ReceiverRegister())); | 336 ASSERT(r1.is(ReceiverRegister())); |
339 ASSERT(r2.is(NameRegister())); | 337 ASSERT(r2.is(NameRegister())); |
340 | 338 |
341 Label miss, slow; | 339 Label miss, slow; |
342 | 340 |
343 GenerateNameDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss); | 341 GenerateNameDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss); |
344 | 342 |
345 // r1: elements | 343 // r0: elements |
346 GenerateDictionaryLoad(masm, &slow, r1, r2, r0, r3, r4); | 344 GenerateDictionaryLoad(masm, &slow, r0, r2, r0, r3, r4); |
347 __ Ret(); | 345 __ Ret(); |
348 | 346 |
349 // Dictionary load failed, go slow (but don't miss). | 347 // Dictionary load failed, go slow (but don't miss). |
350 __ bind(&slow); | 348 __ bind(&slow); |
351 GenerateRuntimeGetProperty(masm); | 349 GenerateRuntimeGetProperty(masm); |
352 | 350 |
353 // Cache miss: Jump to runtime. | 351 // Cache miss: Jump to runtime. |
354 __ bind(&miss); | 352 __ bind(&miss); |
355 GenerateMiss(masm); | 353 GenerateMiss(masm); |
356 } | 354 } |
357 | 355 |
358 | 356 |
359 // A register that isn't one of the parameters to the load ic. | 357 // A register that isn't one of the parameters to the load ic. |
360 static const Register LoadIC_TempRegister() { return r3; } | 358 static const Register LoadIC_TempRegister() { return r3; } |
361 | 359 |
362 | 360 |
363 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 361 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
364 // The return address is on the stack. | 362 // The return address is in lr. |
365 Isolate* isolate = masm->isolate(); | 363 Isolate* isolate = masm->isolate(); |
366 | 364 |
367 __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4); | 365 __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4); |
368 | 366 |
369 __ mov(LoadIC_TempRegister(), ReceiverRegister()); | 367 __ mov(LoadIC_TempRegister(), ReceiverRegister()); |
370 __ Push(LoadIC_TempRegister(), NameRegister()); | 368 __ Push(LoadIC_TempRegister(), NameRegister()); |
371 | 369 |
372 // Perform tail call to the entry. | 370 // Perform tail call to the entry. |
373 ExternalReference ref = | 371 ExternalReference ref = |
374 ExternalReference(IC_Utility(kLoadIC_Miss), isolate); | 372 ExternalReference(IC_Utility(kLoadIC_Miss), isolate); |
375 __ TailCallExternalReference(ref, 2, 1); | 373 __ TailCallExternalReference(ref, 2, 1); |
376 } | 374 } |
377 | 375 |
378 | 376 |
379 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 377 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
380 // The return address is on the stack. | 378 // The return address is in lr. |
381 | 379 |
382 __ mov(LoadIC_TempRegister(), ReceiverRegister()); | 380 __ mov(LoadIC_TempRegister(), ReceiverRegister()); |
383 __ Push(LoadIC_TempRegister(), NameRegister()); | 381 __ Push(LoadIC_TempRegister(), NameRegister()); |
384 | 382 |
385 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); | 383 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); |
386 } | 384 } |
387 | 385 |
388 | 386 |
389 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, | 387 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, |
390 Register object, | 388 Register object, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 __ mov(scratch, Operand(kPointerSize >> 1)); | 463 __ mov(scratch, Operand(kPointerSize >> 1)); |
466 __ mul(scratch, key, scratch); | 464 __ mul(scratch, key, scratch); |
467 __ add(scratch, | 465 __ add(scratch, |
468 scratch, | 466 scratch, |
469 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 467 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
470 return MemOperand(backing_store, scratch); | 468 return MemOperand(backing_store, scratch); |
471 } | 469 } |
472 | 470 |
473 | 471 |
474 void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) { | 472 void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) { |
475 // ---------- S t a t e -------------- | 473 // The return address is in lr. |
476 // -- lr : return address | 474 Register receiver = ReceiverRegister(); |
477 // -- r0 : key | 475 Register key = NameRegister(); |
478 // -- r1 : receiver | 476 ASSERT(receiver.is(r1)); |
479 // ----------------------------------- | 477 ASSERT(key.is(r2)); |
480 ASSERT(r1.is(ReceiverRegister())); | 478 |
481 ASSERT(r0.is(NameRegister())); | |
482 Label slow, notin; | 479 Label slow, notin; |
483 MemOperand mapped_location = | 480 MemOperand mapped_location = |
484 GenerateMappedArgumentsLookup(masm, r1, r0, r2, r3, r4, ¬in, &slow); | 481 GenerateMappedArgumentsLookup( |
| 482 masm, receiver, key, r0, r3, r4, ¬in, &slow); |
485 __ ldr(r0, mapped_location); | 483 __ ldr(r0, mapped_location); |
486 __ Ret(); | 484 __ Ret(); |
487 __ bind(¬in); | 485 __ bind(¬in); |
488 // The unmapped lookup expects that the parameter map is in r2. | 486 // The unmapped lookup expects that the parameter map is in r0. |
489 MemOperand unmapped_location = | 487 MemOperand unmapped_location = |
490 GenerateUnmappedArgumentsLookup(masm, r0, r2, r3, &slow); | 488 GenerateUnmappedArgumentsLookup(masm, key, r0, r3, &slow); |
491 __ ldr(r2, unmapped_location); | 489 __ ldr(r0, unmapped_location); |
492 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); | 490 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); |
493 __ cmp(r2, r3); | 491 __ cmp(r0, r3); |
494 __ b(eq, &slow); | 492 __ b(eq, &slow); |
495 __ mov(r0, r2); | |
496 __ Ret(); | 493 __ Ret(); |
497 __ bind(&slow); | 494 __ bind(&slow); |
498 GenerateMiss(masm); | 495 GenerateMiss(masm); |
499 } | 496 } |
500 | 497 |
501 | 498 |
502 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) { | 499 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) { |
503 // ---------- S t a t e -------------- | 500 // ---------- S t a t e -------------- |
504 // -- r0 : value | 501 // -- r0 : value |
505 // -- r1 : key | 502 // -- r1 : key |
(...skipping 16 matching lines...) Expand all Loading... |
522 __ add(r6, r3, r4); | 519 __ add(r6, r3, r4); |
523 __ mov(r9, r0); | 520 __ mov(r9, r0); |
524 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs); | 521 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs); |
525 __ Ret(); | 522 __ Ret(); |
526 __ bind(&slow); | 523 __ bind(&slow); |
527 GenerateMiss(masm); | 524 GenerateMiss(masm); |
528 } | 525 } |
529 | 526 |
530 | 527 |
531 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 528 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
532 // The return address is on the stack. | 529 // The return address is in lr. |
533 Isolate* isolate = masm->isolate(); | 530 Isolate* isolate = masm->isolate(); |
534 | 531 |
535 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4); | 532 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4); |
536 | 533 |
537 __ Push(ReceiverRegister(), NameRegister()); | 534 __ Push(ReceiverRegister(), NameRegister()); |
538 | 535 |
539 // Perform tail call to the entry. | 536 // Perform tail call to the entry. |
540 ExternalReference ref = | 537 ExternalReference ref = |
541 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); | 538 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); |
542 | 539 |
543 __ TailCallExternalReference(ref, 2, 1); | 540 __ TailCallExternalReference(ref, 2, 1); |
544 } | 541 } |
545 | 542 |
546 | 543 |
547 // IC register specifications | 544 // IC register specifications |
548 const Register LoadIC::ReceiverRegister() { return r0; } | 545 const Register LoadIC::ReceiverRegister() { return r1; } |
549 const Register LoadIC::NameRegister() { return r2; } | 546 const Register LoadIC::NameRegister() { return r2; } |
550 const Register KeyedLoadIC::ReceiverRegister() { return r1; } | |
551 const Register KeyedLoadIC::NameRegister() { return r0; } | |
552 | 547 |
553 | 548 |
554 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 549 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
555 // The return address is on the stack. | 550 // The return address is in lr. |
556 | 551 |
557 __ Push(ReceiverRegister(), NameRegister()); | 552 __ Push(ReceiverRegister(), NameRegister()); |
558 | 553 |
559 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 554 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
560 } | 555 } |
561 | 556 |
562 | 557 |
563 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 558 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
564 // ---------- S t a t e -------------- | 559 // The return address is in lr. |
565 // -- lr : return address | |
566 // -- r0 : key | |
567 // -- r1 : receiver | |
568 // ----------------------------------- | |
569 Label slow, check_name, index_smi, index_name, property_array_property; | 560 Label slow, check_name, index_smi, index_name, property_array_property; |
570 Label probe_dictionary, check_number_dictionary; | 561 Label probe_dictionary, check_number_dictionary; |
571 | 562 |
572 Register key = NameRegister(); | 563 Register key = NameRegister(); |
573 Register receiver = ReceiverRegister(); | 564 Register receiver = ReceiverRegister(); |
574 ASSERT(key.is(r0)); | 565 ASSERT(key.is(r2)); |
575 ASSERT(receiver.is(r1)); | 566 ASSERT(receiver.is(r1)); |
576 | 567 |
577 Isolate* isolate = masm->isolate(); | 568 Isolate* isolate = masm->isolate(); |
578 | 569 |
579 // Check that the key is a smi. | 570 // Check that the key is a smi. |
580 __ JumpIfNotSmi(key, &check_name); | 571 __ JumpIfNotSmi(key, &check_name); |
581 __ bind(&index_smi); | 572 __ bind(&index_smi); |
582 // Now the key is known to be a smi. This place is also jumped to from below | 573 // Now the key is known to be a smi. This place is also jumped to from below |
583 // where a numeric string is converted to a smi. | 574 // where a numeric string is converted to a smi. |
584 | 575 |
585 GenerateKeyedLoadReceiverCheck( | 576 GenerateKeyedLoadReceiverCheck( |
586 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow); | 577 masm, receiver, r0, r3, Map::kHasIndexedInterceptor, &slow); |
587 | 578 |
588 // Check the receiver's map to see if it has fast elements. | 579 // Check the receiver's map to see if it has fast elements. |
589 __ CheckFastElements(r2, r3, &check_number_dictionary); | 580 __ CheckFastElements(r0, r3, &check_number_dictionary); |
590 | 581 |
591 GenerateFastArrayLoad( | 582 GenerateFastArrayLoad( |
592 masm, receiver, key, r4, r3, r2, r0, NULL, &slow); | 583 masm, receiver, key, r0, r3, r4, r0, NULL, &slow); |
593 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3); | 584 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r4, r3); |
594 __ Ret(); | 585 __ Ret(); |
595 | 586 |
596 __ bind(&check_number_dictionary); | 587 __ bind(&check_number_dictionary); |
597 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 588 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
598 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); | 589 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); |
599 | 590 |
600 // Check whether the elements is a number dictionary. | 591 // Check whether the elements is a number dictionary. |
601 // r0: key | |
602 // r3: elements map | 592 // r3: elements map |
603 // r4: elements | 593 // r4: elements |
604 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 594 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
605 __ cmp(r3, ip); | 595 __ cmp(r3, ip); |
606 __ b(ne, &slow); | 596 __ b(ne, &slow); |
607 __ SmiUntag(r2, r0); | 597 __ SmiUntag(r0, key); |
608 __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5); | 598 __ LoadFromNumberDictionary(&slow, r4, key, r0, r0, r3, r5); |
609 __ Ret(); | 599 __ Ret(); |
610 | 600 |
611 // Slow case, key and receiver still in r0 and r1. | 601 // Slow case, key and receiver still in r2 and r1. |
612 __ bind(&slow); | 602 __ bind(&slow); |
613 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), | 603 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), |
614 1, r2, r3); | 604 1, r4, r3); |
615 GenerateRuntimeGetProperty(masm); | 605 GenerateRuntimeGetProperty(masm); |
616 | 606 |
617 __ bind(&check_name); | 607 __ bind(&check_name); |
618 GenerateKeyNameCheck(masm, key, r2, r3, &index_name, &slow); | 608 GenerateKeyNameCheck(masm, key, r0, r3, &index_name, &slow); |
619 | 609 |
620 GenerateKeyedLoadReceiverCheck( | 610 GenerateKeyedLoadReceiverCheck( |
621 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow); | 611 masm, receiver, r0, r3, Map::kHasNamedInterceptor, &slow); |
622 | 612 |
623 // If the receiver is a fast-case object, check the keyed lookup | 613 // If the receiver is a fast-case object, check the keyed lookup |
624 // cache. Otherwise probe the dictionary. | 614 // cache. Otherwise probe the dictionary. |
625 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); | 615 __ ldr(r3, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
626 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); | 616 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); |
627 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 617 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
628 __ cmp(r4, ip); | 618 __ cmp(r4, ip); |
629 __ b(eq, &probe_dictionary); | 619 __ b(eq, &probe_dictionary); |
630 | 620 |
631 // Load the map of the receiver, compute the keyed lookup cache hash | 621 // Load the map of the receiver, compute the keyed lookup cache hash |
632 // based on 32 bits of the map pointer and the name hash. | 622 // based on 32 bits of the map pointer and the name hash. |
633 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 623 __ ldr(r0, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
634 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift)); | 624 __ mov(r3, Operand(r0, ASR, KeyedLookupCache::kMapHashShift)); |
635 __ ldr(r4, FieldMemOperand(r0, Name::kHashFieldOffset)); | 625 __ ldr(r4, FieldMemOperand(key, Name::kHashFieldOffset)); |
636 __ eor(r3, r3, Operand(r4, ASR, Name::kHashShift)); | 626 __ eor(r3, r3, Operand(r4, ASR, Name::kHashShift)); |
637 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; | 627 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; |
638 __ And(r3, r3, Operand(mask)); | 628 __ And(r3, r3, Operand(mask)); |
639 | 629 |
640 // Load the key (consisting of map and unique name) from the cache and | 630 // Load the key (consisting of map and unique name) from the cache and |
641 // check for match. | 631 // check for match. |
642 Label load_in_object_property; | 632 Label load_in_object_property; |
643 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; | 633 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; |
644 Label hit_on_nth_entry[kEntriesPerBucket]; | 634 Label hit_on_nth_entry[kEntriesPerBucket]; |
645 ExternalReference cache_keys = | 635 ExternalReference cache_keys = |
646 ExternalReference::keyed_lookup_cache_keys(isolate); | 636 ExternalReference::keyed_lookup_cache_keys(isolate); |
647 | 637 |
648 __ mov(r4, Operand(cache_keys)); | 638 __ mov(r4, Operand(cache_keys)); |
649 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1)); | 639 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1)); |
650 | 640 |
651 for (int i = 0; i < kEntriesPerBucket - 1; i++) { | 641 for (int i = 0; i < kEntriesPerBucket - 1; i++) { |
652 Label try_next_entry; | 642 Label try_next_entry; |
653 // Load map and move r4 to next entry. | 643 // Load map and move r4 to next entry. |
654 __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex)); | 644 __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex)); |
655 __ cmp(r2, r5); | 645 __ cmp(r0, r5); |
656 __ b(ne, &try_next_entry); | 646 __ b(ne, &try_next_entry); |
657 __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load name | 647 __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load name |
658 __ cmp(r0, r5); | 648 __ cmp(key, r5); |
659 __ b(eq, &hit_on_nth_entry[i]); | 649 __ b(eq, &hit_on_nth_entry[i]); |
660 __ bind(&try_next_entry); | 650 __ bind(&try_next_entry); |
661 } | 651 } |
662 | 652 |
663 // Last entry: Load map and move r4 to name. | 653 // Last entry: Load map and move r4 to name. |
664 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); | 654 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); |
665 __ cmp(r2, r5); | 655 __ cmp(r0, r5); |
666 __ b(ne, &slow); | 656 __ b(ne, &slow); |
667 __ ldr(r5, MemOperand(r4)); | 657 __ ldr(r5, MemOperand(r4)); |
668 __ cmp(r0, r5); | 658 __ cmp(key, r5); |
669 __ b(ne, &slow); | 659 __ b(ne, &slow); |
670 | 660 |
671 // Get field offset. | 661 // Get field offset. |
672 // r0 : key | 662 // r0 : receiver's map |
673 // r1 : receiver | |
674 // r2 : receiver's map | |
675 // r3 : lookup cache index | 663 // r3 : lookup cache index |
676 ExternalReference cache_field_offsets = | 664 ExternalReference cache_field_offsets = |
677 ExternalReference::keyed_lookup_cache_field_offsets(isolate); | 665 ExternalReference::keyed_lookup_cache_field_offsets(isolate); |
678 | 666 |
679 // Hit on nth entry. | 667 // Hit on nth entry. |
680 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { | 668 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { |
681 __ bind(&hit_on_nth_entry[i]); | 669 __ bind(&hit_on_nth_entry[i]); |
682 __ mov(r4, Operand(cache_field_offsets)); | 670 __ mov(r4, Operand(cache_field_offsets)); |
683 if (i != 0) { | 671 if (i != 0) { |
684 __ add(r3, r3, Operand(i)); | 672 __ add(r3, r3, Operand(i)); |
685 } | 673 } |
686 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2)); | 674 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2)); |
687 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset)); | 675 __ ldrb(r6, FieldMemOperand(r0, Map::kInObjectPropertiesOffset)); |
688 __ sub(r5, r5, r6, SetCC); | 676 __ sub(r5, r5, r6, SetCC); |
689 __ b(ge, &property_array_property); | 677 __ b(ge, &property_array_property); |
690 if (i != 0) { | 678 if (i != 0) { |
691 __ jmp(&load_in_object_property); | 679 __ jmp(&load_in_object_property); |
692 } | 680 } |
693 } | 681 } |
694 | 682 |
695 // Load in-object property. | 683 // Load in-object property. |
696 __ bind(&load_in_object_property); | 684 __ bind(&load_in_object_property); |
697 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset)); | 685 __ ldrb(r6, FieldMemOperand(r0, Map::kInstanceSizeOffset)); |
698 __ add(r6, r6, r5); // Index from start of object. | 686 __ add(r6, r6, r5); // Index from start of object. |
699 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag. | 687 __ sub(receiver, receiver, Operand(kHeapObjectTag)); // Remove the heap tag. |
700 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2)); | 688 __ ldr(r0, MemOperand(receiver, r6, LSL, kPointerSizeLog2)); |
701 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), | 689 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), |
702 1, r2, r3); | 690 1, r4, r3); |
703 __ Ret(); | 691 __ Ret(); |
704 | 692 |
705 // Load property array property. | 693 // Load property array property. |
706 __ bind(&property_array_property); | 694 __ bind(&property_array_property); |
707 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset)); | 695 __ ldr(receiver, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
708 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 696 __ add(receiver, receiver, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
709 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2)); | 697 __ ldr(r0, MemOperand(receiver, r5, LSL, kPointerSizeLog2)); |
710 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), | 698 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), |
711 1, r2, r3); | 699 1, r4, r3); |
712 __ Ret(); | 700 __ Ret(); |
713 | 701 |
714 // Do a quick inline probe of the receiver's dictionary, if it | 702 // Do a quick inline probe of the receiver's dictionary, if it |
715 // exists. | 703 // exists. |
716 __ bind(&probe_dictionary); | 704 __ bind(&probe_dictionary); |
717 // r1: receiver | |
718 // r0: key | |
719 // r3: elements | 705 // r3: elements |
720 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 706 __ ldr(r0, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
721 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 707 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
722 GenerateGlobalInstanceTypeCheck(masm, r2, &slow); | 708 GenerateGlobalInstanceTypeCheck(masm, r0, &slow); |
723 // Load the property to r0. | 709 // Load the property to r0. |
724 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4); | 710 GenerateDictionaryLoad(masm, &slow, r3, key, r0, r5, r4); |
725 __ IncrementCounter( | 711 __ IncrementCounter( |
726 isolate->counters()->keyed_load_generic_symbol(), 1, r2, r3); | 712 isolate->counters()->keyed_load_generic_symbol(), 1, r4, r3); |
727 __ Ret(); | 713 __ Ret(); |
728 | 714 |
729 __ bind(&index_name); | 715 __ bind(&index_name); |
730 __ IndexFromHash(r3, key); | 716 __ IndexFromHash(r3, key); |
731 // Now jump to the place where smi keys are handled. | 717 // Now jump to the place where smi keys are handled. |
732 __ jmp(&index_smi); | 718 __ jmp(&index_smi); |
733 } | 719 } |
734 | 720 |
735 | 721 |
736 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 722 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
737 // Return address is on the stack. | 723 // Return address is in lr. |
738 Label miss; | 724 Label miss; |
739 | 725 |
740 Register receiver = ReceiverRegister(); | 726 Register receiver = ReceiverRegister(); |
741 Register index = NameRegister(); | 727 Register index = NameRegister(); |
742 Register scratch = r3; | 728 Register scratch = r3; |
743 Register result = r0; | 729 Register result = r0; |
744 ASSERT(!scratch.is(receiver) && !scratch.is(index)); | 730 ASSERT(!scratch.is(receiver) && !scratch.is(index)); |
745 | 731 |
746 StringCharAtGenerator char_at_generator(receiver, | 732 StringCharAtGenerator char_at_generator(receiver, |
747 index, | 733 index, |
748 scratch, | 734 scratch, |
749 result, | 735 result, |
750 &miss, // When not a string. | 736 &miss, // When not a string. |
751 &miss, // When not a number. | 737 &miss, // When not a number. |
752 &miss, // When index out of range. | 738 &miss, // When index out of range. |
753 STRING_INDEX_IS_ARRAY_INDEX); | 739 STRING_INDEX_IS_ARRAY_INDEX); |
754 char_at_generator.GenerateFast(masm); | 740 char_at_generator.GenerateFast(masm); |
755 __ Ret(); | 741 __ Ret(); |
756 | 742 |
757 StubRuntimeCallHelper call_helper; | 743 StubRuntimeCallHelper call_helper; |
758 char_at_generator.GenerateSlow(masm, call_helper); | 744 char_at_generator.GenerateSlow(masm, call_helper); |
759 | 745 |
760 __ bind(&miss); | 746 __ bind(&miss); |
761 GenerateMiss(masm); | 747 GenerateMiss(masm); |
762 } | 748 } |
763 | 749 |
764 | 750 |
765 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { | 751 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { |
766 // Return address is on the stack. | 752 // Return address is in lr. |
767 Label slow; | 753 Label slow; |
768 | 754 |
769 Register receiver = ReceiverRegister(); | 755 Register receiver = ReceiverRegister(); |
770 Register key = NameRegister(); | 756 Register key = NameRegister(); |
771 Register scratch1 = r2; | 757 Register scratch1 = r3; |
772 Register scratch2 = r3; | 758 Register scratch2 = r4; |
773 ASSERT(!scratch1.is(receiver) && !scratch1.is(key)); | 759 ASSERT(!scratch1.is(receiver) && !scratch1.is(key)); |
774 ASSERT(!scratch2.is(receiver) && !scratch2.is(key)); | 760 ASSERT(!scratch2.is(receiver) && !scratch2.is(key)); |
775 | 761 |
776 // Check that the receiver isn't a smi. | 762 // Check that the receiver isn't a smi. |
777 __ JumpIfSmi(receiver, &slow); | 763 __ JumpIfSmi(receiver, &slow); |
778 | 764 |
779 // Check that the key is an array index, that is Uint32. | 765 // Check that the key is an array index, that is Uint32. |
780 __ NonNegativeSmiTst(key); | 766 __ NonNegativeSmiTst(key); |
781 __ b(ne, &slow); | 767 __ b(ne, &slow); |
782 | 768 |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1316 } else { | 1302 } else { |
1317 ASSERT(Assembler::GetCondition(branch_instr) == ne); | 1303 ASSERT(Assembler::GetCondition(branch_instr) == ne); |
1318 patcher.EmitCondition(eq); | 1304 patcher.EmitCondition(eq); |
1319 } | 1305 } |
1320 } | 1306 } |
1321 | 1307 |
1322 | 1308 |
1323 } } // namespace v8::internal | 1309 } } // namespace v8::internal |
1324 | 1310 |
1325 #endif // V8_TARGET_ARCH_ARM | 1311 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |