Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: runtime/vm/opt_code_generator_ia32.cc

Issue 9007027: Add (debug) printing when IC is used in optimized code (must eliminate it). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/compiler.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/compiler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698