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 |