| 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 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 } | 578 } |
| 579 | 579 |
| 580 | 580 |
| 581 void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { | 581 void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
| 582 if (FLAG_enable_type_checks) { | 582 if (FLAG_enable_type_checks) { |
| 583 CodeGenerator::VisitStoreLocalNode(node); | 583 CodeGenerator::VisitStoreLocalNode(node); |
| 584 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); | 584 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
| 585 return; | 585 return; |
| 586 } | 586 } |
| 587 CodeGenInfo value_info(node->value()); | 587 CodeGenInfo value_info(node->value()); |
| 588 value_info.set_allow_temp(true); | 588 value_info.set_allow_temp(false); |
| 589 value_info.set_request_result_in_eax(true); | 589 value_info.set_request_result_in_eax(true); |
| 590 node->value()->Visit(this); | 590 node->value()->Visit(this); |
| 591 if (value_info.is_temp()) { | 591 if (!value_info.result_returned_in_eax()) { |
| 592 if (value_info.IsClass(double_class_)) { | 592 __ popl(EAX); |
| 593 if (value_info.result_returned_in_eax()) { | |
| 594 __ pushl(EAX); | |
| 595 } | |
| 596 const Code& stub = | |
| 597 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | |
| 598 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | |
| 599 GenerateCall(node->token_index(), &label); | |
| 600 // New allocated object is in EAX; copy value from temporary object. | |
| 601 __ popl(EDX); // temporary object from value. | |
| 602 __ movsd(XMM0, FieldAddress(EDX, Double::value_offset())); | |
| 603 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | |
| 604 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); | |
| 605 } else { | |
| 606 UNIMPLEMENTED(); // Cannot handle other temporary types yet. | |
| 607 } | |
| 608 } else { | |
| 609 if (!value_info.result_returned_in_eax()) { | |
| 610 __ popl(EAX); | |
| 611 } | |
| 612 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); | |
| 613 } | 593 } |
| 594 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); |
| 614 HandleResult(node, EAX); | 595 HandleResult(node, EAX); |
| 615 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); | 596 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); |
| 616 } | 597 } |
| 617 | 598 |
| 618 | 599 |
| 619 static bool NodeHasBothReceiverClasses(AstNode* node, | 600 static bool NodeHasBothReceiverClasses(AstNode* node, |
| 620 const Class& cls1, | 601 const Class& cls1, |
| 621 const Class& cls2) { | 602 const Class& cls2) { |
| 622 ASSERT(node != NULL); | 603 ASSERT(node != NULL); |
| 623 ASSERT(!cls1.IsNull() && !cls2.IsNull()); | 604 ASSERT(!cls1.IsNull() && !cls2.IsNull()); |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 void OptimizingCodeGenerator::GenerateDoubleUnaryOp(UnaryOpNode* node) { | 829 void OptimizingCodeGenerator::GenerateDoubleUnaryOp(UnaryOpNode* node) { |
| 849 const Register kOperandRegister = ECX; | 830 const Register kOperandRegister = ECX; |
| 850 const Register kTempRegister = EBX; | 831 const Register kTempRegister = EBX; |
| 851 const Register kResultRegister = EAX; | 832 const Register kResultRegister = EAX; |
| 852 const ICData& ic_data = node->ICDataAtId(node->id()); | 833 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 853 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? | 834 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? |
| 854 kDeoptNoTypeFeedback : kDeoptUnaryOp; | 835 kDeoptNoTypeFeedback : kDeoptUnaryOp; |
| 855 DeoptimizationBlob* deopt_blob = | 836 DeoptimizationBlob* deopt_blob = |
| 856 AddDeoptimizationBlob(node, kOperandRegister, deopt_reason_id); | 837 AddDeoptimizationBlob(node, kOperandRegister, deopt_reason_id); |
| 857 CodeGenInfo info(node->operand()); | 838 CodeGenInfo info(node->operand()); |
| 839 info.set_allow_temp(true); |
| 858 VisitLoadOne(node->operand(), kOperandRegister); | 840 VisitLoadOne(node->operand(), kOperandRegister); |
| 859 if (ic_data.NumberOfChecks() == 0) { | 841 if (ic_data.NumberOfChecks() == 0) { |
| 860 // No type feedback. | 842 // No type feedback. |
| 861 __ jmp(deopt_blob->label()); | 843 __ jmp(deopt_blob->label()); |
| 862 return; | 844 return; |
| 863 } | 845 } |
| 864 ASSERT(ic_data.NumberOfChecks() == 1); | 846 ASSERT(ic_data.NumberOfChecks() == 1); |
| 865 CheckIfDoubleOrSmi(kOperandRegister, | 847 if (!info.IsClass(double_class_)) { |
| 866 kTempRegister, | 848 // Deoptimize if not double. |
| 867 deopt_blob->label(), | 849 CheckIfDoubleOrSmi(kOperandRegister, |
| 868 deopt_blob->label()); | 850 kTempRegister, |
| 869 PropagateBackLocalClass(node->operand(), double_class_); | 851 deopt_blob->label(), |
| 870 // TODO(srdjan): check if we could reuse a temporary object instead of | 852 deopt_blob->label()); |
| 871 // allocating a new one. | 853 PropagateBackLocalClass(node->operand(), double_class_); |
| 872 const Code& stub = | 854 } |
| 873 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 855 const bool using_temp = |
| 874 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 856 (node->info() != NULL) && node->info()->allow_temp(); |
| 875 __ pushl(kOperandRegister); | 857 if (!using_temp) { |
| 876 GenerateCall(node->token_index(), &label); | 858 const Code& stub = |
| 877 ASSERT(kResultRegister == EAX); | 859 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 878 __ popl(kOperandRegister); | 860 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 861 __ pushl(kOperandRegister); |
| 862 GenerateCall(node->token_index(), &label); |
| 863 ASSERT(kResultRegister == EAX); |
| 864 __ popl(kOperandRegister); |
| 865 } else if (info.is_temp()) { |
| 866 __ movl(kResultRegister, kOperandRegister); |
| 867 } else { |
| 868 const Double& double_object = |
| 869 Double::ZoneHandle(Double::New(0.0, Heap::kOld)); |
| 870 __ LoadObject(kResultRegister, double_object); |
| 871 } |
| 879 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); | 872 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); |
| 880 __ xorps(XMM1, XMM1); // 0.0 -> XMM1. | 873 __ xorps(XMM1, XMM1); // 0.0 -> XMM1. |
| 874 ASSERT(node->kind() == Token::kSUB); |
| 881 __ subsd(XMM1, XMM0); | 875 __ subsd(XMM1, XMM0); |
| 882 __ movsd(FieldAddress(kResultRegister, Double::value_offset()), XMM1); | 876 __ movsd(FieldAddress(kResultRegister, Double::value_offset()), XMM1); |
| 883 if (CodeGenerator::IsResultNeeded(node)) { | 877 if (CodeGenerator::IsResultNeeded(node)) { |
| 884 if (node->info() != NULL) { | 878 if (node->info() != NULL) { |
| 885 // TODO(srdjan): Enable once we use a temporary object. | 879 node->info()->set_is_temp(using_temp); |
| 886 // node->info()->set_is_temp(true); | |
| 887 node->info()->set_is_class(&double_class_); | 880 node->info()->set_is_class(&double_class_); |
| 888 } | 881 } |
| 889 HandleResult(node, kResultRegister); | 882 HandleResult(node, kResultRegister); |
| 890 } | 883 } |
| 891 } | 884 } |
| 892 | 885 |
| 893 | 886 |
| 894 // Handles only Smi & Smi. | 887 // Handles only Smi & Smi. |
| 895 // TODO(srdjan): Certain operations always overflow, and thus cause | 888 // TODO(srdjan): Certain operations always overflow, and thus cause |
| 896 // deoptimization. We need to mark those places and handle them. | 889 // deoptimization. We need to mark those places and handle them. |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1084 // - true if both nodes are LoadLocalNodes with the same index. | 1077 // - true if both nodes are LoadLocalNodes with the same index. |
| 1085 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { | 1078 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { |
| 1086 ASSERT((a != NULL) && (b != NULL)); | 1079 ASSERT((a != NULL) && (b != NULL)); |
| 1087 if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { | 1080 if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { |
| 1088 return a->AsLoadLocalNode()->local().Equals(b->AsLoadLocalNode()->local()); | 1081 return a->AsLoadLocalNode()->local().Equals(b->AsLoadLocalNode()->local()); |
| 1089 } | 1082 } |
| 1090 return false; | 1083 return false; |
| 1091 } | 1084 } |
| 1092 | 1085 |
| 1093 | 1086 |
| 1094 // If possible propagate node type back to the local. | 1087 // If possible propagate node type back to the local, therefore next load |
| 1088 // of local can use that class and eliminate type checks. |
| 1095 void OptimizingCodeGenerator::PropagateBackLocalClass(AstNode* node, | 1089 void OptimizingCodeGenerator::PropagateBackLocalClass(AstNode* node, |
| 1096 const Class& cls) { | 1090 const Class& cls) { |
| 1097 if (node->IsLoadLocalNode()) { | 1091 if (node->IsLoadLocalNode()) { |
| 1098 LoadLocalNode* local_node = node->AsLoadLocalNode(); | 1092 LoadLocalNode* local_node = node->AsLoadLocalNode(); |
| 1099 classes_for_locals_->SetLocalType(local_node->local(), cls); | 1093 classes_for_locals_->SetLocalType(local_node->local(), cls); |
| 1100 } | 1094 } |
| 1101 } | 1095 } |
| 1102 | 1096 |
| 1103 | 1097 |
| 1104 // 'reg' is not modified, 'temp' is trashed. | 1098 // 'reg' is not modified, 'temp' is trashed. |
| (...skipping 2025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3130 } | 3124 } |
| 3131 } | 3125 } |
| 3132 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 3126 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 3133 CodeGenerator::VisitUnaryOpNode(node); | 3127 CodeGenerator::VisitUnaryOpNode(node); |
| 3134 } | 3128 } |
| 3135 | 3129 |
| 3136 | 3130 |
| 3137 } // namespace dart | 3131 } // namespace dart |
| 3138 | 3132 |
| 3139 #endif // defined TARGET_ARCH_IA32 | 3133 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |