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

Side by Side Diff: vm/opt_code_generator_ia32.cc

Issue 8919025: Added type propagation from store to load locals, but only within a sequence node (not across bas... (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
« no previous file with comments | « vm/opt_code_generator_ia32.h ('k') | vm/scopes.h » ('j') | 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 18 matching lines...) Expand all
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « vm/opt_code_generator_ia32.h ('k') | vm/scopes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698