| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_XXX. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_XXX. |
| 6 | 6 |
| 7 #include "vm/flow_graph_compiler.h" | 7 #include "vm/flow_graph_compiler.h" |
| 8 | 8 |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 11 #include "vm/debugger.h" | 11 #include "vm/debugger.h" |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 ASSERT(bitmap->Length() <= StackSize()); | 348 ASSERT(bitmap->Length() <= StackSize()); |
| 349 // Pad the bitmap out to describe all the spill slots. | 349 // Pad the bitmap out to describe all the spill slots. |
| 350 bitmap->SetLength(StackSize()); | 350 bitmap->SetLength(StackSize()); |
| 351 | 351 |
| 352 // Mark the bits in the stack map in the same order we push registers in | 352 // Mark the bits in the stack map in the same order we push registers in |
| 353 // slow path code (see FlowGraphCompiler::SaveLiveRegisters). | 353 // slow path code (see FlowGraphCompiler::SaveLiveRegisters). |
| 354 // | 354 // |
| 355 // Slow path code can have registers at the safepoint. | 355 // Slow path code can have registers at the safepoint. |
| 356 if (!locs->always_calls()) { | 356 if (!locs->always_calls()) { |
| 357 RegisterSet* regs = locs->live_registers(); | 357 RegisterSet* regs = locs->live_registers(); |
| 358 if (regs->xmm_regs_count() > 0) { | 358 if (regs->fpu_regs_count() > 0) { |
| 359 // Denote XMM registers with 0 bits in the stackmap. Based on the | 359 // Denote FPU registers with 0 bits in the stackmap. Based on the |
| 360 // assumption that there are normally few live XMM registers, this | 360 // assumption that there are normally few live FPU registers, this |
| 361 // encoding is simpler and roughly as compact as storing a separate | 361 // encoding is simpler and roughly as compact as storing a separate |
| 362 // count of XMM registers. | 362 // count of FPU registers. |
| 363 // | 363 // |
| 364 // XMM registers have the highest register number at the highest | 364 // FPU registers have the highest register number at the highest |
| 365 // address (i.e., first in the stackmap). | 365 // address (i.e., first in the stackmap). |
| 366 for (intptr_t i = kNumberOfXmmRegisters - 1; i >= 0; --i) { | 366 for (intptr_t i = kNumberOfFpuRegisters - 1; i >= 0; --i) { |
| 367 XmmRegister reg = static_cast<XmmRegister>(i); | 367 FpuRegister reg = static_cast<FpuRegister>(i); |
| 368 if (regs->ContainsXmmRegister(reg)) { | 368 if (regs->ContainsFpuRegister(reg)) { |
| 369 for (intptr_t j = 0; | 369 for (intptr_t j = 0; |
| 370 j < FlowGraphAllocator::kDoubleSpillSlotFactor; | 370 j < FlowGraphAllocator::kDoubleSpillSlotFactor; |
| 371 ++j) { | 371 ++j) { |
| 372 bitmap->Set(bitmap->Length(), false); | 372 bitmap->Set(bitmap->Length(), false); |
| 373 } | 373 } |
| 374 } | 374 } |
| 375 } | 375 } |
| 376 } | 376 } |
| 377 // General purpose registers have the lowest register number at the | 377 // General purpose registers have the lowest register number at the |
| 378 // highest address (i.e., first in the stackmap). | 378 // highest address (i.e., first in the stackmap). |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 | 653 |
| 654 | 654 |
| 655 void FlowGraphCompiler::EmitComment(Instruction* instr) { | 655 void FlowGraphCompiler::EmitComment(Instruction* instr) { |
| 656 char buffer[256]; | 656 char buffer[256]; |
| 657 BufferFormatter f(buffer, sizeof(buffer)); | 657 BufferFormatter f(buffer, sizeof(buffer)); |
| 658 instr->PrintTo(&f); | 658 instr->PrintTo(&f); |
| 659 assembler()->Comment("%s", buffer); | 659 assembler()->Comment("%s", buffer); |
| 660 } | 660 } |
| 661 | 661 |
| 662 | 662 |
| 663 struct CidTarget { | |
| 664 intptr_t cid; | |
| 665 Function* target; | |
| 666 intptr_t count; | |
| 667 CidTarget(intptr_t cid_arg, | |
| 668 Function* target_arg, | |
| 669 intptr_t count_arg) | |
| 670 : cid(cid_arg), target(target_arg), count(count_arg) {} | |
| 671 }; | |
| 672 | |
| 673 | |
| 674 // Returns 'sorted' array in decreasing count order. | |
| 675 // The expected number of elements to sort is less than 10. | |
| 676 static void SortICDataByCount(const ICData& ic_data, | |
| 677 GrowableArray<CidTarget>* sorted) { | |
| 678 ASSERT(ic_data.num_args_tested() == 1); | |
| 679 const intptr_t len = ic_data.NumberOfChecks(); | |
| 680 sorted->Clear(); | |
| 681 | |
| 682 for (int i = 0; i < len; i++) { | |
| 683 sorted->Add(CidTarget(ic_data.GetReceiverClassIdAt(i), | |
| 684 &Function::ZoneHandle(ic_data.GetTargetAt(i)), | |
| 685 ic_data.GetCountAt(i))); | |
| 686 } | |
| 687 for (int i = 0; i < len; i++) { | |
| 688 intptr_t largest_ix = i; | |
| 689 for (int k = i + 1; k < len; k++) { | |
| 690 if ((*sorted)[largest_ix].count < (*sorted)[k].count) { | |
| 691 largest_ix = k; | |
| 692 } | |
| 693 } | |
| 694 if (i != largest_ix) { | |
| 695 // Swap. | |
| 696 CidTarget temp = (*sorted)[i]; | |
| 697 (*sorted)[i] = (*sorted)[largest_ix]; | |
| 698 (*sorted)[largest_ix] = temp; | |
| 699 } | |
| 700 } | |
| 701 } | |
| 702 | |
| 703 | |
| 704 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | |
| 705 Register class_id_reg, | |
| 706 intptr_t arg_count, | |
| 707 const Array& arg_names, | |
| 708 Label* deopt, | |
| 709 intptr_t deopt_id, | |
| 710 intptr_t token_index, | |
| 711 LocationSummary* locs) { | |
| 712 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | |
| 713 Label match_found; | |
| 714 const intptr_t len = ic_data.NumberOfChecks(); | |
| 715 GrowableArray<CidTarget> sorted(len); | |
| 716 SortICDataByCount(ic_data, &sorted); | |
| 717 for (intptr_t i = 0; i < len; i++) { | |
| 718 const bool is_last_check = (i == (len - 1)); | |
| 719 Label next_test; | |
| 720 assembler()->cmpl(class_id_reg, Immediate(sorted[i].cid)); | |
| 721 if (is_last_check) { | |
| 722 assembler()->j(NOT_EQUAL, deopt); | |
| 723 } else { | |
| 724 assembler()->j(NOT_EQUAL, &next_test); | |
| 725 } | |
| 726 GenerateStaticCall(deopt_id, | |
| 727 token_index, | |
| 728 *sorted[i].target, | |
| 729 arg_count, | |
| 730 arg_names, | |
| 731 locs); | |
| 732 if (!is_last_check) { | |
| 733 assembler()->jmp(&match_found); | |
| 734 } | |
| 735 assembler()->Bind(&next_test); | |
| 736 } | |
| 737 assembler()->Bind(&match_found); | |
| 738 } | |
| 739 | |
| 740 | |
| 741 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, | |
| 742 XmmRegister left, | |
| 743 XmmRegister right, | |
| 744 BranchInstr* branch) { | |
| 745 ASSERT(branch != NULL); | |
| 746 assembler()->comisd(left, right); | |
| 747 BlockEntryInstr* nan_result = (true_condition == NOT_EQUAL) ? | |
| 748 branch->true_successor() : branch->false_successor(); | |
| 749 assembler()->j(PARITY_EVEN, GetBlockLabel(nan_result)); | |
| 750 branch->EmitBranchOnCondition(this, true_condition); | |
| 751 } | |
| 752 | |
| 753 | |
| 754 | |
| 755 void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition, | |
| 756 XmmRegister left, | |
| 757 XmmRegister right, | |
| 758 Register result) { | |
| 759 assembler()->comisd(left, right); | |
| 760 Label is_false, is_true, done; | |
| 761 assembler()->j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN false; | |
| 762 assembler()->j(true_condition, &is_true, Assembler::kNearJump); | |
| 763 assembler()->Bind(&is_false); | |
| 764 assembler()->LoadObject(result, Bool::False()); | |
| 765 assembler()->jmp(&done); | |
| 766 assembler()->Bind(&is_true); | |
| 767 assembler()->LoadObject(result, Bool::True()); | |
| 768 assembler()->Bind(&done); | |
| 769 } | |
| 770 | |
| 771 | |
| 772 // Allocate a register that is not explicitly blocked. | 663 // Allocate a register that is not explicitly blocked. |
| 773 static Register AllocateFreeRegister(bool* blocked_registers) { | 664 static Register AllocateFreeRegister(bool* blocked_registers) { |
| 774 for (intptr_t regno = 0; regno < kNumberOfCpuRegisters; regno++) { | 665 for (intptr_t regno = 0; regno < kNumberOfCpuRegisters; regno++) { |
| 775 if (!blocked_registers[regno]) { | 666 if (!blocked_registers[regno]) { |
| 776 blocked_registers[regno] = true; | 667 blocked_registers[regno] = true; |
| 777 return static_cast<Register>(regno); | 668 return static_cast<Register>(regno); |
| 778 } | 669 } |
| 779 } | 670 } |
| 780 UNREACHABLE(); | 671 UNREACHABLE(); |
| 781 return kNoRegister; | 672 return kNoRegister; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 case Location::kAny: | 757 case Location::kAny: |
| 867 case Location::kPrefersRegister: | 758 case Location::kPrefersRegister: |
| 868 case Location::kRequiresRegister: | 759 case Location::kRequiresRegister: |
| 869 case Location::kWritableRegister: | 760 case Location::kWritableRegister: |
| 870 result_location = Location::RegisterLocation( | 761 result_location = Location::RegisterLocation( |
| 871 AllocateFreeRegister(blocked_registers)); | 762 AllocateFreeRegister(blocked_registers)); |
| 872 break; | 763 break; |
| 873 case Location::kSameAsFirstInput: | 764 case Location::kSameAsFirstInput: |
| 874 result_location = locs->in(0); | 765 result_location = locs->in(0); |
| 875 break; | 766 break; |
| 876 case Location::kRequiresXmmRegister: | 767 case Location::kRequiresFpuRegister: |
| 877 UNREACHABLE(); | 768 UNREACHABLE(); |
| 878 break; | 769 break; |
| 879 } | 770 } |
| 880 locs->set_out(result_location); | 771 locs->set_out(result_location); |
| 881 } | 772 } |
| 882 } | 773 } |
| 883 | 774 |
| 884 | 775 |
| 885 ParallelMoveResolver::ParallelMoveResolver(FlowGraphCompiler* compiler) | 776 ParallelMoveResolver::ParallelMoveResolver(FlowGraphCompiler* compiler) |
| 886 : compiler_(compiler), moves_(32) {} | 777 : compiler_(compiler), moves_(32) {} |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 983 EmitSwap(index); | 874 EmitSwap(index); |
| 984 return; | 875 return; |
| 985 } | 876 } |
| 986 } | 877 } |
| 987 | 878 |
| 988 // This move is not blocked. | 879 // This move is not blocked. |
| 989 EmitMove(index); | 880 EmitMove(index); |
| 990 } | 881 } |
| 991 | 882 |
| 992 | 883 |
| 993 Condition FlowGraphCompiler::FlipCondition(Condition condition) { | |
| 994 switch (condition) { | |
| 995 case EQUAL: return EQUAL; | |
| 996 case NOT_EQUAL: return NOT_EQUAL; | |
| 997 case LESS: return GREATER; | |
| 998 case LESS_EQUAL: return GREATER_EQUAL; | |
| 999 case GREATER: return LESS; | |
| 1000 case GREATER_EQUAL: return LESS_EQUAL; | |
| 1001 case BELOW: return ABOVE; | |
| 1002 case BELOW_EQUAL: return ABOVE_EQUAL; | |
| 1003 case ABOVE: return BELOW; | |
| 1004 case ABOVE_EQUAL: return BELOW_EQUAL; | |
| 1005 default: | |
| 1006 UNIMPLEMENTED(); | |
| 1007 return EQUAL; | |
| 1008 } | |
| 1009 } | |
| 1010 | |
| 1011 | |
| 1012 bool FlowGraphCompiler::EvaluateCondition(Condition condition, | |
| 1013 intptr_t left, | |
| 1014 intptr_t right) { | |
| 1015 const uintptr_t unsigned_left = static_cast<uintptr_t>(left); | |
| 1016 const uintptr_t unsigned_right = static_cast<uintptr_t>(right); | |
| 1017 switch (condition) { | |
| 1018 case EQUAL: return left == right; | |
| 1019 case NOT_EQUAL: return left != right; | |
| 1020 case LESS: return left < right; | |
| 1021 case LESS_EQUAL: return left <= right; | |
| 1022 case GREATER: return left > right; | |
| 1023 case GREATER_EQUAL: return left >= right; | |
| 1024 case BELOW: return unsigned_left < unsigned_right; | |
| 1025 case BELOW_EQUAL: return unsigned_left <= unsigned_right; | |
| 1026 case ABOVE: return unsigned_left > unsigned_right; | |
| 1027 case ABOVE_EQUAL: return unsigned_left >= unsigned_right; | |
| 1028 default: | |
| 1029 UNIMPLEMENTED(); | |
| 1030 return false; | |
| 1031 } | |
| 1032 } | |
| 1033 | |
| 1034 | |
| 1035 intptr_t FlowGraphCompiler::ElementSizeFor(intptr_t cid) { | 884 intptr_t FlowGraphCompiler::ElementSizeFor(intptr_t cid) { |
| 1036 switch (cid) { | 885 switch (cid) { |
| 1037 case kArrayCid: | 886 case kArrayCid: |
| 1038 case kImmutableArrayCid: | 887 case kImmutableArrayCid: |
| 1039 return Array::kBytesPerElement; | 888 return Array::kBytesPerElement; |
| 1040 case kFloat32ArrayCid: | 889 case kFloat32ArrayCid: |
| 1041 return Float32Array::kBytesPerElement; | 890 return Float32Array::kBytesPerElement; |
| 1042 case kFloat64ArrayCid: | 891 case kFloat64ArrayCid: |
| 1043 return Float64Array::kBytesPerElement; | 892 return Float64Array::kBytesPerElement; |
| 1044 case kUint8ArrayCid: | 893 case kUint8ArrayCid: |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1073 return OneByteString::data_offset(); | 922 return OneByteString::data_offset(); |
| 1074 case kTwoByteStringCid: | 923 case kTwoByteStringCid: |
| 1075 return TwoByteString::data_offset(); | 924 return TwoByteString::data_offset(); |
| 1076 default: | 925 default: |
| 1077 UNIMPLEMENTED(); | 926 UNIMPLEMENTED(); |
| 1078 return Array::data_offset(); | 927 return Array::data_offset(); |
| 1079 } | 928 } |
| 1080 } | 929 } |
| 1081 | 930 |
| 1082 | 931 |
| 1083 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid, | |
| 1084 Register array, | |
| 1085 intptr_t index) { | |
| 1086 const int64_t disp = | |
| 1087 static_cast<int64_t>(index) * ElementSizeFor(cid) + DataOffsetFor(cid); | |
| 1088 ASSERT(Utils::IsInt(32, disp)); | |
| 1089 return FieldAddress(array, static_cast<int32_t>(disp)); | |
| 1090 } | |
| 1091 | |
| 1092 | |
| 1093 FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid, | |
| 1094 Register array, | |
| 1095 Register index) { | |
| 1096 // Note that index is smi-tagged, (i.e, times 2) for all arrays with element | |
| 1097 // size > 1. For Uint8Array and OneByteString the index is expected to be | |
| 1098 // untagged before accessing. | |
| 1099 ASSERT(kSmiTagShift == 1); | |
| 1100 switch (cid) { | |
| 1101 case kArrayCid: | |
| 1102 case kImmutableArrayCid: | |
| 1103 return FieldAddress( | |
| 1104 array, index, TIMES_HALF_WORD_SIZE, Array::data_offset()); | |
| 1105 case kFloat32ArrayCid: | |
| 1106 return FieldAddress(array, index, TIMES_2, Float32Array::data_offset()); | |
| 1107 case kFloat64ArrayCid: | |
| 1108 return FieldAddress(array, index, TIMES_4, Float64Array::data_offset()); | |
| 1109 case kUint8ArrayCid: | |
| 1110 return FieldAddress(array, index, TIMES_1, Uint8Array::data_offset()); | |
| 1111 case kUint8ClampedArrayCid: | |
| 1112 return | |
| 1113 FieldAddress(array, index, TIMES_1, Uint8ClampedArray::data_offset()); | |
| 1114 case kOneByteStringCid: | |
| 1115 return FieldAddress(array, index, TIMES_1, OneByteString::data_offset()); | |
| 1116 case kTwoByteStringCid: | |
| 1117 return FieldAddress(array, index, TIMES_1, TwoByteString::data_offset()); | |
| 1118 default: | |
| 1119 UNIMPLEMENTED(); | |
| 1120 return FieldAddress(SPREG, 0); | |
| 1121 } | |
| 1122 } | |
| 1123 | |
| 1124 | |
| 1125 // Returns true if checking against this type is a direct class id comparison. | 932 // Returns true if checking against this type is a direct class id comparison. |
| 1126 bool FlowGraphCompiler::TypeCheckAsClassEquality(const AbstractType& type) { | 933 bool FlowGraphCompiler::TypeCheckAsClassEquality(const AbstractType& type) { |
| 1127 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 934 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1128 // Requires CHA, which can be applied in optimized code only, | 935 // Requires CHA, which can be applied in optimized code only, |
| 1129 if (!FLAG_use_cha || !is_optimizing()) return false; | 936 if (!FLAG_use_cha || !is_optimizing()) return false; |
| 1130 if (!type.IsInstantiated()) return false; | 937 if (!type.IsInstantiated()) return false; |
| 1131 const Class& type_class = Class::Handle(type.type_class()); | 938 const Class& type_class = Class::Handle(type.type_class()); |
| 1132 // Signature classes have different type checking rules. | 939 // Signature classes have different type checking rules. |
| 1133 if (type_class.IsSignatureClass()) return false; | 940 if (type_class.IsSignatureClass()) return false; |
| 1134 // Could be an interface check? | 941 // Could be an interface check? |
| 1135 if (type_class.is_implemented()) return false; | 942 if (type_class.is_implemented()) return false; |
| 1136 const intptr_t type_cid = type_class.id(); | 943 const intptr_t type_cid = type_class.id(); |
| 1137 if (CHA::HasSubclasses(type_cid)) return false; | 944 if (CHA::HasSubclasses(type_cid)) return false; |
| 1138 if (type_class.HasTypeArguments()) { | 945 if (type_class.HasTypeArguments()) { |
| 1139 // Only raw types can be directly compared, thus disregarding type | 946 // Only raw types can be directly compared, thus disregarding type |
| 1140 // arguments. | 947 // arguments. |
| 1141 const AbstractTypeArguments& type_arguments = | 948 const AbstractTypeArguments& type_arguments = |
| 1142 AbstractTypeArguments::Handle(type.arguments()); | 949 AbstractTypeArguments::Handle(type.arguments()); |
| 1143 const bool is_raw_type = type_arguments.IsNull() || | 950 const bool is_raw_type = type_arguments.IsNull() || |
| 1144 type_arguments.IsRaw(type_arguments.Length()); | 951 type_arguments.IsRaw(type_arguments.Length()); |
| 1145 return is_raw_type; | 952 return is_raw_type; |
| 1146 } | 953 } |
| 1147 return true; | 954 return true; |
| 1148 } | 955 } |
| 1149 | 956 |
| 1150 } // namespace dart | 957 } // namespace dart |
| OLD | NEW |