| 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 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 deopt_reason_id_(deopt_reason_id) {} | 117 deopt_reason_id_(deopt_reason_id) {} |
| 118 | 118 |
| 119 void Push(Register reg) { registers_.Add(reg); } | 119 void Push(Register reg) { registers_.Add(reg); } |
| 120 | 120 |
| 121 void Generate(OptimizingCodeGenerator* codegen) { | 121 void Generate(OptimizingCodeGenerator* codegen) { |
| 122 codegen->assembler()->Bind(&label_); | 122 codegen->assembler()->Bind(&label_); |
| 123 for (int i = 0; i < registers_.length(); i++) { | 123 for (int i = 0; i < registers_.length(); i++) { |
| 124 codegen->assembler()->pushl(registers_[i]); | 124 codegen->assembler()->pushl(registers_[i]); |
| 125 } | 125 } |
| 126 codegen->assembler()->movl(EAX, Immediate(Smi::RawValue(deopt_reason_id_))); | 126 codegen->assembler()->movl(EAX, Immediate(Smi::RawValue(deopt_reason_id_))); |
| 127 codegen->CallDeoptimize(node_->id(), node_->token_index()); | 127 codegen->CallDeoptimize(node_->id(), node_->token_pos()); |
| 128 #if defined(DEBUG) | 128 #if defined(DEBUG) |
| 129 // Check that deoptimization point exists in unoptimized code. | 129 // Check that deoptimization point exists in unoptimized code. |
| 130 const Code& unoptimized_code = | 130 const Code& unoptimized_code = |
| 131 Code::Handle(codegen->parsed_function().function().unoptimized_code()); | 131 Code::Handle(codegen->parsed_function().function().unoptimized_code()); |
| 132 ASSERT(!unoptimized_code.IsNull()); | 132 ASSERT(!unoptimized_code.IsNull()); |
| 133 uword continue_at_pc = | 133 uword continue_at_pc = |
| 134 unoptimized_code.GetDeoptPcAtNodeId(node_->id()); | 134 unoptimized_code.GetDeoptPcAtNodeId(node_->id()); |
| 135 ASSERT(continue_at_pc != 0); | 135 ASSERT(continue_at_pc != 0); |
| 136 #endif // DEBUG | 136 #endif // DEBUG |
| 137 } | 137 } |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 // Debugging helper function. TODO(srdjan): Remove | 339 // Debugging helper function. TODO(srdjan): Remove |
| 340 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { | 340 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { |
| 341 const ICData& ic_data = node->ic_data(); | 341 const ICData& ic_data = node->ic_data(); |
| 342 OS::Print("Collected classes id %d num: %d\n", | 342 OS::Print("Collected classes id %d num: %d\n", |
| 343 node->id(), ic_data.NumberOfChecks()); | 343 node->id(), ic_data.NumberOfChecks()); |
| 344 } | 344 } |
| 345 | 345 |
| 346 | 346 |
| 347 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { | 347 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { |
| 348 if (FLAG_trace_optimization) { | 348 if (FLAG_trace_optimization) { |
| 349 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message); | 349 OS::Print("Opt node ix: %d; %s\n", node->token_pos(), message); |
| 350 } | 350 } |
| 351 } | 351 } |
| 352 | 352 |
| 353 | 353 |
| 354 void OptimizingCodeGenerator::TraceNotOpt(AstNode* node, const char* message) { | 354 void OptimizingCodeGenerator::TraceNotOpt(AstNode* node, const char* message) { |
| 355 if (FLAG_trace_optimization) { | 355 if (FLAG_trace_optimization) { |
| 356 OS::Print("NOTOpt node ix: %d; %s: ", node->token_index(), message); | 356 OS::Print("NOTOpt node ix: %d; %s: ", node->token_pos(), message); |
| 357 AstPrinter::PrintNode(node); | 357 AstPrinter::PrintNode(node); |
| 358 OS::Print("\n"); | 358 OS::Print("\n"); |
| 359 } | 359 } |
| 360 } | 360 } |
| 361 | 361 |
| 362 | 362 |
| 363 void OptimizingCodeGenerator::CallDeoptimize(intptr_t node_id, | 363 void OptimizingCodeGenerator::CallDeoptimize(intptr_t node_id, |
| 364 intptr_t token_index) { | 364 intptr_t token_pos) { |
| 365 __ call(&StubCode::DeoptimizeLabel()); | 365 __ call(&StubCode::DeoptimizeLabel()); |
| 366 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index); | 366 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_pos); |
| 367 #if defined(DEBUG) | 367 #if defined(DEBUG) |
| 368 __ int3(); | 368 __ int3(); |
| 369 #endif | 369 #endif |
| 370 } | 370 } |
| 371 | 371 |
| 372 | 372 |
| 373 // Quick loads do not clobber registers. | 373 // Quick loads do not clobber registers. |
| 374 static bool IsQuickLoad(AstNode* node) { | 374 static bool IsQuickLoad(AstNode* node) { |
| 375 if (node->IsLoadLocalNode() && (!node->AsLoadLocalNode()->HasPseudo())) { | 375 if (node->IsLoadLocalNode() && (!node->AsLoadLocalNode()->HasPseudo())) { |
| 376 return true; | 376 return true; |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. | 665 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. |
| 666 __ shll(EAX, imm); // Shift for result now we know there is no overflow. | 666 __ shll(EAX, imm); // Shift for result now we know there is no overflow. |
| 667 __ jmp(&done); | 667 __ jmp(&done); |
| 668 __ Bind(&slow_case); | 668 __ Bind(&slow_case); |
| 669 __ pushl(EAX); | 669 __ pushl(EAX); |
| 670 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); | 670 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); |
| 671 const int number_of_arguments = 2; | 671 const int number_of_arguments = 2; |
| 672 const Array& no_optional_argument_names = Array::Handle(); | 672 const Array& no_optional_argument_names = Array::Handle(); |
| 673 GenerateCheckedInstanceCalls(node, | 673 GenerateCheckedInstanceCalls(node, |
| 674 node->left(), | 674 node->left(), |
| 675 node->token_index(), | 675 node->token_pos(), |
| 676 number_of_arguments, | 676 number_of_arguments, |
| 677 no_optional_argument_names); | 677 no_optional_argument_names); |
| 678 __ Bind(&done); | 678 __ Bind(&done); |
| 679 return; | 679 return; |
| 680 } | 680 } |
| 681 } | 681 } |
| 682 | 682 |
| 683 Label slow_case, done; | 683 Label slow_case, done; |
| 684 CodeGenInfo left_info(node->left()); | 684 CodeGenInfo left_info(node->left()); |
| 685 CodeGenInfo right_info(node->right()); | 685 CodeGenInfo right_info(node->right()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 709 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. | 709 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. |
| 710 // EAX is the correctly tagged Smi. | 710 // EAX is the correctly tagged Smi. |
| 711 __ jmp(&done); | 711 __ jmp(&done); |
| 712 __ Bind(&slow_case); | 712 __ Bind(&slow_case); |
| 713 __ pushl(EAX); | 713 __ pushl(EAX); |
| 714 __ pushl(EDX); | 714 __ pushl(EDX); |
| 715 const int number_of_arguments = 2; | 715 const int number_of_arguments = 2; |
| 716 const Array& no_optional_argument_names = Array::Handle(); | 716 const Array& no_optional_argument_names = Array::Handle(); |
| 717 GenerateCheckedInstanceCalls(node, | 717 GenerateCheckedInstanceCalls(node, |
| 718 node->left(), | 718 node->left(), |
| 719 node->token_index(), | 719 node->token_pos(), |
| 720 number_of_arguments, | 720 number_of_arguments, |
| 721 no_optional_argument_names); | 721 no_optional_argument_names); |
| 722 __ Bind(&done); | 722 __ Bind(&done); |
| 723 } | 723 } |
| 724 | 724 |
| 725 | 725 |
| 726 // Implement Token::kSUB and Token::kBIT_NOT. | 726 // Implement Token::kSUB and Token::kBIT_NOT. |
| 727 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { | 727 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { |
| 728 const ICData& ic_data = node->ic_data(); | 728 const ICData& ic_data = node->ic_data(); |
| 729 ASSERT(ic_data.num_args_tested() == 1); | 729 ASSERT(ic_data.num_args_tested() == 1); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 deopt_blob->label()); | 782 deopt_blob->label()); |
| 783 PropagateBackLocalClass(node->operand(), double_class_); | 783 PropagateBackLocalClass(node->operand(), double_class_); |
| 784 } | 784 } |
| 785 const bool using_temp = | 785 const bool using_temp = |
| 786 (node->info() != NULL) && node->info()->allow_temp(); | 786 (node->info() != NULL) && node->info()->allow_temp(); |
| 787 if (!using_temp) { | 787 if (!using_temp) { |
| 788 const Code& stub = | 788 const Code& stub = |
| 789 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 789 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 790 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 790 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 791 __ pushl(kOperandRegister); | 791 __ pushl(kOperandRegister); |
| 792 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); | 792 GenerateCall(node->token_pos(), &label, PcDescriptors::kOther); |
| 793 ASSERT(kResultRegister == EAX); | 793 ASSERT(kResultRegister == EAX); |
| 794 __ popl(kOperandRegister); | 794 __ popl(kOperandRegister); |
| 795 } else if (info.is_temp()) { | 795 } else if (info.is_temp()) { |
| 796 __ movl(kResultRegister, kOperandRegister); | 796 __ movl(kResultRegister, kOperandRegister); |
| 797 } else { | 797 } else { |
| 798 const Double& double_object = | 798 const Double& double_object = |
| 799 Double::ZoneHandle(Double::New(0.0, Heap::kOld)); | 799 Double::ZoneHandle(Double::New(0.0, Heap::kOld)); |
| 800 __ LoadObject(kResultRegister, double_object); | 800 __ LoadObject(kResultRegister, double_object); |
| 801 } | 801 } |
| 802 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); | 802 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 928 UNREACHABLE(); | 928 UNREACHABLE(); |
| 929 } | 929 } |
| 930 } else if ((kind == Token::kSHL) || (kind == Token::kSHR)) { | 930 } else if ((kind == Token::kSHL) || (kind == Token::kSHR)) { |
| 931 GenerateSmiShiftBinaryOp(node); | 931 GenerateSmiShiftBinaryOp(node); |
| 932 } else { | 932 } else { |
| 933 // Unhandled node kind. | 933 // Unhandled node kind. |
| 934 TraceNotOpt(node, kOptMessage); | 934 TraceNotOpt(node, kOptMessage); |
| 935 node->left()->Visit(this); | 935 node->left()->Visit(this); |
| 936 node->right()->Visit(this); | 936 node->right()->Visit(this); |
| 937 CodeGenerator::GenerateBinaryOperatorCall(node->id(), | 937 CodeGenerator::GenerateBinaryOperatorCall(node->id(), |
| 938 node->token_index(), | 938 node->token_pos(), |
| 939 node->Name()); | 939 node->Name()); |
| 940 } | 940 } |
| 941 __ Bind(&done); | 941 __ Bind(&done); |
| 942 HandleResult(node, EAX); | 942 HandleResult(node, EAX); |
| 943 } | 943 } |
| 944 | 944 |
| 945 | 945 |
| 946 // Supports some mixed Smi/Mint operations. | 946 // Supports some mixed Smi/Mint operations. |
| 947 // For BIT_AND operation with right operand being Smi, we can throw away | 947 // For BIT_AND operation with right operand being Smi, we can throw away |
| 948 // any Mint bits above the Smi range as long as the right operand is positive. | 948 // any Mint bits above the Smi range as long as the right operand is positive. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 976 __ Bind(&is_smi); | 976 __ Bind(&is_smi); |
| 977 __ andl(EAX, EDX); | 977 __ andl(EAX, EDX); |
| 978 __ jmp(&done); | 978 __ jmp(&done); |
| 979 __ Bind(&slow_case); | 979 __ Bind(&slow_case); |
| 980 __ pushl(EAX); | 980 __ pushl(EAX); |
| 981 __ pushl(EDX); | 981 __ pushl(EDX); |
| 982 const int number_of_arguments = 2; | 982 const int number_of_arguments = 2; |
| 983 const Array& no_optional_argument_names = Array::Handle(); | 983 const Array& no_optional_argument_names = Array::Handle(); |
| 984 GenerateCheckedInstanceCalls(node, | 984 GenerateCheckedInstanceCalls(node, |
| 985 node->left(), | 985 node->left(), |
| 986 node->token_index(), | 986 node->token_pos(), |
| 987 number_of_arguments, | 987 number_of_arguments, |
| 988 no_optional_argument_names); | 988 no_optional_argument_names); |
| 989 __ Bind(&done); | 989 __ Bind(&done); |
| 990 HandleResult(node, EAX); | 990 HandleResult(node, EAX); |
| 991 return; | 991 return; |
| 992 } | 992 } |
| 993 if ((kind == Token::kSHL) && allow_smi) { | 993 if ((kind == Token::kSHL) && allow_smi) { |
| 994 GenerateSmiShiftBinaryOp(node); | 994 GenerateSmiShiftBinaryOp(node); |
| 995 HandleResult(node, EAX); | 995 HandleResult(node, EAX); |
| 996 return; | 996 return; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1069 (node->info() != NULL) && node->info()->allow_temp(); | 1069 (node->info() != NULL) && node->info()->allow_temp(); |
| 1070 if (!using_temp) { | 1070 if (!using_temp) { |
| 1071 // Parent node cannot handle a temporary double object, allocate one | 1071 // Parent node cannot handle a temporary double object, allocate one |
| 1072 // each time. | 1072 // each time. |
| 1073 result_register = kAllocatedRegister; | 1073 result_register = kAllocatedRegister; |
| 1074 const Code& stub = | 1074 const Code& stub = |
| 1075 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 1075 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 1076 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 1076 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 1077 __ pushl(kLeftRegister); | 1077 __ pushl(kLeftRegister); |
| 1078 __ pushl(kRightRegister); | 1078 __ pushl(kRightRegister); |
| 1079 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); | 1079 GenerateCall(node->token_pos(), &label, PcDescriptors::kOther); |
| 1080 __ movl(result_register, EAX); | 1080 __ movl(result_register, EAX); |
| 1081 __ popl(kRightRegister); | 1081 __ popl(kRightRegister); |
| 1082 __ popl(kLeftRegister); | 1082 __ popl(kLeftRegister); |
| 1083 } else if (left_info.IsClass(double_class_) && left_info.is_temp()) { | 1083 } else if (left_info.IsClass(double_class_) && left_info.is_temp()) { |
| 1084 result_register = kLeftRegister; | 1084 result_register = kLeftRegister; |
| 1085 } else if (right_info.IsClass(double_class_) && right_info.is_temp()) { | 1085 } else if (right_info.IsClass(double_class_) && right_info.is_temp()) { |
| 1086 result_register = kRightRegister; | 1086 result_register = kRightRegister; |
| 1087 } else { | 1087 } else { |
| 1088 result_register = kAllocatedRegister; | 1088 result_register = kAllocatedRegister; |
| 1089 // Use inlined temporary double object. | 1089 // Use inlined temporary double object. |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 // TODO(srdjan): Implement "+" for Strings. | 1320 // TODO(srdjan): Implement "+" for Strings. |
| 1321 // Type feedback tells this is not a Smi or Double operation. | 1321 // Type feedback tells this is not a Smi or Double operation. |
| 1322 TraceNotOpt(node, | 1322 TraceNotOpt(node, |
| 1323 "BinaryOp: type feedback tells this is not a Smi, Mint or Double op"); | 1323 "BinaryOp: type feedback tells this is not a Smi, Mint or Double op"); |
| 1324 node->left()->Visit(this); | 1324 node->left()->Visit(this); |
| 1325 node->right()->Visit(this); | 1325 node->right()->Visit(this); |
| 1326 const int number_of_arguments = 2; | 1326 const int number_of_arguments = 2; |
| 1327 const Array& no_optional_argument_names = Array::Handle(); | 1327 const Array& no_optional_argument_names = Array::Handle(); |
| 1328 GenerateCheckedInstanceCalls(node, | 1328 GenerateCheckedInstanceCalls(node, |
| 1329 node->left(), | 1329 node->left(), |
| 1330 node->token_index(), | 1330 node->token_pos(), |
| 1331 number_of_arguments, | 1331 number_of_arguments, |
| 1332 no_optional_argument_names); | 1332 no_optional_argument_names); |
| 1333 HandleResult(node, EAX); | 1333 HandleResult(node, EAX); |
| 1334 return; | 1334 return; |
| 1335 } | 1335 } |
| 1336 | 1336 |
| 1337 | 1337 |
| 1338 // Return offset of a field or -1 if field is not found. | 1338 // Return offset of a field or -1 if field is not found. |
| 1339 static intptr_t GetFieldOffset(const Class& field_class, | 1339 static intptr_t GetFieldOffset(const Class& field_class, |
| 1340 const String& field_name) { | 1340 const String& field_name) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1499 receiver, | 1499 receiver, |
| 1500 field_name, | 1500 field_name, |
| 1501 recv_reg); | 1501 recv_reg); |
| 1502 } else { | 1502 } else { |
| 1503 // TODO(srdjan): Inline access. | 1503 // TODO(srdjan): Inline access. |
| 1504 __ pushl(recv_reg); | 1504 __ pushl(recv_reg); |
| 1505 const int kNumberOfArguments = 1; | 1505 const int kNumberOfArguments = 1; |
| 1506 const Array& kNoArgumentNames = Array::Handle(); | 1506 const Array& kNoArgumentNames = Array::Handle(); |
| 1507 GenerateCheckedInstanceCalls(node, | 1507 GenerateCheckedInstanceCalls(node, |
| 1508 receiver, | 1508 receiver, |
| 1509 node->token_index(), | 1509 node->token_pos(), |
| 1510 kNumberOfArguments, | 1510 kNumberOfArguments, |
| 1511 kNoArgumentNames); | 1511 kNoArgumentNames); |
| 1512 } | 1512 } |
| 1513 } | 1513 } |
| 1514 | 1514 |
| 1515 | 1515 |
| 1516 // TODO(srdjan): Implement for multiple getter targets. | 1516 // TODO(srdjan): Implement for multiple getter targets. |
| 1517 // For every class inline its implicit getter, or call the instance getter. | 1517 // For every class inline its implicit getter, or call the instance getter. |
| 1518 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1518 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| 1519 InstanceGetterNode* node) { | 1519 InstanceGetterNode* node) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1538 | 1538 |
| 1539 | 1539 |
| 1540 // Helper struct to pass arguments to 'GenerateInstanceSetter'. | 1540 // Helper struct to pass arguments to 'GenerateInstanceSetter'. |
| 1541 struct InstanceSetterArgs { | 1541 struct InstanceSetterArgs { |
| 1542 const Class* cls; | 1542 const Class* cls; |
| 1543 const Function* target; | 1543 const Function* target; |
| 1544 const String* field_name; | 1544 const String* field_name; |
| 1545 Register recv_reg; | 1545 Register recv_reg; |
| 1546 Register value_reg; | 1546 Register value_reg; |
| 1547 intptr_t id; | 1547 intptr_t id; |
| 1548 intptr_t token_index; | 1548 intptr_t token_pos; |
| 1549 }; | 1549 }; |
| 1550 | 1550 |
| 1551 | 1551 |
| 1552 // Preserves 'args.value_reg'. Either stores instance field directly or | 1552 // Preserves 'args.value_reg'. Either stores instance field directly or |
| 1553 // calls the setter method. | 1553 // calls the setter method. |
| 1554 void OptimizingCodeGenerator::GenerateInstanceSetter( | 1554 void OptimizingCodeGenerator::GenerateInstanceSetter( |
| 1555 const InstanceSetterArgs& args) { | 1555 const InstanceSetterArgs& args) { |
| 1556 if (args.target->kind() == RawFunction::kImplicitSetter) { | 1556 if (args.target->kind() == RawFunction::kImplicitSetter) { |
| 1557 intptr_t field_offset = GetFieldOffset(*(args.cls), *(args.field_name)); | 1557 intptr_t field_offset = GetFieldOffset(*(args.cls), *(args.field_name)); |
| 1558 ASSERT(field_offset >= 0); | 1558 ASSERT(field_offset >= 0); |
| 1559 __ StoreIntoObject(args.recv_reg, | 1559 __ StoreIntoObject(args.recv_reg, |
| 1560 FieldAddress(args.recv_reg, field_offset), args.value_reg); | 1560 FieldAddress(args.recv_reg, field_offset), args.value_reg); |
| 1561 } else { | 1561 } else { |
| 1562 __ pushl(args.value_reg); | 1562 __ pushl(args.value_reg); |
| 1563 __ pushl(args.recv_reg); | 1563 __ pushl(args.recv_reg); |
| 1564 __ pushl(args.value_reg); | 1564 __ pushl(args.value_reg); |
| 1565 const Array& no_optional_argument_names = Array::Handle(); | 1565 const Array& no_optional_argument_names = Array::Handle(); |
| 1566 GenerateDirectCall(args.id, | 1566 GenerateDirectCall(args.id, |
| 1567 args.token_index, | 1567 args.token_pos, |
| 1568 *(args.target), | 1568 *(args.target), |
| 1569 2, | 1569 2, |
| 1570 no_optional_argument_names); | 1570 no_optional_argument_names); |
| 1571 __ popl(args.value_reg); | 1571 __ popl(args.value_reg); |
| 1572 } | 1572 } |
| 1573 } | 1573 } |
| 1574 | 1574 |
| 1575 | 1575 |
| 1576 // Returns value in 'value_reg', clobbers EBX. | 1576 // Returns value in 'value_reg', clobbers EBX. |
| 1577 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, | 1577 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); | 1609 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); |
| 1610 // Deoptimize if Smi, since they do not have setters. | 1610 // Deoptimize if Smi, since they do not have setters. |
| 1611 if (NodeMayBeSmi(receiver)) { | 1611 if (NodeMayBeSmi(receiver)) { |
| 1612 __ testl(recv_reg, Immediate(kSmiTagMask)); | 1612 __ testl(recv_reg, Immediate(kSmiTagMask)); |
| 1613 __ j(ZERO, deopt_blob->label()); | 1613 __ j(ZERO, deopt_blob->label()); |
| 1614 } | 1614 } |
| 1615 __ LoadClassId(EBX, recv_reg); | 1615 __ LoadClassId(EBX, recv_reg); |
| 1616 // Initialize setter arguments, but leave the class and target fields NULL. | 1616 // Initialize setter arguments, but leave the class and target fields NULL. |
| 1617 InstanceSetterArgs setter_args = | 1617 InstanceSetterArgs setter_args = |
| 1618 {NULL, NULL, &field_name, recv_reg, value_reg, | 1618 {NULL, NULL, &field_name, recv_reg, value_reg, |
| 1619 node->id(), node->token_index()}; | 1619 node->id(), node->token_pos()}; |
| 1620 | 1620 |
| 1621 if (unique_target) { | 1621 if (unique_target) { |
| 1622 Label store_field; | 1622 Label store_field; |
| 1623 for (intptr_t i = 0; i < classes.length(); i++) { | 1623 for (intptr_t i = 0; i < classes.length(); i++) { |
| 1624 __ cmpl(EBX, Immediate(classes[i]->id())); | 1624 __ cmpl(EBX, Immediate(classes[i]->id())); |
| 1625 if (i == (classes.length() - 1)) { | 1625 if (i == (classes.length() - 1)) { |
| 1626 __ j(NOT_EQUAL, deopt_blob->label()); | 1626 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1627 } else { | 1627 } else { |
| 1628 __ j(EQUAL, &store_field); | 1628 __ j(EQUAL, &store_field); |
| 1629 } | 1629 } |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1801 __ jmp(&evaluate_comparison); | 1801 __ jmp(&evaluate_comparison); |
| 1802 | 1802 |
| 1803 __ Bind(&call_operator); | 1803 __ Bind(&call_operator); |
| 1804 // Left is Smi. | 1804 // Left is Smi. |
| 1805 const int kNumberOfArguments = 2; | 1805 const int kNumberOfArguments = 2; |
| 1806 const Array& kNoArgumentNames = Array::Handle(); | 1806 const Array& kNoArgumentNames = Array::Handle(); |
| 1807 __ pushl(EAX); | 1807 __ pushl(EAX); |
| 1808 __ pushl(EDX); | 1808 __ pushl(EDX); |
| 1809 GenerateCheckedInstanceCalls(node, | 1809 GenerateCheckedInstanceCalls(node, |
| 1810 node->left(), | 1810 node->left(), |
| 1811 node->token_index(), | 1811 node->token_pos(), |
| 1812 kNumberOfArguments, | 1812 kNumberOfArguments, |
| 1813 kNoArgumentNames); | 1813 kNoArgumentNames); |
| 1814 __ CompareObject(EAX, bool_true); | 1814 __ CompareObject(EAX, bool_true); |
| 1815 // Fall through to evaluate result. | 1815 // Fall through to evaluate result. |
| 1816 } | 1816 } |
| 1817 __ Bind(&evaluate_comparison); | 1817 __ Bind(&evaluate_comparison); |
| 1818 // Condition is set by a previous comparison operation. | 1818 // Condition is set by a previous comparison operation. |
| 1819 Condition condition = OVERFLOW; // Initialize to something. | 1819 Condition condition = OVERFLOW; // Initialize to something. |
| 1820 bool ok = SupportedTokenKindToSmiCondition(node->kind(), &condition); | 1820 bool ok = SupportedTokenKindToSmiCondition(node->kind(), &condition); |
| 1821 ASSERT(ok); | 1821 ASSERT(ok); |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2095 __ PushObject(bool_true); | 2095 __ PushObject(bool_true); |
| 2096 __ Bind(&done); | 2096 __ Bind(&done); |
| 2097 } | 2097 } |
| 2098 return; | 2098 return; |
| 2099 } | 2099 } |
| 2100 | 2100 |
| 2101 if (Token::IsInstanceofOperator(node->kind())) { | 2101 if (Token::IsInstanceofOperator(node->kind())) { |
| 2102 VisitLoadOne(node->left(), EAX); | 2102 VisitLoadOne(node->left(), EAX); |
| 2103 ASSERT(node->right()->IsTypeNode()); | 2103 ASSERT(node->right()->IsTypeNode()); |
| 2104 GenerateInstanceOf(node->id(), | 2104 GenerateInstanceOf(node->id(), |
| 2105 node->token_index(), | 2105 node->token_pos(), |
| 2106 node->left(), | 2106 node->left(), |
| 2107 node->right()->AsTypeNode()->type(), | 2107 node->right()->AsTypeNode()->type(), |
| 2108 (node->kind() == Token::kISNOT)); | 2108 (node->kind() == Token::kISNOT)); |
| 2109 if (!IsResultNeeded(node)) { | 2109 if (!IsResultNeeded(node)) { |
| 2110 __ popl(EAX); // Pop the result of the instanceof operation. | 2110 __ popl(EAX); // Pop the result of the instanceof operation. |
| 2111 } | 2111 } |
| 2112 return; | 2112 return; |
| 2113 } | 2113 } |
| 2114 | 2114 |
| 2115 if (NodeHasClassAt(node, smi_class_, 0)) { | 2115 if (NodeHasClassAt(node, smi_class_, 0)) { |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2317 // Note that EAX is Smi, i.e, times 2. | 2317 // Note that EAX is Smi, i.e, times 2. |
| 2318 ASSERT(kSmiTagShift == 1); | 2318 ASSERT(kSmiTagShift == 1); |
| 2319 __ StoreIntoObject(EDX, | 2319 __ StoreIntoObject(EDX, |
| 2320 FieldAddress(EDX, EBX, TIMES_2, sizeof(RawArray)), | 2320 FieldAddress(EDX, EBX, TIMES_2, sizeof(RawArray)), |
| 2321 ECX); | 2321 ECX); |
| 2322 HandleResult(node, ECX); | 2322 HandleResult(node, ECX); |
| 2323 return; | 2323 return; |
| 2324 } | 2324 } |
| 2325 node->index_expr()->Visit(this); | 2325 node->index_expr()->Visit(this); |
| 2326 node->value()->Visit(this); | 2326 node->value()->Visit(this); |
| 2327 GenerateStoreIndexed(node->id(), node->token_index(), IsResultNeeded(node)); | 2327 GenerateStoreIndexed(node->id(), node->token_pos(), IsResultNeeded(node)); |
| 2328 } | 2328 } |
| 2329 | 2329 |
| 2330 | 2330 |
| 2331 void OptimizingCodeGenerator::VisitForNode(ForNode* node) { | 2331 void OptimizingCodeGenerator::VisitForNode(ForNode* node) { |
| 2332 if (FLAG_enable_type_checks) { | 2332 if (FLAG_enable_type_checks) { |
| 2333 CodeGenerator::VisitForNode(node); | 2333 CodeGenerator::VisitForNode(node); |
| 2334 return; | 2334 return; |
| 2335 } | 2335 } |
| 2336 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 2336 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 2337 node->initializer()->Visit(this); | 2337 node->initializer()->Visit(this); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2348 if (condition_info.labels_used()) { | 2348 if (condition_info.labels_used()) { |
| 2349 __ Bind(&iterate_label); | 2349 __ Bind(&iterate_label); |
| 2350 } else { | 2350 } else { |
| 2351 __ popl(EAX); | 2351 __ popl(EAX); |
| 2352 __ LoadObject(EDX, bool_true); | 2352 __ LoadObject(EDX, bool_true); |
| 2353 __ cmpl(EAX, EDX); | 2353 __ cmpl(EAX, EDX); |
| 2354 __ j(NOT_EQUAL, label->break_label()); | 2354 __ j(NOT_EQUAL, label->break_label()); |
| 2355 } | 2355 } |
| 2356 } | 2356 } |
| 2357 node->body()->Visit(this); | 2357 node->body()->Visit(this); |
| 2358 HandleBackwardBranch(node->id(), node->token_index()); | 2358 HandleBackwardBranch(node->id(), node->token_pos()); |
| 2359 __ Bind(label->continue_label()); | 2359 __ Bind(label->continue_label()); |
| 2360 node->increment()->Visit(this); | 2360 node->increment()->Visit(this); |
| 2361 __ jmp(&loop); | 2361 __ jmp(&loop); |
| 2362 __ Bind(label->break_label()); | 2362 __ Bind(label->break_label()); |
| 2363 } | 2363 } |
| 2364 | 2364 |
| 2365 | 2365 |
| 2366 void OptimizingCodeGenerator::VisitDoWhileNode(DoWhileNode* node) { | 2366 void OptimizingCodeGenerator::VisitDoWhileNode(DoWhileNode* node) { |
| 2367 if (FLAG_enable_type_checks) { | 2367 if (FLAG_enable_type_checks) { |
| 2368 CodeGenerator::VisitDoWhileNode(node); | 2368 CodeGenerator::VisitDoWhileNode(node); |
| 2369 return; | 2369 return; |
| 2370 } | 2370 } |
| 2371 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 2371 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 2372 SourceLabel* label = node->label(); | 2372 SourceLabel* label = node->label(); |
| 2373 Label loop; | 2373 Label loop; |
| 2374 __ Bind(&loop); | 2374 __ Bind(&loop); |
| 2375 node->body()->Visit(this); | 2375 node->body()->Visit(this); |
| 2376 HandleBackwardBranch(node->id(), node->token_index()); | 2376 HandleBackwardBranch(node->id(), node->token_pos()); |
| 2377 __ Bind(label->continue_label()); | 2377 __ Bind(label->continue_label()); |
| 2378 CodeGenInfo condition_info(node->condition()); | 2378 CodeGenInfo condition_info(node->condition()); |
| 2379 condition_info.set_false_label(label->break_label()); | 2379 condition_info.set_false_label(label->break_label()); |
| 2380 condition_info.set_true_label(&loop); | 2380 condition_info.set_true_label(&loop); |
| 2381 condition_info.set_fallthrough_label(label->break_label()); | 2381 condition_info.set_fallthrough_label(label->break_label()); |
| 2382 node->condition()->Visit(this); | 2382 node->condition()->Visit(this); |
| 2383 if (!condition_info.labels_used()) { | 2383 if (!condition_info.labels_used()) { |
| 2384 __ popl(EAX); | 2384 __ popl(EAX); |
| 2385 __ LoadObject(EDX, bool_true); | 2385 __ LoadObject(EDX, bool_true); |
| 2386 __ cmpl(EAX, EDX); | 2386 __ cmpl(EAX, EDX); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2406 node->condition()->Visit(this); | 2406 node->condition()->Visit(this); |
| 2407 if (condition_info.labels_used()) { | 2407 if (condition_info.labels_used()) { |
| 2408 __ Bind(&iterate_label); | 2408 __ Bind(&iterate_label); |
| 2409 } else { | 2409 } else { |
| 2410 __ popl(EAX); | 2410 __ popl(EAX); |
| 2411 __ LoadObject(EDX, bool_true); | 2411 __ LoadObject(EDX, bool_true); |
| 2412 __ cmpl(EAX, EDX); | 2412 __ cmpl(EAX, EDX); |
| 2413 __ j(NOT_EQUAL, label->break_label()); | 2413 __ j(NOT_EQUAL, label->break_label()); |
| 2414 } | 2414 } |
| 2415 node->body()->Visit(this); | 2415 node->body()->Visit(this); |
| 2416 HandleBackwardBranch(node->id(), node->token_index()); | 2416 HandleBackwardBranch(node->id(), node->token_pos()); |
| 2417 __ jmp(label->continue_label()); | 2417 __ jmp(label->continue_label()); |
| 2418 __ Bind(label->break_label()); | 2418 __ Bind(label->break_label()); |
| 2419 } | 2419 } |
| 2420 | 2420 |
| 2421 | 2421 |
| 2422 void OptimizingCodeGenerator::VisitIfNode(IfNode* node) { | 2422 void OptimizingCodeGenerator::VisitIfNode(IfNode* node) { |
| 2423 if (FLAG_enable_type_checks) { | 2423 if (FLAG_enable_type_checks) { |
| 2424 CodeGenerator::VisitIfNode(node); | 2424 CodeGenerator::VisitIfNode(node); |
| 2425 return; | 2425 return; |
| 2426 } | 2426 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2447 __ Bind(&done); | 2447 __ Bind(&done); |
| 2448 } else { | 2448 } else { |
| 2449 __ Bind(&false_label); | 2449 __ Bind(&false_label); |
| 2450 } | 2450 } |
| 2451 __ Bind(&done); | 2451 __ Bind(&done); |
| 2452 } | 2452 } |
| 2453 | 2453 |
| 2454 | 2454 |
| 2455 void OptimizingCodeGenerator::GenerateDirectCall( | 2455 void OptimizingCodeGenerator::GenerateDirectCall( |
| 2456 intptr_t node_id, | 2456 intptr_t node_id, |
| 2457 intptr_t token_index, | 2457 intptr_t token_pos, |
| 2458 const Function& target, | 2458 const Function& target, |
| 2459 intptr_t arg_count, | 2459 intptr_t arg_count, |
| 2460 const Array& optional_argument_names) { | 2460 const Array& optional_argument_names) { |
| 2461 ASSERT(!target.IsNull()); | 2461 ASSERT(!target.IsNull()); |
| 2462 const Code& code = Code::Handle(target.CurrentCode()); | 2462 const Code& code = Code::Handle(target.CurrentCode()); |
| 2463 ASSERT(!code.IsNull()); | 2463 ASSERT(!code.IsNull()); |
| 2464 ExternalLabel target_label("DirectInstanceCall", code.EntryPoint()); | 2464 ExternalLabel target_label("DirectInstanceCall", code.EntryPoint()); |
| 2465 | 2465 |
| 2466 __ LoadObject(ECX, target); | 2466 __ LoadObject(ECX, target); |
| 2467 __ LoadObject(EDX, ArgumentsDescriptor(arg_count, optional_argument_names)); | 2467 __ LoadObject(EDX, ArgumentsDescriptor(arg_count, optional_argument_names)); |
| 2468 __ call(&target_label); | 2468 __ call(&target_label); |
| 2469 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index); | 2469 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_pos); |
| 2470 __ addl(ESP, Immediate(arg_count * kWordSize)); | 2470 __ addl(ESP, Immediate(arg_count * kWordSize)); |
| 2471 } | 2471 } |
| 2472 | 2472 |
| 2473 | 2473 |
| 2474 // Generate inline cache calls instead of deoptimizing when no type feedback is | 2474 // Generate inline cache calls instead of deoptimizing when no type feedback is |
| 2475 // provided. | 2475 // provided. |
| 2476 // TODO(srdjan): Recompilation framework should recognize active IC calls | 2476 // TODO(srdjan): Recompilation framework should recognize active IC calls |
| 2477 // in optimized code and mark them for reoptimization since type feedback was | 2477 // in optimized code and mark them for reoptimization since type feedback was |
| 2478 // collected in the meantime. | 2478 // collected in the meantime. |
| 2479 void OptimizingCodeGenerator::GenerateInlineCacheCall( | 2479 void OptimizingCodeGenerator::GenerateInlineCacheCall( |
| 2480 intptr_t node_id, | 2480 intptr_t node_id, |
| 2481 intptr_t token_index, | 2481 intptr_t token_pos, |
| 2482 const ICData& ic_data, | 2482 const ICData& ic_data, |
| 2483 intptr_t num_args, | 2483 intptr_t num_args, |
| 2484 const Array& optional_arguments_names) { | 2484 const Array& optional_arguments_names) { |
| 2485 __ LoadObject(ECX, ic_data); | 2485 __ LoadObject(ECX, ic_data); |
| 2486 __ LoadObject(EDX, ArgumentsDescriptor(num_args, optional_arguments_names)); | 2486 __ LoadObject(EDX, ArgumentsDescriptor(num_args, optional_arguments_names)); |
| 2487 | 2487 |
| 2488 uword label_address = 0; | 2488 uword label_address = 0; |
| 2489 switch (ic_data.num_args_tested()) { | 2489 switch (ic_data.num_args_tested()) { |
| 2490 case 1: | 2490 case 1: |
| 2491 label_address = StubCode::OneArgCheckInlineCacheEntryPoint(); | 2491 label_address = StubCode::OneArgCheckInlineCacheEntryPoint(); |
| 2492 break; | 2492 break; |
| 2493 case 2: | 2493 case 2: |
| 2494 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint(); | 2494 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint(); |
| 2495 break; | 2495 break; |
| 2496 default: | 2496 default: |
| 2497 UNIMPLEMENTED(); | 2497 UNIMPLEMENTED(); |
| 2498 } | 2498 } |
| 2499 | 2499 |
| 2500 ExternalLabel target_label("InlineCache", label_address); | 2500 ExternalLabel target_label("InlineCache", label_address); |
| 2501 | 2501 |
| 2502 __ call(&target_label); | 2502 __ call(&target_label); |
| 2503 AddCurrentDescriptor(PcDescriptors::kIcCall, | 2503 AddCurrentDescriptor(PcDescriptors::kIcCall, |
| 2504 node_id, | 2504 node_id, |
| 2505 token_index); | 2505 token_pos); |
| 2506 __ addl(ESP, Immediate(num_args * kWordSize)); | 2506 __ addl(ESP, Immediate(num_args * kWordSize)); |
| 2507 } | 2507 } |
| 2508 | 2508 |
| 2509 | 2509 |
| 2510 // Normalizes the ic_data class/target pairs: | 2510 // Normalizes the ic_data class/target pairs: |
| 2511 // - If Smi class exists, make it the first one. | 2511 // - If Smi class exists, make it the first one. |
| 2512 // - If 'null_target' not null, append null-class/'null_target' | 2512 // - If 'null_target' not null, append null-class/'null_target' |
| 2513 void OptimizingCodeGenerator::NormalizeClassChecks( | 2513 void OptimizingCodeGenerator::NormalizeClassChecks( |
| 2514 const ICData& ic_data, | 2514 const ICData& ic_data, |
| 2515 const Function& null_target, | 2515 const Function& null_target, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2551 targets->Add(&null_target); | 2551 targets->Add(&null_target); |
| 2552 } | 2552 } |
| 2553 } | 2553 } |
| 2554 | 2554 |
| 2555 | 2555 |
| 2556 // Use IC data in 'node' to issues checks and calls. | 2556 // Use IC data in 'node' to issues checks and calls. |
| 2557 // IC data can contain one or more argument checks. | 2557 // IC data can contain one or more argument checks. |
| 2558 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( | 2558 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( |
| 2559 AstNode* node, | 2559 AstNode* node, |
| 2560 AstNode* receiver, | 2560 AstNode* receiver, |
| 2561 intptr_t token_index, | 2561 intptr_t token_pos, |
| 2562 intptr_t num_args, | 2562 intptr_t num_args, |
| 2563 const Array& optional_arguments_names) { | 2563 const Array& optional_arguments_names) { |
| 2564 ASSERT(node != NULL); | 2564 ASSERT(node != NULL); |
| 2565 ASSERT(receiver != NULL); | 2565 ASSERT(receiver != NULL); |
| 2566 ASSERT(num_args > 0); | 2566 ASSERT(num_args > 0); |
| 2567 const ICData& ic_data = node->ic_data(); | 2567 const ICData& ic_data = node->ic_data(); |
| 2568 if (ic_data.NumberOfChecks() == 0) { | 2568 if (ic_data.NumberOfChecks() == 0) { |
| 2569 // No type feedback means node was never executed. However that can be | 2569 // No type feedback means node was never executed. However that can be |
| 2570 // a common case especially in case of large switch statements. | 2570 // a common case especially in case of large switch statements. |
| 2571 // Use a special inline cache call which can help us decide when to | 2571 // Use a special inline cache call which can help us decide when to |
| 2572 // re-optimize this optiumized function. | 2572 // re-optimize this optiumized function. |
| 2573 GenerateInlineCacheCall( | 2573 GenerateInlineCacheCall( |
| 2574 node->id(), token_index, ic_data, num_args, optional_arguments_names); | 2574 node->id(), token_pos, ic_data, num_args, optional_arguments_names); |
| 2575 return; | 2575 return; |
| 2576 } | 2576 } |
| 2577 | 2577 |
| 2578 Function& target_for_null = Function::ZoneHandle(); | 2578 Function& target_for_null = Function::ZoneHandle(); |
| 2579 ObjectStore* object_store = Isolate::Current()->object_store(); | 2579 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2580 int num_optional_args = | 2580 int num_optional_args = |
| 2581 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); | 2581 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); |
| 2582 target_for_null = Resolver::ResolveDynamicForReceiverClass( | 2582 target_for_null = Resolver::ResolveDynamicForReceiverClass( |
| 2583 Class::Handle(object_store->object_class()), | 2583 Class::Handle(object_store->object_class()), |
| 2584 String::Handle(ic_data.target_name()), | 2584 String::Handle(ic_data.target_name()), |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2597 if (classes[0]->raw() == smi_class_.raw()) { | 2597 if (classes[0]->raw() == smi_class_.raw()) { |
| 2598 start_ix++; | 2598 start_ix++; |
| 2599 // Smi test is needed. | 2599 // Smi test is needed. |
| 2600 __ testl(EAX, Immediate(kSmiTagMask)); | 2600 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2601 if (classes.length() == 1) { | 2601 if (classes.length() == 1) { |
| 2602 // Only Smi test. | 2602 // Only Smi test. |
| 2603 DeoptimizationBlob* deopt_blob = | 2603 DeoptimizationBlob* deopt_blob = |
| 2604 AddDeoptimizationBlob(node, kDeoptPolymorphicInstanceCallSmiOnly); | 2604 AddDeoptimizationBlob(node, kDeoptPolymorphicInstanceCallSmiOnly); |
| 2605 __ j(NOT_ZERO, deopt_blob->label()); | 2605 __ j(NOT_ZERO, deopt_blob->label()); |
| 2606 GenerateDirectCall(node->id(), | 2606 GenerateDirectCall(node->id(), |
| 2607 token_index, | 2607 token_pos, |
| 2608 *targets[0], | 2608 *targets[0], |
| 2609 num_args, | 2609 num_args, |
| 2610 optional_arguments_names); | 2610 optional_arguments_names); |
| 2611 return; | 2611 return; |
| 2612 } | 2612 } |
| 2613 Label not_smi; | 2613 Label not_smi; |
| 2614 __ j(NOT_ZERO, ¬_smi); | 2614 __ j(NOT_ZERO, ¬_smi); |
| 2615 GenerateDirectCall(node->id(), | 2615 GenerateDirectCall(node->id(), |
| 2616 token_index, | 2616 token_pos, |
| 2617 *targets[0], | 2617 *targets[0], |
| 2618 num_args, | 2618 num_args, |
| 2619 optional_arguments_names); | 2619 optional_arguments_names); |
| 2620 __ jmp(&done); | 2620 __ jmp(&done); |
| 2621 __ Bind(¬_smi); // Continue with other test below. | 2621 __ Bind(¬_smi); // Continue with other test below. |
| 2622 } else if (NodeMayBeSmi(receiver)) { | 2622 } else if (NodeMayBeSmi(receiver)) { |
| 2623 DeoptimizationBlob* deopt_blob = | 2623 DeoptimizationBlob* deopt_blob = |
| 2624 AddDeoptimizationBlob(node, kDeoptPolymorphicInstanceCallSmiFail); | 2624 AddDeoptimizationBlob(node, kDeoptPolymorphicInstanceCallSmiFail); |
| 2625 __ testl(EAX, Immediate(kSmiTagMask)); | 2625 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2626 __ j(ZERO, deopt_blob->label()); | 2626 __ j(ZERO, deopt_blob->label()); |
| 2627 } else { | 2627 } else { |
| 2628 // Receiver cannot be Smi, no need to test it. | 2628 // Receiver cannot be Smi, no need to test it. |
| 2629 } | 2629 } |
| 2630 __ LoadClassId(EAX, EAX); // Receiver's class id. | 2630 __ LoadClassId(EAX, EAX); // Receiver's class id. |
| 2631 for (intptr_t i = start_ix; i < classes.length(); i++) { | 2631 for (intptr_t i = start_ix; i < classes.length(); i++) { |
| 2632 const Class& cls = *classes[i]; | 2632 const Class& cls = *classes[i]; |
| 2633 const Function& target = *targets[i]; | 2633 const Function& target = *targets[i]; |
| 2634 __ cmpl(EAX, Immediate(cls.id())); | 2634 __ cmpl(EAX, Immediate(cls.id())); |
| 2635 if (i == (classes.length() - 1)) { | 2635 if (i == (classes.length() - 1)) { |
| 2636 // Last check. | 2636 // Last check. |
| 2637 DeoptimizationBlob* deopt_blob = | 2637 DeoptimizationBlob* deopt_blob = |
| 2638 AddDeoptimizationBlob(node, kDeoptPolymorphicInstanceCallTestFail); | 2638 AddDeoptimizationBlob(node, kDeoptPolymorphicInstanceCallTestFail); |
| 2639 __ j(NOT_EQUAL, deopt_blob->label()); | 2639 __ j(NOT_EQUAL, deopt_blob->label()); |
| 2640 GenerateDirectCall(node->id(), | 2640 GenerateDirectCall(node->id(), |
| 2641 token_index, | 2641 token_pos, |
| 2642 target, | 2642 target, |
| 2643 num_args, | 2643 num_args, |
| 2644 optional_arguments_names); | 2644 optional_arguments_names); |
| 2645 } else { | 2645 } else { |
| 2646 Label next; | 2646 Label next; |
| 2647 __ j(NOT_EQUAL, &next); | 2647 __ j(NOT_EQUAL, &next); |
| 2648 GenerateDirectCall(node->id(), | 2648 GenerateDirectCall(node->id(), |
| 2649 token_index, | 2649 token_pos, |
| 2650 target, | 2650 target, |
| 2651 num_args, | 2651 num_args, |
| 2652 optional_arguments_names); | 2652 optional_arguments_names); |
| 2653 __ jmp(&done); | 2653 __ jmp(&done); |
| 2654 __ Bind(&next); | 2654 __ Bind(&next); |
| 2655 } | 2655 } |
| 2656 } | 2656 } |
| 2657 __ Bind(&done); | 2657 __ Bind(&done); |
| 2658 } | 2658 } |
| 2659 | 2659 |
| 2660 | 2660 |
| 2661 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { | 2661 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { |
| 2662 const int number_of_arguments = node->arguments()->length() + 1; | 2662 const int number_of_arguments = node->arguments()->length() + 1; |
| 2663 // Compute the receiver object and pass it as first argument to call. | 2663 // Compute the receiver object and pass it as first argument to call. |
| 2664 node->receiver()->Visit(this); | 2664 node->receiver()->Visit(this); |
| 2665 // Now compute rest of the arguments to the call. | 2665 // Now compute rest of the arguments to the call. |
| 2666 node->arguments()->Visit(this); | 2666 node->arguments()->Visit(this); |
| 2667 if (TryInlineInstanceCall(node)) { | 2667 if (TryInlineInstanceCall(node)) { |
| 2668 // Instance call is inlined. | 2668 // Instance call is inlined. |
| 2669 } else { | 2669 } else { |
| 2670 GenerateCheckedInstanceCalls(node, | 2670 GenerateCheckedInstanceCalls(node, |
| 2671 node->receiver(), | 2671 node->receiver(), |
| 2672 node->token_index(), | 2672 node->token_pos(), |
| 2673 number_of_arguments, | 2673 number_of_arguments, |
| 2674 node->arguments()->names()); | 2674 node->arguments()->names()); |
| 2675 } | 2675 } |
| 2676 // Result is in EAX. | 2676 // Result is in EAX. |
| 2677 HandleResult(node, EAX); | 2677 HandleResult(node, EAX); |
| 2678 } | 2678 } |
| 2679 | 2679 |
| 2680 | 2680 |
| 2681 // Returns true if an instance call was replaced with its intrinsic. | 2681 // Returns true if an instance call was replaced with its intrinsic. |
| 2682 // Returns result in EAX. | 2682 // Returns result in EAX. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2697 target.ToFullyQualifiedCString(), | 2697 target.ToFullyQualifiedCString(), |
| 2698 Recognizer::KindToCString(recognized)); | 2698 Recognizer::KindToCString(recognized)); |
| 2699 } | 2699 } |
| 2700 if ((recognized == Recognizer::kIntegerToDouble) && | 2700 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2701 NodeHasClassAt(node, smi_class_, 0)) { | 2701 NodeHasClassAt(node, smi_class_, 0)) { |
| 2702 // TODO(srdjan): Check if we could use temporary double instead of | 2702 // TODO(srdjan): Check if we could use temporary double instead of |
| 2703 // allocating a new object every time. | 2703 // allocating a new object every time. |
| 2704 const Code& stub = | 2704 const Code& stub = |
| 2705 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2705 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2706 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2706 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2707 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); | 2707 GenerateCall(node->token_pos(), &label, PcDescriptors::kOther); |
| 2708 // EAX is double object. | 2708 // EAX is double object. |
| 2709 DeoptimizationBlob* deopt_blob = | 2709 DeoptimizationBlob* deopt_blob = |
| 2710 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); | 2710 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); |
| 2711 __ popl(EBX); // Receiver | 2711 __ popl(EBX); // Receiver |
| 2712 __ testl(EBX, Immediate(kSmiTagMask)); | 2712 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2713 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2713 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2714 __ SmiUntag(EBX); | 2714 __ SmiUntag(EBX); |
| 2715 __ cvtsi2sd(XMM0, EBX); | 2715 __ cvtsi2sd(XMM0, EBX); |
| 2716 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2716 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2717 return true; | 2717 return true; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2744 double_class_, | 2744 double_class_, |
| 2745 &call_method, | 2745 &call_method, |
| 2746 EAX); // Result register. | 2746 EAX); // Result register. |
| 2747 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2747 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2748 __ jmp(&done); | 2748 __ jmp(&done); |
| 2749 __ Bind(&smi_to_double); | 2749 __ Bind(&smi_to_double); |
| 2750 __ Bind(&call_method); | 2750 __ Bind(&call_method); |
| 2751 __ LoadObject(ECX, node->function()); | 2751 __ LoadObject(ECX, node->function()); |
| 2752 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), | 2752 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), |
| 2753 node->arguments()->names())); | 2753 node->arguments()->names())); |
| 2754 GenerateCall(node->token_index(), &StubCode::CallStaticFunctionLabel(), | 2754 GenerateCall(node->token_pos(), &StubCode::CallStaticFunctionLabel(), |
| 2755 PcDescriptors::kFuncCall); | 2755 PcDescriptors::kFuncCall); |
| 2756 __ Bind(&done); | 2756 __ Bind(&done); |
| 2757 return true; | 2757 return true; |
| 2758 } | 2758 } |
| 2759 return false; | 2759 return false; |
| 2760 } | 2760 } |
| 2761 | 2761 |
| 2762 | 2762 |
| 2763 void OptimizingCodeGenerator::VisitStaticCallNode(StaticCallNode* node) { | 2763 void OptimizingCodeGenerator::VisitStaticCallNode(StaticCallNode* node) { |
| 2764 node->arguments()->Visit(this); | 2764 node->arguments()->Visit(this); |
| 2765 if (TryInlineStaticCall(node)) { | 2765 if (TryInlineStaticCall(node)) { |
| 2766 // Static method is inlined, result is in EAX. | 2766 // Static method is inlined, result is in EAX. |
| 2767 } else { | 2767 } else { |
| 2768 __ LoadObject(ECX, node->function()); | 2768 __ LoadObject(ECX, node->function()); |
| 2769 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), | 2769 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), |
| 2770 node->arguments()->names())); | 2770 node->arguments()->names())); |
| 2771 GenerateCall(node->token_index(), &StubCode::CallStaticFunctionLabel(), | 2771 GenerateCall(node->token_pos(), &StubCode::CallStaticFunctionLabel(), |
| 2772 PcDescriptors::kFuncCall); | 2772 PcDescriptors::kFuncCall); |
| 2773 } | 2773 } |
| 2774 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2774 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2775 // Result is in EAX. | 2775 // Result is in EAX. |
| 2776 HandleResult(node, EAX); | 2776 HandleResult(node, EAX); |
| 2777 } | 2777 } |
| 2778 | 2778 |
| 2779 | 2779 |
| 2780 void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) { | 2780 void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) { |
| 2781 if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) { | 2781 if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2880 } | 2880 } |
| 2881 } | 2881 } |
| 2882 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 2882 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 2883 CodeGenerator::VisitUnaryOpNode(node); | 2883 CodeGenerator::VisitUnaryOpNode(node); |
| 2884 } | 2884 } |
| 2885 | 2885 |
| 2886 | 2886 |
| 2887 } // namespace dart | 2887 } // namespace dart |
| 2888 | 2888 |
| 2889 #endif // defined TARGET_ARCH_IA32 | 2889 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |