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/ia32/codegen-ia32.h" | 5 #include "src/ia32/codegen-ia32.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/heap/heap.h" | 10 #include "src/heap/heap.h" |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 } | 478 } |
479 | 479 |
480 | 480 |
481 #undef __ | 481 #undef __ |
482 | 482 |
483 // ------------------------------------------------------------------------- | 483 // ------------------------------------------------------------------------- |
484 // Code generators | 484 // Code generators |
485 | 485 |
486 #define __ ACCESS_MASM(masm) | 486 #define __ ACCESS_MASM(masm) |
487 | 487 |
488 | |
489 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | |
490 MacroAssembler* masm, | |
491 Register receiver, | |
492 Register key, | |
493 Register value, | |
494 Register target_map, | |
495 AllocationSiteMode mode, | |
496 Label* allocation_memento_found) { | |
497 Register scratch = edi; | |
498 DCHECK(!AreAliased(receiver, key, value, target_map, scratch)); | |
499 | |
500 if (mode == TRACK_ALLOCATION_SITE) { | |
501 DCHECK(allocation_memento_found != NULL); | |
502 __ JumpIfJSArrayHasAllocationMemento( | |
503 receiver, scratch, allocation_memento_found); | |
504 } | |
505 | |
506 // Set transitioned map. | |
507 __ mov(FieldOperand(receiver, HeapObject::kMapOffset), target_map); | |
508 __ RecordWriteField(receiver, | |
509 HeapObject::kMapOffset, | |
510 target_map, | |
511 scratch, | |
512 kDontSaveFPRegs, | |
513 EMIT_REMEMBERED_SET, | |
514 OMIT_SMI_CHECK); | |
515 } | |
516 | |
517 | |
518 void ElementsTransitionGenerator::GenerateSmiToDouble( | |
519 MacroAssembler* masm, | |
520 Register receiver, | |
521 Register key, | |
522 Register value, | |
523 Register target_map, | |
524 AllocationSiteMode mode, | |
525 Label* fail) { | |
526 // Return address is on the stack. | |
527 DCHECK(receiver.is(edx)); | |
528 DCHECK(key.is(ecx)); | |
529 DCHECK(value.is(eax)); | |
530 DCHECK(target_map.is(ebx)); | |
531 | |
532 Label loop, entry, convert_hole, gc_required, only_change_map; | |
533 | |
534 if (mode == TRACK_ALLOCATION_SITE) { | |
535 __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail); | |
536 } | |
537 | |
538 // Check for empty arrays, which only require a map transition and no changes | |
539 // to the backing store. | |
540 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | |
541 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); | |
542 __ j(equal, &only_change_map); | |
543 | |
544 __ push(eax); | |
545 __ push(ebx); | |
546 __ push(esi); | |
547 | |
548 __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset)); | |
549 | |
550 // Allocate new FixedDoubleArray. | |
551 // edx: receiver | |
552 // edi: length of source FixedArray (smi-tagged) | |
553 AllocationFlags flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT); | |
554 __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi, | |
555 REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags); | |
556 | |
557 // eax: destination FixedDoubleArray | |
558 // edi: number of elements | |
559 // edx: receiver | |
560 __ mov(FieldOperand(eax, HeapObject::kMapOffset), | |
561 Immediate(masm->isolate()->factory()->fixed_double_array_map())); | |
562 __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi); | |
563 __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset)); | |
564 // Replace receiver's backing store with newly created FixedDoubleArray. | |
565 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax); | |
566 __ mov(ebx, eax); | |
567 __ RecordWriteField(edx, | |
568 JSObject::kElementsOffset, | |
569 ebx, | |
570 edi, | |
571 kDontSaveFPRegs, | |
572 EMIT_REMEMBERED_SET, | |
573 OMIT_SMI_CHECK); | |
574 | |
575 __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset)); | |
576 | |
577 // Prepare for conversion loop. | |
578 ExternalReference canonical_the_hole_nan_reference = | |
579 ExternalReference::address_of_the_hole_nan(); | |
580 XMMRegister the_hole_nan = xmm1; | |
581 __ movsd(the_hole_nan, | |
582 Operand::StaticVariable(canonical_the_hole_nan_reference)); | |
583 __ jmp(&entry); | |
584 | |
585 // Call into runtime if GC is required. | |
586 __ bind(&gc_required); | |
587 | |
588 // Restore registers before jumping into runtime. | |
589 __ pop(esi); | |
590 __ pop(ebx); | |
591 __ pop(eax); | |
592 __ jmp(fail); | |
593 | |
594 // Convert and copy elements | |
595 // esi: source FixedArray | |
596 __ bind(&loop); | |
597 __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize)); | |
598 // ebx: current element from source | |
599 // edi: index of current element | |
600 __ JumpIfNotSmi(ebx, &convert_hole); | |
601 | |
602 // Normal smi, convert it to double and store. | |
603 __ SmiUntag(ebx); | |
604 __ Cvtsi2sd(xmm0, ebx); | |
605 __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize), | |
606 xmm0); | |
607 __ jmp(&entry); | |
608 | |
609 // Found hole, store hole_nan_as_double instead. | |
610 __ bind(&convert_hole); | |
611 | |
612 if (FLAG_debug_code) { | |
613 __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); | |
614 __ Assert(equal, kObjectFoundInSmiOnlyArray); | |
615 } | |
616 | |
617 __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize), | |
618 the_hole_nan); | |
619 | |
620 __ bind(&entry); | |
621 __ sub(edi, Immediate(Smi::FromInt(1))); | |
622 __ j(not_sign, &loop); | |
623 | |
624 // Restore registers. | |
625 __ pop(esi); | |
626 __ pop(ebx); | |
627 __ pop(eax); | |
628 | |
629 __ bind(&only_change_map); | |
630 // eax: value | |
631 // ebx: target map | |
632 // Set transitioned map. | |
633 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); | |
634 __ RecordWriteField(edx, | |
635 HeapObject::kMapOffset, | |
636 ebx, | |
637 edi, | |
638 kDontSaveFPRegs, | |
639 OMIT_REMEMBERED_SET, | |
640 OMIT_SMI_CHECK); | |
641 } | |
642 | |
643 | |
644 void ElementsTransitionGenerator::GenerateDoubleToObject( | |
645 MacroAssembler* masm, | |
646 Register receiver, | |
647 Register key, | |
648 Register value, | |
649 Register target_map, | |
650 AllocationSiteMode mode, | |
651 Label* fail) { | |
652 // Return address is on the stack. | |
653 DCHECK(receiver.is(edx)); | |
654 DCHECK(key.is(ecx)); | |
655 DCHECK(value.is(eax)); | |
656 DCHECK(target_map.is(ebx)); | |
657 | |
658 Label loop, entry, convert_hole, gc_required, only_change_map, success; | |
659 | |
660 if (mode == TRACK_ALLOCATION_SITE) { | |
661 __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail); | |
662 } | |
663 | |
664 // Check for empty arrays, which only require a map transition and no changes | |
665 // to the backing store. | |
666 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | |
667 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); | |
668 __ j(equal, &only_change_map); | |
669 | |
670 __ push(esi); | |
671 __ push(eax); | |
672 __ push(edx); | |
673 __ push(ebx); | |
674 | |
675 __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); | |
676 | |
677 // Allocate new FixedArray. | |
678 // ebx: length of source FixedDoubleArray (smi-tagged) | |
679 __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize)); | |
680 __ Allocate(edi, eax, esi, no_reg, &gc_required, NO_ALLOCATION_FLAGS); | |
681 | |
682 // eax: destination FixedArray | |
683 // ebx: number of elements | |
684 __ mov(FieldOperand(eax, HeapObject::kMapOffset), | |
685 Immediate(masm->isolate()->factory()->fixed_array_map())); | |
686 __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx); | |
687 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | |
688 | |
689 // Allocating heap numbers in the loop below can fail and cause a jump to | |
690 // gc_required. We can't leave a partly initialized FixedArray behind, | |
691 // so pessimistically fill it with holes now. | |
692 Label initialization_loop, initialization_loop_entry; | |
693 __ jmp(&initialization_loop_entry, Label::kNear); | |
694 __ bind(&initialization_loop); | |
695 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), | |
696 masm->isolate()->factory()->the_hole_value()); | |
697 __ bind(&initialization_loop_entry); | |
698 __ sub(ebx, Immediate(Smi::FromInt(1))); | |
699 __ j(not_sign, &initialization_loop); | |
700 | |
701 __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); | |
702 __ jmp(&entry); | |
703 | |
704 // ebx: target map | |
705 // edx: receiver | |
706 // Set transitioned map. | |
707 __ bind(&only_change_map); | |
708 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); | |
709 __ RecordWriteField(edx, | |
710 HeapObject::kMapOffset, | |
711 ebx, | |
712 edi, | |
713 kDontSaveFPRegs, | |
714 OMIT_REMEMBERED_SET, | |
715 OMIT_SMI_CHECK); | |
716 __ jmp(&success); | |
717 | |
718 // Call into runtime if GC is required. | |
719 __ bind(&gc_required); | |
720 __ pop(ebx); | |
721 __ pop(edx); | |
722 __ pop(eax); | |
723 __ pop(esi); | |
724 __ jmp(fail); | |
725 | |
726 // Box doubles into heap numbers. | |
727 // edi: source FixedDoubleArray | |
728 // eax: destination FixedArray | |
729 __ bind(&loop); | |
730 // ebx: index of current element (smi-tagged) | |
731 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); | |
732 __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32)); | |
733 __ j(equal, &convert_hole); | |
734 | |
735 // Non-hole double, copy value into a heap number. | |
736 __ AllocateHeapNumber(edx, esi, no_reg, &gc_required); | |
737 // edx: new heap number | |
738 __ movsd(xmm0, | |
739 FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize)); | |
740 __ movsd(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); | |
741 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx); | |
742 __ mov(esi, ebx); | |
743 __ RecordWriteArray(eax, | |
744 edx, | |
745 esi, | |
746 kDontSaveFPRegs, | |
747 EMIT_REMEMBERED_SET, | |
748 OMIT_SMI_CHECK); | |
749 __ jmp(&entry, Label::kNear); | |
750 | |
751 // Replace the-hole NaN with the-hole pointer. | |
752 __ bind(&convert_hole); | |
753 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), | |
754 masm->isolate()->factory()->the_hole_value()); | |
755 | |
756 __ bind(&entry); | |
757 __ sub(ebx, Immediate(Smi::FromInt(1))); | |
758 __ j(not_sign, &loop); | |
759 | |
760 __ pop(ebx); | |
761 __ pop(edx); | |
762 // ebx: target map | |
763 // edx: receiver | |
764 // Set transitioned map. | |
765 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); | |
766 __ RecordWriteField(edx, | |
767 HeapObject::kMapOffset, | |
768 ebx, | |
769 edi, | |
770 kDontSaveFPRegs, | |
771 OMIT_REMEMBERED_SET, | |
772 OMIT_SMI_CHECK); | |
773 // Replace receiver's backing store with newly created and filled FixedArray. | |
774 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax); | |
775 __ RecordWriteField(edx, | |
776 JSObject::kElementsOffset, | |
777 eax, | |
778 edi, | |
779 kDontSaveFPRegs, | |
780 EMIT_REMEMBERED_SET, | |
781 OMIT_SMI_CHECK); | |
782 | |
783 // Restore registers. | |
784 __ pop(eax); | |
785 __ pop(esi); | |
786 | |
787 __ bind(&success); | |
788 } | |
789 | |
790 | |
791 void StringCharLoadGenerator::Generate(MacroAssembler* masm, | 488 void StringCharLoadGenerator::Generate(MacroAssembler* masm, |
792 Factory* factory, | 489 Factory* factory, |
793 Register string, | 490 Register string, |
794 Register index, | 491 Register index, |
795 Register result, | 492 Register result, |
796 Label* call_runtime) { | 493 Label* call_runtime) { |
797 // Fetch the instance type of the receiver into result register. | 494 // Fetch the instance type of the receiver into result register. |
798 __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); | 495 __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); |
799 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | 496 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
800 | 497 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
948 CodePatcher patcher(isolate, sequence, young_length); | 645 CodePatcher patcher(isolate, sequence, young_length); |
949 patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32); | 646 patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32); |
950 } | 647 } |
951 } | 648 } |
952 | 649 |
953 | 650 |
954 } // namespace internal | 651 } // namespace internal |
955 } // namespace v8 | 652 } // namespace v8 |
956 | 653 |
957 #endif // V8_TARGET_ARCH_IA32 | 654 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |