OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 | 9 |
10 #include "lib/error.h" | 10 #include "lib/error.h" |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 | 537 |
538 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 538 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
539 const LocationSummary& locs, | 539 const LocationSummary& locs, |
540 Token::Kind kind, | 540 Token::Kind kind, |
541 BranchInstr* branch, | 541 BranchInstr* branch, |
542 intptr_t deopt_id, | 542 intptr_t deopt_id, |
543 intptr_t try_index) { | 543 intptr_t try_index) { |
544 Register left = locs.in(0).reg(); | 544 Register left = locs.in(0).reg(); |
545 Register right = locs.in(1).reg(); | 545 Register right = locs.in(1).reg(); |
546 const bool left_is_smi = (branch == NULL) ? | 546 const bool left_is_smi = (branch == NULL) ? |
547 false : (branch->left()->ResultCid() == kSmiCid); | 547 false : (branch->computation()->left()->ResultCid() == kSmiCid); |
548 const bool right_is_smi = (branch == NULL) ? | 548 const bool right_is_smi = (branch == NULL) ? |
549 false : (branch->right()->ResultCid() == kSmiCid); | 549 false : (branch->computation()->right()->ResultCid() == kSmiCid); |
| 550 // TODO(fschneider): Move smi smi checks outside this instruction. |
550 if (!left_is_smi || !right_is_smi) { | 551 if (!left_is_smi || !right_is_smi) { |
551 Register temp = locs.temp(0).reg(); | 552 Register temp = locs.temp(0).reg(); |
552 Label* deopt = compiler->AddDeoptStub(deopt_id, | 553 Label* deopt = compiler->AddDeoptStub(deopt_id, |
553 try_index, | 554 try_index, |
554 kDeoptSmiCompareSmi); | 555 kDeoptSmiCompareSmi); |
555 __ movl(temp, left); | 556 __ movl(temp, left); |
556 __ orl(temp, right); | 557 __ orl(temp, right); |
557 __ testl(temp, Immediate(kSmiTagMask)); | 558 __ testl(temp, Immediate(kSmiTagMask)); |
558 __ j(NOT_ZERO, deopt); | 559 __ j(NOT_ZERO, deopt); |
559 } | 560 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 compiler->EmitDoubleCompareBranch( | 613 compiler->EmitDoubleCompareBranch( |
613 true_condition, XMM0, XMM1, branch); | 614 true_condition, XMM0, XMM1, branch); |
614 } else { | 615 } else { |
615 compiler->EmitDoubleCompareBool( | 616 compiler->EmitDoubleCompareBool( |
616 true_condition, XMM0, XMM1, locs.out().reg()); | 617 true_condition, XMM0, XMM1, locs.out().reg()); |
617 } | 618 } |
618 } | 619 } |
619 | 620 |
620 | 621 |
621 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 622 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 623 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
622 if (receiver_class_id() == kSmiCid) { | 624 if (receiver_class_id() == kSmiCid) { |
623 // Deoptimizes if both arguments not Smi. | 625 // Deoptimizes if both arguments not Smi. |
624 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 626 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
625 deopt_id(), try_index()); | 627 deopt_id(), try_index()); |
626 return; | 628 return; |
627 } | 629 } |
628 if (receiver_class_id() == kDoubleCid) { | 630 if (receiver_class_id() == kDoubleCid) { |
629 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. | 631 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. |
630 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 632 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
631 deopt_id(), try_index()); | 633 deopt_id(), try_index()); |
632 return; | 634 return; |
633 } | 635 } |
634 const bool is_checked_strict_equal = | 636 const bool is_checked_strict_equal = |
635 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 637 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
636 if (is_checked_strict_equal) { | 638 if (is_checked_strict_equal) { |
637 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL, | 639 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL, |
638 deopt_id(), try_index()); | 640 deopt_id(), try_index()); |
639 return; | 641 return; |
640 } | 642 } |
641 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 643 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
642 EmitGenericEqualityCompare(compiler, locs(), kind(), NULL, *ic_data(), | 644 EmitGenericEqualityCompare(compiler, locs(), kind(), NULL, *ic_data(), |
643 deopt_id(), token_pos(), try_index()); | 645 deopt_id(), token_pos(), try_index()); |
644 } else { | 646 return; |
645 Register left = locs()->in(0).reg(); | |
646 Register right = locs()->in(1).reg(); | |
647 __ pushl(left); | |
648 __ pushl(right); | |
649 EmitEqualityAsInstanceCall(compiler, | |
650 deopt_id(), | |
651 token_pos(), | |
652 try_index(), | |
653 kind(), | |
654 locs()); | |
655 ASSERT(locs()->out().reg() == EAX); | |
656 } | 647 } |
| 648 Register left = locs()->in(0).reg(); |
| 649 Register right = locs()->in(1).reg(); |
| 650 __ pushl(left); |
| 651 __ pushl(right); |
| 652 EmitEqualityAsInstanceCall(compiler, |
| 653 deopt_id(), |
| 654 token_pos(), |
| 655 try_index(), |
| 656 kind(), |
| 657 locs()); |
| 658 ASSERT(locs()->out().reg() == EAX); |
| 659 } |
| 660 |
| 661 |
| 662 void EqualityCompareComp::EmitBranchCode(FlowGraphCompiler* compiler, |
| 663 BranchInstr* branch) { |
| 664 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 665 if (receiver_class_id() == kSmiCid) { |
| 666 // Deoptimizes if both arguments not Smi. |
| 667 EmitSmiComparisonOp(compiler, *locs(), kind(), branch, |
| 668 deopt_id(), try_index()); |
| 669 return; |
| 670 } |
| 671 if (receiver_class_id() == kDoubleCid) { |
| 672 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. |
| 673 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, |
| 674 deopt_id(), try_index()); |
| 675 return; |
| 676 } |
| 677 const bool is_checked_strict_equal = |
| 678 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 679 if (is_checked_strict_equal) { |
| 680 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch, |
| 681 deopt_id(), try_index()); |
| 682 return; |
| 683 } |
| 684 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 685 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), |
| 686 deopt_id(), token_pos(), try_index()); |
| 687 return; |
| 688 } |
| 689 Register left = locs()->in(0).reg(); |
| 690 Register right = locs()->in(1).reg(); |
| 691 __ pushl(left); |
| 692 __ pushl(right); |
| 693 EmitEqualityAsInstanceCall(compiler, |
| 694 deopt_id(), |
| 695 token_pos(), |
| 696 try_index(), |
| 697 Token::kEQ, // kNE reverse occurs at branch. |
| 698 locs()); |
| 699 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; |
| 700 __ CompareObject(EAX, compiler->bool_true()); |
| 701 branch->EmitBranchOnCondition(compiler, branch_condition); |
657 } | 702 } |
658 | 703 |
659 | 704 |
660 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 705 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
661 const intptr_t kNumInputs = 2; | 706 const intptr_t kNumInputs = 2; |
662 if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) { | 707 if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) { |
663 const intptr_t kNumTemps = 1; | 708 const intptr_t kNumTemps = 1; |
664 LocationSummary* summary = | 709 LocationSummary* summary = |
665 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 710 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
666 summary->set_in(0, Location::RequiresRegister()); | 711 summary->set_in(0, Location::RequiresRegister()); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
715 __ Bind(&done); | 760 __ Bind(&done); |
716 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), | 761 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), |
717 EDI, // Class id register. | 762 EDI, // Class id register. |
718 kNumArguments, | 763 kNumArguments, |
719 Array::Handle(), // No named arguments. | 764 Array::Handle(), // No named arguments. |
720 deopt, // Deoptimize target. | 765 deopt, // Deoptimize target. |
721 deopt_id(), | 766 deopt_id(), |
722 token_pos(), | 767 token_pos(), |
723 try_index(), | 768 try_index(), |
724 locs()); | 769 locs()); |
725 ASSERT(locs()->out().reg() == EAX); | |
726 return; | 770 return; |
727 } | 771 } |
728 const String& function_name = | 772 const String& function_name = |
729 String::ZoneHandle(Symbols::New(Token::Str(kind()))); | 773 String::ZoneHandle(Symbols::New(Token::Str(kind()))); |
730 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 774 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
731 deopt_id(), | 775 deopt_id(), |
732 token_pos(), | 776 token_pos(), |
733 try_index()); | 777 try_index()); |
734 const intptr_t kNumArguments = 2; | 778 const intptr_t kNumArguments = 2; |
735 const intptr_t kNumArgsChecked = 2; // Type-feedback. | 779 const intptr_t kNumArgsChecked = 2; // Type-feedback. |
736 compiler->GenerateInstanceCall(deopt_id(), | 780 compiler->GenerateInstanceCall(deopt_id(), |
737 token_pos(), | 781 token_pos(), |
738 try_index(), | 782 try_index(), |
739 function_name, | 783 function_name, |
740 kNumArguments, | 784 kNumArguments, |
741 Array::ZoneHandle(), // No optional arguments. | 785 Array::ZoneHandle(), // No optional arguments. |
742 kNumArgsChecked, | 786 kNumArgsChecked, |
743 locs()); | 787 locs()); |
744 ASSERT(locs()->out().reg() == EAX); | 788 } |
| 789 |
| 790 |
| 791 void RelationalOpComp::EmitBranchCode(FlowGraphCompiler* compiler, |
| 792 BranchInstr* branch) { |
| 793 if (operands_class_id() == kSmiCid) { |
| 794 EmitSmiComparisonOp(compiler, *locs(), kind(), branch, |
| 795 deopt_id(), try_index()); |
| 796 return; |
| 797 } |
| 798 if (operands_class_id() == kDoubleCid) { |
| 799 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, |
| 800 deopt_id(), try_index()); |
| 801 return; |
| 802 } |
| 803 EmitNativeCode(compiler); |
| 804 __ CompareObject(EAX, compiler->bool_true()); |
| 805 branch->EmitBranchOnCondition(compiler, EQUAL); |
745 } | 806 } |
746 | 807 |
747 | 808 |
748 LocationSummary* NativeCallComp::MakeLocationSummary() const { | 809 LocationSummary* NativeCallComp::MakeLocationSummary() const { |
749 const intptr_t kNumInputs = 0; | 810 const intptr_t kNumInputs = 0; |
750 const intptr_t kNumTemps = 3; | 811 const intptr_t kNumTemps = 3; |
751 LocationSummary* locs = | 812 LocationSummary* locs = |
752 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 813 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
753 locs->set_temp(0, Location::RegisterLocation(EAX)); | 814 locs->set_temp(0, Location::RegisterLocation(EAX)); |
754 locs->set_temp(1, Location::RegisterLocation(ECX)); | 815 locs->set_temp(1, Location::RegisterLocation(ECX)); |
(...skipping 1371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2126 instance_call()->ArgumentCount(), | 2187 instance_call()->ArgumentCount(), |
2127 instance_call()->argument_names(), | 2188 instance_call()->argument_names(), |
2128 deopt, | 2189 deopt, |
2129 instance_call()->deopt_id(), | 2190 instance_call()->deopt_id(), |
2130 instance_call()->token_pos(), | 2191 instance_call()->token_pos(), |
2131 instance_call()->try_index(), | 2192 instance_call()->try_index(), |
2132 locs()); | 2193 locs()); |
2133 } | 2194 } |
2134 | 2195 |
2135 | 2196 |
2136 // TODO(srdjan): Move to shared. | |
2137 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { | |
2138 if (ic_data.num_args_tested() != 2) return false; | |
2139 if (ic_data.NumberOfChecks() != 1) return false; | |
2140 Function& target = Function::Handle(); | |
2141 GrowableArray<intptr_t> class_ids; | |
2142 ic_data.GetCheckAt(0, &class_ids, &target); | |
2143 return (class_ids[0] == class_id) && (class_ids[1] == class_id); | |
2144 } | |
2145 | |
2146 | |
2147 static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) { | |
2148 if ((kind == Token::kEQ) || (kind == Token::kNE)) { | |
2149 return ic_data.AllTargetsHaveSameOwner(kInstanceCid); | |
2150 } | |
2151 return false; | |
2152 } | |
2153 | |
2154 | |
2155 LocationSummary* BranchInstr::MakeLocationSummary() const { | |
2156 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | |
2157 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || | |
2158 ICDataWithBothClassIds(*ic_data(), kDoubleCid) || | |
2159 IsCheckedStrictEquals(*ic_data(), kind())) { | |
2160 const intptr_t kNumInputs = 2; | |
2161 const intptr_t kNumTemps = 1; | |
2162 LocationSummary* summary = | |
2163 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
2164 summary->set_in(0, Location::RequiresRegister()); | |
2165 summary->set_in(1, Location::RequiresRegister()); | |
2166 summary->set_temp(0, Location::RequiresRegister()); | |
2167 return summary; | |
2168 } | |
2169 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | |
2170 const intptr_t kNumInputs = 2; | |
2171 const intptr_t kNumTemps = 1; | |
2172 LocationSummary* locs = | |
2173 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
2174 locs->set_in(0, Location::RegisterLocation(EAX)); | |
2175 locs->set_in(1, Location::RegisterLocation(ECX)); | |
2176 locs->set_temp(0, Location::RegisterLocation(EDX)); | |
2177 return locs; | |
2178 } | |
2179 // Otherwise polymorphic dispatch. | |
2180 } | |
2181 // Call. | |
2182 const intptr_t kNumInputs = 2; | |
2183 const intptr_t kNumTemps = 0; | |
2184 LocationSummary* locs = | |
2185 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
2186 locs->set_in(0, Location::RegisterLocation(EAX)); | |
2187 locs->set_in(1, Location::RegisterLocation(ECX)); | |
2188 return locs; | |
2189 } | |
2190 | |
2191 | |
2192 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2197 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2193 // Relational or equality. | 2198 computation()->EmitBranchCode(compiler, this); |
2194 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | |
2195 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { | |
2196 EmitSmiComparisonOp(compiler, *locs(), kind(), this, | |
2197 deopt_id(), try_index()); | |
2198 return; | |
2199 } | |
2200 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { | |
2201 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, | |
2202 deopt_id(), try_index()); | |
2203 return; | |
2204 } | |
2205 if (IsCheckedStrictEquals(*ic_data(), kind())) { | |
2206 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this, | |
2207 deopt_id(), try_index()); | |
2208 return; | |
2209 } | |
2210 | |
2211 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. | |
2212 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | |
2213 EmitGenericEqualityCompare(compiler, locs(), kind(), this, *ic_data(), | |
2214 deopt_id(), token_pos(), try_index()); | |
2215 return; | |
2216 } | |
2217 // Otherwise polymorphic dispatch? | |
2218 } | |
2219 Register left = locs()->in(0).reg(); | |
2220 Register right = locs()->in(1).reg(); | |
2221 __ pushl(left); | |
2222 __ pushl(right); | |
2223 if ((kind() == Token::kNE) || (kind() == Token::kEQ)) { | |
2224 EmitEqualityAsInstanceCall(compiler, | |
2225 deopt_id(), | |
2226 token_pos(), | |
2227 try_index(), | |
2228 Token::kEQ, // kNE reverse occurs at branch. | |
2229 locs()); | |
2230 } else { | |
2231 const String& function_name = | |
2232 String::ZoneHandle(Symbols::New(Token::Str(kind()))); | |
2233 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | |
2234 deopt_id(), | |
2235 token_pos(), | |
2236 try_index()); | |
2237 const intptr_t kNumArguments = 2; | |
2238 const intptr_t kNumArgsChecked = 2; // Type-feedback. | |
2239 compiler->GenerateInstanceCall(deopt_id(), | |
2240 token_pos(), | |
2241 try_index(), | |
2242 function_name, | |
2243 kNumArguments, | |
2244 Array::ZoneHandle(), // No optional args. | |
2245 kNumArgsChecked, | |
2246 locs()); | |
2247 } | |
2248 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; | |
2249 __ CompareObject(EAX, compiler->bool_true()); | |
2250 EmitBranchOnCondition(compiler, branch_condition); | |
2251 } | |
2252 | |
2253 | |
2254 LocationSummary* StrictCompareAndBranchInstr::MakeLocationSummary() const { | |
2255 const int kNumInputs = 2; | |
2256 const int kNumTemps = 0; | |
2257 LocationSummary* locs = | |
2258 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
2259 locs->set_in(0, Location::RequiresRegister()); | |
2260 locs->set_in(1, Location::RequiresRegister()); | |
2261 return locs; | |
2262 } | |
2263 | |
2264 | |
2265 void StrictCompareAndBranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
2266 Register left = locs()->in(0).reg(); | |
2267 Register right = locs()->in(1).reg(); | |
2268 __ cmpl(left, right); | |
2269 Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; | |
2270 EmitBranchOnCondition(compiler, cond); | |
2271 } | 2199 } |
2272 | 2200 |
2273 | 2201 |
2274 LocationSummary* CheckClassComp::MakeLocationSummary() const { | 2202 LocationSummary* CheckClassComp::MakeLocationSummary() const { |
2275 const intptr_t kNumInputs = 1; | 2203 const intptr_t kNumInputs = 1; |
2276 const intptr_t kNumTemps = 1; | 2204 const intptr_t kNumTemps = 1; |
2277 LocationSummary* summary = | 2205 LocationSummary* summary = |
2278 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2206 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
2279 summary->set_in(0, Location::RequiresRegister()); | 2207 summary->set_in(0, Location::RequiresRegister()); |
2280 summary->set_temp(0, Location::RequiresRegister()); | 2208 summary->set_temp(0, Location::RequiresRegister()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2360 } | 2288 } |
2361 __ j(ABOVE_EQUAL, deopt); | 2289 __ j(ABOVE_EQUAL, deopt); |
2362 } | 2290 } |
2363 | 2291 |
2364 | 2292 |
2365 } // namespace dart | 2293 } // namespace dart |
2366 | 2294 |
2367 #undef __ | 2295 #undef __ |
2368 | 2296 |
2369 #endif // defined TARGET_ARCH_X64 | 2297 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |