| 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 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 deoptimization_blobs_[i]->Generate(this); | 261 deoptimization_blobs_[i]->Generate(this); |
| 262 } | 262 } |
| 263 } | 263 } |
| 264 | 264 |
| 265 | 265 |
| 266 bool OptimizingCodeGenerator::IsResultInEaxRequested(AstNode* node) const { | 266 bool OptimizingCodeGenerator::IsResultInEaxRequested(AstNode* node) const { |
| 267 return (node->info() != NULL) && node->info()->request_result_in_eax(); | 267 return (node->info() != NULL) && node->info()->request_result_in_eax(); |
| 268 } | 268 } |
| 269 | 269 |
| 270 | 270 |
| 271 static const ZoneGrowableArray<const Class*>* |
| 272 CollectedClassesAtNode(AstNode* node) { |
| 273 ZoneGrowableArray<const Class*>* result = |
| 274 new ZoneGrowableArray<const Class*>(); |
| 275 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 276 if (ic_data.NumberOfChecks() == 0) { |
| 277 return result; |
| 278 } |
| 279 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 280 Function& target = Function::Handle(); |
| 281 GrowableArray<const Class*> classes; |
| 282 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 283 ic_data.GetCheckAt(i, &classes, &target); |
| 284 ASSERT(classes.length() == 1); |
| 285 result->Add(classes[0]); |
| 286 } |
| 287 return result; |
| 288 } |
| 289 |
| 290 |
| 271 // Debugging helper function. | 291 // Debugging helper function. |
| 272 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { | 292 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { |
| 273 const ZoneGrowableArray<const Class*>* classes = | 293 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 274 node->CollectedClassesAtId(node->id()); | |
| 275 for (intptr_t i = 0; i < classes->length(); i++) { | 294 for (intptr_t i = 0; i < classes->length(); i++) { |
| 276 OS::Print("- %s\n", (*classes)[i]->ToCString()); | 295 OS::Print("- %s\n", (*classes)[i]->ToCString()); |
| 277 } | 296 } |
| 278 } | 297 } |
| 279 | 298 |
| 280 | 299 |
| 281 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { | 300 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { |
| 282 if (FLAG_trace_optimization) { | 301 if (FLAG_trace_optimization) { |
| 283 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message); | 302 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message); |
| 284 } | 303 } |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 if (!value_info.result_returned_in_eax()) { | 526 if (!value_info.result_returned_in_eax()) { |
| 508 __ popl(EAX); | 527 __ popl(EAX); |
| 509 } | 528 } |
| 510 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); | 529 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); |
| 511 } | 530 } |
| 512 if (IsResultNeeded(node)) { | 531 if (IsResultNeeded(node)) { |
| 513 __ pushl(EAX); | 532 __ pushl(EAX); |
| 514 } | 533 } |
| 515 } | 534 } |
| 516 | 535 |
| 536 |
| 517 static bool NodeHasBothClasses(AstNode* node, | 537 static bool NodeHasBothClasses(AstNode* node, |
| 518 const Class& cls1, | 538 const Class& cls1, |
| 519 const Class& cls2) { | 539 const Class& cls2) { |
| 520 ASSERT(node != NULL); | 540 ASSERT(node != NULL); |
| 521 ASSERT(!cls1.IsNull() && !cls2.IsNull()); | 541 ASSERT(!cls1.IsNull() && !cls2.IsNull()); |
| 522 const ZoneGrowableArray<const Class*>* classes = | 542 |
| 523 node->CollectedClassesAtId(node->id()); | 543 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 524 if ((classes == NULL) || (classes->length() != 2)) { | 544 if ((classes == NULL) || (classes->length() != 2)) { |
| 525 return false; | 545 return false; |
| 526 } | 546 } |
| 527 if ((cls1.raw() != (*classes)[0]->raw()) && | 547 if ((cls1.raw() != (*classes)[0]->raw()) && |
| 528 (cls1.raw() != (*classes)[1]->raw())) { | 548 (cls1.raw() != (*classes)[1]->raw())) { |
| 529 return false; | 549 return false; |
| 530 } | 550 } |
| 531 if ((cls2.raw() != (*classes)[0]->raw()) && | 551 if ((cls2.raw() != (*classes)[0]->raw()) && |
| 532 (cls2.raw() != (*classes)[1]->raw())) { | 552 (cls2.raw() != (*classes)[1]->raw())) { |
| 533 return false; | 553 return false; |
| 534 } | 554 } |
| 535 return true; | 555 return true; |
| 536 } | 556 } |
| 537 | 557 |
| 538 | 558 |
| 539 static bool NodeHasOnlyClass(AstNode* node, const Class& cls) { | 559 static bool NodeHasOnlyClass(AstNode* node, const Class& cls) { |
| 540 ASSERT(node != NULL); | 560 ASSERT(node != NULL); |
| 541 ASSERT(!cls.IsNull()); | 561 ASSERT(!cls.IsNull()); |
| 542 const ZoneGrowableArray<const Class*>* classes = | 562 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 543 node->CollectedClassesAtId(node->id()); | |
| 544 return (classes != NULL) && | 563 return (classes != NULL) && |
| 545 (classes->length() == 1) && | 564 (classes->length() == 1) && |
| 546 ((*classes)[0]->raw() == cls.raw()); | 565 ((*classes)[0]->raw() == cls.raw()); |
| 547 } | 566 } |
| 548 | 567 |
| 549 | 568 |
| 550 // Implement with slow case so that it can work both with Smi and Mint types. | 569 // Implement with slow case so that it can work both with Smi and Mint types. |
| 551 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { | 570 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { |
| 552 ASSERT(node->kind() == Token::kSHL); | 571 ASSERT(node->kind() == Token::kSHL); |
| 553 Label done; | 572 Label done; |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 } | 1138 } |
| 1120 } | 1139 } |
| 1121 return true; | 1140 return true; |
| 1122 } | 1141 } |
| 1123 | 1142 |
| 1124 | 1143 |
| 1125 // Emits code for an instance getter that has one or more collected classes, | 1144 // Emits code for an instance getter that has one or more collected classes, |
| 1126 // all with the same target. | 1145 // all with the same target. |
| 1127 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( | 1146 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( |
| 1128 InstanceGetterNode* node, const Function& target) { | 1147 InstanceGetterNode* node, const Function& target) { |
| 1129 const ZoneGrowableArray<const Class*>* classes = | 1148 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 1130 node->CollectedClassesAtId(node->id()); | |
| 1131 ASSERT(classes->length() > 0); | 1149 ASSERT(classes->length() > 0); |
| 1132 Label load_field; | 1150 Label load_field; |
| 1133 VisitLoadOne(node->receiver(), EBX); | 1151 VisitLoadOne(node->receiver(), EBX); |
| 1134 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1152 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 1135 if (NodeMayBeSmi(node->receiver())) { | 1153 if (NodeMayBeSmi(node->receiver())) { |
| 1136 __ testl(EBX, Immediate(kSmiTagMask)); | 1154 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1137 __ j(ZERO, deopt_blob->label()); | 1155 __ j(ZERO, deopt_blob->label()); |
| 1138 } | 1156 } |
| 1139 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1157 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1140 const int num_classes = classes->length(); | 1158 const int num_classes = classes->length(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1192 } | 1210 } |
| 1193 return false; | 1211 return false; |
| 1194 } | 1212 } |
| 1195 | 1213 |
| 1196 | 1214 |
| 1197 // TODO(srdjan): Implement for multiple getter targets. | 1215 // TODO(srdjan): Implement for multiple getter targets. |
| 1198 // For every class inline its implicit getter, or call the instance getter. | 1216 // For every class inline its implicit getter, or call the instance getter. |
| 1199 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1217 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| 1200 InstanceGetterNode* node) { | 1218 InstanceGetterNode* node) { |
| 1201 const char* kMessage = "Inline instance getter"; | 1219 const char* kMessage = "Inline instance getter"; |
| 1202 const ZoneGrowableArray<const Class*>* classes = | 1220 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 1203 node->CollectedClassesAtId(node->id()); | |
| 1204 const String& getter_name = | 1221 const String& getter_name = |
| 1205 String::Handle(Field::GetterName(node->field_name())); | 1222 String::Handle(Field::GetterName(node->field_name())); |
| 1206 if (FLAG_trace_optimization) { | 1223 if (FLAG_trace_optimization) { |
| 1207 OS::Print("Getter %s ", getter_name.ToCString()); | 1224 OS::Print("Getter %s ", getter_name.ToCString()); |
| 1208 } | 1225 } |
| 1209 if ((classes == NULL) || classes->is_empty()) { | 1226 if ((classes == NULL) || classes->is_empty()) { |
| 1210 TraceNotOpt(node, kMessage); | 1227 TraceNotOpt(node, kMessage); |
| 1211 CodeGenerator::VisitInstanceGetterNode(node); | 1228 CodeGenerator::VisitInstanceGetterNode(node); |
| 1212 return; | 1229 return; |
| 1213 } | 1230 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1253 | 1270 |
| 1254 // The call to the instance setter implements the assignment to a field. | 1271 // The call to the instance setter implements the assignment to a field. |
| 1255 // The result of the assignment to a field is the value being stored. | 1272 // The result of the assignment to a field is the value being stored. |
| 1256 void OptimizingCodeGenerator::VisitInstanceSetterNode( | 1273 void OptimizingCodeGenerator::VisitInstanceSetterNode( |
| 1257 InstanceSetterNode* node) { | 1274 InstanceSetterNode* node) { |
| 1258 if (FLAG_enable_type_checks) { | 1275 if (FLAG_enable_type_checks) { |
| 1259 CodeGenerator::VisitInstanceSetterNode(node); | 1276 CodeGenerator::VisitInstanceSetterNode(node); |
| 1260 return; | 1277 return; |
| 1261 } | 1278 } |
| 1262 const char* kMessage = "Inline instance setter"; | 1279 const char* kMessage = "Inline instance setter"; |
| 1263 const ZoneGrowableArray<const Class*>* classes = | 1280 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 1264 node->CollectedClassesAtId(node->id()); | |
| 1265 if ((classes == NULL) || classes->is_empty()) { | 1281 if ((classes == NULL) || classes->is_empty()) { |
| 1266 // Type feedback not yet collected. | 1282 // Type feedback not yet collected. |
| 1267 TraceNotOpt(node, kMessage); | 1283 TraceNotOpt(node, kMessage); |
| 1268 CodeGenerator::VisitInstanceSetterNode(node); | 1284 CodeGenerator::VisitInstanceSetterNode(node); |
| 1269 return; | 1285 return; |
| 1270 } | 1286 } |
| 1271 const int num_classes = classes->length(); | 1287 const int num_classes = classes->length(); |
| 1272 bool all_inlineable = true; | 1288 bool all_inlineable = true; |
| 1273 const String& setter_name = | 1289 const String& setter_name = |
| 1274 String::Handle(Field::SetterName(node->field_name())); | 1290 String::Handle(Field::SetterName(node->field_name())); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1474 | 1490 |
| 1475 | 1491 |
| 1476 // Checks if an inlined equality/non-equality operation can be emitted: | 1492 // Checks if an inlined equality/non-equality operation can be emitted: |
| 1477 // - type feedback must exist. | 1493 // - type feedback must exist. |
| 1478 // - no class in type feedback list overrides '=='. | 1494 // - no class in type feedback list overrides '=='. |
| 1479 // - no Smi class in type feedback class list. | 1495 // - no Smi class in type feedback class list. |
| 1480 bool OptimizingCodeGenerator::GenerateEqualityComparison(ComparisonNode* node) { | 1496 bool OptimizingCodeGenerator::GenerateEqualityComparison(ComparisonNode* node) { |
| 1481 ASSERT((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)); | 1497 ASSERT((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)); |
| 1482 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1498 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1483 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1499 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1484 const ZoneGrowableArray<const Class*>* classes = | 1500 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 1485 node->CollectedClassesAtId(node->id()); | |
| 1486 if (classes == NULL) { | 1501 if (classes == NULL) { |
| 1487 return false; | 1502 return false; |
| 1488 } | 1503 } |
| 1489 const int num_classes = classes->length(); | 1504 const int num_classes = classes->length(); |
| 1490 // 'num_classes' can be 0 if the receiver was always null. | 1505 // 'num_classes' can be 0 if the receiver was always null. |
| 1491 const String& operator_name = String::Handle(String::NewSymbol("==")); | 1506 const String& operator_name = String::Handle(String::NewSymbol("==")); |
| 1492 // Check that all classes resolve to Object.==. Object.!= is not overridable | 1507 // Check that all classes resolve to Object.==. Object.!= is not overridable |
| 1493 // and is based on Object.==. | 1508 // and is based on Object.==. |
| 1494 ObjectStore* object_store = Isolate::Current()->object_store(); | 1509 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1495 Function& function = Function::Handle(); | 1510 Function& function = Function::Handle(); |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1957 __ addl(ESP, Immediate(arg_count * kWordSize)); | 1972 __ addl(ESP, Immediate(arg_count * kWordSize)); |
| 1958 } | 1973 } |
| 1959 | 1974 |
| 1960 | 1975 |
| 1961 // Using collected type feedback, inline class checks and call the targets | 1976 // Using collected type feedback, inline class checks and call the targets |
| 1962 // directly instead of via inline cache stub. TODO(srdjan): Use type propagation | 1977 // directly instead of via inline cache stub. TODO(srdjan): Use type propagation |
| 1963 // and CHA to eliminate checks. | 1978 // and CHA to eliminate checks. |
| 1964 // Return false if no code was generated (because no type feedback was found). | 1979 // Return false if no code was generated (because no type feedback was found). |
| 1965 bool OptimizingCodeGenerator::GenerateCheckedInstanceCalls( | 1980 bool OptimizingCodeGenerator::GenerateCheckedInstanceCalls( |
| 1966 InstanceCallNode* node) { | 1981 InstanceCallNode* node) { |
| 1967 const ZoneGrowableArray<const Class*>* classes = | 1982 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 1968 node->CollectedClassesAtId(node->id()); | |
| 1969 if ((classes == NULL) || classes->is_empty()) { | 1983 if ((classes == NULL) || classes->is_empty()) { |
| 1970 return false; | 1984 return false; |
| 1971 } | 1985 } |
| 1972 | 1986 |
| 1973 const int arg_count = node->arguments()->length() + 1; // With receiver. | 1987 const int arg_count = node->arguments()->length() + 1; // With receiver. |
| 1974 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); | 1988 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); |
| 1975 ASSERT(arg_count > 0); | 1989 ASSERT(arg_count > 0); |
| 1976 __ movl(EAX, Address(ESP, (arg_count - 1) * kWordSize)); // Load receiver. | 1990 __ movl(EAX, Address(ESP, (arg_count - 1) * kWordSize)); // Load receiver. |
| 1977 | 1991 |
| 1978 Label done; | 1992 Label done; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2049 // Result is in EAX. | 2063 // Result is in EAX. |
| 2050 if (IsResultNeeded(node)) { | 2064 if (IsResultNeeded(node)) { |
| 2051 __ pushl(EAX); | 2065 __ pushl(EAX); |
| 2052 } | 2066 } |
| 2053 } | 2067 } |
| 2054 | 2068 |
| 2055 | 2069 |
| 2056 // Returns true if an instance call was replaced with its intrinsic. | 2070 // Returns true if an instance call was replaced with its intrinsic. |
| 2057 // Returns result in EAX. | 2071 // Returns result in EAX. |
| 2058 bool OptimizingCodeGenerator::TryInlineInstanceCall(InstanceCallNode* node) { | 2072 bool OptimizingCodeGenerator::TryInlineInstanceCall(InstanceCallNode* node) { |
| 2059 const ZoneGrowableArray<const Class*>* classes = | 2073 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 2060 node->CollectedClassesAtId(node->id()); | |
| 2061 if ((classes != NULL) && (classes->length() == 1)) { | 2074 if ((classes != NULL) && (classes->length() == 1)) { |
| 2062 const int num_arguments = node->arguments()->length() + 1; | 2075 const int num_arguments = node->arguments()->length() + 1; |
| 2063 const int num_named_arguments = node->arguments()->names().IsNull() ? | 2076 const int num_named_arguments = node->arguments()->names().IsNull() ? |
| 2064 0 : node->arguments()->names().Length(); | 2077 0 : node->arguments()->names().Length(); |
| 2065 const Function& target = Function::ZoneHandle( | 2078 const Function& target = Function::ZoneHandle( |
| 2066 Resolver::ResolveDynamicForReceiverClass(*(*classes)[0], | 2079 Resolver::ResolveDynamicForReceiverClass(*(*classes)[0], |
| 2067 node->function_name(), | 2080 node->function_name(), |
| 2068 num_arguments, | 2081 num_arguments, |
| 2069 num_named_arguments)); | 2082 num_named_arguments)); |
| 2070 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); | 2083 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2147 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2160 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2148 // Result is in EAX. | 2161 // Result is in EAX. |
| 2149 if (IsResultNeeded(node)) { | 2162 if (IsResultNeeded(node)) { |
| 2150 __ pushl(EAX); | 2163 __ pushl(EAX); |
| 2151 } | 2164 } |
| 2152 } | 2165 } |
| 2153 | 2166 |
| 2154 } // namespace dart | 2167 } // namespace dart |
| 2155 | 2168 |
| 2156 #endif // defined TARGET_ARCH_IA32 | 2169 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |