| 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 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 __ j(greater, &negative, Label::kNear); | 510 __ j(greater, &negative, Label::kNear); |
| 511 __ mov(ecx, scratch2); | 511 __ mov(ecx, scratch2); |
| 512 __ jmp(&done, Label::kNear); | 512 __ jmp(&done, Label::kNear); |
| 513 __ bind(&negative); | 513 __ bind(&negative); |
| 514 __ sub(ecx, Operand(scratch2)); | 514 __ sub(ecx, Operand(scratch2)); |
| 515 __ bind(&done); | 515 __ bind(&done); |
| 516 } | 516 } |
| 517 } | 517 } |
| 518 | 518 |
| 519 | 519 |
| 520 Handle<Code> GetTypeRecordingUnaryOpStub(int key, | 520 Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info) { |
| 521 TRUnaryOpIC::TypeInfo type_info) { | 521 UnaryOpStub stub(key, type_info); |
| 522 TypeRecordingUnaryOpStub stub(key, type_info); | |
| 523 return stub.GetCode(); | 522 return stub.GetCode(); |
| 524 } | 523 } |
| 525 | 524 |
| 526 | 525 |
| 527 const char* TypeRecordingUnaryOpStub::GetName() { | 526 const char* UnaryOpStub::GetName() { |
| 528 if (name_ != NULL) return name_; | 527 if (name_ != NULL) return name_; |
| 529 const int kMaxNameLength = 100; | 528 const int kMaxNameLength = 100; |
| 530 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | 529 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 531 kMaxNameLength); | 530 kMaxNameLength); |
| 532 if (name_ == NULL) return "OOM"; | 531 if (name_ == NULL) return "OOM"; |
| 533 const char* op_name = Token::Name(op_); | 532 const char* op_name = Token::Name(op_); |
| 534 const char* overwrite_name = NULL; // Make g++ happy. | 533 const char* overwrite_name = NULL; // Make g++ happy. |
| 535 switch (mode_) { | 534 switch (mode_) { |
| 536 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 535 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 537 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | 536 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; |
| 538 } | 537 } |
| 539 | 538 |
| 540 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 539 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 541 "TypeRecordingUnaryOpStub_%s_%s_%s", | 540 "UnaryOpStub_%s_%s_%s", |
| 542 op_name, | 541 op_name, |
| 543 overwrite_name, | 542 overwrite_name, |
| 544 TRUnaryOpIC::GetName(operand_type_)); | 543 UnaryOpIC::GetName(operand_type_)); |
| 545 return name_; | 544 return name_; |
| 546 } | 545 } |
| 547 | 546 |
| 548 | 547 |
| 549 // TODO(svenpanne): Use virtual functions instead of switch. | 548 // TODO(svenpanne): Use virtual functions instead of switch. |
| 550 void TypeRecordingUnaryOpStub::Generate(MacroAssembler* masm) { | 549 void UnaryOpStub::Generate(MacroAssembler* masm) { |
| 551 switch (operand_type_) { | 550 switch (operand_type_) { |
| 552 case TRUnaryOpIC::UNINITIALIZED: | 551 case UnaryOpIC::UNINITIALIZED: |
| 553 GenerateTypeTransition(masm); | 552 GenerateTypeTransition(masm); |
| 554 break; | 553 break; |
| 555 case TRUnaryOpIC::SMI: | 554 case UnaryOpIC::SMI: |
| 556 GenerateSmiStub(masm); | 555 GenerateSmiStub(masm); |
| 557 break; | 556 break; |
| 558 case TRUnaryOpIC::HEAP_NUMBER: | 557 case UnaryOpIC::HEAP_NUMBER: |
| 559 GenerateHeapNumberStub(masm); | 558 GenerateHeapNumberStub(masm); |
| 560 break; | 559 break; |
| 561 case TRUnaryOpIC::GENERIC: | 560 case UnaryOpIC::GENERIC: |
| 562 GenerateGenericStub(masm); | 561 GenerateGenericStub(masm); |
| 563 break; | 562 break; |
| 564 } | 563 } |
| 565 } | 564 } |
| 566 | 565 |
| 567 | 566 |
| 568 void TypeRecordingUnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 567 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 569 __ pop(ecx); // Save return address. | 568 __ pop(ecx); // Save return address. |
| 570 __ push(eax); | 569 __ push(eax); |
| 571 // the argument is now on top. | 570 // the argument is now on top. |
| 572 // Push this stub's key. Although the operation and the type info are | 571 // Push this stub's key. Although the operation and the type info are |
| 573 // encoded into the key, the encoding is opaque, so push them too. | 572 // encoded into the key, the encoding is opaque, so push them too. |
| 574 __ push(Immediate(Smi::FromInt(MinorKey()))); | 573 __ push(Immediate(Smi::FromInt(MinorKey()))); |
| 575 __ push(Immediate(Smi::FromInt(op_))); | 574 __ push(Immediate(Smi::FromInt(op_))); |
| 576 __ push(Immediate(Smi::FromInt(operand_type_))); | 575 __ push(Immediate(Smi::FromInt(operand_type_))); |
| 577 | 576 |
| 578 __ push(ecx); // Push return address. | 577 __ push(ecx); // Push return address. |
| 579 | 578 |
| 580 // Patch the caller to an appropriate specialized stub and return the | 579 // Patch the caller to an appropriate specialized stub and return the |
| 581 // operation result to the caller of the stub. | 580 // operation result to the caller of the stub. |
| 582 __ TailCallExternalReference( | 581 __ TailCallExternalReference( |
| 583 ExternalReference(IC_Utility(IC::kTypeRecordingUnaryOp_Patch), | 582 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), |
| 584 masm->isolate()), | 583 masm->isolate()), 4, 1); |
| 585 4, | |
| 586 1); | |
| 587 } | 584 } |
| 588 | 585 |
| 589 | 586 |
| 590 // TODO(svenpanne): Use virtual functions instead of switch. | 587 // TODO(svenpanne): Use virtual functions instead of switch. |
| 591 void TypeRecordingUnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 588 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 592 switch (op_) { | 589 switch (op_) { |
| 593 case Token::SUB: | 590 case Token::SUB: |
| 594 GenerateSmiStubSub(masm); | 591 GenerateSmiStubSub(masm); |
| 595 break; | 592 break; |
| 596 case Token::BIT_NOT: | 593 case Token::BIT_NOT: |
| 597 GenerateSmiStubBitNot(masm); | 594 GenerateSmiStubBitNot(masm); |
| 598 break; | 595 break; |
| 599 default: | 596 default: |
| 600 UNREACHABLE(); | 597 UNREACHABLE(); |
| 601 } | 598 } |
| 602 } | 599 } |
| 603 | 600 |
| 604 | 601 |
| 605 void TypeRecordingUnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { | 602 void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { |
| 606 Label non_smi, undo, slow; | 603 Label non_smi, undo, slow; |
| 607 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, | 604 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, |
| 608 Label::kNear, Label::kNear, Label::kNear); | 605 Label::kNear, Label::kNear, Label::kNear); |
| 609 __ bind(&undo); | 606 __ bind(&undo); |
| 610 GenerateSmiCodeUndo(masm); | 607 GenerateSmiCodeUndo(masm); |
| 611 __ bind(&non_smi); | 608 __ bind(&non_smi); |
| 612 __ bind(&slow); | 609 __ bind(&slow); |
| 613 GenerateTypeTransition(masm); | 610 GenerateTypeTransition(masm); |
| 614 } | 611 } |
| 615 | 612 |
| 616 | 613 |
| 617 void TypeRecordingUnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { | 614 void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { |
| 618 Label non_smi; | 615 Label non_smi; |
| 619 GenerateSmiCodeBitNot(masm, &non_smi); | 616 GenerateSmiCodeBitNot(masm, &non_smi); |
| 620 __ bind(&non_smi); | 617 __ bind(&non_smi); |
| 621 GenerateTypeTransition(masm); | 618 GenerateTypeTransition(masm); |
| 622 } | 619 } |
| 623 | 620 |
| 624 | 621 |
| 625 void TypeRecordingUnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, | 622 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, |
| 626 Label* non_smi, | 623 Label* non_smi, |
| 627 Label* undo, | 624 Label* undo, |
| 628 Label* slow, | 625 Label* slow, |
| 629 Label::Distance non_smi_near, | 626 Label::Distance non_smi_near, |
| 630 Label::Distance undo_near, | 627 Label::Distance undo_near, |
| 631 Label::Distance slow_near) { | 628 Label::Distance slow_near) { |
| 632 // Check whether the value is a smi. | 629 // Check whether the value is a smi. |
| 633 __ test(eax, Immediate(kSmiTagMask)); | 630 __ test(eax, Immediate(kSmiTagMask)); |
| 634 __ j(not_zero, non_smi, non_smi_near); | 631 __ j(not_zero, non_smi, non_smi_near); |
| 635 | 632 |
| 636 // We can't handle -0 with smis, so use a type transition for that case. | 633 // We can't handle -0 with smis, so use a type transition for that case. |
| 637 __ test(eax, Operand(eax)); | 634 __ test(eax, Operand(eax)); |
| 638 __ j(zero, slow, slow_near); | 635 __ j(zero, slow, slow_near); |
| 639 | 636 |
| 640 // Try optimistic subtraction '0 - value', saving operand in eax for undo. | 637 // Try optimistic subtraction '0 - value', saving operand in eax for undo. |
| 641 __ mov(edx, Operand(eax)); | 638 __ mov(edx, Operand(eax)); |
| 642 __ Set(eax, Immediate(0)); | 639 __ Set(eax, Immediate(0)); |
| 643 __ sub(eax, Operand(edx)); | 640 __ sub(eax, Operand(edx)); |
| 644 __ j(overflow, undo, undo_near); | 641 __ j(overflow, undo, undo_near); |
| 645 __ ret(0); | 642 __ ret(0); |
| 646 } | 643 } |
| 647 | 644 |
| 648 | 645 |
| 649 void TypeRecordingUnaryOpStub::GenerateSmiCodeBitNot( | 646 void UnaryOpStub::GenerateSmiCodeBitNot( |
| 650 MacroAssembler* masm, | 647 MacroAssembler* masm, |
| 651 Label* non_smi, | 648 Label* non_smi, |
| 652 Label::Distance non_smi_near) { | 649 Label::Distance non_smi_near) { |
| 653 // Check whether the value is a smi. | 650 // Check whether the value is a smi. |
| 654 __ test(eax, Immediate(kSmiTagMask)); | 651 __ test(eax, Immediate(kSmiTagMask)); |
| 655 __ j(not_zero, non_smi, non_smi_near); | 652 __ j(not_zero, non_smi, non_smi_near); |
| 656 | 653 |
| 657 // Flip bits and revert inverted smi-tag. | 654 // Flip bits and revert inverted smi-tag. |
| 658 __ not_(eax); | 655 __ not_(eax); |
| 659 __ and_(eax, ~kSmiTagMask); | 656 __ and_(eax, ~kSmiTagMask); |
| 660 __ ret(0); | 657 __ ret(0); |
| 661 } | 658 } |
| 662 | 659 |
| 663 | 660 |
| 664 void TypeRecordingUnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { | 661 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { |
| 665 __ mov(eax, Operand(edx)); | 662 __ mov(eax, Operand(edx)); |
| 666 } | 663 } |
| 667 | 664 |
| 668 | 665 |
| 669 // TODO(svenpanne): Use virtual functions instead of switch. | 666 // TODO(svenpanne): Use virtual functions instead of switch. |
| 670 void TypeRecordingUnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 667 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |
| 671 switch (op_) { | 668 switch (op_) { |
| 672 case Token::SUB: | 669 case Token::SUB: |
| 673 GenerateHeapNumberStubSub(masm); | 670 GenerateHeapNumberStubSub(masm); |
| 674 break; | 671 break; |
| 675 case Token::BIT_NOT: | 672 case Token::BIT_NOT: |
| 676 GenerateHeapNumberStubBitNot(masm); | 673 GenerateHeapNumberStubBitNot(masm); |
| 677 break; | 674 break; |
| 678 default: | 675 default: |
| 679 UNREACHABLE(); | 676 UNREACHABLE(); |
| 680 } | 677 } |
| 681 } | 678 } |
| 682 | 679 |
| 683 | 680 |
| 684 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { | 681 void UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { |
| 685 Label non_smi, undo, slow, call_builtin; | 682 Label non_smi, undo, slow, call_builtin; |
| 686 GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); | 683 GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); |
| 687 __ bind(&non_smi); | 684 __ bind(&non_smi); |
| 688 GenerateHeapNumberCodeSub(masm, &slow); | 685 GenerateHeapNumberCodeSub(masm, &slow); |
| 689 __ bind(&undo); | 686 __ bind(&undo); |
| 690 GenerateSmiCodeUndo(masm); | 687 GenerateSmiCodeUndo(masm); |
| 691 __ bind(&slow); | 688 __ bind(&slow); |
| 692 GenerateTypeTransition(masm); | 689 GenerateTypeTransition(masm); |
| 693 __ bind(&call_builtin); | 690 __ bind(&call_builtin); |
| 694 GenerateGenericCodeFallback(masm); | 691 GenerateGenericCodeFallback(masm); |
| 695 } | 692 } |
| 696 | 693 |
| 697 | 694 |
| 698 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubBitNot( | 695 void UnaryOpStub::GenerateHeapNumberStubBitNot( |
| 699 MacroAssembler* masm) { | 696 MacroAssembler* masm) { |
| 700 Label non_smi, slow; | 697 Label non_smi, slow; |
| 701 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); | 698 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 702 __ bind(&non_smi); | 699 __ bind(&non_smi); |
| 703 GenerateHeapNumberCodeBitNot(masm, &slow); | 700 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 704 __ bind(&slow); | 701 __ bind(&slow); |
| 705 GenerateTypeTransition(masm); | 702 GenerateTypeTransition(masm); |
| 706 } | 703 } |
| 707 | 704 |
| 708 | 705 |
| 709 void TypeRecordingUnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | 706 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, |
| 710 Label* slow) { | 707 Label* slow) { |
| 711 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 708 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 712 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); | 709 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); |
| 713 __ j(not_equal, slow); | 710 __ j(not_equal, slow); |
| 714 | 711 |
| 715 if (mode_ == UNARY_OVERWRITE) { | 712 if (mode_ == UNARY_OVERWRITE) { |
| 716 __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), | 713 __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), |
| 717 Immediate(HeapNumber::kSignMask)); // Flip sign. | 714 Immediate(HeapNumber::kSignMask)); // Flip sign. |
| 718 } else { | 715 } else { |
| 719 __ mov(edx, Operand(eax)); | 716 __ mov(edx, Operand(eax)); |
| 720 // edx: operand | 717 // edx: operand |
| (...skipping 14 matching lines...) Expand all Loading... |
| 735 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 732 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
| 736 __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. | 733 __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. |
| 737 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); | 734 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); |
| 738 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); | 735 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); |
| 739 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | 736 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
| 740 } | 737 } |
| 741 __ ret(0); | 738 __ ret(0); |
| 742 } | 739 } |
| 743 | 740 |
| 744 | 741 |
| 745 void TypeRecordingUnaryOpStub::GenerateHeapNumberCodeBitNot( | 742 void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, |
| 746 MacroAssembler* masm, | 743 Label* slow) { |
| 747 Label* slow) { | |
| 748 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 744 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 749 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); | 745 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); |
| 750 __ j(not_equal, slow); | 746 __ j(not_equal, slow); |
| 751 | 747 |
| 752 // Convert the heap number in eax to an untagged integer in ecx. | 748 // Convert the heap number in eax to an untagged integer in ecx. |
| 753 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); | 749 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); |
| 754 | 750 |
| 755 // Do the bitwise operation and check if the result fits in a smi. | 751 // Do the bitwise operation and check if the result fits in a smi. |
| 756 Label try_float; | 752 Label try_float; |
| 757 __ not_(ecx); | 753 __ not_(ecx); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 __ push(ecx); | 792 __ push(ecx); |
| 797 __ fild_s(Operand(esp, 0)); | 793 __ fild_s(Operand(esp, 0)); |
| 798 __ pop(ecx); | 794 __ pop(ecx); |
| 799 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 795 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 800 } | 796 } |
| 801 __ ret(0); | 797 __ ret(0); |
| 802 } | 798 } |
| 803 | 799 |
| 804 | 800 |
| 805 // TODO(svenpanne): Use virtual functions instead of switch. | 801 // TODO(svenpanne): Use virtual functions instead of switch. |
| 806 void TypeRecordingUnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { | 802 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { |
| 807 switch (op_) { | 803 switch (op_) { |
| 808 case Token::SUB: | 804 case Token::SUB: |
| 809 GenerateGenericStubSub(masm); | 805 GenerateGenericStubSub(masm); |
| 810 break; | 806 break; |
| 811 case Token::BIT_NOT: | 807 case Token::BIT_NOT: |
| 812 GenerateGenericStubBitNot(masm); | 808 GenerateGenericStubBitNot(masm); |
| 813 break; | 809 break; |
| 814 default: | 810 default: |
| 815 UNREACHABLE(); | 811 UNREACHABLE(); |
| 816 } | 812 } |
| 817 } | 813 } |
| 818 | 814 |
| 819 | 815 |
| 820 void TypeRecordingUnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { | 816 void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { |
| 821 Label non_smi, undo, slow; | 817 Label non_smi, undo, slow; |
| 822 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); | 818 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); |
| 823 __ bind(&non_smi); | 819 __ bind(&non_smi); |
| 824 GenerateHeapNumberCodeSub(masm, &slow); | 820 GenerateHeapNumberCodeSub(masm, &slow); |
| 825 __ bind(&undo); | 821 __ bind(&undo); |
| 826 GenerateSmiCodeUndo(masm); | 822 GenerateSmiCodeUndo(masm); |
| 827 __ bind(&slow); | 823 __ bind(&slow); |
| 828 GenerateGenericCodeFallback(masm); | 824 GenerateGenericCodeFallback(masm); |
| 829 } | 825 } |
| 830 | 826 |
| 831 | 827 |
| 832 void TypeRecordingUnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { | 828 void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { |
| 833 Label non_smi, slow; | 829 Label non_smi, slow; |
| 834 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); | 830 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 835 __ bind(&non_smi); | 831 __ bind(&non_smi); |
| 836 GenerateHeapNumberCodeBitNot(masm, &slow); | 832 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 837 __ bind(&slow); | 833 __ bind(&slow); |
| 838 GenerateGenericCodeFallback(masm); | 834 GenerateGenericCodeFallback(masm); |
| 839 } | 835 } |
| 840 | 836 |
| 841 | 837 |
| 842 void TypeRecordingUnaryOpStub::GenerateGenericCodeFallback( | 838 void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { |
| 843 MacroAssembler* masm) { | |
| 844 // Handle the slow case by jumping to the corresponding JavaScript builtin. | 839 // Handle the slow case by jumping to the corresponding JavaScript builtin. |
| 845 __ pop(ecx); // pop return address. | 840 __ pop(ecx); // pop return address. |
| 846 __ push(eax); | 841 __ push(eax); |
| 847 __ push(ecx); // push return address | 842 __ push(ecx); // push return address |
| 848 switch (op_) { | 843 switch (op_) { |
| 849 case Token::SUB: | 844 case Token::SUB: |
| 850 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); | 845 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); |
| 851 break; | 846 break; |
| 852 case Token::BIT_NOT: | 847 case Token::BIT_NOT: |
| 853 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | 848 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
| 854 break; | 849 break; |
| 855 default: | 850 default: |
| 856 UNREACHABLE(); | 851 UNREACHABLE(); |
| 857 } | 852 } |
| 858 } | 853 } |
| 859 | 854 |
| 860 | 855 |
| 861 Handle<Code> GetTypeRecordingBinaryOpStub(int key, | 856 Handle<Code> GetBinaryOpStub(int key, |
| 862 TRBinaryOpIC::TypeInfo type_info, | 857 BinaryOpIC::TypeInfo type_info, |
| 863 TRBinaryOpIC::TypeInfo result_type_info) { | 858 BinaryOpIC::TypeInfo result_type_info) { |
| 864 TypeRecordingBinaryOpStub stub(key, type_info, result_type_info); | 859 BinaryOpStub stub(key, type_info, result_type_info); |
| 865 return stub.GetCode(); | 860 return stub.GetCode(); |
| 866 } | 861 } |
| 867 | 862 |
| 868 | 863 |
| 869 void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 864 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 870 __ pop(ecx); // Save return address. | 865 __ pop(ecx); // Save return address. |
| 871 __ push(edx); | 866 __ push(edx); |
| 872 __ push(eax); | 867 __ push(eax); |
| 873 // Left and right arguments are now on top. | 868 // Left and right arguments are now on top. |
| 874 // Push this stub's key. Although the operation and the type info are | 869 // Push this stub's key. Although the operation and the type info are |
| 875 // encoded into the key, the encoding is opaque, so push them too. | 870 // encoded into the key, the encoding is opaque, so push them too. |
| 876 __ push(Immediate(Smi::FromInt(MinorKey()))); | 871 __ push(Immediate(Smi::FromInt(MinorKey()))); |
| 877 __ push(Immediate(Smi::FromInt(op_))); | 872 __ push(Immediate(Smi::FromInt(op_))); |
| 878 __ push(Immediate(Smi::FromInt(operands_type_))); | 873 __ push(Immediate(Smi::FromInt(operands_type_))); |
| 879 | 874 |
| 880 __ push(ecx); // Push return address. | 875 __ push(ecx); // Push return address. |
| 881 | 876 |
| 882 // Patch the caller to an appropriate specialized stub and return the | 877 // Patch the caller to an appropriate specialized stub and return the |
| 883 // operation result to the caller of the stub. | 878 // operation result to the caller of the stub. |
| 884 __ TailCallExternalReference( | 879 __ TailCallExternalReference( |
| 885 ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch), | 880 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), |
| 886 masm->isolate()), | 881 masm->isolate()), |
| 887 5, | 882 5, |
| 888 1); | 883 1); |
| 889 } | 884 } |
| 890 | 885 |
| 891 | 886 |
| 892 // Prepare for a type transition runtime call when the args are already on | 887 // Prepare for a type transition runtime call when the args are already on |
| 893 // the stack, under the return address. | 888 // the stack, under the return address. |
| 894 void TypeRecordingBinaryOpStub::GenerateTypeTransitionWithSavedArgs( | 889 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { |
| 895 MacroAssembler* masm) { | |
| 896 __ pop(ecx); // Save return address. | 890 __ pop(ecx); // Save return address. |
| 897 // Left and right arguments are already on top of the stack. | 891 // Left and right arguments are already on top of the stack. |
| 898 // Push this stub's key. Although the operation and the type info are | 892 // Push this stub's key. Although the operation and the type info are |
| 899 // encoded into the key, the encoding is opaque, so push them too. | 893 // encoded into the key, the encoding is opaque, so push them too. |
| 900 __ push(Immediate(Smi::FromInt(MinorKey()))); | 894 __ push(Immediate(Smi::FromInt(MinorKey()))); |
| 901 __ push(Immediate(Smi::FromInt(op_))); | 895 __ push(Immediate(Smi::FromInt(op_))); |
| 902 __ push(Immediate(Smi::FromInt(operands_type_))); | 896 __ push(Immediate(Smi::FromInt(operands_type_))); |
| 903 | 897 |
| 904 __ push(ecx); // Push return address. | 898 __ push(ecx); // Push return address. |
| 905 | 899 |
| 906 // Patch the caller to an appropriate specialized stub and return the | 900 // Patch the caller to an appropriate specialized stub and return the |
| 907 // operation result to the caller of the stub. | 901 // operation result to the caller of the stub. |
| 908 __ TailCallExternalReference( | 902 __ TailCallExternalReference( |
| 909 ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch), | 903 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), |
| 910 masm->isolate()), | 904 masm->isolate()), |
| 911 5, | 905 5, |
| 912 1); | 906 1); |
| 913 } | 907 } |
| 914 | 908 |
| 915 | 909 |
| 916 void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) { | 910 void BinaryOpStub::Generate(MacroAssembler* masm) { |
| 917 switch (operands_type_) { | 911 switch (operands_type_) { |
| 918 case TRBinaryOpIC::UNINITIALIZED: | 912 case BinaryOpIC::UNINITIALIZED: |
| 919 GenerateTypeTransition(masm); | 913 GenerateTypeTransition(masm); |
| 920 break; | 914 break; |
| 921 case TRBinaryOpIC::SMI: | 915 case BinaryOpIC::SMI: |
| 922 GenerateSmiStub(masm); | 916 GenerateSmiStub(masm); |
| 923 break; | 917 break; |
| 924 case TRBinaryOpIC::INT32: | 918 case BinaryOpIC::INT32: |
| 925 GenerateInt32Stub(masm); | 919 GenerateInt32Stub(masm); |
| 926 break; | 920 break; |
| 927 case TRBinaryOpIC::HEAP_NUMBER: | 921 case BinaryOpIC::HEAP_NUMBER: |
| 928 GenerateHeapNumberStub(masm); | 922 GenerateHeapNumberStub(masm); |
| 929 break; | 923 break; |
| 930 case TRBinaryOpIC::ODDBALL: | 924 case BinaryOpIC::ODDBALL: |
| 931 GenerateOddballStub(masm); | 925 GenerateOddballStub(masm); |
| 932 break; | 926 break; |
| 933 case TRBinaryOpIC::BOTH_STRING: | 927 case BinaryOpIC::BOTH_STRING: |
| 934 GenerateBothStringStub(masm); | 928 GenerateBothStringStub(masm); |
| 935 break; | 929 break; |
| 936 case TRBinaryOpIC::STRING: | 930 case BinaryOpIC::STRING: |
| 937 GenerateStringStub(masm); | 931 GenerateStringStub(masm); |
| 938 break; | 932 break; |
| 939 case TRBinaryOpIC::GENERIC: | 933 case BinaryOpIC::GENERIC: |
| 940 GenerateGeneric(masm); | 934 GenerateGeneric(masm); |
| 941 break; | 935 break; |
| 942 default: | 936 default: |
| 943 UNREACHABLE(); | 937 UNREACHABLE(); |
| 944 } | 938 } |
| 945 } | 939 } |
| 946 | 940 |
| 947 | 941 |
| 948 const char* TypeRecordingBinaryOpStub::GetName() { | 942 const char* BinaryOpStub::GetName() { |
| 949 if (name_ != NULL) return name_; | 943 if (name_ != NULL) return name_; |
| 950 const int kMaxNameLength = 100; | 944 const int kMaxNameLength = 100; |
| 951 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | 945 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 952 kMaxNameLength); | 946 kMaxNameLength); |
| 953 if (name_ == NULL) return "OOM"; | 947 if (name_ == NULL) return "OOM"; |
| 954 const char* op_name = Token::Name(op_); | 948 const char* op_name = Token::Name(op_); |
| 955 const char* overwrite_name; | 949 const char* overwrite_name; |
| 956 switch (mode_) { | 950 switch (mode_) { |
| 957 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 951 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 958 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 952 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 959 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 953 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 960 default: overwrite_name = "UnknownOverwrite"; break; | 954 default: overwrite_name = "UnknownOverwrite"; break; |
| 961 } | 955 } |
| 962 | 956 |
| 963 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 957 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 964 "TypeRecordingBinaryOpStub_%s_%s_%s", | 958 "BinaryOpStub_%s_%s_%s", |
| 965 op_name, | 959 op_name, |
| 966 overwrite_name, | 960 overwrite_name, |
| 967 TRBinaryOpIC::GetName(operands_type_)); | 961 BinaryOpIC::GetName(operands_type_)); |
| 968 return name_; | 962 return name_; |
| 969 } | 963 } |
| 970 | 964 |
| 971 | 965 |
| 972 void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, | 966 void BinaryOpStub::GenerateSmiCode( |
| 967 MacroAssembler* masm, |
| 973 Label* slow, | 968 Label* slow, |
| 974 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { | 969 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { |
| 975 // 1. Move arguments into edx, eax except for DIV and MOD, which need the | 970 // 1. Move arguments into edx, eax except for DIV and MOD, which need the |
| 976 // dividend in eax and edx free for the division. Use eax, ebx for those. | 971 // dividend in eax and edx free for the division. Use eax, ebx for those. |
| 977 Comment load_comment(masm, "-- Load arguments"); | 972 Comment load_comment(masm, "-- Load arguments"); |
| 978 Register left = edx; | 973 Register left = edx; |
| 979 Register right = eax; | 974 Register right = eax; |
| 980 if (op_ == Token::DIV || op_ == Token::MOD) { | 975 if (op_ == Token::DIV || op_ == Token::MOD) { |
| 981 left = eax; | 976 left = eax; |
| 982 right = ebx; | 977 right = ebx; |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1337 __ mov(edx, eax); | 1332 __ mov(edx, eax); |
| 1338 __ mov(eax, ebx); | 1333 __ mov(eax, ebx); |
| 1339 break; | 1334 break; |
| 1340 | 1335 |
| 1341 default: | 1336 default: |
| 1342 break; | 1337 break; |
| 1343 } | 1338 } |
| 1344 } | 1339 } |
| 1345 | 1340 |
| 1346 | 1341 |
| 1347 void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1342 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 1348 Label call_runtime; | 1343 Label call_runtime; |
| 1349 | 1344 |
| 1350 switch (op_) { | 1345 switch (op_) { |
| 1351 case Token::ADD: | 1346 case Token::ADD: |
| 1352 case Token::SUB: | 1347 case Token::SUB: |
| 1353 case Token::MUL: | 1348 case Token::MUL: |
| 1354 case Token::DIV: | 1349 case Token::DIV: |
| 1355 break; | 1350 break; |
| 1356 case Token::MOD: | 1351 case Token::MOD: |
| 1357 case Token::BIT_OR: | 1352 case Token::BIT_OR: |
| 1358 case Token::BIT_AND: | 1353 case Token::BIT_AND: |
| 1359 case Token::BIT_XOR: | 1354 case Token::BIT_XOR: |
| 1360 case Token::SAR: | 1355 case Token::SAR: |
| 1361 case Token::SHL: | 1356 case Token::SHL: |
| 1362 case Token::SHR: | 1357 case Token::SHR: |
| 1363 GenerateRegisterArgsPush(masm); | 1358 GenerateRegisterArgsPush(masm); |
| 1364 break; | 1359 break; |
| 1365 default: | 1360 default: |
| 1366 UNREACHABLE(); | 1361 UNREACHABLE(); |
| 1367 } | 1362 } |
| 1368 | 1363 |
| 1369 if (result_type_ == TRBinaryOpIC::UNINITIALIZED || | 1364 if (result_type_ == BinaryOpIC::UNINITIALIZED || |
| 1370 result_type_ == TRBinaryOpIC::SMI) { | 1365 result_type_ == BinaryOpIC::SMI) { |
| 1371 GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); | 1366 GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); |
| 1372 } else { | 1367 } else { |
| 1373 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); | 1368 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); |
| 1374 } | 1369 } |
| 1375 __ bind(&call_runtime); | 1370 __ bind(&call_runtime); |
| 1376 switch (op_) { | 1371 switch (op_) { |
| 1377 case Token::ADD: | 1372 case Token::ADD: |
| 1378 case Token::SUB: | 1373 case Token::SUB: |
| 1379 case Token::MUL: | 1374 case Token::MUL: |
| 1380 case Token::DIV: | 1375 case Token::DIV: |
| 1381 GenerateTypeTransition(masm); | 1376 GenerateTypeTransition(masm); |
| 1382 break; | 1377 break; |
| 1383 case Token::MOD: | 1378 case Token::MOD: |
| 1384 case Token::BIT_OR: | 1379 case Token::BIT_OR: |
| 1385 case Token::BIT_AND: | 1380 case Token::BIT_AND: |
| 1386 case Token::BIT_XOR: | 1381 case Token::BIT_XOR: |
| 1387 case Token::SAR: | 1382 case Token::SAR: |
| 1388 case Token::SHL: | 1383 case Token::SHL: |
| 1389 case Token::SHR: | 1384 case Token::SHR: |
| 1390 GenerateTypeTransitionWithSavedArgs(masm); | 1385 GenerateTypeTransitionWithSavedArgs(masm); |
| 1391 break; | 1386 break; |
| 1392 default: | 1387 default: |
| 1393 UNREACHABLE(); | 1388 UNREACHABLE(); |
| 1394 } | 1389 } |
| 1395 } | 1390 } |
| 1396 | 1391 |
| 1397 | 1392 |
| 1398 void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { | 1393 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { |
| 1399 ASSERT(operands_type_ == TRBinaryOpIC::STRING); | 1394 ASSERT(operands_type_ == BinaryOpIC::STRING); |
| 1400 ASSERT(op_ == Token::ADD); | 1395 ASSERT(op_ == Token::ADD); |
| 1401 // Try to add arguments as strings, otherwise, transition to the generic | 1396 // Try to add arguments as strings, otherwise, transition to the generic |
| 1402 // TRBinaryOpIC type. | 1397 // BinaryOpIC type. |
| 1403 GenerateAddStrings(masm); | 1398 GenerateAddStrings(masm); |
| 1404 GenerateTypeTransition(masm); | 1399 GenerateTypeTransition(masm); |
| 1405 } | 1400 } |
| 1406 | 1401 |
| 1407 | 1402 |
| 1408 void TypeRecordingBinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { | 1403 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { |
| 1409 Label call_runtime; | 1404 Label call_runtime; |
| 1410 ASSERT(operands_type_ == TRBinaryOpIC::BOTH_STRING); | 1405 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); |
| 1411 ASSERT(op_ == Token::ADD); | 1406 ASSERT(op_ == Token::ADD); |
| 1412 // If both arguments are strings, call the string add stub. | 1407 // If both arguments are strings, call the string add stub. |
| 1413 // Otherwise, do a transition. | 1408 // Otherwise, do a transition. |
| 1414 | 1409 |
| 1415 // Registers containing left and right operands respectively. | 1410 // Registers containing left and right operands respectively. |
| 1416 Register left = edx; | 1411 Register left = edx; |
| 1417 Register right = eax; | 1412 Register right = eax; |
| 1418 | 1413 |
| 1419 // Test if left operand is a string. | 1414 // Test if left operand is a string. |
| 1420 __ test(left, Immediate(kSmiTagMask)); | 1415 __ test(left, Immediate(kSmiTagMask)); |
| 1421 __ j(zero, &call_runtime); | 1416 __ j(zero, &call_runtime); |
| 1422 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); | 1417 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); |
| 1423 __ j(above_equal, &call_runtime); | 1418 __ j(above_equal, &call_runtime); |
| 1424 | 1419 |
| 1425 // Test if right operand is a string. | 1420 // Test if right operand is a string. |
| 1426 __ test(right, Immediate(kSmiTagMask)); | 1421 __ test(right, Immediate(kSmiTagMask)); |
| 1427 __ j(zero, &call_runtime); | 1422 __ j(zero, &call_runtime); |
| 1428 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); | 1423 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); |
| 1429 __ j(above_equal, &call_runtime); | 1424 __ j(above_equal, &call_runtime); |
| 1430 | 1425 |
| 1431 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); | 1426 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); |
| 1432 GenerateRegisterArgsPush(masm); | 1427 GenerateRegisterArgsPush(masm); |
| 1433 __ TailCallStub(&string_add_stub); | 1428 __ TailCallStub(&string_add_stub); |
| 1434 | 1429 |
| 1435 __ bind(&call_runtime); | 1430 __ bind(&call_runtime); |
| 1436 GenerateTypeTransition(masm); | 1431 GenerateTypeTransition(masm); |
| 1437 } | 1432 } |
| 1438 | 1433 |
| 1439 | 1434 |
| 1440 void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | 1435 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { |
| 1441 Label call_runtime; | 1436 Label call_runtime; |
| 1442 ASSERT(operands_type_ == TRBinaryOpIC::INT32); | 1437 ASSERT(operands_type_ == BinaryOpIC::INT32); |
| 1443 | 1438 |
| 1444 // Floating point case. | 1439 // Floating point case. |
| 1445 switch (op_) { | 1440 switch (op_) { |
| 1446 case Token::ADD: | 1441 case Token::ADD: |
| 1447 case Token::SUB: | 1442 case Token::SUB: |
| 1448 case Token::MUL: | 1443 case Token::MUL: |
| 1449 case Token::DIV: { | 1444 case Token::DIV: { |
| 1450 Label not_floats; | 1445 Label not_floats; |
| 1451 Label not_int32; | 1446 Label not_int32; |
| 1452 if (CpuFeatures::IsSupported(SSE2)) { | 1447 if (CpuFeatures::IsSupported(SSE2)) { |
| 1453 CpuFeatures::Scope use_sse2(SSE2); | 1448 CpuFeatures::Scope use_sse2(SSE2); |
| 1454 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 1449 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
| 1455 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); | 1450 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); |
| 1456 switch (op_) { | 1451 switch (op_) { |
| 1457 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1452 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 1458 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1453 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 1459 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1454 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 1460 case Token::DIV: __ divsd(xmm0, xmm1); break; | 1455 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 1461 default: UNREACHABLE(); | 1456 default: UNREACHABLE(); |
| 1462 } | 1457 } |
| 1463 // Check result type if it is currently Int32. | 1458 // Check result type if it is currently Int32. |
| 1464 if (result_type_ <= TRBinaryOpIC::INT32) { | 1459 if (result_type_ <= BinaryOpIC::INT32) { |
| 1465 __ cvttsd2si(ecx, Operand(xmm0)); | 1460 __ cvttsd2si(ecx, Operand(xmm0)); |
| 1466 __ cvtsi2sd(xmm2, Operand(ecx)); | 1461 __ cvtsi2sd(xmm2, Operand(ecx)); |
| 1467 __ ucomisd(xmm0, xmm2); | 1462 __ ucomisd(xmm0, xmm2); |
| 1468 __ j(not_zero, ¬_int32); | 1463 __ j(not_zero, ¬_int32); |
| 1469 __ j(carry, ¬_int32); | 1464 __ j(carry, ¬_int32); |
| 1470 } | 1465 } |
| 1471 GenerateHeapResultAllocation(masm, &call_runtime); | 1466 GenerateHeapResultAllocation(masm, &call_runtime); |
| 1472 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1467 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 1473 __ ret(0); | 1468 __ ret(0); |
| 1474 } else { // SSE2 not available, use FPU. | 1469 } else { // SSE2 not available, use FPU. |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1632 break; | 1627 break; |
| 1633 case Token::SHR: | 1628 case Token::SHR: |
| 1634 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 1629 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
| 1635 break; | 1630 break; |
| 1636 default: | 1631 default: |
| 1637 UNREACHABLE(); | 1632 UNREACHABLE(); |
| 1638 } | 1633 } |
| 1639 } | 1634 } |
| 1640 | 1635 |
| 1641 | 1636 |
| 1642 void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 1637 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
| 1643 if (op_ == Token::ADD) { | 1638 if (op_ == Token::ADD) { |
| 1644 // Handle string addition here, because it is the only operation | 1639 // Handle string addition here, because it is the only operation |
| 1645 // that does not do a ToNumber conversion on the operands. | 1640 // that does not do a ToNumber conversion on the operands. |
| 1646 GenerateAddStrings(masm); | 1641 GenerateAddStrings(masm); |
| 1647 } | 1642 } |
| 1648 | 1643 |
| 1649 Factory* factory = masm->isolate()->factory(); | 1644 Factory* factory = masm->isolate()->factory(); |
| 1650 | 1645 |
| 1651 // Convert odd ball arguments to numbers. | 1646 // Convert odd ball arguments to numbers. |
| 1652 Label check, done; | 1647 Label check, done; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1665 __ xor_(eax, Operand(eax)); | 1660 __ xor_(eax, Operand(eax)); |
| 1666 } else { | 1661 } else { |
| 1667 __ mov(eax, Immediate(factory->nan_value())); | 1662 __ mov(eax, Immediate(factory->nan_value())); |
| 1668 } | 1663 } |
| 1669 __ bind(&done); | 1664 __ bind(&done); |
| 1670 | 1665 |
| 1671 GenerateHeapNumberStub(masm); | 1666 GenerateHeapNumberStub(masm); |
| 1672 } | 1667 } |
| 1673 | 1668 |
| 1674 | 1669 |
| 1675 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 1670 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |
| 1676 Label call_runtime; | 1671 Label call_runtime; |
| 1677 | 1672 |
| 1678 // Floating point case. | 1673 // Floating point case. |
| 1679 switch (op_) { | 1674 switch (op_) { |
| 1680 case Token::ADD: | 1675 case Token::ADD: |
| 1681 case Token::SUB: | 1676 case Token::SUB: |
| 1682 case Token::MUL: | 1677 case Token::MUL: |
| 1683 case Token::DIV: { | 1678 case Token::DIV: { |
| 1684 Label not_floats; | 1679 Label not_floats; |
| 1685 if (CpuFeatures::IsSupported(SSE2)) { | 1680 if (CpuFeatures::IsSupported(SSE2)) { |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1846 break; | 1841 break; |
| 1847 case Token::SHR: | 1842 case Token::SHR: |
| 1848 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 1843 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
| 1849 break; | 1844 break; |
| 1850 default: | 1845 default: |
| 1851 UNREACHABLE(); | 1846 UNREACHABLE(); |
| 1852 } | 1847 } |
| 1853 } | 1848 } |
| 1854 | 1849 |
| 1855 | 1850 |
| 1856 void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { | 1851 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { |
| 1857 Label call_runtime; | 1852 Label call_runtime; |
| 1858 | 1853 |
| 1859 Counters* counters = masm->isolate()->counters(); | 1854 Counters* counters = masm->isolate()->counters(); |
| 1860 __ IncrementCounter(counters->generic_binary_stub_calls(), 1); | 1855 __ IncrementCounter(counters->generic_binary_stub_calls(), 1); |
| 1861 | 1856 |
| 1862 switch (op_) { | 1857 switch (op_) { |
| 1863 case Token::ADD: | 1858 case Token::ADD: |
| 1864 case Token::SUB: | 1859 case Token::SUB: |
| 1865 case Token::MUL: | 1860 case Token::MUL: |
| 1866 case Token::DIV: | 1861 case Token::DIV: |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2043 break; | 2038 break; |
| 2044 case Token::SHR: | 2039 case Token::SHR: |
| 2045 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 2040 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
| 2046 break; | 2041 break; |
| 2047 default: | 2042 default: |
| 2048 UNREACHABLE(); | 2043 UNREACHABLE(); |
| 2049 } | 2044 } |
| 2050 } | 2045 } |
| 2051 | 2046 |
| 2052 | 2047 |
| 2053 void TypeRecordingBinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { | 2048 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { |
| 2054 ASSERT(op_ == Token::ADD); | 2049 ASSERT(op_ == Token::ADD); |
| 2055 Label left_not_string, call_runtime; | 2050 Label left_not_string, call_runtime; |
| 2056 | 2051 |
| 2057 // Registers containing left and right operands respectively. | 2052 // Registers containing left and right operands respectively. |
| 2058 Register left = edx; | 2053 Register left = edx; |
| 2059 Register right = eax; | 2054 Register right = eax; |
| 2060 | 2055 |
| 2061 // Test if left operand is a string. | 2056 // Test if left operand is a string. |
| 2062 __ test(left, Immediate(kSmiTagMask)); | 2057 __ test(left, Immediate(kSmiTagMask)); |
| 2063 __ j(zero, &left_not_string, Label::kNear); | 2058 __ j(zero, &left_not_string, Label::kNear); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2077 | 2072 |
| 2078 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); | 2073 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); |
| 2079 GenerateRegisterArgsPush(masm); | 2074 GenerateRegisterArgsPush(masm); |
| 2080 __ TailCallStub(&string_add_right_stub); | 2075 __ TailCallStub(&string_add_right_stub); |
| 2081 | 2076 |
| 2082 // Neither argument is a string. | 2077 // Neither argument is a string. |
| 2083 __ bind(&call_runtime); | 2078 __ bind(&call_runtime); |
| 2084 } | 2079 } |
| 2085 | 2080 |
| 2086 | 2081 |
| 2087 void TypeRecordingBinaryOpStub::GenerateHeapResultAllocation( | 2082 void BinaryOpStub::GenerateHeapResultAllocation( |
| 2088 MacroAssembler* masm, | 2083 MacroAssembler* masm, |
| 2089 Label* alloc_failure) { | 2084 Label* alloc_failure) { |
| 2090 Label skip_allocation; | 2085 Label skip_allocation; |
| 2091 OverwriteMode mode = mode_; | 2086 OverwriteMode mode = mode_; |
| 2092 switch (mode) { | 2087 switch (mode) { |
| 2093 case OVERWRITE_LEFT: { | 2088 case OVERWRITE_LEFT: { |
| 2094 // If the argument in edx is already an object, we skip the | 2089 // If the argument in edx is already an object, we skip the |
| 2095 // allocation of a heap number. | 2090 // allocation of a heap number. |
| 2096 __ test(edx, Immediate(kSmiTagMask)); | 2091 __ test(edx, Immediate(kSmiTagMask)); |
| 2097 __ j(not_zero, &skip_allocation); | 2092 __ j(not_zero, &skip_allocation); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2119 // Now eax can be overwritten losing one of the arguments as we are | 2114 // Now eax can be overwritten losing one of the arguments as we are |
| 2120 // now done and will not need it any more. | 2115 // now done and will not need it any more. |
| 2121 __ mov(eax, ebx); | 2116 __ mov(eax, ebx); |
| 2122 __ bind(&skip_allocation); | 2117 __ bind(&skip_allocation); |
| 2123 break; | 2118 break; |
| 2124 default: UNREACHABLE(); | 2119 default: UNREACHABLE(); |
| 2125 } | 2120 } |
| 2126 } | 2121 } |
| 2127 | 2122 |
| 2128 | 2123 |
| 2129 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | 2124 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| 2130 __ pop(ecx); | 2125 __ pop(ecx); |
| 2131 __ push(edx); | 2126 __ push(edx); |
| 2132 __ push(eax); | 2127 __ push(eax); |
| 2133 __ push(ecx); | 2128 __ push(ecx); |
| 2134 } | 2129 } |
| 2135 | 2130 |
| 2136 | 2131 |
| 2137 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 2132 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 2138 // TAGGED case: | 2133 // TAGGED case: |
| 2139 // Input: | 2134 // Input: |
| (...skipping 4051 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6191 __ Drop(1); | 6186 __ Drop(1); |
| 6192 __ ret(2 * kPointerSize); | 6187 __ ret(2 * kPointerSize); |
| 6193 } | 6188 } |
| 6194 | 6189 |
| 6195 | 6190 |
| 6196 #undef __ | 6191 #undef __ |
| 6197 | 6192 |
| 6198 } } // namespace v8::internal | 6193 } } // namespace v8::internal |
| 6199 | 6194 |
| 6200 #endif // V8_TARGET_ARCH_IA32 | 6195 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |