| 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 |