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

Side by Side Diff: vm/opt_code_generator_ia32.cc

Issue 8827015: Implement two-argument check inline cache. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
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
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 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 result->Add(&cls); 298 result->Add(&cls);
299 } 299 }
300 return result; 300 return result;
301 } 301 }
302 302
303 303
304 // Debugging helper function. 304 // Debugging helper function.
305 void OptimizingCodeGenerator::PrintCollectedClassesAtId(AstNode* node, 305 void OptimizingCodeGenerator::PrintCollectedClassesAtId(AstNode* node,
306 intptr_t id) { 306 intptr_t id) {
307 const ICData& ic_data = node->ICDataAtId(id); 307 const ICData& ic_data = node->ICDataAtId(id);
308 ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
309 Function& target = Function::Handle();
310 Class& cls = Class::Handle();
311 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 308 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
312 ic_data.GetOneClassCheckAt(i, &cls, &target); 309 Function& target = Function::Handle();
313 OS::Print("- %s -> %s\n", cls.ToCString(), 310 GrowableArray<const Class*> classes;
314 target.ToFullyQualifiedCString()); 311 ic_data.GetCheckAt(i, &classes, &target);
312 OS::Print("[");
313 for (intptr_t c = 0; c < classes.length(); c++) {
314 OS::Print("%s%s", (c > 0) ? ", " : "", classes[c]->ToCString());
315 }
316 OS::Print("] -> %s\n", target.ToFullyQualifiedCString());
315 } 317 }
316 } 318 }
317 319
318 320
319 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { 321 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) {
320 if (FLAG_trace_optimization) { 322 if (FLAG_trace_optimization) {
321 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message); 323 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message);
322 } 324 }
323 } 325 }
324 326
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 __ popl(EAX); 548 __ popl(EAX);
547 } 549 }
548 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); 550 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX);
549 } 551 }
550 if (IsResultNeeded(node)) { 552 if (IsResultNeeded(node)) {
551 __ pushl(EAX); 553 __ pushl(EAX);
552 } 554 }
553 } 555 }
554 556
555 557
556 static bool NodeHasBothClasses(AstNode* node, 558 static bool NodeHasBothReceiverClasses(AstNode* node,
557 const Class& cls1, 559 const Class& cls1,
558 const Class& cls2) { 560 const Class& cls2) {
559 ASSERT(node != NULL); 561 ASSERT(node != NULL);
560 ASSERT(!cls1.IsNull() && !cls2.IsNull()); 562 ASSERT(!cls1.IsNull() && !cls2.IsNull());
563 const ICData& ic_data = node->ICDataAtId(node->id());
564 bool cls1_found = false;
565 bool cls2_found = false;
566 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
567 GrowableArray<const Class*> classes;
568 Function& target = Function::Handle();
569 ic_data.GetCheckAt(i, &classes, &target);
570 if (!classes.is_empty()) {
571 if (classes[0]->raw() == cls1.raw()) {
572 cls1_found = true;
573 }
574 if (classes[0]->raw() == cls2.raw()) {
575 cls2_found = true;
576 }
577 if (cls1_found && cls2_found) {
578 return true;
579 }
580 }
581 }
582 return false;
583 }
561 584
562 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); 585
563 if ((classes == NULL) || (classes->length() != 2)) { 586 // Look only at the first class in all check groups.
587 static bool AtIdNodeHasReceiverClass(AstNode* node,
588 intptr_t id,
589 const Class& cls) {
590 ASSERT(node != NULL);
591 ASSERT(!cls.IsNull());
592 const ICData& ic_data = node->ICDataAtId(id);
593 if (ic_data.NumberOfChecks() == 0) {
564 return false; 594 return false;
565 } 595 }
566 if ((cls1.raw() != (*classes)[0]->raw()) && 596 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
567 (cls1.raw() != (*classes)[1]->raw())) { 597 GrowableArray<const Class*> classes;
568 return false; 598 Function& target = Function::Handle();
569 } 599 ic_data.GetCheckAt(i, &classes, &target);
570 if ((cls2.raw() != (*classes)[0]->raw()) && 600 if (classes.is_empty()) {
571 (cls2.raw() != (*classes)[1]->raw())) { 601 return false;
572 return false; 602 }
603 if (classes[0]->raw() != cls.raw()) {
604 return false;
605 }
573 } 606 }
574 return true; 607 return true;
575 } 608 }
576 609
577 610
578 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) { 611 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) {
579 ASSERT(node != NULL); 612 ASSERT(node != NULL);
580 ASSERT(!cls.IsNull()); 613 ASSERT(!cls.IsNull());
581 const ICData& ic_data = node->ICDataAtId(id); 614 const ICData& ic_data = node->ICDataAtId(id);
582 if ((ic_data.NumberOfArgumentsChecked() != 1) || 615 if ((ic_data.NumberOfArgumentsChecked() != 1) ||
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 const char* kOptMessage = "Inlines BinaryOp for Smi"; 703 const char* kOptMessage = "Inlines BinaryOp for Smi";
671 Label done; 704 Label done;
672 const Token::Kind kind = node->kind(); 705 const Token::Kind kind = node->kind();
673 if ((kind == Token::kADD) || 706 if ((kind == Token::kADD) ||
674 (kind == Token::kSUB) || 707 (kind == Token::kSUB) ||
675 (kind == Token::kMUL) || 708 (kind == Token::kMUL) ||
676 (kind == Token::kBIT_AND) || 709 (kind == Token::kBIT_AND) ||
677 (kind == Token::kBIT_OR) || 710 (kind == Token::kBIT_OR) ||
678 (kind == Token::kBIT_XOR)) { 711 (kind == Token::kBIT_XOR)) {
679 TraceOpt(node, kOptMessage); 712 TraceOpt(node, kOptMessage);
713 // Check if both arguments are expected to be Smi.
714 const ICData& ic_data = node->ICDataAtId(node->id());
715 ASSERT(ic_data.NumberOfArgumentsChecked() == 2);
716 ASSERT(ic_data.NumberOfChecks() > 0);
717 Function& target = Function::Handle();
718 GrowableArray<const Class*> classes;
719 ic_data.GetCheckAt(0, &classes, &target);
720 const bool both_args_expected_smi =
721 (ic_data.NumberOfChecks() == 1) &&
722 (classes[0]->raw() == smi_class_.raw()) &&
723 (classes[1]->raw() == smi_class_.raw());
724
680 CodeGenInfo left_info(node->left()); 725 CodeGenInfo left_info(node->left());
681 CodeGenInfo right_info(node->right()); 726 CodeGenInfo right_info(node->right());
682 VisitLoadTwo(node->left(), node->right(), EAX, EDX); 727 VisitLoadTwo(node->left(), node->right(), EAX, EDX);
683 Label* overflow_label = NULL; 728 Label* overflow_label = NULL;
684 Label two_smis, call_operator; 729 Label two_smis, call_operator;
685 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { 730 if (both_args_expected_smi) {
686 DeoptimizationBlob* deopt_blob = 731 DeoptimizationBlob* deopt_blob =
687 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp); 732 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp);
688 overflow_label = deopt_blob->label(); 733 overflow_label = deopt_blob->label();
689 __ movl(ECX, EAX); // Save if overflow (needs original value). 734 __ movl(ECX, EAX); // Save if overflow (needs original value).
690 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { 735
691 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; 736 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) {
692 __ testl(test_reg, Immediate(kSmiTagMask)); 737 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) {
738 // One of the type is not known (statically) to be Smi. Check it.
739 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX;
740 __ testl(test_reg, Immediate(kSmiTagMask));
741 __ j(NOT_ZERO, deopt_blob->label());
742 }
743 } else {
744 // Type feedback says both types are Smi, but static type analysis
745 // does not know if any of them is Smi, therefore check.
746 __ orl(EAX, EDX);
747 __ testl(EAX, Immediate(kSmiTagMask));
693 __ j(NOT_ZERO, deopt_blob->label()); 748 __ j(NOT_ZERO, deopt_blob->label());
749 __ movl(EAX, ECX);
694 } 750 }
695 if (node->info() != NULL) { 751 if (node->info() != NULL) {
696 node->info()->set_is_class(&smi_class_); 752 node->info()->set_is_class(&smi_class_);
697 } 753 }
698 } else { 754 } else {
699 overflow_label = &call_operator; 755 overflow_label = &call_operator;
700 __ movl(ECX, EAX); 756 __ movl(ECX, EAX);
701 __ orl(EAX, EDX); 757 __ orl(EAX, EDX);
702 __ testl(EAX, Immediate(kSmiTagMask)); 758 __ testl(EAX, Immediate(kSmiTagMask));
703 __ j(ZERO, &two_smis, Assembler::kNearJump); 759 __ j(ZERO, &two_smis, Assembler::kNearJump);
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
1053 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { 1109 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
1054 if (FLAG_enable_type_checks) { 1110 if (FLAG_enable_type_checks) {
1055 CodeGenerator::VisitBinaryOpNode(node); 1111 CodeGenerator::VisitBinaryOpNode(node);
1056 return; 1112 return;
1057 } 1113 }
1058 GenerateLogicalBinaryOp(node); 1114 GenerateLogicalBinaryOp(node);
1059 return; 1115 return;
1060 } 1116 }
1061 1117
1062 ObjectStore* object_store = Isolate::Current()->object_store(); 1118 ObjectStore* object_store = Isolate::Current()->object_store();
1063 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { 1119 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) {
1064 GenerateSmiBinaryOp(node); 1120 GenerateSmiBinaryOp(node);
1065 return; 1121 return;
1066 } 1122 }
1067 1123
1068 if (AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { 1124 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) {
1069 GenerateDoubleBinaryOp(node); 1125 GenerateDoubleBinaryOp(node);
1070 return; 1126 return;
1071 } 1127 }
1072 1128
1073 if (AtIdNodeHasOnlyClass(node, 1129 if (AtIdNodeHasReceiverClass(node,
1074 node->id(), 1130 node->id(),
regis 2011/12/09 23:08:03 indentation
1075 Class::Handle(object_store->mint_class()))) { 1131 Class::Handle(object_store->mint_class()))) {
1076 GenerateMintBinaryOp(node, false); 1132 GenerateMintBinaryOp(node, false);
1077 return; 1133 return;
1078 } 1134 }
1079 1135
1080 if (NodeHasBothClasses(node, 1136 if (NodeHasBothReceiverClasses(node,
1081 smi_class_, Class::Handle(object_store->mint_class()))) { 1137 smi_class_, Class::Handle(object_store->mint_class()))) {
1082 GenerateMintBinaryOp(node, true); 1138 GenerateMintBinaryOp(node, true);
1083 return; 1139 return;
1084 } 1140 }
1085 1141
1086 // Type feedback tells this is not a Smi or Double operation. 1142 // Type feedback tells this is not a Smi or Double operation.
1087 TraceNotOpt(node, 1143 TraceNotOpt(node,
1088 "BinaryOp: type feedback tells this is not a Smi or Double op"); 1144 "BinaryOp: type feedback tells this is not a Smi or Double op");
1089 CodeGenerator::VisitBinaryOpNode(node); 1145 CodeGenerator::VisitBinaryOpNode(node);
1090 return; 1146 return;
1091 } 1147 }
1092 1148
1093 1149
1094 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { 1150 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) {
1095 if (FLAG_enable_type_checks) { 1151 if (FLAG_enable_type_checks) {
1096 CodeGenerator::VisitIncrOpLocalNode(node); 1152 CodeGenerator::VisitIncrOpLocalNode(node);
1097 return; 1153 return;
1098 } 1154 }
1099 const char* kOptMessage = "Inlines IncrOpLocal"; 1155 const char* kOptMessage = "Inlines IncrOpLocal";
1100 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); 1156 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR));
1101 if (!AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { 1157 if (!AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) {
1102 TraceNotOpt(node, kOptMessage); 1158 TraceNotOpt(node, kOptMessage);
1103 CodeGenerator::VisitIncrOpLocalNode(node); 1159 CodeGenerator::VisitIncrOpLocalNode(node);
1104 return; 1160 return;
1105 } 1161 }
1106 TraceOpt(node, kOptMessage); 1162 TraceOpt(node, kOptMessage);
1107 1163
1108 GenerateLoadVariable(EAX, node->local()); 1164 GenerateLoadVariable(EAX, node->local());
1109 if (!node->prefix() && IsResultNeeded(node)) { 1165 if (!node->prefix() && IsResultNeeded(node)) {
1110 // Preserve as result. 1166 // Preserve as result.
1111 __ movl(ECX, EAX); 1167 __ movl(ECX, EAX);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 node->getter_id(), 1241 node->getter_id(),
1186 node->receiver(), 1242 node->receiver(),
1187 node->field_name(), 1243 node->field_name(),
1188 EBX); 1244 EBX);
1189 // result is in EAX. 1245 // result is in EAX.
1190 __ popl(EDX); // Get receiver. 1246 __ popl(EDX); // Get receiver.
1191 const bool return_original_value = !node->prefix() && IsResultNeeded(node); 1247 const bool return_original_value = !node->prefix() && IsResultNeeded(node);
1192 const Immediate one_value = Immediate(Smi::RawValue(1)); 1248 const Immediate one_value = Immediate(Smi::RawValue(1));
1193 // EAX: Value. 1249 // EAX: Value.
1194 // EDX: Receiver. 1250 // EDX: Receiver.
1195 if (AtIdNodeHasOnlyClass(node, node->operator_id(), smi_class_)) { 1251 if (AtIdNodeHasReceiverClass(node, node->operator_id(), smi_class_)) {
1196 // Deoptimization point for this node is after receiver has been 1252 // Deoptimization point for this node is after receiver has been
1197 // pushed twice on stack and before the getter (above) was executed. 1253 // pushed twice on stack and before the getter (above) was executed.
1198 DeoptimizationBlob* deopt_blob = 1254 DeoptimizationBlob* deopt_blob =
1199 AddDeoptimizationBlob(node, EDX, EDX, kDeoptIncrInstanceOneClass); 1255 AddDeoptimizationBlob(node, EDX, EDX, kDeoptIncrInstanceOneClass);
1200 if (return_original_value) { 1256 if (return_original_value) {
1201 // Preserve pre increment result. 1257 // Preserve pre increment result.
1202 __ movl(ECX, EAX); 1258 __ movl(ECX, EAX);
1203 } 1259 }
1204 __ testl(EAX, Immediate(kSmiTagMask)); 1260 __ testl(EAX, Immediate(kSmiTagMask));
1205 __ j(NOT_ZERO, deopt_blob->label()); 1261 __ j(NOT_ZERO, deopt_blob->label());
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after
1964 __ j(condition, &is_true); 2020 __ j(condition, &is_true);
1965 __ PushObject(bool_false); 2021 __ PushObject(bool_false);
1966 __ jmp(&done); 2022 __ jmp(&done);
1967 __ Bind(&is_true); 2023 __ Bind(&is_true);
1968 __ PushObject(bool_true); 2024 __ PushObject(bool_true);
1969 __ Bind(&done); 2025 __ Bind(&done);
1970 } 2026 }
1971 return; 2027 return;
1972 } 2028 }
1973 2029
1974 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { 2030 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) {
1975 if (GenerateSmiComparison(node)) { 2031 if (GenerateSmiComparison(node)) {
1976 return; 2032 return;
1977 } 2033 }
1978 // Fall through if condition is not supported. 2034 // Fall through if condition is not supported.
1979 } else if (AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { 2035 } else if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) {
1980 // Double comparison 2036 // Double comparison
1981 if (GenerateDoubleComparison(node)) { 2037 if (GenerateDoubleComparison(node)) {
1982 return; 2038 return;
1983 } 2039 }
1984 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { 2040 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) {
1985 // Equality, not-equality comparison of any other type. 2041 // Equality, not-equality comparison of any other type.
1986 if (GenerateEqualityComparison(node)) { 2042 if (GenerateEqualityComparison(node)) {
1987 return; 2043 return;
1988 } 2044 }
1989 } 2045 }
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
2266 // collected in the meantime. 2322 // collected in the meantime.
2267 void OptimizingCodeGenerator::GenerateInlineCacheCall( 2323 void OptimizingCodeGenerator::GenerateInlineCacheCall(
2268 intptr_t node_id, 2324 intptr_t node_id,
2269 intptr_t token_index, 2325 intptr_t token_index,
2270 const ICData& ic_data, 2326 const ICData& ic_data,
2271 intptr_t num_args, 2327 intptr_t num_args,
2272 const Array& optional_arguments_names) { 2328 const Array& optional_arguments_names) {
2273 __ LoadObject(ECX, Array::ZoneHandle(ic_data.data())); 2329 __ LoadObject(ECX, Array::ZoneHandle(ic_data.data()));
2274 __ LoadObject(EDX, ArgumentsDescriptor(num_args, optional_arguments_names)); 2330 __ LoadObject(EDX, ArgumentsDescriptor(num_args, optional_arguments_names));
2275 ExternalLabel target_label( 2331 ExternalLabel target_label(
2276 "InlineCache", StubCode::InlineCacheEntryPoint()); 2332 "InlineCache", StubCode::OneArgCheckInlineCacheEntryPoint());
2277 2333
2278 __ call(&target_label); 2334 __ call(&target_label);
2279 AddCurrentDescriptor(PcDescriptors::kIcCall, 2335 AddCurrentDescriptor(PcDescriptors::kIcCall,
2280 node_id, 2336 node_id,
2281 token_index); 2337 token_index);
2282 __ addl(ESP, Immediate(num_args * kWordSize)); 2338 __ addl(ESP, Immediate(num_args * kWordSize));
2283 } 2339 }
2284 2340
2285 2341
2286 // Normalizes the ic_data class/target pairs: 2342 // Normalizes the ic_data class/target pairs:
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
2594 if (IsResultNeeded(node)) { 2650 if (IsResultNeeded(node)) {
2595 // The result is the input value. 2651 // The result is the input value.
2596 __ pushl(EAX); 2652 __ pushl(EAX);
2597 } 2653 }
2598 } 2654 }
2599 2655
2600 2656
2601 } // namespace dart 2657 } // namespace dart
2602 2658
2603 #endif // defined TARGET_ARCH_IA32 2659 #endif // defined TARGET_ARCH_IA32
OLDNEW
« vm/code_generator_ia32.cc ('K') | « vm/ic_data.cc ('k') | vm/stub_code.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698