Chromium Code Reviews| 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 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 648 return false; | 648 return false; |
| 649 } | 649 } |
| 650 if (classes[0]->raw() != cls.raw()) { | 650 if (classes[0]->raw() != cls.raw()) { |
| 651 return false; | 651 return false; |
| 652 } | 652 } |
| 653 } | 653 } |
| 654 return true; | 654 return true; |
| 655 } | 655 } |
| 656 | 656 |
| 657 | 657 |
| 658 // IC data may have only one check, and it has to contain the two classes in | |
| 659 // specified order. | |
| 660 static bool AtIdNodeHasTwoClasses(AstNode* node, | |
| 661 intptr_t id, | |
| 662 const Class& cls0, | |
| 663 const Class& cls1) { | |
| 664 ASSERT(node != NULL); | |
| 665 ASSERT(!cls0.IsNull() && !cls1.IsNull()); | |
|
hausner
2011/12/20 21:50:08
You could move this assertion after line 670 to ma
srdjan
2011/12/20 21:55:05
Yes, but I want to catch mistakes at call site ear
| |
| 666 const ICData& ic_data = node->ICDataAtId(id); | |
| 667 ASSERT(ic_data.NumberOfArgumentsChecked() == 2); | |
| 668 if (ic_data.NumberOfChecks() != 1) { | |
| 669 return false; | |
| 670 } | |
| 671 Function& target = Function::Handle(); | |
| 672 GrowableArray<const Class*> classes; | |
| 673 ic_data.GetCheckAt(0, &classes, &target); | |
| 674 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) { | |
| 675 return true; | |
| 676 } | |
| 677 return false; | |
| 678 } | |
| 679 | |
| 680 | |
| 658 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) { | 681 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) { |
| 659 ASSERT(node != NULL); | 682 ASSERT(node != NULL); |
| 660 ASSERT(!cls.IsNull()); | 683 ASSERT(!cls.IsNull()); |
| 661 const ICData& ic_data = node->ICDataAtId(id); | 684 const ICData& ic_data = node->ICDataAtId(id); |
| 662 if ((ic_data.NumberOfArgumentsChecked() != 1) || | 685 if ((ic_data.NumberOfArgumentsChecked() != 1) || |
| 663 (ic_data.NumberOfChecks() != 1)) { | 686 (ic_data.NumberOfChecks() != 1)) { |
| 664 return false; | 687 return false; |
| 665 } | 688 } |
| 666 Class& target_cls = Class::Handle(); | 689 Class& target_cls = Class::Handle(); |
| 667 Function& target = Function::Handle(); | 690 Function& target = Function::Handle(); |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 851 if (IsResultInEaxRequested(node)) { | 874 if (IsResultInEaxRequested(node)) { |
| 852 ASSERT(kResultRegister == EAX); | 875 ASSERT(kResultRegister == EAX); |
| 853 node->info()->set_result_returned_in_eax(true); | 876 node->info()->set_result_returned_in_eax(true); |
| 854 } else { | 877 } else { |
| 855 __ pushl(kResultRegister); | 878 __ pushl(kResultRegister); |
| 856 } | 879 } |
| 857 } | 880 } |
| 858 } | 881 } |
| 859 | 882 |
| 860 | 883 |
| 861 // TODO(srdjan): Expand inline caches to detect Smi/double operations, so that | 884 // Handles only Smi & Smi. |
| 862 // we do not have to call the instance method, and therefore could guarantee | |
| 863 // that the result is a Smi at the end. | |
| 864 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { | 885 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { |
| 865 const char* kOptMessage = "Inlines BinaryOp for Smi"; | 886 const char* kOptMessage = "Inlines BinaryOp for Smi"; |
| 866 Label done; | 887 Label done; |
| 867 const Token::Kind kind = node->kind(); | 888 const Token::Kind kind = node->kind(); |
| 868 if ((kind == Token::kADD) || | 889 if ((kind == Token::kADD) || |
| 869 (kind == Token::kSUB) || | 890 (kind == Token::kSUB) || |
| 870 (kind == Token::kMUL) || | 891 (kind == Token::kMUL) || |
| 871 (kind == Token::kTRUNCDIV) || | 892 (kind == Token::kTRUNCDIV) || |
| 872 (kind == Token::kBIT_AND) || | 893 (kind == Token::kBIT_AND) || |
| 873 (kind == Token::kBIT_OR) || | 894 (kind == Token::kBIT_OR) || |
| 874 (kind == Token::kBIT_XOR)) { | 895 (kind == Token::kBIT_XOR)) { |
| 875 TraceOpt(node, kOptMessage); | 896 TraceOpt(node, kOptMessage); |
| 876 // Check if both arguments are expected to be Smi. | 897 // Check if both arguments are expected to be Smi. |
| 877 const ICData& ic_data = node->ICDataAtId(node->id()); | 898 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 878 ASSERT(ic_data.NumberOfArgumentsChecked() == 2); | 899 ASSERT(ic_data.NumberOfArgumentsChecked() == 2); |
| 879 ASSERT(ic_data.NumberOfChecks() > 0); | 900 ASSERT(ic_data.NumberOfChecks() > 0); |
| 880 Function& target = Function::Handle(); | 901 Function& target = Function::Handle(); |
| 881 GrowableArray<const Class*> classes; | 902 GrowableArray<const Class*> classes; |
| 882 ic_data.GetCheckAt(0, &classes, &target); | 903 ic_data.GetCheckAt(0, &classes, &target); |
| 883 const bool both_args_expected_smi = | 904 ASSERT(ic_data.NumberOfChecks() == 1); |
| 884 (ic_data.NumberOfChecks() == 1) && | 905 ASSERT((classes[0]->raw() == smi_class_.raw()) && |
| 885 (classes[0]->raw() == smi_class_.raw()) && | 906 (classes[1]->raw() == smi_class_.raw())); |
| 886 (classes[1]->raw() == smi_class_.raw()); | |
| 887 | |
| 888 CodeGenInfo left_info(node->left()); | 907 CodeGenInfo left_info(node->left()); |
| 889 CodeGenInfo right_info(node->right()); | 908 CodeGenInfo right_info(node->right()); |
| 890 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 909 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 891 Label* overflow_label = NULL; | |
| 892 Label two_smis, call_operator; | 910 Label two_smis, call_operator; |
| 893 if (both_args_expected_smi) { | 911 DeoptimizationBlob* deopt_blob = |
| 894 DeoptimizationBlob* deopt_blob = | 912 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp); |
| 895 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp); | 913 __ movl(ECX, EAX); // Save if overflow (needs original value). |
| 896 overflow_label = deopt_blob->label(); | |
| 897 __ movl(ECX, EAX); // Save if overflow (needs original value). | |
| 898 | 914 |
| 899 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { | 915 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { |
| 900 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { | 916 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { |
| 901 // One of the type is not known (statically) to be Smi. Check it. | 917 // One of the type is not known (statically) to be Smi. Check it. |
| 902 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; | 918 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; |
| 903 __ testl(test_reg, Immediate(kSmiTagMask)); | 919 __ testl(test_reg, Immediate(kSmiTagMask)); |
| 904 __ j(NOT_ZERO, deopt_blob->label()); | |
| 905 } | |
| 906 } else { | |
| 907 // Type feedback says both types are Smi, but static type analysis | |
| 908 // does not know if any of them is Smi, therefore check. | |
| 909 __ orl(EAX, EDX); | |
| 910 __ testl(EAX, Immediate(kSmiTagMask)); | |
| 911 __ j(NOT_ZERO, deopt_blob->label()); | 920 __ j(NOT_ZERO, deopt_blob->label()); |
| 912 __ movl(EAX, ECX); | |
| 913 } | |
| 914 if (node->info() != NULL) { | |
| 915 node->info()->set_is_class(&smi_class_); | |
| 916 } | 921 } |
| 917 } else { | 922 } else { |
| 918 overflow_label = &call_operator; | 923 // Type feedback says both types are Smi, but static type analysis |
| 919 __ movl(ECX, EAX); | 924 // does not know if any of them is Smi, therefore check. |
| 920 __ orl(EAX, EDX); | 925 __ orl(EAX, EDX); |
| 921 __ testl(EAX, Immediate(kSmiTagMask)); | 926 __ testl(EAX, Immediate(kSmiTagMask)); |
| 922 __ j(ZERO, &two_smis, Assembler::kNearJump); | 927 __ j(NOT_ZERO, deopt_blob->label()); |
| 923 | |
| 924 // Operator is called either if one of the arguments is not Smi or | |
| 925 // if we hit an overflow in an arithmetic operation. | |
| 926 __ Bind(&call_operator); | |
| 927 // Restore arguments on stack, and dispatch to operator, thus preventing | |
| 928 // deoptimization in case of smi/non-smi operations. At exit we do not | |
| 929 // know the result is Smi or not. | |
| 930 // TODO(srdjan): Handle type feedback for both arguments instead of for | |
| 931 // receiver only, deoptimize if the type changes. | |
| 932 __ pushl(ECX); | |
| 933 __ pushl(EDX); | |
| 934 GenerateBinaryOperatorCall(node->id(), | |
| 935 node->token_index(), | |
| 936 node->Name()); | |
| 937 __ jmp(&done); | |
| 938 __ Bind(&two_smis); | |
| 939 // Restore left operand. EAX will be 'destroyed', ECX holds the left | |
| 940 // argument, which may be needed for deoptimization. | |
| 941 __ movl(EAX, ECX); | 928 __ movl(EAX, ECX); |
| 942 } | 929 } |
| 930 if (node->info() != NULL) { | |
| 931 node->info()->set_is_class(&smi_class_); | |
| 932 } | |
| 943 switch (kind) { | 933 switch (kind) { |
| 944 case Token::kADD: { | 934 case Token::kADD: { |
| 945 __ addl(EAX, EDX); | 935 __ addl(EAX, EDX); |
| 946 __ j(OVERFLOW, overflow_label); | 936 __ j(OVERFLOW, deopt_blob->label()); |
| 947 break; | 937 break; |
| 948 } | 938 } |
| 949 case Token::kSUB: { | 939 case Token::kSUB: { |
| 950 __ subl(EAX, EDX); | 940 __ subl(EAX, EDX); |
| 951 __ j(OVERFLOW, overflow_label); | 941 __ j(OVERFLOW, deopt_blob->label()); |
| 952 break; | 942 break; |
| 953 } | 943 } |
| 954 case Token::kMUL: { | 944 case Token::kMUL: { |
| 955 __ SmiUntag(EAX); | 945 __ SmiUntag(EAX); |
| 956 __ imull(EAX, EDX); | 946 __ imull(EAX, EDX); |
| 957 __ j(OVERFLOW, overflow_label); | 947 __ j(OVERFLOW, deopt_blob->label()); |
| 958 break; | 948 break; |
| 959 } | 949 } |
| 960 case Token::kBIT_AND: { | 950 case Token::kBIT_AND: { |
| 961 // No overflow check. | 951 // No overflow check. |
| 962 __ andl(EAX, EDX); | 952 __ andl(EAX, EDX); |
| 963 break; | 953 break; |
| 964 } | 954 } |
| 965 case Token::kBIT_OR: { | 955 case Token::kBIT_OR: { |
| 966 // No overflow check. | 956 // No overflow check. |
| 967 __ orl(EAX, EDX); | 957 __ orl(EAX, EDX); |
| 968 break; | 958 break; |
| 969 } | 959 } |
| 970 case Token::kBIT_XOR: { | 960 case Token::kBIT_XOR: { |
| 971 // No overflow check. | 961 // No overflow check. |
| 972 __ xorl(EAX, EDX); | 962 __ xorl(EAX, EDX); |
| 973 break; | 963 break; |
| 974 } | 964 } |
| 975 case Token::kTRUNCDIV: { | 965 case Token::kTRUNCDIV: { |
| 976 // Handle divide by zero in runtime. | 966 // Handle divide by zero in runtime. |
| 977 __ cmpl(EDX, Immediate(0)); | 967 __ cmpl(EDX, Immediate(0)); |
| 978 __ j(EQUAL, overflow_label); | 968 __ j(EQUAL, deopt_blob->label()); |
| 979 // Preserve left & right in case of 'overflow'. | 969 // Preserve left & right in case of 'overflow'. |
| 980 __ pushl(EDX); | 970 __ pushl(EDX); |
| 981 __ pushl(ECX); | 971 __ pushl(ECX); |
| 982 // Move right to ECX, left is in EAX. | 972 // Move right to ECX, left is in EAX. |
| 983 __ movl(ECX, EDX); | 973 __ movl(ECX, EDX); |
| 984 __ SmiUntag(ECX); | 974 __ SmiUntag(ECX); |
| 985 __ SmiUntag(EAX); | 975 __ SmiUntag(EAX); |
| 986 // Sign extend EAX -> EDX:EAX. | 976 // Sign extend EAX -> EDX:EAX. |
| 987 __ cdq(); | 977 __ cdq(); |
| 988 __ idivl(ECX); // Result in EAX. | 978 __ idivl(ECX); // Result in EAX. |
| 989 __ popl(ECX); | 979 __ popl(ECX); |
| 990 __ popl(EDX); | 980 __ popl(EDX); |
| 991 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 981 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 992 // case we cannot tag the result. | 982 // case we cannot tag the result. |
| 993 __ cmpl(EAX, Immediate(0x40000000)); | 983 __ cmpl(EAX, Immediate(0x40000000)); |
| 994 __ j(EQUAL, overflow_label); | 984 __ j(EQUAL, deopt_blob->label()); |
| 995 __ SmiTag(EAX); | 985 __ SmiTag(EAX); |
| 996 break; | 986 break; |
| 997 } | 987 } |
| 998 default: | 988 default: |
| 999 UNREACHABLE(); | 989 UNREACHABLE(); |
| 1000 } | 990 } |
| 1001 } else if ((kind == Token::kSHL) || (kind == Token::kSAR)) { | 991 } else if ((kind == Token::kSHL) || (kind == Token::kSAR)) { |
| 1002 GenerateSmiShiftBinaryOp(node); | 992 GenerateSmiShiftBinaryOp(node); |
| 1003 } else { | 993 } else { |
| 1004 // Unhandled node kind. | 994 // Unhandled node kind. |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1303 | 1293 |
| 1304 const ICData& ic_data = node->ICDataAtId(node->id()); | 1294 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1305 if (ic_data.NumberOfChecks() == 0) { | 1295 if (ic_data.NumberOfChecks() == 0) { |
| 1306 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1296 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1307 DeoptimizationBlob* deopt_blob = | 1297 DeoptimizationBlob* deopt_blob = |
| 1308 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); | 1298 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); |
| 1309 __ jmp(deopt_blob->label()); | 1299 __ jmp(deopt_blob->label()); |
| 1310 return; | 1300 return; |
| 1311 } | 1301 } |
| 1312 | 1302 |
| 1313 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 1303 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { |
| 1314 GenerateSmiBinaryOp(node); | 1304 GenerateSmiBinaryOp(node); |
| 1315 return; | 1305 return; |
| 1316 } | 1306 } |
| 1317 | 1307 |
| 1318 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 1308 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 1319 GenerateDoubleBinaryOp(node); | 1309 GenerateDoubleBinaryOp(node); |
| 1320 return; | 1310 return; |
| 1321 } | 1311 } |
| 1322 | 1312 |
| 1323 const Class& mint_class = | 1313 const Class& mint_class = |
| (...skipping 1687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3011 } | 3001 } |
| 3012 } | 3002 } |
| 3013 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 3003 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 3014 CodeGenerator::VisitUnaryOpNode(node); | 3004 CodeGenerator::VisitUnaryOpNode(node); |
| 3015 } | 3005 } |
| 3016 | 3006 |
| 3017 | 3007 |
| 3018 } // namespace dart | 3008 } // namespace dart |
| 3019 | 3009 |
| 3020 #endif // defined TARGET_ARCH_IA32 | 3010 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |