| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/opt_code_generator.h" | 8 #include "vm/opt_code_generator.h" |
| 9 | 9 |
| 10 #include "vm/assembler_macros.h" | 10 #include "vm/assembler_macros.h" |
| (...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 } | 623 } |
| 624 if (cls1_found && cls2_found) { | 624 if (cls1_found && cls2_found) { |
| 625 return true; | 625 return true; |
| 626 } | 626 } |
| 627 } | 627 } |
| 628 } | 628 } |
| 629 return false; | 629 return false; |
| 630 } | 630 } |
| 631 | 631 |
| 632 | 632 |
| 633 // Look only at the first class in all check groups. | 633 // Look only at the first class in all check groups. Returns true if all |
| 634 // receiver classes are 'cls'. |
| 634 static bool AtIdNodeHasReceiverClass(AstNode* node, | 635 static bool AtIdNodeHasReceiverClass(AstNode* node, |
| 635 intptr_t id, | 636 intptr_t id, |
| 636 const Class& cls) { | 637 const Class& cls) { |
| 637 ASSERT(node != NULL); | 638 ASSERT(node != NULL); |
| 638 ASSERT(!cls.IsNull()); | 639 ASSERT(!cls.IsNull()); |
| 639 const ICData& ic_data = node->ICDataAtId(id); | 640 const ICData& ic_data = node->ICDataAtId(id); |
| 640 if (ic_data.NumberOfChecks() == 0) { | 641 if (ic_data.NumberOfChecks() == 0) { |
| 641 return false; | 642 return false; |
| 642 } | 643 } |
| 643 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 644 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 671 Function& target = Function::Handle(); | 672 Function& target = Function::Handle(); |
| 672 GrowableArray<const Class*> classes; | 673 GrowableArray<const Class*> classes; |
| 673 ic_data.GetCheckAt(0, &classes, &target); | 674 ic_data.GetCheckAt(0, &classes, &target); |
| 674 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) { | 675 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) { |
| 675 return true; | 676 return true; |
| 676 } | 677 } |
| 677 return false; | 678 return false; |
| 678 } | 679 } |
| 679 | 680 |
| 680 | 681 |
| 681 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) { | |
| 682 ASSERT(node != NULL); | |
| 683 ASSERT(!cls.IsNull()); | |
| 684 const ICData& ic_data = node->ICDataAtId(id); | |
| 685 if ((ic_data.NumberOfArgumentsChecked() != 1) || | |
| 686 (ic_data.NumberOfChecks() != 1)) { | |
| 687 return false; | |
| 688 } | |
| 689 Class& target_cls = Class::Handle(); | |
| 690 Function& target = Function::Handle(); | |
| 691 ic_data.GetOneClassCheckAt(0, &target_cls, &target); | |
| 692 return target_cls.raw() == cls.raw(); | |
| 693 } | |
| 694 | |
| 695 | |
| 696 | |
| 697 // SHL: Implement with slow case so that it works both with Smi and Mint types. | 682 // SHL: Implement with slow case so that it works both with Smi and Mint types. |
| 698 // Result is in EAX. Mangles ECX, EBX, EDX. | 683 // Result is in EAX. Mangles ECX, EBX, EDX. |
| 699 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { | 684 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { |
| 700 if (node->kind() == Token::kSAR) { | 685 if (node->kind() == Token::kSAR) { |
| 701 // TODO(srdjan): Implement for Mint? | 686 // TODO(srdjan): Implement for Mint? |
| 702 DeoptimizationBlob* deopt_blob = | 687 DeoptimizationBlob* deopt_blob = |
| 703 AddDeoptimizationBlob(node, EAX, ECX, kDeoptSAR); | 688 AddDeoptimizationBlob(node, EAX, ECX, kDeoptSAR); |
| 704 // EAX: value to shift, ECX: amount to shift. | 689 // EAX: value to shift, ECX: amount to shift. |
| 705 VisitLoadTwo(node->left(), node->right(), EAX, ECX); | 690 VisitLoadTwo(node->left(), node->right(), EAX, ECX); |
| 706 // Check if both Smi. | 691 // Check if both Smi. |
| 707 __ movl(EBX, EAX); | 692 __ movl(EBX, EAX); |
| 708 __ orl(EBX, ECX); | 693 __ orl(EBX, ECX); |
| 709 __ testl(EBX, Immediate(kSmiTagMask)); | 694 __ testl(EBX, Immediate(kSmiTagMask)); |
| 710 __ j(NOT_ZERO, deopt_blob->label()); | 695 __ j(NOT_ZERO, deopt_blob->label()); |
| 711 Immediate count_limit = Immediate(0x1F); | 696 Immediate count_limit = Immediate(0x1F); |
| 712 __ SmiUntag(ECX); | 697 __ SmiUntag(ECX); |
| 713 __ cmpl(ECX, count_limit); | 698 __ cmpl(ECX, count_limit); |
| 714 Label shift_count_ok; | 699 Label shift_count_ok; |
| 715 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); | 700 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); |
| 716 __ movl(ECX, count_limit); | 701 __ movl(ECX, count_limit); |
| 717 __ Bind(&shift_count_ok); | 702 __ Bind(&shift_count_ok); |
| 718 // Shift amount must be in ECX. | 703 // Shift amount must be in ECX. |
| 719 __ SmiUntag(EAX); // Value. | 704 __ SmiUntag(EAX); // Value. |
| 720 __ sarl(EAX, ECX); | 705 __ sarl(EAX, ECX); |
| 721 __ SmiTag(EAX); | 706 __ SmiTag(EAX); |
| 722 return; | 707 return; |
| 723 } | 708 } |
| 724 ASSERT(node->kind() == Token::kSHL); | 709 ASSERT(node->kind() == Token::kSHL); |
| 725 Label done; | |
| 726 bool shift_generated = false; | |
| 727 if (node->right()->IsLiteralNode() && | 710 if (node->right()->IsLiteralNode() && |
| 728 node->right()->AsLiteralNode()->literal().IsSmi()) { | 711 node->right()->AsLiteralNode()->literal().IsSmi()) { |
| 712 Label done; |
| 729 // Shift count is a Smi literal. | 713 // Shift count is a Smi literal. |
| 730 Smi& smi = Smi::Handle(); | 714 Smi& smi = Smi::Handle(); |
| 731 smi ^= node->right()->AsLiteralNode()->literal().raw(); | 715 smi ^= node->right()->AsLiteralNode()->literal().raw(); |
| 732 if (smi.Value() < Smi::kBits) { | 716 if (smi.Value() < Smi::kBits) { |
| 733 Label slow_case; | 717 Label slow_case; |
| 734 VisitLoadOne(node->left(), EAX); | 718 VisitLoadOne(node->left(), EAX); |
| 735 __ testl(EAX, Immediate(kSmiTagMask)); | 719 __ testl(EAX, Immediate(kSmiTagMask)); |
| 736 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); // left not smi | 720 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); // left not smi |
| 737 // Overflow test. | 721 // Overflow test. |
| 738 __ movl(EBX, EAX); | 722 __ movl(EBX, EAX); |
| 739 Immediate imm(smi.Value()); | 723 Immediate imm(smi.Value()); |
| 740 __ shll(EBX, imm); | 724 __ shll(EBX, imm); |
| 741 __ sarl(EBX, imm); | 725 __ sarl(EBX, imm); |
| 742 __ cmpl(EAX, EBX); | 726 __ cmpl(EAX, EBX); |
| 743 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. | 727 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. |
| 744 __ shll(EAX, imm); // Shift for result now we know there is no overflow. | 728 __ shll(EAX, imm); // Shift for result now we know there is no overflow. |
| 745 __ jmp(&done); | 729 __ jmp(&done); |
| 746 __ Bind(&slow_case); | 730 __ Bind(&slow_case); |
| 747 __ pushl(EAX); | 731 __ pushl(EAX); |
| 748 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); | 732 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); |
| 749 CodeGenerator::GenerateBinaryOperatorCall(node->id(), | 733 const int number_of_arguments = 2; |
| 750 node->token_index(), | 734 const Array& no_optional_argument_names = Array::Handle(); |
| 751 node->Name()); | 735 GenerateCheckedInstanceCalls(node, |
| 752 shift_generated = true; | 736 node->left(), |
| 737 node->id(), |
| 738 node->token_index(), |
| 739 number_of_arguments, |
| 740 no_optional_argument_names); |
| 741 __ Bind(&done); |
| 742 return; |
| 753 } | 743 } |
| 754 } | 744 } |
| 755 | 745 |
| 756 if (!shift_generated) { | 746 Label slow_case, done; |
| 757 Label slow_case; | 747 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 758 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 748 // TODO(srdjan): Better code for count being a Smi literal. |
| 759 // TODO(srdjan): Better code for count being a Smi literal. | 749 // EAX: value, EDX: shift amount. Preserve them for slow case. |
| 760 // EAX: value, EDX: shift amount. Preserve them for slow case. | 750 // Fast case only if both ar Smi. |
| 761 // Fast case only if both ar Smi. | 751 __ movl(EBX, EAX); |
| 762 __ movl(EBX, EAX); | 752 __ orl(EBX, EDX); |
| 763 __ orl(EBX, EDX); | 753 __ testl(EBX, Immediate(kSmiTagMask)); |
| 764 __ testl(EBX, Immediate(kSmiTagMask)); | 754 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); |
| 765 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); | 755 // Check if count too large for handling it inlined. |
| 766 // Check if count too large for handling it inlined. | 756 __ cmpl(EDX, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| 767 __ cmpl(EDX, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | 757 __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump); |
| 768 __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump); | 758 // Shift amount must be in ECX. |
| 769 // Shift amount must be in ECX. | 759 __ movl(ECX, EDX); |
| 770 __ movl(ECX, EDX); | 760 __ movl(EBX, EAX); |
| 771 __ movl(EBX, EAX); | 761 __ SmiUntag(ECX); |
| 772 __ SmiUntag(ECX); | 762 // Overflow test. |
| 773 // Overflow test. | 763 __ shll(EBX, ECX); |
| 774 __ shll(EBX, ECX); | 764 __ sarl(EBX, ECX); |
| 775 __ sarl(EBX, ECX); | 765 __ cmpl(EAX, EBX); |
| 776 __ cmpl(EAX, EBX); | 766 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. |
| 777 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. | |
| 778 | 767 |
| 779 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. | 768 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. |
| 780 // EAX is the correctly tagged Smi. | 769 // EAX is the correctly tagged Smi. |
| 781 __ jmp(&done); | 770 __ jmp(&done); |
| 782 __ Bind(&slow_case); | 771 __ Bind(&slow_case); |
| 783 __ pushl(EAX); | 772 __ pushl(EAX); |
| 784 __ pushl(EDX); | 773 __ pushl(EDX); |
| 785 const int number_of_arguments = 2; | 774 const int number_of_arguments = 2; |
| 786 const Array& no_optional_argument_names = Array::Handle(); | 775 const Array& no_optional_argument_names = Array::Handle(); |
| 787 GenerateCheckedInstanceCalls(node, | 776 GenerateCheckedInstanceCalls(node, |
| 788 node->left(), | 777 node->left(), |
| 789 node->id(), | 778 node->id(), |
| 790 node->token_index(), | 779 node->token_index(), |
| 791 number_of_arguments, | 780 number_of_arguments, |
| 792 no_optional_argument_names); | 781 no_optional_argument_names); |
| 793 shift_generated = true; | |
| 794 } | |
| 795 __ Bind(&done); | 782 __ Bind(&done); |
| 796 } | 783 } |
| 797 | 784 |
| 798 | 785 |
| 799 // Implement Token::kSUB and Token::kBIT_NOT. | 786 // Implement Token::kSUB and Token::kBIT_NOT. |
| 800 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { | 787 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { |
| 801 const ICData& ic_data = node->ICDataAtId(node->id()); | 788 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 802 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 789 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 803 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? | 790 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? |
| 804 kDeoptNoTypeFeedback : kDeoptUnaryOp; | 791 kDeoptNoTypeFeedback : kDeoptUnaryOp; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 875 ASSERT(kResultRegister == EAX); | 862 ASSERT(kResultRegister == EAX); |
| 876 node->info()->set_result_returned_in_eax(true); | 863 node->info()->set_result_returned_in_eax(true); |
| 877 } else { | 864 } else { |
| 878 __ pushl(kResultRegister); | 865 __ pushl(kResultRegister); |
| 879 } | 866 } |
| 880 } | 867 } |
| 881 } | 868 } |
| 882 | 869 |
| 883 | 870 |
| 884 // Handles only Smi & Smi. | 871 // Handles only Smi & Smi. |
| 872 // TODO(srdjan): Certain operations always overflow, and thus cause |
| 873 // deoptimization. We need to mark those places and handle them. |
| 885 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { | 874 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { |
| 886 const char* kOptMessage = "Inlines BinaryOp for Smi"; | 875 const char* kOptMessage = "Inlines BinaryOp for Smi"; |
| 887 Label done; | 876 Label done; |
| 888 const Token::Kind kind = node->kind(); | 877 const Token::Kind kind = node->kind(); |
| 889 if ((kind == Token::kADD) || | 878 if ((kind == Token::kADD) || |
| 890 (kind == Token::kSUB) || | 879 (kind == Token::kSUB) || |
| 891 (kind == Token::kMUL) || | 880 (kind == Token::kMUL) || |
| 892 (kind == Token::kTRUNCDIV) || | 881 (kind == Token::kTRUNCDIV) || |
| 893 (kind == Token::kBIT_AND) || | 882 (kind == Token::kBIT_AND) || |
| 894 (kind == Token::kBIT_OR) || | 883 (kind == Token::kBIT_OR) || |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1039 // Load lower Mint word, convert to Smi. It is OK to loose bits. | 1028 // Load lower Mint word, convert to Smi. It is OK to loose bits. |
| 1040 __ movl(EAX, FieldAddress(EAX, Mint::value_offset())); | 1029 __ movl(EAX, FieldAddress(EAX, Mint::value_offset())); |
| 1041 __ SmiTag(EAX); | 1030 __ SmiTag(EAX); |
| 1042 | 1031 |
| 1043 __ Bind(&is_smi); | 1032 __ Bind(&is_smi); |
| 1044 __ andl(EAX, EDX); | 1033 __ andl(EAX, EDX); |
| 1045 __ jmp(&done); | 1034 __ jmp(&done); |
| 1046 __ Bind(&slow_case); | 1035 __ Bind(&slow_case); |
| 1047 __ pushl(EAX); | 1036 __ pushl(EAX); |
| 1048 __ pushl(EDX); | 1037 __ pushl(EDX); |
| 1049 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); | 1038 const int number_of_arguments = 2; |
| 1039 const Array& no_optional_argument_names = Array::Handle(); |
| 1040 GenerateCheckedInstanceCalls(node, |
| 1041 node->left(), |
| 1042 node->id(), |
| 1043 node->token_index(), |
| 1044 number_of_arguments, |
| 1045 no_optional_argument_names); |
| 1050 __ Bind(&done); | 1046 __ Bind(&done); |
| 1051 if (CodeGenerator::IsResultNeeded(node)) { | 1047 if (CodeGenerator::IsResultNeeded(node)) { |
| 1052 __ pushl(EAX); | 1048 __ pushl(EAX); |
| 1053 } | 1049 } |
| 1054 return; | 1050 return; |
| 1055 } | 1051 } |
| 1056 if ((kind == Token::kSHL) && allow_smi) { | 1052 if ((kind == Token::kSHL) && allow_smi) { |
| 1057 GenerateSmiShiftBinaryOp(node); | 1053 GenerateSmiShiftBinaryOp(node); |
| 1058 if (CodeGenerator::IsResultNeeded(node)) { | 1054 if (CodeGenerator::IsResultNeeded(node)) { |
| 1059 __ pushl(EAX); | 1055 __ pushl(EAX); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1083 Label* is_smi, | 1079 Label* is_smi, |
| 1084 Label* not_double_or_smi) { | 1080 Label* not_double_or_smi) { |
| 1085 __ testl(reg, Immediate(kSmiTagMask)); | 1081 __ testl(reg, Immediate(kSmiTagMask)); |
| 1086 __ j(ZERO, is_smi); | 1082 __ j(ZERO, is_smi); |
| 1087 __ movl(temp, FieldAddress(reg, Object::class_offset())); | 1083 __ movl(temp, FieldAddress(reg, Object::class_offset())); |
| 1088 __ CompareObject(temp, double_class_); | 1084 __ CompareObject(temp, double_class_); |
| 1089 __ j(NOT_EQUAL, not_double_or_smi); | 1085 __ j(NOT_EQUAL, not_double_or_smi); |
| 1090 } | 1086 } |
| 1091 | 1087 |
| 1092 | 1088 |
| 1093 // TODO(srdjan): Detect double/Smi operation and remove extra code to | |
| 1094 // always check for Smi on the right hand side. | |
| 1095 // Result of the computation is a newly allocated double object or | 1089 // Result of the computation is a newly allocated double object or |
| 1096 // a temporary object if the parent node specifies a CodeGenInfo for this node | 1090 // a temporary object if the parent node specifies a CodeGenInfo for this node |
| 1097 // and therefore knows how to handle a temporary. A temporary object cannot | 1091 // and therefore knows how to handle a temporary. A temporary object cannot |
| 1098 // be used for long living values (e.g., the ones stored on stack or into other | 1092 // be used for long living values (e.g., the ones stored on stack or into other |
| 1099 // objects). | 1093 // objects). |
| 1100 void OptimizingCodeGenerator::GenerateDoubleBinaryOp(BinaryOpNode* node) { | 1094 // Implement for combinations: Double/Double, Double/Smi, Smi/Double, as |
| 1095 // the result is always double. |
| 1096 // TODO(srdjan): Implement Smi/Smi for kDIV (result also double). |
| 1097 void OptimizingCodeGenerator::GenerateDoubleBinaryOp(BinaryOpNode* node, |
| 1098 bool receiver_can_be_smi) { |
| 1101 const char* kOptMessage = "Inlines BinaryOp for Doubles"; | 1099 const char* kOptMessage = "Inlines BinaryOp for Doubles"; |
| 1102 const Token::Kind kind = node->kind(); | 1100 const Token::Kind kind = node->kind(); |
| 1103 if ((kind == Token::kADD) || | 1101 if ((kind == Token::kADD) || |
| 1104 (kind == Token::kSUB) || | 1102 (kind == Token::kSUB) || |
| 1105 (kind == Token::kMUL) || | 1103 (kind == Token::kMUL) || |
| 1106 (kind == Token::kDIV)) { | 1104 (kind == Token::kDIV)) { |
| 1107 TraceOpt(node, kOptMessage); | 1105 TraceOpt(node, kOptMessage); |
| 1108 // All four register below must be different. | 1106 // All four register below must be different. |
| 1109 const Register kLeftRegister = EAX; | 1107 const Register kLeftRegister = EAX; |
| 1110 const Register kRightRegister = EDX; | 1108 const Register kRightRegister = EDX; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1132 result_register = kLeftRegister; | 1130 result_register = kLeftRegister; |
| 1133 } else if (right_info.IsClass(double_class_) && right_info.is_temp()) { | 1131 } else if (right_info.IsClass(double_class_) && right_info.is_temp()) { |
| 1134 result_register = kRightRegister; | 1132 result_register = kRightRegister; |
| 1135 } else { | 1133 } else { |
| 1136 result_register = kAllocatedRegister; | 1134 result_register = kAllocatedRegister; |
| 1137 // Use inlined temporary double object. | 1135 // Use inlined temporary double object. |
| 1138 const Double& double_object = | 1136 const Double& double_object = |
| 1139 Double::ZoneHandle(Double::New(0.0, Heap::kOld)); | 1137 Double::ZoneHandle(Double::New(0.0, Heap::kOld)); |
| 1140 __ LoadObject(result_register, double_object); | 1138 __ LoadObject(result_register, double_object); |
| 1141 } | 1139 } |
| 1142 Label is_smi, extract_left; | 1140 |
| 1143 DeoptimizationBlob* deopt_blob = NULL; | 1141 DeoptimizationBlob* deopt_blob = NULL; |
| 1144 Label* deopt_lbl = NULL; | 1142 Label* deopt_lbl = NULL; |
| 1143 // Deoptimization can only occur if one of arguments is not double. |
| 1145 if (!left_info.IsClass(double_class_) || | 1144 if (!left_info.IsClass(double_class_) || |
| 1146 !right_info.IsClass(double_class_)) { | 1145 !right_info.IsClass(double_class_)) { |
| 1147 deopt_blob = AddDeoptimizationBlob(node, | 1146 deopt_blob = AddDeoptimizationBlob(node, |
| 1148 kLeftRegister, | 1147 kLeftRegister, |
| 1149 kRightRegister, | 1148 kRightRegister, |
| 1150 kDeoptDoubleBinaryOp); | 1149 kDeoptDoubleBinaryOp); |
| 1151 deopt_lbl = deopt_blob->label(); | 1150 deopt_lbl = deopt_blob->label(); |
| 1152 } | 1151 } |
| 1153 | 1152 |
| 1153 if (receiver_can_be_smi) { |
| 1154 // Only deoptimize if both argument are Smi. |
| 1155 __ movl(kTempRegister, kLeftRegister); |
| 1156 __ orl(kTempRegister, kRightRegister); |
| 1157 __ testl(kTempRegister, Immediate(kSmiTagMask)); |
| 1158 __ j(ZERO, deopt_lbl); |
| 1159 } |
| 1160 |
| 1154 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right()); | 1161 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right()); |
| 1155 if (!left_info.IsClass(double_class_)) { | 1162 if (!left_info.IsClass(double_class_)) { |
| 1156 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); | 1163 Label is_smi, done; |
| 1157 // Fall through for double. Jump to 'deopt' if not double. | 1164 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, &is_smi, deopt_lbl); |
| 1165 // Fall through for double. Jump to 'is_smi' if double, jump to |
| 1166 // 'deopt' if neither smi nor double. |
| 1167 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); |
| 1168 __ jmp(&done); |
| 1169 __ Bind(&is_smi); |
| 1170 __ SmiUntag(kLeftRegister); |
| 1171 __ cvtsi2sd(XMM0, kLeftRegister); |
| 1172 __ Bind(&done); |
| 1173 } else { |
| 1174 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); |
| 1158 } | 1175 } |
| 1159 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) { | 1176 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) { |
| 1177 Label is_smi, done; |
| 1160 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); | 1178 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); |
| 1161 // Fall through for double. Jump to 'is_smi' if double, jump to | 1179 // Fall through for double. Jump to 'is_smi' if double, jump to |
| 1162 // 'deopt' if neither smi nor double. | 1180 // 'deopt' if neither smi nor double. |
| 1163 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); | 1181 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); |
| 1164 __ jmp(&extract_left); | 1182 __ jmp(&done); |
| 1165 __ Bind(&is_smi); | 1183 __ Bind(&is_smi); |
| 1166 __ SmiUntag(kRightRegister); | 1184 __ SmiUntag(kRightRegister); |
| 1167 __ cvtsi2sd(XMM1, kRightRegister); | 1185 __ cvtsi2sd(XMM1, kRightRegister); |
| 1168 __ Bind(&extract_left); | 1186 __ Bind(&done); |
| 1169 } else { | 1187 } else { |
| 1170 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); | 1188 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); |
| 1171 } | 1189 } |
| 1172 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); | |
| 1173 | 1190 |
| 1174 switch (kind) { | 1191 switch (kind) { |
| 1175 case Token::kADD: __ addsd(XMM0, XMM1); break; | 1192 case Token::kADD: __ addsd(XMM0, XMM1); break; |
| 1176 case Token::kSUB: __ subsd(XMM0, XMM1); break; | 1193 case Token::kSUB: __ subsd(XMM0, XMM1); break; |
| 1177 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | 1194 case Token::kMUL: __ mulsd(XMM0, XMM1); break; |
| 1178 case Token::kDIV: __ divsd(XMM0, XMM1); break; | 1195 case Token::kDIV: __ divsd(XMM0, XMM1); break; |
| 1179 default: UNREACHABLE(); | 1196 default: UNREACHABLE(); |
| 1180 } | 1197 } |
| 1181 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); | 1198 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); |
| 1182 if (CodeGenerator::IsResultNeeded(node)) { | 1199 if (CodeGenerator::IsResultNeeded(node)) { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1299 __ jmp(deopt_blob->label()); | 1316 __ jmp(deopt_blob->label()); |
| 1300 return; | 1317 return; |
| 1301 } | 1318 } |
| 1302 | 1319 |
| 1303 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { | 1320 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { |
| 1304 GenerateSmiBinaryOp(node); | 1321 GenerateSmiBinaryOp(node); |
| 1305 return; | 1322 return; |
| 1306 } | 1323 } |
| 1307 | 1324 |
| 1308 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 1325 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 1309 GenerateDoubleBinaryOp(node); | 1326 const bool receiver_can_be_smi = false; |
| 1327 GenerateDoubleBinaryOp(node, receiver_can_be_smi); |
| 1328 return; |
| 1329 } |
| 1330 |
| 1331 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, double_class_)) { |
| 1332 const bool receiver_can_be_smi = true; |
| 1333 GenerateDoubleBinaryOp(node, receiver_can_be_smi); |
| 1310 return; | 1334 return; |
| 1311 } | 1335 } |
| 1312 | 1336 |
| 1313 const Class& mint_class = | 1337 const Class& mint_class = |
| 1314 Class::Handle(Isolate::Current()->object_store()->mint_class()); | 1338 Class::Handle(Isolate::Current()->object_store()->mint_class()); |
| 1315 if (AtIdNodeHasReceiverClass(node, node->id(), mint_class)) { | 1339 if (AtIdNodeHasReceiverClass(node, node->id(), mint_class)) { |
| 1316 GenerateMintBinaryOp(node, false); | 1340 GenerateMintBinaryOp(node, false); |
| 1317 return; | 1341 return; |
| 1318 } | 1342 } |
| 1319 | 1343 |
| (...skipping 997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2317 } | 2341 } |
| 2318 | 2342 |
| 2319 | 2343 |
| 2320 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 2344 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 2321 const char* kMessage = "Inline indexed access"; | 2345 const char* kMessage = "Inline indexed access"; |
| 2322 ObjectStore* object_store = Isolate::Current()->object_store(); | 2346 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2323 const Class& object_array_class = | 2347 const Class& object_array_class = |
| 2324 Class::ZoneHandle(object_store->array_class()); | 2348 Class::ZoneHandle(object_store->array_class()); |
| 2325 const Class& immutable_object_array_class = | 2349 const Class& immutable_object_array_class = |
| 2326 Class::ZoneHandle(object_store->immutable_array_class()); | 2350 Class::ZoneHandle(object_store->immutable_array_class()); |
| 2327 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class) || | 2351 if (AtIdNodeHasReceiverClass(node, node->id(), object_array_class) || |
| 2328 AtIdNodeHasOnlyClass(node, node->id(), immutable_object_array_class)) { | 2352 AtIdNodeHasReceiverClass(node, node->id(), |
| 2353 immutable_object_array_class)) { |
| 2329 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); | 2354 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); |
| 2330 DeoptimizationBlob* deopt_blob = | 2355 DeoptimizationBlob* deopt_blob = |
| 2331 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); | 2356 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); |
| 2332 const Class& test_class = | 2357 const Class& test_class = |
| 2333 AtIdNodeHasOnlyClass(node, node->id(), object_array_class) ? | 2358 AtIdNodeHasReceiverClass(node, node->id(), object_array_class) ? |
| 2334 object_array_class : immutable_object_array_class; | 2359 object_array_class : immutable_object_array_class; |
| 2335 // Type checks of array. | 2360 // Type checks of array. |
| 2336 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 2361 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 2337 __ j(ZERO, deopt_blob->label()); | 2362 __ j(ZERO, deopt_blob->label()); |
| 2338 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 2363 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 2339 __ CompareObject(EAX, test_class); | 2364 __ CompareObject(EAX, test_class); |
| 2340 __ j(NOT_EQUAL, deopt_blob->label()); | 2365 __ j(NOT_EQUAL, deopt_blob->label()); |
| 2341 | 2366 |
| 2342 // Type check of index. | 2367 // Type check of index. |
| 2343 __ testl(EDX, Immediate(kSmiTagMask)); | 2368 __ testl(EDX, Immediate(kSmiTagMask)); |
| 2344 __ j(NOT_ZERO, deopt_blob->label()); | 2369 __ j(NOT_ZERO, deopt_blob->label()); |
| 2345 // Range check. | 2370 // Range check. |
| 2346 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); | 2371 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); |
| 2347 __ j(ABOVE_EQUAL, deopt_blob->label()); | 2372 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 2348 // Note that EDX is Smi, i.e, times 2. | 2373 // Note that EDX is Smi, i.e, times 2. |
| 2349 ASSERT(kSmiTagShift == 1); | 2374 ASSERT(kSmiTagShift == 1); |
| 2350 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); | 2375 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); |
| 2351 if (CodeGenerator::IsResultNeeded(node)) { | 2376 if (CodeGenerator::IsResultNeeded(node)) { |
| 2352 __ pushl(EAX); | 2377 __ pushl(EAX); |
| 2353 } | 2378 } |
| 2354 TraceOpt(node, kMessage); | 2379 TraceOpt(node, kMessage); |
| 2355 return; | 2380 return; |
| 2356 } | 2381 } |
| 2357 | 2382 |
| 2358 const String& growable_object_array_class_name = String::Handle( | 2383 const String& growable_object_array_class_name = String::Handle( |
| 2359 String::NewSymbol(kGrowableArrayClassName)); | 2384 String::NewSymbol(kGrowableArrayClassName)); |
| 2360 const Class& growable_array_class = Class::ZoneHandle( | 2385 const Class& growable_array_class = Class::ZoneHandle( |
| 2361 Library::Handle(Library::CoreImplLibrary()). | 2386 Library::Handle(Library::CoreImplLibrary()). |
| 2362 LookupClass(growable_object_array_class_name)); | 2387 LookupClass(growable_object_array_class_name)); |
| 2363 if (AtIdNodeHasOnlyClass(node, node->id(), growable_array_class)) { | 2388 if (AtIdNodeHasReceiverClass(node, node->id(), growable_array_class)) { |
| 2364 const String& growable_array_length_field_name = | 2389 const String& growable_array_length_field_name = |
| 2365 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); | 2390 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); |
| 2366 const String& growable_array_array_field_name = | 2391 const String& growable_array_array_field_name = |
| 2367 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); | 2392 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); |
| 2368 intptr_t length_offset = GetFieldOffset(growable_array_class, | 2393 intptr_t length_offset = GetFieldOffset(growable_array_class, |
| 2369 growable_array_length_field_name); | 2394 growable_array_length_field_name); |
| 2370 intptr_t array_offset = GetFieldOffset(growable_array_class, | 2395 intptr_t array_offset = GetFieldOffset(growable_array_class, |
| 2371 growable_array_array_field_name); | 2396 growable_array_array_field_name); |
| 2372 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); | 2397 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); |
| 2373 DeoptimizationBlob* deopt_blob = | 2398 DeoptimizationBlob* deopt_blob = |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2411 const Class& object_array_class = | 2436 const Class& object_array_class = |
| 2412 Class::ZoneHandle(object_store->array_class()); | 2437 Class::ZoneHandle(object_store->array_class()); |
| 2413 const ICData& ic_data = node->ICDataAtId(node->id()); | 2438 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 2414 if (ic_data.NumberOfChecks() == 0) { | 2439 if (ic_data.NumberOfChecks() == 0) { |
| 2415 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2440 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2416 DeoptimizationBlob* deopt_blob = | 2441 DeoptimizationBlob* deopt_blob = |
| 2417 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); | 2442 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); |
| 2418 __ jmp(deopt_blob->label()); | 2443 __ jmp(deopt_blob->label()); |
| 2419 return; | 2444 return; |
| 2420 } | 2445 } |
| 2421 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class)) { | 2446 if (AtIdNodeHasReceiverClass(node, node->id(), object_array_class)) { |
| 2422 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2447 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2423 DeoptimizationBlob* deopt_blob = | 2448 DeoptimizationBlob* deopt_blob = |
| 2424 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed); | 2449 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed); |
| 2425 __ popl(EAX); // array. | 2450 __ popl(EAX); // array. |
| 2426 // ECX: value, EBX:index, EAX: array. | 2451 // ECX: value, EBX:index, EAX: array. |
| 2427 // Check type of array. | 2452 // Check type of array. |
| 2428 __ testl(EAX, Immediate(kSmiTagMask)); | 2453 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2429 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. | 2454 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. |
| 2430 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); | 2455 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); |
| 2431 __ CompareObject(EDX, object_array_class); | 2456 __ CompareObject(EDX, object_array_class); |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2804 node->function_name(), | 2829 node->function_name(), |
| 2805 num_arguments, | 2830 num_arguments, |
| 2806 num_named_arguments)); | 2831 num_named_arguments)); |
| 2807 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); | 2832 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); |
| 2808 if (FLAG_trace_optimization) { | 2833 if (FLAG_trace_optimization) { |
| 2809 OS::Print("Monomorphic inline candidate: %s -> %s\n", | 2834 OS::Print("Monomorphic inline candidate: %s -> %s\n", |
| 2810 target.ToFullyQualifiedCString(), | 2835 target.ToFullyQualifiedCString(), |
| 2811 Recognizer::KindToCString(recognized)); | 2836 Recognizer::KindToCString(recognized)); |
| 2812 } | 2837 } |
| 2813 if ((recognized == Recognizer::kIntegerToDouble) && | 2838 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2814 AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { | 2839 AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
| 2815 // TODO(srdjan): Check if we could use temporary double instead of | 2840 // TODO(srdjan): Check if we could use temporary double instead of |
| 2816 // allocating a new object every time. | 2841 // allocating a new object every time. |
| 2817 const Code& stub = | 2842 const Code& stub = |
| 2818 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2843 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2819 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2844 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2820 GenerateCall(node->token_index(), &label); | 2845 GenerateCall(node->token_index(), &label); |
| 2821 // EAX is double object. | 2846 // EAX is double object. |
| 2822 DeoptimizationBlob* deopt_blob = | 2847 DeoptimizationBlob* deopt_blob = |
| 2823 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); | 2848 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); |
| 2824 __ popl(EBX); // Receiver | 2849 __ popl(EBX); // Receiver |
| 2825 __ testl(EBX, Immediate(kSmiTagMask)); | 2850 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2826 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2851 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2827 __ SmiUntag(EBX); | 2852 __ SmiUntag(EBX); |
| 2828 __ cvtsi2sd(XMM0, EBX); | 2853 __ cvtsi2sd(XMM0, EBX); |
| 2829 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2854 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2830 return true; | 2855 return true; |
| 2831 } | 2856 } |
| 2832 | 2857 |
| 2833 if ((recognized == Recognizer::kDoubleToDouble) && | 2858 if ((recognized == Recognizer::kDoubleToDouble) && |
| 2834 AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { | 2859 AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 2835 DeoptimizationBlob* deopt_blob = | 2860 DeoptimizationBlob* deopt_blob = |
| 2836 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); | 2861 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); |
| 2837 __ popl(EAX); | 2862 __ popl(EAX); |
| 2838 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2863 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2839 return true; | 2864 return true; |
| 2840 } | 2865 } |
| 2841 } | 2866 } |
| 2842 return false; | 2867 return false; |
| 2843 } | 2868 } |
| 2844 | 2869 |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2978 if (IsResultInEaxRequested(node)) { | 3003 if (IsResultInEaxRequested(node)) { |
| 2979 node->info()->set_result_returned_in_eax(true); | 3004 node->info()->set_result_returned_in_eax(true); |
| 2980 } else { | 3005 } else { |
| 2981 __ pushl(EAX); | 3006 __ pushl(EAX); |
| 2982 } | 3007 } |
| 2983 } | 3008 } |
| 2984 return; | 3009 return; |
| 2985 } | 3010 } |
| 2986 | 3011 |
| 2987 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { | 3012 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { |
| 2988 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { | 3013 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
| 2989 const ICData& ic_data = node->ICDataAtId(node->id()); | 3014 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 2990 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 3015 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 2991 GenerateSmiUnaryOp(node); | 3016 GenerateSmiUnaryOp(node); |
| 2992 return; | 3017 return; |
| 2993 } | 3018 } |
| 2994 } | 3019 } |
| 2995 if (node->kind() == Token::kSUB) { | 3020 if (node->kind() == Token::kSUB) { |
| 2996 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 3021 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 2997 const ICData& ic_data = node->ICDataAtId(node->id()); | 3022 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 2998 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 3023 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 2999 GenerateDoubleUnaryOp(node); | 3024 GenerateDoubleUnaryOp(node); |
| 3000 return; | 3025 return; |
| 3001 } | 3026 } |
| 3002 } | 3027 } |
| 3003 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 3028 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 3004 CodeGenerator::VisitUnaryOpNode(node); | 3029 CodeGenerator::VisitUnaryOpNode(node); |
| 3005 } | 3030 } |
| 3006 | 3031 |
| 3007 | 3032 |
| 3008 } // namespace dart | 3033 } // namespace dart |
| 3009 | 3034 |
| 3010 #endif // defined TARGET_ARCH_IA32 | 3035 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |