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 18 matching lines...) Expand all Loading... |
29 // and a getter of specified type and name. | 29 // and a getter of specified type and name. |
30 // (name, type, default) | 30 // (name, type, default) |
31 #define PROPERTY_LIST(V) \ | 31 #define PROPERTY_LIST(V) \ |
32 V(is_temp, bool, false) \ | 32 V(is_temp, bool, false) \ |
33 V(true_label, Label*, NULL) \ | 33 V(true_label, Label*, NULL) \ |
34 V(false_label, Label*, NULL) \ | 34 V(false_label, Label*, NULL) \ |
35 V(labels_used, bool, false) \ | 35 V(labels_used, bool, false) \ |
36 V(request_result_in_eax, bool, false) \ | 36 V(request_result_in_eax, bool, false) \ |
37 V(result_returned_in_eax, bool, false) \ | 37 V(result_returned_in_eax, bool, false) \ |
38 V(fallthrough_label, Label*, NULL) \ | 38 V(fallthrough_label, Label*, NULL) \ |
39 V(is_class, const Class*, NULL) \ | 39 V(is_class, const Class*, &Class::ZoneHandle()) \ |
40 | 40 |
41 | 41 |
42 // Class holding information being passed from source to destination. | 42 // Class holding information being passed from source to destination. |
43 // Add needed properties in the PROPERTY_LIST above. | 43 // Add needed properties in the PROPERTY_LIST above. |
44 class CodeGenInfo : public ValueObject { | 44 class CodeGenInfo : public ValueObject { |
45 public: | 45 public: |
46 explicit CodeGenInfo(AstNode* node) | 46 explicit CodeGenInfo(AstNode* node) |
47 : node_(node), data_(4) { | 47 : node_(node), data_(4) { |
48 ASSERT(node != NULL); | 48 ASSERT(node != NULL); |
49 ASSERT(node->info() == NULL); | 49 ASSERT(node->info() == NULL); |
50 node->set_info(this); | 50 node->set_info(this); |
51 } | 51 } |
52 | 52 |
53 ~CodeGenInfo() { | 53 ~CodeGenInfo() { |
54 ASSERT(node_->info() == this); | 54 ASSERT(node_->info() == this); |
55 node_->set_info(NULL); | 55 node_->set_info(NULL); |
56 } | 56 } |
57 | 57 |
58 bool IsClass(const Class& cls) const { | 58 bool IsClass(const Class& cls) const { |
59 if (is_class() == NULL) { | |
60 return cls.IsNullClass(); | |
61 } | |
62 return is_class()->raw() == cls.raw(); | 59 return is_class()->raw() == cls.raw(); |
63 } | 60 } |
64 | 61 |
65 #define GETTER(name, type, default) \ | 62 #define GETTER(name, type, default) \ |
66 type name() const { \ | 63 type name() const { \ |
67 Pair* p = Get(k_##name); \ | 64 Pair* p = Get(k_##name); \ |
68 return p == NULL ? default : p->name; \ | 65 return p == NULL ? default : p->name; \ |
69 } | 66 } |
70 PROPERTY_LIST(GETTER) | 67 PROPERTY_LIST(GETTER) |
71 #undef GETTER | 68 #undef GETTER |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 RECOGNIZED_LIST(KIND_TO_STRING) | 197 RECOGNIZED_LIST(KIND_TO_STRING) |
201 #undef KIND_TO_STRING | 198 #undef KIND_TO_STRING |
202 return "?"; | 199 return "?"; |
203 } | 200 } |
204 | 201 |
205 private: | 202 private: |
206 DISALLOW_COPY_AND_ASSIGN(Recognizer); | 203 DISALLOW_COPY_AND_ASSIGN(Recognizer); |
207 }; | 204 }; |
208 | 205 |
209 | 206 |
| 207 // Maintain classes of locals as defined by a store to that local. |
| 208 // A simple initial implementation, memorizes last typed stores. Does not |
| 209 // scale well for large code pieces. This will be replaced by SSA based |
| 210 // type propagation. |
| 211 class ClassesForLocals : public ZoneAllocated { |
| 212 public: |
| 213 ClassesForLocals() : classes_(), locals_() {} |
| 214 void SetLocalType(const LocalVariable& local, const Class& cls) { |
| 215 classes_.Add(&cls); |
| 216 locals_.Add(&local); |
| 217 } |
| 218 // If no type is stored/known, we return a null class in 'cls'. |
| 219 void GetLocalClass(const LocalVariable& local, const Class** cls) const { |
| 220 for (intptr_t i = locals_.length() - 1; i >=0; i--) { |
| 221 if (locals_[i]->Equals(local)) { |
| 222 *cls = classes_[i]; |
| 223 return; |
| 224 } |
| 225 } |
| 226 *cls = &Class::ZoneHandle(); |
| 227 } |
| 228 |
| 229 void Clear() { |
| 230 classes_.Clear(); |
| 231 locals_.Clear(); |
| 232 } |
| 233 |
| 234 private: |
| 235 GrowableArray<const Class*> classes_; |
| 236 GrowableArray<const LocalVariable*> locals_; |
| 237 |
| 238 DISALLOW_COPY_AND_ASSIGN(ClassesForLocals); |
| 239 }; |
| 240 |
| 241 |
210 static const char* kGrowableArrayClassName = "GrowableObjectArray"; | 242 static const char* kGrowableArrayClassName = "GrowableObjectArray"; |
211 static const char* kGrowableArrayLengthFieldName = "_length"; | 243 static const char* kGrowableArrayLengthFieldName = "_length"; |
212 static const char* kGrowableArrayArrayFieldName = "backingArray"; | 244 static const char* kGrowableArrayArrayFieldName = "backingArray"; |
213 | 245 |
214 | 246 |
215 OptimizingCodeGenerator::OptimizingCodeGenerator( | 247 OptimizingCodeGenerator::OptimizingCodeGenerator( |
216 Assembler* assembler, const ParsedFunction& parsed_function) | 248 Assembler* assembler, const ParsedFunction& parsed_function) |
217 : CodeGenerator(assembler, parsed_function), | 249 : CodeGenerator(assembler, parsed_function), |
218 deoptimization_blobs_(4), | 250 deoptimization_blobs_(4), |
| 251 classes_for_locals_(new ClassesForLocals()), |
219 smi_class_(Class::ZoneHandle(Isolate::Current()->object_store() | 252 smi_class_(Class::ZoneHandle(Isolate::Current()->object_store() |
220 ->smi_class())), | 253 ->smi_class())), |
221 double_class_(Class::ZoneHandle(Isolate::Current()->object_store() | 254 double_class_(Class::ZoneHandle(Isolate::Current()->object_store() |
222 ->double_class())) { | 255 ->double_class())) { |
223 ASSERT(parsed_function.function().is_optimizable()); | 256 ASSERT(parsed_function.function().is_optimizable()); |
224 } | 257 } |
225 | 258 |
226 | 259 |
227 DeoptimizationBlob* | 260 DeoptimizationBlob* |
228 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, | 261 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 void OptimizingCodeGenerator::VisitLoadOne(AstNode* node, Register reg) { | 456 void OptimizingCodeGenerator::VisitLoadOne(AstNode* node, Register reg) { |
424 if (!IsQuickLoad(node)) { | 457 if (!IsQuickLoad(node)) { |
425 node->Visit(this); | 458 node->Visit(this); |
426 __ popl(reg); | 459 __ popl(reg); |
427 return; | 460 return; |
428 } | 461 } |
429 if (node->AsLoadLocalNode()) { | 462 if (node->AsLoadLocalNode()) { |
430 LoadLocalNode* local_node = node->AsLoadLocalNode(); | 463 LoadLocalNode* local_node = node->AsLoadLocalNode(); |
431 ASSERT(local_node != NULL); | 464 ASSERT(local_node != NULL); |
432 GenerateLoadVariable(reg, local_node->local()); | 465 GenerateLoadVariable(reg, local_node->local()); |
| 466 if (node->info() != NULL) { |
| 467 const Class* cls = NULL; |
| 468 classes_for_locals_->GetLocalClass(local_node->local(), &cls); |
| 469 if (cls != NULL) { |
| 470 node->info()->set_is_class(cls); |
| 471 } |
| 472 } |
433 return; | 473 return; |
434 } | 474 } |
435 if (node->AsLiteralNode()) { | 475 if (node->AsLiteralNode()) { |
436 LiteralNode* literal_node = node->AsLiteralNode(); | 476 LiteralNode* literal_node = node->AsLiteralNode(); |
437 ASSERT(literal_node != NULL); | 477 ASSERT(literal_node != NULL); |
438 __ LoadObject(reg, literal_node->literal()); | 478 __ LoadObject(reg, literal_node->literal()); |
439 if (node->info() != NULL) { | 479 if (node->info() != NULL) { |
440 const Object& literal = literal_node->literal(); | 480 const Object& literal = literal_node->literal(); |
441 if (literal.IsSmi()) { | 481 if (literal.IsSmi()) { |
442 node->info()->set_is_class(&smi_class_); | 482 node->info()->set_is_class(&smi_class_); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 | 548 |
509 | 549 |
510 void OptimizingCodeGenerator::VisitLoadLocalNode(LoadLocalNode* node) { | 550 void OptimizingCodeGenerator::VisitLoadLocalNode(LoadLocalNode* node) { |
511 if (!IsResultNeeded(node)) return; | 551 if (!IsResultNeeded(node)) return; |
512 if (IsResultInEaxRequested(node)) { | 552 if (IsResultInEaxRequested(node)) { |
513 GenerateLoadVariable(EAX, node->local()); | 553 GenerateLoadVariable(EAX, node->local()); |
514 node->info()->set_result_returned_in_eax(true); | 554 node->info()->set_result_returned_in_eax(true); |
515 } else { | 555 } else { |
516 GeneratePushVariable(node->local(), EAX); | 556 GeneratePushVariable(node->local(), EAX); |
517 } | 557 } |
| 558 if (node->info() != NULL) { |
| 559 const Class* cls = NULL; |
| 560 classes_for_locals_->GetLocalClass(node->local(), &cls); |
| 561 if (cls != NULL) { |
| 562 node->info()->set_is_class(cls); |
| 563 } |
| 564 } |
518 } | 565 } |
519 | 566 |
520 | 567 |
521 void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { | 568 void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
522 if (FLAG_enable_type_checks) { | 569 if (FLAG_enable_type_checks) { |
523 CodeGenerator::VisitStoreLocalNode(node); | 570 CodeGenerator::VisitStoreLocalNode(node); |
| 571 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
524 return; | 572 return; |
525 } | 573 } |
526 CodeGenInfo value_info(node->value()); | 574 CodeGenInfo value_info(node->value()); |
527 value_info.set_request_result_in_eax(true); | 575 value_info.set_request_result_in_eax(true); |
528 node->value()->Visit(this); | 576 node->value()->Visit(this); |
529 if (value_info.is_temp()) { | 577 if (value_info.is_temp()) { |
530 if (value_info.IsClass(double_class_)) { | 578 if (value_info.IsClass(double_class_)) { |
531 if (value_info.result_returned_in_eax()) { | 579 if (value_info.result_returned_in_eax()) { |
532 __ pushl(EAX); | 580 __ pushl(EAX); |
533 } | 581 } |
(...skipping 11 matching lines...) Expand all Loading... |
545 } | 593 } |
546 } else { | 594 } else { |
547 if (!value_info.result_returned_in_eax()) { | 595 if (!value_info.result_returned_in_eax()) { |
548 __ popl(EAX); | 596 __ popl(EAX); |
549 } | 597 } |
550 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); | 598 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); |
551 } | 599 } |
552 if (IsResultNeeded(node)) { | 600 if (IsResultNeeded(node)) { |
553 __ pushl(EAX); | 601 __ pushl(EAX); |
554 } | 602 } |
| 603 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); |
555 } | 604 } |
556 | 605 |
557 | 606 |
558 static bool NodeHasBothReceiverClasses(AstNode* node, | 607 static bool NodeHasBothReceiverClasses(AstNode* node, |
559 const Class& cls1, | 608 const Class& cls1, |
560 const Class& cls2) { | 609 const Class& cls2) { |
561 ASSERT(node != NULL); | 610 ASSERT(node != NULL); |
562 ASSERT(!cls1.IsNull() && !cls2.IsNull()); | 611 ASSERT(!cls1.IsNull() && !cls2.IsNull()); |
563 const ICData& ic_data = node->ICDataAtId(node->id()); | 612 const ICData& ic_data = node->ICDataAtId(node->id()); |
564 bool cls1_found = false; | 613 bool cls1_found = false; |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
886 TraceNotOpt(node, kOptMessage); | 935 TraceNotOpt(node, kOptMessage); |
887 CodeGenerator::VisitBinaryOpNode(node); | 936 CodeGenerator::VisitBinaryOpNode(node); |
888 } | 937 } |
889 | 938 |
890 | 939 |
891 // Conservative approach: | 940 // Conservative approach: |
892 // - true if both nodes are LoadLocalNodes with the same index. | 941 // - true if both nodes are LoadLocalNodes with the same index. |
893 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { | 942 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { |
894 ASSERT((a != NULL) && (b != NULL)); | 943 ASSERT((a != NULL) && (b != NULL)); |
895 if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { | 944 if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { |
896 return a->AsLoadLocalNode()->local().index() == | 945 return a->AsLoadLocalNode()->local().Equals(b->AsLoadLocalNode()->local()); |
897 b->AsLoadLocalNode()->local().index(); | |
898 } | 946 } |
899 return false; | 947 return false; |
900 } | 948 } |
901 | 949 |
902 // 'reg' is not modified, 'temp' is trashed. | 950 // 'reg' is not modified, 'temp' is trashed. |
903 // Fall through if double, jump to 'is_smi' if Smi and | 951 // Fall through if double, jump to 'is_smi' if Smi and |
904 // jump to 'not_double_or_smi' if neither double nor Smi. | 952 // jump to 'not_double_or_smi' if neither double nor Smi. |
905 void OptimizingCodeGenerator::CheckIfDoubleOrSmi(Register reg, | 953 void OptimizingCodeGenerator::CheckIfDoubleOrSmi(Register reg, |
906 Register temp, | 954 Register temp, |
907 Label* is_smi, | 955 Label* is_smi, |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1142 // Type feedback tells this is not a Smi or Double operation. | 1190 // Type feedback tells this is not a Smi or Double operation. |
1143 TraceNotOpt(node, | 1191 TraceNotOpt(node, |
1144 "BinaryOp: type feedback tells this is not a Smi or Double op"); | 1192 "BinaryOp: type feedback tells this is not a Smi or Double op"); |
1145 CodeGenerator::VisitBinaryOpNode(node); | 1193 CodeGenerator::VisitBinaryOpNode(node); |
1146 return; | 1194 return; |
1147 } | 1195 } |
1148 | 1196 |
1149 | 1197 |
1150 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { | 1198 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { |
1151 if (FLAG_enable_type_checks) { | 1199 if (FLAG_enable_type_checks) { |
| 1200 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
1152 CodeGenerator::VisitIncrOpLocalNode(node); | 1201 CodeGenerator::VisitIncrOpLocalNode(node); |
1153 return; | 1202 return; |
1154 } | 1203 } |
1155 const char* kOptMessage = "Inlines IncrOpLocal"; | 1204 const char* kOptMessage = "Inlines IncrOpLocal"; |
1156 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); | 1205 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
1157 if (!AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 1206 if (!AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
| 1207 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
1158 TraceNotOpt(node, kOptMessage); | 1208 TraceNotOpt(node, kOptMessage); |
1159 CodeGenerator::VisitIncrOpLocalNode(node); | 1209 CodeGenerator::VisitIncrOpLocalNode(node); |
1160 return; | 1210 return; |
1161 } | 1211 } |
1162 TraceOpt(node, kOptMessage); | 1212 TraceOpt(node, kOptMessage); |
1163 | 1213 |
1164 GenerateLoadVariable(EAX, node->local()); | 1214 GenerateLoadVariable(EAX, node->local()); |
1165 if (!node->prefix() && IsResultNeeded(node)) { | 1215 if (!node->prefix() && IsResultNeeded(node)) { |
1166 // Preserve as result. | 1216 // Preserve as result. |
1167 __ movl(ECX, EAX); | 1217 __ movl(ECX, EAX); |
(...skipping 10 matching lines...) Expand all Loading... |
1178 if (IsResultNeeded(node)) { | 1228 if (IsResultNeeded(node)) { |
1179 if (node->info() != NULL) { | 1229 if (node->info() != NULL) { |
1180 node->info()->set_is_class(&smi_class_); | 1230 node->info()->set_is_class(&smi_class_); |
1181 } | 1231 } |
1182 if (node->prefix()) { | 1232 if (node->prefix()) { |
1183 __ pushl(EAX); | 1233 __ pushl(EAX); |
1184 } else { | 1234 } else { |
1185 __ pushl(ECX); | 1235 __ pushl(ECX); |
1186 } | 1236 } |
1187 } | 1237 } |
| 1238 classes_for_locals_->SetLocalType(node->local(), smi_class_); |
1188 } | 1239 } |
1189 | 1240 |
1190 | 1241 |
1191 // Debugging helper method, used in assert only. | 1242 // Debugging helper method, used in assert only. |
1192 static bool HaveSameClassesInICData(const ICData& a, const ICData& b) { | 1243 static bool HaveSameClassesInICData(const ICData& a, const ICData& b) { |
1193 if (a.NumberOfChecks() != b.NumberOfChecks()) { | 1244 if (a.NumberOfChecks() != b.NumberOfChecks()) { |
1194 return false; | 1245 return false; |
1195 } | 1246 } |
1196 if (a.NumberOfChecks() == 0) { | 1247 if (a.NumberOfChecks() == 0) { |
1197 return true; | 1248 return true; |
(...skipping 1418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2616 return; | 2667 return; |
2617 } | 2668 } |
2618 ASSERT(!IsResultNeeded(node)); | 2669 ASSERT(!IsResultNeeded(node)); |
2619 ASSERT(node->value() != NULL); | 2670 ASSERT(node->value() != NULL); |
2620 VisitLoadOne(node->value(), EAX); | 2671 VisitLoadOne(node->value(), EAX); |
2621 GenerateReturnEpilog(); | 2672 GenerateReturnEpilog(); |
2622 } | 2673 } |
2623 | 2674 |
2624 | 2675 |
2625 void OptimizingCodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) { | 2676 void OptimizingCodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) { |
| 2677 // TODO(srdjan): Allow limited forwarding of types across sequence nodes. |
| 2678 classes_for_locals_->Clear(); |
2626 const intptr_t num_context_variables = (node_sequence->scope() != NULL) ? | 2679 const intptr_t num_context_variables = (node_sequence->scope() != NULL) ? |
2627 node_sequence->scope()->num_context_variables() : 0; | 2680 node_sequence->scope()->num_context_variables() : 0; |
2628 if (FLAG_enable_type_checks || (num_context_variables > 0)) { | 2681 if (FLAG_enable_type_checks || (num_context_variables > 0)) { |
2629 CodeGenerator::VisitSequenceNode(node_sequence); | 2682 CodeGenerator::VisitSequenceNode(node_sequence); |
2630 return; | 2683 return; |
2631 } | 2684 } |
2632 for (int i = 0; i < node_sequence->length(); i++) { | 2685 for (int i = 0; i < node_sequence->length(); i++) { |
2633 AstNode* child_node = node_sequence->NodeAt(i); | 2686 AstNode* child_node = node_sequence->NodeAt(i); |
2634 state()->set_root_node(child_node); | 2687 state()->set_root_node(child_node); |
2635 child_node->Visit(this); | 2688 child_node->Visit(this); |
2636 } | 2689 } |
2637 if (node_sequence->label() != NULL) { | 2690 if (node_sequence->label() != NULL) { |
2638 __ Bind(node_sequence->label()->break_label()); | 2691 __ Bind(node_sequence->label()->break_label()); |
2639 } | 2692 } |
| 2693 classes_for_locals_->Clear(); |
2640 } | 2694 } |
2641 | 2695 |
2642 | 2696 |
2643 void OptimizingCodeGenerator::VisitStoreInstanceFieldNode( | 2697 void OptimizingCodeGenerator::VisitStoreInstanceFieldNode( |
2644 StoreInstanceFieldNode* node) { | 2698 StoreInstanceFieldNode* node) { |
2645 if (FLAG_enable_type_checks) { | 2699 if (FLAG_enable_type_checks) { |
2646 CodeGenerator::VisitStoreInstanceFieldNode(node); | 2700 CodeGenerator::VisitStoreInstanceFieldNode(node); |
2647 return; | 2701 return; |
2648 } | 2702 } |
2649 VisitLoadTwo(node->instance(), node->value(), EDX, EAX); | 2703 VisitLoadTwo(node->instance(), node->value(), EDX, EAX); |
2650 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); | 2704 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); |
2651 if (IsResultNeeded(node)) { | 2705 if (IsResultNeeded(node)) { |
2652 // The result is the input value. | 2706 // The result is the input value. |
2653 __ pushl(EAX); | 2707 __ pushl(EAX); |
2654 } | 2708 } |
2655 } | 2709 } |
2656 | 2710 |
2657 | 2711 |
| 2712 void OptimizingCodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { |
| 2713 // TODO(srdjan): Set classes for locals. |
| 2714 classes_for_locals_->Clear(); |
| 2715 CodeGenerator::VisitCatchClauseNode(node); |
| 2716 } |
| 2717 |
| 2718 |
| 2719 void OptimizingCodeGenerator::VisitTryCatchNode(TryCatchNode* node) { |
| 2720 // TODO(srdjan): Set classes for locals. |
| 2721 classes_for_locals_->Clear(); |
| 2722 CodeGenerator::VisitTryCatchNode(node); |
| 2723 } |
| 2724 |
| 2725 |
2658 } // namespace dart | 2726 } // namespace dart |
2659 | 2727 |
2660 #endif // defined TARGET_ARCH_IA32 | 2728 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |