| 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 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 | 313 |
| 314 bool OptimizingCodeGenerator::IsResultInEaxRequested(AstNode* node) const { | 314 bool OptimizingCodeGenerator::IsResultInEaxRequested(AstNode* node) const { |
| 315 return (node->info() != NULL) && node->info()->request_result_in_eax(); | 315 return (node->info() != NULL) && node->info()->request_result_in_eax(); |
| 316 } | 316 } |
| 317 | 317 |
| 318 | 318 |
| 319 static const ZoneGrowableArray<const Class*>* | 319 static const ZoneGrowableArray<const Class*>* |
| 320 CollectedClassesAtNode(AstNode* node) { | 320 CollectedClassesAtNode(AstNode* node) { |
| 321 ZoneGrowableArray<const Class*>* result = | 321 ZoneGrowableArray<const Class*>* result = |
| 322 new ZoneGrowableArray<const Class*>(); | 322 new ZoneGrowableArray<const Class*>(); |
| 323 const ICData& ic_data = node->ICDataAtId(node->id()); | 323 const ICData& ic_data = node->ic_data(); |
| 324 if (ic_data.NumberOfChecks() == 0) { | 324 if (ic_data.NumberOfChecks() == 0) { |
| 325 return result; | 325 return result; |
| 326 } | 326 } |
| 327 ASSERT(ic_data.num_args_tested() == 1); | 327 ASSERT(ic_data.num_args_tested() == 1); |
| 328 Function& target = Function::Handle(); | 328 Function& target = Function::Handle(); |
| 329 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 329 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 330 Class& cls = Class::ZoneHandle(); | 330 Class& cls = Class::ZoneHandle(); |
| 331 ic_data.GetOneClassCheckAt(i, &cls, &target); | 331 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 332 result->Add(&cls); | 332 result->Add(&cls); |
| 333 } | 333 } |
| 334 return result; | 334 return result; |
| 335 } | 335 } |
| 336 | 336 |
| 337 | 337 |
| 338 // Debugging helper function. | 338 // Debugging helper function. |
| 339 void OptimizingCodeGenerator::PrintCollectedClassesAtId(AstNode* node, | 339 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { |
| 340 intptr_t id) { | 340 const ICData& ic_data = node->ic_data(); |
| 341 const ICData& ic_data = node->ICDataAtId(id); | 341 OS::Print("Collected classes id %d num: %d\n", |
| 342 OS::Print("Collected classes id %d num: %d\n", id, ic_data.NumberOfChecks()); | 342 node->id(), ic_data.NumberOfChecks()); |
| 343 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 343 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 344 Function& target = Function::Handle(); | 344 Function& target = Function::Handle(); |
| 345 GrowableArray<const Class*> classes; | 345 GrowableArray<const Class*> classes; |
| 346 ic_data.GetCheckAt(i, &classes, &target); | 346 ic_data.GetCheckAt(i, &classes, &target); |
| 347 OS::Print("["); | 347 OS::Print("["); |
| 348 for (intptr_t c = 0; c < classes.length(); c++) { | 348 for (intptr_t c = 0; c < classes.length(); c++) { |
| 349 OS::Print("%s%s", (c > 0) ? ", " : "", classes[c]->ToCString()); | 349 OS::Print("%s%s", (c > 0) ? ", " : "", classes[c]->ToCString()); |
| 350 } | 350 } |
| 351 OS::Print("] -> %s\n", target.ToFullyQualifiedCString()); | 351 OS::Print("] -> %s\n", target.ToFullyQualifiedCString()); |
| 352 } | 352 } |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 HandleResult(node, EAX); | 544 HandleResult(node, EAX); |
| 545 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); | 545 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); |
| 546 } | 546 } |
| 547 | 547 |
| 548 | 548 |
| 549 static bool NodeHasBothReceiverClasses(AstNode* node, | 549 static bool NodeHasBothReceiverClasses(AstNode* node, |
| 550 const Class& cls1, | 550 const Class& cls1, |
| 551 const Class& cls2) { | 551 const Class& cls2) { |
| 552 ASSERT(node != NULL); | 552 ASSERT(node != NULL); |
| 553 ASSERT(!cls1.IsNull() && !cls2.IsNull()); | 553 ASSERT(!cls1.IsNull() && !cls2.IsNull()); |
| 554 const ICData& ic_data = node->ICDataAtId(node->id()); | 554 const ICData& ic_data = node->ic_data(); |
| 555 bool cls1_found = false; | 555 bool cls1_found = false; |
| 556 bool cls2_found = false; | 556 bool cls2_found = false; |
| 557 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 557 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 558 GrowableArray<const Class*> classes; | 558 GrowableArray<const Class*> classes; |
| 559 Function& target = Function::Handle(); | 559 Function& target = Function::Handle(); |
| 560 ic_data.GetCheckAt(i, &classes, &target); | 560 ic_data.GetCheckAt(i, &classes, &target); |
| 561 if (!classes.is_empty()) { | 561 if (!classes.is_empty()) { |
| 562 if (classes[0]->raw() == cls1.raw()) { | 562 if (classes[0]->raw() == cls1.raw()) { |
| 563 cls1_found = true; | 563 cls1_found = true; |
| 564 } | 564 } |
| 565 if (classes[0]->raw() == cls2.raw()) { | 565 if (classes[0]->raw() == cls2.raw()) { |
| 566 cls2_found = true; | 566 cls2_found = true; |
| 567 } | 567 } |
| 568 if (cls1_found && cls2_found) { | 568 if (cls1_found && cls2_found) { |
| 569 return true; | 569 return true; |
| 570 } | 570 } |
| 571 } | 571 } |
| 572 } | 572 } |
| 573 return false; | 573 return false; |
| 574 } | 574 } |
| 575 | 575 |
| 576 | 576 |
| 577 // Look only at the first class in all check groups. Returns true if all | 577 // Look only at the first class in all check groups. Returns true if all |
| 578 // receiver classes are 'cls'. | 578 // receiver classes are 'cls'. |
| 579 static bool AtIdNodeHasClassAt(AstNode* node, | 579 static bool NodeHasClassAt(AstNode* node, |
| 580 intptr_t id, | 580 const Class& cls, |
| 581 const Class& cls, | 581 intptr_t arg_index) { |
| 582 intptr_t arg_index) { | |
| 583 ASSERT(node != NULL); | 582 ASSERT(node != NULL); |
| 584 ASSERT(!cls.IsNull()); | 583 ASSERT(!cls.IsNull()); |
| 585 const ICData& ic_data = node->ICDataAtId(id); | 584 const ICData& ic_data = node->ic_data(); |
| 586 if (ic_data.NumberOfChecks() == 0) { | 585 if (ic_data.NumberOfChecks() == 0) { |
| 587 return false; | 586 return false; |
| 588 } | 587 } |
| 589 ASSERT(ic_data.num_args_tested() > arg_index); | 588 ASSERT(ic_data.num_args_tested() > arg_index); |
| 590 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 589 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 591 GrowableArray<const Class*> classes; | 590 GrowableArray<const Class*> classes; |
| 592 Function& target = Function::Handle(); | 591 Function& target = Function::Handle(); |
| 593 ic_data.GetCheckAt(i, &classes, &target); | 592 ic_data.GetCheckAt(i, &classes, &target); |
| 594 if (classes.is_empty()) { | 593 if (classes.is_empty()) { |
| 595 return false; | 594 return false; |
| 596 } | 595 } |
| 597 if (classes[arg_index]->raw() != cls.raw()) { | 596 if (classes[arg_index]->raw() != cls.raw()) { |
| 598 return false; | 597 return false; |
| 599 } | 598 } |
| 600 } | 599 } |
| 601 return true; | 600 return true; |
| 602 } | 601 } |
| 603 | 602 |
| 604 | 603 |
| 605 // IC data may have only one check, and it has to contain the two classes in | 604 // IC data may have only one check, and it has to contain the two classes in |
| 606 // specified order. | 605 // specified order. |
| 607 static bool AtIdNodeHasTwoClasses(AstNode* node, | 606 static bool NodeHasTwoClasses(AstNode* node, |
| 608 intptr_t id, | 607 const Class& cls0, |
| 609 const Class& cls0, | 608 const Class& cls1) { |
| 610 const Class& cls1) { | |
| 611 ASSERT(node != NULL); | 609 ASSERT(node != NULL); |
| 612 ASSERT(!cls0.IsNull() && !cls1.IsNull()); | 610 ASSERT(!cls0.IsNull() && !cls1.IsNull()); |
| 613 const ICData& ic_data = node->ICDataAtId(id); | 611 const ICData& ic_data = node->ic_data(); |
| 614 ASSERT(ic_data.num_args_tested() == 2); | 612 ASSERT(ic_data.num_args_tested() == 2); |
| 615 if (ic_data.NumberOfChecks() != 1) { | 613 if (ic_data.NumberOfChecks() != 1) { |
| 616 return false; | 614 return false; |
| 617 } | 615 } |
| 618 Function& target = Function::Handle(); | 616 Function& target = Function::Handle(); |
| 619 GrowableArray<const Class*> classes; | 617 GrowableArray<const Class*> classes; |
| 620 ic_data.GetCheckAt(0, &classes, &target); | 618 ic_data.GetCheckAt(0, &classes, &target); |
| 621 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) { | 619 if ((cls0.raw() == classes[0]->raw()) && (cls1.raw() == classes[1]->raw())) { |
| 622 return true; | 620 return true; |
| 623 } | 621 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. | 680 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. |
| 683 __ shll(EAX, imm); // Shift for result now we know there is no overflow. | 681 __ shll(EAX, imm); // Shift for result now we know there is no overflow. |
| 684 __ jmp(&done); | 682 __ jmp(&done); |
| 685 __ Bind(&slow_case); | 683 __ Bind(&slow_case); |
| 686 __ pushl(EAX); | 684 __ pushl(EAX); |
| 687 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); | 685 __ pushl(Immediate(reinterpret_cast<int32_t>(smi.raw()))); |
| 688 const int number_of_arguments = 2; | 686 const int number_of_arguments = 2; |
| 689 const Array& no_optional_argument_names = Array::Handle(); | 687 const Array& no_optional_argument_names = Array::Handle(); |
| 690 GenerateCheckedInstanceCalls(node, | 688 GenerateCheckedInstanceCalls(node, |
| 691 node->left(), | 689 node->left(), |
| 692 node->id(), | |
| 693 node->token_index(), | 690 node->token_index(), |
| 694 number_of_arguments, | 691 number_of_arguments, |
| 695 no_optional_argument_names); | 692 no_optional_argument_names); |
| 696 __ Bind(&done); | 693 __ Bind(&done); |
| 697 return; | 694 return; |
| 698 } | 695 } |
| 699 } | 696 } |
| 700 | 697 |
| 701 Label slow_case, done; | 698 Label slow_case, done; |
| 702 CodeGenInfo left_info(node->left()); | 699 CodeGenInfo left_info(node->left()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 727 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. | 724 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. |
| 728 // EAX is the correctly tagged Smi. | 725 // EAX is the correctly tagged Smi. |
| 729 __ jmp(&done); | 726 __ jmp(&done); |
| 730 __ Bind(&slow_case); | 727 __ Bind(&slow_case); |
| 731 __ pushl(EAX); | 728 __ pushl(EAX); |
| 732 __ pushl(EDX); | 729 __ pushl(EDX); |
| 733 const int number_of_arguments = 2; | 730 const int number_of_arguments = 2; |
| 734 const Array& no_optional_argument_names = Array::Handle(); | 731 const Array& no_optional_argument_names = Array::Handle(); |
| 735 GenerateCheckedInstanceCalls(node, | 732 GenerateCheckedInstanceCalls(node, |
| 736 node->left(), | 733 node->left(), |
| 737 node->id(), | |
| 738 node->token_index(), | 734 node->token_index(), |
| 739 number_of_arguments, | 735 number_of_arguments, |
| 740 no_optional_argument_names); | 736 no_optional_argument_names); |
| 741 __ Bind(&done); | 737 __ Bind(&done); |
| 742 } | 738 } |
| 743 | 739 |
| 744 | 740 |
| 745 // Implement Token::kSUB and Token::kBIT_NOT. | 741 // Implement Token::kSUB and Token::kBIT_NOT. |
| 746 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { | 742 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { |
| 747 const ICData& ic_data = node->ICDataAtId(node->id()); | 743 const ICData& ic_data = node->ic_data(); |
| 748 ASSERT(ic_data.num_args_tested() == 1); | 744 ASSERT(ic_data.num_args_tested() == 1); |
| 749 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? | 745 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? |
| 750 kDeoptNoTypeFeedback : kDeoptUnaryOp; | 746 kDeoptNoTypeFeedback : kDeoptUnaryOp; |
| 751 DeoptimizationBlob* deopt_blob = | 747 DeoptimizationBlob* deopt_blob = |
| 752 AddDeoptimizationBlob(node, EAX, deopt_reason_id); | 748 AddDeoptimizationBlob(node, EAX, deopt_reason_id); |
| 753 CodeGenInfo info(node->operand()); | 749 CodeGenInfo info(node->operand()); |
| 754 VisitLoadOne(node->operand(), EAX); | 750 VisitLoadOne(node->operand(), EAX); |
| 755 if (ic_data.NumberOfChecks() == 0) { | 751 if (ic_data.NumberOfChecks() == 0) { |
| 756 // No type feedback. | 752 // No type feedback. |
| 757 __ jmp(deopt_blob->label()); | 753 __ jmp(deopt_blob->label()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 772 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 768 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 773 } | 769 } |
| 774 HandleResult(node, EAX); | 770 HandleResult(node, EAX); |
| 775 } | 771 } |
| 776 | 772 |
| 777 | 773 |
| 778 void OptimizingCodeGenerator::GenerateDoubleUnaryOp(UnaryOpNode* node) { | 774 void OptimizingCodeGenerator::GenerateDoubleUnaryOp(UnaryOpNode* node) { |
| 779 const Register kOperandRegister = ECX; | 775 const Register kOperandRegister = ECX; |
| 780 const Register kTempRegister = EBX; | 776 const Register kTempRegister = EBX; |
| 781 const Register kResultRegister = EAX; | 777 const Register kResultRegister = EAX; |
| 782 const ICData& ic_data = node->ICDataAtId(node->id()); | 778 const ICData& ic_data = node->ic_data(); |
| 783 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? | 779 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? |
| 784 kDeoptNoTypeFeedback : kDeoptUnaryOp; | 780 kDeoptNoTypeFeedback : kDeoptUnaryOp; |
| 785 DeoptimizationBlob* deopt_blob = | 781 DeoptimizationBlob* deopt_blob = |
| 786 AddDeoptimizationBlob(node, kOperandRegister, deopt_reason_id); | 782 AddDeoptimizationBlob(node, kOperandRegister, deopt_reason_id); |
| 787 CodeGenInfo info(node->operand()); | 783 CodeGenInfo info(node->operand()); |
| 788 info.set_allow_temp(true); | 784 info.set_allow_temp(true); |
| 789 VisitLoadOne(node->operand(), kOperandRegister); | 785 VisitLoadOne(node->operand(), kOperandRegister); |
| 790 if (ic_data.NumberOfChecks() == 0) { | 786 if (ic_data.NumberOfChecks() == 0) { |
| 791 // No type feedback. | 787 // No type feedback. |
| 792 __ jmp(deopt_blob->label()); | 788 __ jmp(deopt_blob->label()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 const Token::Kind kind = node->kind(); | 837 const Token::Kind kind = node->kind(); |
| 842 if ((kind == Token::kADD) || | 838 if ((kind == Token::kADD) || |
| 843 (kind == Token::kSUB) || | 839 (kind == Token::kSUB) || |
| 844 (kind == Token::kMUL) || | 840 (kind == Token::kMUL) || |
| 845 (kind == Token::kTRUNCDIV) || | 841 (kind == Token::kTRUNCDIV) || |
| 846 (kind == Token::kBIT_AND) || | 842 (kind == Token::kBIT_AND) || |
| 847 (kind == Token::kBIT_OR) || | 843 (kind == Token::kBIT_OR) || |
| 848 (kind == Token::kBIT_XOR)) { | 844 (kind == Token::kBIT_XOR)) { |
| 849 TraceOpt(node, kOptMessage); | 845 TraceOpt(node, kOptMessage); |
| 850 // Check if both arguments are expected to be Smi. | 846 // Check if both arguments are expected to be Smi. |
| 851 const ICData& ic_data = node->ICDataAtId(node->id()); | 847 const ICData& ic_data = node->ic_data(); |
| 852 ASSERT(ic_data.num_args_tested() == 2); | 848 ASSERT(ic_data.num_args_tested() == 2); |
| 853 ASSERT(ic_data.NumberOfChecks() > 0); | 849 ASSERT(ic_data.NumberOfChecks() > 0); |
| 854 Function& target = Function::Handle(); | 850 Function& target = Function::Handle(); |
| 855 GrowableArray<const Class*> classes; | 851 GrowableArray<const Class*> classes; |
| 856 ic_data.GetCheckAt(0, &classes, &target); | 852 ic_data.GetCheckAt(0, &classes, &target); |
| 857 ASSERT(ic_data.NumberOfChecks() == 1); | 853 ASSERT(ic_data.NumberOfChecks() == 1); |
| 858 ASSERT((classes[0]->raw() == smi_class_.raw()) && | 854 ASSERT((classes[0]->raw() == smi_class_.raw()) && |
| 859 (classes[1]->raw() == smi_class_.raw())); | 855 (classes[1]->raw() == smi_class_.raw())); |
| 860 CodeGenInfo left_info(node->left()); | 856 CodeGenInfo left_info(node->left()); |
| 861 CodeGenInfo right_info(node->right()); | 857 CodeGenInfo right_info(node->right()); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 __ Bind(&is_smi); | 994 __ Bind(&is_smi); |
| 999 __ andl(EAX, EDX); | 995 __ andl(EAX, EDX); |
| 1000 __ jmp(&done); | 996 __ jmp(&done); |
| 1001 __ Bind(&slow_case); | 997 __ Bind(&slow_case); |
| 1002 __ pushl(EAX); | 998 __ pushl(EAX); |
| 1003 __ pushl(EDX); | 999 __ pushl(EDX); |
| 1004 const int number_of_arguments = 2; | 1000 const int number_of_arguments = 2; |
| 1005 const Array& no_optional_argument_names = Array::Handle(); | 1001 const Array& no_optional_argument_names = Array::Handle(); |
| 1006 GenerateCheckedInstanceCalls(node, | 1002 GenerateCheckedInstanceCalls(node, |
| 1007 node->left(), | 1003 node->left(), |
| 1008 node->id(), | |
| 1009 node->token_index(), | 1004 node->token_index(), |
| 1010 number_of_arguments, | 1005 number_of_arguments, |
| 1011 no_optional_argument_names); | 1006 no_optional_argument_names); |
| 1012 __ Bind(&done); | 1007 __ Bind(&done); |
| 1013 HandleResult(node, EAX); | 1008 HandleResult(node, EAX); |
| 1014 return; | 1009 return; |
| 1015 } | 1010 } |
| 1016 if ((kind == Token::kSHL) && allow_smi) { | 1011 if ((kind == Token::kSHL) && allow_smi) { |
| 1017 GenerateSmiShiftBinaryOp(node); | 1012 GenerateSmiShiftBinaryOp(node); |
| 1018 HandleResult(node, EAX); | 1013 HandleResult(node, EAX); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 __ SmiUntag(kLeftRegister); | 1146 __ SmiUntag(kLeftRegister); |
| 1152 __ cvtsi2sd(XMM0, kLeftRegister); | 1147 __ cvtsi2sd(XMM0, kLeftRegister); |
| 1153 __ Bind(&done); | 1148 __ Bind(&done); |
| 1154 } else { | 1149 } else { |
| 1155 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); | 1150 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); |
| 1156 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); | 1151 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); |
| 1157 PropagateBackLocalClass(node->left(), double_class_); | 1152 PropagateBackLocalClass(node->left(), double_class_); |
| 1158 } | 1153 } |
| 1159 } | 1154 } |
| 1160 | 1155 |
| 1161 const bool right_must_be_double = | 1156 const bool right_must_be_double = NodeHasClassAt(node, double_class_, 1); |
| 1162 AtIdNodeHasClassAt(node, node->id(), double_class_, 1); | |
| 1163 | 1157 |
| 1164 // If arguments are of same type (e.g., same local), then the test of left | 1158 // If arguments are of same type (e.g., same local), then the test of left |
| 1165 // argument was sufficient. | 1159 // argument was sufficient. |
| 1166 if (right_info.IsClass(double_class_) || args_of_same_type) { | 1160 if (right_info.IsClass(double_class_) || args_of_same_type) { |
| 1167 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); | 1161 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); |
| 1168 if (!right_info.IsClass(double_class_)) { | 1162 if (!right_info.IsClass(double_class_)) { |
| 1169 PropagateBackLocalClass(node->right(), double_class_); | 1163 PropagateBackLocalClass(node->right(), double_class_); |
| 1170 } | 1164 } |
| 1171 } else { | 1165 } else { |
| 1172 if (right_must_be_double) { | 1166 if (right_must_be_double) { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 // TODO(srdjan): Test in checked mode if they are Booleans otherwise | 1289 // TODO(srdjan): Test in checked mode if they are Booleans otherwise |
| 1296 // throw exception. | 1290 // throw exception. |
| 1297 if (FLAG_enable_type_checks) { | 1291 if (FLAG_enable_type_checks) { |
| 1298 CodeGenerator::VisitBinaryOpNode(node); | 1292 CodeGenerator::VisitBinaryOpNode(node); |
| 1299 return; | 1293 return; |
| 1300 } | 1294 } |
| 1301 GenerateLogicalBinaryOp(node); | 1295 GenerateLogicalBinaryOp(node); |
| 1302 return; | 1296 return; |
| 1303 } | 1297 } |
| 1304 | 1298 |
| 1305 const ICData& ic_data = node->ICDataAtId(node->id()); | 1299 const ICData& ic_data = node->ic_data(); |
| 1306 if (ic_data.NumberOfChecks() == 0) { | 1300 if (ic_data.NumberOfChecks() == 0) { |
| 1307 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1301 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1308 DeoptimizationBlob* deopt_blob = | 1302 DeoptimizationBlob* deopt_blob = |
| 1309 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); | 1303 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); |
| 1310 __ jmp(deopt_blob->label()); | 1304 __ jmp(deopt_blob->label()); |
| 1311 return; | 1305 return; |
| 1312 } | 1306 } |
| 1313 | 1307 |
| 1314 ASSERT(ic_data.num_args_tested() == 2); | 1308 ASSERT(ic_data.num_args_tested() == 2); |
| 1315 | 1309 |
| 1316 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { | 1310 if (NodeHasTwoClasses(node, smi_class_, smi_class_)) { |
| 1317 GenerateSmiBinaryOp(node); | 1311 GenerateSmiBinaryOp(node); |
| 1318 return; | 1312 return; |
| 1319 } | 1313 } |
| 1320 | 1314 |
| 1321 if (AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { | 1315 if (NodeHasClassAt(node, double_class_, 0)) { |
| 1322 const bool receiver_can_be_smi = false; | 1316 const bool receiver_can_be_smi = false; |
| 1323 GenerateDoubleBinaryOp(node, receiver_can_be_smi); | 1317 GenerateDoubleBinaryOp(node, receiver_can_be_smi); |
| 1324 return; | 1318 return; |
| 1325 } | 1319 } |
| 1326 | 1320 |
| 1327 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, double_class_)) { | 1321 if (NodeHasTwoClasses(node, smi_class_, double_class_)) { |
| 1328 const bool receiver_can_be_smi = true; | 1322 const bool receiver_can_be_smi = true; |
| 1329 GenerateDoubleBinaryOp(node, receiver_can_be_smi); | 1323 GenerateDoubleBinaryOp(node, receiver_can_be_smi); |
| 1330 return; | 1324 return; |
| 1331 } | 1325 } |
| 1332 | 1326 |
| 1333 const Class& mint_class = | 1327 const Class& mint_class = |
| 1334 Class::Handle(Isolate::Current()->object_store()->mint_class()); | 1328 Class::Handle(Isolate::Current()->object_store()->mint_class()); |
| 1335 if (AtIdNodeHasClassAt(node, node->id(), mint_class, 0)) { | 1329 if (NodeHasClassAt(node, mint_class, 0)) { |
| 1336 GenerateMintBinaryOp(node, false); | 1330 GenerateMintBinaryOp(node, false); |
| 1337 return; | 1331 return; |
| 1338 } | 1332 } |
| 1339 | 1333 |
| 1340 if (NodeHasBothReceiverClasses(node, smi_class_, mint_class)) { | 1334 if (NodeHasBothReceiverClasses(node, smi_class_, mint_class)) { |
| 1341 GenerateMintBinaryOp(node, true); | 1335 GenerateMintBinaryOp(node, true); |
| 1342 return; | 1336 return; |
| 1343 } | 1337 } |
| 1344 | 1338 |
| 1345 // TODO(srdjan): Implement "+" for Strings. | 1339 // TODO(srdjan): Implement "+" for Strings. |
| 1346 // Type feedback tells this is not a Smi or Double operation. | 1340 // Type feedback tells this is not a Smi or Double operation. |
| 1347 TraceNotOpt(node, | 1341 TraceNotOpt(node, |
| 1348 "BinaryOp: type feedback tells this is not a Smi, Mint or Double op"); | 1342 "BinaryOp: type feedback tells this is not a Smi, Mint or Double op"); |
| 1349 node->left()->Visit(this); | 1343 node->left()->Visit(this); |
| 1350 node->right()->Visit(this); | 1344 node->right()->Visit(this); |
| 1351 const int number_of_arguments = 2; | 1345 const int number_of_arguments = 2; |
| 1352 const Array& no_optional_argument_names = Array::Handle(); | 1346 const Array& no_optional_argument_names = Array::Handle(); |
| 1353 GenerateCheckedInstanceCalls(node, | 1347 GenerateCheckedInstanceCalls(node, |
| 1354 node->left(), | 1348 node->left(), |
| 1355 node->id(), | |
| 1356 node->token_index(), | 1349 node->token_index(), |
| 1357 number_of_arguments, | 1350 number_of_arguments, |
| 1358 no_optional_argument_names); | 1351 no_optional_argument_names); |
| 1359 HandleResult(node, EAX); | 1352 HandleResult(node, EAX); |
| 1360 return; | 1353 return; |
| 1361 } | 1354 } |
| 1362 | 1355 |
| 1363 | 1356 |
| 1364 // Return offset of a field or -1 if field is not found. | 1357 // Return offset of a field or -1 if field is not found. |
| 1365 static intptr_t GetFieldOffset(const Class& field_class, | 1358 static intptr_t GetFieldOffset(const Class& field_class, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 return true; | 1396 return true; |
| 1404 } | 1397 } |
| 1405 | 1398 |
| 1406 | 1399 |
| 1407 // Emits code for an instance getter that has one or more collected classes, | 1400 // Emits code for an instance getter that has one or more collected classes, |
| 1408 // all with the same target. Deoptimizes for Smi or unexpected class. | 1401 // all with the same target. Deoptimizes for Smi or unexpected class. |
| 1409 // EBX: loaded receiver. | 1402 // EBX: loaded receiver. |
| 1410 // Result is returned in EAX. | 1403 // Result is returned in EAX. |
| 1411 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( | 1404 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( |
| 1412 AstNode* node, | 1405 AstNode* node, |
| 1413 intptr_t id, | |
| 1414 AstNode* receiver, | 1406 AstNode* receiver, |
| 1415 const String& field_name, | 1407 const String& field_name, |
| 1416 Register recv_reg) { | 1408 Register recv_reg) { |
| 1417 if (recv_reg != EBX) { | 1409 if (recv_reg != EBX) { |
| 1418 // TODO(srdjan): Do not hardwire register. | 1410 // TODO(srdjan): Do not hardwire register. |
| 1419 UNIMPLEMENTED(); | 1411 UNIMPLEMENTED(); |
| 1420 } | 1412 } |
| 1421 DeoptimizationBlob* deopt_blob = | 1413 DeoptimizationBlob* deopt_blob = |
| 1422 AddDeoptimizationBlob(node, EBX, kDeoptInstanceGetterSameTarget); | 1414 AddDeoptimizationBlob(node, EBX, kDeoptInstanceGetterSameTarget); |
| 1423 if (NodeMayBeSmi(receiver)) { | 1415 if (NodeMayBeSmi(receiver)) { |
| 1424 __ testl(EBX, Immediate(kSmiTagMask)); | 1416 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1425 __ j(ZERO, deopt_blob->label()); | 1417 __ j(ZERO, deopt_blob->label()); |
| 1426 } | 1418 } |
| 1427 | 1419 |
| 1428 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1420 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1429 const ICData& ic_data = node->ICDataAtId(id); | 1421 const ICData& ic_data = node->ic_data(); |
| 1430 Function& target = Function::Handle(); | 1422 Function& target = Function::Handle(); |
| 1431 Label load_field; | 1423 Label load_field; |
| 1432 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 1424 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1433 Class& cls = Class::ZoneHandle(); | 1425 Class& cls = Class::ZoneHandle(); |
| 1434 ic_data.GetOneClassCheckAt(i, &cls, &target); | 1426 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1435 __ CompareObject(EAX, cls); | 1427 __ CompareObject(EAX, cls); |
| 1436 if (i == (ic_data.NumberOfChecks() - 1)) { | 1428 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 1437 __ j(NOT_EQUAL, deopt_blob->label()); | 1429 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1438 } else { | 1430 } else { |
| 1439 __ j(EQUAL, &load_field); | 1431 __ j(EQUAL, &load_field); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1509 | 1501 |
| 1510 // Return true if all targets in 'ic_data' point to same | 1502 // Return true if all targets in 'ic_data' point to same |
| 1511 // inlineable getter target. | 1503 // inlineable getter target. |
| 1512 static bool ICDataToSameInlineableInstanceGetter(const ICData& ic_data) { | 1504 static bool ICDataToSameInlineableInstanceGetter(const ICData& ic_data) { |
| 1513 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); | 1505 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); |
| 1514 return !target.IsNull() && IsInlineableInstanceGetter(target); | 1506 return !target.IsNull() && IsInlineableInstanceGetter(target); |
| 1515 } | 1507 } |
| 1516 | 1508 |
| 1517 | 1509 |
| 1518 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, | 1510 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, |
| 1519 intptr_t id, | |
| 1520 AstNode* receiver, | 1511 AstNode* receiver, |
| 1521 const String& field_name, | 1512 const String& field_name, |
| 1522 Register recv_reg) { | 1513 Register recv_reg) { |
| 1523 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { | 1514 if (ICDataToSameInlineableInstanceGetter(node->ic_data())) { |
| 1524 InlineInstanceGettersWithSameTarget(node, | 1515 InlineInstanceGettersWithSameTarget(node, |
| 1525 id, | |
| 1526 receiver, | 1516 receiver, |
| 1527 field_name, | 1517 field_name, |
| 1528 recv_reg); | 1518 recv_reg); |
| 1529 } else { | 1519 } else { |
| 1530 // TODO(srdjan): Inline access. | 1520 // TODO(srdjan): Inline access. |
| 1531 __ pushl(recv_reg); | 1521 __ pushl(recv_reg); |
| 1532 const int kNumberOfArguments = 1; | 1522 const int kNumberOfArguments = 1; |
| 1533 const Array& kNoArgumentNames = Array::Handle(); | 1523 const Array& kNoArgumentNames = Array::Handle(); |
| 1534 GenerateCheckedInstanceCalls(node, | 1524 GenerateCheckedInstanceCalls(node, |
| 1535 receiver, | 1525 receiver, |
| 1536 id, | |
| 1537 node->token_index(), | 1526 node->token_index(), |
| 1538 kNumberOfArguments, | 1527 kNumberOfArguments, |
| 1539 kNoArgumentNames); | 1528 kNoArgumentNames); |
| 1540 } | 1529 } |
| 1541 } | 1530 } |
| 1542 | 1531 |
| 1543 | 1532 |
| 1544 // TODO(srdjan): Implement for multiple getter targets. | 1533 // TODO(srdjan): Implement for multiple getter targets. |
| 1545 // For every class inline its implicit getter, or call the instance getter. | 1534 // For every class inline its implicit getter, or call the instance getter. |
| 1546 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1535 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| 1547 InstanceGetterNode* node) { | 1536 InstanceGetterNode* node) { |
| 1548 const ICData& ic_data = node->ICDataAtId(node->id()); | 1537 const ICData& ic_data = node->ic_data(); |
| 1549 if (ic_data.NumberOfChecks() == 0) { | 1538 if (ic_data.NumberOfChecks() == 0) { |
| 1550 // No type feedback collected. | 1539 // No type feedback collected. |
| 1551 node->receiver()->Visit(this); | 1540 node->receiver()->Visit(this); |
| 1552 DeoptimizationBlob* deopt_blob = | 1541 DeoptimizationBlob* deopt_blob = |
| 1553 AddDeoptimizationBlob(node, kDeoptInstanceGetter); | 1542 AddDeoptimizationBlob(node, kDeoptInstanceGetter); |
| 1554 __ jmp(deopt_blob->label()); | 1543 __ jmp(deopt_blob->label()); |
| 1555 return; | 1544 return; |
| 1556 } | 1545 } |
| 1557 | 1546 |
| 1558 VisitLoadOne(node->receiver(), EBX); | 1547 VisitLoadOne(node->receiver(), EBX); |
| 1559 InlineInstanceGetter(node, | 1548 InlineInstanceGetter(node, |
| 1560 node->id(), | |
| 1561 node->receiver(), | 1549 node->receiver(), |
| 1562 node->field_name(), | 1550 node->field_name(), |
| 1563 EBX); | 1551 EBX); |
| 1564 // Result is in EAX. | 1552 // Result is in EAX. |
| 1565 HandleResult(node, EAX); | 1553 HandleResult(node, EAX); |
| 1566 } | 1554 } |
| 1567 | 1555 |
| 1568 | 1556 |
| 1569 // Helper struct to pass arguments to 'GenerateInstanceSetter'. | 1557 // Helper struct to pass arguments to 'GenerateInstanceSetter'. |
| 1570 struct InstanceSetterArgs { | 1558 struct InstanceSetterArgs { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1597 *(args.target), | 1585 *(args.target), |
| 1598 2, | 1586 2, |
| 1599 no_optional_argument_names); | 1587 no_optional_argument_names); |
| 1600 __ popl(args.value_reg); | 1588 __ popl(args.value_reg); |
| 1601 } | 1589 } |
| 1602 } | 1590 } |
| 1603 | 1591 |
| 1604 | 1592 |
| 1605 // Returns value in 'value_reg', clobbers EBX. | 1593 // Returns value in 'value_reg', clobbers EBX. |
| 1606 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, | 1594 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, |
| 1607 intptr_t id, | |
| 1608 AstNode* receiver, | 1595 AstNode* receiver, |
| 1609 const String& field_name, | 1596 const String& field_name, |
| 1610 Register recv_reg, | 1597 Register recv_reg, |
| 1611 Register value_reg) { | 1598 Register value_reg) { |
| 1612 // EBX is used as temporary register for class. | 1599 // EBX is used as temporary register for class. |
| 1613 ASSERT((recv_reg != EBX) && (value_reg != EBX)); | 1600 ASSERT((recv_reg != EBX) && (value_reg != EBX)); |
| 1614 GrowableArray<Class*> classes; | 1601 GrowableArray<Class*> classes; |
| 1615 GrowableArray<Function*> targets; | 1602 GrowableArray<Function*> targets; |
| 1616 bool unique_target = true; | 1603 bool unique_target = true; |
| 1617 { | 1604 { |
| 1618 const ICData& ic_data = node->ICDataAtId(id); | 1605 const ICData& ic_data = node->ic_data(); |
| 1619 ASSERT(ic_data.NumberOfChecks() > 0); | 1606 ASSERT(ic_data.NumberOfChecks() > 0); |
| 1620 ASSERT(ic_data.num_args_tested() == 1); | 1607 ASSERT(ic_data.num_args_tested() == 1); |
| 1621 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 1608 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1622 Class& cls = Class::ZoneHandle(); | 1609 Class& cls = Class::ZoneHandle(); |
| 1623 Function& target = Function::ZoneHandle(); | 1610 Function& target = Function::ZoneHandle(); |
| 1624 ic_data.GetOneClassCheckAt(i, &cls, &target); | 1611 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1625 classes.Add(&cls); | 1612 classes.Add(&cls); |
| 1626 targets.Add(&target); | 1613 targets.Add(&target); |
| 1627 } | 1614 } |
| 1628 for (intptr_t i = 1; i < targets.length(); i++) { | 1615 for (intptr_t i = 1; i < targets.length(); i++) { |
| 1629 if (targets[i - 1]->raw() != targets[i]->raw()) { | 1616 if (targets[i - 1]->raw() != targets[i]->raw()) { |
| 1630 unique_target = false; | 1617 unique_target = false; |
| 1631 break; | 1618 break; |
| 1632 } | 1619 } |
| 1633 } | 1620 } |
| 1634 } | 1621 } |
| 1635 // TODO(srdjan): sort classes/target by their invocation count. | 1622 // TODO(srdjan): sort classes/target by their invocation count. |
| 1636 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob( | 1623 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob( |
| 1637 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); | 1624 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); |
| 1638 // Deoptimize if Smi, since they do not have setters. | 1625 // Deoptimize if Smi, since they do not have setters. |
| 1639 if (NodeMayBeSmi(receiver)) { | 1626 if (NodeMayBeSmi(receiver)) { |
| 1640 __ testl(recv_reg, Immediate(kSmiTagMask)); | 1627 __ testl(recv_reg, Immediate(kSmiTagMask)); |
| 1641 __ j(ZERO, deopt_blob->label()); | 1628 __ j(ZERO, deopt_blob->label()); |
| 1642 } | 1629 } |
| 1643 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); | 1630 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); |
| 1644 // Initialize setter arguments, but leave the class and target fields NULL. | 1631 // Initialize setter arguments, but leave the class and target fields NULL. |
| 1645 InstanceSetterArgs setter_args = | 1632 InstanceSetterArgs setter_args = |
| 1646 {NULL, NULL, &field_name, recv_reg, value_reg, id, node->token_index()}; | 1633 {NULL, NULL, &field_name, recv_reg, value_reg, |
| 1634 node->id(), node->token_index()}; |
| 1647 | 1635 |
| 1648 if (unique_target) { | 1636 if (unique_target) { |
| 1649 Label store_field; | 1637 Label store_field; |
| 1650 for (intptr_t i = 0; i < classes.length(); i++) { | 1638 for (intptr_t i = 0; i < classes.length(); i++) { |
| 1651 __ CompareObject(EBX, *classes[i]); | 1639 __ CompareObject(EBX, *classes[i]); |
| 1652 if (i == (classes.length() - 1)) { | 1640 if (i == (classes.length() - 1)) { |
| 1653 __ j(NOT_EQUAL, deopt_blob->label()); | 1641 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1654 } else { | 1642 } else { |
| 1655 __ j(EQUAL, &store_field); | 1643 __ j(EQUAL, &store_field); |
| 1656 } | 1644 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1685 // The call to the instance setter implements the assignment to a field. | 1673 // The call to the instance setter implements the assignment to a field. |
| 1686 // The result of the assignment to a field is the value being stored. | 1674 // The result of the assignment to a field is the value being stored. |
| 1687 void OptimizingCodeGenerator::VisitInstanceSetterNode( | 1675 void OptimizingCodeGenerator::VisitInstanceSetterNode( |
| 1688 InstanceSetterNode* node) { | 1676 InstanceSetterNode* node) { |
| 1689 // TODO(srdjan): inline setters to different targets as well. | 1677 // TODO(srdjan): inline setters to different targets as well. |
| 1690 if (FLAG_enable_type_checks) { | 1678 if (FLAG_enable_type_checks) { |
| 1691 CodeGenerator::VisitInstanceSetterNode(node); | 1679 CodeGenerator::VisitInstanceSetterNode(node); |
| 1692 return; | 1680 return; |
| 1693 } | 1681 } |
| 1694 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); | 1682 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); |
| 1695 const ICData& ic_data = node->ICDataAtId(node->id()); | 1683 const ICData& ic_data = node->ic_data(); |
| 1696 if (ic_data.NumberOfChecks() == 0) { | 1684 if (ic_data.NumberOfChecks() == 0) { |
| 1697 DeoptimizationBlob* deopt_blob = | 1685 DeoptimizationBlob* deopt_blob = |
| 1698 AddDeoptimizationBlob(node, EDX, EAX, kDeoptInstanceSetter); | 1686 AddDeoptimizationBlob(node, EDX, EAX, kDeoptInstanceSetter); |
| 1699 __ jmp(deopt_blob->label()); | 1687 __ jmp(deopt_blob->label()); |
| 1700 return; | 1688 return; |
| 1701 } | 1689 } |
| 1702 // Value in EAX survives and will be stored on stack if result is needed. | 1690 // Value in EAX survives and will be stored on stack if result is needed. |
| 1703 InlineInstanceSetter(node, | 1691 InlineInstanceSetter(node, |
| 1704 node->id(), | |
| 1705 node->receiver(), | 1692 node->receiver(), |
| 1706 node->field_name(), | 1693 node->field_name(), |
| 1707 EDX, | 1694 EDX, |
| 1708 EAX); | 1695 EAX); |
| 1709 | 1696 |
| 1710 HandleResult(node, EAX); | 1697 HandleResult(node, EAX); |
| 1711 } | 1698 } |
| 1712 | 1699 |
| 1713 | 1700 |
| 1714 // Return false if condition is not supported. | 1701 // Return false if condition is not supported. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1829 __ jmp(&evaluate_comparison); | 1816 __ jmp(&evaluate_comparison); |
| 1830 | 1817 |
| 1831 __ Bind(&call_operator); | 1818 __ Bind(&call_operator); |
| 1832 // Left is Smi. | 1819 // Left is Smi. |
| 1833 const int kNumberOfArguments = 2; | 1820 const int kNumberOfArguments = 2; |
| 1834 const Array& kNoArgumentNames = Array::Handle(); | 1821 const Array& kNoArgumentNames = Array::Handle(); |
| 1835 __ pushl(EAX); | 1822 __ pushl(EAX); |
| 1836 __ pushl(EDX); | 1823 __ pushl(EDX); |
| 1837 GenerateCheckedInstanceCalls(node, | 1824 GenerateCheckedInstanceCalls(node, |
| 1838 node->left(), | 1825 node->left(), |
| 1839 node->id(), | |
| 1840 node->token_index(), | 1826 node->token_index(), |
| 1841 kNumberOfArguments, | 1827 kNumberOfArguments, |
| 1842 kNoArgumentNames); | 1828 kNoArgumentNames); |
| 1843 __ CompareObject(EAX, bool_true); | 1829 __ CompareObject(EAX, bool_true); |
| 1844 // Fall through to evaluate result. | 1830 // Fall through to evaluate result. |
| 1845 } | 1831 } |
| 1846 __ Bind(&evaluate_comparison); | 1832 __ Bind(&evaluate_comparison); |
| 1847 // Condition is set by a previous comparison operation. | 1833 // Condition is set by a previous comparison operation. |
| 1848 Condition condition = OVERFLOW; // Initialize to something. | 1834 Condition condition = OVERFLOW; // Initialize to something. |
| 1849 bool ok = SupportedTokenKindToSmiCondition(node->kind(), &condition); | 1835 bool ok = SupportedTokenKindToSmiCondition(node->kind(), &condition); |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2134 node->token_index(), | 2120 node->token_index(), |
| 2135 node->left(), | 2121 node->left(), |
| 2136 node->right()->AsTypeNode()->type(), | 2122 node->right()->AsTypeNode()->type(), |
| 2137 (node->kind() == Token::kISNOT)); | 2123 (node->kind() == Token::kISNOT)); |
| 2138 if (!IsResultNeeded(node)) { | 2124 if (!IsResultNeeded(node)) { |
| 2139 __ popl(EAX); // Pop the result of the instanceof operation. | 2125 __ popl(EAX); // Pop the result of the instanceof operation. |
| 2140 } | 2126 } |
| 2141 return; | 2127 return; |
| 2142 } | 2128 } |
| 2143 | 2129 |
| 2144 if (AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { | 2130 if (NodeHasClassAt(node, smi_class_, 0)) { |
| 2145 if (GenerateSmiComparison(node)) { | 2131 if (GenerateSmiComparison(node)) { |
| 2146 // The comparison was handled, code was emitted. | 2132 // The comparison was handled, code was emitted. |
| 2147 return; | 2133 return; |
| 2148 } | 2134 } |
| 2149 // Fall through if condition is not supported. | 2135 // Fall through if condition is not supported. |
| 2150 } else if (AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { | 2136 } else if (NodeHasClassAt(node, double_class_, 0)) { |
| 2151 // Double comparison. | 2137 // Double comparison. |
| 2152 if (GenerateDoubleComparison(node)) { | 2138 if (GenerateDoubleComparison(node)) { |
| 2153 return; | 2139 return; |
| 2154 } | 2140 } |
| 2155 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { | 2141 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
| 2156 // Equality, not-equality comparison of any other type. | 2142 // Equality, not-equality comparison of any other type. |
| 2157 if (GenerateEqualityComparison(node)) { | 2143 if (GenerateEqualityComparison(node)) { |
| 2158 return; | 2144 return; |
| 2159 } | 2145 } |
| 2160 } | 2146 } |
| 2161 | 2147 |
| 2162 // Fall through here if a comparison was not implemented. | 2148 // Fall through here if a comparison was not implemented. |
| 2163 // TODO(srdjan): Implement for Strings. | 2149 // TODO(srdjan): Implement for Strings. |
| 2164 CodeGenerator::VisitComparisonNode(node); | 2150 CodeGenerator::VisitComparisonNode(node); |
| 2165 } | 2151 } |
| 2166 | 2152 |
| 2167 | 2153 |
| 2168 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 2154 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 2169 const char* kMessage = "Inline indexed access"; | 2155 const char* kMessage = "Inline indexed access"; |
| 2170 ObjectStore* object_store = Isolate::Current()->object_store(); | 2156 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2171 const Class& object_array_class = | 2157 const Class& object_array_class = |
| 2172 Class::ZoneHandle(object_store->array_class()); | 2158 Class::ZoneHandle(object_store->array_class()); |
| 2173 const Class& immutable_object_array_class = | 2159 const Class& immutable_object_array_class = |
| 2174 Class::ZoneHandle(object_store->immutable_array_class()); | 2160 Class::ZoneHandle(object_store->immutable_array_class()); |
| 2175 if (AtIdNodeHasClassAt(node, node->id(), object_array_class, 0) || | 2161 if (NodeHasClassAt(node, object_array_class, 0) || |
| 2176 AtIdNodeHasClassAt(node, node->id(), | 2162 NodeHasClassAt(node, immutable_object_array_class, 0)) { |
| 2177 immutable_object_array_class, 0)) { | |
| 2178 CodeGenInfo array_info(node->array()); | 2163 CodeGenInfo array_info(node->array()); |
| 2179 CodeGenInfo index_info(node->index_expr()); | 2164 CodeGenInfo index_info(node->index_expr()); |
| 2180 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); | 2165 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); |
| 2181 DeoptimizationBlob* deopt_blob = | 2166 DeoptimizationBlob* deopt_blob = |
| 2182 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); | 2167 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); |
| 2183 const Class& test_class = | 2168 const Class& test_class = NodeHasClassAt(node, object_array_class, 0) ? |
| 2184 AtIdNodeHasClassAt(node, node->id(), object_array_class, 0) ? | 2169 object_array_class : immutable_object_array_class; |
| 2185 object_array_class : immutable_object_array_class; | |
| 2186 // Type checks of array. | 2170 // Type checks of array. |
| 2187 if (!array_info.IsClass(test_class)) { | 2171 if (!array_info.IsClass(test_class)) { |
| 2188 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 2172 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 2189 __ j(ZERO, deopt_blob->label()); | 2173 __ j(ZERO, deopt_blob->label()); |
| 2190 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 2174 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 2191 __ CompareObject(EAX, test_class); | 2175 __ CompareObject(EAX, test_class); |
| 2192 __ j(NOT_EQUAL, deopt_blob->label()); | 2176 __ j(NOT_EQUAL, deopt_blob->label()); |
| 2193 PropagateBackLocalClass(node->array(), test_class); | 2177 PropagateBackLocalClass(node->array(), test_class); |
| 2194 } | 2178 } |
| 2195 | 2179 |
| 2196 // Type check of index. | 2180 // Type check of index. |
| 2197 if (!index_info.IsClass(smi_class_)) { | 2181 if (!index_info.IsClass(smi_class_)) { |
| 2198 __ testl(EDX, Immediate(kSmiTagMask)); | 2182 __ testl(EDX, Immediate(kSmiTagMask)); |
| 2199 __ j(NOT_ZERO, deopt_blob->label()); | 2183 __ j(NOT_ZERO, deopt_blob->label()); |
| 2200 PropagateBackLocalClass(node->index_expr(), smi_class_); | 2184 PropagateBackLocalClass(node->index_expr(), smi_class_); |
| 2201 } | 2185 } |
| 2202 // Range check. | 2186 // Range check. |
| 2203 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); | 2187 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); |
| 2204 __ j(ABOVE_EQUAL, deopt_blob->label()); | 2188 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 2205 // Note that EDX is Smi, i.e, times 2. | 2189 // Note that EDX is Smi, i.e, times 2. |
| 2206 ASSERT(kSmiTagShift == 1); | 2190 ASSERT(kSmiTagShift == 1); |
| 2207 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); | 2191 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); |
| 2208 HandleResult(node, EAX); | 2192 HandleResult(node, EAX); |
| 2209 TraceOpt(node, kMessage); | 2193 TraceOpt(node, kMessage); |
| 2210 return; | 2194 return; |
| 2211 } | 2195 } |
| 2212 | 2196 |
| 2213 if (AtIdNodeHasClassAt(node, node->id(), growable_object_array_class_, 0)) { | 2197 if (NodeHasClassAt(node, growable_object_array_class_, 0)) { |
| 2214 CodeGenInfo array_info(node->array()); | 2198 CodeGenInfo array_info(node->array()); |
| 2215 CodeGenInfo index_info(node->index_expr()); | 2199 CodeGenInfo index_info(node->index_expr()); |
| 2216 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); | 2200 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); |
| 2217 DeoptimizationBlob* deopt_blob = | 2201 DeoptimizationBlob* deopt_blob = |
| 2218 AddDeoptimizationBlob(node, EDX, EAX, kDeoptLoadIndexedGrowableArray); | 2202 AddDeoptimizationBlob(node, EDX, EAX, kDeoptLoadIndexedGrowableArray); |
| 2219 // EAX: index, EDX: array. | 2203 // EAX: index, EDX: array. |
| 2220 if (!index_info.IsClass(smi_class_)) { | 2204 if (!index_info.IsClass(smi_class_)) { |
| 2221 __ testl(EAX, Immediate(kSmiTagMask)); | 2205 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2222 __ j(NOT_ZERO, deopt_blob->label()); // Not Smi index. | 2206 __ j(NOT_ZERO, deopt_blob->label()); // Not Smi index. |
| 2223 PropagateBackLocalClass(node->index_expr(), smi_class_); | 2207 PropagateBackLocalClass(node->index_expr(), smi_class_); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2257 // array (e.g. in a[x] += 3). Fixes issue 1570. | 2241 // array (e.g. in a[x] += 3). Fixes issue 1570. |
| 2258 { | 2242 { |
| 2259 CodeGenInfo array_info(node->array()); | 2243 CodeGenInfo array_info(node->array()); |
| 2260 node->array()->Visit(this); | 2244 node->array()->Visit(this); |
| 2261 class_of_this_array = array_info.is_class()->raw(); | 2245 class_of_this_array = array_info.is_class()->raw(); |
| 2262 } | 2246 } |
| 2263 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). | 2247 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). |
| 2264 ObjectStore* object_store = Isolate::Current()->object_store(); | 2248 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2265 const Class& object_array_class = | 2249 const Class& object_array_class = |
| 2266 Class::ZoneHandle(object_store->array_class()); | 2250 Class::ZoneHandle(object_store->array_class()); |
| 2267 const ICData& ic_data = node->ICDataAtId(node->id()); | 2251 const ICData& ic_data = node->ic_data(); |
| 2268 if (ic_data.NumberOfChecks() == 0) { | 2252 if (ic_data.NumberOfChecks() == 0) { |
| 2269 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2253 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2270 DeoptimizationBlob* deopt_blob = | 2254 DeoptimizationBlob* deopt_blob = |
| 2271 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); | 2255 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); |
| 2272 __ jmp(deopt_blob->label()); | 2256 __ jmp(deopt_blob->label()); |
| 2273 return; | 2257 return; |
| 2274 } | 2258 } |
| 2275 | 2259 |
| 2276 | 2260 |
| 2277 if (AtIdNodeHasClassAt(node, node->id(), object_array_class, 0)) { | 2261 if (NodeHasClassAt(node, object_array_class, 0)) { |
| 2278 // Release CodeGenInfo of index quickly as it may be used in the value, | 2262 // Release CodeGenInfo of index quickly as it may be used in the value, |
| 2279 // e.g. a[i] += 3. Fixes issue 1570. | 2263 // e.g. a[i] += 3. Fixes issue 1570. |
| 2280 bool index_is_smi = false; | 2264 bool index_is_smi = false; |
| 2281 { | 2265 { |
| 2282 CodeGenInfo index_info(node->index_expr()); | 2266 CodeGenInfo index_info(node->index_expr()); |
| 2283 node->index_expr()->Visit(this); | 2267 node->index_expr()->Visit(this); |
| 2284 index_is_smi = index_info.IsClass(smi_class_); | 2268 index_is_smi = index_info.IsClass(smi_class_); |
| 2285 } | 2269 } |
| 2286 VisitLoadOne(node->value(), ECX); | 2270 VisitLoadOne(node->value(), ECX); |
| 2287 DeoptimizationBlob* deopt_blob = | 2271 DeoptimizationBlob* deopt_blob = |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2308 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); | 2292 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); |
| 2309 __ j(ABOVE_EQUAL, deopt_blob->label()); // Range error -> deopt. | 2293 __ j(ABOVE_EQUAL, deopt_blob->label()); // Range error -> deopt. |
| 2310 ASSERT(kSmiTagShift == 1); | 2294 ASSERT(kSmiTagShift == 1); |
| 2311 __ StoreIntoObject(EAX, | 2295 __ StoreIntoObject(EAX, |
| 2312 FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)), | 2296 FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)), |
| 2313 ECX); | 2297 ECX); |
| 2314 HandleResult(node, ECX); | 2298 HandleResult(node, ECX); |
| 2315 return; | 2299 return; |
| 2316 } | 2300 } |
| 2317 | 2301 |
| 2318 if (AtIdNodeHasClassAt(node, node->id(), growable_object_array_class_, 0)) { | 2302 if (NodeHasClassAt(node, growable_object_array_class_, 0)) { |
| 2319 bool index_is_smi = false; | 2303 bool index_is_smi = false; |
| 2320 // Release CodeGenInfo of index quickly as it may be used in the value, | 2304 // Release CodeGenInfo of index quickly as it may be used in the value, |
| 2321 // e.g. a[i] += 3. Fixes issue 1570. | 2305 // e.g. a[i] += 3. Fixes issue 1570. |
| 2322 { | 2306 { |
| 2323 CodeGenInfo index_info(node->index_expr()); | 2307 CodeGenInfo index_info(node->index_expr()); |
| 2324 node->index_expr()->Visit(this); | 2308 node->index_expr()->Visit(this); |
| 2325 index_is_smi = index_info.IsClass(smi_class_); | 2309 index_is_smi = index_info.IsClass(smi_class_); |
| 2326 } | 2310 } |
| 2327 VisitLoadOne(node->value(), ECX); | 2311 VisitLoadOne(node->value(), ECX); |
| 2328 DeoptimizationBlob* deopt_blob = | 2312 DeoptimizationBlob* deopt_blob = |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2587 targets->Add(&null_target); | 2571 targets->Add(&null_target); |
| 2588 } | 2572 } |
| 2589 } | 2573 } |
| 2590 | 2574 |
| 2591 | 2575 |
| 2592 // Use IC data in 'node' to issues checks and calls. | 2576 // Use IC data in 'node' to issues checks and calls. |
| 2593 // IC data can contain one or more argument checks. | 2577 // IC data can contain one or more argument checks. |
| 2594 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( | 2578 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( |
| 2595 AstNode* node, | 2579 AstNode* node, |
| 2596 AstNode* receiver, | 2580 AstNode* receiver, |
| 2597 intptr_t node_id, | |
| 2598 intptr_t token_index, | 2581 intptr_t token_index, |
| 2599 intptr_t num_args, | 2582 intptr_t num_args, |
| 2600 const Array& optional_arguments_names) { | 2583 const Array& optional_arguments_names) { |
| 2601 ASSERT(node != NULL); | 2584 ASSERT(node != NULL); |
| 2602 ASSERT(receiver != NULL); | 2585 ASSERT(receiver != NULL); |
| 2603 ASSERT(num_args > 0); | 2586 ASSERT(num_args > 0); |
| 2604 const ICData& ic_data = node->ICDataAtId(node_id); | 2587 const ICData& ic_data = node->ic_data(); |
| 2605 if (ic_data.NumberOfChecks() == 0) { | 2588 if (ic_data.NumberOfChecks() == 0) { |
| 2606 // No type feedback means node was never executed. However that can be | 2589 // No type feedback means node was never executed. However that can be |
| 2607 // a common case especially in case of large switch statements. | 2590 // a common case especially in case of large switch statements. |
| 2608 // Use a special inline cache call which can help us decide when to | 2591 // Use a special inline cache call which can help us decide when to |
| 2609 // re-optimize this optiumized function. | 2592 // re-optimize this optiumized function. |
| 2610 GenerateInlineCacheCall( | 2593 GenerateInlineCacheCall( |
| 2611 node_id, token_index, ic_data, num_args, optional_arguments_names); | 2594 node->id(), token_index, ic_data, num_args, optional_arguments_names); |
| 2612 return; | 2595 return; |
| 2613 } | 2596 } |
| 2614 | 2597 |
| 2615 Function& target_for_null = Function::ZoneHandle(); | 2598 Function& target_for_null = Function::ZoneHandle(); |
| 2616 ObjectStore* object_store = Isolate::Current()->object_store(); | 2599 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2617 int num_optional_args = | 2600 int num_optional_args = |
| 2618 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); | 2601 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); |
| 2619 target_for_null = Resolver::ResolveDynamicForReceiverClass( | 2602 target_for_null = Resolver::ResolveDynamicForReceiverClass( |
| 2620 Class::Handle(object_store->object_class()), | 2603 Class::Handle(object_store->object_class()), |
| 2621 String::Handle(ic_data.target_name()), | 2604 String::Handle(ic_data.target_name()), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2633 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver. | 2616 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver. |
| 2634 if (classes[0]->raw() == smi_class_.raw()) { | 2617 if (classes[0]->raw() == smi_class_.raw()) { |
| 2635 start_ix++; | 2618 start_ix++; |
| 2636 // Smi test is needed. | 2619 // Smi test is needed. |
| 2637 __ testl(EAX, Immediate(kSmiTagMask)); | 2620 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2638 if (classes.length() == 1) { | 2621 if (classes.length() == 1) { |
| 2639 // Only Smi test. | 2622 // Only Smi test. |
| 2640 DeoptimizationBlob* deopt_blob = | 2623 DeoptimizationBlob* deopt_blob = |
| 2641 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallSmiOnly); | 2624 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallSmiOnly); |
| 2642 __ j(NOT_ZERO, deopt_blob->label()); | 2625 __ j(NOT_ZERO, deopt_blob->label()); |
| 2643 GenerateDirectCall(node_id, | 2626 GenerateDirectCall(node->id(), |
| 2644 token_index, | 2627 token_index, |
| 2645 *targets[0], | 2628 *targets[0], |
| 2646 num_args, | 2629 num_args, |
| 2647 optional_arguments_names); | 2630 optional_arguments_names); |
| 2648 return; | 2631 return; |
| 2649 } | 2632 } |
| 2650 Label not_smi; | 2633 Label not_smi; |
| 2651 __ j(NOT_ZERO, ¬_smi); | 2634 __ j(NOT_ZERO, ¬_smi); |
| 2652 GenerateDirectCall(node_id, | 2635 GenerateDirectCall(node->id(), |
| 2653 token_index, | 2636 token_index, |
| 2654 *targets[0], | 2637 *targets[0], |
| 2655 num_args, | 2638 num_args, |
| 2656 optional_arguments_names); | 2639 optional_arguments_names); |
| 2657 __ jmp(&done); | 2640 __ jmp(&done); |
| 2658 __ Bind(¬_smi); // Continue with other test below. | 2641 __ Bind(¬_smi); // Continue with other test below. |
| 2659 } else if (NodeMayBeSmi(receiver)) { | 2642 } else if (NodeMayBeSmi(receiver)) { |
| 2660 DeoptimizationBlob* deopt_blob = | 2643 DeoptimizationBlob* deopt_blob = |
| 2661 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallSmiFail); | 2644 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallSmiFail); |
| 2662 __ testl(EAX, Immediate(kSmiTagMask)); | 2645 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2663 __ j(ZERO, deopt_blob->label()); | 2646 __ j(ZERO, deopt_blob->label()); |
| 2664 } else { | 2647 } else { |
| 2665 // Receiver cannot be Smi, no need to test it. | 2648 // Receiver cannot be Smi, no need to test it. |
| 2666 } | 2649 } |
| 2667 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); // Receiver's class. | 2650 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); // Receiver's class. |
| 2668 for (intptr_t i = start_ix; i < classes.length(); i++) { | 2651 for (intptr_t i = start_ix; i < classes.length(); i++) { |
| 2669 const Class& cls = *classes[i]; | 2652 const Class& cls = *classes[i]; |
| 2670 const Function& target = *targets[i]; | 2653 const Function& target = *targets[i]; |
| 2671 __ CompareObject(EAX, cls); | 2654 __ CompareObject(EAX, cls); |
| 2672 if (i == (classes.length() - 1)) { | 2655 if (i == (classes.length() - 1)) { |
| 2673 // Last check. | 2656 // Last check. |
| 2674 DeoptimizationBlob* deopt_blob = | 2657 DeoptimizationBlob* deopt_blob = |
| 2675 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallCheckFail); | 2658 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallCheckFail); |
| 2676 __ j(NOT_EQUAL, deopt_blob->label()); | 2659 __ j(NOT_EQUAL, deopt_blob->label()); |
| 2677 GenerateDirectCall(node_id, | 2660 GenerateDirectCall(node->id(), |
| 2678 token_index, | 2661 token_index, |
| 2679 target, | 2662 target, |
| 2680 num_args, | 2663 num_args, |
| 2681 optional_arguments_names); | 2664 optional_arguments_names); |
| 2682 } else { | 2665 } else { |
| 2683 Label next; | 2666 Label next; |
| 2684 __ j(NOT_EQUAL, &next); | 2667 __ j(NOT_EQUAL, &next); |
| 2685 GenerateDirectCall(node_id, | 2668 GenerateDirectCall(node->id(), |
| 2686 token_index, | 2669 token_index, |
| 2687 target, | 2670 target, |
| 2688 num_args, | 2671 num_args, |
| 2689 optional_arguments_names); | 2672 optional_arguments_names); |
| 2690 __ jmp(&done); | 2673 __ jmp(&done); |
| 2691 __ Bind(&next); | 2674 __ Bind(&next); |
| 2692 } | 2675 } |
| 2693 } | 2676 } |
| 2694 __ Bind(&done); | 2677 __ Bind(&done); |
| 2695 } | 2678 } |
| 2696 | 2679 |
| 2697 | 2680 |
| 2698 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { | 2681 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { |
| 2699 const int number_of_arguments = node->arguments()->length() + 1; | 2682 const int number_of_arguments = node->arguments()->length() + 1; |
| 2700 // Compute the receiver object and pass it as first argument to call. | 2683 // Compute the receiver object and pass it as first argument to call. |
| 2701 node->receiver()->Visit(this); | 2684 node->receiver()->Visit(this); |
| 2702 // Now compute rest of the arguments to the call. | 2685 // Now compute rest of the arguments to the call. |
| 2703 node->arguments()->Visit(this); | 2686 node->arguments()->Visit(this); |
| 2704 if (TryInlineInstanceCall(node)) { | 2687 if (TryInlineInstanceCall(node)) { |
| 2705 // Instance call is inlined. | 2688 // Instance call is inlined. |
| 2706 } else { | 2689 } else { |
| 2707 GenerateCheckedInstanceCalls(node, | 2690 GenerateCheckedInstanceCalls(node, |
| 2708 node->receiver(), | 2691 node->receiver(), |
| 2709 node->id(), | |
| 2710 node->token_index(), | 2692 node->token_index(), |
| 2711 number_of_arguments, | 2693 number_of_arguments, |
| 2712 node->arguments()->names()); | 2694 node->arguments()->names()); |
| 2713 } | 2695 } |
| 2714 // Result is in EAX. | 2696 // Result is in EAX. |
| 2715 HandleResult(node, EAX); | 2697 HandleResult(node, EAX); |
| 2716 } | 2698 } |
| 2717 | 2699 |
| 2718 | 2700 |
| 2719 // Returns true if an instance call was replaced with its intrinsic. | 2701 // Returns true if an instance call was replaced with its intrinsic. |
| 2720 // Returns result in EAX. | 2702 // Returns result in EAX. |
| 2721 bool OptimizingCodeGenerator::TryInlineInstanceCall(InstanceCallNode* node) { | 2703 bool OptimizingCodeGenerator::TryInlineInstanceCall(InstanceCallNode* node) { |
| 2722 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 2704 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 2723 if ((classes != NULL) && (classes->length() == 1)) { | 2705 if ((classes != NULL) && (classes->length() == 1)) { |
| 2724 const int num_arguments = node->arguments()->length() + 1; | 2706 const int num_arguments = node->arguments()->length() + 1; |
| 2725 const int num_named_arguments = node->arguments()->names().IsNull() ? | 2707 const int num_named_arguments = node->arguments()->names().IsNull() ? |
| 2726 0 : node->arguments()->names().Length(); | 2708 0 : node->arguments()->names().Length(); |
| 2727 const Function& target = Function::ZoneHandle( | 2709 const Function& target = Function::ZoneHandle( |
| 2728 Resolver::ResolveDynamicForReceiverClass(*(*classes)[0], | 2710 Resolver::ResolveDynamicForReceiverClass(*(*classes)[0], |
| 2729 node->function_name(), | 2711 node->function_name(), |
| 2730 num_arguments, | 2712 num_arguments, |
| 2731 num_named_arguments)); | 2713 num_named_arguments)); |
| 2732 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); | 2714 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); |
| 2733 if (FLAG_trace_optimization) { | 2715 if (FLAG_trace_optimization) { |
| 2734 OS::Print("Monomorphic inline candidate: %s -> %s\n", | 2716 OS::Print("Monomorphic inline candidate: %s -> %s\n", |
| 2735 target.ToFullyQualifiedCString(), | 2717 target.ToFullyQualifiedCString(), |
| 2736 Recognizer::KindToCString(recognized)); | 2718 Recognizer::KindToCString(recognized)); |
| 2737 } | 2719 } |
| 2738 if ((recognized == Recognizer::kIntegerToDouble) && | 2720 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2739 AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { | 2721 NodeHasClassAt(node, smi_class_, 0)) { |
| 2740 // TODO(srdjan): Check if we could use temporary double instead of | 2722 // TODO(srdjan): Check if we could use temporary double instead of |
| 2741 // allocating a new object every time. | 2723 // allocating a new object every time. |
| 2742 const Code& stub = | 2724 const Code& stub = |
| 2743 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2725 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2744 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2726 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2745 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); | 2727 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); |
| 2746 // EAX is double object. | 2728 // EAX is double object. |
| 2747 DeoptimizationBlob* deopt_blob = | 2729 DeoptimizationBlob* deopt_blob = |
| 2748 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); | 2730 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); |
| 2749 __ popl(EBX); // Receiver | 2731 __ popl(EBX); // Receiver |
| 2750 __ testl(EBX, Immediate(kSmiTagMask)); | 2732 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2751 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2733 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2752 __ SmiUntag(EBX); | 2734 __ SmiUntag(EBX); |
| 2753 __ cvtsi2sd(XMM0, EBX); | 2735 __ cvtsi2sd(XMM0, EBX); |
| 2754 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2736 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2755 return true; | 2737 return true; |
| 2756 } | 2738 } |
| 2757 | 2739 |
| 2758 if ((recognized == Recognizer::kDoubleToDouble) && | 2740 if ((recognized == Recognizer::kDoubleToDouble) && |
| 2759 AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { | 2741 NodeHasClassAt(node, double_class_, 0)) { |
| 2760 DeoptimizationBlob* deopt_blob = | 2742 DeoptimizationBlob* deopt_blob = |
| 2761 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); | 2743 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); |
| 2762 __ popl(EAX); | 2744 __ popl(EAX); |
| 2763 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2745 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2764 return true; | 2746 return true; |
| 2765 } | 2747 } |
| 2766 } | 2748 } |
| 2767 return false; | 2749 return false; |
| 2768 } | 2750 } |
| 2769 | 2751 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2896 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); | 2878 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); |
| 2897 __ cmpl(EDX, EAX); | 2879 __ cmpl(EDX, EAX); |
| 2898 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 2880 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 2899 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); | 2881 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); |
| 2900 __ Bind(&done); | 2882 __ Bind(&done); |
| 2901 HandleResult(node, EAX); | 2883 HandleResult(node, EAX); |
| 2902 return; | 2884 return; |
| 2903 } | 2885 } |
| 2904 | 2886 |
| 2905 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { | 2887 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { |
| 2906 if (AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { | 2888 if (NodeHasClassAt(node, smi_class_, 0)) { |
| 2907 const ICData& ic_data = node->ICDataAtId(node->id()); | 2889 const ICData& ic_data = node->ic_data(); |
| 2908 ASSERT(ic_data.num_args_tested() == 1); | 2890 ASSERT(ic_data.num_args_tested() == 1); |
| 2909 GenerateSmiUnaryOp(node); | 2891 GenerateSmiUnaryOp(node); |
| 2910 return; | 2892 return; |
| 2911 } | 2893 } |
| 2912 } | 2894 } |
| 2913 if (node->kind() == Token::kSUB) { | 2895 if (node->kind() == Token::kSUB) { |
| 2914 if (AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { | 2896 if (NodeHasClassAt(node, double_class_, 0)) { |
| 2915 const ICData& ic_data = node->ICDataAtId(node->id()); | 2897 const ICData& ic_data = node->ic_data(); |
| 2916 ASSERT(ic_data.num_args_tested() == 1); | 2898 ASSERT(ic_data.num_args_tested() == 1); |
| 2917 GenerateDoubleUnaryOp(node); | 2899 GenerateDoubleUnaryOp(node); |
| 2918 return; | 2900 return; |
| 2919 } | 2901 } |
| 2920 } | 2902 } |
| 2921 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 2903 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 2922 CodeGenerator::VisitUnaryOpNode(node); | 2904 CodeGenerator::VisitUnaryOpNode(node); |
| 2923 } | 2905 } |
| 2924 | 2906 |
| 2925 | 2907 |
| 2926 } // namespace dart | 2908 } // namespace dart |
| 2927 | 2909 |
| 2928 #endif // defined TARGET_ARCH_IA32 | 2910 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |